From fc887d595d2e8d21c12b9763903270142edf08ac Mon Sep 17 00:00:00 2001 From: cag-uconn Date: Fri, 17 Nov 2023 13:47:35 -0500 Subject: [PATCH] . --- pa4/Makefile | 18 ++ pa4/README.md | 21 ++ pa4/assemble_all.sh | 24 ++ pa4/src/instruction_map.h | 61 ++++ pa4/src/register_map.c | 49 +++ pa4/src/register_map.h | 16 + pa4/src/sim_core.c | 242 +++++++++++++++ pa4/src/sim_core.h | 134 +++++++++ pa4/src/sim_stages.c | 71 +++++ pa4/src/sim_stages.h | 26 ++ pa4/src/util.c | 415 ++++++++++++++++++++++++++ pa4/src/util.h | 24 ++ pa4/unittests/.gitignore | 1 + pa4/unittests/array_adder.asm | 55 ++++ pa4/unittests/basics.asm | 22 ++ pa4/unittests/beq_test.asm | 20 ++ pa4/unittests/blt_bge_test.asm | 28 ++ pa4/unittests/bne_test.asm | 50 ++++ pa4/unittests/colliding_cache.asm | 71 +++++ pa4/unittests/correlation.asm | 100 +++++++ pa4/unittests/derivative.asm | 60 ++++ pa4/unittests/derivative_unrolled.asm | 91 ++++++ pa4/unittests/endian_reverse.asm | 31 ++ pa4/unittests/fibonacci.asm | 26 ++ pa4/unittests/jal_no_link.asm | 26 ++ pa4/unittests/jal_w_link.asm | 19 ++ pa4/unittests/jalr_test.asm | 25 ++ pa4/unittests/lw_sw_test.asm | 56 ++++ pa4/unittests/multiplier.asm | 22 ++ pa4/unittests/nested_loops.asm | 23 ++ pa4/unittests/no_dep_test.asm | 12 + pa4/unittests/twos_compliment.asm | 22 ++ pa4/unittests/wordsearch.asm | 35 +++ 33 files changed, 1896 insertions(+) create mode 100644 pa4/Makefile create mode 100644 pa4/README.md create mode 100644 pa4/assemble_all.sh create mode 100644 pa4/src/instruction_map.h create mode 100644 pa4/src/register_map.c create mode 100644 pa4/src/register_map.h create mode 100644 pa4/src/sim_core.c create mode 100644 pa4/src/sim_core.h create mode 100644 pa4/src/sim_stages.c create mode 100644 pa4/src/sim_stages.h create mode 100644 pa4/src/util.c create mode 100644 pa4/src/util.h create mode 100644 pa4/unittests/.gitignore create mode 100644 pa4/unittests/array_adder.asm create mode 100644 pa4/unittests/basics.asm create mode 100644 pa4/unittests/beq_test.asm create mode 100644 pa4/unittests/blt_bge_test.asm create mode 100644 pa4/unittests/bne_test.asm create mode 100644 pa4/unittests/colliding_cache.asm create mode 100644 pa4/unittests/correlation.asm create mode 100644 pa4/unittests/derivative.asm create mode 100644 pa4/unittests/derivative_unrolled.asm create mode 100644 pa4/unittests/endian_reverse.asm create mode 100644 pa4/unittests/fibonacci.asm create mode 100644 pa4/unittests/jal_no_link.asm create mode 100644 pa4/unittests/jal_w_link.asm create mode 100644 pa4/unittests/jalr_test.asm create mode 100644 pa4/unittests/lw_sw_test.asm create mode 100644 pa4/unittests/multiplier.asm create mode 100644 pa4/unittests/nested_loops.asm create mode 100644 pa4/unittests/no_dep_test.asm create mode 100644 pa4/unittests/twos_compliment.asm create mode 100644 pa4/unittests/wordsearch.asm diff --git a/pa4/Makefile b/pa4/Makefile new file mode 100644 index 0000000..295470f --- /dev/null +++ b/pa4/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/pa4/README.md b/pa4/README.md new file mode 100644 index 0000000..26d23fc --- /dev/null +++ b/pa4/README.md @@ -0,0 +1,21 @@ +# Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard Algorithm +A pipelined CPU simulator for the RISC-V riscv-uconn instruction set architecture implementing a scoreboard algorithm. The simulator translates machine code created by the riscv-uconn assembler, and issues one instruction at a time. + +## Build Instructions + $ make + +## Usage + $ ./simulator assembled_program_file.out + +where `assembled_program_file.out` may be any assembled program file generated by the riscy-uconn +assembler. + +## 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. 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 \ No newline at end of file diff --git a/pa4/assemble_all.sh b/pa4/assemble_all.sh new file mode 100644 index 0000000..add48ac --- /dev/null +++ b/pa4/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/pa4/src/instruction_map.h b/pa4/src/instruction_map.h new file mode 100644 index 0000000..e8bb68e --- /dev/null +++ b/pa4/src/instruction_map.h @@ -0,0 +1,61 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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/pa4/src/register_map.c b/pa4/src/register_map.c new file mode 100644 index 0000000..5e1ef67 --- /dev/null +++ b/pa4/src/register_map.c @@ -0,0 +1,49 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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/pa4/src/register_map.h b/pa4/src/register_map.h new file mode 100644 index 0000000..a1b65a2 --- /dev/null +++ b/pa4/src/register_map.h @@ -0,0 +1,16 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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/pa4/src/sim_core.c b/pa4/src/sim_core.c new file mode 100644 index 0000000..0517c43 --- /dev/null +++ b/pa4/src/sim_core.c @@ -0,0 +1,242 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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 cycle = 0; // CPU cycle +int registers[MAX_LENGTH] = {0}; // Registers +unsigned int pc = 0; // Program Counter (PC) register +int committed_instructions = 0; // Committed instructions +int *memory = NULL; // Data & instruction memory +struct ScoreboardEntry *scoreboard; // Scoreboard + +/* Pipeline related initialization */ +int br_taken = 0; + +/* Scoreboard related initialization */ +int register_result[MAX_LENGTH] = { [0 ... (MAX_LENGTH - 1)] = -1 }; // Scoreboard register results +int br_taken_instruction_number = 0; + +/* Instruction latencies */ +const int LATENCY_MEMORY = 3; +const int LATENCY_BRANCH = 1; +const int LATENCY_OTHER = 5; + +/** + * Utility + */ +FILE *fptr_pt; + +/** + * Simulator entry point + */ +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "[ERROR] incorrect number of arguments.\n"); + printf("usage: simulator PROGRAM_FILE\n"); + exit(1); + } else { + /* Open input program file */ + FILE *fp; + fp = fopen(argv[1], "r"); + + /* 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); + free(scoreboard); + fclose(fp); + if (pipe_trace) { + fclose(fptr_pt); + } + + return 0; + } +} + +void process_instructions() { + int terminate = 0; + int instruction_counter = 0; //committed instruction count + + while (terminate != 1) { + + /* Update state */ + write_result(); + execute(); + read_operands(); + issue(); + + /* Print information at cycle end */ + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle: %d \n", cycle); + fprintf(fptr_pt, "PC: %d\n", pc); + fprintf(fptr_pt, "Committed Instructions: %d\n", committed_instructions); + fprintf(fptr_pt, "\n"); + + print_scoreboard(); + + fprintf(fptr_pt, "\n"); + rdump_pt(); + fprintf(fptr_pt, "\n"); + fprintf(fptr_pt, "=================================================================================================================================\n"); + fprintf(fptr_pt, "\n"); + + fflush(fptr_pt); + } + + if (registers[0] != 0) { + terminate = 1; // set terminate flag when $zero is updated + } + + cycle++; // Increment cycle count + + /* Potential infinite loop detected */ + 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", committed_instructions); + printf("TOTAL CYCLES SIMULATED: %d\n", cycle); + printf("AVERAGE CPI: %0.3f\n", (double)cycle/(double)committed_instructions); +} + +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 and zero-initialize scoreboard */ + scoreboard = (struct ScoreboardEntry*) calloc(SCOREBOARD_ENTRIES, sizeof(struct ScoreboardEntry)); + if (scoreboard == NULL) { + fprintf(stderr, "[ERROR] not enough memory. Aborting.\n"); + exit(1); + } + printf("Initialized Scoreboard\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/pa4/src/sim_core.h b/pa4/src/sim_core.h new file mode 100644 index 0000000..afb123e --- /dev/null +++ b/pa4/src/sim_core.h @@ -0,0 +1,134 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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 + +/* Instruction and data memory */ +extern int *memory; + +/* Committed instructions */ +extern int committed_instructions; + +/* 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 br_taken; + +/* Scoreboard related */ +#define SCOREBOARD_ENTRIES 100 + +extern int register_result[MAX_LENGTH]; +extern int br_taken_instruction_number; + +enum Stage {STAGE_INVALID, STAGE_ISSUE, STAGE_READ_OPERANDS, STAGE_EXECUTE, STAGE_WRITE_RESULT}; +enum Hazard {HAZARD_NONE, HAZARD_RAW, HAZARD_WAW, HAZARD_WAR, HAZARD_STRUCTURAL}; + +struct ScoreboardEntry { + /* Flag indicating if entry is valid */ + int valid; + + /* Instruction number of instruction corresponding to entry */ + int instruction_number; + + /* Pipeline stage of entry */ + enum Stage stage; + + /* Operation and funct3 / funct7 bits corresponding to the instruction */ + int operation; + int f3; + int f7; + + /* Hazard of entry (if any) */ + enum Hazard hazard; + + /* Source and destination register indices */ + int src_reg_1; + int src_reg_2; + int dest_reg; + + /* Source operand data */ + int src_reg_1_data; + int src_reg_2_data; + + /* Scoreboard entry that produces source operand data */ + int scb_1; + int scb_2; + + /* Flags indicating if source operands are available */ + int scb_1_ready; + int scb_2_ready; + + /* Immediate and shift amount for relevant instructions */ + int imm; + + /* Branch and jump destination address */ + int target_address; + + /* Number of cycles spent in operation and operation latency */ + int cycles; + int latency; + + /* Operation result */ + int result; +}; +extern struct ScoreboardEntry *scoreboard; + +/* Instruction latencies */ +extern const int LATENCY_MEMORY; +extern const int LATENCY_BRANCH; +extern const int LATENCY_OTHER; + +void initialize(FILE *fp); +void process_instructions(); \ No newline at end of file diff --git a/pa4/src/sim_stages.c b/pa4/src/sim_stages.c new file mode 100644 index 0000000..dc10503 --- /dev/null +++ b/pa4/src/sim_stages.c @@ -0,0 +1,71 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * YOUR NAME HERE + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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 + +/** + * Issue stage implementation. + */ +void issue(void) { + + /** TODO: Your code for the issue stage goes here. */ + +} + +/** + * Read Operands stage implementation. + */ +void read_operands(void) { + + /** TODO: Your code for the read operands stage goes here. */ + +} + +/** + * Execute stage implementation + */ +void execute(void) { + + /** TODO: Your code for the execute stage goes here. */ + +} + +/** + * Write Result stage implementation + */ +void write_result(void) { + + /** TODO: Your code for the write result stage goes here. */ + +} + +/** + * Advance PC. + * DO NOT MODIFY. + */ +void advance_pc(int step) { + pc += step; +} \ No newline at end of file diff --git a/pa4/src/sim_stages.h b/pa4/src/sim_stages.h new file mode 100644 index 0000000..0f005c9 --- /dev/null +++ b/pa4/src/sim_stages.h @@ -0,0 +1,26 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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; + +void issue(void); +void read_operands(void); +void execute(void); +void write_result(void); +void advance_pc(int step); \ No newline at end of file diff --git a/pa4/src/util.c b/pa4/src/util.c new file mode 100644 index 0000000..2b473ec --- /dev/null +++ b/pa4/src/util.c @@ -0,0 +1,415 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * riscy-uconn: util.c + * + * DO NOT MODIFY THIS FILE + * + */ + +#include +#include +#include +#include +#include + +#include "instruction_map.h" +#include "register_map.h" +#include "sim_core.h" +#include "sim_stages.h" + +static const char* stage_map[] = { + [STAGE_INVALID] = "Invalid", + [STAGE_ISSUE] = "Issue", + [STAGE_READ_OPERANDS] = "Read Operands", + [STAGE_EXECUTE] = "Execute", + [STAGE_WRITE_RESULT] = "Write Result" +}; + +/** + * Dump register contents. + * Will format for desired number of columns and output in specified file. + */ +/** + * 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 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; + } +} + +/** + * Print instruction information + */ +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 rresult_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 Results ---\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, "Entry"); + 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, "-----"); + 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%-*i", index_col_width, i, tab_spaces - 1, "", name_col_width, register_map[i], tab_spaces - 1, "", value_col_width, register_result[i]); + } else { + fprintf(file, "\n"); + break; + } + + if (col == columns - 1) { + fprintf(file, "\n"); + } else { + fprintf(file, "%*s", col_sep * tab_spaces, ""); + } + } + } +} + +/** + * Print scoreboard + */ +void print_scoreboard() { + fprintf(fptr_pt, "--------------------------\n"); + fprintf(fptr_pt, "--- Instruction Status ---\n"); + fprintf(fptr_pt, "--------------------------\n"); + fprintf(fptr_pt, "Instruction Number Stage Operation dest_reg src_reg_1 src_reg_2 scb_1 scb_2 scb_1_ready scb_2_ready\n"); + fprintf(fptr_pt, "------------------ ----- --------- -------- --------- --------- ----- ----- ----------- -----------\n"); + for (int i = 0; i < SCOREBOARD_ENTRIES; i++) { + struct ScoreboardEntry *entry = &scoreboard[i]; + + if (!entry->valid) { + continue; + } + + char op[8]; + getInstStr(entry->operation, entry->f3, entry->f7, op); + + fprintf(fptr_pt, "%-18i %-13s %-9s %-8i %-9i %-9i %-5i %-5i %-11s %-11s\n", + entry->instruction_number, stage_map[entry->stage], op, entry->dest_reg, entry->src_reg_1, entry->src_reg_2, entry->scb_1, entry->scb_2, (entry->scb_1_ready == 1) ? "yes" : "no", (entry->scb_2_ready == 1) ? "yes" : "no"); + } + fprintf(fptr_pt, "\n"); + rresult_file_columns(fptr_pt, 3); +} + +/** + * 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/pa4/src/util.h b/pa4/src/util.h new file mode 100644 index 0000000..29586e1 --- /dev/null +++ b/pa4/src/util.h @@ -0,0 +1,24 @@ +/** + * University of Connecticut + * CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 4: Pipelined RISC-V Simulator With Scoreboard + * + * 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 print_scoreboard(); +int getDec(char *bin); \ No newline at end of file diff --git a/pa4/unittests/.gitignore b/pa4/unittests/.gitignore new file mode 100644 index 0000000..e2e7327 --- /dev/null +++ b/pa4/unittests/.gitignore @@ -0,0 +1 @@ +/out diff --git a/pa4/unittests/array_adder.asm b/pa4/unittests/array_adder.asm new file mode 100644 index 0000000..e1dfd25 --- /dev/null +++ b/pa4/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/pa4/unittests/basics.asm b/pa4/unittests/basics.asm new file mode 100644 index 0000000..76a9192 --- /dev/null +++ b/pa4/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/pa4/unittests/beq_test.asm b/pa4/unittests/beq_test.asm new file mode 100644 index 0000000..800a977 --- /dev/null +++ b/pa4/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/pa4/unittests/blt_bge_test.asm b/pa4/unittests/blt_bge_test.asm new file mode 100644 index 0000000..cff7a7b --- /dev/null +++ b/pa4/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/pa4/unittests/bne_test.asm b/pa4/unittests/bne_test.asm new file mode 100644 index 0000000..4a7d0b2 --- /dev/null +++ b/pa4/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/pa4/unittests/colliding_cache.asm b/pa4/unittests/colliding_cache.asm new file mode 100644 index 0000000..03686ef --- /dev/null +++ b/pa4/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/pa4/unittests/correlation.asm b/pa4/unittests/correlation.asm new file mode 100644 index 0000000..213752a --- /dev/null +++ b/pa4/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/pa4/unittests/derivative.asm b/pa4/unittests/derivative.asm new file mode 100644 index 0000000..a1377b6 --- /dev/null +++ b/pa4/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/pa4/unittests/derivative_unrolled.asm b/pa4/unittests/derivative_unrolled.asm new file mode 100644 index 0000000..e1f14be --- /dev/null +++ b/pa4/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/pa4/unittests/endian_reverse.asm b/pa4/unittests/endian_reverse.asm new file mode 100644 index 0000000..feae597 --- /dev/null +++ b/pa4/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/pa4/unittests/fibonacci.asm b/pa4/unittests/fibonacci.asm new file mode 100644 index 0000000..7afe811 --- /dev/null +++ b/pa4/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/pa4/unittests/jal_no_link.asm b/pa4/unittests/jal_no_link.asm new file mode 100644 index 0000000..3127793 --- /dev/null +++ b/pa4/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/pa4/unittests/jal_w_link.asm b/pa4/unittests/jal_w_link.asm new file mode 100644 index 0000000..b11eb0a --- /dev/null +++ b/pa4/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/pa4/unittests/jalr_test.asm b/pa4/unittests/jalr_test.asm new file mode 100644 index 0000000..d00b1e1 --- /dev/null +++ b/pa4/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/pa4/unittests/lw_sw_test.asm b/pa4/unittests/lw_sw_test.asm new file mode 100644 index 0000000..453499c --- /dev/null +++ b/pa4/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/pa4/unittests/multiplier.asm b/pa4/unittests/multiplier.asm new file mode 100644 index 0000000..d310a63 --- /dev/null +++ b/pa4/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/pa4/unittests/nested_loops.asm b/pa4/unittests/nested_loops.asm new file mode 100644 index 0000000..281fb08 --- /dev/null +++ b/pa4/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/pa4/unittests/no_dep_test.asm b/pa4/unittests/no_dep_test.asm new file mode 100644 index 0000000..684cbb6 --- /dev/null +++ b/pa4/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/pa4/unittests/twos_compliment.asm b/pa4/unittests/twos_compliment.asm new file mode 100644 index 0000000..8f7b863 --- /dev/null +++ b/pa4/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/pa4/unittests/wordsearch.asm b/pa4/unittests/wordsearch.asm new file mode 100644 index 0000000..3500624 --- /dev/null +++ b/pa4/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