Skip to content

Commit

Permalink
Merge pull request pulp-platform#277 from pulp-platform/axi_rw_join_s…
Browse files Browse the repository at this point in the history
…plit-tbenz

Add rw_split and rw_join modules
  • Loading branch information
thommythomaso authored Nov 11, 2022
2 parents 3781060 + c7d995b commit af8b0ce
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 21 deletions.
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ sources:
- src/axi_lite_to_axi.sv
- src/axi_modify_address.sv
- src/axi_mux.sv
- src/axi_rw_join.sv
- src/axi_rw_split.sv
- src/axi_serializer.sv
- src/axi_slave_compare.sv
- src/axi_throttle.sv
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add `axi_bus_compare` and `axi_slave_compare`; two synthesizable verification IPs meant to be used
to compare two AXI buses on an FPGA.
- Add `axi_lite_from_mem` and `axi_from_mem` acting like SRAMs making AXI4 requests downstream.
- Add `axi_rw_join` and `axi_rw_split` to split/join AXI buses.

### Changed
- `axi_demux`: Replace FIFO between AW and W channel by a register plus a counter. This prevents
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ In addition to the documents linked in the following table, we are setting up [d
| [`axi_multicut`](src/axi_multicut.sv) | AXI register which can be used to relax timing pressure on long AXI buses. | |
| [`axi_mux`](src/axi_mux.sv) | Multiplexes the AXI4 slave ports down to one master port. | [Doc](doc/axi_mux.md) |
| [`axi_pkg`](src/axi_pkg.sv) | Contains AXI definitions, common structs, and useful helper functions. | |
| [`axi_rw_join`](src/axi_rw_join.sv) | Joins a read and a write slave into one single read / write master. | |
| [`axi_rw_split`](src/axi_rw_split.sv) | Splits a single read / write slave into one read and one write master. | |
| [`axi_serializer`](src/axi_serializer.sv) | Serializes transactions with different IDs to the same ID. | |
| [`axi_throttle`](src/axi_throttle.sv) | Limits the maximum number of outstanding transfers sent to the downstream logic. | |
| [`axi_test`](src/axi_test.sv) | A set of testbench utilities for AXI interfaces. | |
Expand Down
2 changes: 2 additions & 0 deletions axi.core
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ filesets:
- src/axi_lite_to_axi.sv
- src/axi_modify_address.sv
- src/axi_mux.sv
- src/axi_rw_join.sv
- src/axi_rw_split.sv
- src/axi_serializer.sv
- src/axi_slave_compare.sv
- src/axi_throttle.sv
Expand Down
110 changes: 110 additions & 0 deletions src/axi_rw_join.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) 2022 ETH Zurich, 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:
// - Tobias Senti <[email protected]>

`include "axi/assign.svh"
`include "common_cells/assertions.svh"

/// Joins a read and a write slave into one single read / write master
///
/// Connects the ar and r channel of the read slave to the read / write master
/// and the aw, w and b channel of the write slave to the read / write master
module axi_rw_join #(
parameter type axi_req_t = logic,
parameter type axi_resp_t = logic
) (
input logic clk_i,
input logic rst_ni,
// Read Slave
input axi_req_t slv_read_req_i,
output axi_resp_t slv_read_resp_o,

// Write Slave
input axi_req_t slv_write_req_i,
output axi_resp_t slv_write_resp_o,

// Read / Write Master
output axi_req_t mst_req_o,
input axi_resp_t mst_resp_i
);

//--------------------------------------
// Read channel data
//--------------------------------------

// Assign Read Structs
`AXI_ASSIGN_AR_STRUCT ( mst_req_o.ar , slv_read_req_i.ar )
`AXI_ASSIGN_R_STRUCT ( slv_read_resp_o.r , mst_resp_i.r )

// Read B channel data
assign slv_read_resp_o.b = '0;


//--------------------------------------
// Read channel handshakes
//--------------------------------------

// Read AR channel handshake
assign mst_req_o.ar_valid = slv_read_req_i.ar_valid;
assign slv_read_resp_o.ar_ready = mst_resp_i.ar_ready;

