
/***************************************************************/
/*                                                             */
/*   LC-3b Instruction Level Simulator                         */
/*                                                             */
/*   Courtesy: Prof. Yale N. Patt (UT Austin)                  */
/*                                                             */
/***************************************************************/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Macros for switch
 */

#define ADD "0001"
#define AND "0101"
#define BR "0000"
#define JMPRET "1100"
#define JSRJSRR "0100"
#define LDB "0010"
#define LDW "0110"
#define LEA "1110"
#define NOTXOR "1001"
#define SHF "1101"
#define STB "0011"
#define STW "0111"
#define TRAP "1111"

/***************************************************************/
/*                                                             */
/* Files: isaprogram   LC-3b machine language program file     */
/*                                                             */
/***************************************************************/

/***************************************************************/
/* These are the functions you'll have to write.               */
/***************************************************************/

void process_instruction();

/***************************************************************/
/* A couple of useful definitions.                             */
/***************************************************************/
#define FALSE 0
#define TRUE  1

/***************************************************************/
/* Use this to avoid overflowing 16 bits on the bus.           */
/***************************************************************/
#define Low16bits(x) ((x) & 0xFFFF)

/***************************************************************/
/* Main memory.                                                */
/***************************************************************/
/* MEMORY[A][0] stores the least significant byte of word at word address A
   MEMORY[A][1] stores the most significant byte of word at word address A 
 */

#define WORDS_IN_MEM    0x08000 
int MEMORY[WORDS_IN_MEM][2];

/***************************************************************/

/***************************************************************/

/***************************************************************/
/* LC-3b State info.                                           */
/***************************************************************/
#define LC_3b_REGS 8

int RUN_BIT; /* run bit */

typedef struct System_Latches_Struct {
    int PC, /* program counter */
            N, /* n condition bit */
            Z, /* z condition bit */
            P; /* p condition bit */
    int REGS[LC_3b_REGS]; /* register file. */
} System_Latches;

/* Data Structure for Latch */

System_Latches CURRENT_LATCHES, NEXT_LATCHES;

/***************************************************************/
/* A cycle counter.                                            */
/***************************************************************/
int INSTRUCTION_COUNT;

/***************************************************************/
/*                                                             */
/* Procedure : help                                            */
/*                                                             */
/* Purpose   : Print out a list of commands                    */
/*                                                             */

/***************************************************************/
void help() {
    printf("----------------LC-3b ISIM Help-----------------------\n");
    printf("go               -  run program to completion         \n");
    printf("run n            -  execute program for n instructions\n");
    printf("mdump low high   -  dump memory from low to high      \n");
    printf("rdump            -  dump the register & bus values    \n");
    printf("?                -  display this help menu            \n");
    printf("quit             -  exit the program                  \n\n");
}

/***************************************************************/
/*                                                             */
/* Procedure : cycle                                           */
/*                                                             */
/* Purpose   : Execute a cycle                                 */
/*                                                             */

/***************************************************************/
void cycle() {

    process_instruction();
    CURRENT_LATCHES = NEXT_LATCHES;
    INSTRUCTION_COUNT++;
}

/***************************************************************/
/*                                                             */
/* Procedure : run n                                           */
/*                                                             */
/* Purpose   : Simulate the LC-3b for n cycles                 */
/*                                                             */

/***************************************************************/
void run(int num_cycles) {
    int i;

    if (RUN_BIT == FALSE) {
        printf("Can't simulate, Simulator is halted\n\n");
        return;
    }

    printf("Simulating for %d cycles...\n\n", num_cycles);
    for (i = 0; i < num_cycles; i++) {
        if (CURRENT_LATCHES.PC == 0x0000) {
            RUN_BIT = FALSE;
            printf("Simulator halted\n\n");
            break;
        }
        cycle();
    }
}

/***************************************************************/
/*                                                             */
/* Procedure : go                                              */
/*                                                             */
/* Purpose   : Simulate the LC-3b until HALTed                 */
/*                                                             */

/***************************************************************/
void go() {
    if (RUN_BIT == FALSE) {
        printf("Can't simulate, Simulator is halted\n\n");
        return;
    }

    printf("Simulating...\n\n");
    while (CURRENT_LATCHES.PC != 0x0000)
        cycle();
    RUN_BIT = FALSE;
    printf("Simulator halted\n\n");
}

