Moving toward a slightly larger system... Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
diff --git a/.pydevproject b/.pydevproject index 4684ce1..7f15358 100644 --- a/.pydevproject +++ b/.pydevproject
@@ -5,5 +5,6 @@ <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> <path>/${PROJECT_DIR_NAME}/packages/wishbone-bfms/src</path> <path>/${PROJECT_DIR_NAME}/dv/bringup/python</path> + <path>/${PROJECT_DIR_NAME}/packages/pybfms-logic-analyzer/src</path> </pydev_pathproperty> </pydev_project>
diff --git a/dv/bringup/Makefile b/dv/bringup/Makefile index 990c880..ad7dbab 100644 --- a/dv/bringup/Makefile +++ b/dv/bringup/Makefile
@@ -1,5 +1,5 @@ BRINGUP_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) -RTL_DIR:=$(abspath $(BRINGUP_DIR)/../../rtl) +RTL_DIR:=$(abspath $(BRINGUP_DIR)/../../verilog/rtl) PACKAGES_DIR:=$(abspath $(BRINGUP_DIR)/../../packages) FWRISC_RTL_DIR:=$(PACKAGES_DIR)/fwrisc/rtl @@ -10,32 +10,44 @@ INCDIRS += $(FWRISC_RTL_DIR) 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 += $(RTL_DIR)/spram_32x256.sv +SRCS += $(RTL_DIR)/spram.v SRCS += $(FWRISC_SRCS) +TOP_MODULE = bringup_tb + +TESTS=mgmt_mem_access + #******************************************************************** #* cocotb testbench setup #******************************************************************** -MODULE=bringup_tb +MODULE=bringup_tests.$(TEST) export MODULE PYTHONPATH := $(BRINGUP_DIR)/python:$(PYTHONPATH) export PYTHONPATH PATH := $(PACKAGES_DIR)/python/bin:$(PATH) export PATH COCOTB_PREFIX := $(shell $(PACKAGES_DIR)/python/bin/cocotb-config --prefix) -VPI_LIBS += $(COCOTB_PREFIX)/cocotb/libs/libcocotbvpi_verilator.so +VPI_LIBS += $(COCOTB_PREFIX)/cocotb/libs/libcocotbvpi_modelsim.so VLSIM_CLKSPEC += -clkspec clk=10ns -VLSIM_OPTIONS += -Wno-fatal --top-module bringup_tb +VLSIM_OPTIONS += -Wno-fatal --top-module bringup_tb --autoflush SRCS += $(BRINGUP_DIR)/bringup_tb.sv SIM?=vlsim -all : build run +all : build + for test in $(TESTS); do \ + $(MAKE) -f $(BRINGUP_DIR)/Makefile run TEST=$${test}; \ + done clean :: echo "TODO" + include $(BRINGUP_DIR)/../common/$(SIM).mk
diff --git a/dv/bringup/bringup_tb.sv b/dv/bringup/bringup_tb.sv index 8fd59a2..d28b0ee 100644 --- a/dv/bringup/bringup_tb.sv +++ b/dv/bringup/bringup_tb.sv
@@ -17,9 +17,10 @@ assign clk_r = #5ns ~clk_r; `endif - wire clock = clk; + + wire clock = clk; reg[15:0] reset_cnt; - reg[15:0] reset_key; + reg[15:0] reset_key /*verilator public*/; always @(posedge clock) begin if (reset_key != 16'ha520) begin @@ -44,9 +45,35 @@ wire wbs_ack_o; wire [31:0] wbs_dat_o; + wb_initiator_bfm #( + .ADDR_WIDTH(32), + .DATA_WIDTH(32) + ) 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) + ); + wire [127:0] la_data_in; wire [127:0] la_data_out; - wire [127:0] la_oen = 128'hFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; + wire [127:0] la_oen; // = 128'hFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; + + la_initiator_bfm #( + .WIDTH(128) + ) u_la ( + .clock(wb_clk_i), + .reset(wb_rst_i), + .data_in(la_data_out), + .data_out(la_data_in), + .oen(la_oen) + ); wire [`MPRJ_IO_PADS-1:0] io_in; wire [`MPRJ_IO_PADS-1:0] io_out;
diff --git a/dv/bringup/python/__pycache__/bringup_tb.cpython-36.pyc b/dv/bringup/python/__pycache__/bringup_tb.cpython-36.pyc deleted file mode 100644 index f96b60b..0000000 --- a/dv/bringup/python/__pycache__/bringup_tb.cpython-36.pyc +++ /dev/null Binary files differ
diff --git a/dv/bringup/python/bringup_tb.py b/dv/bringup/python/bringup_tb.py index 68e8135..774cffa 100644 --- a/dv/bringup/python/bringup_tb.py +++ b/dv/bringup/python/bringup_tb.py
@@ -4,9 +4,28 @@ @author: mballance ''' import cocotb +import wishbone_bfms +import pybfms +from wishbone_bfms.wb_initiator_bfm import WbInitiatorBfm +from logic_analyzer_bfms.la_initiator_bfm import LaInitiatorBfm @cocotb.test() async def test(root): - print("Hello") + await pybfms.init() + u_wb : WbInitiatorBfm = pybfms.find_bfm(".*u_wb") + u_la : LaInitiatorBfm = pybfms.find_bfm(".*u_la") + + print("--> u_la.set_bits") + await u_la.set_bits(0, 0x55AAEEFF, 0xFFFFFFFF) + print("<-- u_la.set_bits") +# print("--> u_la.propagate") +# await u_la.propagate() +# print("<-- u_la.propagate") + + for i in range(10): + await u_wb.write(0x0, 0x55aa+i, 0xF) + dat = await u_wb.read(0x0) + print("dat=" + hex(dat)) +
diff --git a/dv/bringup/python/bringup_tests/__init__.py b/dv/bringup/python/bringup_tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/dv/bringup/python/bringup_tests/__init__.py
diff --git a/dv/bringup/python/bringup_tests/__pycache__/__init__.cpython-36.pyc b/dv/bringup/python/bringup_tests/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..8a49a25 --- /dev/null +++ b/dv/bringup/python/bringup_tests/__pycache__/__init__.cpython-36.pyc Binary files differ
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 new file mode 100644 index 0000000..3ed6cd8 --- /dev/null +++ b/dv/bringup/python/bringup_tests/__pycache__/mgmt_mem_access.cpython-36.pyc Binary files differ
diff --git a/dv/bringup/python/bringup_tests/la_reset_dut.py b/dv/bringup/python/bringup_tests/la_reset_dut.py new file mode 100644 index 0000000..e8c293f --- /dev/null +++ b/dv/bringup/python/bringup_tests/la_reset_dut.py
@@ -0,0 +1,28 @@ +''' +Created on Nov 22, 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 bringup_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") + + la_utils = LaUtils(u_la) + + await la_utils.set_dut_clock_control(True) + await la_utils.reset_cycle_dut(100) + + \ No newline at end of file
diff --git a/dv/bringup/python/bringup_tests/la_utils.py b/dv/bringup/python/bringup_tests/la_utils.py new file mode 100644 index 0000000..90976e8 --- /dev/null +++ b/dv/bringup/python/bringup_tests/la_utils.py
@@ -0,0 +1,50 @@ +''' +Created on Nov 22, 2020 + +@author: mballance +''' + +class LaUtils(object): + CLOCK_IDX = 127 + RESET_IDX = 126 + + 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, 1, 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 reset_cycle_dut(self, cycles=10): + # Set reset high + await self.la_bfm.set_bits(LaUtils.RESET_IDX, 1, 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, 0, 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/bringup/python/bringup_tests/mgmt_mem_access.py b/dv/bringup/python/bringup_tests/mgmt_mem_access.py new file mode 100644 index 0000000..fbf7a38 --- /dev/null +++ b/dv/bringup/python/bringup_tests/mgmt_mem_access.py
@@ -0,0 +1,39 @@ +''' +Created on Nov 22, 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 + + +@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") + + # Test that we can write and read dut 'ROM' + wr_data = [] + r = Random(0) + for i in range(16): + data = r.randint(0, 0xFFFFFFFF) + print("Write: " + hex(0x80000000+4*i) + " = " + hex(data)) + await u_wb.write(0x80000000 + 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(0x80000000 + 4*i) + if wr_data[i] == data: + print("PASS: " + hex(0x80000000+4*i)) + else: + print("FAIL: " + hex(0x80000000+4*i) + " expect " + hex(wr_data[i]) + " receive " + hex(data)) +
diff --git a/dv/common/icarus.mk b/dv/common/icarus.mk new file mode 100644 index 0000000..f0fc7c5 --- /dev/null +++ b/dv/common/icarus.mk
@@ -0,0 +1,54 @@ +#**************************************************************************** +#* icarus.mk +#* +#* Simulator support for Icarus Verilog +#* +#* SRCS - List of source files +#* INCDIRS - Include paths +#* DEFINES - Defines +#* PYBFMS_MODULES - Modules to query for BFMs +#* SIM_ARGS - generic simulation arguments +#* VPI_LIBS - List of PLI libraries +#* DPI_LIBS - List of DPI libraries +#* TIMEOUT - Simulation timeout, in units of ns,us,ms,s +#**************************************************************************** + +COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) +VLSIM := $(PACKAGES_DIR)/python/bin/vlsim +PYBFMS_VPI_LIB := $(shell $(PACKAGES_DIR)/python/bin/pybfms lib) + +SIMV=simv.vvp +ifneq (,$(DEBUG)) +VLSIM_OPTIONS += --trace-fst +SIMV_ARGS += +vlsim.trace +SIMV := simv.debug +else +SIMV := simv.ndebug +endif + +# Enable VPI for Verilator +VLSIM_OPTIONS += --vpi +VLSIM_OPTIONS += --top-module $(TOP_MODULE) + +IVERILOG_OPTIONS += $(foreach inc,$(INCDIRS),-I $(inc)) +IVERILOG_OPTIONS += $(foreach def,$(DEFINES),-D $(def)) +VVP_ARGS += $(foreach vpi,$(VPI_LIBS),-m $(vpi)) + +VPI_LIBS += $(PYBFMS_DPI_LIB) + +build : $(SIMV) + +$(SIMV) : $(SRCS) pybfms_gen.v + iverilog -o $@ $(IVERILOG_OPTIONS) $(SRCS) pybfms_gen.v + +run : $(SIMV) + vvp $(SIMV) $(VVP_ARGS) + +pybfms_gen.v : + $(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
diff --git a/dv/common/questa.mk b/dv/common/questa.mk new file mode 100644 index 0000000..e68ccba --- /dev/null +++ b/dv/common/questa.mk
@@ -0,0 +1,45 @@ +#**************************************************************************** +#* questa.mk +#* +#* Simulator support for Mentor Questa +#* +#* SRCS - List of source files +#* INCDIRS - Include paths +#* DEFINES - Defines +#* TOP_MODULE - Top module to load +#* SIM_ARGS - generic simulation arguments +#* QUESTA_SIM_ARGS - vlsim-specific simulation arguments +#* VPI_LIBS - List of PLI libraries +#* DPI_LIBS - List of DPI libraries +#* TIMEOUT - Simulation timeout, in units of ns,us,ms,s +#**************************************************************************** + +COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) + +ifneq (,$(DEBUG)) +VLSIM_OPTIONS += --trace-fst +SIMV_ARGS += +vlsim.trace +SIMV := simv.debug +else +SIMV := simv.ndebug +endif + +# Enable VPI for Verilator +VLSIM_OPTIONS += --vpi --public-flat-rw + +VLSIM_OPTIONS += $(foreach inc,$(INCDIRS),+incdir+$(inc)) +VLSIM_OPTIONS += $(foreach def,$(DEFINES),+define+$(def)) +SIMV_ARGS += $(foreach vpi,$(VPI_LIBS),+vpi=$(vpi)) + +build : $(SIMV) + +$(SIMV) : $(SRCS) + $(VLSIM) -o $@ $(VLSIM_CLKSPEC) $(VLSIM_OPTIONS) $(SRCS) + +run : $(SIMV) + ./$(SIMV) $(SIMV_ARGS) + +clean :: + rm -f simv.* simx.fst simx.vcd + rm -rf obj_dir
diff --git a/dv/common/vlsim.mk b/dv/common/vlsim.mk index 1a34b7e..184767b 100644 --- a/dv/common/vlsim.mk +++ b/dv/common/vlsim.mk
@@ -6,6 +6,7 @@ #* SRCS - List of source files #* INCDIRS - Include paths #* DEFINES - Defines +#* PYBFMS_MODULES - Modules to query for BFMs #* SIM_ARGS - generic simulation arguments #* VLSIM_SIM_ARGS - vlsim-specific simulation arguments #* VLSIM_CLKSPEC - clock-generation options for VLSIM @@ -17,6 +18,7 @@ COMMON_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) PACKAGES_DIR := $(abspath $(COMMON_DIR)/../../packages) VLSIM := $(PACKAGES_DIR)/python/bin/vlsim +PYBFMS_DPI_LIB := $(shell $(PACKAGES_DIR)/python/bin/pybfms lib) ifneq (,$(DEBUG)) VLSIM_OPTIONS += --trace-fst @@ -26,20 +28,29 @@ SIMV := simv.ndebug endif -VLSIM_OPTIONS += --vpi --public-flat-rw +# Enable VPI for Verilator +VLSIM_OPTIONS += --vpi +VLSIM_OPTIONS += --top-module $(TOP_MODULE) VLSIM_OPTIONS += $(foreach inc,$(INCDIRS),+incdir+$(inc)) VLSIM_OPTIONS += $(foreach def,$(DEFINES),+define+$(def)) SIMV_ARGS += $(foreach vpi,$(VPI_LIBS),+vpi=$(vpi)) +DPI_LIBS += $(PYBFMS_DPI_LIB) + build : $(SIMV) -$(SIMV) : $(SRCS) - $(VLSIM) -o $@ $(VLSIM_CLKSPEC) $(VLSIM_OPTIONS) $(SRCS) +$(SIMV) : $(SRCS) pybfms_gen.sv pybfms_gen.c + $(VLSIM) -o $@ $(VLSIM_CLKSPEC) $(VLSIM_OPTIONS) $(SRCS) pybfms_gen.sv pybfms_gen.c \ + $(foreach l,$(DPI_LIBS),$(l)) run : $(SIMV) ./$(SIMV) $(SIMV_ARGS) + +pybfms_gen.sv : + $(PACKAGES_DIR)/python/bin/pybfms generate \ + -l sv $(foreach m,$(PYBFMS_MODULES),-m $(m)) -o $@ clean :: - rm -f simv.* simx.fst simx.vcd + rm -f simv.* simx.fst simx.vcd pybfms_gen.sv pybfms_gen.c rm -rf obj_dir
diff --git a/etc/packages.mf b/etc/packages.mf index 254989b..482dac7 100644 --- a/etc/packages.mf +++ b/etc/packages.mf
@@ -1,3 +1,4 @@ fwrisc@https://github.com/mballance/fwrisc.git +wb_sys_ip@https://github.com/mballance/wb_sys_ip.git
diff --git a/requirements.txt b/requirements.txt index d071710..11f4039 100644 --- a/requirements.txt +++ b/requirements.txt
@@ -4,4 +4,5 @@ -e git+https://github.com/pybfms/pybfms.git#egg=pybfms -e git+https://github.com/pybfms/wishbone_bfms.git#egg=wishbone_bfms +-e git+https://github.com/pybfms/pybfms_logic_analyzer.git#egg=pybfms-logic-analyzer
diff --git a/rtl/spram.v b/rtl/spram.v deleted file mode 100644 index 3eb911e..0000000 --- a/rtl/spram.v +++ /dev/null
@@ -1,35 +0,0 @@ - -module spram_byte_en #( - parameter ADDR_BITS = 9, // 8=1KB 9=2KB 10=4KB - parameter DATA_BITS = 32 - ) ( - input clock, - // Port A - input [ADDR_BITS-1:0] a_adr, - input [DATA_BITS-1:0] a_dat_i, - output reg [DATA_BITS-1:0] a_dat_o, - input a_we, - input [DATA_BITS/8-1:0] a_sel - - ); - - reg[7:0] ram_0[(1 << ADDR_BITS)-1:0]; - reg[7:0] ram_1[(1 << ADDR_BITS)-1:0]; - reg[7:0] ram_2[(1 << ADDR_BITS)-1:0]; - reg[7:0] ram_3[(1 << ADDR_BITS)-1:0]; - - always @(posedge clock) begin - if (a_we) begin - if (a_sel[0]) ram_0[a_adr] <= a_dat_i[7:0]; - if (a_sel[1]) ram_1[a_adr] <= a_dat_i[15:8]; - if (a_sel[2]) ram_2[a_adr] <= a_dat_i[23:16]; - if (a_sel[3]) ram_3[a_adr] <= a_dat_i[31:24]; - end - a_dat_o[7:0] <= ram_0[a_adr]; - a_dat_o[15:8] <= ram_1[a_adr]; - a_dat_o[23:16] <= ram_2[a_adr]; - a_dat_o[31:24] <= ram_2[a_adr]; - end - -endmodule -
diff --git a/rtl/fwpayload.v b/verilog/rtl/fwpayload.v similarity index 65% rename from rtl/fwpayload.v rename to verilog/rtl/fwpayload.v index 9ad390f..f585e22 100644 --- a/rtl/fwpayload.v +++ b/verilog/rtl/fwpayload.v
@@ -48,12 +48,95 @@ ); wire clk, rst; + + // System interconnect + localparam N_INITIATORS = 3; + localparam INIT_ID_CORE_I = 0; + localparam INIT_ID_CORE_D = 1; + localparam INIT_ID_MGMT = 2; + + localparam N_TARGETS = 1; + localparam TGT_ID_SRAM = 0; + wire[31:0] IC_I_ADR[N_INITIATORS-1:0]; + wire[31:0] IC_I_DAT_W[N_INITIATORS-1:0]; + wire[31:0] IC_I_DAT_R[N_INITIATORS-1:0]; + wire IC_I_CYC[N_INITIATORS-1:0]; + wire IC_I_ERR[N_INITIATORS-1:0]; + wire[3:0] IC_I_SEL[N_INITIATORS-1:0]; + wire IC_I_STB[N_INITIATORS-1:0]; + wire IC_I_ACK[N_INITIATORS-1:0]; + wire IC_I_WE[N_INITIATORS-1:0]; + + wire[31:0] IC_T_ADR[N_TARGETS:0]; + wire[31:0] IC_T_DAT_W[N_TARGETS:0]; + wire[31:0] IC_T_DAT_R[N_TARGETS:0]; + wire IC_T_CYC[N_TARGETS:0]; + wire IC_T_ERR[N_TARGETS:0]; + wire[3:0] IC_T_SEL[N_TARGETS:0]; + wire IC_T_STB[N_TARGETS:0]; + wire IC_T_ACK[N_TARGETS:0]; + wire IC_T_WE[N_TARGETS:0]; + + assign IC_T_ACK[N_TARGETS] = 1; + assign IC_T_ERR[N_TARGETS] = 1; + assign IC_T_DAT_R[N_TARGETS] = 0; + + // Interconnect + wb_interconnect_NxN #( + .WB_ADDR_WIDTH(32), + .WB_DATA_WIDTH(32), + .N_INITIATORS(N_INITIATORS), + .N_TARGETS(N_TARGETS), + .I_ADR_MASK({ + { 8'hFF, {24{1'b0}} } + }), + .T_ADR({ + { 32'h8000_0000 } + }) + ) 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) + ); + + /**************************************************************** + * Connect management interface to port 1 on the interconnect + ****************************************************************/ + assign IC_I_ADR[INIT_ID_MGMT] = wbs_adr_i; + assign IC_I_DAT_W[INIT_ID_MGMT] = wbs_dat_i; + assign wbs_dat_o = IC_I_DAT_R[INIT_ID_MGMT]; + assign IC_I_CYC[INIT_ID_MGMT] = wbs_cyc_i; +// assign IC_I_ERR[INIT_ID_MGMT] = //wbs_cyc_i; + assign IC_I_SEL[INIT_ID_MGMT] = 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; // 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 clk = (~la_oen[127]) ? la_data_in[127]: wb_clk_i; +// assign rst = (~la_oen[126]) ? la_data_in[126]: wb_rst_i; + assign clk = wb_clk_i; + assign rst = wb_rst_i; wire[31:0] iaddr; reg[31:0] idata; @@ -70,8 +153,6 @@ localparam RAM_BITS = 8; localparam ROM_BITS = 8; -`ifdef UNDEFINED -`endif fwrisc_rv32i u_core ( .clock(clk), .reset(rst), @@ -89,6 +170,7 @@ .drdata(drdata), .dready(dready) ); + // Probes // - PC @@ -135,7 +217,7 @@ reg[7:0] ram_2[(1 << RAM_BITS)-1:0]; // 16k ram reg[7:0] ram_3[(1 << RAM_BITS)-1:0]; // 16k ram reg[31:0] rom[(1 << ROM_BITS)-1:0]; // 16k rom - reg[31:0] led; +// reg[31:0] led; reg[31:0] tx_r; reg iready_r, dready_r; @@ -189,28 +271,54 @@ end /**************************************************************** - * Simple WB to storage bridge + * Simple WB to SRAM bridge ****************************************************************/ reg[1:0] wb_bridge_state = 0; + wire[31:0] sram_adr_i = IC_T_ADR[TGT_ID_SRAM]; + wire[31:0] sram_dat_w = IC_T_DAT_W[TGT_ID_SRAM]; + wire[31:0] sram_dat_r; + assign IC_T_DAT_R[TGT_ID_SRAM] = 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[TGT_ID_SRAM]; + 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]; always @(posedge wb_clk_i) begin - if (wb_rst_i == 1) begin + if (rst == 1) begin wb_bridge_state <= 0; end else begin case (wb_bridge_state) 0: - if (wbs_cyc_i && wbs_stb_i) begin + if (sram_cyc_i && sram_stb_i) begin wb_bridge_state <= 1; end 1: wb_bridge_state <= 2; 2: + wb_bridge_state <= 3; + 3: wb_bridge_state <= 0; default: wb_bridge_state <= 0; endcase end end + + /**************************************************************** + * SRAM + ****************************************************************/ + spram_32x256 u_sram( + .clock(clk), + .a_adr(sram_adr_i), + .a_dat_i(sram_dat_w), + .a_dat_o(sram_dat_r), + .a_we(sram_we_i), + .a_sel(sram_sel_i)); + assign sram_ack_o = (wb_bridge_state == 3); + wire [31:0] storage_mgmt_addr = wbs_adr_i; // [ADDRESS_WIDTH+(DATA_WIDTH/32):(DATA_WIDTH/32)+1]; wire storage_mgmt_rd_en = (wbs_cyc_i & wbs_stb_i & !wbs_we_i);
diff --git a/verilog/rtl/simple_spi_master.v b/verilog/rtl/simple_spi_master.v new file mode 100755 index 0000000..4cf8b46 --- /dev/null +++ b/verilog/rtl/simple_spi_master.v
@@ -0,0 +1,390 @@ +//---------------------------------------------------------------------------- +// Module: simple_spi_master +// +//---------------------------------------------------------------------------- +// Copyright (C) 2019 efabless, inc. +// +// This source file may be used and distributed without +// restriction provided that this copyright statement is not +// removed from the file and that any derivative work contains +// the original copyright notice and the associated disclaimer. +// +// This source file is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; +// either version 2.1 of the License, or (at your option) any +// later version. +// +// This source is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the GNU Lesser General Public License for more +// details. +// +//-------------------------------------------------------------------- +// +// resetn: active low async reset +// clk: master clock (before prescaler) +// stream: +// 0 = apply/release CSB separately for each byte +// 1 = apply CSB until stream bit is cleared +// mlb: +// 0 = msb 1st +// 1 = lsb 1st +// invsck: +// 0 = normal SCK +// 1 = inverted SCK +// invcsb: +// 0 = normal CSB (active low) +// 1 = inverted CSB (active high) +// mode: +// 0 = read and change data on opposite SCK edges +// 1 = read and change data on the same SCK edge +// enable: +// 0 = disable the SPI master +// 1 = enable the SPI master +// irqena: +// 0 = disable interrupt +// 1 = enable interrupt +// hkconn: +// 0 = housekeeping SPI disconnected +// 1 = housekeeping SPI connected (when SPI master enabled) +// prescaler: count (in master clock cycles) of 1/2 SCK cycle. +// +// reg_dat_we: +// 1 = data write enable +// reg_dat_re: +// 1 = data read enable +// reg_cfg_*: Signaling for read/write of configuration register +// reg_dat_*: Signaling for read/write of data register +// +// err_out: Indicates attempt to read/write before data ready +// (failure to wait for reg_dat_wait to clear) +// +// Between "mode" and "invsck", all four standard SPI modes are supported +// +//-------------------------------------------------------------------- + +module simple_spi_master_wb #( + parameter BASE_ADR = 32'h2100_0000, + parameter CONFIG = 8'h00, + parameter DATA = 8'h04 +) ( + input wb_clk_i, + input wb_rst_i, + input [31:0] wb_adr_i, + input [31:0] wb_dat_i, + input [3:0] wb_sel_i, + input wb_we_i, + input wb_cyc_i, + input wb_stb_i, + output wb_ack_o, + output [31:0] wb_dat_o, + + output hk_connect, // Connect to housekeeping SPI + input sdi, // SPI input + output csb, // SPI chip select + output sck, // SPI clock + output sdo, // SPI output + output sdoenb, // SPI output enable + output irq // interrupt output +); + + wire [31:0] simple_spi_master_reg_cfg_do; + wire [31:0] simple_spi_master_reg_dat_do; + + wire resetn = ~wb_rst_i; + wire valid = wb_stb_i && wb_cyc_i; + wire simple_spi_master_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG)); + wire simple_spi_master_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA)); + + wire [1:0] reg_cfg_we = (simple_spi_master_reg_cfg_sel) ? + (wb_sel_i[1:0] & {2{wb_we_i}}): 2'b00; + wire reg_dat_we = (simple_spi_master_reg_dat_sel) ? (wb_sel_i[0] & wb_we_i): 1'b0; + wire reg_dat_wait; + + wire [31:0] mem_wdata = wb_dat_i; + wire reg_dat_re = simple_spi_master_reg_dat_sel && !wb_sel_i && ~wb_we_i; + + assign wb_dat_o = (simple_spi_master_reg_cfg_sel) ? simple_spi_master_reg_cfg_do : + simple_spi_master_reg_dat_do; + assign wb_ack_o = (simple_spi_master_reg_cfg_sel || simple_spi_master_reg_dat_sel) + && (!reg_dat_wait); + + simple_spi_master spi_master ( + .resetn(resetn), + .clk(wb_clk_i), + .reg_cfg_we(reg_cfg_we), + .reg_cfg_di(mem_wdata), + .reg_cfg_do(simple_spi_master_reg_cfg_do), + .reg_dat_we(reg_dat_we), + .reg_dat_re(reg_dat_re), + .reg_dat_di(mem_wdata), + .reg_dat_do(simple_spi_master_reg_dat_do), + .reg_dat_wait(reg_dat_wait), + + .hk_connect(hk_connect), // Attach to housekeeping SPI slave + .sdi(sdi), // SPI input + .csb(csb), // SPI chip select + .sck(sck), // SPI clock + .sdo(sdo), // SPI output + .irq_out(irq) // interrupt + ); +endmodule + +module simple_spi_master ( + input resetn, + input clk, // master clock (assume 100MHz) + + input [1:0] reg_cfg_we, + input [31:0] reg_cfg_di, + output [31:0] reg_cfg_do, + + input reg_dat_we, + input reg_dat_re, + input [31:0] reg_dat_di, + output [31:0] reg_dat_do, + output reg_dat_wait, + output irq_out, + output err_out, + + output hk_connect, // Connect to housekeeping SPI + input sdi, // SPI input + output csb, // SPI chip select + output sck, // SPI clock + output sdo // SPI output +); + + parameter IDLE = 2'b00; + parameter SENDL = 2'b01; + parameter SENDH = 2'b10; + parameter FINISH = 2'b11; + + reg done; + reg isdo, hsck, icsb; + reg [1:0] state; + reg isck; + reg err_out; + + reg [7:0] treg, rreg, d_latched; + reg [2:0] nbit; + + reg [7:0] prescaler; + reg [7:0] count; + reg invsck; + reg invcsb; + reg mlb; + reg irqena; + reg stream; + reg mode; + 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; + + // No bidirectional 3-pin mode defined, so SDO is enabled whenever CSB is low. + assign sdoenb = icsb; + // assign sdo = (enable == 1'b0) ? 1'bz : icsb ? 1'bz : isdo; + assign sdo = (enable == 1'b0) ? 1'bz : isdo; + + assign irq_out = irqena & done; + assign hk_connect = (enable == 1'b1) ? hkconn : 1'b0; + + // Read configuration and data registers + assign reg_cfg_do = {16'd0, hkconn, irqena, enable, stream, mode, + invsck, invcsb, mlb, prescaler}; + assign reg_dat_wait = ~done; + assign reg_dat_do = done ? rreg : ~0; + + // Write configuration register + always @(posedge clk or negedge resetn) begin + if (resetn == 1'b0) begin + prescaler <= 8'd2; + invcsb <= 1'b0; + invsck <= 1'b0; + mlb <= 1'b0; + enable <= 1'b0; + irqena <= 1'b0; + stream <= 1'b0; + mode <= 1'b0; + hkconn <= 1'b0; + end else begin + if (reg_cfg_we[0]) prescaler <= reg_cfg_di[7:0]; + if (reg_cfg_we[1]) begin + mlb <= reg_cfg_di[8]; + invcsb <= reg_cfg_di[9]; + invsck <= reg_cfg_di[10]; + mode <= reg_cfg_di[11]; + stream <= reg_cfg_di[12]; + enable <= reg_cfg_di[13]; + irqena <= reg_cfg_di[14]; + hkconn <= reg_cfg_di[15]; + end //reg_cfg_we[1] + end //resetn + end //always + + // Watch for read and write enables on clk, not hsck, so as not to + // miss them. + + reg w_latched, r_latched; + + always @(posedge clk or negedge resetn) begin + if (resetn == 1'b0) begin + err_out <= 1'b0; + w_latched <= 1'b0; + r_latched <= 1'b0; + d_latched <= 8'd0; + end else begin + // Clear latches on SEND, otherwise latch when seen + if (state == SENDL || state == SENDH) begin + if (reg_dat_we == 1'b0) begin + w_latched <= 1'b0; + end + end else begin + if (reg_dat_we == 1'b1) begin + if (done == 1'b0 && w_latched == 1'b1) begin + err_out <= 1'b1; + end else begin + w_latched <= 1'b1; + d_latched <= reg_dat_di[7:0]; + err_out <= 1'b0; + end + end + end + + if (reg_dat_re == 1'b1) begin + if (r_latched == 1'b1) begin + r_latched <= 1'b0; + end else begin + err_out <= 1'b1; // byte not available + end + end else if (state == FINISH) begin + r_latched <= 1'b1; + end if (state == SENDL || state == SENDH) begin + if (r_latched == 1'b1) begin + err_out <= 1'b1; // last byte was never read + end else begin + r_latched <= 1'b0; + end + end + end + end + + // State transition. + + always @(posedge hsck or negedge resetn) begin + if (resetn == 1'b0) begin + state <= IDLE; + nbit <= 3'd0; + icsb <= 1'b1; + done <= 1'b1; + end else begin + if (state == IDLE) begin + if (w_latched == 1'b1) begin + state <= SENDL; + nbit <= 3'd0; + icsb <= 1'b0; + done <= 1'b0; + end else begin + icsb <= ~stream; + end + end else if (state == SENDL) begin + state <= SENDH; + end else if (state == SENDH) begin + nbit <= nbit + 1; + if (nbit == 3'd7) begin + state <= FINISH; + end else begin + state <= SENDL; + end + end else if (state == FINISH) begin + icsb <= ~stream; + done <= 1'b1; + state <= IDLE; + end + end + end + + // Set up internal clock. The enable bit gates the internal clock + // to shut down the master SPI when disabled. + + always @(posedge clk or negedge resetn) begin + if (resetn == 1'b0) begin + count <= 8'd0; + hsck <= 1'b0; + end else begin + if (enable == 1'b0) begin + count <= 8'd0; + end else begin + count <= count + 1; + if (count == prescaler) begin + hsck <= ~hsck; + count <= 8'd0; + end // count + end // enable + end // resetn + end // always + + // sck is half the rate of hsck + + always @(posedge hsck or negedge resetn) begin + if (resetn == 1'b0) begin + isck <= 1'b0; + end else begin + if (state == IDLE || state == FINISH) + isck <= 1'b0; + else + isck <= ~isck; + end // resetn + end // always + + // Main procedure: read, write, shift data + + always @(posedge hsck or negedge resetn) begin + if (resetn == 1'b0) begin + rreg <= 8'hff; + treg <= 8'hff; + isdo <= 1'b0; + end else begin + if (isck == 1'b0 && (state == SENDL || state == SENDH)) begin + if (mlb == 1'b1) begin + // LSB first, sdi@msb -> right shift + rreg <= {sdi, rreg[7:1]}; + end else begin + // MSB first, sdi@lsb -> left shift + rreg <= {rreg[6:0], sdi}; + end + end // read on ~isck + + if (w_latched == 1'b1) begin + if (mlb == 1'b1) begin + treg <= {1'b1, d_latched[7:1]}; + isdo <= d_latched[0]; + end else begin + treg <= {d_latched[6:0], 1'b1}; + isdo <= d_latched[7]; + end // mlb + end else if ((mode ^ isck) == 1'b1) begin + if (mlb == 1'b1) begin + // LSB first, shift right + treg <= {1'b1, treg[7:1]}; + isdo <= treg[0]; + end else begin + // MSB first shift LEFT + treg <= {treg[6:0], 1'b1}; + isdo <= treg[7]; + end // mlb + end // write on mode ^ isck + end // resetn + end // always + +endmodule
diff --git a/verilog/rtl/simpleuart.v b/verilog/rtl/simpleuart.v new file mode 100644 index 0000000..96b3b4e --- /dev/null +++ b/verilog/rtl/simpleuart.v
@@ -0,0 +1,220 @@ +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +module simpleuart_wb # ( + parameter BASE_ADR = 32'h 2000_0000, + parameter CLK_DIV = 8'h00, + parameter DATA = 8'h04, + parameter CONFIG = 8'h08 +) ( + input wb_clk_i, + input wb_rst_i, + + input [31:0] wb_adr_i, // (verify): input address was originaly 22 bits , why ? (max number of words ?) + input [31:0] wb_dat_i, + input [3:0] wb_sel_i, + input wb_we_i, + input wb_cyc_i, + input wb_stb_i, + + output wb_ack_o, + output [31:0] wb_dat_o, + + output uart_enabled, + output ser_tx, + input ser_rx + +); + wire [31:0] simpleuart_reg_div_do; + wire [31:0] simpleuart_reg_dat_do; + wire [31:0] simpleuart_reg_cfg_do; + + wire resetn = ~wb_rst_i; + wire valid = wb_stb_i && wb_cyc_i; + wire simpleuart_reg_div_sel = valid && (wb_adr_i == (BASE_ADR | CLK_DIV)); + wire simpleuart_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA)); + wire simpleuart_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG)); + + wire [3:0] reg_div_we = simpleuart_reg_div_sel ? (wb_sel_i & {4{wb_we_i}}): 4'b 0000; + wire reg_dat_we = simpleuart_reg_dat_sel ? (wb_sel_i[0] & wb_we_i): 1'b 0; // simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0 + wire reg_cfg_we = simpleuart_reg_cfg_sel ? (wb_sel_i[0] & wb_we_i): 1'b 0; + + wire [31:0] mem_wdata = wb_dat_i; + wire reg_dat_re = simpleuart_reg_dat_sel && !wb_sel_i && ~wb_we_i; // read_enable + + wire reg_dat_wait; + + assign wb_dat_o = simpleuart_reg_div_sel ? simpleuart_reg_div_do: + simpleuart_reg_cfg_sel ? simpleuart_reg_cfg_do: + simpleuart_reg_dat_do; + assign wb_ack_o = (simpleuart_reg_div_sel || simpleuart_reg_dat_sel + || simpleuart_reg_cfg_sel) && (!reg_dat_wait); + + simpleuart simpleuart ( + .clk (wb_clk_i), + .resetn (resetn), + + .ser_tx (ser_tx), + .ser_rx (ser_rx), + .enabled (uart_enabled), + + .reg_div_we (reg_div_we), + .reg_div_di (mem_wdata), + .reg_div_do (simpleuart_reg_div_do), + + .reg_cfg_we (reg_cfg_we), + .reg_cfg_di (mem_wdata), + .reg_cfg_do (simpleuart_reg_cfg_do), + + .reg_dat_we (reg_dat_we), + .reg_dat_re (reg_dat_re), + .reg_dat_di (mem_wdata), + .reg_dat_do (simpleuart_reg_dat_do), + .reg_dat_wait(reg_dat_wait) + ); + +endmodule + +module simpleuart ( + input clk, + input resetn, + + output enabled, + output ser_tx, + input ser_rx, + + input [3:0] reg_div_we, + input [31:0] reg_div_di, + output [31:0] reg_div_do, + + input reg_cfg_we, + input [31:0] reg_cfg_di, + output [31:0] reg_cfg_do, + + input reg_dat_we, + input reg_dat_re, + input [31:0] reg_dat_di, + output [31:0] reg_dat_do, + output reg_dat_wait +); + reg [31:0] cfg_divider; + reg enabled; + + reg [3:0] recv_state; + reg [31:0] recv_divcnt; + reg [7:0] recv_pattern; + reg [7:0] recv_buf_data; + reg recv_buf_valid; + + reg [9:0] send_pattern; + reg [3:0] send_bitcnt; + reg [31:0] send_divcnt; + reg send_dummy; + + assign reg_div_do = cfg_divider; + assign reg_ena_do = {31'd0, enabled}; + + assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); + assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; + + always @(posedge clk) begin + if (!resetn) begin + cfg_divider <= 1; + enabled <= 1'b0; + end else begin + if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0]; + if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8]; + if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16]; + if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24]; + if (reg_cfg_we) enabled <= reg_div_di[0]; + end + end + + always @(posedge clk) begin + if (!resetn) begin + recv_state <= 0; + recv_divcnt <= 0; + recv_pattern <= 0; + recv_buf_data <= 0; + recv_buf_valid <= 0; + end else begin + recv_divcnt <= recv_divcnt + 1; + if (reg_dat_re) + recv_buf_valid <= 0; + case (recv_state) + 0: begin + if (!ser_rx && enabled) + recv_state <= 1; + recv_divcnt <= 0; + end + 1: begin + if (2*recv_divcnt > cfg_divider) begin + recv_state <= 2; + recv_divcnt <= 0; + end + end + 10: begin + if (recv_divcnt > cfg_divider) begin + recv_buf_data <= recv_pattern; + recv_buf_valid <= 1; + recv_state <= 0; + end + end + default: begin + if (recv_divcnt > cfg_divider) begin + recv_pattern <= {ser_rx, recv_pattern[7:1]}; + recv_state <= recv_state + 1; + recv_divcnt <= 0; + end + end + endcase + end + end + + assign ser_tx = send_pattern[0]; + + always @(posedge clk) begin + if (reg_div_we && enabled) + send_dummy <= 1; + send_divcnt <= send_divcnt + 1; + if (!resetn) begin + send_pattern <= ~0; + send_bitcnt <= 0; + send_divcnt <= 0; + send_dummy <= 1; + end else begin + if (send_dummy && !send_bitcnt) begin + send_pattern <= ~0; + send_bitcnt <= 15; + send_divcnt <= 0; + send_dummy <= 0; + end else + if (reg_dat_we && !send_bitcnt) begin + send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0}; + send_bitcnt <= 10; + send_divcnt <= 0; + end else + if (send_divcnt > cfg_divider && send_bitcnt) begin + send_pattern <= {1'b1, send_pattern[9:1]}; + send_bitcnt <= send_bitcnt - 1; + send_divcnt <= 0; + end + end + end +endmodule
diff --git a/verilog/rtl/spram.v b/verilog/rtl/spram.v new file mode 100644 index 0000000..7961565 --- /dev/null +++ b/verilog/rtl/spram.v
@@ -0,0 +1,33 @@ + +module spram_byte_en #( + parameter ADDR_BITS = 9, // 8=1KB 9=2KB 10=4KB + parameter DATA_BITS = 32 + ) ( + input clock, + // Port A + input [ADDR_BITS-1:0] a_adr, + input [DATA_BITS-1:0] a_dat_i, + output reg [DATA_BITS-1:0] a_dat_o, + input a_we, + input [DATA_BITS/8-1:0] a_sel); + + reg[7:0] ram_0[(1 << ADDR_BITS)-1:0]; + reg[7:0] ram_1[(1 << ADDR_BITS)-1:0]; + reg[7:0] ram_2[(1 << ADDR_BITS)-1:0]; + reg[7:0] ram_3[(1 << ADDR_BITS)-1:0]; + + always @(posedge clock) begin + if (a_we) begin + if (a_sel[0]) ram_0[a_adr[ADDR_BITS-1:2]] <= a_dat_i[7:0]; + if (a_sel[1]) ram_1[a_adr[ADDR_BITS-1:2]] <= a_dat_i[15:8]; + if (a_sel[2]) ram_2[a_adr[ADDR_BITS-1:2]] <= a_dat_i[23:16]; + if (a_sel[3]) ram_3[a_adr[ADDR_BITS-1:2]] <= a_dat_i[31:24]; + end + a_dat_o[7:0] <= ram_0[a_adr[ADDR_BITS-1:2]]; + a_dat_o[15:8] <= ram_1[a_adr[ADDR_BITS-1:2]]; + a_dat_o[23:16] <= ram_2[a_adr[ADDR_BITS-1:2]]; + a_dat_o[31:24] <= ram_3[a_adr[ADDR_BITS-1:2]]; + end + +endmodule +
diff --git a/verilog/rtl/spram_32x256.sv b/verilog/rtl/spram_32x256.sv new file mode 100644 index 0000000..cea0682 --- /dev/null +++ b/verilog/rtl/spram_32x256.sv
@@ -0,0 +1,31 @@ +/**************************************************************************** + * spram_32x256.sv + ****************************************************************************/ + +/** + * Module: spram_32x256 + * + * TODO: Add module documentation + */ +module spram_32x256( + 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(8), + .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/rtl/user_project_wrapper.v b/verilog/rtl/user_project_wrapper.v similarity index 100% rename from rtl/user_project_wrapper.v rename to verilog/rtl/user_project_wrapper.v
diff --git a/verilog/rtl/wb_interconnect_NxN.sv b/verilog/rtl/wb_interconnect_NxN.sv new file mode 100644 index 0000000..b87cf56 --- /dev/null +++ b/verilog/rtl/wb_interconnect_NxN.sv
@@ -0,0 +1,321 @@ +/**************************************************************************** + * ${NAME}.sv + ****************************************************************************/ + +/** + * Module: wb_interconnect_NxN + * + * TODO: Add module documentation + */ +module wb_interconnect_NxN #( + parameter int WB_ADDR_WIDTH=32, + parameter int unsigned WB_DATA_WIDTH=32, + parameter int unsigned N_INITIATORS=1, + parameter int unsigned N_TARGETS=1, + parameter bit [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-1:0] ADR[N_INITIATORS-1:0], + input[WB_DATA_WIDTH-1:0] DAT_W[N_INITIATORS-1:0], + output[WB_DATA_WIDTH-1:0] DAT_R[N_INITIATORS-1:0], + input CYC[N_INITIATORS-1:0], + output ERR[N_INITIATORS-1:0], + input[(WB_DATA_WIDTH/8)-1:0] SEL[N_INITIATORS-1:0], + input STB[N_INITIATORS-1:0], + output ACK[N_INITIATORS-1:0], + input WE[N_INITIATORS-1:0], + + output[WB_ADDR_WIDTH-1:0] TADR[N_TARGETS:0], + output[WB_DATA_WIDTH-1:0] TDAT_W[N_TARGETS:0], + input[WB_DATA_WIDTH-1:0] TDAT_R[N_TARGETS:0], + output TCYC[N_TARGETS:0], + input TERR[N_TARGETS:0], + output[(WB_DATA_WIDTH/8)-1:0] TSEL[N_TARGETS:0], + output TSTB[N_TARGETS:0], + input TACK[N_TARGETS:0], + output TWE[N_TARGETS:0] + ); + + localparam int WB_DATA_MSB = (WB_DATA_WIDTH-1); + localparam int N_INIT_ID_BITS = (N_INITIATORS>1)?$clog2(N_INITIATORS):1; + localparam int N_TARG_ID_BITS = $clog2(N_TARGETS+1); + localparam bit[N_TARG_ID_BITS:0] NO_TARGET = {(N_TARG_ID_BITS+1){1'b1}}; + localparam bit[N_INIT_ID_BITS:0] 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( + reg[N_INIT_ID_BITS-1:0] initiator, + reg[WB_ADDR_WIDTH-1:0] addr + ); +// $display("addr2targ_id: 'h%08h 'h%08h", addr, ADDR_RANGES); + for (int 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); + return N_TARGETS-1; + end + end + $display("%t: Address 'h%08h - decode fail", $time, addr); + return (N_TARGETS); + endfunction + +// Read request state machine + + // Master 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++) 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[m_i] + ); +// $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++) begin : block_m_req_i + for (m_req_j=0; m_req_j < N_INITIATORS; m_req_j++) 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++) 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++) 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++) begin : block_s2m_i + assign DAT_R[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)? + TDAT_R[initiator_selected_target[s2m_i]]: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++) begin : WB_M2S_assign + assign TADR[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:ADR[target_active_initiator[m2s_i]]; + assign TDAT_W[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:DAT_W[target_active_initiator[m2s_i]]; + assign TCYC[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:CYC[target_active_initiator[m2s_i]]; + assign TSEL[m2s_i] = (target_active_initiator[m2s_i] == NO_INITIATOR)?0:SEL[target_active_initiator[m2s_i]]; + 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 int 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--) 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++) 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++) 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(reg[N_REQ-1:0] gnt); + automatic int i; + reg[$clog2(N_REQ)-1:0] result; + + result = 0; + + for (i=0; i<N_REQ; i++) begin + if (gnt[i]) begin + result |= i; + end + end + + return result; + endfunction + +endmodule