initial commit
This commit is contained in:
6331
rtl/ip/Bus_interconnects/AxiCrossbar_2x8.v
Normal file
6331
rtl/ip/Bus_interconnects/AxiCrossbar_2x8.v
Normal file
File diff suppressed because it is too large
Load Diff
1608
rtl/ip/Bus_interconnects/Axi_CDC.v
Normal file
1608
rtl/ip/Bus_interconnects/Axi_CDC.v
Normal file
File diff suppressed because it is too large
Load Diff
520
rtl/ip/Bus_interconnects/axi2sram_dp.v
Normal file
520
rtl/ip/Bus_interconnects/axi2sram_dp.v
Normal file
@@ -0,0 +1,520 @@
|
||||
//+FHDR-----------------------------------------------------------------
|
||||
// (C) Copyright Loongson Technology Corporation Limited. All rights reserved
|
||||
// Loongson Confidential Proprietary
|
||||
//-FHDR-----------------------------------------------------------------
|
||||
module axi2sram_dp#(
|
||||
parameter BUS_WIDTH = 32,
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter CPU_WIDTH = 32
|
||||
)
|
||||
(
|
||||
input wire aclk ,
|
||||
input wire aresetn ,
|
||||
output wire [BUS_WIDTH-1 :0] ram_raddr,
|
||||
input wire [DATA_WIDTH-1 :0] ram_rdata,
|
||||
output wire ram_ren ,
|
||||
output wire [BUS_WIDTH-1 :0] ram_waddr,
|
||||
output wire [DATA_WIDTH-1 :0] ram_wdata,
|
||||
output wire [DATA_WIDTH/8-1 :0] ram_wen ,
|
||||
input wire [BUS_WIDTH-1 :0] m_araddr ,
|
||||
input wire [1 :0] m_arburst,
|
||||
input wire [3 :0] m_arcache,
|
||||
input wire [4 :0] m_arid ,
|
||||
input wire [3 :0] m_arlen ,
|
||||
input wire [1 :0] m_arlock ,
|
||||
input wire [2 :0] m_arprot ,
|
||||
output wire m_arready,
|
||||
input wire [2 :0] m_arsize ,
|
||||
input wire m_arvalid,
|
||||
input wire [BUS_WIDTH-1 :0] m_awaddr ,
|
||||
input wire [1 :0] m_awburst,
|
||||
input wire [3 :0] m_awcache,
|
||||
input wire [4 :0] m_awid ,
|
||||
input wire [3 :0] m_awlen ,
|
||||
input wire [1 :0] m_awlock ,
|
||||
input wire [2 :0] m_awprot ,
|
||||
output wire m_awready,
|
||||
input wire [2 :0] m_awsize ,
|
||||
input wire m_awvalid,
|
||||
output wire [4 :0] m_bid ,
|
||||
input wire m_bready ,
|
||||
output wire [1 :0] m_bresp ,
|
||||
output wire m_bvalid ,
|
||||
output wire [DATA_WIDTH-1 :0] m_rdata ,
|
||||
output wire [4 :0] m_rid ,
|
||||
output wire m_rlast ,
|
||||
input wire m_rready ,
|
||||
output wire [1 :0] m_rresp ,
|
||||
output wire m_rvalid ,
|
||||
input wire [DATA_WIDTH-1 :0] m_wdata ,
|
||||
input wire m_wlast ,
|
||||
output wire m_wready ,
|
||||
input wire [DATA_WIDTH/8-1 :0] m_wstrb ,
|
||||
input wire m_wvalid
|
||||
);
|
||||
localparam ADDR_INCR_BASE=($clog2(DATA_WIDTH) - 3);
|
||||
|
||||
wire [BUS_WIDTH+13-1 :0] ram_r_a_data ;
|
||||
reg [BUS_WIDTH-1 :0] ram_r_a_data_araddr ;
|
||||
wire [BUS_WIDTH-1 :0] ram_r_a_data_araddr_fixed ;
|
||||
wire [BUS_WIDTH-1 :0] ram_r_a_data_araddr_incr ;
|
||||
wire [BUS_WIDTH-1 :0] ram_r_a_data_araddr_next ;
|
||||
wire ram_r_a_data_araddr_update ;
|
||||
wire [BUS_WIDTH-1 :0] ram_r_a_data_araddr_wrap ;
|
||||
reg [1 :0] ram_r_a_data_arburst ;
|
||||
wire ram_r_a_data_arburst_fixed ;
|
||||
wire ram_r_a_data_arburst_incr ;
|
||||
wire ram_r_a_data_arburst_wrap ;
|
||||
reg [4 :0] ram_r_a_data_arid ;
|
||||
reg [3 :0] ram_r_a_data_arlen ;
|
||||
wire ram_r_a_data_arlen_last ;
|
||||
reg [2 :0] ram_r_a_data_arsize ;
|
||||
wire ram_r_a_data_push ;
|
||||
wire ram_r_a_full ;
|
||||
wire ram_r_a_pop ;
|
||||
wire ram_r_a_push ;
|
||||
wire [BUS_WIDTH+14-1 :0] ram_r_a_push_data ;
|
||||
reg [BUS_WIDTH+14-1 :0] ram_r_a_queue_datas ;
|
||||
wire [BUS_WIDTH-1 :0] ram_r_a_queue_datas_araddr ;
|
||||
wire [1 :0] ram_r_a_queue_datas_arburst;
|
||||
wire [4 :0] ram_r_a_queue_datas_arid ;
|
||||
wire [3 :0] ram_r_a_queue_datas_arlen ;
|
||||
wire [2 :0] ram_r_a_queue_datas_arsize ;
|
||||
wire ram_r_a_queue_empty ;
|
||||
wire ram_r_a_queue_full ;
|
||||
wire ram_r_a_queue_pop ;
|
||||
wire ram_r_a_queue_push ;
|
||||
reg ram_r_a_queue_valid ;
|
||||
reg ram_r_a_valid ;
|
||||
wire [BUS_WIDTH-1 :0] ram_r_addr ;
|
||||
wire ram_r_allow_out ;
|
||||
wire [DATA_WIDTH-1 :0] ram_r_data ;
|
||||
wire ram_r_en ;
|
||||
reg [3 :0] ram_r_rcur ;
|
||||
wire ram_r_rcur_reset ;
|
||||
reg [4 :0] ram_r_rid ;
|
||||
reg ram_r_rlast ;
|
||||
reg ram_r_rvalid ;
|
||||
wire [BUS_WIDTH+13-1 :0] ram_w_a_data ;
|
||||
reg [BUS_WIDTH-1 :0] ram_w_a_data_awaddr ;
|
||||
wire [BUS_WIDTH-1 :0] ram_w_a_data_awaddr_fixed ;
|
||||
wire [BUS_WIDTH-1 :0] ram_w_a_data_awaddr_incr ;
|
||||
wire [BUS_WIDTH-1 :0] ram_w_a_data_awaddr_next ;
|
||||
wire ram_w_a_data_awaddr_update ;
|
||||
wire [BUS_WIDTH-1 :0] ram_w_a_data_awaddr_wrap ;
|
||||
reg [1 :0] ram_w_a_data_awburst ;
|
||||
wire ram_w_a_data_awburst_fixed ;
|
||||
wire ram_w_a_data_awburst_incr ;
|
||||
wire ram_w_a_data_awburst_wrap ;
|
||||
reg [4 :0] ram_w_a_data_awid ;
|
||||
reg [3 :0] ram_w_a_data_awlen ;
|
||||
reg [2 :0] ram_w_a_data_awsize ;
|
||||
wire ram_w_a_data_push ;
|
||||
wire ram_w_a_full ;
|
||||
wire ram_w_a_pop ;
|
||||
wire ram_w_a_push ;
|
||||
wire [BUS_WIDTH+14-1 :0] ram_w_a_push_data ;
|
||||
reg [BUS_WIDTH+14-1 :0] ram_w_a_queue_datas ;
|
||||
wire [BUS_WIDTH-1 :0] ram_w_a_queue_datas_awaddr ;
|
||||
wire [1 :0] ram_w_a_queue_datas_awburst;
|
||||
wire [4 :0] ram_w_a_queue_datas_awid ;
|
||||
wire [3 :0] ram_w_a_queue_datas_awlen ;
|
||||
wire [2 :0] ram_w_a_queue_datas_awsize ;
|
||||
wire ram_w_a_queue_empty ;
|
||||
wire ram_w_a_queue_full ;
|
||||
wire ram_w_a_queue_pop ;
|
||||
wire ram_w_a_queue_push ;
|
||||
reg ram_w_a_queue_valid ;
|
||||
reg ram_w_a_valid ;
|
||||
wire [BUS_WIDTH-1 :0] ram_w_addr ;
|
||||
wire ram_w_allow_out ;
|
||||
reg [4 :0] ram_w_b_data ;
|
||||
wire ram_w_b_data_push ;
|
||||
wire ram_w_b_full ;
|
||||
wire ram_w_b_pop ;
|
||||
wire ram_w_b_push ;
|
||||
reg [4 :0] ram_w_b_queue_datas ;
|
||||
wire ram_w_b_queue_empty ;
|
||||
wire ram_w_b_queue_full ;
|
||||
wire ram_w_b_queue_pop ;
|
||||
wire ram_w_b_queue_push ;
|
||||
reg ram_w_b_queue_valid ;
|
||||
reg ram_w_b_valid ;
|
||||
wire ram_w_en ;
|
||||
wire ram_w_go ;
|
||||
wire [DATA_WIDTH/8-1 :0] ram_w_strb ;
|
||||
reg [DATA_WIDTH-1 :0] ram_w_wdata ;
|
||||
reg ram_w_wlast ;
|
||||
reg [DATA_WIDTH/8-1 :0] ram_w_wstrb ;
|
||||
reg ram_w_wvalid ;
|
||||
assign m_arready = !ram_r_a_full;
|
||||
assign m_awready = !ram_w_a_full;
|
||||
assign m_bid = ram_w_b_data;
|
||||
assign m_bresp = 2'h0;
|
||||
assign m_bvalid = ram_w_b_valid;
|
||||
assign m_rdata = ram_rdata ;
|
||||
assign m_rid = ram_r_rid ;
|
||||
assign m_rlast = ram_r_rlast ;
|
||||
assign m_rresp = 2'h0;
|
||||
assign m_rvalid = ram_r_rvalid;
|
||||
assign m_wready = ram_w_allow_out || !ram_w_wvalid;
|
||||
assign ram_r_a_data = {ram_r_a_data_arburst,ram_r_a_data_arsize,ram_r_a_data_arlen,ram_r_a_data_araddr,ram_r_a_data_arid};
|
||||
assign ram_r_a_data_araddr_fixed = ram_r_a_data_araddr;
|
||||
assign ram_r_a_data_araddr_incr [ADDR_INCR_BASE-1:0] = ram_r_a_data_araddr[ADDR_INCR_BASE-1:0];
|
||||
assign ram_r_a_data_araddr_incr [BUS_WIDTH-1 :ADDR_INCR_BASE ] = ram_r_a_data_araddr[BUS_WIDTH-1:ADDR_INCR_BASE] + {{BUS_WIDTH-ADDR_INCR_BASE-1{1'b0}},1'b1};
|
||||
assign ram_r_a_data_araddr_next = {BUS_WIDTH{ram_r_a_data_arburst_fixed}} & ram_r_a_data_araddr_fixed
|
||||
| {BUS_WIDTH{ram_r_a_data_arburst_incr }} & ram_r_a_data_araddr_incr
|
||||
| {BUS_WIDTH{ram_r_a_data_arburst_wrap }} & ram_r_a_data_araddr_wrap ;
|
||||
assign ram_r_a_data_araddr_update = ram_r_en && !ram_r_a_data_arlen_last;
|
||||
assign ram_r_a_data_araddr_wrap [ADDR_INCR_BASE-1 :0] = ram_r_a_data_araddr[ADDR_INCR_BASE-1 :0];
|
||||
assign ram_r_a_data_araddr_wrap [BUS_WIDTH-1:ADDR_INCR_BASE+4] = ram_r_a_data_araddr[BUS_WIDTH-1:ADDR_INCR_BASE+4];
|
||||
assign ram_r_a_data_araddr_wrap [ADDR_INCR_BASE+3 :ADDR_INCR_BASE] = ram_r_a_data_araddr[ADDR_INCR_BASE+3:ADDR_INCR_BASE] & ~ram_r_a_data_arlen | ram_r_a_data_arlen & ram_r_a_data_araddr[ADDR_INCR_BASE+3:ADDR_INCR_BASE] + 4'h1;
|
||||
assign ram_r_a_data_arburst_fixed = ram_r_a_data_arburst == 2'h0;
|
||||
assign ram_r_a_data_arburst_incr = ram_r_a_data_arburst == 2'h1;
|
||||
assign ram_r_a_data_arburst_wrap = ram_r_a_data_arburst == 2'h2;
|
||||
assign ram_r_a_data_arlen_last = ram_r_a_data_arlen == ram_r_rcur;
|
||||
assign ram_r_a_data_push = ram_r_a_push && (ram_r_a_pop || !ram_r_a_valid);
|
||||
assign ram_r_a_full = ram_r_a_queue_full;
|
||||
assign ram_r_a_pop = ram_r_en && ram_r_a_data_arlen_last;
|
||||
assign ram_r_a_push = m_arvalid && !ram_r_a_full ;
|
||||
//assign ram_r_a_push_data = {m_arburst,m_arsize ,m_arlen,m_araddr,m_arid};
|
||||
assign ram_r_a_push_data = {m_araddr,m_arburst,m_arsize,m_arlen,m_arid};
|
||||
assign ram_r_a_queue_datas_araddr = ram_r_a_queue_datas[BUS_WIDTH-1+14:14];
|
||||
assign ram_r_a_queue_datas_arburst = ram_r_a_queue_datas[13 :12];
|
||||
assign ram_r_a_queue_datas_arid = ram_r_a_queue_datas[4 : 0];
|
||||
assign ram_r_a_queue_datas_arlen = ram_r_a_queue_datas[8 : 5];
|
||||
assign ram_r_a_queue_datas_arsize = ram_r_a_queue_datas[11 : 9];
|
||||
assign ram_r_a_queue_empty = !ram_r_a_queue_valid;
|
||||
assign ram_r_a_queue_full = ram_r_a_queue_valid;
|
||||
assign ram_r_a_queue_pop = ram_r_a_pop && !ram_r_a_queue_empty;
|
||||
assign ram_r_a_queue_push = ram_r_a_push && ram_r_a_valid && !ram_r_a_pop && !ram_r_a_queue_full;
|
||||
assign ram_r_addr = ram_r_a_data_araddr;
|
||||
assign ram_r_allow_out = m_rready || !m_rvalid;
|
||||
assign ram_r_data = ram_rdata;
|
||||
assign ram_r_en = ram_r_a_valid && ram_r_allow_out;
|
||||
assign ram_r_rcur_reset = !aresetn || ram_r_a_pop;
|
||||
assign ram_w_a_data = {ram_w_a_data_awaddr,ram_w_a_data_awburst,ram_w_a_data_awsize ,ram_w_a_data_awlen,ram_w_a_data_awid};
|
||||
assign ram_w_a_data_awaddr_fixed = ram_w_a_data_awaddr;
|
||||
assign ram_w_a_data_awaddr_incr [ADDR_INCR_BASE-1 :0] = ram_w_a_data_awaddr[ADDR_INCR_BASE-1:0];
|
||||
assign ram_w_a_data_awaddr_incr [BUS_WIDTH-1:ADDR_INCR_BASE] = ram_w_a_data_awaddr[BUS_WIDTH-1:ADDR_INCR_BASE] + {{BUS_WIDTH-ADDR_INCR_BASE-1{1'b0}},1'b1};
|
||||
assign ram_w_a_data_awaddr_next = {BUS_WIDTH{ram_w_a_data_awburst_fixed}} & ram_w_a_data_awaddr_fixed
|
||||
| {BUS_WIDTH{ram_w_a_data_awburst_incr }} & ram_w_a_data_awaddr_incr
|
||||
| {BUS_WIDTH{ram_w_a_data_awburst_wrap }} & ram_w_a_data_awaddr_wrap ;
|
||||
assign ram_w_a_data_awaddr_update = ram_w_en && !ram_w_wlast;
|
||||
assign ram_w_a_data_awaddr_wrap [ADDR_INCR_BASE-1 :0] = ram_w_a_data_awaddr[ADDR_INCR_BASE-1 :0];
|
||||
assign ram_w_a_data_awaddr_wrap [BUS_WIDTH-1:ADDR_INCR_BASE+4] = ram_w_a_data_awaddr[BUS_WIDTH-1:ADDR_INCR_BASE+4];
|
||||
assign ram_w_a_data_awaddr_wrap [ADDR_INCR_BASE+3:ADDR_INCR_BASE] = ram_w_a_data_awaddr[ADDR_INCR_BASE+3:ADDR_INCR_BASE] & ~ram_w_a_data_awlen | ram_w_a_data_awlen & ram_w_a_data_awaddr[ADDR_INCR_BASE+3:ADDR_INCR_BASE] + 4'h1;
|
||||
assign ram_w_a_data_awburst_fixed = ram_w_a_data_awburst == 2'h0;
|
||||
assign ram_w_a_data_awburst_incr = ram_w_a_data_awburst == 2'h1;
|
||||
assign ram_w_a_data_awburst_wrap = ram_w_a_data_awburst == 2'h2;
|
||||
assign ram_w_a_data_push = ram_w_a_push && (ram_w_a_pop || !ram_w_a_valid);
|
||||
assign ram_w_a_full = ram_w_a_queue_full;
|
||||
assign ram_w_a_pop = ram_w_en && ram_w_wlast ;
|
||||
assign ram_w_a_push = m_awvalid && !ram_w_a_full;
|
||||
assign ram_w_a_push_data = {m_awaddr,m_awburst,m_awsize ,m_awlen,m_awid};
|
||||
assign ram_w_a_queue_datas_awaddr = ram_w_a_queue_datas[BUS_WIDTH-1+14:14];
|
||||
assign ram_w_a_queue_datas_awburst = ram_w_a_queue_datas[13 :12];
|
||||
assign ram_w_a_queue_datas_awid = ram_w_a_queue_datas[4 : 0];
|
||||
assign ram_w_a_queue_datas_awlen = ram_w_a_queue_datas[8 : 5];
|
||||
assign ram_w_a_queue_datas_awsize = ram_w_a_queue_datas[11 : 9];
|
||||
assign ram_w_a_queue_empty = !ram_w_a_queue_valid;
|
||||
assign ram_w_a_queue_full = ram_w_a_queue_valid;
|
||||
assign ram_w_a_queue_pop = ram_w_a_pop && !ram_w_a_queue_empty;
|
||||
assign ram_w_a_queue_push = ram_w_a_push && ram_w_a_valid && !ram_w_a_pop && !ram_w_a_queue_full;
|
||||
assign ram_w_addr = ram_w_a_data_awaddr;
|
||||
assign ram_w_allow_out = ram_w_a_valid && !ram_w_b_full;
|
||||
assign ram_w_b_data_push = ram_w_b_push && (ram_w_b_pop || !ram_w_b_valid);
|
||||
assign ram_w_b_full = ram_w_b_queue_full;
|
||||
assign ram_w_b_pop = m_bready && ram_w_b_valid;
|
||||
assign ram_w_b_push = ram_w_a_pop ;
|
||||
assign ram_w_b_queue_empty = !ram_w_b_queue_valid;
|
||||
assign ram_w_b_queue_full = ram_w_b_queue_valid;
|
||||
assign ram_w_b_queue_pop = ram_w_b_pop && !ram_w_b_queue_empty;
|
||||
assign ram_w_b_queue_push = ram_w_b_push && ram_w_b_valid && !ram_w_b_pop && !ram_w_b_queue_full;
|
||||
assign ram_w_en = ram_w_wvalid && ram_w_allow_out && aresetn;
|
||||
assign ram_w_go = m_wvalid && m_wready;
|
||||
assign ram_w_strb = ram_w_wstrb;
|
||||
assign ram_raddr = ram_r_addr ;
|
||||
assign ram_ren = ram_r_en ;
|
||||
assign ram_waddr = ram_w_addr ;
|
||||
assign ram_wdata = ram_w_wdata;
|
||||
assign ram_wen = ram_w_strb & {DATA_WIDTH/8{ram_w_en}};
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_r_rcur_reset)
|
||||
begin
|
||||
ram_r_rcur<=4'h0;
|
||||
end
|
||||
else
|
||||
if(ram_r_en)
|
||||
begin
|
||||
ram_r_rcur<=ram_r_rcur + 4'h1;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_r_en)
|
||||
begin
|
||||
ram_r_rid<=ram_r_a_data_arid;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_r_en)
|
||||
begin
|
||||
ram_r_rlast<=ram_r_a_data_arlen_last;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_r_rvalid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_r_en)
|
||||
begin
|
||||
ram_r_rvalid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(m_rready)
|
||||
begin
|
||||
ram_r_rvalid<=1'h0;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_r_a_valid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_r_a_push)
|
||||
begin
|
||||
ram_r_a_valid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_r_a_pop)
|
||||
begin
|
||||
ram_r_a_valid<=ram_r_a_queue_valid;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_r_a_queue_valid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_r_a_queue_push)
|
||||
begin
|
||||
ram_r_a_queue_valid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_r_a_queue_pop)
|
||||
begin
|
||||
ram_r_a_queue_valid<=1'h0;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_r_a_queue_push)
|
||||
begin
|
||||
ram_r_a_queue_datas<=ram_r_a_push_data;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_r_a_data_push)
|
||||
begin
|
||||
ram_r_a_data_arburst<=m_arburst;
|
||||
ram_r_a_data_arid <=m_arid ;
|
||||
ram_r_a_data_arlen <=m_arlen ;
|
||||
ram_r_a_data_arsize <=m_arsize ;
|
||||
end
|
||||
else
|
||||
if(ram_r_a_pop)
|
||||
begin
|
||||
ram_r_a_data_arburst<=ram_r_a_queue_datas_arburst;
|
||||
ram_r_a_data_arid <=ram_r_a_queue_datas_arid ;
|
||||
ram_r_a_data_arlen <=ram_r_a_queue_datas_arlen ;
|
||||
ram_r_a_data_arsize <=ram_r_a_queue_datas_arsize ;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_r_a_data_push)
|
||||
begin
|
||||
ram_r_a_data_araddr<=m_araddr;
|
||||
end
|
||||
else
|
||||
if(ram_r_a_pop)
|
||||
begin
|
||||
ram_r_a_data_araddr<=ram_r_a_queue_datas_araddr;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(ram_r_a_data_araddr_update)
|
||||
begin
|
||||
ram_r_a_data_araddr<=ram_r_a_data_araddr_next;
|
||||
end
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_w_go)
|
||||
begin
|
||||
ram_w_wdata<=m_wdata;
|
||||
ram_w_wlast<=m_wlast;
|
||||
ram_w_wstrb<=m_wstrb;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_w_wvalid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_w_go)
|
||||
begin
|
||||
ram_w_wvalid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_w_en)
|
||||
begin
|
||||
ram_w_wvalid<=1'h0;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_w_a_valid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_w_a_push)
|
||||
begin
|
||||
ram_w_a_valid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_w_a_pop)
|
||||
begin
|
||||
ram_w_a_valid<=ram_w_a_queue_valid;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_w_a_queue_valid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_w_a_queue_push)
|
||||
begin
|
||||
ram_w_a_queue_valid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_w_a_queue_pop)
|
||||
begin
|
||||
ram_w_a_queue_valid<=1'h0;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_w_a_queue_push)
|
||||
begin
|
||||
ram_w_a_queue_datas<=ram_w_a_push_data;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_w_a_data_push)
|
||||
begin
|
||||
ram_w_a_data_awburst<=m_awburst;
|
||||
ram_w_a_data_awid <=m_awid ;
|
||||
ram_w_a_data_awlen <=m_awlen ;
|
||||
ram_w_a_data_awsize <=m_awsize ;
|
||||
end
|
||||
else
|
||||
if(ram_w_a_pop)
|
||||
begin
|
||||
ram_w_a_data_awburst<=ram_w_a_queue_datas_awburst;
|
||||
ram_w_a_data_awid <=ram_w_a_queue_datas_awid ;
|
||||
ram_w_a_data_awlen <=ram_w_a_queue_datas_awlen ;
|
||||
ram_w_a_data_awsize <=ram_w_a_queue_datas_awsize ;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_w_a_data_push)
|
||||
begin
|
||||
ram_w_a_data_awaddr<=m_awaddr;
|
||||
end
|
||||
else
|
||||
if(ram_w_a_pop)
|
||||
begin
|
||||
ram_w_a_data_awaddr<=ram_w_a_queue_datas_awaddr;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(ram_w_a_data_awaddr_update)
|
||||
begin
|
||||
ram_w_a_data_awaddr<=ram_w_a_data_awaddr_next;
|
||||
end
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_w_b_valid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_w_b_push)
|
||||
begin
|
||||
ram_w_b_valid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_w_b_pop)
|
||||
begin
|
||||
ram_w_b_valid<=ram_w_b_queue_valid;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(!aresetn)
|
||||
begin
|
||||
ram_w_b_queue_valid<=1'h0;
|
||||
end
|
||||
else
|
||||
if(ram_w_b_queue_push)
|
||||
begin
|
||||
ram_w_b_queue_valid<=1'h1;
|
||||
end
|
||||
else
|
||||
if(ram_w_b_queue_pop)
|
||||
begin
|
||||
ram_w_b_queue_valid<=1'h0;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_w_b_queue_push)
|
||||
begin
|
||||
ram_w_b_queue_datas<=ram_w_a_data_awid;
|
||||
end
|
||||
end
|
||||
always@(posedge aclk)
|
||||
begin
|
||||
if(ram_w_b_data_push)
|
||||
begin
|
||||
ram_w_b_data<=ram_w_a_data_awid;
|
||||
end
|
||||
else
|
||||
if(ram_w_b_pop)
|
||||
begin
|
||||
ram_w_b_data<=ram_w_b_queue_datas;
|
||||
end
|
||||
end
|
||||
endmodule // soc_axi_sram_bridge
|
||||
350
rtl/ip/Bus_interconnects/axi2sram_sp.v
Normal file
350
rtl/ip/Bus_interconnects/axi2sram_sp.v
Normal file
@@ -0,0 +1,350 @@
|
||||
// Copyright 2018 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.
|
||||
//
|
||||
// ----------------------------
|
||||
// AXI to SRAM Adapter
|
||||
// ----------------------------
|
||||
// Author: Florian Zaruba (zarubaf@iis.ee.ethz.ch)
|
||||
//
|
||||
// Description: Manages AXI transactions
|
||||
// Supports all burst accesses but only on aligned addresses and with full data width.
|
||||
// Assertions should guide you if there is something unsupported happening.
|
||||
//
|
||||
module axi2sram_sp #(
|
||||
parameter AXI_ID_WIDTH = 5,
|
||||
parameter AXI_ADDR_WIDTH = 32,
|
||||
parameter AXI_DATA_WIDTH = 32
|
||||
)(
|
||||
input clk,
|
||||
input resetn,
|
||||
|
||||
input [AXI_ADDR_WIDTH-1:0] s_araddr ,
|
||||
input [1 :0] s_arburst,
|
||||
input [3 :0] s_arcache,
|
||||
input [AXI_ID_WIDTH-1 :0] s_arid ,
|
||||
input [3 :0] s_arlen ,
|
||||
input [1 :0] s_arlock ,
|
||||
input [2 :0] s_arprot ,
|
||||
output reg s_arready,
|
||||
input [2 :0] s_arsize ,
|
||||
input s_arvalid,
|
||||
input [AXI_ADDR_WIDTH-1:0] s_awaddr ,
|
||||
input [1 :0] s_awburst,
|
||||
input [3 :0] s_awcache,
|
||||
input [AXI_ID_WIDTH :0] s_awid ,
|
||||
input [3 :0] s_awlen ,
|
||||
input [1 :0] s_awlock ,
|
||||
input [2 :0] s_awprot ,
|
||||
output reg s_awready,
|
||||
input [2 :0] s_awsize ,
|
||||
input s_awvalid,
|
||||
output reg [AXI_ID_WIDTH-1 :0] s_bid ,
|
||||
input s_bready ,
|
||||
output reg [1 :0] s_bresp ,
|
||||
output reg s_bvalid ,
|
||||
output reg [AXI_DATA_WIDTH-1:0] s_rdata ,
|
||||
output reg [AXI_ID_WIDTH :0] s_rid ,
|
||||
output reg s_rlast ,
|
||||
input s_rready ,
|
||||
output reg [1 :0] s_rresp ,
|
||||
output reg s_rvalid ,
|
||||
input [AXI_DATA_WIDTH-1:0] s_wdata ,
|
||||
input s_wlast ,
|
||||
output reg s_wready ,
|
||||
input [AXI_DATA_WIDTH/8-1:0] s_wstrb ,
|
||||
input s_wvalid ,
|
||||
|
||||
output reg req_o,
|
||||
output reg we_o,
|
||||
output reg [AXI_ADDR_WIDTH-1:0] addr_o,
|
||||
output reg [AXI_DATA_WIDTH/8-1:0] be_o,
|
||||
output reg [AXI_DATA_WIDTH-1:0] data_o,
|
||||
input [AXI_DATA_WIDTH-1:0] data_i
|
||||
);
|
||||
// AXI has the following rules governing the use of bursts:
|
||||
// - for wrapping bursts, the burst length must be 2, 4, 8, or 16
|
||||
// - a burst must not cross a 4KB address boundary
|
||||
// - early termination of bursts is not supported.
|
||||
|
||||
localparam LOG_NR_BYTES = $clog2(AXI_DATA_WIDTH/8);
|
||||
|
||||
reg [AXI_ID_WIDTH-1:0] ax_req_d_id;
|
||||
reg [AXI_ADDR_WIDTH-1:0] ax_req_d_addr;
|
||||
reg [7:0] ax_req_d_len;
|
||||
reg [2:0] ax_req_d_size;
|
||||
reg [1:0] ax_req_d_burst;
|
||||
|
||||
reg [AXI_ID_WIDTH-1:0] ax_req_q_id;
|
||||
reg [AXI_ADDR_WIDTH-1:0] ax_req_q_addr;
|
||||
reg [7:0] ax_req_q_len;
|
||||
reg [2:0] ax_req_q_size;
|
||||
reg [1:0] ax_req_q_burst;
|
||||
|
||||
reg [2:0] state_d;
|
||||
reg [2:0] state_q;
|
||||
|
||||
localparam IDLE = 3'h0;
|
||||
localparam READ = 3'h1;
|
||||
localparam WRITE = 3'h2;
|
||||
localparam SEND_B = 3'h3;
|
||||
localparam WAIT_WVALID = 3'h4;
|
||||
|
||||
localparam FIXED = 2'b00;
|
||||
localparam INCR = 2'b01;
|
||||
localparam WRAP = 2'b10;
|
||||
|
||||
reg [AXI_ADDR_WIDTH-1:0] req_addr_d, req_addr_q;
|
||||
reg [7:0] cnt_d, cnt_q;
|
||||
|
||||
function automatic [AXI_ADDR_WIDTH-1:0] get_wrap_boundary;
|
||||
input [AXI_ADDR_WIDTH-1:0] unaligned_address;
|
||||
input [7:0] len;
|
||||
begin
|
||||
get_wrap_boundary = 'h0;
|
||||
// for wrapping transfers ax_len can only be of size 1, 3, 7 or 15
|
||||
if (len == 4'b1)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES];
|
||||
else if (len == 4'b11)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES];
|
||||
else if (len == 4'b111)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:3+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:2+LOG_NR_BYTES];
|
||||
else if (len == 4'b1111)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:4+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:4+LOG_NR_BYTES];
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg [AXI_ADDR_WIDTH-1:0] aligned_address;
|
||||
reg [AXI_ADDR_WIDTH-1:0] wrap_boundary;
|
||||
reg [AXI_ADDR_WIDTH-1:0] upper_wrap_boundary;
|
||||
reg [AXI_ADDR_WIDTH-1:0] cons_addr;
|
||||
|
||||
always @ (*) begin
|
||||
// address generation
|
||||
aligned_address = {ax_req_q_addr[AXI_ADDR_WIDTH-1:LOG_NR_BYTES], {{LOG_NR_BYTES}{1'b0}}};
|
||||
wrap_boundary = get_wrap_boundary(ax_req_q_addr, ax_req_q_len);
|
||||
// this will overflow
|
||||
upper_wrap_boundary = wrap_boundary + ((ax_req_q_len + 1) << LOG_NR_BYTES);
|
||||
// calculate consecutive address
|
||||
cons_addr = aligned_address + (cnt_q << LOG_NR_BYTES);
|
||||
|
||||
// Transaction attributes
|
||||
// default assignments
|
||||
state_d = state_q;
|
||||
ax_req_d_id = ax_req_q_id;
|
||||
ax_req_d_addr = ax_req_q_addr;
|
||||
ax_req_d_len = ax_req_q_len;
|
||||
ax_req_d_size = ax_req_q_size;
|
||||
ax_req_d_burst = ax_req_q_burst;
|
||||
req_addr_d = req_addr_q;
|
||||
cnt_d = cnt_q;
|
||||
// Memory default assignments
|
||||
data_o = s_wdata;
|
||||
be_o = s_wstrb;
|
||||
we_o = 1'b0;
|
||||
req_o = 1'b0;
|
||||
addr_o = 'h0;
|
||||
// AXI assignments
|
||||
// request
|
||||
s_awready = 1'b0;
|
||||
s_arready = 1'b0;
|
||||
// read response channel
|
||||
s_rvalid = 1'b0;
|
||||
s_rdata = data_i;
|
||||
s_rresp = 'h0;
|
||||
s_rlast = 'h0;
|
||||
s_rid = ax_req_q_id;
|
||||
// slave write data channel
|
||||
s_wready = 1'b0;
|
||||
// write response channel
|
||||
s_bvalid = 1'b0;
|
||||
s_bresp = 1'b0;
|
||||
s_bid = 1'b0;
|
||||
|
||||
case (state_q)
|
||||
|
||||
IDLE: begin
|
||||
// Wait for a read or write
|
||||
// ------------
|
||||
// Read
|
||||
// ------------
|
||||
if (s_arvalid) begin
|
||||
s_arready = 1'b1;
|
||||
// sample ax
|
||||
ax_req_d_id = s_arid;
|
||||
ax_req_d_addr = s_araddr;
|
||||
ax_req_d_len = s_arlen;
|
||||
ax_req_d_size = s_arsize;
|
||||
ax_req_d_burst = s_arburst;
|
||||
state_d = READ;
|
||||
// we can request the first address, this saves us time
|
||||
req_o = 1'b1;
|
||||
addr_o = s_araddr;
|
||||
// save the address
|
||||
req_addr_d = s_araddr;
|
||||
// save the ar_len
|
||||
cnt_d = 1;
|
||||
// ------------
|
||||
// Write
|
||||
// ------------
|
||||
end else if (s_awvalid) begin
|
||||
s_awready = 1'b1;
|
||||
s_wready = 1'b1;
|
||||
addr_o = s_awaddr;
|
||||
// sample ax
|
||||
ax_req_d_id = s_awid;
|
||||
ax_req_d_addr = s_awaddr;
|
||||
ax_req_d_len = s_awlen;
|
||||
ax_req_d_size = s_awsize;
|
||||
ax_req_d_burst = s_awburst;
|
||||
// we've got our first w_valid so start the write process
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
we_o = 1'b1;
|
||||
state_d = (s_wlast) ? SEND_B : WRITE;
|
||||
cnt_d = 1;
|
||||
// we still have to wait for the first w_valid to arrive
|
||||
end else
|
||||
state_d = WAIT_WVALID;
|
||||
end
|
||||
end
|
||||
|
||||
// ~> we are still missing a w_valid
|
||||
WAIT_WVALID: begin
|
||||
s_wready = 1'b1;
|
||||
addr_o = ax_req_q_addr;
|
||||
// we can now make our first request
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
we_o = 1'b1;
|
||||
state_d = (s_wlast) ? SEND_B : WRITE;
|
||||
cnt_d = 1;
|
||||
end
|
||||
end
|
||||
|
||||
READ: begin
|
||||
// keep request to memory high
|
||||
req_o = 1'b1;
|
||||
addr_o = req_addr_q;
|
||||
// send the response
|
||||
s_rvalid = 1'b1;
|
||||
s_rdata = data_i;
|
||||
s_rid = ax_req_q_id;
|
||||
s_rlast = (cnt_q == ax_req_q_len + 1);
|
||||
|
||||
// check that the master is ready, the slave must not wait on this
|
||||
if (s_rready) begin
|
||||
// ----------------------------
|
||||
// Next address generation
|
||||
// ----------------------------
|
||||
// handle the correct burst type
|
||||
case (ax_req_q_burst)
|
||||
FIXED, INCR: addr_o = cons_addr;
|
||||
WRAP: begin
|
||||
// check if the address reached warp boundary
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
addr_o = wrap_boundary;
|
||||
// address warped beyond boundary
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
// we are still in the incremental regime
|
||||
end else begin
|
||||
addr_o = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// we need to change the address here for the upcoming request
|
||||
// we sent the last byte -> go back to idle
|
||||
if (s_rlast) begin
|
||||
state_d = IDLE;
|
||||
// we already got everything
|
||||
req_o = 1'b0;
|
||||
end
|
||||
// save the request address for the next cycle
|
||||
req_addr_d = addr_o;
|
||||
// we can decrease the counter as the master has consumed the read data
|
||||
cnt_d = cnt_q + 1;
|
||||
// TODO: configure correct byte-lane
|
||||
end
|
||||
end
|
||||
// ~> we already wrote the first word here
|
||||
WRITE: begin
|
||||
|
||||
s_wready = 1'b1;
|
||||
|
||||
// consume a word here
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
we_o = 1'b1;
|
||||
// ----------------------------
|
||||
// Next address generation
|
||||
// ----------------------------
|
||||
// handle the correct burst type
|
||||
case (ax_req_q_burst)
|
||||
|
||||
FIXED, INCR: addr_o = cons_addr;
|
||||
WRAP: begin
|
||||
// check if the address reached warp boundary
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
addr_o = wrap_boundary;
|
||||
// address warped beyond boundary
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
// we are still in the incremental regime
|
||||
end else begin
|
||||
addr_o = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// save the request address for the next cycle
|
||||
req_addr_d = addr_o;
|
||||
// we can decrease the counter as the master has consumed the read data
|
||||
cnt_d = cnt_q + 1;
|
||||
|
||||
if (s_wlast)
|
||||
state_d = SEND_B;
|
||||
end
|
||||
end
|
||||
// ~> send a write acknowledge back
|
||||
SEND_B: begin
|
||||
s_bvalid = 1'b1;
|
||||
s_bid = ax_req_q_id;
|
||||
if (s_bready)
|
||||
state_d = IDLE;
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
// --------------
|
||||
// Registers
|
||||
// --------------
|
||||
always @(posedge clk or negedge resetn) begin
|
||||
if (~resetn) begin
|
||||
state_q <= IDLE;
|
||||
ax_req_q_addr <= 32'h0;
|
||||
ax_req_q_burst <= 2'h0;
|
||||
ax_req_q_id <= 'h0;
|
||||
ax_req_q_len <= 8'h0;
|
||||
ax_req_q_size <= 3'h0;
|
||||
req_addr_q <= 'h0;
|
||||
cnt_q <= 8'h0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
ax_req_q_addr <= ax_req_d_addr;
|
||||
ax_req_q_burst <= ax_req_d_burst;
|
||||
ax_req_q_id <= ax_req_d_id;
|
||||
ax_req_q_len <= ax_req_d_len;
|
||||
ax_req_q_size <= ax_req_d_size;
|
||||
req_addr_q <= req_addr_d;
|
||||
cnt_q <= cnt_d;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
380
rtl/ip/Bus_interconnects/axi2sram_sp_external.v
Normal file
380
rtl/ip/Bus_interconnects/axi2sram_sp_external.v
Normal file
@@ -0,0 +1,380 @@
|
||||
// Copyright 2018 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.
|
||||
//
|
||||
// ----------------------------
|
||||
// AXI to SRAM Adapter
|
||||
// ----------------------------
|
||||
// Author: Florian Zaruba (zarubaf@iis.ee.ethz.ch)
|
||||
//
|
||||
// Description: Manages AXI transactions
|
||||
// Supports all burst accesses but only on aligned addresses and with full data width.
|
||||
// Assertions should guide you if there is something unsupported happening.
|
||||
//
|
||||
module axi2sram_sp_external #(
|
||||
parameter AXI_ID_WIDTH = 5,
|
||||
parameter AXI_ADDR_WIDTH = 32,
|
||||
parameter AXI_DATA_WIDTH = 32
|
||||
)(
|
||||
input clk,
|
||||
input resetn,
|
||||
|
||||
input [AXI_ADDR_WIDTH-1:0] s_araddr ,
|
||||
input [1 :0] s_arburst,
|
||||
input [3 :0] s_arcache,
|
||||
input [AXI_ID_WIDTH-1 :0] s_arid ,
|
||||
input [7 :0] s_arlen ,
|
||||
input s_arlock ,
|
||||
input [2 :0] s_arprot ,
|
||||
output reg s_arready,
|
||||
input [2 :0] s_arsize ,
|
||||
input s_arvalid,
|
||||
input [AXI_ADDR_WIDTH-1:0] s_awaddr ,
|
||||
input [1 :0] s_awburst,
|
||||
input [3 :0] s_awcache,
|
||||
input [AXI_ID_WIDTH-1 :0] s_awid ,
|
||||
input [7 :0] s_awlen ,
|
||||
input s_awlock ,
|
||||
input [2 :0] s_awprot ,
|
||||
output reg s_awready,
|
||||
input [2 :0] s_awsize ,
|
||||
input s_awvalid,
|
||||
output reg [AXI_ID_WIDTH-1 :0] s_bid ,
|
||||
input s_bready ,
|
||||
output reg [1 :0] s_bresp ,
|
||||
output reg s_bvalid ,
|
||||
output reg [AXI_DATA_WIDTH-1:0] s_rdata ,
|
||||
output reg [AXI_ID_WIDTH-1 :0] s_rid ,
|
||||
output reg s_rlast ,
|
||||
input s_rready ,
|
||||
output reg [1 :0] s_rresp ,
|
||||
output reg s_rvalid ,
|
||||
input [AXI_DATA_WIDTH-1:0] s_wdata ,
|
||||
input s_wlast ,
|
||||
output reg s_wready ,
|
||||
input [AXI_DATA_WIDTH/8-1:0] s_wstrb ,
|
||||
input s_wvalid ,
|
||||
|
||||
output reg req_o,
|
||||
output reg we_o,
|
||||
output reg [AXI_ADDR_WIDTH-1:0] addr_o,
|
||||
output reg [AXI_DATA_WIDTH/8-1:0] be_o,
|
||||
output reg [AXI_DATA_WIDTH-1:0] data_o,
|
||||
input [AXI_DATA_WIDTH-1:0] data_i
|
||||
);
|
||||
// AXI has the following rules governing the use of bursts:
|
||||
// - for wrapping bursts, the burst length must be 2, 4, 8, or 16
|
||||
// - a burst must not cross a 4KB address boundary
|
||||
// - early termination of bursts is not supported.
|
||||
|
||||
localparam LOG_NR_BYTES = $clog2(AXI_DATA_WIDTH/8);
|
||||
|
||||
reg [AXI_ID_WIDTH-1:0] ax_req_d_id;
|
||||
reg [AXI_ADDR_WIDTH-1:0] ax_req_d_addr;
|
||||
reg [7:0] ax_req_d_len;
|
||||
reg [2:0] ax_req_d_size;
|
||||
reg [1:0] ax_req_d_burst;
|
||||
|
||||
reg [AXI_ID_WIDTH-1:0] ax_req_q_id;
|
||||
reg [AXI_ADDR_WIDTH-1:0] ax_req_q_addr;
|
||||
reg [7:0] ax_req_q_len;
|
||||
reg [2:0] ax_req_q_size;
|
||||
reg [1:0] ax_req_q_burst;
|
||||
|
||||
reg [2:0] state_d;
|
||||
reg [2:0] state_q;
|
||||
|
||||
localparam IDLE = 3'h0;
|
||||
localparam READ = 3'h1;
|
||||
localparam WRITE = 3'h2;
|
||||
localparam SEND_B = 3'h3;
|
||||
localparam WAIT_WVALID = 3'h4;
|
||||
localparam WRITE_NOP = 3'h5;
|
||||
localparam READ_ADDR = 3'h6;
|
||||
|
||||
localparam FIXED = 2'b00;
|
||||
localparam INCR = 2'b01;
|
||||
localparam WRAP = 2'b10;
|
||||
|
||||
reg [AXI_ADDR_WIDTH-1:0] req_addr_d, req_addr_q;
|
||||
reg [7:0] cnt_d, cnt_q;
|
||||
|
||||
function automatic [AXI_ADDR_WIDTH-1:0] get_wrap_boundary;
|
||||
input [AXI_ADDR_WIDTH-1:0] unaligned_address;
|
||||
input [7:0] len;
|
||||
begin
|
||||
get_wrap_boundary = 'h0;
|
||||
// for wrapping transfers ax_len can only be of size 1, 3, 7 or 15
|
||||
if (len == 4'b1)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES];
|
||||
else if (len == 4'b11)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES];
|
||||
else if (len == 4'b111)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:3+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:2+LOG_NR_BYTES];
|
||||
else if (len == 4'b1111)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:4+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:4+LOG_NR_BYTES];
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg [AXI_ADDR_WIDTH-1:0] aligned_address;
|
||||
reg [AXI_ADDR_WIDTH-1:0] wrap_boundary;
|
||||
reg [AXI_ADDR_WIDTH-1:0] upper_wrap_boundary;
|
||||
reg [AXI_ADDR_WIDTH-1:0] cons_addr;
|
||||
|
||||
always @ (*) begin
|
||||
// address generation
|
||||
aligned_address = {ax_req_q_addr[AXI_ADDR_WIDTH-1:LOG_NR_BYTES], {{LOG_NR_BYTES}{1'b0}}};
|
||||
wrap_boundary = get_wrap_boundary(ax_req_q_addr, ax_req_q_len);
|
||||
// this will overflow
|
||||
upper_wrap_boundary = wrap_boundary + ((ax_req_q_len + 1) << LOG_NR_BYTES);
|
||||
// calculate consecutive address
|
||||
cons_addr = aligned_address + (cnt_q << LOG_NR_BYTES);
|
||||
|
||||
// Transaction attributes
|
||||
// default assignments
|
||||
state_d = state_q;
|
||||
ax_req_d_id = ax_req_q_id;
|
||||
ax_req_d_addr = ax_req_q_addr;
|
||||
ax_req_d_len = ax_req_q_len;
|
||||
ax_req_d_size = ax_req_q_size;
|
||||
ax_req_d_burst = ax_req_q_burst;
|
||||
req_addr_d = req_addr_q;
|
||||
cnt_d = cnt_q;
|
||||
// Memory default assignments
|
||||
data_o = s_wdata;
|
||||
be_o = s_wstrb;
|
||||
we_o = 1'b0;
|
||||
req_o = 1'b0;
|
||||
addr_o = 'h0;
|
||||
// AXI assignments
|
||||
// request
|
||||
s_awready = 1'b0;
|
||||
s_arready = 1'b0;
|
||||
// read response channel
|
||||
s_rvalid = 1'b0;
|
||||
s_rresp = 'h0;
|
||||
s_rlast = 'h0;
|
||||
s_rid = ax_req_q_id;
|
||||
// slave write data channel
|
||||
s_wready = 1'b0;
|
||||
// write response channel
|
||||
s_bvalid = 1'b0;
|
||||
s_bresp = 1'b0;
|
||||
s_bid = 1'b0;
|
||||
|
||||
case (state_q)
|
||||
|
||||
IDLE: begin
|
||||
// Wait for a read or write
|
||||
// ------------
|
||||
// Read
|
||||
// ------------
|
||||
if (s_arvalid) begin
|
||||
s_arready = 1'b1;
|
||||
// sample ax
|
||||
ax_req_d_id = s_arid;
|
||||
ax_req_d_addr = s_araddr;
|
||||
ax_req_d_len = s_arlen;
|
||||
ax_req_d_size = s_arsize;
|
||||
ax_req_d_burst = s_arburst;
|
||||
state_d = READ;
|
||||
// we can request the first address, this saves us time
|
||||
req_o = 1'b1;
|
||||
addr_o = s_araddr;
|
||||
// save the address
|
||||
req_addr_d = s_araddr;
|
||||
// save the ar_len
|
||||
cnt_d = 1;
|
||||
// ------------
|
||||
// Write
|
||||
// ------------
|
||||
end else if (s_awvalid) begin
|
||||
s_awready = 1'b1;
|
||||
s_wready = 1'b1;
|
||||
addr_o = s_awaddr;
|
||||
// sample ax
|
||||
ax_req_d_id = s_awid;
|
||||
ax_req_d_addr = s_awaddr;
|
||||
ax_req_d_len = s_awlen;
|
||||
ax_req_d_size = s_awsize;
|
||||
ax_req_d_burst = s_awburst;
|
||||
// we've got our first w_valid so start the write process
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
we_o = 1'b1;
|
||||
state_d = (s_wlast) ? SEND_B : WRITE_NOP;
|
||||
cnt_d = 1;
|
||||
// we still have to wait for the first w_valid to arrive
|
||||
end else
|
||||
state_d = WAIT_WVALID;
|
||||
end
|
||||
end
|
||||
|
||||
// ~> we are still missing a w_valid
|
||||
WAIT_WVALID: begin
|
||||
s_wready = 1'b1;
|
||||
addr_o = ax_req_q_addr;
|
||||
// we can now make our first request
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
we_o = 1'b1;
|
||||
state_d = (s_wlast) ? SEND_B : WRITE;
|
||||
cnt_d = 1;
|
||||
end
|
||||
end
|
||||
|
||||
READ: begin
|
||||
// keep request to memory high
|
||||
req_o = 1'b1;
|
||||
addr_o = req_addr_q;
|
||||
// send the response
|
||||
s_rvalid = 1'b1;
|
||||
s_rdata = data_i;
|
||||
s_rid = ax_req_q_id;
|
||||
s_rlast = (cnt_q == ax_req_q_len + 1);
|
||||
// check that the master is ready, the slave must not wait on this
|
||||
if (s_rready) begin
|
||||
// we sent the last byte -> go back to idle
|
||||
if (s_rlast) begin
|
||||
state_d = IDLE;
|
||||
// we already got everything
|
||||
end
|
||||
else begin
|
||||
state_d = READ_ADDR;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
READ_ADDR: begin
|
||||
// keep request to memory high
|
||||
req_o = 1'b1;
|
||||
// send the response
|
||||
s_rvalid = 1'b0;
|
||||
// ----------------------------
|
||||
// Next address generation
|
||||
// ----------------------------
|
||||
// handle the correct burst type
|
||||
case (ax_req_q_burst)
|
||||
FIXED, INCR: addr_o = cons_addr;
|
||||
WRAP: begin
|
||||
// check if the address reached warp boundary
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
addr_o = wrap_boundary;
|
||||
// address warped beyond boundary
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
// we are still in the incremental regime
|
||||
end else begin
|
||||
addr_o = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// we need to change the address here for the upcoming request
|
||||
// we can decrease the counter as the master has consumed the read data
|
||||
cnt_d = cnt_q + 1;
|
||||
// save the request address for the next cycle
|
||||
req_addr_d = addr_o;
|
||||
state_d = READ;
|
||||
end
|
||||
|
||||
//ext SRAM need nop between continuous write operations
|
||||
WRITE_NOP: begin
|
||||
s_wready = 1'b0;
|
||||
state_d = WRITE;
|
||||
end
|
||||
|
||||
// ~> we already wrote the first word here
|
||||
WRITE: begin
|
||||
|
||||
s_wready = 1'b1;
|
||||
state_d = WRITE_NOP;
|
||||
|
||||
// consume a word here
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
we_o = 1'b1;
|
||||
// ----------------------------
|
||||
// Next address generation
|
||||
// ----------------------------
|
||||
// handle the correct burst type
|
||||
case (ax_req_q_burst)
|
||||
|
||||
FIXED, INCR: addr_o = cons_addr;
|
||||
WRAP: begin
|
||||
// check if the address reached warp boundary
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
addr_o = wrap_boundary;
|
||||
// address warped beyond boundary
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
// we are still in the incremental regime
|
||||
end else begin
|
||||
addr_o = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// save the request address for the next cycle
|
||||
req_addr_d = addr_o;
|
||||
// we can decrease the counter as the master has consumed the read data
|
||||
cnt_d = cnt_q + 1;
|
||||
|
||||
if (s_wlast)
|
||||
state_d = SEND_B;
|
||||
end
|
||||
end
|
||||
// ~> send a write acknowledge back
|
||||
SEND_B: begin
|
||||
s_bvalid = 1'b1;
|
||||
s_bid = ax_req_q_id;
|
||||
if (s_bready)
|
||||
state_d = IDLE;
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
// --------------
|
||||
// Registers
|
||||
// --------------
|
||||
always @(posedge clk or negedge resetn) begin
|
||||
if (~resetn) begin
|
||||
state_q <= IDLE;
|
||||
ax_req_q_addr <= 32'h0;
|
||||
ax_req_q_burst <= 2'h0;
|
||||
ax_req_q_id <= 'h0;
|
||||
ax_req_q_len <= 8'h0;
|
||||
ax_req_q_size <= 3'h0;
|
||||
req_addr_q <= 'h0;
|
||||
cnt_q <= 8'h0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
ax_req_q_addr <= ax_req_d_addr;
|
||||
ax_req_q_burst <= ax_req_d_burst;
|
||||
ax_req_q_id <= ax_req_d_id;
|
||||
ax_req_q_len <= ax_req_d_len;
|
||||
ax_req_q_size <= ax_req_d_size;
|
||||
req_addr_q <= req_addr_d;
|
||||
cnt_q <= cnt_d;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// always @(posedge clk or negedge resetn) begin
|
||||
// if (~resetn) begin
|
||||
// s_rdata <= 'h0;
|
||||
// end else begin
|
||||
// if(req_o == 1'b1 && we_o == 1'b0)
|
||||
// s_rdata <= data_i;
|
||||
// else
|
||||
// s_rdata <= s_rdata;
|
||||
// end
|
||||
// end
|
||||
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user