/***************************************************************/
/*                                                             */
/* Procedure : mdump                                           */
/*                                                             */
/* Purpose   : Dump a word-aligned region of memory to the     */
/*             output file.                                    */
/*                                                             */

/***************************************************************/
void mdump(FILE * dumpsim_file, int start, int stop) {
    int address; /* this is a byte address */

    printf("\nMemory content [0x%0.4x..0x%0.4x] :\n", start, stop);
    printf("-------------------------------------\n");
    for (address = (start >> 1); address <= (stop >> 1); address++)
        printf("  0x%0.4x (%d) : 0x%0.2x%0.2x\n", address << 1, address << 1, MEMORY[address][1], MEMORY[address][0]);
    printf("\n");

    /* dump the memory contents into the dumpsim file */
    fprintf(dumpsim_file, "\nMemory content [0x%0.4x..0x%0.4x] :\n", start, stop);
    fprintf(dumpsim_file, "-------------------------------------\n");
    for (address = (start >> 1); address <= (stop >> 1); address++)
        fprintf(dumpsim_file, " 0x%0.4x (%d) : 0x%0.2x%0.2x\n", address << 1, address << 1, MEMORY[address][1], MEMORY[address][0]);
    fprintf(dumpsim_file, "\n");
}

/***************************************************************/
/*                                                             */
/* Procedure : rdump                                           */
/*                                                             */
/* Purpose   : Dump current register and bus values to the     */
/*             output file.                                    */
/*                                                             */

/***************************************************************/
void rdump(FILE * dumpsim_file) {
    int k;

    printf("\nCurrent register/bus values :\n");
    printf("-------------------------------------\n");
    printf("Instruction Count : %d\n", INSTRUCTION_COUNT);
    printf("PC                : 0x%0.4x\n", CURRENT_LATCHES.PC);
    printf("CCs: N = %d  Z = %d  P = %d\n", CURRENT_LATCHES.N, CURRENT_LATCHES.Z, CURRENT_LATCHES.P);
    printf("Registers:\n");
    for (k = 0; k < LC_3b_REGS; k++)
        printf("%d: 0x%0.4x\n", k, CURRENT_LATCHES.REGS[k]);
    printf("\n");

    /* dump the state information into the dumpsim file */
    fprintf(dumpsim_file, "\nCurrent register/bus values :\n");
    fprintf(dumpsim_file, "-------------------------------------\n");
    fprintf(dumpsim_file, "Instruction Count : %d\n", INSTRUCTION_COUNT);
    fprintf(dumpsim_file, "PC                : 0x%0.4x\n", CURRENT_LATCHES.PC);
    fprintf(dumpsim_file, "CCs: N = %d  Z = %d  P = %d\n", CURRENT_LATCHES.N, CURRENT_LATCHES.Z, CURRENT_LATCHES.P);
    fprintf(dumpsim_file, "Registers:\n");
    for (k = 0; k < LC_3b_REGS; k++)
        fprintf(dumpsim_file, "%d: 0x%0.4x\n", k, CURRENT_LATCHES.REGS[k]);
    fprintf(dumpsim_file, "\n");
}

/***************************************************************/
/*                                                             */
/* Procedure : get_command                                     */
/*                                                             */
/* Purpose   : Read a command from standard input.             */
/*                                                             */

/***************************************************************/
void get_command(FILE * dumpsim_file) {
    char buffer[20];
    int start, stop, cycles;

    printf("LC-3b-SIM> ");

    scanf("%s", buffer);
    printf("\n");

    switch (buffer[0]) {
        case 'G':
        case 'g':
            go();
            break;

        case 'M':
        case 'm':
            scanf("%i %i", &start, &stop);
            mdump(dumpsim_file, start, stop);
            break;

        case '?':
            help();
            break;
        case 'Q':
        case 'q':
            printf("Bye.\n");
            exit(0);

        case 'R':
        case 'r':
            if (buffer[1] == 'd' || buffer[1] == 'D')
                rdump(dumpsim_file);
            else {
                scanf("%d", &cycles);
                run(cycles);
            }
            break;

        default:
            printf("Invalid Command\n");
            break;
    }
}

/***************************************************************/
/*                                                             */
/* Procedure : init_memory                                     */
/*                                                             */
/* Purpose   : Zero out the memory array                       */
/*                                                             */

