From db61ca2d74a8a59386fd1e7600fa55f47b37091d Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Sat, 18 Apr 2026 18:50:18 -0700 Subject: [PATCH] Create project --- .gitignore | 2 + .gitmodules | 6 + init_env.sh | 10 + requirements.txt | 12 + sim/sources.list | 27 ++ sim/sub/taxi | 1 + sim/sub/verilog-6502 | 1 + sim/verilator.vlt | 7 + sim/verilog6502_wrapper.yaml | 9 + sim/verilog6502_wrapper_tb.sv | 30 +++ sim/verilog6502_wrapper_test.py | 48 ++++ src/fpga6502.sv | 387 ++++++++++++++++++++++++++++ src/regs/gen_regs.sh | 1 + src/regs/verilog6502_io_regs.rdl | 60 +++++ src/regs/verilog6502_io_regs.sv | 340 ++++++++++++++++++++++++ src/regs/verilog6502_io_regs_pkg.sv | 53 ++++ src/verilog6502_addr_decoder.sv | 124 +++++++++ src/verilog6502_apb_adapter.sv | 116 +++++++++ src/verilog6502_external_memory.sv | 61 +++++ src/verilog6502_internal_memory.sv | 226 ++++++++++++++++ src/verilog6502_wrapper.sv | 205 +++++++++++++++ 21 files changed, 1726 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 init_env.sh create mode 100644 requirements.txt create mode 100644 sim/sources.list create mode 160000 sim/sub/taxi create mode 160000 sim/sub/verilog-6502 create mode 100644 sim/verilator.vlt create mode 100644 sim/verilog6502_wrapper.yaml create mode 100644 sim/verilog6502_wrapper_tb.sv create mode 100644 sim/verilog6502_wrapper_test.py create mode 100644 src/fpga6502.sv create mode 100755 src/regs/gen_regs.sh create mode 100644 src/regs/verilog6502_io_regs.rdl create mode 100644 src/regs/verilog6502_io_regs.sv create mode 100644 src/regs/verilog6502_io_regs_pkg.sv create mode 100644 src/verilog6502_addr_decoder.sv create mode 100644 src/verilog6502_apb_adapter.sv create mode 100644 src/verilog6502_external_memory.sv create mode 100644 src/verilog6502_internal_memory.sv create mode 100644 src/verilog6502_wrapper.sv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0eb1c57 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +sim_build +__pycache__ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fb5d0f4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "sim/sub/taxi"] + path = sim/sub/taxi + url = git@git.byronlathi.com:bslathi19/taxi.git +[submodule "sim/sub/verilog-6502"] + path = sim/sub/verilog-6502 + url = git@git.byronlathi.com:third-party/verilog-6502.git diff --git a/init_env.sh b/init_env.sh new file mode 100644 index 0000000..820e49f --- /dev/null +++ b/init_env.sh @@ -0,0 +1,10 @@ +export REPO_TOP=$(git rev-parse --show-toplevel) + +python3.13 -m venv .user_venv +. .user_venv/bin/activate + +pip install -r requirements.txt + +export PYTHON3=$(which python) + +module load verilator \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e9f96e2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +peakrdl +rtl-manifest +cocotb +cocotb-bus +cocotbext-axi>=0.1.30 +cocotbext-eth>=0.1.24 +pytest +fpga-sim>=0.5.4 +build_fpga +git+https://github.com/arnavsacheti/PeakRDL-BusDecoder.git +peakrdl-python-regmap>=0.0.5 +taxi-peakrdl-extensions diff --git a/sim/sources.list b/sim/sources.list new file mode 100644 index 0000000..357fd5b --- /dev/null +++ b/sim/sources.list @@ -0,0 +1,27 @@ +verilator.vlt +verilog6502_wrapper_tb.sv + +../src/regs/verilog6502_io_regs_pkg.sv +../src/regs/verilog6502_io_regs.sv + +../src/verilog6502_addr_decoder.sv +../src/verilog6502_internal_memory.sv +../src/verilog6502_apb_adapter.sv +../src/verilog6502_external_memory.sv +../src/verilog6502_wrapper.sv + + +sub/verilog-6502/ALU.v +sub/verilog-6502/cpu_65c02.v + +sub/taxi/src/apb/rtl/taxi_apb_if.sv +sub/taxi/src/axi/rtl/taxi_axi_if.sv +sub/taxi/src/axi/rtl/taxi_axil_if.sv +sub/taxi/src/axi/rtl/taxi_axi_ram_if_rd.sv +sub/taxi/src/axi/rtl/taxi_axi_ram_if_wr.sv +sub/taxi/src/axi/rtl/taxi_axi_ram_if_rdwr.sv +sub/taxi/src/apb/rtl/taxi_apb_interconnect.sv +sub/taxi/src/apb/rtl/taxi_apb_tie.sv +sub/taxi/src/prim/rtl/taxi_arbiter.sv +sub/taxi/src/prim/rtl/taxi_penc.sv +sub/taxi/src/apb/rtl/taxi_apb_axil_adapter.sv \ No newline at end of file diff --git a/sim/sub/taxi b/sim/sub/taxi new file mode 160000 index 0000000..1fe508a --- /dev/null +++ b/sim/sub/taxi @@ -0,0 +1 @@ +Subproject commit 1fe508a6bf17edbb29bce9a8477be615b1012789 diff --git a/sim/sub/verilog-6502 b/sim/sub/verilog-6502 new file mode 160000 index 0000000..8f19e45 --- /dev/null +++ b/sim/sub/verilog-6502 @@ -0,0 +1 @@ +Subproject commit 8f19e45b40f546e8b0fa58d43c1208d151652984 diff --git a/sim/verilator.vlt b/sim/verilator.vlt new file mode 100644 index 0000000..6ea35fc --- /dev/null +++ b/sim/verilator.vlt @@ -0,0 +1,7 @@ +`verilator_config + +lint_off -file "**/ALU.v" +lint_off -file "**/cpu_65c02.v" +lint_off -rule MULTIDRIVEN -file "**/verilog6502_io_regs.sv" +lint_off -rule UNOPTFLAT +lint_off -rule TIMESCALEMOD \ No newline at end of file diff --git a/sim/verilog6502_wrapper.yaml b/sim/verilog6502_wrapper.yaml new file mode 100644 index 0000000..549c201 --- /dev/null +++ b/sim/verilog6502_wrapper.yaml @@ -0,0 +1,9 @@ +tests: + - name: "verilog6502_wrapper" + toplevel: "verilog6502_wrapper_tb" + modules: + - "verilog6502_wrapper_test" + sources: "sources.list" + waves: True + defines: + SIM: "hi" \ No newline at end of file diff --git a/sim/verilog6502_wrapper_tb.sv b/sim/verilog6502_wrapper_tb.sv new file mode 100644 index 0000000..8eea85f --- /dev/null +++ b/sim/verilog6502_wrapper_tb.sv @@ -0,0 +1,30 @@ +module verilog6502_wrapper_tb(); + +`define SIM + +taxi_apb_if s_apb(); +taxi_axil_if m_axil(); +taxi_axi_if s_axi(); + +logic clk; +logic rst; + +logic o_irq_ext; +logic i_irq_ext; +logic i_nmi_ext; + + +verilog6502_wrapper u_dut( + .clk(clk), + .rst(rst), + .s_apb(s_apb), + .m_axil_rd(m_axil), + .m_axil_wr(m_axil), + .s_axi_rd(s_axi), + .s_axi_wr(s_axi), + .o_irq_ext(o_irq_ext), + .i_irq_ext(i_irq_ext), + .i_nmi_ext(i_nmi_ext) +); + +endmodule \ No newline at end of file diff --git a/sim/verilog6502_wrapper_test.py b/sim/verilog6502_wrapper_test.py new file mode 100644 index 0000000..f24348e --- /dev/null +++ b/sim/verilog6502_wrapper_test.py @@ -0,0 +1,48 @@ +import cocotb +from cocotb.handle import Immediate + +from cocotb.clock import Clock +from cocotb.triggers import Timer, RisingEdge + +from cocotbext.axi.apb import ApbMaster, ApbBus +from cocotbext.axi import AxiMaster, AxiBus, AxiLiteBus, AxiLiteRam + + + +CLK_PERIOD = 5 + + +@cocotb.test +async def test_sanity(dut): + print("Hello world") + cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) + + s_apb = ApbMaster(ApbBus.from_prefix(dut.s_apb, ""), dut.clk, dut.rst) + + s_axi = AxiMaster(AxiBus.from_prefix(dut.s_axi, ""), dut.clk, dut.rst) + m_axil = AxiLiteRam(AxiLiteBus.from_prefix(dut.m_axil, ""), dut.clk, dut.rst, size=2**32) + + m_axil.write(0, b"Hello, world!") + + + dut.rst.value = Immediate(1) + for _ in range(10): + await RisingEdge(dut.clk) + dut.rst.value = 0 + for _ in range(10): + await RisingEdge(dut.clk) + + # await s_axi.write(0x200, [0x58, 0xa9, 0x00, 0x1a, 0xcb, 0x4c, 0x03, 0x02]) + await s_axi.write(0x200, [0xAD, 0x00, 0xE0, 0xAD, 0x01, 0xE0, 0xAD, 0x02, 0xE0, 0xAD, 0x03, 0xE0, 0xAD, 0x04, 0xE0, 0xCB]) + + cocotb.start_soon(s_axi.read(0x200, 8)) + + await Timer(10, "us") + + await s_apb.write_dword(0x0, 0) + + await Timer(1, "us") + + dut.i_nmi_ext.value = Immediate(1) + + await Timer(1, "us") \ No newline at end of file diff --git a/src/fpga6502.sv b/src/fpga6502.sv new file mode 100644 index 0000000..996362e --- /dev/null +++ b/src/fpga6502.sv @@ -0,0 +1,387 @@ +module fpga6502 ( + output jtagCtrl_tdi, + input jtagCtrl_tdo, + output jtagCtrl_enable, + output jtagCtrl_capture, + output jtagCtrl_shift, + output jtagCtrl_update, + output jtagCtrl_reset, + input ut_jtagCtrl_tdi, + output ut_jtagCtrl_tdo, + input ut_jtagCtrl_enable, + input ut_jtagCtrl_capture, + input ut_jtagCtrl_shift, + input ut_jtagCtrl_update, + input ut_jtagCtrl_reset, + input io_cfuClk, + input io_cfuReset, + input cpu0_customInstruction_cmd_valid, + output cpu0_customInstruction_cmd_ready, + input [9:0] cpu0_customInstruction_function_id, + input [31:0] cpu0_customInstruction_inputs_0, + input [31:0] cpu0_customInstruction_inputs_1, + output cpu0_customInstruction_rsp_valid, + input cpu0_customInstruction_rsp_ready, + output [31:0] cpu0_customInstruction_outputs_0, + input cpu1_customInstruction_cmd_valid, + output cpu1_customInstruction_cmd_ready, + input [9:0] cpu1_customInstruction_function_id, + input [31:0] cpu1_customInstruction_inputs_0, + input [31:0] cpu1_customInstruction_inputs_1, + output cpu1_customInstruction_rsp_valid, + input cpu1_customInstruction_rsp_ready, + output [31:0] cpu1_customInstruction_outputs_0, + input cpu2_customInstruction_cmd_valid, + output cpu2_customInstruction_cmd_ready, + input [9:0] cpu2_customInstruction_function_id, + input [31:0] cpu2_customInstruction_inputs_0, + input [31:0] cpu2_customInstruction_inputs_1, + output cpu2_customInstruction_rsp_valid, + input cpu2_customInstruction_rsp_ready, + output [31:0] cpu2_customInstruction_outputs_0, + input cpu3_customInstruction_cmd_valid, + output cpu3_customInstruction_cmd_ready, + input [9:0] cpu3_customInstruction_function_id, + input [31:0] cpu3_customInstruction_inputs_0, + input [31:0] cpu3_customInstruction_inputs_1, + output cpu3_customInstruction_rsp_valid, + input cpu3_customInstruction_rsp_ready, + output [31:0] cpu3_customInstruction_outputs_0, + output io_ddrMasters_0_aw_valid, + input io_ddrMasters_0_aw_ready, + output [31:0] io_ddrMasters_0_aw_payload_addr, + output [3:0] io_ddrMasters_0_aw_payload_id, + output [3:0] io_ddrMasters_0_aw_payload_region, + output [7:0] io_ddrMasters_0_aw_payload_len, + output [2:0] io_ddrMasters_0_aw_payload_size, + output [1:0] io_ddrMasters_0_aw_payload_burst, + output io_ddrMasters_0_aw_payload_lock, + output [3:0] io_ddrMasters_0_aw_payload_cache, + output [3:0] io_ddrMasters_0_aw_payload_qos, + output [2:0] io_ddrMasters_0_aw_payload_prot, + output io_ddrMasters_0_aw_payload_allStrb, + output io_ddrMasters_0_w_valid, + input io_ddrMasters_0_w_ready, + output [127:0] io_ddrMasters_0_w_payload_data, + output [15:0] io_ddrMasters_0_w_payload_strb, + output io_ddrMasters_0_w_payload_last, + input io_ddrMasters_0_b_valid, + output io_ddrMasters_0_b_ready, + input [3:0] io_ddrMasters_0_b_payload_id, + input [1:0] io_ddrMasters_0_b_payload_resp, + output io_ddrMasters_0_ar_valid, + input io_ddrMasters_0_ar_ready, + output [31:0] io_ddrMasters_0_ar_payload_addr, + output [3:0] io_ddrMasters_0_ar_payload_id, + output [3:0] io_ddrMasters_0_ar_payload_region, + output [7:0] io_ddrMasters_0_ar_payload_len, + output [2:0] io_ddrMasters_0_ar_payload_size, + output [1:0] io_ddrMasters_0_ar_payload_burst, + output io_ddrMasters_0_ar_payload_lock, + output [3:0] io_ddrMasters_0_ar_payload_cache, + output [3:0] io_ddrMasters_0_ar_payload_qos, + output [2:0] io_ddrMasters_0_ar_payload_prot, + input io_ddrMasters_0_r_valid, + output io_ddrMasters_0_r_ready, + input [127:0] io_ddrMasters_0_r_payload_data, + input [3:0] io_ddrMasters_0_r_payload_id, + input [1:0] io_ddrMasters_0_r_payload_resp, + input io_ddrMasters_0_r_payload_last, + input io_ddrMasters_0_clk, + input io_ddrMasters_0_reset, + output io_ddrMasters_memCheck_pass, + output userInterruptA, + output userInterruptB, + output userInterruptC, + output userInterruptD, + output userInterruptE, + output userInterruptF, + output userInterruptH, + output userInterruptG, + output userInterruptI, + input [3:0] system_gpio_0_io_read, + output [3:0] system_gpio_0_io_write, + output [3:0] system_gpio_0_io_writeEnable, + output system_uart_0_io_txd, + input system_uart_0_io_rxd, + output system_spi_0_io_sclk_write, + output system_spi_0_io_data_0_writeEnable, + input system_spi_0_io_data_0_read, + output system_spi_0_io_data_0_write, + output system_spi_0_io_data_1_writeEnable, + input system_spi_0_io_data_1_read, + output system_spi_0_io_data_1_write, + output system_spi_0_io_data_2_writeEnable, + input system_spi_0_io_data_2_read, + output system_spi_0_io_data_2_write, + output system_spi_0_io_data_3_writeEnable, + input system_spi_0_io_data_3_read, + output system_spi_0_io_data_3_write, + output [3:0] system_spi_0_io_ss, + output system_i2c_0_io_sda_writeEnable, + output system_i2c_0_io_sda_write, + input system_i2c_0_io_sda_read, + output system_i2c_0_io_scl_writeEnable, + output system_i2c_0_io_scl_write, + input system_i2c_0_io_scl_read, + input [31:0] axiA_awaddr, + input [7:0] axiA_awlen, + input [2:0] axiA_awsize, + input [1:0] axiA_awburst, + input axiA_awlock, + input [3:0] axiA_awcache, + input [2:0] axiA_awprot, + input [3:0] axiA_awqos, + input [3:0] axiA_awregion, + input axiA_awvalid, + output axiA_awready, + input [31:0] axiA_wdata, + input [3:0] axiA_wstrb, + input axiA_wvalid, + input axiA_wlast, + output axiA_wready, + output [1:0] axiA_bresp, + output axiA_bvalid, + input axiA_bready, + input [31:0] axiA_araddr, + input [7:0] axiA_arlen, + input [2:0] axiA_arsize, + input [1:0] axiA_arburst, + input axiA_arlock, + input [3:0] axiA_arcache, + input [2:0] axiA_arprot, + input [3:0] axiA_arqos, + input [3:0] axiA_arregion, + input axiA_arvalid, + output axiA_arready, + output [31:0] axiA_rdata, + output [1:0] axiA_rresp, + output axiA_rlast, + output axiA_rvalid, + input axiA_rready, + output axiAInterrupt, + input cfg_done, + output cfg_start, + output cfg_sel, + output cfg_reset, + input io_peripheralClk, + input io_peripheralReset, + output io_asyncReset, + input io_gpio_sw_n, + input pll_peripheral_locked, + input pll_system_locked, + input pll_tse_locked, + // SDHC + input sd_base_clk, + output sd_clk_hi, + output sd_clk_lo, + input sd_cmd_i, + output sd_cmd_o, + output sd_cmd_oe, + input [3:0] sd_dat_i, + output [3:0] sd_dat_o, + output [3:0] sd_dat_oe, + input sd_cd_n, + input sd_wp, + // TSEMAC + input io_tseClk, + // MAC + output [3:0] rgmii_txd_HI, + output [3:0] rgmii_txd_LO, + output rgmii_tx_ctl_HI, + output rgmii_tx_ctl_LO, + output rgmii_txc_HI, + output rgmii_txc_LO, + input [3:0] rgmii_rxd_HI, + input [3:0] rgmii_rxd_LO, + input rgmii_rx_ctl_HI, + input rgmii_rx_ctl_LO, + input mux_clk, + output [1:0] mux_clk_sw, + // PHY + output phy_rst, + input phy_mdi, + output phy_mdo, + output phy_mdo_en, + output phy_mdc, + input rgmii_rxc, + input rgmii_rxc_slow +); + + + +top_soc u_top_soc ( + .jtagCtrl_tdi (jtagCtrl_tdi), + .jtagCtrl_tdo (jtagCtrl_tdo), + .jtagCtrl_enable (jtagCtrl_enable), + .jtagCtrl_capture (jtagCtrl_capture), + .jtagCtrl_shift (jtagCtrl_shift), + .jtagCtrl_update (jtagCtrl_update), + .jtagCtrl_reset (jtagCtrl_reset), + .ut_jtagCtrl_tdi (ut_jtagCtrl_tdi), + .ut_jtagCtrl_tdo (ut_jtagCtrl_tdo), + .ut_jtagCtrl_enable (ut_jtagCtrl_enable), + .ut_jtagCtrl_capture (ut_jtagCtrl_capture), + .ut_jtagCtrl_shift (ut_jtagCtrl_shift), + .ut_jtagCtrl_update (ut_jtagCtrl_update), + .ut_jtagCtrl_reset (ut_jtagCtrl_reset), + .io_cfuClk (io_cfuClk), + .io_cfuReset (io_cfuReset), + .io_ddrMasters_0_aw_valid (io_ddrMasters_0_aw_valid), + .io_ddrMasters_0_aw_ready (io_ddrMasters_0_aw_ready), + .io_ddrMasters_0_aw_payload_addr (io_ddrMasters_0_aw_payload_addr), + .io_ddrMasters_0_aw_payload_id (io_ddrMasters_0_aw_payload_id), + .io_ddrMasters_0_aw_payload_region (io_ddrMasters_0_aw_payload_region), + .io_ddrMasters_0_aw_payload_len (io_ddrMasters_0_aw_payload_len), + .io_ddrMasters_0_aw_payload_size (io_ddrMasters_0_aw_payload_size), + .io_ddrMasters_0_aw_payload_burst (io_ddrMasters_0_aw_payload_burst), + .io_ddrMasters_0_aw_payload_lock (io_ddrMasters_0_aw_payload_lock), + .io_ddrMasters_0_aw_payload_cache (io_ddrMasters_0_aw_payload_cache), + .io_ddrMasters_0_aw_payload_qos (io_ddrMasters_0_aw_payload_qos), + .io_ddrMasters_0_aw_payload_prot (io_ddrMasters_0_aw_payload_prot), + .io_ddrMasters_0_aw_payload_allStrb (io_ddrMasters_0_aw_payload_allStrb), + .io_ddrMasters_0_w_valid (io_ddrMasters_0_w_valid), + .io_ddrMasters_0_w_ready (io_ddrMasters_0_w_ready), + .io_ddrMasters_0_w_payload_data (io_ddrMasters_0_w_payload_data), + .io_ddrMasters_0_w_payload_strb (io_ddrMasters_0_w_payload_strb), + .io_ddrMasters_0_w_payload_last (io_ddrMasters_0_w_payload_last), + .io_ddrMasters_0_b_valid (io_ddrMasters_0_b_valid), + .io_ddrMasters_0_b_ready (io_ddrMasters_0_b_ready), + .io_ddrMasters_0_b_payload_id (io_ddrMasters_0_b_payload_id), + .io_ddrMasters_0_b_payload_resp (io_ddrMasters_0_b_payload_resp), + .io_ddrMasters_0_ar_valid (io_ddrMasters_0_ar_valid), + .io_ddrMasters_0_ar_ready (io_ddrMasters_0_ar_ready), + .io_ddrMasters_0_ar_payload_addr (io_ddrMasters_0_ar_payload_addr), + .io_ddrMasters_0_ar_payload_id (io_ddrMasters_0_ar_payload_id), + .io_ddrMasters_0_ar_payload_region (io_ddrMasters_0_ar_payload_region), + .io_ddrMasters_0_ar_payload_len (io_ddrMasters_0_ar_payload_len), + .io_ddrMasters_0_ar_payload_size (io_ddrMasters_0_ar_payload_size), + .io_ddrMasters_0_ar_payload_burst (io_ddrMasters_0_ar_payload_burst), + .io_ddrMasters_0_ar_payload_lock (io_ddrMasters_0_ar_payload_lock), + .io_ddrMasters_0_ar_payload_cache (io_ddrMasters_0_ar_payload_cache), + .io_ddrMasters_0_ar_payload_qos (io_ddrMasters_0_ar_payload_qos), + .io_ddrMasters_0_ar_payload_prot (io_ddrMasters_0_ar_payload_prot), + .io_ddrMasters_0_r_valid (io_ddrMasters_0_r_valid), + .io_ddrMasters_0_r_ready (io_ddrMasters_0_r_ready), + .io_ddrMasters_0_r_payload_data (io_ddrMasters_0_r_payload_data), + .io_ddrMasters_0_r_payload_id (io_ddrMasters_0_r_payload_id), + .io_ddrMasters_0_r_payload_resp (io_ddrMasters_0_r_payload_resp), + .io_ddrMasters_0_r_payload_last (io_ddrMasters_0_r_payload_last), + .io_ddrMasters_0_clk (io_ddrMasters_0_clk), + .io_ddrMasters_0_reset (io_ddrMasters_0_reset), + .io_ddrMasters_memCheck_pass (io_ddrMasters_memCheck_pass), + .userInterruptA (userInterruptA), + .userInterruptB (userInterruptB), + .userInterruptC (userInterruptC), + .userInterruptD (userInterruptD), + .userInterruptE (userInterruptE), + .userInterruptF (userInterruptF), + .userInterruptH (userInterruptH), + .userInterruptG (userInterruptG), + .userInterruptI (userInterruptI), + .system_gpio_0_io_read (system_gpio_0_io_read), + .system_gpio_0_io_write (system_gpio_0_io_write), + .system_gpio_0_io_writeEnable (system_gpio_0_io_writeEnable), + .system_uart_0_io_txd (system_uart_0_io_txd), + .system_uart_0_io_rxd (system_uart_0_io_rxd), + .system_spi_0_io_sclk_write (system_spi_0_io_sclk_write), + .system_spi_0_io_data_0_writeEnable (system_spi_0_io_data_0_writeEnable), + .system_spi_0_io_data_0_read (system_spi_0_io_data_0_read), + .system_spi_0_io_data_0_write (system_spi_0_io_data_0_write), + .system_spi_0_io_data_1_writeEnable (system_spi_0_io_data_1_writeEnable), + .system_spi_0_io_data_1_read (system_spi_0_io_data_1_read), + .system_spi_0_io_data_1_write (system_spi_0_io_data_1_write), + .system_spi_0_io_data_2_writeEnable (system_spi_0_io_data_2_writeEnable), + .system_spi_0_io_data_2_read (system_spi_0_io_data_2_read), + .system_spi_0_io_data_2_write (system_spi_0_io_data_2_write), + .system_spi_0_io_data_3_writeEnable (system_spi_0_io_data_3_writeEnable), + .system_spi_0_io_data_3_read (system_spi_0_io_data_3_read), + .system_spi_0_io_data_3_write (system_spi_0_io_data_3_write), + .system_spi_0_io_ss (system_spi_0_io_ss), + .system_i2c_0_io_sda_writeEnable (system_i2c_0_io_sda_writeEnable), + .system_i2c_0_io_sda_write (system_i2c_0_io_sda_write), + .system_i2c_0_io_sda_read (system_i2c_0_io_sda_read), + .system_i2c_0_io_scl_writeEnable (system_i2c_0_io_scl_writeEnable), + .system_i2c_0_io_scl_write (system_i2c_0_io_scl_write), + .system_i2c_0_io_scl_read (system_i2c_0_io_scl_read), + .axiA_awaddr (axiA_awaddr), + .axiA_awlen (axiA_awlen), + .axiA_awsize (axiA_awsize), + .axiA_awburst (axiA_awburst), + .axiA_awlock (axiA_awlock), + .axiA_awcache (axiA_awcache), + .axiA_awprot (axiA_awprot), + .axiA_awqos (axiA_awqos), + .axiA_awregion (axiA_awregion), + .axiA_awvalid (axiA_awvalid), + .axiA_awready (axiA_awready), + .axiA_wdata (axiA_wdata), + .axiA_wstrb (axiA_wstrb), + .axiA_wvalid (axiA_wvalid), + .axiA_wlast (axiA_wlast), + .axiA_wready (axiA_wready), + .axiA_bresp (axiA_bresp), + .axiA_bvalid (axiA_bvalid), + .axiA_bready (axiA_bready), + .axiA_araddr (axiA_araddr), + .axiA_arlen (axiA_arlen), + .axiA_arsize (axiA_arsize), + .axiA_arburst (axiA_arburst), + .axiA_arlock (axiA_arlock), + .axiA_arcache (axiA_arcache), + .axiA_arprot (axiA_arprot), + .axiA_arqos (axiA_arqos), + .axiA_arregion (axiA_arregion), + .axiA_arvalid (axiA_arvalid), + .axiA_arready (axiA_arready), + .axiA_rdata (axiA_rdata), + .axiA_rresp (axiA_rresp), + .axiA_rlast (axiA_rlast), + .axiA_rvalid (axiA_rvalid), + .axiA_rready (axiA_rready), + .axiAInterrupt (axiAInterrupt), + .cfg_done (cfg_done), + .cfg_start (cfg_start), + .cfg_sel (cfg_sel), + .cfg_reset (cfg_reset), + .io_peripheralClk (io_peripheralClk), + .io_peripheralReset (io_peripheralReset), + .io_asyncReset (io_asyncReset), + .io_gpio_sw_n (io_gpio_sw_n), + .pll_peripheral_locked (pll_peripheral_locked), + .pll_system_locked (pll_system_locked), + .pll_tse_locked (pll_tse_locked), + .sd_base_clk (sd_base_clk), + .sd_clk_hi (sd_clk_hi), + .sd_clk_lo (sd_clk_lo), + .sd_cmd_i (sd_cmd_i), + .sd_cmd_o (sd_cmd_o), + .sd_cmd_oe (sd_cmd_oe), + .sd_dat_i (sd_dat_i), + .sd_dat_o (sd_dat_o), + .sd_dat_oe (sd_dat_oe), + .sd_cd_n (sd_cd_n), + .sd_wp (sd_wp), + .io_tseClk (io_tseClk), + .rgmii_txd_HI (rgmii_txd_HI), + .rgmii_txd_LO (rgmii_txd_LO), + .rgmii_tx_ctl_HI (rgmii_tx_ctl_HI), + .rgmii_tx_ctl_LO (rgmii_tx_ctl_LO), + .rgmii_txc_HI (rgmii_txc_HI), + .rgmii_txc_LO (rgmii_txc_LO), + .rgmii_rxd_HI (rgmii_rxd_HI), + .rgmii_rxd_LO (rgmii_rxd_LO), + .rgmii_rx_ctl_HI (rgmii_rx_ctl_HI), + .rgmii_rx_ctl_LO (rgmii_rx_ctl_LO), + .mux_clk (mux_clk), + .mux_clk_sw (mux_clk_sw), + .phy_rst (phy_rst), + .phy_mdi (phy_mdi), + .phy_mdo (phy_mdo), + .phy_mdo_en (phy_mdo_en), + .phy_mdc (phy_mdc), + .rgmii_rxc (rgmii_rxc), + .rgmii_rxc_slow (rgmii_rxc_slow) +); + +endmodule \ No newline at end of file diff --git a/src/regs/gen_regs.sh b/src/regs/gen_regs.sh new file mode 100755 index 0000000..b8a12a2 --- /dev/null +++ b/src/regs/gen_regs.sh @@ -0,0 +1 @@ +peakrdl regblock -o . --cpuif taxi-apb verilog6502_io_regs.rdl \ No newline at end of file diff --git a/src/regs/verilog6502_io_regs.rdl b/src/regs/verilog6502_io_regs.rdl new file mode 100644 index 0000000..7aeefef --- /dev/null +++ b/src/regs/verilog6502_io_regs.rdl @@ -0,0 +1,60 @@ +addrmap verilog6502_io_regs { + name = ""; + desc = ""; + + reg { + name = "Core Control"; + desc = ""; + + field { + name = "reset"; + desc = ""; + hw = r; + sw = rw; + } reset[0:0] = 0x1; + + } core_ctrl @ 0x0; + + reg { + name = "AXI Base Address"; + desc = ""; + + field { + name = "val"; + desc = ""; + hw = r; + sw = rw; + } val[31:0] = 0x0; + + } axi_base_address @ 0x10; + + reg { + name = "nmi"; + + field { + name = "nmi"; + desc = ""; + hw = r; + sw = rw; + } nmi[31:16] = 0x200; + } nmi @ 0xff8; + + reg { + name = "reset_brq"; + desc = ""; + + field { + name = "reset"; + desc = ""; + hw = r; + sw = rw; + } reset[15:0] = 0x200; + + field { + name = "brq"; + desc = ""; + hw = r; + sw = rw; + } brk[31:16] = 0x200; + } reset_brq @ 0xffc; +}; \ No newline at end of file diff --git a/src/regs/verilog6502_io_regs.sv b/src/regs/verilog6502_io_regs.sv new file mode 100644 index 0000000..147881d --- /dev/null +++ b/src/regs/verilog6502_io_regs.sv @@ -0,0 +1,340 @@ +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +module verilog6502_io_regs ( + input wire clk, + input wire rst, + + taxi_apb_if.slv s_apb, + + output verilog6502_io_regs_pkg::verilog6502_io_regs__out_t hwif_out + ); + + //-------------------------------------------------------------------------- + // CPU Bus interface logic + //-------------------------------------------------------------------------- + logic cpuif_req; + logic cpuif_req_is_wr; + logic [11:0] cpuif_addr; + logic [31:0] cpuif_wr_data; + logic [31:0] cpuif_wr_biten; + logic cpuif_req_stall_wr; + logic cpuif_req_stall_rd; + + logic cpuif_rd_ack; + logic cpuif_rd_err; + logic [31:0] cpuif_rd_data; + + logic cpuif_wr_ack; + logic cpuif_wr_err; + + `ifndef SYNTHESIS + initial begin + assert_bad_addr_width: assert($bits(s_apb.paddr) >= verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_MIN_ADDR_WIDTH) + else $error("Interface address width of %0d is too small. Shall be at least %0d bits", $bits(s_apb.paddr), verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_MIN_ADDR_WIDTH); + assert_bad_data_width: assert($bits(s_apb.pwdata) == verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_DATA_WIDTH) + else $error("Interface data width of %0d is incorrect. Shall be %0d bits", $bits(s_apb.pwdata), verilog6502_io_regs_pkg::VERILOG6502_IO_REGS_DATA_WIDTH); + end + `endif + + // Request + logic is_active; + always_ff @(posedge clk) begin + if(rst) begin + is_active <= '0; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + if(~is_active) begin + if(s_apb.psel) begin + is_active <= '1; + cpuif_req <= '1; + cpuif_req_is_wr <= s_apb.pwrite; + cpuif_addr <= {s_apb.paddr[11:2], 2'b0}; + cpuif_wr_data <= s_apb.pwdata; + for(int i=0; i<4; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{s_apb.pstrb[i]}}; + end + end + end else begin + cpuif_req <= '0; + if(cpuif_rd_ack || cpuif_wr_ack) begin + is_active <= '0; + end + end + end + end + + // Response + assign s_apb.pready = cpuif_rd_ack | cpuif_wr_ack; + assign s_apb.prdata = cpuif_rd_data; + assign s_apb.pslverr = cpuif_rd_err | cpuif_wr_err; + + logic cpuif_req_masked; + + // Read & write latencies are balanced. Stalls not required + assign cpuif_req_stall_rd = '0; + assign cpuif_req_stall_wr = '0; + assign cpuif_req_masked = cpuif_req + & !(!cpuif_req_is_wr & cpuif_req_stall_rd) + & !(cpuif_req_is_wr & cpuif_req_stall_wr); + + //-------------------------------------------------------------------------- + // Address Decode + //-------------------------------------------------------------------------- + typedef struct { + logic core_ctrl; + logic axi_base_address; + logic nmi; + logic reset_brq; + } decoded_reg_strb_t; + decoded_reg_strb_t decoded_reg_strb; + logic decoded_err; + logic [11:0] decoded_addr; + logic decoded_req; + logic decoded_req_is_wr; + logic [31:0] decoded_wr_data; + logic [31:0] decoded_wr_biten; + + always_comb begin + automatic logic is_valid_addr; + automatic logic is_valid_rw; + is_valid_addr = '1; // No valid address check + is_valid_rw = '1; // No valid RW check + decoded_reg_strb.core_ctrl = cpuif_req_masked & (cpuif_addr == 12'h0); + decoded_reg_strb.axi_base_address = cpuif_req_masked & (cpuif_addr == 12'h10); + decoded_reg_strb.nmi = cpuif_req_masked & (cpuif_addr == 12'hff8); + decoded_reg_strb.reset_brq = cpuif_req_masked & (cpuif_addr == 12'hffc); + decoded_err = '0; + end + + // Pass down signals to next stage + assign decoded_addr = cpuif_addr; + assign decoded_req = cpuif_req_masked; + assign decoded_req_is_wr = cpuif_req_is_wr; + assign decoded_wr_data = cpuif_wr_data; + assign decoded_wr_biten = cpuif_wr_biten; + + //-------------------------------------------------------------------------- + // Field logic + //-------------------------------------------------------------------------- + typedef struct { + struct { + struct { + logic next; + logic load_next; + } reset; + } core_ctrl; + struct { + struct { + logic [31:0] next; + logic load_next; + } val; + } axi_base_address; + struct { + struct { + logic [15:0] next; + logic load_next; + } nmi; + } nmi; + struct { + struct { + logic [15:0] next; + logic load_next; + } reset; + struct { + logic [15:0] next; + logic load_next; + } brk; + } reset_brq; + } field_combo_t; + field_combo_t field_combo; + + typedef struct { + struct { + struct { + logic value; + } reset; + } core_ctrl; + struct { + struct { + logic [31:0] value; + } val; + } axi_base_address; + struct { + struct { + logic [15:0] value; + } nmi; + } nmi; + struct { + struct { + logic [15:0] value; + } reset; + struct { + logic [15:0] value; + } brk; + } reset_brq; + } field_storage_t; + field_storage_t field_storage; + + // Field: verilog6502_io_regs.core_ctrl.reset + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.core_ctrl.reset.value; + load_next_c = '0; + if(decoded_reg_strb.core_ctrl && decoded_req_is_wr) begin // SW write + next_c = (field_storage.core_ctrl.reset.value & ~decoded_wr_biten[0:0]) | (decoded_wr_data[0:0] & decoded_wr_biten[0:0]); + load_next_c = '1; + end + field_combo.core_ctrl.reset.next = next_c; + field_combo.core_ctrl.reset.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.core_ctrl.reset.value <= 1'h1; + end else begin + if(field_combo.core_ctrl.reset.load_next) begin + field_storage.core_ctrl.reset.value <= field_combo.core_ctrl.reset.next; + end + end + end + assign hwif_out.core_ctrl.reset.value = field_storage.core_ctrl.reset.value; + // Field: verilog6502_io_regs.axi_base_address.val + always_comb begin + automatic logic [31:0] next_c; + automatic logic load_next_c; + next_c = field_storage.axi_base_address.val.value; + load_next_c = '0; + if(decoded_reg_strb.axi_base_address && decoded_req_is_wr) begin // SW write + next_c = (field_storage.axi_base_address.val.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]); + load_next_c = '1; + end + field_combo.axi_base_address.val.next = next_c; + field_combo.axi_base_address.val.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.axi_base_address.val.value <= 32'h0; + end else begin + if(field_combo.axi_base_address.val.load_next) begin + field_storage.axi_base_address.val.value <= field_combo.axi_base_address.val.next; + end + end + end + assign hwif_out.axi_base_address.val.value = field_storage.axi_base_address.val.value; + // Field: verilog6502_io_regs.nmi.nmi + always_comb begin + automatic logic [15:0] next_c; + automatic logic load_next_c; + next_c = field_storage.nmi.nmi.value; + load_next_c = '0; + if(decoded_reg_strb.nmi && decoded_req_is_wr) begin // SW write + next_c = (field_storage.nmi.nmi.value & ~decoded_wr_biten[31:16]) | (decoded_wr_data[31:16] & decoded_wr_biten[31:16]); + load_next_c = '1; + end + field_combo.nmi.nmi.next = next_c; + field_combo.nmi.nmi.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.nmi.nmi.value <= 16'h200; + end else begin + if(field_combo.nmi.nmi.load_next) begin + field_storage.nmi.nmi.value <= field_combo.nmi.nmi.next; + end + end + end + assign hwif_out.nmi.nmi.value = field_storage.nmi.nmi.value; + // Field: verilog6502_io_regs.reset_brq.reset + always_comb begin + automatic logic [15:0] next_c; + automatic logic load_next_c; + next_c = field_storage.reset_brq.reset.value; + load_next_c = '0; + if(decoded_reg_strb.reset_brq && decoded_req_is_wr) begin // SW write + next_c = (field_storage.reset_brq.reset.value & ~decoded_wr_biten[15:0]) | (decoded_wr_data[15:0] & decoded_wr_biten[15:0]); + load_next_c = '1; + end + field_combo.reset_brq.reset.next = next_c; + field_combo.reset_brq.reset.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.reset_brq.reset.value <= 16'h200; + end else begin + if(field_combo.reset_brq.reset.load_next) begin + field_storage.reset_brq.reset.value <= field_combo.reset_brq.reset.next; + end + end + end + assign hwif_out.reset_brq.reset.value = field_storage.reset_brq.reset.value; + // Field: verilog6502_io_regs.reset_brq.brk + always_comb begin + automatic logic [15:0] next_c; + automatic logic load_next_c; + next_c = field_storage.reset_brq.brk.value; + load_next_c = '0; + if(decoded_reg_strb.reset_brq && decoded_req_is_wr) begin // SW write + next_c = (field_storage.reset_brq.brk.value & ~decoded_wr_biten[31:16]) | (decoded_wr_data[31:16] & decoded_wr_biten[31:16]); + load_next_c = '1; + end + field_combo.reset_brq.brk.next = next_c; + field_combo.reset_brq.brk.load_next = load_next_c; + end + always_ff @(posedge clk) begin + if(rst) begin + field_storage.reset_brq.brk.value <= 16'h200; + end else begin + if(field_combo.reset_brq.brk.load_next) begin + field_storage.reset_brq.brk.value <= field_combo.reset_brq.brk.next; + end + end + end + assign hwif_out.reset_brq.brk.value = field_storage.reset_brq.brk.value; + + //-------------------------------------------------------------------------- + // Write response + //-------------------------------------------------------------------------- + assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; + // Writes are always granted with no error response + assign cpuif_wr_err = '0; + + //-------------------------------------------------------------------------- + // Readback + //-------------------------------------------------------------------------- + + logic [11:0] rd_mux_addr; + assign rd_mux_addr = decoded_addr; + + logic readback_err; + logic readback_done; + logic [31:0] readback_data; + always_comb begin + automatic logic [31:0] readback_data_var; + readback_data_var = '0; + if(rd_mux_addr == 12'h0) begin + readback_data_var[0] = field_storage.core_ctrl.reset.value; + end + if(rd_mux_addr == 12'h10) begin + readback_data_var[31:0] = field_storage.axi_base_address.val.value; + end + if(rd_mux_addr == 12'hff8) begin + readback_data_var[31:16] = field_storage.nmi.nmi.value; + end + if(rd_mux_addr == 12'hffc) begin + readback_data_var[15:0] = field_storage.reset_brq.reset.value; + readback_data_var[31:16] = field_storage.reset_brq.brk.value; + end + readback_data = readback_data_var; + readback_done = decoded_req & ~decoded_req_is_wr; + readback_err = '0; + end + + assign cpuif_rd_ack = readback_done; + assign cpuif_rd_data = readback_data; + assign cpuif_rd_err = readback_err; +endmodule diff --git a/src/regs/verilog6502_io_regs_pkg.sv b/src/regs/verilog6502_io_regs_pkg.sv new file mode 100644 index 0000000..d533c72 --- /dev/null +++ b/src/regs/verilog6502_io_regs_pkg.sv @@ -0,0 +1,53 @@ +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +package verilog6502_io_regs_pkg; + + localparam VERILOG6502_IO_REGS_DATA_WIDTH = 32; + localparam VERILOG6502_IO_REGS_MIN_ADDR_WIDTH = 12; + localparam VERILOG6502_IO_REGS_SIZE = 'h1000; + + typedef struct { + logic value; + } verilog6502_io_regs__core_ctrl__reset__out_t; + + typedef struct { + verilog6502_io_regs__core_ctrl__reset__out_t reset; + } verilog6502_io_regs__core_ctrl__out_t; + + typedef struct { + logic [31:0] value; + } verilog6502_io_regs__axi_base_address__val__out_t; + + typedef struct { + verilog6502_io_regs__axi_base_address__val__out_t val; + } verilog6502_io_regs__axi_base_address__out_t; + + typedef struct { + logic [15:0] value; + } verilog6502_io_regs__nmi__nmi__out_t; + + typedef struct { + verilog6502_io_regs__nmi__nmi__out_t nmi; + } verilog6502_io_regs__nmi__out_t; + + typedef struct { + logic [15:0] value; + } verilog6502_io_regs__reset_brq__reset__out_t; + + typedef struct { + logic [15:0] value; + } verilog6502_io_regs__reset_brq__brk__out_t; + + typedef struct { + verilog6502_io_regs__reset_brq__reset__out_t reset; + verilog6502_io_regs__reset_brq__brk__out_t brk; + } verilog6502_io_regs__reset_brq__out_t; + + typedef struct { + verilog6502_io_regs__core_ctrl__out_t core_ctrl; + verilog6502_io_regs__axi_base_address__out_t axi_base_address; + verilog6502_io_regs__nmi__out_t nmi; + verilog6502_io_regs__reset_brq__out_t reset_brq; + } verilog6502_io_regs__out_t; +endpackage diff --git a/src/verilog6502_addr_decoder.sv b/src/verilog6502_addr_decoder.sv new file mode 100644 index 0000000..84cbaa8 --- /dev/null +++ b/src/verilog6502_addr_decoder.sv @@ -0,0 +1,124 @@ +module verilog6502_addr_decoder( + input i_clk, + input i_rst, + + input logic [15:0] i_cpu_addr, + input logic [7:0] i_cpu_data, + output logic [7:0] o_cpu_data, + input logic i_cpu_we, + input logic i_cpu_rdy, + output logic o_cpu_rdy, + + + output logic [15:0] o_mem_addr, + output logic [7:0] o_mem_data, + input logic [7:0] i_mem_data, + output logic o_mem_rd, + output logic o_mem_we, + input logic i_mem_rdy, + + output logic [15:0] o_external_addr, + output logic [7:0] o_external_data, + input logic [7:0] i_external_data, + output logic o_external_rd, + output logic o_external_we, + input logic i_external_rdy, + + output logic [15:0] o_io_addr, + output logic [7:0] o_io_data, + input logic [7:0] i_io_data, + output logic o_io_rd, + output logic o_io_we, + input logic i_io_rdy +); + +enum logic [1:0] {NONE, MEM, EXT, IO} prev_addr, prev_addr_next; + +always_ff @(posedge i_clk) begin + if (i_rst) begin + prev_addr <= NONE; + end else begin + prev_addr <= prev_addr_next; + end +end + +always_comb begin + prev_addr_next = prev_addr; + + o_mem_addr = '0; + o_mem_data = '0; + o_mem_rd = '0; + o_mem_we = '0; + + o_external_addr = '0; + o_external_data = '0; + o_external_rd = '0; + o_external_we = '0; + + o_io_addr = '0; + o_io_data = '0; + o_io_rd = '0; + o_io_we = '0; + + case (prev_addr) + NONE: begin + o_cpu_rdy = '1; + o_cpu_data = '0; + end + + MEM: begin + o_cpu_rdy = i_mem_rdy; + o_cpu_data = i_mem_data; + end + + EXT: begin + o_cpu_rdy = i_external_rdy; + o_cpu_data = i_external_data; + end + + IO: begin + o_cpu_rdy = i_io_rdy; + o_cpu_data = i_io_data; + end + + default: begin + o_cpu_rdy = '1; + o_cpu_data = '0; + end + endcase + + if (o_cpu_rdy) begin + if (i_cpu_addr < 16'hE000) begin + o_mem_addr = i_cpu_addr; + o_mem_data = i_cpu_data; + o_mem_we = i_cpu_we & o_cpu_rdy; + o_mem_rd = ~i_cpu_we & o_cpu_rdy; + prev_addr_next = MEM; + end else if (i_cpu_addr < 16'hF000) begin + o_external_addr = {4'b0, i_cpu_addr[11:0]}; + o_external_data = i_cpu_data; + o_external_we = i_cpu_we & o_cpu_rdy; + o_external_rd = ~i_cpu_we & o_cpu_rdy; + prev_addr_next = EXT; + end else begin + o_io_addr = {4'b0, i_cpu_addr[11:0]}; + o_io_data = i_cpu_data; + o_io_we = i_cpu_we & o_cpu_rdy; + o_io_rd = ~i_cpu_we & o_cpu_rdy; + prev_addr_next = IO; + end + end + + if (i_rst | ~i_cpu_rdy) begin + prev_addr_next = NONE; + o_mem_rd = 0; + o_mem_we = 0; + o_external_rd = 0; + o_external_we = 0; + o_io_rd = 0; + o_io_we = 0; + end + +end + +endmodule \ No newline at end of file diff --git a/src/verilog6502_apb_adapter.sv b/src/verilog6502_apb_adapter.sv new file mode 100644 index 0000000..6d1bb36 --- /dev/null +++ b/src/verilog6502_apb_adapter.sv @@ -0,0 +1,116 @@ +module verilog6502_apb_adapter( + input i_clk, + input i_rst, + + input logic [15:0] i_addr, + input logic [7:0] i_data, + output logic [7:0] o_data, + input logic i_rd, + input logic i_we, + output logic o_rdy, + + taxi_apb_if.mst m_apb +); + +enum logic {IDLE, ENABLE} state, state_next; + +logic [15:0] latched_addr, latched_addr_next; +logic [15:0] second_addr, second_addr_next; +logic second_we, second_rd, second_we_next, second_rd_next; +logic [7:0] latched_data, latched_data_next; +logic [7:0] second_data, second_data_next; +logic latched_pwrite, latched_pwrite_next; + +always_ff @(posedge i_clk) begin + if (i_rst) begin + state <= IDLE; + latched_addr <= '0; + second_addr <= '0; + second_we <= '0; + second_rd <= '0; + latched_data <= '0; + latched_pwrite <= '0; + second_data <= '0; + end else begin + state <= state_next; + latched_addr <= latched_addr_next; + second_addr <= second_addr_next; + second_we <= second_we_next; + second_rd <= second_rd_next; + latched_data <= latched_data_next; + latched_pwrite <= latched_pwrite_next; + second_data <= second_data_next; + end +end + + +always_comb begin + + + case (state) + IDLE: begin + if (i_rd | i_we) begin + m_apb.pprot = '0; + m_apb.paddr = {16'b0, i_addr} & 32'hfffc; // 32 bit address + m_apb.psel = '1; + m_apb.pwrite = i_we; + m_apb.pstrb = 4'h1 << i_addr[1:0]; // shift based on lower 2 bits + m_apb.pwdata = {24'b0, i_data} << i_addr[1:0]; + o_rdy = '0; + + m_apb.penable = '0; + state_next = ENABLE; + latched_addr_next = i_addr; + latched_data_next = i_data; + latched_pwrite_next = i_we; + end else if (second_rd | second_we) begin + m_apb.pprot = '0; + m_apb.paddr = {16'b0, second_addr} & 32'hfffc; // 32 bit address + m_apb.psel = '1; + m_apb.pwrite = second_we; + m_apb.pstrb = 4'h1 << second_addr[1:0]; // shift based on lower 2 bits + m_apb.pwdata = {24'b0, second_data} << second_addr[1:0]; + o_rdy = '0; + + m_apb.penable = '0; + state_next = ENABLE; + latched_addr_next = second_addr; + latched_data_next = second_data; + latched_pwrite_next = second_we; + end else begin + m_apb.pprot = '0; + m_apb.paddr = '0; + m_apb.psel = '0; + m_apb.pwrite = '0; + m_apb.pstrb = '0; + m_apb.pwdata = '0; + o_rdy = '0; + end + end + + ENABLE: begin + m_apb.penable = '1; + + second_we_next = i_we; + second_rd_next = i_rd; + second_addr_next = i_addr; + second_data_next = i_data; + + m_apb.pprot = '0; + m_apb.paddr = {16'b0, latched_addr} & 32'hfffc; // 32 bit address + m_apb.psel = '1; + m_apb.pwrite = latched_pwrite; + m_apb.pstrb = 4'h1 << latched_addr[1:0]; // shift based on lower 2 bits + m_apb.pwdata = {24'b0, latched_data} << latched_addr[1:0]; + + if (m_apb.pready) begin + state_next = IDLE; + o_data = m_apb.prdata[8 * latched_addr[1:0] +: 8]; + o_rdy = '1; + end + end + + endcase +end + +endmodule \ No newline at end of file diff --git a/src/verilog6502_external_memory.sv b/src/verilog6502_external_memory.sv new file mode 100644 index 0000000..778e9cb --- /dev/null +++ b/src/verilog6502_external_memory.sv @@ -0,0 +1,61 @@ +module verilog6502_external_memory ( + input i_clk, + input i_rst, + + input logic [15:0] i_addr, + input logic [7:0] i_data, + output logic [7:0] o_data, + input logic i_rd, + input logic i_we, + output logic o_rdy, + + input logic [31:0] i_axi_base_addr, + + + taxi_axil_if.wr_mst m_axil_wr, + taxi_axil_if.rd_mst m_axil_rd +); + +taxi_apb_if internal_apb(); +taxi_apb_if addr_shift_apb(); + +verilog6502_apb_adapter u_internal_apb_adapter ( + .i_clk (i_clk), + .i_rst (i_rst), + + .i_addr (i_addr), + .i_data (i_data), + .o_data (o_data), + .i_rd (i_rd), + .i_we (i_we), + .o_rdy (o_rdy), + + .m_apb (internal_apb) +); + +assign addr_shift_apb.paddr = {i_axi_base_addr[31:12], {internal_apb.paddr[11:0]}}; +assign addr_shift_apb.pprot = internal_apb.pprot; +assign addr_shift_apb.psel = internal_apb.psel; +assign addr_shift_apb.penable = internal_apb.penable; +assign addr_shift_apb.pwrite = internal_apb.pwrite; +assign addr_shift_apb.pwdata = internal_apb.pwdata; +assign addr_shift_apb.pstrb = internal_apb.pstrb; +assign internal_apb.pready = addr_shift_apb.pready; +assign internal_apb.prdata = addr_shift_apb.prdata; +assign internal_apb.pslverr = addr_shift_apb.pslverr; +assign addr_shift_apb.pauser = '0; +assign addr_shift_apb.pwuser = '0; +assign internal_apb.pruser = '0; +assign internal_apb.pbuser = '0; + +taxi_apb_axil_adapter u_apb_axil_adapter ( + .clk (i_clk), + .rst (i_rst), + + .s_apb (addr_shift_apb), + + .m_axil_wr (m_axil_wr), + .m_axil_rd (m_axil_rd) +); + +endmodule \ No newline at end of file diff --git a/src/verilog6502_internal_memory.sv b/src/verilog6502_internal_memory.sv new file mode 100644 index 0000000..12b0399 --- /dev/null +++ b/src/verilog6502_internal_memory.sv @@ -0,0 +1,226 @@ +module verilog6502_internal_memory( + input i_clk, + input i_rst, + + taxi_axi_if.rd_slv s_axi_rd, + taxi_axi_if.wr_slv s_axi_wr, + + input logic [15:0] i_addr, + input logic [7:0] i_data, + output logic [7:0] o_data, + input logic i_rd, + input logic i_we, + output logic o_rdy +); + +localparam ID_W = 8; +localparam ADDR_W = 32; +localparam AUSER_W = 1; +localparam RUSER_W = 1; +localparam WUSER_W = 1; +localparam DATA_W = 32; +localparam STRB_W = 4; + +logic [ID_W-1:0] ram_cmd_id; +logic [ADDR_W-1:0] ram_cmd_addr; +logic [DATA_W-1:0] ram_cmd_wr_data; +logic [STRB_W-1:0] ram_cmd_wr_strb; +logic ram_cmd_wr_en; +logic ram_cmd_rd_en; +logic ram_cmd_last; +logic ram_cmd_ready; +logic [DATA_W-1:0] ram_rd_resp_data; +logic ram_rd_resp_last; +logic ram_rd_resp_valid; +logic ram_rd_resp_ready; + +taxi_axi_ram_if_rdwr #( + .DATA_W(DATA_W), + .ADDR_W(ADDR_W), + .STRB_W(STRB_W), + .ID_W(ID_W), + .AUSER_W(AUSER_W), + .WUSER_W(WUSER_W), + .RUSER_W(RUSER_W) +) axi_ram_if_rdwr ( + .clk (i_clk), + .rst (i_rst), + + .s_axi_wr (s_axi_wr), + .s_axi_rd (s_axi_rd), + + .ram_cmd_id (ram_cmd_id), + .ram_cmd_addr (ram_cmd_addr), + .ram_cmd_lock (), + .ram_cmd_cache (), + .ram_cmd_prot (), + .ram_cmd_qos (), + .ram_cmd_region (), + .ram_cmd_auser (), + .ram_cmd_wr_data (ram_cmd_wr_data), + .ram_cmd_wr_strb (ram_cmd_wr_strb), + .ram_cmd_wr_user (), + .ram_cmd_wr_en (ram_cmd_wr_en), + .ram_cmd_rd_en (ram_cmd_rd_en), + .ram_cmd_last (ram_cmd_last), + .ram_cmd_ready (ram_cmd_ready), + .ram_rd_resp_id (), + .ram_rd_resp_data (ram_rd_resp_data), + .ram_rd_resp_last (ram_rd_resp_last), + .ram_rd_resp_user (), + .ram_rd_resp_valid (ram_rd_resp_valid), + .ram_rd_resp_ready (ram_rd_resp_ready) +); + + +logic [7:0] mem [4][14*1024]; + + +enum logic {CPU, EXT} sel, sel_next; + +logic o_rdy_next; + +logic [15:0] ram_addr; +logic [31:0] ram_wdata; +logic [3:0] ram_wstrb; +logic ram_we; + +logic ram_re; +logic [31:0] ram_rdata; +logic ram_rdata_valid; + +logic [1:0] latched_byte_select; + +logic [15:0] pending_addr; +logic [7:0] pending_data; +logic pending_rd; +logic pending_we; + + +always_ff @(posedge i_clk) begin + if (i_rst) begin + sel <= CPU; + o_rdy <= '0; + end else begin + sel <= sel_next; + o_rdy <= o_rdy_next; + + ram_rdata_valid <= '0; + ram_rd_resp_last <= '0; + + if (ram_we) begin + for (int i = 0; i < 4; i++) begin + if (ram_wstrb[i]) begin + mem[i][ram_addr[15:2]] <= ram_wdata[8*i +: 8]; + end + end + end + + if (ram_re) begin + for (int i = 0; i < 4; i++) begin + ram_rdata[8*i +: 8] <= mem[i][ram_addr[15:2]]; + end + ram_rdata_valid <= '1; + ram_rd_resp_last <= ram_cmd_last; + + latched_byte_select <= ram_addr[1:0]; + end + + if (sel == EXT) begin + if (i_we) begin + pending_we <= '1; + pending_addr <= i_addr; + pending_data <= i_data; + end + + if (i_rd) begin + pending_rd <= '1; + pending_addr <= i_addr; + end + end else begin + pending_we <= '0; + pending_rd <= '0; + pending_addr <= '0; + pending_data <= '0; + end + end +end + +always_comb begin + sel_next = sel; + + ram_cmd_ready = '0; + + ram_addr = '0; + ram_we = '0; + ram_wdata = '0; + ram_we = '0; + ram_re = '0; + + ram_rd_resp_valid = '0; + ram_rd_resp_data = '0; + + o_rdy_next = '0; + o_data = '0; + + case (sel) + CPU: begin + // if there was no CPU op, then give external bus a chance + if (~(i_rd | i_we | pending_rd | pending_we)) begin + sel_next = EXT; + end + + if (i_we) begin + ram_addr = i_addr; + ram_wstrb = 4'b1 << i_addr[1:0]; + ram_wdata = {24'b0, i_data} << (i_addr[1:0] * 8); + ram_we = '1; + o_rdy_next = '1; + end + if (pending_we) begin + ram_addr = pending_addr; + ram_wstrb = 4'b1 << pending_addr[1:0]; + ram_wdata = {24'b0, pending_data} << (pending_addr[1:0] * 8); + ram_we = '1; + o_rdy_next = '1; + end + + if (i_rd) begin + ram_addr = i_addr; + ram_re = '1; + o_rdy_next = '1; + end + if (pending_rd) begin + ram_addr = pending_addr; + ram_re = '1; + o_rdy_next = '1; + end + + o_data = ram_rdata[8*latched_byte_select +: 8]; + + end + + EXT: begin + ram_cmd_ready = '1; + + if (ram_cmd_wr_en) begin + ram_addr = ram_cmd_addr[15:0]; + ram_wdata = ram_cmd_wr_data; + ram_wstrb = ram_cmd_wr_strb; + ram_we = '1; + end else if (ram_cmd_rd_en) begin + ram_addr = ram_cmd_addr[15:0]; + ram_re = '1; + + end else begin + sel_next = CPU; + end + + ram_rd_resp_valid = ram_rdata_valid; + ram_rd_resp_data = ram_rdata; + end + endcase +end + + +endmodule \ No newline at end of file diff --git a/src/verilog6502_wrapper.sv b/src/verilog6502_wrapper.sv new file mode 100644 index 0000000..a4ff43f --- /dev/null +++ b/src/verilog6502_wrapper.sv @@ -0,0 +1,205 @@ +// Wrapper around verilog-6502 + +// memory map: +// 0x0000-0x00FF Zero Page (Hard coded) +// 0x0100-0x01FF Stack (Hard coded) +// 0x0200-0xCFFF Internal Memory +// 0xE000-0xEFFF External AXI +// 0xF000-0xFFFF Processor IO + +module verilog6502_wrapper( + input clk, + input rst, + + taxi_apb_if.slv s_apb, + + taxi_axil_if.wr_mst m_axil_wr, + taxi_axil_if.rd_mst m_axil_rd, + taxi_axi_if.rd_slv s_axi_rd, + taxi_axi_if.wr_slv s_axi_wr, + + output logic o_irq_ext, + input logic i_irq_ext, + input logic i_nmi_ext +); + +taxi_apb_if internal_apb(); + +taxi_apb_if s_apb_mux[2](); +taxi_apb_if m_apb_mux[1](); +taxi_apb_if m_apb(); + +taxi_apb_tie u_external_apb_tie( + .s_apb(s_apb), + .m_apb(s_apb_mux[0]) +); + +taxi_apb_tie u_internal_apb_tie( + .s_apb(internal_apb), + .m_apb(s_apb_mux[1]) +); + +taxi_apb_tie u_master_apb_tie( + .s_apb(m_apb_mux[0]), + .m_apb(m_apb) +); + +taxi_apb_interconnect #( + .S_CNT(2), + .M_CNT(1), + .ADDR_W(32) +) u_apb_interconnect ( + .clk (clk), + .rst (rst), + + .s_apb (s_apb_mux), + .m_apb (m_apb_mux) +); + + +logic cpu_clk; +logic cpu_reset; +logic [15:0] cpu_addr; +logic [7:0] cpu_data_in; +logic [7:0] cpu_data_out; + +logic cpu_we; +logic cpu_irq; +logic cpu_nmi; +logic cpu_rdy; +logic cpu_rdy_o; +logic cpu_sync; + +assign cpu_clk = clk; +assign cpu_reset = hwif_out.core_ctrl.reset.value; + +assign cpu_irq = i_irq_ext; +assign cpu_nmi = i_nmi_ext; + +logic [15:0] mem_addr; +logic [7:0] mem_data_in; +logic [7:0] mem_data_out; +logic mem_rd; +logic mem_we; +logic mem_rdy; + +logic [15:0] ext_addr; +logic [7:0] ext_data_in; +logic [7:0] ext_data_out; +logic ext_rd; +logic ext_we; +logic ext_rdy; + +logic [15:0] io_addr; +logic [7:0] io_data_in; +logic [7:0] io_data_out; +logic io_rd; +logic io_we; +logic io_rdy; + +verilog6502_io_regs_pkg::verilog6502_io_regs__out_t hwif_out; + +cpu_65c02 u_cpu_6502( + .clk (cpu_clk), + .reset (cpu_reset), + + .AB (cpu_addr), + .DI (cpu_data_in), + .DO (cpu_data_out), + .WE (cpu_we), + .IRQ (cpu_irq), + .NMI (cpu_nmi), + .RDY (cpu_rdy), + .RDY_O (cpu_rdy_o), + .SYNC (cpu_sync) +); + +verilog6502_addr_decoder u_addr_decoder( + .i_clk (cpu_clk), + .i_rst (cpu_reset), + + .i_cpu_addr (cpu_addr), + .i_cpu_data (cpu_data_out), + .o_cpu_data (cpu_data_in), + .i_cpu_we (cpu_we), + .i_cpu_rdy (cpu_rdy_o), + .o_cpu_rdy (cpu_rdy), + + .o_mem_addr (mem_addr), + .o_mem_data (mem_data_in), + .i_mem_data (mem_data_out), + .o_mem_rd (mem_rd), + .o_mem_we (mem_we), + .i_mem_rdy (mem_rdy), + + .o_external_addr (ext_addr), + .o_external_data (ext_data_in), + .i_external_data (ext_data_out), + .o_external_rd (ext_rd), + .o_external_we (ext_we), + .i_external_rdy (ext_rdy), + + .o_io_addr (io_addr), + .o_io_data (io_data_in), + .i_io_data (io_data_out), + .o_io_rd (io_rd), + .o_io_we (io_we), + .i_io_rdy (io_rdy) +); + +verilog6502_internal_memory u_internal_memory( + .i_clk (cpu_clk), + .i_rst (rst), + + .s_axi_rd (s_axi_rd), + .s_axi_wr (s_axi_wr), + + .i_addr (mem_addr), + .i_data (mem_data_in), + .o_data (mem_data_out), + .i_rd (mem_rd), + .i_we (mem_we), + .o_rdy (mem_rdy) +); + +verilog6502_external_memory u_external_memory ( + .i_clk (clk), + .i_rst (rst), + + .i_addr (ext_addr), + .i_data (ext_data_in), + .o_data (ext_data_out), + .i_rd (ext_rd), + .i_we (ext_we), + .o_rdy (ext_rdy), + + .i_axi_base_addr (hwif_out.axi_base_address.val.value), + + .m_axil_rd (m_axil_rd), + .m_axil_wr (m_axil_wr) +); + +verilog6502_apb_adapter u_io_apb_adapter( + .i_clk (cpu_clk), + .i_rst (rst), + + .i_addr (io_addr), + .i_data (io_data_in), + .o_data (io_data_out), + .i_rd (io_rd), + .i_we (io_we), + .o_rdy (io_rdy), + + .m_apb (internal_apb) +); + + +verilog6502_io_regs u_io_regs ( + .clk (cpu_clk), + .rst (rst), + .s_apb (m_apb), + + .hwif_out (hwif_out) +); + +endmodule \ No newline at end of file