// File: /workspace/github_cpp_makefile_star2_O3/saumya-prakash[P]AssemblerEmulator/Emulator.cpp
// Function: Emulator::execute[abi:cxx11]()
string Emulator::execute()
{   
    if(fault==true)
    {
        return fault_cause;
    }

    if(finished==true)
        return string();

    if(text_size==0)
    {
        finished = true;
        return "No text segment to execute";
    }

    string res = current_state();

    int mach_code = mempory_space[PC];     // get current machine code

    int opcode = (mach_code<<24)>>24;
    int operand = (mach_code & static_cast<int>(0xffffff00)) / 256; // cast required for operations to work correctly work correctly


    ++PC;   // PC incremented to point to next instruction

    check_PC(PC);
    if(PC>pc_upper)
    {   
        fault = true;

        string tmp = faults.find(0)->second;
        fault_cause = tmp + " as upper limit for text segment crossed; no HALT encountered";
        
        return fault_cause;
    }

    switch(opcode)
    {
        case 0:         // ldc value
                B = A;
                A = operand;
                break;
        
        case 1:         // adc value
                A = A + operand;
                break;

        case 2:         // ldl value      // proper checks to be included

                check_memory_access(SP+operand);
                if(fault==true)
                    return fault_cause;

                B = A;
                A = mempory_space[SP+operand];
                break;

        case 3:         // stl value
                check_memory_access(SP+operand);
                if(fault==true)
                    return fault_cause;

                mempory_space[SP+operand] = A;
                A = B;
                break;

        case 4:         // ldnl offset
                check_memory_access(A+operand);
                if(fault==true)
                    return fault_cause;
                
                A = mempory_space[A+operand];
                break;
        
        case 5:         // stnl offset
                check_memory_access(A+operand);
                if(fault==true)
                    return fault_cause;

                mempory_space[A+operand] = B;
                break;

        case 6:         // add
                A = B + A;
                break;

        case 7:         // sub
                A = B - A;
                break;

        case 8:         // shl
                A = B<<A;
                break;
        
        case 9:         // shr
                A = B>>A;
                break;
        
        case 10:        // adj value
                check_SP(SP+operand);
                if(fault==true)
                    return fault_cause;

                SP = SP + operand;
                break;
        
        case 11:        //a2sp
                check_SP(A);
                if(fault==true)
                    return fault_cause;

                SP = A;
                A = B;
                break;
        
        case 12:        // sp2a
                B = A;
                A = SP;
                break;
        
        case 13:        // call offset

                check_PC(PC+operand);
                if(fault==true)
                    return fault_cause;
                
                B = A;
                A = PC;
                PC = PC+operand;
                break;

        case 14:        // return 
                check_PC(A);
                if(fault==true)
                    return fault_cause;
                
                PC = A;
                A = B;
                break;

        case 15:        // brz offset
                if(A==0)
                {   check_PC(PC+operand);
                    if(fault==true)
                        return fault_cause;
                
                    PC = PC+operand;
                }

                break;
        
        case 16:        // brlz offset
                if(A<0)
                {
                    check_PC(PC+operand);
                    if(fault==true)
                        return fault_cause;
                    
                    PC = PC+operand;
                }

                break;

        case 17:        // br offset
                check_PC(PC+operand);
                if(fault==true)
                    return fault_cause;
                
                PC = PC+operand;
                break;
        
        case 18:        // HALT
                finished = true;
                break;
        
        default:    
                fault = true;
                fault_cause = faults.find(7)->second;
                return fault_cause;
                
                break;
    }

    ++instr_cnt; 

    if(instr_cnt==max_instruction_count) // looped back to 0 -> limit crossed
    {
        fault = true;          
                                  // indiacte program took too long to finish
        ostringstream oss;

        oss<<faults.find(6)->second;
        oss<<'\n';
        
        oss<<instr_cnt<<" instructions executed so far\n";

        fault_cause = oss.str();

        return fault_cause;
    }

    return res;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1b8, %rsp            # imm = 0x1B8
movq %rsi, %r14
movq %rdi, %rbx
cmpb $0x1, 0x51(%rsi)
jne 0x47bc
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
movq 0x58(%r14), %rsi
movq 0x60(%r14), %rdx
addq %rsi, %rdx
movq %rbx, %rdi
callq 0x431c
jmp 0x4d6b
cmpb $0x1, 0x50(%r14)
jne 0x47db
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
movq $0x0, 0x8(%rbx)
movb $0x0, 0x10(%rbx)
jmp 0x4d6b
cmpl $0x0, 0x48(%r14)
je 0x4853
leaq 0x20(%rsp), %rdi
movq %r14, %rsi
callq 0x4e0c
movq 0x30(%r14), %rax
movslq 0x28(%r14), %rcx
movl (%rax,%rcx,4), %ebp
leal 0x1(%rcx), %esi
movl %esi, 0x28(%r14)
movq %r14, %rdi
callq 0x512a
movl 0x28(%r14), %esi
cmpl $0x400, %esi            # imm = 0x400
jb 0x487a
movb $0x1, 0x51(%r14)
movq 0x5997(%rip), %rax      # 0xa1b8
testq %rax, %rax
je 0x48ad
movq %rax, %rcx
movq 0x10(%rax), %rax
testq %rax, %rax
jne 0x482a
leaq 0x5973(%rip), %rax      # 0xa1b0
cmpq %rax, %rcx
je 0x48b4
cmpl $0x0, 0x20(%rcx)
leaq 0x5963(%rip), %rax      # 0xa1b0
cmoveq %rcx, %rax
jmp 0x48b4
movb $0x1, 0x50(%r14)
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
leaq 0x2c04(%rip), %rsi      # 0x746a
leaq 0x2c17(%rip), %rdx      # 0x7484
movq %rbx, %rdi
callq 0x43b2
jmp 0x4d6b
movsbl %bpl, %eax
cmpl $0x12, %eax
ja 0x4cd6
sarl $0x8, %ebp
movl %eax, %eax
leaq 0x2a1d(%rip), %rcx      # 0x72b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl 0x20(%r14), %eax
movl %eax, 0x24(%r14)
movl %ebp, 0x20(%r14)
jmp 0x4b5d
leaq 0x58fc(%rip), %rax      # 0xa1b0
leaq 0x50(%rsp), %r12
movq %r12, -0x10(%r12)
movq 0x28(%rax), %rsi
movq 0x30(%rax), %rdx
addq %rsi, %rdx
leaq 0x40(%rsp), %rdi
callq 0x431c
leaq 0x10(%rsp), %r13
movq %r13, -0x10(%r13)
movq 0x40(%rsp), %rsi
movq 0x48(%rsp), %rdx
addq %rsi, %rdx
movq %rsp, %rdi
callq 0x431c
leaq 0x2b8d(%rip), %rsi      # 0x7485
movq %rsp, %rdi
callq 0x2290
leaq 0x58(%r14), %rdi
movq %rsp, %r15
movq %r15, %rsi
callq 0x21c0
movq (%r15), %rdi
cmpq %r13, %rdi
je 0x4924
movq 0x10(%rsp), %rsi
incq %rsi
callq 0x2190
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
movq 0x58(%r14), %rsi
movq 0x60(%r14), %rdx
addq %rsi, %rdx
movq %rbx, %rdi
callq 0x431c
movq 0x40(%rsp), %rdi
cmpq %r12, %rdi
je 0x4d50
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x2190
jmp 0x4d50
cmpl $0x0, 0x20(%r14)
jns 0x4b5d
addl %ebp, %esi
movq %r14, %rdi
callq 0x512a
jmp 0x4aae
movl 0x20(%r14), %esi
movq %r14, %rdi
callq 0x512a
cmpb $0x1, 0x51(%r14)
je 0x4d36
movl 0x20(%r14), %eax
movl 0x24(%r14), %ecx
movl %eax, 0x28(%r14)
jmp 0x49f1
movl 0x20(%r14), %esi
movq %r14, %rdi
callq 0x55ce
cmpb $0x1, 0x51(%r14)
je 0x4d36
movl 0x20(%r14), %eax
movl 0x24(%r14), %ecx
movl %eax, 0x2c(%r14)
jmp 0x49f1
movl 0x20(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x5338
cmpb $0x1, 0x51(%r14)
je 0x4d36
movq 0x30(%r14), %rax
movslq 0x20(%r14), %rcx
jmp 0x4a32
movl 0x20(%r14), %eax
movl 0x2c(%r14), %ecx
movl %eax, 0x24(%r14)
movl %ecx, 0x20(%r14)
jmp 0x4b5d
movl 0x24(%r14), %eax
movb 0x20(%r14), %cl
sarl %cl, %eax
jmp 0x4b59
movl 0x2c(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x5338
cmpb $0x1, 0x51(%r14)
je 0x4d36
movl 0x20(%r14), %eax
movl %eax, 0x24(%r14)
movq 0x30(%r14), %rax
movslq 0x2c(%r14), %rcx
movslq %ebp, %rdx
addq %rcx, %rdx
movl (%rax,%rdx,4), %eax
jmp 0x4b59
cmpl $0x0, 0x20(%r14)
jne 0x4b5d
addl %ebp, %esi
movq %r14, %rdi
callq 0x512a
jmp 0x4aae
movl 0x2c(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x5338
cmpb $0x1, 0x51(%r14)
je 0x4d36
movl 0x20(%r14), %eax
movq 0x30(%r14), %rcx
movslq 0x2c(%r14), %rdx
movslq %ebp, %rsi
addq %rdx, %rsi
movl %eax, (%rcx,%rsi,4)
movl 0x24(%r14), %eax
jmp 0x4b59
movl 0x24(%r14), %eax
subl 0x20(%r14), %eax
jmp 0x4b59
addl %ebp, 0x20(%r14)
jmp 0x4b5d
addl %ebp, %esi
movq %r14, %rdi
callq 0x512a
cmpb $0x1, 0x51(%r14)
je 0x4d36
addl %ebp, 0x28(%r14)
jmp 0x4b5d
movl 0x20(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x5338
cmpb $0x1, 0x51(%r14)
je 0x4d36
movl 0x24(%r14), %eax
movq 0x30(%r14), %rcx
movslq 0x20(%r14), %rdx
movslq %ebp, %rsi
addq %rdx, %rsi
movl %eax, (%rcx,%rsi,4)
jmp 0x4b5d
addl %ebp, %esi
movq %r14, %rdi
callq 0x512a
cmpb $0x1, 0x51(%r14)
je 0x4d36
movl 0x20(%r14), %eax
movl 0x28(%r14), %ecx
movl %eax, 0x24(%r14)
movl %ecx, 0x20(%r14)
addl %ecx, %ebp
movl %ebp, 0x28(%r14)
jmp 0x4b5d
movl 0x24(%r14), %eax
addl %eax, 0x20(%r14)
jmp 0x4b5d
movb $0x1, 0x50(%r14)
jmp 0x4b5d
movl 0x2c(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x55ce
cmpb $0x1, 0x51(%r14)
je 0x4d36
addl %ebp, 0x2c(%r14)
jmp 0x4b5d
movl 0x24(%r14), %eax
movb 0x20(%r14), %cl
shll %cl, %eax
movl %eax, 0x20(%r14)
movq 0x40(%r14), %rax
incq %rax
movq %rax, 0x40(%r14)
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, %rax
jne 0x4bcc
movb $0x1, 0x51(%r14)
leaq 0x40(%rsp), %rdi
callq 0x2200
movq 0x5630(%rip), %rcx      # 0xa1b8
testq %rcx, %rcx
je 0x4c16
leaq 0x5618(%rip), %rax      # 0xa1b0
xorl %edx, %edx
cmpl $0x6, 0x20(%rcx)
setb %dl
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rdx,8), %rcx
testq %rcx, %rcx
jne 0x4b98
leaq 0x55fa(%rip), %rcx      # 0xa1b0
cmpq %rcx, %rax
je 0x4c1d
cmpl $0x7, 0x20(%rax)
leaq 0x55ea(%rip), %rcx      # 0xa1b0
cmovbq %rax, %rcx
jmp 0x4c1d
leaq 0x10(%rbx), %rcx
movq %rcx, (%rbx)
leaq 0x30(%rsp), %rax
movq -0x10(%rax), %rdx
cmpq %rax, %rdx
je 0x4bef
movq %rdx, (%rbx)
movq 0x30(%rsp), %rcx
movq %rcx, 0x10(%rbx)
jmp 0x4bf5
movups (%rax), %xmm0
movups %xmm0, (%rcx)
movq 0x28(%rsp), %rcx
movq %rcx, 0x8(%rbx)
movq %rax, 0x20(%rsp)
movq $0x0, 0x28(%rsp)
movb $0x0, 0x30(%rsp)
jmp 0x4d50
leaq 0x5593(%rip), %rcx      # 0xa1b0
movq 0x28(%rcx), %rsi
movq 0x30(%rcx), %rdx
leaq 0x40(%rsp), %rdi
callq 0x21b0
movq %rsp, %rsi
movb $0xa, (%rsi)
leaq 0x40(%rsp), %rdi
movl $0x1, %edx
callq 0x21b0
movq 0x40(%r14), %rsi
leaq 0x40(%rsp), %rdi
callq 0x2100
leaq 0x286a(%rip), %rsi      # 0x74c3
movl $0x1e, %edx
movq %rax, %rdi
callq 0x21b0
leaq 0x48(%rsp), %rsi
movq %rsp, %rdi
callq 0x2230
leaq 0x58(%r14), %rdi
movq %rsp, %r15
movq %r15, %rsi
callq 0x21c0
movq (%r15), %rdi
leaq 0x10(%rsp), %rax
cmpq %rax, %rdi
je 0x4c9c
movq 0x10(%rsp), %rsi
incq %rsi
callq 0x2190
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
movq 0x58(%r14), %rsi
movq 0x60(%r14), %rdx
addq %rsi, %rdx
movq %rbx, %rdi
callq 0x431c
movq 0x530b(%rip), %rsi      # 0x9fc8
leaq 0x40(%rsp), %rdi
callq 0x20d0
leaq 0xb0(%rsp), %rdi
callq 0x20a0
jmp 0x4d50
movb $0x1, 0x51(%r14)
movq 0x54d6(%rip), %rcx      # 0xa1b8
testq %rcx, %rcx
je 0x4d22
leaq 0x54c2(%rip), %rax      # 0xa1b0
xorl %edx, %edx
cmpl $0x7, 0x20(%rcx)
setb %dl
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rdx,8), %rcx
testq %rcx, %rcx
jne 0x4cee
leaq 0x54a4(%rip), %rsi      # 0xa1b0
cmpq %rsi, %rax
je 0x4d29
cmpl $0x8, 0x20(%rax)
leaq 0x5494(%rip), %rsi      # 0xa1b0
cmovbq %rax, %rsi
jmp 0x4d29
leaq 0x5487(%rip), %rsi      # 0xa1b0
addq $0x28, %rsi
leaq 0x58(%r14), %rdi
callq 0x20e0
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
movq 0x58(%r14), %rsi
movq 0x60(%r14), %rdx
addq %rsi, %rdx
movq %rbx, %rdi
callq 0x431c
leaq 0x30(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x4d6b
movq 0x30(%rsp), %rsi
incq %rsi
callq 0x2190
movq %rbx, %rax
addq $0x1b8, %rsp            # imm = 0x1B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x4de6
jmp 0x4dc3
jmp 0x4dc3
jmp 0x4de6
jmp 0x4da5
movq %rax, %rbx
movq (%rsp), %rdi
cmpq %r13, %rdi
je 0x4da8
movq 0x10(%rsp), %rsi
incq %rsi
callq 0x2190
jmp 0x4da8
movq %rax, %rbx
movq 0x40(%rsp), %rdi
cmpq %r12, %rdi
je 0x4de9
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x2190
jmp 0x4de9
jmp 0x4de6
movq %rax, %rbx
movq 0x51fb(%rip), %rsi      # 0x9fc8
leaq 0x40(%rsp), %rdi
callq 0x20d0
leaq 0xb0(%rsp), %rdi
callq 0x20a0
jmp 0x4de9
movq %rax, %rbx
leaq 0x30(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x4e04
movq 0x30(%rsp), %rsi
incq %rsi
callq 0x2190
movq %rbx, %rdi
callq 0x2270