From 2d24280f64ae7a6ec7f645dcab02192b8b3f1a41 Mon Sep 17 00:00:00 2001 From: cag-uconn Date: Fri, 8 Sep 2023 19:35:20 -0400 Subject: [PATCH] . --- assembler/README.md | 37 ++-- assembler/file_parser.c | 20 +- pa1/Makefile | 19 ++ pa1/README.md | 27 +++ pa1/assemble_all.sh | 19 ++ pa1/src/instruction_map.h | 62 ++++++ pa1/src/register_map.c | 50 +++++ pa1/src/register_map.h | 16 ++ pa1/src/sim_core.c | 257 ++++++++++++++++++++++++ pa1/src/sim_core.h | 70 +++++++ pa1/src/sim_stages.c | 104 ++++++++++ pa1/src/sim_stages.h | 27 +++ pa1/src/util.c | 322 ++++++++++++++++++++++++++++++ pa1/src/util.h | 24 +++ pa1/unittests/basics.asm | 22 ++ pa1/unittests/beq_test.asm | 20 ++ pa1/unittests/blt_bge_test.asm | 28 +++ pa1/unittests/bne_test.asm | 22 ++ pa1/unittests/endian_reverse.asm | 33 +++ pa1/unittests/fibonacci.asm | 26 +++ pa1/unittests/jal_no_link.asm | 27 +++ pa1/unittests/jal_w_link.asm | 19 ++ pa1/unittests/jalr_test.asm | 25 +++ pa1/unittests/lw_sw_test.asm | 57 ++++++ pa1/unittests/multiplier.asm | 22 ++ pa1/unittests/twos_compliment.asm | 22 ++ pa1/unittests/wordsearch.asm | 35 ++++ 27 files changed, 1378 insertions(+), 34 deletions(-) create mode 100644 pa1/Makefile create mode 100644 pa1/README.md create mode 100644 pa1/assemble_all.sh create mode 100644 pa1/src/instruction_map.h create mode 100644 pa1/src/register_map.c create mode 100644 pa1/src/register_map.h create mode 100644 pa1/src/sim_core.c create mode 100644 pa1/src/sim_core.h create mode 100644 pa1/src/sim_stages.c create mode 100644 pa1/src/sim_stages.h create mode 100644 pa1/src/util.c create mode 100644 pa1/src/util.h create mode 100644 pa1/unittests/basics.asm create mode 100644 pa1/unittests/beq_test.asm create mode 100644 pa1/unittests/blt_bge_test.asm create mode 100644 pa1/unittests/bne_test.asm create mode 100644 pa1/unittests/endian_reverse.asm create mode 100644 pa1/unittests/fibonacci.asm create mode 100644 pa1/unittests/jal_no_link.asm create mode 100644 pa1/unittests/jal_w_link.asm create mode 100644 pa1/unittests/jalr_test.asm create mode 100644 pa1/unittests/lw_sw_test.asm create mode 100644 pa1/unittests/multiplier.asm create mode 100644 pa1/unittests/twos_compliment.asm create mode 100644 pa1/unittests/wordsearch.asm diff --git a/assembler/README.md b/assembler/README.md index 3e88b66..c841ef1 100644 --- a/assembler/README.md +++ b/assembler/README.md @@ -1,52 +1,41 @@ -RISC-V Assembler +Mips Assembler ============== -An assembler for a subset of the RISC-V instruction set architecture +An assembler for a subset of the MIPS like instruction set architecture # How to use -The assembler will take a file written in assembly language as an input on the command line, and will produce an output file containing the RISC-V machine code. The input file should be in ASCII text. Each line in the input assembly file contains either a mnemonic, a section header (such as .data) or a label (jump or branch target). The maximum length of a line is 4 bytes. Section headers such as .data and .text should be in a line by themselves with no other assembly mnemonic. Similarly, branch targets such as loop: will be on a line by themselves with no other assembly mnemonic. The input assembly file should only contain one data section and one text section. The first section in the file will be the .text section, followed by the .data section. +The assembler will take a file written in assembly language as input on the command line and will produce an output file containing the MIPS machine code. The input file should be in ASCII text. Each line in the input assembly file contains either a mnemonic, a section header (such as .data) or a label (jump or branch target. The maximum length of a line is 4 bytes. Section headers such as .data and .text should be in a line by themselves with no other assembly mnemonic. Similarly, branch targets such as loop: will be on a line by themselves with no other assembly mnemonic. The input assembly file should only contain one data section and one text section. The first section in the file will be the .text section, followed by the .data section. The assembler supports the following instruction set: R-Type - add - sub -- slt -- sll -- srl - and - or -- xor +- sll +- slt +- srl +- jr I-Type -- jalr +- lw +- sw +- andi - addi - slti -- andi - ori -- xori -- slli -- srli -- lw - -S-Type -- sw - -B-Type +- lui - beq - bne -- blt -- bge J-Type +- j - jal -U-Type -- lui - # Run to compile the assembler - $ make + $ ./make to run the assembler on a nop.asm assembly file to write machine code in nop.out $ ./assembler nop.asm nop.out diff --git a/assembler/file_parser.c b/assembler/file_parser.c index 25ce8c7..8665963 100644 --- a/assembler/file_parser.c +++ b/assembler/file_parser.c @@ -26,13 +26,13 @@ struct { { "x0", "zero", "00000" }, { "x1", "ra", "00001" }, { "x2", "sp", "00010" }, - { "x3", "gp", "00011" }, - { "x4", "tp", "00100" }, - { "x5", "t0", "00101" }, - { "x6", "t1", "00110" }, - { "x7", "t2", "00111" }, - { "x8", "s0", "01000" }, - { "x9", "s1", "01001" }, + { "x3", "gp", "00011" }, + { "x4", "tp", "00100" }, + { "x5", "t0", "00101" }, + { "x6", "t1", "00110" }, + { "x7", "t2", "00111" }, + { "x8", "s0", "01000" }, + { "x9", "s1", "01001" }, { "x10", "a0", "01010" }, { "x11", "a1", "01011" }, { "x12", "a2", "01100" }, @@ -55,7 +55,7 @@ struct { { "x29", "t4", "11101" }, { "x30", "t5", "11110" }, { "x31", "t6", "11111" }, - { NULL, NULL, 0 } + { NULL, NULL, 0 } }; // Struct for R-Type instructions mapping for the 'function' field in the instruction @@ -73,7 +73,7 @@ struct { { "and", "0000000", "111", "0110011" }, { "or", "0000000", "110", "0110011" }, { "xor", "0000000", "100", "0110011" }, - { NULL, 0 } + { NULL, NULL, NULL, NULL } }; // Struct for I-Type instructions @@ -503,7 +503,7 @@ void parse_file(FILE *fptr, int pass, char *instructions[], size_t inst_len, has // rs1 in position 0, rs2 in position 1 int immediate = (*address - instruction_count + 4) >> 1; //What in tarnation? - btype_instruction(token, reg_store[1], reg_store[0], immediate, Out); + btype_instruction(token, reg_store[0], reg_store[1], immediate, Out); // Dealloc reg_store for (int i = 0; i < 2; i++) { diff --git a/pa1/Makefile b/pa1/Makefile new file mode 100644 index 0000000..a55cdf5 --- /dev/null +++ b/pa1/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/pa1/README.md b/pa1/README.md new file mode 100644 index 0000000..ed97375 --- /dev/null +++ b/pa1/README.md @@ -0,0 +1,27 @@ +# Programming Assignment 1: Non-pipelined riscy-uconn Simulator + +A non-pipelined CPU simulator for the RISC-V 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: + + $ ../assembler/assembler unittests/unit_test_file.asm unittests/unit_test_file.out + +where `unit_test_file` is any of the unit test files (written in riscy-uconn assembly) in the +`unittests` directory. Note that you do not need to store the output files in the `unittests` directory. You may also use the provided `assemble_all.sh' script: + + $ bash assemble_all.sh + +## Usage + $ ./simulator unittests/unit_test_file.out + +where `unit_test_file.out` may be any assembled program file generated by the riscy-uconn +assembler. diff --git a/pa1/assemble_all.sh b/pa1/assemble_all.sh new file mode 100644 index 0000000..32cb46b --- /dev/null +++ b/pa1/assemble_all.sh @@ -0,0 +1,19 @@ +#!/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 + +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/pa1/src/instruction_map.h b/pa1/src/instruction_map.h new file mode 100644 index 0000000..69f10c6 --- /dev/null +++ b/pa1/src/instruction_map.h @@ -0,0 +1,62 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.c + * + * DO NOT MODIFY THIS FILE + * + */ + + +#pragma once + +/* Some helpful defines for decoding instructions */ +#define bit_7 0x00000080 +#define bit_31 0x80000000 +#define bit_20 0x00100000 +#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/pa1/src/register_map.c b/pa1/src/register_map.c new file mode 100644 index 0000000..7517832 --- /dev/null +++ b/pa1/src/register_map.c @@ -0,0 +1,50 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.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/pa1/src/register_map.h b/pa1/src/register_map.h new file mode 100644 index 0000000..97eca99 --- /dev/null +++ b/pa1/src/register_map.h @@ -0,0 +1,16 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.c + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +extern const char* register_map[]; \ No newline at end of file diff --git a/pa1/src/sim_core.c b/pa1/src/sim_core.c new file mode 100644 index 0000000..0ccc0b3 --- /dev/null +++ b/pa1/src/sim_core.c @@ -0,0 +1,257 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.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 +unsigned int pc_n = 0; // Next PC +int *memory = NULL; // Data & instruction memory + +/** + * 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"); + + 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; + int instruction_counter = 0; //committed instruction count + + while (terminate != 1) { + /* Initial cycle state */ + struct State fetch_out = {0}; + struct State decode_out = {0}; + struct State ex_out = {0}; + struct State mem_out = {0}; + + /* Fetch stage */ + fetch_out = fetch(); + cycle++; + + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle %d, PC %d, Next PC %d: ", cycle, pc, pc_n); + inst_dump("[Fetch]", fetch_out.inst); + } + + /* Decode stage */ + decode_out = decode(fetch_out); + cycle++; + + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle %d, PC %d, Next PC %d: ", cycle, pc, pc_n); + inst_dump("[Decode]", decode_out.inst); + } + + /* Execute stage */ + ex_out = execute(decode_out); + cycle++; + + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle %d, PC %d, Next PC %d: ", cycle, pc, pc_n); + inst_dump("[Execute]", ex_out.inst); + } + + /* Memory stage */ + mem_out = memory_stage(ex_out); + cycle++; + + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle %d, PC %d, Next PC %d: ", cycle, pc, pc_n); + inst_dump("[Memory]", mem_out.inst); + } + + /* Writeback stage */ + unsigned int committed_inst; + committed_inst = writeback(mem_out); + cycle++; + + if (pipe_trace == 1) { + fprintf(fptr_pt, "Cycle %d, PC %d, Next PC %d: ", cycle, pc, pc_n); + 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 == 1) + fprintf(stderr, "[DEBUG] Cycle: %d, Instruction Memory Address: %d, Instruction: 0x%08X\n", cycle, pc / 4, fetch_out.inst); + + if ((committed_inst != 0xffffffff) & (committed_inst != nop)) { + instruction_counter++; + } + + if (registers[0] != 0) { + terminate = 1; // set terminate flag when $zero is updated + } + + pc = pc_n; + + 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); +} + +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("===================================="); +} \ No newline at end of file diff --git a/pa1/src/sim_core.h b/pa1/src/sim_core.h new file mode 100644 index 0000000..dd404e4 --- /dev/null +++ b/pa1/src/sim_core.h @@ -0,0 +1,70 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.c + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +#include +#include + +extern FILE *fptr_pt; + +/* Max number of registers, and instruction length in bits */ +#define MAX_LENGTH 32 + +/* nop is encoded as "addi zero, zero, 0" in RISC-V */ +#define nop 0x00000013 + +/* 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 + +/* Instruction and data memory */ +extern int *memory; + +/* 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 Related*/ + unsigned int alu_in1; + unsigned int alu_in2; + unsigned int alu_out; + +}; + +void initialize(FILE *fp); +void process_instructions(); \ No newline at end of file diff --git a/pa1/src/sim_stages.c b/pa1/src/sim_stages.c new file mode 100644 index 0000000..5983dde --- /dev/null +++ b/pa1/src/sim_stages.c @@ -0,0 +1,104 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * TODO: Your Name Here + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.c + * + */ + +#include +#include +#include +#include + +#include "instruction_map.h" +#include "sim_core.h" +#include "sim_stages.h" + +/** + * Debug flags + */ +bool debug = false; // Set to 1 for additional debugging information. +bool pipe_trace = true; // Set to 1 for pipe trace. +int pipe_trace_mode = 3; // Set the pipe trace mode (see the PA1 documentation for more info) + +/** + * Fetch stage implementation. + * DO NOT MODIFY. + */ + +struct State fetch(void) { + + //A new initialized state structure + struct State fetch_out = {0}; + + //Use the current PC to store i) The instruction ii) The instruction's address + fetch_out.inst = memory[pc / 4]; + fetch_out.inst_addr = pc; + + //Advance the program counter and return the state structure + advance_pc(4); + return fetch_out; +} + +/** + * Decode stage implementation + */ +struct State decode(struct State fetch_out) { + + /** + * TODO: Decode the 32-bit instruction (fetch_out.inst). Populate the fetch_out structure as necessary. + */ + + return fetch_out; + +} + +/** + * Execute stage implementation + */ +struct State execute(struct State decode_out) { + + /** + * TODO: Your code for the execute stage here. + */ + + return decode_out; +} + +/** + * Memory stage implementation + */ +struct State memory_stage(struct State ex_out) { + + /** + * TODO: Your code for the memory stage here. + */ + + return ex_out; +} + + +/** + * Writeback stage implementation + */ +unsigned int writeback(struct State mem_out) { + + /** + * TODO: Your code for the writeback stage here. + */ + + return mem_out.inst; +} + +/** + * Advance PC. + * DO NOT MODIFY. + */ +void advance_pc(int step) { + pc_n = pc + step; +} \ No newline at end of file diff --git a/pa1/src/sim_stages.h b/pa1/src/sim_stages.h new file mode 100644 index 0000000..d9447b4 --- /dev/null +++ b/pa1/src/sim_stages.h @@ -0,0 +1,27 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.c + * + * DO NOT MODIFY THIS FILE + * + */ + +#pragma once + +#include "sim_core.h" + +extern bool debug; +extern bool 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 advance_pc(int step); \ No newline at end of file diff --git a/pa1/src/util.c b/pa1/src/util.c new file mode 100644 index 0000000..3c5eda0 --- /dev/null +++ b/pa1/src/util.c @@ -0,0 +1,322 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.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); + + if (inst == 0xffffffff) { + fprintf(fptr_pt, "INVALID INSTRUCTION\n"); + } + + 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/pa1/src/util.h b/pa1/src/util.h new file mode 100644 index 0000000..ef1ac21 --- /dev/null +++ b/pa1/src/util.h @@ -0,0 +1,24 @@ +/** + * University of Connecticut + * CSE 4302/ CSE 5302 / ECE 5402: Computer Architecture + * Fall 2023 + * + * Programming Assignment 1: Non-pipelined Simulator + * + * riscy-uconn: sim_stages.c + * + * 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/pa1/unittests/basics.asm b/pa1/unittests/basics.asm new file mode 100644 index 0000000..76a9192 --- /dev/null +++ b/pa1/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/pa1/unittests/beq_test.asm b/pa1/unittests/beq_test.asm new file mode 100644 index 0000000..800a977 --- /dev/null +++ b/pa1/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/pa1/unittests/blt_bge_test.asm b/pa1/unittests/blt_bge_test.asm new file mode 100644 index 0000000..cff7a7b --- /dev/null +++ b/pa1/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/pa1/unittests/bne_test.asm b/pa1/unittests/bne_test.asm new file mode 100644 index 0000000..c47dcb5 --- /dev/null +++ b/pa1/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/pa1/unittests/endian_reverse.asm b/pa1/unittests/endian_reverse.asm new file mode 100644 index 0000000..3d48125 --- /dev/null +++ b/pa1/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/pa1/unittests/fibonacci.asm b/pa1/unittests/fibonacci.asm new file mode 100644 index 0000000..7afe811 --- /dev/null +++ b/pa1/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/pa1/unittests/jal_no_link.asm b/pa1/unittests/jal_no_link.asm new file mode 100644 index 0000000..99b3503 --- /dev/null +++ b/pa1/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, 257(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/pa1/unittests/jal_w_link.asm b/pa1/unittests/jal_w_link.asm new file mode 100644 index 0000000..f31ce49 --- /dev/null +++ b/pa1/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/pa1/unittests/jalr_test.asm b/pa1/unittests/jalr_test.asm new file mode 100644 index 0000000..b92c021 --- /dev/null +++ b/pa1/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/pa1/unittests/lw_sw_test.asm b/pa1/unittests/lw_sw_test.asm new file mode 100644 index 0000000..2a4bfb8 --- /dev/null +++ b/pa1/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/pa1/unittests/multiplier.asm b/pa1/unittests/multiplier.asm new file mode 100644 index 0000000..42e3bb2 --- /dev/null +++ b/pa1/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/pa1/unittests/twos_compliment.asm b/pa1/unittests/twos_compliment.asm new file mode 100644 index 0000000..8f7b863 --- /dev/null +++ b/pa1/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/pa1/unittests/wordsearch.asm b/pa1/unittests/wordsearch.asm new file mode 100644 index 0000000..3500624 --- /dev/null +++ b/pa1/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