Skip to content

Instantly share code, notes, and snippets.

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

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

Select an option

Save neilzheng/b4320882c05f2981da3214dbbfbc2eab to your computer and use it in GitHub Desktop.
/*
* a mem filler
* when activiated, fill a memory region
* with current bytes already filled
* in 32 data width
* that's 0, 4, 8, 12, 16, ...
*/
module axi_wr #
(
// 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 write interface
*/
output wire [ID_WIDTH-1:0] m_axi_awid,
output wire [ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire [3:0] m_axi_awqos,
output wire [3:0] m_axi_awregion,
output wire [0:0] m_axi_awuser, // not used
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [DATA_WIDTH-1:0] m_axi_wdata,
output wire [STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire [0:0] m_axi_wuser, // not used
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire [0:0] m_axi_buser, // not used
input wire m_axi_bvalid,
output wire m_axi_bready
);
// unused consts
assign m_axi_awuser = 0;
assign m_axi_wuser = 0;
// const state/ unsupported features
assign m_axi_awid = 0;
assign m_axi_awlock = 0;
// Normal, Non-cacheable, Bufferable
assign m_axi_awcache = 4'b0011;
// Unprivileged, Secure, Data access
assign m_axi_awprot = 0;
assign m_axi_awqos = 0;
assign m_axi_awregion = 0;
// always ready to receive response
assign m_axi_bready = 1'b1;
// always word write
assign m_axi_wstrb = {STRB_WIDTH{1'b1}};
// handshakes
wire addr_write_en;
wire data_write_en;
wire resp_read_en;
assign addr_write_en = m_axi_awready & awvalid_reg;
assign data_write_en = m_axi_wready & wvalid_reg;
assign resp_read_en = m_axi_bready & m_axi_bvalid;
// xfer counter
reg [7:0] xfer_counter_reg;
reg [7:0] next_xfer_counter;
// output regs
reg [ADDR_WIDTH-1:0] awaddr_reg;
reg [7:0] awlen_reg;
reg [2:0] awsize_reg;
reg [1:0] awburst_reg;
reg awvalid_reg;
reg [DATA_WIDTH-1:0] wdata_reg;
reg wlast_reg;
reg wvalid_reg;
reg txn_done_reg;
reg txn_error_reg;
// next state generation
localparam STATE_WRITE_IDLE = 2'b00;
localparam STATE_WRITE_ADDR = 2'b01;
localparam STATE_WRITE_DATA = 2'b10;
localparam STATE_WRITE_DONE = 2'b11;
reg [1:0] current_state_reg;
reg [1:0] next_state;
always @* begin
next_state = current_state_reg;
case(current_state_reg)
STATE_WRITE_IDLE: begin
if (init_txn) begin
next_state = STATE_WRITE_ADDR;
end
end
STATE_WRITE_ADDR: begin
if (addr_write_en) begin
next_state = STATE_WRITE_DATA;
end
end
STATE_WRITE_DATA: begin
if (data_write_en & wlast_reg) begin
next_state = STATE_WRITE_DONE;
end
end
STATE_WRITE_DONE: begin
if (resp_read_en) begin
next_state = STATE_WRITE_IDLE;
end
end
default: ;
endcase
end
// output generation
reg [ADDR_WIDTH-1:0] next_awaddr;
reg next_awvalid;
reg [DATA_WIDTH-1:0] next_wdata;
reg next_wlast;
reg next_wvalid;
reg next_txn_done;
reg next_txn_error;
// output generation
always @* begin
next_xfer_counter = xfer_counter_reg;
next_awaddr = 0;
next_awvalid = 1'b0;
next_wdata = 0;
next_wlast = 1'b0;
next_wvalid = 1'b0;
next_txn_done = txn_done_reg;
next_txn_error = txn_error_reg;
// secondary state, the counter, increment on write enabled
if (data_write_en) begin
next_xfer_counter = xfer_counter_reg + 1'b1;
end
// state output
case (next_state)
STATE_WRITE_ADDR: begin
next_awvalid = 1'b1;
next_awaddr = txn_addr;
next_txn_done = 1'b0;
next_txn_error = 1'b0;
end
STATE_WRITE_DATA: begin
next_wvalid = 1'b1;
next_wdata = {{(DATA_WIDTH-8){1'b0}}, next_xfer_counter};
if (next_xfer_counter == M_AXI_BURST_LEN-1'b1) begin
next_wlast = 1'b1;
end
end
STATE_WRITE_IDLE: if (current_state_reg == STATE_WRITE_DONE) begin
next_xfer_counter = 0;
next_txn_done = 1'b1;
next_txn_error = m_axi_bresp[1];
end
default:;
endcase
end
// output logic
always @(posedge clk or negedge rst_n)
begin
if (~rst_n) begin
// reset logic
current_state_reg <= STATE_WRITE_IDLE;
// default parameters
xfer_counter_reg <= 0;
awlen_reg <= M_AXI_BURST_LEN-1;
awsize_reg <= 3'($clog2(STRB_WIDTH));
awburst_reg <= M_AXI_BURST_INCR;
awaddr_reg <= 0;
awvalid_reg <= 0;
wdata_reg <= 0;
wlast_reg <= 0;
wvalid_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;
awaddr_reg <= next_awaddr;
awvalid_reg <= next_awvalid;
wdata_reg <= next_wdata;
wlast_reg <= next_wlast;
wvalid_reg <= next_wvalid;
txn_done_reg <= next_txn_done;
txn_error_reg <= next_txn_error;
end
end
assign m_axi_awaddr = awaddr_reg;
assign m_axi_awlen = awlen_reg;
assign m_axi_awsize = awsize_reg;
assign m_axi_awburst = awburst_reg;
assign m_axi_awvalid = awvalid_reg;
assign m_axi_wdata = wdata_reg;
assign m_axi_wlast = wlast_reg;
assign m_axi_wvalid = wvalid_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