// File: 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:
subq $0x2d8, %rsp            # imm = 0x2D8
movq %rdi, 0x58(%rsp)
movq %rdi, %rax
movq %rax, 0x60(%rsp)
movq %rdi, 0x2d0(%rsp)
movq %rsi, 0x2c8(%rsp)
movq 0x2c8(%rsp), %rax
movq %rax, 0x68(%rsp)
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x5036
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x59e1
movq 0x68(%rsp), %rax
movb 0x50(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x5057
movq 0x58(%rsp), %rdi
callq 0x2320
jmp 0x59e1
movq 0x68(%rsp), %rax
cmpl $0x0, 0x48(%rax)
jne 0x50cd
movq 0x68(%rsp), %rax
movb $0x1, 0x50(%rax)
leaq 0x2c7(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x23a0
movq 0x58(%rsp), %rdi
movq 0x50(%rsp), %rdx
leaq 0x541e(%rip), %rsi      # 0xa4ac
callq 0x4470
jmp 0x5095
leaq 0x2c7(%rsp), %rdi
callq 0x2260
jmp 0x59e1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2b8(%rsp)
movl %eax, 0x2b4(%rsp)
leaq 0x2c7(%rsp), %rdi
callq 0x2260
jmp 0x59ee
movq 0x68(%rsp), %rsi
leaq 0x290(%rsp), %rdi
callq 0x5a00
movq 0x68(%rsp), %rdi
movq 0x30(%rdi), %rax
movslq 0x28(%rdi), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x28c(%rsp)
movsbl 0x28c(%rsp), %eax
movl %eax, 0x288(%rsp)
movl 0x28c(%rsp), %eax
sarl $0x8, %eax
movl %eax, 0x284(%rsp)
movl 0x28(%rdi), %eax
incl %eax
movl %eax, 0x28(%rdi)
movl 0x28(%rdi), %esi
callq 0x5ea0
jmp 0x5128
movq 0x68(%rsp), %rax
cmpl $0x3ff, 0x28(%rax)      # imm = 0x3FF
jbe 0x524e
movq 0x68(%rsp), %rax
movb $0x1, 0x51(%rax)
movl $0x0, 0x254(%rsp)
leaq 0x90fb(%rip), %rdi      # 0xe250
leaq 0x254(%rsp), %rsi
callq 0x7420
movq %rax, 0x48(%rsp)
jmp 0x5169
movq 0x48(%rsp), %rax
movq %rax, 0x258(%rsp)
leaq 0x258(%rsp), %rdi
callq 0x7450
movq %rax, %rsi
addq $0x8, %rsi
leaq 0x260(%rsp), %rdi
callq 0x20e0
jmp 0x5199
leaq 0x5327(%rip), %rdx      # 0xa4c7
leaq 0x230(%rsp), %rdi
leaq 0x260(%rsp), %rsi
callq 0x7470
jmp 0x51b7
movq 0x68(%rsp), %rdi
addq $0x58, %rdi
movq %rdi, 0x40(%rsp)
leaq 0x230(%rsp), %rsi
movq %rsi, 0x38(%rsp)
callq 0x22b0
movq 0x38(%rsp), %rdi
callq 0x2140
movq 0x58(%rsp), %rdi
movq 0x40(%rsp), %rsi
callq 0x20e0
jmp 0x51f2
movl $0x1, 0x22c(%rsp)
leaq 0x260(%rsp), %rdi
callq 0x2140
jmp 0x59c3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2b8(%rsp)
movl %eax, 0x2b4(%rsp)
jmp 0x59d2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2b8(%rsp)
movl %eax, 0x2b4(%rsp)
leaq 0x260(%rsp), %rdi
callq 0x2140
jmp 0x59d2
movl 0x288(%rsp), %eax
movq %rax, 0x30(%rsp)
subq $0x12, %rax
ja 0x57c6
movq 0x30(%rsp), %rax
leaq 0x505c(%rip), %rcx      # 0xa2cc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
movl %ecx, 0x24(%rax)
movl 0x284(%rsp), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
addl 0x284(%rsp), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x2c(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x6050
jmp 0x52c2
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x52f9
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x52e9
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
movl %ecx, 0x24(%rax)
movq 0x30(%rax), %rcx
movl 0x2c(%rax), %edx
addl 0x284(%rsp), %edx
movslq %edx, %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x2c(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x6050
jmp 0x5338
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x536f
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x535f
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x20(%rax), %esi
movq 0x30(%rax), %rcx
movl 0x2c(%rax), %edx
addl 0x284(%rsp), %edx
movslq %edx, %rdx
movl %esi, (%rcx,%rdx,4)
movl 0x24(%rax), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x20(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x6050
jmp 0x53ae
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x53e5
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x53d5
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movq 0x30(%rax), %rcx
movl 0x20(%rax), %edx
addl 0x284(%rsp), %edx
movslq %edx, %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x20(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x6050
jmp 0x541e
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x5455
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x5445
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rcx
movl 0x24(%rcx), %edx
movq 0x30(%rcx), %rax
movl 0x20(%rcx), %ecx
addl 0x284(%rsp), %ecx
movslq %ecx, %rcx
movl %edx, (%rax,%rcx,4)
jmp 0x584b
movq 0x68(%rsp), %rax
movl 0x24(%rax), %ecx
addl 0x20(%rax), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movl 0x24(%rax), %ecx
subl 0x20(%rax), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movl 0x24(%rax), %edx
movl 0x20(%rax), %ecx
shll %cl, %edx
movl %edx, %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movl 0x24(%rax), %edx
movl 0x20(%rax), %ecx
sarl %cl, %edx
movl %edx, %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x2c(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x62c0
jmp 0x54e2
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x5519
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x5509
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x2c(%rax), %ecx
addl 0x284(%rsp), %ecx
movl %ecx, 0x2c(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x20(%rdi), %esi
callq 0x62c0
jmp 0x553f
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x5576
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x5566
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
movl %ecx, 0x2c(%rax)
movl 0x24(%rax), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
movl %ecx, 0x24(%rax)
movl 0x2c(%rax), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x28(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x5ea0
jmp 0x55ba
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x55f1
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x55e1
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
movl %ecx, 0x24(%rax)
movl 0x28(%rax), %ecx
movl %ecx, 0x20(%rax)
movl 0x28(%rax), %ecx
addl 0x284(%rsp), %ecx
movl %ecx, 0x28(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x20(%rdi), %esi
callq 0x5ea0
jmp 0x5623
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x565a
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x564a
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x20(%rax), %ecx
movl %ecx, 0x28(%rax)
movl 0x24(%rax), %ecx
movl %ecx, 0x20(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
cmpl $0x0, 0x20(%rax)
jne 0x56dc
movq 0x68(%rsp), %rdi
movl 0x28(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x5ea0
jmp 0x5693
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x56ca
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x56ba
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x28(%rax), %ecx
addl 0x284(%rsp), %ecx
movl %ecx, 0x28(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
cmpl $0x0, 0x20(%rax)
jge 0x574d
movq 0x68(%rsp), %rdi
movl 0x28(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x5ea0
jmp 0x5704
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x573b
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x572b
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x28(%rax), %ecx
addl 0x284(%rsp), %ecx
movl %ecx, 0x28(%rax)
jmp 0x584b
movq 0x68(%rsp), %rdi
movl 0x28(%rdi), %esi
movl 0x284(%rsp), %eax
addl %eax, %esi
callq 0x5ea0
jmp 0x576a
movq 0x68(%rsp), %rax
movb 0x51(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x57a1
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x5791
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movl 0x28(%rax), %ecx
addl 0x284(%rsp), %ecx
movl %ecx, 0x28(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movb $0x1, 0x50(%rax)
jmp 0x584b
movq 0x68(%rsp), %rax
movb $0x1, 0x51(%rax)
movl $0x7, 0x21c(%rsp)
leaq 0x8a6f(%rip), %rdi      # 0xe250
leaq 0x21c(%rsp), %rsi
callq 0x7420
movq %rax, 0x28(%rsp)
jmp 0x57f5
movq 0x28(%rsp), %rax
movq %rax, 0x220(%rsp)
leaq 0x220(%rsp), %rdi
callq 0x7450
movq 0x68(%rsp), %rdi
movq %rax, %rsi
addq $0x8, %rsi
addq $0x58, %rdi
callq 0x2040
jmp 0x5826
movq 0x58(%rsp), %rdi
movq 0x68(%rsp), %rsi
addq $0x58, %rsi
callq 0x20e0
jmp 0x583b
movl $0x1, 0x22c(%rsp)
jmp 0x59c3
movq 0x68(%rsp), %rax
movq 0x40(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x40(%rax)
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpq %rcx, 0x40(%rax)
jne 0x59a6
movq 0x68(%rsp), %rax
movb $0x1, 0x51(%rax)
leaq 0xa0(%rsp), %rdi
callq 0x2310
jmp 0x5883
movl $0x6, 0x94(%rsp)
leaq 0x89bb(%rip), %rdi      # 0xe250
leaq 0x94(%rsp), %rsi
callq 0x7420
movq %rax, 0x20(%rsp)
jmp 0x58a9
movq 0x20(%rsp), %rax
movq %rax, 0x98(%rsp)
leaq 0x98(%rsp), %rdi
callq 0x7450
movq %rax, %rsi
addq $0x8, %rsi
leaq 0xa0(%rsp), %rdi
callq 0x21d0
jmp 0x58d9
leaq 0xa0(%rsp), %rdi
movl $0xa, %esi
callq 0x22a0
jmp 0x58ed
movq 0x68(%rsp), %rax
movq 0x40(%rax), %rsi
leaq 0xa0(%rsp), %rdi
callq 0x21e0
movq %rax, 0x18(%rsp)
jmp 0x590a
movq 0x18(%rsp), %rdi
leaq 0x4bef(%rip), %rsi      # 0xa505
callq 0x21f0
jmp 0x591d
leaq 0x70(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x2220
jmp 0x5931
movq 0x68(%rsp), %rdi
addq $0x58, %rdi
movq %rdi, 0x10(%rsp)
leaq 0x70(%rsp), %rsi
movq %rsi, 0x8(%rsp)
callq 0x22b0
movq 0x8(%rsp), %rdi
callq 0x2140
movq 0x58(%rsp), %rdi
movq 0x10(%rsp), %rsi
callq 0x20e0
jmp 0x5969
movl $0x1, 0x22c(%rsp)
leaq 0xa0(%rsp), %rdi
callq 0x2080
jmp 0x59c3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2b8(%rsp)
movl %eax, 0x2b4(%rsp)
leaq 0xa0(%rsp), %rdi
callq 0x2080
jmp 0x59d2
movq 0x58(%rsp), %rdi
leaq 0x290(%rsp), %rsi
callq 0x2120
movl $0x1, 0x22c(%rsp)
leaq 0x290(%rsp), %rdi
callq 0x2140
jmp 0x59e1
leaq 0x290(%rsp), %rdi
callq 0x2140
jmp 0x59ee
movq 0x60(%rsp), %rax
addq $0x2d8, %rsp            # imm = 0x2D8
retq
movq 0x2b8(%rsp), %rdi
callq 0x2390
nopl (%rax,%rax)