Merge pull request #5 from AngeloJacobo/new_feature_axi

added AXI4 interface option on top of current wishbone interface
This commit is contained in:
Angelo Jacobo 2024-06-03 17:41:45 +08:00 committed by GitHub
commit df776e059a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 5121 additions and 0 deletions

235
rtl/axi/axi_addr.v Normal file
View File

@ -0,0 +1,235 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: axi_addr.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: The AXI (full) standard has some rather complicated addressing
// modes, where the address can either be FIXED, INCRementing, or
// even where it can WRAP around some boundary. When in either INCR or
// WRAP modes, the next address must always be aligned. In WRAP mode,
// the next address calculation needs to wrap around a given value, and
// that value is dependent upon the burst size (i.e. bytes per beat) and
// length (total numbers of beats). Since this calculation can be
// non-trivial, and since it needs to be done multiple times, the logic
// below captures it for every time it might be needed.
//
// 20200918 - modified to accommodate (potential) AXI3 burst lengths
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2019-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
// }}}
module axi_addr #(
// {{{
parameter AW = 32,
DW = 32,
// parameter [0:0] OPT_AXI3 = 1'b0,
localparam LENB = 8
// }}}
) (
// {{{
input wire [AW-1:0] i_last_addr,
input wire [2:0] i_size, // 1b, 2b, 4b, 8b, etc
input wire [1:0] i_burst, // fixed, incr, wrap, reserved
input wire [LENB-1:0] i_len,
output wire [AW-1:0] o_next_addr
// }}}
);
// Parameter/register declarations
// {{{
localparam DSZ = $clog2(DW)-3;
localparam [1:0] FIXED = 2'b00;
// localparam [1:0] INCREMENT = 2'b01;
// localparam [1:0] WRAP = 2'b10;
localparam IN_AW = (AW >= 12) ? 12 : AW;
localparam [IN_AW-1:0] ONE = 1;
reg [IN_AW-1:0] wrap_mask, increment;
reg [IN_AW-1:0] crossblk_addr, aligned_addr, unaligned_addr;
// }}}
// Address increment
// {{{
always @(*)
if (DSZ == 0)
increment = 1;
else if (DSZ == 1)
increment = (i_size[0]) ? 2 : 1;
else if (DSZ == 2)
increment = (i_size[1]) ? 4 : ((i_size[0]) ? 2 : 1);
else if (DSZ == 3)
case(i_size[1:0])
2'b00: increment = 1;
2'b01: increment = 2;
2'b10: increment = 4;
2'b11: increment = 8;
endcase
else
increment = (1<<i_size);
// }}}
// wrap_mask
// {{{
// The wrap_mask is used to determine which bits remain stable across
// the burst, and which are allowed to change. It is only used during
// wrapped addressing.
always @(*)
begin
// Start with the default, minimum mask
/*
// Here's the original code. It works, but it's
// not economical (uses too many LUTs)
//
if (i_len[3:0] == 1)
wrap_mask = (1<<(i_size+1));
else if (i_len[3:0] == 3)
wrap_mask = (1<<(i_size+2));
else if (i_len[3:0] == 7)
wrap_mask = (1<<(i_size+3));
else if (i_len[3:0] == 15)
wrap_mask = (1<<(i_size+4));
wrap_mask = wrap_mask - 1;
*/
// Here's what we *want*
//
// wrap_mask[i_size:0] = -1;
//
// On the other hand, since we're already guaranteed that our
// addresses are aligned, do we really care about
// wrap_mask[i_size-1:0] ?
// What we want:
//
// wrap_mask[i_size+3:i_size] |= i_len[3:0]
//
// We could simplify this to
//
// wrap_mask = wrap_mask | (i_len[3:0] << (i_size));
// Verilator lint_off WIDTH
if (DSZ < 2)
wrap_mask = ONE | ({{(IN_AW-4){1'b0}},i_len[3:0]} << (i_size[0]));
else if (DSZ < 4)
wrap_mask = ONE | ({{(IN_AW-4){1'b0}},i_len[3:0]} << (i_size[1:0]));
else
wrap_mask = ONE | ({{(IN_AW-4){1'b0}},i_len[3:0]} << (i_size));
// Verilator lint_on WIDTH
end
// }}}
// unaligned_addr
always @(*)
unaligned_addr = i_last_addr[IN_AW-1:0] + increment[IN_AW-1:0];
// aligned_addr
// {{{
always @(*)
if (i_burst != FIXED)
begin
// Align subsequent beats in any burst
// {{{
aligned_addr = unaligned_addr;
// We use the bus size here to simplify the logic
// required in case the bus is smaller than the
// maximum. This depends upon AxSIZE being less than
// $clog2(DATA_WIDTH/8).
if (DSZ < 2)
begin
// {{{
// Align any subsequent address
if (i_size[0])
aligned_addr[0] = 0;
// }}}
end else if (DSZ < 4)
begin
// {{{
// Align any subsequent address
case(i_size[1:0])
2'b00: aligned_addr = unaligned_addr;
2'b01: aligned_addr[ 0] = 0;
2'b10: aligned_addr[(AW-1>1) ? 1 : (AW-1):0]= 0;
2'b11: aligned_addr[(AW-1>2) ? 2 : (AW-1):0]= 0;
endcase
// }}}
end else begin
// {{{
// Align any subsequent address
case(i_size)
3'b001: aligned_addr[ 0] = 0;
3'b010: aligned_addr[(AW-1>1) ? 1 : (AW-1):0]=0;
3'b011: aligned_addr[(AW-1>2) ? 2 : (AW-1):0]=0;
3'b100: aligned_addr[(AW-1>3) ? 3 : (AW-1):0]=0;
3'b101: aligned_addr[(AW-1>4) ? 4 : (AW-1):0]=0;
3'b110: aligned_addr[(AW-1>5) ? 5 : (AW-1):0]=0;
3'b111: aligned_addr[(AW-1>6) ? 6 : (AW-1):0]=0;
default: aligned_addr = unaligned_addr;
endcase
// }}}
end
// }}}
end else
aligned_addr = i_last_addr[IN_AW-1:0];
// }}}
// crossblk_addr from aligned_addr, for WRAP addressing
// {{{
always @(*)
if (i_burst[1])
begin
// WRAP!
crossblk_addr[IN_AW-1:0] = (i_last_addr[IN_AW-1:0] & ~wrap_mask)
| (aligned_addr & wrap_mask);
end else
crossblk_addr[IN_AW-1:0] = aligned_addr;
// }}}
// o_next_addr: Guarantee only the bottom 12 bits change
// {{{
// This is really a logic simplification. AXI bursts aren't allowed
// to cross 4kB boundaries. Given that's the case, we don't have to
// suffer from the propagation across all AW bits, and can limit any
// address propagation to just the lower 12 bits
generate if (AW > 12)
begin : WIDE_ADDRESS
assign o_next_addr = { i_last_addr[AW-1:12],
crossblk_addr[11:0] };
end else begin : NARROW_ADDRESS
assign o_next_addr = crossblk_addr[AW-1:0];
end endgenerate
// }}}
// Make Verilator happy
// {{{
// Verilator lint_off UNUSED
wire unused;
assign unused = (LENB <= 4) ? &{1'b0, i_len[0] }
: &{ 1'b0, i_len[LENB-1:4], i_len[0] };
// Verilator lint_on UNUSED
// }}}
endmodule

317
rtl/axi/axim2wbsp.v Normal file
View File

@ -0,0 +1,317 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: axim2wbsp.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: So ... this converter works in the other direction from
// wbm2axisp. This converter takes AXI commands, and organizes
// them into pipelined wishbone commands.
//
// This particular core treats AXI as two separate buses: one for writes,
// and the other for reads. This particular core combines the two channels
// into one. The designer should be aware that the two AXI buses turned
// Wishbone buses can be kept separate as separate inputs to a WB crosssbar
// for better performance in some circumstances.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2016-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
// }}}
module axim2wbsp #(
// {{{
parameter C_AXI_ID_WIDTH = 2, // The AXI id width used for R&W
// This is an int between 1-16
parameter C_AXI_DATA_WIDTH = 32,// Width of the AXI R&W data
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width
localparam AXI_LSBS = $clog2(C_AXI_DATA_WIDTH)-3,
localparam DW = C_AXI_DATA_WIDTH,
localparam AW = C_AXI_ADDR_WIDTH - AXI_LSBS,
parameter LGFIFO = 5,
parameter [0:0] OPT_SWAP_ENDIANNESS = 1'b0,
parameter [0:0] OPT_READONLY = 1'b0,
parameter [0:0] OPT_WRITEONLY = 1'b0
// }}}
) (
// {{{
//
input wire S_AXI_ACLK, // System clock
input wire S_AXI_ARESETN,
// AXI write address channel signals
// {{{
input wire S_AXI_AWVALID,
output wire S_AXI_AWREADY,
input wire [C_AXI_ID_WIDTH-1:0] S_AXI_AWID,
input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR,
input wire [7:0] S_AXI_AWLEN,
input wire [2:0] S_AXI_AWSIZE,
input wire [1:0] S_AXI_AWBURST,
input wire [0:0] S_AXI_AWLOCK,
input wire [3:0] S_AXI_AWCACHE,
input wire [2:0] S_AXI_AWPROT,
input wire [3:0] S_AXI_AWQOS,
// }}}
// AXI write data channel signals
// {{{
input wire S_AXI_WVALID,
output wire S_AXI_WREADY,
input wire [C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA,
input wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
input wire S_AXI_WLAST,
// }}}
// AXI write response channel signals
// {{{
output wire S_AXI_BVALID,
input wire S_AXI_BREADY,
output wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID,
output wire [1:0] S_AXI_BRESP,
// }}}
// AXI read address channel signals
// {{{
input wire S_AXI_ARVALID,
output wire S_AXI_ARREADY,
input wire [C_AXI_ID_WIDTH-1:0] S_AXI_ARID,
input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR,
input wire [7:0] S_AXI_ARLEN,
input wire [2:0] S_AXI_ARSIZE,
input wire [1:0] S_AXI_ARBURST,
input wire [0:0] S_AXI_ARLOCK,
input wire [3:0] S_AXI_ARCACHE,
input wire [2:0] S_AXI_ARPROT,
input wire [3:0] S_AXI_ARQOS,
// }}}
// AXI read data channel signals
// {{{
output wire S_AXI_RVALID, // Rd rslt valid
input wire S_AXI_RREADY, // Rd rslt ready
output wire [C_AXI_ID_WIDTH-1:0] S_AXI_RID, // Response ID
output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,// Read data
output wire S_AXI_RLAST, // Read last
output wire [1:0] S_AXI_RRESP, // Read response
// }}}
// We'll share the clock and the reset
// {{{
output wire o_reset,
output wire o_wb_cyc,
output wire o_wb_stb,
output wire o_wb_we,
output wire [(AW-1):0] o_wb_addr,
output wire [(C_AXI_DATA_WIDTH-1):0] o_wb_data,
output wire [(C_AXI_DATA_WIDTH/8-1):0] o_wb_sel,
input wire i_wb_stall,
input wire i_wb_ack,
input wire [(C_AXI_DATA_WIDTH-1):0] i_wb_data,
input wire i_wb_err
// }}}
// }}}
);
//
//
//
wire [(AW-1):0] w_wb_addr, r_wb_addr;
wire [(C_AXI_DATA_WIDTH-1):0] w_wb_data;
wire [(C_AXI_DATA_WIDTH/8-1):0] w_wb_sel, r_wb_sel;
wire r_wb_err, r_wb_cyc, r_wb_stb, r_wb_stall, r_wb_ack;
wire w_wb_err, w_wb_cyc, w_wb_stb, w_wb_stall, w_wb_ack;
wire r_wb_we, w_wb_we;
assign r_wb_we = 1'b0;
assign w_wb_we = 1'b1;
generate if (!OPT_READONLY)
begin : AXI_WR
// {{{
aximwr2wbsp #(
// {{{
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
.OPT_SWAP_ENDIANNESS(OPT_SWAP_ENDIANNESS),
.LGFIFO(LGFIFO)
// }}}
) axi_write_decoder(
// {{{
.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
//
.S_AXI_AWVALID(S_AXI_AWVALID),
.S_AXI_AWREADY(S_AXI_AWREADY),
.S_AXI_AWID( S_AXI_AWID),
.S_AXI_AWADDR( S_AXI_AWADDR),
.S_AXI_AWLEN( S_AXI_AWLEN),
.S_AXI_AWSIZE( S_AXI_AWSIZE),
.S_AXI_AWBURST(S_AXI_AWBURST),
.S_AXI_AWLOCK( S_AXI_AWLOCK),
.S_AXI_AWCACHE(S_AXI_AWCACHE),
.S_AXI_AWPROT( S_AXI_AWPROT),
.S_AXI_AWQOS( S_AXI_AWQOS),
//
.S_AXI_WVALID( S_AXI_WVALID),
.S_AXI_WREADY( S_AXI_WREADY),
.S_AXI_WDATA( S_AXI_WDATA),
.S_AXI_WSTRB( S_AXI_WSTRB),
.S_AXI_WLAST( S_AXI_WLAST),
//
.S_AXI_BVALID(S_AXI_BVALID),
.S_AXI_BREADY(S_AXI_BREADY),
.S_AXI_BID( S_AXI_BID),
.S_AXI_BRESP( S_AXI_BRESP),
//
.o_wb_cyc( w_wb_cyc),
.o_wb_stb( w_wb_stb),
.o_wb_addr( w_wb_addr),
.o_wb_data( w_wb_data),
.o_wb_sel( w_wb_sel),
.i_wb_ack( w_wb_ack),
.i_wb_stall(w_wb_stall),
.i_wb_err( w_wb_err)
// }}}
);
// }}}
end else begin : NO_WRITE_CHANNEL
// {{{
assign w_wb_cyc = 0;
assign w_wb_stb = 0;
assign w_wb_addr = 0;
assign w_wb_data = 0;
assign w_wb_sel = 0;
assign S_AXI_AWREADY = 0;
assign S_AXI_WREADY = 0;
assign S_AXI_BVALID = 0;
assign S_AXI_BRESP = 2'b11;
assign S_AXI_BID = 0;
// }}}
end endgenerate
generate if (!OPT_WRITEONLY)
begin : AXI_RD
// {{{
aximrd2wbsp #(
// {{{
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
.OPT_SWAP_ENDIANNESS(OPT_SWAP_ENDIANNESS),
.LGFIFO(LGFIFO)
// }}}
) axi_read_decoder(
// {{{
.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
//
.S_AXI_ARVALID(S_AXI_ARVALID),
.S_AXI_ARREADY(S_AXI_ARREADY),
.S_AXI_ARID( S_AXI_ARID),
.S_AXI_ARADDR( S_AXI_ARADDR),
.S_AXI_ARLEN( S_AXI_ARLEN),
.S_AXI_ARSIZE( S_AXI_ARSIZE),
.S_AXI_ARBURST(S_AXI_ARBURST),
.S_AXI_ARLOCK( S_AXI_ARLOCK),
.S_AXI_ARCACHE(S_AXI_ARCACHE),
.S_AXI_ARPROT( S_AXI_ARPROT),
.S_AXI_ARQOS( S_AXI_ARQOS),
//
.S_AXI_RVALID(S_AXI_RVALID),
.S_AXI_RREADY(S_AXI_RREADY),
.S_AXI_RID( S_AXI_RID),
.S_AXI_RDATA( S_AXI_RDATA),
.S_AXI_RLAST( S_AXI_RLAST),
.S_AXI_RRESP( S_AXI_RRESP),
//
.o_wb_cyc( r_wb_cyc),
.o_wb_stb( r_wb_stb),
.o_wb_addr( r_wb_addr),
.o_wb_sel( r_wb_sel),
.i_wb_ack( r_wb_ack),
.i_wb_stall(r_wb_stall),
.i_wb_data( i_wb_data),
.i_wb_err( r_wb_err)
// }}}
);
// }}}
end else begin : NO_READ_CHANNEL
// {{{
assign r_wb_cyc = 0;
assign r_wb_stb = 0;
assign r_wb_addr = 0;
//
assign S_AXI_ARREADY = 0;
assign S_AXI_RVALID = 0;
assign S_AXI_RID = 0;
assign S_AXI_RDATA = 0;
assign S_AXI_RLAST = 0;
assign S_AXI_RRESP = 0;
// }}}
end endgenerate
generate if (OPT_READONLY)
begin : ARB_RD
// {{{
assign o_wb_cyc = r_wb_cyc;
assign o_wb_stb = r_wb_stb;
assign o_wb_we = r_wb_we;
assign o_wb_addr = r_wb_addr;
assign o_wb_data = 0;
assign o_wb_sel = r_wb_sel;
assign r_wb_ack = i_wb_ack;
assign r_wb_stall= i_wb_stall;
assign r_wb_ack = i_wb_ack;
assign r_wb_err = i_wb_err;
// }}}
end else if (OPT_WRITEONLY)
begin : ARB_WR
// {{{
assign o_wb_cyc = w_wb_cyc;
assign o_wb_stb = w_wb_stb;
assign o_wb_we = w_wb_we;
assign o_wb_addr = w_wb_addr;
assign o_wb_data = w_wb_data;
assign o_wb_sel = w_wb_sel;
assign w_wb_ack = i_wb_ack;
assign w_wb_stall= i_wb_stall;
assign w_wb_ack = i_wb_ack;
assign w_wb_err = i_wb_err;
// }}}
end else begin : ARB_WB
// {{{
wbarbiter #(.DW(DW), .AW(AW))
readorwrite(S_AXI_ACLK, o_reset,
r_wb_cyc, r_wb_stb, r_wb_we, r_wb_addr, w_wb_data, r_wb_sel,
r_wb_ack, r_wb_stall, r_wb_err,
w_wb_cyc, w_wb_stb, w_wb_we, w_wb_addr, w_wb_data, w_wb_sel,
w_wb_ack, w_wb_stall, w_wb_err,
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
i_wb_ack, i_wb_stall, i_wb_err
);
// }}}
end endgenerate
assign o_reset = (S_AXI_ARESETN == 1'b0);
`ifdef FORMAL
`endif
endmodule

740
rtl/axi/aximrd2wbsp.v Normal file
View File

@ -0,0 +1,740 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: aximrd2wbsp.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: Bridge an AXI read channel pair to a single wishbone read
// channel.
//
// Rules:
// 1. Any read channel error *must* be returned to the correct
// read channel ID. In other words, we can't pipeline between IDs
// 2. A FIFO must be used on getting a WB return, to make certain that
// the AXI return channel is able to stall with no loss
// 3. No request can be accepted unless there is room in the return
// channel for it
//
// Status: Passes a formal bounded model check at 15 steps. Should be
// ready for a hardware check.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2019-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
// }}}
module aximrd2wbsp #(
// {{{
parameter C_AXI_ID_WIDTH = 6, // The AXI id width used for R&W
// This is an int between 1-16
parameter C_AXI_DATA_WIDTH = 32,// Width of the AXI R&W data
parameter C_AXI_ADDR_WIDTH = 28, // AXI Address width
localparam AXI_LSBS = $clog2(C_AXI_DATA_WIDTH/8),
localparam AW = C_AXI_ADDR_WIDTH - AXI_LSBS,
parameter LGFIFO = 3,
parameter [0:0] OPT_SWAP_ENDIANNESS = 1'b0,
parameter [0:0] OPT_SIZESEL = 1
// parameter WBMODE = "B4PIPELINE"
// Could also be "BLOCK"
// }}}
) (
// {{{
input wire S_AXI_ACLK, // Bus clock
input wire S_AXI_ARESETN, // Bus reset
// AXI
// {{{
// AXI read address channel signals
input wire S_AXI_ARVALID,
output wire S_AXI_ARREADY,
input wire [C_AXI_ID_WIDTH-1:0] S_AXI_ARID,
input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR,
input wire [7:0] S_AXI_ARLEN,
input wire [2:0] S_AXI_ARSIZE,
input wire [1:0] S_AXI_ARBURST,
input wire [0:0] S_AXI_ARLOCK,
input wire [3:0] S_AXI_ARCACHE,
input wire [2:0] S_AXI_ARPROT,
input wire [3:0] S_AXI_ARQOS,
// AXI read data channel signals
output reg S_AXI_RVALID,
input wire S_AXI_RREADY,
output wire [C_AXI_ID_WIDTH-1:0] S_AXI_RID,
output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,
output wire S_AXI_RLAST,
output reg [1:0] S_AXI_RRESP,
// }}}
// Wishbone channel
// {{{
// We'll share the clock and the reset
output reg o_wb_cyc,
output reg o_wb_stb,
output reg [(AW-1):0] o_wb_addr,
output wire [(C_AXI_DATA_WIDTH/8-1):0] o_wb_sel,
input wire i_wb_stall,
input wire i_wb_ack,
input wire [(C_AXI_DATA_WIDTH-1):0] i_wb_data,
input wire i_wb_err
// }}}
// }}}
);
// Register/net definitions
// {{{
wire w_reset;
wire lastid_fifo_full, lastid_fifo_empty,
resp_fifo_full, resp_fifo_empty;
wire [LGFIFO:0] lastid_fifo_fill, resp_fifo_fill;
reg last_stb, last_ack, err_state;
reg [C_AXI_ID_WIDTH-1:0] axi_id;
reg [7:0] stblen;
wire skid_arvalid;
wire [C_AXI_ID_WIDTH-1:0] skid_arid;// r_id;
wire [C_AXI_ADDR_WIDTH-1:0] skid_araddr;// r_addr;
wire [7:0] skid_arlen;// r_len;
wire [2:0] skid_arsize;// r_size;
wire [1:0] skid_arburst;// r_burst;
reg fifo_nearfull;
wire accept_request;
reg [1:0] axi_burst;
reg [2:0] axi_size;
reg [C_AXI_DATA_WIDTH/8-1:0] axi_strb;
reg [7:0] axi_len;
reg [C_AXI_ADDR_WIDTH-1:0] axi_addr;
wire [C_AXI_ADDR_WIDTH-1:0] next_addr;
wire response_err;
wire lastid_fifo_wr;
reg midissue, wb_empty;
reg [LGFIFO+7:0] acks_expected;
reg [C_AXI_DATA_WIDTH-1:0] read_data;
assign w_reset = (S_AXI_ARESETN == 1'b0);
// }}}
// incoming skidbuffer
// {{{
skidbuffer #(
.OPT_OUTREG(0),
.DW(C_AXI_ID_WIDTH + C_AXI_ADDR_WIDTH + 8 + 3 + 2)
) axirqbuf(S_AXI_ACLK, !S_AXI_ARESETN,
S_AXI_ARVALID, S_AXI_ARREADY,
{ S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN,
S_AXI_ARSIZE, S_AXI_ARBURST },
skid_arvalid, accept_request,
{ skid_arid, skid_araddr, skid_arlen,
skid_arsize, skid_arburst });
// }}}
// accept_request
// {{{
assign accept_request = (!err_state)
&&((!o_wb_cyc)||(!i_wb_err))
// &&(!lastid_fifo_full)
&&(!midissue
||(o_wb_stb && last_stb && !i_wb_stall))
&&(skid_arvalid)
// One ID at a time, lest we return a bus error
// to the wrong AXI master
&&(wb_empty ||(skid_arid == axi_id));
// }}}
// o_wb_cyc, o_wb_stb, stblen, last_stb
// {{{
initial o_wb_cyc = 0;
initial o_wb_stb = 0;
initial stblen = 0;
initial last_stb = 0;
always @(posedge S_AXI_ACLK)
if (w_reset)
begin
o_wb_stb <= 1'b0;
o_wb_cyc <= 1'b0;
end else if (err_state || (o_wb_cyc && i_wb_err))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if ((!o_wb_stb)||(!i_wb_stall))
begin
if (accept_request)
begin
// Process the new request
o_wb_cyc <= 1'b1;
if (lastid_fifo_full && (!S_AXI_RVALID||!S_AXI_RREADY))
o_wb_stb <= 1'b0;
else if (fifo_nearfull && midissue
&& (!S_AXI_RVALID||!S_AXI_RREADY))
o_wb_stb <= 1'b0;
else
o_wb_stb <= 1'b1;
end else if (!o_wb_stb && midissue)
begin
// Restart a transfer once the FIFO clears
if (S_AXI_RVALID)
o_wb_stb <= S_AXI_RREADY;
// end else if ((o_wb_cyc)&&(i_wb_err)||(err_state))
end else if (o_wb_stb && !last_stb)
begin
if (fifo_nearfull
&& (!S_AXI_RVALID||!S_AXI_RREADY))
o_wb_stb <= 1'b0;
end else if (!o_wb_stb || last_stb)
begin
// End the request
o_wb_stb <= 1'b0;
// Check for the last acknowledgment
if ((i_wb_ack)&&(last_ack))
o_wb_cyc <= 1'b0;
if (i_wb_err)
o_wb_cyc <= 1'b0;
end
end
// }}}
// stblen, last_stb, midissue
// {{{
initial stblen = 0;
initial last_stb = 0;
initial midissue = 0;
always @(posedge S_AXI_ACLK)
if (w_reset)
begin
stblen <= 0;
last_stb <= 0;
midissue <= 0;
end else if (accept_request)
begin
stblen <= skid_arlen;
last_stb <= (skid_arlen == 0);
midissue <= 1'b1;
end else if (lastid_fifo_wr)
begin
if (stblen > 0)
stblen <= stblen - 1;
last_stb <= (stblen == 1);
midissue <= (stblen > 0);
end
// }}}
// axi_id, axi_burst, axi_size, axi_len
// {{{
initial axi_size = AXI_LSBS[2:0];
initial axi_strb = -1;
always @(posedge S_AXI_ACLK)
if (accept_request)
begin
axi_id <= skid_arid;
axi_burst <= skid_arburst;
axi_size <= skid_arsize;
axi_len <= skid_arlen;
if (OPT_SIZESEL)
axi_strb <= (1<<(1<<(skid_arsize)))-1;
else
axi_strb <= { (C_AXI_DATA_WIDTH/8){1'b1} };
end
`ifdef FORMAL
always @(*)
case(axi_size)
0: assert(axi_strb == 1);
1: assert((C_AXI_DATA_WIDTH > 8) && (axi_strb == 2'b11));
2: assert((C_AXI_DATA_WIDTH > 16) && (axi_strb == 4'b1111));
3: assert((C_AXI_DATA_WIDTH > 32) && (axi_strb == 8'hff));
4: assert((C_AXI_DATA_WIDTH > 64) && (axi_strb == 16'hffff));
5: assert((C_AXI_DATA_WIDTH > 128) && (axi_strb == 32'hffff_ffff));
6: assert((C_AXI_DATA_WIDTH > 256) && (axi_strb == 64'hffff_ffff_ffff_ffff));
default: assert((C_AXI_DATA_WIDTH == 1024) && (&axi_strb));
endcase
`endif
// }}}
// next_addr
// {{{
axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
next_read_addr(axi_addr, axi_size, axi_burst, axi_len, next_addr);
// }}}
// {{{
always @(posedge S_AXI_ACLK)
if (accept_request)
axi_addr <= skid_araddr;
else if (!i_wb_stall)
axi_addr <= next_addr;
// }}}
always @(*)
o_wb_addr = axi_addr[(C_AXI_ADDR_WIDTH-1):C_AXI_ADDR_WIDTH-AW];
// o_wb_sel
// {{{
generate if (OPT_SIZESEL && C_AXI_DATA_WIDTH > 8)
begin : MULTI_BYTE_SEL
// {{{
assign o_wb_sel = axi_strb << axi_addr[AXI_LSBS-1:0];
// }}}
end else begin : FULL_WORD_SEL
assign o_wb_sel = {(C_AXI_DATA_WIDTH/8){1'b1}};
// Verilator lint_off UNUSED
wire unused_sel;
assign unused_sel = &{ 1'b0, axi_strb };
// Verilator lint_on UNUSED
end endgenerate
// }}}
// lastid_fifo
// {{{
assign lastid_fifo_wr = (o_wb_stb && (i_wb_err || !i_wb_stall))
||(err_state && midissue && !lastid_fifo_full);
sfifo #(.BW(C_AXI_ID_WIDTH+1), .LGFLEN(LGFIFO))
lastid_fifo(S_AXI_ACLK, w_reset,
lastid_fifo_wr,
{ axi_id, last_stb },
lastid_fifo_full, lastid_fifo_fill,
S_AXI_RVALID && S_AXI_RREADY,
{ S_AXI_RID, S_AXI_RLAST },
lastid_fifo_empty);
// }}}
// read_data
// {{{
generate if (OPT_SWAP_ENDIANNESS)
begin : SWAP_ENDIANNESS
integer ik;
// AXI is little endian. WB can be either. Most of my WB
// work is big-endian.
//
// This will convert byte ordering between the two
always @(*)
for(ik=0; ik<C_AXI_DATA_WIDTH/8; ik=ik+1)
read_data[ik*8 +: 8]
= i_wb_data[(C_AXI_DATA_WIDTH-(ik+1)*8) +: 8];
end else begin : KEEP_ENDIANNESS
always @(*)
read_data = i_wb_data;
end endgenerate
// }}}
// resp_fifo
// {{{
sfifo #(.BW(C_AXI_DATA_WIDTH+1), .LGFLEN(LGFIFO))
resp_fifo(S_AXI_ACLK, w_reset,
o_wb_cyc && (i_wb_ack || i_wb_err), { read_data, i_wb_err },
resp_fifo_full, resp_fifo_fill,
S_AXI_RVALID && S_AXI_RREADY,
{ S_AXI_RDATA, response_err },
resp_fifo_empty);
// }}}
// acks_expected
// {{{
// Count the number of acknowledgements we are still expecting. This
// is to support the last_ack calculation in the next process
initial acks_expected = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || err_state)
acks_expected <= 0;
else case({ accept_request, o_wb_cyc && i_wb_ack })
2'b01: acks_expected <= acks_expected -1;
2'b10: acks_expected <= acks_expected+({{(LGFIFO){1'b0}},skid_arlen} + 1);
2'b11: acks_expected <= acks_expected+{{(LGFIFO){1'b0}},skid_arlen};
default: begin end
endcase
// }}}
// last_ack
// {{{
// last_ack should be true if the next acknowledgment will end the bus
// cycle
initial last_ack = 1;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || err_state)
last_ack <= 1;
else case({ accept_request, i_wb_ack })
2'b01: last_ack <= (acks_expected <= 2);
2'b10: last_ack <= (acks_expected == 0)&&(skid_arlen == 0);
2'b11: last_ack <= (acks_expected < 2)&&(skid_arlen < 2)
&&(!acks_expected[0]||!skid_arlen[0]);
default: begin end
endcase
// }}}
// fifo_nearfull
// {{{
initial fifo_nearfull = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
fifo_nearfull <= 1'b0;
else case({ lastid_fifo_wr, S_AXI_RVALID && S_AXI_RREADY })
2'b10: fifo_nearfull <= (lastid_fifo_fill >= (1<<LGFIFO)-2);
2'b01: fifo_nearfull <= lastid_fifo_full;
default: begin end
endcase
// }}}
// wb_empty
// {{{
initial wb_empty = 1'b1;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || !o_wb_cyc)
wb_empty <= 1'b1;
else case({ lastid_fifo_wr, (i_wb_ack || i_wb_err) })
2'b10: wb_empty <= 1'b0;
2'b01: wb_empty <= (lastid_fifo_fill == resp_fifo_fill + 1);
default: begin end
endcase
// }}}
// S_AXI_RRESP, S_AXI_RVALID
// {{{
always @(*)
begin
S_AXI_RRESP[0] = 1'b0;
S_AXI_RRESP[1] = response_err || (resp_fifo_empty && err_state);
S_AXI_RVALID = !resp_fifo_empty
|| (err_state && !lastid_fifo_empty);
end
// }}}
// err_state
// {{{
initial err_state = 0;
always @(posedge S_AXI_ACLK)
if (w_reset)
err_state <= 1'b0;
else if ((o_wb_cyc)&&(i_wb_err))
err_state <= 1'b1;
else if (lastid_fifo_empty && !midissue)
err_state <= 1'b0;
// }}}
// Make Verilator happy
// {{{
// verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, S_AXI_ARLOCK, S_AXI_ARCACHE,
S_AXI_ARPROT, S_AXI_ARQOS, resp_fifo_full };
// verilator lint_on UNUSED
// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal properties
// {{{
//
// The following are the formal properties used to verify this core.
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
////////////////////////////////////////////////////////////////////////
//
// The following are a subset of the properties used to verify this
// core.
//
////////////////////////////////////////////////////////////////////////
//
//
localparam DW = C_AXI_DATA_WIDTH;
reg f_past_valid;
initial f_past_valid = 1'b0;
always @(posedge S_AXI_ACLK)
f_past_valid <= 1'b1;
////////////////////////////////////////////////////////////////////////
//
// Assumptions
//
//
always @(*)
if (!f_past_valid)
assume(w_reset);
////////////////////////////////////////////////////////////////////////
//
// Ad-hoc assertions
//
//
////////////////////////////////////////////////////////////////////////
//
// Error state
//
//
always @(*)
if (err_state)
assert(!o_wb_stb && !o_wb_cyc);
////////////////////////////////////////////////////////////////////////
//
// Bus properties
//
//
localparam F_LGDEPTH = (LGFIFO>8) ? LGFIFO+1 : 10, F_LGRDFIFO = 72; // 9*F_LGFIFO;
//
// ...
//
wire [(F_LGDEPTH-1):0]
fwb_nreqs, fwb_nacks, fwb_outstanding;
fwb_master #(.AW(AW), .DW(C_AXI_DATA_WIDTH), .F_MAX_STALL(2),
.F_MAX_ACK_DELAY(3), .F_LGDEPTH(F_LGDEPTH),
.F_OPT_DISCONTINUOUS(1))
fwb(S_AXI_ACLK, w_reset,
o_wb_cyc, o_wb_stb, 1'b0, o_wb_addr, {(DW){1'b0}}, 4'hf,
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
fwb_nreqs, fwb_nacks, fwb_outstanding);
always @(*)
if (err_state)
assert(fwb_outstanding == 0);
faxi_slave #(
// {{{
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
.F_LGDEPTH(F_LGDEPTH),
.F_AXI_MAXSTALL(0),
.F_AXI_MAXDELAY(0)
// }}}
) faxi(
// {{{
.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
.i_axi_awready(1'b0),
.i_axi_awaddr(0),
.i_axi_awlen(8'h0),
.i_axi_awsize(3'h0),
.i_axi_awburst(2'h0),
.i_axi_awlock(1'b0),
.i_axi_awcache(4'h0),
.i_axi_awprot(3'h0),
.i_axi_awqos(4'h0),
.i_axi_awvalid(1'b0),
//
.i_axi_wready(1'b0),
.i_axi_wdata(0),
.i_axi_wstrb(0),
.i_axi_wlast(0),
.i_axi_wvalid(1'b0),
//
.i_axi_bid(0),
.i_axi_bresp(0),
.i_axi_bvalid(1'b0),
.i_axi_bready(1'b0),
//
.i_axi_arready(S_AXI_ARREADY),
.i_axi_arid(S_AXI_ARID),
.i_axi_araddr(S_AXI_ARADDR),
.i_axi_arlen(S_AXI_ARLEN),
.i_axi_arsize(S_AXI_ARSIZE),
.i_axi_arburst(S_AXI_ARBURST),
.i_axi_arlock(S_AXI_ARLOCK),
.i_axi_arcache(S_AXI_ARCACHE),
.i_axi_arprot(S_AXI_ARPROT),
.i_axi_arqos(S_AXI_ARQOS),
.i_axi_arvalid(S_AXI_ARVALID),
//
.i_axi_rresp(S_AXI_RRESP),
.i_axi_rid(S_AXI_RID),
.i_axi_rvalid(S_AXI_RVALID),
.i_axi_rdata(S_AXI_RDATA),
.i_axi_rlast(S_AXI_RLAST),
.i_axi_rready(S_AXI_RREADY)
//
// ...
//
);
//
// ...
//
always @(*)
if (!resp_fifo_empty && response_err)
assert(resp_fifo_fill == 1);
always @(*)
assert(midissue == ((stblen > 0)||(last_stb)));
always @(*)
if (last_stb && !err_state)
assert(o_wb_stb || lastid_fifo_full);
always @(*)
if (last_stb)
assert(stblen == 0);
always @(*)
if (lastid_fifo_full)
begin
assert(!o_wb_stb);
assert(!lastid_fifo_wr);
end
always @(*)
if (!err_state)
begin
if (midissue && !last_stb)
assert(!last_ack);
assert(lastid_fifo_fill - resp_fifo_fill
== fwb_outstanding);
if (fwb_outstanding > 1)
assert(!last_ack);
else if (fwb_outstanding == 1)
assert(midissue || last_ack);
else if (o_wb_cyc) // && (fwb_outstanding ==0)
assert(last_ack == last_stb);
if (midissue)
assert(o_wb_cyc);
end
// wb_empty
// {{{
always @(*)
if (o_wb_cyc)
assert(wb_empty == (lastid_fifo_fill == resp_fifo_fill));
// }}}
// !o_wb_cyc, if nothing pending
// {{{
always @(*)
if ((fwb_nacks == fwb_nreqs)&&(!midissue))
assert(!o_wb_cyc);
// }}}
always @(*)
assert(fwb_outstanding <= (1<<LGFIFO));
// fifo_nearfull
// {{{
always @(*)
assert(fifo_nearfull == (lastid_fifo_fill >= (1<<LGFIFO)-1));
// }}}
always @(*)
if (o_wb_stb)
assert(last_ack == (last_stb&& wb_empty));//&&(!i_wb_stall);
else if (o_wb_cyc && !midissue)
assert(last_ack == (resp_fifo_fill + 1 >= lastid_fifo_fill));
////////////////////////////////////////////////////////////////////////
//
// Cover checks
// {{{
////////////////////////////////////////////////////////////////////////
//
//
reg [3:0] cvr_reads, cvr_read_bursts, cvr_rdid_bursts;
reg [C_AXI_ID_WIDTH-1:0] cvr_read_id;
// cvr_reads
// {{{
initial cvr_reads = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_reads <= 1;
else if (i_wb_err)
cvr_reads <= 0;
else if (S_AXI_RVALID && S_AXI_RREADY && !cvr_reads[3]
&& cvr_reads > 0)
cvr_reads <= cvr_reads + 1;
// }}}
// cvr_read_bursts
// {{{
initial cvr_read_bursts = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_read_bursts <= 1;
else if (S_AXI_ARVALID && S_AXI_ARLEN < 1)
cvr_read_bursts <= 0;
else if (i_wb_err)
cvr_read_bursts <= 0;
else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
&& !cvr_read_bursts[3] && cvr_read_bursts > 0)
cvr_read_bursts <= cvr_read_bursts + 1;
// }}}
// cvr_read_id
// {{{
initial cvr_read_id = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_read_id <= 1;
else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST)
cvr_read_id <= cvr_read_id + 1;
// }}}
// cvr_rdid_bursts
// {{{
initial cvr_rdid_bursts = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_rdid_bursts <= 1;
else if (S_AXI_ARVALID && S_AXI_ARLEN < 1)
cvr_rdid_bursts <= 0;
else if (i_wb_err)
cvr_rdid_bursts <= 0;
else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
&& S_AXI_RID == cvr_read_id
&& !cvr_rdid_bursts[3] && cvr_rdid_bursts > 0)
cvr_rdid_bursts <= cvr_rdid_bursts + 1;
// }}}
always @(*)
cover(cvr_reads == 4);
always @(*)
cover(cvr_read_bursts == 4);
always @(*)
cover(cvr_rdid_bursts == 4);
// }}}
`endif
// }}}
endmodule

751
rtl/axi/aximwr2wbsp.v Normal file
View File

@ -0,0 +1,751 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: aximwr2wbsp.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: Convert the three AXI4 write channels to a single wishbone
// channel to write the results.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2015-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
// }}}
module aximwr2wbsp #(
// {{{
parameter C_AXI_ID_WIDTH = 6,
parameter C_AXI_DATA_WIDTH = 32,
parameter C_AXI_ADDR_WIDTH = 28,
parameter [0:0] OPT_SWAP_ENDIANNESS = 1'b0,
localparam AXI_LSBS = $clog2(C_AXI_DATA_WIDTH)-3,
localparam AW = C_AXI_ADDR_WIDTH-AXI_LSBS,
parameter LGFIFO = 5
// }}}
) (
// {{{
input wire S_AXI_ACLK, // System clock
input wire S_AXI_ARESETN,
// Incoming AXI bus connections
// {{{
// AXI write address channel signals
input wire S_AXI_AWVALID,
output wire S_AXI_AWREADY,
input wire [C_AXI_ID_WIDTH-1:0] S_AXI_AWID,
input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR,
input wire [7:0] S_AXI_AWLEN,
input wire [2:0] S_AXI_AWSIZE,
input wire [1:0] S_AXI_AWBURST,
input wire [0:0] S_AXI_AWLOCK,
input wire [3:0] S_AXI_AWCACHE,
input wire [2:0] S_AXI_AWPROT,
input wire [3:0] S_AXI_AWQOS,
// AXI write data channel signals
input wire S_AXI_WVALID,
output wire S_AXI_WREADY,
input wire [C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA,
input wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
input wire S_AXI_WLAST,
// AXI write response channel signals
output wire S_AXI_BVALID,
input wire S_AXI_BREADY,
output wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID,
output wire [1:0] S_AXI_BRESP,
// }}}
// Downstream wishbone bus
// {{{
// We'll share the clock and the reset
output reg o_wb_cyc,
output reg o_wb_stb,
output reg [(AW-1):0] o_wb_addr,
output reg [(C_AXI_DATA_WIDTH-1):0] o_wb_data,
output reg [(C_AXI_DATA_WIDTH/8-1):0] o_wb_sel,
input wire i_wb_stall,
input wire i_wb_ack,
// input [(C_AXI_DATA_WIDTH-1):0] i_wb_data,
input wire i_wb_err
// }}}
// }}}
);
// Register/net declarations
// {{{
localparam DW = C_AXI_DATA_WIDTH;
wire w_reset;
wire skid_awvalid;
reg accept_write_burst;
wire [C_AXI_ID_WIDTH-1:0] skid_awid;
wire [C_AXI_ADDR_WIDTH-1:0] skid_awaddr;
wire [7:0] skid_awlen;
wire [2:0] skid_awsize;
wire [1:0] skid_awburst;
//
wire skid_wvalid, skid_wlast;
reg skid_wready;
wire [C_AXI_DATA_WIDTH-1:0] skid_wdata;
wire [C_AXI_DATA_WIDTH/8-1:0] skid_wstrb;
reg skid_awready;
reg [7:0] axi_wlen, wlen;
reg [C_AXI_ID_WIDTH-1:0] axi_wid;
reg [C_AXI_ADDR_WIDTH-1:0] axi_waddr;
wire [C_AXI_ADDR_WIDTH-1:0] next_addr;
reg [1:0] axi_wburst;
reg [2:0] axi_wsize;
reg [LGFIFO+7:0] acks_expected;
reg [LGFIFO:0] writes_expected;
reg last_ack;
reg err_state;
reg read_ack_fifo;
wire [7:0] fifo_ack_ln;
reg [8:0] acklen;
reg ack_last, ack_err, ack_empty;
reg [LGFIFO:0] total_fifo_fill;
reg total_fifo_full;
wire wb_ack_fifo_full, wb_ack_fifo_empty;
wire [LGFIFO:0] wb_ack_fifo_fill;
wire err_fifo_full, err_fifo_empty;
wire [LGFIFO:0] err_fifo_fill;
reg err_fifo_write;
wire bid_fifo_full, bid_fifo_empty;
wire [LGFIFO:0] bid_fifo_fill;
reg [8:0] next_acklen;
reg [1:0] next_acklow;
assign w_reset = (S_AXI_ARESETN == 1'b0);
// }}}
////////////////////////////////////////////////////////////////////////
//
// Skid buffers--all incoming signals go throug skid buffers
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// write address skid buffer
// {{{
skidbuffer #(
.OPT_OUTREG(0),
.DW(C_AXI_ADDR_WIDTH+C_AXI_ID_WIDTH+8+3+2))
awskid(S_AXI_ACLK, !S_AXI_ARESETN, S_AXI_AWVALID, S_AXI_AWREADY,
{ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN,
S_AXI_AWSIZE, S_AXI_AWBURST },
skid_awvalid, accept_write_burst,
{ skid_awid, skid_awaddr, skid_awlen,
skid_awsize, skid_awburst });
// }}}
// write channel skid buffer
// {{{
skidbuffer #(
`ifdef FORMAL
.OPT_PASSTHROUGH(1'b1),
`endif
.OPT_OUTREG(0),
.DW(C_AXI_DATA_WIDTH + C_AXI_DATA_WIDTH/8+1))
wskid(S_AXI_ACLK, !S_AXI_ARESETN,
S_AXI_WVALID, S_AXI_WREADY,
{ S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST },
skid_wvalid, skid_wready,
{ skid_wdata, skid_wstrb, skid_wlast });
// }}}
// accept_write_burst
// {{{
always @(*)
begin
accept_write_burst = (skid_awready)&&(!o_wb_stb || !i_wb_stall)
&&(!err_state)&&(skid_awvalid)
&&(!total_fifo_full);
if (axi_wid != skid_awid && (acks_expected > 0))
accept_write_burst = 0;
if (!skid_wvalid)
accept_write_burst = 0;
end
// }}}
// skid_wready
// {{{
always @(*)
skid_wready = (!o_wb_stb || !i_wb_stall || err_state)
&&(!skid_awready || accept_write_burst);
// }}}
// skid_awready
// {{{
initial skid_awready = 1'b1;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
skid_awready <= 1'b1;
else if (accept_write_burst)
skid_awready <= (skid_awlen == 0)&&(skid_wvalid)&&(skid_wlast);
else if (skid_wvalid && skid_wready && skid_wlast)
skid_awready <= 1'b1;
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// Burst unwinding
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// axi_w*, wlen -- properties of the currently active burst
// {{{
always @(posedge S_AXI_ACLK)
if (accept_write_burst)
begin
axi_wid <= skid_awid;
axi_waddr <= skid_awaddr;
axi_wsize <= skid_awsize;
axi_wburst <= skid_awburst;
axi_wlen <= skid_awlen;
wlen <= skid_awlen;
end else if (skid_wvalid && skid_wready)
begin
axi_waddr <= next_addr;
if (!skid_awready)
wlen <= wlen - 1;
end
// }}}
// next_addr
// {{{
axi_addr #(.AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH))
next_write_addr(axi_waddr, axi_wsize, axi_wburst, axi_wlen, next_addr);
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// Issue the Wishbone request
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// o_wb_cyc, o_wb_stb
// {{{
initial { o_wb_cyc, o_wb_stb } = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || err_state || (o_wb_cyc && i_wb_err))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if (accept_write_burst)
begin
o_wb_cyc <= 1'b1;
o_wb_stb <= skid_wvalid && skid_wready;
end else begin
if (!o_wb_stb || !i_wb_stall)
o_wb_stb <= (!skid_awready)&&(skid_wvalid&&skid_wready);
if (o_wb_cyc && last_ack && i_wb_ack && !skid_awvalid)
o_wb_cyc <= 0;
end
// }}}
always @(*)
o_wb_addr = axi_waddr[C_AXI_ADDR_WIDTH-1:AXI_LSBS];
// o_wb_data, o_wb_sel
// {{{
generate if (OPT_SWAP_ENDIANNESS)
begin : SWAP_ENDIANNESS
integer ik;
always @(posedge S_AXI_ACLK)
if (!o_wb_stb || !i_wb_stall)
begin
for(ik=0; ik<DW/8; ik=ik+1)
begin
o_wb_data[ik*8 +: 8]
<= skid_wdata[(DW/8-1-ik)*8 +: 8];
o_wb_sel[ik] <= skid_wstrb[DW/8-1-ik];
end
end
end else begin : KEEP_ENDIANNESS
always @(posedge S_AXI_ACLK)
if (!o_wb_stb || !i_wb_stall)
begin
o_wb_data <= skid_wdata;
o_wb_sel <= skid_wstrb;
end
end endgenerate
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// FIFO usage tracking
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// writes_expected
// {{{
initial writes_expected = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
begin
writes_expected <= 0;
end else case({skid_wvalid && skid_wready && skid_wlast,
S_AXI_BVALID && S_AXI_BREADY })
2'b01: writes_expected <= writes_expected - 1;
2'b10: writes_expected <= writes_expected + 1;
default: begin end
endcase
// }}}
// acks_expected
// {{{
initial acks_expected = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || i_wb_err || err_state)
begin
acks_expected <= 0;
end else case({skid_awvalid && accept_write_burst, {i_wb_ack|i_wb_err}})
2'b01: acks_expected <= acks_expected - 1;
2'b10: acks_expected <= acks_expected + ({{(LGFIFO){1'b0}},skid_awlen} + 1);
2'b11: acks_expected <= acks_expected + {{(LGFIFO){1'b0}},skid_awlen};
default: begin end
endcase
// }}}
// last_ack
// {{{
initial last_ack = 1;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || i_wb_err || err_state)
begin
last_ack <= 1;
end else case({skid_awvalid && accept_write_burst, i_wb_ack })
2'b01: last_ack <= (acks_expected <= 2);
2'b10: last_ack <= (acks_expected == 0)&&(skid_awlen == 0);
2'b11: last_ack <= last_ack && (skid_awlen == 0);
default: begin end
endcase
// }}}
// total_fifo_fill
// {{{
initial total_fifo_fill = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
total_fifo_fill <= 0;
else case({ accept_write_burst, S_AXI_BVALID && S_AXI_BREADY })
2'b01: total_fifo_fill <= total_fifo_fill - 1;
2'b10: total_fifo_fill <= total_fifo_fill + 1;
default: begin end
endcase
// }}}
// total_fifo_full
// {{{
always @(*)
total_fifo_full = total_fifo_fill[LGFIFO];
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// Return channel
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// wb_ack_fifo
// {{{
sfifo #(.BW(8), .LGFLEN(LGFIFO),
.OPT_ASYNC_READ(1'b1))
wb_ack_fifo(S_AXI_ACLK, !S_AXI_ARESETN,
accept_write_burst, skid_awlen,
wb_ack_fifo_full, wb_ack_fifo_fill,
read_ack_fifo, fifo_ack_ln, wb_ack_fifo_empty);
// }}}
// read_ack_fifo
// {{{
always @(*)
begin
read_ack_fifo = ack_last && (i_wb_ack || i_wb_err);
if (err_state || ack_empty)
read_ack_fifo = 1;
if (wb_ack_fifo_empty)
read_ack_fifo = 1'b0;
end
// }}}
// next_acklen
// {{{
always @(*)
next_acklen = fifo_ack_ln + ((acklen[0] ? 1:0)
+ ((i_wb_ack|i_wb_err)? 0:1));
// }}}
// next_acklow
// {{{
always @(*)
next_acklow = fifo_ack_ln[0] + ((acklen[0] ? 1:0)
+ ((i_wb_ack|i_wb_err)? 0:1));
// }}}
// acklen, ack_last, ack_empty
// {{{
initial acklen = 0;
initial ack_last = 0;
initial ack_empty = 1;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN || err_state)
begin
acklen <= 0;
ack_last <= 0;
ack_empty<= 1;
end else if (read_ack_fifo)
begin
acklen <= next_acklen;
ack_last <= (fifo_ack_ln < 2)&&(next_acklow == 1);
ack_empty<= (fifo_ack_ln == 0)&&(!acklen[0])
&&(i_wb_ack || i_wb_err);
end else if (i_wb_ack || i_wb_err)
begin
if (acklen > 0)
acklen <= acklen - 1;
ack_last <= (acklen == 2);
ack_empty <= ack_last;
end
// }}}
// ack_err
// {{{
always @(posedge S_AXI_ACLK)
if (read_ack_fifo)
begin
ack_err <= (wb_ack_fifo_empty) || err_state || i_wb_err;
end else if (i_wb_ack || i_wb_err || err_state)
ack_err <= ack_err || (i_wb_err || err_state);
// }}}
// err_state
// {{{
initial err_state = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
err_state <= 0;
else if (o_wb_cyc && i_wb_err)
err_state <= 1;
else if ((total_fifo_fill == bid_fifo_fill)
&&(total_fifo_fill == err_fifo_fill))
err_state <= 0;
// }}}
// err_fifo_write
// {{{
initial err_fifo_write = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
err_fifo_write <= 0;
else if (read_ack_fifo && ack_empty && fifo_ack_ln == 0)
err_fifo_write <= (i_wb_ack || i_wb_err || err_state);
else if (ack_last)
err_fifo_write <= (i_wb_ack || i_wb_err || err_state);
else
err_fifo_write <= 1'b0;
// }}}
// bid_fifo - Keep track of BID's
// {{{
sfifo #(.BW(C_AXI_ID_WIDTH), .LGFLEN(LGFIFO))
bid_fifo(S_AXI_ACLK, !S_AXI_ARESETN,
skid_wvalid && skid_wready && skid_wlast,
(total_fifo_fill == bid_fifo_fill) ? skid_awid:axi_wid,
bid_fifo_full, bid_fifo_fill,
S_AXI_BVALID & S_AXI_BREADY, S_AXI_BID, bid_fifo_empty);
// }}}
// err_fifo - Keep track of error returns
// {{{
sfifo #(.BW(1), .LGFLEN(LGFIFO))
err_fifo(S_AXI_ACLK, !S_AXI_ARESETN,
err_fifo_write, { ack_err || i_wb_err },
err_fifo_full, err_fifo_fill,
S_AXI_BVALID & S_AXI_BREADY, S_AXI_BRESP[1], err_fifo_empty);
// }}}
assign S_AXI_BVALID = !bid_fifo_empty && !err_fifo_empty;
assign S_AXI_BRESP[0]= 1'b0;
// }}}
// Make Verilator happy
// {{{
// verilator lint_on UNUSED
wire unused;
assign unused = &{ 1'b0, S_AXI_AWBURST, S_AXI_AWSIZE,
S_AXI_AWLOCK, S_AXI_AWCACHE, S_AXI_AWPROT,
S_AXI_AWQOS, S_AXI_WLAST,
wb_ack_fifo_full, wb_ack_fifo_fill,
bid_fifo_full, err_fifo_full,
w_reset
};
// verilator lint_off UNUSED
// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal property section
// {{{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
////////////////////////////////////////////////////////////////////////
//
// The following are a subset of the properties used to verify this
// core
//
////////////////////////////////////////////////////////////////////////
//
//
// Formal only register/wire/parameter definitions
// {{{
localparam F_LGDEPTH = (LGFIFO>8) ? LGFIFO+1 : 10,
F_LGRDFIFO = 72; // 9*F_LGFIFO;
reg f_past_valid;
initial f_past_valid = 1'b0;
always @(posedge S_AXI_ACLK)
f_past_valid <= 1'b1;
localparam F_LGDEPTH = (LGFIFO>8) ? LGFIFO+1 : 10, F_LGRDFIFO = 72; // 9*F_LGFIFO;
wire [(F_LGDEPTH-1):0]
fwb_nreqs, fwb_nacks, fwb_outstanding;
//
// ...
//
////////////////////////////////////////////////////////////////////////
//
// Wishbone properties
// {{{
////////////////////////////////////////////////////////////////////////
//
//
fwb_master #(
// {{{
.AW(AW), .DW(C_AXI_DATA_WIDTH), .F_MAX_STALL(2),
.F_MAX_ACK_DELAY(3), .F_LGDEPTH(F_LGDEPTH),
.F_OPT_DISCONTINUOUS(1)
// }}}
) fwb(S_AXI_ACLK, w_reset,
// {{{
o_wb_cyc, o_wb_stb, 1'b1, o_wb_addr, o_wb_data, o_wb_sel,
i_wb_ack, i_wb_stall, {(DW){1'b0}}, i_wb_err,
fwb_nreqs, fwb_nacks, fwb_outstanding
// }}}
);
//
// ...
//
// }}}
////////////////////////////////////////////////////////////////////////
//
// AXI bus properties
// {{{
////////////////////////////////////////////////////////////////////////
//
//
faxi_slave #(
// {{{
.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
.F_LGDEPTH(F_LGDEPTH),
.F_AXI_MAXSTALL(0),
.F_AXI_MAXDELAY(0)
// }}}
) faxi(.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
// {{{
.i_axi_awready(S_AXI_AWREADY),
.i_axi_awid( S_AXI_AWID),
.i_axi_awaddr( S_AXI_AWADDR),
.i_axi_awlen( S_AXI_AWLEN),
.i_axi_awsize( S_AXI_AWSIZE),
.i_axi_awburst(S_AXI_AWBURST),
.i_axi_awlock( S_AXI_AWLOCK),
.i_axi_awcache(S_AXI_AWCACHE),
.i_axi_awprot( S_AXI_AWPROT),
.i_axi_awqos( S_AXI_AWQOS),
.i_axi_awvalid(S_AXI_AWVALID),
//
.i_axi_wready(S_AXI_WREADY),
.i_axi_wdata( S_AXI_WDATA),
.i_axi_wstrb( S_AXI_WSTRB),
.i_axi_wlast( S_AXI_WLAST),
.i_axi_wvalid(S_AXI_WVALID),
//
.i_axi_bid( S_AXI_BID),
.i_axi_bresp( S_AXI_BRESP),
.i_axi_bvalid(S_AXI_BVALID),
.i_axi_bready(S_AXI_BREADY),
//
.i_axi_arready(1'b0),
.i_axi_arid( {(C_AXI_ID_WIDTH){1'b0}}),
.i_axi_araddr({(C_AXI_ADDR_WIDTH){1'b0}}),
.i_axi_arlen( 8'h0),
.i_axi_arsize( 3'h0),
.i_axi_arburst(2'h0),
.i_axi_arlock( 1'b0),
.i_axi_arcache(4'h0),
.i_axi_arprot( 3'h0),
.i_axi_arqos( 4'h0),
.i_axi_arvalid(1'b0),
//
.i_axi_rresp( 2'h0),
.i_axi_rid( {(C_AXI_ID_WIDTH){1'b0}}),
.i_axi_rvalid(1'b0),
.i_axi_rdata( {(C_AXI_DATA_WIDTH){1'b0}}),
.i_axi_rlast( 1'b0),
.i_axi_rready(1'b0)
//
// ...
//
);
// never_err control(s)
// {{{
always @(*)
if (never_err)
begin
assume(!i_wb_err);
assert(!err_state);
if (!skid_awvalid)
assert(o_wb_cyc == (acks_expected != 0));
if (!skid_awready)
assert(o_wb_cyc);
if (S_AXI_BVALID)
assert(!S_AXI_BRESP[1]);
assert(!S_AXI_BRESP[0]);
end
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// Cover checks
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// Cover registers
// {{{
reg [3:0] cvr_writes, cvr_write_bursts,
cvr_wrid_bursts;
reg [C_AXI_ID_WIDTH-1:0] cvr_write_id;
// }}}
// cvr_writes
// {{{
initial cvr_writes = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_writes <= 1;
else if (i_wb_err)
cvr_writes <= 0;
else if (S_AXI_BVALID && S_AXI_BREADY && !cvr_writes[3]
&& cvr_writes > 0)
cvr_writes <= cvr_writes + 1;
// }}}
// cvr_write_bursts
// {{{
initial cvr_write_bursts = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_write_bursts <= 1;
else if (S_AXI_AWVALID && S_AXI_AWLEN < 1)
cvr_write_bursts <= 0;
else if (i_wb_err)
cvr_write_bursts <= 0;
else if (S_AXI_BVALID && S_AXI_BREADY
&& !cvr_write_bursts[3] && cvr_write_bursts > 0)
cvr_write_bursts <= cvr_write_bursts + 1;
// }}}
// cvr_write_id
// {{{
initial cvr_write_id = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_write_id <= 1;
else if (S_AXI_BVALID && S_AXI_BREADY)
cvr_write_id <= cvr_write_id + 1;
// }}}
// cvr_wrid_bursts
// {{{
initial cvr_wrid_bursts = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
cvr_wrid_bursts <= 1;
else if (S_AXI_AWVALID && S_AXI_AWLEN < 1)
cvr_wrid_bursts <= 0;
else if (i_wb_err)
cvr_wrid_bursts <= 0;
else if (S_AXI_BVALID && S_AXI_BREADY
&& S_AXI_BID == cvr_write_id
&& !cvr_wrid_bursts[3] && cvr_wrid_bursts > 0)
cvr_wrid_bursts <= cvr_wrid_bursts + 1;
// }}}
always @(*) cover(cvr_writes == 4);
always @(*) cover(cvr_write_bursts == 4);
always @(*) cover(cvr_wrid_bursts == 4);
// }}}
`endif
// }}}
endmodule

258
rtl/axi/ddr3_top_axi.v Normal file
View File

@ -0,0 +1,258 @@
`default_nettype none
`timescale 1ps / 1ps
module ddr3_top_axi #(
parameter CONTROLLER_CLK_PERIOD = 12_000, //ps, clock period of the controller interface
DDR3_CLK_PERIOD = 3_000, //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD)
ROW_BITS = 14, //width of row address
COL_BITS = 10, //width of column address
BA_BITS = 3, //width of bank address
BYTE_LANES = 2, //number of byte lanes of DDR3 RAM
AXI_ID_WIDTH = 4, // The AXI id width used for R&W, an int between 1-16
WB2_ADDR_BITS = 7, //width of 2nd wishbone address bus
WB2_DATA_BITS = 32, //width of 2nd wishbone data bus
/* verilator lint_off UNUSEDPARAM */
parameter[0:0] MICRON_SIM = 0, //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
ODELAY_SUPPORTED = 0, //set to 1 when ODELAYE2 is supported
SECOND_WISHBONE = 0, //set to 1 if 2nd wishbone for debugging is needed
parameter // The next parameters act more like a localparam (since user does not have to set this manually) but was added here to simplify port declaration
DQ_BITS = 8, //device width (fixed to 8, if DDR3 is x16 then BYTE_LANES will be 2 while )
serdes_ratio = 4, // this controller is fixed as a 4:1 memory controller (CONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD = 4)
wb_addr_bits = ROW_BITS + COL_BITS + BA_BITS - $clog2(serdes_ratio*2),
wb_data_bits = DQ_BITS*BYTE_LANES*serdes_ratio*2,
wb_sel_bits = wb_data_bits / 8,
wb2_sel_bits = WB2_DATA_BITS / 8,
//4 is the width of a single ddr3 command {cs_n, ras_n, cas_n, we_n} plus 3 (ck_en, odt, reset_n) plus bank bits plus row bits
cmd_len = 4 + 3 + BA_BITS + ROW_BITS,
AXI_LSBS = $clog2(wb_data_bits)-3,
AXI_ADDR_WIDTH = wb_addr_bits + AXI_LSBS,
AXI_DATA_WIDTH = wb_data_bits
)
(
input wire i_controller_clk, i_ddr3_clk, i_ref_clk, //i_controller_clk = CONTROLLER_CLK_PERIOD, i_ddr3_clk = DDR3_CLK_PERIOD, i_ref_clk = 200MHz
input wire i_ddr3_clk_90, //required only when ODELAY_SUPPORTED is zero
input wire i_rst_n,
//
// AXI Interface
// AXI write address channel signals
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [AXI_ID_WIDTH-1:0] s_axi_awid,
input wire [AXI_ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire [0:0] s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
// AXI write data channel signals
input wire s_axi_wvalid,
output wire s_axi_wready,
input wire [AXI_DATA_WIDTH-1:0] s_axi_wdata,
input wire [AXI_DATA_WIDTH/8-1:0] s_axi_wstrb,
input wire s_axi_wlast,
// AXI write response channel signals
output wire s_axi_bvalid,
input wire s_axi_bready,
output wire [AXI_ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
// AXI read address channel signals
input wire s_axi_arvalid,
output wire s_axi_arready,
input wire [AXI_ID_WIDTH-1:0] s_axi_arid,
input wire [AXI_ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire [0:0] s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
// AXI read data channel signals
output wire s_axi_rvalid, // rd rslt valid
input wire s_axi_rready, // rd rslt ready
output wire [AXI_ID_WIDTH-1:0] s_axi_rid, // response id
output wire [AXI_DATA_WIDTH-1:0] s_axi_rdata,// read data
output wire s_axi_rlast, // read last
output wire [1:0] s_axi_rresp, // read response
//
// DDR3 I/O Interface
output wire o_ddr3_clk_p, o_ddr3_clk_n,
output wire o_ddr3_reset_n,
output wire o_ddr3_cke,
output wire o_ddr3_cs_n,
output wire o_ddr3_ras_n,
output wire o_ddr3_cas_n,
output wire o_ddr3_we_n,
output wire[ROW_BITS-1:0] o_ddr3_addr,
output wire[BA_BITS-1:0] o_ddr3_ba_addr,
inout wire[(DQ_BITS*BYTE_LANES)-1:0] io_ddr3_dq,
inout wire[BYTE_LANES-1:0] io_ddr3_dqs, io_ddr3_dqs_n,
output wire[BYTE_LANES-1:0] o_ddr3_dm,
output wire o_ddr3_odt,
//
// Debug outputs
output wire[31:0] o_debug1,
output wire[31:0] o_debug2,
output wire[31:0] o_debug3,
output wire[(DQ_BITS*BYTE_LANES)/8-1:0] o_ddr3_debug_read_dqs_p,
output wire[(DQ_BITS*BYTE_LANES)/8-1:0] o_ddr3_debug_read_dqs_n
);
wire wb_cyc;
wire wb_stb;
wire wb_we;
wire[wb_addr_bits-1:0] wb_addr;
wire[wb_data_bits-1:0] o_wb_data;
wire[wb_sel_bits-1:0] wb_sel;
wire wb_stall;
wire wb_ack;
wire[wb_data_bits-1:0] i_wb_data;
// DDR3 Controller
ddr3_top #(
.CONTROLLER_CLK_PERIOD(CONTROLLER_CLK_PERIOD), //ps, clock period of the controller interface
.DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD)
.ROW_BITS(ROW_BITS), //width of row address
.COL_BITS(COL_BITS), //width of column address
.BA_BITS(BA_BITS), //width of bank address
.BYTE_LANES(BYTE_LANES), //number of byte lanes of DDR3 RAM
.AUX_WIDTH(AXI_ID_WIDTH), //width of aux line (must be >= 4)
.MICRON_SIM(MICRON_SIM), //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
.ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 if ODELAYE2 is supported
.SECOND_WISHBONE(SECOND_WISHBONE), //set to 1 if 2nd wishbone for debugging is needed
.WB2_ADDR_BITS(WB2_ADDR_BITS), //width of 2nd wishbone address bus
.WB2_DATA_BITS(WB2_DATA_BITS) //width of 2nd wishbone data bus
) ddr3_top_inst
(
//clock and reset
.i_controller_clk(i_controller_clk),
.i_ddr3_clk(i_ddr3_clk), //i_controller_clk has period of CONTROLLER_CLK_PERIOD, i_ddr3_clk has period of DDR3_CLK_PERIOD
.i_ref_clk(i_ref_clk), // usually set to 200 MHz
.i_ddr3_clk_90(i_ddr3_clk_90), //90 degree phase shifted version i_ddr3_clk (required only when ODELAY_SUPPORTED is zero)
.i_rst_n(i_rst_n),
//
// Wishbone inputs
.i_wb_cyc(wb_cyc), //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled)
.i_wb_stb(wb_stb), //request a transfer
.i_wb_we(wb_we), //write-enable (1 = write, 0 = read)
.i_wb_addr(wb_addr), //burst-addressable {row,bank,col}
.i_wb_data(o_wb_data), //write data, for a 4:1 controller data width is 8 times the number of pins on the device
.i_wb_sel(wb_sel), //byte strobe for write (1 = write the byte)
.i_aux(0), //for AXI-interface compatibility (given upon strobe)
// Wishbone outputs
.o_wb_stall(wb_stall), //1 = busy, cannot accept requests
.o_wb_ack(wb_ack), //1 = read/write request has completed
.o_wb_data(i_wb_data), //read data, for a 4:1 controller data width is 8 times the number of pins on the device
.o_aux(),
//
// Wishbone 2 (PHY) inputs (WISHBONE 2 UNCONNECTED IN AXI MODE)
.i_wb2_cyc(0), //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled)
.i_wb2_stb(0), //request a transfer
.i_wb2_we(0), //write-enable (1 = write, 0 = read)
.i_wb2_addr(0), //burst-addressable {row,bank,col}
.i_wb2_data(0), //write data, for a 4:1 controller data width is 8 times the number of pins on the device
.i_wb2_sel(0), //byte strobe for write (1 = write the byte)
// Wishbone 2 (Controller) outputs
.o_wb2_stall(), //1 = busy, cannot accept requests
.o_wb2_ack(), //1 = read/write request has completed
.o_wb2_data(), //read data, for a 4:1 controller data width is 8 times the number of pins on the device
//
// DDR3 I/O Interface
.o_ddr3_clk_p(o_ddr3_clk_p),
.o_ddr3_clk_n(o_ddr3_clk_n),
.o_ddr3_reset_n(o_ddr3_reset_n),
.o_ddr3_cke(o_ddr3_cke),
.o_ddr3_cs_n(o_ddr3_cs_n), // width = number of DDR3 ranks
.o_ddr3_ras_n(o_ddr3_ras_n),
.o_ddr3_cas_n(o_ddr3_cas_n),
.o_ddr3_we_n(o_ddr3_we_n),
.o_ddr3_addr(o_ddr3_addr), // width = ROW_BITS
.o_ddr3_ba_addr(o_ddr3_ba_addr), // width = BA_BITS
.io_ddr3_dq(io_ddr3_dq), // width = BYTE_LANES*8
.io_ddr3_dqs(io_ddr3_dqs), // width = BYTE_LANES
.io_ddr3_dqs_n(io_ddr3_dqs_n), // width = BYTE_LANES
.o_ddr3_dm(o_ddr3_dm), // width = BYTE_LANES
.o_ddr3_odt(o_ddr3_odt),
//
// Debug outputs
.o_debug1(o_debug1),
.o_debug2(o_debug2),
.o_debug3(o_debug3),
.o_ddr3_debug_read_dqs_p(o_ddr3_debug_read_dqs_p),
.o_ddr3_debug_read_dqs_n(o_ddr3_debug_read_dqs_n)
////////////////////////////////////
);
axim2wbsp #(
.C_AXI_ID_WIDTH(AXI_ID_WIDTH), // The AXI id width used for R&W, an int between 1-16
.C_AXI_DATA_WIDTH(AXI_DATA_WIDTH),// Width of the AXI R&W data
.C_AXI_ADDR_WIDTH(AXI_ADDR_WIDTH), // AXI Address width
.LGFIFO(5),
.OPT_SWAP_ENDIANNESS(0),
.OPT_READONLY(0),
.OPT_WRITEONLY(0)
) axim2wbsp_inst (
.S_AXI_ACLK(i_controller_clk), // System clock
.S_AXI_ARESETN(i_rst_n),
// AXI write address channel signals
.S_AXI_AWVALID(s_axi_awvalid),
.S_AXI_AWREADY(s_axi_awready),
.S_AXI_AWID(s_axi_awid),
.S_AXI_AWADDR(s_axi_awaddr),
.S_AXI_AWLEN(s_axi_awlen),
.S_AXI_AWSIZE(s_axi_awsize),
.S_AXI_AWBURST(s_axi_awburst),
.S_AXI_AWLOCK(s_axi_awlock),
.S_AXI_AWCACHE(s_axi_awcache),
.S_AXI_AWPROT(s_axi_awprot),
.S_AXI_AWQOS(s_axi_awqos),
// AXI write data channel signals
.S_AXI_WVALID(s_axi_wvalid),
.S_AXI_WREADY(s_axi_wready),
.S_AXI_WDATA(s_axi_wdata),
.S_AXI_WSTRB(s_axi_wstrb),
.S_AXI_WLAST(s_axi_wlast),
// AXI write response channel signals
.S_AXI_BVALID(s_axi_bvalid),
.S_AXI_BREADY(s_axi_bready),
.S_AXI_BID(s_axi_bid),
.S_AXI_BRESP(s_axi_bresp),
// AXI read address channel signals
.S_AXI_ARVALID(s_axi_arvalid),
.S_AXI_ARREADY(s_axi_arready),
.S_AXI_ARID(s_axi_arid),
.S_AXI_ARADDR(s_axi_araddr),
.S_AXI_ARLEN(s_axi_arlen),
.S_AXI_ARSIZE(s_axi_arsize),
.S_AXI_ARBURST(s_axi_arburst),
.S_AXI_ARLOCK(s_axi_arlock),
.S_AXI_ARCACHE(s_axi_arcache),
.S_AXI_ARPROT(s_axi_arprot),
.S_AXI_ARQOS(s_axi_arqos),
// AXI read data channel signals
.S_AXI_RVALID(s_axi_rvalid), // Rd rslt valid
.S_AXI_RREADY(s_axi_rready), // Rd rslt ready
.S_AXI_RID(s_axi_rid), // Response ID
.S_AXI_RDATA(s_axi_rdata),// Read data
.S_AXI_RLAST(s_axi_rlast), // Read last
.S_AXI_RRESP(s_axi_rresp), // Read response
// We'll share the clock and the reset
.o_reset(),
.o_wb_cyc(wb_cyc),
.o_wb_stb(wb_stb),
.o_wb_we(wb_we),
.o_wb_addr(wb_addr),
.o_wb_data(o_wb_data),
.o_wb_sel(wb_sel),
.i_wb_stall(wb_stall),
.i_wb_ack(wb_ack),
.i_wb_data(i_wb_data),
.i_wb_err(0)
);
endmodule

482
rtl/axi/sfifo.v Normal file
View File

@ -0,0 +1,482 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: sfifo.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: A synchronous data FIFO.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Written and distributed by Gisselquist Technology, LLC
// }}}
// This design is hereby granted to the public domain.
// {{{
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
////////////////////////////////////////////////////////////////////////////////
//
`default_nettype none
// }}}
module sfifo #(
// {{{
parameter BW=8, // Byte/data width
parameter LGFLEN=4,
parameter [0:0] OPT_ASYNC_READ = 1'b1,
parameter [0:0] OPT_WRITE_ON_FULL = 1'b0,
parameter [0:0] OPT_READ_ON_EMPTY = 1'b0
// }}}
) (
// {{{
input wire i_clk,
input wire i_reset,
//
// Write interface
input wire i_wr,
input wire [(BW-1):0] i_data,
output wire o_full,
output reg [LGFLEN:0] o_fill,
//
// Read interface
input wire i_rd,
output reg [(BW-1):0] o_data,
output wire o_empty // True if FIFO is empty
`ifdef FORMAL
`ifdef F_PEEK
, output wire [LGFLEN:0] f_first_addr,
output wire [LGFLEN:0] f_second_addr,
output reg [BW-1:0] f_first_data, f_second_data,
output reg f_first_in_fifo,
f_second_in_fifo,
output reg [LGFLEN:0] f_distance_to_first,
f_distance_to_second
`endif
`endif
// }}}
);
// Register/net declarations
// {{{
localparam FLEN=(1<<LGFLEN);
reg r_full, r_empty;
reg [(BW-1):0] mem[0:(FLEN-1)];
reg [LGFLEN:0] wr_addr, rd_addr;
wire w_wr = (i_wr && !o_full);
wire w_rd = (i_rd && !o_empty);
// }}}
////////////////////////////////////////////////////////////////////////
//
// Write half
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// o_fill
// {{{
initial o_fill = 0;
always @(posedge i_clk)
if (i_reset)
o_fill <= 0;
else case({ w_wr, w_rd })
2'b01: o_fill <= o_fill - 1;
2'b10: o_fill <= o_fill + 1;
default: o_fill <= wr_addr - rd_addr;
endcase
// }}}
// r_full, o_full
// {{{
initial r_full = 0;
always @(posedge i_clk)
if (i_reset)
r_full <= 0;
else case({ w_wr, w_rd})
2'b01: r_full <= 1'b0;
2'b10: r_full <= (o_fill == { 1'b0, {(LGFLEN){1'b1}} });
default: r_full <= (o_fill == { 1'b1, {(LGFLEN){1'b0}} });
endcase
assign o_full = (i_rd && OPT_WRITE_ON_FULL) ? 1'b0 : r_full;
// }}}
// wr_addr, the write address pointer
// {{{
initial wr_addr = 0;
always @(posedge i_clk)
if (i_reset)
wr_addr <= 0;
else if (w_wr)
wr_addr <= wr_addr + 1'b1;
// }}}
// Write to memory
// {{{
always @(posedge i_clk)
if (w_wr)
mem[wr_addr[(LGFLEN-1):0]] <= i_data;
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
//
// Read half
// {{{
////////////////////////////////////////////////////////////////////////
//
//
// rd_addr, the read address pointer
// {{{
initial rd_addr = 0;
always @(posedge i_clk)
if (i_reset)
rd_addr <= 0;
else if (w_rd)
rd_addr <= rd_addr + 1;
// }}}
// r_empty, o_empty
// {{{
initial r_empty = 1'b1;
always @(posedge i_clk)
if (i_reset)
r_empty <= 1'b1;
else case ({ w_wr, w_rd })
2'b01: r_empty <= (o_fill <= 1);
2'b10: r_empty <= 1'b0;
default: begin end
endcase
assign o_empty = (OPT_READ_ON_EMPTY && i_wr) ? 1'b0 : r_empty;
// }}}
// Read from the FIFO
// {{{
generate if (OPT_ASYNC_READ && OPT_READ_ON_EMPTY)
begin : ASYNCHRONOUS_READ_ON_EMPTY
// o_data
// {{{
always @(*)
begin
o_data = mem[rd_addr[LGFLEN-1:0]];
if (r_empty)
o_data = i_data;
end
// }}}
end else if (OPT_ASYNC_READ)
begin : ASYNCHRONOUS_READ
// o_data
// {{{
always @(*)
o_data = mem[rd_addr[LGFLEN-1:0]];
// }}}
end else begin : REGISTERED_READ
// {{{
reg bypass_valid;
reg [BW-1:0] bypass_data, rd_data;
reg [LGFLEN-1:0] rd_next;
always @(*)
rd_next = rd_addr[LGFLEN-1:0] + 1;
// Memory read, bypassing it if we must
// {{{
initial bypass_valid = 0;
always @(posedge i_clk)
if (i_reset)
bypass_valid <= 0;
else if (r_empty || i_rd)
begin
if (!i_wr)
bypass_valid <= 1'b0;
else if (r_empty || (i_rd && (o_fill == 1)))
bypass_valid <= 1'b1;
else
bypass_valid <= 1'b0;
end
always @(posedge i_clk)
if (r_empty || i_rd)
bypass_data <= i_data;
initial mem[0] = 0;
initial rd_data = 0;
always @(posedge i_clk)
if (w_rd)
rd_data <= mem[rd_next];
always @(*)
if (OPT_READ_ON_EMPTY && r_empty)
o_data = i_data;
else if (bypass_valid)
o_data = bypass_data;
else
o_data = rd_data;
// }}}
// }}}
end endgenerate
// }}}
// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// FORMAL METHODS
// {{{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
`ifdef FORMAL
//
// Assumptions about our input(s)
//
//
`ifdef SFIFO
`define ASSUME assume
`else
`define ASSUME assert
`endif
reg f_past_valid;
wire [LGFLEN:0] f_fill, f_next;
wire f_empty;
initial f_past_valid = 1'b0;
always @(posedge i_clk)
f_past_valid <= 1'b1;
////////////////////////////////////////////////////////////////////////
//
// Assertions about our flags and counters
// {{{
////////////////////////////////////////////////////////////////////////
//
//
assign f_fill = wr_addr - rd_addr;
assign f_empty = (wr_addr == rd_addr);
assign f_next = rd_addr + 1'b1;
always @(*)
begin
assert(f_fill <= { 1'b1, {(LGFLEN){1'b0}} });
assert(o_fill == f_fill);
assert(r_full == (f_fill == {1'b1, {(LGFLEN){1'b0}} }));
assert(r_empty == (f_fill == 0));
if (!OPT_WRITE_ON_FULL)
begin
assert(o_full == r_full);
end else begin
assert(o_full == (r_full && !i_rd));
end
if (!OPT_READ_ON_EMPTY)
begin
assert(o_empty == r_empty);
end else begin
assert(o_empty == (r_empty && !i_wr));
end
end
always @(posedge i_clk)
if (!OPT_ASYNC_READ && f_past_valid)
begin
if (f_fill == 0)
begin
assert(r_empty);
assert(o_empty || (OPT_READ_ON_EMPTY && i_wr));
end else if ($past(f_fill)>1)
begin
assert(!r_empty);
end else if ($past(!i_rd && f_fill > 0))
assert(!r_empty);
end
always @(*)
if (!r_empty)
begin
// This also applies for the registered read case
assert(mem[rd_addr[LGFLEN-1:0]] == o_data);
end else if (OPT_READ_ON_EMPTY)
assert(o_data == i_data);
// }}}
////////////////////////////////////////////////////////////////////////
//
// Formal contract: (Twin write test)
// {{{
// If you write two values in succession, you should be able to read
// those same two values in succession some time later.
//
////////////////////////////////////////////////////////////////////////
//
//
// Verilator lint_off UNDRIVEN
(* anyconst *) reg [LGFLEN:0] fw_first_addr;
// Verilator lint_on UNDRIVEN
`ifndef F_PEEK
wire [LGFLEN:0] f_first_addr;
wire [LGFLEN:0] f_second_addr;
reg [BW-1:0] f_first_data, f_second_data;
reg f_first_in_fifo, f_second_in_fifo;
reg [LGFLEN:0] f_distance_to_first, f_distance_to_second;
`endif
reg f_first_addr_in_fifo, f_second_addr_in_fifo;
assign f_first_addr = fw_first_addr;
assign f_second_addr = f_first_addr + 1;
always @(*)
begin
f_distance_to_first = (f_first_addr - rd_addr);
f_first_addr_in_fifo = 0;
if ((f_fill != 0) && (f_distance_to_first < f_fill))
f_first_addr_in_fifo = 1;
end
always @(*)
begin
f_distance_to_second = (f_second_addr - rd_addr);
f_second_addr_in_fifo = 0;
if ((f_fill != 0) && (f_distance_to_second < f_fill))
f_second_addr_in_fifo = 1;
end
always @(posedge i_clk)
if (w_wr && wr_addr == f_first_addr)
f_first_data <= i_data;
always @(posedge i_clk)
if (w_wr && wr_addr == f_second_addr)
f_second_data <= i_data;
always @(*)
if (f_first_addr_in_fifo)
assert(mem[f_first_addr[LGFLEN-1:0]] == f_first_data);
always @(*)
f_first_in_fifo = (f_first_addr_in_fifo && (mem[f_first_addr[LGFLEN-1:0]] == f_first_data));
always @(*)
if (f_second_addr_in_fifo)
assert(mem[f_second_addr[LGFLEN-1:0]] == f_second_data);
always @(*)
f_second_in_fifo = (f_second_addr_in_fifo && (mem[f_second_addr[LGFLEN-1:0]] == f_second_data));
always @(*)
if (f_first_in_fifo && (o_fill == 1 || f_distance_to_first == 0))
assert(o_data == f_first_data);
always @(*)
if (f_second_in_fifo && (o_fill == 1 || f_distance_to_second == 0))
assert(o_data == f_second_data);
always @(posedge i_clk)
if (f_past_valid && !$past(i_reset))
begin
case({$past(f_first_in_fifo), $past(f_second_in_fifo)})
2'b00: begin
if ($past(w_wr && (!w_rd || !r_empty))
&&($past(wr_addr == f_first_addr)))
begin
assert(f_first_in_fifo);
end else begin
assert(!f_first_in_fifo);
end
//
// The second could be in the FIFO, since
// one might write other data than f_first_data
//
// assert(!f_second_in_fifo);
end
2'b01: begin
assert(!f_first_in_fifo);
if ($past(w_rd && (rd_addr==f_second_addr)))
begin
assert((o_empty&&!OPT_ASYNC_READ)||!f_second_in_fifo);
end else begin
assert(f_second_in_fifo);
end
end
2'b10: begin
if ($past(w_wr)
&&($past(wr_addr == f_second_addr)))
begin
assert(f_second_in_fifo);
end else begin
assert(!f_second_in_fifo);
end
if ($past(!w_rd ||(rd_addr != f_first_addr)))
assert(f_first_in_fifo);
end
2'b11: begin
assert(f_second_in_fifo);
if ($past(!w_rd ||(rd_addr != f_first_addr)))
begin
assert(f_first_in_fifo);
if (rd_addr == f_first_addr)
assert(o_data == f_first_data);
end else begin
assert(!f_first_in_fifo);
assert(o_data == f_second_data);
end
end
endcase
end
// }}}
////////////////////////////////////////////////////////////////////////
//
// Cover properties
// {{{
////////////////////////////////////////////////////////////////////////
//
//
`ifdef SFIFO
reg f_was_full;
initial f_was_full = 0;
always @(posedge i_clk)
if (o_full)
f_was_full <= 1;
always @(posedge i_clk)
cover($fell(f_empty));
always @(posedge i_clk)
cover($fell(o_empty));
always @(posedge i_clk)
cover(f_was_full && f_empty);
always @(posedge i_clk)
cover($past(o_full,2)&&(!$past(o_full))&&(o_full));
always @(posedge i_clk)
if (f_past_valid)
cover($past(o_empty,2)&&(!$past(o_empty))&& o_empty);
`endif
// }}}
// Make Verilator happy
// Verilator lint_off UNUSED
wire unused_formal;
assign unused_formal = &{ 1'b0, f_next[LGFLEN], f_empty };
// Verilator lint_on UNUSED
`endif // FORMAL
// }}}
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

495
rtl/axi/skidbuffer.v Normal file
View File

@ -0,0 +1,495 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: skidbuffer.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: A basic SKID buffer.
// {{{
// Skid buffers are required for high throughput AXI code, since the AXI
// specification requires that all outputs be registered. This means
// that, if there are any stall conditions calculated, it will take a clock
// cycle before the stall can be propagated up stream. This means that
// the data will need to be buffered for a cycle until the stall signal
// can make it to the output.
//
// Handling that buffer is the purpose of this core.
//
// On one end of this core, you have the i_valid and i_data inputs to
// connect to your bus interface. There's also a registered o_ready
// signal to signal stalls for the bus interface.
//
// The other end of the core has the same basic interface, but it isn't
// registered. This allows you to interact with the bus interfaces
// as though they were combinatorial logic, by interacting with this half
// of the core.
//
// If at any time the incoming !stall signal, i_ready, signals a stall,
// the incoming data is placed into a buffer. Internally, that buffer
// is held in r_data with the r_valid flag used to indicate that valid
// data is within it.
// }}}
// Parameters:
// {{{
// DW or data width
// In order to make this core generic, the width of the data in the
// skid buffer is parameterized
//
// OPT_LOWPOWER
// Forces both o_data and r_data to zero if the respective *VALID
// signal is also low. While this costs extra logic, it can also
// be used to guarantee that any unused values aren't toggling and
// therefore unnecessarily using power.
//
// This excess toggling can be particularly problematic if the
// bus signals have a high fanout rate, or a long signal path
// across an FPGA.
//
// OPT_OUTREG
// Causes the outputs to be registered
//
// OPT_PASSTHROUGH
// Turns the skid buffer into a passthrough. Used for formal
// verification only.
// }}}
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2019-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
// }}}
module skidbuffer #(
// {{{
parameter [0:0] OPT_LOWPOWER = 0,
parameter [0:0] OPT_OUTREG = 1,
//
parameter [0:0] OPT_PASSTHROUGH = 0,
parameter DW = 8,
parameter [0:0] OPT_INITIAL = 1'b1
// }}}
) (
// {{{
input wire i_clk, i_reset,
input wire i_valid,
output wire o_ready,
input wire [DW-1:0] i_data,
output wire o_valid,
input wire i_ready,
output reg [DW-1:0] o_data
// }}}
);
wire [DW-1:0] w_data;
generate if (OPT_PASSTHROUGH)
begin : PASSTHROUGH
// {{{
assign { o_valid, o_ready } = { i_valid, i_ready };
always @(*)
if (!i_valid && OPT_LOWPOWER)
o_data = 0;
else
o_data = i_data;
assign w_data = 0;
// Keep Verilator happy
// Verilator lint_off UNUSED
// {{{
wire unused_passthrough;
assign unused_passthrough = &{ 1'b0, i_clk, i_reset };
// }}}
// Verilator lint_on UNUSED
// }}}
end else begin : LOGIC
// We'll start with skid buffer itself
// {{{
reg r_valid;
reg [DW-1:0] r_data;
// r_valid
// {{{
initial if (OPT_INITIAL) r_valid = 0;
always @(posedge i_clk)
if (i_reset)
r_valid <= 0;
else if ((i_valid && o_ready) && (o_valid && !i_ready))
// We have incoming data, but the output is stalled
r_valid <= 1;
else if (i_ready)
r_valid <= 0;
// }}}
// r_data
// {{{
initial if (OPT_INITIAL) r_data = 0;
always @(posedge i_clk)
if (OPT_LOWPOWER && i_reset)
r_data <= 0;
else if (OPT_LOWPOWER && (!o_valid || i_ready))
r_data <= 0;
else if ((!OPT_LOWPOWER || !OPT_OUTREG || i_valid) && o_ready)
r_data <= i_data;
assign w_data = r_data;
// }}}
// o_ready
// {{{
assign o_ready = !r_valid;
// }}}
//
// And then move on to the output port
//
if (!OPT_OUTREG)
begin : NET_OUTPUT
// Outputs are combinatorially determined from inputs
// {{{
// o_valid
// {{{
assign o_valid = !i_reset && (i_valid || r_valid);
// }}}
// o_data
// {{{
always @(*)
if (r_valid)
o_data = r_data;
else if (!OPT_LOWPOWER || i_valid)
o_data = i_data;
else
o_data = 0;
// }}}
// }}}
end else begin : REG_OUTPUT
// Register our outputs
// {{{
// o_valid
// {{{
reg ro_valid;
initial if (OPT_INITIAL) ro_valid = 0;
always @(posedge i_clk)
if (i_reset)
ro_valid <= 0;
else if (!o_valid || i_ready)
ro_valid <= (i_valid || r_valid);
assign o_valid = ro_valid;
// }}}
// o_data
// {{{
initial if (OPT_INITIAL) o_data = 0;
always @(posedge i_clk)
if (OPT_LOWPOWER && i_reset)
o_data <= 0;
else if (!o_valid || i_ready)
begin
if (r_valid)
o_data <= r_data;
else if (!OPT_LOWPOWER || i_valid)
o_data <= i_data;
else
o_data <= 0;
end
// }}}
// }}}
end
// }}}
end endgenerate
// Keep Verilator happy
// {{{
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, w_data };
// Verilator lint_on UNUSED
// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal properties
// {{{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
`ifdef SKIDBUFFER
`define ASSUME assume
`else
`define ASSUME assert
`endif
reg f_past_valid;
initial f_past_valid = 0;
always @(posedge i_clk)
f_past_valid <= 1;
always @(*)
if (!f_past_valid)
assume(i_reset);
////////////////////////////////////////////////////////////////////////
//
// Incoming stream properties / assumptions
// {{{
////////////////////////////////////////////////////////////////////////
//
always @(posedge i_clk)
if (!f_past_valid)
begin
`ASSUME(!i_valid || !OPT_INITIAL);
end else if ($past(i_valid && !o_ready && !i_reset) && !i_reset)
`ASSUME(i_valid && $stable(i_data));
`ifdef VERIFIC
`define FORMAL_VERIFIC
// Reset properties
property RESET_CLEARS_IVALID;
@(posedge i_clk) i_reset |=> !i_valid;
endproperty
property IDATA_HELD_WHEN_NOT_READY;
@(posedge i_clk) disable iff (i_reset)
i_valid && !o_ready |=> i_valid && $stable(i_data);
endproperty
`ifdef SKIDBUFFER
assume property (IDATA_HELD_WHEN_NOT_READY);
`else
assert property (IDATA_HELD_WHEN_NOT_READY);
`endif
`endif
// }}}
////////////////////////////////////////////////////////////////////////
//
// Outgoing stream properties / assumptions
// {{{
////////////////////////////////////////////////////////////////////////
//
generate if (!OPT_PASSTHROUGH)
begin
always @(posedge i_clk)
if (!f_past_valid) // || $past(i_reset))
begin
// Following any reset, valid must be deasserted
assert(!o_valid || !OPT_INITIAL);
end else if ($past(o_valid && !i_ready && !i_reset) && !i_reset)
// Following any stall, valid must remain high and
// data must be preserved
assert(o_valid && $stable(o_data));
end endgenerate
// }}}
////////////////////////////////////////////////////////////////////////
//
// Other properties
// {{{
////////////////////////////////////////////////////////////////////////
//
//
generate if (!OPT_PASSTHROUGH)
begin
// Rule #1:
// If registered, then following any reset we should be
// ready for a new request
// {{{
always @(posedge i_clk)
if (f_past_valid && $past(OPT_OUTREG && i_reset))
assert(o_ready);
// }}}
// Rule #2:
// All incoming data must either go directly to the
// output port, or into the skid buffer
// {{{
`ifndef VERIFIC
always @(posedge i_clk)
if (f_past_valid && !$past(i_reset) && $past(i_valid && o_ready
&& (!OPT_OUTREG || o_valid) && !i_ready))
assert(!o_ready && w_data == $past(i_data));
`else
assert property (@(posedge i_clk)
disable iff (i_reset)
(i_valid && o_ready
&& (!OPT_OUTREG || o_valid) && !i_ready)
|=> (!o_ready && w_data == $past(i_data)));
`endif
// }}}
// Rule #3:
// After the last transaction, o_valid should become idle
// {{{
if (!OPT_OUTREG)
begin
// {{{
always @(posedge i_clk)
if (f_past_valid && !$past(i_reset) && !i_reset
&& $past(i_ready))
begin
assert(o_valid == i_valid);
assert(!i_valid || (o_data == i_data));
end
// }}}
end else begin
// {{{
always @(posedge i_clk)
if (f_past_valid && !$past(i_reset))
begin
if ($past(i_valid && o_ready))
assert(o_valid);
if ($past(!i_valid && o_ready && i_ready))
assert(!o_valid);
end
// }}}
end
// }}}
// Rule #4
// Same thing, but this time for o_ready
// {{{
always @(posedge i_clk)
if (f_past_valid && $past(!o_ready && i_ready))
assert(o_ready);
// }}}
// If OPT_LOWPOWER is set, o_data and w_data both need to be
// zero any time !o_valid or !r_valid respectively
// {{{
if (OPT_LOWPOWER)
begin
always @(*)
if ((OPT_OUTREG || !i_reset) && !o_valid)
assert(o_data == 0);
always @(*)
if (o_ready)
assert(w_data == 0);
end
// }}}
end endgenerate
// }}}
////////////////////////////////////////////////////////////////////////
//
// Cover checks
// {{{
////////////////////////////////////////////////////////////////////////
//
//
`ifdef SKIDBUFFER
generate if (!OPT_PASSTHROUGH)
begin
reg f_changed_data;
initial f_changed_data = 0;
always @(posedge i_clk)
if (i_reset)
f_changed_data <= 1;
else if (i_valid && $past(!i_valid || o_ready))
begin
if (i_data != $past(i_data + 1))
f_changed_data <= 0;
end else if (!i_valid && i_data != 0)
f_changed_data <= 0;
`ifndef VERIFIC
reg [3:0] cvr_steps, cvr_hold;
always @(posedge i_clk)
if (i_reset)
begin
cvr_steps <= 0;
cvr_hold <= 0;
end else begin
cvr_steps <= cvr_steps + 1;
cvr_hold <= cvr_hold + 1;
case(cvr_steps)
0: if (o_valid || i_valid)
cvr_steps <= 0;
1: if (!i_valid || !i_ready)
cvr_steps <= 0;
2: if (!i_valid || !i_ready)
cvr_steps <= 0;
3: if (!i_valid || !i_ready)
cvr_steps <= 0;
4: if (!i_valid || i_ready)
cvr_steps <= 0;
5: if (!i_valid || !i_ready)
cvr_steps <= 0;
6: if (!i_valid || !i_ready)
cvr_steps <= 0;
7: if (!i_valid || i_ready)
cvr_steps <= 0;
8: if (!i_valid || i_ready)
cvr_steps <= 0;
9: if (!i_valid || !i_ready)
cvr_steps <= 0;
10: if (!i_valid || !i_ready)
cvr_steps <= 0;
11: if (!i_valid || !i_ready)
cvr_steps <= 0;
12: begin
cvr_steps <= cvr_steps;
cover(!o_valid && !i_valid && f_changed_data);
if (!o_valid || !i_ready)
cvr_steps <= 0;
else
cvr_hold <= cvr_hold + 1;
end
default: assert(0);
endcase
end
`else
// Cover test
cover property (@(posedge i_clk)
disable iff (i_reset)
(!o_valid && !i_valid)
##1 i_valid && i_ready [*3]
##1 i_valid && !i_ready
##1 i_valid && i_ready [*2]
##1 i_valid && !i_ready [*2]
##1 i_valid && i_ready [*3]
// Wait for the design to clear
##1 o_valid && i_ready [*0:5]
##1 (!o_valid && !i_valid && f_changed_data));
`endif
end endgenerate
`endif // SKIDBUFFER
// }}}
`endif
// }}}
endmodule

404
rtl/axi/wbarbiter.v Normal file
View File

@ -0,0 +1,404 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbarbiter.v
// {{{
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: This is a priority bus arbiter. It allows two separate wishbone
// masters to connect to the same bus, while also guaranteeing
// that the last master can have the bus with no delay any time it is
// idle. The goal is to minimize the combinatorial logic required in this
// process, while still minimizing access time.
//
// The core logic works like this:
//
// 1. If 'A' or 'B' asserts the o_cyc line, a bus cycle will begin,
// with acccess granted to whomever requested it.
// 2. If both 'A' and 'B' assert o_cyc at the same time, only 'A'
// will be granted the bus. (If the alternating parameter
// is set, A and B will alternate who gets the bus in
// this case.)
// 3. The bus will remain owned by whomever the bus was granted to
// until they deassert the o_cyc line.
// 4. At the end of a bus cycle, o_cyc is guaranteed to be
// deasserted (low) for one clock.
// 5. On the next clock, bus arbitration takes place again. If
// 'A' requests the bus, no matter how long 'B' was
// waiting, 'A' will then be granted the bus. (Unless
// again the alternating parameter is set, then the
// access is guaranteed to switch to B.)
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2015-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
//
`define WBA_ALTERNATING
// }}}
module wbarbiter #(
// {{{
parameter DW=32, AW=32,
parameter SCHEME="ALTERNATING",
parameter [0:0] OPT_ZERO_ON_IDLE = 1'b0,
parameter [31:0] F_MAX_STALL = 3,
parameter [31:0] F_MAX_ACK_DELAY = 3,
parameter [31:0] F_LGDEPTH=3
// }}}
) (
// {{{
input wire i_clk, i_reset,
// Bus A
// {{{
input wire i_a_cyc, i_a_stb, i_a_we,
input wire [(AW-1):0] i_a_adr,
input wire [(DW-1):0] i_a_dat,
input wire [(DW/8-1):0] i_a_sel,
output wire o_a_ack, o_a_stall, o_a_err,
// }}}
// Bus B
// {{{
input wire i_b_cyc, i_b_stb, i_b_we,
input wire [(AW-1):0] i_b_adr,
input wire [(DW-1):0] i_b_dat,
input wire [(DW/8-1):0] i_b_sel,
output wire o_b_ack, o_b_stall, o_b_err,
// }}}
// Combined/arbitrated bus
// {{{
output wire o_cyc, o_stb, o_we,
output wire [(AW-1):0] o_adr,
output wire [(DW-1):0] o_dat,
output wire [(DW/8-1):0] o_sel,
input wire i_ack, i_stall, i_err
// }}}
`ifdef FORMAL
// {{{
,
output wire [(F_LGDEPTH-1):0]
f_nreqs, f_nacks, f_outstanding,
f_a_nreqs, f_a_nacks, f_a_outstanding,
f_b_nreqs, f_b_nacks, f_b_outstanding
// }}}
`endif
// }}}
);
//
// Go high immediately (new cycle) if ...
// Previous cycle was low and *someone* is requesting a bus cycle
// Go low immadiately if ...
// We were just high and the owner no longer wants the bus
// WISHBONE Spec recommends no logic between a FF and the o_cyc
// This violates that spec. (Rec 3.15, p35)
reg r_a_owner;
assign o_cyc = (r_a_owner) ? i_a_cyc : i_b_cyc;
initial r_a_owner = 1'b1;
generate if (SCHEME == "PRIORITY")
begin : PRI
always @(posedge i_clk)
if (!i_b_cyc)
r_a_owner <= 1'b1;
// Allow B to set its CYC line w/o activating this
// interface
else if ((i_b_stb)&&(!i_a_cyc))
r_a_owner <= 1'b0;
end else if (SCHEME == "ALTERNATING")
begin : ALT
reg last_owner;
initial last_owner = 1'b0;
always @(posedge i_clk)
if ((i_a_cyc)&&(r_a_owner))
last_owner <= 1'b1;
else if ((i_b_cyc)&&(!r_a_owner))
last_owner <= 1'b0;
always @(posedge i_clk)
if ((!i_a_cyc)&&(!i_b_cyc))
r_a_owner <= !last_owner;
else if ((r_a_owner)&&(!i_a_cyc))
begin
if (i_b_stb)
r_a_owner <= 1'b0;
end else if ((!r_a_owner)&&(!i_b_cyc))
begin
if (i_a_stb)
r_a_owner <= 1'b1;
end
end else // if (SCHEME == "LAST")
begin : LST
always @(posedge i_clk)
if ((!i_a_cyc)&&(i_b_stb))
r_a_owner <= 1'b0;
else if ((!i_b_cyc)&&(i_a_stb))
r_a_owner <= 1'b1;
end endgenerate
// Realistically, if neither master owns the bus, the output is a
// don't care. Thus we trigger off whether or not 'A' owns the bus.
// If 'B' owns it all we care is that 'A' does not. Likewise, if
// neither owns the bus than the values on the various lines are
// irrelevant.
assign o_we = (r_a_owner) ? i_a_we : i_b_we;
generate if (OPT_ZERO_ON_IDLE)
begin : ZERO_IDLE
// {{{
//
// OPT_ZERO_ON_IDLE will use up more logic and may even slow
// down the master clock if set. However, it may also reduce
// the power used by the FPGA by preventing things from toggling
// when the bus isn't in use. The option is here because it
// also makes it a lot easier to look for when things happen
// on the bus via VERILATOR when timing and logic counts
// don't matter.
//
assign o_stb = (o_cyc)? ((r_a_owner) ? i_a_stb : i_b_stb):0;
assign o_adr = (o_stb)? ((r_a_owner) ? i_a_adr : i_b_adr):0;
assign o_dat = (o_stb)? ((r_a_owner) ? i_a_dat : i_b_dat):0;
assign o_sel = (o_stb)? ((r_a_owner) ? i_a_sel : i_b_sel):0;
assign o_a_ack = (o_cyc)&&( r_a_owner) ? i_ack : 1'b0;
assign o_b_ack = (o_cyc)&&(!r_a_owner) ? i_ack : 1'b0;
assign o_a_stall = (o_cyc)&&( r_a_owner) ? i_stall : 1'b1;
assign o_b_stall = (o_cyc)&&(!r_a_owner) ? i_stall : 1'b1;
assign o_a_err = (o_cyc)&&( r_a_owner) ? i_err : 1'b0;
assign o_b_err = (o_cyc)&&(!r_a_owner) ? i_err : 1'b0;
// }}}
end else begin : LOW_LOGIC
// {{{
assign o_stb = (r_a_owner) ? i_a_stb : i_b_stb;
assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr;
assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat;
assign o_sel = (r_a_owner) ? i_a_sel : i_b_sel;
// We cannot allow the return acknowledgement to ever go high if
// the master in question does not own the bus. Hence we force
// it low if the particular master doesn't own the bus.
assign o_a_ack = ( r_a_owner) ? i_ack : 1'b0;
assign o_b_ack = (!r_a_owner) ? i_ack : 1'b0;
// Stall must be asserted on the same cycle the input master
// asserts the bus, if the bus isn't granted to him.
assign o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
assign o_b_stall = (!r_a_owner) ? i_stall : 1'b1;
//
//
assign o_a_err = ( r_a_owner) ? i_err : 1'b0;
assign o_b_err = (!r_a_owner) ? i_err : 1'b0;
// }}}
end endgenerate
// Make Verilator happy
// {{{
// verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, i_reset, F_LGDEPTH, F_MAX_STALL,
F_MAX_ACK_DELAY };
// verilator lint_on UNUSED
// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal properties
// {{{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
`ifdef WBARBITER
`define ASSUME assume
`else
`define ASSUME assert
`endif
reg f_prior_a_ack, f_prior_b_ack;
reg f_past_valid;
initial f_past_valid = 1'b0;
always @(posedge i_clk)
f_past_valid <= 1'b1;
initial `ASSUME(!i_a_cyc);
initial `ASSUME(!i_a_stb);
initial `ASSUME(!i_b_cyc);
initial `ASSUME(!i_b_stb);
initial `ASSUME(!i_ack);
initial `ASSUME(!i_err);
always @(*)
if (!f_past_valid)
`ASSUME(i_reset);
always @(posedge i_clk)
begin
if (o_cyc)
assert((i_a_cyc)||(i_b_cyc));
if ((f_past_valid)&&($past(o_cyc))&&(o_cyc))
assert($past(r_a_owner) == r_a_owner);
end
fwb_master #(
// {{{
.DW(DW), .AW(AW),
.F_MAX_STALL(F_MAX_STALL),
.F_LGDEPTH(F_LGDEPTH),
.F_MAX_ACK_DELAY(F_MAX_ACK_DELAY),
.F_OPT_RMW_BUS_OPTION(1),
.F_OPT_DISCONTINUOUS(1)
// }}}
) f_wbm(
// {{{
i_clk, i_reset,
o_cyc, o_stb, o_we, o_adr, o_dat, o_sel,
i_ack, i_stall, 32'h0, i_err,
f_nreqs, f_nacks, f_outstanding
// }}}
);
fwb_slave #(
// {{{
.DW(DW), .AW(AW),
.F_MAX_STALL(0),
.F_LGDEPTH(F_LGDEPTH),
.F_MAX_ACK_DELAY(0),
.F_OPT_RMW_BUS_OPTION(1),
.F_OPT_DISCONTINUOUS(1)
// }}}
) f_wba(
// {{{
i_clk, i_reset,
i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, i_a_sel,
o_a_ack, o_a_stall, 32'h0, o_a_err,
f_a_nreqs, f_a_nacks, f_a_outstanding
// }}}
);
fwb_slave #(
// {{{
.DW(DW), .AW(AW),
.F_MAX_STALL(0),
.F_LGDEPTH(F_LGDEPTH),
.F_MAX_ACK_DELAY(0),
.F_OPT_RMW_BUS_OPTION(1),
.F_OPT_DISCONTINUOUS(1)
// }}}
) f_wbb(
// {{{
i_clk, i_reset,
i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, i_b_sel,
o_b_ack, o_b_stall, 32'h0, o_b_err,
f_b_nreqs, f_b_nacks, f_b_outstanding
// }}}
);
always @(posedge i_clk)
if (r_a_owner)
begin
assert(f_b_nreqs == 0);
assert(f_b_nacks == 0);
assert(f_a_outstanding == f_outstanding);
end else begin
assert(f_a_nreqs == 0);
assert(f_a_nacks == 0);
assert(f_b_outstanding == f_outstanding);
end
always @(posedge i_clk)
if ((f_past_valid)&&(!$past(i_reset))
&&($past(i_a_stb))&&(!$past(i_b_cyc)))
assert(r_a_owner);
always @(posedge i_clk)
if ((f_past_valid)&&(!$past(i_reset))
&&(!$past(i_a_cyc))&&($past(i_b_stb)))
assert(!r_a_owner);
always @(posedge i_clk)
if ((f_past_valid)&&(r_a_owner != $past(r_a_owner)))
assert(!$past(o_cyc));
////////////////////////////////////////////////////////////////////////
//
// Cover checks
// {{{
////////////////////////////////////////////////////////////////////////
//
//
initial f_prior_a_ack = 1'b0;
always @(posedge i_clk)
if ((i_reset)||(o_a_err)||(o_b_err))
f_prior_a_ack <= 1'b0;
else if ((o_cyc)&&(o_a_ack))
f_prior_a_ack <= 1'b1;
initial f_prior_b_ack = 1'b0;
always @(posedge i_clk)
if ((i_reset)||(o_a_err)||(o_b_err))
f_prior_b_ack <= 1'b0;
else if ((o_cyc)&&(o_b_ack))
f_prior_b_ack <= 1'b1;
always @(posedge i_clk)
begin
cover(f_prior_b_ack && o_cyc && o_a_ack);
cover((o_cyc && o_a_ack)
&&($past(o_cyc && o_a_ack))
&&($past(o_cyc && o_a_ack,2)));
cover(f_prior_a_ack && o_cyc && o_b_ack);
cover((o_cyc && o_b_ack)
&&($past(o_cyc && o_b_ack))
&&($past(o_cyc && o_b_ack,2)));
end
always @(*)
cover(o_cyc && o_b_ack);
// }}}
// }}}
`endif
endmodule
`ifndef YOSYS
`default_nettype wire
`endif

258
testbench/axi_tb/addr.coe Normal file
View File

@ -0,0 +1,258 @@
memory_initialization_radix = 16;
memory_initialization_vector =
00000000
00000000
00000010
00000010
00000020
00000020
00000030
00000030
00000040
00000040
00000050
00000050
00000060
00000060
00000070
00000070
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
ffffffff
;

258
testbench/axi_tb/ctrl.coe Normal file
View File

@ -0,0 +1,258 @@
memory_initialization_radix = 16;
memory_initialization_vector =
00030100
00020201
00030302
00020403
00030504
00020605
00030706
00020807
00030908
00020a09
00030b0a
00020c0b
00030d0c
00020e0d
00030f0e
0002100f
00031110
00031211
00031312
00031413
00031514
00031615
00031716
00031817
00031918
00031a19
00031b1a
00031c1b
00031d1c
00031e1d
00031f1e
0003201f
00032120
00032221
00032322
00032423
00032524
00032625
00032726
00032827
00032928
00032a29
00032b2a
00032c2b
00032d2c
00032e2d
00032f2e
0003302f
00033130
00033231
00033332
00033433
00033534
00033635
00033736
00033837
00033938
00033a39
00033b3a
00033c3b
00033d3c
00033e3d
00033f3e
0003403f
00034140
00034241
00034342
00034443
00034544
00034645
00034746
00034847
00034948
00034a49
00034b4a
00034c4b
00034d4c
00034e4d
00034f4e
0003504f
00035150
00035251
00035352
00035453
00035554
00035655
00035756
00035857
00035958
00035a59
00035b5a
00035c5b
00035d5c
00035e5d
00035f5e
0003605f
00036160
00036261
00036362
00036463
00036564
00036665
00036766
00036867
00036968
00036a69
00036b6a
00036c6b
00036d6c
00036e6d
00036f6e
0003706f
00037170
00037271
00037372
00037473
00037574
00037675
00037776
00037877
00037978
00037a79
00037b7a
00037c7b
00037d7c
00037e7d
00037f7e
0003807f
00038180
00038281
00038382
00038483
00038584
00038685
00038786
00038887
00038988
00038a89
00038b8a
00038c8b
00038d8c
00038e8d
00038f8e
0003908f
00039190
00039291
00039392
00039493
00039594
00039695
00039796
00039897
00039998
00039a99
00039b9a
00039c9b
00039d9c
00039e9d
00039f9e
0003a09f
0003a1a0
0003a2a1
0003a3a2
0003a4a3
0003a5a4
0003a6a5
0003a7a6
0003a8a7
0003a9a8
0003aaa9
0003abaa
0003acab
0003adac
0003aead
0003afae
0003b0af
0003b1b0
0003b2b1
0003b3b2
0003b4b3
0003b5b4
0003b6b5
0003b7b6
0003b8b7
0003b9b8
0003bab9
0003bbba
0003bcbb
0003bdbc
0003bebd
0003bfbe
0003c0bf
0003c1c0
0003c2c1
0003c3c2
0003c4c3
0003c5c4
0003c6c5
0003c7c6
0003c8c7
0003c9c8
0003cac9
0003cbca
0003cccb
0003cdcc
0003cecd
0003cfce
0003d0cf
0003d1d0
0003d2d1
0003d3d2
0003d4d3
0003d5d4
0003d6d5
0003d7d6
0003d8d7
0003d9d8
0003dad9
0003dbda
0003dcdb
0003dddc
0003dedd
0003dfde
0003e0df
0003e1e0
0003e2e1
0003e3e2
0003e4e3
0003e5e4
0003e6e5
0003e7e6
0003e8e7
0003e9e8
0003eae9
0003ebea
0003eceb
0003edec
0003eeed
0003efee
0003f0ef
0003f1f0
0003f2f1
0003f3f2
0003f4f3
0003f5f4
0003f6f5
0003f7f6
0003f8f7
0003f9f8
0003faf9
0003fbfa
0003fcfb
0003fdfc
0003fefd
0003fffe
;

BIN
testbench/axi_tb/data.atg Normal file

Binary file not shown.

258
testbench/axi_tb/data.coe Normal file
View File

@ -0,0 +1,258 @@
memory_initialization_radix = 16;
memory_initialization_vector =
01234567
00000000
89abcdef
00000000
19283746
00000000
afdec70a
00000000
12121212
00000000
34343434
00000000
00000000
00000000
ffffffff
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
;

View File

@ -0,0 +1,205 @@
<?xml version="1.0" encoding="UTF-8"?>
<wave_config>
<wave_state>
</wave_state>
<db_ref_list>
<db_ref path="ddr3_axi_traffic_gen_behav.wdb" id="1">
<top_modules>
<top_module name="ddr3_axi_traffic_gen_tb" />
<top_module name="glbl" />
</top_modules>
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="56,185.259 ns"></ZoomStartTime>
<ZoomEndTime time="56,341.826 ns"></ZoomEndTime>
<Cursor1Time time="56,242.459 ns"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="276"></NameColumnWidth>
<ValueColumnWidth column_width="84"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="45" />
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/i_controller_clk">
<obj_property name="ElementShortName">i_controller_clk</obj_property>
<obj_property name="ObjectShortName">i_controller_clk</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/i_ddr3_clk">
<obj_property name="ElementShortName">i_ddr3_clk</obj_property>
<obj_property name="ObjectShortName">i_ddr3_clk</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/i_ref_clk">
<obj_property name="ElementShortName">i_ref_clk</obj_property>
<obj_property name="ObjectShortName">i_ref_clk</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/i_ddr3_clk_90">
<obj_property name="ElementShortName">i_ddr3_clk_90</obj_property>
<obj_property name="ObjectShortName">i_ddr3_clk_90</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/i_rst_n">
<obj_property name="ElementShortName">i_rst_n</obj_property>
<obj_property name="ObjectShortName">i_rst_n</obj_property>
</wvobject>
<wvobject fp_name="divider622" type="divider">
<obj_property name="label">AXI Lite (Traffic Generator)</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/s_axi_aclk">
<obj_property name="ElementShortName">s_axi_aclk</obj_property>
<obj_property name="ObjectShortName">s_axi_aclk</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/s_axi_aresetn">
<obj_property name="ElementShortName">s_axi_aresetn</obj_property>
<obj_property name="ObjectShortName">s_axi_aresetn</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_awaddr">
<obj_property name="ElementShortName">m_axi_lite_ch1_awaddr[31:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_awaddr[31:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_awprot">
<obj_property name="ElementShortName">m_axi_lite_ch1_awprot[2:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_awprot[2:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_awvalid">
<obj_property name="ElementShortName">m_axi_lite_ch1_awvalid</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_awvalid</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_awready">
<obj_property name="ElementShortName">m_axi_lite_ch1_awready</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_awready</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_wdata">
<obj_property name="ElementShortName">m_axi_lite_ch1_wdata[31:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_wdata[31:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_wstrb">
<obj_property name="ElementShortName">m_axi_lite_ch1_wstrb[3:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_wstrb[3:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_wvalid">
<obj_property name="ElementShortName">m_axi_lite_ch1_wvalid</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_wvalid</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_wready">
<obj_property name="ElementShortName">m_axi_lite_ch1_wready</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_wready</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_bresp">
<obj_property name="ElementShortName">m_axi_lite_ch1_bresp[1:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_bresp[1:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_bvalid">
<obj_property name="ElementShortName">m_axi_lite_ch1_bvalid</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_bvalid</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/m_axi_lite_ch1_bready">
<obj_property name="ElementShortName">m_axi_lite_ch1_bready</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_bready</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_araddr">
<obj_property name="ElementShortName">m_axi_lite_ch1_araddr[31:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_araddr[31:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_arvalid">
<obj_property name="ElementShortName">m_axi_lite_ch1_arvalid</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_arvalid</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_arready">
<obj_property name="ElementShortName">m_axi_lite_ch1_arready</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_arready</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_rdata">
<obj_property name="ElementShortName">m_axi_lite_ch1_rdata[31:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_rdata[31:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_rvalid">
<obj_property name="ElementShortName">m_axi_lite_ch1_rvalid</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_rvalid</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_rresp">
<obj_property name="ElementShortName">m_axi_lite_ch1_rresp[1:0]</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_rresp[1:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/m_axi_lite_ch1_rready">
<obj_property name="ElementShortName">m_axi_lite_ch1_rready</obj_property>
<obj_property name="ObjectShortName">m_axi_lite_ch1_rready</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/done">
<obj_property name="ElementShortName">done</obj_property>
<obj_property name="ObjectShortName">done</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/axi_traffic_gen_inst/status">
<obj_property name="ElementShortName">status[31:0]</obj_property>
<obj_property name="ObjectShortName">status[31:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/s_axi_wdata">
<obj_property name="ElementShortName">s_axi_wdata[127:0]</obj_property>
<obj_property name="ObjectShortName">s_axi_wdata[127:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/s_axi_wstrb">
<obj_property name="ElementShortName">s_axi_wstrb[15:0]</obj_property>
<obj_property name="ObjectShortName">s_axi_wstrb[15:0]</obj_property>
</wvobject>
<wvobject fp_name="divider621" type="divider">
<obj_property name="label">Controller</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/ddr3_controller_inst/instruction_address">
<obj_property name="ElementShortName">instruction_address[4:0]</obj_property>
<obj_property name="ObjectShortName">instruction_address[4:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/ddr3_controller_inst/state_calibrate">
<obj_property name="ElementShortName">state_calibrate[5:0]</obj_property>
<obj_property name="ObjectShortName">state_calibrate[5:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/ddr3_controller_inst/lane">
<obj_property name="ElementShortName">lane[0:0]</obj_property>
<obj_property name="ObjectShortName">lane[0:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/ddr3_controller_inst/correct_read_data">
<obj_property name="ElementShortName">correct_read_data[31:0]</obj_property>
<obj_property name="ObjectShortName">correct_read_data[31:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/ddr3_controller_inst/wrong_read_data">
<obj_property name="ElementShortName">wrong_read_data[31:0]</obj_property>
<obj_property name="ObjectShortName">wrong_read_data[31:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/i_wb_cyc">
<obj_property name="ElementShortName">i_wb_cyc</obj_property>
<obj_property name="ObjectShortName">i_wb_cyc</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/i_wb_stb">
<obj_property name="ElementShortName">i_wb_stb</obj_property>
<obj_property name="ObjectShortName">i_wb_stb</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/i_wb_we">
<obj_property name="ElementShortName">i_wb_we</obj_property>
<obj_property name="ObjectShortName">i_wb_we</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/i_wb_addr">
<obj_property name="ElementShortName">i_wb_addr[23:0]</obj_property>
<obj_property name="ObjectShortName">i_wb_addr[23:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/i_wb_data">
<obj_property name="ElementShortName">i_wb_data[127:0]</obj_property>
<obj_property name="ObjectShortName">i_wb_data[127:0]</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/i_wb_sel">
<obj_property name="ElementShortName">i_wb_sel[15:0]</obj_property>
<obj_property name="ObjectShortName">i_wb_sel[15:0]</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/o_wb_stall">
<obj_property name="ElementShortName">o_wb_stall</obj_property>
<obj_property name="ObjectShortName">o_wb_stall</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/o_wb_ack">
<obj_property name="ElementShortName">o_wb_ack</obj_property>
<obj_property name="ObjectShortName">o_wb_ack</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_axi_traffic_gen_tb/dut/ddr3_top_inst/o_wb_data">
<obj_property name="ElementShortName">o_wb_data[127:0]</obj_property>
<obj_property name="ObjectShortName">o_wb_data[127:0]</obj_property>
</wvobject>
</wave_config>

View File

@ -0,0 +1,202 @@
module ddr3_axi_traffic_gen_tb;
reg i_controller_clk, i_ddr3_clk, i_ref_clk, i_ddr3_clk_90;
reg i_rst_n;
// DDR3 Pins
wire o_ddr3_clk_p;
wire o_ddr3_clk_n;
wire o_ddr3_reset_n;
wire o_ddr3_cke;
wire o_ddr3_cs_n;
wire o_ddr3_ras_n;
wire o_ddr3_cas_n;
wire o_ddr3_we_n;
wire[dut.ROW_BITS-1:0] o_ddr3_addr;
wire[dut.BA_BITS-1:0] o_ddr3_ba_addr;
wire[(dut.DQ_BITS*dut.BYTE_LANES)-1:0] io_ddr3_dq;
wire[dut.BYTE_LANES-1:0] io_ddr3_dqs, io_ddr3_dqs_n;
wire[dut.BYTE_LANES-1:0] o_ddr3_dm;
wire o_ddr3_odt;
localparam CONTROLLER_CLK_PERIOD = 10_000, //ps, period of clock input to this DDR3 controller module
DDR3_CLK_PERIOD = 2500; //ps, period of clock input to DDR3 RAM device
// Clocks and reset
always #(CONTROLLER_CLK_PERIOD/2) i_controller_clk = !i_controller_clk;
always #(DDR3_CLK_PERIOD/2) i_ddr3_clk = !i_ddr3_clk;
always #2500 i_ref_clk = !i_ref_clk;
initial begin //90 degree phase shifted ddr3_clk
#(DDR3_CLK_PERIOD/4);
while(1) begin
#(DDR3_CLK_PERIOD/2) i_ddr3_clk_90 = !i_ddr3_clk_90;
end
end
initial begin
i_controller_clk = 1;
i_ddr3_clk = 1;
i_ref_clk = 1;
i_ddr3_clk_90 = 1;
i_rst_n = 0;
#1_000_000;
i_rst_n = 1;
wait(done);
#1_000_000;
$finish;
end
wire [31 : 0] m_axi_lite_ch1_awaddr;
wire [2 : 0] m_axi_lite_ch1_awprot;
wire m_axi_lite_ch1_awvalid;
wire m_axi_lite_ch1_awready;
wire [31 : 0] m_axi_lite_ch1_wdata;
wire [3 : 0] m_axi_lite_ch1_wstrb;
wire m_axi_lite_ch1_wvalid;
wire m_axi_lite_ch1_wready;
wire [1 : 0] m_axi_lite_ch1_bresp;
wire m_axi_lite_ch1_bvalid;
wire m_axi_lite_ch1_bready;
wire [31 : 0] m_axi_lite_ch1_araddr;
wire m_axi_lite_ch1_arvalid;
wire m_axi_lite_ch1_arready;
wire [31 : 0] m_axi_lite_ch1_rdata;
wire m_axi_lite_ch1_rvalid;
wire [1 : 0] m_axi_lite_ch1_rresp;
wire m_axi_lite_ch1_rready;
wire done;
wire [31 : 0] status;
axi_traffic_gen_0 axi_traffic_gen_inst(
.s_axi_aclk(i_controller_clk),
.s_axi_aresetn(i_rst_n && (dut.ddr3_top_inst.ddr3_controller_inst.state_calibrate == 23)), //stay reset until calibration is done
.m_axi_lite_ch1_awaddr(m_axi_lite_ch1_awaddr),
.m_axi_lite_ch1_awprot(m_axi_lite_ch1_awprot),
.m_axi_lite_ch1_awvalid(m_axi_lite_ch1_awvalid),
.m_axi_lite_ch1_awready(m_axi_lite_ch1_awready),
.m_axi_lite_ch1_wdata(m_axi_lite_ch1_wdata),
.m_axi_lite_ch1_wstrb(m_axi_lite_ch1_wstrb), // assuming full byte enable for simplicity
.m_axi_lite_ch1_wvalid(m_axi_lite_ch1_wvalid),
.m_axi_lite_ch1_wready(m_axi_lite_ch1_wready),
.m_axi_lite_ch1_bresp(m_axi_lite_ch1_bresp),
.m_axi_lite_ch1_bvalid(m_axi_lite_ch1_bvalid),
.m_axi_lite_ch1_bready(m_axi_lite_ch1_bready),
.m_axi_lite_ch1_araddr(m_axi_lite_ch1_araddr),
.m_axi_lite_ch1_arvalid(m_axi_lite_ch1_arvalid),
.m_axi_lite_ch1_arready(m_axi_lite_ch1_arready),
.m_axi_lite_ch1_rdata(m_axi_lite_ch1_rdata),
.m_axi_lite_ch1_rvalid(m_axi_lite_ch1_rvalid),
.m_axi_lite_ch1_rresp(m_axi_lite_ch1_rresp),
.m_axi_lite_ch1_rready(m_axi_lite_ch1_rready),
.done(done),
.status(status)
);
ddr3_top_axi #(
.CONTROLLER_CLK_PERIOD(10_000), //ps, clock period of the controller interface
.DDR3_CLK_PERIOD(2_500), //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD)
.ROW_BITS(14), //width of row address
.COL_BITS(10), //width of column address
.BA_BITS(3), //width of bank address
.BYTE_LANES(2), //number of byte lanes of DDR3 RAM
.AXI_ID_WIDTH(4), // The AXI id width used for R&W, an int between 1-16
.MICRON_SIM(1), //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
.ODELAY_SUPPORTED(0), //set to 1 when ODELAYE2 is supported
.SECOND_WISHBONE(0) //set to 1 if 2nd wishbone for debugging is needed
) dut (
.i_controller_clk(i_controller_clk),
.i_ddr3_clk(i_ddr3_clk),
.i_ref_clk(i_ref_clk), //i_controller_clk = CONTROLLER_CLK_PERIOD, i_ddr3_clk = DDR3_CLK_PERIOD, i_ref_clk = 200MHz
.i_ddr3_clk_90(i_ddr3_clk_90), //required only when ODELAY_SUPPORTED is zero
.i_rst_n(i_rst_n),
// AXI Interface
// AXI write address channel signals
.s_axi_awvalid(m_axi_lite_ch1_awvalid),
.s_axi_awready(m_axi_lite_ch1_awready),
.s_axi_awid(4'b0000), // AXI-Lite doesn't have ID, so set to 0
.s_axi_awaddr(m_axi_lite_ch1_awaddr),
.s_axi_awlen(8'b00000000), // AXI-Lite doesn't use burst length
.s_axi_awsize(3'b010), // Assuming 32-bit size
.s_axi_awburst(2'b01), // AXI-Lite doesn't use burst, set to incrementing
.s_axi_awlock(1'b0), // AXI-Lite doesn't use lock, set to 0
.s_axi_awcache(4'b0000), // Assuming normal non-cacheable memory
.s_axi_awprot(m_axi_lite_ch1_awprot ), // Set to normal, non-secure, data access
.s_axi_awqos(4'b0000), // Quality of Service, set to 0
// AXI write data channel signals
.s_axi_wvalid(m_axi_lite_ch1_wvalid),
.s_axi_wready(m_axi_lite_ch1_wready),
.s_axi_wdata({128'd0,m_axi_lite_ch1_wdata}),
.s_axi_wstrb({0,m_axi_lite_ch1_wstrb}), // Assuming full byte enable
.s_axi_wlast(m_axi_lite_ch1_wvalid), // AXI-Lite only has single beat transfers
// AXI write response channel signals
.s_axi_bvalid(m_axi_lite_ch1_bvalid),
.s_axi_bready(m_axi_lite_ch1_bready),
.s_axi_bid(), // AXI-Lite doesn't have ID, so set to 0
.s_axi_bresp(m_axi_lite_ch1_bresp),
// AXI read address channel signals
.s_axi_arvalid(m_axi_lite_ch1_arvalid), // No read transactions in this example
.s_axi_arready(m_axi_lite_ch1_arready),
.s_axi_arid(4'b0000),
.s_axi_araddr(m_axi_lite_ch1_araddr),
.s_axi_arlen(8'b00000000),
.s_axi_arsize(3'b010),
.s_axi_arburst(2'b01),
.s_axi_arlock(1'b0),
.s_axi_arcache(4'b0000),
.s_axi_arprot(3'b000),
.s_axi_arqos(4'b0000),
// AXI read data channel signals
.s_axi_rvalid(m_axi_lite_ch1_rvalid),
.s_axi_rready(m_axi_lite_ch1_rready), // No read transactions in this example
.s_axi_rid(),
.s_axi_rdata(m_axi_lite_ch1_rdata),
.s_axi_rlast(),
.s_axi_rresp(m_axi_lite_ch1_rresp),
// DDR3 I/O Interface
.o_ddr3_clk_p(o_ddr3_clk_p),
.o_ddr3_clk_n(o_ddr3_clk_n),
.o_ddr3_reset_n(o_ddr3_reset_n),
.o_ddr3_cke(o_ddr3_cke),
.o_ddr3_cs_n(o_ddr3_cs_n),
.o_ddr3_ras_n(o_ddr3_ras_n),
.o_ddr3_cas_n(o_ddr3_cas_n),
.o_ddr3_we_n(o_ddr3_we_n),
.o_ddr3_addr(o_ddr3_addr),
.o_ddr3_ba_addr(o_ddr3_ba_addr),
.io_ddr3_dq(io_ddr3_dq),
.io_ddr3_dqs(io_ddr3_dqs),
.io_ddr3_dqs_n(io_ddr3_dqs_n),
.o_ddr3_dm(o_ddr3_dm),
.o_ddr3_odt(o_ddr3_odt)
);
ddr3 ddr3_0(
.rst_n(o_ddr3_reset_n),
.ck(o_ddr3_clk_p),
.ck_n(o_ddr3_clk_n),
.cke(o_ddr3_cke),
.cs_n(o_ddr3_cs_n),
.ras_n(o_ddr3_ras_n),
.cas_n(o_ddr3_cas_n),
.we_n(o_ddr3_we_n),
.dm_tdqs(o_ddr3_dm),
.ba(o_ddr3_ba_addr),
.addr({0,o_ddr3_addr}),
.dq(io_ddr3_dq),
.dqs(io_ddr3_dqs),
.dqs_n(io_ddr3_dqs_n),
.tdqs_n(),
.odt(o_ddr3_odt)
);
endmodule

258
testbench/axi_tb/mask.coe Normal file
View File

@ -0,0 +1,258 @@
memory_initialization_radix = 16;
memory_initialization_vector =
ffffffff
00000000
ffffffff
00000000
ffffffff
00000000
ffffffff
00000000
ffffffff
00000000
ffffffff
00000000
ffffffff
00000000
ffffffff
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
;