Skip to content

Commit

Permalink
axi_lite_lfsr: Add an AXI4 and AXI4 Lite LFSR
Browse files Browse the repository at this point in the history
  • Loading branch information
thommythomaso committed Sep 27, 2022
1 parent 9b1a082 commit d96fb65
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ sources:
- src/axi_join.sv
- src/axi_lite_demux.sv
- src/axi_lite_join.sv
- src/axi_lite_lfsr.sv
- src/axi_lite_mailbox.sv
- src/axi_lite_mux.sv
- src/axi_lite_regs.sv
Expand All @@ -55,6 +56,7 @@ sources:
- src/axi_err_slv.sv
- src/axi_dw_converter.sv
- src/axi_id_serialize.sv
- src/axi_lfsr.sv
- src/axi_multicut.sv
- src/axi_to_axi_lite.sv
- src/axi_to_mem_banked.sv
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add `axi_dumper` and `axi_dumper_interpret` script to dump log from an AXI bus for debugging purposes.
- Add FuseSoC and Vivado XSIM limited test to CI
- `assign.svh`: Add macros to assign flat buses using the Vivado naming style.
- `axi_lfsr` and `axi_lite_lfsr`: Add AXI4 and AXI4 Lite LFSR Subordinate devices.

### Changed
- Improve compatibility with FuseSoC
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ In addition to the documents linked in the following table, we are setting up [d
| [`axi_isolate`](src/axi_isolate.sv) | A module that can isolate downstream slaves from receiving new AXI4 transactions. | |
| [`axi_iw_converter`](src/axi_iw_converter.sv) | Convert between any two AXI ID widths. | [Doc][doc.axi_iw_converter] |
| [`axi_join`](src/axi_join.sv) | A connector that joins two AXI interfaces. | |
| [`axi_lfsr`](src/axi_lfsr.sv) | AXI4-attached LFSR; read returns pseudo-random data, writes are compressed into a checksum. | |
| [`axi_lite_demux`](src/axi_lite_demux.sv) | Demultiplexes an AXI4-Lite bus from one slave port to multiple master ports. | [Doc](doc/axi_lite_demux.md) |
| [`axi_lite_join`](src/axi_lite_join.sv) | A connector that joins two AXI-Lite interfaces. | |
| [`axi_lite_lfsr`](src/axi_lite_lfsr.sv) | AXI4-Lite-attached LFSR; read returns pseudo-random data, writes are compressed into a checksum. | |
| [`axi_lite_mailbox`](src/axi_lite_mailbox.sv) | A AXI4-Lite Mailbox with two slave ports and usage triggered irq. | [Doc](doc/axi_lite_mailbox.md) |
| [`axi_lite_mux`](src/axi_lite_mux.sv) | Multiplexes AXI4-Lite slave ports down to one master port. | [Doc](doc/axi_lite_mux.md) |
| [`axi_lite_regs`](src/axi_lite_regs.sv) | AXI4-Lite registers with optional read-only and protection features. | [Doc][doc.axi_lite_regs] |
Expand Down
2 changes: 2 additions & 0 deletions axi.core
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ filesets:
- src/axi_join.sv
- src/axi_lite_demux.sv
- src/axi_lite_join.sv
- src/axi_lite_lfsr.sv
- src/axi_lite_mailbox.sv
- src/axi_lite_mux.sv
- src/axi_lite_regs.sv
Expand All @@ -46,6 +47,7 @@ filesets:
- src/axi_err_slv.sv
- src/axi_dw_converter.sv
- src/axi_id_serialize.sv
- src/axi_lfsr.sv
- src/axi_multicut.sv
- src/axi_to_axi_lite.sv
- src/axi_to_mem_banked.sv
Expand Down
121 changes: 121 additions & 0 deletions src/axi_lfsr.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2022 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Thomas Benz <[email protected]>

`include "axi/typedef.svh"

/// AXI4 LFSR Subordinate device. Responds with a pseudo random answer. Serial interface to
/// set the internal state.
module axi_lfsr #(
/// AXI4 Data Width
parameter int unsigned DataWidth = 32'd0,
/// AXI4 Addr Width
parameter int unsigned AddrWidth = 32'd0,
/// AXI4 Id Width
parameter int unsigned IdWidth = 32'd0,
/// AXI4 User Width
parameter int unsigned UserWidth = 32'd0,
/// AXI4 request struct definition
parameter type axi_req_t = logic,
/// AXI4 response struct definition
parameter type axi_rsp_t = logic
)(
/// Rising-edge clock
input logic clk_i,
/// Active-low reset
input logic rst_ni,
/// Testmode
input logic testmode_i,
/// AXI4 request struct
input axi_req_t req_i,
/// AXI4 response struct
output axi_rsp_t rsp_o,
/// Serial shift data in (write)
input logic w_ser_data_i,
/// Serial shift data out (write)
output logic w_ser_data_o,
/// Serial shift enable (write)
input logic w_ser_en_i,
/// Serial shift data in (read)
input logic r_ser_data_i,
/// Serial shift data out (read)
output logic r_ser_data_o,
/// Serial shift enable (read)
input logic r_ser_en_i
);

/// AXI4 Strobe Width
localparam int unsigned StrbWidth = DataWidth / 8;

/// Address Type
typedef logic [AddrWidth-1:0] addr_t;
/// Data type
typedef logic [DataWidth-1:0] data_t;
/// Strobe Type
typedef logic [StrbWidth-1:0] strb_t;

// AXI Lite typedef
`AXI_LITE_TYPEDEF_AW_CHAN_T(axi_lite_aw_chan_t, addr_t)
`AXI_LITE_TYPEDEF_W_CHAN_T(axi_lite_w_chan_t, data_t, strb_t)
`AXI_LITE_TYPEDEF_B_CHAN_T(axi_lite_b_chan_t)

`AXI_LITE_TYPEDEF_AR_CHAN_T(axi_lite_ar_chan_t, addr_t)
`AXI_LITE_TYPEDEF_R_CHAN_T(axi_lite_r_chan_t, data_t)

`AXI_LITE_TYPEDEF_REQ_T(axi_lite_req_t, axi_lite_aw_chan_t, axi_lite_w_chan_t, axi_lite_ar_chan_t)
`AXI_LITE_TYPEDEF_RESP_T(axi_lite_rsp_t, axi_lite_b_chan_t, axi_lite_r_chan_t)

// AXI Lite buses
axi_lite_req_t axi_lite_req;
axi_lite_rsp_t axi_lite_rsp;

axi_to_axi_lite #(
.AxiAddrWidth ( AddrWidth ),
.AxiDataWidth ( DataWidth ),
.AxiIdWidth ( IdWidth ),
.AxiUserWidth ( UserWidth ),
.AxiMaxWriteTxns ( 'd2 ), // We only have 1 cycle latency; 2 is enough
.AxiMaxReadTxns ( 'd2 ), // We only have 1 cycle latency; 2 is enough
.FallThrough ( 1'b0 ),
.full_req_t ( axi_req_t ),
.full_resp_t ( axi_rsp_t ),
.lite_req_t ( axi_lite_req_t ),
.lite_resp_t ( axi_lite_rsp_t )
) i_axi_to_axi_lite (
.clk_i,
.rst_ni,
.test_i ( testmode_i ),
.slv_req_i ( req_i ),
.slv_resp_o ( rsp_o ),
.mst_req_o ( axi_lite_req ),
.mst_resp_i ( axi_lite_rsp )
);

axi_lite_lfsr #(
.DataWidth ( DataWidth ),
.axi_lite_req_t ( axi_lite_req_t ),
.axi_lite_rsp_t ( axi_lite_rsp_t )
) i_axi_lite_lfsr (
.clk_i,
.rst_ni,
.testmode_i,
.w_ser_data_i,
.w_ser_data_o,
.w_ser_en_i,
.r_ser_data_i,
.r_ser_data_o,
.r_ser_en_i,
.req_i ( axi_lite_req ),
.rsp_o ( axi_lite_rsp )
);

endmodule : axi_lfsr
223 changes: 223 additions & 0 deletions src/axi_lite_lfsr.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Copyright 2022 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Thomas Benz <[email protected]>

`include "common_cells/registers.svh"

/// AXI4 Lite LFSR Subordinate device. Responds with a pseudo random answer. Serial interface to
/// set the internal state.
module axi_lite_lfsr #(
/// AXI4 Lite Data Width
parameter int unsigned DataWidth = 32'd0,
/// AXI4 Lite request struct definition
parameter type axi_lite_req_t = logic,
/// AXI4 Lite response struct definition
parameter type axi_lite_rsp_t = logic
)(
/// Rising-edge clock
input logic clk_i,
/// Active-low reset
input logic rst_ni,
/// Testmode
input logic testmode_i,
/// AXI4 Lite request struct
input axi_lite_req_t req_i,
/// AXI4 Lite response struct
output axi_lite_rsp_t rsp_o,
/// Serial shift data in (write)
input logic w_ser_data_i,
/// Serial shift data out (write)
output logic w_ser_data_o,
/// Serial shift enable (write)
input logic w_ser_en_i,
/// Serial shift data in (read)
input logic r_ser_data_i,
/// Serial shift data out (read)
output logic r_ser_data_o,
/// Serial shift enable (read)
input logic r_ser_en_i
);

/// AXI4 Strobe Width
localparam int unsigned StrbWidth = DataWidth / 8;

logic w_lfsr_en;
logic r_lfsr_en;

logic w_b_fifo_ready;

// LFSR outputs
logic [DataWidth-1:0] w_data_in, w_data_out;

// AW (ignored)
assign rsp_o.aw_ready = !w_ser_en_i;

// W
axi_opt_lfsr #(
.Width ( DataWidth )
) i_axi_opt_lfsr_w (
.clk_i,
.rst_ni,
.en_i ( w_lfsr_en ),
.ser_data_i ( w_ser_data_i ),
.ser_data_o ( w_ser_data_o ),
.ser_en_i ( w_ser_en_i ),
.inp_en_i ( w_lfsr_en ),
.data_i ( w_data_in ),
.data_o ( w_data_out )
);
assign w_lfsr_en = req_i.w_valid & rsp_o.w_ready;
assign rsp_o.w_ready = !w_ser_en_i & w_b_fifo_ready;

// only write bytes with strobe signal enabled
always_comb begin : gen_data_strb_connect
for (int unsigned i = 0; i < StrbWidth; i++) begin : gen_strb_en
if (req_i.w.strb[i] == 1'b0) begin
w_data_in[i*8+:8] = w_data_out[i*8+:8];
end else if (req_i.w.strb[i] == 1'b1) begin
w_data_in[i*8+:8] = req_i.w.data[i*8+:8];
end else begin
w_data_in[i*8+:8] = 'x;
end
end
end

// B
stream_fifo #(
.FALL_THROUGH ( 1'b0 ),
.DATA_WIDTH ( 'd1 ),
.DEPTH ( 'd2 )
) i_stream_fifo_w_b (
.clk_i,
.rst_ni,
.testmode_i,
.flush_i ( 1'b0 ),
.usage_o ( /* NOT CONNECTED */ ),
.data_i ( 1'b0 ),
.valid_i ( req_i.w_valid ),
.ready_o ( w_b_fifo_ready ),
.data_o ( /* NOT CONNECTED */ ),
.valid_o ( w_b_fifo_valid ),
.ready_i ( req_i.b_ready )
);
assign rsp_o.b.resp = axi_pkg::RESP_OKAY;
assign rsp_o.b_valid = w_b_fifo_valid;

// AR (ignored)
assign rsp_o.ar_ready = !w_ser_en_i;

// R
axi_opt_lfsr #(
.Width ( DataWidth )
) i_axi_opt_lfsr_r (
.clk_i,
.rst_ni,
.en_i ( r_lfsr_en ),
.ser_data_i ( r_ser_data_i ),
.ser_data_o ( r_ser_data_o ),
.ser_en_i ( r_ser_en_i ),
.inp_en_i ( 1'b0 ),
.data_i ( /* NOT CONNECTED */ ),
.data_o ( rsp_o.r.data )
);
assign rsp_o.r.resp = axi_pkg::RESP_OKAY;
assign r_lfsr_en = req_i.r_ready & rsp_o.r_valid;
assign rsp_o.r_valid = !r_ser_en_i;

endmodule : axi_lite_lfsr


/// XOR LFSR with tabs based on the [lfsr_table](https://datacipy.cz/lfsr_table.pdf). LFSR has
/// a serial interface to set the initial state
module axi_opt_lfsr #(
parameter int unsigned Width = 32'd0
) (
/// Rising-edge clock
input logic clk_i,
/// Active-low reset
input logic rst_ni,
input logic en_i,
input logic ser_data_i,
output logic ser_data_o,
input logic ser_en_i,
input logic inp_en_i,
input logic [Width-1:0] data_i,
output logic [Width-1:0] data_o
);

/// Number of bits required to hold the LFSR tab configuration
localparam int unsigned LfsrIdxWidth = cf_math_pkg::idx_width(Width);
/// Maximum number of tabs
localparam int unsigned MaxNumTabs = 4;

/// Type specifying the tap positions
typedef logic [LfsrIdxWidth:0] xnor_entry_t [MaxNumTabs-1:0];
xnor_entry_t XnorFeedback;

// the shift register
logic [Width-1:0] reg_d, reg_q;

// the feedback signal
logic xnor_feedback;

always_comb begin : gen_register

// get the parameters
case (Width)
'd8 : XnorFeedback = { 'd8, 'd6, 'd5, 'd4 };
'd16 : XnorFeedback = { 'd16, 'd14, 'd13, 'd11 };
'd32 : XnorFeedback = { 'd32, 'd30, 'd26, 'd25 };
'd64 : XnorFeedback = { 'd64, 'd63, 'd61, 'd60 };
'd128 : XnorFeedback = { 'd128, 'd127, 'd126, 'd119 };
'd256 : XnorFeedback = { 'd256, 'd256, 'd521, 'd246 };
'd512 : XnorFeedback = { 'd512, 'd510, 'd507, 'd504 };
'd1024 : XnorFeedback = { 'd1024, 'd1015, 'd1002, 'd1001 };
default : XnorFeedback = { 'x, 'x, 'x, 'x };
endcase

// shift register functionality
// compression mode
if (inp_en_i) begin
for (int unsigned i = 0; i < Width - 1; i++) begin : gen_comp_conection
reg_d[i] = reg_q[i+1] ^ data_i[i];
end
// generation mode
end else begin
for (int unsigned i = 0; i < Width - 1; i++) begin : gen_gen_conection
reg_d[i] = reg_q[i+1];
end
end
// serial access mode
if (ser_en_i) begin
// new head element
reg_d[Width-1] = ser_data_i;
// LFSR mode
end else begin
xnor_feedback = reg_q[XnorFeedback[MaxNumTabs-1]-1];
for (int unsigned t = 0; t < MaxNumTabs - 1; t++) begin : gen_feedback_path
xnor_feedback = xnor_feedback;
if (XnorFeedback[t] != 0) begin
xnor_feedback = xnor_feedback ^ reg_q[XnorFeedback[t]-1];
end
end
reg_d[Width-1] = inp_en_i ? xnor_feedback ^ data_i[Width-1] : xnor_feedback;
end
end

// connect outputs
assign ser_data_o = reg_q[0];
assign data_o = reg_q;

// state
`FFL(reg_q, reg_d, en_i | ser_en_i, '1, clk_i, rst_ni)

endmodule : axi_opt_lfsr
Loading

0 comments on commit d96fb65

Please sign in to comment.