diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2bd93be..a3afe9f30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased ### Added - `axi_sim_mem`: Increase number of request ports, add multiport interface variant. +- `axi_bus_compare`: Optionally consider AXI `size` field to only compare used data. + +### Fixed +- `axi_bus_compare`: Fix mismatch detection. ## 0.39.3 - 2024-05-08 ### Added diff --git a/src/axi_bus_compare.sv b/src/axi_bus_compare.sv index b92e6159f..e1a3426ee 100644 --- a/src/axi_bus_compare.sv +++ b/src/axi_bus_compare.sv @@ -20,6 +20,10 @@ module axi_bus_compare #( parameter int unsigned AxiIdWidth = 32'd0, /// FIFO depth parameter int unsigned FifoDepth = 32'd0, + /// Consider size field in comparison + parameter bit UseSize = 1'b0, + /// Data width of the AXI4+ATOP interface + parameter int unsigned DataWidth = 32'd8, /// AW channel type of the AXI4+ATOP interface parameter type axi_aw_chan_t = logic, /// W channel type of the AXI4+ATOP interface @@ -151,6 +155,12 @@ module axi_bus_compare #( axi_r_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_r_b; + // Size alignment signals + logic [2:0] w_size; + logic [$clog2(DataWidth/8)-1:0] w_lower, w_offset, w_increment; + logic [2**AxiIdWidth-1:0][2:0] r_size; + logic [2**AxiIdWidth-1:0][$clog2(DataWidth/8)-1:0] r_lower, r_offset, r_increment; + //----------------------------------- // Channel A stream forks //----------------------------------- @@ -272,6 +282,46 @@ module axi_bus_compare #( .ready_i ( fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id] ) ); + if (UseSize) begin : gen_r_size + stream_fifo #( + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), + // .DATA_WIDTH ( 7+3 ), + .DEPTH ( 2*FifoDepth ) + ) i_stream_fifo_w_size ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i ( 1'b0 ), + .usage_o (), + .data_i ( {axi_a_req_i.ar.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.ar.size} ), + .valid_i ( fifo_valid_ar_a [id] & fifo_ready_ar_a [id] ), + .ready_o (), + .data_o ( {r_offset[id], r_size[id]} ), + .valid_o (), + .ready_i ( fifo_cmp_valid_r_a[id] & fifo_cmp_valid_r_b[id] & fifo_cmp_data_r_a[id].last ) + ); + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_r_increment + if(!rst_ni) begin + r_increment[id] <= '0; + end else begin + if (fifo_cmp_valid_r_a[id] && fifo_cmp_valid_r_b[id]) begin + if (fifo_cmp_data_r_a[id].last) begin + r_increment[id] <= '0; + end else begin + r_increment[id] <= r_increment[id] + 2**r_size[id] - ((r_offset[id]+r_increment[id])%(2**r_size[id])); + end + end + end + end + assign r_lower[id] = r_offset[id] + r_increment[id]; + end else begin : gen_no_size + assign r_offset[id] = '0; + assign r_size[id] = '1; + assign r_lower[id] = '0; + end + + stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), @@ -292,6 +342,45 @@ module axi_bus_compare #( ); end + if (UseSize) begin : gen_w_size + stream_fifo #( + .FALL_THROUGH ( 1'b0 ), + .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), + // .DATA_WIDTH ( 7+3 ), + .DEPTH ( FifoDepth ) + ) i_stream_fifo_w_size ( + .clk_i, + .rst_ni, + .testmode_i, + .flush_i ( 1'b0 ), + .usage_o (), + .data_i ( {axi_a_req_i.aw.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.aw.size} ), + .valid_i ( axi_a_req_i.aw_valid & axi_a_rsp_o.aw_ready ), + .ready_o (), + .data_o ( {w_offset, w_size} ), + .valid_o (), + .ready_i ( fifo_cmp_valid_w_a & fifo_cmp_valid_w_b & fifo_cmp_data_w_a.last ) + ); + always_ff @(posedge clk_i or negedge rst_ni) begin : proc_w_increment + if(!rst_ni) begin + w_increment <= '0; + end else begin + if (fifo_cmp_valid_w_a && fifo_cmp_valid_w_b) begin + if (fifo_cmp_data_w_a.last) begin + w_increment <= '0; + end else begin + w_increment <= (w_increment + 2**w_size) - ((w_offset+w_increment)%(2**w_size)); + end + end + end + end + assign w_lower = w_offset + w_increment; + end else begin : gen_no_size + assign w_offset = '0; + assign w_size = '1; + assign w_lower = '0; + end + stream_fifo #( .FALL_THROUGH ( 1'b0 ), .DATA_WIDTH ( 1'b0 ), @@ -555,18 +644,68 @@ module axi_bus_compare #( // Comparison //----------------------------------- for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_cmp + logic [DataWidth/8-1:0] r_data_partial_mismatch; + logic r_data_mismatch; + + if (UseSize) begin : gen_r_mismatch_sized + for (genvar j = 0; j < DataWidth/8; j++) begin : gen_r_partial_mismatch + assign r_data_partial_mismatch[j] = fifo_cmp_data_r_a[id].data[8*j+:8] != fifo_cmp_data_r_b[id].data[8*j+:8]; + end + + always_comb begin : proc_r_data_mismatch + r_data_mismatch = '0; + for (int unsigned j = 0; j < DataWidth/8; j++) begin + if (j >= r_lower[id] && j < (r_lower[id] + 2**r_size[id])-((r_lower[id] + 2**r_size[id])%(2**r_size[id])) ) begin + r_data_mismatch |= r_data_partial_mismatch[j]; + end + end + end + end else begin : gen_r_mismatch_unsized + assign r_data_mismatch = fifo_cmp_data_r_a[id].data != fifo_cmp_data_r_b[id].data; + end + assign aw_mismatch_o [id] = (fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id]) ? - fifo_cmp_data_aw_a [id] == fifo_cmp_data_aw_b [id] : '0; + fifo_cmp_data_aw_a [id] != fifo_cmp_data_aw_b [id] : '0; assign b_mismatch_o [id] = (fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id]) ? - fifo_cmp_data_b_a [id] == fifo_cmp_data_b_b [id] : '0; + fifo_cmp_data_b_a [id] != fifo_cmp_data_b_b [id] : '0; assign ar_mismatch_o [id] = (fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id]) ? - fifo_cmp_data_ar_a [id] == fifo_cmp_data_ar_b [id] : '0; + fifo_cmp_data_ar_a [id] != fifo_cmp_data_ar_b [id] : '0; assign r_mismatch_o [id] = (fifo_cmp_valid_r_a [id] & fifo_cmp_valid_r_b [id]) ? - fifo_cmp_data_r_a [id] == fifo_cmp_data_r_b [id] : '0; + ( fifo_cmp_data_r_a[id].id != fifo_cmp_data_r_b[id].id | + r_data_mismatch | + fifo_cmp_data_r_a[id].resp != fifo_cmp_data_r_b[id].resp | + fifo_cmp_data_r_a[id].last != fifo_cmp_data_r_b[id].last | + fifo_cmp_data_r_a[id].user != fifo_cmp_data_r_b[id].user ) + : '0; + end + + logic [DataWidth/8-1:0] w_data_partial_mismatch; + logic w_data_mismatch; + + if (UseSize) begin : gen_w_mismatch_sized + for (genvar j = 0; j < DataWidth/8; j++) begin : gen_w_partial_mismatch + assign w_data_partial_mismatch[j] = fifo_cmp_data_w_a.data[8*j+:8] != fifo_cmp_data_w_b.data[8*j+:8] | + fifo_cmp_data_w_a.strb[ j ] != fifo_cmp_data_w_b.strb[ j ]; + end + + always_comb begin : proc_w_data_mismatch + w_data_mismatch = '0; + for (int unsigned j = 0; j < DataWidth/8; j++) begin + if (j >= w_lower && j < (w_lower + 2**w_size)-((w_lower + 2**w_size)%(2**w_size)) ) begin + w_data_mismatch |= w_data_partial_mismatch[j]; + end + end + end + end else begin : gen_w_mismatch_unsized + assign w_data_mismatch = fifo_cmp_data_w_a.data != fifo_cmp_data_w_b.data | + fifo_cmp_data_w_a.strb != fifo_cmp_data_w_b.strb; end assign w_mismatch_o = (fifo_cmp_valid_w_a & fifo_cmp_valid_w_b ) ? - fifo_cmp_data_w_a != fifo_cmp_data_w_b : '0; + ( w_data_mismatch | + fifo_cmp_data_w_a.last != fifo_cmp_data_w_b.last | + fifo_cmp_data_w_a.user != fifo_cmp_data_w_b.user ) + : '0; //----------------------------------- diff --git a/src/axi_slave_compare.sv b/src/axi_slave_compare.sv index a4442985c..6cda82e05 100644 --- a/src/axi_slave_compare.sv +++ b/src/axi_slave_compare.sv @@ -22,6 +22,10 @@ module axi_slave_compare #( parameter int unsigned AxiIdWidth = 32'd0, /// FIFO depth parameter int unsigned FifoDepth = 32'd0, + /// Consider size field in comparison + parameter bit UseSize = 1'b0, + /// Data width of the AXI4+ATOP interface + parameter int unsigned DataWidth = 32'd8, /// AW channel type of the AXI4+ATOP interface parameter type axi_aw_chan_t = logic, /// W channel type of the AXI4+ATOP interface @@ -154,6 +158,8 @@ module axi_slave_compare #( axi_bus_compare #( .AxiIdWidth ( AxiIdWidth ), .FifoDepth ( FifoDepth ), + .UseSize ( UseSize ), + .DataWidth ( DataWidth ), .axi_aw_chan_t ( axi_aw_chan_t ), .axi_w_chan_t ( axi_w_chan_t ), .axi_b_chan_t ( axi_b_chan_t ),