|
| 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