Skip to content

Commit 68b33a1

Browse files
committed
Added simple UART logger
1 parent c6d4f60 commit 68b33a1

File tree

2 files changed

+625
-0
lines changed

2 files changed

+625
-0
lines changed

axi4l_logger.sv

+298
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
//------------------------------------------------------------------------------
2+
// axi4l_logger.sv
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, [email protected]
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// AXI4-Lite logger
9+
// Sniffs all AXI transactions and stores address and data to fifo
10+
//
11+
// - optimized for `AXI_ADDR_WIDTH = 32 and `AXI_DATA_WIDTH = 32
12+
//
13+
14+
/* --- INSTANTIATION TEMPLATE BEGIN ---
15+
16+
axi4l_logger AL (
17+
.clk_axi( ),
18+
.anrst_axi( ),
19+
20+
// axi interface here
21+
22+
.clk( ),
23+
24+
.empty( )
25+
.r_req( ),
26+
.r_rnw( ),
27+
.r_addr( ),
28+
.r_data( )
29+
);
30+
31+
--- INSTANTIATION TEMPLATE END ---*/
32+
33+
34+
module axi4l_logger #( parameter
35+
bit [`AXI_ADDR_WIDTH-1:0] REG_ADDRESS_FROM = '0, // register address
36+
bit [`AXI_ADDR_WIDTH-1:0] REG_ADDRESS_TO = '1 // space to log
37+
)(
38+
input clk_axi, // axi clock
39+
input anrst_axi, // axi async reset (inversed)
40+
41+
input [`AXI_ADDR_WIDTH-1:0] s_axi_araddr, // axil
42+
input [1:0] s_axi_arburst,
43+
input [3:0] s_axi_arcache,
44+
input [`AXI_LEN_WIDTH-1:0] s_axi_arlen,
45+
input [0:0] s_axi_arlock,
46+
input [2:0] s_axi_arprot, // axil // NU here
47+
input [3:0] s_axi_arqos,
48+
input s_axi_arready, // axil
49+
input [3:0] s_axi_arregion,
50+
input [`AXI_SIZE_WIDTH-1:0] s_axi_arsize,
51+
input s_axi_arvalid, // axil
52+
53+
input [`AXI_ADDR_WIDTH-1:0] s_axi_awaddr, // axil
54+
input [1:0] s_axi_awburst,
55+
input [3:0] s_axi_awcache,
56+
input [`AXI_LEN_WIDTH-1:0] s_axi_awlen,
57+
input [0:0] s_axi_awlock,
58+
input [2:0] s_axi_awprot, // axil // NU here
59+
input [3:0] s_axi_awqos,
60+
input s_axi_awready, // axil
61+
input [3:0] s_axi_awregion,
62+
input [`AXI_SIZE_WIDTH-1:0] s_axi_awsize,
63+
input s_axi_awvalid, // axil
64+
65+
input s_axi_bready, // axil
66+
input [1:0] s_axi_bresp, // axil
67+
input s_axi_bvalid, // axil
68+
69+
input [`AXI_DATA_WIDTH-1:0] s_axi_rdata, // axil
70+
input s_axi_rlast,
71+
input s_axi_rready, // axil
72+
input [1:0] s_axi_rresp, // axil
73+
input s_axi_rvalid, // axil
74+
75+
input [`AXI_DATA_WIDTH-1:0] s_axi_wdata, // axil
76+
input s_axi_wlast,
77+
input s_axi_wready, // axil
78+
input [`AXI_DATA_BYTES-1:0] s_axi_wstrb, // axil
79+
input s_axi_wvalid, // axil
80+
81+
// fifo output interface
82+
input clk,
83+
output empty,
84+
input r_req,
85+
86+
output r_rnw,
87+
output [`AXI_ADDR_WIDTH-1:0] r_addr,
88+
output [`AXI_DATA_WIDTH-1:0] r_data
89+
);
90+
91+
92+
logic aw_w_req; // axi addr write request
93+
logic ar_w_req; // axi addr read request
94+
95+
logic aw_w_req_d1;
96+
logic ar_w_req_d1;
97+
always_ff @( posedge clk_axi or negedge anrst_axi ) begin
98+
if( ~anrst_axi ) begin
99+
aw_w_req_d1 <= 1'b0;
100+
ar_w_req_d1 <= 1'b0;
101+
end else begin
102+
aw_w_req_d1 <= aw_w_req;
103+
ar_w_req_d1 <= ar_w_req;
104+
end
105+
end
106+
107+
108+
// WRITE =======================================================================
109+
110+
logic aw_en = 1'b1;
111+
always_ff @( posedge clk_axi or negedge anrst_axi ) begin
112+
if ( ~anrst_axi ) begin
113+
aw_en <= 1'b1;
114+
end else begin
115+
if (~s_axi_awready && s_axi_awvalid && s_axi_wvalid && aw_en) begin
116+
aw_en <= 1'b0;
117+
end else if (s_axi_bready && s_axi_bvalid) begin
118+
aw_en <= 1'b1;
119+
end
120+
end
121+
end
122+
123+
logic [`AXI_DATA_WIDTH-1:0] s_axi_awaddr_buf = '0;
124+
always_ff @( posedge clk_axi or negedge anrst_axi ) begin
125+
if ( ~anrst_axi ) begin
126+
s_axi_awaddr_buf[`AXI_DATA_WIDTH-1:0] <= '0;
127+
end else begin
128+
if (~s_axi_awready && s_axi_awvalid && s_axi_wvalid && aw_en) begin
129+
s_axi_awaddr_buf[`AXI_DATA_WIDTH-1:0] <= s_axi_awaddr[`AXI_DATA_WIDTH-1:0];
130+
end
131+
end
132+
end
133+
134+
always_comb begin
135+
aw_w_req = s_axi_wready && s_axi_wvalid && s_axi_awready && s_axi_awvalid &&
136+
(s_axi_awaddr_buf[`AXI_ADDR_WIDTH-1:0] >= REG_ADDRESS_FROM[`AXI_ADDR_WIDTH-1:0]) &&
137+
(s_axi_awaddr_buf[`AXI_ADDR_WIDTH-1:0] <= REG_ADDRESS_TO[`AXI_ADDR_WIDTH-1:0]);
138+
end
139+
140+
141+
// READ ========================================================================
142+
143+
logic [`AXI_ADDR_WIDTH-1:0] s_axi_araddr_buf = '0;
144+
always_ff @( posedge clk_axi or negedge anrst_axi ) begin
145+
if ( ~anrst_axi ) begin
146+
s_axi_araddr_buf[`AXI_ADDR_WIDTH-1:0] <= '0;
147+
end else begin
148+
if (~s_axi_arready && s_axi_arvalid) begin
149+
s_axi_araddr_buf[`AXI_ADDR_WIDTH-1:0] <= s_axi_araddr[`AXI_ADDR_WIDTH-1:0];
150+
end
151+
end
152+
end
153+
154+
always_comb begin
155+
ar_w_req = s_axi_arready && s_axi_arvalid && ~s_axi_rvalid &&
156+
(s_axi_araddr_buf[`AXI_ADDR_WIDTH-1:0] >= REG_ADDRESS_FROM[`AXI_ADDR_WIDTH-1:0]) &&
157+
(s_axi_araddr_buf[`AXI_ADDR_WIDTH-1:0] <= REG_ADDRESS_TO[`AXI_ADDR_WIDTH-1:0]);
158+
end
159+
160+
161+
// FIFO ========================================================================
162+
163+
// fifo inputs
164+
logic [31:0] w_addr_f;
165+
logic [31:0] w_data_f;
166+
logic [31:0] w_rnwr_f;
167+
always_comb begin
168+
if( aw_w_req_d1 ) begin
169+
w_addr_f[31:0] = s_axi_awaddr_buf[31:0];
170+
w_data_f[31:0] = s_axi_wdata[31:0];
171+
w_rnwr_f[31:0] = '0;
172+
end else if( ar_w_req_d1 ) begin
173+
w_addr_f[31:0] = s_axi_araddr_buf[31:0];
174+
w_data_f[31:0] = s_axi_rdata[31:0];
175+
w_rnwr_f[31:0] = 32'b1;
176+
end else begin
177+
w_addr_f[31:0] = '0;
178+
w_data_f[31:0] = '0;
179+
w_rnwr_f[31:0] = '0;
180+
end
181+
end
182+
183+
// fifo outputs
184+
logic [31:0] r_addr_f;
185+
logic [31:0] r_data_f;
186+
logic [31:0] r_rnwr_f;
187+
188+
FIFO18E1 #(
189+
.ALMOST_EMPTY_OFFSET ( 13'h0006 ), // min. value is 6 for FWFT mode, Sets the almost empty threshold
190+
.ALMOST_FULL_OFFSET ( 13'h0005 ), // min. value is 4, Sets almost full threshold
191+
.DATA_WIDTH ( 36 ), // Sets data width to 4-36
192+
.DO_REG ( 1 ), // Enable output register ( 1-0 ) Must be 1 if EN_SYN = FALSE
193+
.EN_SYN ( "FALSE" ), // Specifies FIFO as dual-clock ( FALSE ) or Synchronous ( TRUE )
194+
.FIFO_MODE ( "FIFO18_36" ), // Sets mode to FIFO18 or FIFO18_36
195+
.FIRST_WORD_FALL_THROUGH ( "TRUE" ), // Sets the FIFO FWFT to FALSE, TRUE
196+
.INIT ( 36'h000000000 ), // Initial values on output port
197+
.SIM_DEVICE ( "7SERIES" ), // Must be set to "7SERIES" for simulation behavior
198+
.SRVAL ( 36'h000000000 ) // Set/Reset value for output port
199+
) addr_fifo_b (
200+
.RST ( ~anrst_axi ), // 1-bit input: Asynchronous Reset
201+
.RSTREG ( 1'b0 ), // 1-bit input: Output register set/reset
202+
203+
.WRCLK ( clk_axi ), // 1-bit input: Write clock
204+
.WREN ( aw_w_req_d1 || ar_w_req_d1 ), // 1-bit input: Write enable
205+
.DI ( w_addr_f[31:0] ), // 32-bit input: Data input
206+
.DIP ( 4'b0 ), // 4-bit input: Parity input
207+
.FULL ( ), // 1-bit output: Full flag
208+
.ALMOSTFULL ( ), // 1-bit output: Almost full flag
209+
.WRCOUNT ( ), // 12-bit output: Write count
210+
.WRERR ( ), // 1-bit output: Write error
211+
212+
.RDCLK ( clk ), // 1-bit input: Read clock
213+
.REGCE ( 1'b1 ), // 1-bit input: Clock enable
214+
.RDEN ( r_req ), // 1-bit input: Read enable
215+
.DO ( r_addr_f[31:0] ), // 32-bit output: Data output
216+
.DOP ( ), // 4-bit output: Parity data output
217+
.EMPTY ( empty ), // 1-bit output: Empty flag
218+
.ALMOSTEMPTY ( ), // 1-bit output: Almost empty flag
219+
.RDCOUNT ( ), // 12-bit output: Read count
220+
.RDERR ( ) // 1-bit output: Read error
221+
);
222+
223+
FIFO18E1 #(
224+
.ALMOST_EMPTY_OFFSET ( 13'h0006 ), // min. value is 6 for FWFT mode, Sets the almost empty threshold
225+
.ALMOST_FULL_OFFSET ( 13'h0005 ), // min. value is 4, Sets almost full threshold
226+
.DATA_WIDTH ( 36 ), // Sets data width to 4-36
227+
.DO_REG ( 1 ), // Enable output register ( 1-0 ) Must be 1 if EN_SYN = FALSE
228+
.EN_SYN ( "FALSE" ), // Specifies FIFO as dual-clock ( FALSE ) or Synchronous ( TRUE )
229+
.FIFO_MODE ( "FIFO18_36" ), // Sets mode to FIFO18 or FIFO18_36
230+
.FIRST_WORD_FALL_THROUGH ( "TRUE" ), // Sets the FIFO FWFT to FALSE, TRUE
231+
.INIT ( 36'h000000000 ), // Initial values on output port
232+
.SIM_DEVICE ( "7SERIES" ), // Must be set to "7SERIES" for simulation behavior
233+
.SRVAL ( 36'h000000000 ) // Set/Reset value for output port
234+
) data_fifo_b (
235+
.RST ( ~anrst_axi ), // 1-bit input: Asynchronous Reset
236+
.RSTREG ( 1'b0 ), // 1-bit input: Output register set/reset
237+
238+
.WRCLK ( clk_axi ), // 1-bit input: Write clock
239+
.WREN ( aw_w_req_d1 || ar_w_req_d1 ), // 1-bit input: Write enable
240+
.DI ( w_data_f[31:0] ), // 32-bit input: Data input
241+
.DIP ( 4'b0 ), // 4-bit input: Parity input
242+
.FULL ( ), // 1-bit output: Full flag
243+
.ALMOSTFULL ( ), // 1-bit output: Almost full flag
244+
.WRCOUNT ( ), // 12-bit output: Write count
245+
.WRERR ( ), // 1-bit output: Write error
246+
247+
.RDCLK ( clk ), // 1-bit input: Read clock
248+
.REGCE ( 1'b1 ), // 1-bit input: Clock enable
249+
.RDEN ( r_req ), // 1-bit input: Read enable
250+
.DO ( r_data_f[31:0] ), // 32-bit output: Data output
251+
.DOP ( ), // 4-bit output: Parity data output
252+
.EMPTY ( ), // 1-bit output: Empty flag
253+
.ALMOSTEMPTY ( ), // 1-bit output: Almost empty flag
254+
.RDCOUNT ( ), // 12-bit output: Read count
255+
.RDERR ( ) // 1-bit output: Read error
256+
);
257+
258+
FIFO18E1 #(
259+
.ALMOST_EMPTY_OFFSET ( 13'h0006 ), // min. value is 6 for FWFT mode, Sets the almost empty threshold
260+
.ALMOST_FULL_OFFSET ( 13'h0005 ), // min. value is 4, Sets almost full threshold
261+
.DATA_WIDTH ( 36 ), // Sets data width to 4-36
262+
.DO_REG ( 1 ), // Enable output register ( 1-0 ) Must be 1 if EN_SYN = FALSE
263+
.EN_SYN ( "FALSE" ), // Specifies FIFO as dual-clock ( FALSE ) or Synchronous ( TRUE )
264+
.FIFO_MODE ( "FIFO18_36" ), // Sets mode to FIFO18 or FIFO18_36
265+
.FIRST_WORD_FALL_THROUGH ( "TRUE" ), // Sets the FIFO FWFT to FALSE, TRUE
266+
.INIT ( 36'h000000000 ), // Initial values on output port
267+
.SIM_DEVICE ( "7SERIES" ), // Must be set to "7SERIES" for simulation behavior
268+
.SRVAL ( 36'h000000000 ) // Set/Reset value for output port
269+
) rnmr_fifo_b (
270+
.RST ( ~anrst_axi ), // 1-bit input: Asynchronous Reset
271+
.RSTREG ( 1'b0 ), // 1-bit input: Output register set/reset
272+
273+
.WRCLK ( clk_axi ), // 1-bit input: Write clock
274+
.WREN ( aw_w_req_d1 || ar_w_req_d1 ), // 1-bit input: Write enable
275+
.DI ( w_rnwr_f[31:0] ), // 32-bit input: Data input
276+
.DIP ( 4'b0 ), // 4-bit input: Parity input
277+
.FULL ( ), // 1-bit output: Full flag
278+
.ALMOSTFULL ( ), // 1-bit output: Almost full flag
279+
.WRCOUNT ( ), // 12-bit output: Write count
280+
.WRERR ( ), // 1-bit output: Write error
281+
282+
.RDCLK ( clk ), // 1-bit input: Read clock
283+
.REGCE ( 1'b1 ), // 1-bit input: Clock enable
284+
.RDEN ( r_req ), // 1-bit input: Read enable
285+
.DO ( r_rnwr_f[31:0] ), // 32-bit output: Data output
286+
.DOP ( ), // 4-bit output: Parity data output
287+
.EMPTY ( ), // 1-bit output: Empty flag
288+
.ALMOSTEMPTY ( ), // 1-bit output: Almost empty flag
289+
.RDCOUNT ( ), // 12-bit output: Read count
290+
.RDERR ( ) // 1-bit output: Read error
291+
);
292+
293+
assign r_rnw = r_rnwr_f[0];
294+
assign r_addr[31:0] = r_addr_f[31:0];
295+
assign r_data[31:0] = r_data_f[31:0];
296+
297+
endmodule
298+

0 commit comments

Comments
 (0)