├── .DS_Store ├── .gitmodules ├── LICENSE ├── README.md ├── docs └── TODO.txt ├── hardware ├── .DS_Store ├── Makefile ├── README.md ├── run_all_sims ├── scripts │ ├── audio │ │ ├── archive │ │ │ ├── Blocks.py │ │ │ ├── musicxml_parser.py │ │ │ ├── piano_scale_generator │ │ │ ├── rom_generator │ │ │ ├── synth.py │ │ │ └── synthesizer.py │ │ ├── audio_from_sim │ │ ├── generate_sine_lut │ │ ├── models │ │ │ ├── __pycache__ │ │ │ │ ├── lut.cpython-37.pyc │ │ │ │ ├── nco.cpython-37.pyc │ │ │ │ └── synth.cpython-37.pyc │ │ │ ├── lut.py │ │ │ ├── nco.py │ │ │ ├── synth.py │ │ │ └── utils.py │ │ ├── nco_reference │ │ ├── piano │ │ └── synth_reference │ ├── elaborate.tcl │ ├── hex_to_serial │ ├── impl.tcl │ ├── program.tcl │ ├── program_2021.tcl │ └── synth.tcl ├── sim │ ├── asm_tb.v │ ├── bios_tb.v │ ├── branch_predictor_tb.v │ ├── c_tests_tb.v │ ├── cpu_tb.v │ ├── echo_tb.v │ ├── isa │ │ └── isa_tb.tbi │ ├── isa_tb.v │ ├── mem_path.vh │ ├── mmio_counter_tb.v │ └── uart_parse_tb.v ├── sim_models │ ├── BUFG.v │ ├── PLLE2_ADV.v │ └── glbl.v ├── src │ ├── EECS151.v │ ├── clocks.v │ ├── io_circuits │ │ ├── button_parser.v │ │ ├── debouncer.v │ │ ├── edge_detector.v │ │ ├── fifo.v │ │ ├── synchronizer.v │ │ ├── uart.v │ │ ├── uart_receiver.v │ │ └── uart_transmitter.v │ ├── memories │ │ ├── bios_mem.v │ │ ├── dmem.v │ │ └── imem.v │ ├── riscv_core │ │ ├── branch_prediction │ │ │ ├── bp_cache.v │ │ │ ├── branch_predictor.v │ │ │ └── sat_updn.v │ │ ├── cpu.v │ │ ├── opcode.vh │ │ └── reg_file.v │ ├── z1top.v │ └── z1top.xdc └── stubs │ └── PLLE2_ADV.v ├── scripts ├── hex_to_serial └── init_arm.tcl ├── software ├── .gitignore ├── 151_library │ ├── ascii.c │ ├── ascii.h │ ├── memory_map.h │ ├── string.c │ ├── string.h │ ├── types.h │ ├── uart.c │ └── uart.h ├── Makefrag ├── asm │ ├── Makefile │ ├── asm.ld │ └── start.s ├── bios │ ├── Makefile │ ├── bios.c │ ├── bios.ld │ └── start.s ├── c_tests │ ├── cachetest │ │ ├── Makefile │ │ ├── cachetest.c │ │ ├── cachetest.ld │ │ └── start.s │ ├── fib │ │ ├── Makefile │ │ ├── fib.c │ │ ├── fib.ld │ │ └── start.s │ ├── replace │ │ ├── Makefile │ │ ├── replace.c │ │ ├── replace.ld │ │ └── start.s │ ├── strcmp │ │ ├── Makefile │ │ ├── start.s │ │ ├── strcmp.c │ │ └── strcmp.ld │ ├── sum │ │ ├── Makefile │ │ ├── start.s │ │ ├── sum.c │ │ └── sum.ld │ └── vecadd │ │ ├── Makefile │ │ ├── start.s │ │ ├── vecadd.c │ │ └── vecadd.ld ├── echo │ ├── Makefile │ ├── echo.c │ ├── echo.ld │ └── start.s ├── mmult │ ├── Makefile │ ├── benchmark.c │ ├── benchmark.h │ ├── mmult.c │ ├── mmult.ld │ └── start.s ├── riscv-isa-tests │ ├── Makefile │ └── env_151 │ │ ├── link.ld │ │ └── riscv_test.h └── uart_parse │ ├── Makefile │ ├── start.s │ ├── uart_parse.c │ └── uart_parse.ld └── spec ├── .DS_Store ├── EECS151_FPGA_Project_Fa22.pdf ├── Makefile ├── defines.tex ├── fpga_project.tex ├── images ├── Seal_of_University_of_California_Berkeley.png ├── axi_read.png ├── axi_read_burst.png ├── axi_write.png ├── axi_write_burst.png ├── bios_flow.png ├── branch_predictor.png ├── compute_memif.png ├── conv2D_engine.png ├── conv3D.png ├── ddr_layout.png ├── endianness_img.jpg ├── full_system.png ├── lenet.png ├── lenet_hybrid_flow.png ├── memory_arch.pdf ├── saturating_counter.png ├── vivado-ila-2.png ├── vivado-ila-3.png ├── vivado-ila-4.png ├── vivado-ila-5.png ├── vivado-ila-6.png ├── vivado-ila-7.png ├── vivado-ila-8.png ├── vivado-ila-9.png ├── vivado_bd_z1top_axi.png ├── vivado_ila1.png ├── vivado_ila10.png ├── vivado_ila11.png ├── vivado_ila2.png ├── vivado_ila3.png ├── vivado_ila4.png ├── vivado_ila5.png ├── vivado_ila6.png ├── vivado_ila7.png ├── vivado_ila8.png ├── vivado_ila9.png ├── vivado_ipi0.png ├── vivado_ipi1.png ├── vivado_ipi10.png ├── vivado_ipi11.png ├── vivado_ipi12.png ├── vivado_ipi13.png ├── vivado_ipi14.png ├── vivado_ipi15.png ├── vivado_ipi16.png ├── vivado_ipi17.png ├── vivado_ipi18.png ├── vivado_ipi19.png ├── vivado_ipi2.png ├── vivado_ipi3.png ├── vivado_ipi4.png ├── vivado_ipi5.png ├── vivado_ipi6.png ├── vivado_ipi7.png ├── vivado_ipi8.png └── vivado_ipi9.png ├── isa.tex └── memory_arch.svg /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/.DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "software/riscv-isa-tests/riscv-tests"] 2 | path = software/riscv-isa-tests/riscv-tests 3 | url = https://github.com/riscv/riscv-tests 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, EECS150 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EECS 151/251A FPGA Project Skeleton for Fall 2022 2 | 3 | ## Specs 4 | 5 | Please see ***[/spec/EECS151_FPGA_Project_Fa22.pdf](https://github.com/EECS150/fpga_project_skeleton_fa22/blob/master/spec/EECS151_FPGA_Project_Fa22.pdf)*** for the specifications. Click "More Pages" at the bottom to see the complete pdf. 6 | 7 | ## Deadlines 8 | 9 | **Checkpoint 1:** 3-stage RISC-V (rv32ui) Processor Block Design Diagram & Questions 10 | 11 | **Checkpoint 2:** Fully functional 3-stage RISC-V (rv32ui) Processor 12 | 13 | **Checkpoint 3:** Branch Predictor using Branch History Table 14 | 15 | **Checkpoint 4:** Processor Optimization 16 | 17 | 18 | ## Resources: 19 | 20 | RISC-V Instruction Set Manual: https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf 21 | 22 | Hardware for Machine Learning: https://inst.eecs.berkeley.edu//~ee290-2 23 | 24 | MIT Eyeriss Tutorial: http://eyeriss.mit.edu/tutorial.html 25 | 26 | FPGA Labs FA22: https://github.com/EECS150/fpga_labs_fa22 27 | -------------------------------------------------------------------------------- /docs/TODO.txt: -------------------------------------------------------------------------------- 1 | Push your Block diagram + Report here, then delete this file 2 | -------------------------------------------------------------------------------- /hardware/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/hardware/.DS_Store -------------------------------------------------------------------------------- /hardware/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) -o pipefail 2 | ABS_TOP := $(subst /cygdrive/c/,C:/,$(shell pwd)) 3 | SCRIPTS := $(ABS_TOP)/scripts 4 | VIVADO ?= vivado 5 | VIVADO_OPTS ?= -nolog -nojournal -mode batch 6 | FPGA_PART ?= xc7z020clg400-1 7 | RTL += $(subst /cygdrive/c/,C:/,$(shell find $(ABS_TOP)/src -type f -name "*.v")) 8 | CONSTRAINTS += $(subst /cygdrive/c/,C:/,$(shell find $(ABS_TOP)/src -type f -name "*.xdc")) 9 | TOP ?= z1top 10 | VCS := vcs -full64 11 | VCS_OPTS := -notice -line +lint=all,noVCDE,noNS,noSVA-UA -sverilog -timescale=1ns/10ps -debug +define+ABS_TOP=$(ABS_TOP) +incdir+$(ABS_TOP)/src/riscv_core 12 | SIM_RTL := $(subst /cygdrive/c/,C:/,$(shell find $(ABS_TOP)/sim -type f -name "*.v")) 13 | SIM_MODELS := $(subst /cygdrive/c/,C:/,$(shell find $(ABS_TOP)/sim_models -type f -name "*.v")) 14 | IVERILOG := iverilog 15 | IVERILOG_OPTS := -Ttyp -D IVERILOG=1 -g2012 -gassertions -Wall -Wno-timescale -D ABS_TOP=$(ABS_TOP) -I $(ABS_TOP)/src/riscv_core -I $(ABS_TOP)/sim 16 | VVP := vvp 17 | ISA_TESTS := $(subst /cygdrive/c/,C:/,$(shell find $(ABS_TOP)/../software/riscv-isa-tests -type f -name "*.hex")) 18 | ISA_TESTS_FILES := $(notdir $(ISA_TESTS)) 19 | ISA_TESTS_FST := $(addprefix sim/isa/,$(subst .hex,.fst,$(ISA_TESTS_FILES))) 20 | C_TESTS := $(subst /cygdrive/c/,C:/,$(shell find $(ABS_TOP)/../software/c_tests -type f -name "*.c")) 21 | C_TESTS_FILES := $(notdir $(C_TESTS)) 22 | C_TESTS_FST := $(addprefix sim/c_tests/,$(subst .c,.fst,$(C_TESTS_FILES))) 23 | 24 | sim/%.tb: sim/%.v $(RTL) $(SIM_MODELS) 25 | cd sim && $(VCS) $(VCS_OPTS) -o $*.tb $(RTL) $(SIM_MODELS) $*.v -top $* -top glbl 26 | 27 | sim/%.vpd: sim/%.tb 28 | cd sim && ./$*.tb +verbose=1 +vpdfile+$*.vpd |& tee $*.log 29 | 30 | sim/%.tbi: sim/%.v $(RTL) 31 | cd sim && $(IVERILOG) $(IVERILOG_OPTS) -o $*.tbi $*.v $(RTL) $(SIM_MODELS) 32 | 33 | sim/%.fst: sim/%.tbi 34 | cd sim && $(VVP) $*.tbi -fst |& tee $*.log 35 | 36 | # ISA Tests 37 | sim/isa/isa_tb.tbi: sim/isa_tb.v $(RTL) $(SIM_MODELS) 38 | mkdir -p sim/isa 39 | cd sim/isa && $(IVERILOG) $(IVERILOG_OPTS) -o isa_tb.tbi ../isa_tb.v $(RTL) $(SIM_MODELS) 40 | 41 | sim/isa/%.fst: sim/isa/isa_tb.tbi $(ABS_TOP)/../software/riscv-isa-tests/%.hex 42 | cd sim/isa && $(VVP) isa_tb.tbi -fst +hex_file=$(word 2,$^) +test_name=$(basename $(notdir $(word 2,$^))) |& tee $(basename $(notdir $(word 2,$^))).log 43 | 44 | isa-tests: $(ISA_TESTS_FST) 45 | 46 | # C Tests 47 | sim/c_tests/c_tests_tb.tbi: sim/c_tests_tb.v $(RTL) $(SIM_MODELS) 48 | mkdir -p sim/c_tests 49 | cd sim/c_tests && $(IVERILOG) $(IVERILOG_OPTS) -o c_tests_tb.tbi ../c_tests_tb.v $(RTL) $(SIM_MODELS) 50 | 51 | sim/c_tests/%.fst: sim/c_tests/c_tests_tb.tbi $(ABS_TOP)/../software/c_tests/% 52 | cd sim/c_tests && $(VVP) c_tests_tb.tbi -fst +hex_file=$(word 2,$^)/$*.hex +test_name=$(basename $(notdir $(word 2,$^))) |& tee $(basename $(notdir $(word 2,$^))).log 53 | 54 | c-tests: $(C_TESTS_FST) 55 | 56 | build/target.tcl: $(RTL) $(CONSTRAINTS) 57 | mkdir -p build 58 | truncate -s 0 $@ 59 | echo "set ABS_TOP $(ABS_TOP)" >> $@ 60 | echo "set TOP $(TOP)" >> $@ 61 | echo "set FPGA_PART $(FPGA_PART)" >> $@ 62 | echo "set_param general.maxThreads 4" >> $@ 63 | echo "set_param general.maxBackupLogs 0" >> $@ 64 | echo -n "set RTL { " >> $@ 65 | FLIST="$(RTL)"; for f in $$FLIST; do echo -n "$$f " ; done >> $@ 66 | echo "}" >> $@ 67 | echo -n "set CONSTRAINTS { " >> $@ 68 | FLIST="$(CONSTRAINTS)"; for f in $$FLIST; do echo -n "$$f " ; done >> $@ 69 | echo "}" >> $@ 70 | 71 | setup: build/target.tcl 72 | 73 | elaborate: build/target.tcl $(SCRIPTS)/elaborate.tcl 74 | mkdir -p ./build 75 | cd ./build && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/elaborate.tcl |& tee elaborate.log 76 | 77 | build/synth/$(TOP).dcp: build/target.tcl $(SCRIPTS)/synth.tcl 78 | mkdir -p ./build/synth/ 79 | cd ./build/synth/ && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/synth.tcl |& tee synth.log 80 | 81 | synth: build/synth/$(TOP).dcp 82 | 83 | build/impl/$(TOP).bit: build/synth/$(TOP).dcp $(SCRIPTS)/impl.tcl 84 | mkdir -p ./build/impl/ 85 | cd ./build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/impl.tcl |& tee impl.log 86 | 87 | impl: build/impl/$(TOP).bit 88 | all: build/impl/$(TOP).bit 89 | 90 | program: build/impl/$(TOP).bit $(SCRIPTS)/program.tcl 91 | cd build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/program.tcl 92 | 93 | program-force: 94 | cd build/impl && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/program.tcl 95 | 96 | vivado: build 97 | cd build && nohup $(VIVADO) /dev/null 2>&1 & 98 | 99 | lint: 100 | verilator -DABS_TOP=$(ABS_TOP) --lint-only --top-module $(TOP) $(RTL) -I$(ABS_TOP)/src/riscv_core $(ABS_TOP)/stubs/PLLE2_ADV.v $(ABS_TOP)/sim_models/BUFG.v 101 | 102 | sim_build/compile_simlib/synopsys_sim.setup: 103 | mkdir -p sim_build/compile_simlib 104 | cd build/sim_build/compile_simlib && $(VIVADO) $(VIVADO_OPTS) -source $(SCRIPTS)/compile_simlib.tcl 105 | 106 | compile_simlib: sim_build/compile_simlib/synopsys_sim.setup 107 | 108 | screen: 109 | screen /dev/ttyUSB0 115200 110 | 111 | clean-sim: 112 | rm -rf *.daidir sim/output.txt \ 113 | sim/*.tb sim/*.daidir sim/csrc \ 114 | sim/ucli.key sim/*.vpd sim/*.vcd \ 115 | sim/*.tbi sim/*.fst sim/*.jou sim/*.log sim/*.out \ 116 | sim/isa sim/c_tests 117 | 118 | clean-build: 119 | rm -rf ./build 120 | 121 | .PHONY: setup synth impl program program-force vivado all clean-build clean-sim %.tb 122 | .PRECIOUS: sim/%.tb sim/%.tbi sim/%.fst sim/%.vpd 123 | -------------------------------------------------------------------------------- /hardware/run_all_sims: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from subprocess import run, CompletedProcess 4 | from os import remove, makedirs, path 5 | from shutil import rmtree 6 | from typing import Callable 7 | import argparse 8 | 9 | RESULT_DIR = "test_results" 10 | 11 | 12 | def run_bench( 13 | name: str, cleanup: Callable[[], None], success_cond: Callable[[str], bool] 14 | ) -> None: 15 | """Runs a particular testbench 16 | 17 | 'name': used in the command `make {name}` 18 | 'cleanup': function to delete testbench output of the previous run 19 | 'success_cond': takes in the stdout of running a testbench 20 | returns whether the run was successful 21 | """ 22 | print(f"Running make {name}: ", end="") 23 | cleanup() 24 | proc = run(["make", name], capture_output=True) 25 | stdout = proc.stdout.decode("utf-8") 26 | stderr = proc.stderr.decode("utf-8") 27 | with open(path.join(RESULT_DIR, f'{name.split("/")[-1]}.out'), "w") as fout: 28 | fout.write(stdout) 29 | with open(path.join(RESULT_DIR, f'{name.split("/")[-1]}.err'), "w") as ferr: 30 | ferr.write(stderr) 31 | if not success_cond(stdout): 32 | print(f"Failed") 33 | print("stdout:") 34 | print(stdout) 35 | print("stderr:") 36 | print(stderr) 37 | print(f"See {RESULT_DIR} for logs") 38 | exit(1) 39 | else: 40 | print("Passed") 41 | 42 | 43 | def cleanup_isa_tests() -> None: 44 | rmtree("sim/isa", ignore_errors=True) 45 | 46 | 47 | def cleanup_c_tests() -> None: 48 | rmtree("sim/c_tests", ignore_errors=True) 49 | 50 | 51 | def get_grep_output(proc: CompletedProcess) -> str: 52 | stdout = proc.stdout.decode("utf-8").strip() 53 | return stdout.split("\n") 54 | 55 | 56 | def isa_test_success_cond(_: str) -> bool: 57 | proc_failed = run( 58 | 'grep -r -i "failed" sim/isa/*.log', shell=True, capture_output=True 59 | ) 60 | proc_timout = run( 61 | 'grep -r -i "timeout" sim/isa/*.log', shell=True, capture_output=True 62 | ) 63 | tests_failed = get_grep_output(proc_failed) + get_grep_output(proc_timout) 64 | filtered_tests = list( 65 | filter(lambda l: ("fence_i" not in l) and l != "", tests_failed) 66 | ) 67 | if filtered_tests: 68 | return False 69 | return True 70 | 71 | 72 | def c_test_success_cond(_: str) -> bool: 73 | proc_failed = run( 74 | 'grep -r -i "failed" sim/c_tests/*.log', shell=True, capture_output=True 75 | ) 76 | proc_timout = run( 77 | 'grep -r -i "timeout" sim/c_tests/*.log', shell=True, capture_output=True 78 | ) 79 | tests_failed = get_grep_output(proc_failed) + get_grep_output(proc_timout) 80 | filtered_tests = list(filter(lambda l: l != "", tests_failed)) 81 | if filtered_tests: 82 | return False 83 | return True 84 | 85 | 86 | def silent_remove_factory(testbench: str, simulator: str) -> Callable[[], None]: 87 | def foo(): 88 | try: 89 | if simulator == "vcs": 90 | remove(f"sim/{testbench}.tb") 91 | remove(f"sim/{testbench}.vpd") 92 | else: 93 | remove(f"sim/{testbench}.tbi") 94 | remove(f"sim/{testbench}.fst") 95 | remove(f"sim/{testbench}.log") 96 | except OSError: 97 | pass 98 | 99 | return foo 100 | 101 | 102 | def main(): 103 | makedirs(RESULT_DIR, exist_ok=True) 104 | parser = argparse.ArgumentParser(description="Run all RTL simulations and perform checks") 105 | parser.add_argument("--simulator", type=str, choices=["vcs", "iverilog"], default="vcs", help="The RTL simulator to use") 106 | args = parser.parse_args() 107 | waveform_suffix = "vpd" if args.simulator == "vcs" else "fst" 108 | run_bench( 109 | f"sim/cpu_tb.{waveform_suffix}", 110 | silent_remove_factory("cpu_tb", args.simulator), 111 | lambda stdout: "All tests passed!" in stdout, 112 | ) 113 | run_bench( 114 | f"sim/asm_tb.{waveform_suffix}", 115 | silent_remove_factory("asm_tb", args.simulator), 116 | lambda stdout: "ALL ASSEMBLY TESTS PASSED!" in stdout, 117 | ) 118 | run_bench("isa-tests", cleanup_isa_tests, isa_test_success_cond) 119 | run_bench("c-tests", cleanup_c_tests, c_test_success_cond) 120 | run_bench( 121 | f"sim/echo_tb.{waveform_suffix}", 122 | silent_remove_factory("echo_tb", args.simulator), 123 | lambda stdout: "Test passed!" in stdout, 124 | ) 125 | run_bench( 126 | f"sim/uart_parse_tb.{waveform_suffix}", 127 | silent_remove_factory("uart_parse_tb", args.simulator), 128 | lambda stdout: "CSR test PASSED! Strings matched." in stdout, 129 | ) 130 | run_bench( 131 | f"sim/bios_tb.{waveform_suffix}", 132 | silent_remove_factory("bios_tb", args.simulator), 133 | lambda stdout: "BIOS testbench done! Num failed tests: 0" in stdout, 134 | ) 135 | print("All tests passed!") 136 | 137 | 138 | if __name__ == "__main__": 139 | main() 140 | -------------------------------------------------------------------------------- /hardware/scripts/audio/archive/Blocks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from nco import NCOType, output_type 3 | from FixedPoint import FXfamily, FXnum 4 | import numpy as np 5 | 6 | class Summer: 7 | def __init__(self, sine_shift: int, square_shift: int, triangle_shift: int, sawtooth_shift: int) -> None: 8 | self.shifts = [sine_shift, square_shift, triangle_shift, sawtooth_shift] 9 | 10 | def next_sample(self, nco_in: NCOType) -> FXnum: 11 | sample = FXnum(0, family=output_type) 12 | for wave,shift in zip(nco_in, self.shifts): 13 | sample = sample + (wave >> shift) 14 | return sample 15 | 16 | class Truncator: 17 | def __init__(self, global_gain: int) -> None: 18 | self.global_gain = global_gain 19 | 20 | def next_sample(self, samp_in: FXnum) -> int: 21 | samp_gained = samp_in >> self.global_gain 22 | sample_bin = samp_gained.toBinaryString().replace('.', '') 23 | sample_bin_msbs = sample_bin[:12] 24 | #print("Sample bin: ", sample_bin) 25 | #print("MSB int val: ", int(sample_bin_msbs, 2)) 26 | if sample_bin_msbs[0] == '1': # negative number 27 | return (~(-1*int(sample_bin_msbs, 2)) + 1) - 2**11 28 | else: # positive number 29 | return int(sample_bin_msbs, 2) + 2**11 30 | 31 | if __name__ == "__main__": 32 | print("Testing truncator sweep") 33 | t = Truncator(0) 34 | for x in np.linspace(-8, 7.9, 10): 35 | print(t.next_sample(FXnum(x, output_type))) 36 | print("Testing truncator critical values") 37 | for x in [-8, 0, 8 - 2**-16]: 38 | print(t.next_sample(FXnum(x, output_type))) 39 | 40 | print("Testing summer") 41 | s = Summer(0, 32, 32, 32) 42 | for sample in np.linspace(-1, 1, 1000): 43 | out = s.next_sample([FXnum(sample, output_type), FXnum(-1, output_type), FXnum(-1, output_type), FXnum(-1, output_type)]) 44 | assert abs(out - sample) < 1e-4 45 | -------------------------------------------------------------------------------- /hardware/scripts/audio/archive/musicxml_parser.py: -------------------------------------------------------------------------------- 1 | import wave 2 | import random 3 | import struct 4 | import sys 5 | import zipfile 6 | from xml.dom import minidom 7 | import os 8 | import glob 9 | import shutil 10 | 11 | step_to_int = { 12 | 'A': 1, 13 | 'B': 3, 14 | 'C': 4, 15 | 'D': 6, 16 | 'E': 8, 17 | 'F': 9, 18 | 'G': 11 19 | } 20 | 21 | # Remove the temp directory from previous runs 22 | if (os.path.isdir('temp/')): 23 | shutil.rmtree('temp/') 24 | 25 | # Fetch the filepath to the compressed MusicXML file (.mxl) 26 | musicxml_filepath = sys.argv[1] 27 | 28 | # Fetch the filepath to the generated memory contents file 29 | memory_contents_filepath = sys.argv[2] 30 | 31 | # Unzip the compressed file to the temp directory 32 | zip_ref = zipfile.ZipFile(musicxml_filepath, 'r') 33 | zip_ref.extractall('temp/') 34 | zip_ref.close() 35 | 36 | # Fetch and parse the XML file in the temp directory 37 | xml_filepath = glob.glob("temp/*.xml") 38 | #print(xml_filepath) 39 | xmldoc = minidom.parse(xml_filepath[0]) 40 | 41 | # Print the XML tree for debugging 42 | #print(xmldoc.toprettyxml()) 43 | 44 | # For the first part in the sheet music 45 | parts = xmldoc.getElementsByTagName('part')[0] 46 | 47 | notes = [] 48 | 49 | # Loop through every measure and pull each note 50 | for measure in parts.getElementsByTagName('measure'): 51 | print("measure %s" % (measure.getAttribute('number'))) 52 | for note in measure.getElementsByTagName('note'): 53 | rest_check = note.getElementsByTagName('rest') 54 | if (len(rest_check) > 0): 55 | duration = int(note.getElementsByTagName('duration')[0].childNodes[0].nodeValue) 56 | print("\trest note, duration %d" % (duration)) 57 | notes += [(0, 0, 0, duration)] 58 | else: 59 | note_pitch = note.getElementsByTagName('pitch').item(0) 60 | step = note_pitch.getElementsByTagName('step')[0].childNodes[0].nodeValue 61 | octave = int(note_pitch.getElementsByTagName('octave')[0].childNodes[0].nodeValue) 62 | alter = note_pitch.getElementsByTagName('alter') 63 | if (len(alter) > 0): 64 | alter = int(alter[0].childNodes[0].nodeValue) 65 | else: 66 | alter = 0 67 | duration = int(note.getElementsByTagName('duration')[0].childNodes[0].nodeValue) 68 | note_type = note.getElementsByTagName('type')[0].childNodes[0].nodeValue 69 | print("\tnote with step %s octave %d alter %d duration %d type %s" % (step, octave, alter, duration, note_type)) 70 | notes += [(step, octave, alter, duration)] 71 | 72 | note_list = [] 73 | for note in notes: 74 | if (note[0] == 0): 75 | note_list += [(0, note[3])] 76 | else: 77 | semitone_above_below_middle_C = step_to_int[note[0]] - step_to_int['C'] + note[2] 78 | if (step_to_int[note[0]] >= step_to_int['C']): 79 | note_number = semitone_above_below_middle_C + ((note[1] - 4) * 12) 80 | else: 81 | note_number = semitone_above_below_middle_C + ((note[1] - 3) * 12) 82 | note_number = note_number + 40 83 | frequency = (2 ** ((float(note_number) - 49.0)/12.0)) * 440.0 84 | note_list += [(int(frequency), note[3])] 85 | 86 | print("note_list (frequency, duration)\n") 87 | print(note_list) 88 | 89 | # Translate each note to the equivalent frequency and to the individual half-periods of 32nd notes 90 | with open(memory_contents_filepath, 'w') as memory_file: 91 | for note in note_list: 92 | if (note[0] == 0): 93 | for i in range(0, 4 * note[1]): 94 | memory_file.write(str(0) + "\n") 95 | continue 96 | # Write the note in terms of tone_switch_period (125 Mhz clock) 97 | for i in range(0, 4 * note[1]): 98 | memory_file.write(str(int(125e6/note[0]/2)) + "\n") 99 | # Write a note pause for each note corresponding to its duration 100 | for i in range(0, note[1]): 101 | memory_file.write(str(0) + "\n") 102 | 103 | # Remove the temp directory from current run 104 | if (os.path.isdir('temp/')): 105 | shutil.rmtree('temp/') 106 | -------------------------------------------------------------------------------- /hardware/scripts/audio/archive/piano_scale_generator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import wave 4 | import random 5 | import struct 6 | import sys 7 | import math 8 | 9 | """ 10 | This script will generate a text file to be fed into the rom_generator.py script. 11 | It will print out the keyboard letter mappings in ASCII to piano notes. The piano notes 12 | are stored in terms of tone_switch_periods for a given clock frequency. 13 | """ 14 | output_file = sys.argv[1] 15 | # Can supply custom clock frequency, otherwise defaults to 125 Mhz 16 | if len(sys.argv) > 2: 17 | clock_freq = float(sys.argv[2]) 18 | else: 19 | clock_freq = 125.0e6 20 | 21 | piano_output_file = open(output_file, 'w') 22 | for ascii_index in range(256): 23 | if chr(ascii_index) in note_map: 24 | note_freq = note_map[chr(ascii_index)] 25 | note_fcw = (note_freq / (125e6 / 1024)) * (2**24) 26 | piano_output_file.write(str(int(round(note_fcw))) + "\n") 27 | else: 28 | piano_output_file.write("0\n") 29 | 30 | piano_output_file.close() 31 | -------------------------------------------------------------------------------- /hardware/scripts/audio/archive/rom_generator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import wave 4 | import random 5 | import struct 6 | import sys 7 | import math 8 | 9 | generated_verilog_filepath = sys.argv[2] 10 | memory_file = sys.argv[1] 11 | memory_depth = int(sys.argv[3]) 12 | memory_width = int(sys.argv[4]) 13 | address_bits = int(math.ceil(math.log(memory_depth, 2))) 14 | data_bits = memory_width 15 | 16 | with open(memory_file, 'r') as memory_data: 17 | data = memory_data.read() 18 | 19 | data = data.split('\n') 20 | 21 | verilog_file = open(generated_verilog_filepath, 'w') 22 | verilog_file.write("module rom (input [%d:0] address, output reg [%d:0] data, output [%d:0] last_address);\n" % (address_bits - 1, data_bits - 1, address_bits - 1)) 23 | verilog_file.write(" assign last_address = %d;\n" % (min(len(data) - 1, memory_depth - 1))) 24 | verilog_file.write(" always @ (*) begin\n") 25 | verilog_file.write(" case(address)\n") 26 | 27 | for i in range(0, memory_depth): 28 | if (i >= len(data) or len(data[i]) == 0): # Write a 0 29 | verilog_file.write(" %d'd%d: data = %d'd%d;\n" % (address_bits, i, data_bits, 0)) 30 | else: 31 | verilog_file.write(" %d'd%d: data = %d'd%d;\n" % (address_bits, i, data_bits, int(data[i]))) 32 | 33 | verilog_file.write(" endcase\n") 34 | verilog_file.write(" end\n") 35 | verilog_file.write("endmodule\n") 36 | verilog_file.close() 37 | 38 | -------------------------------------------------------------------------------- /hardware/scripts/audio/archive/synth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from dataclasses import dataclass 4 | from nco import NCO, output_type 5 | from Blocks import Summer, Truncator 6 | from FixedPoint import FXnum 7 | import wave 8 | import struct 9 | 10 | @dataclass 11 | class Patch: 12 | sine_shift: int 13 | square_shift: int 14 | triangle_shift: int 15 | sawtooth_shift: int 16 | global_gain: int 17 | 18 | pure_sine = Patch(0, 32, 32, 32, 0) 19 | pure_triangle = Patch(32, 32, 0, 32, 0) 20 | harmonics = Patch(0, 0, 32, 32, 0) 21 | 22 | 23 | 24 | # A base models that doesn't use the truncator at the end 25 | class Synth: 26 | def __init__(self, fsamp: float, patch: Patch) -> None: 27 | self.nco = NCO(fsamp, interpolate = True) 28 | self.summer = Summer(patch.sine_shift, patch.square_shift, patch.triangle_shift, patch.sawtooth_shift) 29 | self.truncator = Truncator(patch.global_gain) 30 | self.playing_note = False 31 | self.note_freq = 0 32 | 33 | def start_note(self, freq: float) -> None: 34 | self.nco.reset() 35 | self.note_freq = freq 36 | self.playing_note = True 37 | 38 | def release_note(self) -> None: 39 | self.playing_note = False 40 | 41 | def next_sample(self) -> int: 42 | nco_out = self.nco.next_sample_f(self.note_freq) 43 | summer_out = self.summer.next_sample(nco_out) 44 | if self.playing_note: 45 | return summer_out 46 | else: 47 | return FXnum(0, output_type) 48 | 49 | # A monophonic models that uses the truncator at the output of 1 base models 50 | class MonoSynth(Synth): 51 | def next_sample(self) -> int: 52 | nco_out = self.nco.next_sample_f(self.note_freq) 53 | summer_out = self.summer.next_sample(nco_out) 54 | truncator_out = self.truncator.next_sample(summer_out) 55 | if self.playing_note: 56 | return int(truncator_out) 57 | else: 58 | return 0 59 | 60 | # A polyphonic models that uses the truncator at the output of N base synths after summing 61 | class PolySynth: 62 | def __init__(self, fsamp: float, patch: Patch, polyphony: int) -> None: 63 | self.synths = [Synth(fsamp, patch) for s in range(polyphony)] 64 | self.active = [False]*polyphony 65 | self.notes = [0]*polyphony 66 | self.truncator = Truncator(patch.global_gain) 67 | 68 | def start_note(self, freq: float) -> None: 69 | for idx,synth in enumerate(self.synths): 70 | if not self.active[idx]: 71 | synth.start_note(freq) 72 | self.active[idx] = True 73 | self.notes[idx] = freq 74 | break 75 | 76 | def release_note(self, freq: float) -> None: 77 | for idx,note in enumerate(self.notes): 78 | if freq == note and self.active[idx]: 79 | self.synths[idx].release_note() 80 | self.active[idx] = False 81 | self.notes[idx] = freq 82 | break 83 | 84 | def next_sample(self) -> int: 85 | sample = FXnum(0, output_type) 86 | for synth in self.synths: 87 | sample = sample + synth.next_sample() 88 | return self.truncator.next_sample(sample) 89 | 90 | if __name__ == "__main__": 91 | fsamp = 30e3 92 | 93 | s = MonoSynth(fsamp, pure_sine) 94 | #s = PolySynth(fsamp, pure_sine, 4) 95 | s.start_note(220) 96 | samples = [s.next_sample() for x in range(10000)] 97 | s.start_note(440) 98 | samples.extend([s.next_sample() for x in range(10000)]) 99 | s.start_note(880) 100 | samples.extend([s.next_sample() for x in range(10000)]) 101 | 102 | for s in samples: 103 | print(s) 104 | 105 | output_wav = wave.open('models.wav','w') 106 | output_wav.setparams((2,2,int(fsamp),0,'NONE','not compressed')) 107 | values = [] 108 | for s in samples: 109 | result = int(s) 110 | packed_value = struct.pack('h',result) 111 | values.append(packed_value) 112 | values.append(packed_value) 113 | value_str = b''.join(values) 114 | output_wav.writeframes(value_str) 115 | output_wav.close() 116 | 117 | import matplotlib.pyplot as plt 118 | plt.plot(samples) 119 | plt.show() 120 | -------------------------------------------------------------------------------- /hardware/scripts/audio/archive/synthesizer.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | from scipy import signal 4 | import matplotlib.pyplot as plt 5 | import random 6 | import wave 7 | import struct 8 | import sys 9 | 10 | # This function converts a number to fixed point representation of a certain 11 | # resolution. The numbers are limited to between -1 and 1, so there is no 12 | # integer but only fractions. 13 | def resolution_limit(number, res): 14 | sign = 0 15 | if (number < 0): 16 | sign = 1 17 | 18 | number = abs(number) 19 | bin_rep = [] 20 | for i in range(res): 21 | if (number >= 1/(2**(i+1))): 22 | number = number - 1/(2**(i+1)) 23 | bin_rep.append(1) 24 | else: 25 | bin_rep.append(0) 26 | 27 | result = 0 28 | for j in range(res): 29 | result += 1/(2**(j+1))*bin_rep[j] 30 | 31 | return -1*result if sign else result 32 | 33 | 34 | # This function generates three types of waves: sine, square and sawtooth for a 35 | # given time point and frequency 36 | def wave_generator(time, melody, time_unit, signal_type): 37 | 38 | # sine wave 39 | if (signal_type == 1): 40 | wave_out = math.sin(2 * math.pi * melody * time * time_unit) 41 | 42 | # square wave 43 | elif (signal_type == 2): 44 | if ((time * time_unit) % (1/melody) < (1/melody)/2): 45 | wave_out = 1 46 | else: 47 | wave_out = -1 48 | 49 | # sawtooth wave 50 | elif (signal_type == 3): 51 | wave_out = 2*melody*((time_unit*time)%(1/melody))-1 52 | else: 53 | wave_out = 0 54 | 55 | return wave_out 56 | 57 | 58 | # State Variable Filter 59 | def svf(din, res): 60 | 61 | # coefficients F and Q 62 | F = 2*math.sin(math.pi*fc*time_unit) 63 | F = resolution_limit(F, res) 64 | # a typical number of Q is sqrt(2), but it would require more complicated 65 | # arithmetic, so we use 1 for simplicity 66 | Q = 1 67 | 68 | # x[n] - yl[n] - Q*yb[n] 69 | yh = din[0] - din[1] - Q * din[2] 70 | # limit resolution after each operation to avoid overflow 71 | yh = resolution_limit(yh,res) 72 | 73 | # F*yh[n] + yb[n-1] 74 | yb = F * yh + din[2] 75 | yb = resolution_limit(yb,res) 76 | 77 | # F*yb[n-1] + yl[n-1] 78 | yl = F * yb + din[1] 79 | yl = resolution_limit(yl,res) 80 | 81 | return [yl, yb, yh] 82 | 83 | # melody (integer): tone to play 84 | # attack_release (tuple): absolute time for attack and release 85 | # fc (integer): corner frequency of SVF filter 86 | # time_unit (float): sampling period of input signal 87 | # res: resolution of data and coefficient 88 | def synthesizer(melody, attack_release, fc, time_unit, res): 89 | 90 | # input wave 91 | waves = np.zeros((len(melody)+1,),dtype=np.float64) 92 | # Final output 93 | waves_out = np.zeros((len(melody)+1,),dtype=np.float64) 94 | # lowpass output of SVF 95 | waves_lp = np.zeros((len(melody)+1,),dtype=np.float64) 96 | # highpass output of SVF 97 | waves_hp = np.zeros((len(melody)+1,),dtype=np.float64) 98 | # bandpass output of SVF 99 | waves_bp = np.zeros((len(melody)+1,),dtype=np.float64) 100 | state = 0 101 | 102 | for time in range(len(melody)): 103 | 104 | # generates wave based on frequency 105 | wave = wave_generator(time, melody[time], time_unit, 1) 106 | wave = resolution_limit(wave,res) 107 | waves[time] = wave 108 | 109 | # Pass data through SVF filter 110 | if (time == 0): 111 | [yl, yb, yh] = svf([wave, 0.0, 0.0, 0.0], res) 112 | else: 113 | [yl, yb, yh] = svf([wave, waves_lp[time-1], waves_bp[time-1], waves_hp[time-1]], res) 114 | 115 | waves_lp[time] = yl 116 | waves_hp[time] = yh 117 | waves_bp[time] = yb 118 | 119 | 120 | # A(D)SR: in this section, we implement attack, sustain and release. 121 | # "attack_release" is a tuple that contains the attack and release time, 122 | # in hardware this will be implemented as key press and key release. 123 | # The duration of attack and release is customizable. 124 | 125 | # state --- 0: quiet, 1: attack, 2: sustain, 3: release 126 | 127 | if (time == attack_release[0]): 128 | state = 1 129 | elif ((time - attack_release[0]) == 4096): # play with this number to mimic actual instrument 130 | state = 2 131 | elif (time == attack_release[1]): 132 | state = 3 133 | elif ((time - attack_release[1]) == 4096): 134 | state = 0 135 | 136 | # change output based on state 137 | if (state == 0): 138 | waves_out[time] = 0 139 | elif (state == 1): 140 | waves_out[time] = waves_lp[time] * (time - attack_release[0]) * 0.000244140625 # 1/4096 in fixed point 141 | elif (state == 2): 142 | waves_out[time] = waves_lp[time] 143 | elif (state == 3): 144 | waves_out[time] = waves_lp[time] * (4096 - time + attack_release[1]) * 0.000244140625 145 | else: 146 | waves_out[time] = 0 147 | 148 | time = time + 1 149 | return waves, waves_out 150 | 151 | 152 | 153 | ############################################################################################################### 154 | 155 | 156 | fs = 44100 # sampling frequency 44.1KHz 157 | time_unit = 1/fs # sampling period 158 | res = 9 # resolution of data & coefficient 159 | melody = [100] * 60000 # array of frequencies to be played (100Hz) 160 | fc = 10000 # corner frequency of filter, play with this yourself 161 | attack,release = (1000,30000) # onset time of attack and release 162 | waves, waves_out = synthesizer(melody, (attack,release), fc, time_unit, res) 163 | plt.plot(waves) 164 | plt.plot(waves_out) 165 | plt.show() 166 | 167 | # write to wav file 168 | output_wav = wave.open('piano_note.wav','w') 169 | output_wav.setparams((2,2,44100,0,'NONE','not compressed')) 170 | values = [] 171 | for note in waves_out: 172 | result = int(note * 20000) 173 | packed_value = struct.pack('h',result) 174 | values.append(packed_value) 175 | values.append(packed_value) 176 | 177 | value_str = b''.join(values) 178 | output_wav.writeframes(value_str) 179 | output_wav.close() 180 | sys.exit(0) 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /hardware/scripts/audio/audio_from_sim: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import wave 3 | import argparse 4 | import struct 5 | # import matplotlib.pyplot as plt 6 | 7 | if __name__ == "__main__": 8 | parser = argparse.ArgumentParser( 9 | description='Convert a text file of binary samples to an audio file', 10 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 11 | parser.add_argument('--f-samp', default=60000, type=float, help="Sampling frequency") 12 | # parser.add_argument('--num-int-bits', default=9, type=int, help="Number of integer bits (including sign) for each sample") 13 | # parser.add_argument('--num-frac-bits', default=3, type=int, help="Number of fractional bits for each sample") 14 | parser.add_argument('input_file', type=str, help="Input .txt file path") 15 | parser.add_argument('output_file', default="output.wav", type=str, help="Output .wav file path") 16 | args = parser.parse_args() 17 | 18 | def renormalize(n, range1, range2): 19 | delta1 = range1[1] - range1[0] 20 | delta2 = range2[1] - range2[0] 21 | return (delta2 * (n - range1[0]) / delta1) + range2[0] 22 | 23 | def bin_str_to_sint(bin_str: str) -> int: 24 | # extend binary string to 32 bits 25 | bin_str = bin_str + '0' * (32 - len(bin_str)) 26 | # interpret as unsigned 32-bit integer 27 | unsigned_bytes = struct.pack("I", int(bin_str, 2)) 28 | # cast to signed 32-bit value 29 | return struct.unpack("i", unsigned_bytes)[0] 30 | 31 | with open(args.input_file, 'r') as samples_file: 32 | samples_bin_str = [line.rstrip('\n') for line in samples_file] 33 | # assert all(len(x) == args.num_int_bits + args.num_frac_bits for x in samples_bin_str) 34 | 35 | samples = [bin_str_to_sint(x) for x in samples_bin_str] 36 | # print(min(samples), max(samples)) 37 | # plt.plot(samples_scaled) 38 | # plt.show() 39 | 40 | samples_scaled = [renormalize(s, (-2**31, 2**31-1), (-2**15, 2**15-1)) for s in samples] 41 | samples_packed = [struct.pack(' List[FXnum]: 22 | raise NotImplementedError 23 | 24 | def binary_entries(self) -> List[str]: 25 | return [x.toBinaryString().replace('.', '') for x in self.data] 26 | 27 | def __getitem__(self, idx: int) -> FXnum: 28 | return self.data[idx] 29 | 30 | @property 31 | def addr_bits(self) -> int: 32 | return int(math.log2(self.num_rows)) 33 | 34 | 35 | class SineLUT(LUT): 36 | def generate(self) -> List[FXnum]: 37 | sine_lut_float = [np.sin(i * 2 * np.pi / self.num_rows) for i in range(self.num_rows)] 38 | return [FXnum(x, family=self.data_type) for x in sine_lut_float] 39 | 40 | 41 | # TODO: the three LUT types below don't work properly 42 | class SquareLUT(LUT): 43 | def generate(self) -> List[FXnum]: 44 | return [FXnum(1, family=self.data_type) for x in range(int(self.num_rows / 2))] + \ 45 | [FXnum(-1, family=self.data_type) for x in range(int(self.num_rows / 2))] 46 | 47 | 48 | class TriangleLUT(LUT): 49 | def generate(self) -> List[FXnum]: 50 | triangle_lut_float = [np.max(1 - np.abs(x)) for x in np.linspace(-1, 1, self.num_rows)] 51 | triangle_lut_float = [x * 2 - 1 for x in triangle_lut_float] # scale to range from -1 to 1 52 | return [FXnum(x, family=self.data_type) for x in triangle_lut_float] 53 | 54 | 55 | class SawtoothLUT(LUT): 56 | def generate(self) -> List[FXnum]: 57 | sawtooth_lut_float = [x - np.floor(x) for x in np.linspace(0, 1 - 1e-16, self.num_rows)] 58 | sawtooth_lut_float = [x * 2 - 1 for x in sawtooth_lut_float] # scaling again 59 | return [FXnum(x, family=self.data_type) for x in sawtooth_lut_float] 60 | -------------------------------------------------------------------------------- /hardware/scripts/audio/models/nco.py: -------------------------------------------------------------------------------- 1 | # Requires: pip install spfpm 2 | from typing import List, Optional 3 | from dataclasses import dataclass 4 | 5 | from FixedPoint import FXnum 6 | 7 | from models.lut import LUT 8 | 9 | 10 | @dataclass 11 | class NCO: 12 | luts: List[LUT] 13 | fsamp: float = 150e6 / 2500 # 60 kHz 14 | pa_bits: int = 24 15 | interpolate: bool = False 16 | pa: int = 0 17 | 18 | @property 19 | def max_pa_value(self) -> int: 20 | return 2**self.pa_bits - 1 21 | 22 | @property 23 | def zero(self) -> FXnum: 24 | return FXnum(0, family=self.luts[0].data_type) 25 | 26 | def __post_init__(self): 27 | assert len(set(x.data_type for x in self.luts)) == 1 # all LUTs should share the same number format 28 | assert len(set(x.num_rows for x in self.luts)) == 1 # all LUTs should have the same depth 29 | self.lut_addr_bits = self.luts[0].addr_bits 30 | 31 | def reset(self) -> None: 32 | self.pa = 0 33 | 34 | def freq_to_fcw(self, freq: float) -> int: 35 | return int(round((freq / self.fsamp) * 2**self.pa_bits)) 36 | 37 | def fcw_to_freq(self, fcw: int) -> float: 38 | return (fcw * self.fsamp) / (2**self.pa_bits) 39 | 40 | @property 41 | def freq_resolution(self) -> float: 42 | return self.fsamp / (2**self.pa_bits) 43 | 44 | def msb_bits_of_pa(self) -> int: 45 | return (self.pa >> (self.pa_bits - self.lut_addr_bits)) & int('1'*self.lut_addr_bits, 2) 46 | 47 | def lsb_bits_of_pa(self) -> int: 48 | return self.pa & int('1' * (self.pa_bits - self.lut_addr_bits), 2) # take LSB (N-M) bits of phase_acc 49 | 50 | def next_sample(self, fcw: Optional[int]) -> List[FXnum]: 51 | # take MSB lut_addr_bits bits of the PA to index the LUTs 52 | lut_index = self.msb_bits_of_pa() 53 | samples = [] 54 | for lut in self.luts: 55 | if self.interpolate is False: 56 | samples.append(lut[lut_index]) 57 | else: 58 | samp1 = lut[lut_index] 59 | samp2 = lut[(lut_index + 1) % lut.num_rows] 60 | residual = self.lsb_bits_of_pa() 61 | # Cast residual as fixed point 62 | residual = FXnum(residual / (2**(self.pa_bits - self.lut_addr_bits)), family=lut.data_type) 63 | diff = samp2 - samp1 64 | samples.append(samp1 + residual*diff) 65 | 66 | if fcw: 67 | self.pa = self.pa + fcw 68 | self.pa = self.pa % self.max_pa_value # overflow on N bits 69 | return samples 70 | -------------------------------------------------------------------------------- /hardware/scripts/audio/models/synth.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import List 3 | 4 | from FixedPoint import FXnum 5 | 6 | from models.nco import NCO 7 | 8 | 9 | @dataclass 10 | class Synth: 11 | carrier_ncos: List[NCO] 12 | modulator_ncos: List[NCO] 13 | modulator_idx_shift: int = field(default=0) 14 | modulator_fcw: int = field(default=0) 15 | fcws: List[int] = field(init=False) 16 | note_enabled: List[bool] = field(init=False) 17 | # TODO: implement mixer 18 | 19 | def __post_init__(self): 20 | assert len(self.carrier_ncos) == len(self.modulator_ncos) 21 | assert all(self.carrier_ncos[0].fsamp == x.fsamp for x in self.carrier_ncos) 22 | assert all(self.modulator_ncos[0].fsamp == x.fsamp for x in self.modulator_ncos) 23 | self.fcws = [0] * len(self.carrier_ncos) 24 | self.note_enabled = [False] * len(self.carrier_ncos) 25 | 26 | def next_sample(self) -> FXnum: 27 | modulator_samples = [nco.next_sample(self.modulator_fcw if en else None)[0] for nco, en in zip(self.modulator_ncos, self.note_enabled)] 28 | # print("Mod Sample:", modulator_samples[0].scaledval) 29 | freq_modulated_fcws = [fcw + (mod_samp.scaledval << self.modulator_idx_shift) for fcw, mod_samp in zip(self.fcws, modulator_samples)] 30 | # print("Modulated FCWs:", freq_modulated_fcws) 31 | carrier_samples = [nco.next_sample(fcw if en else None)[0] for nco, fcw, en in zip(self.carrier_ncos, freq_modulated_fcws, self.note_enabled)] 32 | # print("Carrier Sample:", carrier_samples[0].scaledval) 33 | return sum(carrier_samples) 34 | -------------------------------------------------------------------------------- /hardware/scripts/audio/models/utils.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict 2 | import math 3 | 4 | from FixedPoint import FXnum 5 | 6 | 7 | def generate_verilog_rom(data: List[FXnum], name: str) -> str: 8 | address_bits = math.ceil(math.log2(len(data))) 9 | num_rows = 2**address_bits 10 | data_bits = len(data[0].toBinaryString().replace('.', '')) 11 | 12 | # vlog = "module {} (input [{}:0] address, output reg [{}:0] data, output [{}:0] last_address);\n".format(name, address_bits - 1, data_bits - 1, address_bits - 1) 13 | # vlog = vlog + " assign last_address = {};\n".format((min(len(data) - 1, num_rows - 1))) 14 | vlog = "module {} (input [{}:0] address, output reg [{}:0] data);\n".format(name, address_bits - 1, data_bits - 1) 15 | vlog = vlog + " always @ (*) begin\n" 16 | vlog = vlog + " case(address)\n" 17 | 18 | for i in range(0, num_rows): 19 | if i >= len(data): # Write a 0 20 | vlog = vlog + " {}'d{}: data = {}'d{};\n".format(address_bits, i, data_bits, 0) 21 | else: 22 | vlog = vlog + " {}'d{}: data = {}'b{};\n".format(address_bits, i, data_bits, data[i].toBinaryString().replace('.', '')) 23 | 24 | vlog = vlog + " endcase\n" 25 | vlog = vlog + " end\n" 26 | vlog = vlog + "endmodule" 27 | return vlog 28 | 29 | 30 | # A map from keyboard key to a frequency in Hz 31 | # See: https://en.wikipedia.org/wiki/Piano_key_frequencies 32 | # 'z' -> ',' maps to C3 -> C4 33 | note_map: Dict[str, float] = { 34 | 'Z': 65.4064, 35 | 'S': 69.2957, 36 | 'X': 73.4162, 37 | 'D': 77.7817, 38 | 'C': 82.4069, 39 | 'V': 87.3071, 40 | 'G': 92.4986, 41 | 'B': 97.9989, 42 | 'H': 103.826, 43 | 'N': 110.000, 44 | 'J': 116.541, 45 | 'M': 123.471, 46 | '<': 130.813, 47 | 48 | 'z': 130.813, 49 | 's': 138.591, 50 | 'x': 146.832, 51 | 'd': 155.563, 52 | 'c': 164.814, 53 | 'v': 174.614, 54 | 'g': 184.997, 55 | 'b': 195.998, 56 | 'h': 207.652, 57 | 'n': 220.000, 58 | 'j': 233.082, 59 | 'm': 246.942, 60 | ',': 261.626, 61 | 62 | 'q': 261.626, 63 | '2': 277.183, 64 | 'w': 293.665, 65 | '3': 311.127, 66 | 'e': 329.628, 67 | 'r': 349.228, 68 | '5': 369.994, 69 | 't': 391.127, 70 | '6': 415.305, 71 | 'y': 440.000, 72 | '7': 466.164, 73 | 'u': 493.883, 74 | 'i': 523.251, 75 | 76 | 'Q': 523.251, 77 | '@': 554.365, 78 | 'W': 587.330, 79 | '#': 622.254, 80 | 'E': 659.255, 81 | 'R': 698.456, 82 | '%': 739.989, 83 | 'T': 783.991, 84 | '^': 830.609, 85 | 'Y': 880.000, 86 | '&': 932.328, 87 | 'U': 987.767, 88 | 'I': 1046.50 89 | } 90 | -------------------------------------------------------------------------------- /hardware/scripts/audio/nco_reference: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import math 4 | 5 | from FixedPoint import FXfamily 6 | # import matplotlib.pyplot as plt 7 | 8 | from models.lut import SineLUT 9 | from models.nco import NCO 10 | 11 | if __name__ == "__main__": 12 | parser = argparse.ArgumentParser(description='Print reference samples (in binary) for an NCO for comparison with simulation', 13 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 14 | parser.add_argument('--f-samp', default=60000, type=float, help="Sampling frequency") 15 | parser.add_argument('--pa-bits', default=24, type=int, help="Number of bits used for the phase accumulator") 16 | parser.add_argument('--f-sig', default=440, type=float, help="Signal frequency") 17 | parser.add_argument('--num-samples', default=1000, type=int, help="Number of samples") 18 | parser.add_argument('--num-entries', default=256, type=int, help="Number of entries in the LUT") 19 | parser.add_argument('--num-int-bits', default=4, type=int, help="Number of integer bits (including sign) per LUT entry") 20 | parser.add_argument('--num-frac-bits', default=10, type=int, help="Number of fractional bits per LUT entry") 21 | args = parser.parse_args() 22 | 23 | if not math.log2(args.num_entries).is_integer(): 24 | parser.error("Number of LUT entries must be a power of 2, num_entries = {}".format(args.num_entries)) 25 | 26 | lut = SineLUT(args.num_entries, FXfamily(n_bits=args.num_frac_bits, n_intbits=args.num_int_bits)) 27 | nco = NCO([lut], fsamp=args.f_samp, pa_bits=args.pa_bits, interpolate=False) 28 | fcw = nco.freq_to_fcw(args.f_sig) 29 | samples = [nco.next_sample(fcw)[0] for _ in range(args.num_samples)] 30 | samples_bin_str = [x.toBinaryString().replace('.', '') for x in samples] 31 | # plt.plot([x.scaledval for x in samples]) 32 | # plt.show() 33 | print("\n".join(samples_bin_str)) 34 | -------------------------------------------------------------------------------- /hardware/scripts/audio/piano: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import serial 5 | import time 6 | from enum import IntEnum 7 | 8 | from models.utils import note_map 9 | 10 | from tkinter import * 11 | import tkinter as tk 12 | from tkinter import ttk 13 | 14 | if __name__ == "__main__": 15 | if os.name == 'nt': 16 | print('Windows machine!') 17 | ser = serial.Serial() 18 | ser.baudrate = 115200 19 | ser.port = 'COM11' # CHANGE THIS COM PORT 20 | ser.open() 21 | else: 22 | print('Not windows machine!') 23 | ser = serial.Serial('/dev/ttyUSB0') 24 | ser.baudrate = 115200 25 | 26 | class Command(IntEnum): 27 | SET_MOD_FCW = 1 28 | SET_MOD_SHIFT = 2 29 | START_PLAY = 3 30 | STOP_PLAY = 4 31 | SET_SYNTH_SHIFT = 5 32 | RESET = 6 33 | 34 | def cmd(command: Command, args: bytearray): 35 | # Write the command code 36 | ser.write(bytearray([int(command)])) 37 | time.sleep(0.001) 38 | # Write the argument from lowest byte to next 39 | for b in args: 40 | ser.write(bytearray([b])) 41 | time.sleep(0.001) 42 | time.sleep(0.002) 43 | 44 | def fcw_to_bytearray(fcw: int) -> bytearray: 45 | bytes = [] 46 | for byte_idx in range(3): 47 | mask = 0xFF << (8 * byte_idx) 48 | fcw_byte = (fcw & mask) >> (8 * byte_idx) 49 | bytes.append(fcw_byte) 50 | return bytearray(bytes) 51 | 52 | def freq_to_fcw(freq: float, fsamp: int = 60000, pa_bits: int = 24) -> int: 53 | return int(round((freq / fsamp) * 2**pa_bits)) 54 | 55 | cmd(Command.RESET, bytearray([])) 56 | cmd(Command.SET_MOD_SHIFT, bytearray([0])) 57 | cmd(Command.SET_MOD_FCW, fcw_to_bytearray(freq_to_fcw(0))) 58 | 59 | cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(440))) 60 | time.sleep(0.1) 61 | cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(220))) 62 | time.sleep(0.1) 63 | cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(110))) 64 | time.sleep(0.1) 65 | cmd(Command.STOP_PLAY, fcw_to_bytearray(freq_to_fcw(110))) 66 | 67 | os.system('xset r off') # see https://stackoverflow.com/questions/27215326/tkinter-keypress-keyrelease-events 68 | 69 | def keyup(e): 70 | char = chr(e.keysym_num) 71 | if char in note_map: 72 | cmd(Command.STOP_PLAY, fcw_to_bytearray(freq_to_fcw(note_map[char]))) 73 | 74 | def keydown(e): 75 | char = chr(e.keysym_num) 76 | if char in note_map: 77 | cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(note_map[char]))) 78 | 79 | def change_mod_fcw(val): 80 | if int(val) == 0: 81 | freq = 0 82 | else: 83 | freq = int(round(10**(int(val) / 1000))) 84 | cmd(Command.SET_MOD_FCW, fcw_to_bytearray(freq_to_fcw(freq))) 85 | mod_fcw_freq["text"] = "Modulator Frequency (Hz): {}".format(freq) 86 | 87 | def change_mod_shift(val): 88 | cmd(Command.SET_MOD_SHIFT, bytearray([int(val)])) 89 | 90 | root = Tk() 91 | frm = tk.Frame(root) 92 | frm.grid() 93 | frm.bind("", keydown) 94 | frm.bind("", keyup) 95 | tk.Label(frm, text="FM Synth").grid(column=0, row=0) 96 | mod_fcw = tk.Scale(frm, from_=0, to=4500, length=1000, tickinterval=1000, label="Modulator Freq (Log scale)", orient=HORIZONTAL, command=change_mod_fcw) 97 | mod_fcw.grid(column=0, row=1) 98 | mod_fcw.set(0) 99 | 100 | mod_fcw_freq = tk.Label(frm, text="") 101 | mod_fcw_freq.grid(column=0, row=2) 102 | 103 | mod_shift = tk.Scale(frm, from_=0, to=10, length=600, tickinterval=1, label="Modulator Shift", orient=HORIZONTAL, command=change_mod_shift) 104 | mod_shift.grid(column=0, row=3) 105 | mod_shift.set(0) 106 | 107 | tk.Label(frm, text="Type in this window to play notes").grid(column=0, row=4) 108 | 109 | tk.Button(frm, text="Quit", command=root.destroy).grid(column=0, row=5) 110 | frm.pack() 111 | frm.focus_set() 112 | root.mainloop() 113 | 114 | os.system('xset r on') 115 | -------------------------------------------------------------------------------- /hardware/scripts/audio/synth_reference: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import math 4 | import sys 5 | 6 | from FixedPoint import FXfamily 7 | # import matplotlib.pyplot as plt 8 | 9 | from models.lut import SineLUT 10 | from models.nco import NCO 11 | from models.synth import Synth 12 | 13 | if __name__ == "__main__": 14 | parser = argparse.ArgumentParser(description='Print reference samples (in binary) for a full synth for comparison with simulation', 15 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 16 | parser.add_argument('--f-samp', default=60000, type=float, help="Sampling frequency") 17 | parser.add_argument('--pa-bits', default=24, type=int, help="Number of bits used for the phase accumulator") 18 | parser.add_argument('--num-samples', default=1000, type=int, help="Number of samples") 19 | parser.add_argument('--num-entries', default=256, type=int, help="Number of entries in the LUT") 20 | parser.add_argument('--num-int-bits', default=4, type=int, help="Number of integer bits (including sign) per LUT entry") 21 | parser.add_argument('--num-frac-bits', default=10, type=int, help="Number of fractional bits per LUT entry") 22 | args = parser.parse_args() 23 | 24 | if not math.log2(args.num_entries).is_integer(): 25 | parser.error("Number of LUT entries must be a power of 2, num_entries = {}".format(args.num_entries)) 26 | 27 | lut = SineLUT(args.num_entries, FXfamily(n_bits=args.num_frac_bits, n_intbits=args.num_int_bits)) 28 | carrier_ncos = [NCO([lut], fsamp=args.f_samp, pa_bits=args.pa_bits, interpolate=False) for _ in range(4)] 29 | modulator_ncos = [NCO([lut], fsamp=args.f_samp, pa_bits=args.pa_bits, interpolate=False) for _ in range(4)] 30 | synth = Synth(carrier_ncos, modulator_ncos, modulator_idx_shift=0, modulator_fcw=0) 31 | 32 | synth.fcws[0] = carrier_ncos[0].freq_to_fcw(440) 33 | synth.modulator_fcw = modulator_ncos[0].freq_to_fcw(800) 34 | synth.modulator_idx_shift = 8 35 | synth.note_enabled[0] = True 36 | print("Carrier FCW: {}, Modulator FCW: {}".format(synth.fcws[0], synth.modulator_fcw), file=sys.stderr) 37 | 38 | # synth.fcws[1] = carrier_ncos[1].freq_to_fcw(880) 39 | # synth.note_enabled[1] = True 40 | 41 | samples = [synth.next_sample() for _ in range(args.num_samples)] 42 | samples_bin_str = [x.toBinaryString().replace('.', '') for x in samples] 43 | # plt.plot([x.scaledval for x in samples]) 44 | # plt.show() 45 | print("\n".join(samples_bin_str)) 46 | -------------------------------------------------------------------------------- /hardware/scripts/elaborate.tcl: -------------------------------------------------------------------------------- 1 | source ./target.tcl 2 | 3 | # Read Verilog source files 4 | if {[string trim ${RTL}] ne ""} { 5 | read_verilog -v ${RTL} 6 | } 7 | 8 | # Read user constraints 9 | if {[string trim ${CONSTRAINTS}] ne ""} { 10 | read_xdc ${CONSTRAINTS} 11 | } 12 | 13 | # Only elaborate RTL (don't synthesize to netlist) 14 | synth_design -verilog_define SYNTHESIS -verilog_define ABS_TOP=${ABS_TOP} -top ${TOP} -part ${FPGA_PART} -include_dirs ${ABS_TOP}/src/riscv_core -rtl 15 | 16 | # write_checkpoint doesn't work: 17 | # Vivado% write_checkpoint -force z1top_post_elab.dcp 18 | # ERROR: [Common 17-69] Command failed: Checkpoints are not supported for RTL designs 19 | 20 | # Open the schematic visualization 21 | start_gui 22 | -------------------------------------------------------------------------------- /hardware/scripts/hex_to_serial: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # ported from /home/ff/eecs151/tools-151/bin/coe_to_serial 3 | import os 4 | import serial 5 | import sys 6 | import time 7 | 8 | # Windows 9 | if os.name == 'nt': 10 | ser = serial.Serial() 11 | ser.baudrate = 115200 12 | ser.port = 'COM11' # CHANGE THIS COM PORT 13 | ser.open() 14 | else: 15 | ser = serial.Serial('/dev/ttyUSB0') 16 | ser.baudrate = 115200 17 | 18 | if len(sys.argv) != 3: 19 | print("Usage: hex_to_serial \nExample: hex_to_serial echo.hex 30000000") 20 | sys.exit(1) 21 | 22 | #input("Open a serial program in another terminal, then hit Enter") 23 | 24 | addr = int(sys.argv[2], 16); 25 | with open(sys.argv[1], "r") as f: 26 | program = f.readlines() 27 | if ('@' in program[0]): 28 | program = program[1:] # remove first line '@0' 29 | program = [inst.rstrip() for inst in program] 30 | size = len(program)*4 # in bytes 31 | 32 | # write a newline to clear any input tokens before entering the command 33 | command = "\n\rfile {:08x} {:d} ".format(addr, size) 34 | print("Sending command: {}".format(command)) 35 | for char in command: 36 | ser.write(bytearray([ord(char)])) 37 | time.sleep(0.01) 38 | 39 | for inst_num, inst in enumerate(program): 40 | for char in inst: 41 | ser.write(bytearray([ord(char)])) 42 | time.sleep(0.001) 43 | time.sleep(0.001) 44 | if (inst_num == len(program)-1): 45 | print("Sent {:d}/{:d} bytes".format(4+inst_num*4, size), end='\n') 46 | else: 47 | print("Sent {:d}/{:d} bytes".format(4+inst_num*4, size), end='\r') 48 | 49 | print("Done") 50 | -------------------------------------------------------------------------------- /hardware/scripts/impl.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | 3 | open_checkpoint ${ABS_TOP}/build/synth/${TOP}.dcp 4 | 5 | if {[string trim ${CONSTRAINTS}] ne ""} { 6 | read_xdc ${CONSTRAINTS} 7 | } 8 | 9 | opt_design 10 | place_design 11 | write_checkpoint -force ${TOP}_placed.dcp 12 | report_utilization -file post_place_utilization.rpt 13 | phys_opt_design 14 | route_design 15 | 16 | write_checkpoint -force ${TOP}_routed.dcp 17 | write_verilog -force post_route.v 18 | write_xdc -force post_route.xdc 19 | report_drc -file post_route_drc.rpt 20 | report_timing_summary -warn_on_violation -file post_route_timing_summary.rpt 21 | 22 | write_bitstream -force ${TOP}.bit 23 | -------------------------------------------------------------------------------- /hardware/scripts/program.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | open_hw 3 | 4 | connect_hw_server -url localhost:3121 5 | current_hw_target [get_hw_targets */xilinx_tcf/Digilent/*] 6 | set_property PARAM.FREQUENCY 15000000 [get_hw_targets */xilinx_tcf/Digilent/*] 7 | open_hw_target 8 | 9 | current_hw_device [get_hw_devices xc7z*] 10 | set_property PROBES.FILE {} [get_hw_devices xc7z*] 11 | set_property FULL_PROBES.FILE {} [get_hw_devices xc7z*] 12 | 13 | # Hack to expand ${ABS_TOP} and ${TOP} properly, running set_property directly doesn't expand these variables 14 | set set_cmd "set_property PROGRAM.FILE \{${ABS_TOP}/build/impl/${TOP}.bit\} \[get_hw_devices xc7z*\]" 15 | eval ${set_cmd} 16 | program_hw_devices [get_hw_devices xc7z*] 17 | refresh_hw_device [get_hw_devices xc7z*] 18 | 19 | close_hw 20 | -------------------------------------------------------------------------------- /hardware/scripts/program_2021.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | open_hw_manager 3 | 4 | connect_hw_server -url localhost:3121 -allow_non_jtag 5 | current_hw_target [get_hw_targets */xilinx_tcf/Digilent/*] 6 | set_property PARAM.FREQUENCY 15000000 [get_hw_targets */xilinx_tcf/Digilent/*] 7 | open_hw_target 8 | 9 | current_hw_device [get_hw_devices xc7z*] 10 | refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7z*] 0] 11 | set_property PROBES.FILE {} [get_hw_devices xc7z020_1] 12 | set_property FULL_PROBES.FILE {} [get_hw_devices xc7z020_1] 13 | 14 | # Hack to expand ${ABS_TOP} and ${TOP} properly, running set_property directly doesn't expand these variables 15 | set set_cmd "set_property PROGRAM.FILE \{${ABS_TOP}/build/impl/${TOP}.bit\} \[get_hw_devices xc7z*\]" 16 | eval ${set_cmd} 17 | program_hw_devices [get_hw_devices xc7z*] 18 | refresh_hw_device [lindex [get_hw_devices xc7z*] 0] 19 | 20 | close_hw_manager 21 | 22 | # Raw TCL and log 23 | # start_gui 24 | # open_hw_manager 25 | # INFO: [IP_Flow 19-234] Refreshing IP repositories 26 | # INFO: [IP_Flow 19-1704] No user IP repositories specified 27 | # INFO: [IP_Flow 19-2313] Loaded Vivado IP repository '/opt/vivado/Vivado/2021.1/data/ip'. 28 | # open_hw_manager: Time (s): cpu = 00:00:14 ; elapsed = 00:00:05 . Memory (MB): peak = 7493.453 ; gain = 58.125 ; free physical = 12289 ; free virtual = 35691 29 | # connect_hw_server -url localhost:3121 -allow_non_jtag 30 | # INFO: [Labtools 27-2285] Connecting to hw_server url TCP:localhost:3121 31 | # INFO: [Labtools 27-3415] Connecting to cs_server url TCP:localhost:3042 32 | # INFO: [Labtools 27-3414] Connected to existing cs_server. 33 | # current_hw_target [get_hw_targets */xilinx_tcf/Digilent/003017A8B74BA] 34 | # set_property PARAM.FREQUENCY 15000000 [get_hw_targets */xilinx_tcf/Digilent/003017A8B74BA] 35 | # open_hw_target 36 | # INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/003017A8B74BA 37 | # current_hw_device [get_hw_devices xc7z020_1] 38 | # refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7z020_1] 0] 39 | # INFO: [Labtools 27-1434] Device xc7z020 (JTAG device index = 1) is programmed with a design that has no supported debug core(s) in it. 40 | # set_property PROBES.FILE {} [get_hw_devices xc7z020_1] 41 | # set_property FULL_PROBES.FILE {} [get_hw_devices xc7z020_1] 42 | # set_property PROGRAM.FILE {/home/vighnesh/10-school/12-secondary/19-eecs151/labs_skeleton/fpga_labs_fa21/lab1/build/impl/z1top.bit} [get_hw_devices xc7z020_1] 43 | # program_hw_devices [get_hw_devices xc7z020_1] 44 | # INFO: [Labtools 27-3164] End of startup status: HIGH 45 | # refresh_hw_device [lindex [get_hw_devices xc7z020_1] 0] 46 | # INFO: [Labtools 27-1434] Device xc7z020 (JTAG device index = 1) is programmed with a design that has no supported debug core(s) in it. 47 | # close_hw_manager 48 | # ****** Webtalk v2021.1 (64-bit) 49 | # **** SW Build 3247384 on Thu Jun 10 19:36:07 MDT 2021 50 | # **** IP Build 3246043 on Fri Jun 11 00:30:35 MDT 2021 51 | # ** Copyright 1986-2021 Xilinx, Inc. All Rights Reserved. 52 | # 53 | # source /home/vighnesh/10-school/12-secondary/19-eecs151/labs_skeleton/fpga_labs_fa21/lab1/build/.Xil/Vivado-186575-vighnesh-t480/webtalk/labtool_webtalk.tcl -notrace 54 | # INFO: [Common 17-186] '/home/vighnesh/10-school/12-secondary/19-eecs151/labs_skeleton/fpga_labs_fa21/lab1/build/.Xil/Vivado-186575-vighnesh-t480/webtalk/usage_statistics_ext_labtool.xml' has been successfully sent to Xilinx on Fri Aug 27 17:02:08 2021. For additional details about this file, please refer to the WebTalk help file at /opt/vivado/Vivado/2021.1/doc/webtalk_introduction.html. 55 | # INFO: [Common 17-206] Exiting Webtalk at Fri Aug 27 17:02:08 2021... 56 | # close_hw_manager: Time (s): cpu = 00:00:09 ; elapsed = 00:00:08 . Memory (MB): peak = 8461.398 ; gain = 7.219 ; free physical = 10648 ; free virtual = 34132 57 | -------------------------------------------------------------------------------- /hardware/scripts/synth.tcl: -------------------------------------------------------------------------------- 1 | source ../target.tcl 2 | 3 | # Read Verilog source files 4 | if {[string trim ${RTL}] ne ""} { 5 | read_verilog -sv ${RTL} 6 | } 7 | 8 | # Read user constraints 9 | if {[string trim ${CONSTRAINTS}] ne ""} { 10 | read_xdc ${CONSTRAINTS} 11 | } 12 | 13 | synth_design -verilog_define SYNTHESIS -verilog_define ABS_TOP=${ABS_TOP} -top ${TOP} -part ${FPGA_PART} -include_dirs ${ABS_TOP}/src/riscv_core 14 | 15 | write_checkpoint -force ${TOP}.dcp 16 | report_timing_summary -file post_synth_timing_summary.rpt 17 | report_drc -file post_synth_drc.rpt 18 | report_utilization -file post_synth_utilization.rpt 19 | write_verilog -force -file post_synth.v 20 | write_xdc -force -file post_synth.xdc 21 | -------------------------------------------------------------------------------- /hardware/sim/asm_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `include "mem_path.vh" 3 | 4 | module asm_tb(); 5 | reg clk, rst; 6 | parameter CPU_CLOCK_PERIOD = 20; 7 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 8 | 9 | initial clk = 0; 10 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 11 | 12 | reg bp_enable = 1'b0; 13 | 14 | cpu # ( 15 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ) 16 | ) cpu ( 17 | .clk(clk), 18 | .rst(rst), 19 | .bp_enable(bp_enable), 20 | .serial_in(1'b1), 21 | .serial_out() 22 | ); 23 | 24 | // A task to check if the value contained in a register equals an expected value 25 | task check_reg; 26 | input [4:0] reg_number; 27 | input [31:0] expected_value; 28 | input [10:0] test_num; 29 | if (expected_value !== `RF_PATH.mem[reg_number]) begin 30 | $display("FAIL - test %d, got: %d, expected: %d for reg %d", 31 | test_num, `RF_PATH.mem[reg_number], expected_value, reg_number); 32 | $finish(); 33 | end 34 | else begin 35 | $display("PASS - test %d, got: %d for reg %d", test_num, expected_value, reg_number); 36 | end 37 | endtask 38 | 39 | // A task that runs the simulation until a register contains some value 40 | task wait_for_reg_to_equal; 41 | input [4:0] reg_number; 42 | input [31:0] expected_value; 43 | while (`RF_PATH.mem[reg_number] !== expected_value) 44 | @(posedge clk); 45 | endtask 46 | 47 | initial begin 48 | $readmemh("../../software/asm/asm.hex", `BIOS_PATH.mem, 0, 4095); 49 | 50 | `ifndef IVERILOG 51 | $vcdpluson; 52 | `endif 53 | `ifdef IVERILOG 54 | $dumpfile("asm_tb.fst"); 55 | $dumpvars(0, asm_tb); 56 | `endif 57 | rst = 0; 58 | 59 | // Reset the CPU 60 | rst = 1; 61 | repeat (10) @(posedge clk); // Hold reset for 10 cycles 62 | @(negedge clk); 63 | rst = 0; 64 | 65 | // Your processor should begin executing the code in /software/asm/start.s 66 | 67 | // Test ADD 68 | wait_for_reg_to_equal(20, 32'd1); // Run the simulation until the flag is set to 1 69 | check_reg(1, 32'd300, 1); // Verify that x1 contains 300 70 | 71 | // Test BEQ 72 | wait_for_reg_to_equal(20, 32'd2); // Run the simulation until the flag is set to 2 73 | check_reg(1, 32'd500, 2); // Verify that x1 contains 500 74 | check_reg(2, 32'd100, 3); // Verify that x2 contains 100 75 | $display("ALL ASSEMBLY TESTS PASSED!"); 76 | $finish(); 77 | end 78 | 79 | initial begin 80 | repeat (100) @(posedge clk); 81 | $display("Failed: timing out"); 82 | $fatal(); 83 | end 84 | endmodule 85 | -------------------------------------------------------------------------------- /hardware/sim/bios_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `include "../src/riscv_core/opcode.vh" 3 | `include "mem_path.vh" 4 | 5 | module bios_tb(); 6 | reg clk, rst; 7 | parameter CPU_CLOCK_PERIOD = 20; 8 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 9 | localparam BAUD_RATE = 10_000_000; 10 | localparam BAUD_PERIOD = 1_000_000_000 / BAUD_RATE; // 8680.55 ns 11 | 12 | localparam TIMEOUT_CYCLE = 100_000; 13 | 14 | initial clk = 0; 15 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 16 | 17 | reg bp_enable = 1'b0; 18 | 19 | reg serial_in; 20 | wire serial_out; 21 | 22 | cpu # ( 23 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 24 | .RESET_PC(32'h4000_0000), 25 | .BAUD_RATE(BAUD_RATE) 26 | ) cpu ( 27 | .clk(clk), 28 | .rst(rst), 29 | .bp_enable(bp_enable), 30 | .serial_in(serial_in), // input 31 | .serial_out(serial_out) // output 32 | ); 33 | 34 | integer i, j; 35 | reg [31:0] cycle; 36 | always @(posedge clk) begin 37 | if (rst === 1) 38 | cycle <= 0; 39 | else 40 | cycle <= cycle + 1; 41 | end 42 | 43 | // Host off-chip UART --> FPGA on-chip UART (receiver) 44 | // The host (testbench) sends a character to the CPU via the serial line 45 | task host_to_fpga; 46 | input [7:0] char_in; 47 | begin 48 | serial_in = 0; 49 | #(BAUD_PERIOD); 50 | // Data bits (payload) 51 | for (i = 0; i < 8; i = i + 1) begin 52 | serial_in = char_in[i]; 53 | #(BAUD_PERIOD); 54 | end 55 | // Stop bit 56 | serial_in = 1; 57 | #(BAUD_PERIOD); 58 | 59 | $display("[time %t, sim. cycle %d] [Host (tb) --> FPGA_SERIAL_RX] Sent char 8'h%h", 60 | $time, cycle, char_in); 61 | repeat (300) @(posedge clk); 62 | end 63 | endtask 64 | 65 | reg [9:0] char_out; 66 | reg [63:0] test_status; 67 | reg [31:0] num_failed_tests = 0; 68 | 69 | // Host off-chip UART <-- FPGA on-chip UART (transmitter) 70 | // The host (testbench) expects to receive a character from the CPU via the serial line 71 | task fpga_to_host; 72 | input [7:0] expected_char; 73 | begin 74 | // Wait until serial_out is LOW (start of transaction) 75 | wait (serial_out === 1'b0); 76 | 77 | for (j = 0; j < 10; j = j + 1) begin 78 | // sample output half-way through the baud period to avoid tricky edge cases 79 | #(BAUD_PERIOD / 2); 80 | char_out[j] = serial_out; 81 | #(BAUD_PERIOD / 2); 82 | end 83 | 84 | if (expected_char === char_out[8:1]) begin 85 | test_status = "PASSED"; 86 | end 87 | else begin 88 | test_status = "FAILED"; 89 | num_failed_tests = num_failed_tests + 1; 90 | end 91 | 92 | if (expected_char != "\n" && expected_char != 8'h0d) begin 93 | $display("[time %t, sim. cycle %d] [Host (tb) <-- FPGA_SERIAL_TX] Got char 8'h%h, expected 8'h%h == %s [ %s ]", 94 | $time, cycle, char_out[8:1], expected_char, expected_char, test_status); 95 | end else begin 96 | $display("[time %t, sim. cycle %d] [Host (tb) <-- FPGA_SERIAL_TX] Got char 8'h%h, expected 8'h%h == %s [ %s ]", 97 | $time, cycle, char_out[8:1], expected_char, "newline/CR", test_status); 98 | end 99 | end 100 | endtask 101 | 102 | reg [14:0] INST_ADDR; 103 | reg [31:0] IMM; 104 | 105 | initial begin 106 | #1; 107 | 108 | // Initialize IMem with the instruction: addi x3, x0, 8 109 | IMM[11:0] = 8; 110 | INST_ADDR = 14'h0000; 111 | `IMEM_PATH.mem[INST_ADDR + 0] = {IMM[11:0], 5'd0, `FNC_ADD_SUB, 5'd3, `OPC_ARI_ITYPE}; 112 | end 113 | 114 | initial begin 115 | $readmemh("../../software/bios/bios.hex", `BIOS_PATH.mem, 0, 4095); 116 | 117 | `ifndef IVERILOG 118 | $vcdpluson; 119 | `endif 120 | `ifdef IVERILOG 121 | $dumpfile("bios_tb.fst"); 122 | $dumpvars(0, bios_tb); 123 | `endif 124 | 125 | rst = 1; 126 | serial_in = 1; 127 | 128 | // Hold reset for a while 129 | repeat (10) @(posedge clk); 130 | 131 | @(negedge clk); 132 | rst = 0; 133 | 134 | // Delay for some time 135 | repeat (10) @(posedge clk); 136 | 137 | $display("[TEST 1] BIOS startup. Expect to see: \\r\\n151> "); 138 | 139 | // initial printout from BIOS program 140 | fpga_to_host(8'h0d); // \r 141 | fpga_to_host(8'h0a); // \n 142 | fpga_to_host(8'h31); // 1 143 | fpga_to_host(8'h35); // 5 144 | fpga_to_host(8'h31); // 1 145 | fpga_to_host(8'h3e); // > 146 | fpga_to_host(8'h20); // [space] 147 | 148 | // Test invalid command 149 | $display("[TEST 2] Send an invalid command. Expect to see: \\n\\rUnrecognized token: "); 150 | fork 151 | begin 152 | host_to_fpga(8'h61); // 'a' 153 | host_to_fpga(8'h62); // 'b' 154 | host_to_fpga(8'h63); // 'c' 155 | host_to_fpga(8'h64); // 'd' 156 | host_to_fpga(8'h20); // [space] 157 | end 158 | begin 159 | // echo back the input characters ... 160 | fpga_to_host(8'h61); // 'a' 161 | fpga_to_host(8'h62); // 'b' 162 | fpga_to_host(8'h63); // 'c' 163 | fpga_to_host(8'h64); // 'd' 164 | fpga_to_host(8'h20); // '[space]' 165 | 166 | // message from BIOS program 167 | fpga_to_host(8'h0a); // '\n' 168 | fpga_to_host(8'h0d); // '\r' 169 | fpga_to_host(8'h55); // 'U' 170 | fpga_to_host(8'h6e); // 'n' 171 | fpga_to_host(8'h72); // 'r' 172 | fpga_to_host(8'h65); // 'e' 173 | fpga_to_host(8'h63); // 'c' 174 | fpga_to_host(8'h6f); // 'o' 175 | fpga_to_host(8'h67); // 'g' 176 | fpga_to_host(8'h6e); // 'n' 177 | fpga_to_host(8'h69); // 'i' 178 | fpga_to_host(8'h7a); // 'z' 179 | fpga_to_host(8'h65); // 'e' 180 | fpga_to_host(8'h64); // 'd' 181 | fpga_to_host(8'h20); // [space] 182 | fpga_to_host(8'h74); // 't' 183 | fpga_to_host(8'h6f); // 'o' 184 | fpga_to_host(8'h6b); // 'k' 185 | fpga_to_host(8'h65); // 'e' 186 | fpga_to_host(8'h6e); // 'n' 187 | fpga_to_host(8'h3a); // ':' 188 | fpga_to_host(8'h20); // [space] 189 | 190 | fpga_to_host(8'h61); // 'a' 191 | fpga_to_host(8'h62); // 'b' 192 | fpga_to_host(8'h63); // 'c' 193 | fpga_to_host(8'h64); // 'd' 194 | 195 | fpga_to_host(8'h0a); // \n 196 | fpga_to_host(8'h0d); // \r 197 | fpga_to_host(8'h31); // 1 198 | fpga_to_host(8'h35); // 5 199 | fpga_to_host(8'h31); // 1 200 | fpga_to_host(8'h3e); // > 201 | fpga_to_host(8'h20); // [space] 202 | 203 | end 204 | join 205 | 206 | // Test store command in BIOS mode 207 | $display("[TEST 3] Send [sw cafeaaaa 30000004] command. Expect to write 32'hcafeaaaa to both IMem[1] and DMem[1]"); 208 | fork 209 | begin 210 | host_to_fpga(8'h73); // 's' 211 | host_to_fpga(8'h77); // 'w' 212 | host_to_fpga(8'h20); // [space] 213 | host_to_fpga(8'h63); // 'c' 214 | host_to_fpga(8'h61); // 'a' 215 | host_to_fpga(8'h66); // 'f' 216 | host_to_fpga(8'h65); // 'e' 217 | host_to_fpga(8'h61); // 'a' 218 | host_to_fpga(8'h61); // 'a' 219 | host_to_fpga(8'h61); // 'a' 220 | host_to_fpga(8'h61); // 'a' 221 | host_to_fpga(8'h20); // [space] 222 | host_to_fpga(8'h33); // '3' 223 | host_to_fpga(8'h30); // '0' 224 | host_to_fpga(8'h30); // '0' 225 | host_to_fpga(8'h30); // '0' 226 | host_to_fpga(8'h30); // '0' 227 | host_to_fpga(8'h30); // '0' 228 | host_to_fpga(8'h30); // '0' 229 | host_to_fpga(8'h34); // '4' 230 | host_to_fpga(8'h0d); // \r 231 | end 232 | begin 233 | // echo back the input characters ... 234 | fpga_to_host(8'h73); // 's' 235 | fpga_to_host(8'h77); // 'w' 236 | fpga_to_host(8'h20); // [space] 237 | fpga_to_host(8'h63); // 'c' 238 | fpga_to_host(8'h61); // 'a' 239 | fpga_to_host(8'h66); // 'f' 240 | fpga_to_host(8'h65); // 'e' 241 | fpga_to_host(8'h61); // 'a' 242 | fpga_to_host(8'h61); // 'a' 243 | fpga_to_host(8'h61); // 'a' 244 | fpga_to_host(8'h61); // 'a' 245 | fpga_to_host(8'h20); // [space] 246 | fpga_to_host(8'h33); // '3' 247 | fpga_to_host(8'h30); // '0' 248 | fpga_to_host(8'h30); // '0' 249 | fpga_to_host(8'h30); // '0' 250 | fpga_to_host(8'h30); // '0' 251 | fpga_to_host(8'h30); // '0' 252 | fpga_to_host(8'h30); // '0' 253 | fpga_to_host(8'h34); // '4' 254 | 255 | fpga_to_host(8'h0d); // \r 256 | fpga_to_host(8'h0a); // \n 257 | fpga_to_host(8'h31); // 1 258 | fpga_to_host(8'h35); // 5 259 | fpga_to_host(8'h31); // 1 260 | fpga_to_host(8'h3e); // > 261 | fpga_to_host(8'h20); // [space] 262 | end 263 | join 264 | 265 | $display("Imem[1]=%h DMem[1]=%h", `IMEM_PATH.mem[1], `DMEM_PATH.mem[1]); 266 | 267 | $display("Test Write to IMem"); 268 | if (`IMEM_PATH.mem[1] === 32'hcafeaaaa) begin 269 | $display("PASSED!"); 270 | end 271 | else 272 | $display("FAILED!"); 273 | 274 | $display("Test Write to DMem"); 275 | if (`DMEM_PATH.mem[1] === 32'hcafeaaaa) begin 276 | $display("PASSED!"); 277 | end 278 | else 279 | $display("FAILED!"); 280 | 281 | // Test load command in BIOS mode 282 | $display("[TEST 4] Send [lw 30000004] command. Expect to see: 30000004:cafeaaaa"); 283 | fork 284 | begin 285 | host_to_fpga(8'h6c); // 'l' 286 | host_to_fpga(8'h77); // 'w' 287 | host_to_fpga(8'h20); // [space] 288 | host_to_fpga(8'h33); // '3' 289 | host_to_fpga(8'h30); // '0' 290 | host_to_fpga(8'h30); // '0' 291 | host_to_fpga(8'h30); // '0' 292 | host_to_fpga(8'h30); // '0' 293 | host_to_fpga(8'h30); // '0' 294 | host_to_fpga(8'h30); // '0' 295 | host_to_fpga(8'h34); // '4' 296 | host_to_fpga(8'h0d); // \r 297 | end 298 | begin 299 | // echo back the input characters ... 300 | fpga_to_host(8'h6c); // 'l' 301 | fpga_to_host(8'h77); // 'w' 302 | fpga_to_host(8'h20); // [space] 303 | fpga_to_host(8'h33); // '3' 304 | fpga_to_host(8'h30); // '0' 305 | fpga_to_host(8'h30); // '0' 306 | fpga_to_host(8'h30); // '0' 307 | fpga_to_host(8'h30); // '0' 308 | fpga_to_host(8'h30); // '0' 309 | fpga_to_host(8'h30); // '0' 310 | fpga_to_host(8'h34); // '4' 311 | fpga_to_host(8'h0d); // \r 312 | 313 | // message from BIOS program 314 | fpga_to_host(8'h0a); // \n 315 | fpga_to_host(8'h33); // '3' 316 | fpga_to_host(8'h30); // '0' 317 | fpga_to_host(8'h30); // '0' 318 | fpga_to_host(8'h30); // '0' 319 | fpga_to_host(8'h30); // '0' 320 | fpga_to_host(8'h30); // '0' 321 | fpga_to_host(8'h30); // '0' 322 | fpga_to_host(8'h34); // '4' 323 | fpga_to_host(8'h3a); // ':' 324 | fpga_to_host(8'h63); // 'c' 325 | fpga_to_host(8'h61); // 'a' 326 | fpga_to_host(8'h66); // 'f' 327 | fpga_to_host(8'h65); // 'e' 328 | fpga_to_host(8'h61); // 'a' 329 | fpga_to_host(8'h61); // 'a' 330 | fpga_to_host(8'h61); // 'a' 331 | fpga_to_host(8'h61); // 'a' 332 | 333 | fpga_to_host(8'h0d); // \r 334 | fpga_to_host(8'h0a); // \n 335 | fpga_to_host(8'h31); // 1 336 | fpga_to_host(8'h35); // 5 337 | fpga_to_host(8'h31); // 1 338 | fpga_to_host(8'h3e); // > 339 | fpga_to_host(8'h20); // [space] 340 | end 341 | join 342 | 343 | // Test jump command: switch to IMem address space 344 | $display("[TEST 5] Send [jal 10000000] command. Expect to see: jal 10000000"); 345 | fork 346 | begin 347 | host_to_fpga(8'h6a); // 'j' 348 | host_to_fpga(8'h61); // 'a' 349 | host_to_fpga(8'h6c); // 'l' 350 | host_to_fpga(8'h20); // [space] 351 | host_to_fpga(8'h31); // '1' 352 | host_to_fpga(8'h30); // '0' 353 | host_to_fpga(8'h30); // '0' 354 | host_to_fpga(8'h30); // '0' 355 | host_to_fpga(8'h30); // '0' 356 | host_to_fpga(8'h30); // '0' 357 | host_to_fpga(8'h30); // '0' 358 | host_to_fpga(8'h30); // '0' 359 | host_to_fpga(8'h0d); // \r 360 | end 361 | begin 362 | // echo back the input characters ... 363 | fpga_to_host(8'h6a); // 'j' 364 | fpga_to_host(8'h61); // 'a' 365 | fpga_to_host(8'h6c); // 'l' 366 | fpga_to_host(8'h20); // [space] 367 | fpga_to_host(8'h31); // '1' 368 | fpga_to_host(8'h30); // '0' 369 | fpga_to_host(8'h30); // '0' 370 | fpga_to_host(8'h30); // '0' 371 | fpga_to_host(8'h30); // '0' 372 | fpga_to_host(8'h30); // '0' 373 | fpga_to_host(8'h30); // '0' 374 | fpga_to_host(8'h30); // '0' 375 | fpga_to_host(8'h0d); // \r 376 | end 377 | join 378 | 379 | repeat (1000) @(posedge clk); 380 | 381 | // The instruction in IMem should be executed after jumping to IMem space 382 | $display("Test RF: RF[3]=%h", `RF_PATH.mem[3]); 383 | if (`RF_PATH.mem[3] === IMM[11:0]) begin 384 | $display("PASSED!"); 385 | end 386 | else 387 | $display("FAILED!"); 388 | 389 | repeat (100) @(posedge clk); 390 | $display("BIOS testbench done! Num failed tests: %d", num_failed_tests); 391 | $finish(); 392 | end 393 | 394 | initial begin 395 | repeat (TIMEOUT_CYCLE) @(posedge clk); 396 | $display("Timeout!"); 397 | $fatal(); 398 | end 399 | 400 | endmodule 401 | -------------------------------------------------------------------------------- /hardware/sim/branch_predictor_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `define CLK_PERIOD 8 3 | 4 | module branch_predictor_tb(); 5 | // Generate 125 Mhz clock 6 | reg clk = 0; 7 | always #(`CLK_PERIOD/2) clk = ~clk; 8 | 9 | // I/O 10 | localparam PC_WIDTH = 32; 11 | localparam LINES = 8; 12 | reg rst; 13 | reg [PC_WIDTH-1:0] pc_guess, pc_check; 14 | reg is_br_guess, is_br_check, br_taken_check; 15 | wire br_pred_taken; 16 | 17 | branch_predictor #( 18 | .PC_WIDTH(PC_WIDTH), 19 | .LINES(LINES) 20 | ) DUT ( 21 | .clk(clk), 22 | .reset(rst), 23 | .pc_guess(pc_guess), 24 | .is_br_guess(is_br_guess), 25 | .pc_check(pc_check), 26 | .is_br_check(is_br_check), 27 | .br_taken_check(br_taken_check), 28 | .br_pred_taken(br_pred_taken) 29 | ); 30 | 31 | integer num_tests_failed; 32 | integer i; 33 | 34 | task test_pred(input [PC_WIDTH-1:0] pc, input is_br, input exp_pred_taken); 35 | begin 36 | pc_guess = pc; 37 | is_br_guess = is_br; 38 | #1; 39 | assert(br_pred_taken == exp_pred_taken) else begin 40 | $error("Expected branch taken prediction = %b, got %b", exp_pred_taken, br_pred_taken); 41 | num_tests_failed = num_tests_failed + 1; 42 | end 43 | end 44 | endtask 45 | 46 | task update_taken(input [PC_WIDTH-1:0] pc, input is_br, input br_taken); 47 | begin 48 | @(negedge clk); 49 | pc_check = pc; 50 | is_br_check = is_br; 51 | br_taken_check = br_taken; 52 | @(posedge clk); #1; 53 | end 54 | endtask 55 | 56 | /* 57 | A basic test that covers some different test cases for a given PC. 58 | It is not meant to be an exhaustive test. 59 | */ 60 | task test_basic(input [PC_WIDTH-1:0] pc); 61 | begin 62 | $display("Testing branch prediction for PC address: %x", pc); 63 | test_pred(pc, 1, 0); // On cache miss, branch should not be taken 64 | update_taken(pc, 0, 1); // Non-branch 65 | test_pred(pc, 1, 0); // Still cache miss 66 | update_taken(pc, 1, 1); // Branch taken 67 | test_pred(pc, 1, 1); // cntr should be 10 68 | update_taken(pc, 1, 1); // Branch taken 69 | test_pred(pc, 1, 1); // cntr should be 11 70 | update_taken(pc, 1, 1); // Branch taken 71 | test_pred(pc, 1, 1); // cntr should be 11 (saturation) 72 | update_taken(pc, 1, 0); // Branch not taken 73 | test_pred(pc, 1, 1); // cntr should be 10 74 | update_taken(pc, 1, 0); // Branch not taken 75 | test_pred(pc, 1, 0); // cntr should be 01 76 | update_taken(pc, 1, 0); // Branch not taken 77 | test_pred(pc, 1, 0); // cntr should be 00 78 | update_taken(pc, 1, 0); // Branch not taken 79 | test_pred(pc, 1, 0); // cntr should be 00 (saturation) 80 | update_taken(pc, 1, 1); // Branch taken 81 | test_pred(pc, 1, 0); // cntr should be 01 82 | update_taken(pc, 1, 1); // Branch taken 83 | test_pred(pc, 1, 1); // cntr should be 10 84 | update_taken(pc, 0, 1); // Non-branch 85 | test_pred(pc, 1, 1); // cntr should be 10 86 | end 87 | endtask 88 | 89 | initial begin 90 | `ifdef IVERILOG 91 | $dumpfile("branch_predictor_tb.fst"); 92 | $dumpvars(0, branch_predictor_tb); 93 | `endif 94 | `ifndef IVERILOG 95 | $vcdpluson; 96 | $vcdplusmemon; 97 | `endif 98 | 99 | num_tests_failed = 0; 100 | 101 | is_br_check = 0; 102 | br_taken_check = 0; 103 | rst = 1; 104 | @(posedge clk); #1; 105 | rst = 0; 106 | 107 | repeat (5) @(negedge clk); 108 | 109 | for (i = 0; i < 2 * LINES; i = i + 1) 110 | test_basic(i << 2); 111 | 112 | $display("Testing branch prediction caching"); 113 | for (i = 0; i < LINES; i = i + 1) begin 114 | test_pred(i << 2, 1, 0); // On cache miss, should predict not taken 115 | test_pred((i + LINES) << 2, 1, 1); // On cache hit, should predict the currently stored value (taken) 116 | end 117 | 118 | if (num_tests_failed > 0) $error("%d tests failed", num_tests_failed); 119 | else $display("All tests passed!"); 120 | 121 | `ifndef IVERILOG 122 | $vcdplusoff; 123 | `endif 124 | $finish(); 125 | end 126 | endmodule 127 | -------------------------------------------------------------------------------- /hardware/sim/c_tests_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `include "mem_path.vh" 3 | 4 | // This testbench consolidates all the software tests that relies on the CSR check. 5 | // A software test is compiled to a hex file, then loaded to the testbench for simulation. 6 | // All the software tests have the same CSR check: if the expected result matches 7 | // the generated result, 1 is written to the CSR which indicates a passing status. 8 | 9 | module c_tests_tb(); 10 | reg clk, rst; 11 | parameter CPU_CLOCK_PERIOD = 20; 12 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 13 | 14 | localparam TIMEOUT_CYCLE = 100_000; 15 | 16 | initial clk = 0; 17 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 18 | 19 | reg bp_enable = 1'b0; 20 | 21 | cpu # ( 22 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 23 | .RESET_PC(32'h1000_0000) 24 | ) cpu ( 25 | .clk(clk), 26 | .rst(rst), 27 | .bp_enable(bp_enable), 28 | .serial_in(1'b1), // input 29 | .serial_out() // output 30 | ); 31 | 32 | reg [31:0] cycle; 33 | always @(posedge clk) begin 34 | if (rst === 1) 35 | cycle <= 0; 36 | else 37 | cycle <= cycle + 1; 38 | end 39 | 40 | reg [255:0] MIF_FILE; 41 | string hex_file, test_name; 42 | initial begin 43 | if (!$value$plusargs("hex_file=%s", hex_file)) begin 44 | $display("Must supply hex_file!"); 45 | $fatal(); 46 | end 47 | 48 | if (!$value$plusargs("test_name=%s", test_name)) begin 49 | $display("Must supply test_name!"); 50 | $fatal(); 51 | end 52 | 53 | $readmemh(hex_file, `IMEM_PATH.mem, 0, 16384-1); 54 | $readmemh(hex_file, `DMEM_PATH.mem, 0, 16384-1); 55 | 56 | `ifndef IVERILOG 57 | $vcdpluson; 58 | `endif 59 | `ifdef IVERILOG 60 | $dumpfile({test_name, ".fst"}); 61 | $dumpvars(0, c_tests_tb); 62 | `endif 63 | 64 | rst = 1; 65 | 66 | // Hold reset for a while 67 | repeat (10) @(posedge clk); 68 | 69 | @(negedge clk); 70 | rst = 0; 71 | 72 | // Delay for some time 73 | repeat (10) @(posedge clk); 74 | 75 | // Wait until csr is updated 76 | while (`CSR_PATH === 0) 77 | @(posedge clk); 78 | 79 | if (`CSR_PATH === 32'b1) begin 80 | $display("[%d sim. cycles] CSR test PASSED!", cycle); 81 | end else begin 82 | $display("[%d sim. cycles] CSR test FAILED!", cycle); 83 | end 84 | 85 | repeat (100) @(posedge clk); 86 | $finish(); 87 | end 88 | 89 | initial begin 90 | repeat (TIMEOUT_CYCLE) @(posedge clk); 91 | $display("Timeout!"); 92 | $finish(); 93 | end 94 | 95 | endmodule 96 | -------------------------------------------------------------------------------- /hardware/sim/echo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `include "mem_path.vh" 3 | 4 | module echo_tb(); 5 | reg clk, rst; 6 | parameter CPU_CLOCK_PERIOD = 20; 7 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 8 | localparam BAUD_RATE = 1_000_000; 9 | localparam BAUD_PERIOD = 1_000_000_000 / BAUD_RATE; // 8680.55 ns 10 | 11 | localparam CHAR0 = 8'h61; // ~ 'a' 12 | localparam NUM_CHARS = 10; 13 | 14 | localparam TIMEOUT_CYCLE = 10_000 * NUM_CHARS; 15 | 16 | initial clk = 0; 17 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 18 | 19 | reg serial_in; 20 | wire serial_out; 21 | reg bp_enable = 1'b0; 22 | 23 | cpu # ( 24 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 25 | .RESET_PC(32'h1000_0000), 26 | .BAUD_RATE(BAUD_RATE) 27 | ) cpu ( 28 | .clk(clk), 29 | .rst(rst), 30 | .bp_enable(bp_enable), 31 | .serial_in(serial_in), // input 32 | .serial_out(serial_out) // output 33 | ); 34 | 35 | integer i, j, c, c1, c2; 36 | reg [31:0] cycle; 37 | always @(posedge clk) begin 38 | if (rst === 1) 39 | cycle <= 0; 40 | else 41 | cycle <= cycle + 1; 42 | end 43 | 44 | integer num_mismatches = 0; 45 | 46 | // this holds characters sent by the host via serial line 47 | reg [7:0] chars_from_host [NUM_CHARS-1:0]; 48 | // this holds characters received by the host via serial line 49 | reg [9:0] chars_to_host [NUM_CHARS-1:0]; 50 | 51 | // initialize test vectors 52 | initial begin 53 | #0; 54 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 55 | chars_from_host[c] = CHAR0 + c; 56 | end 57 | end 58 | 59 | // Host off-chip UART --> FPGA on-chip UART (receiver) 60 | // The host (testbench) sends a character to the CPU via the serial line 61 | task host_to_fpga; 62 | begin 63 | for (c1 = 0; c1 < NUM_CHARS; c1 = c1 + 1) begin 64 | serial_in = 0; 65 | #(BAUD_PERIOD); 66 | // Data bits (payload) 67 | for (i = 0; i < 8; i = i + 1) begin 68 | serial_in = chars_from_host[c1][i]; 69 | #(BAUD_PERIOD); 70 | end 71 | // Stop bit 72 | serial_in = 1; 73 | #(BAUD_PERIOD); 74 | 75 | $display("[time %t, sim. cycle %d] [Host (tb) --> FPGA_SERIAL_RX] Sent char 8'h%h", 76 | $time, cycle, chars_from_host[c1]); 77 | repeat (100) @(posedge clk); // Give time for the echo program to process each character 78 | end 79 | end 80 | endtask 81 | 82 | // Host off-chip UART <-- FPGA on-chip UART (transmitter) 83 | // The host (testbench) expects to receive a character from the CPU via the serial line (echoed) 84 | task fpga_to_host; 85 | begin 86 | 87 | for (c2 = 0; c2 < NUM_CHARS; c2 = c2 + 1) begin 88 | // Wait until serial_out is LOW (start of transaction) 89 | wait (serial_out === 1'b0); 90 | 91 | for (j = 0; j < 10; j = j + 1) begin 92 | // sample output half-way through the baud period to avoid tricky edge cases 93 | #(BAUD_PERIOD / 2); 94 | chars_to_host[c2][j] = serial_out; 95 | #(BAUD_PERIOD / 2); 96 | end 97 | 98 | $display("[time %t, sim. cycle %d] [Host (tb) <-- FPGA_SERIAL_TX] Got char: start_bit=%b, payload=8'h%h, stop_bit=%b", 99 | $time, cycle, chars_to_host[c2][0], chars_to_host[c2][8:1], chars_to_host[c2][9]); 100 | end 101 | end 102 | endtask 103 | 104 | initial begin 105 | $readmemh("../../software/echo/echo.hex", `IMEM_PATH.mem, 0, 16384-1); 106 | $readmemh("../../software/echo/echo.hex", `DMEM_PATH.mem, 0, 16384-1); 107 | 108 | `ifndef IVERILOG 109 | $vcdpluson; 110 | `endif 111 | `ifdef IVERILOG 112 | $dumpfile("echo_tb.fst"); 113 | $dumpvars(0, echo_tb); 114 | `endif 115 | rst = 1; 116 | serial_in = 1; 117 | 118 | // Hold reset for a while 119 | repeat (10) @(posedge clk); 120 | 121 | @(negedge clk); 122 | rst = 0; 123 | 124 | // Delay for some time 125 | repeat (10) @(posedge clk); 126 | 127 | fork 128 | begin 129 | host_to_fpga(); 130 | end 131 | begin 132 | fpga_to_host(); 133 | end 134 | join 135 | 136 | // Check results 137 | for (c = 0; c < NUM_CHARS; c = c + 1) begin 138 | if (chars_from_host[c] !== chars_to_host[c][8:1]) begin 139 | $display("Mismatches at char %d: char_from_host=%h, char_to_host=%h", 140 | c, chars_from_host[c], chars_to_host[c][8:1]); 141 | num_mismatches = num_mismatches + 1; 142 | end 143 | end 144 | 145 | if (num_mismatches > 0) 146 | $display("Test failed"); 147 | else 148 | $display("Test passed!"); 149 | 150 | $finish(); 151 | end 152 | 153 | initial begin 154 | repeat (TIMEOUT_CYCLE) @(posedge clk); 155 | $display("Timeout!"); 156 | $fatal(); 157 | end 158 | 159 | endmodule 160 | -------------------------------------------------------------------------------- /hardware/sim/isa_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `include "mem_path.vh" 3 | 4 | module isa_tb(); 5 | reg clk, rst; 6 | parameter CPU_CLOCK_PERIOD = 20; 7 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 8 | 9 | localparam TIMEOUT_CYCLE = 1000; 10 | 11 | initial clk = 0; 12 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 13 | 14 | reg bp_enable = 1'b0; 15 | 16 | cpu # ( 17 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 18 | .RESET_PC(32'h1000_0000) 19 | ) cpu ( 20 | .clk(clk), 21 | .rst(rst), 22 | .bp_enable(bp_enable), 23 | .serial_in(1'b1), 24 | .serial_out() 25 | ); 26 | 27 | reg [31:0] cycle; 28 | always @(posedge clk) begin 29 | if (rst === 1) 30 | cycle <= 0; 31 | else 32 | cycle <= cycle + 1; 33 | end 34 | 35 | string hex_file; 36 | string test_name; 37 | initial begin 38 | if (!$value$plusargs("hex_file=%s", hex_file)) begin 39 | $display("Must supply hex_file!"); 40 | $fatal(); 41 | end 42 | 43 | if (!$value$plusargs("test_name=%s", test_name)) begin 44 | $display("Must supply test_name!"); 45 | $fatal(); 46 | end 47 | 48 | $readmemh(hex_file, `IMEM_PATH.mem, 0, 16384-1); 49 | $readmemh(hex_file, `DMEM_PATH.mem, 0, 16384-1); 50 | 51 | $dumpfile({test_name, ".fst"}); 52 | $dumpvars(0, isa_tb); 53 | 54 | rst = 0; 55 | 56 | // Reset the CPU 57 | rst = 1; 58 | repeat (30) @(posedge clk); // Hold reset for 30 cycles 59 | 60 | @(negedge clk); 61 | rst = 0; 62 | 63 | // Wait until csr[0] is asserted 64 | while (`CSR_PATH[0] !== 1'b1) 65 | @(posedge clk); 66 | 67 | if (`CSR_PATH[0] === 1'b1 && `CSR_PATH[31:1] === 31'b0) begin 68 | $display("[passed] - %s in %d simulation cycles", test_name, cycle); 69 | end else begin 70 | $display("[failed] - %s. Failed test: %d", test_name, `CSR_PATH[31:1]); 71 | end 72 | $finish(); 73 | end 74 | 75 | initial begin 76 | repeat (TIMEOUT_CYCLE) @(posedge clk); 77 | $display("Timeout!"); 78 | $finish(); 79 | end 80 | 81 | endmodule 82 | -------------------------------------------------------------------------------- /hardware/sim/mem_path.vh: -------------------------------------------------------------------------------- 1 | // TODO: change these paths if you move the Memory or RegFile instantiation 2 | // to a different module 3 | `define RF_PATH cpu.rf 4 | `define DMEM_PATH cpu.dmem 5 | `define IMEM_PATH cpu.imem 6 | `define BIOS_PATH cpu.bios_mem 7 | `define CSR_PATH cpu.tohost_csr 8 | -------------------------------------------------------------------------------- /hardware/sim/mmio_counter_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `include "../src/riscv_core/opcode.vh" 4 | `include "mem_path.vh" 5 | 6 | /* 7 | This testbench contains small sets of RV32I instructions to verify MMIO counters are working. 8 | It is based on cpu_tb.v. 9 | 10 | How does the testbench work? 11 | For each test, the testbench initializes IMem with one or several instructions 12 | (encoded in binary format as specified in the spec) for testing. 13 | RegFile and DMem are also initialized with some data. 14 | 15 | Each test program should contain the following instructions: 16 | 1. Reset MMIO counters (task write_reset_cntr_inst) 17 | 2. Some user-defined instructions 18 | 3. Load MMIO counter values to registers, set CSR to 1, and then set CSR to 0 (task write_load_cntr_insts) 19 | 20 | Then, the clock is advanced until the CSR is set to 1 (indicating end of program). 21 | If no correct result is returned after a "timeout" cycle, the testbench will be terminated (or failed). 22 | 23 | Once all instructions are written into CPU's IMEM, the task run_cpu should be called, 24 | which will reset the CPU, wait for the program to finish, and then print counter values. 25 | 26 | Don't just run the testbench, look at the tests, see what they do. 27 | The testbench is intended to provide you some examples to get started. 28 | Feel free to make your own change. 29 | Note that the testbench is by no means exhaustive. 30 | You should add your own tests if there are cases you think the testbench 31 | does not cover. 32 | */ 33 | 34 | module mmio_counter_tb(); 35 | reg clk, rst; 36 | parameter CPU_CLOCK_PERIOD = 20; 37 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 38 | 39 | initial clk = 0; 40 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 41 | wire [31:0] csr; 42 | reg bp_enable = 1'b0; 43 | 44 | // Init PC with 32'h1000_0000 -- address space of IMem 45 | // When PC is in IMem's address space, IMem is read-only 46 | // DMem can be R/W as long as the addr bits [31:28] is 4'b00x1 47 | cpu # ( 48 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 49 | .RESET_PC(32'h1000_0000) 50 | ) cpu ( 51 | .clk(clk), 52 | .rst(rst), 53 | .bp_enable(bp_enable), 54 | .serial_in(1'b1), 55 | .serial_out() 56 | ); 57 | 58 | wire [31:0] timeout_cycle = 100; // TODO: change this to a larger number if longer program tests are added. 59 | 60 | // Reset IMem, DMem, and RegFile before running new test 61 | task reset; 62 | integer i; 63 | begin 64 | for (i = 0; i < `RF_PATH.DEPTH; i = i + 1) begin 65 | `RF_PATH.mem[i] = 0; 66 | end 67 | for (i = 0; i < `DMEM_PATH.DEPTH; i = i + 1) begin 68 | `DMEM_PATH.mem[i] = 0; 69 | end 70 | for (i = 0; i < `IMEM_PATH.DEPTH; i = i + 1) begin 71 | `IMEM_PATH.mem[i] = 0; 72 | end 73 | end 74 | endtask 75 | 76 | task reset_cpu; 77 | @(negedge clk); 78 | rst = 1; 79 | @(negedge clk); 80 | rst = 0; 81 | endtask 82 | 83 | reg [31:0] cycle; 84 | reg done; 85 | reg [255:0] current_test_type; 86 | reg all_tests_passed = 0; 87 | 88 | 89 | // Check for timeout 90 | // If a test does not set CSR to 1 in a given timeout cycle, we terminate the testbench 91 | initial begin 92 | while (all_tests_passed === 0) begin 93 | @(posedge clk); 94 | if (cycle === timeout_cycle) begin 95 | $display("[Failed] Timeout at test %s, CSR = %x", current_test_type, `CSR_PATH); 96 | $finish(); 97 | end 98 | end 99 | end 100 | 101 | always @(posedge clk) begin 102 | if (done === 0) 103 | cycle <= cycle + 1; 104 | else 105 | cycle <= 0; 106 | end 107 | 108 | integer i; 109 | 110 | reg [31:0] IMM; 111 | reg [14:0] INST_ADDR; 112 | 113 | // Display RegFile register value 114 | task display_result_rf; 115 | input [31:0] rf_addr; 116 | input [255:0] test_type; 117 | begin 118 | $display("%s : %d", test_type, `RF_PATH.mem[rf_addr]); 119 | end 120 | endtask 121 | 122 | task display_counter_values; 123 | begin 124 | display_result_rf(5'd7, "Cycle"); 125 | display_result_rf(5'd8, "Instruction"); 126 | display_result_rf(5'd9, "Branch Instruction"); 127 | display_result_rf(5'd10, "Correct Branch Prediction"); 128 | end 129 | endtask 130 | 131 | task write_reset_cntr_inst; 132 | begin 133 | `RF_PATH.mem[1] = 32'hxxxx_xxxx; 134 | `RF_PATH.mem[2] = 32'h8000_0018; // The reset counter address 135 | `IMEM_PATH.mem[INST_ADDR] = {7'd0, 5'd1, 5'd2, `FNC_SW, 5'd0, `OPC_STORE}; 136 | INST_ADDR = INST_ADDR + 'd1; 137 | end 138 | endtask 139 | 140 | task write_load_cntr_insts; 141 | begin 142 | `RF_PATH.mem[3] = 32'h8000_0010; // The cycle counter address 143 | `RF_PATH.mem[4] = 32'h8000_0014; // The instruction counter address 144 | `RF_PATH.mem[5] = 32'h8000_001c; // The branch instruction counter address 145 | `RF_PATH.mem[6] = 32'h8000_0020; // The correct branch prediction counter address 146 | 147 | `IMEM_PATH.mem[INST_ADDR + 0] = {12'd0, 5'd3, `FNC_LW, 5'd7, `OPC_LOAD}; 148 | `IMEM_PATH.mem[INST_ADDR + 1] = {12'd0, 5'd4, `FNC_LW, 5'd8, `OPC_LOAD}; 149 | `IMEM_PATH.mem[INST_ADDR + 2] = {12'd0, 5'd5, `FNC_LW, 5'd9, `OPC_LOAD}; 150 | `IMEM_PATH.mem[INST_ADDR + 3] = {12'd0, 5'd6, `FNC_LW, 5'd10, `OPC_LOAD}; 151 | `IMEM_PATH.mem[INST_ADDR + 4] = {12'h51e, 5'd1, 3'b101, 5'd0, `OPC_CSR}; 152 | `IMEM_PATH.mem[INST_ADDR + 5] = {12'h51e, 5'd0, 3'b101, 5'd0, `OPC_CSR}; 153 | INST_ADDR = INST_ADDR + 'd6; 154 | end 155 | endtask 156 | 157 | task write_nop_inst; 158 | begin 159 | // NOP (ADDI x0, x0, 0) 160 | `IMEM_PATH.mem[INST_ADDR] = {12'd0, 5'd0, `FNC_ADD_SUB, 5'd0, `OPC_ARI_ITYPE}; 161 | INST_ADDR = INST_ADDR + 'd1; 162 | end 163 | endtask 164 | 165 | task write_for_loop_program_insts; 166 | input [11:0] max_iter; 167 | reg [4:0] RVAR; 168 | /* 169 | 170 | Implements the following code: 171 | 1. Initialize RVAR to max_iter (ADDI RVAR, x0, max_iter) 172 | 2. Decrement RVAR by 1 (SUB RVAR, RVAR, -1) 173 | 3. Go back to #2 if RVAR != 0 (BEQ RVAR, x0, -4) 174 | 175 | In other words, the pseudocode is "for (x = max_iter - 1; x != 0; x = x - 1);" 176 | */ 177 | begin 178 | RVAR = 5'd11; 179 | IMM = 32'hffff_fffc; 180 | `IMEM_PATH.mem[INST_ADDR + 0] = {max_iter, 5'd0, `FNC_ADD_SUB, RVAR, `OPC_ARI_ITYPE}; 181 | `IMEM_PATH.mem[INST_ADDR + 1] = {12'hfff, RVAR, `FNC_ADD_SUB, RVAR, `OPC_ARI_ITYPE}; 182 | `IMEM_PATH.mem[INST_ADDR + 2] = {IMM[12], IMM[10:5], 5'd0, RVAR, `FNC_BNE, IMM[4:1], IMM[11], `OPC_BRANCH}; 183 | INST_ADDR = INST_ADDR + 'd3; 184 | end 185 | endtask 186 | 187 | task run_cpu; 188 | begin 189 | reset_cpu(); 190 | done = 0; 191 | wait (`CSR_PATH === 1); 192 | done = 1; 193 | display_counter_values(); 194 | wait (`CSR_PATH === 0); 195 | end 196 | endtask 197 | 198 | initial begin 199 | `ifndef IVERILOG 200 | $vcdpluson; 201 | $vcdplusmemon; 202 | `endif 203 | `ifdef IVERILOG 204 | $dumpfile("mmio_counter_tb.fst"); 205 | $dumpvars(0, mmio_counter_tb); 206 | `endif 207 | 208 | #0; 209 | rst = 0; 210 | 211 | // Reset the CPU 212 | rst = 1; 213 | // Hold reset for a while 214 | repeat (10) @(posedge clk); 215 | 216 | @(negedge clk); 217 | rst = 0; 218 | 219 | // Test NOP Insts -------------------------------------------------- 220 | current_test_type = "NOP"; 221 | $display("Benchmarking %s Program", current_test_type); 222 | 223 | reset(); 224 | 225 | // Write program 226 | INST_ADDR = 14'h0000; 227 | write_reset_cntr_inst(); 228 | for (i = 0; i < 10; i = i + 1) begin 229 | write_nop_inst(); 230 | end 231 | write_load_cntr_insts(); 232 | 233 | run_cpu(); 234 | 235 | // Test Branching Insts -------------------------------------------- 236 | current_test_type = "For Loop"; 237 | $display("Benchmarking %s Program", current_test_type); 238 | reset(); 239 | 240 | // Write program 241 | INST_ADDR = 14'h0000; 242 | write_reset_cntr_inst(); 243 | write_for_loop_program_insts(10); 244 | write_load_cntr_insts(); 245 | 246 | run_cpu(); 247 | 248 | // ... what else? 249 | all_tests_passed = 1'b1; 250 | 251 | repeat (100) @(posedge clk); 252 | $display("All tests passed!"); 253 | $finish(); 254 | end 255 | 256 | endmodule 257 | -------------------------------------------------------------------------------- /hardware/sim/uart_parse_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | `include "mem_path.vh" 3 | 4 | module uart_parse_tb(); 5 | reg clk, rst; 6 | parameter CPU_CLOCK_PERIOD = 20; 7 | parameter CPU_CLOCK_FREQ = 1_000_000_000 / CPU_CLOCK_PERIOD; 8 | localparam BAUD_RATE = 10_000_000; 9 | localparam BAUD_PERIOD = 1_000_000_000 / BAUD_RATE; // 8680.55 ns 10 | 11 | localparam TIMEOUT_CYCLE = 100_000; 12 | 13 | initial clk = 0; 14 | always #(CPU_CLOCK_PERIOD/2) clk = ~clk; 15 | reg bp_enable = 1'b0; 16 | 17 | reg serial_in; 18 | wire serial_out; 19 | 20 | cpu # ( 21 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 22 | .RESET_PC(32'h1000_0000), 23 | .BAUD_RATE(BAUD_RATE) 24 | ) cpu ( 25 | .clk(clk), 26 | .rst(rst), 27 | .bp_enable(bp_enable), 28 | .serial_in(serial_in), // input 29 | .serial_out(serial_out) // output 30 | ); 31 | 32 | integer i, j; 33 | reg [31:0] cycle; 34 | always @(posedge clk) begin 35 | if (rst === 1) 36 | cycle <= 0; 37 | else 38 | cycle <= cycle + 1; 39 | end 40 | 41 | // Host off-chip UART --> FPGA on-chip UART (receiver) 42 | // The host (testbench) sends a character to the CPU via the serial line 43 | task host_to_fpga; 44 | input [7:0] char_in; 45 | begin 46 | serial_in = 0; 47 | #(BAUD_PERIOD); 48 | // Data bits (payload) 49 | for (i = 0; i < 8; i = i + 1) begin 50 | serial_in = char_in[i]; 51 | #(BAUD_PERIOD); 52 | end 53 | // Stop bit 54 | serial_in = 1; 55 | #(BAUD_PERIOD); 56 | 57 | $display("[time %t, sim. cycle %d] [Host (tb) --> FPGA_SERIAL_RX] Sent char 8'h%h", 58 | $time, cycle, char_in); 59 | repeat (200) @(posedge clk); 60 | end 61 | endtask 62 | 63 | reg [9:0] char_out; 64 | reg [63:0] test_status; 65 | 66 | // Host off-chip UART <-- FPGA on-chip UART (transmitter) 67 | // The host (testbench) expects to receive a character from the CPU via the serial line 68 | task fpga_to_host; 69 | input [7:0] expected_char; 70 | begin 71 | // Wait until serial_out is LOW (start of transaction) 72 | while (serial_out === 1) begin 73 | @(posedge clk); 74 | end 75 | 76 | for (j = 0; j < 10; j = j + 1) begin 77 | char_out[j] = serial_out; 78 | #(BAUD_PERIOD); 79 | end 80 | 81 | if (expected_char === char_out[8:1]) 82 | test_status = "PASSED"; 83 | else 84 | test_status = "FAILED"; 85 | 86 | if (expected_char != 8'h0d && expected_char != 8'h0a) begin 87 | $display("[time %t, sim. cycle %d] [Host (tb) <-- FPGA_SERIAL_TX] Got char 8'h%h, expected 8'h%h == %s [ %s ]", 88 | $time, cycle, char_out[8:1], expected_char, expected_char, test_status); 89 | end else begin 90 | $display("[time %t, sim. cycle %d] [Host (tb) <-- FPGA_SERIAL_TX] Got char 8'h%h, expected 8'h%h == newline/CR [ %s ]", 91 | $time, cycle, char_out[8:1], expected_char, test_status); 92 | end 93 | end 94 | endtask 95 | 96 | initial begin 97 | $readmemh("../../software/uart_parse/uart_parse.hex", `IMEM_PATH.mem, 0, 16384-1); 98 | $readmemh("../../software/uart_parse/uart_parse.hex", `DMEM_PATH.mem, 0, 16384-1); 99 | 100 | `ifndef IVERILOG 101 | $vcdpluson; 102 | `endif 103 | `ifdef IVERILOG 104 | $dumpfile("uart_parse_tb.fst"); 105 | $dumpvars(0, uart_parse_tb); 106 | `endif 107 | 108 | rst = 1; 109 | serial_in = 1; 110 | 111 | // Hold reset for a while 112 | repeat (10) @(posedge clk); 113 | 114 | @(negedge clk); 115 | rst = 0; 116 | 117 | // Delay for some time 118 | repeat (10) @(posedge clk); 119 | 120 | $display("[TEST 1] Expect to see: \\r\\n151> "); 121 | 122 | fpga_to_host(8'h0d); // \r 123 | fpga_to_host(8'h0a); // \n 124 | fpga_to_host(8'h31); // 1 125 | fpga_to_host(8'h35); // 5 126 | fpga_to_host(8'h31); // 1 127 | fpga_to_host(8'h3e); // > 128 | fpga_to_host(8'h20); // [space] 129 | 130 | $display("[TEST 2]"); 131 | fork 132 | begin 133 | host_to_fpga(8'h78); // 'x' 134 | host_to_fpga(8'h79); // 'y' 135 | host_to_fpga(8'h7a); // 'z' 136 | host_to_fpga(8'h0d); // '\r' 137 | end 138 | begin 139 | // echo back the input characters ... 140 | fpga_to_host(8'h78); // 'x' 141 | fpga_to_host(8'h79); // 'y' 142 | fpga_to_host(8'h7a); // 'z' 143 | fpga_to_host(8'h0d); // '\r' 144 | end 145 | join 146 | 147 | // Wait until csr is updated 148 | while (`CSR_PATH === 32'd0) begin 149 | @(posedge clk); 150 | end 151 | 152 | if (`CSR_PATH === 32'b1) begin 153 | $display("[%d sim. cycles] CSR test PASSED! Strings matched.", cycle); 154 | end else begin 155 | $display("[%d sim. cycles] CSR test FAILED! Strings mismatched.", cycle); 156 | end 157 | 158 | repeat (100) @(posedge clk); 159 | $finish(); 160 | end 161 | 162 | initial begin 163 | repeat (TIMEOUT_CYCLE) @(posedge clk); 164 | $display("Timeout!"); 165 | $fatal(); 166 | end 167 | 168 | endmodule 169 | -------------------------------------------------------------------------------- /hardware/sim_models/BUFG.v: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 1995/2018 Xilinx, Inc. 3 | // All Right Reserved. 4 | /////////////////////////////////////////////////////////////////////////////// 5 | // ____ ____ 6 | // / /\/ / 7 | // /___/ \ / Vendor : Xilinx 8 | // \ \ \/ Version : 2018.3 9 | // \ \ Description : Xilinx Unified Simulation Library Component 10 | // / / General Clock Buffer 11 | // /___/ /\ Filename : BUFG.v 12 | // \ \ / \ 13 | // \___\/\___\ 14 | // 15 | /////////////////////////////////////////////////////////////////////////////// 16 | // Revision: 17 | // 03/23/04 - Initial version. 18 | // 05/23/07 - Changed timescale to 1 ps / 1 ps. 19 | // 12/13/11 - 524859 - Added `celldefine and `endcelldefine 20 | // End Revision: 21 | /////////////////////////////////////////////////////////////////////////////// 22 | 23 | //`timescale 1 ps / 1 ps 24 | 25 | `celldefine 26 | 27 | module BUFG 28 | `ifdef XIL_TIMING 29 | #( 30 | parameter LOC = "UNPLACED" 31 | ) 32 | `endif 33 | ( 34 | output O, 35 | 36 | input I 37 | ); 38 | 39 | // define constants 40 | localparam MODULE_NAME = "BUFG"; 41 | 42 | `ifdef XIL_TIMING 43 | reg notifier; 44 | `endif 45 | 46 | // begin behavioral model 47 | 48 | buf B1 (O, I); 49 | 50 | // end behavioral model 51 | 52 | `ifndef XIL_XECLIB 53 | `ifdef XIL_TIMING 54 | specify 55 | (I => O) = (0:0:0, 0:0:0); 56 | $period (negedge I, 0:0:0, notifier); 57 | $period (posedge I, 0:0:0, notifier); 58 | specparam PATHPULSE$ = 0; 59 | endspecify 60 | `endif 61 | `endif 62 | 63 | endmodule 64 | 65 | `endcelldefine 66 | -------------------------------------------------------------------------------- /hardware/sim_models/glbl.v: -------------------------------------------------------------------------------- 1 | // $Header: /devl/xcs/repo/env/Databases/CAEInterfaces/verunilibs/data/glbl.v,v 1.14 2010/10/28 20:44:00 fphillip Exp $ 2 | `ifndef GLBL 3 | `define GLBL 4 | //`timescale 1 ps / 1 ps 5 | 6 | module glbl (); 7 | 8 | parameter ROC_WIDTH = 100000; 9 | parameter TOC_WIDTH = 0; 10 | 11 | //-------- STARTUP Globals -------------- 12 | wire GSR; 13 | wire GTS; 14 | wire GWE; 15 | wire PRLD; 16 | tri1 p_up_tmp; 17 | tri (weak1, strong0) PLL_LOCKG = p_up_tmp; 18 | 19 | wire PROGB_GLBL; 20 | wire CCLKO_GLBL; 21 | wire FCSBO_GLBL; 22 | wire [3:0] DO_GLBL; 23 | wire [3:0] DI_GLBL; 24 | 25 | reg GSR_int; 26 | reg GTS_int; 27 | reg PRLD_int; 28 | 29 | //-------- JTAG Globals -------------- 30 | wire JTAG_TDO_GLBL; 31 | wire JTAG_TCK_GLBL; 32 | wire JTAG_TDI_GLBL; 33 | wire JTAG_TMS_GLBL; 34 | wire JTAG_TRST_GLBL; 35 | 36 | reg JTAG_CAPTURE_GLBL; 37 | reg JTAG_RESET_GLBL; 38 | reg JTAG_SHIFT_GLBL; 39 | reg JTAG_UPDATE_GLBL; 40 | reg JTAG_RUNTEST_GLBL; 41 | 42 | reg JTAG_SEL1_GLBL = 0; 43 | reg JTAG_SEL2_GLBL = 0 ; 44 | reg JTAG_SEL3_GLBL = 0; 45 | reg JTAG_SEL4_GLBL = 0; 46 | 47 | reg JTAG_USER_TDO1_GLBL = 1'bz; 48 | reg JTAG_USER_TDO2_GLBL = 1'bz; 49 | reg JTAG_USER_TDO3_GLBL = 1'bz; 50 | reg JTAG_USER_TDO4_GLBL = 1'bz; 51 | 52 | assign (strong1, weak0) GSR = GSR_int; 53 | assign (strong1, weak0) GTS = GTS_int; 54 | assign (weak1, weak0) PRLD = PRLD_int; 55 | 56 | initial begin 57 | GSR_int = 1'b1; 58 | PRLD_int = 1'b1; 59 | #(ROC_WIDTH) 60 | GSR_int = 1'b0; 61 | PRLD_int = 1'b0; 62 | end 63 | 64 | initial begin 65 | GTS_int = 1'b1; 66 | #(TOC_WIDTH) 67 | GTS_int = 1'b0; 68 | end 69 | 70 | endmodule 71 | `endif 72 | -------------------------------------------------------------------------------- /hardware/src/clocks.v: -------------------------------------------------------------------------------- 1 | module clocks #( 2 | parameter CLK_PERIOD = 8, // period of the primary clock into the FPGA 3 | // Sets the CPU clock = 125Mhz * 34 / 5 / 17 = 50 MHz 4 | parameter CPU_CLK_CLKFBOUT_MULT = 34, 5 | parameter CPU_CLK_DIVCLK_DIVIDE = 5, 6 | parameter CPU_CLK_CLKOUT_DIVIDE = 17, 7 | // Sets the PWM clock = 125 MHz * 36 / 5 / 6 = 150 MHz 8 | parameter PWM_CLK_CLKFBOUT_MULT = 36, 9 | parameter PWM_CLK_DIVCLK_DIVIDE = 5, 10 | parameter PWM_CLK_CLKOUT_DIVIDE = 6 11 | ) ( 12 | input clk_125mhz, 13 | output cpu_clk, 14 | output cpu_clk_locked, 15 | output pwm_clk, 16 | output pwm_clk_locked 17 | ); 18 | wire cpu_clk_int, cpu_clk_g; 19 | wire cpu_clk_pll_fb_out, cpu_clk_pll_fb_in; 20 | assign cpu_clk = cpu_clk_g; 21 | 22 | BUFG cpu_clk_buf (.I(cpu_clk_int), .O(cpu_clk_g)); 23 | BUFG cpu_clk_f_buf (.I(cpu_clk_pll_fb_out), .O (cpu_clk_pll_fb_in)); 24 | 25 | // This PLL generates the cpu_clk from the 125 Mhz clock 26 | PLLE2_ADV #( 27 | .BANDWIDTH ("OPTIMIZED"), 28 | .COMPENSATION ("BUF_IN"), // Not "ZHOLD" 29 | .STARTUP_WAIT ("FALSE"), 30 | .DIVCLK_DIVIDE (CPU_CLK_DIVCLK_DIVIDE), 31 | .CLKFBOUT_MULT (CPU_CLK_CLKFBOUT_MULT), 32 | .CLKFBOUT_PHASE (0.000), 33 | .CLKOUT0_DIVIDE (CPU_CLK_CLKOUT_DIVIDE), 34 | .CLKOUT0_PHASE (0.000), 35 | .CLKOUT0_DUTY_CYCLE (0.500), 36 | .CLKIN1_PERIOD (CLK_PERIOD) 37 | ) plle2_cpu_inst ( 38 | .CLKFBOUT (cpu_clk_pll_fb_out), 39 | .CLKOUT0 (cpu_clk_int), 40 | .CLKOUT1 (), 41 | .CLKOUT2 (), 42 | .CLKOUT3 (), 43 | .CLKOUT4 (), 44 | .CLKOUT5 (), 45 | // Input clock control 46 | .CLKFBIN (cpu_clk_pll_fb_in), 47 | .CLKIN1 (clk_125mhz), 48 | .CLKIN2 (1'b0), 49 | // Tied to always select the primary input clock 50 | .CLKINSEL (1'b1), 51 | // Other control and status signals 52 | .LOCKED (cpu_clk_locked), 53 | .PWRDWN (1'b0), 54 | .RST (1'b0), 55 | .DCLK (1'b0), 56 | .DEN (1'b0), 57 | .DI (16'd0), 58 | .DWE (1'b0), 59 | .DADDR (7'd0), 60 | .DO (), 61 | .DRDY () 62 | ); 63 | 64 | wire pwm_clk_int, pwm_clk_g; 65 | wire pwm_clk_pll_fb_out, pwm_clk_pll_fb_in; 66 | assign pwm_clk = pwm_clk_g; 67 | 68 | BUFG pwm_clk_buf (.I(pwm_clk_int), .O(pwm_clk_g)); 69 | BUFG pwm_clk_f_buf (.I(pwm_clk_pll_fb_out), .O (pwm_clk_pll_fb_in)); 70 | 71 | // This PLL generates the pwm_clk from the 125 Mhz clock 72 | PLLE2_ADV #( 73 | .BANDWIDTH ("OPTIMIZED"), 74 | .COMPENSATION ("BUF_IN"), // Not "ZHOLD" 75 | .STARTUP_WAIT ("FALSE"), 76 | .DIVCLK_DIVIDE (PWM_CLK_DIVCLK_DIVIDE), 77 | .CLKFBOUT_MULT (PWM_CLK_CLKFBOUT_MULT), 78 | .CLKFBOUT_PHASE (0.000), 79 | .CLKOUT0_DIVIDE (PWM_CLK_CLKOUT_DIVIDE), 80 | .CLKOUT0_PHASE (0.000), 81 | .CLKOUT0_DUTY_CYCLE (0.500), 82 | .CLKIN1_PERIOD (CLK_PERIOD) 83 | ) plle2_pwm_inst ( 84 | .CLKFBOUT (pwm_clk_pll_fb_out), 85 | .CLKOUT0 (pwm_clk_int), 86 | .CLKOUT1 (), 87 | .CLKOUT2 (), 88 | .CLKOUT3 (), 89 | .CLKOUT4 (), 90 | .CLKOUT5 (), 91 | // Input clock control 92 | .CLKFBIN (pwm_clk_pll_fb_in), 93 | .CLKIN1 (clk_125mhz), 94 | .CLKIN2 (1'b0), 95 | // Tied to always select the primary input clock 96 | .CLKINSEL (1'b1), 97 | // Other control and status signals 98 | .LOCKED (pwm_clk_locked), 99 | .PWRDWN (1'b0), 100 | .RST (1'b0), 101 | .DCLK (1'b0), 102 | .DEN (1'b0), 103 | .DI (16'd0), 104 | .DWE (1'b0), 105 | .DADDR (7'd0), 106 | .DO (), 107 | .DRDY () 108 | ); 109 | endmodule 110 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/button_parser.v: -------------------------------------------------------------------------------- 1 | 2 | // This module instantiates the synchronizer -> debouncer -> edge detector signal chain for button inputs 3 | module button_parser #( 4 | parameter WIDTH = 1, 5 | parameter SAMPLE_CNT_MAX = 25000, 6 | parameter PULSE_CNT_MAX = 150 7 | ) ( 8 | input clk, 9 | input [WIDTH-1:0] in, 10 | output [WIDTH-1:0] out 11 | ); 12 | 13 | wire [WIDTH-1:0] synchronized_signals; 14 | wire [WIDTH-1:0] debounced_signals; 15 | 16 | synchronizer # ( 17 | .WIDTH(WIDTH) 18 | ) button_synchronizer ( 19 | .clk(clk), 20 | .async_signal(in), 21 | .sync_signal(synchronized_signals) 22 | ); 23 | 24 | debouncer # ( 25 | .WIDTH(WIDTH), 26 | .SAMPLE_CNT_MAX(SAMPLE_CNT_MAX), 27 | .PULSE_CNT_MAX(PULSE_CNT_MAX) 28 | ) button_debouncer ( 29 | .clk(clk), 30 | .glitchy_signal(synchronized_signals), 31 | .debounced_signal(debounced_signals) 32 | ); 33 | 34 | edge_detector # ( 35 | .WIDTH(WIDTH) 36 | ) button_edge_detector ( 37 | .clk(clk), 38 | .signal_in(debounced_signals), 39 | .edge_detect_pulse(out) 40 | ); 41 | 42 | endmodule 43 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/debouncer.v: -------------------------------------------------------------------------------- 1 | 2 | module debouncer #( 3 | parameter WIDTH = 1, 4 | parameter SAMPLE_CNT_MAX = 25000, 5 | parameter PULSE_CNT_MAX = 150, 6 | parameter WRAPPING_CNT_WIDTH = $clog2(SAMPLE_CNT_MAX) + 1, 7 | parameter SAT_CNT_WIDTH = $clog2(PULSE_CNT_MAX) + 1 8 | ) ( 9 | input clk, 10 | input [WIDTH-1:0] glitchy_signal, 11 | output [WIDTH-1:0] debounced_signal 12 | ); 13 | 14 | // TODO: Your code 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/edge_detector.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module edge_detector #( 4 | parameter WIDTH = 1 5 | )( 6 | input clk, 7 | input [WIDTH-1:0] signal_in, 8 | output [WIDTH-1:0] edge_detect_pulse 9 | ); 10 | 11 | // TODO: Your code 12 | 13 | endmodule 14 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/fifo.v: -------------------------------------------------------------------------------- 1 | 2 | module fifo #( 3 | parameter WIDTH = 32, // data width is 32-bit 4 | parameter LOGDEPTH = 3 // 2^3 = 8 entries 5 | ) ( 6 | input clk, 7 | input rst, 8 | 9 | // Write interface (enqueue) 10 | input enq_valid, 11 | input [WIDTH-1:0] enq_data, 12 | output enq_ready, 13 | 14 | // Read interface (dequeue) 15 | output deq_valid, 16 | output [WIDTH-1:0] deq_data, 17 | input deq_ready 18 | ); 19 | 20 | // TODO: Your code 21 | 22 | endmodule 23 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/synchronizer.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module synchronizer #(parameter WIDTH = 1) ( 4 | input [WIDTH-1:0] async_signal, 5 | input clk, 6 | output [WIDTH-1:0] sync_signal 7 | ); 8 | 9 | // TODO: Your code 10 | 11 | endmodule 12 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/uart.v: -------------------------------------------------------------------------------- 1 | module uart #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200 4 | ) ( 5 | input clk, 6 | input reset, 7 | 8 | input [7:0] data_in, 9 | input data_in_valid, 10 | output data_in_ready, 11 | 12 | output [7:0] data_out, 13 | output data_out_valid, 14 | input data_out_ready, 15 | 16 | input serial_in, 17 | output serial_out 18 | ); 19 | reg serial_in_reg, serial_out_reg; 20 | wire serial_out_tx; 21 | assign serial_out = serial_out_reg; 22 | always @ (posedge clk) begin 23 | serial_out_reg <= reset ? 1'b1 : serial_out_tx; 24 | serial_in_reg <= reset ? 1'b1 : serial_in; 25 | end 26 | 27 | uart_transmitter #( 28 | .CLOCK_FREQ(CLOCK_FREQ), 29 | .BAUD_RATE(BAUD_RATE) 30 | ) uatransmit ( 31 | .clk(clk), 32 | .reset(reset), 33 | .data_in(data_in), 34 | .data_in_valid(data_in_valid), 35 | .data_in_ready(data_in_ready), 36 | .serial_out(serial_out_tx) 37 | ); 38 | 39 | uart_receiver #( 40 | .CLOCK_FREQ(CLOCK_FREQ), 41 | .BAUD_RATE(BAUD_RATE) 42 | ) uareceive ( 43 | .clk(clk), 44 | .reset(reset), 45 | .data_out(data_out), 46 | .data_out_valid(data_out_valid), 47 | .data_out_ready(data_out_ready), 48 | .serial_in(serial_in_reg) 49 | ); 50 | endmodule 51 | -------------------------------------------------------------------------------- /hardware/src/io_circuits/uart_receiver.v: -------------------------------------------------------------------------------- 1 | module uart_receiver #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200) 4 | ( 5 | input clk, 6 | input reset, 7 | 8 | output [7:0] data_out, 9 | output data_out_valid, 10 | input data_out_ready, 11 | 12 | input serial_in 13 | ); 14 | // See diagram in the lab guide 15 | localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 16 | localparam SAMPLE_TIME = SYMBOL_EDGE_TIME / 2; 17 | localparam CLOCK_COUNTER_WIDTH= $clog2(SYMBOL_EDGE_TIME); 18 | 19 | wire symbol_edge; 20 | wire sample; 21 | wire start; 22 | wire rx_running; 23 | 24 | reg [9:0] rx_shift; 25 | reg [3:0] bit_counter; 26 | reg [CLOCK_COUNTER_WIDTH-1:0] clock_counter; 27 | reg has_byte; 28 | 29 | //--|Signal Assignments|------------------------------------------------------ 30 | 31 | // Goes high at every symbol edge 32 | /* verilator lint_off WIDTH */ 33 | assign symbol_edge = clock_counter == (SYMBOL_EDGE_TIME - 1); 34 | /* lint_on */ 35 | 36 | // Goes high halfway through each symbol 37 | /* verilator lint_off WIDTH */ 38 | assign sample = clock_counter == SAMPLE_TIME; 39 | /* lint_on */ 40 | 41 | // Goes high when it is time to start receiving a new character 42 | assign start = !serial_in && !rx_running; 43 | 44 | // Goes high while we are receiving a character 45 | assign rx_running = bit_counter != 4'd0; 46 | 47 | // Outputs 48 | assign data_out = rx_shift[8:1]; 49 | assign data_out_valid = has_byte && !rx_running; 50 | 51 | //--|Counters|---------------------------------------------------------------- 52 | 53 | // Counts cycles until a single symbol is done 54 | always @ (posedge clk) begin 55 | clock_counter <= (start || reset || symbol_edge) ? 0 : clock_counter + 1; 56 | end 57 | 58 | // Counts down from 10 bits for every character 59 | always @ (posedge clk) begin 60 | if (reset) begin 61 | bit_counter <= 0; 62 | end else if (start) begin 63 | bit_counter <= 10; 64 | end else if (symbol_edge && rx_running) begin 65 | bit_counter <= bit_counter - 1; 66 | end 67 | end 68 | 69 | //--|Shift Register|---------------------------------------------------------- 70 | always @(posedge clk) begin 71 | if (sample && rx_running) rx_shift <= {serial_in, rx_shift[9:1]}; 72 | end 73 | 74 | //--|Extra State For Ready/Valid|--------------------------------------------- 75 | // This block and the has_byte signal aren't needed in the uart_transmitter 76 | always @ (posedge clk) begin 77 | if (reset) has_byte <= 1'b0; 78 | else if (bit_counter == 1 && symbol_edge) has_byte <= 1'b1; 79 | else if (data_out_ready) has_byte <= 1'b0; 80 | end 81 | endmodule -------------------------------------------------------------------------------- /hardware/src/io_circuits/uart_transmitter.v: -------------------------------------------------------------------------------- 1 | module uart_transmitter #( 2 | parameter CLOCK_FREQ = 125_000_000, 3 | parameter BAUD_RATE = 115_200) 4 | ( 5 | input clk, 6 | input reset, 7 | 8 | input [7:0] data_in, 9 | input data_in_valid, 10 | output data_in_ready, 11 | 12 | output serial_out 13 | ); 14 | // See diagram in the lab guide 15 | localparam SYMBOL_EDGE_TIME = CLOCK_FREQ / BAUD_RATE; 16 | localparam CLOCK_COUNTER_WIDTH = $clog2(SYMBOL_EDGE_TIME); 17 | 18 | // Remove these assignments when implementing this module 19 | assign serial_out = 1'b0; 20 | assign data_in_ready = 1'b0; 21 | endmodule -------------------------------------------------------------------------------- /hardware/src/memories/bios_mem.v: -------------------------------------------------------------------------------- 1 | module bios_mem ( 2 | input clk, 3 | input ena, 4 | input [11:0] addra, 5 | output reg [31:0] douta, 6 | input enb, 7 | input [11:0] addrb, 8 | output reg [31:0] doutb 9 | ); 10 | parameter DEPTH = 4096; 11 | reg [31:0] mem [4096-1:0]; 12 | always @(posedge clk) begin 13 | if (ena) begin 14 | douta <= mem[addra]; 15 | end 16 | end 17 | 18 | always @(posedge clk) begin 19 | if (enb) begin 20 | doutb <= mem[addrb]; 21 | end 22 | end 23 | 24 | `define STRINGIFY_BIOS(x) `"x/../software/bios/bios.hex`" 25 | `ifdef SYNTHESIS 26 | initial begin 27 | $readmemh(`STRINGIFY_BIOS(`ABS_TOP), mem); 28 | end 29 | `endif 30 | endmodule 31 | -------------------------------------------------------------------------------- /hardware/src/memories/dmem.v: -------------------------------------------------------------------------------- 1 | module dmem ( 2 | input clk, 3 | input en, 4 | input [3:0] we, 5 | input [13:0] addr, 6 | input [31:0] din, 7 | output reg [31:0] dout 8 | ); 9 | parameter DEPTH = 16384; 10 | 11 | // See page 133 of the Vivado Synthesis Guide for the template 12 | // https://www.xilinx.com/support/documentation/sw_manuals/xilinx2016_4/ug901-vivado-synthesis.pdf 13 | 14 | reg [31:0] mem [16384-1:0]; 15 | integer i; 16 | always @(posedge clk) begin 17 | if (en) begin 18 | for(i=0; i<4; i=i+1) begin 19 | if (we[i]) begin 20 | mem[addr][i*8 +: 8] <= din[i*8 +: 8]; 21 | end 22 | end 23 | dout <= mem[addr]; 24 | end 25 | end 26 | endmodule 27 | -------------------------------------------------------------------------------- /hardware/src/memories/imem.v: -------------------------------------------------------------------------------- 1 | module imem ( 2 | input clk, 3 | input ena, 4 | input [3:0] wea, 5 | input [13:0] addra, 6 | input [31:0] dina, 7 | input [13:0] addrb, 8 | output reg [31:0] doutb 9 | ); 10 | parameter DEPTH = 16384; 11 | 12 | // See page 133 of the Vivado Synthesis Guide for the template 13 | // https://www.xilinx.com/support/documentation/sw_manuals/xilinx2016_4/ug901-vivado-synthesis.pdf 14 | 15 | reg [31:0] mem [16384-1:0]; 16 | integer i; 17 | always @(posedge clk) begin 18 | if (ena) begin 19 | for(i=0; i<4; i=i+1) begin 20 | if (wea[i]) begin 21 | mem[addra][i*8 +: 8] <= dina[i*8 +: 8]; 22 | end 23 | end 24 | end 25 | end 26 | 27 | always @(posedge clk) begin 28 | doutb <= mem[addrb]; 29 | end 30 | endmodule 31 | -------------------------------------------------------------------------------- /hardware/src/riscv_core/branch_prediction/bp_cache.v: -------------------------------------------------------------------------------- 1 | /* 2 | A cache module for storing branch prediction data. 3 | 4 | Inputs: 2 asynchronous read ports and 1 synchronous write port. 5 | Outputs: data and cache hit (for each read port) 6 | */ 7 | 8 | module bp_cache #( 9 | parameter AWIDTH=32, // Address bit width 10 | parameter DWIDTH=32, // Data bit width 11 | parameter LINES=128 // Number of cache lines 12 | ) ( 13 | input clk, 14 | input reset, 15 | 16 | // IO for 1st read port 17 | input [AWIDTH-1:0] ra0, 18 | output [DWIDTH-1:0] dout0, 19 | output hit0, 20 | 21 | // IO for 2nd read port 22 | input [AWIDTH-1:0] ra1, 23 | output [DWIDTH-1:0] dout1, 24 | output hit1, 25 | 26 | // IO for write port 27 | input [AWIDTH-1:0] wa, 28 | input [DWIDTH-1:0] din, 29 | input we 30 | 31 | ); 32 | 33 | // TODO: Your code 34 | assign dout0 = '0; 35 | assign dout1 = '0; 36 | assign hit0 = 1'b0; 37 | assign hit1 = 1'b0; 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /hardware/src/riscv_core/branch_prediction/branch_predictor.v: -------------------------------------------------------------------------------- 1 | /* 2 | A branch predictor module that implements a branch history table (BHT). 3 | 4 | Branch prediction guessing is done with inputs *_guess (IF stage). 5 | Branch prediction checking is done with inputs *_check (whichever stage 6 | the branch comparison is computed) and updates next prediction. 7 | 8 | Predictions are updated via a 2-bit saturating counter. 9 | */ 10 | 11 | module branch_predictor #( 12 | parameter PC_WIDTH=32, 13 | parameter LINES=128 14 | ) ( 15 | input clk, 16 | input reset, 17 | 18 | input [PC_WIDTH-1:0] pc_guess, 19 | input is_br_guess, 20 | 21 | input [PC_WIDTH-1:0] pc_check, 22 | input is_br_check, 23 | input br_taken_check, 24 | 25 | output br_pred_taken 26 | ); 27 | 28 | wire cache_hit_guess, cache_hit_check; 29 | wire [1:0] cache_out_guess, cache_out_check; 30 | wire [1:0] sat_out; 31 | 32 | // Since PC should be 4-byte aligned, discard 2 lowest bits of PC for caching 33 | bp_cache #( 34 | .AWIDTH(PC_WIDTH-2), 35 | .DWIDTH(2), 36 | .LINES(LINES) 37 | ) cache ( 38 | .clk(clk), 39 | .reset(reset), 40 | .ra0(pc_guess[PC_WIDTH-1:2]), 41 | .ra1(pc_check[PC_WIDTH-1:2]), 42 | .wa(pc_check[PC_WIDTH-1:2]), 43 | .din(cache_hit_check ? sat_out : (br_taken_check ? 2'b10 : 2'b01)), 44 | .we(is_br_check), 45 | .hit0(cache_hit_guess), 46 | .dout0(cache_out_guess), 47 | .hit1(cache_hit_check), 48 | .dout1(cache_out_check) 49 | ); 50 | 51 | sat_updn #( 52 | .WIDTH(2) 53 | ) sat ( 54 | .in(cache_out_check), 55 | .up(br_taken_check), 56 | .dn(!br_taken_check), 57 | .out(sat_out) 58 | ); 59 | 60 | assign br_pred_taken = is_br_guess && cache_hit_guess && cache_out_guess[1]; 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /hardware/src/riscv_core/branch_prediction/sat_updn.v: -------------------------------------------------------------------------------- 1 | /* 2 | A saturating incrementer/decrementer. 3 | Adds +/-1 to the input with saturation to prevent overflow. 4 | */ 5 | 6 | module sat_updn #( 7 | parameter WIDTH=2 8 | ) ( 9 | input [WIDTH-1:0] in, 10 | input up, 11 | input dn, 12 | 13 | output [WIDTH-1:0] out 14 | ); 15 | 16 | // TODO: Your code 17 | assign out = '0; 18 | 19 | endmodule 20 | -------------------------------------------------------------------------------- /hardware/src/riscv_core/cpu.v: -------------------------------------------------------------------------------- 1 | module cpu #( 2 | parameter CPU_CLOCK_FREQ = 50_000_000, 3 | parameter RESET_PC = 32'h4000_0000, 4 | parameter BAUD_RATE = 115200 5 | ) ( 6 | input clk, 7 | input rst, 8 | input bp_enable, 9 | input serial_in, 10 | output serial_out 11 | ); 12 | // BIOS Memory 13 | // Synchronous read: read takes one cycle 14 | // Synchronous write: write takes one cycle 15 | wire [11:0] bios_addra, bios_addrb; 16 | wire [31:0] bios_douta, bios_doutb; 17 | wire bios_ena, bios_enb; 18 | bios_mem bios_mem ( 19 | .clk(clk), 20 | .ena(bios_ena), 21 | .addra(bios_addra), 22 | .douta(bios_douta), 23 | .enb(bios_enb), 24 | .addrb(bios_addrb), 25 | .doutb(bios_doutb) 26 | ); 27 | 28 | // Data Memory 29 | // Synchronous read: read takes one cycle 30 | // Synchronous write: write takes one cycle 31 | // Write-byte-enable: select which of the four bytes to write 32 | wire [13:0] dmem_addr; 33 | wire [31:0] dmem_din, dmem_dout; 34 | wire [3:0] dmem_we; 35 | wire dmem_en; 36 | dmem dmem ( 37 | .clk(clk), 38 | .en(dmem_en), 39 | .we(dmem_we), 40 | .addr(dmem_addr), 41 | .din(dmem_din), 42 | .dout(dmem_dout) 43 | ); 44 | 45 | // Instruction Memory 46 | // Synchronous read: read takes one cycle 47 | // Synchronous write: write takes one cycle 48 | // Write-byte-enable: select which of the four bytes to write 49 | wire [31:0] imem_dina, imem_doutb; 50 | wire [13:0] imem_addra, imem_addrb; 51 | wire [3:0] imem_wea; 52 | wire imem_ena; 53 | imem imem ( 54 | .clk(clk), 55 | .ena(imem_ena), 56 | .wea(imem_wea), 57 | .addra(imem_addra), 58 | .dina(imem_dina), 59 | .addrb(imem_addrb), 60 | .doutb(imem_doutb) 61 | ); 62 | 63 | // Register file 64 | // Asynchronous read: read data is available in the same cycle 65 | // Synchronous write: write takes one cycle 66 | wire we; 67 | wire [4:0] ra1, ra2, wa; 68 | wire [31:0] wd; 69 | wire [31:0] rd1, rd2; 70 | reg_file rf ( 71 | .clk(clk), 72 | .we(we), 73 | .ra1(ra1), .ra2(ra2), .wa(wa), 74 | .wd(wd), 75 | .rd1(rd1), .rd2(rd2) 76 | ); 77 | 78 | // On-chip UART 79 | //// UART Receiver 80 | wire [7:0] uart_rx_data_out; 81 | wire uart_rx_data_out_valid; 82 | wire uart_rx_data_out_ready; 83 | //// UART Transmitter 84 | wire [7:0] uart_tx_data_in; 85 | wire uart_tx_data_in_valid; 86 | wire uart_tx_data_in_ready; 87 | uart #( 88 | .CLOCK_FREQ(CPU_CLOCK_FREQ), 89 | .BAUD_RATE(BAUD_RATE) 90 | ) on_chip_uart ( 91 | .clk(clk), 92 | .reset(rst), 93 | 94 | .serial_in(serial_in), 95 | .data_out(uart_rx_data_out), 96 | .data_out_valid(uart_rx_data_out_valid), 97 | .data_out_ready(uart_rx_data_out_ready), 98 | 99 | .serial_out(serial_out), 100 | .data_in(uart_tx_data_in), 101 | .data_in_valid(uart_tx_data_in_valid), 102 | .data_in_ready(uart_tx_data_in_ready) 103 | ); 104 | 105 | reg [31:0] tohost_csr = 0; 106 | 107 | // TODO: Your code to implement a fully functioning RISC-V core 108 | // Add as many modules as you want 109 | // Feel free to move the memory modules around 110 | endmodule 111 | -------------------------------------------------------------------------------- /hardware/src/riscv_core/opcode.vh: -------------------------------------------------------------------------------- 1 | // List of RISC-V opcodes and funct codes. 2 | // Use `include "opcode.vh" to use these in the decoder 3 | 4 | `ifndef OPCODE 5 | `define OPCODE 6 | 7 | // ***** Opcodes ***** 8 | // CSR instructions 9 | `define OPC_CSR 7'b1110011 10 | 11 | // Special immediate instructions 12 | `define OPC_LUI 7'b0110111 13 | `define OPC_AUIPC 7'b0010111 14 | 15 | // Jump instructions 16 | `define OPC_JAL 7'b1101111 17 | `define OPC_JALR 7'b1100111 18 | 19 | // Branch instructions 20 | `define OPC_BRANCH 7'b1100011 21 | 22 | // Load and store instructions 23 | `define OPC_STORE 7'b0100011 24 | `define OPC_LOAD 7'b0000011 25 | 26 | // Arithmetic instructions 27 | `define OPC_ARI_RTYPE 7'b0110011 28 | `define OPC_ARI_ITYPE 7'b0010011 29 | 30 | // ***** 5-bit Opcodes ***** 31 | `define OPC_LUI_5 5'b01101 32 | `define OPC_AUIPC_5 5'b00101 33 | `define OPC_JAL_5 5'b11011 34 | `define OPC_JALR_5 5'b11001 35 | `define OPC_BRANCH_5 5'b11000 36 | `define OPC_STORE_5 5'b01000 37 | `define OPC_LOAD_5 5'b00000 38 | `define OPC_ARI_RTYPE_5 5'b01100 39 | `define OPC_ARI_ITYPE_5 5'b00100 40 | 41 | // ***** Function codes ***** 42 | 43 | // Branch function codes 44 | `define FNC_BEQ 3'b000 45 | `define FNC_BNE 3'b001 46 | `define FNC_BLT 3'b100 47 | `define FNC_BGE 3'b101 48 | `define FNC_BLTU 3'b110 49 | `define FNC_BGEU 3'b111 50 | 51 | // Load and store function codes 52 | `define FNC_LB 3'b000 53 | `define FNC_LH 3'b001 54 | `define FNC_LW 3'b010 55 | `define FNC_LBU 3'b100 56 | `define FNC_LHU 3'b101 57 | `define FNC_SB 3'b000 58 | `define FNC_SH 3'b001 59 | `define FNC_SW 3'b010 60 | 61 | // Arithmetic R-type and I-type functions codes 62 | `define FNC_ADD_SUB 3'b000 63 | `define FNC_SLL 3'b001 64 | `define FNC_SLT 3'b010 65 | `define FNC_SLTU 3'b011 66 | `define FNC_XOR 3'b100 67 | `define FNC_OR 3'b110 68 | `define FNC_AND 3'b111 69 | `define FNC_SRL_SRA 3'b101 70 | 71 | // ADD and SUB use the same opcode + function code 72 | // SRA and SRL also use the same opcode + function code 73 | // For these operations, we also need to look at bit 30 of the instruction 74 | `define FNC2_ADD 1'b0 75 | `define FNC2_SUB 1'b1 76 | `define FNC2_SRL 1'b0 77 | `define FNC2_SRA 1'b1 78 | 79 | `define FNC7_0 7'b0000000 // ADD, SRL 80 | `define FNC7_1 7'b0100000 // SUB, SRA 81 | `endif //OPCODE 82 | -------------------------------------------------------------------------------- /hardware/src/riscv_core/reg_file.v: -------------------------------------------------------------------------------- 1 | module reg_file ( 2 | input clk, 3 | input we, 4 | input [4:0] ra1, ra2, wa, 5 | input [31:0] wd, 6 | output [31:0] rd1, rd2 7 | ); 8 | parameter DEPTH = 32; 9 | reg [31:0] mem [0:31]; 10 | assign rd1 = 32'd0; 11 | assign rd2 = 32'd0; 12 | endmodule 13 | -------------------------------------------------------------------------------- /hardware/src/z1top.v: -------------------------------------------------------------------------------- 1 | module z1top #( 2 | parameter BAUD_RATE = 115_200, 3 | // Warning: CPU_CLOCK_FREQ must match the PLL parameters! 4 | parameter CPU_CLOCK_FREQ = 50_000_000, 5 | // PLL Parameters: sets the CPU clock = 125Mhz * 34 / 5 / 17 = 50 MHz 6 | parameter CPU_CLK_CLKFBOUT_MULT = 34, 7 | parameter CPU_CLK_DIVCLK_DIVIDE = 5, 8 | parameter CPU_CLK_CLKOUT_DIVIDE = 17, 9 | /* verilator lint_off REALCVT */ 10 | // Sample the button signal every 500us 11 | parameter integer B_SAMPLE_CNT_MAX = 0.0005 * CPU_CLOCK_FREQ, 12 | // The button is considered 'pressed' after 100ms of continuous pressing 13 | parameter integer B_PULSE_CNT_MAX = 0.100 / 0.0005, 14 | /* lint_on */ 15 | // The PC the RISC-V CPU should start at after reset 16 | parameter RESET_PC = 32'h4000_0000 17 | ) ( 18 | input CLK_125MHZ_FPGA, 19 | input [3:0] BUTTONS, 20 | input [1:0] SWITCHES, 21 | output [5:0] LEDS, 22 | input FPGA_SERIAL_RX, 23 | output FPGA_SERIAL_TX, 24 | output AUD_PWM, 25 | output AUD_SD 26 | ); 27 | // Clocks and PLL lock status 28 | wire cpu_clk, cpu_clk_locked, pwm_clk, pwm_clk_locked; 29 | 30 | // Buttons after the button_parser 31 | wire [3:0] buttons_pressed; 32 | 33 | // Switches after the synchronizer 34 | wire [1:0] switches_sync; 35 | 36 | // Reset the CPU and all components on the cpu_clk if the reset button is 37 | // pushed or whenever the CPU clock PLL isn't locked 38 | wire cpu_reset; 39 | assign cpu_reset = buttons_pressed[0] || !cpu_clk_locked; 40 | 41 | // Use IOBs to drive/sense the UART serial lines 42 | wire cpu_tx, cpu_rx; 43 | (* IOB = "true" *) reg fpga_serial_tx_iob; 44 | (* IOB = "true" *) reg fpga_serial_rx_iob; 45 | assign FPGA_SERIAL_TX = fpga_serial_tx_iob; 46 | assign cpu_rx = fpga_serial_rx_iob; 47 | always @(posedge cpu_clk) begin 48 | fpga_serial_tx_iob <= cpu_tx; 49 | fpga_serial_rx_iob <= FPGA_SERIAL_RX; 50 | end 51 | 52 | // Use IOBs to drive the PWM output 53 | (* IOB = "true" *) reg pwm_iob; 54 | wire pwm_out; // TODO: connect this wire to your DAC 55 | assign pwm_out = 1'b0; 56 | assign AUD_PWM = pwm_iob; 57 | assign AUD_SD = 1'b1; 58 | always @(posedge pwm_clk) begin 59 | pwm_iob <= pwm_out; 60 | end 61 | 62 | // Generate a reset for the PWM clock domain 63 | wire pwm_rst, reset_button_pwm_domain; 64 | synchronizer rst_pwm_sync (.async_signal(buttons_pressed[0]), .sync_signal(reset_button_pwm_domain), .clk(pwm_clk)); 65 | assign pwm_rst = reset_button_pwm_domain || ~pwm_clk_locked; 66 | 67 | clocks #( 68 | .CPU_CLK_CLKFBOUT_MULT(CPU_CLK_CLKFBOUT_MULT), 69 | .CPU_CLK_DIVCLK_DIVIDE(CPU_CLK_DIVCLK_DIVIDE), 70 | .CPU_CLK_CLKOUT_DIVIDE(CPU_CLK_CLKOUT_DIVIDE) 71 | ) clk_gen ( 72 | .clk_125mhz(CLK_125MHZ_FPGA), 73 | .cpu_clk(cpu_clk), 74 | .cpu_clk_locked(cpu_clk_locked), 75 | .pwm_clk(pwm_clk), 76 | .pwm_clk_locked(pwm_clk_locked) 77 | ); 78 | 79 | button_parser #( 80 | .WIDTH(4), 81 | .SAMPLE_CNT_MAX(B_SAMPLE_CNT_MAX), 82 | .PULSE_CNT_MAX(B_PULSE_CNT_MAX) 83 | ) bp ( 84 | .clk(cpu_clk), 85 | .in(BUTTONS), 86 | .out(buttons_pressed) 87 | ); 88 | 89 | synchronizer #( 90 | .WIDTH(2) 91 | ) switch_synchronizer ( 92 | .clk(cpu_clk), 93 | .async_signal(SWITCHES), 94 | .sync_signal(switches_sync) 95 | ); 96 | 97 | cpu #( 98 | .CPU_CLOCK_FREQ(CPU_CLOCK_FREQ), 99 | .RESET_PC(RESET_PC), 100 | .BAUD_RATE(BAUD_RATE) 101 | ) cpu ( 102 | .clk(cpu_clk), 103 | .rst(cpu_reset), 104 | .bp_enable(switches_sync[0]), 105 | .serial_out(cpu_tx), 106 | .serial_in(cpu_rx) 107 | ); 108 | 109 | 110 | endmodule 111 | -------------------------------------------------------------------------------- /hardware/src/z1top.xdc: -------------------------------------------------------------------------------- 1 | ## Source: https://reference.digilentinc.com/_media/reference/programmable-logic/pynq-z1/pynq-z1_c.zip 2 | ## 3 | 4 | ##RGB LEDs 5 | 6 | set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS33} [get_ports {LEDS[4]}] 7 | set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {LEDS[5]}] 8 | 9 | ##LEDs 10 | 11 | set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {LEDS[0]}] 12 | set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {LEDS[1]}] 13 | set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {LEDS[2]}] 14 | set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {LEDS[3]}] 15 | 16 | ##Buttons 17 | 18 | set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[0]}] 19 | set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[1]}] 20 | set_property -dict {PACKAGE_PIN L20 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[2]}] 21 | set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports {BUTTONS[3]}] 22 | 23 | ##Switches 24 | 25 | set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports {SWITCHES[0]}] 26 | set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports {SWITCHES[1]}] 27 | 28 | ## Clock signal 125 MHz 29 | 30 | set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports CLK_125MHZ_FPGA] 31 | create_clock -period 8.000 -name CLK_125MHZ_FPGA -waveform {0.000 4.000} -add [get_ports CLK_125MHZ_FPGA] 32 | 33 | #set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports CTS] 34 | set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 IOB TRUE} [get_ports FPGA_SERIAL_TX] 35 | set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 IOB TRUE} [get_ports FPGA_SERIAL_RX] 36 | #set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports RTS] 37 | 38 | ##Audio Out 39 | 40 | set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 IOB TRUE} [get_ports { AUD_PWM }]; #IO_L20N_T3_34 Sch=aud_pwm 41 | set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { AUD_SD }]; #IO_L20P_T3_34 Sch=aud_sd 42 | -------------------------------------------------------------------------------- /hardware/stubs/PLLE2_ADV.v: -------------------------------------------------------------------------------- 1 | //`timescale 1 ps / 1 ps 2 | 3 | `celldefine 4 | 5 | module PLLE2_ADV #( 6 | `ifdef XIL_TIMING 7 | parameter LOC = "UNPLACED", 8 | parameter real CLKIN_FREQ_MAX = 1066.000, 9 | parameter real CLKIN_FREQ_MIN = 19.000, 10 | parameter real CLKPFD_FREQ_MAX = 550.0, 11 | parameter real CLKPFD_FREQ_MIN = 19.0, 12 | parameter real VCOCLK_FREQ_MAX = 2133.000, 13 | parameter real VCOCLK_FREQ_MIN = 800.000, 14 | `endif 15 | parameter BANDWIDTH = "OPTIMIZED", 16 | parameter integer CLKFBOUT_MULT = 5, 17 | parameter real CLKFBOUT_PHASE = 0.000, 18 | parameter real CLKIN1_PERIOD = 0.000, 19 | parameter real CLKIN2_PERIOD = 0.000, 20 | parameter integer CLKOUT0_DIVIDE = 1, 21 | parameter real CLKOUT0_DUTY_CYCLE = 0.500, 22 | parameter real CLKOUT0_PHASE = 0.000, 23 | parameter integer CLKOUT1_DIVIDE = 1, 24 | parameter real CLKOUT1_DUTY_CYCLE = 0.500, 25 | parameter real CLKOUT1_PHASE = 0.000, 26 | parameter integer CLKOUT2_DIVIDE = 1, 27 | parameter real CLKOUT2_DUTY_CYCLE = 0.500, 28 | parameter real CLKOUT2_PHASE = 0.000, 29 | parameter integer CLKOUT3_DIVIDE = 1, 30 | parameter real CLKOUT3_DUTY_CYCLE = 0.500, 31 | parameter real CLKOUT3_PHASE = 0.000, 32 | parameter integer CLKOUT4_DIVIDE = 1, 33 | parameter real CLKOUT4_DUTY_CYCLE = 0.500, 34 | parameter real CLKOUT4_PHASE = 0.000, 35 | parameter integer CLKOUT5_DIVIDE = 1, 36 | parameter real CLKOUT5_DUTY_CYCLE = 0.500, 37 | parameter real CLKOUT5_PHASE = 0.000, 38 | parameter COMPENSATION = "ZHOLD", 39 | parameter integer DIVCLK_DIVIDE = 1, 40 | parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0, 41 | parameter [0:0] IS_PWRDWN_INVERTED = 1'b0, 42 | parameter [0:0] IS_RST_INVERTED = 1'b0, 43 | parameter real REF_JITTER1 = 0.010, 44 | parameter real REF_JITTER2 = 0.010, 45 | parameter STARTUP_WAIT = "FALSE" 46 | )( 47 | output CLKFBOUT, 48 | output CLKOUT0, 49 | output CLKOUT1, 50 | output CLKOUT2, 51 | output CLKOUT3, 52 | output CLKOUT4, 53 | output CLKOUT5, 54 | output [15:0] DO, 55 | output DRDY, 56 | output LOCKED, 57 | 58 | input CLKFBIN, 59 | input CLKIN1, 60 | input CLKIN2, 61 | input CLKINSEL, 62 | input [6:0] DADDR, 63 | input DCLK, 64 | input DEN, 65 | input [15:0] DI, 66 | input DWE, 67 | input PWRDWN, 68 | input RST 69 | ); 70 | 71 | endmodule 72 | -------------------------------------------------------------------------------- /scripts/hex_to_serial: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # ported from /home/ff/eecs151/tools-151/bin/coe_to_serial 3 | import os 4 | import serial 5 | import sys 6 | import time 7 | 8 | # Windows 9 | if os.name == 'nt': 10 | ser = serial.Serial() 11 | ser.baudrate = 115200 12 | ser.port = 'COM11' # CHANGE THIS COM PORT 13 | ser.open() 14 | else: 15 | ser = serial.Serial('/dev/ttyUSB0') 16 | ser.baudrate = 115200 17 | 18 | if len(sys.argv) != 3: 19 | print("Usage: hex_to_serial \nExample: hex_to_serial echo.hex 30000000") 20 | sys.exit(1) 21 | 22 | #input("Open a serial program in another terminal, then hit Enter") 23 | 24 | addr = int(sys.argv[2], 16); 25 | with open(sys.argv[1], "r") as f: 26 | program = f.readlines() 27 | if ('@' in program[0]): 28 | program = program[1:] # remove first line '@0' 29 | program = [inst.rstrip() for inst in program] 30 | size = len(program)*4 # in bytes 31 | 32 | # write a newline to clear any input tokens before entering the command 33 | command = "\n\rfile {:08x} {:d} ".format(addr, size) 34 | print("Sending command: {}".format(command)) 35 | for char in command: 36 | ser.write(bytearray([ord(char)])) 37 | time.sleep(0.01) 38 | 39 | for inst_num, inst in enumerate(program): 40 | for char in inst: 41 | ser.write(bytearray([ord(char)])) 42 | time.sleep(0.001) 43 | time.sleep(0.001) 44 | if (inst_num == len(program)-1): 45 | print("Sent {:d}/{:d} bytes".format(4+inst_num*4, size), end='\n') 46 | else: 47 | print("Sent {:d}/{:d} bytes".format(4+inst_num*4, size), end='\r') 48 | 49 | print("Done") 50 | -------------------------------------------------------------------------------- /scripts/init_arm.tcl: -------------------------------------------------------------------------------- 1 | 2 | set project_name z1top_axi 3 | connect -url tcp:127.0.0.1:3121 4 | source ${project_name}_proj/${project_name}_proj.sdk/ps7_init.tcl 5 | targets -set -nocase -filter {name =~"APU*"} -index 0 6 | loadhw -hw ${project_name}_proj/${project_name}_proj.sdk/hwdef.xml -mem-ranges [list {0x40000000 0xbfffffff}] 7 | configparams force-mem-access 1 8 | targets -set -nocase -filter {name =~"APU*"} -index 0 9 | stop 10 | ps7_init 11 | ps7_post_config 12 | targets -set -nocase -filter {name =~ "ARM*#0"} -index 0 13 | rst -processor 14 | targets -set -nocase -filter {name =~ "ARM*#0"} -index 0 15 | dow system/Debug/system.elf 16 | configparams force-mem-access 0 17 | con 18 | -------------------------------------------------------------------------------- /software/.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.dump 3 | *.log 4 | *.hex 5 | *.elf 6 | -------------------------------------------------------------------------------- /software/151_library/ascii.c: -------------------------------------------------------------------------------- 1 | #include "ascii.h" 2 | 3 | #define DEFINE_FROM_ASCII_DEC(type) \ 4 | type##_t ascii_dec_to_##type(const char* s) \ 5 | { \ 6 | type##_t t = 0; \ 7 | for (uint32_t i = 0; i < (((sizeof(type##_t)/sizeof(uint8_t))<<1)+1) && s[i] != '\0'; i++) { \ 8 | if (s[i] >= '0' && s[i] <= '9') { \ 9 | t = (t << 3) + (t << 1) + (s[i] - '0'); \ 10 | } \ 11 | } \ 12 | return t; \ 13 | } 14 | 15 | DEFINE_FROM_ASCII_DEC(uint8) 16 | DEFINE_FROM_ASCII_DEC(uint16) 17 | DEFINE_FROM_ASCII_DEC(uint32) 18 | 19 | #define DEFINE_FROM_ASCII_HEX(type) \ 20 | type##_t ascii_hex_to_##type(const char* s) \ 21 | { \ 22 | type##_t t = 0, i = 0; \ 23 | for ( ; i < ((sizeof(type##_t)/sizeof(uint8_t))<<1) && s[i] != '\0'; i++) { \ 24 | if (s[i] >= '0' && s[i] <= '9') { \ 25 | t = (t << 4) + (s[i] - '0'); \ 26 | } \ 27 | if (s[i] >= 'a' && s[i] <= 'f') { \ 28 | t = (t << 4) + (s[i] - 'a' + 10); \ 29 | } \ 30 | if (s[i] >= 'A' && s[i] <= 'F') { \ 31 | t = (t << 4) + (s[i] - 'A' + 10); \ 32 | } \ 33 | } \ 34 | return t; \ 35 | } 36 | 37 | DEFINE_FROM_ASCII_HEX(uint8) 38 | DEFINE_FROM_ASCII_HEX(uint16) 39 | DEFINE_FROM_ASCII_HEX(uint32) 40 | 41 | #define DEFINE_TO_ASCII_HEX(type) \ 42 | int8_t* type##_to_ascii_hex(type##_t x, int8_t* buffer, uint32_t n) \ 43 | { \ 44 | uint32_t i = 0; \ 45 | uint32_t m = ((sizeof(type##_t) / sizeof(uint8_t)) << 1); \ 46 | for ( ; i < m && i + 1 < n; i++) { \ 47 | int8_t t = (x >> ((m - 1 - i) << 2)) & 0xf; \ 48 | if (t >= 0 && t <= 9) { \ 49 | buffer[i] = t + '0'; \ 50 | } \ 51 | if (t >= 0xa && t <= 0xf) { \ 52 | buffer[i] = (t - 0xa) + 'a'; \ 53 | } \ 54 | } \ 55 | buffer[i] = '\0'; \ 56 | return buffer; \ 57 | } 58 | 59 | DEFINE_TO_ASCII_HEX(uint8) 60 | DEFINE_TO_ASCII_HEX(uint16) 61 | DEFINE_TO_ASCII_HEX(uint32) 62 | -------------------------------------------------------------------------------- /software/151_library/ascii.h: -------------------------------------------------------------------------------- 1 | #ifndef ASCII_H_ 2 | #define ASCII_H_ 3 | 4 | #include "types.h" 5 | 6 | #define DECLARE_FROM_ASCII_HEX(type) \ 7 | type##_t ascii_hex_to_##type(const char* s); 8 | 9 | DECLARE_FROM_ASCII_HEX(uint8) 10 | DECLARE_FROM_ASCII_HEX(uint16) 11 | DECLARE_FROM_ASCII_HEX(uint32) 12 | 13 | #define DECLARE_FROM_ASCII_DEC(type) \ 14 | type##_t ascii_dec_to_##type(const char* s); 15 | 16 | DECLARE_FROM_ASCII_DEC(uint8) 17 | DECLARE_FROM_ASCII_DEC(uint16) 18 | DECLARE_FROM_ASCII_DEC(uint32) 19 | 20 | #define DECLARE_TO_ASCII_HEX(type) \ 21 | int8_t* type##_to_ascii_hex(type##_t x, int8_t* buffer, uint32_t n); 22 | 23 | DECLARE_TO_ASCII_HEX(uint8) 24 | DECLARE_TO_ASCII_HEX(uint16) 25 | DECLARE_TO_ASCII_HEX(uint32) 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /software/151_library/memory_map.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | #define csr_tohost(csr_val) { \ 4 | asm volatile ("csrw 0x51e,%[v]" :: [v]"r"(csr_val)); \ 5 | } 6 | 7 | #define COUNTER_RST (*((volatile uint32_t*) 0x80000018)) 8 | #define CYCLE_COUNTER (*((volatile uint32_t*)0x80000010)) 9 | #define INSTRUCTION_COUNTER (*((volatile uint32_t*)0x80000014)) 10 | #define BRANCH_INSTRUCTION_COUNTER (*((volatile uint32_t*)0x8000001c)) 11 | #define BRANCH_PREDICTION_CORRECT_COUNTER (*((volatile uint32_t*)0x80000020)) 12 | -------------------------------------------------------------------------------- /software/151_library/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | int32_t strcmp(const int8_t* s0, const int8_t* s1) { 4 | /* 5 | uwrite_int8s("\n\rComparing "); 6 | uwrite_int8s(s0); 7 | uwrite_int8s("|"); 8 | uwrite_int8s("with "); 9 | uwrite_int8s(s1); 10 | uwrite_int8s("|"); 11 | uwrite_int8s("\n\r"); 12 | */ 13 | for (uint32_t i = 0; ; i++) { 14 | if (s0[i] != s1[i]) { 15 | return 1; 16 | } 17 | if (s0[i] == '\0') { 18 | break; 19 | } 20 | } 21 | return 0; 22 | } 23 | 24 | uint32_t strlen(const int8_t* s) { 25 | uint32_t i = 0; 26 | for ( ; s[i] != '\0'; i++) ; 27 | return i; 28 | } 29 | -------------------------------------------------------------------------------- /software/151_library/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H_ 2 | #define STRING_H_ 3 | 4 | #include "types.h" 5 | 6 | int32_t strcmp(const int8_t* s0, const int8_t* s1); 7 | uint32_t strlen(const int8_t* s); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /software/151_library/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H_ 2 | #define TYPES_H_ 3 | 4 | typedef unsigned char uint8_t; 5 | typedef unsigned short uint16_t; 6 | typedef unsigned int uint32_t; 7 | 8 | typedef char int8_t; 9 | typedef short int16_t; 10 | typedef int int32_t; 11 | 12 | #define NULL 0 13 | 14 | #define TRUE 1 15 | #define FALSE 0 16 | 17 | #define HILO16(x, y) (((x & 0xFFFF) << 16) | (y & 0xFFFF)) 18 | 19 | #define HI16(x) ((x >> 16) & 0xFFFF) 20 | #define LO16(x) (x & 0xFFFF) 21 | 22 | #define HILO8(x, y) (((x & 0xFF) << 8) | (y & 0xFF)) 23 | 24 | #define HI8(x) ((x >> 8) & 0xFF) 25 | #define LO8(x) (x & 0xFF) 26 | 27 | #define HILO4(x, y) (((x & 0xF) << 4) | (y & 0xF)) 28 | 29 | #define HI4(x) ((x >> 4) & 0xF) 30 | #define LO4(x) (x & 0xF) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /software/151_library/uart.c: -------------------------------------------------------------------------------- 1 | #include "uart.h" 2 | 3 | void uwrite_int8(int8_t c) { 4 | while (!UTRAN_CTRL) ; 5 | UTRAN_DATA = c; 6 | } 7 | 8 | void uwrite_int8s(const int8_t* s) { 9 | for (int i = 0; s[i] != '\0'; i++) { 10 | uwrite_int8(s[i]); 11 | } 12 | } 13 | 14 | int8_t uread_int8(void) { 15 | while (!URECV_CTRL) ; 16 | int8_t ch = URECV_DATA; 17 | if (ch == '\x0d') { 18 | uwrite_int8s("\r\n"); 19 | } else { 20 | uwrite_int8(ch); 21 | } 22 | return ch; 23 | } 24 | 25 | int8_t uread_int8_noecho(void) { 26 | while (!URECV_CTRL) ; 27 | int8_t ch = URECV_DATA; 28 | return ch; 29 | } 30 | -------------------------------------------------------------------------------- /software/151_library/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef UART_H_ 2 | #define UART_H_ 3 | 4 | #include "types.h" 5 | 6 | #define URECV_CTRL (*((volatile uint32_t*)0x80000000) & 0x02) 7 | #define URECV_DATA (*((volatile uint32_t*)0x80000004) & 0xff) 8 | 9 | #define UTRAN_CTRL (*((volatile uint32_t*)0x80000000) & 0x01) 10 | #define UTRAN_DATA (*((volatile uint32_t*)0x80000008)) 11 | 12 | void uwrite_int8(int8_t c); 13 | 14 | void uwrite_int8s(const int8_t* s); 15 | 16 | int8_t uread_int8(void); 17 | 18 | int8_t uread_int8_noecho(void); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /software/Makefrag: -------------------------------------------------------------------------------- 1 | RISCV := riscv64-unknown-elf 2 | 3 | # get the absolute path of this Makefrag 4 | MAKEFRAG_PATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 5 | LIB_PATH := $(MAKEFRAG_PATH)151_library 6 | LIB_SOURCES := $(wildcard $(LIB_PATH)/*.c) 7 | CSRCS := $(wildcard *.c) 8 | SSRCS := $(wildcard *.s) 9 | LDSRC := $(TARGET).ld 10 | 11 | GCC_OPTS += -mabi=ilp32 -march=rv32i -static -mcmodel=medany -nostdlib -nostartfiles -T $(LDSRC) 12 | 13 | default: $(TARGET).elf 14 | 15 | SOURCES = $(CSRCS) $(SSRCS) 16 | ifeq ($(INCLUDE_LIB), true) 17 | SOURCES += $(LIB_SOURCES) 18 | endif 19 | 20 | # objdump is called before strip because it inlines functions and makes the assembly harder to read 21 | $(TARGET).elf: $(SOURCES) 22 | $(RISCV)-gcc $(GCC_OPTS) -I$(LIB_PATH) $^ -o $@ 23 | $(RISCV)-objdump -D -Mnumeric $@ > $(basename $@).dump 24 | $(RISCV)-strip -R .comment -R .note.gnu.build-id -R .riscv.attributes $@ 25 | $(RISCV)-objcopy $(basename $@).elf -O binary $(basename $@).bin 26 | $(RISCV)-bin2hex -w 32 $(basename $@).bin $(basename $@).hex 27 | 28 | clean: 29 | rm -f *.elf *.dump *.hex *.bin 30 | 31 | .PHONY: target 32 | -------------------------------------------------------------------------------- /software/asm/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := asm 3 | INCLUDE_LIB := false 4 | 5 | include ../Makefrag 6 | -------------------------------------------------------------------------------- /software/asm/asm.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH( "riscv" ) 2 | ENTRY( _start ) 3 | 4 | SECTIONS 5 | { 6 | . = 0x40000000; 7 | .text : { 8 | * (.start); 9 | * (.text); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /software/asm/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | 6 | # Follow a convention 7 | # x1 = result register 1 8 | # x2 = result register 2 9 | # x10 = argument 1 register 10 | # x11 = argument 2 register 11 | # x20 = flag register 12 | 13 | # Test ADD 14 | li x10, 100 # Load argument 1 (rs1) 15 | li x11, 200 # Load argument 2 (rs2) 16 | add x1, x10, x11 # Execute the instruction being tested 17 | li x20, 1 # Set the flag register to stop execution and inspect the result register 18 | # Now we check that x1 contains 300 19 | 20 | # Test BEQ 21 | li x2, 100 # Set an initial value of x2 22 | beq x0, x0, branch1 # This branch should succeed and jump to branch1 23 | li x2, 123 # This shouldn't execute, but if it does x2 becomes an undesirable value 24 | branch1: li x1, 500 # x1 now contains 500 25 | li x20, 2 # Set the flag register 26 | # Now we check that x1 contains 500 and x2 contains 100 27 | 28 | # TODO: add more tests here 29 | 30 | done: j done 31 | -------------------------------------------------------------------------------- /software/bios/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := bios 3 | INCLUDE_LIB := true 4 | 5 | include ../Makefrag 6 | -------------------------------------------------------------------------------- /software/bios/bios.c: -------------------------------------------------------------------------------- 1 | #include "ascii.h" 2 | #include "uart.h" 3 | #include "string.h" 4 | #include "memory_map.h" 5 | 6 | int8_t* read_n(int8_t*b, uint32_t n) { 7 | for (uint32_t i = 0; i < n; i++) { 8 | b[i] = uread_int8(); 9 | } 10 | b[n] = '\0'; 11 | return b; 12 | } 13 | 14 | int8_t* read_token(int8_t* b, uint32_t n, int8_t* ds) { 15 | uint32_t i = 0; 16 | while (i < n) { 17 | int8_t ch = uread_int8(); 18 | if (ch == '\x08') { // backspace character 19 | if (i == 0) 20 | uwrite_int8('\x20'); // space 21 | else { 22 | b[i] = '\0'; // null current idx in buffer 23 | i = i - 1; 24 | uwrite_int8s("\x20\x08"); // space + backspace 25 | } 26 | } else { 27 | for (uint32_t j = 0; ds[j] != '\0'; j++) { 28 | if (ch == ds[j]) { 29 | b[i] = '\0'; 30 | return b; 31 | } 32 | } 33 | b[i] = ch; 34 | i = i + 1; 35 | } 36 | } 37 | b[n - 1] = '\0'; 38 | return b; 39 | } 40 | 41 | void store(uint32_t address, uint32_t length) { 42 | for (uint32_t i = 0; i*4 < length; i++) { 43 | int8_t buffer[9]; 44 | int8_t* ascii_instruction = read_n(buffer,8); 45 | volatile uint32_t* p = (volatile uint32_t*)(address+i*4); 46 | *p = ascii_hex_to_uint32(ascii_instruction); 47 | } 48 | } 49 | 50 | 51 | #define BUFFER_LEN 128 52 | 53 | typedef void (*entry_t)(void); 54 | 55 | int main(void) { 56 | uwrite_int8s("\r\n"); 57 | 58 | for ( ; ; ) { 59 | uwrite_int8s("151> "); 60 | 61 | int8_t buffer[BUFFER_LEN]; 62 | int8_t* input = read_token(buffer, BUFFER_LEN, " \x0d"); 63 | 64 | if (strcmp(input, "file") == 0) { 65 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 66 | uint32_t file_length = ascii_dec_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 67 | store(address, file_length); 68 | } else if (strcmp(input, "jal") == 0) { 69 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 70 | 71 | entry_t start = (entry_t)(address); 72 | start(); 73 | } else if (strcmp(input, "lw") == 0) { 74 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 75 | volatile uint32_t* p = (volatile uint32_t*)(address); 76 | 77 | uwrite_int8s(uint32_to_ascii_hex(address, buffer, BUFFER_LEN)); 78 | uwrite_int8s(":"); 79 | uwrite_int8s(uint32_to_ascii_hex(*p, buffer, BUFFER_LEN)); 80 | uwrite_int8s("\r\n"); 81 | } else if (strcmp(input, "lhu") == 0) { 82 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 83 | volatile uint16_t* p = (volatile uint16_t*)(address); 84 | 85 | uwrite_int8s(uint32_to_ascii_hex(address, buffer, BUFFER_LEN)); 86 | uwrite_int8s(":"); 87 | uwrite_int8s(uint16_to_ascii_hex(*p, buffer, BUFFER_LEN)); 88 | uwrite_int8s("\r\n"); 89 | } else if (strcmp(input, "lbu") == 0) { 90 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 91 | volatile uint8_t* p = (volatile uint8_t*)(address); 92 | 93 | uwrite_int8s(uint32_to_ascii_hex(address, buffer, BUFFER_LEN)); 94 | uwrite_int8s(":"); 95 | uwrite_int8s(uint8_to_ascii_hex(*p, buffer, BUFFER_LEN)); 96 | uwrite_int8s("\r\n"); 97 | } else if (strcmp(input, "sw") == 0) { 98 | uint32_t word = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 99 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 100 | 101 | volatile uint32_t* p = (volatile uint32_t*)(address); 102 | *p = word; 103 | } else if (strcmp(input, "sh") == 0) { 104 | uint16_t half = ascii_hex_to_uint16(read_token(buffer, BUFFER_LEN, " \x0d")); 105 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 106 | 107 | volatile uint16_t* p = (volatile uint16_t*)(address); 108 | *p = half; 109 | } else if (strcmp(input, "sb") == 0) { 110 | uint8_t byte = ascii_hex_to_uint8(read_token(buffer, BUFFER_LEN, " \x0d")); 111 | uint32_t address = ascii_hex_to_uint32(read_token(buffer, BUFFER_LEN, " \x0d")); 112 | 113 | volatile uint8_t* p = (volatile uint8_t*)(address); 114 | *p = byte; 115 | } else { 116 | uwrite_int8s("\n\rUnrecognized token: "); 117 | uwrite_int8s(input); 118 | uwrite_int8s("\n\r"); 119 | } 120 | } 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /software/bios/bios.ld: -------------------------------------------------------------------------------- 1 | 2 | OUTPUT_ARCH( "riscv" ) 3 | ENTRY( _start ) 4 | 5 | SECTIONS 6 | { 7 | . = 0x40000000; 8 | .text : { 9 | * (.start); 10 | * (.text); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /software/bios/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/cachetest/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := cachetest 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../../Makefrag 7 | -------------------------------------------------------------------------------- /software/c_tests/cachetest/cachetest.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "memory_map.h" 3 | 4 | // Source: one of the bmark tests from ASIC lab 5 | // John C. Wright 6 | // johnwright@eecs.berkeley.edu 7 | // Do some random stuff to test EECS151/251A rv32ui processors 8 | 9 | #define PRBS 10 10 | #define CONST 1011556 11 | 12 | #define NUMELTS (1<> 1) & MASK) | (((x[i-1] & 1) ^ ((x[i-1] & 2) >> 1)) << (PRBS-1)); 24 | } 25 | 26 | int y = 0; 27 | for(i = 0; i < NUMELTS; i++) { 28 | y += x[i] + x[NUMELTS-1-i]; 29 | } 30 | 31 | if(assert_equals(y, CONST)) { 32 | csr_tohost(1); 33 | } else { 34 | csr_tohost(2); 35 | } 36 | 37 | // spin 38 | for( ; ; ) { 39 | asm volatile ("nop"); 40 | } 41 | } 42 | 43 | unsigned int assert_equals(unsigned int a, unsigned int b) { 44 | return (a == b); 45 | } 46 | -------------------------------------------------------------------------------- /software/c_tests/cachetest/cachetest.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/c_tests/cachetest/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/fib/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := fib 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../../Makefrag 7 | -------------------------------------------------------------------------------- /software/c_tests/fib/fib.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "memory_map.h" 3 | 4 | // Source: one of the bmark tests from ASIC lab 5 | // John C. Wright 6 | // johnwright@eecs.berkeley.edu 7 | // Do some random stuff to test EECS151/251A rv32ui processors 8 | 9 | #define NUMELTS 150 10 | 11 | uint32_t assert_equals(uint32_t a, uint32_t b); 12 | int x[NUMELTS]; 13 | 14 | void main() { 15 | csr_tohost(0); 16 | x[0] = 0; 17 | x[1] = 1; 18 | int i; 19 | for(i = 2; i < NUMELTS; i++) { 20 | x[i] = x[i-1] + x[i-2]; 21 | } 22 | 23 | if (assert_equals(x[35], 9227465)) { 24 | csr_tohost(1); 25 | } else { 26 | csr_tohost(2); 27 | } 28 | 29 | // spin 30 | for( ; ; ) { 31 | asm volatile ("nop"); 32 | } 33 | } 34 | 35 | uint32_t assert_equals(uint32_t a, uint32_t b) { 36 | return (a == b); 37 | } 38 | -------------------------------------------------------------------------------- /software/c_tests/fib/fib.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/c_tests/fib/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/replace/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := replace 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../../Makefrag 7 | -------------------------------------------------------------------------------- /software/c_tests/replace/replace.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "memory_map.h" 3 | 4 | // Source: one of the bmark tests from ASIC lab 5 | // John C. Wright 6 | // johnwright@eecs.berkeley.edu 7 | // Do some random stuff to test EECS151/251A rv32ui processors 8 | 9 | #define NUMELTS 64 10 | #define CONST 2080 11 | 12 | #define MASK (1<<31)-1 13 | 14 | unsigned int assert_equals(unsigned int a, unsigned int b); 15 | int x[NUMELTS]; 16 | int y[NUMELTS]; 17 | 18 | void main() { 19 | csr_tohost(0); 20 | int i; 21 | int j; 22 | for(i = 0; i < NUMELTS; i++) { 23 | x[i] = i + 1; 24 | } 25 | 26 | for(i = 0; i < NUMELTS; i+=4) { 27 | y[i] = 0; 28 | for(j=0; j < i+1; j++) { 29 | y[i] = y[i] + x[j]; 30 | } 31 | } 32 | 33 | for(i = 1; i < NUMELTS; i+=4) { 34 | y[i] = 0; 35 | for(j=0; j < i+1; j++) { 36 | y[i] = y[i] + x[j]; 37 | } 38 | } 39 | 40 | for(i = 2; i < NUMELTS; i+=4) { 41 | y[i] = 0; 42 | for(j=0; j < i+1; j++) { 43 | y[i] = y[i] + x[j]; 44 | } 45 | } 46 | 47 | for(i = 3; i < NUMELTS; i+=4) { 48 | y[i] = 0; 49 | for(j=0; j < i+1; j++) { 50 | y[i] = y[i] + x[j]; 51 | } 52 | } 53 | 54 | if(assert_equals(y[NUMELTS-1], CONST)) { 55 | csr_tohost(1); 56 | } else { 57 | csr_tohost(2); 58 | } 59 | 60 | // spin 61 | for( ; ; ) { 62 | asm volatile ("nop"); 63 | } 64 | 65 | } 66 | 67 | unsigned int assert_equals(unsigned int a, unsigned int b) { 68 | return (a == b); 69 | } 70 | -------------------------------------------------------------------------------- /software/c_tests/replace/replace.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/c_tests/replace/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/strcmp/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := strcmp 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../../Makefrag 7 | -------------------------------------------------------------------------------- /software/c_tests/strcmp/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/strcmp/strcmp.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "memory_map.h" 3 | 4 | 5 | int main(void) { 6 | csr_tohost(0); 7 | char str[10] = "EECS151"; 8 | 9 | if (strcmp(str ,"EECS151") == 0) { 10 | // pass 11 | csr_tohost(1); 12 | } else { 13 | // fail code 2 14 | csr_tohost(2); 15 | } 16 | 17 | // spin 18 | for( ; ; ) { 19 | asm volatile ("nop"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /software/c_tests/strcmp/strcmp.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/c_tests/sum/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := sum 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../../Makefrag 7 | -------------------------------------------------------------------------------- /software/c_tests/sum/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/sum/sum.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "memory_map.h" 3 | 4 | // Source: one of the bmark tests from ASIC lab 5 | // John C. Wright 6 | // johnwright@eecs.berkeley.edu 7 | // Do some random stuff to test EECS151/251A rv32ui processors 8 | 9 | #define NUMELTS 64 10 | #define CONST 2080 11 | 12 | unsigned int assert_equals(unsigned int a, unsigned int b); 13 | int x[NUMELTS]; 14 | int y[NUMELTS]; 15 | 16 | void main() { 17 | csr_tohost(0); 18 | int i; 19 | int j; 20 | for(i = 0; i < NUMELTS; i++) { 21 | x[i] = i + 1; 22 | } 23 | 24 | for(i = 0; i < NUMELTS; i++) { 25 | y[i] = 0; 26 | for(j=0; j < i+1; j++) { 27 | y[i] = y[i] + x[j]; 28 | } 29 | } 30 | 31 | if (assert_equals(y[NUMELTS-1], CONST)) { 32 | csr_tohost(1); 33 | } else { 34 | csr_tohost(2); 35 | } 36 | 37 | // spin 38 | for( ; ; ) { 39 | asm volatile ("nop"); 40 | } 41 | } 42 | 43 | unsigned int assert_equals(unsigned int a, unsigned int b) { 44 | return (a == b); 45 | } 46 | -------------------------------------------------------------------------------- /software/c_tests/sum/sum.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/c_tests/vecadd/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := vecadd 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../../Makefrag 7 | -------------------------------------------------------------------------------- /software/c_tests/vecadd/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/c_tests/vecadd/vecadd.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "ascii.h" 3 | #include "uart.h" 4 | #include "memory_map.h" 5 | 6 | #define BUF_LEN 128 7 | 8 | #define DIM 64 9 | #define SIZE 1024 10 | static int32_t A[SIZE] = {0}; // 3x1024x32b 16384x32b 11 | static int32_t B[SIZE] = {0}; 12 | static int32_t C[SIZE] = {0}; 13 | 14 | typedef void (*entry_t)(void); 15 | 16 | int main(int argc, char**argv) { 17 | csr_tohost(0); 18 | int8_t buffer[BUF_LEN]; 19 | 20 | int i, j; 21 | int chksum = 0; 22 | 23 | for (i = 0; i < SIZE; i++) { 24 | A[i] = 1; 25 | B[i] = i; 26 | } 27 | 28 | for (i = 0; i < SIZE; i++) { 29 | C[i] = A[i] + B[i]; 30 | } 31 | 32 | for (i = 0; i < SIZE; i++) { 33 | chksum += C[i]; 34 | } 35 | 36 | csr_tohost(0); 37 | 38 | if (chksum == 0x80200) { 39 | // pass 40 | csr_tohost(1); 41 | } else { 42 | // fail code 2 43 | csr_tohost(2); 44 | } 45 | 46 | // spin 47 | for( ; ; ) { 48 | asm volatile ("nop"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /software/c_tests/vecadd/vecadd.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/echo/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := echo 3 | INCLUDE_LIB := false 4 | 5 | include ../Makefrag 6 | -------------------------------------------------------------------------------- /software/echo/echo.c: -------------------------------------------------------------------------------- 1 | #define RECV_CTRL (*((volatile unsigned int*)0x80000000) & 0x02) 2 | #define RECV_DATA (*((volatile unsigned int*)0x80000004) & 0xFF) 3 | 4 | #define TRAN_CTRL (*((volatile unsigned int*)0x80000000) & 0x01) 5 | #define TRAN_DATA (*((volatile unsigned int*)0x80000008)) 6 | 7 | int main(void) 8 | { 9 | for ( ; ; ) 10 | { 11 | while (!RECV_CTRL) ; 12 | char byte = RECV_DATA; 13 | while (!TRAN_CTRL) ; 14 | TRAN_DATA = byte; 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /software/echo/echo.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/echo/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x10001000 6 | jal main 7 | -------------------------------------------------------------------------------- /software/mmult/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := mmult 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 5 | 6 | include ../Makefrag 7 | -------------------------------------------------------------------------------- /software/mmult/benchmark.c: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" 2 | #include "ascii.h" 3 | #include "uart.h" 4 | #include "memory_map.h" 5 | 6 | #define BUF_LEN 128 7 | 8 | void run_and_time(uint32_t (*f)()) { 9 | uint32_t result, time, instructions, br_insts, bp_correct; 10 | int8_t buffer[BUF_LEN]; 11 | COUNTER_RST = 0; 12 | result = (*f)(); 13 | time = CYCLE_COUNTER; 14 | instructions = INSTRUCTION_COUNTER; 15 | br_insts = BRANCH_INSTRUCTION_COUNTER; 16 | bp_correct = BRANCH_PREDICTION_CORRECT_COUNTER; 17 | uwrite_int8s("Result: "); 18 | uwrite_int8s(uint32_to_ascii_hex(result, buffer, BUF_LEN)); 19 | uwrite_int8s("\r\nCycle Count: "); 20 | uwrite_int8s(uint32_to_ascii_hex(time, buffer, BUF_LEN)); 21 | uwrite_int8s("\r\nInstruction Count: "); 22 | uwrite_int8s(uint32_to_ascii_hex(instructions, buffer, BUF_LEN)); 23 | uwrite_int8s("\r\nBranch Instruction Count: "); 24 | uwrite_int8s(uint32_to_ascii_hex(br_insts, buffer, BUF_LEN)); 25 | uwrite_int8s("\r\nCorrect Branch Prediction Count: "); 26 | uwrite_int8s(uint32_to_ascii_hex(bp_correct, buffer, BUF_LEN)); 27 | uwrite_int8s("\r\n"); 28 | } 29 | -------------------------------------------------------------------------------- /software/mmult/benchmark.h: -------------------------------------------------------------------------------- 1 | #ifndef BENCHMARK_H_ 2 | #define BENCHMARK_H_ 3 | 4 | #include "types.h" 5 | 6 | void run_and_time(uint32_t (*f)()); 7 | #endif 8 | -------------------------------------------------------------------------------- /software/mmult/mmult.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "benchmark.h" 3 | #include "ascii.h" 4 | #include "uart.h" 5 | 6 | #define N 6 7 | #define MAT_SIZE (1 << (N << 1)) 8 | #define DIM_SIZE (1 << N) 9 | static int32_t A[MAT_SIZE] = {0}; 10 | static int32_t B[MAT_SIZE] = {0}; 11 | static int32_t S[MAT_SIZE] = {0}; 12 | 13 | /* Computes S = AB where A, B, and S are all of 2^N x 2^N matrices. A, B, and S 14 | * are stored sequentially in row-major order beginning at DATA. Prints the sum 15 | * of the entries of S to the UART. */ 16 | 17 | int32_t times(int32_t a, int32_t b) { 18 | int32_t a_neg = a < 0; 19 | int32_t b_neg = b < 0; 20 | int32_t result = 0; 21 | if (a_neg) a = -a; 22 | if (b_neg) b = -b; 23 | while (b) { 24 | if (b & 1) { 25 | result += a; 26 | } 27 | a <<= 1; 28 | b >>= 1; 29 | } 30 | if ((a_neg && !b_neg) || (!a_neg && b_neg)) { 31 | result = -result; 32 | } 33 | return result; 34 | } 35 | 36 | uint32_t mmult() { 37 | int32_t sum = 0; 38 | int32_t i, j, k; 39 | for (i = 0; i < DIM_SIZE; i++) { 40 | for (j = 0; j < DIM_SIZE; j++) { 41 | int32_t* s = S + (i << N) + j; 42 | *s = 0; 43 | for (k = 0; k < DIM_SIZE; k++) { 44 | int32_t a = *(A + (i << N) + k); 45 | int32_t b = *(B + (k << N) + j); 46 | int32_t prod = times(a, b); 47 | *s = *s + prod; 48 | } 49 | sum += *s; 50 | } 51 | } 52 | return (uint32_t) sum; 53 | } 54 | 55 | void generate_matrices() { 56 | int32_t i, j; 57 | for (i = 0; i < DIM_SIZE; i++) { 58 | for (j = 0; j < DIM_SIZE; j++) { 59 | *(A + (i << N) + j) = (i == j) ? 1 : 0; 60 | } 61 | } 62 | for (i = 0; i < DIM_SIZE; i++) { 63 | for (j = 0; j < DIM_SIZE; j++) { 64 | *(B + (i << N) + j) = j; 65 | } 66 | } 67 | } 68 | 69 | 70 | typedef void (*entry_t)(void); 71 | 72 | int main(int argc, char**argv) { 73 | generate_matrices(); 74 | run_and_time(&mmult); 75 | // go back to the bios - using this function causes a jr to the addr, 76 | // the compiler "jals" otherwise and then cannot set PC[31:28] 77 | uint32_t bios = ascii_hex_to_uint32("40000000"); 78 | entry_t start = (entry_t) (bios); 79 | start(); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /software/mmult/mmult.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /software/mmult/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/riscv-isa-tests/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) -o pipefail 2 | TESTS := $(notdir $(shell find riscv-tests/isa/rv32ui -type f -name "*.S")) 3 | TESTS_HEX := $(subst .S,.hex,$(TESTS)) 4 | GCC_OPTS := -march=rv32i -mabi=ilp32 -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -T env_151/link.ld -Wl,--build-id=none 5 | 6 | RISCV := riscv64-unknown-elf 7 | 8 | all: $(TESTS_HEX) 9 | 10 | %.hex: riscv-tests/isa/rv32ui/%.S 11 | $(RISCV)-gcc $(GCC_OPTS) -Ienv_151 -Iriscv-tests/env -Iriscv-tests/isa/macros/scalar $^ -o $(basename $(notdir $^)).elf 12 | $(RISCV)-objdump -D -Mnumeric $(basename $(notdir $^)).elf > $(basename $@).dump 13 | $(RISCV)-objcopy $(basename $@).elf -O binary $(basename $@).bin 14 | $(RISCV)-bin2hex -w 32 $(basename $@).bin $(basename $@).hex 15 | 16 | clean: 17 | rm -f *.elf *.bin *.hex *.dump 18 | -------------------------------------------------------------------------------- /software/riscv-isa-tests/env_151/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH( "riscv" ) 2 | ENTRY(_start) 3 | 4 | SECTIONS 5 | { 6 | . = 0x10000000; 7 | .text.init : { *(.text.init) } 8 | . = ALIGN(0x1000); 9 | .text : { *(.text) } 10 | . = ALIGN(0x1000); 11 | .data : { *(.data) } 12 | .bss : { *(.bss) } 13 | _end = .; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /software/riscv-isa-tests/env_151/riscv_test.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef _ENV_PHYSICAL_SINGLE_CORE_H 4 | #define _ENV_PHYSICAL_SINGLE_CORE_H 5 | 6 | #include "encoding.h" 7 | 8 | //----------------------------------------------------------------------- 9 | // Begin Macro 10 | //----------------------------------------------------------------------- 11 | 12 | #define RVTEST_RV64U \ 13 | .macro init; \ 14 | .endm 15 | 16 | #define RVTEST_RV64UF \ 17 | .macro init; \ 18 | .endm 19 | 20 | #define RVTEST_RV32U \ 21 | .macro init; \ 22 | .endm 23 | 24 | #define RVTEST_RV32UF \ 25 | .macro init; \ 26 | .endm 27 | 28 | #define RVTEST_RV64M \ 29 | .macro init; \ 30 | .endm 31 | 32 | #define RVTEST_RV64S \ 33 | .macro init; \ 34 | .endm 35 | 36 | #define RVTEST_RV32M \ 37 | .macro init; \ 38 | .endm 39 | 40 | #define RVTEST_RV32S \ 41 | .macro init; \ 42 | .endm 43 | 44 | #define RVTEST_CODE_BEGIN \ 45 | .section .text.init; \ 46 | .align 6; \ 47 | .globl _start; \ 48 | _start: \ 49 | /* reset vector */ \ 50 | j reset_vector; \ 51 | .align 2; \ 52 | reset_vector: \ 53 | csrwi 0x51e, 0; \ 54 | li TESTNUM, 0; \ 55 | init \ 56 | 57 | //----------------------------------------------------------------------- 58 | // End Macro 59 | //----------------------------------------------------------------------- 60 | 61 | #define RVTEST_CODE_END \ 62 | unimp 63 | 64 | //----------------------------------------------------------------------- 65 | // Pass/Fail Macro 66 | //----------------------------------------------------------------------- 67 | 68 | #define RVTEST_PASS \ 69 | li TESTNUM, 1; \ 70 | csrw 0x51e, TESTNUM; \ 71 | p: j p 72 | 73 | #define TESTNUM gp 74 | #define RVTEST_FAIL \ 75 | sll TESTNUM, TESTNUM, 1; \ 76 | or TESTNUM, TESTNUM, 1; \ 77 | csrw 0x51e, TESTNUM; \ 78 | f: j f 79 | 80 | //----------------------------------------------------------------------- 81 | // Data Section Macro 82 | //----------------------------------------------------------------------- 83 | 84 | #define EXTRA_DATA 85 | 86 | #define RVTEST_DATA_BEGIN \ 87 | EXTRA_DATA \ 88 | .align 4; .global begin_signature; begin_signature: 89 | 90 | #define RVTEST_DATA_END .align 4; .global end_signature; end_signature: 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /software/uart_parse/Makefile: -------------------------------------------------------------------------------- 1 | # Master Makefile dependencies 2 | TARGET := uart_parse 3 | INCLUDE_LIB := true 4 | GCC_OPTS += -O2 -flto 5 | 6 | include ../Makefrag 7 | -------------------------------------------------------------------------------- /software/uart_parse/start.s: -------------------------------------------------------------------------------- 1 | .section .start 2 | .global _start 3 | 4 | _start: 5 | li sp, 0x1000fff0 6 | jal main 7 | -------------------------------------------------------------------------------- /software/uart_parse/uart_parse.c: -------------------------------------------------------------------------------- 1 | #include "memory_map.h" 2 | #include "uart.h" 3 | #include "string.h" 4 | 5 | int8_t* read_n(int8_t*b, uint32_t n) { 6 | for (uint32_t i = 0; i < n; i++) { 7 | b[i] = uread_int8(); 8 | } 9 | b[n] = '\0'; 10 | return b; 11 | } 12 | 13 | int8_t* read_token(int8_t* b, uint32_t n, int8_t* ds) { 14 | for (uint32_t i = 0; i < n; i++) { 15 | int8_t ch = uread_int8(); 16 | for (uint32_t j = 0; ds[j] != '\0'; j++) { 17 | if (ch == ds[j]) { 18 | b[i] = '\0'; 19 | return b; 20 | } 21 | } 22 | b[i] = ch; 23 | } 24 | b[n - 1] = '\0'; 25 | return b; 26 | } 27 | 28 | #define BUFFER_LEN 16 29 | int main(void) { 30 | csr_tohost(0); 31 | uwrite_int8s("\r\n151> "); 32 | int8_t buffer[BUFFER_LEN]; 33 | int8_t* input = read_token(buffer, BUFFER_LEN, " \x0d"); 34 | if (strcmp(input, "xyz") == 0) { 35 | csr_tohost(1); 36 | } else { 37 | csr_tohost(2); 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /software/uart_parse/uart_parse.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0x10000000; 4 | .text : { 5 | * (.start); 6 | * (.text); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /spec/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/.DS_Store -------------------------------------------------------------------------------- /spec/EECS151_FPGA_Project_Fa22.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/EECS151_FPGA_Project_Fa22.pdf -------------------------------------------------------------------------------- /spec/Makefile: -------------------------------------------------------------------------------- 1 | #======================================================================= 2 | # Makefile for generating latex documents 3 | #----------------------------------------------------------------------- 4 | # 5 | # This is a simple makefile for generating latex documents. It will 6 | # run bibtex, generate eps from xfig figures, and make pdfs. The 7 | # makefile supports builds in non-source directories: just make a 8 | # build directory, copy the makefile there, and change the srcdir 9 | # variable accordingly. 10 | # 11 | # Note that the makefile assumes that the default dvips/ps2pdfwr 12 | # commands "do the right thing" for fonts in pdfs. This is true on 13 | # Athena/Linux and Fedora Core but is not true for older redhat installs ... 14 | # 15 | # At a minimum you should just change the main variable to be 16 | # the basename of your toplevel tex file. If you use a bibliography 17 | # then you should set the bibfile variable to be the name of your 18 | # .bib file (assumed to be in the source directory). 19 | # 20 | 21 | srcdir = . 22 | 23 | main = fpga_project 24 | srcs = $(wildcard *.tex) 25 | figs = $(wildcard figs/*) 26 | bibs = 27 | 28 | #======================================================================= 29 | # You shouldn't need to change anything below this 30 | #======================================================================= 31 | 32 | default : pdf 33 | 34 | #------------------------------------------------------------ 35 | # PDF 36 | 37 | output_pdf = $(main).pdf 38 | pdf : $(output_pdf) 39 | .PHONY: pdf 40 | 41 | $(output_pdf) : $(srcs) $(figs) $(bibs) 42 | texfot pdflatex -shell-escape $(main) 43 | ifneq ($(strip $(bibs)),) 44 | texfot bibtex $(main) 45 | texfot pdflatex -shell-escape $(main) 46 | endif 47 | texfot pdflatex -shell-escape $(main) 48 | 49 | junk += $(output_pdf) *.aux *.log *.toc *.out _minted-fpga_project 50 | 51 | #------------------------------------------------------------ 52 | # Other Targets 53 | 54 | clean : 55 | rm -rf $(junk) *~ \#* 56 | -------------------------------------------------------------------------------- /spec/defines.tex: -------------------------------------------------------------------------------- 1 | \newcommand{\currentSemester}{Fall 2022} 2 | \newcommand{\projectSpecVersion}{1.22} 3 | 4 | %\newcommand{\dueDateTime}{end of week} 5 | 6 | \newcommand{\blockDiagramTaskName}{Checkpoint 1} 7 | \newcommand{\blockDiagramDueDate}{Nov 4, 2022} 8 | \newcommand{\blockDiagramTimeAlloted}{2 weeks} 9 | 10 | \newcommand{\baseCPUTaskName}{Checkpoint 2} 11 | \newcommand{\baseCPUDueDate}{Nov 18, 2022} 12 | \newcommand{\baseCPUTimeAlloted}{2 weeks} 13 | 14 | \newcommand{\branchPredictorTaskName}{Checkpoint 3} 15 | \newcommand{\branchPredictorDueDate}{Dec 02, 2021} 16 | \newcommand{\branchPredictorTimeAlloted}{2 weeks} 17 | 18 | 19 | % \newcommand{\cacheTaskName}{Checkpoint 3} 20 | % \newcommand{\cacheDueDate}{Dec 02, 2021} 21 | % \newcommand{\cacheTimeAlloted}{2 weeks} 22 | 23 | %\newcommand{\imageTaskName}{Checkpoint 3} 24 | %\newcommand{\imageDueDate}{May 05, 2021} 25 | %\newcommand{\imageTimeAlloted}{3 weeks} 26 | 27 | %\newcommand{\optTaskName}{Checkpoint 3} 28 | %\newcommand{\optDueDate}{Nov 25, 2022} 29 | %\newcommand{\optTimeAlloted}{3 week} 30 | 31 | \newcommand{\finalCheckoffDueDate}{Dec 09, 2022} 32 | 33 | \newcommand{\finalReportDueDate}{Dec 12, 2022} 34 | 35 | \newcommand{\skeletonRepoName}{fpga\_project\_skeleton\_fa22} 36 | \newcommand{\semesterName}{fa22} 37 | 38 | %Also, change the info in minted blocks. This includes the "Setting up your Code Repository" section and the "Setting up the Vivado Project" section 39 | -------------------------------------------------------------------------------- /spec/images/Seal_of_University_of_California_Berkeley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/Seal_of_University_of_California_Berkeley.png -------------------------------------------------------------------------------- /spec/images/axi_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/axi_read.png -------------------------------------------------------------------------------- /spec/images/axi_read_burst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/axi_read_burst.png -------------------------------------------------------------------------------- /spec/images/axi_write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/axi_write.png -------------------------------------------------------------------------------- /spec/images/axi_write_burst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/axi_write_burst.png -------------------------------------------------------------------------------- /spec/images/bios_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/bios_flow.png -------------------------------------------------------------------------------- /spec/images/branch_predictor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/branch_predictor.png -------------------------------------------------------------------------------- /spec/images/compute_memif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/compute_memif.png -------------------------------------------------------------------------------- /spec/images/conv2D_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/conv2D_engine.png -------------------------------------------------------------------------------- /spec/images/conv3D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/conv3D.png -------------------------------------------------------------------------------- /spec/images/ddr_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/ddr_layout.png -------------------------------------------------------------------------------- /spec/images/endianness_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/endianness_img.jpg -------------------------------------------------------------------------------- /spec/images/full_system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/full_system.png -------------------------------------------------------------------------------- /spec/images/lenet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/lenet.png -------------------------------------------------------------------------------- /spec/images/lenet_hybrid_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/lenet_hybrid_flow.png -------------------------------------------------------------------------------- /spec/images/memory_arch.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/memory_arch.pdf -------------------------------------------------------------------------------- /spec/images/saturating_counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/saturating_counter.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-2.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-3.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-4.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-5.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-6.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-7.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-8.png -------------------------------------------------------------------------------- /spec/images/vivado-ila-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado-ila-9.png -------------------------------------------------------------------------------- /spec/images/vivado_bd_z1top_axi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_bd_z1top_axi.png -------------------------------------------------------------------------------- /spec/images/vivado_ila1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila1.png -------------------------------------------------------------------------------- /spec/images/vivado_ila10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila10.png -------------------------------------------------------------------------------- /spec/images/vivado_ila11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila11.png -------------------------------------------------------------------------------- /spec/images/vivado_ila2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila2.png -------------------------------------------------------------------------------- /spec/images/vivado_ila3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila3.png -------------------------------------------------------------------------------- /spec/images/vivado_ila4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila4.png -------------------------------------------------------------------------------- /spec/images/vivado_ila5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila5.png -------------------------------------------------------------------------------- /spec/images/vivado_ila6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila6.png -------------------------------------------------------------------------------- /spec/images/vivado_ila7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila7.png -------------------------------------------------------------------------------- /spec/images/vivado_ila8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila8.png -------------------------------------------------------------------------------- /spec/images/vivado_ila9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ila9.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi0.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi1.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi10.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi11.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi12.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi13.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi14.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi15.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi16.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi17.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi18.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi19.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi2.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi3.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi4.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi5.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi6.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi7.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi8.png -------------------------------------------------------------------------------- /spec/images/vivado_ipi9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EECS150/fpga_project_skeleton_fa22/8811dbcd32483b4203b0aa15698edf27e975af1f/spec/images/vivado_ipi9.png -------------------------------------------------------------------------------- /spec/isa.tex: -------------------------------------------------------------------------------- 1 | \begin{table}[p] 2 | \caption{RISC-V ISA} 3 | \label{tab:ISA} 4 | \begin{small} 5 | \begin{center} 6 | \begin{tabular}{p{0in}p{0.4in}p{0.05in}p{0.05in}p{0.05in}p{0.05in}p{0.4in}p{0.6in}p{0.4in}p{0.6in}p{0.7in}l} 7 | & & & & & & & & & & \\ 8 | & 9 | \multicolumn{1}{l}{\instbit{31}} & 10 | \multicolumn{1}{r}{\instbit{27}} & 11 | \instbit{26} & 12 | \instbit{25} & 13 | \multicolumn{1}{l}{\instbit{24}} & 14 | \multicolumn{1}{r}{\instbit{20}} & 15 | \instbitrange{19}{15} & 16 | \instbitrange{14}{12} & 17 | \instbitrange{11}{7} & 18 | \instbitrange{6}{0} \\ 19 | \cline{2-11} 20 | 21 | 22 | & 23 | \multicolumn{4}{|c|}{funct7} & 24 | \multicolumn{2}{c|}{rs2} & 25 | \multicolumn{1}{c|}{rs1} & 26 | \multicolumn{1}{c|}{funct3} & 27 | \multicolumn{1}{c|}{rd} & 28 | \multicolumn{1}{c|}{opcode} & R-type \\ 29 | \cline{2-11} 30 | 31 | 32 | & 33 | \multicolumn{6}{|c|}{imm[11:0]} & 34 | \multicolumn{1}{c|}{rs1} & 35 | \multicolumn{1}{c|}{funct3} & 36 | \multicolumn{1}{c|}{rd} & 37 | \multicolumn{1}{c|}{opcode} & I-type \\ 38 | \cline{2-11} 39 | 40 | 41 | & 42 | \multicolumn{4}{|c|}{imm[11:5]} & 43 | \multicolumn{2}{c|}{rs2} & 44 | \multicolumn{1}{c|}{rs1} & 45 | \multicolumn{1}{c|}{funct3} & 46 | \multicolumn{1}{c|}{imm[4:0]} & 47 | \multicolumn{1}{c|}{opcode} & S-type \\ 48 | \cline{2-11} 49 | 50 | 51 | & 52 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 53 | \multicolumn{2}{c|}{rs2} & 54 | \multicolumn{1}{c|}{rs1} & 55 | \multicolumn{1}{c|}{funct3} & 56 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 57 | \multicolumn{1}{c|}{opcode} & B-type \\ 58 | \cline{2-11} 59 | 60 | 61 | & 62 | \multicolumn{8}{|c|}{imm[31:12]} & 63 | \multicolumn{1}{c|}{rd} & 64 | \multicolumn{1}{c|}{opcode} & U-type \\ 65 | \cline{2-11} 66 | 67 | 68 | & 69 | \multicolumn{8}{|c|}{imm[20$\vert$10:1$\vert$11$\vert$19:12]} & 70 | \multicolumn{1}{c|}{rd} & 71 | \multicolumn{1}{c|}{opcode} & J-type \\ 72 | \cline{2-11} 73 | 74 | 75 | & 76 | \multicolumn{10}{c}{} & \\ 77 | & 78 | \multicolumn{10}{c}{\bf RV32I Base Instruction Set} & \\ 79 | \cline{2-11} 80 | 81 | 82 | & 83 | \multicolumn{8}{|c|}{imm[31:12]} & 84 | \multicolumn{1}{c|}{rd} & 85 | \multicolumn{1}{c|}{0110111} & LUI \\ 86 | \cline{2-11} 87 | 88 | 89 | & 90 | \multicolumn{8}{|c|}{imm[31:12]} & 91 | \multicolumn{1}{c|}{rd} & 92 | \multicolumn{1}{c|}{0010111} & AUIPC \\ 93 | \cline{2-11} 94 | 95 | 96 | & 97 | \multicolumn{8}{|c|}{imm[20$\vert$10:1$\vert$11$\vert$19:12]} & 98 | \multicolumn{1}{c|}{rd} & 99 | \multicolumn{1}{c|}{1101111} & JAL \\ 100 | \cline{2-11} 101 | 102 | 103 | & 104 | \multicolumn{6}{|c|}{imm[11:0]} & 105 | \multicolumn{1}{c|}{rs1} & 106 | \multicolumn{1}{c|}{000} & 107 | \multicolumn{1}{c|}{rd} & 108 | \multicolumn{1}{c|}{1100111} & JALR \\ 109 | \cline{2-11} 110 | 111 | 112 | & 113 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 114 | \multicolumn{2}{c|}{rs2} & 115 | \multicolumn{1}{c|}{rs1} & 116 | \multicolumn{1}{c|}{000} & 117 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 118 | \multicolumn{1}{c|}{1100011} & BEQ \\ 119 | \cline{2-11} 120 | 121 | 122 | & 123 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 124 | \multicolumn{2}{c|}{rs2} & 125 | \multicolumn{1}{c|}{rs1} & 126 | \multicolumn{1}{c|}{001} & 127 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 128 | \multicolumn{1}{c|}{1100011} & BNE \\ 129 | \cline{2-11} 130 | 131 | 132 | & 133 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 134 | \multicolumn{2}{c|}{rs2} & 135 | \multicolumn{1}{c|}{rs1} & 136 | \multicolumn{1}{c|}{100} & 137 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 138 | \multicolumn{1}{c|}{1100011} & BLT \\ 139 | \cline{2-11} 140 | 141 | 142 | & 143 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 144 | \multicolumn{2}{c|}{rs2} & 145 | \multicolumn{1}{c|}{rs1} & 146 | \multicolumn{1}{c|}{101} & 147 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 148 | \multicolumn{1}{c|}{1100011} & BGE \\ 149 | \cline{2-11} 150 | 151 | 152 | & 153 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 154 | \multicolumn{2}{c|}{rs2} & 155 | \multicolumn{1}{c|}{rs1} & 156 | \multicolumn{1}{c|}{110} & 157 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 158 | \multicolumn{1}{c|}{1100011} & BLTU \\ 159 | \cline{2-11} 160 | 161 | 162 | & 163 | \multicolumn{4}{|c|}{imm[12$\vert$10:5]} & 164 | \multicolumn{2}{c|}{rs2} & 165 | \multicolumn{1}{c|}{rs1} & 166 | \multicolumn{1}{c|}{111} & 167 | \multicolumn{1}{c|}{imm[4:1$\vert$11]} & 168 | \multicolumn{1}{c|}{1100011} & BGEU \\ 169 | \cline{2-11} 170 | 171 | 172 | & 173 | \multicolumn{6}{|c|}{imm[11:0]} & 174 | \multicolumn{1}{c|}{rs1} & 175 | \multicolumn{1}{c|}{000} & 176 | \multicolumn{1}{c|}{rd} & 177 | \multicolumn{1}{c|}{0000011} & LB \\ 178 | \cline{2-11} 179 | 180 | 181 | & 182 | \multicolumn{6}{|c|}{imm[11:0]} & 183 | \multicolumn{1}{c|}{rs1} & 184 | \multicolumn{1}{c|}{001} & 185 | \multicolumn{1}{c|}{rd} & 186 | \multicolumn{1}{c|}{0000011} & LH \\ 187 | \cline{2-11} 188 | 189 | 190 | & 191 | \multicolumn{6}{|c|}{imm[11:0]} & 192 | \multicolumn{1}{c|}{rs1} & 193 | \multicolumn{1}{c|}{010} & 194 | \multicolumn{1}{c|}{rd} & 195 | \multicolumn{1}{c|}{0000011} & LW \\ 196 | \cline{2-11} 197 | 198 | 199 | & 200 | \multicolumn{6}{|c|}{imm[11:0]} & 201 | \multicolumn{1}{c|}{rs1} & 202 | \multicolumn{1}{c|}{100} & 203 | \multicolumn{1}{c|}{rd} & 204 | \multicolumn{1}{c|}{0000011} & LBU \\ 205 | \cline{2-11} 206 | 207 | 208 | & 209 | \multicolumn{6}{|c|}{imm[11:0]} & 210 | \multicolumn{1}{c|}{rs1} & 211 | \multicolumn{1}{c|}{101} & 212 | \multicolumn{1}{c|}{rd} & 213 | \multicolumn{1}{c|}{0000011} & LHU \\ 214 | \cline{2-11} 215 | 216 | 217 | & 218 | \multicolumn{4}{|c|}{imm[11:5]} & 219 | \multicolumn{2}{c|}{rs2} & 220 | \multicolumn{1}{c|}{rs1} & 221 | \multicolumn{1}{c|}{000} & 222 | \multicolumn{1}{c|}{imm[4:0]} & 223 | \multicolumn{1}{c|}{0100011} & SB \\ 224 | \cline{2-11} 225 | 226 | 227 | & 228 | \multicolumn{4}{|c|}{imm[11:5]} & 229 | \multicolumn{2}{c|}{rs2} & 230 | \multicolumn{1}{c|}{rs1} & 231 | \multicolumn{1}{c|}{001} & 232 | \multicolumn{1}{c|}{imm[4:0]} & 233 | \multicolumn{1}{c|}{0100011} & SH \\ 234 | \cline{2-11} 235 | 236 | & 237 | \multicolumn{4}{|c|}{imm[11:5]} & 238 | \multicolumn{2}{c|}{rs2} & 239 | \multicolumn{1}{c|}{rs1} & 240 | \multicolumn{1}{c|}{010} & 241 | \multicolumn{1}{c|}{imm[4:0]} & 242 | \multicolumn{1}{c|}{0100011} & SW \\ 243 | \cline{2-11} 244 | 245 | & 246 | \multicolumn{6}{|c|}{imm[11:0]} & 247 | \multicolumn{1}{c|}{rs1} & 248 | \multicolumn{1}{c|}{000} & 249 | \multicolumn{1}{c|}{rd} & 250 | \multicolumn{1}{c|}{0010011} & ADDI \\ 251 | \cline{2-11} 252 | 253 | & 254 | \multicolumn{6}{|c|}{imm[11:0]} & 255 | \multicolumn{1}{c|}{rs1} & 256 | \multicolumn{1}{c|}{010} & 257 | \multicolumn{1}{c|}{rd} & 258 | \multicolumn{1}{c|}{0010011} & SLTI \\ 259 | \cline{2-11} 260 | 261 | & 262 | \multicolumn{6}{|c|}{imm[11:0]} & 263 | \multicolumn{1}{c|}{rs1} & 264 | \multicolumn{1}{c|}{011} & 265 | \multicolumn{1}{c|}{rd} & 266 | \multicolumn{1}{c|}{0010011} & SLTIU \\ 267 | \cline{2-11} 268 | 269 | & 270 | \multicolumn{6}{|c|}{imm[11:0]} & 271 | \multicolumn{1}{c|}{rs1} & 272 | \multicolumn{1}{c|}{100} & 273 | \multicolumn{1}{c|}{rd} & 274 | \multicolumn{1}{c|}{0010011} & XORI \\ 275 | \cline{2-11} 276 | 277 | & 278 | \multicolumn{6}{|c|}{imm[11:0]} & 279 | \multicolumn{1}{c|}{rs1} & 280 | \multicolumn{1}{c|}{110} & 281 | \multicolumn{1}{c|}{rd} & 282 | \multicolumn{1}{c|}{0010011} & ORI \\ 283 | \cline{2-11} 284 | 285 | & 286 | \multicolumn{6}{|c|}{imm[11:0]} & 287 | \multicolumn{1}{c|}{rs1} & 288 | \multicolumn{1}{c|}{111} & 289 | \multicolumn{1}{c|}{rd} & 290 | \multicolumn{1}{c|}{0010011} & ANDI \\ 291 | \cline{2-11} 292 | 293 | & 294 | \multicolumn{4}{|c|}{0000000} & 295 | \multicolumn{2}{c|}{shamt} & 296 | \multicolumn{1}{c|}{rs1} & 297 | \multicolumn{1}{c|}{001} & 298 | \multicolumn{1}{c|}{rd} & 299 | \multicolumn{1}{c|}{0010011} & SLLI \\ 300 | \cline{2-11} 301 | 302 | & 303 | \multicolumn{4}{|c|}{0000000} & 304 | \multicolumn{2}{c|}{shamt} & 305 | \multicolumn{1}{c|}{rs1} & 306 | \multicolumn{1}{c|}{101} & 307 | \multicolumn{1}{c|}{rd} & 308 | \multicolumn{1}{c|}{0010011} & SRLI \\ 309 | \cline{2-11} 310 | 311 | & 312 | \multicolumn{4}{|c|}{0100000} & 313 | \multicolumn{2}{c|}{shamt} & 314 | \multicolumn{1}{c|}{rs1} & 315 | \multicolumn{1}{c|}{101} & 316 | \multicolumn{1}{c|}{rd} & 317 | \multicolumn{1}{c|}{0010011} & SRAI \\ 318 | \cline{2-11} 319 | 320 | & 321 | \multicolumn{4}{|c|}{0000000} & 322 | \multicolumn{2}{c|}{rs2} & 323 | \multicolumn{1}{c|}{rs1} & 324 | \multicolumn{1}{c|}{000} & 325 | \multicolumn{1}{c|}{rd} & 326 | \multicolumn{1}{c|}{0110011} & ADD \\ 327 | \cline{2-11} 328 | 329 | & 330 | \multicolumn{4}{|c|}{0100000} & 331 | \multicolumn{2}{c|}{rs2} & 332 | \multicolumn{1}{c|}{rs1} & 333 | \multicolumn{1}{c|}{000} & 334 | \multicolumn{1}{c|}{rd} & 335 | \multicolumn{1}{c|}{0110011} & SUB \\ 336 | \cline{2-11} 337 | 338 | & 339 | \multicolumn{4}{|c|}{0000000} & 340 | \multicolumn{2}{c|}{rs2} & 341 | \multicolumn{1}{c|}{rs1} & 342 | \multicolumn{1}{c|}{001} & 343 | \multicolumn{1}{c|}{rd} & 344 | \multicolumn{1}{c|}{0110011} & SLL \\ 345 | \cline{2-11} 346 | 347 | & 348 | \multicolumn{4}{|c|}{0000000} & 349 | \multicolumn{2}{c|}{rs2} & 350 | \multicolumn{1}{c|}{rs1} & 351 | \multicolumn{1}{c|}{010} & 352 | \multicolumn{1}{c|}{rd} & 353 | \multicolumn{1}{c|}{0110011} & SLT \\ 354 | \cline{2-11} 355 | 356 | & 357 | \multicolumn{4}{|c|}{0000000} & 358 | \multicolumn{2}{c|}{rs2} & 359 | \multicolumn{1}{c|}{rs1} & 360 | \multicolumn{1}{c|}{011} & 361 | \multicolumn{1}{c|}{rd} & 362 | \multicolumn{1}{c|}{0110011} & SLTU \\ 363 | \cline{2-11} 364 | 365 | & 366 | \multicolumn{4}{|c|}{0000000} & 367 | \multicolumn{2}{c|}{rs2} & 368 | \multicolumn{1}{c|}{rs1} & 369 | \multicolumn{1}{c|}{100} & 370 | \multicolumn{1}{c|}{rd} & 371 | \multicolumn{1}{c|}{0110011} & XOR \\ 372 | \cline{2-11} 373 | 374 | & 375 | \multicolumn{4}{|c|}{0000000} & 376 | \multicolumn{2}{c|}{rs2} & 377 | \multicolumn{1}{c|}{rs1} & 378 | \multicolumn{1}{c|}{101} & 379 | \multicolumn{1}{c|}{rd} & 380 | \multicolumn{1}{c|}{0110011} & SRL \\ 381 | \cline{2-11} 382 | 383 | & 384 | \multicolumn{4}{|c|}{0100000} & 385 | \multicolumn{2}{c|}{rs2} & 386 | \multicolumn{1}{c|}{rs1} & 387 | \multicolumn{1}{c|}{101} & 388 | \multicolumn{1}{c|}{rd} & 389 | \multicolumn{1}{c|}{0110011} & SRA \\ 390 | \cline{2-11} 391 | 392 | & 393 | \multicolumn{4}{|c|}{0000000} & 394 | \multicolumn{2}{c|}{rs2} & 395 | \multicolumn{1}{c|}{rs1} & 396 | \multicolumn{1}{c|}{110} & 397 | \multicolumn{1}{c|}{rd} & 398 | \multicolumn{1}{c|}{0110011} & OR \\ 399 | \cline{2-11} 400 | 401 | & 402 | \multicolumn{4}{|c|}{0000000} & 403 | \multicolumn{2}{c|}{rs2} & 404 | \multicolumn{1}{c|}{rs1} & 405 | \multicolumn{1}{c|}{111} & 406 | \multicolumn{1}{c|}{rd} & 407 | \multicolumn{1}{c|}{0110011} & AND \\ 408 | \cline{2-11} 409 | 410 | & 411 | \multicolumn{10}{c}{} & \\ 412 | & 413 | \multicolumn{10}{c}{\bf RV32/RV64 \emph{Zicsr} Standard Extension} & \\ 414 | \cline{2-11} 415 | 416 | & 417 | \multicolumn{6}{|c|}{csr} & 418 | \multicolumn{1}{c|}{rs1} & 419 | \multicolumn{1}{c|}{001} & 420 | \multicolumn{1}{c|}{rd} & 421 | \multicolumn{1}{c|}{1110011} & CSRRW \\ 422 | \cline{2-11} 423 | 424 | & 425 | \multicolumn{6}{|c|}{csr} & 426 | \multicolumn{1}{c|}{uimm} & 427 | \multicolumn{1}{c|}{101} & 428 | \multicolumn{1}{c|}{rd} & 429 | \multicolumn{1}{c|}{1110011} & CSRRWI \\ 430 | \cline{2-11} 431 | 432 | \end{tabular} 433 | \end{center} 434 | \end{small} 435 | 436 | \end{table} 437 | --------------------------------------------------------------------------------