// Read R channel handshake
assign slv_read_resp_o.r_valid = mst_resp_i.r_valid;
assign mst_req_o.r_ready = slv_read_req_i.r_ready;

// Read AW, W and B handshake
assign slv_read_resp_o.aw_ready = 1'b0;
assign slv_read_resp_o.w_ready = 1'b0;
assign slv_read_resp_o.b_valid = 1'b0;

// check for AW and W never to be valid
`ASSERT_NEVER(slv_read_req_aw_valid, slv_read_req_i.aw_valid, clk_i, !rst_ni)
`ASSERT_NEVER(slv_read_req_w_valid, slv_read_req_i.w_valid, clk_i, !rst_ni)

//--------------------------------------
// Write channel data
//--------------------------------------

// Assign Write Structs
`AXI_ASSIGN_AW_STRUCT ( mst_req_o.aw , slv_write_req_i.aw )
`AXI_ASSIGN_W_STRUCT ( mst_req_o.w , slv_write_req_i.w )
`AXI_ASSIGN_B_STRUCT ( slv_write_resp_o.b , mst_resp_i.b )

// Write R channel data
assign slv_write_resp_o.r = '0;


//--------------------------------------
// Write channel handshakes
//--------------------------------------

// Write AR and R channel handshake
assign slv_write_resp_o.ar_ready = 1'b0;
assign slv_write_resp_o.r_valid = 1'b0;

// check for AR to never be valid
`ASSERT_NEVER(slv_write_req_ar_valid, slv_write_req_i.ar_valid, clk_i, !rst_ni)

// Write AW channel handshake
assign mst_req_o.aw_valid = slv_write_req_i.aw_valid;
assign slv_write_resp_o.aw_ready = mst_resp_i.aw_ready;

// Write W channel handshake
assign mst_req_o.w_valid = slv_write_req_i.w_valid;
assign slv_write_resp_o.w_ready = mst_resp_i.w_ready;

// Write B channel handshake
assign slv_write_resp_o.b_valid = mst_resp_i.b_valid;
assign mst_req_o.b_ready = slv_write_req_i.b_ready;

endmodule : axi_rw_join
111 changes: 111 additions & 0 deletions src/axi_rw_split.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) 2022 ETH Zurich, 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:
// - Tobias Senti <[email protected]>

`include "axi/assign.svh"
`include "common_cells/assertions.svh"

/// Splits a single read / write slave into one read and one write master
///
/// Connects the ar and r channel of the read / write slave to the read master
/// and the aw, w and b channel of the read / write slave to the write master
module axi_rw_split #(
parameter type axi_req_t = logic,
parameter type axi_resp_t = logic
) (
input logic clk_i,
input logic rst_ni,
// Read / Write Slave
input axi_req_t slv_req_i,
output axi_resp_t slv_resp_o,

// Read Master
output axi_req_t mst_read_req_o,
input axi_resp_t mst_read_resp_i,

// Write Master
output axi_req_t mst_write_req_o,
input axi_resp_t mst_write_resp_i
);

//--------------------------------------
// Read channel data
//--------------------------------------

// Assign Read channel structs
`AXI_ASSIGN_AR_STRUCT ( mst_read_req_o.ar , slv_req_i.ar )
`AXI_ASSIGN_R_STRUCT ( slv_resp_o.r , mst_read_resp_i.r )

// Read AW and W channel data
assign mst_read_req_o.aw = '0;
assign mst_read_req_o.w = '0;


//--------------------------------------
// Read channel handshakes
//--------------------------------------

// Read AR channel handshake
assign mst_read_req_o.ar_valid = slv_req_i.ar_valid;
assign slv_resp_o.ar_ready = mst_read_resp_i.ar_ready;

// Read R channel handshake
assign slv_resp_o.r_valid = mst_read_resp_i.r_valid;
assign mst_read_req_o.r_ready = slv_req_i.r_ready;

// Read AW, W and B handshake
assign mst_read_req_o.aw_valid = 1'b0;
assign mst_read_req_o.w_valid = 1'b0;
assign mst_read_req_o.b_ready = 1'b0;

