From fcb78f141958260498472063bab197a1984352f6 Mon Sep 17 00:00:00 2001 From: cag-uconn Date: Wed, 8 Nov 2023 08:04:16 -0500 Subject: [PATCH] . --- pa3/.DS_Store | Bin 0 -> 6148 bytes pa3/Makefile | 18 ++ pa3/README.md | 24 ++ pa3/assemble_all.sh | 24 ++ pa3/src/instruction_map.h | 62 ++++ pa3/src/register_map.c | 49 +++ pa3/src/register_map.h | 16 + pa3/src/sim_core.c | 365 ++++++++++++++++++++++ pa3/src/sim_core.h | 156 ++++++++++ pa3/src/sim_stages.c | 197 ++++++++++++ pa3/src/sim_stages.h | 42 +++ pa3/src/util.c | 426 ++++++++++++++++++++++++++ pa3/src/util.h | 27 ++ pa3/unittests/.gitignore | 1 + pa3/unittests/array_adder.asm | 55 ++++ pa3/unittests/basics.asm | 22 ++ pa3/unittests/beq_test.asm | 20 ++ pa3/unittests/blt_bge_test.asm | 28 ++ pa3/unittests/bne_test.asm | 50 +++ pa3/unittests/colliding_cache.asm | 71 +++++ pa3/unittests/correlation.asm | 100 ++++++ pa3/unittests/derivative.asm | 60 ++++ pa3/unittests/derivative_unrolled.asm | 91 ++++++ pa3/unittests/endian_reverse.asm | 31 ++ pa3/unittests/fibonacci.asm | 26 ++ pa3/unittests/jal_no_link.asm | 26 ++ pa3/unittests/jal_w_link.asm | 19 ++ pa3/unittests/jalr_test.asm | 25 ++ pa3/unittests/lw_sw_test.asm | 56 ++++ pa3/unittests/multiplier.asm | 22 ++ pa3/unittests/nested_loops.asm | 23 ++ pa3/unittests/no_dep_test.asm | 12 + pa3/unittests/twos_compliment.asm | 22 ++ pa3/unittests/wordsearch.asm | 35 +++ 34 files changed, 2201 insertions(+) create mode 100644 pa3/.DS_Store create mode 100644 pa3/Makefile create mode 100644 pa3/README.md create mode 100644 pa3/assemble_all.sh create mode 100644 pa3/src/instruction_map.h create mode 100644 pa3/src/register_map.c create mode 100644 pa3/src/register_map.h create mode 100644 pa3/src/sim_core.c create mode 100644 pa3/src/sim_core.h create mode 100644 pa3/src/sim_stages.c create mode 100644 pa3/src/sim_stages.h create mode 100644 pa3/src/util.c create mode 100644 pa3/src/util.h create mode 100644 pa3/unittests/.gitignore create mode 100644 pa3/unittests/array_adder.asm create mode 100644 pa3/unittests/basics.asm create mode 100644 pa3/unittests/beq_test.asm create mode 100644 pa3/unittests/blt_bge_test.asm create mode 100644 pa3/unittests/bne_test.asm create mode 100644 pa3/unittests/colliding_cache.asm create mode 100644 pa3/unittests/correlation.asm create mode 100644 pa3/unittests/derivative.asm create mode 100644 pa3/unittests/derivative_unrolled.asm create mode 100644 pa3/unittests/endian_reverse.asm create mode 100644 pa3/unittests/fibonacci.asm create mode 100644 pa3/unittests/jal_no_link.asm create mode 100644 pa3/unittests/jal_w_link.asm create mode 100644 pa3/unittests/jalr_test.asm create mode 100644 pa3/unittests/lw_sw_test.asm create mode 100644 pa3/unittests/multiplier.asm create mode 100644 pa3/unittests/nested_loops.asm create mode 100644 pa3/unittests/no_dep_test.asm create mode 100644 pa3/unittests/twos_compliment.asm create mode 100644 pa3/unittests/wordsearch.asm diff --git a/pa3/.DS_Store b/pa3/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5172429f264de2441865cb4700216d4256da9242 GIT binary patch literal 6148 zcmeH~J!%6%427R!7lt%jx}3%b$PET#pTHLgIFQEJ;E>dF^gR7ES*H$5cmnB-G%I%Z zD|S`@Z2$T80!#olbXV*=%*>dt@PRwdU#I)^a=X5>;#J@&VrHyNnC;iLL0pQvfVyTmjO&;ssLc!1UOG})p;=82 zR;?Ceh}WZ?+UmMqI#RP8R>OzYoz15hnq@nzF`-!xQ4j$Um=RcIKKc27r2jVm&svm< zfC&6E0=7P!4tu^-ovjbA=k?dB`g+i*aXG_}p8zI)6mRKa+;6_1_R^8c3Qa!(fk8n8 H{*=HsM+*^= literal 0 HcmV?d00001 diff --git a/pa3/Makefile b/pa3/Makefile new file mode 100644 index 0000000..295470f --- /dev/null +++ b/pa3/Makefile @@ -0,0 +1,18 @@ +SRCS = $(wildcard src/*.c) +HEADERS = $(wildcard src/*.h) +CC = gcc +CFLAGS = -g -std=c99 +LDFLAGS = -lm + +default: simulator + +simulator: $(SRCS) $(HEADERS) + @echo "Building $@..." + @echo "Sources: $(SRCS)" + @echo "Headers: $(HEADERS)" + $(CC) $(CFLAGS) -o $@ $(SRCS) $(LDFLAGS) + +clean: + -rm -f simulator + -rm -f *.txt + -rm -fr assembled_tests diff --git a/pa3/README.md b/pa3/README.md new file mode 100644 index 0000000..2f7a692 --- /dev/null +++ b/pa3/README.md @@ -0,0 +1,24 @@ +# Programming Assignment 3: Dynamic Branch Prediction & Set Associative Data Cache + +A 5-stage pipelined CPU simulator for the RISC-V based riscv-uconn instruction set architecture, including a 4-way set associative data cache and dynamic branch prediction support. The simulator translates machine code created by the riscv-uconn assembler, and executes instructions one at a time. Each instruction goes through a Fetch, Decode, Execute, Memory and Writeback stage of processing. + +## Build Instructions + $ make + +## Unit Tests +Several unit tests are provided in the `unittests` directory. These unit tests must be assembled +before use with the simulator. Ensure that the assembler is compiled (this should be done after completing PA0). +The unit tests can all be assembled by executing the following command in the `pa2` directory: + + $ ../assembler/assembler unittests/unit_test_file.asm /unit_test_file.out + +where `unit_test_file` is any of the unit test files (written in riscv-uconn assembly) in the +`unittests` directory. You may also use the provided `assemble_all.sh' script: + + $ bash assemble_all.sh + +## Usage + $ ./simulator assembled_program_file.out FORWARDING_ENABLED DATA_CACHE_ENABLED DYNAMIC_BP_ENABLED + +where `assembled_program_file.out` may be any assembled program file generated by the riscv-uconn +assembler, `FORWARDING_ENABLED`, `DATA_CACHE_ENABLED`, `DYNAMIC_BP_ENABLED` and may be 0 (disabled) or 1 (enabled), for 8 total possible combinations. \ No newline at end of file diff --git a/pa3/assemble_all.sh b/pa3/assemble_all.sh new file mode 100644 index 0000000..add48ac --- /dev/null +++ b/pa3/assemble_all.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# This script is privided to you to assemble all unit tests for you. +# 1) First ensure that that your assembler is compiled +# 2) Then, run "$ bash assemble_all.sh". +# A new directory "assembled tests will be generated, populated with all the binary tests. +# Note: "$ make clean" will remove these tests + +if [ ! -d assembled_tests ]; then + echo "Creating \"assembled_tests\" directory..." + mkdir assembled_tests +fi + +if [ ! -f ../assembler/assembler ]; then + echo "Error: Assembler is not compiled." + exit +fi + +for test in unittests/*.asm; do + echo "Assembling test \"$test\"..." + testname=$(basename $test .asm) + ../assembler/assembler $test assembled_tests/$testname.out > /dev/null 2>&1 +done +echo "Done!" \ No newline at end of file diff --git a/pa3/src/instruction_map.h b/pa3/src/instruction_map.h new file mode 100644 index 0000000..b859fca --- /dev/null +++ b/pa3/src/instruction_map.h @@ -0,0 +1,62 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +/* Some helpful defines for decoding instructions */ +#define bit_7 0x00000080 +#define bit_20 0x00100000 +#define bit_31 0x80000000 +#define bit_2_downto_0 0x00000007 +#define bit_4_downto_0 0x0000001F +#define bit_6_downto_0 0x0000007F +#define bit_10_downto_7 0x00000780 +#define bit_11_downto_7 0x00000F80 +#define bit_11_downto_8 0x00000F00 +#define bit_19_downto_12 0x000FF000 +#define bit_30_downto_21 0x7FE00000 +#define bit_30_downto_25 0x7E000000 +#define bit_31_downto_12 0xFFFFF000 +#define bit_31_downto_20 0xFFF00000 +#define bit_31_downto_25 0xFE000000 + +/* Opcode Bits */ +#define RTYPE 0x33 +#define ITYPE_ARITH 0x13 +#define ITYPE_LOAD 0x3 +#define STYPE 0x23 +#define BTYPE 0x63 +#define LUI 0x37 +#define JAL 0x6F +#define JALR 0x67 + +/* Funct3 Bits */ +/* R and I-Type Arithmetic */ +#define ADD_SUB 0b000 +#define SUB 0b000 +#define SLT 0b010 +#define SLL 0b001 +#define SRL 0b101 +#define AND 0b111 +#define OR 0b110 +#define XOR 0b100 +/* I-type JALR and Load, S-type, and B-type */ +#define LW_SW 0b010 +#define BEQ 0b000 +#define BNE 0b001 +#define BLT 0b100 +#define BGE 0b101 + +/* R-type Funct7s */ +#define ADD_F7 0x0 +#define SUB_F7 0x20 \ No newline at end of file diff --git a/pa3/src/register_map.c b/pa3/src/register_map.c new file mode 100644 index 0000000..ad53868 --- /dev/null +++ b/pa3/src/register_map.c @@ -0,0 +1,49 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#include "register_map.h" + +const char* register_map[] = { + [0] = "zero", + [1] = "ra", + [2] = "sp", + [3] = "gp", + [4] = "tp", + [5] = "t0", + [6] = "t1", + [7] = "t2", + [8] = "s0", + [9] = "s1", + [10] = "a0", + [11] = "a1", + [12] = "a2", + [13] = "a3", + [14] = "a4", + [15] = "a5", + [16] = "a6", + [17] = "a7", + [18] = "s2", + [19] = "s3", + [20] = "s4", + [21] = "s5", + [22] = "s6", + [23] = "s7", + [24] = "s8", + [25] = "s9", + [26] = "s10", + [27] = "s11", + [28] = "t3", + [29] = "t4", + [30] = "t5", + [31] = "t6", +}; \ No newline at end of file diff --git a/pa3/src/register_map.h b/pa3/src/register_map.h new file mode 100644 index 0000000..856bdb8 --- /dev/null +++ b/pa3/src/register_map.h @@ -0,0 +1,16 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +extern const char* register_map[]; \ No newline at end of file diff --git a/pa3/src/sim_core.c b/pa3/src/sim_core.c new file mode 100644 index 0000000..e2bfa32 --- /dev/null +++ b/pa3/src/sim_core.c @@ -0,0 +1,365 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#include +#include +#include + +#include "instruction_map.h" +#include "register_map.h" +#include "sim_core.h" +#include "sim_stages.h" +#include "util.h" + +/** + * Initial CPU state + */ +int registers[MAX_LENGTH] = {0}; // Registers +unsigned int pc = 0; // Program Counter (PC) register +unsigned int pc_n = 0; // Next Program Counter +int *memory = NULL; // Data & instruction memory + +/** + * Utility + */ +FILE *fptr_pt; + +/* Set the nop variable */ +const struct State nop = {.inst = 0x0000000013}; + +/* Different settings that can be enabled */ +int forwarding_enabled = 0; +int branch_prediction_enabled = 0; +int dcache_enabled = 0; + +/* Initialize pipeline state */ +struct State fetch_out, fetch_out_n; +struct State decode_out, decode_out_n; +struct State ex_out, ex_out_n; +struct State mem_out, mem_out_n; + +/* Pipeline-related initialization */ +int pipe_stall = 0; +int j_taken = 0; +int lw_in_exe = 0; +int we_exe = 0, ws_exe = 0, dout_exe = 0; +int we_mem = 0, ws_mem = 0, dout_mem = 0; +int we_wb = 0, ws_wb = 0, dout_wb = 0; + +/* Multi-cycle operation-related initialization */ +const int dmem_access_cycles = 6; +const int dcache_access_cycles = 2; +int dmem_busy = 0; +int dmem_cycles = 0; + +/* Data cache-related */ +CacheSet *dcache; +int dmem_accesses = 0; +int dcache_hits = 0; + +/* Predictor Relted */ +BranchTargetBuffer *btb; +enum PREDICTION *bht; +uint8_t bhsr; +int br_mispredicted = 0; +int total_branches = 0; +int correctly_predicted_branches = 0; + +/* Count all non-nop instructions */ +int instruction_counter = 0; + +/* Total Cycles */ +int cycle = 0; + +/* BHSR/BHT info */ +char BHSR_string[5]; +char BHT_string[3]; + +/** + * Simulator entry point + */ +int main(int argc, char *argv[]) { + if (argc != 5) { + fprintf(stderr, "[ERROR] incorrect number of arguments.\n"); + printf("usage: simulator PROGRAM_FILE FORWARDING_ENABLED DATA_CACHE_ENABLED DYNAMIC_BP_ENABLED\n"); + exit(1); + } else { + /* Open input program file */ + FILE *fp; + fp = fopen(argv[1], "r"); + + /* Enable/disable forwarding */ + sscanf(argv[2],"%d", &forwarding_enabled); + if (forwarding_enabled > 1) { + fprintf(stderr, "[ERROR] FORWARDING_ENABLED must be either 0 (disabled) or 1 (enabled).\n"); + exit(1); + } + printf("Pipeline Forwarding: %s\n", forwarding_enabled ? "Enabled" : "Disabled"); + + /* Enable/disable data cache */ + sscanf(argv[3], "%d", &dcache_enabled); + if (dcache_enabled > 1) { + fprintf(stderr, "[ERROR] DATA_CACHE_ENABLED must be either 0 (disabled) or 1 (enabled).\n"); + exit(1); + } + printf("Data Cache: %s\n", dcache_enabled ? "Enabled" : "Disabled"); + + /* Enable/disable data cache */ + sscanf(argv[4], "%d", &branch_prediction_enabled); + if (branch_prediction_enabled > 1) { + fprintf(stderr, "[ERROR] DYNAMIC_BP_ENABLED must be either 0 (disabled) or 1 (enabled).\n"); + exit(1); + } + printf("Dynamic Branch Prediction: %s\n", branch_prediction_enabled ? "Enabled" : "Disabled"); + + /* Open pipe trace */ + if (pipe_trace) { + fptr_pt = fopen("pipe_trace.txt", "w"); + } + + /* Initialize registers and instruction/data memory */ + initialize(fp); + + puts("\n"); + printf("Simulating...\n"); + + /* Process instructions one at a time */ + process_instructions(); + + puts(""); + + /* Output state after termination */ + rdump(); // Register dump + mdump(); // Memory dump + cdump(); // Data cache dump + bdump(); // Branch prediction dump + + /* Cleanup */ + free(memory); + fclose(fp); + if (pipe_trace) { + fclose(fptr_pt); + } + + return 0; + } +} + +void process_instructions() { + int terminate = 0; + unsigned int committed_inst; + while (terminate != 1) { + + /* Update pipeline state */ + committed_inst = writeback(mem_out); + mem_out_n = memory_stage(ex_out); + ex_out_n = execute(decode_out); + decode_out_n = decode(fetch_out); + fetch_out_n = fetch(); + + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle %d, PC %d, Next PC %d\n", cycle, pc, pc_n); + inst_dump("[Fetch]", fetch_out_n.inst); + inst_dump("[Decode]", decode_out_n.inst); + inst_dump("[Execute]", ex_out_n.inst); + inst_dump("[Memory]", mem_out_n.inst); + inst_dump("[Writeback]", committed_inst); + if (branch_prediction_enabled){ + getBin(bhsr, BHSR_string, 4); + getBin(bht[bhsr], BHT_string, 2); + fprintf(fptr_pt, "\n[BHSR] --> [State]\n[%s] --> [%s]", BHSR_string, BHT_string); + } + + fprintf(fptr_pt, "\n"); + rdump_pt(); + fprintf(fptr_pt, "\n"); + fprintf(fptr_pt, "=================================================================================================================================\n"); + fprintf(fptr_pt, "\n"); + } + + if (debug) { + fprintf(stderr, "[DEBUG] Cycle: %d, Instruction Memory Address: %d, Instruction: 0x%08x\n", cycle, pc / 4, fetch_out_n.inst); + } + + if (debug) { + fprintf(stderr, "[DEBUG] Cycle: %d, Committed Instruction: 0x%08x\n", cycle, committed_inst); + } + + if (registers[0] != 0) { + terminate = 1; // set terminate flag when $zero is updated + } + + /* Update state for next cycle */ + update_simulator_state(); + + if (cycle == 25000) { + fprintf(stderr, "\n[WARNING] Simulation has simulated 25,000 cycles without terminating. Something might be wrong. Terminating.\n"); + exit(1); + } + } + + float dcache_hitrate = 0, br_correct_predictions = 0; + + if (dmem_accesses){ + dcache_hitrate = ((float)dcache_hits/(float)dmem_accesses)*100; + } + + if (total_branches){ + br_correct_predictions = ((float)correctly_predicted_branches/(float)total_branches)*100; + } + + printf("\nFinished simulation!\n"); + printf("\nTOTAL INSTRUCTIONS COMMITTED: %d\n", instruction_counter); + printf("TOTAL CYCLES SIMULATED: %d\n", cycle); + printf("AVERAGE CPI: %0.3f\n\n", (double)cycle/(double)instruction_counter); + + printf("TOTAL CONDITIONAL BRANCHES: %d\n", total_branches); + printf("BRANCHES CORRECTLY PREDICTED: %d\n", correctly_predicted_branches); + printf("BRANCH PREDICTION ACCURACY: %.2f%%\n\n", br_correct_predictions); + + printf("TOTAL MEMORY ACCESSES: %d\n", dmem_accesses); + printf("CACHE HITS: %d\n", dcache_hits); + printf("CACHE HIT RATE: %.2f%%\n", dcache_hitrate); +} + +void initialize(FILE *fp) { + printf("======================================\n"); + printf("=== BEGIN SIMULATOR INITIALIZATION ===\n"); + printf("======================================\n"); + if (fp == NULL) { + fprintf(stderr, "[ERROR] opening input file. Aborting.\n"); + exit(1); + } + + /* Initialize the starting states */ + fetch_out = nop; + decode_out = nop; + ex_out = nop; + mem_out = nop; + + /* Zero initialize registers */ + memset(registers, 0, sizeof(registers)); + printf("Initialized Registers\n"); + puts(""); + + /* Allocate instruction and data memory */ + memory = (int*) malloc(16384 * sizeof(int)); + if (memory == NULL) { + fprintf(stderr, "[ERROR] not enough memory for data memory. Aborting.\n"); + exit(1); + } + + /* Initialize instruction memory to "nop" -1 */ + for (int i = 0; i < 256; i++) { + memory[i] = nop.inst; + } + + /* Initialize data memory to "nop" -1 */ + for (int i = 256; i < 16384; i++) { + memory[i] = -1; + } + + printf("Initialized Memory\n"); + puts(""); + + /* Allocate data cache */ + dcache = (CacheSet*) calloc(DCACHE_NUM_SETS, sizeof(CacheSet)); + + if (dcache == NULL) { + fprintf(stderr, "[ERROR] not enough memory for cache. Aborting.\n"); + exit(1); + } + printf("Initialized Data Cache\n"); + puts(""); + + /* Allocate and zero-initialize target buffer */ + btb = (BranchTargetBuffer *) calloc(BTB_SIZE, sizeof(BranchTargetBuffer)); + bht = (enum PREDICTION *) calloc(BHT_SIZE, sizeof(enum PREDICTION)); + + /* Initialize the BHT */ + for (int i = 0; i < BHT_SIZE; i++){ + bht[i] = NT; + } + + bhsr = 0; + if (btb == NULL || bht == NULL){ + fprintf(stderr, "[ERROR] not enough memory for dynamic branch prediction. Aborting.\n"); + exit(1); + } + printf("Initialized BTB, BHT, and BHSR.\n"); + puts(""); + + printf("----------------------\n"); + printf("--- Section: .text ---\n"); + printf("----------------------\n"); + + /* Initialize parsing variables */ + char line[MAX_LENGTH + 2]; + char *p; + int i = 0, line_num = 0; + + /* Copy .text section to memory, break 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); + + /* If 'nop' found, move to 0x8000 / 2048 in memory and break */ + if (strcmp(line, "11111111111111111111111111111111") == 0) { + memory[i] = nop.inst; + i = 256; //Data Memory Starts at 256 + break; + } else { + printf("memory[%d] = 0x%08x\n", i, memory[i]); + i++; + } + } + int j; + for (j = i; j < 16384; j++) { + memory[j] = 0; + } + + puts(""); + + printf("----------------------\n"); + printf("--- Section: .data ---\n"); + printf("----------------------\n"); + + /* 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("memory[%d] = 0x%08x\n", i, memory[i]); + i++; + } + + printf("====================================\n"); + printf("=== END SIMULATOR INITIALIZATION ===\n"); + printf("===================================="); +} diff --git a/pa3/src/sim_core.h b/pa3/src/sim_core.h new file mode 100644 index 0000000..9737e33 --- /dev/null +++ b/pa3/src/sim_core.h @@ -0,0 +1,156 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +#include +#include + +extern FILE *fptr_pt; + +/* Max number of registers, and instruction length in bits */ +#define MAX_LENGTH 32 + +/* Number of cache blocks per set */ +#define DCACHE_NUM_BLOCKS 4 + +/* Number of 4-byte data words in a block */ +#define DCACHE_BLOCK_SIZE 4 + +/* Number of cache sets ( 256 total bytes / (4 blocks per set * 16 bytes per block) ) */ +#define DCACHE_NUM_SETS 4 + +/* Size of the BTB */ +#define BTB_SIZE 32 + +/* Size of the BHSR (in bits) */ +#define BHSR_SIZE 4 + +/* Size of the BHT */ +#define BHT_SIZE 16 + +/* Array of registers (register file) */ +extern int registers[MAX_LENGTH]; + +/* Clock cycle */ +extern int cycle; + +/* Program Counter (PC) register */ +extern unsigned int pc; // Current PC +extern unsigned int pc_n; // Next PC + +/* Microarchitechtual state */ +extern struct State fetch_out, fetch_out_n; +extern struct State decode_out, decode_out_n; +extern struct State ex_out, ex_out_n; +extern struct State mem_out, mem_out_n; + +/* nop instruction, used when flushing the pipeline */ +extern const struct State nop; + +/* Instruction and data memory */ +extern int *memory; + +/* Instruction and cycle counters */ +extern int instruction_counter; +extern int cycle; + +/* CPU state */ +struct State { + /* Fetched instruction */ + unsigned int inst; + unsigned int inst_addr; + + /* Decoded instruction fields */ + unsigned int opcode; + unsigned int funct3; + unsigned int funct7; + unsigned int rd; + unsigned int rs1; + unsigned int rs2; + unsigned int imm; + + /* Memory related */ + unsigned int mem_buffer; + + /* Branch Related */ + unsigned int br_addr; + unsigned int link_addr; + unsigned int br_predicted; /* **NEW** from PA1 / PA2 */ + + /* ALU */ + unsigned int alu_in1; + unsigned int alu_in2; + unsigned int alu_out; +}; + + +/* Pipeline related */ +extern int forwarding_enabled; +extern int pipe_stall; +extern int j_taken; +extern int br_mispredicted; +extern int lw_in_exe; +extern int we_exe, ws_exe, dout_exe; +extern int we_mem, ws_mem, dout_mem; +extern int we_wb, ws_wb, dout_wb; + +/* Multi-cycle operation-related */ +extern const int dmem_access_cycles; +extern const int dcache_access_cycles; +extern int dmem_busy; +extern int dmem_cycles; + +/* Data Cache-related */ +extern int dcache_enabled; +extern int dmem_accesses; +extern int dcache_hits; + +/* BTB Stats-related */ +extern int branch_prediction_enabled; +extern int total_branches; +extern int correctly_predicted_branches; + +/* BHT States for two-bit prediction */ +/* Encoding is N = '00', NT = '01', TN = '10', T = '11'*/ +enum PREDICTION {N, NT, TN, T}; + +/* Structure that defines the cache block */ +typedef struct { + unsigned int tag; + unsigned int valid; +} CacheBlock; + +/* Structure that defines the cache set */ +typedef struct { + CacheBlock block[DCACHE_NUM_BLOCKS]; + uint8_t lru_tree; +} CacheSet; + +/* Structure of the branch predictor */ +typedef struct { + unsigned int inst_addr; + unsigned int branch_target; + unsigned int valid; +} BranchTargetBuffer; + +/* Allocate memory for the BTB, BHT, and BHSR */ +extern BranchTargetBuffer *btb; +extern enum PREDICTION *bht; +extern uint8_t bhsr; + +/* Allocate memory for the Data Cache*/ +extern CacheSet *dcache; + +void initialize(FILE *fp); +void process_instructions(); \ No newline at end of file diff --git a/pa3/src/sim_stages.c b/pa3/src/sim_stages.c new file mode 100644 index 0000000..e6f1349 --- /dev/null +++ b/pa3/src/sim_stages.c @@ -0,0 +1,197 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * TODO: YOUR NAME HERE + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: sim_stages.c + * + */ +#include +#include +#include +#include + +#include "instruction_map.h" +#include "sim_core.h" +#include "sim_stages.h" + +/** + * Debug flags + */ +int debug = 0; /* Set to 1 for additional debugging information. */ +int pipe_trace = 1; /* Set to 1 for pipe trace. */ +int pipe_trace_mode = 3; /* See PA1 handout, section 5 for usage */ + +/** + * Fetch stage implementation. + */ +struct State fetch(void) { + /* Use the current PC to store i) The instruction ii) The instruction address */ + struct State fetch_out = {0}; + fetch_out.inst = memory[pc / 4]; + fetch_out.inst_addr = pc; + + /* Pipeline must be flushed */ + if (0) { + return nop; + } + + /* Pipeline is stalled */ + else if (0){ + return fetch_out; + } + + /** TODO: Your branch prediction implementation here **/ + + /* Return the instruction */ + return fetch_out; +} + +/** + * Decode stage implementation + */ +struct State decode(struct State fetch_out) { + + /** TODO: Insert your logic for the decode stage **/ + + return fetch_out; +} + +/** + * Execute stage implementation + */ +struct State execute(struct State decode_out) { + + /** TODO: Insert your logic for the execute stage **/ + + return decode_out; +} + +/** + * Memory stage implementation + */ +struct State memory_stage(struct State ex_out) { + + /** TODO: Insert your logic for the memory stage **/ + + return ex_out; +} + +/** + * Writeback stage implementation + */ +unsigned int writeback(struct State mem_out) { + + /** TODO: Insert your logic for the execute stage **/ + + return mem_out.inst; +} + +/*******************************/ +/* BRANCH PREDICTION FUNCTIONS */ +/*******************************/ + +/** + * Branch target buffer hit lookup: +*/ +unsigned int BTB_lookup(unsigned int inst_addr){ + + /** TODO: Your implementation for the BTB_lookup() function here **/ + +} + +/** + * Branch target buffer target address lookup +*/ +unsigned int BTB_target(unsigned int inst_addr){ + + /** TODO: Your implementation of the BTB_target() function here **/ + +} + +/** + * Branch target buffer entry update + */ +void BTB_update(unsigned int inst_addr, unsigned int branch_target){ + + /** TODO: Your implementation of the BTB_update() function here **/ + +} + +/** + * BHT predictor lookup +*/ +unsigned int predict_direction(void){ + + /** TODO: Your implementation of the predict_direction() function here **/ + +} + +/** + * BHT and BHSR update +*/ +void direction_update(unsigned int direction){ + + /** TODO: Your implementation of the direction_update() function here **/ + +} + +/************************/ +/* DATA CACHE FUNCTIONS */ +/************************/ + +/** + * Data cache lookup + */ +unsigned int dcache_lookup(unsigned int addr_mem) { + + /** TODO: Your implementation of dcache_lookup() here **/ + +} + +/** + * Data cache update + */ +void dcache_update(unsigned int addr_mem) { + + /** TODO: Your implementation of the dcache_update() function here **/ + +} + +/** + * Advance PC. + * DO NOT MODIFY. + */ +void advance_pc(int step) { + pc_n = pc + step; +} + +/** + * Update the states of the simulator. + * DO NOT MODIFY. + */ +void update_simulator_state() { + + /* Stall every stage and overwrite memory for correct pipe trace */ + if (dmem_busy) { + mem_out = nop; + + /* Hold the old values of pc and fetch_out. */ + /* Inject NOP into decode_out, allow following stages to proceed. */ + }else if (pipe_stall) { + decode_out = nop; + ex_out = ex_out_n; + mem_out = mem_out_n; + + /* No stalls, so advance every stage down the pipeline */ + }else { + pc = pc_n; + fetch_out = fetch_out_n; + decode_out = decode_out_n; + ex_out = ex_out_n; + mem_out = mem_out_n; + } +} diff --git a/pa3/src/sim_stages.h b/pa3/src/sim_stages.h new file mode 100644 index 0000000..da2a76b --- /dev/null +++ b/pa3/src/sim_stages.h @@ -0,0 +1,42 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +#include "sim_core.h" + +extern int debug; +extern int pipe_trace; +extern int pipe_trace_mode; + +struct State fetch(void); +struct State decode(struct State fetch_out); +struct State execute(struct State decode_out); +struct State memory_stage(struct State alu_out); +unsigned int writeback(struct State memory_out); + + +/* Related to branch prediction */ +unsigned int BTB_lookup(unsigned int inst_addr); +unsigned int BTB_target(unsigned int inst_addr); +unsigned int predict_direction(void); +void BTB_update(unsigned int inst_addr, unsigned int branch_target); +void direction_update(unsigned int direction); + +/* Related to data caching */ +unsigned int dcache_lookup(unsigned int addr_mem); +void dcache_update(unsigned int addr_mem); + +/* Related to simulator loop */ +void update_simulator_state(void); +void advance_pc(int step); \ No newline at end of file diff --git a/pa3/src/util.c b/pa3/src/util.c new file mode 100644 index 0000000..fc76ae7 --- /dev/null +++ b/pa3/src/util.c @@ -0,0 +1,426 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#include +#include +#include +#include +#include + +#include "instruction_map.h" +#include "register_map.h" +#include "sim_stages.h" +#include "sim_core.h" +#include "util.h" + +/** + * Dump register contents. + * Will format for desired number of columns and output in specified file. + */ +void rdump_file_columns(FILE* file, unsigned columns) { + static const unsigned int index_col_width = 4; + static const unsigned int name_col_width = 5; + static const unsigned int value_col_width = 8; + static const unsigned int tab_spaces = 4; + static const unsigned int col_sep = 2; + + assert(columns > 0); + + /* Calculate number of rows and total row length*/ + const unsigned int rows = (int)ceil((double) MAX_LENGTH / columns); + const unsigned int row_length = columns * (index_col_width + name_col_width + value_col_width + 2 + 2 * tab_spaces) + (columns - 1) * (col_sep * tab_spaces); + + /* Print header */ + fprintf(file, "---------------------\n"); + fprintf(file, "--- Register Dump ---\n"); + fprintf(file, "---------------------\n"); + for (int col = 0; col < columns; col++) { + fprintf(file, "%-*s%-*s%-*s", index_col_width + tab_spaces, "Index", name_col_width + tab_spaces, "Name", value_col_width + 2, "Value"); + if (col == columns - 1) { + fprintf(file, "\n"); + } else { + fprintf(file, "%*s", col_sep * tab_spaces, ""); + } + } + for (int col = 0; col < columns; col++) { + fprintf(file, "%-*s%-*s%-*s", index_col_width + tab_spaces, "-----", name_col_width + tab_spaces, "----", value_col_width + 2, "-----"); + if (col == columns - 1) { + fprintf(file, "\n"); + } else { + fprintf(file, "%*s", col_sep * tab_spaces, ""); + } + } + + /* Print rows */ + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + unsigned int i = row + col * rows; + + if (i < MAX_LENGTH) { + fprintf(file, "x%-*i%*s%-*s%*s 0x%0*X", index_col_width, i, tab_spaces - 1, "", name_col_width, register_map[i], tab_spaces - 1, "", value_col_width, registers[i]); + } else { + fprintf(file, "\n"); + break; + } + + if (col == columns - 1) { + fprintf(file, "\n"); + } else { + fprintf(file, "%*s", col_sep * tab_spaces, ""); + } + } + } + fprintf(file, "%-*s%*s%-*s%*s0x%08X\n", index_col_width, "N/A", tab_spaces, "", name_col_width, "pc", tab_spaces, "", pc); +} + +void rdump_pt() { + rdump_file_columns(fptr_pt, 4); +} + +void rdump() { + rdump_file_columns(stdout, 4); +} + +/** + * Dump memory contents. + */ +void mdump() { + FILE* fptr; + fptr = fopen("mdump.txt", "w"); + int i = 0; + for (i = 0; i < 16384; i++) { + fprintf(fptr, "Memory[%d] = 0x%08X\n", i, memory[i]); + } + fclose(fptr); +} + + +/** + * Print cache information + */ +void cdump() { + FILE *fptr; + fptr = fopen("cdump.txt","w"); + + /* Create the set # headers*/ + fprintf(fptr, "%23s", ""); + for (int i = 0; i < DCACHE_NUM_BLOCKS; i++){ + fprintf(fptr, "%9s %d ", "Block", i); + } + fprintf(fptr, "\n"); + + /* Create the cache line headers*/ + fprintf(fptr, "%s %s ", "Set No.","LRU b2|b1|b0"); + for (int i = 0; i < DCACHE_NUM_BLOCKS; i++){ + fprintf(fptr, "%s %s ","Valid","Tag"); + } + fprintf(fptr, "\n"); + + /* Formatting */ + fprintf(fptr, "%s", "------- ------------ "); + for (int i = 0; i < DCACHE_NUM_BLOCKS; i++){ + fprintf(fptr, "%s","----- --- "); + } + fprintf(fptr, "\n"); + + /* Print the relevent data*/ + char lru_s[4]; + for (int i = 0; i < DCACHE_NUM_SETS; i++){ + getBin(dcache[i].lru_tree, lru_s, 3); + fprintf(fptr, "%7d %c %c %c ", i, lru_s[0], lru_s[1], lru_s[2]); + for (int j = 0; j < DCACHE_NUM_BLOCKS; j++){ + fprintf(fptr, "%5d %3d ", dcache[i].block[j].valid, dcache[i].block[j].tag); + } + fprintf(fptr, "\n"); + } + fclose(fptr); +} + +/** + * Print Branch Information + */ +void bdump(){ + FILE *fptr; + fptr = fopen("bdump.txt", "w"); + fprintf(fptr, "%s\n%s %s %s %s %s\n%s\n", + "**** Branch Target Buffer Info ****", + "Index","Inst Type","Address","Target Address","Valid", + "----- --------- ------- -------------- -----"); + for (int i = 0; i < BTB_SIZE; i++){ + int instruction = memory[btb[i].inst_addr/4]; + char inst_type[8]; + if (btb[i].valid){ + unsigned f3 = (instruction >> 12) & 0x7; + switch(f3){ + case 0b000: + strcpy(inst_type, "beq"); + break; + case 0b001: + strcpy(inst_type, "bne"); + break; + case 0b100: + strcpy(inst_type, "blt"); + break; + case 0b101: + strcpy(inst_type, "bge"); + break; + } + }else{ + strcpy(inst_type, ""); + } + fprintf(fptr, "%5d %9s %7d %14d %5d\n", + i, inst_type, btb[i].inst_addr, btb[i].branch_target, btb[i].valid); + } + fprintf(fptr, "\n\n%s\n%s %s\n%s\n", + "**** Branch History Info ****", + "Bit Pattern","Predictor State", + "----------- ---------------"); + char pattern_buff[5], state_buff[3]; + for (int i = 0; i < BHT_SIZE; i++){ + getBin(i, pattern_buff, 4); + getBin(bht[i], state_buff, 2); + fprintf(fptr, "%11s %15s\n", + pattern_buff, state_buff); + } + fclose(fptr); +} + +/** + * Print intructions +*/ +void inst_dump(const char stage[], const unsigned int inst) { + int op = inst & 0x7F; + int funct3 = (inst >> 12) & 0x7; + int funct7 = (inst >> 25) & 0x7F; + int rd = (inst >> 7) & 0x1F; + int rs1 = (inst >> 15) & 0x1F; + int rs2 = (inst >> 20) & 0x1F; + char rds[5], rs1s[5], rs2s[5]; + int show_name = pipe_trace_mode & 0b01; + int show_dec = ((pipe_trace_mode & 0b10) >> 1); + + if (show_name){ + sprintf(rds, "%s", register_map[rd]); + sprintf(rs1s, "%s", register_map[rs1]); + sprintf(rs2s, "%s", register_map[rs2]); + }else{ + sprintf(rds, "x%d", rd); + sprintf(rs1s, "x%d", rs1); + sprintf(rs2s, "x%d", rs2); + } + + char istring[6]; + getInstStr(op, funct3, funct7, istring); + int iimm = (signed)(inst & 0xFFF00000) >> 20; + int simm = ((signed)(inst & 0xFE000000) >> 20) | + ( (inst & 0x00000F80) >> 7); + int bimm = ((signed)(inst & 0x80000000) >> 19) | + ( (inst & 0x7E000000) >> 20) | + ( (inst & 0x00000F00) >> 7) | + ( (inst & 0x00000080) << 4); + int uimm = (inst & 0xFFFFF000) >> 12; + int jimm = ((signed)(inst & 0x80000000) >> 11) | + ( (inst & 0x7FE00000) >> 20) | + ( (inst & 0x00100000) >> 9) | + ( (inst & 0x000FF000)); + + char iimms[32], simms[32], bimms[32], uimms[32], jimms[32]; + if (show_dec){ + sprintf(iimms, "%d", iimm); + sprintf(simms, "%d", simm); + sprintf(bimms, "%d", bimm); + sprintf(uimms, "%d", uimm); + sprintf(jimms, "%d", jimm); + }else{ + sprintf(iimms, "0x%X", (unsigned)iimm); + sprintf(simms, "0x%X", (unsigned)simm); + sprintf(bimms, "0x%X", (unsigned)bimm); + sprintf(uimms, "0x%X", (unsigned)uimm); + sprintf(jimms, "0x%X", (unsigned)jimm); + } + + fprintf(fptr_pt, "%-12s ", stage); + + switch (op) { + case 0b0110011: + fprintf(fptr_pt, "%-4s %s, %s, %s\n", istring, rds, rs1s, rs2s); + break; + + case 0b1100111: + iimm &= ~0b1; + case 0b0010011: + fprintf(fptr_pt, "%-4s %s, %s, %s\n", istring, rds, rs1s, iimms); + break; + + case 0b0100011: + fprintf(fptr_pt, "%-4s %s, %s(%s)\n", istring, rs2s, simms, rs1s); + break; + + case 0b0000011: + fprintf(fptr_pt, "%-4s %s, %s(%s)\n", istring, rds, iimms, rs1s); + break; + + case 0b1100011: + fprintf(fptr_pt, "%-4s %s, %s, %s\n", istring, rs1s, rs2s, bimms); + break; + + case 0b0110111: + fprintf(fptr_pt, "%-4s %s, %s\n", istring, rds, uimms); + break; + + case 0b1101111: + fprintf(fptr_pt, "%-4s %s, %s\n", istring, rds, jimms); + break; + + default: + fprintf(fptr_pt, "INVALID INSTRUCTION\n"); + break; + } +} + +void getInstStr(int op, int f3, int f7, char *buffer){ + switch(op){ + case 0b0110011: + switch(f3){ + case 0b000: + if (f7) strcpy(buffer, "sub"); else strcpy(buffer, "add"); + break; + case 0b001: + strcpy(buffer, "sll"); + break; + case 0b101: + strcpy(buffer, "srl"); + break; + case 0b111: + strcpy(buffer, "and"); + break; + case 0b110: + strcpy(buffer, "or"); + break; + case 0b100: + strcpy(buffer, "xor"); + break; + case 0b010: + strcpy(buffer, "slt"); + break; + } + break; + case 0b0010011: + switch(f3){ + case 0b000: + strcpy(buffer, "addi"); + break; + case 0b010: + strcpy(buffer, "slti"); + break; + case 0b111: + strcpy(buffer, "andi"); + break; + case 0b110: + strcpy(buffer, "ori"); + break; + case 0b100: + strcpy(buffer, "xori"); + break; + case 0b001: + strcpy(buffer, "slli"); + break; + case 0b101: + strcpy(buffer, "srli"); + break; + } + break; + + case 0b1100111: + strcpy(buffer, "jalr"); + break; + + case 0b0000011: + strcpy(buffer, "lw"); + break; + + case 0b1100011: + switch(f3){ + case 0b000: + strcpy(buffer, "beq"); + break; + case 0b001: + strcpy(buffer, "bne"); + break; + case 0b100: + strcpy(buffer, "blt"); + break; + case 0b101: + strcpy(buffer, "bge"); + break; + } + break; + + case 0b100011: + strcpy(buffer, "sw"); + break; + + case 0b1101111: + strcpy(buffer, "jal"); + break; + + case 0b0110111: + strcpy(buffer, "lui"); + break; + + default: + break; + } +} + + +/** + * Convert a decimal string to binary + */ +void getBin(int num, char *str, int size) { + int n = num; + char *lsb = str; + for (int i = 0; i < size; i++){ + if (n & 1) lsb[size-i-1] = '1'; else lsb[size-i-1] = '0'; + n >>= 1; + } + str[size] = '\0'; +} + +/** + * Convert a binary string to an integer + */ +int getDec(char *bin) { + int b, k, m, n; + int len, sum = 0; + + len = strlen(bin) - 1; + + /* Iterate over 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; +} \ No newline at end of file diff --git a/pa3/src/util.h b/pa3/src/util.h new file mode 100644 index 0000000..3bf14a5 --- /dev/null +++ b/pa3/src/util.h @@ -0,0 +1,27 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 3: Dynamic Branch Prediction & Set Associative Cache + * + * riscy-uconn: instruction_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +#include + +void rdump_file_columns(FILE* file, unsigned columns); +void rdump(); +void rdump_pt(); +void mdump(); +void cdump(); +void bdump(); +void inst_dump(const char stage[], const unsigned int inst); +void getInstStr(int op, int f3, int f7, char *buffer); +int getDec(char *bin); +void getBin(int num, char *str, int size); \ No newline at end of file diff --git a/pa3/unittests/.gitignore b/pa3/unittests/.gitignore new file mode 100644 index 0000000..e2e7327 --- /dev/null +++ b/pa3/unittests/.gitignore @@ -0,0 +1 @@ +/out diff --git a/pa3/unittests/array_adder.asm b/pa3/unittests/array_adder.asm new file mode 100644 index 0000000..e1dfd25 --- /dev/null +++ b/pa3/unittests/array_adder.asm @@ -0,0 +1,55 @@ +.text +addi s9, zero, 10 +loop: +lw s2, 257(s1) #s2 = mem[257 + s1] +lw s3, 273(s1) #s3 = mem[273 + s1] +addi s1, s1, 1 #s1++ +lw s4, 257(s1) #s4 = mem[257 + s1] +lw s5, 273(s1) #s5 = mem[273 + s1] +addi s1, s1, 1 #s1++ + +add s6, s2, s3 #s6 = 20, 60, 100, 140, 180 +add s7, s4, s5 #s7 = 40, 80, 120, 160, 200 + +sw s6, 256(s8) +addi s8, s8, 1 +sw s7, 256(s8) +addi s8, s8, 1 +bne s1, s9, loop + +addi zero, zero, 1 + +.data +256: .word 10 +257: .word 10 +258: .word 20 +259: .word 30 +260: .word 40 +261: .word 50 +262: .word 60 +263: .word 70 +264: .word 80 +266 .word 90 +267: .word 100 +268: .word 3 +269: .word 3 +270: .word 3 +271: .word 3 +272: .word +273: .word 11 +274: .word 10 +275: .word 20 +276: .word 30 +277: .word 40 +278: .word 50 +279: .word 60 +280: .word 70 +281: .word 80 +282: .word 90 +283: .word 100 +284: .word 3 +285: .word 3 +286: .word 3 +287: .word 3 +288: .word 3 +289: .word 5 \ No newline at end of file diff --git a/pa3/unittests/basics.asm b/pa3/unittests/basics.asm new file mode 100644 index 0000000..76a9192 --- /dev/null +++ b/pa3/unittests/basics.asm @@ -0,0 +1,22 @@ +.text +addi s0, zero, 0x123 # set s0 = 0x123 +addi s1, zero, 0x456 # set s1 = 0x456 + +# Test some basic R-Type / I-Type instructions +add s2, s0, s1 # s2 = 0x579 +sub s3, s1, s0 # s3 = 0x333 +or s4, s3, s2 # s4 = 0x77B +srli s5, s4, 1 # s5 = 0x3BD +and s6, s5, s4 # s6 = 0x339 +xor s7, s3, s0 # s7 = 0x210 +slli s8, s7, 3 # s8 = 0x1080 +xori s9, s3, 0xFFF # s9 = 0xFFFFFCCC +slt s10, s3, s6 # s10 = 1 +sll t0, s0, s10 # t0 = 0x246 +srl t1, s1, s10 # t1 = 0x22B +addi zero, zero, 1 # detect this change and quit simulator + +.data +256: .word 4302 +257: .word 5402 +258: .word 5302 \ No newline at end of file diff --git a/pa3/unittests/beq_test.asm b/pa3/unittests/beq_test.asm new file mode 100644 index 0000000..800a977 --- /dev/null +++ b/pa3/unittests/beq_test.asm @@ -0,0 +1,20 @@ +.text +addi s0, zero, 1 # set s0 = 0 +addi s1, zero, 0x8 # set s1 = 0b1000 +add s2, zero, zero # set s2 = 0 (shift counter) + +loop: +beq s0, s1, end # if s0 = s1, branch to end label +slli s0, s0, 1 # shift s0 left by 1 (s0 = s0 << 1) +addi s2, s2, 1 # increment shift counter +beq zero, zero, loop # branch to label loop -- always branches + +end: +sw s2, 256(zero) # store shift counter in memory +sw s0, 257(zero) # store final s0 value in memory +addi zero, zero, 1 # detect this change and quit simulator + +.data +256: .word 10 +257: .word 32 +258: .word 2 \ No newline at end of file diff --git a/pa3/unittests/blt_bge_test.asm b/pa3/unittests/blt_bge_test.asm new file mode 100644 index 0000000..cff7a7b --- /dev/null +++ b/pa3/unittests/blt_bge_test.asm @@ -0,0 +1,28 @@ +.text +add s0, zero, zero # set s0 = 0 +addi s1, zero, 5 # set s1 = 5 + +addloop: +addi s0, s0, 1 # s0++ +blt s0, s1, addloop # loop if s0 < s1 + +#swap s0 and s1 +add s10, s0, zero # move value of s0 to s10 +add s0, s0, s1 # s0 = s0 + s1 = 5 + 5 = 10 +sub s1, s0, s1 # s1 = s0 - s1 = 10 - 5 = 5 + +subloop: +addi s0, s0, -1 # s0-- +bge s0, s1, subloop # loop if s0 >= s1 + +add s11, s0, zero # move value of s0 to s11 + +end: +sw s10, 256(zero) # store first value of s0 in memory +sw s11, 257(zero) # store final s0 value in memory +addi zero, zero, 1 # detect this change and quit simulator + +.data +256: .word 10 +257: .word 32 +258: .word 2 \ No newline at end of file diff --git a/pa3/unittests/bne_test.asm b/pa3/unittests/bne_test.asm new file mode 100644 index 0000000..4a7d0b2 --- /dev/null +++ b/pa3/unittests/bne_test.asm @@ -0,0 +1,50 @@ +.text +lui s0, 0x8000 # set s0 = 0x08000000 +addi s1, zero, 0xFFF # set s1 = 0xFFFFFFFF +addi s11, zero, 1 # set s1 = 1 (constant) +add s2, zero, zero # set s2 = 0 (shift counter) + +loop: +slt t0, s1, s0 # set t0 = s0 < s1 +bne t0, zero, end # branch to end if t0 = zero (if previous condition is false) +srli s1, s1, 1 # shift s1 right by 1 (s1 = s1 >> 1) +addi s2, s2, 1 # increment shift counter +bne zero, s11, loop # branch to label loop -- always branches + +end: +sw s2, 256(zero) # store shift counter in memory +sw s0, 257(zero) # store final s0 value in memory +addi zero, zero, 1 # detect this change and quit simulator + +.data +256: .word 8 +257: .word 22 +258: .word 42 +259: .word 68 +260: .word 100 +261: .word 138 +262: .word 182 +263: .word 232 +264: .word 288 +265: .word 350 +266: .word 418 +267: .word 492 +268: .word 572 +269: .word 658 +270: .word 750 +271: .word 848 +272: .word 952 +273: .word 1062 +274: .word 1178 +275: .word 1300 +276: .word 1428 +277: .word 1562 +278: .word 1702 +279: .word 1848 +280: .word 2000 +281: .word 2158 +282: .word 2322 +283: .word 2492 +284: .word 2668 +285: .word 2850 +286: .word 3038 \ No newline at end of file diff --git a/pa3/unittests/colliding_cache.asm b/pa3/unittests/colliding_cache.asm new file mode 100644 index 0000000..03686ef --- /dev/null +++ b/pa3/unittests/colliding_cache.asm @@ -0,0 +1,71 @@ +# Testing 4-way SA pseudo-LRU replacement policy + +.text +addi s0, zero, 16 # Distance between addresses to access +add s1, zero, zero # Offset from starting data address + +# Load first data block from memory (starting address = 0x100000000) -> cold miss +lw s2, 256(s1) +lw s3, 257(s1) +lw s4, 258(s1) +lw s5, 259(s1) + +# Increment sw address +add s1, s1, s0 + +# Store data block in memory (starting address = 0x100010000) -> cold miss +sw s2, 256(s1) +sw s3, 257(s1) +sw s4, 258(s1) +sw s5, 259(s1) + +# Increment sw address +add s1, s1, s0 + +# Store data block in memory in reverse order (starting address = 0x100100000) -> cold miss +sw s5, 256(s1) +sw s4, 257(s1) +sw s3, 258(s1) +sw s2, 259(s1) + +# Increment sw address +add s1, s1, s0 + +# Load the original data block to different registers (starting address = 0x100000000) -> cache hit! +lw s6, 256(zero) +lw s7, 257(zero) +lw s8, 258(zero) +lw s9, 259(zero) + +# Store the data block in shuffled order (starting address = 0x100110000) -> cold miss +sw s8, 256(s1) +sw s9, 257(s1) +sw s6, 258(s1) +sw s7, 259(s1) + +# Increment sw address +add s1, s1, s0 + +# Operate on the data before storing it in memory (starting address = 0x101000000) -> conflict miss +add t0, s2, s9 +add t1, s3, s8 +add t2, s4, s7 +add t3, s5, s6 +sw t0, 256(s1) +sw t1, 257(s1) +sw t2, 258(s1) +sw t3, 259(s1) + +# Load circular shifted from original addr (starting address = 0x100000000) -> ...miss? ...hit? +lw s5, 256(zero) +lw s2, 257(zero) +lw s3, 258(zero) +lw s4, 259(zero) + +addi zero, zero 1 # Terminate + +.data +256: .word 0xA +257: .word 0xB +258: .word 0xC +259: .word 0xD \ No newline at end of file diff --git a/pa3/unittests/correlation.asm b/pa3/unittests/correlation.asm new file mode 100644 index 0000000..213752a --- /dev/null +++ b/pa3/unittests/correlation.asm @@ -0,0 +1,100 @@ +.text +addi a1, zero, 1000 # constant 1 +addi a2, zero, 0xA # constant 2 +addi a3, zero, 0xB # constant 3 +addi a4, zero, 0xC # constant 4 + +# Call f(a) 11 times with a = {1500, 500, 1400, 600, 1300, 700, 1200, 800, 1100, 900, 1000} + +# funct call 1 +addi a0, zero, 1500 +jal ra, f +add s2, a0, zero + +# funct call 2 +addi a0, zero, 500 +jal ra, f +add s3, a0, zero + +# funct call 3 +addi a0, zero, 1400 +jal ra, f +add s4, a0, zero + +# funct call 4 +addi a0, zero, 600 +jal ra, f +add s5, a0, zero + +# funct call 5 +addi a0, zero, 1300 +jal ra, f +add s6, a0, zero + +# funct call 6 +addi a0, zero, 700 +jal ra, f +add s7, a0, zero + +# funct call 7 +addi a0, zero, 1200 +jal ra, f +add s8, a0, zero + +# funct call 8 +addi a0, zero, 800 +jal ra, f +add s9, a0, zero + +# funct call 9 +addi a0, zero, 1100 +jal ra, f +add s8, a0, zero + +# funct call 10 +addi a0, zero, 900 +jal ra, f +add s9, a0, zero + +# funct call 11 +addi a0, zero, 1000 +jal ra, f +add s8, a0, zero + +# goto end +jal x0, end + +f: +add t0, zero, zero # t0 = 0 + +bge a0, a1, skip1 # b1: if a0 >= 1000, branch T (skip assignment) --> "if (a0 < 1000) t0 = 0xA" +addi t0, zero, 0xA + +skip1: +slli t1, t0, 12 # t1 = t0 << 12 +bne t0, a2, skip2 # b2: if t0 != 0xA, branch T (skip assignment) --> "if (t0 == 0xA) t0 = 0xB" +addi t0, zero, 0xB + +skip2: +slli t2, t0, 8 # t2 = t0 << 8 +bne t0, a3, skip3 # b3: if t0 != 0xB, branch T (skip assignemnt) --> "if (t0 == 0xB) t0 = 0xC" +addi t0, zero, 0xC + +skip3: +slli t3, t0, 4 # t3 = t0 << 4 +bne t0, a4, skip4 # b4: if t1 != 0xC, branch T (skip assignment) --> "if (t0 == 0xC) t0 = 0xD" +addi t0, zero, 0xD + +skip4: +or t4, t0, t1 +or t5, t2, t3 +or a0, t4, t5 # set the output +jalr x0, ra, zero # return + +end: +addi zero, zero, 1 # terminate + +.data +256: .word 4302 +257: .word 5402 +258: .word 5302 \ No newline at end of file diff --git a/pa3/unittests/derivative.asm b/pa3/unittests/derivative.asm new file mode 100644 index 0000000..a1377b6 --- /dev/null +++ b/pa3/unittests/derivative.asm @@ -0,0 +1,60 @@ +# y(t) = 3*t^2 + 5*t +# y'(t) = 6*t + 5 +# Estimate y(t) as a discrete sequence: y[n] = 3*n^2 + 5*n ; n:{1 <= n <= 32} +# Derivative approximation: f[n] = (y[n+1] - y[n-1]) / 2 + +# Starting address of y[n]: 256 (# of elements 32) +# Starting address of f[n]: 288 (# of elements 31) + +.text +addi s0, zero, 31 # Upper bound for counter +add s1, zero, zero # Counter i: 0 -> 31 + +lw s3, 256(s1) # load y[i] temp for later + +loop: +lw s4, 257(s1) # y[i+1] load +sub s5, s4, s2 # y[i+1] - y[i-1] +srli s5, s5, 1 # f[n] = ( y[i+1] - y[i-1] ) / 2 +sw s5, 288(s1) # f[n] store +add s2, s3, zero # y[i-1] = y[i] +add s3, s4, zero # y[i] = y[i+1] (to avoid double loading) +addi s1, s1, 1 # i++ +blt s1, s0, loop # Loop through whole array + +addi zero, zero, 1 + +.data +# y[n] sequence +256: .word 8 +257: .word 22 +258: .word 42 +259: .word 68 +260: .word 100 +261: .word 138 +262: .word 182 +263: .word 232 +264: .word 288 +265: .word 350 +266: .word 418 +267: .word 492 +268: .word 572 +269: .word 658 +270: .word 750 +271: .word 848 +272: .word 952 +273: .word 1062 +274: .word 1178 +275: .word 1300 +276: .word 1428 +277: .word 1562 +278: .word 1702 +279: .word 1848 +280: .word 2000 +281: .word 2158 +282: .word 2322 +283: .word 2492 +284: .word 2668 +285: .word 2850 +286: .word 3038 +287: .word 3232 \ No newline at end of file diff --git a/pa3/unittests/derivative_unrolled.asm b/pa3/unittests/derivative_unrolled.asm new file mode 100644 index 0000000..e1f14be --- /dev/null +++ b/pa3/unittests/derivative_unrolled.asm @@ -0,0 +1,91 @@ +# Same operation as derivative.asm, except loop unrolled 8x + +# Starting address of y[n]: 256 (# of elements 32) +# Starting address of f[n]: 288 (# of elements 31) + +.text +addi s0, zero, 31 # Upper bound for counter +add s1, zero, zero # Counter i: 0 -> 3 +lw s3, 256(s1) # y[i] load +loop: + +lw s4, 257(s1) # y[i+1] load +lw s5, 258(s1) # y[i+2] load +lw s6, 259(s1) # y[i+3] load +lw s7, 260(s1) # y[i+4] load +lw s8, 261(s1) # y[i+5] load +lw s9, 262(s1) # y[i+6] load +lw s10, 263(s1) # y[i+7] load +lw s11, 264(s1) # y[i+8] load + +sub s2, s4, s2 # y[i+1] - y[i-1] +sub s3, s5, s3 # y[i+2] - y[i] +sub s4, s6, s4 # y[i+3] - y[i+1] +sub s5, s7, s5 # y[i+4] - y[i+2] +sub s6, s8, s6 # y[i+5] - y[i+3] +sub s7, s9, s7 # y[i+6] - y[i+4] +sub s8, s10, s8 # y[i+7] - y[i+5] +sub s9, s11, s9 # y[i+8] - y[i+6] + +addi s1, s1, 8 # Update the counter here to remove the RAW hazard on SW / BLT! + +srli s2, s2, 1 # f[n] = ( y[i+1] - y[i-1] ) / 2 +srli s3, s3, 1 # f[n+1] = ( y[i+2] - y[i] ) / 2 +srli s4, s4, 1 # f[n+2] = ( y[i+3] - y[i+1] ) / 2 +srli s5, s5, 1 # f[n+3] = ( y[i+4] - y[i+2] ) / 2 +srli s6, s6, 1 # f[n+4] = ( y[i+5] - y[i+3] ) / 2 +srli s7, s7, 1 # f[n+5] = ( y[i+6] - y[i+4] ) / 2 +srli s8, s8, 1 # f[n+6] = ( y[i+7] - y[i+5] ) / 2 +srli s9, s9, 1 # f[n+7] = ( y[i+8] - y[i+6] ) / 2 + +# (Accounting for the previously incrememnted counter) +sw s2, 280(s1) # f[n] store +sw s3, 281(s1) # f[n+1] store +sw s4, 282(s1) # f[n+2] store +sw s5, 283(s1) # f[n+3] store +sw s6, 284(s1) # f[n+4] store +sw s7, 285(s1) # f[n+5] store +sw s8, 286(s1) # f[n+6] store +sw s9, 287(s1) # f[n+7] store + +add s2, s10, zero # y[i-1] = y[i+7] (to avoid double loading) +add s3, s11, zero # y[i] = y[i+8] (to avoid double loading) +blt s1, s0, loop # Loop through whole array +sw zero, 287(s1) # Since the output length is 31, the 32'nd element is erroneous: clear it + +addi zero, zero, 1 + +.data +# y[n] sequence +256: .word 8 +257: .word 22 +258: .word 42 +259: .word 68 +260: .word 100 +261: .word 138 +262: .word 182 +263: .word 232 +264: .word 288 +265: .word 350 +266: .word 418 +267: .word 492 +268: .word 572 +269: .word 658 +270: .word 750 +271: .word 848 +272: .word 952 +273: .word 1062 +274: .word 1178 +275: .word 1300 +276: .word 1428 +277: .word 1562 +278: .word 1702 +279: .word 1848 +280: .word 2000 +281: .word 2158 +282: .word 2322 +283: .word 2492 +284: .word 2668 +285: .word 2850 +286: .word 3038 +287: .word 3232 \ No newline at end of file diff --git a/pa3/unittests/endian_reverse.asm b/pa3/unittests/endian_reverse.asm new file mode 100644 index 0000000..feae597 --- /dev/null +++ b/pa3/unittests/endian_reverse.asm @@ -0,0 +1,31 @@ +.text +addi s0, zero, 256 # starting address of data +lw a0, 0(s0) # load argument from memory +jal ra, reverse # procedure call + +sw a0, 1(s0) # store output in memory +addi zero, zero, 1 # terminate + +#reverse the endianness (eg 0x 01 23 45 67 --> 0x 67 45 23 01) +reverse: +add t0, zero, zero # t0 = 0 +add t1, zero, zero # t1 = 0 +add t2, zero, zero # t2 = 0 +add t3, zero, zero # t3 = 0 +add t4, zero, zero # t4 = 0 +addi t5, zero, 24 # t5 = 24 (constant) +add t6, zero, zero # temp output register +loop: +sub t1, t5, t0 # t1 = 24 - t0 +srl t2, a0, t0 # t2 = a0 >> t0 +andi t3, t2, 0xFF # t3 = 8-LSB of t2 +sll t4, t3, t1 # t4 = t3 << t1 +or t6, t6, t4 # t6 |= t4 +addi t0, t0, 8 # t0 += 8 +bge t5, t0, loop # loop while t0 <= 24 + +add a0, t6, zero # set return value +jalr zero, ra, 0 # output is set so return + +.data +256: .word 0x43022023 \ No newline at end of file diff --git a/pa3/unittests/fibonacci.asm b/pa3/unittests/fibonacci.asm new file mode 100644 index 0000000..7afe811 --- /dev/null +++ b/pa3/unittests/fibonacci.asm @@ -0,0 +1,26 @@ +.text +addi t6, zero, 10 # t6 = 10 (upper bound) +addi t1, zero, 0 # t1 = 0 (F_0) +addi t2, zero, 1 # t2 = 1 (F_1) +jal x0, fibonacci + +fibonacci: +add t3, t2, t1 # F_n = F_(n-1) + F_(n-2) +add t1, zero, t2 # F_(n-2) = F_(n-1) +add t2, zero, t3 # F_(n-1) = F_n +addi t5, t5, 1 # i++ +bne t5, t6, fibonacci +addi zero, zero, 1 # zero register should never be updated, so detect this change and quit simulator + +.data +256: .word 10 +257: .word 10 +258: .word 20 +259: .word 30 +260: .word 40 +261: .word 50 +262: .word 60 +263: .word 70 +264: .word 80 +265: .word 90 +266: .word 100 \ No newline at end of file diff --git a/pa3/unittests/jal_no_link.asm b/pa3/unittests/jal_no_link.asm new file mode 100644 index 0000000..3127793 --- /dev/null +++ b/pa3/unittests/jal_no_link.asm @@ -0,0 +1,26 @@ +.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 +jal x0, jump_test1 # Jump to procedure "jump_test1" + +jump_test2: +lw a1, 256(t2) # Load a1 = 2, Mem[256] = 2, 2 in simulator +addi t2, t2, 1 # Add 1 to the pointer to access Mem[2049] +lw a2, 256(t2) # Load a2 = 10, Mem[257] = 10, 10 in simulator +jal x0, 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 +jal x0, jump_test2 # Jump to procedure "jump_test2" + +end: +addi zero, zero, 1 # zero register should never be updated, so detect this change and quit simulator + +# --- Start of the Memory Layout --- + +.data +256: .word 2 +257: .word 10 \ No newline at end of file diff --git a/pa3/unittests/jal_w_link.asm b/pa3/unittests/jal_w_link.asm new file mode 100644 index 0000000..b11eb0a --- /dev/null +++ b/pa3/unittests/jal_w_link.asm @@ -0,0 +1,19 @@ +.text +addi a2, zero, 2 # argument 0 = 2 +addi a3, zero, 3 # argument 1 = 3 +addi a4, zero, 4 # argument 2 = 4 +addi a5, zero, 5 # argument 3 = 5 +jal ra, diffofsums # call procedure +add s0, a0, zero # y = returned value +addi zero, zero, 1 # zero register should never be updated, so detect this change and quit simulator + +diffofsums: +add t0, a2, a3 # $t0 = f + g +add t1, a4, a5 # $t1 = h + i +sub s0, t0, t1 # result = (f+g)-(h+i) +add a0, s0, zero # put return value in a0 +jalr zero, ra, 0 # return to caller + +.data +256: .word 10 +257: .word 10 \ No newline at end of file diff --git a/pa3/unittests/jalr_test.asm b/pa3/unittests/jalr_test.asm new file mode 100644 index 0000000..d00b1e1 --- /dev/null +++ b/pa3/unittests/jalr_test.asm @@ -0,0 +1,25 @@ +.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 +addi t4, zero, 36 # t4 = address where procedure starts +jalr ra, t4, 0 # call procedure + +addi zero, zero, 1 # this instruction should be skipped! +add s0, a0, zero # y = returned value +jalr x0, x0, 56 # go to end + +#procedure +add t0, a0, a1 # $t0 = f + g +add t1, a2, a3 # $t1 = h + i +sub s0, t0, t1 # result = (f+g)-(h+i) +add a0, s0, zero # put return value in $v0 +jalr x0, ra, 4 # return to the caller, and SKIP the instruction following "jalr ra, t4, 0" by including +4 offset + +#end +addi zero, zero, 1 # $zero register should never be updated, so detect this change and quit simulator + +.data +256: .word 10 +257: .word 10 \ No newline at end of file diff --git a/pa3/unittests/lw_sw_test.asm b/pa3/unittests/lw_sw_test.asm new file mode 100644 index 0000000..453499c --- /dev/null +++ b/pa3/unittests/lw_sw_test.asm @@ -0,0 +1,56 @@ +.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 + +lw t1, 256(t0) # t1 = 20 +lw t2, 256(t1) # t2 = 4 +add t4, t1, t2 # t4 = 24 +lw t3, 256(t4) # t3 = 8 +add t4, t4, t3 # t4 = 32 +sw t4, 256(t0) # mem[256] = 32 +lw t1, 256(t0) # t1 = 32 <-- observation of stored value 32 as $t1=0x00000020 +lw t2, 256(t1) # t2 = 5 +add t4, t1, t2 # t4 = 37 +sw t4, 256(t1) # mem[288] = 37 +lw t5, 256(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 +256: .word 20 +257: .word 32 +258: .word 2 +259: .word 2 +260: .word 3 +261: .word 3 +262: .word 3 +263: .word 3 +264: .word 3 +265: .word 3 +266: .word 3 +267: .word 3 +268: .word 3 +269: .word 3 +270: .word 3 +271: .word 3 +272: .word 3 +273: .word 3 +274: .word 3 +275: .word 3 +276: .word 4 +277: .word 3 +278: .word 3 +279: .word 3 +280: .word 8 +281: .word 3 +282: .word 3 +283: .word 3 +284: .word 3 +285: .word 3 +286: .word 3 +287: .word 3 +288: .word 5 \ No newline at end of file diff --git a/pa3/unittests/multiplier.asm b/pa3/unittests/multiplier.asm new file mode 100644 index 0000000..d310a63 --- /dev/null +++ b/pa3/unittests/multiplier.asm @@ -0,0 +1,22 @@ +.text +addi s0, zero, 20 # s0 = multiplier +addi s1, zero, 23 # s1 = multiplicand +add s2, zero, zero # s2 = 0 (counter) +addi s3, zero, 1 # s3 = 1 (constant) +slli s1, s1, 8 # s1 = s1 << 8 + +mult: +and t0, s0, s3 # test lsb of multiplier +beq zero, t0, skip_add # only do an add if LSB is 1, so skip if 0 +add s0, s0, s1 # add multiplier and multiplicand +skip_add: +srli s0, s0, 1 # s0 = s0 >> 1 +addi s2, s2, 1 # s2++ +slti t0, s2, 8 # check if s2 < 8 +bne t0, zero, mult # if it is, keep looping +add s10, s0, zero # s10 = s0 +addi zero, zero, 1 # $zero register should never be updated, so detect this change and quit simulator + +.data +256: .word 10 +257: .word 10 \ No newline at end of file diff --git a/pa3/unittests/nested_loops.asm b/pa3/unittests/nested_loops.asm new file mode 100644 index 0000000..281fb08 --- /dev/null +++ b/pa3/unittests/nested_loops.asm @@ -0,0 +1,23 @@ +.text +addi s0, zero, 8 # outer loop upper bound +addi s1, zero, 3 # inner loop upper bound +addi s2, zero, 256 # memory address to keep track of +add s3, zero, zero # i = 0 + +outer_loop: +add s4, zero, zero # j = 0 + inner_loop: + add t0, s3, s4 # i + j + sw t0, 0(s2) # store i + j in memory + addi s2, s2, 1 # increase memory pointer + addi s4, s4, 1 # j++ + bne s4, s1, inner_loop +addi s3, s3, 1 # i++ +bne s3, s0, outer_loop + +addi zero, zero, 1 # terminate + +.data +256: .word 4302 +257: .word 5402 +258: .word 5302 \ No newline at end of file diff --git a/pa3/unittests/no_dep_test.asm b/pa3/unittests/no_dep_test.asm new file mode 100644 index 0000000..684cbb6 --- /dev/null +++ b/pa3/unittests/no_dep_test.asm @@ -0,0 +1,12 @@ +.text +addi t0, zero, 10 +addi t1, zero, 25 +addi t2, zero, 20 +addi t3, zero, 19 +addi t4, zero, 18 +sw t0, 256(zero) +addi, zero, zero, 1 # $zero register should never be updated, so detect this change and quit simulator + +.data +256: .word 4302 +257: .word 3666 \ No newline at end of file diff --git a/pa3/unittests/twos_compliment.asm b/pa3/unittests/twos_compliment.asm new file mode 100644 index 0000000..8f7b863 --- /dev/null +++ b/pa3/unittests/twos_compliment.asm @@ -0,0 +1,22 @@ +.text +lui s0, 0xFFFFF # s0 = all '1' in 20 MSB +ori s0, s0, 0xFFF # s1 = all '1' in MSB (constant) + +# Words to test +addi s1, zero, 2023 +addi s2, zero, -2023 + +# Convert t1 to +4302 +xor t1, s2, s0 # flip all bits in s2 +addi t2, t1, 1 # add 1 to t2 + +and t3, t2, s1 # Check mutual bits +bne t3, s1, fail +xori s0, s0, 0xAAA # Imprint pattern on s0 + +fail: +addi zero, zero, 1 # terminate + +.data +256: .word 10 +257: .word 10 \ No newline at end of file diff --git a/pa3/unittests/wordsearch.asm b/pa3/unittests/wordsearch.asm new file mode 100644 index 0000000..3500624 --- /dev/null +++ b/pa3/unittests/wordsearch.asm @@ -0,0 +1,35 @@ +.text +addi t0, zero, 15 # max number of memory lookups +addi t1, t0, 1 # for upper bound of loop +add s0, zero, zero # stores 0 if the word is not found in memory, else stores 1 + +addi s1, zero, 255 # We want to look up this word in memory +add t2, zero, zero # value to store memory address + +loop: +addi t2, t2, 1 +slt t4, t2, t1 # check if counter < upper bound +beq t4, zero, not_found # if we have serched max memory locations, quit +lw t5, 256(t2) # look for word +beq s1, t5, found # found the word +jal x0, loop # keep looping + +found: +addi s0, zero, 1 # set 1 to s0 and fall through to termination +not_found: +addi zero, zero, 1 # end the program + +.data +256: .word 3 +257: .word 671 +258: .word 5402 +259: .word 0 +260: .word 4302 +261: .word 15 +262: .word 255 +263: .word 5402 +264: .word 5302 +265: .word 3 +266: .word 23 +267: .word 1 +268: .word 2024 \ No newline at end of file