/***************************************************************/
void init_memory() {
    int i;

    for (i = 0; i < WORDS_IN_MEM; i++) {
        MEMORY[i][0] = 0;
        MEMORY[i][1] = 0;
    }
}

/**************************************************************/
/*                                                            */
/* Procedure : load_program                                   */
/*                                                            */
/* Purpose   : Load program and service routines into mem.    */
/*                                                            */

/**************************************************************/
void load_program(char *program_filename) {
    FILE * prog;
    int ii, word, program_base;

    /* Open program file. */
    prog = fopen(program_filename, "r");
    if (prog == NULL) {
        printf("Error: Can't open program file %s\n", program_filename);
        exit(-1);
    }

    /* Read in the program. */
    if (fscanf(prog, "%x\n", &word) != EOF)
        program_base = word >> 1;
    else {
        printf("Error: Program file is empty\n");
        exit(-1);
    }

    ii = 0;
    while (fscanf(prog, "%x\n", &word) != EOF) {
        /* Make sure it fits. */
        if (program_base + ii >= WORDS_IN_MEM) {
            printf("Error: Program file %s is too long to fit in memory. %x\n",
                    program_filename, ii);
            exit(-1);
        }

        /* Write the word to memory array. */
        MEMORY[program_base + ii][0] = word & 0x00FF;
        MEMORY[program_base + ii][1] = (word >> 8) & 0x00FF;
        ii++;
    }

    if (CURRENT_LATCHES.PC == 0) CURRENT_LATCHES.PC = (program_base << 1);

    printf("Read %d words from program into memory.\n\n", ii);
}

/************************************************************/
/*                                                          */
/* Procedure : initialize                                   */
/*                                                          */
/* Purpose   : Load machine language program                */
/*             and set up initial state of the machine.     */
/*                                                          */

/************************************************************/
void initialize(char *program_filename, int num_prog_files) {
    int i;

    init_memory();
    for (i = 0; i < num_prog_files; i++) {
        load_program(program_filename);
        while (*program_filename++ != '\0');
    }
    CURRENT_LATCHES.Z = 1;
    NEXT_LATCHES = CURRENT_LATCHES;

    RUN_BIT = TRUE;
}

/***************************************************************/
/*                                                             */
/* Procedure : main                                            */
/*                                                             */

/***************************************************************/
int main(int argc, char *argv[]) {
    FILE * dumpsim_file;

    /* Error Checking */
    if (argc < 2) {
        printf("Error: usage: %s <program_file_1> <program_file_2> ...\n",
                argv[0]);
        exit(1);
    }

    printf("LC-3b Simulator\n\n");

    initialize(argv[1], argc - 1);

    if ((dumpsim_file = fopen("dumpsim", "w")) == NULL) {
        printf("Error: Can't open dumpsim file\n");
        exit(-1);
    }

    while (1)
        get_command(dumpsim_file);

}

/***************************************************************/
/* Do not modify the above code.
   You are allowed to use the following global variables in your
   code. These are defined above.

   MEMORY

   CURRENT_LATCHES
   NEXT_LATCHES

   You may define your own local/global variables and functions.
   You may use the functions to get at the control bits defined
   above.

   Begin your code here 	  			       */

/***************************************************************/

void hexadecimal2binary(int hexInstruction, char *string) {
    int i;
    int k;
    for (i = 15; i >= 0; i--) {
        k = hexInstruction >> i;
        if (k & 1) {
            *(string + 15 - i) = '1';
        } else {
            *(string + 15 - i) = '0';
        }
    }
    *(string + 16) = '\0';
}

char* integer2binaryString(int num) {
    const int BITS_PER_BYTE = 8;
    int i, bitStrLen = sizeof (short) * BITS_PER_BYTE * sizeof (char);
    char* p = (char*) malloc(bitStrLen);
    for (i = (bitStrLen - 1); i >= 0; i--) {
        int k = 1 & num;
        *(p + i) = ((k == 1) ? '1' : '0');
        num >>= 1;
    }
    return p;
}

int binary2integer(char *binaryString) {
    int length = strlen(binaryString);
    int i, result = 0;
    for (i = 0; i < length; i++) {
        result = result * 2 + (binaryString[i] - (int) '0');
    }
    return result;
}