// check for B never to be valid
`ASSERT_NEVER(mst_read_resp_b_valid, mst_read_resp_i.b_valid, clk_i, !rst_ni)


//--------------------------------------
// Write channel data
//--------------------------------------

// Assign Write channel structs
`AXI_ASSIGN_AW_STRUCT ( mst_write_req_o.aw , slv_req_i.aw )
`AXI_ASSIGN_W_STRUCT ( mst_write_req_o.w , slv_req_i.w )
`AXI_ASSIGN_B_STRUCT ( slv_resp_o.b , mst_write_resp_i.b )

// Write AR channel data
assign mst_write_req_o.ar = '0;


//--------------------------------------
// Write channel handshakes
//--------------------------------------

// Write AR and R channel handshake
assign mst_write_req_o.ar_valid = 1'b0;
assign mst_write_req_o.r_ready = 1'b0;

// check for R never to be valid
`ASSERT_NEVER(mst_read_resp_r_valid, mst_read_resp_i.r_valid, clk_i, !rst_ni)

// Write AW channel handshake
assign mst_write_req_o.aw_valid = slv_req_i.aw_valid;
assign slv_resp_o.aw_ready = mst_write_resp_i.aw_ready;

// Write W channel handshake
assign mst_write_req_o.w_valid = slv_req_i.w_valid;
assign slv_resp_o.w_ready = mst_write_resp_i.w_ready;

// Write B channel handshake
assign slv_resp_o.b_valid = mst_write_resp_i.b_valid;
assign mst_write_req_o.b_ready = slv_req_i.b_ready;

endmodule : axi_rw_split
34 changes: 13 additions & 21 deletions src/axi_to_mem_split.sv
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,19 @@ module axi_to_mem_split #(

logic read_busy, write_busy;

always_comb begin: proc_axi_rw_split
`AXI_SET_R_STRUCT(axi_resp_o.r, axi_read_resp.r)
axi_resp_o.r_valid = axi_read_resp.r_valid;
axi_resp_o.ar_ready = axi_read_resp.ar_ready;
`AXI_SET_B_STRUCT(axi_resp_o.b, axi_write_resp.b)
axi_resp_o.b_valid = axi_write_resp.b_valid;
axi_resp_o.aw_ready = axi_write_resp.aw_ready;
axi_resp_o.w_ready = axi_write_resp.w_ready;

axi_write_req = '0;
`AXI_SET_AW_STRUCT(axi_write_req.aw, axi_req_i.aw)
axi_write_req.aw_valid = axi_req_i.aw_valid;
`AXI_SET_W_STRUCT(axi_write_req.w, axi_req_i.w)
axi_write_req.w_valid = axi_req_i.w_valid;
axi_write_req.b_ready = axi_req_i.b_ready;

axi_read_req = '0;
`AXI_SET_AR_STRUCT(axi_read_req.ar, axi_req_i.ar)
axi_read_req.ar_valid = axi_req_i.ar_valid;
axi_read_req.r_ready = axi_req_i.r_ready;
end
axi_rw_split #(
.axi_req_t ( axi_req_t ),
.axi_resp_t ( axi_resp_t )
) i_axi_rw_split (
.clk_i,
.rst_ni,
.slv_req_i ( axi_req_i ),
.slv_resp_o ( axi_resp_o ),
.mst_read_req_o ( axi_read_req ),
.mst_read_resp_i ( axi_read_resp ),
.mst_write_req_o ( axi_write_req ),
.mst_write_resp_i ( axi_write_resp )
);

assign busy_o = read_busy || write_busy;

Expand Down
2 changes: 2 additions & 0 deletions src_files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ axi:
- src/axi_lite_to_axi.sv
- src/axi_modify_address.sv
- src/axi_mux.sv
- src/axi_rw_join.sv
- src/axi_rw_split.sv
- src/axi_serializer.sv
- src/axi_slave_compare.sv
- src/axi_throttle.sv
Expand Down

0 comments on commit af8b0ce

Please sign in to comment.