RISC-ISA-Pipeline-1 / simulator.h
simulator.h
Raw
#define NUMMEMORY 65536 /* maximum number of data words in memory */
#define NUMREGS 8 /* number of machine registers */

#define ADD 0
#define NOR 1
#define LW 2
#define SW 3
#define BEQ 4
#define JALR 5 /* JALR will not implemented for Project 3 */
#define HALT 6
#define NOOP 7

#define NOOPINSTRUCTION 0x1c00000
#define MAXLINELENGTH 1000

typedef struct IFIDStruct {
    int instr;
    int pcPlus1;
} IFIDType;

typedef struct IDEXStruct {
    int instr;
    int pcPlus1;
    int readRegA;
    int readRegB;
    int offset;
} IDEXType;

typedef struct EXMEMStruct {
    int instr;
    int branchTarget;
    int eq;
    int aluResult;
    int readRegB;
} EXMEMType;

typedef struct MEMWBStruct {
    int instr;
    int writeData;
} MEMWBType;

typedef struct WBENDStruct {
    int instr;
    int writeData;
} WBENDType;

typedef struct stateStruct {
    int pc;
    int instrMem[NUMMEMORY];
    int dataMem[NUMMEMORY];
    int reg[NUMREGS];
    int numMemory;
    IFIDType IFID;
    IDEXType IDEX;
    EXMEMType EXMEM;
    MEMWBType MEMWB;
    WBENDType WBEND;
    int cycles; /* number of cycles run so far */
} stateType;

int
field0(int instruction) // regA
{
    return((instruction >> 19) & 0x7);
}

int
field1(int instruction) // regB
{
    return((instruction >> 16) & 0x7);
}

int
field2(int instruction) // offset
{
    return(instruction & 0xFFFF);
}

int
opcode(int instruction)
{
    return(instruction >> 22);
}

void printInstruction(int instr) {
    switch (opcode(instr)) {
    case ADD:
        printf("add");
        break;
    case NOR:
        printf("nor");
        break;
    case LW:
        printf("lw");
        break;
    case SW:
        printf("sw");
        break;
    case BEQ:
        printf("beq");
        break;
    case JALR:
        printf("jalr");
        break;
    case HALT:
        printf("halt");
        break;
    case NOOP:
        printf("noop");
        break;
    default:
        printf(".fill %d", instr);
        return;
    }
    printf(" %d %d %d", field0(instr), field1(instr), field2(instr));
}

