From ed9edba7959d7e0caf41f60bf05530e2d010c93e Mon Sep 17 00:00:00 2001 From: AirPodsRed Date: Sun, 15 Mar 2026 08:55:25 -0700 Subject: [PATCH 1/6] Update bootrom.sv --- rtl/mem/bootrom.sv | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/rtl/mem/bootrom.sv b/rtl/mem/bootrom.sv index e69de29..f62f680 100644 --- a/rtl/mem/bootrom.sv +++ b/rtl/mem/bootrom.sv @@ -0,0 +1,34 @@ +module boot_rom #( + parameter ADDR_W = 12, + parameter DATA_W = 32 +)( +input logic clk_i, +input logic rst_ni, + input logic [ADDR_W-1:0] addr_i, + output logic [DATA_W-1:0] data_o, + output logic valid_o +); + + logic [DATA_W-1:0] rom [0:2**ADDR_W-1]; + + initial begin + $readmemh("boot_code.mem", rom); + end + +logic [DATA_W-1:0] data_q; +logic valid_q; + + always_ff @(posedge clk_i) begin + if (!rst_ni) begin + data_q <= '0; + valid_q <= 1'b0; + end else begin + data_q <= rom[addr_i[ADDR_W-1: 2]]; + valid_q <= 1'b1; + end + end + +assign data_o = data_q; +assign valid_o = valid_q; + +endmodule From a8ad220f00b5ea8e76affa1f97be71c431188990 Mon Sep 17 00:00:00 2001 From: AirPodsRed Date: Sun, 15 Mar 2026 08:56:06 -0700 Subject: [PATCH 2/6] Update sram_dualport.sv --- rtl/mem/sram_dualport.sv | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/rtl/mem/sram_dualport.sv b/rtl/mem/sram_dualport.sv index e69de29..9088e30 100644 --- a/rtl/mem/sram_dualport.sv +++ b/rtl/mem/sram_dualport.sv @@ -0,0 +1,54 @@ +module sram_dualport #( + parameter int DATA_W = 32, + parameter int ADDR_W = 10, + parameter bit OUT_REG = 0 +) ( + input logic clk_i, + // Port A + input logic [ADDR_W-1:0] port_a_addr_i, // port a address input + input logic [DATA_W-1:0] port_a_wdata_i, // port a write data + input logic port_a_we_i, // port a write enable input, 1 = write, 0 = read + input logic [(DATA_W/8)-1:0] port_a_be_i, // port a byte write enable input, corresponds to which bytes in mem to be overwritten + output logic [DATA_W-1:0] port_a_rdata_o, // read data output + // Port B + input logic [ADDR_W-1:0] port_b_addr_i, // port b address input + input logic [DATA_W-1:0] port_b_wdata_i, // port b write data + input logic port_b_we_i, // port b write enable input, 1 = write, 0 = read + input logic [(DATA_W/8)-1:0] port_b_be_i, // port b byte write enable input, corresponds to which bytes in mem to be overwritten + output logic [DATA_W-1:0] port_b_rdata_o // read data output +); + + // Shared memory array + logic [DATA_W-1:0] mem_a [0:(1< Date: Sun, 15 Mar 2026 08:59:57 -0700 Subject: [PATCH 3/6] Update dma_controller.sv --- rtl/dma/dma_controller.sv | 100 ++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/rtl/dma/dma_controller.sv b/rtl/dma/dma_controller.sv index 39319e0..74d0e28 100644 --- a/rtl/dma/dma_controller.sv +++ b/rtl/dma/dma_controller.sv @@ -1,45 +1,93 @@ //====================================================================== // DMA Controller - Top Level -// Author: Evan Eichholz +// Author: Evan Eichholz // Description: Multi-channel DMA with scatter-gather support // References: specs/registers/dma.yaml, docs/dma_operation.md //====================================================================== -module dma_controller import dma_pkg::*; ( - // Clock and reset +module dma_controller + import dma_pkg::*; +( input logic clk_i, input logic rst_ni, - - // AXI4 Memory Interface (Master) - Write address channel + output logic [ADDR_W-1:0] m_axi_awaddr_o, output logic [7:0] m_axi_awlen_o, - // ... (other AXI ports - truncated for brevity) - - // AXI4-Lite Control Interface (Slave) + output logic [2:0] m_axi_awsize_o, + output logic [1:0] m_axi_awburst_o, + output logic m_axi_awvalid_o, + input logic m_axi_awready_i, + + output logic [DATA_W-1:0] m_axi_wdata_o, + output logic [DATA_W/8-1:0] m_axi_wstrb_o, + output logic m_axi_wlast_o, + output logic m_axi_wvalid_o, + input logic m_axi_wready_i, + + input logic [1:0] m_axi_bresp_i, + input logic m_axi_bvalid_i, + output logic m_axi_bready_o, + + output logic [ADDR_W-1:0] m_axi_araddr_o, + output logic [7:0] m_axi_arlen_o, + output logic [2:0] m_axi_arsize_o, + output logic [1:0] m_axi_arburst_o, + output logic m_axi_arvalid_o, + input logic m_axi_arready_i, + + input logic [DATA_W-1:0] m_axi_rdata_i, + input logic [1:0] m_axi_rresp_i, + input logic m_axi_rlast_i, + input logic m_axi_rvalid_i, + output logic m_axi_rready_o, + input logic [ADDR_W-1:0] s_axi_awaddr_i, - // ... (other AXI-Lite ports) - - // Interrupt outputs + input logic s_axi_awvalid_i, + output logic s_axi_awready_o, + + input logic [DATA_W-1:0] s_axi_wdata_i, + input logic [DATA_W/8-1:0] s_axi_wstrb_i, + input logic s_axi_wvalid_i, + output logic s_axi_wready_o, + + output logic [1:0] s_axi_bresp_o, + output logic s_axi_bvalid_o, + input logic s_axi_bready_i, + + input logic [ADDR_W-1:0] s_axi_araddr_i, + input logic s_axi_arvalid_i, + output logic s_axi_arready_o, + + output logic [DATA_W-1:0] s_axi_rdata_o, + output logic [1:0] s_axi_rresp_o, + output logic s_axi_rvalid_o, + input logic s_axi_rready_i, + output logic [N_CHANNELS-1:0] irq_done_o, output logic [N_CHANNELS-1:0] irq_error_o, - - // Peripheral request interface + input logic [N_CHANNELS-1:0] periph_req_i, output logic [N_CHANNELS-1:0] periph_ack_o ); - // Internal signals - dma_regs_t regs_q, regs_d; - channel_state_e [N_CHANNELS-1:0] channel_state; - logic [N_CHANNELS-1:0] channel_grant; + dma_regs_t regs; + logic [N_CHANNELS-1:0] ch_req; + logic [N_CHANNELS-1:0] ch_grant; + logic [CHANNEL_W-1:0] grant_ch; + logic grant_valid; + ch_status_t [N_CHANNELS-1:0] ch_status; + xfer_req_t xfer_req; + xfer_resp_t xfer_resp; + desc_fetch_req_t desc_req; + desc_fetch_resp_t desc_resp; + irq_type_e [N_CHANNELS-1:0] irq_type; - // Module instances + dma_reg_if u_reg_if (.*); dma_channel_arbiter u_channel_arbiter (.*); - dma_desc_fetch u_desc_fetch (.*); - dma_xfer_engine u_xfer_engine (.*); - dma_axi_mux u_axi_mux (.*); - dma_reg_if u_reg_if (.*); - dma_irq_ctrl u_irq_ctrl (.*); - dma_status u_status (.*); - -endmodule \ No newline at end of file + dma_desc_fetch u_desc_fetch (.*); + dma_xfer_engine u_xfer_engine (.*); + dma_axi_mux u_axi_mux (.*); + dma_irq_ctrl u_irq_ctrl (.*); + dma_status u_status (.*); + +endmodule From 3d31ea5755347204b1bc8263890ab938df3f42a2 Mon Sep 17 00:00:00 2001 From: AirPodsRed Date: Sun, 15 Mar 2026 09:01:04 -0700 Subject: [PATCH 4/6] Update dma_pkg.sv --- rtl/dma/dma_pkg.sv | 53 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/rtl/dma/dma_pkg.sv b/rtl/dma/dma_pkg.sv index 720e3ca..81d4bea 100644 --- a/rtl/dma/dma_pkg.sv +++ b/rtl/dma/dma_pkg.sv @@ -45,4 +45,55 @@ package dma_pkg; logic [31:0] channel_enable; } dma_regs_t; -endpackage \ No newline at end of file + parameter logic [ADDR_W-1:0] REG_CTRL_OFFSET = 32'h0000_0000; + parameter logic [ADDR_W-1:0] REG_STATUS_OFFSET = 32'h0000_0004; + parameter logic [ADDR_W-1:0] REG_CHANNEL_ENABLE = 32'h0000_0008; + parameter logic [ADDR_W-1:0] REG_DESC_PTR_BASE = 32'h0000_0100; + parameter int CTRL_GLOBAL_ENABLE_BIT = 0; + parameter int CTRL_IRQ_ENABLE_BIT = 1; + parameter int STATUS_BUSY_BIT = 0; + parameter int STATUS_ERROR_BIT = 1; + + typedef enum logic [1:0] { + IRQ_NONE = 2'b00, + IRQ_DONE = 2'b01, + IRQ_ERROR = 2'b10 + } irq_type_e; + + typedef struct packed { + channel_state_e state; + logic done; + logic error; + } ch_status_t; + + typedef struct packed { + logic valid; + logic [ADDR_W-1:0] addr; + } desc_fetch_req_t; + typedef struct packed { + logic valid; + dma_desc_t desc; + } desc_fetch_resp_t; + + typedef struct packed { + logic valid; + logic [ADDR_W-1:0] src_addr; + logic [ADDR_W-1:0] dst_addr; + logic [23:0] length; + logic is_last; + } xfer_req_t; + typedef struct packed { + logic done; + logic error; + } xfer_resp_t; + + parameter int unsigned MAX_BURST_BEATS = 16; + parameter int unsigned MAX_BURST_BYTES = MAX_BURST_BEATS * (DATA_W/8); + + function automatic [7:0] calc_axi_len(input int unsigned bytes); + if (bytes > MAX_BURST_BYTES) + return MAX_BURST_BEATS - 1; + else + return (bytes / (DATA_W/8)) - 1; + endfunction +endpackage From 320a8a78ffc824aa956b94b73089254fc8f485cb Mon Sep 17 00:00:00 2001 From: AirPodsRed Date: Sun, 15 Mar 2026 09:01:48 -0700 Subject: [PATCH 5/6] Update dma_channel_arbiter.sv --- rtl/dma/dma_channel_arbiter.sv | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/rtl/dma/dma_channel_arbiter.sv b/rtl/dma/dma_channel_arbiter.sv index 646826d..e78f8f2 100644 --- a/rtl/dma/dma_channel_arbiter.sv +++ b/rtl/dma/dma_channel_arbiter.sv @@ -12,21 +12,36 @@ module dma_channel_arbiter import dma_pkg::*; ( ); logic [CHANNEL_W-1:0] current_channel; + logic [N_CHANNELS-1:0] grant_next; + // fixed priority logic + always_comb begin + grant_next = '0; + + // Channel 0 has highest priority + for (int i = 0; i < N_CHANNELS; i++) begin + if (req_i[i]) begin + grant_next[i] = 1'b1; + break; + end + end + end + + // reg outputs always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin current_channel <= '0; grant_o <= '0; - end else begin - // Fixed priority arbitration (Channel 0 highest priority) - grant_o <= '0; + end + else begin + grant_o <= grant_next; + + // track which channel got granted for (int i = 0; i < N_CHANNELS; i++) begin - if (req_i[i]) begin - grant_o[i] <= 1'b1; - break; - end + if (grant_next[i]) + current_channel <= i; end end end -endmodule \ No newline at end of file +endmodule From e160d9cfd8360242f4fb7c7afc749c8f213d94d8 Mon Sep 17 00:00:00 2001 From: AirPodsRed Date: Sun, 15 Mar 2026 09:04:24 -0700 Subject: [PATCH 6/6] Create boot_rom_tb.sv --- rtl/mem/boot_rom_tb.sv | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 rtl/mem/boot_rom_tb.sv diff --git a/rtl/mem/boot_rom_tb.sv b/rtl/mem/boot_rom_tb.sv new file mode 100644 index 0000000..815b70d --- /dev/null +++ b/rtl/mem/boot_rom_tb.sv @@ -0,0 +1,57 @@ +//when the reset is active, data_o should just be all zeroes. Then every reset is inactive and now every 4th period (40 ns) it should first read +//@0000 at addr_i = 12h'000, +//0000006F at addr_i = 12h'004, +//00000013 at addr_i = 12h'008. + +`timescale 1ns / 1ps + +module boot_rom_tb(); + localparam ADDR_W = 12; + localparam DATA_W = 32; + + logic clk_i, rst_ni, valid_o; + logic [ADDR_W-1: 0] addr_i; + logic [DATA_W-1:0] data_o; + + boot_rom UTT(.clk_i(clk_i), .rst_ni(rst_ni), .valid_o(valid_o), .addr_i(addr_i), .data_o(data_o)); + + initial begin + forever #10 clk_i = ~clk_i; + end + + initial begin + rst_ni = 0; + addr_i = 0; + + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + + rst_ni = 1; + + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + + addr_i = 12'h000; + + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + + addr_i = 12'h004; + + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + @(posedge clk_i); + + addr_i = 12'h008; + + end + + +endmodule