void signExtension(char *input, char *result) {
    int length = strlen(input), i;
    int extendLength = 16 - length;
    if (*input == '1') {
        for (i = 0; i < extendLength; i++) {
            *(result + i) = '1';
        }
        for (i = extendLength; i < 16; i++) {
            *(result + i) = *(input + i - extendLength);
        }
    } else {
        for (i = 0; i < extendLength; i++) {
            *(result + i) = '0';
        }
        for (i = extendLength; i < 16; i++) {
            *(result + i) = *(input + i - extendLength);
        }
    }
    *(result + 16) = '\0';
}

void zeroExtension(char *input, char *result) {
    char prefix[8];
    strcpy(prefix, "00000000");
    strncat(result, prefix, 8);
    strncat(result, input + 24, 8);
}

void negativeZeroPositive(int val) {
    if (val < 0) {
        NEXT_LATCHES.N = Low16bits(1);
        NEXT_LATCHES.Z = Low16bits(0);
        NEXT_LATCHES.P = Low16bits(0);
    } else if (val > 0) {
        NEXT_LATCHES.P = Low16bits(1);
        NEXT_LATCHES.N = Low16bits(0);
        NEXT_LATCHES.Z = Low16bits(0);
    } else if (val == 0) {
        NEXT_LATCHES.Z = Low16bits(1);
        NEXT_LATCHES.P = Low16bits(0);
        NEXT_LATCHES.N = Low16bits(0);
    }
}

void binaryInvert(char *input) {

    int i, length = strlen(input);
    for (i = 0; i < length; i++) {
        if (*(input + i) == '0') {
            *(input + i) = '1';
        } else if (*(input + i) == '1') {
            *(input + i) = '0';
        }
    }

}

void getBinaryString(int number, char *string) {
    *(string + 16) = '\0';
    int maskVal = 0x8000 << 1;
    while (maskVal >>= 1)
        *string++ = !!(maskVal & number) + '0';
}

void rightArithmeticShift(char *value, int shift, int num) {
    char temp[16] = "";
    getBinaryString(num, temp);
    char first = temp[0];
    num = num >> shift;
    getBinaryString(num, value);
    int i;
    for (i = 0; i < shift; i++) {
        value[i] = first;
    }
}

void AddAndXorNotLogic(char *opcode, char *hexInstructionString, char *DR, char *SR1, char *SR2, char* imm5, char *sExt) {
    int val;
    char SEXTNum[16] = "";
    strncpy(DR, hexInstructionString + 4, 3);
    *(DR + 3) = '\0';
    int destinationReg = binary2integer(DR);
    strncpy(SR1, hexInstructionString + 7, 3);
    *(SR1 + 3) = '\0';
    int sourceReg1 = binary2integer(SR1);
    if (*(hexInstructionString + 10) == '0') {
        strncpy(SR2, hexInstructionString + 13, 3);
        *(SR2 + 3) = '\0';
        int sourceReg2 = binary2integer(SR2);
        if (strcmp(opcode, "0001") == 0) {/*ADD*/
            val = CURRENT_LATCHES.REGS[sourceReg1] + CURRENT_LATCHES.REGS[sourceReg2];
            NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
        } else if (strcmp(opcode, "0101") == 0) {/*AND*/
            val = CURRENT_LATCHES.REGS[sourceReg1] & CURRENT_LATCHES.REGS[sourceReg2];
            NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
        } else if (strcmp(opcode, "1001") == 0) {/*XOR*/
            val = CURRENT_LATCHES.REGS[sourceReg1] ^ CURRENT_LATCHES.REGS[sourceReg2];
            NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
        }
    } else if (*(hexInstructionString + 10) == '1') {
        strncpy(imm5, hexInstructionString + 11, 5);
        *(imm5 + 5) = '\0';
        signExtension(imm5, sExt);
        if (*sExt == '0') {
            int temp = binary2integer(sExt);
            if (strcmp(opcode, "0001") == 0) {/*ADD*/
                val = CURRENT_LATCHES.REGS[sourceReg1] + temp;
                NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
            } else if (strcmp(opcode, "0101") == 0) {/*AND*/

                val = CURRENT_LATCHES.REGS[sourceReg1] & temp;
                NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
            } else if (strcmp(opcode, "1001") == 0) {/*XOR*/
                val = CURRENT_LATCHES.REGS[sourceReg1] ^ temp;
                NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
            }
        } else if (*sExt == '1') {
            binaryInvert(sExt);
            int temp = binary2integer(sExt) + 1;
            if (strcmp(opcode, "0001") == 0) {/*ADD*/
                val = CURRENT_LATCHES.REGS[sourceReg1] - temp;
                NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
            } else if (strcmp(opcode, "0101") == 0) {/*AND*/
                val = CURRENT_LATCHES.REGS[sourceReg1] & (-1 * temp);
                NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
            } else if (strcmp(opcode, "1001") == 0) {/*XOR_NOT*/
                val = CURRENT_LATCHES.REGS[sourceReg1] ^ (-1 * temp);
                NEXT_LATCHES.REGS[destinationReg] = Low16bits(val);
            }
        }
    }
    getBinaryString(val, SEXTNum);
    if (SEXTNum[0] == '1') {
        val = -10;
    } else if (val == 0) {
        val = 0;
    } else {
        val = 10;
    }
    negativeZeroPositive(val);
    NEXT_LATCHES.PC = CURRENT_LATCHES.PC + 2;
}

