From 59394319fc17cb792554da5dfc989a4d26b0458d Mon Sep 17 00:00:00 2001 From: Thomas Benz Date: Mon, 7 Aug 2023 21:20:46 +0200 Subject: [PATCH] hw: Add improved `axi_to_reg` adapter (#62) * axi_to_reg: Create a better version * axi_to_reg: Fix write enable polarity * axi_to_reg: Filter zero strobe writes * axi_to_reg: Change type definition scope to localparam --- Bender.yml | 1 + hw/cheshire_soc.sv | 65 +++++--------- hw/future/axi_to_reg_v2.sv | 170 +++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 46 deletions(-) create mode 100644 hw/future/axi_to_reg_v2.sv diff --git a/Bender.yml b/Bender.yml index 8f478b1bc..b13581ff5 100644 --- a/Bender.yml +++ b/Bender.yml @@ -33,6 +33,7 @@ export_include_dirs: - hw/include sources: + - hw/future/axi_to_reg_v2.sv - hw/bootrom/cheshire_bootrom.sv - hw/regs/cheshire_reg_pkg.sv - hw/regs/cheshire_reg_top.sv diff --git a/hw/cheshire_soc.sv b/hw/cheshire_soc.sv index 7b767ca00..b5797a1e6 100644 --- a/hw/cheshire_soc.sv +++ b/hw/cheshire_soc.sv @@ -307,12 +307,12 @@ module cheshire_soc import cheshire_pkg::*; #( axi_slv_req_t axi_reg_amo_req, axi_reg_cut_req; axi_slv_rsp_t axi_reg_amo_rsp, axi_reg_cut_rsp; - axi_d32_req_t axi_reg_d32_req; - axi_d32_rsp_t axi_reg_d32_rsp; reg_req_t reg_in_req; reg_rsp_t reg_in_rsp; + logic[AxiSlvIdWidth-1:0] reg_id; + reg_req_t [RegOut.num_out-1:0] reg_out_req; reg_rsp_t [RegOut.num_out-1:0] reg_out_rsp; @@ -359,53 +359,26 @@ module cheshire_soc import cheshire_pkg::*; #( .mst_resp_i ( axi_reg_cut_rsp ) ); - // Convert to 32-bit reg datawidth - axi_dw_converter #( - .AxiSlvPortDataWidth ( Cfg.AxiDataWidth ), - .AxiMstPortDataWidth ( 32 ), - .AxiAddrWidth ( Cfg.AddrWidth ), - .AxiIdWidth ( AxiSlvIdWidth ), - .aw_chan_t ( axi_slv_aw_chan_t ), - .mst_w_chan_t ( axi_d32_w_chan_t ), - .slv_w_chan_t ( axi_slv_w_chan_t ), - .b_chan_t ( axi_slv_b_chan_t ), - .ar_chan_t ( axi_slv_ar_chan_t ), - .mst_r_chan_t ( axi_d32_r_chan_t ), - .slv_r_chan_t ( axi_slv_r_chan_t ), - .axi_mst_req_t ( axi_d32_req_t ), - .axi_mst_resp_t ( axi_d32_rsp_t ), - .axi_slv_req_t ( axi_slv_req_t ), - .axi_slv_resp_t ( axi_slv_rsp_t ) - ) i_reg_axi_dw_converter ( - .clk_i, - .rst_ni, - .slv_req_i ( axi_reg_cut_req ), - .slv_resp_o ( axi_reg_cut_rsp ), - .mst_req_o ( axi_reg_d32_req ), - .mst_resp_i ( axi_reg_d32_rsp ) - ); - // Convert from AXI to reg protocol - axi_to_reg #( - .ADDR_WIDTH ( Cfg.AddrWidth ), - .DATA_WIDTH ( 32 ), - .ID_WIDTH ( AxiSlvIdWidth ), - .USER_WIDTH ( Cfg.AxiUserWidth ), - .AXI_MAX_WRITE_TXNS ( Cfg.RegMaxReadTxns ), - .AXI_MAX_READ_TXNS ( Cfg.RegMaxWriteTxns ), - .DECOUPLE_W ( 1 ), - .axi_req_t ( axi_d32_req_t ), - .axi_rsp_t ( axi_d32_rsp_t ), - .reg_req_t ( reg_req_t ), - .reg_rsp_t ( reg_rsp_t ) - ) i_reg_axi_to_reg ( + axi_to_reg_v2 #( + .AxiAddrWidth ( Cfg.AddrWidth ), + .AxiDataWidth ( Cfg.AxiDataWidth ), + .AxiIdWidth ( AxiSlvIdWidth ), + .AxiUserWidth ( Cfg.AxiUserWidth ), + .RegDataWidth ( 32'd32 ), + .axi_req_t ( axi_slv_req_t ), + .axi_rsp_t ( axi_slv_rsp_t ), + .reg_req_t ( reg_req_t ), + .reg_rsp_t ( reg_rsp_t ) + ) i_axi_to_reg_v2 ( .clk_i, .rst_ni, - .testmode_i ( test_mode_i ), - .axi_req_i ( axi_reg_d32_req ), - .axi_rsp_o ( axi_reg_d32_rsp ), - .reg_req_o ( reg_in_req ), - .reg_rsp_i ( reg_in_rsp ) + .axi_req_i ( axi_reg_cut_req ), + .axi_rsp_o ( axi_reg_cut_rsp ), + .reg_req_o ( reg_in_req ), + .reg_rsp_i ( reg_in_rsp ), + .reg_id_o ( reg_id ), + .busy_o ( ) ); // Non-matching addresses are directed to an error slave diff --git a/hw/future/axi_to_reg_v2.sv b/hw/future/axi_to_reg_v2.sv new file mode 100644 index 000000000..6ba723d8c --- /dev/null +++ b/hw/future/axi_to_reg_v2.sv @@ -0,0 +1,170 @@ +// Copyright 2023 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Thomas Benz + +`include "axi/typedef.svh" + +/// Version 2 of a protocol converter from AXI4 to the register interface. +/// AXI Data Width >= Reg Data Width +module axi_to_reg_v2 #( + /// The width of the address. + parameter int unsigned AxiAddrWidth = 32'd0, + /// The width of the data. + parameter int unsigned AxiDataWidth = 32'd0, + /// The width of the id. + parameter int unsigned AxiIdWidth = 32'd0, + /// The width of the user signal. + parameter int unsigned AxiUserWidth = 32'd0, + /// The data width of the Reg bus + parameter int unsigned RegDataWidth = 32'd0, + /// AXI request struct type. + parameter type axi_req_t = logic, + /// AXI response struct type. + parameter type axi_rsp_t = logic, + /// Regbus request struct type. + parameter type reg_req_t = logic, + /// Regbus response struct type. + parameter type reg_rsp_t = logic, + /// Dependent parameter: ID Width + parameter type id_t = logic[AxiIdWidth-1:0] +)( + input logic clk_i, + input logic rst_ni, + input axi_req_t axi_req_i, + output axi_rsp_t axi_rsp_o, + output reg_req_t reg_req_o, + input reg_rsp_t reg_rsp_i, + output id_t reg_id_o, + output logic busy_o +); + + // how many times is the AXI bus wider than the regbus? + localparam int unsigned NumBanks = AxiDataWidth / RegDataWidth; + + localparam type addr_t = logic [AxiAddrWidth-1 :0]; + localparam type reg_data_t = logic [RegDataWidth-1 :0]; + localparam type reg_strb_t = logic [RegDataWidth/8-1:0]; + + // TCDM BUS + logic [NumBanks-1:0] mem_req; + logic [NumBanks-1:0] mem_gnt; + addr_t [NumBanks-1:0] mem_addr; + reg_data_t [NumBanks-1:0] mem_wdata; + reg_strb_t [NumBanks-1:0] mem_strb; + logic [NumBanks-1:0] mem_we; + id_t [NumBanks-1:0] mem_id; + logic [NumBanks-1:0] mem_rvalid; + reg_data_t [NumBanks-1:0] mem_rdata; + logic [NumBanks-1:0] mem_err; + + // sub reg buses + reg_req_t [NumBanks-1:0] reg_req, valid_req, zero_w_req; + reg_rsp_t [NumBanks-1:0] reg_rsp, valid_rsp, zero_w_rsp; + + // convert to TCDM first + axi_to_detailed_mem #( + .axi_req_t ( axi_req_t ), + .axi_resp_t ( axi_rsp_t ), + .AddrWidth ( AxiAddrWidth ), + .DataWidth ( AxiDataWidth ), + .IdWidth ( AxiIdWidth ), + .UserWidth ( AxiUserWidth ), + .NumBanks ( NumBanks ), + .BufDepth ( 32'd1 ), + .HideStrb ( 1'b0 ), + .OutFifoDepth ( 32'd1 ) + ) i_axi_to_detailed_mem ( + .clk_i, + .rst_ni, + .busy_o, + .axi_req_i, + .axi_resp_o ( axi_rsp_o ), + .mem_req_o ( mem_req ), + .mem_gnt_i ( mem_gnt ), + .mem_addr_o ( mem_addr ), + .mem_wdata_o ( mem_wdata ), + .mem_strb_o ( mem_strb ), + .mem_atop_o ( /* NOT CONNECTED */ ), + .mem_lock_o ( /* NOT CONNECTED */ ), + .mem_we_o ( mem_we ), + .mem_id_o ( mem_id ), + .mem_user_o ( /* NOT CONNECTED */ ), + .mem_cache_o ( /* NOT CONNECTED */ ), + .mem_prot_o ( /* NOT CONNECTED */ ), + .mem_qos_o ( /* NOT CONNECTED */ ), + .mem_region_o ( /* NOT CONNECTED */ ), + .mem_rvalid_i ( mem_rvalid ), + .mem_rdata_i ( mem_rdata ), + .mem_err_i ( mem_err ), + .mem_exokay_i ( '0 ) + ); + + // every subbus is converted independently + for (genvar i = 0; i < NumBanks; i++) begin : gen_tcdm_to_reg + periph_to_reg #( + .AW ( AxiAddrWidth ), + .DW ( RegDataWidth ), + .IW ( AxiIdWidth ), + .req_t ( reg_req_t ), + .rsp_t ( reg_rsp_t ) + ) i_periph_to_reg ( + .clk_i, + .rst_ni, + .req_i ( mem_req [i] ), + .add_i ( mem_addr [i] ), + .wen_i ( !mem_we [i] ), + .wdata_i ( mem_wdata [i] ), + .be_i ( mem_strb [i] ), + .id_i ( '0 ), + .gnt_o ( mem_gnt [i] ), + .r_rdata_o ( mem_rdata [i] ), + .r_opc_o ( mem_err [i] ), + .r_id_o ( /* NOT CONNECTED */ ), + .r_valid_o ( mem_rvalid [i] ), + .reg_req_o ( reg_req [i] ), + .reg_rsp_i ( reg_rsp [i] ) + ); + + // filter zero strobe writes early, directly ack them + reg_demux #( + .NoPorts ( 32'd2 ), + .req_t ( reg_req_t ), + .rsp_t ( reg_rsp_t ) + ) i_reg_demux ( + .clk_i, + .rst_ni, + .in_select_i ( reg_req[i].write & (reg_req[i].wstrb == '0) ), + .in_req_i ( reg_req[i] ), + .in_rsp_o ( reg_rsp[i] ), + .out_req_o ( {zero_w_req[i], valid_req[i]} ), + .out_rsp_i ( {zero_w_rsp[i], valid_rsp[i]} ) + ); + + // ack zero strobe writes here + assign zero_w_rsp[i].ready = 1'b1; + assign zero_w_rsp[i].error = 1'b0; + assign zero_w_rsp[i].rdata = '0; + end + + // arbitrate over valid accesses in sub buses + reg_mux #( + .NoPorts( NumBanks ), + .AW ( AxiAddrWidth ), + .DW ( AxiDataWidth ), + .req_t ( reg_req_t ), + .rsp_t ( reg_rsp_t ) + ) i_reg_mux ( + .clk_i, + .rst_ni, + .in_req_i ( valid_req ), + .in_rsp_o ( valid_rsp ), + .out_req_o ( reg_req_o ), + .out_rsp_i ( reg_rsp_i ) + ); + + // forward the id, all banks carry the same ID here + assign reg_id_o = mem_id[0]; + +endmodule