// File: /workspace/github_cpp_makefile_star2_O2/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 %rbx
subq $0x1b8, %rsp            # imm = 0x1B8
movq %rsi, %r14
movq %rdi, %rbx
cmpb $0x1, 0x51(%rsi)
jne 0x38eb
addq $0x58, %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2230
jmp 0x3d18
cmpb $0x1, 0x50(%r14)
jne 0x3907
leaq 0x10(%rbx), %rax
movq %rax, (%rbx)
andq $0x0, 0x8(%rbx)
movb $0x0, 0x10(%rbx)
jmp 0x3d18
cmpl $0x0, 0x48(%r14)
je 0x39bd
movq %rsp, %rdi
movq %r14, %rsi
callq 0x3da4
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 0x3fd0
movl 0x28(%r14), %esi
cmpl $0x400, %esi            # imm = 0x400
jb 0x39db
movb $0x1, 0x51(%r14)
leaq 0x20(%rsp), %rsi
andl $0x0, (%rsi)
leaq 0x5875(%rip), %rdi      # 0x91d0
callq 0x4f9e
addq $0x28, %rax
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2230
leaq 0x2b33(%rip), %rdx      # 0x64ab
leaq 0x20(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48e1
addq $0x58, %r14
leaq 0x20(%rsp), %r15
movq %r14, %rdi
movq %r15, %rsi
callq 0x21d0
movq %r15, %rdi
callq 0x20c0
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2230
leaq 0x40(%rsp), %rdi
callq 0x20c0
jmp 0x3d10
movb $0x1, 0x50(%r14)
leaq 0x2ac7(%rip), %rsi      # 0x6490
leaq 0x40(%rsp), %rdx
movq %rbx, %rdi
callq 0x34b0
jmp 0x3d18
movsbl %bpl, %eax
cmpl $0x12, %eax
ja 0x3d29
sarl $0x8, %ebp
movl %eax, %eax
leaq 0x28bc(%rip), %rcx      # 0x62b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl 0x20(%r14), %eax
movl %eax, 0x24(%r14)
movl %ebp, 0x20(%r14)
jmp 0x3c13
cmpl $0x0, 0x20(%r14)
jns 0x3c13
addl %ebp, %esi
movq %r14, %rdi
callq 0x3fd0
jmp 0x3b5e
movl 0x20(%r14), %esi
movq %r14, %rdi
callq 0x3fd0
cmpb $0x1, 0x51(%r14)
je 0x3bf1
movl 0x20(%r14), %eax
movl 0x24(%r14), %ecx
movl %eax, 0x28(%r14)
jmp 0x3aa1
movl 0x20(%r14), %esi
movq %r14, %rdi
callq 0x4214
cmpb $0x1, 0x51(%r14)
je 0x3bf1
movl 0x20(%r14), %eax
movl 0x24(%r14), %ecx
movl %eax, 0x2c(%r14)
jmp 0x3aa1
movl 0x20(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x40cc
cmpb $0x1, 0x51(%r14)
je 0x3bf1
movq 0x30(%r14), %rax
movslq 0x20(%r14), %rcx
jmp 0x3ae2
movl 0x20(%r14), %eax
movl 0x2c(%r14), %ecx
movl %eax, 0x24(%r14)
movl %ecx, 0x20(%r14)
jmp 0x3c13
movl 0x24(%r14), %eax
movb 0x20(%r14), %cl
sarl %cl, %eax
jmp 0x3c0f
movl 0x2c(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x40cc
cmpb $0x1, 0x51(%r14)
je 0x3bf1
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 0x3c0f
cmpl $0x0, 0x20(%r14)
jne 0x3c13
addl %ebp, %esi
movq %r14, %rdi
callq 0x3fd0
jmp 0x3b5e
movl 0x2c(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x40cc
cmpb $0x1, 0x51(%r14)
je 0x3bf1
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 0x3c0f
movl 0x24(%r14), %eax
subl 0x20(%r14), %eax
jmp 0x3c0f
addl %ebp, 0x20(%r14)
jmp 0x3c13
addl %ebp, %esi
movq %r14, %rdi
callq 0x3fd0
cmpb $0x1, 0x51(%r14)
je 0x3bf1
addl %ebp, 0x28(%r14)
jmp 0x3c13
movl 0x20(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x40cc
cmpb $0x1, 0x51(%r14)
je 0x3bf1
movl 0x24(%r14), %eax
movq 0x30(%r14), %rcx
movslq 0x20(%r14), %rdx
movslq %ebp, %rsi
addq %rdx, %rsi
movl %eax, (%rcx,%rsi,4)
jmp 0x3c13
addl %ebp, %esi
movq %r14, %rdi
callq 0x3fd0
cmpb $0x1, 0x51(%r14)
je 0x3bf1
movl 0x20(%r14), %eax
movl 0x28(%r14), %ecx
movl %eax, 0x24(%r14)
movl %ecx, 0x20(%r14)
addl %ecx, %ebp
movl %ebp, 0x28(%r14)
jmp 0x3c13
movl 0x24(%r14), %eax
addl %eax, 0x20(%r14)
jmp 0x3c13
movb $0x1, 0x50(%r14)
jmp 0x3c13
movl 0x2c(%r14), %esi
addl %ebp, %esi
movq %r14, %rdi
callq 0x4214
cmpb $0x1, 0x51(%r14)
jne 0x3d5d
addq $0x58, %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2230
jmp 0x3d10
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 0x3ccf
movb $0x1, 0x51(%r14)
leaq 0x40(%rsp), %rdi
callq 0x2220
leaq 0x20(%rsp), %rsi
movl $0x6, (%rsi)
leaq 0x5583(%rip), %rdi      # 0x91d0
callq 0x4f9e
addq $0x28, %rax
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2170
leaq 0x40(%rsp), %rdi
pushq $0xa
popq %rsi
callq 0x21c0
movq 0x40(%r14), %rsi
leaq 0x40(%rsp), %rdi
callq 0x2100
leaq 0x2864(%rip), %rsi      # 0x64e9
movq %rax, %rdi
callq 0x2180
leaq 0x48(%rsp), %rsi
leaq 0x20(%rsp), %rdi
callq 0x2270
addq $0x58, %r14
leaq 0x20(%rsp), %r15
movq %r14, %rdi
movq %r15, %rsi
callq 0x21d0
movq %r15, %rdi
callq 0x20c0
movq %rbx, %rdi
movq %r14, %rsi
callq 0x2230
leaq 0x40(%rsp), %rdi
callq 0x2060
jmp 0x3d10
leaq 0x10(%rbx), %rcx
movq %rcx, (%rbx)
leaq 0x10(%rsp), %rax
movq -0x10(%rax), %rdx
cmpq %rax, %rdx
je 0x3cf2
movq %rdx, (%rbx)
movq 0x10(%rsp), %rcx
movq %rcx, 0x10(%rbx)
jmp 0x3cf8
movups (%rax), %xmm0
movups %xmm0, (%rcx)
movq 0x8(%rsp), %rcx
movq %rcx, 0x8(%rbx)
movq %rax, (%rsp)
andq $0x0, 0x8(%rsp)
movb $0x0, 0x10(%rsp)
movq %rsp, %rdi
callq 0x20c0
movq %rbx, %rax
addq $0x1b8, %rsp            # imm = 0x1B8
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
movb $0x1, 0x51(%r14)
leaq 0x40(%rsp), %rsi
movl $0x7, (%rsi)
leaq 0x5490(%rip), %rdi      # 0x91d0
callq 0x4f9e
addq $0x28, %rax
addq $0x58, %r14
movq %r14, %rdi
movq %rax, %rsi
callq 0x20e0
jmp 0x3bf5
addl %ebp, 0x2c(%r14)
jmp 0x3c13
jmp 0x3d90
jmp 0x3d7f
jmp 0x3d90
jmp 0x3d7f
jmp 0x3d70
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x20c0
jmp 0x3d93
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x2060
jmp 0x3d93
jmp 0x3d90
movq %rax, %rbx
movq %rsp, %rdi
callq 0x20c0
movq %rbx, %rdi
callq 0x22b0
nop