void BRLogic(char *hexInstructionString, char *PCOffset9, char *PCOffsetSExt) {
    int n, z, p;
    if (*(hexInstructionString + 4) == '1') {
        n = 1;
    } else if (*(hexInstructionString + 4) == '0') {
        n = 0;
    }
    if (*(hexInstructionString + 5) == '1') {
        z = 1;
    } else if (*(hexInstructionString + 5) == '0') {
        z = 0;
    }
    if (*(hexInstructionString + 6) == '1') {
        p = 1;
    } else if (*(hexInstructionString + 6) == '0') {
        p = 0;
    }
    if ((n & CURRENT_LATCHES.N) || ((p & CURRENT_LATCHES.P)) || (z & CURRENT_LATCHES.Z)) {
        NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.PC + 2);
        strncpy(PCOffset9, hexInstructionString + 7, 9);
        *(PCOffset9 + 9) = '\0';
        signExtension(PCOffset9, PCOffsetSExt);
        if (*PCOffsetSExt == '0') {
            int temp = binary2integer(PCOffsetSExt);
            temp = temp << 1;
            NEXT_LATCHES.PC = Low16bits(NEXT_LATCHES.PC + temp);
        } else if (*PCOffsetSExt == '1') {
            binaryInvert(PCOffsetSExt);
            int temp = binary2integer(PCOffsetSExt) + 1;
            temp = temp << 1;
            NEXT_LATCHES.PC = Low16bits(NEXT_LATCHES.PC - temp);
        }
    } else {
        NEXT_LATCHES.PC = CURRENT_LATCHES.PC + 2;
    }
}

void LEALogic(char *hexInstructionString, char *DR, char *PCOffset9, char *PCOffsetSExt) {
    NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.PC + 2);

    strncpy(DR, hexInstructionString + 4, 3);
    *(DR + 3) = '\0';
    int destinationRegister = binary2integer(DR);

    strncpy(PCOffset9, hexInstructionString + 7, 9);
    *(PCOffset9 + 9) = '\0';
    signExtension(PCOffset9, PCOffsetSExt);

    if (*PCOffsetSExt == '0') {
        int temp = binary2integer(PCOffsetSExt);
        temp = temp << 1;
        NEXT_LATCHES.REGS[destinationRegister] = Low16bits(NEXT_LATCHES.PC + temp);
        ;
    } else if (*PCOffsetSExt == '1') {
        binaryInvert(PCOffsetSExt);
        int temp = binary2integer(PCOffsetSExt) + 1;
        temp = temp << 1;
        NEXT_LATCHES.REGS[destinationRegister] = Low16bits(NEXT_LATCHES.PC - temp);
    }
    NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.PC + 2);
}

