diff --git a/lab1/Makefile b/lab1/Makefile new file mode 100755 index 0000000..0e79e05 --- /dev/null +++ b/lab1/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 diff --git a/lab1/README.md b/lab1/README.md new file mode 100644 index 0000000..5e8ea55 --- /dev/null +++ b/lab1/README.md @@ -0,0 +1,13 @@ +MIPS Simulator +============== + +A simulator for the MIPS like Instruction Set, that translates machine code created from the assembler, and then executes the machine instructions. Each instruction goes through a Fetch, Decode, Execute, Memory and Writeback stage of processing. + +# Build + $ make + +# RUN add.out assembler output file + $ ./simulator add.out + + + diff --git a/lab1/mipsInstructionMap.h b/lab1/mipsInstructionMap.h new file mode 100644 index 0000000..9994d17 --- /dev/null +++ b/lab1/mipsInstructionMap.h @@ -0,0 +1,35 @@ +/* + * + * mipsInstructionMap.h + * + * Defines instructions as a hex value for comparison + * + * Modified by Masab Ahmad + * + */ + +// 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/lab1/simulator.c b/lab1/simulator.c new file mode 100644 index 0000000..144e709 --- /dev/null +++ b/lab1/simulator.c @@ -0,0 +1,296 @@ +/* + * riscy-uconn simulator.c + */ + +#include +#include +#include +#include "simulator.h" +#include "mipsInstructionMap.h" + +int debug = 0; + +int main(int argc, char *argv[]) { + + if (argc != 2) { + printf("Incorrect number of arguments\n"); + exit(1); + } + else { + // Open Input file + FILE *fp; + fp = fopen(argv[1], "r"); + + // 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(); + + // Dealloc .data + free(memory); + memory = NULL; + + // Close File + fclose (fp); + return 0; + } +} + +// Function to take in instruciton to parse +void process_instructions() { + + int terminate = 0; + // Cycle PC + int instruction_counter = 0; + + while(terminate != 1) + { + // set terminate flag when SLL $0, $0, 0 (aka NOOP) is executed + if (memory[pc/4] == 0) + terminate = 1; + + //Fetch Instruction + unsigned int instruction_fetch; + instruction_fetch = fetch(); + if(debug==1) + printf("\n IMEM ADDR:%d instruction 0x%08x", pc/4, instruction_fetch); + instruction_counter++; + + // Decode Instruction + struct Registers decode_out; + decode_out = decode(instruction_fetch); + + // Execute Instruction + struct Registers alu_out; + alu_out = execute(decode_out); + + // Memory Stage + struct Registers mem_out; + mem_out = memory_stage(alu_out); + + // Write Back Stage + write_back_stage(mem_out); + }//while pc loop + printf("\n TOTAL INSTRUCTIONS EXECUTED: %d", instruction_counter); +} //process_instruction + +// Advance PC +void advance_pc(int step) { + pc += step; +} + +unsigned int fetch() { + unsigned int inst = 0; + return inst = memory[pc/4]; +} + +struct Registers decode(unsigned int instruction_fetch) { + struct Registers reg_temp; + + // your code for decode phase goes here. + + return reg_temp; +} + + +struct Registers execute(struct Registers decode_out) +{ + // your code for execute phase goes here. + + return decode_out; +} + + +struct Registers memory_stage(struct Registers alu_out) +{ + // your code for memory phase goes here. + + return alu_out; +} + +void write_back_stage(struct Registers mem_out) +{ + // your code for write back phase goes here. + +} // WB Done + + +// 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); +} + +// 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]); + } +} + +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 memory + memory = (int *)malloc(16384 * sizeof(int)); + if (memory == NULL) + { + printf("Not enough memory. Aborting..\n"); + exit(1); + } + + // Initialize 'memory' array to -1 + for (int i = 0; i < 16384; i++) + { + memory[i] = -1; + } + + printf("\n Initialized Memory \n"); + + // Initialize variables for parsing + char line[MAX_LENGTH+2]; + char *p; + int i = 0, line_num = 0; + //int line_num = 0, i = 0, data_line = 0; + + // Copy .text section to memory, breaks at nop + while (fgets(line, MAX_LENGTH+2, fp) != NULL) + { + line_num++; + + // Remove '\n' from 'line' + p = strchr(line, '\n'); + if (p != NULL) + *p = '\0'; + + memory[i] = getDec(line); + //printf("\n %d",memory[i]); + + if (strcmp(line, "11111111111111111111111111111111") == 0) + { + memory[i] = 0; + i = 0x800; + break; + } + else + i++; + } + + int j = 2048; //Data Memory Starts at 2048 + for(j=i;j<16384;j++) + { + memory[j] = 2; + //printf("\n %d",memory[i]); + } + + printf("\n Instructions Read, Memory Offset: %d\n", line_num); + + // Seek fp to first instruction in .data + char data[MAX_LENGTH+2]; + int bytes = 33 * line_num; + fseek(fp, bytes, SEEK_SET); + + // Copy .data section to memory + while (fgets(line, MAX_LENGTH+2, fp) != NULL) + { + // Remove '\n' from 'line' + p = strchr(line, '\n'); + if (p != NULL) + *p = '\0'; + + memory[i] = getDec(line); + printf("\n Data: %d %d",i,memory[i]); + i++; + } + + printf("\n Data put in Memory \n"); +} + +// Convert a binary string to a decimal value +int getDec(char *bin) +{ + int b, k, m, n; + int len, sum = 0; + + // Length - 1 to accomodate for null terminator + len = strlen(bin) - 1; + + // Iterate the string + for(k = 0; k <= len; k++) + { + // Convert char to numeric value + n = (bin[k] - '0'); + + // Check the character is binary + if ((n > 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/lab1/simulator.h b/lab1/simulator.h new file mode 100644 index 0000000..1c0a692 --- /dev/null +++ b/lab1/simulator.h @@ -0,0 +1,65 @@ +/* + + * simulator.h + * + * Simulator header file declaring variables and methods + * + * Modified by Masab Ahmad + * 25/07/19 + */ + +#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; + +// Memory Allocated +//unsigned int *memory; +int *memory; + +struct Registers +{ + 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; + +}; + +void initialize(FILE *fp); +void process_instructions(); +int getDec(char *bin); +void isZero(int reg); +void advance_pc(int step); +void rdump(); +void mdump(); + +unsigned int fetch(); +struct Registers decode(unsigned int instuction_fetch); +struct Registers execute(struct Registers decode_out); +struct Registers memory_stage(struct Registers alu_out); +void write_back_stage(struct Registers memory_out); + +#endif /* SIMULATOR_H_ */ diff --git a/lab1/unittests/beq_test1.asm b/lab1/unittests/beq_test1.asm new file mode 100644 index 0000000..e3cdf40 --- /dev/null +++ b/lab1/unittests/beq_test1.asm @@ -0,0 +1,26 @@ +.text +add $a0, $zero, $zero # set $a0=0 : 0 --> i +addi $a1, $zero, 1 # set $a1=1 + +loop: +addi $t0, $zero, 2048 # set $t0 to 2048 +#ori $t0, $zero, 2048 # set $t0 to 2048 +sll $t1, $a0, 2 # $t1 <-- $a0 << 2 : $t1 <-- i*4 +add $t0, $t0, $t1 # form address of array[i] in $t0 +sw $zero, 0($t0) # store 32-bits of zero from $zero into array[i] +addi $a0, $a0, 1 # i++ +slti $t0, $a0, 10 # set $t0=1 if $a0 < 10 otherwise $t0=0 +beq $t0, $a1, loop # if $t0=0, branch to end label +sll $zero $zero, 0 # execute NOOP ... done + +.data +2048: .word 10 +2049: .word 32 +2050: .word 2 +2051: .word 2 +2052: .word 5 +2053: .word 5 +2054: .word 5 +2055: .word 5 +2056: .word 5 + diff --git a/lab1/unittests/beq_test2.asm b/lab1/unittests/beq_test2.asm new file mode 100644 index 0000000..81682c7 --- /dev/null +++ b/lab1/unittests/beq_test2.asm @@ -0,0 +1,27 @@ +.text +add $a0, $zero, $zero # set $a0=0 : 0 --> i + +loop: +slti $t0, $a0, 10 # set $t0=1 if $a0 < 10 otherwise $t0=0 +beq $t0, $zero, end # if $t0=0, branch to end label +addi $t0, $zero, 2048 +sll $t1, $a0, 2 # $t1 <-- $a0 << 2 : $t1 <-- i*4 +add $t0, $t0, $t1 # form address of array[i] in $t0 +sw $zero, 0($t0) # store 32-bits of zero from $zero into array[i] +addi $a0, $a0, 1 # i++ +beq $zero, $zero, loop # branch to label loop -- always branches + +end: +sll $zero $zero, 0 # execute NOOP ... done + +.data +2048: .word 10 +2049: .word 32 +2050: .word 2 +2051: .word 2 +2052: .word 5 +2053: .word 5 +2054: .word 5 +2055: .word 5 +2056: .word 5 + diff --git a/lab1/unittests/bne_test1.asm b/lab1/unittests/bne_test1.asm new file mode 100644 index 0000000..4b36776 --- /dev/null +++ b/lab1/unittests/bne_test1.asm @@ -0,0 +1,27 @@ +.text +add $a0, $zero, $zero # set $a0=0 : 0 --> i + +loop: +#addi $t0, $zero, 2048 # set $t0 to 2048 +ori $t0, $zero, 2048 # set $t0 to 2048 +#lui $t0, 0 # $t0 <-- 0x00000000 +#ori $t0, $t0, 0 # $t0 <-- $t0 | 0x0800 : $t0 = 0x00000800 +sll $t1, $a0, 2 # $t1 <-- $a0 << 2 : $t1 <-- i*4 +add $t0, $t0, $t1 # form address of array[i] in $t0 +sw $zero, 0($t0) # store 32-bits of zero from $zero into array[i] +addi $a0, $a0, 1 # i++ +slti $t0, $a0, 10 # set $t0=1 if $a0 < 10 otherwise $t0=0 +bne $t0, $zero, loop # if $t0=0, branch to end label +sll $zero $zero, 0 # execute NOOP ... done + +.data +2048: .word 10 +2049: .word 32 +2050: .word 2 +2051: .word 2 +2052: .word 5 +2053: .word 5 +2054: .word 5 +2055: .word 5 +2056: .word 5 + diff --git a/lab1/unittests/j_test1.asm b/lab1/unittests/j_test1.asm new file mode 100644 index 0000000..e06b85c --- /dev/null +++ b/lab1/unittests/j_test1.asm @@ -0,0 +1,27 @@ +.text +add $t0, $zero, $zero # iterator i = 0 +add $t2, $zero, $zero # initialize a memory pointer to zero +add $t3, $zero, $zero # initialize temporary register to zero +add $t4, $zero, $zero # initialize temporary register to zero +j jump_test1 # Jump to procedure "jump_test1" + +jump_test2: +lw $a1, 2048($t2) # Load a1 = 2, Mem[2048] = 2, 2 in simulator +addi $t2, $t2, 1 # Add 1 to the pointer to access Mem[2049] +lw $a2, 2048($t2) # Load a2 = 10, Mem[2049] = 10, 10 in simulator +j end # Jump to procedure "end" + +jump_test1: +add $t5, $zero, $zero # initialize temporary register to zero +add $t6, $zero, $zero # initialize temporary register to zero +j jump_test2 # Jump to procedure "jump_test2" + +end: +sll $zero $zero, 0 # execute NOOP ... done + +# --- Start of the Memory Layout --- + +.data +2048: .word 2 +2049: .word 10 + diff --git a/lab1/unittests/jal_test1.asm b/lab1/unittests/jal_test1.asm new file mode 100644 index 0000000..9934c17 --- /dev/null +++ b/lab1/unittests/jal_test1.asm @@ -0,0 +1,20 @@ +.text +addi $a0, $zero, 2 # argument 0 = 2 +addi $a1, $zero, 3 # argument 1 = 3 +addi $a2, $zero, 4 # argument 2 = 4 +addi $a3, $zero, 5 # argument 3 = 5 +add $t4, $zero, $zero +jal diffofsums # call procedure +add $s0, $v0, $zero # y = returned value +sll $zero $zero, 0 # execute NOOP ... done + +diffofsums: +add $t0, $a0, $a1 # $t0 = f + g +add $t1, $a2, $a3 # $t1 = h + i +sub $s0, $t0, $t1 # result = (f+g)-(h+i) +add $v0, $s0, $zero # put return value in $v0 +jr $ra # return to caller + +.data +2048: .word 10 +2049: .word 10 diff --git a/lab1/unittests/jr_test1.asm b/lab1/unittests/jr_test1.asm new file mode 100644 index 0000000..7d4a21c --- /dev/null +++ b/lab1/unittests/jr_test1.asm @@ -0,0 +1,24 @@ +.text +addi $a0, $zero, 2 # argument 0 = 2 +addi $a1, $zero, 3 # argument 1 = 3 +addi $a2, $zero, 4 # argument 2 = 4 +addi $a3, $zero, 5 # argument 3 = 5 +add $t4, $zero, $zero +addi $t4, $t4, 44 +jr $t4 # call procedure +add $s0, $v0, $zero # y = returned value +add $t5, $zero, $zero +addi $t5, $t5, 72 +jr $t5 +add $t0, $a0, $a1 # $t0 = f + g +add $t1, $a2, $a3 # $t1 = h + i +sub $s0, $t0, $t1 # result = (f+g)-(h+i) +add $v0, $s0, $zero # put return value in $v0 +add $t6, $zero, $zero +addi $t6, $t6, 28 +jr $t6 # return to caller +sll $zero $zero, 0 # execute NOOP ... done + +.data +2048: .word 10 +2049: .word 10 diff --git a/lab1/unittests/jr_test2.asm b/lab1/unittests/jr_test2.asm new file mode 100644 index 0000000..bff737c --- /dev/null +++ b/lab1/unittests/jr_test2.asm @@ -0,0 +1,21 @@ +.text +addi $a0, $zero, 2 # argument 0 = 2 +addi $a1, $zero, 3 # argument 1 = 3 +addi $a2, $zero, 4 # argument 2 = 4 +addi $a3, $zero, 5 # argument 3 = 5 +add $t4, $zero, $zero +addi $t4, $t4, 36 +jr $t4 # call procedure +add $s0, $v0, $zero # y = returned value +sll $zero $zero, 0 # execute NOOP ... done +add $t0, $a0, $a1 # $t0 = f + g +add $t1, $a2, $a3 # $t1 = h + i +sub $s0, $t0, $t1 # result = (f+g)-(h+i) +add $v0, $s0, $zero # put return value in $v0 +add $t6, $zero, $zero +addi $t6, $t6, 28 +jr $t6 # return to caller + +.data +2048: .word 10 +2049: .word 10 diff --git a/lab1/unittests/lw_sw_test1.asm b/lab1/unittests/lw_sw_test1.asm new file mode 100644 index 0000000..eacf65f --- /dev/null +++ b/lab1/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 +sll $zero $zero, 0 # execute NOOP ... done + + +.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/lab1/unittests/rand_test1.asm b/lab1/unittests/rand_test1.asm new file mode 100644 index 0000000..a2646e5 --- /dev/null +++ b/lab1/unittests/rand_test1.asm @@ -0,0 +1,38 @@ +.text +add $t0, $zero, $zero +add $t1, $zero, $zero +add $t2, $zero, $zero +add $t3, $zero, $zero +add $t5, $zero, $zero +add $t6, $zero, $zero +add $t7, $zero, $zero + + +lw $t1, 2048($t0) # $t1=5119 or 0x000013ff +andi $t2, $t1, 255 # mask 0x000000ff, so $t2=255 or 0x000000ff +sll $t3, $t2, 1 # times 2, so $t3=510 or 0x000001fe +andi $t4, $t3, 63 # mask 0x0000003f, so $t3=62 or 0x0000003e +#lui $t5, 65535 # $t5=-65536 or 0xffff0000 + +srl $t5, $t4, 1 # div 2, so $t5=31 or 0x0000001f +srl $t6, $t4, 2 # div 4, so $t6=15 or 0x0000000f +srl $t7, $t4, 3 # div 8, so $t7=7 or 0x00000007 + +sub $a0, $t5, $t6 # $a0=16 or 0x00000010 +and $a1, $t5, $t6 # $a1=15 or 0x0000000f +or $a2, $t5, $t6 # $a2=31 or 0x0000001f + + +ori $a3, $a0, 3 # $a3=14 or 0x00000013 + +slti $t0, $a0, 17 # $t0=1 +addi $t0, $t0, 2 # $t0=3 or 0x00000003 + +sll $zero $zero, 0 # execute NOOP ... done + + +.data +2048: .word 5119 +2049: .word 32 + + diff --git a/lab1/unittests/rand_test2.asm b/lab1/unittests/rand_test2.asm new file mode 100644 index 0000000..e6ea707 --- /dev/null +++ b/lab1/unittests/rand_test2.asm @@ -0,0 +1,23 @@ +.text +add $t0, $zero, $zero +add $t1, $zero, $zero +add $t2, $zero, $zero +add $t3, $zero, $zero +add $t5, $zero, $zero +add $t6, $zero, $zero +add $t7, $zero, $zero + + +lw $t1, 2048($t0) # $t1=5119 or 0x000013ff +andi $t2, $t1, 255 # mask 0x000000ff, so $t2=255 or 0x000000ff +sll $t3, $t2, 1 # times 2, so $t3=510 or 0x000001fe +andi $t4, $t3, 63 # mask 0x0000003f, so $t4=62 or 0x0000003e +lui $t5, 65535 # $t5=-65536 or 0xffff0000 + +sll $zero $zero, 0 # execute NOOP ... done + +.data +2048: .word 5119 +2049: .word 32 + +