diff --git a/pa3/Makefile b/pa3/Makefile new file mode 100755 index 0000000..3a588c1 --- /dev/null +++ b/pa3/Makefile @@ -0,0 +1,14 @@ +HEADERS = simulator.h + +default: simulator + +simulator.o: simulator.c $(HEADERS) + gcc -c simulator.c -o simulator.o -ggdb -std=c99 + +simulator: simulator.o + gcc simulator.o -o simulator -ggdb -std=c99 + +clean: + -rm -f simulator.o + -rm -f simulator + -rm -f *.out mdump.txt cdump.txt pipe_trace.txt diff --git a/pa3/mipsInstructionMap.h b/pa3/mipsInstructionMap.h new file mode 100644 index 0000000..f55f5bb --- /dev/null +++ b/pa3/mipsInstructionMap.h @@ -0,0 +1,35 @@ +/* + * + * mipsInstructionMap.h + * + * Defines instructions as a hex value for comparison + * + * Modified by Omer Khan + * + */ + +// R-Type Instructions +#define RTYPEOP 0x0 +#define ADD 0x20 +#define SUB 0x21 +#define AND 0x24 +#define OR 0x25 +#define SLL 0x0 +#define SLT 0x2A +#define SRL 0x2 +#define JR 0x8 + +// I-Type Instructions +#define LW 0x23 +#define SW 0x2B +#define ANDI 0xC +#define ORI 0xD +#define LUI 0xF +#define BEQ 0x4 +#define BNE 0x5 +#define SLTI 0xA +#define ADDI 0x8 + +// J-Type Instructions +#define J 0x2 +#define JAL 0x3 diff --git a/pa3/simulator.c b/pa3/simulator.c new file mode 100644 index 0000000..9b4856d --- /dev/null +++ b/pa3/simulator.c @@ -0,0 +1,487 @@ +/* + * riscy-uconn simulator.c + */ + +#include +#include +#include +#include "simulator.h" +#include "mipsInstructionMap.h" + +int debug = 0; +int pipe_trace = 1; +int forwarding_enabled = 1; +int cache_enabled = 1; +int cycles_to_access_dmem = 10; +int cycles_to_exe = 1; + +static FILE *fptr_pt; + +int main(int argc, char *argv[]) { + + if (argc != 4) { + printf("Incorrect number of arguments\n"); + exit(1); + } + else { + // Open Input file + FILE *fp; + fp = fopen(argv[1], "r"); + + sscanf(argv[2],"%d",&forwarding_enabled); + + if (forwarding_enabled > 1) { + printf("Incorrect selection for forwarding_enabled. Use either 0 or 1 to select disable or enable forwarding!\n"); + exit(1); + } + + printf("\n forwarding_enabled = %d", forwarding_enabled); + + sscanf(argv[3],"%d",&cache_enabled); + + if (cache_enabled > 1) { + printf("Incorrect selection for cache_enabled. Use either 0 or 1 to select disable or enable cache!\n"); + exit(1); + } + + printf("\n cache_enabled = %d\n", cache_enabled); + + fptr_pt = fopen("pipe_trace.txt","w"); + + // Call initialize function for registers and instruction/data memory + initialize(fp); + + // Process one instruction at a time + process_instructions(); + + printf("\n Printing Output Registers \n"); + + // Output registers + rdump(); + + // Output Memory + mdump(); + + // Output Cache + cdump(); + + // Dealloc .data + free(memory); + memory = NULL; + + printf("\n Data Memory Stats: data accesses = %d, cache hits = %d\n", dcache_accesses, dcache_hits); + + // Dealloc cache + free(cache); + cache = NULL; + + // Close File + fclose (fp); + return 0; + } +} + +// Function to take in instruciton to parse +void process_instructions() { + + int terminate = 0; + int instruction_counter = 0; //committed instruction count + + // pipeline state and essential initializations + unsigned int instruction_fetch, instruction_fetch_n; + instruction_fetch = 0xffffffff; // initial state to decode stage + struct Registers decode_out, decode_out_n; + decode_out.inst = 0xffffffff; // initial state to execute stage + decode_out.x = 0xffffffff; + decode_out.y = 0xffffffff; + struct Registers alu_out, alu_out_n; + alu_out.inst = 0xffffffff; // initial state to memory stage + alu_out.x = 0xffffffff; + alu_out.y = 0xffffffff; + alu_out.memory_flag = 0; + struct Registers mem_out, mem_out_n; + mem_out.inst = 0xffffffff; // initial state to write_back stage + mem_out.x = 0xffffffff; + mem_out.y = 0xffffffff; + unsigned int committed_inst; + + while(terminate != 1) + { + // first update all stages with current state + committed_inst = write_back_stage(mem_out); + mem_out_n = memory_stage(alu_out); + alu_out_n = execute(decode_out); + decode_out_n = decode(instruction_fetch); + instruction_fetch_n = fetch(instruction_fetch); + + if (pipe_trace == 1) { + fprintf(fptr_pt, "\ncycle %d, currPC %d, nextPC %d: ", cycle, pc, pc_n); + inst_dump ("Fetch", instruction_fetch_n); + inst_dump ("Decode", decode_out_n.inst); + inst_dump ("Execute", alu_out_n.inst); + inst_dump ("Memory", mem_out_n.inst); + inst_dump ("Writeback", committed_inst); + rdump_pt(); + } + + if(debug==1) + printf("\n cycle: %d IMEM ADDR:%d instruction 0x%08x", cycle, pc/4, instruction_fetch_n); + + if ( (committed_inst != 0xffffffff) & (committed_inst != 0x00000000) ) { + instruction_counter++; + } + + if(debug==1) + printf("\n cycle: %d commited inst: instruction 0x%08x", cycle, committed_inst); + + if (registers[0] != 0) + terminate = 1; // set terminate flag when $zero is updated + + // second, update all state for next cycle + if (dmem_busy == 1) { + + // add code here to hold fetch, decode, execute and memory stages! + + } + else { + pc = pc_n; + instruction_fetch = instruction_fetch_n; + decode_out = decode_out_n; + alu_out = alu_out_n; + mem_out = mem_out_n; + } + + cycle++; + + }//while pc loop + printf("\n TOTAL %d INSTRUCTIONS EXECUTED IN %d CYCLES", instruction_counter, cycle); +} //process_instruction + +// Advance PC +void advance_pc(int step) { + pc_n += step; +} + +unsigned int fetch(unsigned int instruction_fetch) { + unsigned int inst = 0; + + // your code for fetch stage from lab2 goes here. note that this stage needs no further modifications for lab3 + + return inst; +} + +struct Registers decode(unsigned int instruction_fetch) { + struct Registers reg_temp; + + // your code for lab3 goes here. note that this is in addition to your lab2 code + + return reg_temp; +} + + +struct Registers execute(struct Registers decode_out) +{ + + // your code for execute stage from lab2 goes here. note that this stage needs no further modifications for lab3 + + return decode_out; +} + + +struct Registers memory_stage(struct Registers alu_out) +{ + + // your code for lab3 goes here. note that this is in addition to your lab2 code + + return alu_out; +} + +unsigned int write_back_stage(struct Registers mem_out) +{ + + // your code for write-back stage from lab2 goes here. note that this stage needs no further modifications for lab3 + + return mem_out.inst; +} + +int dcache_lookup(int addr_mem) { + int hit = 0; + + // your code for cache lookup operation goes here. + + return hit; +} + +void dcache_update(int addr_mem) { + + // your code for cache update logic goes here. + +} + +// Output reigsters +void rdump() +{ + printf("$0 $zero 0x%08x\n", registers[0]); + printf("$1 $at 0x%08x\n", registers[1]); + printf("$2 $v0 0x%08x\n", registers[2]); + printf("$3 $v1 0x%08x\n", registers[3]); + printf("$4 $a0 0x%08x\n", registers[4]); + printf("$5 $a1 0x%08x\n", registers[5]); + printf("$6 $a2 0x%08x\n", registers[6]); + printf("$7 $a3 0x%08x\n", registers[7]); + printf("$8 $t0 0x%08x\n", registers[8]); + printf("$9 $t1 0x%08x\n", registers[9]); + printf("$10 $t2 0x%08x\n", registers[10]); + printf("$11 $t3 0x%08x\n", registers[11]); + printf("$12 $t4 0x%08x\n", registers[12]); + printf("$13 $t5 0x%08x\n", registers[13]); + printf("$14 $t6 0x%08x\n", registers[14]); + printf("$15 $t7 0x%08x\n", registers[15]); + printf("$16 $s0 0x%08x\n", registers[16]); + printf("$17 $s1 0x%08x\n", registers[17]); + printf("$18 $s2 0x%08x\n", registers[18]); + printf("$19 $s3 0x%08x\n", registers[19]); + printf("$20 $s4 0x%08x\n", registers[20]); + printf("$21 $s5 0x%08x\n", registers[21]); + printf("$22 $s6 0x%08x\n", registers[22]); + printf("$23 $s7 0x%08x\n", registers[23]); + printf("$24 $t8 0x%08x\n", registers[24]); + printf("$25 $t9 0x%08x\n", registers[25]); + printf("$26 $k0 0x%08x\n", registers[26]); + printf("$27 $k1 0x%08x\n", registers[27]); + printf("$28 $gp 0x%08x\n", registers[28]); + printf("$29 $sp 0x%08x\n", registers[29]); + printf("$30 $fp 0x%08x\n", registers[30]); + printf("$31 $ra 0x%08x\n", registers[31]); + + printf(" --> pc 0x%08x\n", pc); +} + +void rdump_pt() { + fprintf(fptr_pt, "\n$0 $zero: %d $8 $t0: %d $16 $s0: %d $24 $t8: %d", registers[0], registers[8], registers[16], registers[24]); + fprintf(fptr_pt, "\n$1 $at: %d $9 $t1: %d $17 $s1: %d $25 $t9: %d", registers[1], registers[9], registers[17], registers[25]); + fprintf(fptr_pt, "\n$2 $v0: %d $10 $t2: %d $18 $s2: %d $26 $k0: %d", registers[2], registers[10], registers[18], registers[26]); + fprintf(fptr_pt, "\n$3 $v1: %d $11 $t3: %d $19 $s3: %d $27 $k1: %d", registers[3], registers[11], registers[19], registers[27]); + fprintf(fptr_pt, "\n$4 $a0: %d $12 $t4: %d $20 $s4: %d $28 $gp: %d", registers[4], registers[12], registers[20], registers[28]); + fprintf(fptr_pt, "\n$5 $a1: %d $13 $t5: %d $21 $s5: %d $29 $sp: %d", registers[5], registers[13], registers[21], registers[29]); + fprintf(fptr_pt, "\n$6 $a2: %d $14 $t6: %d $22 $s6: %d $30 $fp: %d", registers[6], registers[14], registers[22], registers[30]); + fprintf(fptr_pt, "\n$7 $a3: %d $15 $t7: %d $23 $s7: %d $31 $ra: %d\n", registers[7], registers[15], registers[23], registers[31]); +} + +// Output Memory +void mdump() { + FILE *fptr; + fptr = fopen("mdump.txt","w"); + int i = 0; + for(i=0;i<16384;i++) + { + fprintf(fptr,"\n Memory[%d] = %d",i,memory[i]); + //fprintf(fptr,"\n Memory[%d] = %d M[0x%08x]",i,memory[i],i); + } +} + +void cdump() { + FILE *fptr; + fptr = fopen("cdump.txt","w"); + int i = 0; + for (i=0;i> 26; + + unsigned int func = inst << 26; + func = func >> 26; + + int rs = (inst >> 21) & 0x1F; + int rt = (inst >> 16) & 0x1F; + int rd = (inst >> 11) & 0x1F; + int sa = (inst >> 6) & 0x1F; + int imm = inst & 0xFFFF; + short shortImm = (short)imm; + int target = inst & 0x03ffffff; + + if (inst == 0xffffffff) + fprintf(fptr_pt, "\n %s instr: ", stage); + + if (opcode == RTYPEOP) { + if (func == ADD) + fprintf(fptr_pt, "\n %s instr: add $%d, $%d, $%d", stage, rd, rs, rt); + if (func == SUB) + fprintf(fptr_pt, "\n %s instr: sub $%d, $%d, $%d", stage, rd, rs, rt); + if (func == AND) + fprintf(fptr_pt, "\n %s instr: and $%d, $%d, $%d", stage, rd, rs, rt); + if (func == OR) + fprintf(fptr_pt, "\n %s instr: or $%d, $%d, $%d", stage, rd, rs, rt); + if (func == SLL) + fprintf(fptr_pt, "\n %s instr: sll $%d, $%d, %d", stage, rd, rt, sa); + if (func == SRL) + fprintf(fptr_pt, "\n %s instr: srl $%d, $%d, %d", stage, rd, rt, sa); + if (func == SLT) + fprintf(fptr_pt, "\n %s instr: slt $%d, $%d, $%d", stage, rd, rs, rt); + if (func == JR) + fprintf(fptr_pt, "\n %s instr: jr $%d", stage, rs); + } + + if (opcode == LW) + fprintf(fptr_pt, "\n %s instr: lw $%d %d($%d)", stage, rt, imm, rs); + if (opcode == SW) + fprintf(fptr_pt, "\n %s instr: sw $%d %d($%d)", stage, rt, imm, rs); + if (opcode == ANDI) + fprintf(fptr_pt, "\n %s instr: andi $%d, $%d, %d", stage, rt, rs, imm); + if (opcode == ADDI) + fprintf(fptr_pt, "\n %s instr: addi $%d, $%d, %d", stage, rt, rs, imm); + if (opcode == ORI) + fprintf(fptr_pt, "\n %s instr: ori $%d, $%d, %d", stage, rt, rs, imm); + if (opcode == SLTI) + fprintf(fptr_pt, "\n %s instr: slti $%d, $%d, %d", stage, rt, rs, imm); + if (opcode == LUI) + fprintf(fptr_pt, "\n %s instr: lui $%d, %d", stage, rt, imm); + if (opcode == BEQ) + fprintf(fptr_pt, "\n %s instr: beq $%d, $%d, %d", stage, rs, rt, shortImm); + if (opcode == BNE) + fprintf(fptr_pt, "\n %s instr: bne $%d, $%d, %d", stage, rs, rt, shortImm); + + if (opcode == J) + fprintf(fptr_pt, "\n %s instr: j %d", stage, target); + if (opcode == JAL) + fprintf(fptr_pt, "\n %s instr: jal %d", stage, target); +} + +void initialize(FILE *fp) +{ + if (fp == NULL) + { + printf("Error opening input file.\n"); + exit(1); + } + + // Initialize registers values' to 0x0 + for (int i = 0; i < 32; i++) + registers[i] = 0x0; + + printf("\n Initialized Registers \n"); + + // Malloc cache + cache = (cblock *) malloc(NUM_LINES * sizeof(cblock)); + if (cache == NULL) { + printf("Not enough memory. Aborting..\n"); + exit(1); + } + for (int i=0; i 1) || (n < 0)) + { + return 0; + } + + for(b = 1, m = len; m > k; m--) + b *= 2; + + // sum it up + sum = sum + n * b; + } + return sum; +} + diff --git a/pa3/simulator.h b/pa3/simulator.h new file mode 100644 index 0000000..743aeaa --- /dev/null +++ b/pa3/simulator.h @@ -0,0 +1,99 @@ +/* + + * simulator.h + * + * Simulator header file declaring variables and methods + * + */ + +#ifndef SIMULATOR_H_ +#define SIMULATOR_H_ + +// Define MAX_LENGTH for number of registers & instruction length +#define MAX_LENGTH 32 + +// Array of size MAX_LENGTH to hold registers +int registers[MAX_LENGTH]; + +// PC Register +unsigned int pc = 0; +unsigned int pc_n = 0; + +// Memory Allocated +//unsigned int *memory; +int *memory; + +// CLOCK CYCLE +int cycle = 0; + +struct Registers +{ + unsigned int inst; + int x; + unsigned int y; + int reg; + int rs; + int rt; + int rd; + int sa; + unsigned short imm; + + int memory_flag; + int addr_mem; + int branch_flag; + int jmp_out_31; + + //ALU Inputs/Outputs + int A; + int B; + int C; + int D; + +}; + +// Global metadata to support pipelining +int pipe_stall = 0; +int br_taken = 0; +int lw_in_exe = 0; +int we_exe, ws_exe, dout_exe = 0; +int we_mem, ws_mem, dout_mem = 0; +int we_wb, ws_wb, dout_wb = 0; + +int dmem_busy = 0; +int dmem_cycles = 0; +int exe_busy = 0; +int exe_cycles = 1; + +#define NUM_LINES 16 // 1024 bytes (cache size) / 64 bytes (block size) + +typedef struct { + int valid; + int tag; +} cblock; + +cblock *cache; + +int dcache_accesses = 0; +int dcache_hits = 0; + +void initialize(FILE *fp); +void process_instructions(); +int getDec(char *bin); +void isZero(int reg); +void advance_pc(int step); +void rdump(); +void rdump_pt(); +void mdump(); +void cdump(); +void inst_dump(char [], unsigned int inst); + +unsigned int fetch(unsigned int instuction_fetch); +struct Registers decode(unsigned int instuction_fetch); +struct Registers execute(struct Registers decode_out); +struct Registers memory_stage(struct Registers alu_out); +unsigned int write_back_stage(struct Registers memory_out); + +int dcache_lookup(int addr_mem); +void dcache_update(int addr_mem); + +#endif /* SIMULATOR_H_ */ diff --git a/pa3/unittests/lw_sw_test0.asm b/pa3/unittests/lw_sw_test0.asm new file mode 100644 index 0000000..b943de9 --- /dev/null +++ b/pa3/unittests/lw_sw_test0.asm @@ -0,0 +1,16 @@ +.text +lw $t1, 2048($t0) # $t1=5119 or 0x000013f +add $t0, $zero, $zero +add $t2, $zero, $zero +add $t3, $zero, $zero +add $t5, $zero, $zero +add $t6, $zero, $zero +add $t7, $zero, $zero +addi, $zero, $zero, 1 # $zero register should never be updated, so detect this change and quit simulator + + +.data +2048: .word 5119 +2049: .word 32 + + diff --git a/pa3/unittests/lw_sw_test1.asm b/pa3/unittests/lw_sw_test1.asm new file mode 100644 index 0000000..2811d0c --- /dev/null +++ b/pa3/unittests/lw_sw_test1.asm @@ -0,0 +1,59 @@ +.text +add $t0, $zero, $zero # i = 0 +add $t1, $zero, $zero # initialize the sum to zero +add $t2, $zero, $zero # for second loop compare 2 +add $t3, $zero, $zero +add $t5, $zero, $zero # initialize temporary register to zero +add $t6, $zero, $zero # for sw later +add $t7, $zero, $zero + +lw $t1, 2048($t0) # $t1=20 +lw $t2, 2048($t1) # $t2=4 +add $t4, $t1, $t2 # $t4=24 +lw $t3, 2048($t4) # $t3=8 +add $t4, $t4, $t3 # $t4=32 +sw $t4, 2048($t0) # mem[2048]=32 +lw $t1, 2048($t0) # $t1=32 <-- observation of stored value 32 as $t1=0x00000020 +lw $t2, 2048($t1) # $t2=5 +add $t4, $t1, $t2 # $t4=37 +sw $t4, 2048($t1) # mem[2080]=37 +lw $t5, 2048($t1) # $t5=37 <--- observation of stored value 37 as $t5=0x00000025 +addi, $zero, $zero, 1 # $zero register should never be updated, so detect this change and quit simulator + + +.data +2048: .word 20 +2049: .word 32 +2050: .word 2 +2051: .word 2 +2052: .word 3 +2053: .word 3 +2054: .word 3 +2055: .word 3 +2056: .word 3 +2057: .word 3 +2058: .word 3 +2059: .word 3 +2060: .word 3 +2061: .word 3 +2062: .word 3 +2063: .word 3 +2064: .word 3 +2065: .word 3 +2066: .word 3 +2067: .word 3 +2068: .word 4 +2069: .word 3 +2070: .word 3 +2071: .word 3 +2072: .word 8 +2073: .word 3 +2074: .word 3 +2075: .word 3 +2076: .word 3 +2077: .word 3 +2078: .word 3 +2079: .word 3 +2080: .word 5 + + diff --git a/pa3/unittests/lw_sw_test2.asm b/pa3/unittests/lw_sw_test2.asm new file mode 100644 index 0000000..a266623 --- /dev/null +++ b/pa3/unittests/lw_sw_test2.asm @@ -0,0 +1,60 @@ +.text +add $t0, $zero, $zero # i = 0 +add $t1, $zero, $zero # initialize the sum to zero +add $t2, $zero, $zero # for second loop compare 2 +add $t3, $zero, $zero +add $t5, $zero, $zero # initialize temporary register to zero +add $t6, $zero, $zero # for sw later +add $t7, $zero, $zero + +lw $t1, 2048($t0) # $t1=20 +add $t4, $t1, $t1 # $t4=40 +lw $t3, 2048($t4) # $t3=57 +addi, $zero, $zero, 1 # $zero register should never be updated, so detect this change and quit simulator + + +.data +2048: .word 20 +2049: .word 32 +2050: .word 2 +2051: .word 2 +2052: .word 3 +2053: .word 3 +2054: .word 3 +2055: .word 3 +2056: .word 3 +2057: .word 3 +2058: .word 3 +2059: .word 3 +2060: .word 3 +2061: .word 3 +2062: .word 3 +2063: .word 3 +2064: .word 3 +2065: .word 3 +2066: .word 3 +2067: .word 3 +2068: .word 4 +2069: .word 3 +2070: .word 3 +2071: .word 3 +2072: .word 8 +2073: .word 3 +2074: .word 3 +2075: .word 3 +2076: .word 3 +2077: .word 3 +2078: .word 3 +2079: .word 3 +2080: .word 5 +2081: .word 50 +2082: .word 51 +2083: .word 52 +2084: .word 53 +2085: .word 54 +2086: .word 55 +2087: .word 56 +2088: .word 57 + + + diff --git a/pa3/unittests/lw_sw_test3.asm b/pa3/unittests/lw_sw_test3.asm new file mode 100644 index 0000000..2aeaaaa --- /dev/null +++ b/pa3/unittests/lw_sw_test3.asm @@ -0,0 +1,68 @@ +.text +add $t0, $zero, $zero # i = 0 +add $t1, $zero, $zero # initialize the sum to zero +add $t2, $zero, $zero # for second loop compare 2 +add $t3, $zero, $zero +add $t5, $zero, $zero # initialize temporary register to zero +add $t6, $zero, $zero # for sw later +add $t7, $zero, $zero + +lw $t1, 2048($t0) # $t1=20 +lw $t2, 2049($t0) # $t2=32 +add $t4, $t1, $t2 +lw $t1, 2050($t0) # $t1=2 +add $t4, $t1, $t4 +lw $t1, 2051($t0) # $t1=2 +add $t4, $t1, $t4 +lw $t1, 2052($t0) # $t1=3 +add $t4, $t1, $t4 +lw $t1, 2053($t0) # $t1=3 +add $t4, $t1, $t4 +lw $t1, 2054($t0) # $t1=3 +add $t4, $t1, $t4 +lw $t1, 2055($t0) # $t1=3 +add $t4, $t1, $t4 +lw $t1, 2056($t0) # $t1=3 +add $t4, $t1, $t4 +lw $t1, 2057($t0) # $t1=3 +add $t4, $t1, $t4 # $t4 = 74 + +addi, $zero, $zero, 1 # $zero register should never be updated, so detect this change and quit simulator + + +.data +2048: .word 20 +2049: .word 32 +2050: .word 2 +2051: .word 2 +2052: .word 3 +2053: .word 3 +2054: .word 3 +2055: .word 3 +2056: .word 3 +2057: .word 3 +2058: .word 3 +2059: .word 3 +2060: .word 3 +2061: .word 3 +2062: .word 3 +2063: .word 3 +2064: .word 3 +2065: .word 3 +2066: .word 3 +2067: .word 3 +2068: .word 4 +2069: .word 3 +2070: .word 3 +2071: .word 3 +2072: .word 8 +2073: .word 3 +2074: .word 3 +2075: .word 3 +2076: .word 3 +2077: .word 3 +2078: .word 3 +2079: .word 3 +2080: .word 5 + +