void JSRJSRRLogic(char *hexInstructionString, char *baseR, char *PCOffset11, char *PCOffsetSExt) {
    int temporary = Low16bits(CURRENT_LATCHES.PC + 2);

    if (*(hexInstructionString + 4) == '0') {
        strncpy(baseR, hexInstructionString + 7, 3);
        *(baseR + 3) = '\0';
        int baseRegister = binary2integer(baseR);
        NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.REGS[baseRegister]);
    } else {
        strncpy(PCOffset11, hexInstructionString + 5, 11);
        *(PCOffset11 + 11) = '\0';
        signExtension(PCOffset11, PCOffsetSExt);

        NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.PC + 2);

        if (*PCOffsetSExt == '0') {
            int temp = binary2integer(PCOffsetSExt);
            temp = temp << 1;
            NEXT_LATCHES.PC = Low16bits(NEXT_LATCHES.PC + temp);
            ;
        } else if (*PCOffsetSExt == '1') {
            binaryInvert(PCOffsetSExt);
            int temp = binary2integer(PCOffsetSExt) + 1;
            temp = temp << 1;
            NEXT_LATCHES.PC = Low16bits(NEXT_LATCHES.PC - temp);
        }
    }
    NEXT_LATCHES.REGS[7] = Low16bits(temporary);
}

void shiftLogic(char *hexInstructionString, char *DR, char *SR, char *amount4) {
    /*Extract the values*/
    int temporary, finalVal;
    strncpy(DR, hexInstructionString + 4, 3);
    *(DR + 3) = '\0';
    int destinationRegister = binary2integer(DR);

    strncpy(SR, hexInstructionString + 7, 3);
    *(SR + 3) = '\0';
    int sourceRegister = binary2integer(SR);

    strncpy(amount4, hexInstructionString + 12, 4);
    *(SR + 4) = '\0';
    int shiftAmount = binary2integer(amount4);
    /*Decide if it is Left or Right Shift*/

    char SEXTNum[16] = "";

    if (hexInstructionString[11] == '0') {
        finalVal = CURRENT_LATCHES.REGS[sourceRegister] << shiftAmount;
        NEXT_LATCHES.REGS[destinationRegister] = Low16bits(finalVal);
    } else if (hexInstructionString[11] == '1') {
        temporary = CURRENT_LATCHES.REGS[sourceRegister];
        if (hexInstructionString[10] == '0') {
            finalVal = CURRENT_LATCHES.REGS[sourceRegister] >> shiftAmount;
            NEXT_LATCHES.REGS[destinationRegister] = Low16bits(finalVal);
        } else {
            temporary = CURRENT_LATCHES.REGS[sourceRegister];
            rightArithmeticShift(SEXTNum, shiftAmount, temporary);
            finalVal = binary2integer(SEXTNum);
            NEXT_LATCHES.REGS[destinationRegister] = Low16bits(finalVal);
        }
    }

    getBinaryString(finalVal, SEXTNum);
    
    if (SEXTNum[0] == '1') {
        finalVal = -10;
    } else if (finalVal == 0) {
        finalVal = 0;
    } else {
        finalVal = 10;
    }
    /*Update the n,z,p Values*/
    negativeZeroPositive(finalVal);
    /*Increment the PC*/
    NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.PC + 2);
}

void LDBLDWLogic(char *opcode, char *hexInstructionString, char *DR, char* baseR, char *Offset6, char *OffsetSExt) {
    /*Extract the values*/
    int temp, temp1;
    strncpy(Offset6, hexInstructionString + 10, 6);
    *(Offset6 + 6) = '\0';
    signExtension(Offset6, OffsetSExt);

    strncpy(baseR, hexInstructionString + 7, 3);
    *(baseR + 3) = '\0';
    int baseRegister = binary2integer(baseR);

    strncpy(DR, hexInstructionString + 4, 3);
    *(DR + 3) = '\0';
    int destinationRegister = binary2integer(DR);

    if (strcmp(opcode, "0010") == 0) {/*LDB*/
        if (*OffsetSExt == '0') {
            temp = binary2integer(OffsetSExt);
            temp1 = CURRENT_LATCHES.REGS[baseRegister] + temp;
        } else if (*OffsetSExt == '1') {
            binaryInvert(OffsetSExt);
            temp = binary2integer(OffsetSExt) + 1;
            temp1 = CURRENT_LATCHES.REGS[baseRegister] - temp;
        }
        int row = temp1 >> 1;
        int col = temp1 % 2;
        temp1 = MEMORY[row][col];
        char *bin = integer2binaryString(temp1);
        char binSEXT[16];
        signExtension(bin, binSEXT);
        if (*binSEXT == '0') {
            temp = binary2integer(binSEXT);
            NEXT_LATCHES.REGS[destinationRegister] = Low16bits(temp);
            negativeZeroPositive(temp);
        } else if (*binSEXT == '1') {
            binaryInvert(binSEXT);
            temp = binary2integer(binSEXT) + 1;
            NEXT_LATCHES.REGS[destinationRegister] = Low16bits(-1 * temp);
            negativeZeroPositive(-1 * temp);
        }
    } else if (strcmp(opcode, "0110") == 0) {/*LDW*/
        if (*OffsetSExt == '0') {
            temp = binary2integer(OffsetSExt);
        } else if (*OffsetSExt == '1') {
            binaryInvert(OffsetSExt);
            temp = binary2integer(OffsetSExt) + 1;
            temp = -1 * temp;
        }
        temp = temp << 1;
        temp1 = NEXT_LATCHES.REGS[baseRegister] + temp;
        int row = temp1 >> 1;
        temp = (int)MEMORY[row][0];
        temp1 = (int)MEMORY[row][1];
        temp = (temp & 0x00FF) | (temp1 << 8);
        NEXT_LATCHES.REGS[destinationRegister] = Low16bits(temp);
        negativeZeroPositive(temp);
    }
    NEXT_LATCHES.PC = (CURRENT_LATCHES.PC + 2);
}

