Skip to content

Instantly share code, notes, and snippets.

@neilzheng
Created February 21, 2026 02:43
Show Gist options
  • Select an option

  • Save neilzheng/53bdc330972f31835864e456550ad779 to your computer and use it in GitHub Desktop.

Select an option

Save neilzheng/53bdc330972f31835864e456550ad779 to your computer and use it in GitHub Desktop.
/*
* a mem checker
* when activiated, check memory content according to filler result
* pattern is current bytes already filled
* in 32 data width
* that's 0, 4, 8, 12, 16, ...
*/
module axi_rd #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal, not really used
parameter ID_WIDTH = 1,
// Burst Length. Supports 1, 2, 4, 8, 16, 32, 64, 128, 256 burst lengths
parameter M_AXI_BURST_LEN = 16,
// burst mode incr
parameter M_AXI_BURST_INCR = 2'b01
)
(
input wire clk,
input wire rst_n,
// control
output wire txn_done,
output wire txn_error,
input wire [ADDR_WIDTH-1:0] txn_addr,
input wire init_txn,
/*
* AXI master read interface
*/
output wire [ID_WIDTH-1:0] m_axi_arid,
output wire [ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire [3:0] m_axi_arqos,
output wire [3:0] m_axi_arregion,
output wire [0:0] m_axi_aruser, // not used
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [ID_WIDTH-1:0] m_axi_rid,
input wire [DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire [0:0] m_axi_ruser, // not used
input wire m_axi_rvalid,
output wire m_axi_rready
);
// unused consts
assign m_axi_aruser = '0;
// const state/ unsupported features
assign m_axi_arid = '0;
assign m_axi_arlock = '0;
// Normal, Non-cacheable, Bufferable
assign m_axi_arcache = 4'b0011;
// Unprivileged, Secure, Data access
assign m_axi_arprot = '0;
assign m_axi_arqos = '0;
assign m_axi_arregion = '0;
// handshakes
wire addr_read_en;
wire data_read_en;
// xfer counter
reg [7:0] xfer_counter_reg;
reg [7:0] next_xfer_counter;
// output regs
reg [ADDR_WIDTH-1:0] araddr_reg;
reg [7:0] arlen_reg;
reg [2:0] arsize_reg;
reg [1:0] arburst_reg;
reg arvalid_reg;
reg rready_reg;
reg txn_done_reg;
reg txn_error_reg;
assign addr_read_en = m_axi_arready & arvalid_reg;
assign data_read_en = m_axi_rvalid & rready_reg;
// next state generation
localparam STATE_READ_IDLE = 2'b00;
localparam STATE_READ_ADDR = 2'b01;
localparam STATE_READ_DATA = 2'b10;
reg [1:0] current_state_reg;
reg [1:0] next_state;
always @* begin
next_state = current_state_reg;
case(current_state_reg)
STATE_READ_IDLE: begin
if (init_txn) begin
next_state = STATE_READ_ADDR;
end
end
STATE_READ_ADDR: begin
if (addr_read_en) begin
next_state = STATE_READ_DATA;
end
end
STATE_READ_DATA: begin
if (data_read_en & m_axi_rlast) begin
next_state = STATE_READ_IDLE;
end
end
default: ;
endcase
end
// output generation
reg [ADDR_WIDTH-1:0] next_araddr;
reg next_arvalid;
reg next_rready;
reg next_txn_done;
reg next_txn_error;
// output generation
always @* begin
next_xfer_counter = xfer_counter_reg;
next_araddr = '0;
next_arvalid = 1'b0;
next_rready = 1'b0;
next_txn_done = txn_done_reg;
next_txn_error = txn_error_reg;
// secondary state, the counter, increment on read enabled
// and error state
if (data_read_en) begin
next_xfer_counter = xfer_counter_reg + 1'b1;
// error on any mismatch or response error
if (m_axi_rdata[7:0] != xfer_counter_reg | m_axi_rresp[1]) begin
next_txn_error = 1'b1;
end
end
case (next_state)
STATE_READ_ADDR: begin
next_arvalid = 1'b1;
next_araddr = txn_addr;
next_txn_done = 1'b0;
next_txn_error = 1'b0;
end
STATE_READ_DATA: begin
// only validate read in read state
// note this avoids early data read (combitional data read on same cycle of address assert)
next_rready = 1'b1;
end
STATE_READ_IDLE: if (current_state_reg == STATE_READ_DATA) begin
next_xfer_counter = 0;
next_txn_done = 1'b1;
end
default:;
endcase
end
// output logic
always @(posedge clk or negedge rst_n)
begin
if (~rst_n) begin
// reset logic
current_state_reg <= STATE_READ_IDLE;
// default parameters
xfer_counter_reg <= '0;
arlen_reg <= M_AXI_BURST_LEN-1;
arsize_reg <= 3'($clog2(STRB_WIDTH));
arburst_reg <= M_AXI_BURST_INCR;
araddr_reg <= '0;
arvalid_reg <= '0;
rready_reg <= '0;
txn_done_reg <= '0;
txn_error_reg <= '0;
end else begin
// actually output
current_state_reg <= next_state;
xfer_counter_reg <= next_xfer_counter;
araddr_reg <= next_araddr;
arvalid_reg <= next_arvalid;
rready_reg <= next_rready;
txn_done_reg <= next_txn_done;
txn_error_reg <= next_txn_error;
end
end
assign m_axi_araddr = araddr_reg;
assign m_axi_arlen = arlen_reg;
assign m_axi_arsize = arsize_reg;
assign m_axi_arburst = arburst_reg;
assign m_axi_arvalid = arvalid_reg;
assign m_axi_rready = rready_reg;
assign txn_done = txn_done_reg;
assign txn_error = txn_error_reg;
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment