├── .gitignore ├── LICENSE ├── README.md ├── misc └── create_mif.rb ├── quartus_max10_deca ├── .gitignore ├── Makefile ├── mini_cpu.qpf ├── mini_cpu.qsf └── mini_cpu.sdc ├── rtl ├── VexRiscv.fast.v ├── VexRiscv.v └── top.v ├── sw ├── .gitignore ├── Makefile ├── lib.c ├── lib.h ├── main.c ├── reg.h ├── riscv.h ├── sections.lds ├── start.S ├── top_defines.h └── vexriscv_init.cfg └── tb ├── .gitignore ├── Makefile ├── tb.v └── waves.gtkw /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw* 2 | *.bak 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # FPGA Quick RAM Update Example 3 | 4 | This project contains a simple design with a VexRiscv CPU, a bit 5 | of RAM, a control register to set the value of 3 LEDs and a status 6 | register to read back the value of a button. 7 | 8 | It's an example design that goes with my 9 | [A Hack to Update RAM Initialization Contents in Intel FPGA Bitstreams](https://tomverbeure.github.io/2021/04/25/Intel-FPGA-RAM-Bitstream-Patching.html) 10 | blog post. 11 | 12 | ## Contents 13 | 14 | * `./rtl`: RTL files 15 | 16 | The Verilog of the `VexRiscv.v` file was generated from a SpinalHDL 17 | (which is not included in the project.) 18 | 19 | * `./sw`: firmware for the CPU system 20 | 21 | A small C project that toggles 3 LEDs in sequence. When a button in 22 | pressed, the LEDs toggle at double the speed. 23 | 24 | Do `make` to create a firmware image. 25 | 26 | * `./tb`: Testbench 27 | 28 | To verify that the design works in simulation. 29 | 30 | Do `make` to simulate. 31 | 32 | * `./quartus_max10_deca`: Quartus project for an Arrow DECA FPGA board 33 | 34 | In addition to all the standard files that are needed for 35 | a Quartus project, the `./quartus_max10_deca` directory also contains 36 | a makefile to compile the design from the command line. 37 | 38 | Do `make` to compile the whole design from scratch. 39 | 40 | Do `make update_ram` to only update the RAM contains of an already built 41 | bitstream. 42 | 43 | This makefile can trivially be adapted for projects that use different 44 | versions of Quartus, and for different designs. 45 | 46 | The method of updating the RAM has been confirmed to work for Quartus 47 | 13.0sp1 (the last version that supports Cyclone II devices), Quartus 48 | 17, Quartus 18, Quartus 19 and Quartus 20. 49 | 50 | * `./misc` 51 | 52 | Contains helps scripts. In this case, the `create_mif.rb` script which converts 53 | binary files into MIF file (and other formats as well...) 54 | 55 | ## Required software 56 | 57 | * Intel Quartus 58 | * RISC-V GCC toolchain to compile a firmware image 59 | 60 | Precompiled binaries can be downloaded [here](https://github.com/sifive/freedom-tools/releases). 61 | 62 | * Icarus Verilog Simulator 63 | 64 | On Ubuntu: `sudo apt install iverilog` 65 | 66 | * GTKWave Waveform viewer 67 | 68 | On Ubuntu: `sudo apt install gtkwave` 69 | 70 | ## License 71 | 72 | See LICENSE. Use this anyway you want, except for `./rtl/VexRiscv.v`, which is released 73 | under [the MIT license](https://github.com/SpinalHDL/VexRiscv/blob/master/LICENSE). 74 | 75 | -------------------------------------------------------------------------------- /misc/create_mif.rb: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | 3 | require 'optparse' 4 | require 'pp' 5 | 6 | options = {} 7 | OptionParser.new do |opts| 8 | opts.banner = "Usage: create_mif.rb [options]" 9 | opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| 10 | options[:verbose] = v 11 | end 12 | 13 | opts.on("-fFORMAT", "--format=FORMAT", "Specify output format ('mif', 'hex', 'coe', 'mem')") do |f| 14 | options[:format] = f 15 | end 16 | 17 | opts.on("-dDEPTH", "--depth=DEPTH", Integer, "Memory depth") do |d| 18 | options[:depth] = d 19 | end 20 | 21 | opts.on("-wWIDTH", "--width=WIDTH", Integer, "Memory width (bits)") do |w| 22 | options[:width] = w 23 | end 24 | 25 | opts.on("-oOFFSET", "--offset=OFFSET", Integer, "First byte to use of the binary input file (default = 0)") do |o| 26 | options[:offset] = o 27 | end 28 | 29 | opts.on("-iINCREMENT", "--increment=INCREMENT", Integer, "How many bytes to the next byte (default = 1)") do |i| 30 | options[:increment] = i 31 | end 32 | 33 | end.parse! 34 | 35 | start_offset = options[:offset] || 0 36 | increment = options[:increment] || 1 37 | 38 | bin = File.open(ARGV[0], "rb").read 39 | bytes = bin.unpack("C*")[start_offset..-1].each_slice(increment).collect{ |a| a.first } 40 | 41 | depth = options[:depth] || bytes.size 42 | width = options[:width] || 8 43 | format = options[:format] || "mif" 44 | 45 | bytes_per_word = (width+7)>>3 46 | nr_addr_bits = Math.log2(depth).ceil 47 | 48 | if options[:verbose] 49 | STDERR.puts "output format : #{format}" 50 | STDERR.puts "depth : #{depth}" 51 | STDERR.puts "width : #{width}" 52 | STDERR.puts "bytes per word: #{bytes_per_word}" 53 | STDERR.puts "start offset : #{start_offset}" 54 | STDERR.puts "increment : #{increment}" 55 | end 56 | 57 | if format == "mif" 58 | puts %{-- Created by create_mif.rb 59 | DEPTH = #{depth}; 60 | WIDTH = #{width}; 61 | ADDRESS_RADIX = HEX; 62 | DATA_RADIX = HEX; 63 | CONTENT 64 | BEGIN 65 | } 66 | 67 | addr_fmt_string = "%%0%dx" % ((nr_addr_bits+3)>>2) 68 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 69 | 70 | fmt_string = "#{addr_fmt_string}: #{data_fmt_string};" 71 | 72 | words = bytes.each_slice(bytes_per_word) 73 | words.each_with_index do |w, addr| 74 | value = 0 75 | w.reverse.collect { |b| value = value * 256 + b } 76 | puts fmt_string % [addr, value] 77 | end 78 | 79 | if words.size < depth 80 | puts "[#{addr_fmt_string}..#{addr_fmt_string}]: #{data_fmt_string};" % [ words.size, depth-1, 0 ] 81 | end 82 | 83 | puts "END;" 84 | puts 85 | 86 | elsif format == "coe" 87 | puts %{; Created by create_mif.rb 88 | ; block memory configuration: 89 | ; DEPTH = #{depth}; 90 | ; WIDTH = #{width}; 91 | memory_initialization_radix=16; 92 | memory_initialization_vector=} 93 | 94 | words = bytes.each_slice(bytes_per_word).collect do |w| 95 | value = 0 96 | w.reverse.collect { |b| value = value * 256 + b } 97 | value 98 | end 99 | 100 | (depth - words.size).times { words << 0 } 101 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 102 | str = words.collect{ |w| data_fmt_string % w }.join(",\n") + ";" 103 | 104 | puts str 105 | 106 | elsif format == "hex" 107 | 108 | words = bytes.each_slice(bytes_per_word).collect do |w| 109 | value = 0 110 | w.reverse.collect { |b| value = value * 256 + b } 111 | value 112 | end 113 | 114 | (depth - words.size).times { words << 0 } 115 | 116 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 117 | str = words.collect{ |w| data_fmt_string % w }.join("\n") 118 | 119 | puts str 120 | 121 | elsif format == "mem" 122 | 123 | words = bytes.each_slice(bytes_per_word).collect do |w| 124 | value = 0 125 | w.reverse.collect { |b| value = value * 256 + b } 126 | value 127 | end 128 | 129 | (depth - words.size).times { words << 0 } 130 | 131 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 132 | str = words.collect{ |w| data_fmt_string % w }.join("\n") 133 | 134 | puts "@00000000" 135 | puts str 136 | 137 | else 138 | Kernel.abort("Unknown format '#{format}'! Aborting...") 139 | end 140 | -------------------------------------------------------------------------------- /quartus_max10_deca/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /quartus_max10_deca/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DESIGN_NAME = mini_cpu 3 | 4 | QUARTUS_DIR = ~/intelFPGA_lite/20.1/quartus/bin 5 | 6 | DB_CPU_RAM0 = $(wildcard ./db/mini_cpu.ram0_top*.mif) 7 | DB_CPU_RAM1 = $(wildcard ./db/mini_cpu.ram1_top*.mif) 8 | DB_CPU_RAM2 = $(wildcard ./db/mini_cpu.ram2_top*.mif) 9 | DB_CPU_RAM3 = $(wildcard ./db/mini_cpu.ram3_top*.mif) 10 | 11 | DB_CPU_RAMS = $(DB_CPU_RAM0) $(DB_CPU_RAM1) $(DB_CPU_RAM2) $(DB_CPU_RAM3) 12 | 13 | all: compile 14 | 15 | compile: 16 | $(QUARTUS_DIR)/quartus_map --read_settings_files=on --write_settings_files=off $(DESIGN_NAME) -c $(DESIGN_NAME) 17 | $(QUARTUS_DIR)/quartus_fit --read_settings_files=on --write_settings_files=off $(DESIGN_NAME) -c $(DESIGN_NAME) 18 | $(QUARTUS_DIR)/quartus_asm --read_settings_files=on --write_settings_files=off $(DESIGN_NAME) -c $(DESIGN_NAME) 19 | $(QUARTUS_DIR)/quartus_sta $(DESIGN_NAME) -c $(DESIGN_NAME) 20 | 21 | update_ram: sw $(DB_CPU_RAMS) 22 | $(QUARTUS_DIR)/quartus_cdb $(DESIGN_NAME) -c $(DESIGN_NAME) --update_mif 23 | $(QUARTUS_DIR)/quartus_asm --read_settings_files=on --write_settings_files=off $(DESIGN_NAME) -c $(DESIGN_NAME) 24 | 25 | $(DB_CPU_RAM0): ../sw/progmem0.mif 26 | cp $< $@ 27 | 28 | $(DB_CPU_RAM1): ../sw/progmem1.mif 29 | cp $< $@ 30 | 31 | $(DB_CPU_RAM2): ../sw/progmem2.mif 32 | cp $< $@ 33 | 34 | $(DB_CPU_RAM3): ../sw/progmem3.mif 35 | cp $< $@ 36 | 37 | sw: 38 | cd ../sw && make 39 | 40 | clean: 41 | \rm -fr db incremental_db simulation 42 | -------------------------------------------------------------------------------- /quartus_max10_deca/mini_cpu.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2020 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and any partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details, at 16 | # https://fpgasoftware.intel.com/eula. 17 | # 18 | # -------------------------------------------------------------------------- # 19 | # 20 | # Quartus Prime 21 | # Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition 22 | # Date created = 20:27:36 April 25, 2021 23 | # 24 | # -------------------------------------------------------------------------- # 25 | 26 | QUARTUS_VERSION = "20.1" 27 | DATE = "20:27:36 April 25, 2021" 28 | 29 | # Revisions 30 | 31 | PROJECT_REVISION = "mini_cpu" 32 | PROJECT_REVISION = "top" 33 | -------------------------------------------------------------------------------- /quartus_max10_deca/mini_cpu.qsf: -------------------------------------------------------------------------------- 1 | 2 | set_global_assignment -name FAMILY "MAX 10" 3 | set_global_assignment -name DEVICE 10M50DAF484C6GES 4 | set_global_assignment -name TOP_LEVEL_ENTITY top 5 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1" 6 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "16:39:34 APRIL 09, 2021" 7 | set_global_assignment -name LAST_QUARTUS_VERSION "20.1.1 Lite Edition" 8 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 9 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 10 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 11 | set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484 12 | set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 2 13 | set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (VHDL)" 14 | set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation 15 | set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top 16 | set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top 17 | set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top 18 | set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" 19 | set_location_assignment PIN_H21 -to button 20 | set_location_assignment PIN_M8 -to clk 21 | set_location_assignment PIN_C7 -to led0 22 | set_location_assignment PIN_C8 -to led1 23 | set_location_assignment PIN_A6 -to led2 24 | set_global_assignment -name ENABLE_SIGNALTAP OFF 25 | set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp 26 | set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF 27 | set_global_assignment -name VERILOG_MACRO "SYNTHESIS=" 28 | set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 6 29 | set_global_assignment -name ENABLE_OCT_DONE OFF 30 | set_global_assignment -name EXTERNAL_FLASH_FALLBACK_ADDRESS 00000000 31 | set_global_assignment -name USE_CONFIGURATION_DEVICE OFF 32 | set_global_assignment -name INTERNAL_FLASH_UPDATE_MODE "SINGLE COMP IMAGE WITH ERAM" 33 | set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF 34 | set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise 35 | set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall 36 | set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise 37 | set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall 38 | set_global_assignment -name IOBANK_VCCIO 1.2V -section_id 8 39 | set_global_assignment -name IOBANK_VCCIO 1.8V -section_id 7 40 | set_global_assignment -name IOBANK_VCCIO 2.5V -section_id 1A 41 | set_global_assignment -name IOBANK_VCCIO 2.5V -section_id 1B 42 | set_global_assignment -name IOBANK_VCCIO 2.5V -section_id 2 43 | set_global_assignment -name IOBANK_VCCIO 3.3V -section_id 3 44 | set_global_assignment -name IOBANK_VCCIO 3.3V -section_id 4 45 | set_global_assignment -name IOBANK_VCCIO 1.5V -section_id 6 46 | set_global_assignment -name IOBANK_VCCIO 1.5V -section_id 5 47 | set_instance_assignment -name IO_STANDARD "1.5 V" -to button 48 | set_instance_assignment -name IO_STANDARD "1.2 V" -to led0 49 | set_instance_assignment -name IO_STANDARD "1.2 V" -to led1 50 | set_instance_assignment -name IO_STANDARD "1.2 V" -to led2 51 | set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" 52 | set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" 53 | set_instance_assignment -name IO_STANDARD "2.5 V" -to clk 54 | set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON 55 | set_global_assignment -name AUTO_RESTART_CONFIGURATION OFF 56 | set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF 57 | set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF 58 | set_global_assignment -name VERILOG_FILE ../rtl/VexRiscv.v 59 | set_global_assignment -name VERILOG_FILE ../rtl/top.v 60 | 61 | 62 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top -------------------------------------------------------------------------------- /quartus_max10_deca/mini_cpu.sdc: -------------------------------------------------------------------------------- 1 | ## Generated SDC file "vexriscv_ocd.sdc" 2 | 3 | ## Copyright (C) 1991-2013 Altera Corporation 4 | ## Your use of Altera Corporation's design tools, logic functions 5 | ## and other software and tools, and its AMPP partner logic 6 | ## functions, and any output files from any of the foregoing 7 | ## (including device programming or simulation files), and any 8 | ## associated documentation or information are expressly subject 9 | ## to the terms and conditions of the Altera Program License 10 | ## Subscription Agreement, Altera MegaCore Function License 11 | ## Agreement, or other applicable license agreement, including, 12 | ## without limitation, that your use is for the sole purpose of 13 | ## programming logic devices manufactured by Altera and sold by 14 | ## Altera or its authorized distributors. Please refer to the 15 | ## applicable agreement for further details. 16 | 17 | 18 | ## VENDOR "Altera" 19 | ## PROGRAM "Quartus II" 20 | ## VERSION "Version 13.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition" 21 | 22 | ## DATE "Sun Apr 11 23:49:27 2021" 23 | 24 | ## 25 | ## DEVICE "EP2C5T144C6" 26 | ## 27 | 28 | 29 | #************************************************************** 30 | # Time Information 31 | #************************************************************** 32 | 33 | set_time_format -unit ns -decimal_places 3 34 | 35 | 36 | 37 | #************************************************************** 38 | # Create Clock 39 | #************************************************************** 40 | 41 | create_clock -name {clk} -period 20.000 -waveform { 0.000 10.000 } [get_ports {clk}] 42 | 43 | #************************************************************** 44 | # Create Generated Clock 45 | #************************************************************** 46 | 47 | 48 | 49 | #************************************************************** 50 | # Set Clock Latency 51 | #************************************************************** 52 | 53 | 54 | 55 | #************************************************************** 56 | # Set Clock Uncertainty 57 | #************************************************************** 58 | 59 | 60 | 61 | #************************************************************** 62 | # Set Input Delay 63 | #************************************************************** 64 | 65 | 66 | 67 | #************************************************************** 68 | # Set Output Delay 69 | #************************************************************** 70 | 71 | 72 | 73 | #************************************************************** 74 | # Set Clock Groups 75 | #************************************************************** 76 | 77 | set_clock_groups -asynchronous -group [get_clocks {altera_reserved_tck}] 78 | 79 | 80 | #************************************************************** 81 | # Set False Path 82 | #************************************************************** 83 | 84 | 85 | 86 | #************************************************************** 87 | # Set Multicycle Path 88 | #************************************************************** 89 | 90 | 91 | 92 | #************************************************************** 93 | # Set Maximum Delay 94 | #************************************************************** 95 | 96 | 97 | 98 | #************************************************************** 99 | # Set Minimum Delay 100 | #************************************************************** 101 | 102 | 103 | 104 | #************************************************************** 105 | # Set Input Transition 106 | #************************************************************** 107 | 108 | -------------------------------------------------------------------------------- /rtl/top.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | //`define ALTSYNCRAM 4 | 5 | module top( 6 | input wire clk, 7 | input wire button, 8 | output reg led0, 9 | output reg led1, 10 | output reg led2 11 | ); 12 | 13 | // When changing this value, checkout ./sw/Makefile for a list of 14 | // all other files that must be changed as well. 15 | localparam mem_size_bytes = 2048; 16 | 17 | // $clog2 is only supported by Verilog-2005 and later. 18 | // If your synthesis tool doesn't like it, just replace the expression 19 | // below by 11... 20 | localparam mem_addr_bits = $clog2(mem_size_bytes); 21 | 22 | wire iBus_cmd_valid; 23 | wire iBus_cmd_ready; 24 | wire [31:0] iBus_cmd_payload_pc; 25 | 26 | reg iBus_rsp_valid; 27 | wire iBus_rsp_payload_error; 28 | reg [31:0] iBus_rsp_payload_inst; 29 | 30 | wire dBus_cmd_valid; 31 | wire dBus_cmd_ready; 32 | wire dBus_cmd_payload_wr; 33 | wire [31:0] dBus_cmd_payload_address; 34 | wire [31:0] dBus_cmd_payload_data; 35 | wire [1:0] dBus_cmd_payload_size; 36 | 37 | reg dBus_rsp_ready; 38 | wire dBus_rsp_error; 39 | wire [31:0] dBus_rsp_data; 40 | 41 | reg [7:0] reset_vec = 8'hff; 42 | wire reset; 43 | 44 | // 8 clock cycles of active-high reset. 45 | always @(posedge clk) begin 46 | reset_vec <= { reset_vec[6:0], 1'b0 }; 47 | end 48 | 49 | assign reset = reset_vec[7]; 50 | 51 | VexRiscvTop u_vex ( 52 | .clk (clk), 53 | .reset (reset), 54 | 55 | .io_iBus_cmd_valid (iBus_cmd_valid), 56 | .io_iBus_cmd_ready (iBus_cmd_ready), 57 | .io_iBus_cmd_payload_pc (iBus_cmd_payload_pc), 58 | 59 | .io_iBus_rsp_valid (iBus_rsp_valid), 60 | .io_iBus_rsp_payload_error (iBus_rsp_payload_error), 61 | .io_iBus_rsp_payload_inst (iBus_rsp_payload_inst), 62 | 63 | .io_dBus_cmd_valid (dBus_cmd_valid), 64 | .io_dBus_cmd_ready (dBus_cmd_ready), 65 | .io_dBus_cmd_payload_wr (dBus_cmd_payload_wr), 66 | .io_dBus_cmd_payload_address(dBus_cmd_payload_address), 67 | .io_dBus_cmd_payload_data (dBus_cmd_payload_data), 68 | .io_dBus_cmd_payload_size (dBus_cmd_payload_size), 69 | 70 | .io_dBus_rsp_ready (dBus_rsp_ready), 71 | .io_dBus_rsp_error (dBus_rsp_error), 72 | .io_dBus_rsp_data (dBus_rsp_data), 73 | 74 | .io_timerInterrupt (1'b0), 75 | .io_externalInterrupt (1'b0) 76 | ); 77 | 78 | always @(posedge clk) begin 79 | iBus_rsp_valid <= iBus_cmd_valid; 80 | end 81 | 82 | assign iBus_cmd_ready = 1'b1; 83 | assign iBus_rsp_payload_error = 1'b0; 84 | 85 | assign dBus_cmd_ready = 1'b1; 86 | assign dBus_rsp_error = 1'b0; 87 | 88 | wire [31:0] dBus_wdata; 89 | assign dBus_wdata = dBus_cmd_payload_data; 90 | 91 | wire [3:0] dBus_be; 92 | assign dBus_be = (dBus_cmd_payload_size == 2'd0) ? (4'b0001 << dBus_cmd_payload_address[1:0]) : 93 | (dBus_cmd_payload_size == 2'd1) ? (4'b0011 << dBus_cmd_payload_address[1:0]) : 94 | 4'b1111; 95 | 96 | reg [31:0] mem_rdata; 97 | 98 | wire [3:0] mem_wr; 99 | assign mem_wr = {4{dBus_cmd_valid && !dBus_cmd_payload_address[31] && dBus_cmd_payload_wr}} & dBus_be; 100 | 101 | `ifndef ALTSYNCRAM 102 | // Instead of inferring 1 32-bit wide RAM with 4 byte enables, infer 103 | // 4 8-bit wide RAMs. Many synthesis tools have issues with inferring RAMs with byte enables. 104 | // Quartus, for example, only supports them with SystemVerilog, not 105 | // regular Verilog. 106 | 107 | reg [7:0] mem0[0:mem_size_bytes/4-1]; 108 | reg [7:0] mem1[0:mem_size_bytes/4-1]; 109 | reg [7:0] mem2[0:mem_size_bytes/4-1]; 110 | reg [7:0] mem3[0:mem_size_bytes/4-1]; 111 | 112 | initial begin 113 | $readmemh("../sw/progmem0.hex", mem0); 114 | $readmemh("../sw/progmem1.hex", mem1); 115 | $readmemh("../sw/progmem2.hex", mem2); 116 | $readmemh("../sw/progmem3.hex", mem3); 117 | end 118 | 119 | //============================================================ 120 | // CPU memory instruction read port 121 | //============================================================ 122 | 123 | always @(posedge clk) begin 124 | iBus_rsp_payload_inst[ 7: 0] <= mem0[iBus_cmd_payload_pc[mem_addr_bits-1:2]]; 125 | iBus_rsp_payload_inst[15: 8] <= mem1[iBus_cmd_payload_pc[mem_addr_bits-1:2]]; 126 | iBus_rsp_payload_inst[23:16] <= mem2[iBus_cmd_payload_pc[mem_addr_bits-1:2]]; 127 | iBus_rsp_payload_inst[31:24] <= mem3[iBus_cmd_payload_pc[mem_addr_bits-1:2]]; 128 | end 129 | 130 | //============================================================ 131 | // CPU memory data read/write port 132 | //============================================================ 133 | 134 | // Quartus can be very picky about how RTL should structured to infer a true dual-ported RAM... 135 | always @(posedge clk) begin 136 | if (mem_wr[0]) begin 137 | mem0[dBus_cmd_payload_address[mem_addr_bits-1:2]] <= dBus_wdata[ 7: 0]; 138 | mem_rdata[ 7: 0] <= dBus_wdata[ 7: 0]; 139 | end 140 | else 141 | mem_rdata[ 7: 0] <= mem0[dBus_cmd_payload_address[mem_addr_bits-1:2]]; 142 | 143 | if (mem_wr[1]) begin 144 | mem1[dBus_cmd_payload_address[mem_addr_bits-1:2]] <= dBus_wdata[15: 8]; 145 | mem_rdata[15: 8] <= dBus_wdata[15: 8]; 146 | end 147 | else 148 | mem_rdata[15: 8] <= mem1[dBus_cmd_payload_address[mem_addr_bits-1:2]]; 149 | 150 | if (mem_wr[2]) begin 151 | mem2[dBus_cmd_payload_address[mem_addr_bits-1:2]] <= dBus_wdata[23:16]; 152 | mem_rdata[23:16] <= dBus_wdata[23:16]; 153 | end 154 | else 155 | mem_rdata[23:16] <= mem2[dBus_cmd_payload_address[mem_addr_bits-1:2]]; 156 | 157 | if (mem_wr[3]) begin 158 | mem3[dBus_cmd_payload_address[mem_addr_bits-1:2]] <= dBus_wdata[31:24]; 159 | mem_rdata[31:24] <= dBus_wdata[31:24]; 160 | end 161 | else 162 | mem_rdata[31:24] <= mem3[dBus_cmd_payload_address[mem_addr_bits-1:2]]; 163 | end 164 | `else 165 | // altsyncram is the Intel synchronous RAM primitive. This code will only 166 | // work on Intel FPGAs. 167 | // Most Intel FPGAs have block RAMs that have byte-enable support, so the 168 | // 4 8-bit RAMs below could have been replaced by just 1 32-bit RAM... 169 | 170 | altsyncram #( 171 | .operation_mode ("BIDIR_DUAL_PORT"), 172 | .widthad_a (mem_addr_bits-2), 173 | .widthad_b (mem_addr_bits-2), 174 | .width_a (8), 175 | .width_b (8), 176 | .outdata_reg_a ("UNREGISTERED"), 177 | .outdata_reg_b ("UNREGISTERED"), 178 | .init_file ("../sw/progmem0.mif") 179 | ) 180 | u_mem0 ( 181 | .clock0 (clk), 182 | .wren_a (1'b0), 183 | .rden_a (1'b1), 184 | .address_a (iBus_cmd_payload_pc[mem_addr_bits-1:2]), 185 | .data_a (8'd0), 186 | .q_a (iBus_rsp_payload_inst[7:0]), 187 | 188 | .clock1 (clk), 189 | .address_b (dBus_cmd_payload_address[mem_addr_bits-1:2]), 190 | .wren_b (mem_wr[0]), 191 | .rden_b (1'b1), 192 | .data_b (dBus_wdata[7:0]), 193 | .q_b (mem_rdata[7:0]) 194 | ); 195 | 196 | altsyncram #( 197 | .operation_mode ("BIDIR_DUAL_PORT"), 198 | .widthad_a (mem_addr_bits-2), 199 | .widthad_b (mem_addr_bits-2), 200 | .width_a (8), 201 | .width_b (8), 202 | .outdata_reg_a ("UNREGISTERED"), 203 | .outdata_reg_b ("UNREGISTERED"), 204 | .init_file ("../sw/progmem1.mif") 205 | ) 206 | u_mem1 ( 207 | .clock0 (clk), 208 | .wren_a (1'b0), 209 | .rden_a (1'b1), 210 | .address_a (iBus_cmd_payload_pc[mem_addr_bits-1:2]), 211 | .data_a (8'd0), 212 | .q_a (iBus_rsp_payload_inst[15:8]), 213 | 214 | .clock1 (clk), 215 | .address_b (dBus_cmd_payload_address[mem_addr_bits-1:2]), 216 | .wren_b (mem_wr[1]), 217 | .rden_b (1'b1), 218 | .data_b (dBus_wdata[15:8]), 219 | .q_b (mem_rdata[15:8]) 220 | ); 221 | 222 | altsyncram #( 223 | .operation_mode ("BIDIR_DUAL_PORT"), 224 | .widthad_a (mem_addr_bits-2), 225 | .widthad_b (mem_addr_bits-2), 226 | .width_a (8), 227 | .width_b (8), 228 | .outdata_reg_a ("UNREGISTERED"), 229 | .outdata_reg_b ("UNREGISTERED"), 230 | .init_file ("../sw/progmem2.mif") 231 | ) 232 | u_mem2 ( 233 | .clock0 (clk), 234 | .wren_a (1'b0), 235 | .rden_a (1'b1), 236 | .address_a (iBus_cmd_payload_pc[mem_addr_bits-1:2]), 237 | .data_a (8'd0), 238 | .q_a (iBus_rsp_payload_inst[23:16]), 239 | 240 | .clock1 (clk), 241 | .address_b (dBus_cmd_payload_address[mem_addr_bits-1:2]), 242 | .wren_b (mem_wr[2]), 243 | .rden_b (1'b1), 244 | .data_b (dBus_wdata[23:16]), 245 | .q_b (mem_rdata[23:16]) 246 | ); 247 | 248 | altsyncram #( 249 | .operation_mode ("BIDIR_DUAL_PORT"), 250 | .widthad_a (mem_addr_bits-2), 251 | .widthad_b (mem_addr_bits-2), 252 | .width_a (8), 253 | .width_b (8), 254 | .outdata_reg_a ("UNREGISTERED"), 255 | .outdata_reg_b ("UNREGISTERED"), 256 | .init_file ("../sw/progmem3.mif") 257 | ) 258 | u_mem3 ( 259 | .clock0 (clk), 260 | .wren_a (1'b0), 261 | .rden_a (1'b1), 262 | .address_a (iBus_cmd_payload_pc[mem_addr_bits-1:2]), 263 | .data_a (8'd0), 264 | .q_a (iBus_rsp_payload_inst[31:24]), 265 | 266 | .clock1 (clk), 267 | .address_b (dBus_cmd_payload_address[mem_addr_bits-1:2]), 268 | .wren_b (mem_wr[3]), 269 | .rden_b (1'b1), 270 | .data_b (dBus_wdata[31:24]), 271 | .q_b (mem_rdata[31:24]) 272 | ); 273 | `endif 274 | 275 | //============================================================ 276 | // Peripherals 277 | //============================================================ 278 | 279 | reg [31:0] periph_rdata; 280 | 281 | always @(posedge clk or posedge reset) begin 282 | if (reset) begin 283 | led0 <= 1'b1; 284 | led1 <= 1'b1; 285 | led2 <= 1'b1; 286 | periph_rdata <= 32'd0; 287 | end 288 | else if (dBus_cmd_valid && dBus_cmd_payload_address[31]) begin 289 | 290 | // LED register 291 | if (dBus_cmd_payload_address[mem_addr_bits-1:2] == 10'h0) begin 292 | if (dBus_cmd_payload_wr) begin 293 | // LEDs are active low... 294 | led0 <= !dBus_wdata[0]; 295 | led1 <= !dBus_wdata[1]; 296 | led2 <= !dBus_wdata[2]; 297 | end 298 | else begin 299 | periph_rdata <= 'd0; 300 | periph_rdata[0] <= !led0; 301 | periph_rdata[1] <= !led1; 302 | periph_rdata[2] <= !led2; 303 | end 304 | end 305 | 306 | // Status register 307 | if (dBus_cmd_payload_address[mem_addr_bits-1:2] == 10'h1) begin 308 | if (!dBus_cmd_payload_wr) begin 309 | periph_rdata[0] <= button_sync[1]; 310 | 311 | // I don't want to compile different 2 SW version for 312 | // simulation and HW, so this status bit can be used by 313 | // the SW on which platform it's running. 314 | `ifdef SIMULATION 315 | periph_rdata[1] <= 1'b1; 316 | `else 317 | periph_rdata[1] <= 1'b0; 318 | `endif 319 | end 320 | end 321 | end 322 | end 323 | 324 | reg [1:0] button_sync; 325 | 326 | always @(posedge clk) begin 327 | // double FF synchronizer 328 | button_sync <= { button_sync[0], button }; 329 | end 330 | 331 | //============================================================ 332 | // Merge read paths 333 | //============================================================ 334 | 335 | reg periph_sel; 336 | always @(posedge clk or posedge reset) begin 337 | if (reset) begin 338 | dBus_rsp_ready <= 1'b0; 339 | periph_sel <= 1'b0; 340 | end 341 | else begin 342 | // Both memory reads and peripheral reads don't support wait 343 | // cycles. Data is always returned immediately the next cycle. 344 | dBus_rsp_ready <= dBus_cmd_valid && !dBus_cmd_payload_wr; 345 | periph_sel <= dBus_cmd_valid && !dBus_cmd_payload_wr && dBus_cmd_payload_address[31]; 346 | end 347 | end 348 | 349 | assign dBus_rsp_data = periph_sel ? periph_rdata : mem_rdata; 350 | 351 | endmodule 352 | 353 | -------------------------------------------------------------------------------- /sw/.gitignore: -------------------------------------------------------------------------------- 1 | progmem*.* 2 | *.o 3 | coefs.h 4 | -------------------------------------------------------------------------------- /sw/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # When you change the memory size below, make sure to also change it in: 3 | # 4 | # ./sw/sections.lds 5 | # ./sw/start.S 6 | # ./rtl/top.v 7 | 8 | MEM_WORDS = 512 9 | MEM_BYTES = 2048 10 | 11 | MARCH = rv32ic 12 | CPU_FREQ_MHZ = 50 13 | CC_OPT = -Os 14 | 15 | OBJ_FILES = start.o main.o lib.o 16 | 17 | TOOLS_PREFIX = /opt/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-linux-ubuntu14/bin 18 | 19 | TARGET = $(TOOLS_PREFIX)/riscv64-unknown-elf 20 | 21 | AS = $(TARGET)-as 22 | ASFLAGS = -march=$(MARCH) -mabi=ilp32 23 | LD = $(TARGET)-gcc 24 | LDFLAGS = -march=$(MARCH) -g -ggdb -mabi=ilp32 -Wl,-Tsections.lds,-Map,progmem.map -ffreestanding -nostartfiles -Wl,--no-relax -Wl,--start-group,--end-group 25 | CC = $(TARGET)-gcc 26 | CFLAGS = -march=$(MARCH) -g -ggdb -mno-div -mabi=ilp32 -ffunction-sections -fdata-sections -Wall -Wextra -pedantic -DCPU_FREQ=$(CPU_FREQ_MHZ)000000 $(CC_OPT) 27 | OBJCOPY = $(TARGET)-objcopy 28 | OBJDUMP = $(TARGET)-objdump 29 | READELF = $(TARGET)-readelf 30 | 31 | GDBGUI = gdbgui 32 | 33 | CREATE_MIF = ../misc/create_mif.rb 34 | 35 | .PHONY: all clean 36 | 37 | all: progmem.dis progmem.bin progmem0.hex progmem0.mif 38 | 39 | progmem.dis: progmem.elf 40 | $(OBJDUMP) -s -D $< > $@ 41 | 42 | progmem0.hex: progmem.bin 43 | $(CREATE_MIF) -f hex -d $(MEM_WORDS) -w 8 -o 0 -i 4 $< > progmem0.hex 44 | $(CREATE_MIF) -f hex -d $(MEM_WORDS) -w 8 -o 1 -i 4 $< > progmem1.hex 45 | $(CREATE_MIF) -f hex -d $(MEM_WORDS) -w 8 -o 2 -i 4 $< > progmem2.hex 46 | $(CREATE_MIF) -f hex -d $(MEM_WORDS) -w 8 -o 3 -i 4 $< > progmem3.hex 47 | 48 | progmem0.mif: progmem.bin 49 | $(CREATE_MIF) -f mif -d $(MEM_WORDS) -w 8 -o 0 -i 4 $< > progmem0.mif 50 | $(CREATE_MIF) -f mif -d $(MEM_WORDS) -w 8 -o 1 -i 4 $< > progmem1.mif 51 | $(CREATE_MIF) -f mif -d $(MEM_WORDS) -w 8 -o 2 -i 4 $< > progmem2.mif 52 | $(CREATE_MIF) -f mif -d $(MEM_WORDS) -w 8 -o 3 -i 4 $< > progmem3.mif 53 | 54 | progmem.bin: progmem.elf 55 | $(OBJCOPY) -O binary $< $@ 56 | 57 | progmem.elf: $(OBJ_FILES) top_defines.h sections.lds Makefile 58 | $(LD) $(LDFLAGS) -o $@ $(OBJ_FILES) -lm 59 | 60 | main.o: top_defines.h 61 | main.c: top_defines.h 62 | 63 | clean: 64 | \rm -fr *.o *.hex *.elf *.dis *.bin *.coe *.map *.mif *.mem *.funcs *.globs 65 | -------------------------------------------------------------------------------- /sw/lib.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "reg.h" 5 | #include "top_defines.h" 6 | #include "lib.h" 7 | 8 | static inline uint32_t internal_rdcycle(void) { 9 | uint32_t cycle; 10 | asm volatile ("rdcycle %0" : "=r"(cycle)); 11 | return cycle; 12 | } 13 | 14 | static inline uint32_t internal_rdcycleh(void) { 15 | uint32_t cycle; 16 | asm volatile ("rdcycleh %0" : "=r"(cycle)); 17 | return cycle; 18 | } 19 | 20 | uint64_t rdcycle64(void) { 21 | 22 | uint32_t msw; 23 | uint32_t lsw; 24 | 25 | do{ 26 | msw = internal_rdcycleh(); 27 | lsw = internal_rdcycle(); 28 | } while(msw != internal_rdcycleh()); 29 | 30 | return ((uint64_t)msw << 32) | lsw; 31 | } 32 | 33 | void wait_cycles(uint32_t cycles) 34 | { 35 | uint64_t start; 36 | 37 | start = rdcycle64(); 38 | while ((rdcycle64() - start) <= (uint64_t)cycles) {} 39 | } 40 | 41 | 42 | void wait_ms(uint32_t ms) 43 | { 44 | wait_cycles((uint32_t)CPU_FREQ / 1000UL * ms); 45 | } 46 | 47 | void wait_us(uint32_t us) 48 | { 49 | wait_cycles((uint32_t)CPU_FREQ / 1000000UL * us); 50 | } 51 | -------------------------------------------------------------------------------- /sw/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_H 2 | #define LIB_H 3 | 4 | uint64_t rdcycle64(void); 5 | void wait_cycles(uint32_t cycles); 6 | void wait_ms(uint32_t ms); 7 | void wait_us(uint32_t us); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /sw/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "riscv.h" 5 | #include "reg.h" 6 | #include "top_defines.h" 7 | #include "lib.h" 8 | 9 | //#define REVERSE_DIR 10 | 11 | void wait_led_cycle(int ms) 12 | { 13 | if (REG_RD_FIELD(STATUS, SIMULATION) == 1){ 14 | // Wait for a much shorter time when simulation... 15 | wait_cycles(100); 16 | } 17 | else{ 18 | wait_ms(ms); 19 | } 20 | } 21 | 22 | int main() 23 | { 24 | while(1){ 25 | int wait_time = REG_RD_FIELD(STATUS, BUTTON) ? 200 : 100; 26 | #ifdef REVERSE_DIR 27 | REG_WR(LED_CONFIG, 0x04); 28 | wait_led_cycle(wait_time); 29 | 30 | REG_WR(LED_CONFIG, 0x02); 31 | wait_led_cycle(wait_time); 32 | 33 | REG_WR(LED_CONFIG, 0x01); 34 | wait_led_cycle(wait_time); 35 | #else 36 | REG_WR(LED_CONFIG, 0x01); 37 | wait_led_cycle(wait_time); 38 | 39 | REG_WR(LED_CONFIG, 0x02); 40 | wait_led_cycle(wait_time); 41 | 42 | REG_WR(LED_CONFIG, 0x04); 43 | wait_led_cycle(wait_time); 44 | #endif 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sw/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef REG_H 2 | #define REG_H 3 | 4 | #define REG_WR(reg_name, wr_data) (*((volatile uint32_t *)(0x80000000 | reg_name##_ADDR)) = (wr_data)) 5 | #define REG_RD(reg_name) (*((volatile uint32_t *)(0x80000000 | reg_name##_ADDR))) 6 | 7 | #define FIELD_MASK(reg_name, field_name) ( ((1<<(reg_name##_##field_name##_FIELD_LENGTH))-1) << (reg_name##_##field_name##_FIELD_START)) 8 | 9 | #define REG_WR_FIELD(reg_name, field_name, wr_data) (*((volatile uint32_t *)(0x80000000 | reg_name##_ADDR)) = \ 10 | ((REG_RD(reg_name) \ 11 | & ~FIELD_MASK(reg_name, field_name)) \ 12 | | (((wr_data)<<(reg_name##_##field_name##_FIELD_START)) & FIELD_MASK(reg_name, field_name)))) 13 | 14 | #define REG_RD_FIELD(reg_name, field_name) ((REG_RD(reg_name) & FIELD_MASK(reg_name, field_name)) >> (reg_name##_##field_name##_FIELD_START)) 15 | 16 | #define MEM_WR(mem_name, wr_addr, wr_data) (*( (volatile uint32_t *)(0x80000000 | mem_name##_ADDR) + (wr_addr)) = (wr_data)) 17 | 18 | #define MEM_RD(mem_name, rd_addr) (*((volatile uint32_t *)((0x80000000 | mem_name##_ADDR) + ((rd_addr) << 2)))) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /sw/riscv.h: -------------------------------------------------------------------------------- 1 | #ifndef RISCV_H 2 | #define RISCV_H 3 | 4 | //exceptions 5 | #define CAUSE_ILLEGAL_INSTRUCTION 2 6 | #define CAUSE_MACHINE_TIMER 7 7 | #define CAUSE_SCALL 9 8 | 9 | //interrupts 10 | #define CAUSE_MACHINE_EXTERNAL 11 11 | 12 | 13 | #define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) 14 | #define MEDELEG_LOAD_PAGE_FAULT (1 << 13) 15 | #define MEDELEG_STORE_PAGE_FAULT (1 << 15) 16 | #define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8) 17 | #define MIDELEG_SUPERVISOR_SOFTWARE (1 << 1) 18 | #define MIDELEG_SUPERVISOR_TIMER (1 << 5) 19 | #define MIDELEG_SUPERVISOR_EXTERNAL (1 << 9) 20 | 21 | #define MIP_STIP (1 << 5) 22 | #define MIE_MTIE (1 << CAUSE_MACHINE_TIMER) 23 | #define MIE_MEIE (1UL << CAUSE_MACHINE_EXTERNAL) 24 | 25 | #define MSTATUS_UIE 0x00000001UL 26 | #define MSTATUS_SIE 0x00000002UL 27 | #define MSTATUS_HIE 0x00000004UL 28 | #define MSTATUS_MIE 0x00000008UL 29 | #define MSTATUS_UPIE 0x00000010UL 30 | #define MSTATUS_SPIE 0x00000020UL 31 | #define MSTATUS_HPIE 0x00000040UL 32 | #define MSTATUS_MPIE 0x00000080UL 33 | #define MSTATUS_SPP 0x00000100UL 34 | #define MSTATUS_HPP 0x00000600UL 35 | #define MSTATUS_MPP 0x00001800UL 36 | #define MSTATUS_FS 0x00006000UL 37 | #define MSTATUS_XS 0x00018000UL 38 | #define MSTATUS_MPRV 0x00020000UL 39 | #define MSTATUS_SUM 0x00040000UL 40 | #define MSTATUS_MXR 0x00080000UL 41 | #define MSTATUS_TVM 0x00100000UL 42 | #define MSTATUS_TW 0x00200000UL 43 | #define MSTATUS_TSR 0x00400000UL 44 | #define MSTATUS32_SD 0x80000000UL 45 | #define MSTATUS_UXL 0x0000000300000000U 46 | #define MSTATUS_SXL 0x0000000C00000000U 47 | #define MSTATUS64_SD 0x8000000000000000U 48 | 49 | #define SSTATUS_UIE 0x00000001UL 50 | #define SSTATUS_SIE 0x00000002UL 51 | #define SSTATUS_UPIE 0x00000010UL 52 | #define SSTATUS_SPIE 0x00000020UL 53 | #define SSTATUS_SPP 0x00000100UL 54 | #define SSTATUS_FS 0x00006000UL 55 | #define SSTATUS_XS 0x00018000UL 56 | #define SSTATUS_SUM 0x00040000UL 57 | #define SSTATUS_MXR 0x00080000UL 58 | #define SSTATUS32_SD 0x80000000UL 59 | #define SSTATUS_UXL 0x0000000300000000U 60 | #define SSTATUS64_SD 0x8000000000000000U 61 | 62 | 63 | #define PMP_R 0x01 64 | #define PMP_W 0x02 65 | #define PMP_X 0x04 66 | #define PMP_A 0x18 67 | #define PMP_L 0x80 68 | #define PMP_SHIFT 2 69 | 70 | #define PMP_TOR 0x08 71 | #define PMP_NA4 0x10 72 | #define PMP_NAPOT 0x18 73 | 74 | #define MSCRATCH 0x340 75 | #define MCAUSE 0x342 76 | #define MEPC 0x341 77 | #define MEPC 0x341 78 | #define MTVAL 0x343 79 | 80 | #define RDCYCLE 0xC00 81 | #define RDTIME 0xC01 82 | #define RDINSTRET 0xC02 83 | #define RDCYCLEH 0xC80 84 | #define RDTIMEH 0xC81 85 | #define RDINSTRETH 0xC82 86 | 87 | 88 | #define csr_swap(csr, val) \ 89 | ({ \ 90 | uint32_t __v = (uint32_t)(val); \ 91 | __asm__ __volatile__ ("csrrw %0, " #csr ", %1" \ 92 | : "=r" (__v) : "rK" (__v)); \ 93 | __v; \ 94 | }) 95 | 96 | #define csr_read(csr) \ 97 | ({ \ 98 | uint32_t __v; \ 99 | __asm__ __volatile__ ("csrr %0, " #csr \ 100 | : "=r" (__v)); \ 101 | __v; \ 102 | }) 103 | 104 | #define csr_write(csr, val) \ 105 | { \ 106 | uint32_t __v = (uint32_t)(val); \ 107 | __asm__ __volatile__ ("csrw " #csr ", %0" \ 108 | : : "rK" (__v)); \ 109 | } 110 | 111 | #define csr_read_set(csr, val) \ 112 | ({ \ 113 | uint32_t __v = (uint32_t)(val); \ 114 | __asm__ __volatile__ ("csrrs %0, " #csr ", %1" \ 115 | : "=r" (__v) : "rK" (__v)); \ 116 | __v; \ 117 | }) 118 | 119 | #define csr_set(csr, val) \ 120 | { \ 121 | uint32_t __v = (uint32_t)(val); \ 122 | __asm__ __volatile__ ("csrs " #csr ", %0" \ 123 | : : "rK" (__v)); \ 124 | } 125 | 126 | #define csr_read_clear(csr, val) \ 127 | ({ \ 128 | uint32_t __v = (uint32_t)(val); \ 129 | __asm__ __volatile__ ("csrrc %0, " #csr ", %1" \ 130 | : "=r" (__v) : "rK" (__v)); \ 131 | __v; \ 132 | }) 133 | 134 | #define csr_clear(csr, val) \ 135 | { \ 136 | uint32_t __v = (uint32_t)(val); \ 137 | __asm__ __volatile__ ("csrc " #csr ", %0" \ 138 | : : "rK" (__v)); \ 139 | } 140 | 141 | 142 | 143 | #endif 144 | 145 | 146 | -------------------------------------------------------------------------------- /sw/sections.lds: -------------------------------------------------------------------------------- 1 | 2 | MEMORY 3 | { 4 | ram (ax) : ORIGIN = 0x00000000, LENGTH = 2K 5 | } 6 | 7 | SECTIONS 8 | { 9 | .text : 10 | { 11 | start.o(.text*) 12 | *(.text*) 13 | } > ram 14 | 15 | .rodata ALIGN(4) : 16 | { 17 | *(.rodata*) 18 | *(.srodata*) 19 | } > ram 20 | 21 | .data ALIGN (8) : 22 | { 23 | *(.data*) 24 | *(.sdata*) 25 | } > ram 26 | 27 | .bss ALIGN(8) (NOLOAD) : 28 | { 29 | *(.bss*) 30 | *(.sbss*) 31 | *(COMMON) 32 | } > ram 33 | 34 | _end = .; 35 | } 36 | -------------------------------------------------------------------------------- /sw/start.S: -------------------------------------------------------------------------------- 1 | .section .text 2 | .global _start 3 | .global main 4 | 5 | .org 0x00000000 6 | _start: 7 | j _start_continue 8 | 9 | .org 0x00000020 10 | _trap: 11 | j _trap 12 | 13 | 14 | _start_continue: 15 | /* set stack pointer */ 16 | li sp,2048 17 | 18 | /* jump to main C code */ 19 | jal ra,main 20 | 21 | /* trap */ 22 | ebreak 23 | 24 | -------------------------------------------------------------------------------- /sw/top_defines.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TOP_DEFINES_H 3 | #define TOP_DEFINES_H 4 | 5 | //============================================================ 6 | // LED 7 | //============================================================ 8 | 9 | #define LED_CONFIG_ADDR 0x00000000 10 | 11 | #define LED_CONFIG_VALUE_FIELD_START 0 12 | #define LED_CONFIG_VALUE_FIELD_LENGTH 3 13 | 14 | //============================================================ 15 | // STATUS 16 | //============================================================ 17 | 18 | #define STATUS_ADDR 0x00000004 19 | 20 | #define STATUS_BUTTON_FIELD_START 0 21 | #define STATUS_BUTTON_FIELD_LENGTH 1 22 | 23 | #define STATUS_SIMULATION_FIELD_START 1 24 | #define STATUS_SIMULATION_FIELD_LENGTH 1 25 | 26 | #endif 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /sw/vexriscv_init.cfg: -------------------------------------------------------------------------------- 1 | 2 | set _ENDIAN little 3 | set _TAP_TYPE 1234 4 | 5 | if { [info exists CPUTAPID] } { 6 | set _CPUTAPID $CPUTAPID 7 | } else { 8 | # set useful default 9 | set _CPUTAPID 0x10001fff 10 | } 11 | 12 | set _CHIPNAME vexrisc_ocd 13 | 14 | # The JTAG TAP itself is given the name "bridge", because it refers to the 15 | # JtagBridge that's part of the VexRiscv/SpinalHDL debug infrastructure. 16 | # In the example design, there is the JtagBridge controls a single CPU, but 17 | # the capability is there for 1 JTAG TAP + JtagBridge to control multiple 18 | # VexRiscv CPUs. 19 | jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 4 -ircapture 0x1 -irmask 0xF 20 | 21 | # There is 1 CPU controlled by the "bridge" JTAG TAP, "cpu0" 22 | target create $_CHIPNAME.cpu0 vexriscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge 23 | 24 | # The JtagBridge/SystemDebugger receives commands in a serialized way. It gets synchronized into 25 | # a parallel bus, and a response is received. Along the way, there may be various clock domain 26 | # crossings or pipeline delays. 27 | # readWaitCycles instructs OpenOCD to insert idle JTAG clock cycles before shifting out 28 | # the response. 29 | # There aren't many transactions where read-back throughput is important, so there's little 30 | # points in lowballing this number. 31 | vexriscv readWaitCycles 10 32 | 33 | # When the Verilog of a SpinalHDL design with one or more VexRiscv CPUs is created, the system 34 | # also creates a .yaml file with information that's sideband information that's important for 35 | # OpenOCD to control the CPU correctly. 36 | # A good example of this are the number of hardware breakpoints that are supported by the CPU. 37 | vexriscv cpuConfigFile ../spinal/VexRiscvWithDebug.yaml 38 | 39 | # The rate at which OpenOCD polls active JTAG TAPs to check if there has been a notable 40 | # event. (E.g. to check if the CPU has hit a breakpoint.) 41 | # For some reason, making this number really low has an impact on the CPU while semihosting is 42 | # enabled? 43 | poll_period 50 44 | 45 | # Initialize all JTAG TAPs and targets. 46 | init 47 | 48 | echo "Halting processor" 49 | 50 | # Halts the CPU and issue a soft reset. 51 | # The DebugPlugin has a resetOut signal that can be used reset external logic. It is not 52 | # used to reset anything inside the VexRiscv itself though. In our small example, 53 | # resetOut is not connected to anything, so we could have used "halt" instead. 54 | soft_reset_halt 55 | 56 | sleep 1000 57 | 58 | -------------------------------------------------------------------------------- /tb/.gitignore: -------------------------------------------------------------------------------- 1 | *.vcd 2 | tb 3 | -------------------------------------------------------------------------------- /tb/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | VERILOG_FILES = tb.v ../rtl/top.v ../rtl/VexRiscv.v 4 | SW_FILES = ../sw/progmem0.hex 5 | 6 | all: ./tb $(SW_FILES) 7 | ./tb 8 | 9 | waves: 10 | gtkwave waves.vcd 11 | 12 | ./tb: $(VERILOG_FILES) 13 | iverilog -D SIMULATION=1 -o $@ $(VERILOG_FILES) 14 | 15 | $(SW_FILES): 16 | cd ../sw && make 17 | 18 | clean: 19 | \rm -fr *.vcd ./tb 20 | 21 | -------------------------------------------------------------------------------- /tb/tb.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns/100ps 3 | 4 | module tb; 5 | 6 | reg clk = 0; 7 | 8 | always begin 9 | clk=0; 10 | #50; 11 | clk=1; 12 | #50; 13 | end 14 | 15 | initial begin 16 | $dumpfile("waves.vcd"); 17 | $dumpvars(); 18 | repeat(1000) @(posedge clk); 19 | $finish; 20 | end 21 | 22 | wire led0, led1, led2, button; 23 | 24 | assign button = 1'b1; 25 | 26 | top u_top( 27 | .clk(clk), 28 | .led0(led0), 29 | .led1(led1), 30 | .led2(led2), 31 | .button(button) 32 | ); 33 | 34 | reg led0_d, led1_d, led2_d; 35 | 36 | always @(posedge clk) begin 37 | if (led0 != led0_d) begin 38 | $display("%d: led0 changed to %d", $time, led0); 39 | end 40 | if (led1 != led1_d) begin 41 | $display("%d: led1 changed to %d", $time, led1); 42 | end 43 | if (led2 != led2_d) begin 44 | $display("%d: led2 changed to %d", $time, led2); 45 | end 46 | 47 | led0_d <= led0; 48 | led1_d <= led1; 49 | led2_d <= led2; 50 | end 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /tb/waves.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.90 (w)1999-2018 BSI 3 | [*] Thu Apr 22 06:26:36 2021 4 | [*] 5 | [dumpfile] "/home/tom/projects/vexriscv_ocd/verilog_example/tb/waves.vcd" 6 | [dumpfile_mtime] "Thu Apr 22 06:26:34 2021" 7 | [dumpfile_size] 825112 8 | [savefile] "/home/tom/projects/vexriscv_ocd/verilog_example/tb/waves.gtkw" 9 | [timestart] 20583100 10 | [size] 2541 1336 11 | [pos] -1 -1 12 | *-17.000000 21195800 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.u_top. 15 | [treeopen] tb.u_top.u_vex. 16 | [treeopen] tb.u_top.u_vex.cpu. 17 | [sst_width] 484 18 | [signals_width] 443 19 | [sst_expanded] 1 20 | [sst_vpaned_height] 865 21 | @28 22 | tb.u_top.u_vex.clk 23 | @200 24 | - 25 | @28 26 | tb.u_top.led0 27 | tb.u_top.led1 28 | tb.u_top.led2 29 | tb.u_top.u_vex.cpu.DebugPlugin_allowEBreak 30 | tb.u_top.u_vex.cpu.DebugPlugin_haltedByBreak 31 | @200 32 | - 33 | @800200 34 | -iBus 35 | @28 36 | tb.u_top.u_vex.io_iBus_cmd_valid 37 | @22 38 | tb.u_top.u_vex.io_iBus_cmd_payload_pc[31:0] 39 | @8022 40 | tb.u_top.u_vex.io_iBus_cmd_payload_pc[31:0] 41 | @200 42 | - 43 | @28 44 | tb.u_top.u_vex.io_iBus_rsp_valid 45 | @22 46 | tb.u_top.u_vex.io_iBus_rsp_payload_inst[31:0] 47 | @1000200 48 | -iBus 49 | @200 50 | - 51 | @800200 52 | -dBus 53 | @28 54 | tb.u_top.u_vex.cpu.dBus_cmd_valid 55 | @22 56 | tb.u_top.u_vex.cpu.dBus_cmd_payload_address[31:0] 57 | @28 58 | tb.u_top.u_vex.cpu.dBus_cmd_payload_wr 59 | @22 60 | tb.u_top.u_vex.cpu.dBus_cmd_payload_data[31:0] 61 | @28 62 | tb.u_top.u_vex.cpu.dBus_cmd_payload_size[1:0] 63 | @200 64 | - 65 | @28 66 | tb.u_top.u_vex.cpu.dBus_rsp_ready 67 | @22 68 | tb.u_top.u_vex.cpu.dBus_rsp_data[31:0] 69 | @1000200 70 | -dBus 71 | @28 72 | tb.u_top.u_vex.cpu.decode_IS_EBREAK 73 | tb.u_top.u_vex.cpu.decode_DO_EBREAK 74 | tb.u_top.u_vex.cpu.execute_DO_EBREAK 75 | @200 76 | - 77 | - 78 | @28 79 | tb.u_top.u_vex.cpu.execute_arbitration_isValid 80 | tb.u_top.u_vex.cpu.execute_arbitration_isFiring 81 | tb.u_top.u_vex.cpu.execute_arbitration_haltItself 82 | tb.u_top.u_vex.cpu.DebugPlugin_haltIt 83 | tb.u_top.u_vex.cpu.DebugPlugin_haltedByBreak 84 | @200 85 | - 86 | @28 87 | tb.u_top.u_vex.cpu.DebugPlugin_allowEBreak 88 | @22 89 | tb.u_top.u_vex.cpu.DebugPlugin_busReadDataReg[31:0] 90 | @28 91 | tb.u_top.u_vex.cpu.DebugPlugin_firstCycle 92 | tb.u_top.u_vex.cpu.DebugPlugin_godmode 93 | tb.u_top.u_vex.cpu.DebugPlugin_haltIt 94 | tb.u_top.u_vex.cpu.DebugPlugin_haltedByBreak 95 | tb.u_top.u_vex.cpu.DebugPlugin_isPipBusy 96 | tb.u_top.u_vex.cpu.DebugPlugin_resetIt 97 | tb.u_top.u_vex.cpu.DebugPlugin_resetIt_regNext 98 | @29 99 | tb.u_top.u_vex.cpu.DebugPlugin_secondCycle 100 | @28 101 | tb.u_top.u_vex.cpu.DebugPlugin_stepIt 102 | @200 103 | - 104 | @28 105 | tb.u_top.u_vex.cpu.CsrPlugin_selfException_valid 106 | @22 107 | tb.u_top.u_vex.cpu.CsrPlugin_selfException_payload_code[3:0] 108 | @200 109 | - 110 | @28 111 | tb.u_top.u_vex.cpu.execute_arbitration_flushIt 112 | tb.u_top.u_vex.cpu.execute_arbitration_flushNext 113 | tb.u_top.u_vex.cpu.execute_arbitration_haltByOther 114 | tb.u_top.u_vex.cpu.execute_arbitration_haltItself 115 | tb.u_top.u_vex.cpu.execute_arbitration_isFiring 116 | tb.u_top.u_vex.cpu.execute_arbitration_isFlushed 117 | tb.u_top.u_vex.cpu.execute_arbitration_isMoving 118 | tb.u_top.u_vex.cpu.execute_arbitration_isStuck 119 | tb.u_top.u_vex.cpu.execute_arbitration_isStuckByOthers 120 | tb.u_top.u_vex.cpu.execute_arbitration_isValid 121 | tb.u_top.u_vex.cpu.execute_arbitration_removeIt 122 | @200 123 | - 124 | @22 125 | tb.u_top.u_vex.cpu.CsrPlugin_mtval[31:0] 126 | tb.u_top.u_vex.cpu.CsrPlugin_mepc[31:0] 127 | [pattern_trace] 1 128 | [pattern_trace] 0 129 | --------------------------------------------------------------------------------