void STBSTWLogic(char *opcode, char *hexInstructionString, char *SR, char* baseR, char *Offset6, char *OffsetSExt) {
    int temp, temp1, temp2;
    strncpy(Offset6, hexInstructionString + 10, 6);
    *(Offset6 + 6) = '\0';
    signExtension(Offset6, OffsetSExt);

    strncpy(baseR, hexInstructionString + 7, 3);
    *(baseR + 3) = '\0';
    int baseRegister = binary2integer(baseR);

    strncpy(SR, hexInstructionString + 4, 3);
    *(SR + 3) = '\0';
    int sourceRegister = binary2integer(SR);

    if (strcmp(opcode, "0011") == 0) {/*STB*/
        if (*OffsetSExt == '0') {
            temp = binary2integer(OffsetSExt);
            temp1 = CURRENT_LATCHES.REGS[baseRegister] + temp;
        } else if (*OffsetSExt == '1') {
            binaryInvert(OffsetSExt);
            temp = binary2integer(OffsetSExt) + 1;
            temp1 = CURRENT_LATCHES.REGS[baseRegister] - temp;
        }
        int row = temp1 >> 1;
        int col = temp1 % 2;

        MEMORY[row][col] = Low16bits(NEXT_LATCHES.REGS[sourceRegister] & 0x00FF);
    } else if (strcmp(opcode, "0111") == 0) {/*STW*/
        if (*OffsetSExt == '0') {
            temp = binary2integer(OffsetSExt);
            temp = temp << 1;
            temp1 = NEXT_LATCHES.REGS[baseRegister] + temp;
            temp2 = temp1 >> 1;
        } else if (*OffsetSExt == '1') {
            binaryInvert(OffsetSExt);
            temp = binary2integer(OffsetSExt) + 1;
            temp = temp << 1;
            temp1 = NEXT_LATCHES.REGS[baseRegister] - temp;
            temp2 = temp1 >> 1;
        }
        MEMORY[temp2][0] = (NEXT_LATCHES.REGS[sourceRegister] & 0x00FF);
        MEMORY[temp2][1] = ((NEXT_LATCHES.REGS[sourceRegister] >> 8) & 0x00FF);
    }
    NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.PC + 2); /* Incrementing PC */
}