void printState(stateType* statePtr) {
    printf("\n@@@\n");
    printf("state before cycle %d starts:\n", statePtr->cycles);
    printf("\tpc = %d\n", statePtr->pc);

    printf("\tdata memory:\n");
    for (int i = 0; i < statePtr->numMemory; ++i) {
        printf("\t\tdataMem[ %d ] = %d\n", i, statePtr->dataMem[i]);
    }
    printf("\tregisters:\n");
    for (int i = 0; i < NUMREGS; ++i) {
        printf("\t\treg[ %d ] = %d\n", i, statePtr->reg[i]);
    }

    // IF/ID
    printf("\tIF/ID pipeline register:\n");
    printf("\t\tinstruction = %d ( ", statePtr->IFID.instr);
    printInstruction(statePtr->IFID.instr);
    printf(" )\n");
    printf("\t\tpcPlus1 = %d", statePtr->IFID.pcPlus1);
    if (opcode(statePtr->IFID.instr) == NOOP) {
        printf(" (Don't Care)");
    }
    printf("\n");

    // ID/EX
    int idexOp = opcode(statePtr->IDEX.instr);
    printf("\tID/EX pipeline register:\n");
    printf("\t\tinstruction = %d ( ", statePtr->IDEX.instr);
    printInstruction(statePtr->IDEX.instr);
    printf(" )\n");
    printf("\t\tpcPlus1 = %d", statePtr->IDEX.pcPlus1);
    if (idexOp == NOOP) {
        printf(" (Don't Care)");
    }
    printf("\n");
    printf("\t\treadRegA = %d", statePtr->IDEX.readRegA);
    if (idexOp >= HALT || idexOp < 0) {
        printf(" (Don't Care)");
    }
    printf("\n");
    printf("\t\treadRegB = %d", statePtr->IDEX.readRegB);
    if (idexOp == LW || idexOp > BEQ || idexOp < 0) {
        printf(" (Don't Care)");
    }
    printf("\n");
    printf("\t\toffset = %d", statePtr->IDEX.offset);
    if (idexOp != LW && idexOp != SW && idexOp != BEQ) {
        printf(" (Don't Care)");
    }
    printf("\n");

    // EX/MEM
    int exmemOp = opcode(statePtr->EXMEM.instr);
    printf("\tEX/MEM pipeline register:\n");
    printf("\t\tinstruction = %d ( ", statePtr->EXMEM.instr);
    printInstruction(statePtr->EXMEM.instr);
    printf(" )\n");
    printf("\t\tbranchTarget %d", statePtr->EXMEM.branchTarget);
    if (exmemOp != BEQ) {
        printf(" (Don't Care)");
    }
    printf("\n");
    printf("\t\teq ? %s", (statePtr->EXMEM.eq ? "True" : "False"));
    if (exmemOp != BEQ) {
        printf(" (Don't Care)");
    }
    printf("\n");
    printf("\t\taluResult = %d", statePtr->EXMEM.aluResult);
    if (exmemOp > SW || exmemOp < 0) {
        printf(" (Don't Care)");
    }
    printf("\n");
    printf("\t\treadRegB = %d", statePtr->EXMEM.readRegB);
    if (exmemOp != SW) {
        printf(" (Don't Care)");
    }
    printf("\n");

    // MEM/WB
    int memwbOp = opcode(statePtr->MEMWB.instr);
    printf("\tMEM/WB pipeline register:\n");
    printf("\t\tinstruction = %d ( ", statePtr->MEMWB.instr);
    printInstruction(statePtr->MEMWB.instr);
    printf(" )\n");
    printf("\t\twriteData = %d", statePtr->MEMWB.writeData);
    if (memwbOp >= SW || memwbOp < 0) {
        printf(" (Don't Care)");
    }
    printf("\n");

    // WB/END
    int wbendOp = opcode(statePtr->WBEND.instr);
    printf("\tWB/END pipeline register:\n");
    printf("\t\tinstruction = %d ( ", statePtr->WBEND.instr);
    printInstruction(statePtr->WBEND.instr);
    printf(" )\n");
    printf("\t\twriteData = %d", statePtr->WBEND.writeData);
    if (wbendOp >= SW || wbendOp < 0) {
        printf(" (Don't Care)");
    }
    printf("\n");

    printf("end state\n");
}


int
convertNum(int num)
{
    /* converts a 16-bit number into a 32-bit Linux integer */
    if (num & (1 << 15)) {
        num -= (1 << 16);
    }
    return(num);
}

void initialize(stateType* state)
{
    state->pc = 0;
    state->cycles = 0;
    for (int i = 0; i < NUMREGS; i++) {
        state->reg[i] = 0;
    }
    state->IFID.instr = NOOPINSTRUCTION;
    state->IDEX.instr = NOOPINSTRUCTION;
    state->EXMEM.instr = NOOPINSTRUCTION;
    state->MEMWB.instr = NOOPINSTRUCTION;
    state->WBEND.instr = NOOPINSTRUCTION;
}

int stall_check(stateType* state) {
    int stall = 0;
    int instr = state->IFID.instr;
    if (opcode(state->IDEX.instr) == 2) {                   // instr ahead is lw
        if (field1(state->IDEX.instr) == field0(instr)) {
            stall = 1;
        }
        else if (field1(state->IDEX.instr) == field1(instr)) {
            stall = 1;
        }
    }
    return stall;
}

void wbend_check(stateType* state, int* regA, int* regB) {
    int wbend_instr = state->WBEND.instr;
    int idex_instr = state->IDEX.instr;
    if (field2(wbend_instr) == field0(idex_instr)) {
        *regA = state->WBEND.writeData;
    }
    if (field2(wbend_instr) == field1(idex_instr)) {
        *regB = state->WBEND.writeData;
    }
}

void memwb_check(stateType* state, int* regA, int* regB) {
    int memwb_instr = state->MEMWB.instr;
    int idex_instr = state->IDEX.instr;
    if (field2(memwb_instr) == field0(idex_instr)) {
        *regA = state->MEMWB.writeData;
    }
    if (field2(memwb_instr) == field1(idex_instr)) {
        *regB = state->MEMWB.writeData;
    }
}

void exmem_check(stateType* state, int* regA, int* regB) {
    int exmem_instr = state->EXMEM.instr;
    int idex_instr = state->IDEX.instr;
    if (field2(exmem_instr) == field0(idex_instr)) {
        *regA = state->EXMEM.aluResult;
    }
    if (field2(exmem_instr) == field1(idex_instr)) {
        *regB = state->EXMEM.aluResult;
    }
}