basic structure of tests in place Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
diff --git a/.gitignore b/.gitignore index 0a1f620..c5d161b 100644 --- a/.gitignore +++ b/.gitignore
@@ -2,4 +2,6 @@ packages/ simv.* obj_dir/ +__pycache__/ +verilog/gl/
diff --git a/README.md b/README.md index 110acfb..fb112a1 100644 --- a/README.md +++ b/README.md
@@ -1,2 +1,113 @@ -# open_mpw_user_project -Test project for the Open MPW shuttle +# FWPayload + +FWPayload is a small processor+peripherals subsystem, targeting the user-project +area of Caraval. + +## Block diagram + + + +## External IP +FWPayload uses several pieces of external IP. Some are bundled with the project, +and some are fetched during the initialization step. + +### FWRISC +RISC-V core originally targeted for FPGA application +- Git: https://github.com/mballance/fwrisc.git +- License: Apache 2.0 + +### fw-wishbone-interconnect +Parameterized Wishbone interconnect +- Git: https://github.com/featherweight-ip/fw-wishbone-interconnect +- License: Apache 2.0 + +### simple_spi_master +SPI master IP, obtained from the Caravel repository. Bundled with the project. +- License: GNU LGPL + +### simpleuart +UART IP, obtained from the Caravel repository. Bundled with the project. +- License: BSD-style + + +## Memory map + +The FWPayload memory map is designed to fit within the 28-bit user-area +portion of the Caravel memory map. + +- *0xX000_0000..0xX000_03FF* - 1Kb register RAM +- *0xX100_0000..0xX100_00FF* - UART +- *0xX100_0100..0xX100_01FF* - SPI +- *0xX100_0200..0xX100_02FF* - GPIO + +## Pin map + +## Bring-up/Debug Support + +FWPayload uses the Caravel logic analyzer to configure reset and clocking, +probe the program counter of the FWRISC, and optionally, single-step the clock. + +- [127] - Controls the clock when configured as an output +- [126] - Controls the system reset when configured as an output +- [125] - Controls the FWRISC core reset when configured as an output +- [39:36] - Loopback, probing the GPIO output +- [33] - Loopback, probing UART tx output +- [32] - Input, probing the 'instruction-complete' FWRISC net +- [31:0] - Input, probing the FWRISC program-counter net + +# Developer Notes + +## Required Tools +- Python 3 (3.6.8 was used) +- Icarus Verilog (11.0 was used) +- Verilator (4.102 was used) +- Openlane (rc4 was used) +- Skywater PDK (PDK_ROOT is assumed to be properly set) + +## Project Setup +The FWPayload project uses IVPM (IP and Verification Package Manager) to manage +external IP and Python dependencies. The project can be setup both with and +without IVPM installed. + +In both cases, setting up the project will result in creation of a `packages` +directory within the project that contains external IPs and required Python +packages. + +### Setup with IVPM installed +Ensure IVPM is installed: + +``` +% pip3 install ivpm --user --upgrade +``` + +``` +% cd <fwpayload_dir> +% ivpm update +``` + +### Setup without IVPM installed +The project can also be setup without installing IVPM. The `bootstrap.sh` +script is provided for this purpose. `bootstrap.sh` clones a local +copy of ivpm. + +``` +% cd <fwpayload_dir> +% ./bootstrap.sh +``` + + +## Integration Testing + + +## Current Status +Openlane completes with the following status: + +``` +Number of pins violated: 479 +Number of nets violated: 297 +Total number of nets: 44367 +[INFO]: Generating Final Summary Report... +[SUCCESS]: Flow Completed Without Fatal Errors. +``` + +
diff --git a/doc/images/fwpayload_diagram.png b/doc/images/fwpayload_diagram.png new file mode 100644 index 0000000..b62b6a6 --- /dev/null +++ b/doc/images/fwpayload_diagram.png Binary files differ
diff --git a/dv/bringup/.gitignore b/dv/bringup/.gitignore new file mode 100644 index 0000000..a8689d9 --- /dev/null +++ b/dv/bringup/.gitignore
@@ -0,0 +1,3 @@ + +pybfms_gen* +
diff --git a/dv/bringup/Makefile b/dv/bringup/Makefile index edbc363..7ff1b89 100644 --- a/dv/bringup/Makefile +++ b/dv/bringup/Makefile
@@ -8,13 +8,18 @@ #******************************************************************** FWRISC_SRCS = $(wildcard $(FWRISC_RTL_DIR)/*.sv) INCDIRS += $(FWRISC_RTL_DIR) +INCDIRS += $(PACKAGES_DIR)/fwprotocol-defs/src/sv DEFINES += MPRJ_IO_PADS=38 PYBFMS_MODULES += wishbone_bfms logic_analyzer_bfms SRCS += $(RTL_DIR)/fwpayload.v $(RTL_DIR)/user_project_wrapper.v -SRCS += $(RTL_DIR)/wb_interconnect_NxN.sv +SRCS += $(PACKAGES_DIR)/fw-wishbone-interconnect/verilog/rtl/wb_interconnect_NxN.v +SRCS += $(PACKAGES_DIR)/fw-wishbone-interconnect/verilog/rtl/wb_interconnect_arb.v SRCS += $(RTL_DIR)/spram_32x256.sv +SRCS += $(RTL_DIR)/spram_32x512.sv SRCS += $(RTL_DIR)/spram.v +SRCS += $(RTL_DIR)/simple_spi_master.v +SRCS += $(RTL_DIR)/simpleuart.v SRCS += $(FWRISC_SRCS) TOP_MODULE = bringup_tb
diff --git a/dv/bringup/python/bringup_tests/__pycache__/mgmt_mem_access.cpython-36.pyc b/dv/bringup/python/bringup_tests/__pycache__/mgmt_mem_access.cpython-36.pyc deleted file mode 100644 index ca45710..0000000 --- a/dv/bringup/python/bringup_tests/__pycache__/mgmt_mem_access.cpython-36.pyc +++ /dev/null Binary files differ
diff --git a/dv/bringup/python/bringup_tests/la_utils.py b/dv/bringup/python/bringup_tests/la_utils.py index e3c63b3..c0f996b 100644 --- a/dv/bringup/python/bringup_tests/la_utils.py +++ b/dv/bringup/python/bringup_tests/la_utils.py
@@ -5,9 +5,11 @@ ''' class LaUtils(object): - CLOCK_IDX = 127 - RESET_IDX = 126 + CLOCK_IDX = 127 + RESET_IDX = 126 CORE_RESET_IDX = 125 + PC_IDX = 0 + GPIO_OUT_IDX = 36 def __init__(self, la_bfm): self.la_bfm = la_bfm
diff --git a/dv/bringup/python/bringup_tests/mgmt_mem_access.py b/dv/bringup/python/bringup_tests/mgmt_mem_access.py index 1937cc8..c265bd4 100644 --- a/dv/bringup/python/bringup_tests/mgmt_mem_access.py +++ b/dv/bringup/python/bringup_tests/mgmt_mem_access.py
@@ -50,6 +50,23 @@ else: print("FAIL: " + hex(0x80000000+4*i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + # Load a short program that toggles the GPIO lines + gpio_toggle_program = [ + 0x010000b7, + 0x20008093, + 0x00000113, + 0x0020a023, + 0x00110113, + 0xff9ff06f, + 0x00000000] + + for i,data in enumerate(gpio_toggle_program): + print("Write: " + hex(0x30000000+4*i) + " " + hex(data)) + await u_wb.write(0x30000000+4*i, data, 0xF) + + # Take back clock control + await la_utils.set_dut_clock_control(True) + # Release the processor from reset await la_utils.set_core_reset(True) for i in range(10): @@ -57,5 +74,6 @@ await la_utils.set_core_reset(False) for i in range(1000): - await u_la.propagate() + await la_utils.clock_dut() + \ No newline at end of file
diff --git a/dv/common/defs_rules.mk b/dv/common/defs_rules.mk new file mode 100644 index 0000000..7d87f53 --- /dev/null +++ b/dv/common/defs_rules.mk
@@ -0,0 +1,58 @@ + +COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) + +ifneq (1,$(RULES)) +RTL_DIR := $(abspath $(COMMON_DIR)/../../verilog/rtl) +GL_DIR := $(abspath $(COMMON_DIR)/../../verilog/gl) +PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) +SIM ?= icarus +SIMTYPE ?= functional + + +PYBFMS_MODULES += wishbone_bfms logic_analyzer_bfms +VLSIM_CLKSPEC += -clkspec clk=10ns + +TOP_MODULE ?= fwpayload_tb +TB_SRCS ?= $(COMMON_DIR)/sv/fwpayload_tb.sv + +PYTHONPATH := $(COMMON_DIR)/python:$(PYTHONPATH) +export PYTHONPATH + +PATH := $(PACKAGES_DIR)/python/bin:$(PATH) +export PATH + +#******************************************************************** +#* Source setup +#******************************************************************** +FWRISC_SRCS = $(wildcard $(PACKAGES_DIR)/fwrisc/rtl/*.sv) +INCDIRS += $(PACKAGES_DIR)/fwrisc/rtl +INCDIRS += $(PACKAGES_DIR)/fwprotocol-defs/src/sv + +DEFINES += MPRJ_IO_PADS=38 + +ifeq (gate,$(SIMTYPE)) +SRCS += $(GL_DIR)/fwpayload.v +else +SRCS += $(RTL_DIR)/fwpayload.v +SRCS += $(PACKAGES_DIR)/fw-wishbone-interconnect/verilog/rtl/wb_interconnect_NxN.v +SRCS += $(PACKAGES_DIR)/fw-wishbone-interconnect/verilog/rtl/wb_interconnect_arb.v +SRCS += $(RTL_DIR)/spram_32x256.sv +SRCS += $(RTL_DIR)/spram_32x512.sv +SRCS += $(RTL_DIR)/spram.v +SRCS += $(RTL_DIR)/simple_spi_master.v +SRCS += $(RTL_DIR)/simpleuart.v +SRCS += $(FWRISC_SRCS) +endif +SRCS += $(TB_SRCS) + +include $(COMMON_DIR)/$(SIM).mk + +else # Rules + +clean :: + rm -f results.xml + +include $(COMMON_DIR)/$(SIM).mk +include $(wildcard $(COMMON_DIR)/*_clean.mk) + +endif \ No newline at end of file
diff --git a/dv/common/icarus.mk b/dv/common/icarus.mk index d9b319c..9ff0b03 100644 --- a/dv/common/icarus.mk +++ b/dv/common/icarus.mk
@@ -14,6 +14,8 @@ #**************************************************************************** COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) + +ifneq (1,$(RULES)) PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) VLSIM := $(PACKAGES_DIR)/python/bin/vlsim PYBFMS_VPI_LIB := $(shell $(PACKAGES_DIR)/python/bin/pybfms lib) @@ -54,6 +56,8 @@ VPI_LIBS += $(PYBFMS_VPI_LIB) VPI_LIBS += $(COCOTB_PREFIX)/cocotb/libs/libcocotbvpi_icarus.vpl +else # Rules + build : $(SIMV) $(SIMV) : $(SRCS) pybfms_gen.v @@ -66,6 +70,4 @@ $(PACKAGES_DIR)/python/bin/pybfms generate \ -l vlog $(foreach m,$(PYBFMS_MODULES),-m $(m)) -o $@ -clean :: - rm -f simv.* simx.fst simx.vcd pybfms_gen.v - rm -rf obj_dir +endif
diff --git a/dv/common/icarus_clean.mk b/dv/common/icarus_clean.mk new file mode 100644 index 0000000..3dccc2d --- /dev/null +++ b/dv/common/icarus_clean.mk
@@ -0,0 +1,9 @@ +#**************************************************************************** +#* icarus_clean.mk +#* +#* Clean target for Icarus Verilog +#**************************************************************************** + +clean :: + rm -f simv.* simx.fst simx.vcd pybfms_gen.v + rm -rf obj_dir
diff --git a/dv/common/python/fwpayload_tests/la_utils.py b/dv/common/python/fwpayload_tests/la_utils.py new file mode 100644 index 0000000..c0f996b --- /dev/null +++ b/dv/common/python/fwpayload_tests/la_utils.py
@@ -0,0 +1,59 @@ +''' +Created on Nov 22, 2020 + +@author: mballance +''' + +class LaUtils(object): + CLOCK_IDX = 127 + RESET_IDX = 126 + CORE_RESET_IDX = 125 + PC_IDX = 0 + GPIO_OUT_IDX = 36 + + def __init__(self, la_bfm): + self.la_bfm = la_bfm + + async def set_dut_clock_control(self, en): + # First, set reset high and clock low + await self.la_bfm.set_bits(LaUtils.RESET_IDX, 0, 1) + await self.la_bfm.set_bits(LaUtils.CLOCK_IDX, 0, 1) + + if en: + # Now, set output mode for these signals + await self.la_bfm.set_oen(LaUtils.RESET_IDX, 0, 1) + await self.la_bfm.set_oen(LaUtils.CLOCK_IDX, 0, 1) + else: + # Now, set input mode for these signals + await self.la_bfm.set_oen(LaUtils.RESET_IDX, 1, 1) + await self.la_bfm.set_oen(LaUtils.CLOCK_IDX, 1, 1) + + async def set_core_reset(self, en): + if en: + await self.la_bfm.set_bits(LaUtils.CORE_RESET_IDX, 0, 1) + else: + await self.la_bfm.set_bits(LaUtils.CORE_RESET_IDX, 1, 1) + + async def reset_cycle_dut(self, cycles=10): + # Set reset high + await self.la_bfm.set_bits(LaUtils.RESET_IDX, 0, 1) + await self.la_bfm.propagate() + + # Clock + for i in range(cycles): + await self.clock_dut() + + # Set reset low + await self.la_bfm.set_bits(LaUtils.RESET_IDX, 1, 1) + await self.clock_dut() + + pass + + async def clock_dut(self): + await self.la_bfm.set_bits(LaUtils.CLOCK_IDX, 1, 1) + await self.la_bfm.propagate() + await self.la_bfm.set_bits(LaUtils.CLOCK_IDX, 0, 1) + await self.la_bfm.propagate() + + + \ No newline at end of file
diff --git a/dv/common/python/fwpayload_tests/mgmt_mem_access.py b/dv/common/python/fwpayload_tests/mgmt_mem_access.py new file mode 100644 index 0000000..e6da439 --- /dev/null +++ b/dv/common/python/fwpayload_tests/mgmt_mem_access.py
@@ -0,0 +1,101 @@ +''' +Created on Nov 28, 2020 + +@author: mballance +''' + +import cocotb +import pybfms +from wishbone_bfms.wb_initiator_bfm import WbInitiatorBfm +from logic_analyzer_bfms.la_initiator_bfm import LaInitiatorBfm +from random import Random +from fwpayload_tests.la_utils import LaUtils + +@cocotb.test() +async def test(top): + """ + Hold the payload DUT in reset via the logic analyzer + Meanwhile, test that the management interface can access memory + """ + await pybfms.init() + u_wb : WbInitiatorBfm = pybfms.find_bfm(".*u_wb") + u_la : LaInitiatorBfm = pybfms.find_bfm(".*u_la") + + # Bring the system out of reset, while leaving the + # FWRISC core in reset + la_utils = LaUtils(u_la) + await la_utils.reset_cycle_dut(100) + await la_utils.set_dut_clock_control(False) + + # Test that we can write and read dut 'ROM' + n_fails = 0 + r = Random(0) + + # First, do word accesses + print("** Testing Word Accesses") + wr_data = [] + for i in range(16): + data = r.randint(0, 0xFFFFFFFF) + print("Write: " + hex(0x30000000+4*i) + " = " + hex(data)) + await u_wb.write(0x30000000 + 4*i, data, 0xF) + wr_data.append(data) + print("wr_data[" + str(i) + "] = " + hex(wr_data[i])) + + for i in range(16): + data = await u_wb.read(0x30000000 + 4*i) + if wr_data[i] == data: + print("PASS: " + hex(0x30000000+4*i)) + else: + print("FAIL: " + hex(0x30000000+4*i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + raise cocotb.result.TestError( + "Addr: " + hex(0x30000000+4*i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + n_fails += 1 + + # First, do word accesses + print("** Testing Half-word Accesses") + wr_data = [] + for i in range(32): + data = r.randint(0, 0xFFFF) + wr_data.append(data) + data <<= (16*(i%2)) + print("Write: " + hex(0x30000000+2*i) + " = " + hex(data)) + await u_wb.write(0x30000000 + 2*i, data, + 0x3 if (i%2) == 0 else 0xC) + print("wr_data[" + str(i) + "] = " + hex(wr_data[i])) + + for i in range(32): + data = await u_wb.read(0x30000000 + 2*i) + if (i%2) != 0: + data >>= 16 + data &= 0xFFFF + if wr_data[i] == data: + print("PASS: " + hex(0x30000000+2*i)) + else: + print("FAIL: " + hex(0x30000000+2*i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + raise cocotb.result.TestError( + "Addr: " + hex(0x30000000+2*i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + n_fails += 1 + + # First, do word accesses + print("** Testing Byte Accesses") + wr_data = [] + for i in range(64): + data = r.randint(0, 0xFF) + wr_data.append(data) + data <<= (8*(i%4)) + print("Write: " + hex(0x30000000+i) + " = " + hex(data)) + await u_wb.write(0x30000000 + i, data, (1 << (i%4))) + print("wr_data[" + str(i) + "] = " + hex(wr_data[i])) + + for i in range(64): + data = await u_wb.read(0x30000000 + i) + data >>= (8*(i%4)) + data &= 0xFF + if wr_data[i] == data: + print("PASS: " + hex(0x30000000+i)) + else: + print("FAIL: " + hex(0x30000000+i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + raise cocotb.result.TestError( + "Addr: " + hex(0x30000000+i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) + n_fails += 1 +
diff --git a/dv/common/questa.mk b/dv/common/questa.mk index e68ccba..d0532b9 100644 --- a/dv/common/questa.mk +++ b/dv/common/questa.mk
@@ -14,32 +14,36 @@ #* TIMEOUT - Simulation timeout, in units of ns,us,ms,s #**************************************************************************** +ifneq (1,$(RULES)) COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) +PYBFMS_DPI_LIB := $(subst .so,,$(shell $(PACKAGES_DIR)/python/bin/pybfms lib)) +COCOTB_PREFIX := $(shell $(PACKAGES_DIR)/python/bin/cocotb-config --prefix) -ifneq (,$(DEBUG)) -VLSIM_OPTIONS += --trace-fst -SIMV_ARGS += +vlsim.trace -SIMV := simv.debug -else -SIMV := simv.ndebug -endif +DPI_LIBS += $(PYBFMS_DPI_LIB) +VPI_LIBS += $(COCOTB_PREFIX)/cocotb/libs/libcocotbvpi_modelsim.so -# Enable VPI for Verilator -VLSIM_OPTIONS += --vpi --public-flat-rw +VLOG_OPTIONS += $(foreach inc,$(INCDIRS),+incdir+$(inc)) +VLOG_OPTIONS += $(foreach def,$(DEFINES),+define+$(def)) +VSIM_OPTIONS += $(foreach vpi,$(VPI_LIBS),-pli $(vpi)) +VSIM_OPTIONS += $(foreach dpi,$(DPI_LIBS),-sv_lib $(dpi)) -VLSIM_OPTIONS += $(foreach inc,$(INCDIRS),+incdir+$(inc)) -VLSIM_OPTIONS += $(foreach def,$(DEFINES),+define+$(def)) -SIMV_ARGS += $(foreach vpi,$(VPI_LIBS),+vpi=$(vpi)) +SRCS += pybfms_gen.sv pybfms_gen.c -build : $(SIMV) +else # Rules -$(SIMV) : $(SRCS) - $(VLSIM) -o $@ $(VLSIM_CLKSPEC) $(VLSIM_OPTIONS) $(SRCS) +build : $(SRCS) + vlib work + vlog $(VLOG_OPTIONS) $(SRCS) + vopt -o $(TOP_MODULE)_opt $(TOP_MODULE) -run : $(SIMV) - ./$(SIMV) $(SIMV_ARGS) -clean :: - rm -f simv.* simx.fst simx.vcd - rm -rf obj_dir +run : build + vsim -batch -do "run $(TIMEOUT); quit -f" \ + $(VSIM_OPTIONS) $(TOP_MODULE)_opt + +pybfms_gen.sv pybfms_gen.c : + $(PACKAGES_DIR)/python/bin/pybfms generate \ + -l sv $(foreach m,$(PYBFMS_MODULES),-m $(m)) -o $@ + +endif \ No newline at end of file
diff --git a/dv/common/questa_clean.mk b/dv/common/questa_clean.mk new file mode 100644 index 0000000..dd44cdf --- /dev/null +++ b/dv/common/questa_clean.mk
@@ -0,0 +1,12 @@ +#**************************************************************************** +#* questa_target.mk +#* +#* Clean target for Mentor Questa +#* +#**************************************************************************** + +COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) + +clean :: + rm -rf work transcript modelsim.ini
diff --git a/dv/bringup/bringup_tb.sv b/dv/common/sv/fwpayload_tb.sv similarity index 90% rename from dv/bringup/bringup_tb.sv rename to dv/common/sv/fwpayload_tb.sv index 39e33f6..10266e3 100644 --- a/dv/bringup/bringup_tb.sv +++ b/dv/common/sv/fwpayload_tb.sv
@@ -1,5 +1,5 @@ /**************************************************************************** - * bringup_tb.sv + * fwpayload_tb.sv ****************************************************************************/ `ifdef IVERILOG `timescale 1ns/1ns @@ -9,11 +9,11 @@ `define MPRJ_IO_PADS 38 `endif /** - * Module: bringup_tb + * Module: fwpayload_tb * * TODO: Add module documentation */ -module bringup_tb(input clk); +module fwpayload_tb(input clk); `ifdef HAVE_HDL_CLOCKGEN reg clk_r = 0; @@ -33,7 +33,7 @@ initial begin if ($test$plusargs("dumpvars")) begin $dumpfile("simx.vcd"); - $dumpvars(0, bringup_tb); + $dumpvars(0, fwpayload_tb); end if (!$value$plusargs("timeout=%d", timeout)) begin timeout=1000; @@ -78,14 +78,14 @@ ) u_wb ( .clock(wb_clk_i), .reset(wb_rst_i), - .stb_o(wbs_stb_i), - .cyc_o(wbs_cyc_i), - .we_o(wbs_we_i), - .sel_o(wbs_sel_i), - .dat_o(wbs_dat_i), - .adr_o(wbs_adr_i), - .ack_i(wbs_ack_o), - .dat_i(wbs_dat_o) + .stb(wbs_stb_i), + .cyc(wbs_cyc_i), + .we(wbs_we_i), + .sel(wbs_sel_i), + .dat_w(wbs_dat_i), + .adr(wbs_adr_i), + .ack(wbs_ack_o), + .dat_r(wbs_dat_o) ); wire [127:0] la_data_in; @@ -110,7 +110,7 @@ wire user_clock2 = clock; - user_project_wrapper u_dut( + fwpayload u_dut( .vdda1(vdda1), // User area 1 3.3V supply .vdda2(vdda2), // User area 2 3.3V supply .vssa1(vssa1), // User area 1 analog ground @@ -140,8 +140,9 @@ // IOs .io_in(io_in), .io_out(io_out), - .io_oeb(io_oeb), + .io_oeb(io_oeb) + /* // Analog (direct connection to GPIO pad---use with caution) // Note that analog I/O is not available on the 7 lowest-numbered // GPIO pads, and so the analog_io indexing is offset from the @@ -150,6 +151,7 @@ // Independent clock (on independent integer divider) .user_clock2(user_clock2) + */ ); endmodule
diff --git a/dv/common/vlsim.mk b/dv/common/vlsim.mk index 20c6e77..f48611b 100644 --- a/dv/common/vlsim.mk +++ b/dv/common/vlsim.mk
@@ -16,6 +16,8 @@ #**************************************************************************** COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) + +ifneq (1,$(RULES)) PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) VLSIM := $(PACKAGES_DIR)/python/bin/vlsim PYBFMS_DPI_LIB := $(shell $(PACKAGES_DIR)/python/bin/pybfms lib) @@ -40,6 +42,8 @@ DPI_LIBS += $(PYBFMS_DPI_LIB) VPI_LIBS += $(COCOTB_PREFIX)/cocotb/libs/libcocotbvpi_verilator.so +else # Rules + build : $(SIMV) $(SIMV) : $(SRCS) pybfms_gen.sv pybfms_gen.c @@ -53,6 +57,4 @@ $(PACKAGES_DIR)/python/bin/pybfms generate \ -l sv $(foreach m,$(PYBFMS_MODULES),-m $(m)) -o $@ -clean :: - rm -f simv.* simx.fst simx.vcd pybfms_gen.sv pybfms_gen.c - rm -rf obj_dir +endif
diff --git a/dv/common/vlsim_clean.mk b/dv/common/vlsim_clean.mk new file mode 100644 index 0000000..689c6d6 --- /dev/null +++ b/dv/common/vlsim_clean.mk
@@ -0,0 +1,10 @@ +#**************************************************************************** +#* vlsim_clean.mk +#* +#* Clean target for Verilotor Vlsim +#* +#**************************************************************************** + +clean :: + rm -f simv.* simx.fst simx.vcd pybfms_gen.sv pybfms_gen.c + rm -rf obj_dir
diff --git a/dv/mgmt_mem_access/Makefile b/dv/mgmt_mem_access/Makefile new file mode 100644 index 0000000..0130c3e --- /dev/null +++ b/dv/mgmt_mem_access/Makefile
@@ -0,0 +1,21 @@ +TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) + +include $(TEST_DIR)/../common/defs_rules.mk + +#******************************************************************** +#* cocotb testbench setup +#******************************************************************** +PYTHONPATH := $(TEST_DIR):$(PYTHONPATH) +export PYTHONPATH + +MODULE=fwpayload_tests.mgmt_mem_access +export MODULE + +VLSIM_OPTIONS += -Wno-fatal --autoflush + +RULES := 1 + +all : run + +include $(TEST_DIR)/../common/defs_rules.mk +
diff --git a/etc/packages.mf b/etc/packages.mf index 482dac7..e0873b1 100644 --- a/etc/packages.mf +++ b/etc/packages.mf
@@ -1,4 +1,4 @@ fwrisc@https://github.com/mballance/fwrisc.git -wb_sys_ip@https://github.com/mballance/wb_sys_ip.git +fw-wishbone-interconnect@https://github.com/featherweight-ip/fw-wishbone-interconnect.git
diff --git a/openlane/Makefile b/openlane/Makefile new file mode 100644 index 0000000..bbfd5f9 --- /dev/null +++ b/openlane/Makefile
@@ -0,0 +1,63 @@ +#**************************************************************************** +#* +#**************************************************************************** +BLOCKS = $(shell find * -maxdepth 0 -type d) +CONFIG = $(foreach block,$(BLOCKS), ./$(block)/config.tcl) +CLEAN = $(foreach block,$(BLOCKS), clean-$(block)) + +OPENLANE_IMAGE_NAME ?= openlane:rc4 +OPENLANE_BASIC_COMMAND = "cd /project/openlane && flow.tcl -design ./$* -save_path .. -save -tag $* -overwrite" +OPENLANE_INTERACTIVE_COMMAND = "cd /project/openlane && flow.tcl -it -file ./$*/interactive.tcl" + +ifeq (,$(shell which podman)) +# Podman (CentOS8+) doesn't require user-spec options +USER_PERM_OPTIONS=-u $(shell id -u $(USER)):$(shell id -g $(USER)) +endif + +all: $(BLOCKS) + +$(CONFIG) : + @echo "Missing $@. Please create a configuration for that design" + @exit 1 + +$(BLOCKS) : % : ./%/config.tcl FORCE +ifeq ($(OPENLANE_ROOT),) + @echo "Please export OPENLANE_ROOT" + @exit 1 +endif +ifeq ($(PDK_ROOT),) + @echo "Please export PDK_ROOT" + @exit 1 +endif + @echo "###############################################" + @sleep 1 + + @if [[ -f ./$*/interactive.tcl ]]; then\ + docker run -it -v $(OPENLANE_ROOT):/openLANE_flow \ + -v $(PDK_ROOT):$(PDK_ROOT) \ + -v $(PWD)/..:/project \ + -e PDK_ROOT=$(PDK_ROOT) \ + $(USER_PERM_OPTIONS) \ + $(OPENLANE_IMAGE_NAME) sh -c $(OPENLANE_INTERACTIVE_COMMAND);\ + else\ + docker run -it -v $(OPENLANE_ROOT):/openLANE_flow \ + -v $(PDK_ROOT):$(PDK_ROOT) \ + -v $(PWD)/..:/project \ + -e PDK_ROOT=$(PDK_ROOT) \ + $(USER_PERM_OPTIONS) \ + $(OPENLANE_IMAGE_NAME) sh -c $(OPENLANE_BASIC_COMMAND);\ + fi + + +FORCE: + +clean: + @echo "Use clean_all to clean everything :)" + +clean_all: $(CLEAN) + +$(CLEAN): clean-% : + rm -rf runs/$* + rm -rf ../gds/$** + rm -rf ../mag/$** + rm -rf ../lef/$**
diff --git a/openlane/fwpayload/config.tcl b/openlane/fwpayload/config.tcl new file mode 100644 index 0000000..6b7dcb5 --- /dev/null +++ b/openlane/fwpayload/config.tcl
@@ -0,0 +1,69 @@ +set script_dir [file dirname [file normalize [info script]]] + +set ::env(DESIGN_NAME) user_project_wrapper +set ::env(FP_PIN_ORDER_CFG) $script_dir/pin_order.cfg + +#set ::env(CLOCK_PORT) "user_clock2" +set ::env(CLOCK_PORT) "wb_clk_i" +set ::env(CLOCK_NET) "mprj.clk" +#set ::env(CLOCK_NET) "wb_clk_i" + +set ::env(CLOCK_PERIOD) "10" + +set ::env(FP_SIZING) absolute +#set ::env(DIE_AREA) "0 0 2700 3700" +set ::env(DIE_AREA) "0 0 2000 2000" +# Default density is 0.4 +set ::env(PL_TARGET_DENSITY) 0.15 +# set ::env(PL_TARGET_DENSITY) 0.85 +set ::env(PL_OPENPHYSYN_OPTIMIZATIONS) 0 + +set ::env(PL_SKIP_INITIAL_PLACEMENT) 1 + +set vlog_files "" +lappend vlog_files "$script_dir/../../verilog/rtl/user_project_wrapper.v" +lappend vlog_files "$script_dir/../../verilog/rtl/fwpayload.v" +lappend vlog_files "$script_dir/../../verilog/rtl/spram_32x256.sv" +lappend vlog_files "$script_dir/../../verilog/rtl/spram.v" +lappend vlog_files "$script_dir/../../verilog/rtl/simple_spi_master.v" +lappend vlog_files "$script_dir/../../verilog/rtl/simpleuart.v" +lappend vlog_files "$script_dir/../../packages/fw-wishbone-interconnect/verilog/rtl/wb_interconnect_NxN.v" +lappend vlog_files "$script_dir/../../packages/fw-wishbone-interconnect/verilog/rtl/wb_interconnect_arb.v" +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_wb.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_alu.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_c_decode.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_decode.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_exec.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_fetch.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_mem.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_mul_div_shift.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_regfile.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_rv32i.sv +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_rv32i_wb.sv +#lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_rv32im.sv +#lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_rv32imc.sv +#lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_system_op.svh +lappend vlog_files $script_dir/../../packages/fwrisc/rtl/fwrisc_tracer.sv +#foreach path [glob -directory "$script_dir/../../packages/fwrisc/rtl" "*.sv*"] { +# lappend vlog_files $path +#} + +puts "vlog_files=$vlog_files" + +set ::env(VERILOG_INCLUDE_DIRS) "\ + $script_dir/../../packages/fwrisc/rtl \ + $script_dir/../../packages/fwprotocol-defs/src/sv" +set ::env(VERILOG_FILES) "$vlog_files" +#set ::env(VERILOG_FILES) "\ +# $script_dir/../../rtl/user_project_wrapper.v \ +# $script_dir/../../rtl/fwpayload.v" + +#set ::env(VERILOG_FILES_BLACKBOX) "\ +# $script_dir/../../rtl/fwpayload.v" + +#set ::env(EXTRA_LEFS) "\ +# $script_dir/../../lef/user_proj_example.lef" + +#set ::env(EXTRA_GDS_FILES) "\ +# $script_dir/../../gds/user_proj_example.gds"
diff --git a/verilog/rtl/fwpayload.v b/verilog/rtl/fwpayload.v index da198ef..23ec28a 100644 --- a/verilog/rtl/fwpayload.v +++ b/verilog/rtl/fwpayload.v
@@ -2,6 +2,7 @@ /**************************************************************************** * fwpayload.v ****************************************************************************/ +`include "wishbone_macros.svh" `ifndef MPRJ_IO_PADS `define MPRJ_IO_PADS 38 @@ -47,45 +48,33 @@ output [`MPRJ_IO_PADS-1:0] io_oeb ); - wire clk, rst; + wire clk, rst, core_rst; + /**************************************************************** + * Interconnect definitions + ****************************************************************/ // System interconnect localparam N_INITIATORS = 3; localparam INIT_ID_CORE_I = 0; localparam INIT_ID_CORE_D = 1; localparam INIT_ID_MGMT = 2; + `WB_WIRES_ARR(i_ic_,32,32,N_INITIATORS); - localparam N_TARGETS = 1; + localparam N_TARGETS = 4; localparam TGT_ID_SRAM = 0; - // TBD localparam TGT_ID_SPI = 1; localparam TGT_ID_UART = 2; localparam TGT_ID_GPIO = 3; - wire[32*N_INITIATORS-1:0] IC_I_ADR; - wire[32*N_INITIATORS-1:0] IC_I_DAT_W; - wire[32*N_INITIATORS-1:0] IC_I_DAT_R; - wire[N_INITIATORS-1:0] IC_I_CYC; - wire[N_INITIATORS-1:0] IC_I_ERR; - wire[4*N_INITIATORS-1:0] IC_I_SEL; - wire[N_INITIATORS-1:0] IC_I_STB; - wire[N_INITIATORS-1:0] IC_I_ACK; - wire[N_INITIATORS-1:0] IC_I_WE; + `WB_WIRES_ARR(ic_t_,32,32,N_TARGETS); - wire[32*(N_TARGETS+1)-1:0] IC_T_ADR; - wire[32*(N_TARGETS+1)-1:0] IC_T_DAT_W; - wire[32*(N_TARGETS+1)-1:0] IC_T_DAT_R; - wire[N_TARGETS:0] IC_T_CYC; - wire[N_TARGETS:0] IC_T_ERR; - wire[4*(N_TARGETS+1)-1:0] IC_T_SEL; - wire[N_TARGETS:0] IC_T_STB; - wire[N_TARGETS:0] IC_T_ACK; - wire[N_TARGETS:0] IC_T_WE; - - // Interconnect has a default target that - // to which unmapped accesses are directed - assign IC_T_ACK[N_TARGETS] = 1; - assign IC_T_ERR[N_TARGETS] = 1; - assign IC_T_DAT_R[32*N_TARGETS+:32] = 0; + // Memory map + // + // 28-bit address space, with the upper 4 bits masked + // + // 0x00000000..0x00000FFFF - Program/data memory + // 0x01000000..0x010000000 - UART + // 0x01000000..0x010000100 - SPI + // 0x01000000..0x010000200 - GPIO // Interconnect wb_interconnect_NxN #( @@ -94,147 +83,95 @@ .N_INITIATORS(N_INITIATORS), .N_TARGETS(N_TARGETS), .I_ADR_MASK({ - { 8'hFF, {24{1'b0}} } + { 32'h0F00_0000 }, + { 32'h0FFF_FF00 }, + { 32'h0FFF_FF00 }, + { 32'h0FFF_FF00 } }), .T_ADR({ - { 32'h8000_0000 } + { 32'h0000_0000 }, + { 32'h0100_0000 }, + { 32'h0100_0100 }, + { 32'h0100_0200 } }) ) u_ic ( - .clk(clk), - .rst(rst), - .ADR(IC_I_ADR), - .DAT_W(IC_I_DAT_W), - .DAT_R(IC_I_DAT_R), - .CYC(IC_I_CYC), - .ERR(IC_I_ERR), - .SEL(IC_I_SEL), - .STB(IC_I_STB), - .ACK(IC_I_ACK), - .WE(IC_I_WE), - - .TADR(IC_T_ADR), - .TDAT_W(IC_T_DAT_W), - .TDAT_R(IC_T_DAT_R), - .TCYC(IC_T_CYC), - .TERR(IC_T_ERR), - .TSEL(IC_T_SEL), - .TSTB(IC_T_STB), - .TACK(IC_T_ACK), - .TWE(IC_T_WE) + .clock(clk), + .reset(rst), + + `WB_CONNECT(,i_ic_), + `WB_CONNECT(t,ic_t_) ); /**************************************************************** * Connect management interface to port 1 on the interconnect ****************************************************************/ - assign IC_I_ADR[32*INIT_ID_MGMT+:32] = wbs_adr_i; - assign IC_I_DAT_W[32*INIT_ID_MGMT+:32] = wbs_dat_i; - assign wbs_dat_o = IC_I_DAT_R[32*INIT_ID_MGMT+:32]; - assign IC_I_CYC[INIT_ID_MGMT] = wbs_cyc_i; -// assign IC_I_ERR[INIT_ID_MGMT] = //wbs_cyc_i; - assign IC_I_SEL[4*INIT_ID_MGMT+:4] = wbs_sel_i; - assign IC_I_STB[INIT_ID_MGMT] = wbs_stb_i; - assign wbs_ack_o = IC_I_ACK[INIT_ID_MGMT]; - assign IC_I_WE[INIT_ID_MGMT] = wbs_we_i; + assign i_ic_adr[32*INIT_ID_MGMT+:32] = wbs_adr_i; + assign i_ic_dat_w[32*INIT_ID_MGMT+:32] = wbs_dat_i; + assign wbs_dat_o = i_ic_dat_r[32*INIT_ID_MGMT+:32]; + assign i_ic_cyc[INIT_ID_MGMT] = wbs_cyc_i; + assign i_ic_sel[4*INIT_ID_MGMT+:4] = wbs_sel_i; + assign i_ic_stb[INIT_ID_MGMT] = wbs_stb_i; + assign wbs_ack_o = i_ic_ack[INIT_ID_MGMT]; + assign i_ic_we[INIT_ID_MGMT] = wbs_we_i; // Clock/reset control // Allow the logic analyzer to take control of clock/reset - // Default to using the caravel clock/reset assign clk = (~la_oen[127]) ? la_data_in[127]: wb_clk_i; assign rst = (~la_oen[126]) ? ~la_data_in[126]: wb_rst_i; assign core_rst = (~la_oen[125]) ? ~la_data_in[125]: wb_rst_i; -// assign clk = wb_clk_i; -// assign rst = wb_rst_i; - localparam RAM_BITS = 8; - localparam ROM_BITS = 8; - + /**************************************************************** + * FWRISC instance + ****************************************************************/ fwrisc_rv32i_wb u_core ( .clock(clk), .reset(core_rst), - .wbi_adr_o(IC_I_ADR[32*INIT_ID_CORE_I+:32]), - .wbi_dat_o(IC_I_DAT_W[32*INIT_ID_CORE_I+:32]), - .wbi_dat_i(IC_I_DAT_R[32*INIT_ID_CORE_I+:32]), - .wbi_cyc_o(IC_I_CYC[INIT_ID_CORE_I]), - .wbi_err_i(IC_I_ERR[INIT_ID_CORE_I]), - .wbi_sel_o(IC_I_SEL[4*INIT_ID_CORE_I+:4]), - .wbi_stb_o(IC_I_STB[INIT_ID_CORE_I]), - .wbi_ack_i(IC_I_ACK[INIT_ID_CORE_I]), - .wbi_we_o(IC_I_WE[INIT_ID_CORE_I]), - - .wbd_adr_o(IC_I_ADR[32*INIT_ID_CORE_D+:32]), - .wbd_dat_o(IC_I_DAT_W[32*INIT_ID_CORE_D+:32]), - .wbd_dat_i(IC_I_DAT_R[32*INIT_ID_CORE_D+:32]), - .wbd_cyc_o(IC_I_CYC[INIT_ID_CORE_D]), - .wbd_err_i(IC_I_ERR[INIT_ID_CORE_D]), - .wbd_sel_o(IC_I_SEL[4*INIT_ID_CORE_D+:4]), - .wbd_stb_o(IC_I_STB[INIT_ID_CORE_D]), - .wbd_ack_i(IC_I_ACK[INIT_ID_CORE_D]), - .wbd_we_o(IC_I_WE[INIT_ID_CORE_D]) + `WB_CONNECT_ARR(wbi_,i_ic_,INIT_ID_CORE_I,32,32), + `WB_CONNECT_ARR(wbd_,i_ic_,INIT_ID_CORE_D,32,32) ); - // Probes // - PC // - [31:0] input - // - Regs - // - [63:32] input - registers (via mux) - // - [68:64] output - select + // - instr_complete + // - [32] input + // - gpio_out + // - [39:36] input + // - Clock and reset // - 127 output - clock // - 126 output - reset - localparam IVALID_OFF = 65; - localparam REG_PROBE_SEL_OFF = 64; - localparam REG_PROBE_OFF = 32; - localparam PC_PROBE_OFF = 0; - wire[4:0] reg_probe_sel = ( - la_oen[REG_PROBE_SEL_OFF+4:REG_PROBE_SEL_OFF] == 5'b0000)? - la_data_in[REG_PROBE_SEL_OFF+4:REG_PROBE_SEL_OFF]:5'b0000; - wire[31:0] reg_probe; - wire[31:0] pc_probe; + // - 125 output - core_reset + localparam LA_CLOCK = 127; + localparam LA_RESET_SYS = 126; + localparam LA_RESET_CORE = 125; + localparam LA_GPIO_IN = 40; + localparam LA_GPIO_OUT = 36; + localparam LA_UART_RX = 34; + localparam LA_UART_TX = 33; + localparam LA_INSTR_COMPLETE = 32; + localparam LA_PC = 0; - assign la_data_out[REG_PROBE_OFF+31:REG_PROBE_OFF] = reg_probe; - assign la_data_out[PC_PROBE_OFF+31:PC_PROBE_OFF] = pc_probe; -// assign la_data_out[IVALID_OFF] = u_core.u_core.instr_complete; + wire[31:0] pc_probe = u_core.u_core.u_core.pc; + assign la_data_out[LA_PC+:32] = pc_probe; + assign la_data_out[LA_INSTR_COMPLETE] = u_core.u_core.u_core.instr_complete; - // 640 pixels - // 16x16? - // - Each block is 40p wide - // - - // - 40ns per pix, 1600ns per block - // TODO: dedicated reset for core, to allow us to isolate it from the system - // Video shift register - // - Need two levels - // - Output - // - Ready - // - Need clock divider to control shift rate - // - Need IRQ to signal empty - - // Small memory (1KB ok?) - // - Must be dual-port with access from slave port - // ROM: 'h8000_0000 - // RAM: 'h8000_8000 - // LED: 'hC000_0000 - -// initial begin -// $readmemh("rom.hex", rom); -// end - /**************************************************************** * Simple WB to SRAM bridge ****************************************************************/ reg[1:0] wb_bridge_state = 0; - wire[31:0] sram_adr_i = IC_T_ADR[32*TGT_ID_SRAM+:32]; - wire[31:0] sram_dat_w = IC_T_DAT_W[32*TGT_ID_SRAM+:32]; + wire[31:0] sram_adr_i = ic_t_adr[32*TGT_ID_SRAM+:32]; + wire[31:0] sram_dat_w = ic_t_dat_w[32*TGT_ID_SRAM+:32]; wire[31:0] sram_dat_r; - assign IC_T_DAT_R[32*TGT_ID_SRAM+:32] = sram_dat_r; - wire sram_cyc_i = IC_T_CYC[TGT_ID_SRAM]; - assign IC_T_ERR[TGT_ID_SRAM] = 0; - wire[3:0] sram_sel_i = IC_T_SEL[4*TGT_ID_SRAM+:4]; - wire sram_stb_i = IC_T_STB[TGT_ID_SRAM]; + assign ic_t_dat_r[32*TGT_ID_SRAM+:32] = sram_dat_r; + wire sram_cyc_i = ic_t_cyc[TGT_ID_SRAM]; + assign ic_t_err[TGT_ID_SRAM] = 0; + wire[3:0] sram_sel_i = ic_t_sel[4*TGT_ID_SRAM+:4]; + wire sram_stb_i = ic_t_stb[TGT_ID_SRAM]; wire sram_ack_o; - assign IC_T_ACK[TGT_ID_SRAM] = sram_ack_o; - wire sram_we_i = IC_T_WE[TGT_ID_SRAM]; - + assign ic_t_ack[TGT_ID_SRAM] = sram_ack_o; + wire sram_we_i = ic_t_we[TGT_ID_SRAM]; + always @(posedge wb_clk_i) begin if (rst == 1) begin wb_bridge_state <= 0; @@ -268,14 +205,113 @@ .a_sel(sram_sel_i)); assign sram_ack_o = (wb_bridge_state == 3); - // Some form of general I/O - // - GPIO? - // - + /**************************************************************** + * External interfaces + ****************************************************************/ - // Some form of specific I/O // - UART - // - SPI + wire uart_enabled; + wire ser_tx; + wire ser_rx; + simpleuart_wb #( + .BASE_ADR(32'h0000_0000) + ) u_uart ( + .wb_clk_i(clk), + .wb_rst_i(rst), + .wb_adr_i({24'b0, ic_t_adr[32*TGT_ID_UART+:8]}), + .wb_dat_i(ic_t_dat_w[32*TGT_ID_UART+:32]), + .wb_sel_i(ic_t_sel[4*TGT_ID_UART+:4]), + .wb_we_i(ic_t_we[TGT_ID_UART]), + .wb_cyc_i(ic_t_cyc[TGT_ID_UART]), + .wb_stb_i(ic_t_stb[TGT_ID_UART]), + .wb_ack_o(ic_t_ack[TGT_ID_UART]), + .wb_dat_o(ic_t_dat_r[32*TGT_ID_UART+:32]), + + .uart_enabled(uart_enabled), + .ser_tx(ser_tx), + .ser_rx(ser_rx) + ); + // - SPI + wire hk_connect; + wire sdi; + wire csb; + wire sck; + wire sdo; + wire sdoenb; + wire irq; + simple_spi_master_wb #( + .BASE_ADR(32'h0000_0000) + ) u_spi ( + .wb_clk_i(clk), + .wb_rst_i(rst), + .wb_adr_i({24'b0, ic_t_adr[32*TGT_ID_SPI+:8]}), + .wb_dat_i(ic_t_dat_w[32*TGT_ID_SPI+:32]), + .wb_sel_i(ic_t_sel[4*TGT_ID_SPI+:4]), + .wb_we_i(ic_t_we[TGT_ID_SPI]), + .wb_cyc_i(ic_t_cyc[TGT_ID_SPI]), + .wb_stb_i(ic_t_stb[TGT_ID_SPI]), + .wb_ack_o(ic_t_ack[TGT_ID_SPI]), + .wb_dat_o(ic_t_dat_r[32*TGT_ID_SPI+:32]), + + .hk_connect(hk_connect), + .sdi(sdi), + .csb(csb), + .sck(sck), + .sdo(sdo), + .sdoenb(sdoenb), + .irq(irq) + ); + + // - Simple GPIO + reg[3:0] gpio_out; + wire[3:0] gpio_in; + + wire[31:0] gpio_adr_i = ic_t_adr[32*TGT_ID_GPIO+:32]; + wire[31:0] gpio_dat_w = ic_t_dat_w[32*TGT_ID_GPIO+:32]; + wire[31:0] gpio_dat_r = {20'b0, gpio_in, 4'b0, gpio_out}; + assign ic_t_dat_r[32*TGT_ID_GPIO+:32] = gpio_dat_r; + wire gpio_cyc_i = ic_t_cyc[TGT_ID_GPIO]; + assign ic_t_err[TGT_ID_GPIO] = 0; + wire[3:0] gpio_sel_i = ic_t_sel[4*TGT_ID_GPIO+:4]; + wire gpio_stb_i = ic_t_stb[TGT_ID_GPIO]; + reg gpio_ack_o; + assign ic_t_ack[TGT_ID_GPIO] = gpio_ack_o; + wire gpio_we_i = ic_t_we[TGT_ID_GPIO]; + + always @(posedge wb_clk_i) begin + if (rst == 1) begin + gpio_ack_o <= 1'b0; + gpio_out <= 4'b0; + end else begin + gpio_ack_o <= (gpio_cyc_i && gpio_stb_i); + + if (gpio_cyc_i && gpio_stb_i && gpio_we_i) begin + gpio_out <= gpio_dat_w[3:0]; + end + end + end + + + /**************************************************************** + * Outputs + ****************************************************************/ + // UART + assign io_out[16] = ser_tx; + assign ser_rx = io_in[17]; + + assign sdi = io_in[18]; + assign io_out[19] = csb; + assign io_out[20] = sck; + assign io_out[21] = sdo; + assign io_out[22] = sdoenb; + + // GPIO + assign io_out[26:23] = gpio_out; + assign gpio_in = io_in[30:27]; + + // Probe the GPIO output with the LA + assign la_data_in[39:36] = gpio_out; endmodule
diff --git a/verilog/rtl/simple_spi_master.v b/verilog/rtl/simple_spi_master.v index 4cf8b46..c4bbd4d 100755 --- a/verilog/rtl/simple_spi_master.v +++ b/verilog/rtl/simple_spi_master.v
@@ -146,7 +146,7 @@ output [31:0] reg_dat_do, output reg_dat_wait, output irq_out, - output err_out, + output reg err_out, output hk_connect, // Connect to housekeeping SPI input sdi, // SPI input @@ -164,7 +164,6 @@ reg isdo, hsck, icsb; reg [1:0] state; reg isck; - reg err_out; reg [7:0] treg, rreg, d_latched; reg [2:0] nbit; @@ -180,13 +179,6 @@ reg enable; reg hkconn; - wire csb; - wire irq_out; - wire sck; - wire sdo; - wire sdoenb; - wire hk_connect; - // Define behavior for inverted SCK and inverted CSB assign csb = (enable == 1'b0) ? 1'bz : (invcsb) ? ~icsb : icsb; assign sck = (enable == 1'b0) ? 1'bz : (invsck) ? ~isck : isck;
diff --git a/verilog/rtl/simpleuart.v b/verilog/rtl/simpleuart.v index 96b3b4e..055e1c7 100644 --- a/verilog/rtl/simpleuart.v +++ b/verilog/rtl/simpleuart.v
@@ -95,7 +95,7 @@ input clk, input resetn, - output enabled, + output reg enabled, output ser_tx, input ser_rx, @@ -114,7 +114,6 @@ output reg_dat_wait ); reg [31:0] cfg_divider; - reg enabled; reg [3:0] recv_state; reg [31:0] recv_divcnt;
diff --git a/verilog/rtl/spram_32x512.sv b/verilog/rtl/spram_32x512.sv new file mode 100644 index 0000000..3be8195 --- /dev/null +++ b/verilog/rtl/spram_32x512.sv
@@ -0,0 +1,31 @@ +/**************************************************************************** + * spram_32x256.sv + ****************************************************************************/ + +/** + * Module: spram_32x512 + * + * TODO: Add module documentation + */ +module spram_32x512( + input clock, + input [8-1:0] a_adr, + input [32-1:0] a_dat_i, + output [32-1:0] a_dat_o, + input a_we, + input [32/8-1:0] a_sel); + + spram_byte_en #( + .ADDR_BITS(9), + .DATA_BITS(32) + ) u_sram ( + .clock(clock), + .a_adr(a_adr), + .a_dat_i(a_dat_i), + .a_dat_o(a_dat_o), + .a_we(a_we), + .a_sel(a_sel)); + +endmodule + +
diff --git a/verilog/rtl/wb_interconnect_NxN.sv b/verilog/rtl/wb_interconnect_NxN.sv deleted file mode 100644 index f3b0ce3..0000000 --- a/verilog/rtl/wb_interconnect_NxN.sv +++ /dev/null
@@ -1,329 +0,0 @@ -/**************************************************************************** - * ${NAME}.sv - ****************************************************************************/ - -/** - * Module: wb_interconnect_NxN - * - * TODO: Add module documentation - */ -module wb_interconnect_NxN #( - parameter WB_ADDR_WIDTH=32, - parameter WB_DATA_WIDTH=32, - parameter N_INITIATORS=1, - parameter N_TARGETS=1, - parameter [N_INITIATORS*WB_ADDR_WIDTH-1:0] I_ADR_MASK = { - {8'hFF, {24{1'b0}} } - }, - parameter [N_TARGETS*WB_ADDR_WIDTH-1:0] T_ADR = { - { 32'h2800_0000 } - } - ) ( - input clk, - input rst, - input[WB_ADDR_WIDTH*N_INITIATORS-1:0] ADR, - input[WB_DATA_WIDTH*N_INITIATORS-1:0] DAT_W, - output[WB_DATA_WIDTH*N_INITIATORS-1:0] DAT_R, - input[N_INITIATORS-1:0] CYC, - output[N_INITIATORS-1:0] ERR, - input[(WB_DATA_WIDTH/8)*N_INITIATORS-1:0] SEL, - input[N_INITIATORS-1:0] STB, - output[N_INITIATORS-1:0] ACK, - input[N_INITIATORS-1:0] WE, - - output[WB_ADDR_WIDTH*(N_TARGETS+1)-1:0] TADR, - output[WB_DATA_WIDTH*(N_TARGETS+1)-1:0] TDAT_W, - input[WB_DATA_WIDTH*(N_TARGETS+1)-1:0] TDAT_R, - output[N_TARGETS:0] TCYC, - input[N_TARGETS:0] TERR, - output[(WB_DATA_WIDTH/8)*(N_TARGETS+1)-1:0] TSEL, - output[N_TARGETS:0] TSTB, - input[N_TARGETS:0] TACK, - output[N_TARGETS:0] TWE - ); - - localparam WB_DATA_MSB = (WB_DATA_WIDTH-1); - localparam N_INIT_ID_BITS = (N_INITIATORS>1)?$clog2(N_INITIATORS):1; - localparam N_TARG_ID_BITS = $clog2(N_TARGETS+1); - localparam NO_TARGET = {(N_TARG_ID_BITS+1){1'b1}}; - localparam NO_INITIATOR = {(N_INIT_ID_BITS+1){1'b1}}; - - // Interface to the decode-fail target -// wb_if TERR(); - - function reg[N_TARG_ID_BITS:0] addr2targ_id( - input reg[N_INIT_ID_BITS-1:0] initiator, - input reg[WB_ADDR_WIDTH-1:0] addr - ); - integer i; - begin - addr2targ_id = N_TARGETS; -// $display("addr2targ_id: 'h%08h 'h%08h", addr, ADDR_RANGES); - for (i=0; i<N_TARGETS; i+=1) begin -// $display("Address Range: %0d 'h%08h..'h%08h", i, -// ADDR_RANGES[(WB_ADDR_WIDTH*(i+2)-1)-:WB_ADDR_WIDTH], -// ADDR_RANGES[(WB_ADDR_WIDTH*(i+1)-1)-:WB_ADDR_WIDTH]); -// $display(" %0d %0d", (WB_ADDR_WIDTH*(i+2)-1), (WB_ADDR_WIDTH*(i+1)-1)); - if ( - (addr&I_ADR_MASK[(WB_ADDR_WIDTH*(i+1))-1-:WB_ADDR_WIDTH]) == - (T_ADR[(WB_ADDR_WIDTH*(i+1))-1-:WB_ADDR_WIDTH])) begin - $display("Address 'h%08h: range=%0d", addr, N_TARGETS-1); - addr2targ_id = N_TARGETS-1; - end - end - end - endfunction - -// Read request state machine - - // Initiator state machine - reg[2:0] initiator_state[N_INITIATORS-1:0]; - reg[N_TARG_ID_BITS:0] initiator_selected_target[N_INITIATORS-1:0]; - wire initiator_gnt[N_TARGETS:0]; - wire[$clog2(N_INITIATORS)-1:0] initiator_gnt_id[N_TARGETS:0]; - wire[N_INITIATORS-1:0] initiator_target_req[N_TARGETS:0]; - - generate - genvar m_i; - for (m_i=0; m_i<N_INITIATORS; m_i=m_i+1) begin : block_m_i - always @(posedge clk) begin - if (rst == 1) begin - initiator_state[m_i] <= 0; - initiator_selected_target[m_i] <= NO_TARGET; - end else begin - case (initiator_state[m_i]) - 0: begin - if (CYC[m_i] && STB[m_i]) begin - initiator_state[m_i] <= 1; - initiator_selected_target[m_i] <= addr2targ_id( - m_i, - ADR[WB_ADDR_WIDTH*m_i+:WB_ADDR_WIDTH] - ); -// $display("Master %0d => Slave %0d", m_i, addr2targ_id(m_i, ADR[m_i])); - end - end - - 1: begin - // Wait for the addressed target to acknowledge - if (CYC[m_i] && STB[m_i] && ACK[m_i]) begin - initiator_state[m_i] <= 0; - initiator_selected_target[m_i] <= NO_TARGET; - end - end - endcase - end - end - end - endgenerate - - // Build the req vector for each target - generate - genvar m_req_i, m_req_j; - - for (m_req_i=0; m_req_i <(N_TARGETS+1); m_req_i=m_req_i+1) begin : block_m_req_i - for (m_req_j=0; m_req_j < N_INITIATORS; m_req_j=m_req_j+1) begin : block_m_req_j - assign initiator_target_req[m_req_i][m_req_j] = (initiator_selected_target[m_req_j] == m_req_i); - end - end - endgenerate - - generate - genvar s_arb_i; - - for (s_arb_i=0; s_arb_i<(N_TARGETS+1); s_arb_i=s_arb_i+1) begin : s_arb - wb_NxN_arbiter #( - .N_REQ (N_INITIATORS) - ) - aw_arb ( - .clk (clk ), - .rst (rst ), - .req (initiator_target_req[s_arb_i]), - .gnt (initiator_gnt[s_arb_i]), - .gnt_id (initiator_gnt_id[s_arb_i]) - ); - end - endgenerate - - wire[N_INIT_ID_BITS:0] target_active_initiator[N_TARGETS:0]; - - generate - genvar s_am_i; - - for (s_am_i=0; s_am_i<(N_TARGETS+1); s_am_i=s_am_i+1) begin : block_s_am_i - assign target_active_initiator[s_am_i] = - (initiator_gnt[s_am_i])?initiator_gnt_id[s_am_i]:NO_INITIATOR; - end - endgenerate - - // WB signals from target back to initiator - generate - genvar s2m_i; - - for (s2m_i=0; s2m_i<N_INITIATORS; s2m_i=s2m_i+1) begin : block_s2m_i - assign DAT_R[WB_DATA_WIDTH*s2m_i+:WB_DATA_WIDTH] = - (initiator_selected_target[s2m_i] != NO_TARGET && - initiator_gnt[initiator_selected_target[s2m_i]] && - initiator_gnt_id[initiator_selected_target[s2m_i]] == s2m_i)? - TDAT_R[WB_DATA_WIDTH*initiator_selected_target[s2m_i]+:WB_DATA_WIDTH]:0; - assign ERR[s2m_i] = (initiator_selected_target[s2m_i] != NO_TARGET && - initiator_gnt[initiator_selected_target[s2m_i]] && - initiator_gnt_id[initiator_selected_target[s2m_i]] == s2m_i)? - TERR[initiator_selected_target[s2m_i]]:0; - assign ACK[s2m_i] = (initiator_selected_target[s2m_i] != NO_TARGET && - initiator_gnt[initiator_selected_target[s2m_i]] && - initiator_gnt_id[initiator_selected_target[s2m_i]] == s2m_i)? - TACK[initiator_selected_target[s2m_i]]:0; - end - endgenerate - - // WB signals to target mux - generate - genvar m2s_i; - for(m2s_i=0; m2s_i<(N_TARGETS+1); m2s_i=m2s_i+1) begin : WB_M2S_assign - assign TADR[WB_ADDR_WIDTH*m2s_i+:WB_ADDR_WIDTH] = - (target_active_initiator[m2s_i] == NO_INITIATOR)?0:ADR[WB_ADDR_WIDTH*target_active_initiator[m2s_i]+:WB_ADDR_WIDTH]; - assign TDAT_W[WB_DATA_WIDTH*m2s_i+:WB_DATA_WIDTH] = - (target_active_initiator[m2s_i] == NO_INITIATOR)?0:DAT_W[WB_DATA_WIDTH*target_active_initiator[m2s_i]+:WB_DATA_WIDTH]; - assign TCYC[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:CYC[target_active_initiator[m2s_i]]; - assign TSEL[(WB_DATA_WIDTH/8)*m2s_i+:(WB_DATA_WIDTH/8)] = - (target_active_initiator[m2s_i] == NO_INITIATOR)?0: - SEL[(WB_DATA_WIDTH/8)*target_active_initiator[m2s_i]+:(WB_DATA_WIDTH/8)]; - assign TSTB[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:STB[target_active_initiator[m2s_i]]; - assign TWE[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:WE[target_active_initiator[m2s_i]]; - end - endgenerate - - // Error target - reg err_req; - always @(posedge clk) begin - if (rst == 1) begin - err_req <= 0; - end else begin - if (TSTB[N_TARGETS] && TCYC[N_TARGETS] && !err_req) begin - err_req <= 1; - end else begin - err_req <= 0; - end - end - end -endmodule - -module wb_NxN_arbiter #( - parameter N_REQ=2 - ) ( - input clk, - input rst, - input[N_REQ-1:0] req, - output gnt, - output[$clog2(N_REQ)-1:0] gnt_id - ); - - reg state; - - reg [N_REQ-1:0] gnt_o = 0; - reg [N_REQ-1:0] last_gnt = 0; - reg [$clog2(N_REQ)-1:0] gnt_id_o = 0; - assign gnt = |gnt_o; - assign gnt_id = gnt_id_o; - - wire[N_REQ-1:0] gnt_ppc; - wire[N_REQ-1:0] gnt_ppc_next; - - generate - if (N_REQ > 1) begin - assign gnt_ppc_next = {gnt_ppc[N_REQ-2:0], 1'b0}; - end else begin - assign gnt_ppc_next = gnt_ppc; - end - endgenerate - - generate - genvar gnt_ppc_i; - - for (gnt_ppc_i=N_REQ-1; gnt_ppc_i>=0; gnt_ppc_i=gnt_ppc_i-1) begin : block_gnt_ppc_i - if (gnt_ppc_i == 0) begin - assign gnt_ppc[gnt_ppc_i] = last_gnt[0]; - end else begin - assign gnt_ppc[gnt_ppc_i] = |last_gnt[gnt_ppc_i-1:0]; - end - end - endgenerate - - wire[N_REQ-1:0] unmasked_gnt; - generate - genvar unmasked_gnt_i; - - for (unmasked_gnt_i=0; unmasked_gnt_i<N_REQ; unmasked_gnt_i=unmasked_gnt_i+1) begin : block_unmasked_gnt_i - // Prioritized unmasked grant vector. Grant to the lowest active grant - if (unmasked_gnt_i == 0) begin - assign unmasked_gnt[unmasked_gnt_i] = req[unmasked_gnt_i]; - end else begin - assign unmasked_gnt[unmasked_gnt_i] = (req[unmasked_gnt_i] & ~(|req[unmasked_gnt_i-1:0])); - end - end - endgenerate - - wire[N_REQ-1:0] masked_gnt; - generate - genvar masked_gnt_i; - - for (masked_gnt_i=0; masked_gnt_i<N_REQ; masked_gnt_i=masked_gnt_i+1) begin : block_masked_gnt_i - if (masked_gnt_i == 0) begin - assign masked_gnt[masked_gnt_i] = (gnt_ppc_next[masked_gnt_i] & req[masked_gnt_i]); - end else begin - // Select first request above the last grant - assign masked_gnt[masked_gnt_i] = (gnt_ppc_next[masked_gnt_i] & req[masked_gnt_i] & - ~(|(gnt_ppc_next[masked_gnt_i-1:0] & req[masked_gnt_i-1:0]))); - end - end - endgenerate - - wire[N_REQ-1:0] prioritized_gnt; - - // Give priority to the 'next' request - assign prioritized_gnt = (|masked_gnt)?masked_gnt:unmasked_gnt; - - always @(posedge clk) begin - if (rst == 1) begin - state <= 0; - last_gnt <= 0; - gnt_o <= 0; - gnt_id_o <= 0; - end else begin - case (state) - 0: begin - if (|prioritized_gnt) begin - state <= 1; - gnt_o <= prioritized_gnt; - last_gnt <= prioritized_gnt; - gnt_id_o <= gnt2id(prioritized_gnt); - end - end - - 1: begin - if ((gnt_o & req) == 0) begin - state <= 0; - gnt_o <= 0; - end - end - endcase - end - end - - function reg[$clog2(N_REQ)-1:0] gnt2id(input reg[N_REQ-1:0] gnt); - integer i; - begin -// reg[$clog2(N_REQ)-1:0] result; - - gnt2id = 0; - - for (i=0; i<N_REQ; i++) begin - if (gnt[i]) begin - gnt2id |= i; - end - end - - end - endfunction - -endmodule