void execute_instruction(char *opcode, char *hexInstructionString) {
    NEXT_LATCHES = CURRENT_LATCHES;

    if (strcmp(opcode, ADD) == 0) {
        char DR[4] = "", SR1[4] = "", SR2[4] = "", imm5[6] = "", sExt[6] = "";
        AddAndXorNotLogic(opcode, hexInstructionString, DR, SR1, SR2, imm5, sExt);
    } else if (strcmp(opcode, AND) == 0) {
        char DR[4] = "", SR1[4] = "", SR2[4] = "", imm5[6] = "", sExt[6] = "";
        AddAndXorNotLogic(opcode, hexInstructionString, DR, SR1, SR2, imm5, sExt);
    } else if (strcmp(opcode, BR) == 0) {
        char PCOffset9[10] = "", PCOffsetSExt[16] = "";
        BRLogic(hexInstructionString, PCOffset9, PCOffsetSExt);
    } else if (strcmp(opcode, JMPRET) == 0) {
        char BaseR[4] = "";
        strncpy(BaseR, hexInstructionString + 7, 3);
        *(BaseR + 3) = '\0';
        int temp = binary2integer(BaseR);
        NEXT_LATCHES.PC = Low16bits(CURRENT_LATCHES.REGS[temp]);
    } else if (strcmp(opcode, JSRJSRR) == 0) {
        char baseR[4] = "", PCOffset11[12] = "", PCOffsetSExt[16] = "";
        JSRJSRRLogic(hexInstructionString, baseR, PCOffset11, PCOffsetSExt);
    } else if (strcmp(opcode, LDB) == 0) {
        char DR[4] = "", Offset6[7] = "", OffsetSExt[16] = "", baseR[4] = "";
        LDBLDWLogic(opcode, hexInstructionString, DR, baseR, Offset6, OffsetSExt);
    } else if (strcmp(opcode, LDW) == 0) {
        char DR[4] = "", Offset6[7] = "", OffsetSExt[16] = "", baseR[4] = "";
        LDBLDWLogic(opcode, hexInstructionString, DR, baseR, Offset6, OffsetSExt);
    } else if (strcmp(opcode, LEA) == 0) {
        char DR[4] = "", PCOffset9[10] = "", PCOffsetSExt[16] = "";
        LEALogic(hexInstructionString, DR, PCOffset9, PCOffsetSExt);
    } else if (strcmp(opcode, NOTXOR) == 0) {
        char DR[4] = "", SR1[4] = "", SR2[4] = "", imm5[6] = "", sExt[6] = "";
        AddAndXorNotLogic(opcode, hexInstructionString, DR, SR1, SR2, imm5, sExt);
    } else if (strcmp(opcode, SHF) == 0) {
        char DR[4] = "", SR[4] = "", amount4[5] = "";
        shiftLogic(hexInstructionString, DR, SR, amount4);
    } else if (strcmp(opcode, STB) == 0) {
        char SR[4] = "", Offset6[7] = "", OffsetSExt[16] = "", baseR[4] = "";
        STBSTWLogic(opcode, hexInstructionString, SR, baseR, Offset6, OffsetSExt);
    } else if (strcmp(opcode, STW) == 0) {
        char SR[4] = "", Offset6[7] = "", OffsetSExt[16] = "", baseR[4] = "";
        STBSTWLogic(opcode, hexInstructionString, SR, baseR, Offset6, OffsetSExt);
    } else if (strcmp(opcode, TRAP) == 0) {
        NEXT_LATCHES.REGS[7] = Low16bits(NEXT_LATCHES.PC + 2);
        char PCOffset8[16] = "", PCOffsetSExt[16] = "";
        strncpy(PCOffset8, hexInstructionString + 8, 8);
        *(PCOffset8 + 8) = '\0';
        zeroExtension(PCOffset8, PCOffsetSExt);
        int temp = binary2integer(PCOffsetSExt);
        temp = temp << 1;
        int row = temp >> 1; /*ROW Index*/
        int col = temp % 2; /*COLUMN Index*/
        temp = MEMORY[row][col];
        NEXT_LATCHES.PC = Low16bits(temp);
    }
}

void process_instruction() {
    /*  function: process_instruction
     *  
     *    Process one instruction at a time  
     *       -Fetch one instruction
     *       -Decode 
     *       -Execute
     *       -Update NEXT_LATCHES
     */

    int temporary = CURRENT_LATCHES.PC >> 1;
    int lowSignificantByte = MEMORY[temporary][0];
    int mostSignificantByte = MEMORY[temporary][1];

    int hexInstructionTemp = lowSignificantByte & 0x00FF;
    int hexInstructionTemp1 = (mostSignificantByte << 8) & 0xFF00;

    hexInstructionTemp = hexInstructionTemp | hexInstructionTemp1;

    char hexInstructionString[16] = ""; 
    hexadecimal2binary(hexInstructionTemp, hexInstructionString);
    char opcode[4];
    strncpy(opcode, hexInstructionString, 4);
    *(opcode + 4) = '\0';

    execute_instruction(opcode, hexInstructionString);
}