From b5cb1e8372598c353108680c214c9f00a9918dbc Mon Sep 17 00:00:00 2001 From: cag-uconn Date: Wed, 4 Oct 2023 14:29:14 -0400 Subject: [PATCH] . --- pa2/Makefile | 19 ++ pa2/README.md | 27 +++ pa2/assemble_all.sh | 24 +++ pa2/src/instruction_map.h | 61 ++++++ pa2/src/register_map.c | 49 +++++ pa2/src/register_map.h | 16 ++ pa2/src/sim_core.c | 250 +++++++++++++++++++++++ pa2/src/sim_core.h | 89 +++++++++ pa2/src/sim_stages.c | 139 +++++++++++++ pa2/src/sim_stages.h | 29 +++ pa2/src/util.c | 318 ++++++++++++++++++++++++++++++ pa2/src/util.h | 24 +++ pa2/unittests/.gitignore | 1 + pa2/unittests/array_adder.asm | 57 ++++++ pa2/unittests/basics.asm | 22 +++ pa2/unittests/beq_test.asm | 20 ++ pa2/unittests/blt_bge_test.asm | 28 +++ pa2/unittests/bne_test.asm | 22 +++ pa2/unittests/endian_reverse.asm | 33 ++++ pa2/unittests/fibonacci.asm | 26 +++ pa2/unittests/jal_no_link.asm | 27 +++ pa2/unittests/jal_w_link.asm | 19 ++ pa2/unittests/jalr_test.asm | 25 +++ pa2/unittests/lw_sw_test.asm | 57 ++++++ pa2/unittests/multiplier.asm | 22 +++ pa2/unittests/no_dep_test.asm | 14 ++ pa2/unittests/twos_compliment.asm | 22 +++ pa2/unittests/wordsearch.asm | 35 ++++ 28 files changed, 1475 insertions(+) create mode 100644 pa2/Makefile create mode 100644 pa2/README.md create mode 100644 pa2/assemble_all.sh create mode 100644 pa2/src/instruction_map.h create mode 100644 pa2/src/register_map.c create mode 100644 pa2/src/register_map.h create mode 100644 pa2/src/sim_core.c create mode 100644 pa2/src/sim_core.h create mode 100644 pa2/src/sim_stages.c create mode 100644 pa2/src/sim_stages.h create mode 100644 pa2/src/util.c create mode 100644 pa2/src/util.h create mode 100644 pa2/unittests/.gitignore create mode 100644 pa2/unittests/array_adder.asm create mode 100644 pa2/unittests/basics.asm create mode 100644 pa2/unittests/beq_test.asm create mode 100644 pa2/unittests/blt_bge_test.asm create mode 100644 pa2/unittests/bne_test.asm create mode 100644 pa2/unittests/endian_reverse.asm create mode 100644 pa2/unittests/fibonacci.asm create mode 100644 pa2/unittests/jal_no_link.asm create mode 100644 pa2/unittests/jal_w_link.asm create mode 100644 pa2/unittests/jalr_test.asm create mode 100644 pa2/unittests/lw_sw_test.asm create mode 100644 pa2/unittests/multiplier.asm create mode 100644 pa2/unittests/no_dep_test.asm create mode 100644 pa2/unittests/twos_compliment.asm create mode 100644 pa2/unittests/wordsearch.asm diff --git a/pa2/Makefile b/pa2/Makefile new file mode 100644 index 0000000..a55cdf5 --- /dev/null +++ b/pa2/Makefile @@ -0,0 +1,19 @@ +SRCS = $(wildcard src/*.c) +HEADERS = $(wildcard src/*.h) +CC = gcc +CFLAGS = -g -std=c99 +LDFLAGS = -lm + +default: simulator + +simulator: $(SRCS) $(HEADERS) + @echo "Building $@..." + @#gcc simulator.o -o simulator -ggdb -std=c99 + @echo "Sources: $(SRCS)" + @echo "Headers: $(HEADERS)" + $(CC) $(CFLAGS) -o $@ $(SRCS) $(LDFLAGS) + +clean: + -rm -r assembled_tests + -rm -f simulator + -rm -f pipe_trace.txt *.out mdump.txt diff --git a/pa2/README.md b/pa2/README.md new file mode 100644 index 0000000..0da7de4 --- /dev/null +++ b/pa2/README.md @@ -0,0 +1,27 @@ +# Programming Assignment 2: Pipelined riscv-uconn Simulator + +A 5-stage pipelined CPU simulator for the RISC-V based riscv-uconn instruction set architecture. 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 + +where `assembled_program_file.out` may be any assembled program file generated by the riscv-uconn +assembler, and `FORWARDING_ENABLED` may be 0 (disabled) or 1 (enabled). \ No newline at end of file diff --git a/pa2/assemble_all.sh b/pa2/assemble_all.sh new file mode 100644 index 0000000..add48ac --- /dev/null +++ b/pa2/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/pa2/src/instruction_map.h b/pa2/src/instruction_map.h new file mode 100644 index 0000000..4925c19 --- /dev/null +++ b/pa2/src/instruction_map.h @@ -0,0 +1,61 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * 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_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/pa2/src/register_map.c b/pa2/src/register_map.c new file mode 100644 index 0000000..20f8dbe --- /dev/null +++ b/pa2/src/register_map.c @@ -0,0 +1,49 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: register_map.c + * + * 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/pa2/src/register_map.h b/pa2/src/register_map.h new file mode 100644 index 0000000..8e59b8d --- /dev/null +++ b/pa2/src/register_map.h @@ -0,0 +1,16 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: register_map.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +extern const char* register_map[]; \ No newline at end of file diff --git a/pa2/src/sim_core.c b/pa2/src/sim_core.c new file mode 100644 index 0000000..060f35f --- /dev/null +++ b/pa2/src/sim_core.c @@ -0,0 +1,250 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: sim_core.c + * + * 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; + +/* Pipeline related */ +int forwarding_enabled = 0; + +/* Set the nop variable */ +const struct State nop = {.inst = 0x0000000013}; + +/* Initialize pipeline state */ +struct State fetch_out = nop, fetch_out_n; +struct State decode_out = nop, decode_out_n; +struct State ex_out = nop, ex_out_n; +struct State mem_out = nop, mem_out_n; + +/* Count all non-nop instructions */ +int instruction_counter = 0; + +/* Total Cycles */ +int cycle = 0; + +/** + * Simulator entry point + */ +int main(int argc, char *argv[]) { + if (argc != 3) { + fprintf(stderr, "[ERROR] incorrect number of arguments.\n"); + printf("usage: simulator PROGRAM_FILE FORWARDING_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"); + + /* 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 + + /* 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); + 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); + } + } + 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", (double)cycle/(double)instruction_counter); +} + +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); + } + + /* Zero initialize registers */ + memset(registers, 0, sizeof(registers)); + printf("Initialized Registers\n"); + + /* Allocate instruction and data memory */ + memory = (int*) malloc(16384 * sizeof(int)); + if (memory == NULL) { + fprintf(stderr, "[ERROR] not enough memory. Aborting.\n"); + exit(1); + } + + /* Initialize memory to -1 */ + for (int i = 0; i < 16384; i++) { + memory[i] = -1; + } + printf("Initialized Memory\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] = 0; + 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/pa2/src/sim_core.h b/pa2/src/sim_core.h new file mode 100644 index 0000000..1d775df --- /dev/null +++ b/pa2/src/sim_core.h @@ -0,0 +1,89 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: sim_core.h + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +#include + +extern FILE *fptr_pt; + +/* Max number of registers, and instruction length in bits */ +#define MAX_LENGTH 32 + +/* 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; + + /* 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; + +void initialize(FILE *fp); +void process_instructions(); \ No newline at end of file diff --git a/pa2/src/sim_stages.c b/pa2/src/sim_stages.c new file mode 100644 index 0000000..acad28f --- /dev/null +++ b/pa2/src/sim_stages.c @@ -0,0 +1,139 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * TODO: Your Name Here + * + * 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 + +/* Pipeline related */ +int pipe_stall = 0; +int j_taken = 0; +int br_mispredicted = 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; + +/** + * 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; + + /** + * TODO: Your logic for fetch stage here. + */ + + return fetch_out; +} + +/** + * Decode stage implementation + */ +struct State decode(struct State fetch_out) { + + /* Used to check if rs1 / rs2 is read */ + int rs1_read = 0; + int rs2_read = 0; + + /** + * TODO: Your logic for decode stage here. + */ + + return fetch_out; +} + +/** + * Execute stage implementation + */ +struct State execute(struct State decode_out) { + + /** + * TODO: Your logic for the execute stage here. + */ + + return decode_out; +} + +/** + * Memory stage implementation + */ +struct State memory_stage(struct State ex_out) { + + /** + * TODO: Your logic for the memory stage here. + */ + + return ex_out; +} + +/** + * Writeback stage implementation + */ +unsigned int writeback(struct State mem_out) { + + /** + * TODO: Your logic for the writeback stage here. + */ + + return mem_out.inst; +} + +/** + * Update the simulator state. + * DO NOT MODIFY. + */ +void update_simulator_state() { + if (pipe_stall) { + /** + * Hold the old values of pc and fetch_out. + * Inject nop into decode_out, allow following stages to proceed. + */ + decode_out = nop; + ex_out = ex_out_n; + mem_out = mem_out_n; + + }else { + /** + * No stalls, so advance every state down the pipeline + */ + pc = pc_n; + fetch_out = fetch_out_n; + decode_out = decode_out_n; + ex_out = ex_out_n; + mem_out = mem_out_n; + } +} + +/** + * Advance PC. + * DO NOT MODIFY. + */ +void advance_pc(int step) { + pc_n = pc + step; +} \ No newline at end of file diff --git a/pa2/src/sim_stages.h b/pa2/src/sim_stages.h new file mode 100644 index 0000000..a4aafa3 --- /dev/null +++ b/pa2/src/sim_stages.h @@ -0,0 +1,29 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: sim_stages.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); + +void update_simulator_state(void); +void advance_pc(int step); \ No newline at end of file diff --git a/pa2/src/util.c b/pa2/src/util.c new file mode 100644 index 0000000..5bccddc --- /dev/null +++ b/pa2/src/util.c @@ -0,0 +1,318 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: util.c + * + * 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); +} + +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 & 0x00000780) >> 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, "slri"); + 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 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/pa2/src/util.h b/pa2/src/util.h new file mode 100644 index 0000000..d8161b2 --- /dev/null +++ b/pa2/src/util.h @@ -0,0 +1,24 @@ +/** + * University of Connecticut + * CSE 4302 / CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 2: Pipelined 5-Stage Simulator + * + * riscy-uconn: util.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 inst_dump(const char stage[], const unsigned int inst); +void getInstStr(int op, int f3, int f7, char *buffer); +int getDec(char *bin); \ No newline at end of file diff --git a/pa2/unittests/.gitignore b/pa2/unittests/.gitignore new file mode 100644 index 0000000..e2e7327 --- /dev/null +++ b/pa2/unittests/.gitignore @@ -0,0 +1 @@ +/out diff --git a/pa2/unittests/array_adder.asm b/pa2/unittests/array_adder.asm new file mode 100644 index 0000000..7c8d1ad --- /dev/null +++ b/pa2/unittests/array_adder.asm @@ -0,0 +1,57 @@ +.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 +265: .word 90 +266: .word 100 +267: .word 3 +268: .word 3 +269: .word 3 +270: .word 3 +271: .word +272: .word 11 +273: .word 10 +274: .word 20 +275: .word 30 +276: .word 40 +277: .word 50 +278: .word 60 +279: .word 70 +280: .word 80 +281: .word 90 +282: .word 100 +283: .word 3 +284: .word 3 +285: .word 3 +286: .word 3 +287: .word 3 +288: .word 5 + + diff --git a/pa2/unittests/basics.asm b/pa2/unittests/basics.asm new file mode 100644 index 0000000..76a9192 --- /dev/null +++ b/pa2/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/pa2/unittests/beq_test.asm b/pa2/unittests/beq_test.asm new file mode 100644 index 0000000..800a977 --- /dev/null +++ b/pa2/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/pa2/unittests/blt_bge_test.asm b/pa2/unittests/blt_bge_test.asm new file mode 100644 index 0000000..cff7a7b --- /dev/null +++ b/pa2/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/pa2/unittests/bne_test.asm b/pa2/unittests/bne_test.asm new file mode 100644 index 0000000..c47dcb5 --- /dev/null +++ b/pa2/unittests/bne_test.asm @@ -0,0 +1,22 @@ +.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 10 +257: .word 32 +258: .word 2 \ No newline at end of file diff --git a/pa2/unittests/endian_reverse.asm b/pa2/unittests/endian_reverse.asm new file mode 100644 index 0000000..3d48125 --- /dev/null +++ b/pa2/unittests/endian_reverse.asm @@ -0,0 +1,33 @@ +.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 + + + diff --git a/pa2/unittests/fibonacci.asm b/pa2/unittests/fibonacci.asm new file mode 100644 index 0000000..7afe811 --- /dev/null +++ b/pa2/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/pa2/unittests/jal_no_link.asm b/pa2/unittests/jal_no_link.asm new file mode 100644 index 0000000..41c3f30 --- /dev/null +++ b/pa2/unittests/jal_no_link.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 +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 + diff --git a/pa2/unittests/jal_w_link.asm b/pa2/unittests/jal_w_link.asm new file mode 100644 index 0000000..f31ce49 --- /dev/null +++ b/pa2/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 diff --git a/pa2/unittests/jalr_test.asm b/pa2/unittests/jalr_test.asm new file mode 100644 index 0000000..b92c021 --- /dev/null +++ b/pa2/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 diff --git a/pa2/unittests/lw_sw_test.asm b/pa2/unittests/lw_sw_test.asm new file mode 100644 index 0000000..2a4bfb8 --- /dev/null +++ b/pa2/unittests/lw_sw_test.asm @@ -0,0 +1,57 @@ +.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 + diff --git a/pa2/unittests/multiplier.asm b/pa2/unittests/multiplier.asm new file mode 100644 index 0000000..42e3bb2 --- /dev/null +++ b/pa2/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 diff --git a/pa2/unittests/no_dep_test.asm b/pa2/unittests/no_dep_test.asm new file mode 100644 index 0000000..2164208 --- /dev/null +++ b/pa2/unittests/no_dep_test.asm @@ -0,0 +1,14 @@ +.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 + + diff --git a/pa2/unittests/twos_compliment.asm b/pa2/unittests/twos_compliment.asm new file mode 100644 index 0000000..8f7b863 --- /dev/null +++ b/pa2/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/pa2/unittests/wordsearch.asm b/pa2/unittests/wordsearch.asm new file mode 100644 index 0000000..3500624 --- /dev/null +++ b/pa2/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