Pushing the bulk of UHD-3.7.0 code.
Original-commit: ff1546f8137f7f92bb250f685561b0c34cc0e053
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012-2013 Ettus Research LLC
|
||||||
|
#
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# FIFO Sources
|
||||||
|
##################################################
|
||||||
|
AXI_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/axi/, \
|
||||||
|
axi_dma_master.v \
|
||||||
|
axi_dram_fifo.v \
|
||||||
|
axi_embed_tlast.v \
|
||||||
|
axi_extract_tlast.v \
|
||||||
|
axi_chdr_test_pattern.v \
|
||||||
|
axi_fast_fifo.v \
|
||||||
|
axi_fast_extract_tlast.v \
|
||||||
|
axi_chdr_header_trigger.v \
|
||||||
|
))
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
// Copyright 2014 Ettus Research LLC
|
||||||
|
|
||||||
|
|
||||||
|
module axi_chdr_header_trigger
|
||||||
|
#(
|
||||||
|
parameter WIDTH=64,
|
||||||
|
parameter SID=0
|
||||||
|
)
|
||||||
|
(input clk, input reset, input clear,
|
||||||
|
input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, input i_tready,
|
||||||
|
output trigger
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
reg state;
|
||||||
|
localparam IDLE = 0;
|
||||||
|
localparam RUN = 1;
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if(reset | clear)
|
||||||
|
state <= IDLE;
|
||||||
|
else
|
||||||
|
case (state)
|
||||||
|
IDLE :
|
||||||
|
if(i_tvalid && i_tready)
|
||||||
|
state <= RUN;
|
||||||
|
|
||||||
|
RUN :
|
||||||
|
if(i_tready && i_tvalid && i_tlast)
|
||||||
|
state <= IDLE;
|
||||||
|
|
||||||
|
default :
|
||||||
|
state <= IDLE;
|
||||||
|
endcase // case (state)
|
||||||
|
|
||||||
|
assign trigger = i_tvalid && i_tready && (state == IDLE) && (i_tdata[15:0] != SID);
|
||||||
|
|
||||||
|
endmodule // axi_chdr_header_trigger
|
||||||
@@ -0,0 +1,314 @@
|
|||||||
|
//
|
||||||
|
// Synthesizable test pattern generators and checkers
|
||||||
|
// for CHDR that can be used to test transparent blocks
|
||||||
|
// (FIFOs, switches, etc)
|
||||||
|
//
|
||||||
|
|
||||||
|
//`define MTU 8192
|
||||||
|
`define MTU 1536
|
||||||
|
|
||||||
|
module axi_chdr_test_pattern
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI stream input
|
||||||
|
//
|
||||||
|
output reg [63:0] i_tdata,
|
||||||
|
output reg i_tlast,
|
||||||
|
output reg i_tvalid,
|
||||||
|
input wire i_tready,
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI Stream output
|
||||||
|
//
|
||||||
|
input wire [63:0] o_tdata,
|
||||||
|
input wire o_tlast,
|
||||||
|
input wire o_tvalid,
|
||||||
|
output reg o_tready,
|
||||||
|
//
|
||||||
|
// Test flags
|
||||||
|
//
|
||||||
|
input start,
|
||||||
|
input [15:0] control,
|
||||||
|
output reg fail,
|
||||||
|
output reg done
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [7:0] bist_rx_delay = control[7:0];
|
||||||
|
wire [7:0] bist_tx_delay = control[15:8];
|
||||||
|
|
||||||
|
|
||||||
|
reg [15:0] tx_count, rx_count;
|
||||||
|
reg [15:0] tx_data, rx_data;
|
||||||
|
reg [7:0] tx_delay, rx_delay;
|
||||||
|
|
||||||
|
|
||||||
|
localparam TX_IDLE = 0;
|
||||||
|
localparam TX_START = 1;
|
||||||
|
localparam TX_ACTIVE = 2;
|
||||||
|
localparam TX_GAP = 3;
|
||||||
|
localparam TX_DONE = 4;
|
||||||
|
localparam TX_WAIT = 5;
|
||||||
|
|
||||||
|
localparam RX_IDLE = 0;
|
||||||
|
localparam RX_ACTIVE = 1;
|
||||||
|
localparam RX_FAIL = 2;
|
||||||
|
localparam RX_DONE = 3;
|
||||||
|
localparam RX_WAIT = 4;
|
||||||
|
|
||||||
|
reg [2:0] tx_state, rx_state;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Transmitter
|
||||||
|
//
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset)
|
||||||
|
begin
|
||||||
|
tx_delay <= 0;
|
||||||
|
tx_count <= 8;
|
||||||
|
tx_data <= 0;
|
||||||
|
i_tdata <= 64'h0;
|
||||||
|
i_tlast <= 1'b0;
|
||||||
|
i_tvalid <= 1'b0;
|
||||||
|
tx_state <= TX_IDLE;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
case(tx_state)
|
||||||
|
TX_IDLE: begin
|
||||||
|
tx_delay <= 0;
|
||||||
|
i_tdata <= 64'h0;
|
||||||
|
i_tlast <= 1'b0;
|
||||||
|
i_tvalid <= 1'b0;
|
||||||
|
tx_data <= 0;
|
||||||
|
tx_count <= 4;
|
||||||
|
// Run whilst start asserted.
|
||||||
|
if (start) begin
|
||||||
|
tx_state <= TX_START;
|
||||||
|
// ....Go back to initialized state if start deasserted.
|
||||||
|
end else begin
|
||||||
|
tx_state <= TX_IDLE;
|
||||||
|
end
|
||||||
|
end // case: TX_IDLE
|
||||||
|
|
||||||
|
//
|
||||||
|
// START signal is asserted.
|
||||||
|
// Now need to start transmiting a packet.
|
||||||
|
//
|
||||||
|
TX_START: begin
|
||||||
|
// At the next clock edge drive first beat of new packet onto HDR bus.
|
||||||
|
i_tlast <= 1'b0;
|
||||||
|
i_tvalid <= 1'b1;
|
||||||
|
tx_data <= tx_data + 4;
|
||||||
|
// i_tdata <= {tx_data,tx_data+16'd1,tx_data+16'd2,tx_data+16'd3};
|
||||||
|
i_tdata <= {4{(tx_data[2]?16'hffff:16'h0000)^tx_data[15:0]}};
|
||||||
|
tx_state <= TX_ACTIVE;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Valid data is (already) being driven onto the CHDR bus.
|
||||||
|
// i_tlast may also be driven asserted if current data count has reached EOP.
|
||||||
|
// Watch i_tready to see when it's consumed.
|
||||||
|
// When packets are consumed increment data counter or transition state if
|
||||||
|
// EOP has sucsesfully concluded.
|
||||||
|
//
|
||||||
|
TX_ACTIVE: begin
|
||||||
|
i_tvalid <= 1'b1; // Always assert tvalid
|
||||||
|
if (i_tready) begin
|
||||||
|
|
||||||
|
// i_tdata <= {tx_data,tx_data+16'd1,tx_data+16'd2,tx_data+16'd3};
|
||||||
|
i_tdata <= {4{(tx_data[2]?16'hffff:16'h0000)^tx_data[15:0]}};
|
||||||
|
// Will this next beat be the last in a packet?
|
||||||
|
if (tx_data == tx_count) begin
|
||||||
|
tx_data <= 0;
|
||||||
|
i_tlast <= 1'b1;
|
||||||
|
tx_state <= TX_GAP;
|
||||||
|
end else begin
|
||||||
|
tx_data <= tx_data + 4;
|
||||||
|
i_tlast <= 1'b0;
|
||||||
|
tx_state <= TX_ACTIVE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// Keep driving all CHDR bus signals as-is until i_tready is asserted.
|
||||||
|
tx_state <= TX_ACTIVE;
|
||||||
|
end
|
||||||
|
end // case: TX_ACTIVE
|
||||||
|
//
|
||||||
|
// Force an inter-packet gap between packets in a BIST sequence where tvalid is driven low.
|
||||||
|
// As we leave this state check if all packets in BIST sequence have been generated yet,
|
||||||
|
// and if so go to done state.
|
||||||
|
//
|
||||||
|
TX_GAP: begin
|
||||||
|
if (i_tready) begin
|
||||||
|
i_tvalid <= 1'b0;
|
||||||
|
i_tdata <= 64'h0;
|
||||||
|
i_tlast <= 1'b0;
|
||||||
|
tx_count <= tx_count + 4;
|
||||||
|
|
||||||
|
if (tx_count < `MTU) begin
|
||||||
|
tx_state <= TX_WAIT;
|
||||||
|
tx_delay <= bist_tx_delay;
|
||||||
|
end else
|
||||||
|
tx_state <= TX_DONE;
|
||||||
|
end else begin // if (i_tready)
|
||||||
|
tx_state <= TX_GAP;
|
||||||
|
end
|
||||||
|
end // case: TX_GAP
|
||||||
|
//
|
||||||
|
// Simulate inter packet gap in real UHD system
|
||||||
|
TX_WAIT: begin
|
||||||
|
if (tx_delay == 0)
|
||||||
|
tx_state <= TX_START;
|
||||||
|
else begin
|
||||||
|
tx_delay <= tx_delay - 1;
|
||||||
|
tx_state <= TX_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Complete test pattern BIST sequence has been transmitted. Sit in this
|
||||||
|
// state indefinately if START is taken low, which re-inits the whole BIST solution.
|
||||||
|
//
|
||||||
|
TX_DONE: begin
|
||||||
|
if (!start) begin
|
||||||
|
tx_state <= TX_DONE;
|
||||||
|
end else begin
|
||||||
|
tx_state <= TX_IDLE;
|
||||||
|
end
|
||||||
|
i_tvalid <= 1'b0;
|
||||||
|
i_tdata <= 64'd0;
|
||||||
|
i_tlast <= 1'b0;
|
||||||
|
|
||||||
|
end
|
||||||
|
endcase // case (tx_state)
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Receiver
|
||||||
|
//
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset)
|
||||||
|
begin
|
||||||
|
rx_delay <= 0;
|
||||||
|
rx_count <= 0;
|
||||||
|
rx_data <= 0;
|
||||||
|
o_tready <= 1'b0;
|
||||||
|
rx_state <= RX_IDLE;
|
||||||
|
fail <= 1'b0;
|
||||||
|
done <= 1'b0;
|
||||||
|
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
case (rx_state)
|
||||||
|
RX_IDLE: begin
|
||||||
|
rx_delay <= 0;
|
||||||
|
o_tready <= 1'b0;
|
||||||
|
rx_data <= 0;
|
||||||
|
rx_count <= 4;
|
||||||
|
fail <= 1'b0;
|
||||||
|
done <= 1'b0;
|
||||||
|
// Not accepting data whilst Idle,
|
||||||
|
// switch to active when packet arrives
|
||||||
|
if (o_tvalid) begin
|
||||||
|
o_tready <= 1'b1;
|
||||||
|
rx_state <= RX_ACTIVE;
|
||||||
|
end else
|
||||||
|
rx_state <= RX_IDLE;
|
||||||
|
end
|
||||||
|
|
||||||
|
RX_ACTIVE: begin
|
||||||
|
o_tready <= 1'b1;
|
||||||
|
if (o_tvalid)
|
||||||
|
// if (o_tdata != {rx_data,rx_data+16'd1,rx_data+16'd2,rx_data+16'd3})
|
||||||
|
if (o_tdata != {4{(rx_data[2]?16'hffff:16'h0000)^rx_data[15:0]}})
|
||||||
|
begin
|
||||||
|
$display("o_tdata: %x != expected: %x @ time: %d",o_tdata,
|
||||||
|
// {rx_data,rx_data+16'd1,rx_data+16'd2,rx_data+16'd3},
|
||||||
|
{4{(rx_data[2]?16'hffff:16'h0000)^rx_data[15:0]}},
|
||||||
|
$time);
|
||||||
|
rx_state <= RX_FAIL;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
// Should last be asserted?
|
||||||
|
if (rx_data == rx_count)
|
||||||
|
// ...last not asserted when it should be!
|
||||||
|
if (~(o_tlast===1)) begin
|
||||||
|
$display("o_tlast not asserted when it should be @ time: %d",$time);
|
||||||
|
rx_state <= RX_FAIL;
|
||||||
|
end else begin
|
||||||
|
// End of packet, set up to RX next
|
||||||
|
rx_data <= 0;
|
||||||
|
rx_count <= rx_count + 4;
|
||||||
|
rx_delay <= bist_rx_delay;
|
||||||
|
if (rx_count == `MTU) begin
|
||||||
|
rx_state <= RX_DONE;
|
||||||
|
end else begin
|
||||||
|
rx_state <= RX_WAIT;
|
||||||
|
end
|
||||||
|
o_tready <= 1'b0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
// ...last asserted when it should not be!
|
||||||
|
if (~(o_tlast===0)) begin
|
||||||
|
$display("o_tlast asserted when it should not be @ time: %d",$time);
|
||||||
|
rx_state <= RX_FAIL;
|
||||||
|
end else begin
|
||||||
|
// Still in packet body
|
||||||
|
rx_data <= rx_data + 4;
|
||||||
|
rx_delay <= bist_rx_delay;
|
||||||
|
rx_state <= RX_WAIT;
|
||||||
|
o_tready <= 1'b0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
// Nothing to do this cycle
|
||||||
|
rx_state <= RX_ACTIVE;
|
||||||
|
end // case: RX_ACTIVE
|
||||||
|
|
||||||
|
// To simulate the radio consuming samples at a steady rate set by the decimation
|
||||||
|
// have a programable delay here
|
||||||
|
RX_WAIT: begin
|
||||||
|
if (rx_delay == 0) begin
|
||||||
|
rx_state <= RX_ACTIVE;
|
||||||
|
o_tready <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
rx_delay <= rx_delay - 1;
|
||||||
|
rx_state <= RX_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
RX_FAIL: begin
|
||||||
|
o_tready <= 1'b0;
|
||||||
|
done <= 1'b1;
|
||||||
|
fail <= 1'b1;
|
||||||
|
// If start is deasserted allow BIST logic to reset and rearm
|
||||||
|
if (start)
|
||||||
|
rx_state <= RX_FAIL;
|
||||||
|
else
|
||||||
|
rx_state <= RX_IDLE;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
RX_DONE: begin
|
||||||
|
o_tready <= 1'b0;
|
||||||
|
done <= 1'b1;
|
||||||
|
fail <= 1'b0;
|
||||||
|
// If start is asserted allow BIST logic to reset, rearm & restart
|
||||||
|
if (!start)
|
||||||
|
rx_state <= RX_DONE;
|
||||||
|
else
|
||||||
|
rx_state <= RX_IDLE;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
endcase // case (rx_state)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// AXI4 Burst enumeration
|
||||||
|
//
|
||||||
|
`define AXI4_BURST_FIXED 2'b00
|
||||||
|
`define AXI4_BURST_INCR 2'b01
|
||||||
|
`define AXI4_BURST_WRAP 2'b10
|
||||||
|
`define AXI4_BURST_RSVD 2'b11
|
||||||
|
//
|
||||||
|
// AXI4 response code enumeration
|
||||||
|
//
|
||||||
|
`define AXI4_RESP_OKAY 2'b00
|
||||||
|
`define AXI4_RESP_EXOKAY 2'b01
|
||||||
|
`define AXI4_RESP_SLVERR 2'b10
|
||||||
|
`define AXI4_RESP_DECERR 2'b11
|
||||||
|
//
|
||||||
|
// AXI4 lock enumeration
|
||||||
|
//
|
||||||
|
`define AXI4_LOCK_NORMAL 1'b0
|
||||||
|
`define AXI4_LOCK_EXCLUSIVE 1'b1
|
||||||
|
//
|
||||||
|
// AXI4 memory attrubutes
|
||||||
|
//
|
||||||
|
`define AXI4_CACHE_ALLOCATE 4'h8
|
||||||
|
`define AXI4_CACHE_OTHER_ALLOCATE 4'h4
|
||||||
|
`define AXI4_CACHE_MODIFIABLE 4'h2
|
||||||
|
`define AXI4_CACHE_BUFFERABLE 4'h1
|
||||||
|
//
|
||||||
|
// AXI4 PROT attributes
|
||||||
|
//
|
||||||
|
`define AXI4_PROT_PRIVILEDGED 3'h1
|
||||||
|
`define AXI4_PROT_NON_SECURE 3'h2
|
||||||
|
`define AXI4_PROT_INSTRUCTION 3'h4
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,538 @@
|
|||||||
|
|
||||||
|
`include "axi_defs.v"
|
||||||
|
|
||||||
|
`define DEBUG if (1)
|
||||||
|
|
||||||
|
module axi_dma_master
|
||||||
|
(
|
||||||
|
input aclk, // Global AXI clock
|
||||||
|
input areset, // Global AXI reset
|
||||||
|
//
|
||||||
|
// AXI Write address channel
|
||||||
|
//
|
||||||
|
output [0 : 0] m_axi_awid, // Write address ID. This signal is the identification tag for the write address signals
|
||||||
|
output reg [31 : 0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst
|
||||||
|
output reg [7 : 0] m_axi_awlen, // Burst length. The burst length gives the exact number of transfers in a burst.
|
||||||
|
output [2 : 0] m_axi_awsize, // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
output [1 : 0] m_axi_awburst, // Burst type. The burst type and the size information, determine how the address is calculated
|
||||||
|
output [0 : 0] m_axi_awlock, // Lock type. Provides additional information about the atomic characteristics of the transfer.
|
||||||
|
output [3 : 0] m_axi_awcache, // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
output [2 : 0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
output [3 : 0] m_axi_awqos, // Quality of Service, QoS. The QoS identifier sent for each write transaction
|
||||||
|
output [3 : 0] m_axi_awregion, // Region identifier. Permits a single physical interface on a slave to be re-used.
|
||||||
|
output [0 : 0] m_axi_awuser, // User signal. Optional User-defined signal in the write address channel.
|
||||||
|
output reg m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr
|
||||||
|
input m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Write data channel.
|
||||||
|
//
|
||||||
|
output [63 : 0] m_axi_wdata, // Write data
|
||||||
|
output [7 : 0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data.
|
||||||
|
output reg m_axi_wlast, // Write last. This signal indicates the last transfer in a write burst
|
||||||
|
output [0 : 0] m_axi_wuser, // User signal. Optional User-defined signal in the write data channel.
|
||||||
|
output m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available.
|
||||||
|
input m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data.
|
||||||
|
//
|
||||||
|
// AXI Write response channel signals
|
||||||
|
//
|
||||||
|
input [0 : 0] m_axi_bid, // Response ID tag. This signal is the ID tag of the write response.
|
||||||
|
input [1 : 0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction.
|
||||||
|
input [0 : 0] m_axi_buser, // User signal. Optional User-defined signal in the write response channel.
|
||||||
|
input m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response
|
||||||
|
output reg m_axi_bready, // Response ready. This signal indicates that the master can accept a write response
|
||||||
|
//
|
||||||
|
// AXI Read address channel
|
||||||
|
//
|
||||||
|
output [0 : 0] m_axi_arid, // Read address ID. This signal is the identification tag for the read address group of signals
|
||||||
|
output reg [31 : 0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst
|
||||||
|
output reg [7 : 0] m_axi_arlen, // Burst length. This signal indicates the exact number of transfers in a burst.
|
||||||
|
output [2 : 0] m_axi_arsize, // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
output [1 : 0] m_axi_arburst, // Burst type. The burst type and the size information determine how the address for each transfer
|
||||||
|
output [0 : 0] m_axi_arlock, // Lock type. This signal provides additional information about the atomic characteristics
|
||||||
|
output [3 : 0] m_axi_arcache, // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
output [2 : 0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
output [3 : 0] m_axi_arqos, // Quality of Service, QoS. QoS identifier sent for each read transaction.
|
||||||
|
output [3 : 0] m_axi_arregion, // Region identifier. Permits a single physical interface on a slave to be re-used
|
||||||
|
output [0 : 0] m_axi_aruser, // User signal. Optional User-defined signal in the read address channel.
|
||||||
|
output reg m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr
|
||||||
|
input m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Read data channel
|
||||||
|
//
|
||||||
|
input [0 : 0] m_axi_rid, // Read ID tag. This signal is the identification tag for the read data group of signals
|
||||||
|
input [63 : 0] m_axi_rdata, // Read data.
|
||||||
|
input [1 : 0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer
|
||||||
|
input m_axi_rlast, // Read last. This signal indicates the last transfer in a read burst.
|
||||||
|
input [0 : 0] m_axi_ruser, // User signal. Optional User-defined signal in the read data channel.
|
||||||
|
input m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data.
|
||||||
|
output m_axi_rready, // Read ready. This signal indicates that the master can accept the read data and response
|
||||||
|
//
|
||||||
|
// DMA interface for Write transaction
|
||||||
|
//
|
||||||
|
input [31:0] write_addr, // Byte address for start of write transaction (should be 64bit alligned)
|
||||||
|
input [7:0] write_count, // Count of 64bit words to write. (minus one)
|
||||||
|
input write_ctrl_valid,
|
||||||
|
output reg write_ctrl_ready,
|
||||||
|
input [63:0] write_data,
|
||||||
|
input write_data_valid,
|
||||||
|
output write_data_ready,
|
||||||
|
//
|
||||||
|
// DMA interface for Read
|
||||||
|
//
|
||||||
|
input [31:0] read_addr, // Byte address for start of read transaction (should be 64bit alligned)
|
||||||
|
input [7:0] read_count, // Count of 64bit words to read.
|
||||||
|
input read_ctrl_valid,
|
||||||
|
output reg read_ctrl_ready,
|
||||||
|
output [63:0] read_data,
|
||||||
|
output read_data_valid,
|
||||||
|
input read_data_ready,
|
||||||
|
//
|
||||||
|
// Debug Bus
|
||||||
|
//
|
||||||
|
output [31:0] debug
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
localparam AW_IDLE = 0;
|
||||||
|
localparam WAIT_AWREADY = 1;
|
||||||
|
localparam WAIT_BVALID = 2;
|
||||||
|
localparam AW_ERROR = 3;
|
||||||
|
|
||||||
|
reg [1:0] write_addr_state;
|
||||||
|
reg [7:0] write_data_count; // Count write transfers.
|
||||||
|
reg enable_data_write;
|
||||||
|
|
||||||
|
localparam DW_IDLE = 0;
|
||||||
|
localparam DW_RUN = 1;
|
||||||
|
localparam DW_LAST = 2;
|
||||||
|
|
||||||
|
reg [1:0] write_data_state;
|
||||||
|
|
||||||
|
localparam AR_IDLE = 0;
|
||||||
|
localparam WAIT_ARREADY = 1;
|
||||||
|
localparam WAIT_READ_DONE = 2;
|
||||||
|
localparam AR_ERROR = 3;
|
||||||
|
|
||||||
|
reg [1:0] read_addr_state;
|
||||||
|
|
||||||
|
localparam DR_IDLE = 0;
|
||||||
|
localparam DR_RUN = 1;
|
||||||
|
localparam DR_WAIT_ERROR = 2;
|
||||||
|
localparam DR_ERROR = 3;
|
||||||
|
|
||||||
|
reg [1:0] read_data_state;
|
||||||
|
reg [7:0] read_data_count;
|
||||||
|
reg enable_data_read;
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// DEBUG
|
||||||
|
///////////////////////////
|
||||||
|
assign debug= {24'h0,write_addr_state[1:0],write_data_state[1:0],read_addr_state[1:0],read_data_state[1:0]};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// AXI Write address channel
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
assign m_axi_awid = 1'b0;
|
||||||
|
assign m_axi_awsize = 3'h3; // 8 bytes.
|
||||||
|
assign m_axi_awburst = `AXI4_BURST_INCR;
|
||||||
|
assign m_axi_awlock = `AXI4_LOCK_NORMAL;
|
||||||
|
assign m_axi_awcache = `AXI4_CACHE_ALLOCATE | `AXI4_CACHE_OTHER_ALLOCATE | `AXI4_CACHE_MODIFIABLE | `AXI4_CACHE_BUFFERABLE;
|
||||||
|
assign m_axi_awprot = `AXI4_PROT_NON_SECURE;
|
||||||
|
assign m_axi_awqos = 4'h0;
|
||||||
|
assign m_axi_awregion = 4'h0;
|
||||||
|
assign m_axi_awuser = 1'b0;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// AXI Write address state machine
|
||||||
|
//
|
||||||
|
always @(posedge aclk)
|
||||||
|
if (areset) begin
|
||||||
|
write_ctrl_ready <= 1'b0;
|
||||||
|
write_addr_state <= AW_IDLE;
|
||||||
|
m_axi_awaddr[31:0] <= 32'h0;
|
||||||
|
m_axi_awlen[7:0] <= 8'h0;
|
||||||
|
m_axi_awvalid <= 1'b0;
|
||||||
|
m_axi_bready <= 1'b0;
|
||||||
|
end else
|
||||||
|
case (write_addr_state)
|
||||||
|
//
|
||||||
|
// AW_IDLE
|
||||||
|
// We are ready to accept a new write transaction.
|
||||||
|
//
|
||||||
|
AW_IDLE: begin
|
||||||
|
// Premptively accept new write transaction since we are idle.
|
||||||
|
write_ctrl_ready <= 1'b1;
|
||||||
|
// No need to be waiting for a response while idle.
|
||||||
|
m_axi_bready <= 1'b0;
|
||||||
|
// If we are offered a new transaction then.....
|
||||||
|
if (write_ctrl_valid) begin
|
||||||
|
// Drive all the relevent AXI4 write address channel signals next cycle.
|
||||||
|
m_axi_awaddr[31:0] <= write_addr[31:0];
|
||||||
|
m_axi_awlen[7:0] <= {write_count};
|
||||||
|
m_axi_awvalid <= 1'b1;
|
||||||
|
// If the AXI4 write channel is pre-emptively accepting the transaction...
|
||||||
|
if (m_axi_awready == 1'b1) begin
|
||||||
|
// ...go straight to looking for a transaction response...
|
||||||
|
`DEBUG $display("WRITE TRANSACTION: ADDR: %x LEN: %x @ time %d",write_addr[31:0],write_count,$time);
|
||||||
|
write_addr_state <= WAIT_BVALID;
|
||||||
|
m_axi_bready <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
// ...otherwise wait to get the transaction accepted.
|
||||||
|
write_addr_state <= WAIT_AWREADY;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// WAIT_AWREADY
|
||||||
|
// Waiting for AXI4 slave to accept new write transaction.
|
||||||
|
//
|
||||||
|
WAIT_AWREADY: begin
|
||||||
|
write_ctrl_ready <= 1'b0;
|
||||||
|
// If the AXI4 write channel is accepting the transaction...
|
||||||
|
if (m_axi_awready == 1'b1) begin
|
||||||
|
// ...go to looking for a transaction response...
|
||||||
|
write_addr_state <= WAIT_BVALID;
|
||||||
|
m_axi_bready <= 1'b1;
|
||||||
|
`DEBUG $display("WRITE TRANSACTION: ADDR: %x LEN: %x @ time %d",m_axi_awaddr[31:0],m_axi_awlen[7:0],$time);
|
||||||
|
end else begin
|
||||||
|
// ...otherwise wait to get the trasaction accepted.
|
||||||
|
write_addr_state <= WAIT_AWREADY;
|
||||||
|
end
|
||||||
|
end // case: WAIT_AWREADY
|
||||||
|
//
|
||||||
|
// WAIT_BVALID
|
||||||
|
// Write transaction has been accepted, now waiting for a response to signal it's sucsesful.
|
||||||
|
// Ignoring ID tag for the moment
|
||||||
|
//
|
||||||
|
WAIT_BVALID: begin
|
||||||
|
write_ctrl_ready <= 1'b0;
|
||||||
|
m_axi_awvalid <= 1'b0;
|
||||||
|
// Wait for response channel to signal how write transaction went down....
|
||||||
|
if (m_axi_bvalid == 1'b1) begin
|
||||||
|
if ((m_axi_bresp == `AXI4_RESP_OKAY) || (m_axi_bresp == `AXI4_RESP_EXOKAY)) begin
|
||||||
|
// ....it went well, we are ready to start something new.
|
||||||
|
write_addr_state <= AW_IDLE;
|
||||||
|
m_axi_bready <= 1'b0;
|
||||||
|
write_ctrl_ready <= 1'b1; // Ready to run again as soon as we hit idle.
|
||||||
|
end else if ((m_axi_bresp == `AXI4_RESP_SLVERR) || (m_axi_bresp == `AXI4_RESP_DECERR)) begin
|
||||||
|
// ....things got ugly, retreat to an error stat and wait for intervention.
|
||||||
|
write_addr_state <= AW_ERROR;
|
||||||
|
m_axi_bready <= 1'b0;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
write_addr_state <= WAIT_BVALID;
|
||||||
|
m_axi_bready <= 1'b1;
|
||||||
|
end
|
||||||
|
end // case: WAIT_BVALID
|
||||||
|
//
|
||||||
|
// AW_ERROR
|
||||||
|
// Something bad happened, going to need external intervention to restore a safe state.
|
||||||
|
//
|
||||||
|
AW_ERROR: begin
|
||||||
|
write_ctrl_ready <= 1'b0;
|
||||||
|
write_addr_state <= AW_ERROR;
|
||||||
|
m_axi_awaddr[31:0] <= 32'h0;
|
||||||
|
m_axi_awlen[7:0] <= 8'h0;
|
||||||
|
m_axi_awvalid <= 1'b0;
|
||||||
|
m_axi_bready <= 1'b0;
|
||||||
|
end
|
||||||
|
endcase // case(write_addr_state)
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// AXI Write data channel
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
assign m_axi_wstrb = 8'hff;
|
||||||
|
assign m_axi_wuser = 1'b0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// AXI Write data state machine
|
||||||
|
//
|
||||||
|
always @(posedge aclk)
|
||||||
|
if (areset) begin
|
||||||
|
write_data_state <= AW_IDLE;
|
||||||
|
write_data_count <= 1;
|
||||||
|
enable_data_write <= 1'b0;
|
||||||
|
m_axi_wlast <= 1'b0;
|
||||||
|
|
||||||
|
end else
|
||||||
|
case (write_data_state)
|
||||||
|
//
|
||||||
|
// DW_IDLE
|
||||||
|
// Sit in this state until presented with the control details of a new write transaction.
|
||||||
|
//
|
||||||
|
DW_IDLE: begin
|
||||||
|
write_data_count <= 1;
|
||||||
|
m_axi_wlast <= 1'b0;
|
||||||
|
|
||||||
|
if (write_ctrl_valid && write_ctrl_ready) begin
|
||||||
|
enable_data_write <= 1'b1;
|
||||||
|
if (write_count[7:0] == 8'h0) begin
|
||||||
|
// Single transfer transaction
|
||||||
|
write_data_state <= DW_LAST;
|
||||||
|
m_axi_wlast <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
write_data_state <= DW_RUN;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
write_data_state <= DW_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// DW_RUN
|
||||||
|
//
|
||||||
|
DW_RUN : begin
|
||||||
|
enable_data_write <= 1'b1;
|
||||||
|
m_axi_wlast <= 1'b0;
|
||||||
|
|
||||||
|
if (write_data_valid && m_axi_wready) begin
|
||||||
|
// Single write transfer
|
||||||
|
write_data_count <= write_data_count + 1;
|
||||||
|
|
||||||
|
if (write_data_count == m_axi_awlen[7:0]) begin
|
||||||
|
write_data_state <= DW_LAST;
|
||||||
|
m_axi_wlast <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
write_data_state <= DW_RUN;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
write_data_state <= DW_RUN;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// DW_LAST
|
||||||
|
//
|
||||||
|
DW_LAST: begin
|
||||||
|
if (write_data_valid && m_axi_wready) begin
|
||||||
|
enable_data_write <= 1'b0;
|
||||||
|
write_data_state <= DW_IDLE;
|
||||||
|
m_axi_wlast <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
enable_data_write <= 1'b1;
|
||||||
|
write_data_state <= DW_LAST;
|
||||||
|
m_axi_wlast <= 1'b1;
|
||||||
|
end
|
||||||
|
end // case: DW_LAST
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
write_data_state <= DW_IDLE;
|
||||||
|
|
||||||
|
endcase // case(write_data_state)
|
||||||
|
|
||||||
|
|
||||||
|
assign m_axi_wdata = write_data;
|
||||||
|
assign m_axi_wvalid = enable_data_write && write_data_valid;
|
||||||
|
assign write_data_ready = enable_data_write && m_axi_wready;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// AXI Read address channel
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
assign m_axi_arid = 1'b0;
|
||||||
|
assign m_axi_arsize = 3'h3; // 8 bytes
|
||||||
|
assign m_axi_arburst = `AXI4_BURST_INCR;
|
||||||
|
assign m_axi_arlock = `AXI4_LOCK_NORMAL;
|
||||||
|
assign m_axi_arcache = `AXI4_CACHE_ALLOCATE | `AXI4_CACHE_OTHER_ALLOCATE | `AXI4_CACHE_MODIFIABLE | `AXI4_CACHE_BUFFERABLE;
|
||||||
|
assign m_axi_arprot = `AXI4_PROT_NON_SECURE;
|
||||||
|
assign m_axi_arqos = 4'h0;
|
||||||
|
assign m_axi_arregion = 4'h0;
|
||||||
|
assign m_axi_aruser = 1'b0;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// AXI Read address state machine
|
||||||
|
//
|
||||||
|
always @(posedge aclk)
|
||||||
|
if (areset) begin
|
||||||
|
read_ctrl_ready <= 1'b0;
|
||||||
|
read_addr_state <= AR_IDLE;
|
||||||
|
m_axi_araddr[31:0] <= 32'h0;
|
||||||
|
m_axi_arlen[7:0] <= 8'h0;
|
||||||
|
m_axi_arvalid <= 1'b0;
|
||||||
|
end else
|
||||||
|
case (read_addr_state)
|
||||||
|
//
|
||||||
|
// AR_IDLE
|
||||||
|
// We are ready to accept a new read transaction.
|
||||||
|
//
|
||||||
|
AR_IDLE: begin
|
||||||
|
// Premptively accept new read transaction since we are idle.
|
||||||
|
read_ctrl_ready <= 1'b1;
|
||||||
|
// If we are offered a new transaction then.....
|
||||||
|
if (read_ctrl_valid) begin
|
||||||
|
// Drive all the relevent AXI4 read address channel signals next cycle.
|
||||||
|
m_axi_araddr[31:0] <= read_addr[31:0];
|
||||||
|
m_axi_arlen[7:0] <= {read_count};
|
||||||
|
m_axi_arvalid <= 1'b1;
|
||||||
|
// If the AXI4 read channel is pre-emptively accepting the transaction...
|
||||||
|
if (m_axi_arready == 1'b1) begin
|
||||||
|
// ...go straight to looking for the transaction to complete
|
||||||
|
`DEBUG $display("READ TRANSACTION: ADDR: %x LEN: %x @ time %d",read_addr[31:0],read_count,$time);
|
||||||
|
read_addr_state <= WAIT_READ_DONE;
|
||||||
|
end else begin
|
||||||
|
// ...otherwise wait to get the transaction accepted.
|
||||||
|
read_addr_state <= WAIT_ARREADY;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// WAIT_ARREADY
|
||||||
|
// Waiting for AXI4 slave to accept new read transaction.
|
||||||
|
//
|
||||||
|
WAIT_ARREADY: begin
|
||||||
|
read_ctrl_ready <= 1'b0;
|
||||||
|
// If the AXI4 read channel is accepting the transaction...
|
||||||
|
if (m_axi_arready == 1'b1) begin
|
||||||
|
// ...go to looking for the transaction to complete...
|
||||||
|
read_addr_state <= WAIT_READ_DONE;
|
||||||
|
`DEBUG $display("READ TRANSACTION: ADDR: %x LEN: %x @ time %d",m_axi_araddr[31:0],m_axi_arlen[7:0],$time);
|
||||||
|
end else begin
|
||||||
|
// ...otherwise wait to get the trasaction accepted.
|
||||||
|
read_addr_state <= WAIT_ARREADY;
|
||||||
|
end
|
||||||
|
end // case: WAIT_ARREADY
|
||||||
|
//
|
||||||
|
// WAIT_READ_DONE
|
||||||
|
// Read transaction has been accepted, now waiting for the data transfer to complete
|
||||||
|
// Ignoring ID tag for the moment
|
||||||
|
//
|
||||||
|
WAIT_READ_DONE: begin
|
||||||
|
read_ctrl_ready <= 1'b0;
|
||||||
|
m_axi_arvalid <= 1'b0;
|
||||||
|
// Wait for read transaction to complete
|
||||||
|
if (read_data_state == DR_IDLE) begin
|
||||||
|
// ....it went well, we are ready to start something new.
|
||||||
|
read_addr_state <= AR_IDLE;
|
||||||
|
read_ctrl_ready <= 1'b1; // Ready to run again as soon as we hit idle.
|
||||||
|
end else if (read_data_state == DR_ERROR) begin
|
||||||
|
// ....things got ugly, retreat to an error stat and wait for intervention.
|
||||||
|
read_addr_state <= AR_ERROR;
|
||||||
|
end else begin
|
||||||
|
read_addr_state <= WAIT_READ_DONE;
|
||||||
|
end
|
||||||
|
end // case: WAIT_BVALID
|
||||||
|
//
|
||||||
|
// AR_ERROR
|
||||||
|
// Something bad happened, going to need external intervention to restore a safe state.
|
||||||
|
//
|
||||||
|
AR_ERROR: begin
|
||||||
|
read_ctrl_ready <= 1'b0;
|
||||||
|
read_addr_state <= AR_ERROR;
|
||||||
|
m_axi_araddr[31:0] <= 32'h0;
|
||||||
|
m_axi_arlen[7:0] <= 8'h0;
|
||||||
|
m_axi_arvalid <= 1'b0;
|
||||||
|
end
|
||||||
|
endcase // case(read_addr_state)
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// AXI Read data channel
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// AXI Read data state machine
|
||||||
|
//
|
||||||
|
always @(posedge aclk)
|
||||||
|
if (areset) begin
|
||||||
|
read_data_state <= AR_IDLE;
|
||||||
|
read_data_count <= 0;
|
||||||
|
enable_data_read <= 1'b0;
|
||||||
|
|
||||||
|
end else
|
||||||
|
case (read_data_state)
|
||||||
|
//
|
||||||
|
// DR_IDLE
|
||||||
|
// Sit in this state until presented with the control details of a new read transaction.
|
||||||
|
//
|
||||||
|
DR_IDLE: begin
|
||||||
|
read_data_count <= 0;
|
||||||
|
|
||||||
|
if (read_ctrl_valid && read_ctrl_ready) begin
|
||||||
|
enable_data_read <= 1'b1;
|
||||||
|
read_data_state <= DR_RUN;
|
||||||
|
end else begin
|
||||||
|
read_data_state <= DR_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// DR_RUN
|
||||||
|
// Sit here counting read transfers. If any have error's shift to error state.
|
||||||
|
//
|
||||||
|
DR_RUN : begin
|
||||||
|
enable_data_read <= 1'b1;
|
||||||
|
|
||||||
|
if (read_data_ready && m_axi_rvalid) begin
|
||||||
|
// Single read transfer
|
||||||
|
read_data_count <= read_data_count + 1;
|
||||||
|
if ((m_axi_rresp == `AXI4_RESP_SLVERR) || (m_axi_rresp == `AXI4_RESP_DECERR)) begin
|
||||||
|
if (m_axi_rlast) begin
|
||||||
|
read_data_state <= DR_ERROR;
|
||||||
|
end else begin
|
||||||
|
read_data_state <= DR_WAIT_ERROR;
|
||||||
|
end
|
||||||
|
end else if (m_axi_rlast) begin // Implicitly good response signalled this transfer.
|
||||||
|
if (read_data_count == m_axi_arlen[7:0]) begin
|
||||||
|
read_data_state <= DR_IDLE;
|
||||||
|
end else begin
|
||||||
|
read_data_state <= DR_ERROR;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
read_data_state <= DR_RUN;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
read_data_state <= DR_RUN;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// DR_WAIT_ERROR
|
||||||
|
// Something bad happened, wait for last signalled in this burst
|
||||||
|
//
|
||||||
|
DR_WAIT_ERROR: begin
|
||||||
|
if (read_data_ready && m_axi_rvalid && m_axi_rlast) begin
|
||||||
|
enable_data_read <= 1'b0;
|
||||||
|
read_data_state <= DR_ERROR;
|
||||||
|
end else begin
|
||||||
|
enable_data_read <= 1'b1;
|
||||||
|
read_data_state <= DR_WAIT_ERROR;
|
||||||
|
end
|
||||||
|
end // case: DR_WAIT_ERROR
|
||||||
|
//
|
||||||
|
// DR_ERROR
|
||||||
|
// Something bad happened, going to need external intervention to restore a safe state.
|
||||||
|
//
|
||||||
|
DR_ERROR: begin
|
||||||
|
enable_data_read <= 1'b0;
|
||||||
|
read_data_state <= DR_ERROR;
|
||||||
|
end // case: DR_ERROR
|
||||||
|
|
||||||
|
|
||||||
|
endcase // case(read_data_state)
|
||||||
|
|
||||||
|
|
||||||
|
assign read_data = m_axi_rdata;
|
||||||
|
assign m_axi_rready = enable_data_read && read_data_ready;
|
||||||
|
assign read_data_valid = enable_data_read && m_axi_rvalid;
|
||||||
|
|
||||||
|
endmodule // axi_dma_master
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
module axi_dma_master_tb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
wire aclk; // Global AXI clock
|
||||||
|
wire aresetn; // Global AXI reset, active low.
|
||||||
|
//
|
||||||
|
// AXI Write address channel
|
||||||
|
//
|
||||||
|
wire [0 : 0] m_axi_awid; // Write address ID. This signal is the identification tag for the write address signals
|
||||||
|
wire [31 : 0] m_axi_awaddr; // Write address. The write address gives the address of the first transfer in a write burst
|
||||||
|
wire [7 : 0] m_axi_awlen; // Burst length. The burst length gives the exact number of transfers in a burst.
|
||||||
|
wire [2 : 0] m_axi_awsize; // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
wire [1 : 0] m_axi_awburst; // Burst type. The burst type and the size information, determine how the address is calculated
|
||||||
|
wire [0 : 0] m_axi_awlock; // Lock type. Provides additional information about the atomic characteristics of the transfer.
|
||||||
|
wire [3 : 0] m_axi_awcache; // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
wire [2 : 0] m_axi_awprot; // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
wire [3 : 0] m_axi_awqos; // Quality of Service, QoS. The QoS identifier sent for each write transaction
|
||||||
|
wire [3 : 0] m_axi_awregion; // Region identifier. Permits a single physical interface on a slave to be re-used.
|
||||||
|
wire [0 : 0] m_axi_awuser; // User signal. Optional User-defined signal in the write address channel.
|
||||||
|
wire m_axi_awvalid; // Write address valid. This signal indicates that the channel is signaling valid write addr
|
||||||
|
wire m_axi_awready; // Write address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Write data channel.
|
||||||
|
//
|
||||||
|
wire [63 : 0] m_axi_wdata; // Write data
|
||||||
|
wire [7 : 0] m_axi_wstrb; // Write strobes. This signal indicates which byte lanes hold valid data.
|
||||||
|
wire m_axi_wlast; // Write last. This signal indicates the last transfer in a write burst
|
||||||
|
wire [0 : 0] m_axi_wuser; // User signal. Optional User-defined signal in the write data channel.
|
||||||
|
wire m_axi_wvalid; // Write valid. This signal indicates that valid write data and strobes are available.
|
||||||
|
wire m_axi_wready; // Write ready. This signal indicates that the slave can accept the write data.
|
||||||
|
//
|
||||||
|
// AXI Write response channel signals
|
||||||
|
//
|
||||||
|
wire [0 : 0] m_axi_bid; // Response ID tag. This signal is the ID tag of the write response.
|
||||||
|
wire [1 : 0] m_axi_bresp; // Write response. This signal indicates the status of the write transaction.
|
||||||
|
wire [0 : 0] m_axi_buser; // User signal. Optional User-defined signal in the write response channel.
|
||||||
|
wire m_axi_bvalid; // Write response valid. This signal indicates that the channel is signaling a valid response
|
||||||
|
wire m_axi_bready; // Response ready. This signal indicates that the master can accept a write response
|
||||||
|
//
|
||||||
|
// AXI Read address channel
|
||||||
|
//
|
||||||
|
wire [0 : 0] m_axi_arid; // Read address ID. This signal is the identification tag for the read address group of signals
|
||||||
|
wire [31 : 0] m_axi_araddr; // Read address. The read address gives the address of the first transfer in a read burst
|
||||||
|
wire [7 : 0] m_axi_arlen; // Burst length. This signal indicates the exact number of transfers in a burst.
|
||||||
|
wire [2 : 0] m_axi_arsize; // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
wire [1 : 0] m_axi_arburst; // Burst type. The burst type and the size information determine how the address for each transfer
|
||||||
|
wire [0 : 0] m_axi_arlock; // Lock type. This signal provides additional information about the atomic characteristics
|
||||||
|
wire [3 : 0] m_axi_arcache; // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
wire [2 : 0] m_axi_arprot; // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
wire [3 : 0] m_axi_arqos; // Quality of Service, QoS. QoS identifier sent for each read transaction.
|
||||||
|
wire [3 : 0] m_axi_arregion; // Region identifier. Permits a single physical interface on a slave to be re-used
|
||||||
|
wire [0 : 0] m_axi_aruser; // User signal. Optional User-defined signal in the read address channel.
|
||||||
|
wire m_axi_arvalid; // Read address valid. This signal indicates that the channel is signaling valid read addr
|
||||||
|
wire m_axi_arready; // Read address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Read data channel
|
||||||
|
//
|
||||||
|
wire [0 : 0] m_axi_rid; // Read ID tag. This signal is the identification tag for the read data group of signals
|
||||||
|
wire [63 : 0] m_axi_rdata; // Read data.
|
||||||
|
wire [1 : 0] m_axi_rresp; // Read response. This signal indicates the status of the read transfer
|
||||||
|
wire m_axi_rlast; // Read last. This signal indicates the last transfer in a read burst.
|
||||||
|
wire [0 : 0] m_axi_ruser; // User signal. Optional User-defined signal in the read data channel.
|
||||||
|
wire m_axi_rvalid; // Read valid. This signal indicates that the channel is signaling the required read data.
|
||||||
|
wire m_axi_rready; // Read ready. This signal indicates that the master can accept the read data and response
|
||||||
|
//
|
||||||
|
// DMA interface for Write transaction
|
||||||
|
//
|
||||||
|
wire [31:0] write_addr; // Byte address for start of write transaction (should be 64bit alligned)
|
||||||
|
wire [3:0] write_count; // Count of 64 words to write.
|
||||||
|
wire write_ctrl_valid;
|
||||||
|
wire write_ctrl_ready;
|
||||||
|
wire [63:0] write_data;
|
||||||
|
wire write_data_valid;
|
||||||
|
wire write_data_ready;
|
||||||
|
//
|
||||||
|
// DMA interface for Read
|
||||||
|
//
|
||||||
|
wire [31:0] read_addr; // Byte address for start of read transaction (should be 64bit alligned)
|
||||||
|
wire [3:0] read_count; // Count of 64 words to read.
|
||||||
|
wire read_ctrl_valid;
|
||||||
|
wire read_ctrl_ready;
|
||||||
|
wire [63:0] read_data;
|
||||||
|
wire read_data_valid;
|
||||||
|
wire read_data_ready;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
axi_dma_master axi_dma_master_i1
|
||||||
|
(
|
||||||
|
.aclk(s_aclk), // input s_aclk
|
||||||
|
.aresetn(s_aresetn), // input s_aresetn
|
||||||
|
//
|
||||||
|
.s_axi_awid(s_axi_awid), // input [0 : 0] s_axi_awid
|
||||||
|
.s_axi_awaddr(s_axi_awaddr), // input [31 : 0] s_axi_awaddr
|
||||||
|
.s_axi_awlen(s_axi_awlen), // input [7 : 0] s_axi_awlen
|
||||||
|
.s_axi_awsize(s_axi_awsize), // input [2 : 0] s_axi_awsize
|
||||||
|
.s_axi_awburst(s_axi_awburst), // input [1 : 0] s_axi_awburst
|
||||||
|
.s_axi_awvalid(s_axi_awvalid), // input s_axi_awvalid
|
||||||
|
.s_axi_awready(s_axi_awready), // output s_axi_awready
|
||||||
|
//
|
||||||
|
.s_axi_wdata(s_axi_wdata), // input [63 : 0] s_axi_wdata
|
||||||
|
.s_axi_wstrb(s_axi_wstrb), // input [7 : 0] s_axi_wstrb
|
||||||
|
.s_axi_wlast(s_axi_wlast), // input s_axi_wlast
|
||||||
|
.s_axi_wvalid(s_axi_wvalid), // input s_axi_wvalid
|
||||||
|
.s_axi_wready(s_axi_wready), // output s_axi_wready
|
||||||
|
//
|
||||||
|
.s_axi_bid(s_axi_bid), // output [0 : 0] s_axi_bid
|
||||||
|
.s_axi_bresp(s_axi_bresp), // output [1 : 0] s_axi_bresp
|
||||||
|
.s_axi_bvalid(s_axi_bvalid), // output s_axi_bvalid
|
||||||
|
.s_axi_bready(s_axi_bready), // input s_axi_bready
|
||||||
|
//
|
||||||
|
.s_axi_arid(s_axi_arid), // input [0 : 0] s_axi_arid
|
||||||
|
.s_axi_araddr(s_axi_araddr), // input [31 : 0] s_axi_araddr
|
||||||
|
.s_axi_arlen(s_axi_arlen), // input [7 : 0] s_axi_arlen
|
||||||
|
.s_axi_arsize(s_axi_arsize), // input [2 : 0] s_axi_arsize
|
||||||
|
.s_axi_arburst(s_axi_arburst), // input [1 : 0] s_axi_arburst
|
||||||
|
.s_axi_arvalid(s_axi_arvalid), // input s_axi_arvalid
|
||||||
|
.s_axi_arready(s_axi_arready), // output s_axi_arready
|
||||||
|
//
|
||||||
|
.s_axi_rid(s_axi_rid), // output [0 : 0] s_axi_rid
|
||||||
|
.s_axi_rdata(s_axi_rdata), // output [63 : 0] s_axi_rdata
|
||||||
|
.s_axi_rresp(s_axi_rresp), // output [1 : 0] s_axi_rresp
|
||||||
|
.s_axi_rlast(s_axi_rlast), // output s_axi_rlast
|
||||||
|
.s_axi_rvalid(s_axi_rvalid), // output s_axi_rvalid
|
||||||
|
.s_axi_rready(s_axi_rready) // input s_axi_rready
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
axi4_bram_1kx64 axi4_bram_1kx64_i1
|
||||||
|
(
|
||||||
|
.s_aclk(s_aclk), // input s_aclk
|
||||||
|
.s_aresetn(s_aresetn), // input s_aresetn
|
||||||
|
.s_axi_awid(s_axi_awid), // input [0 : 0] s_axi_awid
|
||||||
|
.s_axi_awaddr(s_axi_awaddr), // input [31 : 0] s_axi_awaddr
|
||||||
|
.s_axi_awlen(s_axi_awlen), // input [7 : 0] s_axi_awlen
|
||||||
|
.s_axi_awsize(s_axi_awsize), // input [2 : 0] s_axi_awsize
|
||||||
|
.s_axi_awburst(s_axi_awburst), // input [1 : 0] s_axi_awburst
|
||||||
|
.s_axi_awvalid(s_axi_awvalid), // input s_axi_awvalid
|
||||||
|
.s_axi_awready(s_axi_awready), // output s_axi_awready
|
||||||
|
.s_axi_wdata(s_axi_wdata), // input [63 : 0] s_axi_wdata
|
||||||
|
.s_axi_wstrb(s_axi_wstrb), // input [7 : 0] s_axi_wstrb
|
||||||
|
.s_axi_wlast(s_axi_wlast), // input s_axi_wlast
|
||||||
|
.s_axi_wvalid(s_axi_wvalid), // input s_axi_wvalid
|
||||||
|
.s_axi_wready(s_axi_wready), // output s_axi_wready
|
||||||
|
.s_axi_bid(s_axi_bid), // output [0 : 0] s_axi_bid
|
||||||
|
.s_axi_bresp(s_axi_bresp), // output [1 : 0] s_axi_bresp
|
||||||
|
.s_axi_bvalid(s_axi_bvalid), // output s_axi_bvalid
|
||||||
|
.s_axi_bready(s_axi_bready), // input s_axi_bready
|
||||||
|
.s_axi_arid(s_axi_arid), // input [0 : 0] s_axi_arid
|
||||||
|
.s_axi_araddr(s_axi_araddr), // input [31 : 0] s_axi_araddr
|
||||||
|
.s_axi_arlen(s_axi_arlen), // input [7 : 0] s_axi_arlen
|
||||||
|
.s_axi_arsize(s_axi_arsize), // input [2 : 0] s_axi_arsize
|
||||||
|
.s_axi_arburst(s_axi_arburst), // input [1 : 0] s_axi_arburst
|
||||||
|
.s_axi_arvalid(s_axi_arvalid), // input s_axi_arvalid
|
||||||
|
.s_axi_arready(s_axi_arready), // output s_axi_arready
|
||||||
|
.s_axi_rid(s_axi_rid), // output [0 : 0] s_axi_rid
|
||||||
|
.s_axi_rdata(s_axi_rdata), // output [63 : 0] s_axi_rdata
|
||||||
|
.s_axi_rresp(s_axi_rresp), // output [1 : 0] s_axi_rresp
|
||||||
|
.s_axi_rlast(s_axi_rlast), // output s_axi_rlast
|
||||||
|
.s_axi_rvalid(s_axi_rvalid), // output s_axi_rvalid
|
||||||
|
.s_axi_rready(s_axi_rready) // input s_axi_rready
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule // axi_dma_master_tb
|
||||||
@@ -0,0 +1,816 @@
|
|||||||
|
|
||||||
|
//
|
||||||
|
// There are various obligations put on this code not present in regular BRAM based FIFO's
|
||||||
|
//
|
||||||
|
// 1) Bursts are way more efficient, use local small FIFO's to interact with DRAM
|
||||||
|
// 2) Never cross a 4KByte address boundry within a single transaction, this is an AXI4 rule.
|
||||||
|
// 3) 2^SIZE must be greater than 4KB so that the 4KByte page protection also deals with FIFO wrap corner case.
|
||||||
|
//
|
||||||
|
module axi_dram_fifo
|
||||||
|
// NOTE: SIZE is log2 of size of FIFO buffer in bytes. i.e 13 for 8KBytes which is 1kx64
|
||||||
|
#(parameter BASE=0, SIZE=16, TIMEOUT=64)
|
||||||
|
(
|
||||||
|
input bus_clk,
|
||||||
|
input bus_reset,
|
||||||
|
input clear,
|
||||||
|
input dram_clk,
|
||||||
|
input dram_reset,
|
||||||
|
//
|
||||||
|
// AXI Write address channel
|
||||||
|
//
|
||||||
|
output [0 : 0] m_axi_awid, // Write address ID. This signal is the identification tag for the write address signals
|
||||||
|
output [31 : 0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst
|
||||||
|
output [7 : 0] m_axi_awlen, // Burst length. The burst length gives the exact number of transfers in a burst.
|
||||||
|
output [2 : 0] m_axi_awsize, // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
output [1 : 0] m_axi_awburst, // Burst type. The burst type and the size information, determine how the address is calculated
|
||||||
|
output [0 : 0] m_axi_awlock, // Lock type. Provides additional information about the atomic characteristics of the transfer.
|
||||||
|
output [3 : 0] m_axi_awcache, // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
output [2 : 0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
output [3 : 0] m_axi_awqos, // Quality of Service, QoS. The QoS identifier sent for each write transaction
|
||||||
|
output [3 : 0] m_axi_awregion, // Region identifier. Permits a single physical interface on a slave to be re-used.
|
||||||
|
output [0 : 0] m_axi_awuser, // User signal. Optional User-defined signal in the write address channel.
|
||||||
|
output m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr
|
||||||
|
input m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Write data channel.
|
||||||
|
//
|
||||||
|
output [63 : 0] m_axi_wdata, // Write data
|
||||||
|
output [7 : 0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data.
|
||||||
|
output m_axi_wlast, // Write last. This signal indicates the last transfer in a write burst
|
||||||
|
output [0 : 0] m_axi_wuser, // User signal. Optional User-defined signal in the write data channel.
|
||||||
|
output m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available.
|
||||||
|
input m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data.
|
||||||
|
//
|
||||||
|
// AXI Write response channel signals
|
||||||
|
//
|
||||||
|
input [0 : 0] m_axi_bid, // Response ID tag. This signal is the ID tag of the write response.
|
||||||
|
input [1 : 0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction.
|
||||||
|
input [0 : 0] m_axi_buser, // User signal. Optional User-defined signal in the write response channel.
|
||||||
|
input m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response
|
||||||
|
output m_axi_bready, // Response ready. This signal indicates that the master can accept a write response
|
||||||
|
//
|
||||||
|
// AXI Read address channel
|
||||||
|
//
|
||||||
|
output [0 : 0] m_axi_arid, // Read address ID. This signal is the identification tag for the read address group of signals
|
||||||
|
output [31 : 0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst
|
||||||
|
output [7 : 0] m_axi_arlen, // Burst length. This signal indicates the exact number of transfers in a burst.
|
||||||
|
output [2 : 0] m_axi_arsize, // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
output [1 : 0] m_axi_arburst, // Burst type. The burst type and the size information determine how the address for each transfer
|
||||||
|
output [0 : 0] m_axi_arlock, // Lock type. This signal provides additional information about the atomic characteristics
|
||||||
|
output [3 : 0] m_axi_arcache, // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
output [2 : 0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
output [3 : 0] m_axi_arqos, // Quality of Service, QoS. QoS identifier sent for each read transaction.
|
||||||
|
output [3 : 0] m_axi_arregion, // Region identifier. Permits a single physical interface on a slave to be re-used
|
||||||
|
output [0 : 0] m_axi_aruser, // User signal. Optional User-defined signal in the read address channel.
|
||||||
|
output m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr
|
||||||
|
input m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Read data channel
|
||||||
|
//
|
||||||
|
input [0 : 0] m_axi_rid, // Read ID tag. This signal is the identification tag for the read data group of signals
|
||||||
|
input [63 : 0] m_axi_rdata, // Read data.
|
||||||
|
input [1 : 0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer
|
||||||
|
input m_axi_rlast, // Read last. This signal indicates the last transfer in a read burst.
|
||||||
|
input [0 : 0] m_axi_ruser, // User signal. Optional User-defined signal in the read data channel.
|
||||||
|
input m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data.
|
||||||
|
output m_axi_rready, // Read ready. This signal indicates that the master can accept the read data and response
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI stream input
|
||||||
|
//
|
||||||
|
input [63:0] i_tdata,
|
||||||
|
input i_tlast,
|
||||||
|
input i_tvalid,
|
||||||
|
output i_tready,
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI Stream output
|
||||||
|
//
|
||||||
|
output [63:0] o_tdata,
|
||||||
|
output o_tlast,
|
||||||
|
output o_tvalid,
|
||||||
|
input o_tready,
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
input [15:0] supress_threshold,
|
||||||
|
input supress_enable,
|
||||||
|
//
|
||||||
|
// Debug Bus
|
||||||
|
//
|
||||||
|
output [197:0] debug
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// We are only solving for width 64bits here, since it's our standard CHDR quanta
|
||||||
|
//
|
||||||
|
localparam WIDTH=64;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Input side declarations
|
||||||
|
//
|
||||||
|
localparam INPUT_IDLE = 0;
|
||||||
|
localparam INPUT1 = 1;
|
||||||
|
localparam INPUT2 = 2;
|
||||||
|
localparam INPUT3 = 3;
|
||||||
|
localparam INPUT4 = 4;
|
||||||
|
localparam INPUT5 = 5;
|
||||||
|
localparam INPUT6 = 6;
|
||||||
|
|
||||||
|
reg [2:0] input_state;
|
||||||
|
reg input_timeout_triggered;
|
||||||
|
reg input_timeout_reset;
|
||||||
|
reg [8:0] input_timeout_count;
|
||||||
|
reg [31:0] write_addr;
|
||||||
|
reg write_ctrl_valid;
|
||||||
|
wire write_ctrl_ready;
|
||||||
|
reg [7:0] write_count;
|
||||||
|
reg update_write;
|
||||||
|
wire [63:0] write_data;
|
||||||
|
wire write_data_valid;
|
||||||
|
wire write_data_ready;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Output side declarations
|
||||||
|
//
|
||||||
|
localparam OUTPUT_IDLE = 0;
|
||||||
|
localparam OUTPUT1 = 1;
|
||||||
|
localparam OUTPUT2 = 2;
|
||||||
|
localparam OUTPUT3 = 3;
|
||||||
|
localparam OUTPUT4 = 4;
|
||||||
|
localparam OUTPUT5 = 5;
|
||||||
|
localparam OUTPUT6 = 6;
|
||||||
|
|
||||||
|
reg [2:0] output_state;
|
||||||
|
reg output_timeout_triggered;
|
||||||
|
reg output_timeout_reset;
|
||||||
|
reg [8:0] output_timeout_count;
|
||||||
|
reg [31:0] read_addr;
|
||||||
|
reg read_ctrl_valid;
|
||||||
|
wire read_ctrl_ready;
|
||||||
|
reg [7:0] read_count;
|
||||||
|
reg update_read;
|
||||||
|
wire [63:0] read_data;
|
||||||
|
wire read_data_valid;
|
||||||
|
wire read_data_ready;
|
||||||
|
|
||||||
|
// Track main FIFO active size.
|
||||||
|
reg [SIZE-3:0] space, occupied;
|
||||||
|
wire [11:0] input_page_boundry, output_page_boundry;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Buffer input in FIFO's. Embeded tlast signal using ESCape code.
|
||||||
|
//
|
||||||
|
wire [WIDTH-1:0] i_tdata_i0;
|
||||||
|
wire i_tvalid_i0, i_tready_i0, i_tlast_i0;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] i_tdata_i1;
|
||||||
|
wire i_tvalid_i1, i_tready_i1;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] i_tdata_i2;
|
||||||
|
wire i_tvalid_i2, i_tready_i2;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] i_tdata_input;
|
||||||
|
wire i_tvalid_input, i_tready_input;
|
||||||
|
wire [15:0] space_input, occupied_input;
|
||||||
|
reg [15:0] space_input_reg;
|
||||||
|
reg supress_reads;
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// DEBUG
|
||||||
|
///////////////////////////
|
||||||
|
wire [31:0] debug_axi_dma_master;
|
||||||
|
|
||||||
|
//assign debug = {18'h0, input_state[2:0], output_state[2:0], debug_axi_dma_master[7:0]};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
wire write_in, read_in, empty_in, full_in;
|
||||||
|
assign i_tready = ~full_in;
|
||||||
|
assign write_in = i_tvalid & i_tready;
|
||||||
|
assign i_tvalid_i0 = ~empty_in;
|
||||||
|
assign read_in = i_tvalid_i0 & i_tready_i0;
|
||||||
|
wire [6:0] discard_i0;
|
||||||
|
|
||||||
|
fifo_short_2clk fifo_short_2clk_i0
|
||||||
|
(.rst(bus_reset),
|
||||||
|
.wr_clk(bus_clk),
|
||||||
|
.din({7'h0,i_tlast,i_tdata}), // input [71 : 0] din
|
||||||
|
.wr_en(write_in), // input wr_en
|
||||||
|
.full(full_in), // output full
|
||||||
|
.wr_data_count(), // output [9 : 0] wr_data_count
|
||||||
|
|
||||||
|
.rd_clk(dram_clk), // input rd_clk
|
||||||
|
.dout({discard_i0,i_tlast_i0,i_tdata_i0}), // output [71 : 0] dout
|
||||||
|
.rd_en(read_in), // input rd_en
|
||||||
|
.empty(empty_in), // output empty
|
||||||
|
.rd_data_count() // output [9 : 0] rd_data_count
|
||||||
|
);
|
||||||
|
|
||||||
|
axi_embed_tlast axi_embed_tlast_i
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(i_tdata_i0),
|
||||||
|
.i_tlast(i_tlast_i0),
|
||||||
|
.i_tvalid(i_tvalid_i0),
|
||||||
|
.i_tready(i_tready_i0),
|
||||||
|
//
|
||||||
|
.o_tdata(i_tdata_i1),
|
||||||
|
.o_tvalid(i_tvalid_i1),
|
||||||
|
.o_tready(i_tready_i1)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
axi_fast_fifo #(.WIDTH(WIDTH)) fast_fifo_i0
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(i_tdata_i1),
|
||||||
|
.i_tvalid(i_tvalid_i1),
|
||||||
|
.i_tready(i_tready_i1),
|
||||||
|
//
|
||||||
|
.o_tdata(i_tdata_i2),
|
||||||
|
.o_tvalid(i_tvalid_i2),
|
||||||
|
.o_tready(i_tready_i2)
|
||||||
|
);
|
||||||
|
|
||||||
|
axi_fifo #(.WIDTH(WIDTH),.SIZE(12)) fifo_i1
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(i_tdata_i2),
|
||||||
|
.i_tvalid(i_tvalid_i2),
|
||||||
|
.i_tready(i_tready_i2),
|
||||||
|
//
|
||||||
|
.o_tdata(i_tdata_input),
|
||||||
|
.o_tvalid(i_tvalid_input),
|
||||||
|
.o_tready(i_tready_input),
|
||||||
|
//
|
||||||
|
.space(space_input),
|
||||||
|
.occupied(occupied_input)
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Monitor occupied_input to deduce when DRAM FIFO is running short of bandwidth and there is a danger of backpressure
|
||||||
|
// passing upstream of the DRAM FIFO.
|
||||||
|
// In this situation supress read requests to the DRAM FIFO so that more bandwidth is available to writes.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
begin
|
||||||
|
space_input_reg <= space_input;
|
||||||
|
if ((space_input_reg < supress_threshold[15:0]) && supress_enable)
|
||||||
|
supress_reads <= 1'b1;
|
||||||
|
else
|
||||||
|
supress_reads <= 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
//
|
||||||
|
// Buffer output in 32entry FIFO's. Extract embeded tlast signal.
|
||||||
|
//
|
||||||
|
wire [WIDTH-1:0] o_tdata_output;
|
||||||
|
wire o_tvalid_output, o_tready_output;
|
||||||
|
wire [15:0] space_output, occupied_output;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] o_tdata_i0;
|
||||||
|
wire o_tvalid_i0, o_tready_i0;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] o_tdata_i1;
|
||||||
|
wire o_tvalid_i1, o_tready_i1, o_tlast_i1;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] o_tdata_i2;
|
||||||
|
wire o_tvalid_i2, o_tready_i2, o_tlast_i2;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] o_tdata_i3;
|
||||||
|
wire o_tvalid_i3, o_tready_i3, o_tlast_i3;
|
||||||
|
|
||||||
|
wire checksum_error;
|
||||||
|
|
||||||
|
|
||||||
|
axi_fifo #(.WIDTH(WIDTH),.SIZE(9)) fifo_i2
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(o_tdata_output),
|
||||||
|
.i_tvalid(o_tvalid_output),
|
||||||
|
.i_tready(o_tready_output),
|
||||||
|
//
|
||||||
|
.o_tdata(o_tdata_i0),
|
||||||
|
.o_tvalid(o_tvalid_i0),
|
||||||
|
.o_tready(o_tready_i0),
|
||||||
|
//
|
||||||
|
.space(space_output),
|
||||||
|
.occupied(occupied_output)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Place FLops straight after SRAM read access for timing.
|
||||||
|
axi_fast_fifo #(.WIDTH(WIDTH)) fast_fifo_i1
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(o_tdata_i0),
|
||||||
|
.i_tvalid(o_tvalid_i0),
|
||||||
|
.i_tready(o_tready_i0),
|
||||||
|
//
|
||||||
|
.o_tdata(o_tdata_i1),
|
||||||
|
.o_tvalid(o_tvalid_i1),
|
||||||
|
.o_tready(o_tready_i1 && ~supress_reads)
|
||||||
|
);
|
||||||
|
|
||||||
|
// More pipeline flops to meet timing
|
||||||
|
axi_fast_fifo #(.WIDTH(WIDTH)) fast_fifo_i2
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(o_tdata_i1),
|
||||||
|
.i_tvalid(o_tvalid_i1 && ~supress_reads),
|
||||||
|
.i_tready(o_tready_i1),
|
||||||
|
//
|
||||||
|
.o_tdata(o_tdata_i2),
|
||||||
|
.o_tvalid(o_tvalid_i2),
|
||||||
|
.o_tready(o_tready_i2)
|
||||||
|
);
|
||||||
|
|
||||||
|
axi_fast_extract_tlast axi_fast_extract_tlast_i0
|
||||||
|
(
|
||||||
|
.clk(dram_clk),
|
||||||
|
.reset(dram_reset),
|
||||||
|
.clear(clear),
|
||||||
|
//
|
||||||
|
.i_tdata(o_tdata_i2),
|
||||||
|
.i_tvalid(o_tvalid_i2),
|
||||||
|
.i_tready(o_tready_i2),
|
||||||
|
//
|
||||||
|
.o_tdata(o_tdata_i3),
|
||||||
|
.o_tlast(o_tlast_i3),
|
||||||
|
.o_tvalid(o_tvalid_i3),
|
||||||
|
.o_tready(o_tready_i3)
|
||||||
|
//
|
||||||
|
// .checksum_error_reg(checksum_error)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
wire write_out, read_out, empty_out, full_out;
|
||||||
|
assign o_tready_i3 = ~full_out;
|
||||||
|
assign write_out = o_tvalid_i3 & o_tready_i3;
|
||||||
|
assign o_tvalid = ~empty_out;
|
||||||
|
assign read_out = o_tvalid & o_tready;
|
||||||
|
wire [6:0] discard_i1;
|
||||||
|
|
||||||
|
fifo_short_2clk fifo_short_2clk_i1
|
||||||
|
(
|
||||||
|
.rst(bus_reset),
|
||||||
|
.wr_clk(dram_clk),
|
||||||
|
.din({7'h0,o_tlast_i3,o_tdata_i3}), // input [71 : 0] din
|
||||||
|
.wr_en(write_out), // input wr_en
|
||||||
|
.full(full_out), // output full
|
||||||
|
.wr_data_count(), // output [9 : 0] wr_data_count
|
||||||
|
|
||||||
|
.rd_clk(bus_clk), // input rd_clk
|
||||||
|
.dout({discard_i1,o_tlast,o_tdata}), // output [71 : 0] dout
|
||||||
|
.rd_en(read_out), // input rd_en
|
||||||
|
.empty(empty_out), // output empty
|
||||||
|
.rd_data_count() // output [9 : 0] rd_data_count
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Simple input timeout counter for now.
|
||||||
|
// Timeout count only increments when there is some data waiting to be written.
|
||||||
|
//
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
if (dram_reset | clear) begin
|
||||||
|
input_timeout_count <= 0;
|
||||||
|
input_timeout_triggered <= 1'b0;
|
||||||
|
end else if (input_timeout_reset) begin
|
||||||
|
input_timeout_count <= 0;
|
||||||
|
input_timeout_triggered <= 1'b0;
|
||||||
|
end else if (input_timeout_count == TIMEOUT) begin
|
||||||
|
input_timeout_triggered <= 1'b1;
|
||||||
|
end else if (input_state == INPUT_IDLE) begin
|
||||||
|
input_timeout_count <= input_timeout_count + (occupied_input != 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait for 16 entries in input FIFO to trigger DRAM write burst.
|
||||||
|
// Timeout can also trigger burst so fragments of data are not left to rot in the input FIFO.
|
||||||
|
// Also if enough data is present in the input FIFO to complete a burst upto the edge
|
||||||
|
// of a 4KByte page then immediately start the burst.
|
||||||
|
//
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
if (dram_reset | clear) begin
|
||||||
|
input_state <= INPUT_IDLE;
|
||||||
|
write_addr[31:SIZE] <= BASE >> SIZE;
|
||||||
|
write_addr[SIZE-1:0] <= 0;
|
||||||
|
input_timeout_reset <= 1'b0;
|
||||||
|
write_ctrl_valid <= 1'b0;
|
||||||
|
write_count <= 8'd0;
|
||||||
|
update_write <= 1'b0;
|
||||||
|
end else
|
||||||
|
case (input_state)
|
||||||
|
//
|
||||||
|
// INPUT_IDLE.
|
||||||
|
// To start an input transfer to DRAM need:
|
||||||
|
// 1) Space in the DRAM FIFO
|
||||||
|
// and either
|
||||||
|
// 2) 256 entrys in the input FIFO
|
||||||
|
// or
|
||||||
|
// 3) Timeout waiting for more data.
|
||||||
|
//
|
||||||
|
INPUT_IDLE: begin
|
||||||
|
write_ctrl_valid <= 1'b0;
|
||||||
|
update_write <= 1'b0;
|
||||||
|
if (space > 255) begin // Space in the DRAM FIFO
|
||||||
|
if (occupied_input > 255) begin // 256 or more entrys in input FIFO
|
||||||
|
input_state <= INPUT1;
|
||||||
|
input_timeout_reset <= 1'b1;
|
||||||
|
end else if (input_timeout_triggered) begin // input FIFO timeout waiting for new data.
|
||||||
|
input_state <= INPUT2;
|
||||||
|
input_timeout_reset <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
input_timeout_reset <= 1'b0;
|
||||||
|
input_state <= INPUT_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
input_timeout_reset <= 1'b0;
|
||||||
|
input_state <= INPUT_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// INPUT1.
|
||||||
|
// Caused by input FIFO reaching 256 entries.
|
||||||
|
// Request write burst of lesser of:
|
||||||
|
// 1) Entrys until page boundry crossed
|
||||||
|
// 2) 256.
|
||||||
|
//
|
||||||
|
INPUT1: begin
|
||||||
|
write_count <= (input_page_boundry < 255) ? input_page_boundry[7:0] : 8'd255;
|
||||||
|
write_ctrl_valid <= 1'b1;
|
||||||
|
if (write_ctrl_ready)
|
||||||
|
input_state <= INPUT4; // Pre-emptive ACK
|
||||||
|
else
|
||||||
|
input_state <= INPUT3; // Wait for ACK
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// INPUT2.
|
||||||
|
// Caused by timeout of input FIFO. (occupied_input was implicitly less than 256 last cycle)
|
||||||
|
// Request write burst of lesser of:
|
||||||
|
// 1) Entries until page boundry crossed
|
||||||
|
// 2) Entries in input FIFO
|
||||||
|
//
|
||||||
|
INPUT2: begin
|
||||||
|
write_count <= (input_page_boundry < ({3'h0,occupied_input[8:0]} - 12'd1)) ? input_page_boundry[7:0] : (occupied_input[8:0] - 7'd1);
|
||||||
|
write_ctrl_valid <= 1'b1;
|
||||||
|
if (write_ctrl_ready)
|
||||||
|
input_state <= INPUT4; // Pre-emptive ACK
|
||||||
|
else
|
||||||
|
input_state <= INPUT3; // Wait for ACK
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// INPUT3.
|
||||||
|
// Wait in this state for AXI4_DMA engine to accept transaction.
|
||||||
|
//
|
||||||
|
INPUT3: begin
|
||||||
|
if (write_ctrl_ready) begin
|
||||||
|
write_ctrl_valid <= 1'b0;
|
||||||
|
input_state <= INPUT4; // ACK
|
||||||
|
end else begin
|
||||||
|
write_ctrl_valid <= 1'b1;
|
||||||
|
input_state <= INPUT3; // Wait for ACK
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// INPUT4.
|
||||||
|
// Wait here until write_ctrl_ready_deasserts.
|
||||||
|
// This is important as the next time it asserts we know that a write response was receieved.
|
||||||
|
INPUT4: begin
|
||||||
|
write_ctrl_valid <= 1'b0;
|
||||||
|
if (!write_ctrl_ready)
|
||||||
|
input_state <= INPUT5; // Move on
|
||||||
|
else
|
||||||
|
input_state <= INPUT4; // Wait for deassert
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// INPUT5.
|
||||||
|
// Transaction has been accepted by AXI4 DMA engine. Now we wait for the re-assertion
|
||||||
|
// of write_ctrl_ready which signals that the AXI4 DMA engine has receieved a response
|
||||||
|
// for the whole write transaction and we assume that this means it is commited to DRAM.
|
||||||
|
// We are now free to update write_addr pointer and go back to idle state.
|
||||||
|
//
|
||||||
|
INPUT5: begin
|
||||||
|
write_ctrl_valid <= 1'b0;
|
||||||
|
if (write_ctrl_ready) begin
|
||||||
|
write_addr[SIZE-1:0] <= write_addr[SIZE-1:0] + ((write_count + 1) << 3);
|
||||||
|
input_state <= INPUT6;
|
||||||
|
update_write <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
input_state <= INPUT5;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// INPUT6:
|
||||||
|
// Need to let space update before looking if there's more to do.
|
||||||
|
//
|
||||||
|
INPUT6: begin
|
||||||
|
input_state <= INPUT_IDLE;
|
||||||
|
update_write <= 1'b0;
|
||||||
|
end
|
||||||
|
// Ass covering.
|
||||||
|
default: input_state <= INPUT_IDLE;
|
||||||
|
|
||||||
|
endcase // case(input_state)
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Simple output timeout counter for now
|
||||||
|
//
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
if (dram_reset | clear) begin
|
||||||
|
output_timeout_count <= 0;
|
||||||
|
output_timeout_triggered <= 1'b0;
|
||||||
|
end else if (output_timeout_reset) begin
|
||||||
|
output_timeout_count <= 0;
|
||||||
|
output_timeout_triggered <= 1'b0;
|
||||||
|
end else if (output_timeout_count == TIMEOUT) begin
|
||||||
|
output_timeout_triggered <= 1'b1;
|
||||||
|
end else if (output_state == OUTPUT_IDLE) begin
|
||||||
|
output_timeout_count <= output_timeout_count + (occupied != 0 );
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait for 64 entries in main FIFO to trigger DRAM read burst.
|
||||||
|
// Timeout can also trigger burst so fragments of data are not left to rot in the main FIFO.
|
||||||
|
// Also if enough data is present in the main FIFO to complete a burst upto the edge
|
||||||
|
// of a 4KByte page then immediately start the burst.
|
||||||
|
//
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
if (dram_reset | clear) begin
|
||||||
|
output_state <= OUTPUT_IDLE;
|
||||||
|
read_addr[31:SIZE] <= BASE >> SIZE;
|
||||||
|
read_addr[SIZE-1:0] <= 0;
|
||||||
|
output_timeout_reset <= 1'b0;
|
||||||
|
read_ctrl_valid <= 1'b0;
|
||||||
|
read_count <= 8'd0;
|
||||||
|
update_read <= 1'b0;
|
||||||
|
end else
|
||||||
|
case (output_state)
|
||||||
|
//
|
||||||
|
// OUTPUT_IDLE.
|
||||||
|
// To start an output tranfer from DRAM
|
||||||
|
// 1) Space in the small output FIFO
|
||||||
|
// and either
|
||||||
|
// 2) 256 entrys in the DRAM FIFO
|
||||||
|
// or
|
||||||
|
// 3) Timeout waiting for more data.
|
||||||
|
//
|
||||||
|
OUTPUT_IDLE: begin
|
||||||
|
read_ctrl_valid <= 1'b0;
|
||||||
|
update_read <= 1'b0;
|
||||||
|
if (space_output > 255) begin // Space in the output FIFO.
|
||||||
|
if (occupied > 255) begin // 64 or more entrys in main FIFO
|
||||||
|
output_state <= OUTPUT1;
|
||||||
|
output_timeout_reset <= 1'b1;
|
||||||
|
end else if (output_timeout_triggered) begin // output FIFO timeout waiting for new data.
|
||||||
|
output_state <= OUTPUT2;
|
||||||
|
output_timeout_reset <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
output_timeout_reset <= 1'b0;
|
||||||
|
output_state <= OUTPUT_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
output_timeout_reset <= 1'b0;
|
||||||
|
output_state <= OUTPUT_IDLE;
|
||||||
|
end
|
||||||
|
end // case: OUTPUT_IDLE
|
||||||
|
//
|
||||||
|
// OUTPUT1.
|
||||||
|
// Caused by main FIFO reaching 256 entries.
|
||||||
|
// Request read burst of lesser of lesser of:
|
||||||
|
// 1) Entrys until page boundry crossed
|
||||||
|
// 2) 256.
|
||||||
|
//
|
||||||
|
OUTPUT1: begin
|
||||||
|
read_count <= (output_page_boundry < 255) ? output_page_boundry : 8'd255;
|
||||||
|
read_ctrl_valid <= 1'b1;
|
||||||
|
if (read_ctrl_ready)
|
||||||
|
output_state <= OUTPUT4; // Pre-emptive ACK
|
||||||
|
else
|
||||||
|
output_state <= OUTPUT3; // Wait for ACK
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// OUTPUT2.
|
||||||
|
// Caused by timeout of main FIFO
|
||||||
|
// Request read burst of lesser of:
|
||||||
|
// 1) Entries until page boundry crossed
|
||||||
|
// 2) Entries in main FIFO
|
||||||
|
//
|
||||||
|
OUTPUT2: begin
|
||||||
|
read_count <= (output_page_boundry < (occupied - 1)) ? output_page_boundry : (occupied - 1);
|
||||||
|
read_ctrl_valid <= 1'b1;
|
||||||
|
if (read_ctrl_ready)
|
||||||
|
output_state <= OUTPUT4; // Pre-emptive ACK
|
||||||
|
else
|
||||||
|
output_state <= OUTPUT3; // Wait for ACK
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// OUTPUT3.
|
||||||
|
// Wait in this state for AXI4_DMA engine to accept transaction.
|
||||||
|
//
|
||||||
|
OUTPUT3: begin
|
||||||
|
if (read_ctrl_ready) begin
|
||||||
|
read_ctrl_valid <= 1'b0;
|
||||||
|
output_state <= OUTPUT4; // ACK
|
||||||
|
end else begin
|
||||||
|
read_ctrl_valid <= 1'b1;
|
||||||
|
output_state <= OUTPUT3; // Wait for ACK
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// OUTPUT4.
|
||||||
|
// Wait here unitl read_ctrl_ready_deasserts.
|
||||||
|
// This is important as the next time it asserts we know that a read response was receieved.
|
||||||
|
OUTPUT4: begin
|
||||||
|
read_ctrl_valid <= 1'b0;
|
||||||
|
if (!read_ctrl_ready)
|
||||||
|
output_state <= OUTPUT5; // Move on
|
||||||
|
else
|
||||||
|
output_state <= OUTPUT4; // Wait for deassert
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// OUTPUT5.
|
||||||
|
// Transaction has been accepted by AXI4 DMA engine. Now we wait for the re-assertion
|
||||||
|
// of read_ctrl_ready which signals that the AXI4 DMA engine has receieved a last signal and good response
|
||||||
|
// for the whole read transaction.
|
||||||
|
// We are now free to update read_addr pointer and go back to idle state.
|
||||||
|
//
|
||||||
|
OUTPUT5: begin
|
||||||
|
read_ctrl_valid <= 1'b0;
|
||||||
|
if (read_ctrl_ready) begin
|
||||||
|
read_addr[SIZE-1:0] <= read_addr[SIZE-1:0] + ((read_count + 1) << 3);
|
||||||
|
output_state <= OUTPUT6;
|
||||||
|
update_read <= 1'b1;
|
||||||
|
|
||||||
|
end else begin
|
||||||
|
output_state <= OUTPUT5;
|
||||||
|
end
|
||||||
|
end // case: OUTPUT5
|
||||||
|
//
|
||||||
|
// OUTPUT6.
|
||||||
|
// Need to get occupied value updated before checking if there's more to do.
|
||||||
|
//
|
||||||
|
OUTPUT6: begin
|
||||||
|
update_read <= 1'b0;
|
||||||
|
output_state <= OUTPUT_IDLE;
|
||||||
|
end
|
||||||
|
// Ass covering.
|
||||||
|
default: output_state <= OUTPUT_IDLE;
|
||||||
|
|
||||||
|
endcase // case(output_state)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Calculate number of entries remaining until next 4KB page boundry is crossed minus 1.
|
||||||
|
// Note, units of calculation are 64bit wide words. Address is always 64bit alligned.
|
||||||
|
//
|
||||||
|
assign input_page_boundry = {write_addr[31:12],9'h1ff} - write_addr[31:3];
|
||||||
|
assign output_page_boundry = {read_addr[31:12],9'h1ff} - read_addr[31:3];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Count number of used entries in main DRAM FIFO.
|
||||||
|
// Note that this is expressed in units of 64bit wide words.
|
||||||
|
//
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
if (dram_reset | clear)
|
||||||
|
occupied <= 0;
|
||||||
|
else
|
||||||
|
occupied <= occupied + (update_write ? write_count + 1 : 0) - (update_read ? read_count + 1 : 0);
|
||||||
|
|
||||||
|
always @(posedge dram_clk)
|
||||||
|
if (dram_reset | clear)
|
||||||
|
space <= (1 << SIZE-3) - 'd64; // Subtract 64 from space to make allowance for read/write reordering in DRAM controller confuing pointer math.
|
||||||
|
else
|
||||||
|
space <= space - (update_write ? write_count + 1 : 0) + (update_read ? read_count + 1 : 0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Instamce of axi_dma_master
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
axi_dma_master axi_dma_master_i
|
||||||
|
(
|
||||||
|
.aclk(dram_clk), // input aclk
|
||||||
|
.areset(dram_reset | clear), // input aresetn
|
||||||
|
// Write control
|
||||||
|
.m_axi_awid(m_axi_awid), // input [0 : 0] m_axi_awid
|
||||||
|
.m_axi_awaddr(m_axi_awaddr), // input [31 : 0] m_axi_awaddr
|
||||||
|
.m_axi_awlen(m_axi_awlen), // input [7 : 0] m_axi_awlen
|
||||||
|
.m_axi_awsize(m_axi_awsize), // input [2 : 0] m_axi_awsize
|
||||||
|
.m_axi_awburst(m_axi_awburst), // input [1 : 0] m_axi_awburst
|
||||||
|
.m_axi_awvalid(m_axi_awvalid), // input m_axi_awvalid
|
||||||
|
.m_axi_awready(m_axi_awready), // output m_axi_awready
|
||||||
|
.m_axi_awlock(m_axi_awlock),
|
||||||
|
.m_axi_awcache(m_axi_awcache),
|
||||||
|
.m_axi_awprot(m_axi_awprot),
|
||||||
|
.m_axi_awqos(m_axi_awqos),
|
||||||
|
.m_axi_awregion(m_axi_awregion),
|
||||||
|
.m_axi_awuser(m_axi_awuser),
|
||||||
|
// Write Data
|
||||||
|
.m_axi_wdata(m_axi_wdata), // input [63 : 0] m_axi_wdata
|
||||||
|
.m_axi_wstrb(m_axi_wstrb), // input [7 : 0] m_axi_wstrb
|
||||||
|
.m_axi_wlast(m_axi_wlast), // input m_axi_wlast
|
||||||
|
.m_axi_wvalid(m_axi_wvalid), // input m_axi_wvalid
|
||||||
|
.m_axi_wready(m_axi_wready), // output m_axi_wready
|
||||||
|
.m_axi_wuser(),
|
||||||
|
// Write Response
|
||||||
|
.m_axi_bid(m_axi_bid), // output [0 : 0] m_axi_bid
|
||||||
|
.m_axi_bresp(m_axi_bresp), // output [1 : 0] m_axi_bresp
|
||||||
|
.m_axi_bvalid(m_axi_bvalid), // output m_axi_bvalid
|
||||||
|
.m_axi_bready(m_axi_bready), // input m_axi_bready
|
||||||
|
.m_axi_buser(),
|
||||||
|
// Read Control
|
||||||
|
.m_axi_arid(m_axi_arid), // input [0 : 0] m_axi_arid
|
||||||
|
.m_axi_araddr(m_axi_araddr), // input [31 : 0] m_axi_araddr
|
||||||
|
.m_axi_arlen(m_axi_arlen), // input [7 : 0] m_axi_arlen
|
||||||
|
.m_axi_arsize(m_axi_arsize), // input [2 : 0] m_axi_arsize
|
||||||
|
.m_axi_arburst(m_axi_arburst), // input [1 : 0] m_axi_arburst
|
||||||
|
.m_axi_arvalid(m_axi_arvalid), // input m_axi_arvalid
|
||||||
|
.m_axi_arready(m_axi_arready), // output m_axi_arready
|
||||||
|
.m_axi_arlock(m_axi_arlock),
|
||||||
|
.m_axi_arcache(m_axi_arcache),
|
||||||
|
.m_axi_arprot(m_axi_arprot),
|
||||||
|
.m_axi_arqos(m_axi_arqos),
|
||||||
|
.m_axi_arregion(m_axi_arregion),
|
||||||
|
.m_axi_aruser(m_axi_aruser),
|
||||||
|
// Read Data
|
||||||
|
.m_axi_rid(m_axi_rid), // output [0 : 0] m_axi_rid
|
||||||
|
.m_axi_rdata(m_axi_rdata), // output [63 : 0] m_axi_rdata
|
||||||
|
.m_axi_rresp(m_axi_rresp), // output [1 : 0] m_axi_rresp
|
||||||
|
.m_axi_rlast(m_axi_rlast), // output m_axi_rlast
|
||||||
|
.m_axi_rvalid(m_axi_rvalid), // output m_axi_rvalid
|
||||||
|
.m_axi_rready(m_axi_rready), // input m_axi_rready
|
||||||
|
.m_axi_ruser(),
|
||||||
|
//
|
||||||
|
// DMA interface for Write transaction
|
||||||
|
//
|
||||||
|
.write_addr(write_addr), // Byte address for start of write transaction (should be 64bit alligned)
|
||||||
|
.write_count(write_count), // Count of 64bit words to write.
|
||||||
|
.write_ctrl_valid(write_ctrl_valid),
|
||||||
|
.write_ctrl_ready(write_ctrl_ready),
|
||||||
|
.write_data(i_tdata_input),
|
||||||
|
.write_data_valid(i_tvalid_input),
|
||||||
|
.write_data_ready(i_tready_input),
|
||||||
|
//
|
||||||
|
// DMA interface for Read
|
||||||
|
//
|
||||||
|
.read_addr(read_addr), // Byte address for start of read transaction (should be 64bit alligned)
|
||||||
|
.read_count(read_count), // Count of 64bit words to read.
|
||||||
|
.read_ctrl_valid(read_ctrl_valid),
|
||||||
|
.read_ctrl_ready(read_ctrl_ready),
|
||||||
|
.read_data(o_tdata_output),
|
||||||
|
.read_data_valid(o_tvalid_output),
|
||||||
|
.read_data_ready(o_tready_output),
|
||||||
|
//
|
||||||
|
// Debug
|
||||||
|
//
|
||||||
|
.debug(debug_axi_dma_master)
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Debug
|
||||||
|
//
|
||||||
|
assign debug = { checksum_error,
|
||||||
|
/*debug_axi_dma_master[7:0]*/
|
||||||
|
input_timeout_triggered, // 195
|
||||||
|
input_state[2:0], // 194-192
|
||||||
|
output_timeout_triggered, // 191
|
||||||
|
output_state[2:0], // 190-188
|
||||||
|
space_output[15:0], // 187-172
|
||||||
|
occupied[21:0], // 171-150
|
||||||
|
occupied_input[15:0], // 149-134
|
||||||
|
|
||||||
|
i_tvalid_i0, // 133
|
||||||
|
i_tready_i0, // 132
|
||||||
|
i_tlast_i0, // 131
|
||||||
|
i_tdata_i0[63:0],// 130-67
|
||||||
|
o_tvalid_i1, // 66
|
||||||
|
o_tready_i1, // 65
|
||||||
|
o_tlast_i1, // 64
|
||||||
|
o_tdata_i1[63:0] // 63-0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
endmodule // axi_dram_fifo
|
||||||
|
|
||||||
@@ -0,0 +1,421 @@
|
|||||||
|
module axi_dram_fifo_tb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
reg clk; // Global AXI clock
|
||||||
|
reg reset; // Global reset, active high.
|
||||||
|
reg clear;
|
||||||
|
wire aresetn; // Global AXI reset, active low.
|
||||||
|
//
|
||||||
|
// AXI Write address channel
|
||||||
|
//
|
||||||
|
wire [0 : 0] axi_awid; // Write address ID. This signal is the identification tag for the write address signals
|
||||||
|
wire [31 : 0] axi_awaddr; // Write address. The write address gives the address of the first transfer in a write burst
|
||||||
|
wire [7 : 0] axi_awlen; // Burst length. The burst length gives the exact number of transfers in a burst.
|
||||||
|
wire [2 : 0] axi_awsize; // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
wire [1 : 0] axi_awburst; // Burst type. The burst type and the size information, determine how the address is calculated
|
||||||
|
wire [0 : 0] axi_awlock; // Lock type. Provides additional information about the atomic characteristics of the transfer.
|
||||||
|
wire [3 : 0] axi_awcache; // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
wire [2 : 0] axi_awprot; // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
wire [3 : 0] axi_awqos; // Quality of Service, QoS. The QoS identifier sent for each write transaction
|
||||||
|
wire [3 : 0] axi_awregion; // Region identifier. Permits a single physical interface on a slave to be re-used.
|
||||||
|
wire [0 : 0] axi_awuser; // User signal. Optional User-defined signal in the write address channel.
|
||||||
|
wire axi_awvalid; // Write address valid. This signal indicates that the channel is signaling valid write addr
|
||||||
|
wire axi_awready; // Write address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Write data channel.
|
||||||
|
//
|
||||||
|
wire [63 : 0] axi_wdata; // Write data
|
||||||
|
wire [7 : 0] axi_wstrb; // Write strobes. This signal indicates which byte lanes hold valid data.
|
||||||
|
wire axi_wlast; // Write last. This signal indicates the last transfer in a write burst
|
||||||
|
wire [0 : 0] axi_wuser; // User signal. Optional User-defined signal in the write data channel.
|
||||||
|
wire axi_wvalid; // Write valid. This signal indicates that valid write data and strobes are available.
|
||||||
|
wire axi_wready; // Write ready. This signal indicates that the slave can accept the write data.
|
||||||
|
//
|
||||||
|
// AXI Write response channel signals
|
||||||
|
//
|
||||||
|
wire [0 : 0] axi_bid; // Response ID tag. This signal is the ID tag of the write response.
|
||||||
|
wire [1 : 0] axi_bresp; // Write response. This signal indicates the status of the write transaction.
|
||||||
|
wire [0 : 0] axi_buser; // User signal. Optional User-defined signal in the write response channel.
|
||||||
|
wire axi_bvalid; // Write response valid. This signal indicates that the channel is signaling a valid response
|
||||||
|
wire axi_bready; // Response ready. This signal indicates that the master can accept a write response
|
||||||
|
//
|
||||||
|
// AXI Read address channel
|
||||||
|
//
|
||||||
|
wire [0 : 0] axi_arid; // Read address ID. This signal is the identification tag for the read address group of signals
|
||||||
|
wire [31 : 0] axi_araddr; // Read address. The read address gives the address of the first transfer in a read burst
|
||||||
|
wire [7 : 0] axi_arlen; // Burst length. This signal indicates the exact number of transfers in a burst.
|
||||||
|
wire [2 : 0] axi_arsize; // Burst size. This signal indicates the size of each transfer in the burst.
|
||||||
|
wire [1 : 0] axi_arburst; // Burst type. The burst type and the size information determine how the address for each transfer
|
||||||
|
wire [0 : 0] axi_arlock; // Lock type. This signal provides additional information about the atomic characteristics
|
||||||
|
wire [3 : 0] axi_arcache; // Memory type. This signal indicates how transactions are required to progress
|
||||||
|
wire [2 : 0] axi_arprot; // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
wire [3 : 0] axi_arqos; // Quality of Service, QoS. QoS identifier sent for each read transaction.
|
||||||
|
wire [3 : 0] axi_arregion; // Region identifier. Permits a single physical interface on a slave to be re-used
|
||||||
|
wire [0 : 0] axi_aruser; // User signal. Optional User-defined signal in the read address channel.
|
||||||
|
wire axi_arvalid; // Read address valid. This signal indicates that the channel is signaling valid read addr
|
||||||
|
wire axi_arready; // Read address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Read data channel
|
||||||
|
//
|
||||||
|
wire [0 : 0] axi_rid; // Read ID tag. This signal is the identification tag for the read data group of signals
|
||||||
|
wire [63 : 0] axi_rdata; // Read data.
|
||||||
|
wire [1 : 0] axi_rresp; // Read response. This signal indicates the status of the read transfer
|
||||||
|
wire axi_rlast; // Read last. This signal indicates the last transfer in a read burst.
|
||||||
|
wire [0 : 0] axi_ruser; // User signal. Optional User-defined signal in the read data channel.
|
||||||
|
wire axi_rvalid; // Read valid. This signal indicates that the channel is signaling the required read data.
|
||||||
|
wire axi_rready; // Read ready. This signal indicates that the master can accept the read data and response
|
||||||
|
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI stream input
|
||||||
|
//
|
||||||
|
wire [63:0] i_tdata;
|
||||||
|
wire i_tlast;
|
||||||
|
wire i_tvalid;
|
||||||
|
wire i_tready;
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI Stream output
|
||||||
|
//
|
||||||
|
wire [63:0] o_tdata;
|
||||||
|
wire o_tlast;
|
||||||
|
wire o_tvalid;
|
||||||
|
wire o_tready;
|
||||||
|
|
||||||
|
//
|
||||||
|
// These registers optionaly used
|
||||||
|
// to drive nets through procedural assignments in test bench.
|
||||||
|
// These drivers default to tri-stated.
|
||||||
|
//
|
||||||
|
|
||||||
|
reg [63:0] i_tdata_r;
|
||||||
|
reg i_tlast_r;
|
||||||
|
reg i_tvalid_r;
|
||||||
|
reg o_tready_r;
|
||||||
|
|
||||||
|
assign i_tdata = i_tdata_r;
|
||||||
|
assign i_tlast = i_tlast_r;
|
||||||
|
assign i_tvalid = i_tvalid_r;
|
||||||
|
assign o_tready = o_tready_r;
|
||||||
|
|
||||||
|
initial
|
||||||
|
begin
|
||||||
|
i_tdata_r <= 64'hzzzz_zzzz_zzzz_zzzz;
|
||||||
|
i_tlast_r <= 1'bz;
|
||||||
|
i_tvalid_r <= 1'bz;
|
||||||
|
o_tready_r <= 1'bz;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
axi_dram_fifo
|
||||||
|
#(.SIZE(13))
|
||||||
|
axi_dram_fifo_i1
|
||||||
|
(
|
||||||
|
.bus_clk(clk), // input s_aclk
|
||||||
|
.bus_reset(reset), // input s_aresetn
|
||||||
|
.clear(clear),
|
||||||
|
.dram_clk(clk), // input s_aclk
|
||||||
|
.dram_reset(reset), // input s_aresetn
|
||||||
|
// Write control
|
||||||
|
.m_axi_awid(axi_awid), // input [0 : 0] s_axi_awid
|
||||||
|
.m_axi_awaddr(axi_awaddr), // input [31 : 0] s_axi_awaddr
|
||||||
|
.m_axi_awlen(axi_awlen), // input [7 : 0] s_axi_awlen
|
||||||
|
.m_axi_awsize(axi_awsize), // input [2 : 0] s_axi_awsize
|
||||||
|
.m_axi_awburst(axi_awburst), // input [1 : 0] s_axi_awburst
|
||||||
|
.m_axi_awvalid(axi_awvalid), // input s_axi_awvalid
|
||||||
|
.m_axi_awready(axi_awready), // output s_axi_awready
|
||||||
|
.m_axi_awlock(),
|
||||||
|
.m_axi_awcache(),
|
||||||
|
.m_axi_awprot(),
|
||||||
|
.m_axi_awqos(),
|
||||||
|
.m_axi_awregion(),
|
||||||
|
.m_axi_awuser(),
|
||||||
|
// Write Data
|
||||||
|
.m_axi_wdata(axi_wdata), // input [63 : 0] s_axi_wdata
|
||||||
|
.m_axi_wstrb(axi_wstrb), // input [7 : 0] s_axi_wstrb
|
||||||
|
.m_axi_wlast(axi_wlast), // input s_axi_wlast
|
||||||
|
.m_axi_wvalid(axi_wvalid), // input s_axi_wvalid
|
||||||
|
.m_axi_wready(axi_wready), // output s_axi_wready
|
||||||
|
.m_axi_wuser(),
|
||||||
|
// Write Response
|
||||||
|
.m_axi_bid(axi_bid), // output [0 : 0] s_axi_bid
|
||||||
|
.m_axi_bresp(axi_bresp), // output [1 : 0] s_axi_bresp
|
||||||
|
.m_axi_bvalid(axi_bvalid), // output s_axi_bvalid
|
||||||
|
.m_axi_bready(axi_bready), // input s_axi_bready
|
||||||
|
.m_axi_buser(),
|
||||||
|
// Read Control
|
||||||
|
.m_axi_arid(axi_arid), // input [0 : 0] s_axi_arid
|
||||||
|
.m_axi_araddr(axi_araddr), // input [31 : 0] s_axi_araddr
|
||||||
|
.m_axi_arlen(axi_arlen), // input [7 : 0] s_axi_arlen
|
||||||
|
.m_axi_arsize(axi_arsize), // input [2 : 0] s_axi_arsize
|
||||||
|
.m_axi_arburst(axi_arburst), // input [1 : 0] s_axi_arburst
|
||||||
|
.m_axi_arvalid(axi_arvalid), // input s_axi_arvalid
|
||||||
|
.m_axi_arready(axi_arready), // output s_axi_arready
|
||||||
|
.m_axi_arlock(),
|
||||||
|
.m_axi_arcache(),
|
||||||
|
.m_axi_arprot(),
|
||||||
|
.m_axi_arqos(),
|
||||||
|
.m_axi_arregion(),
|
||||||
|
.m_axi_aruser(),
|
||||||
|
// Read Data
|
||||||
|
.m_axi_rid(axi_rid), // output [0 : 0] s_axi_rid
|
||||||
|
.m_axi_rdata(axi_rdata), // output [63 : 0] s_axi_rdata
|
||||||
|
.m_axi_rresp(axi_rresp), // output [1 : 0] s_axi_rresp
|
||||||
|
.m_axi_rlast(axi_rlast), // output s_axi_rlast
|
||||||
|
.m_axi_rvalid(axi_rvalid), // output s_axi_rvalid
|
||||||
|
.m_axi_rready(axi_rready), // input s_axi_rready
|
||||||
|
.m_axi_ruser(),
|
||||||
|
// CHDR in
|
||||||
|
.i_tdata(i_tdata),
|
||||||
|
.i_tlast(i_tlast),
|
||||||
|
.i_tvalid(i_tvalid),
|
||||||
|
.i_tready(i_tready),
|
||||||
|
// CHDR out
|
||||||
|
.o_tdata(o_tdata),
|
||||||
|
.o_tlast(o_tlast),
|
||||||
|
.o_tvalid(o_tvalid),
|
||||||
|
.o_tready(o_tready),
|
||||||
|
//
|
||||||
|
.supress_threshold(16'h0),
|
||||||
|
.supress_enable(1'b0)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
axi4_bram_1kx64 axi4_bram_1kx64_i1
|
||||||
|
(
|
||||||
|
.s_aclk(clk), // input s_aclk
|
||||||
|
.s_aresetn(aresetn), // input s_aresetn
|
||||||
|
.s_axi_awid(axi_awid), // input [0 : 0] s_axi_awid
|
||||||
|
.s_axi_awaddr(axi_awaddr), // input [31 : 0] s_axi_awaddr
|
||||||
|
.s_axi_awlen(axi_awlen), // input [7 : 0] s_axi_awlen
|
||||||
|
.s_axi_awsize(axi_awsize), // input [2 : 0] s_axi_awsize
|
||||||
|
.s_axi_awburst(axi_awburst), // input [1 : 0] s_axi_awburst
|
||||||
|
.s_axi_awvalid(axi_awvalid), // input s_axi_awvalid
|
||||||
|
.s_axi_awready(axi_awready), // output s_axi_awready
|
||||||
|
.s_axi_wdata(axi_wdata), // input [63 : 0] s_axi_wdata
|
||||||
|
.s_axi_wstrb(axi_wstrb), // input [7 : 0] s_axi_wstrb
|
||||||
|
.s_axi_wlast(axi_wlast), // input s_axi_wlast
|
||||||
|
.s_axi_wvalid(axi_wvalid), // input s_axi_wvalid
|
||||||
|
.s_axi_wready(axi_wready), // output s_axi_wready
|
||||||
|
.s_axi_bid(axi_bid), // output [0 : 0] s_axi_bid
|
||||||
|
.s_axi_bresp(axi_bresp), // output [1 : 0] s_axi_bresp
|
||||||
|
.s_axi_bvalid(axi_bvalid), // output s_axi_bvalid
|
||||||
|
.s_axi_bready(axi_bready), // input s_axi_bready
|
||||||
|
.s_axi_arid(axi_arid), // input [0 : 0] s_axi_arid
|
||||||
|
.s_axi_araddr(axi_araddr), // input [31 : 0] s_axi_araddr
|
||||||
|
.s_axi_arlen(axi_arlen), // input [7 : 0] s_axi_arlen
|
||||||
|
.s_axi_arsize(axi_arsize), // input [2 : 0] s_axi_arsize
|
||||||
|
.s_axi_arburst(axi_arburst), // input [1 : 0] s_axi_arburst
|
||||||
|
.s_axi_arvalid(axi_arvalid), // input s_axi_arvalid
|
||||||
|
.s_axi_arready(axi_arready), // output s_axi_arready
|
||||||
|
.s_axi_rid(axi_rid), // output [0 : 0] s_axi_rid
|
||||||
|
.s_axi_rdata(axi_rdata), // output [63 : 0] s_axi_rdata
|
||||||
|
.s_axi_rresp(axi_rresp), // output [1 : 0] s_axi_rresp
|
||||||
|
.s_axi_rlast(axi_rlast), // output s_axi_rlast
|
||||||
|
.s_axi_rvalid(axi_rvalid), // output s_axi_rvalid
|
||||||
|
.s_axi_rready(axi_rready) // input s_axi_rready
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
task send_ramp;
|
||||||
|
input [31:0] burst_count;
|
||||||
|
input [31:0] len;
|
||||||
|
input [31:0] sid;
|
||||||
|
|
||||||
|
reg [31:0] data;
|
||||||
|
reg [11:0] seqno;
|
||||||
|
|
||||||
|
begin
|
||||||
|
seqno = 0;
|
||||||
|
data = 0;
|
||||||
|
send_packet(len, data, 0, seqno, (burst_count==1), 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
data <= data + len;
|
||||||
|
|
||||||
|
if(burst_count > 2)
|
||||||
|
repeat (burst_count - 2)
|
||||||
|
begin
|
||||||
|
send_packet(len, data, 64'h0, seqno, 0, 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
data <= data + len;
|
||||||
|
end
|
||||||
|
if(burst_count > 1)
|
||||||
|
send_packet(len, data, 64'h0, seqno, 1, 0, sid);
|
||||||
|
end
|
||||||
|
endtask // send_ramp
|
||||||
|
|
||||||
|
|
||||||
|
task send_dc;
|
||||||
|
input [31:0] burst_count;
|
||||||
|
input [31:0] len;
|
||||||
|
input [31:0] sid;
|
||||||
|
|
||||||
|
reg [31:0] data;
|
||||||
|
reg [11:0] seqno;
|
||||||
|
|
||||||
|
begin
|
||||||
|
seqno = 0;
|
||||||
|
data = 1 << 14;
|
||||||
|
send_packet(len, data, 0, seqno, (burst_count==1), 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
|
||||||
|
|
||||||
|
if(burst_count > 2)
|
||||||
|
repeat (burst_count - 2)
|
||||||
|
begin
|
||||||
|
send_packet(len, data, 64'h0, seqno, 0, 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
|
||||||
|
end
|
||||||
|
if(burst_count > 1)
|
||||||
|
send_packet(len, data, 64'h0, seqno, 1, 0, sid);
|
||||||
|
end
|
||||||
|
endtask // send_ramp
|
||||||
|
|
||||||
|
|
||||||
|
task send_burst;
|
||||||
|
input [31:0] burst_count;
|
||||||
|
input [31:0] len;
|
||||||
|
input [31:0] start_data;
|
||||||
|
input [63:0] send_time;
|
||||||
|
input [11:0] start_seqnum;
|
||||||
|
input send_at;
|
||||||
|
input [31:0] sid;
|
||||||
|
|
||||||
|
reg [11:0] seqno;
|
||||||
|
|
||||||
|
begin
|
||||||
|
seqno = start_seqnum;
|
||||||
|
send_packet(len, {seqno,start_data[15:0]}, send_time, seqno, (burst_count==1), send_at, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
|
||||||
|
if(burst_count > 2)
|
||||||
|
repeat (burst_count - 2)
|
||||||
|
begin
|
||||||
|
send_packet(len, {seqno,start_data[15:0]}, 64'h0, seqno, 0, 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
end
|
||||||
|
if(burst_count > 1)
|
||||||
|
send_packet(len, {seqno,start_data[15:0]}, 64'h0, seqno, 1, 0, sid);
|
||||||
|
end
|
||||||
|
endtask // send_burst
|
||||||
|
|
||||||
|
task send_packet;
|
||||||
|
input [31:0] len;
|
||||||
|
input [31:0] start_data;
|
||||||
|
input [63:0] send_time;
|
||||||
|
input [11:0] pkt_seqnum;
|
||||||
|
input eob;
|
||||||
|
input send_at;
|
||||||
|
input [31:0] sid;
|
||||||
|
|
||||||
|
reg [31:0] samp0, samp1;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Send a packet
|
||||||
|
samp0 <= start_data;
|
||||||
|
samp1 <= start_data + 1;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
i_tlast_r <= 0;
|
||||||
|
i_tdata_r <= { 1'b0, 1'b0 /*trl*/, send_at, eob, pkt_seqnum, len[15:0]+16'd2+send_at+send_at, sid };
|
||||||
|
i_tvalid_r <= 1;
|
||||||
|
@(posedge clk)
|
||||||
|
if(send_at)
|
||||||
|
begin
|
||||||
|
i_tdata_r <= send_time;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
|
||||||
|
repeat (len[31:1]+len[0]-1)
|
||||||
|
begin
|
||||||
|
i_tdata_r <= {samp0,samp1};
|
||||||
|
samp0 <= samp0 + 2;
|
||||||
|
samp1 <= samp1 + 2;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
|
||||||
|
i_tdata_r <= {samp0,samp1};
|
||||||
|
i_tlast_r <= 1'b1;
|
||||||
|
@(posedge clk);
|
||||||
|
i_tvalid_r <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
endtask // send_packet
|
||||||
|
|
||||||
|
task send_raw_packet;
|
||||||
|
input [31:0] len;
|
||||||
|
|
||||||
|
reg [63:0] data;
|
||||||
|
|
||||||
|
begin
|
||||||
|
data = 0;
|
||||||
|
@(posedge clk);
|
||||||
|
repeat (len-1) begin
|
||||||
|
i_tlast_r <= 0;
|
||||||
|
i_tdata_r <= data;
|
||||||
|
i_tvalid_r <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~i_tready) @(posedge clk);
|
||||||
|
data = data + 1;
|
||||||
|
end
|
||||||
|
i_tlast_r <= 1;
|
||||||
|
i_tdata_r <= data;
|
||||||
|
i_tvalid_r <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~i_tready) @(posedge clk);
|
||||||
|
i_tvalid_r <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
endtask // send_raw_packet
|
||||||
|
|
||||||
|
task receive_raw_packet;
|
||||||
|
input [31:0] len;
|
||||||
|
output fail;
|
||||||
|
reg [63:0] data;
|
||||||
|
|
||||||
|
begin
|
||||||
|
data = 0;
|
||||||
|
fail = 0;
|
||||||
|
|
||||||
|
@(posedge clk);
|
||||||
|
repeat (len-1) begin
|
||||||
|
o_tready_r <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~o_tvalid) @(posedge clk);
|
||||||
|
//$display("Data = %d, o_tdata = %d, o_tlast = %d",data,o_tdata,o_tlast);
|
||||||
|
|
||||||
|
fail = fail || (data !== o_tdata);
|
||||||
|
fail = fail || ~(o_tlast === 0);
|
||||||
|
data = data + 1;
|
||||||
|
|
||||||
|
end
|
||||||
|
o_tready_r <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~o_tvalid) @(posedge clk);
|
||||||
|
//$display("Data = %d, o_tdata = %d, o_tlast = %d",data,o_tdata,o_tlast);
|
||||||
|
fail = fail || (data !== o_tdata);
|
||||||
|
fail = fail || ~(o_tlast === 1);
|
||||||
|
o_tready_r <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
if (fail) $display("receive_raw_packet size %d failed",len);
|
||||||
|
|
||||||
|
end
|
||||||
|
endtask // receive_raw_packet
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
assign aresetn = ~reset;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Bring in a simulation script here
|
||||||
|
//
|
||||||
|
`include "simulation_script.v"
|
||||||
|
|
||||||
|
endmodule // axi_dram_fifo_tb
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
//
|
||||||
|
// AXI stream neds N+1 bits to transmit packets of N bits so that the LAST bit can be represented.
|
||||||
|
// LAST occurs relatively infrequently and can be synthesized by using an in-band ESC code to generate
|
||||||
|
// a multi-word sequence to encode it (and the escape character when it appears as data input).
|
||||||
|
//
|
||||||
|
// 0x1234567887654321 with last becomes
|
||||||
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0x1234567887654321
|
||||||
|
//
|
||||||
|
// 0xDEADBEEFFEEDCAFE with last becomes
|
||||||
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0xDEADBEEFFEEDCAFE
|
||||||
|
//
|
||||||
|
// 0xDEADBEEFFEEDCAFE without last becomes
|
||||||
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000000 0xDEADBEEFFEEDCAFE
|
||||||
|
//
|
||||||
|
|
||||||
|
module axi_embed_tlast
|
||||||
|
#(parameter WIDTH=64)
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
input clear,
|
||||||
|
//
|
||||||
|
input [WIDTH-1:0] i_tdata,
|
||||||
|
input i_tlast,
|
||||||
|
input i_tvalid,
|
||||||
|
output i_tready,
|
||||||
|
//
|
||||||
|
output reg [WIDTH-1:0] o_tdata,
|
||||||
|
output o_tvalid,
|
||||||
|
input o_tready
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam PASS = 0;
|
||||||
|
localparam ZERO = 1;
|
||||||
|
localparam ONE = 2;
|
||||||
|
localparam ESCAPE = 3;
|
||||||
|
|
||||||
|
localparam IDLE = 0;
|
||||||
|
localparam LAST = 1;
|
||||||
|
localparam ESC = 2;
|
||||||
|
localparam FINISH = 3;
|
||||||
|
|
||||||
|
reg [1:0] state, next_state;
|
||||||
|
|
||||||
|
reg [1:0] select;
|
||||||
|
|
||||||
|
reg [31:0] checksum;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
checksum <= 0;
|
||||||
|
end else if (i_tready && i_tvalid && i_tlast) begin
|
||||||
|
checksum <= 0;
|
||||||
|
end else if (i_tready && i_tvalid) begin
|
||||||
|
checksum <= checksum + i_tdata[31:0] + i_tdata[63:32];
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
state <= IDLE;
|
||||||
|
end else begin if (o_tready)
|
||||||
|
state <= next_state;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
case(state)
|
||||||
|
IDLE: begin
|
||||||
|
if (i_tlast && i_tvalid)
|
||||||
|
begin
|
||||||
|
next_state = LAST;
|
||||||
|
select = ESCAPE;
|
||||||
|
end
|
||||||
|
else if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid)
|
||||||
|
begin
|
||||||
|
next_state = ESC;
|
||||||
|
select = ESCAPE;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
next_state = IDLE;
|
||||||
|
select = PASS;
|
||||||
|
end
|
||||||
|
end // case: IDLE
|
||||||
|
//
|
||||||
|
//
|
||||||
|
LAST: begin
|
||||||
|
select = ONE;
|
||||||
|
next_state = FINISH;
|
||||||
|
end
|
||||||
|
//
|
||||||
|
//
|
||||||
|
ESC: begin
|
||||||
|
select = ZERO;
|
||||||
|
next_state = FINISH;
|
||||||
|
end
|
||||||
|
//
|
||||||
|
//
|
||||||
|
FINISH: begin
|
||||||
|
select = PASS;
|
||||||
|
if (i_tvalid)
|
||||||
|
next_state = IDLE;
|
||||||
|
else
|
||||||
|
next_state = FINISH;
|
||||||
|
end
|
||||||
|
endcase // case(state)
|
||||||
|
end // always @ (*)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Muxes
|
||||||
|
//
|
||||||
|
always @*
|
||||||
|
begin
|
||||||
|
case(select)
|
||||||
|
PASS: o_tdata = i_tdata;
|
||||||
|
ZERO: o_tdata = 0;
|
||||||
|
ONE: o_tdata = {checksum[31:0],32'h1};
|
||||||
|
ESCAPE: o_tdata = 64'hDEADBEEFFEEDCAFE;
|
||||||
|
endcase // case(select)
|
||||||
|
end
|
||||||
|
|
||||||
|
assign o_tvalid = (select == PASS) ? i_tvalid : 1'b1;
|
||||||
|
assign i_tready = (select == PASS) ? o_tready : 1'b0;
|
||||||
|
|
||||||
|
endmodule // axi_embed_tlast
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
//
|
||||||
|
// AXI stream neds N+1 bits to transmit packets of N bits so that the LAST bit can be represented.
|
||||||
|
// LAST occurs relatively infrequently and can be synthesized by using an in-band ESC code to generate
|
||||||
|
// a multi-word sequence to encode it (and the escape character when it appears as data input).
|
||||||
|
//
|
||||||
|
// 0x1234567887654321 with last becomes
|
||||||
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0x1234567887654321
|
||||||
|
//
|
||||||
|
// 0xDEADBEEFFEEDCAFE with last becomes
|
||||||
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0xDEADBEEFFEEDCAFE
|
||||||
|
//
|
||||||
|
// 0xDEADBEEFFEEDCAFE without last becomes
|
||||||
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000000 0xDEADBEEFFEEDCAFE
|
||||||
|
//
|
||||||
|
|
||||||
|
module axi_extract_tlast
|
||||||
|
#(parameter WIDTH=64)
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
input clear,
|
||||||
|
//
|
||||||
|
input [WIDTH-1:0] i_tdata,
|
||||||
|
input i_tvalid,
|
||||||
|
output reg i_tready,
|
||||||
|
//
|
||||||
|
output [WIDTH-1:0] o_tdata,
|
||||||
|
output reg o_tlast,
|
||||||
|
output reg o_tvalid,
|
||||||
|
input o_tready,
|
||||||
|
//
|
||||||
|
output reg checksum_error_reg
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [1:0] state, next_state;
|
||||||
|
|
||||||
|
localparam IDLE = 0;
|
||||||
|
localparam EXTRACT1 = 1;
|
||||||
|
localparam EXTRACT2 = 2;
|
||||||
|
localparam EXTRACT3 = 3;
|
||||||
|
|
||||||
|
assign o_tdata = i_tdata;
|
||||||
|
|
||||||
|
reg [31:0] checksum, old_checksum;
|
||||||
|
reg checksum_error;
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
checksum <= 0;
|
||||||
|
old_checksum <= 0;
|
||||||
|
end else if (o_tready && i_tvalid && o_tlast) begin
|
||||||
|
checksum <= 0;
|
||||||
|
old_checksum <= 0;
|
||||||
|
end else if (i_tready && i_tvalid && (state == IDLE)) begin
|
||||||
|
checksum <= checksum + i_tdata[31:0] + i_tdata[63:32];
|
||||||
|
old_checksum <= checksum;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
checksum_error_reg <= checksum_error;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
state <= IDLE;
|
||||||
|
end else begin
|
||||||
|
state <= next_state;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
checksum_error = 0;
|
||||||
|
case(state)
|
||||||
|
//
|
||||||
|
// Search for Escape sequence "0xDEADBEEFFEEDCAFE"
|
||||||
|
// If ESC found don't pass data downstream but transition to next state.
|
||||||
|
// else pass data downstream.
|
||||||
|
//
|
||||||
|
IDLE: begin
|
||||||
|
o_tlast = 1'b0;
|
||||||
|
if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid)
|
||||||
|
begin
|
||||||
|
next_state = EXTRACT1;
|
||||||
|
o_tvalid = 1'b0;
|
||||||
|
i_tready = 1'b1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
next_state = IDLE;
|
||||||
|
o_tvalid = i_tvalid;
|
||||||
|
i_tready = o_tready;
|
||||||
|
end // else: !if((i_tdata == 'hDEADBEEFFEEDCAFE) && i_tvalid)
|
||||||
|
end // case: IDLE
|
||||||
|
//
|
||||||
|
// Look at next data. If it's a 0x1 then o_tlast should be asserted with next data word.
|
||||||
|
// if it's 0x0 then it signals emulation of the Escape code in the original data stream
|
||||||
|
// and we should just pass the next data word through unchanged with no o_tlast indication.
|
||||||
|
//
|
||||||
|
EXTRACT1: begin
|
||||||
|
o_tvalid = 1'b0;
|
||||||
|
i_tready = 1'b1;
|
||||||
|
o_tlast = 1'b0;
|
||||||
|
if (i_tvalid) begin
|
||||||
|
if (i_tdata[31:0] == 'h1)
|
||||||
|
begin
|
||||||
|
if (old_checksum != i_tdata[63:32])
|
||||||
|
checksum_error = 1'b1;
|
||||||
|
next_state = EXTRACT2;
|
||||||
|
end
|
||||||
|
else // We assume emulation and don't look for illegal codes.
|
||||||
|
begin
|
||||||
|
next_state = EXTRACT3;
|
||||||
|
end // else: !if(i_tdata == 'h1)
|
||||||
|
end else begin // if (i_tvalid)
|
||||||
|
next_state = EXTRACT1;
|
||||||
|
end // else: !if(i_tvalid)
|
||||||
|
end // case: EXTRACT1
|
||||||
|
//
|
||||||
|
// Assert o_tlast with data word.
|
||||||
|
//
|
||||||
|
EXTRACT2: begin
|
||||||
|
o_tvalid = i_tvalid;
|
||||||
|
i_tready = o_tready;
|
||||||
|
o_tlast = 1'b1;
|
||||||
|
if (i_tvalid & o_tready)
|
||||||
|
next_state = IDLE;
|
||||||
|
else
|
||||||
|
next_state = EXTRACT2;
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Emulation, don't assert o_tlast with dataword.
|
||||||
|
//
|
||||||
|
EXTRACT3: begin
|
||||||
|
o_tvalid = i_tvalid;
|
||||||
|
i_tready = o_tready;
|
||||||
|
o_tlast = 1'b0;
|
||||||
|
if (i_tvalid & o_tready)
|
||||||
|
next_state = IDLE;
|
||||||
|
else
|
||||||
|
next_state = EXTRACT2;
|
||||||
|
end
|
||||||
|
endcase // case(state)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
endmodule // axi_extract_tlast
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
//
|
||||||
|
// Ultra fast critical path FIFO.
|
||||||
|
// Only 2 entrys but no combinatorial feed through paths
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module axi_fast_extract_tlast
|
||||||
|
#(parameter WIDTH=64)
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
input clear,
|
||||||
|
//
|
||||||
|
input [WIDTH-1:0] i_tdata,
|
||||||
|
input i_tvalid,
|
||||||
|
output reg i_tready,
|
||||||
|
//
|
||||||
|
output [WIDTH-1:0] o_tdata,
|
||||||
|
output o_tlast,
|
||||||
|
output reg o_tvalid,
|
||||||
|
input o_tready
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [WIDTH:0] data_reg1, data_reg2;
|
||||||
|
|
||||||
|
reg [1:0] fifo_state;
|
||||||
|
|
||||||
|
localparam EMPTY = 0;
|
||||||
|
localparam HALF = 1;
|
||||||
|
localparam FULL = 2;
|
||||||
|
|
||||||
|
reg [1:0] extract_state;
|
||||||
|
|
||||||
|
localparam IDLE = 0;
|
||||||
|
localparam EXTRACT1 = 1;
|
||||||
|
localparam EXTRACT2 = 2;
|
||||||
|
localparam EXTRACT3 = 3;
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
end else begin
|
||||||
|
case (fifo_state)
|
||||||
|
// Nothing in either register.
|
||||||
|
// Upstream can always push data to us.
|
||||||
|
// Downstream has nothing to take from us.
|
||||||
|
EMPTY: begin
|
||||||
|
if ((extract_state == IDLE) && (i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
|
||||||
|
// Embeded escpae code received.
|
||||||
|
extract_state <= EXTRACT1;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
end else if ((extract_state == EXTRACT1) && i_tvalid) begin
|
||||||
|
// Now work out if its a genuine embeded tlast or emulation.
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
if (i_tdata[31:0] == 'h1) begin
|
||||||
|
extract_state <= EXTRACT2;
|
||||||
|
end else begin
|
||||||
|
extract_state <= EXTRACT3;
|
||||||
|
end
|
||||||
|
end else if ((extract_state == EXTRACT2) && i_tvalid) begin
|
||||||
|
// Extract tlast.
|
||||||
|
data_reg1 <= {1'b1,i_tdata};
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
fifo_state <= HALF;
|
||||||
|
extract_state <= IDLE;
|
||||||
|
end else if (i_tvalid) begin
|
||||||
|
// Get here both for normal data and for EXTRACT3 emulation data.
|
||||||
|
data_reg1 <= {1'b0,i_tdata};
|
||||||
|
fifo_state <= HALF;
|
||||||
|
extract_state <= IDLE;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
// Nothing to do.
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// First Register Full.
|
||||||
|
// Upstream can always push data to us.
|
||||||
|
// Downstream can always read from us.
|
||||||
|
HALF: begin
|
||||||
|
if ((extract_state == IDLE) && (i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
|
||||||
|
// Embeded escpae code received.
|
||||||
|
extract_state <= EXTRACT1;
|
||||||
|
if (o_tready) begin
|
||||||
|
// If meanwhile we get read then go empty...
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
end else begin
|
||||||
|
// ...else stay half full.
|
||||||
|
fifo_state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end else if ((extract_state == EXTRACT1) && i_tvalid) begin
|
||||||
|
// Now work out if its a genuine embeded tlast or emulation.
|
||||||
|
if (i_tdata[31:0] == 'h1) begin
|
||||||
|
extract_state <= EXTRACT2;
|
||||||
|
end else begin
|
||||||
|
extract_state <= EXTRACT3;
|
||||||
|
end
|
||||||
|
if (o_tready) begin
|
||||||
|
// If meanwhile we get read then go empty...
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
end else begin
|
||||||
|
// ...else stay half full.
|
||||||
|
fifo_state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end else if ((extract_state == EXTRACT2) && i_tvalid) begin
|
||||||
|
// Extract tlast.
|
||||||
|
data_reg1 <= {1'b1,i_tdata};
|
||||||
|
extract_state <= IDLE;
|
||||||
|
if (o_tready) begin
|
||||||
|
// We get read and writen same cycle...
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
fifo_state <= HALF;
|
||||||
|
end else begin
|
||||||
|
// ...or we get written and go full.
|
||||||
|
data_reg2 <= data_reg1;
|
||||||
|
i_tready <= 1'b0;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
fifo_state <= FULL;
|
||||||
|
end
|
||||||
|
end else if (i_tvalid) begin
|
||||||
|
// Get here both for normal data and for EXTRACT3 emulation data.
|
||||||
|
data_reg1 <= {1'b0,i_tdata};
|
||||||
|
extract_state <= IDLE;
|
||||||
|
if (o_tready) begin
|
||||||
|
// We get read and writen same cycle...
|
||||||
|
fifo_state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
// ...or we get written and go full.
|
||||||
|
data_reg2 <= data_reg1;
|
||||||
|
i_tready <= 1'b0;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
fifo_state <= FULL;
|
||||||
|
end
|
||||||
|
end else if (o_tready) begin // if (i_tvalid)
|
||||||
|
// Only getting read this cycle so go empty
|
||||||
|
fifo_state <= EMPTY;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
// Absolutley nothing happens, everything stays the same.
|
||||||
|
fifo_state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end // case: HALF
|
||||||
|
// Both Registers Full.
|
||||||
|
// Upstream can not push to us in this fifo_state.
|
||||||
|
// Downstream can always read from us.
|
||||||
|
FULL: begin
|
||||||
|
if (o_tready) begin
|
||||||
|
fifo_state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
fifo_state <= FULL;
|
||||||
|
i_tready <= 1'b0;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase // case(fifo_state)
|
||||||
|
end // else: !if(reset | clear)
|
||||||
|
|
||||||
|
assign {o_tlast,o_tdata} = (fifo_state == FULL) ? data_reg2 : data_reg1;
|
||||||
|
|
||||||
|
|
||||||
|
endmodule // axi_fast_fifo
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
//
|
||||||
|
// Ultra fast critical path FIFO.
|
||||||
|
// Only 2 entrys but no combinatorial feed through paths
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module axi_fast_fifo
|
||||||
|
#(parameter WIDTH=64)
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
input clear,
|
||||||
|
//
|
||||||
|
input [WIDTH-1:0] i_tdata,
|
||||||
|
input i_tvalid,
|
||||||
|
output reg i_tready,
|
||||||
|
//
|
||||||
|
output [WIDTH-1:0] o_tdata,
|
||||||
|
output reg o_tvalid,
|
||||||
|
input o_tready
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] data_reg1, data_reg2;
|
||||||
|
|
||||||
|
reg [1:0] state;
|
||||||
|
|
||||||
|
localparam EMPTY = 0;
|
||||||
|
localparam HALF = 1;
|
||||||
|
localparam FULL = 2;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
state <= EMPTY;
|
||||||
|
data_reg1 <= 0;
|
||||||
|
data_reg2 <= 0;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
i_tready <= 1'b0;
|
||||||
|
|
||||||
|
end else begin
|
||||||
|
case (state)
|
||||||
|
// Nothing in either register.
|
||||||
|
// Upstream can always push data to us.
|
||||||
|
// Downstream has nothing to take from us.
|
||||||
|
EMPTY: begin
|
||||||
|
if (i_tvalid) begin
|
||||||
|
data_reg1 <= i_tdata;
|
||||||
|
state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
state <= EMPTY;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// First Register Full.
|
||||||
|
// Upstream can always push data to us.
|
||||||
|
// Downstream can always read from us.
|
||||||
|
HALF: begin
|
||||||
|
if (i_tvalid && o_tready) begin
|
||||||
|
data_reg1 <= i_tdata;
|
||||||
|
state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end else if (i_tvalid) begin
|
||||||
|
data_reg1 <= i_tdata;
|
||||||
|
data_reg2 <= data_reg1;
|
||||||
|
state <= FULL;
|
||||||
|
i_tready <= 1'b0;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end else if (o_tready) begin
|
||||||
|
state <= EMPTY;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end // case: HALF
|
||||||
|
// Both Registers Full.
|
||||||
|
// Upstream can not push to us in this state.
|
||||||
|
// Downstream can always read from us.
|
||||||
|
FULL: begin
|
||||||
|
if (o_tready) begin
|
||||||
|
state <= HALF;
|
||||||
|
i_tready <= 1'b1;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
state <= FULL;
|
||||||
|
i_tready <= 1'b0;
|
||||||
|
o_tvalid <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase // case(state)
|
||||||
|
end // else: !if(reset | clear)
|
||||||
|
|
||||||
|
assign o_tdata = (state == FULL) ? data_reg2 : data_reg1;
|
||||||
|
|
||||||
|
|
||||||
|
endmodule // axi_fast_fifo
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
module axi_lite_slave
|
||||||
|
(
|
||||||
|
input aclk, // Global AXI clock
|
||||||
|
input aresetn, // Global AXI reset, active low.
|
||||||
|
//
|
||||||
|
// AXI Write address channel
|
||||||
|
//
|
||||||
|
input [31 : 0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst
|
||||||
|
input [2 : 0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
input m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr
|
||||||
|
output m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Write data channel.
|
||||||
|
//
|
||||||
|
input [31 : 0] m_axi_wdata, // Write data
|
||||||
|
input [3 : 0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data.
|
||||||
|
input m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available.
|
||||||
|
output m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data.
|
||||||
|
//
|
||||||
|
// AXI Write response channel signals
|
||||||
|
//
|
||||||
|
output [1 : 0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction.
|
||||||
|
output m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response
|
||||||
|
input m_axi_bready, // Response ready. This signal indicates that the master can accept a write response
|
||||||
|
//
|
||||||
|
// AXI Read address channel
|
||||||
|
//
|
||||||
|
input [31 : 0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst
|
||||||
|
input [2 : 0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||||
|
input m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr
|
||||||
|
output m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address
|
||||||
|
//
|
||||||
|
// AXI Read data channel
|
||||||
|
//
|
||||||
|
output [31 : 0] m_axi_rdata, // Read data.
|
||||||
|
output [1 : 0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer
|
||||||
|
output m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data.
|
||||||
|
input m_axi_rready, // Read ready. This signal indicates that the master can accept the read data and response
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
)
|
||||||
@@ -24,4 +24,5 @@ axi_test_vfifo.v \
|
|||||||
dram_2port.v \
|
dram_2port.v \
|
||||||
cvita_uart.v \
|
cvita_uart.v \
|
||||||
serial_to_settings.v \
|
serial_to_settings.v \
|
||||||
|
filter_bad_sid.v \
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This module forms the qualification engine for a single master as
|
// This module forms the qualification engine for a single master as
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
`define LOG2(N) (\
|
`define LOG2(N) (\
|
||||||
N < 2 ? 0 : \
|
N < 2 ? 0 : \
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
`timescale 1 ps / 1 ps
|
`timescale 1 ps / 1 ps
|
||||||
|
|
||||||
module axi_crossbar_tb;
|
module axi_crossbar_tb;
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This module is connected to the output port of an AXI4-STREAM FIFO that is used to move packetized data.
|
// This module is connected to the output port of an AXI4-STREAM FIFO that is used to move packetized data.
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This module implements a highly customized TCAM that enbales forwarding
|
// This module implements a highly customized TCAM that enbales forwarding
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//create a compressed vita based uart data interface
|
//create a compressed vita based uart data interface
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
// Discard silently packets which don't match this SID
|
||||||
|
|
||||||
|
module filter_bad_sid
|
||||||
|
(
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
input clear,
|
||||||
|
//
|
||||||
|
input [64:0] i_tdata,
|
||||||
|
input i_tvalid,
|
||||||
|
output i_tready,
|
||||||
|
//
|
||||||
|
output [64:0] o_tdata,
|
||||||
|
output o_tvalid,
|
||||||
|
input o_tready,
|
||||||
|
//
|
||||||
|
output reg [15:0] count
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [1:0] state;
|
||||||
|
wire good_sid;
|
||||||
|
wire qualify_i_tvalid;
|
||||||
|
|
||||||
|
localparam IDLE = 0;
|
||||||
|
localparam ACCEPT = 1;
|
||||||
|
localparam DISCARD = 2;
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset | clear) begin
|
||||||
|
state <= IDLE;
|
||||||
|
count <= 0;
|
||||||
|
end else
|
||||||
|
case(state)
|
||||||
|
//
|
||||||
|
IDLE: begin
|
||||||
|
if (i_tvalid && i_tready)
|
||||||
|
if (good_sid)
|
||||||
|
state <= ACCEPT;
|
||||||
|
else begin
|
||||||
|
count <= count + 1;
|
||||||
|
state <= DISCARD;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//
|
||||||
|
ACCEPT: begin
|
||||||
|
if (i_tvalid && i_tready && i_tdata[64])
|
||||||
|
state <= IDLE;
|
||||||
|
end
|
||||||
|
//
|
||||||
|
DISCARD: begin
|
||||||
|
if (i_tvalid && i_tready && i_tdata[64])
|
||||||
|
state <= IDLE;
|
||||||
|
end
|
||||||
|
endcase // case(state)
|
||||||
|
|
||||||
|
assign good_sid = ((i_tdata[15:0] == 16'h00A0) || (i_tdata[15:0] == 16'h00B0));
|
||||||
|
|
||||||
|
assign qualify_i_tvalid = (state == IDLE) ? good_sid : ((state == DISCARD) ? 1'b0 : 1'b1);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Buffer output, break combinatorial timing paths
|
||||||
|
//
|
||||||
|
axi_fifo_short #(.WIDTH(65)) fifo_short
|
||||||
|
(
|
||||||
|
.clk(clk), .reset(reset), .clear(clear),
|
||||||
|
.i_tdata(i_tdata), .i_tvalid(i_tvalid && qualify_i_tvalid), .i_tready(i_tready),
|
||||||
|
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
|
||||||
|
.space(), .occupied()
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule // axi_fast_fifo
|
||||||
+6
-16
@@ -2,24 +2,14 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module gpio_atr
|
module gpio_atr
|
||||||
#(parameter BASE = 0,
|
#(parameter BASE = 0,
|
||||||
parameter WIDTH = 32)
|
parameter WIDTH = 32,
|
||||||
|
parameter default_ddr = 0,
|
||||||
|
parameter default_idle = 0)
|
||||||
(input clk, input reset,
|
(input clk, input reset,
|
||||||
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||||
input rx, input tx,
|
input rx, input tx,
|
||||||
@@ -32,7 +22,7 @@ module gpio_atr
|
|||||||
reg [WIDTH-1:0] gpio_pipe;
|
reg [WIDTH-1:0] gpio_pipe;
|
||||||
|
|
||||||
|
|
||||||
setting_reg #(.my_addr(BASE+0), .width(WIDTH)) reg_idle
|
setting_reg #(.my_addr(BASE+0), .width(WIDTH), .at_reset(default_idle)) reg_idle
|
||||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
||||||
.out(in_idle),.changed());
|
.out(in_idle),.changed());
|
||||||
|
|
||||||
@@ -48,7 +38,7 @@ module gpio_atr
|
|||||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
||||||
.out(in_fdx),.changed());
|
.out(in_fdx),.changed());
|
||||||
|
|
||||||
setting_reg #(.my_addr(BASE+4), .width(WIDTH)) reg_ddr
|
setting_reg #(.my_addr(BASE+4), .width(WIDTH), .at_reset(default_ddr)) reg_ddr
|
||||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
||||||
.out(ddr),.changed());
|
.out(ddr),.changed());
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module por_gen
|
module por_gen
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ module serial_to_settings
|
|||||||
// Settngs bus out
|
// Settngs bus out
|
||||||
output reg set_stb,
|
output reg set_stb,
|
||||||
output reg [7:0] set_addr,
|
output reg [7:0] set_addr,
|
||||||
output reg [31:0] set_data
|
output reg [31:0] set_data,
|
||||||
|
// Debug
|
||||||
|
output [31:0] debug
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [2:0] state;
|
reg [2:0] state;
|
||||||
@@ -105,6 +107,14 @@ module serial_to_settings
|
|||||||
|
|
||||||
endcase // case(state)
|
endcase // case(state)
|
||||||
end // else: !if(reset)
|
end // else: !if(reset)
|
||||||
|
|
||||||
|
assign debug =
|
||||||
|
{
|
||||||
|
counter[4:0],
|
||||||
|
state[2:0],
|
||||||
|
scl_reg,
|
||||||
|
sda_reg
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,34 @@ module serial_to_settings_tb();
|
|||||||
.set_data(set_data)
|
.set_data(set_data)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Nasty HAck to convert settings to wishbone crudely.
|
||||||
|
reg wb_stb;
|
||||||
|
wire wb_ack_o;
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (reset)
|
||||||
|
wb_stb <= 0;
|
||||||
|
else
|
||||||
|
wb_stb <= set_stb ? 1 : ((wb_ack_o) ? 0 : wb_stb);
|
||||||
|
|
||||||
|
simple_uart debug_uart
|
||||||
|
(
|
||||||
|
.clk_i(clk),
|
||||||
|
.rst_i(reset),
|
||||||
|
.we_i(wb_stb),
|
||||||
|
.stb_i(wb_stb),
|
||||||
|
.cyc_i(wb_stb),
|
||||||
|
.ack_o(wb_ack_o),
|
||||||
|
.adr_i(set_addr[2:0]),
|
||||||
|
.dat_i(set_data[31:0]),
|
||||||
|
.dat_o(),
|
||||||
|
.rx_int_o(),
|
||||||
|
.tx_int_o(),
|
||||||
|
.tx_o(txd),
|
||||||
|
.rx_i(rxd),
|
||||||
|
.baud_o()
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Bring in a simulation script here
|
// Bring in a simulation script here
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011-2012 Ettus Research LLC
|
// Copyright 2011-2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
//-- A settings register is a peripheral for the settings register bus.
|
//-- A settings register is a peripheral for the settings register bus.
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011-2012 Ettus Research LLC
|
// Copyright 2011-2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Simple I2C core
|
// Simple I2C core
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Simple SPI core, the simplest, yet complete spi core I can think of
|
// Simple SPI core, the simplest, yet complete spi core I can think of
|
||||||
|
|
||||||
@@ -69,9 +57,9 @@ module simple_spi_core
|
|||||||
output ready,
|
output ready,
|
||||||
|
|
||||||
//spi interface, slave selects, clock, data in, data out
|
//spi interface, slave selects, clock, data in, data out
|
||||||
output [WIDTH-1:0] sen,
|
output reg [WIDTH-1:0] sen,
|
||||||
output sclk,
|
output sclk,
|
||||||
output mosi,
|
output reg mosi,
|
||||||
input miso,
|
input miso,
|
||||||
|
|
||||||
//optional debug output
|
//optional debug output
|
||||||
@@ -113,22 +101,30 @@ module simple_spi_core
|
|||||||
assign sclk = sclk_reg;
|
assign sclk = sclk_reg;
|
||||||
|
|
||||||
//serial enables either idle or enabled based on state
|
//serial enables either idle or enabled based on state
|
||||||
|
// IJB. One pipeline stage to break critical path from register in I/O pads.
|
||||||
wire sen_is_idle = (state == WAIT_TRIG) || (state == IDLE_SEN);
|
wire sen_is_idle = (state == WAIT_TRIG) || (state == IDLE_SEN);
|
||||||
wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
|
wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
|
||||||
reg [WIDTH-1:0] sen_reg;
|
reg [WIDTH-1:0] sen_reg;
|
||||||
always @(posedge clock) sen_reg <= sen24[WIDTH-1:0];
|
always @(posedge clock)
|
||||||
assign sen = sen_reg;
|
sen_reg <= sen24[WIDTH-1:0];
|
||||||
|
always @(posedge clock)
|
||||||
|
sen <= sen_reg;
|
||||||
|
|
||||||
//data output shift register
|
//data output shift register
|
||||||
|
// IJB. One pipeline stage to break critical path from register in I/O pads.
|
||||||
reg [31:0] dataout_reg;
|
reg [31:0] dataout_reg;
|
||||||
wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0};
|
wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0};
|
||||||
assign mosi = dataout_reg[31];
|
|
||||||
|
always @(posedge clock)
|
||||||
|
mosi <= dataout_reg[31];
|
||||||
|
|
||||||
//data input shift register
|
//data input shift register
|
||||||
// IJB. One pipeline stage to break critical path from register in I/O pads.
|
// IJB. Two pipeline stages to break critical path from register in I/O pads.
|
||||||
reg miso_pipe;
|
reg miso_pipe, miso_pipe2;
|
||||||
always @(posedge clock)
|
always @(posedge clock) begin
|
||||||
miso_pipe = miso;
|
miso_pipe2 <= miso;
|
||||||
|
miso_pipe <= miso_pipe2;
|
||||||
|
end
|
||||||
|
|
||||||
reg [31:0] datain_reg;
|
reg [31:0] datain_reg;
|
||||||
wire [31:0] datain_next = {datain_reg[30:0], miso_pipe};
|
wire [31:0] datain_next = {datain_reg[30:0], miso_pipe};
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
coregen.log
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
# DSP Sources
|
# DSP Sources
|
||||||
##################################################
|
##################################################
|
||||||
DSP_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/dsp/, \
|
DSP_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/dsp/, \
|
||||||
|
ddc_chain_x300.v \
|
||||||
ddc_chain.v \
|
ddc_chain.v \
|
||||||
duc_chain.v \
|
duc_chain.v \
|
||||||
sign_extend.v \
|
sign_extend.v \
|
||||||
@@ -34,5 +35,6 @@ round.v \
|
|||||||
srl.v \
|
srl.v \
|
||||||
acc.v \
|
acc.v \
|
||||||
rx_frontend.v \
|
rx_frontend.v \
|
||||||
|
tx_frontend.v \
|
||||||
rx_dcoffset.v \
|
rx_dcoffset.v \
|
||||||
))
|
))
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module acc
|
module acc
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module add2
|
module add2
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module add2_and_round
|
module add2_and_round
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module add2_and_round_reg
|
module add2_and_round_reg
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module add2_reg
|
module add2_reg
|
||||||
|
|||||||
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003 Matt Ettus
|
// Copyright (C) 2003 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003 Matt Ettus
|
// Copyright (C) 2003 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003 Matt Ettus
|
// Copyright (C) 2003 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003 Matt Ettus
|
// Copyright (C) 2003 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -3,19 +3,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2008 Matt Ettus
|
// Copyright (C) 2008 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
module cic_strober
|
module cic_strober
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2008 Matt Ettus
|
// Copyright (C) 2008 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
// Clipping "macro", keeps the bottom bits
|
// Clipping "macro", keeps the bottom bits
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2008 Matt Ettus
|
// Copyright (C) 2008 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
// Clipping "macro", keeps the bottom bits
|
// Clipping "macro", keeps the bottom bits
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003 Matt Ettus
|
// Copyright (C) 2003 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
module cordic_stage( clock, reset, enable, xi,yi,zi,constant,xo,yo,zo);
|
module cordic_stage( clock, reset, enable, xi,yi,zi,constant,xo,yo,zo);
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003, 2007 Matt Ettus
|
// Copyright (C) 2003, 2007 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo );
|
module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo );
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011-2013 Ettus Research LLC
|
// Copyright 2011-2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//! The USRP digital down-conversion chain
|
//! The USRP digital down-conversion chain
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2011-2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
//! X300/X310 digital down-conversion chain
|
||||||
|
|
||||||
|
module ddc_chain_x300
|
||||||
|
#(
|
||||||
|
parameter BASE = 0,
|
||||||
|
parameter DSPNO = 0,
|
||||||
|
parameter WIDTH = 24
|
||||||
|
)
|
||||||
|
(input clk, input rst, input clr,
|
||||||
|
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||||
|
|
||||||
|
// From RX frontend
|
||||||
|
input [WIDTH-1:0] rx_fe_i,
|
||||||
|
input [WIDTH-1:0] rx_fe_q,
|
||||||
|
|
||||||
|
// To RX control
|
||||||
|
output [31:0] sample,
|
||||||
|
input run,
|
||||||
|
output strobe,
|
||||||
|
output [31:0] debug
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam cwidth = 25;
|
||||||
|
localparam zwidth = 24;
|
||||||
|
|
||||||
|
wire [31:0] phase_inc;
|
||||||
|
reg [31:0] phase;
|
||||||
|
|
||||||
|
wire [17:0] scale_factor;
|
||||||
|
wire [cwidth-1:0] i_cordic, q_cordic;
|
||||||
|
wire [WIDTH-1:0] i_cordic_clip, q_cordic_clip;
|
||||||
|
wire [WIDTH-1:0] i_cic, q_cic;
|
||||||
|
wire [46:0] i_hb1, q_hb1;
|
||||||
|
wire [46:0] i_hb2, q_hb2;
|
||||||
|
wire [47:0] i_hb3, q_hb3;
|
||||||
|
|
||||||
|
wire strobe_cic, strobe_hb1, strobe_hb2, strobe_hb3;
|
||||||
|
|
||||||
|
wire [7:0] cic_decim_rate;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] rx_fe_i_mux, rx_fe_q_mux;
|
||||||
|
wire realmode;
|
||||||
|
wire swap_iq;
|
||||||
|
wire [1:0] hb_rate;
|
||||||
|
wire [2:0] enable_hb = { hb_rate == 2'b11, hb_rate[1] == 1'b1, hb_rate != 2'b00 };
|
||||||
|
|
||||||
|
wire reload_go, reload_we1, reload_we2, reload_we3, reload_ld1, reload_ld2, reload_ld3;
|
||||||
|
wire [17:0] coef_din;
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+0)) sr_0
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(phase_inc),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+1), .width(18)) sr_1
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(scale_factor),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+2), .width(10)) sr_2
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out({hb_rate, cic_decim_rate}),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+3), .width(2)) sr_3
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out({realmode,swap_iq}),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+4), .width(24)) sr_4
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out({reload_ld3,reload_we3,reload_ld2,reload_we2,reload_ld1,reload_we1,coef_din}),.changed(reload_go));
|
||||||
|
|
||||||
|
// MUX so we can do realmode signals on either input
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if(swap_iq)
|
||||||
|
begin
|
||||||
|
rx_fe_i_mux <= rx_fe_q;
|
||||||
|
rx_fe_q_mux <= realmode ? 0 : rx_fe_i;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
rx_fe_i_mux <= rx_fe_i;
|
||||||
|
rx_fe_q_mux <= realmode ? 0 : rx_fe_q;
|
||||||
|
end
|
||||||
|
|
||||||
|
// NCO
|
||||||
|
always @(posedge clk)
|
||||||
|
if(rst)
|
||||||
|
phase <= 0;
|
||||||
|
else if(~run)
|
||||||
|
phase <= 0;
|
||||||
|
else
|
||||||
|
phase <= phase + phase_inc;
|
||||||
|
|
||||||
|
//sign extension of cordic input
|
||||||
|
wire [cwidth-1:0] to_cordic_i, to_cordic_q;
|
||||||
|
sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_i (.in(rx_fe_i_mux), .out(to_cordic_i));
|
||||||
|
sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_q (.in(rx_fe_q_mux), .out(to_cordic_q));
|
||||||
|
|
||||||
|
// CORDIC 24-bit I/O
|
||||||
|
cordic_z24 #(.bitwidth(cwidth))
|
||||||
|
cordic(.clock(clk), .reset(rst), .enable(run),
|
||||||
|
.xi(to_cordic_i),. yi(to_cordic_q), .zi(phase[31:32-zwidth]),
|
||||||
|
.xo(i_cordic),.yo(q_cordic),.zo() );
|
||||||
|
|
||||||
|
clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_cordic_i
|
||||||
|
(.clk(clk), .in(i_cordic), .strobe_in(1'b1), .out(i_cordic_clip));
|
||||||
|
clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_cordic_q
|
||||||
|
(.clk(clk), .in(q_cordic), .strobe_in(1'b1), .out(q_cordic_clip));
|
||||||
|
|
||||||
|
// CIC decimator 24 bit I/O
|
||||||
|
cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate),
|
||||||
|
.strobe_fast(1'b1),.strobe_slow(strobe_cic) );
|
||||||
|
|
||||||
|
cic_decim #(.bw(WIDTH))
|
||||||
|
decim_i (.clock(clk),.reset(rst),.enable(run),
|
||||||
|
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
|
||||||
|
.signal_in(i_cordic_clip),.signal_out(i_cic));
|
||||||
|
|
||||||
|
cic_decim #(.bw(WIDTH))
|
||||||
|
decim_q (.clock(clk),.reset(rst),.enable(run),
|
||||||
|
.rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic),
|
||||||
|
.signal_in(q_cordic_clip),.signal_out(q_cic));
|
||||||
|
|
||||||
|
// Halfbands
|
||||||
|
wire nd1, nd2, nd3;
|
||||||
|
wire rfd1, rfd2, rfd3;
|
||||||
|
wire rdy1, rdy2, rdy3;
|
||||||
|
wire data_valid1, data_valid2, data_valid3;
|
||||||
|
|
||||||
|
localparam HB1_SCALE = 18;
|
||||||
|
localparam HB2_SCALE = 18;
|
||||||
|
localparam HB3_SCALE = 18;
|
||||||
|
|
||||||
|
assign strobe_hb1 = data_valid1;
|
||||||
|
assign strobe_hb2 = data_valid2;
|
||||||
|
assign strobe_hb3 = data_valid3;
|
||||||
|
assign nd1 = strobe_cic;
|
||||||
|
assign nd2 = strobe_hb1;
|
||||||
|
assign nd3 = strobe_hb2;
|
||||||
|
|
||||||
|
hbdec1 hbdec1
|
||||||
|
(.clk(clk), // input clk
|
||||||
|
.sclr(rst), // input sclr
|
||||||
|
.ce(enable_hb[0]), // input ce
|
||||||
|
.coef_ld(reload_go & reload_ld1), // input coef_ld
|
||||||
|
.coef_we(reload_go & reload_we1), // input coef_we
|
||||||
|
.coef_din(coef_din), // input [17 : 0] coef_din
|
||||||
|
.rfd(rfd1), // output rfd
|
||||||
|
.nd(nd1), // input nd
|
||||||
|
.din_1(i_cic), // input [23 : 0] din_1
|
||||||
|
.din_2(q_cic), // input [23 : 0] din_2
|
||||||
|
.rdy(rdy1), // output rdy
|
||||||
|
.data_valid(data_valid1), // output data_valid
|
||||||
|
.dout_1(i_hb1), // output [46 : 0] dout_1
|
||||||
|
.dout_2(q_hb1)); // output [46 : 0] dout_2
|
||||||
|
|
||||||
|
hbdec2 hbdec2
|
||||||
|
(.clk(clk), // input clk
|
||||||
|
.sclr(rst), // input sclr
|
||||||
|
.ce(enable_hb[1]), // input ce
|
||||||
|
.coef_ld(reload_go & reload_ld2), // input coef_ld
|
||||||
|
.coef_we(reload_go & reload_we2), // input coef_we
|
||||||
|
.coef_din(coef_din), // input [17 : 0] coef_din
|
||||||
|
.rfd(rfd2), // output rfd
|
||||||
|
.nd(nd2), // input nd
|
||||||
|
.din_1(i_hb1[23+HB1_SCALE:HB1_SCALE]), // input [23 : 0] din_1
|
||||||
|
.din_2(q_hb1[23+HB1_SCALE:HB1_SCALE]), // input [23 : 0] din_2
|
||||||
|
.rdy(rdy2), // output rdy
|
||||||
|
.data_valid(data_valid2), // output data_valid
|
||||||
|
.dout_1(i_hb2), // output [46 : 0] dout_1
|
||||||
|
.dout_2(q_hb2)); // output [46 : 0] dout_2
|
||||||
|
|
||||||
|
hbdec3 hbdec3
|
||||||
|
(.clk(clk), // input clk
|
||||||
|
.sclr(rst), // input sclr
|
||||||
|
.ce(enable_hb[2]), // input ce
|
||||||
|
.coef_ld(reload_go & reload_ld3), // input coef_ld
|
||||||
|
.coef_we(reload_go & reload_we3), // input coef_we
|
||||||
|
.coef_din(coef_din), // input [17 : 0] coef_din
|
||||||
|
.rfd(rfd3), // output rfd
|
||||||
|
.nd(strobe_hb2), // input nd
|
||||||
|
.din_1(i_hb2[23+HB2_SCALE:HB2_SCALE]), // input [23 : 0] din_1
|
||||||
|
.din_2(q_hb2[23+HB2_SCALE:HB2_SCALE]), // input [23 : 0] din_2
|
||||||
|
.rdy(rdy3), // output rdy
|
||||||
|
.data_valid(data_valid3), // output data_valid
|
||||||
|
.dout_1(i_hb3), // output [47 : 0] dout_1
|
||||||
|
.dout_2(q_hb3)); // output [47 : 0] dout_2
|
||||||
|
|
||||||
|
reg [23:0] i_unscaled, q_unscaled;
|
||||||
|
reg strobe_unscaled;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
case(hb_rate)
|
||||||
|
2'd0 :
|
||||||
|
begin
|
||||||
|
strobe_unscaled <= strobe_cic;
|
||||||
|
i_unscaled <= i_cic[23:0];
|
||||||
|
q_unscaled <= q_cic[23:0];
|
||||||
|
end
|
||||||
|
2'd1 :
|
||||||
|
begin
|
||||||
|
strobe_unscaled <= strobe_hb1;
|
||||||
|
i_unscaled <= i_hb1[23+HB1_SCALE:HB1_SCALE];
|
||||||
|
q_unscaled <= q_hb1[23+HB1_SCALE:HB1_SCALE];
|
||||||
|
end
|
||||||
|
2'd2 :
|
||||||
|
begin
|
||||||
|
strobe_unscaled <= strobe_hb2;
|
||||||
|
i_unscaled <= i_hb2[23+HB2_SCALE:HB2_SCALE];
|
||||||
|
q_unscaled <= q_hb2[23+HB2_SCALE:HB2_SCALE];
|
||||||
|
end
|
||||||
|
2'd3 :
|
||||||
|
begin
|
||||||
|
strobe_unscaled <= strobe_hb3;
|
||||||
|
i_unscaled <= i_hb3[23+HB3_SCALE:HB3_SCALE];
|
||||||
|
q_unscaled <= q_hb3[23+HB3_SCALE:HB3_SCALE];
|
||||||
|
end
|
||||||
|
endcase // case (hb_rate)
|
||||||
|
|
||||||
|
wire [42:0] i_scaled, q_scaled;
|
||||||
|
wire [23:0] i_clip, q_clip;
|
||||||
|
reg strobe_scaled;
|
||||||
|
wire strobe_clip;
|
||||||
|
|
||||||
|
MULT_MACRO #(.DEVICE("7SERIES"), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES"
|
||||||
|
.LATENCY(1), // Desired clock cycle latency, 0-4
|
||||||
|
.WIDTH_A(25), // Multiplier A-input bus width, 1-25
|
||||||
|
.WIDTH_B(18)) // Multiplier B-input bus width, 1-18
|
||||||
|
SCALE_I (.P(i_scaled), // Multiplier output bus, width determined by WIDTH_P parameter
|
||||||
|
.A({i_unscaled[23],i_unscaled}), // Multiplier input A bus, width determined by WIDTH_A parameter
|
||||||
|
.B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter
|
||||||
|
.CE(strobe_unscaled), // 1-bit active high input clock enable
|
||||||
|
.CLK(clk), // 1-bit positive edge clock input
|
||||||
|
.RST(rst)); // 1-bit input active high reset
|
||||||
|
|
||||||
|
MULT_MACRO #(.DEVICE("7SERIES"), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES"
|
||||||
|
.LATENCY(1), // Desired clock cycle latency, 0-4
|
||||||
|
.WIDTH_A(25), // Multiplier A-input bus width, 1-25
|
||||||
|
.WIDTH_B(18)) // Multiplier B-input bus width, 1-18
|
||||||
|
SCALE_Q (.P(q_scaled), // Multiplier output bus, width determined by WIDTH_P parameter
|
||||||
|
.A({q_unscaled[23],q_unscaled}), // Multiplier input A bus, width determined by WIDTH_A parameter
|
||||||
|
.B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter
|
||||||
|
.CE(strobe_unscaled), // 1-bit active high input clock enable
|
||||||
|
.CLK(clk), // 1-bit positive edge clock input
|
||||||
|
.RST(rst)); // 1-bit input active high reset
|
||||||
|
|
||||||
|
always @(posedge clk) strobe_scaled <= strobe_unscaled;
|
||||||
|
|
||||||
|
clip_reg #(.bits_in(29), .bits_out(24), .STROBED(1)) clip_i
|
||||||
|
(.clk(clk), .in(i_scaled[42:14]), .strobe_in(strobe_scaled), .out(i_clip), .strobe_out(strobe_clip));
|
||||||
|
clip_reg #(.bits_in(29), .bits_out(24), .STROBED(1)) clip_q
|
||||||
|
(.clk(clk), .in(q_scaled[42:14]), .strobe_in(strobe_scaled), .out(q_clip), .strobe_out());
|
||||||
|
|
||||||
|
round_sd #(.WIDTH_IN(24), .WIDTH_OUT(16)) round_i
|
||||||
|
(.clk(clk), .reset(rst), .in(i_clip), .strobe_in(strobe_clip), .out(sample[31:16]), .strobe_out(strobe));
|
||||||
|
round_sd #(.WIDTH_IN(24), .WIDTH_OUT(16)) round_q
|
||||||
|
(.clk(clk), .reset(rst), .in(q_clip), .strobe_in(strobe_clip), .out(sample[15:0]), .strobe_out());
|
||||||
|
|
||||||
|
endmodule // ddc_chain
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
|
module ddc_chain_x300_tb();
|
||||||
|
|
||||||
|
`ifdef ISIM
|
||||||
|
`else //iverilog implied.
|
||||||
|
// xlnx_glbl glbl (.GSR(),.GTS());
|
||||||
|
`endif
|
||||||
|
|
||||||
|
localparam SR_TX_DSP = 8;
|
||||||
|
|
||||||
|
reg clk = 0;
|
||||||
|
reg reset = 1;
|
||||||
|
|
||||||
|
always #10 clk = ~clk;
|
||||||
|
|
||||||
|
initial $dumpfile("ddc_chain_x300_tb.vcd");
|
||||||
|
initial $dumpvars(0,ddc_chain_x300_tb);
|
||||||
|
reg run = 0;
|
||||||
|
wire strobe;
|
||||||
|
|
||||||
|
initial
|
||||||
|
begin
|
||||||
|
#1000 reset = 0;
|
||||||
|
@(posedge clk);
|
||||||
|
set_addr <= 0; set_data <= 32'd8434349; set_stb <= 1; @(posedge clk); // CORDIC
|
||||||
|
set_addr <= 1; set_data <= 18'd19800; set_stb <= 1; @(posedge clk); // Scale factor
|
||||||
|
set_addr <= 2; set_data <= 10'h003; set_stb <= 1; @(posedge clk); // Decim control
|
||||||
|
set_addr <= 3; set_data <= 0; set_stb <= 1; @(posedge clk); // Swap iq
|
||||||
|
set_addr <= 4; set_data <= 0; set_stb <= 1; @(posedge clk); // filter taps
|
||||||
|
set_stb <= 0;
|
||||||
|
|
||||||
|
repeat(10)
|
||||||
|
@(posedge clk);
|
||||||
|
run <= 1'b1;
|
||||||
|
#30000;
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
reg [7:0] set_addr;
|
||||||
|
reg [31:0] set_data;
|
||||||
|
reg set_stb = 1'b0;
|
||||||
|
|
||||||
|
wire [15:0] i_out, q_out;
|
||||||
|
wire [23:0] rx_fe_i, rx_fe_q;
|
||||||
|
|
||||||
|
assign rx_fe_i = 24'd8388607;
|
||||||
|
assign rx_fe_q = 24'd8388607;
|
||||||
|
//assign rx_fe_q = 0;
|
||||||
|
|
||||||
|
ddc_chain_x300 #(.BASE(0), .DSPNO(0), .WIDTH(24)) ddc_chain
|
||||||
|
(.clk(clk), .rst(reset), .clr(1'b0),
|
||||||
|
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
||||||
|
.rx_fe_i(rx_fe_i),.rx_fe_q(rx_fe_q),
|
||||||
|
.sample({i_out,q_out}), .run(run), .strobe(strobe),
|
||||||
|
.debug() );
|
||||||
|
|
||||||
|
endmodule // new_tx_tb
|
||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011-2013 Ettus Research LLC
|
// Copyright 2011-2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//! The USRP digital up-conversion chain
|
//! The USRP digital up-conversion chain
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Final halfband decimator
|
// Final halfband decimator
|
||||||
// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
|
// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// First halfband iterpolator
|
// First halfband iterpolator
|
||||||
// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
|
// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2011 Matt Ettus
|
// Copyright (C) 2011 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
// Rounding "macro"
|
// Rounding "macro"
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2008 Matt Ettus
|
// Copyright (C) 2008 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
// Rounding "macro"
|
// Rounding "macro"
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+18
-22
@@ -14,8 +14,9 @@ module rx_frontend
|
|||||||
);
|
);
|
||||||
|
|
||||||
reg [15:0] adc_i, adc_q;
|
reg [15:0] adc_i, adc_q;
|
||||||
wire [17:0] adc_i_ofs, adc_q_ofs;
|
wire [23:0] adc_i_ofs, adc_q_ofs;
|
||||||
wire [35:0] corr_i, corr_q; wire [17:0] mag_corr,phase_corr;
|
wire [35:0] corr_i, corr_q;
|
||||||
|
wire [17:0] mag_corr,phase_corr;
|
||||||
wire swap_iq;
|
wire swap_iq;
|
||||||
|
|
||||||
setting_reg #(.my_addr(BASE), .width(1)) sr_8
|
setting_reg #(.my_addr(BASE), .width(1)) sr_8
|
||||||
@@ -36,43 +37,38 @@ module rx_frontend
|
|||||||
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
.in(set_data),.out(phase_corr),.changed());
|
.in(set_data),.out(phase_corr),.changed());
|
||||||
|
|
||||||
|
rx_dcoffset #(.WIDTH(24),.ADDR(BASE+3)) rx_dcoffset_i
|
||||||
|
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
||||||
|
.in({adc_i,8'b00}),.out(adc_i_ofs));
|
||||||
|
|
||||||
|
rx_dcoffset #(.WIDTH(24),.ADDR(BASE+4)) rx_dcoffset_q
|
||||||
|
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
||||||
|
.in({adc_q,8'b00}),.out(adc_q_ofs));
|
||||||
|
|
||||||
generate
|
generate
|
||||||
if(IQCOMP_EN == 1)
|
if(IQCOMP_EN == 1)
|
||||||
begin
|
begin
|
||||||
rx_dcoffset #(.WIDTH(18),.ADDR(BASE+3)) rx_dcoffset_i
|
|
||||||
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
|
||||||
.in({adc_i,2'b00}),.out(adc_i_ofs));
|
|
||||||
|
|
||||||
rx_dcoffset #(.WIDTH(18),.ADDR(BASE+4)) rx_dcoffset_q
|
|
||||||
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
|
||||||
.in({adc_q,2'b00}),.out(adc_q_ofs));
|
|
||||||
|
|
||||||
MULT18X18S mult_mag_corr
|
MULT18X18S mult_mag_corr
|
||||||
(.P(corr_i), .A(adc_i_ofs), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
|
(.P(corr_i), .A(adc_i_ofs[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
|
||||||
|
|
||||||
MULT18X18S mult_phase_corr
|
MULT18X18S mult_phase_corr
|
||||||
(.P(corr_q), .A(adc_i_ofs), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
|
(.P(corr_q), .A(adc_i_ofs[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
|
||||||
|
|
||||||
add2_and_clip_reg #(.WIDTH(24)) add_clip_i
|
add2_and_clip_reg #(.WIDTH(24)) add_clip_i
|
||||||
(.clk(clk), .rst(rst),
|
(.clk(clk), .rst(rst),
|
||||||
.in1({adc_i_ofs,6'd0}), .in2(corr_i[35:12]), .strobe_in(1'b1),
|
.in1(adc_i_ofs), .in2(corr_i[35:12]), .strobe_in(1'b1),
|
||||||
.sum(i_out), .strobe_out());
|
.sum(i_out), .strobe_out());
|
||||||
|
|
||||||
add2_and_clip_reg #(.WIDTH(24)) add_clip_q
|
add2_and_clip_reg #(.WIDTH(24)) add_clip_q
|
||||||
(.clk(clk), .rst(rst),
|
(.clk(clk), .rst(rst),
|
||||||
.in1({adc_q_ofs,6'd0}), .in2(corr_q[35:12]), .strobe_in(1'b1),
|
.in1(adc_q_ofs), .in2(corr_q[35:12]), .strobe_in(1'b1),
|
||||||
.sum(q_out), .strobe_out());
|
.sum(q_out), .strobe_out());
|
||||||
end // if (IQCOMP_EN == 1)
|
end // if (IQCOMP_EN == 1)
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
rx_dcoffset #(.WIDTH(24),.ADDR(BASE+3)) rx_dcoffset_i
|
assign i_out = adc_i_ofs;
|
||||||
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
assign q_out = adc_q_ofs;
|
||||||
.in({adc_i,8'b00}),.out(i_out));
|
|
||||||
|
|
||||||
rx_dcoffset #(.WIDTH(24),.ADDR(BASE+4)) rx_dcoffset_q
|
|
||||||
(.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
|
|
||||||
.in({adc_q,8'b00}),.out(q_out));
|
|
||||||
end // else: !if(IQCOMP_EN == 1)
|
end // else: !if(IQCOMP_EN == 1)
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
endmodule // rx_frontend
|
endmodule // rx_frontend
|
||||||
|
|||||||
@@ -13,21 +13,21 @@ module rx_frontend_tb();
|
|||||||
initial $dumpvars(0,rx_frontend_tb);
|
initial $dumpvars(0,rx_frontend_tb);
|
||||||
|
|
||||||
reg [15:0] adc_in;
|
reg [15:0] adc_in;
|
||||||
wire [17:0] adc_out;
|
wire [23:0] adc_out;
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
begin
|
begin
|
||||||
if(adc_in[13])
|
if(adc_in[15])
|
||||||
$write("-%d,",-adc_in);
|
$write("-%d,",-adc_in);
|
||||||
else
|
else
|
||||||
$write("%d,",adc_in);
|
$write("%d,",adc_in);
|
||||||
if(adc_out[13])
|
if(adc_out[23])
|
||||||
$write("-%d\n",-adc_out);
|
$write("-%d\n",-adc_out);
|
||||||
else
|
else
|
||||||
$write("%d\n",adc_out);
|
$write("%d\n",adc_out);
|
||||||
end
|
end
|
||||||
|
|
||||||
rx_frontend #(.BASE(0)) rx_frontend
|
rx_frontend #(.BASE(0), .IQCOMP_EN(1)) rx_frontend
|
||||||
(.clk(clk),.rst(rst),
|
(.clk(clk),.rst(rst),
|
||||||
.set_stb(0),.set_addr(0),.set_data(0),
|
.set_stb(0),.set_addr(0),.set_data(0),
|
||||||
.adc_a(adc_in), .adc_ovf_a(0),
|
.adc_a(adc_in), .adc_ovf_a(0),
|
||||||
|
|||||||
+1
-13
@@ -4,19 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2003 Matt Ettus
|
// Copyright (C) 2003 Matt Ettus
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation; either version 2 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Short halfband decimator (intended to be followed by another stage)
|
// Short halfband decimator (intended to be followed by another stage)
|
||||||
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
|
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Short halfband decimator (intended to be followed by another stage)
|
// Short halfband decimator (intended to be followed by another stage)
|
||||||
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
|
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module srl
|
module srl
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
module tx_frontend
|
||||||
|
#(parameter BASE=0,
|
||||||
|
parameter WIDTH_OUT=16,
|
||||||
|
parameter IQCOMP_EN=1)
|
||||||
|
(input clk, input rst,
|
||||||
|
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||||
|
input [23:0] tx_i, input [23:0] tx_q, input run,
|
||||||
|
output reg [WIDTH_OUT-1:0] dac_a, output reg [WIDTH_OUT-1:0] dac_b
|
||||||
|
);
|
||||||
|
|
||||||
|
// IQ balance --> DC offset --> rounding --> mux
|
||||||
|
|
||||||
|
wire [23:0] i_dco, q_dco, i_ofs, q_ofs;
|
||||||
|
wire [WIDTH_OUT-1:0] i_final, q_final;
|
||||||
|
wire [7:0] mux_ctrl;
|
||||||
|
wire [35:0] corr_i, corr_q;
|
||||||
|
wire [23:0] i_bal, q_bal;
|
||||||
|
wire [17:0] mag_corr, phase_corr;
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+0), .width(24)) sr_0
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(i_dco),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+1), .width(24)) sr_1
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(q_dco),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+2),.width(18)) sr_2
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(mag_corr),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+3),.width(18)) sr_3
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(phase_corr),.changed());
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(BASE+4), .width(8)) sr_4
|
||||||
|
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||||
|
.in(set_data),.out(mux_ctrl),.changed());
|
||||||
|
|
||||||
|
generate
|
||||||
|
if(IQCOMP_EN==1)
|
||||||
|
begin
|
||||||
|
// IQ Balance
|
||||||
|
MULT18X18S mult_mag_corr
|
||||||
|
(.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) );
|
||||||
|
|
||||||
|
MULT18X18S mult_phase_corr
|
||||||
|
(.P(corr_q), .A(tx_i[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) );
|
||||||
|
|
||||||
|
add2_and_clip_reg #(.WIDTH(24)) add_clip_i
|
||||||
|
(.clk(clk), .rst(rst),
|
||||||
|
.in1(tx_i), .in2(corr_i[35:12]), .strobe_in(1'b1),
|
||||||
|
.sum(i_bal), .strobe_out());
|
||||||
|
|
||||||
|
add2_and_clip_reg #(.WIDTH(24)) add_clip_q
|
||||||
|
(.clk(clk), .rst(rst),
|
||||||
|
.in1(tx_q), .in2(corr_q[35:12]), .strobe_in(1'b1),
|
||||||
|
.sum(q_bal), .strobe_out());
|
||||||
|
end // if (IQCOMP_EN==1)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
assign i_bal = tx_i;
|
||||||
|
assign q_bal = tx_q;
|
||||||
|
end // else: !if(IQCOMP_EN==1)
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
// DC Offset
|
||||||
|
add2_and_clip_reg #(.WIDTH(24)) add_dco_i
|
||||||
|
(.clk(clk), .rst(rst), .in1(i_dco), .in2(i_bal), .strobe_in(1'b1), .sum(i_ofs), .strobe_out());
|
||||||
|
|
||||||
|
add2_and_clip_reg #(.WIDTH(24)) add_dco_q
|
||||||
|
(.clk(clk), .rst(rst), .in1(q_dco), .in2(q_bal), .strobe_in(1'b1), .sum(q_ofs), .strobe_out());
|
||||||
|
|
||||||
|
// Rounding
|
||||||
|
round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_i
|
||||||
|
(.clk(clk), .reset(rst), .in(i_ofs),.strobe_in(1'b1), .out(i_final), .strobe_out());
|
||||||
|
|
||||||
|
round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_q
|
||||||
|
(.clk(clk), .reset(rst), .in(q_ofs),.strobe_in(1'b1), .out(q_final), .strobe_out());
|
||||||
|
|
||||||
|
// Mux
|
||||||
|
always @(posedge clk)
|
||||||
|
case(mux_ctrl[3:0])
|
||||||
|
0 : dac_a <= i_final;
|
||||||
|
1 : dac_a <= q_final;
|
||||||
|
default : dac_a <= 0;
|
||||||
|
endcase // case (mux_ctrl[3:0])
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
case(mux_ctrl[7:4])
|
||||||
|
0 : dac_b <= i_final;
|
||||||
|
1 : dac_b <= q_final;
|
||||||
|
default : dac_b <= 0;
|
||||||
|
endcase // case (mux_ctrl[7:4])
|
||||||
|
|
||||||
|
endmodule // tx_frontend
|
||||||
@@ -17,4 +17,5 @@ axi_fifo64_to_fifo32.v \
|
|||||||
axi_fifo32_to_fifo64.v \
|
axi_fifo32_to_fifo64.v \
|
||||||
axi_fifo_2clk.v \
|
axi_fifo_2clk.v \
|
||||||
axi_loopback.v \
|
axi_loopback.v \
|
||||||
|
axi_filter_mux4.v \
|
||||||
))
|
))
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012-2013 Ettus Research LLC
|
// Copyright 2012-2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
// Block RAM AXI fifo
|
// Block RAM AXI fifo
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Special case SIZE <= 5 uses a short fifo
|
// Special case SIZE <= 5 uses a short fifo
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 32 word FIFO with AXI4-STREAM interface.
|
// 32 word FIFO with AXI4-STREAM interface.
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
// Copyright 2014 Ettus Research LLC
|
||||||
|
// axi_filter_mux -- takes 4 64-bit AXI stream of CHDR data, merges them to 1 output channel
|
||||||
|
// Round-robin if PRIO=0, priority if PRIO=1 (lower number ports get priority)
|
||||||
|
// Bubble cycles are inserted after each packet in PRIO mode, or on wraparound in Round Robin mode.
|
||||||
|
// Filter forces specific destination SID to pass per port, else dump data to /dev/null
|
||||||
|
|
||||||
|
module axi_filter_mux4
|
||||||
|
#(parameter PRIO=0,
|
||||||
|
parameter WIDTH=64,
|
||||||
|
parameter BUFFER=0,
|
||||||
|
parameter FILTER0 =0,
|
||||||
|
parameter FILTER1 =0,
|
||||||
|
parameter FILTER2 =0,
|
||||||
|
parameter FILTER3 =0
|
||||||
|
)
|
||||||
|
(input clk, input reset, input clear,
|
||||||
|
input [WIDTH-1:0] i0_tdata, input i0_tlast, input i0_tvalid, output i0_tready,
|
||||||
|
input [WIDTH-1:0] i1_tdata, input i1_tlast, input i1_tvalid, output i1_tready,
|
||||||
|
input [WIDTH-1:0] i2_tdata, input i2_tlast, input i2_tvalid, output i2_tready,
|
||||||
|
input [WIDTH-1:0] i3_tdata, input i3_tlast, input i3_tvalid, output i3_tready,
|
||||||
|
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] o_tdata_int;
|
||||||
|
wire o_tlast_int, o_tvalid_int, o_tready_int;
|
||||||
|
|
||||||
|
reg [3:0] mx_state;
|
||||||
|
reg filter_packet;
|
||||||
|
|
||||||
|
localparam MX_IDLE = 4'b0000;
|
||||||
|
localparam MX_0 = 4'b0001;
|
||||||
|
localparam MX_1 = 4'b0010;
|
||||||
|
localparam MX_2 = 4'b0100;
|
||||||
|
localparam MX_3 = 4'b1000;
|
||||||
|
|
||||||
|
|
||||||
|
assign good0 = i0_tdata[15:0]==FILTER0;
|
||||||
|
assign good1 = i1_tdata[15:0]==FILTER1;
|
||||||
|
assign good2 = i2_tdata[15:0]==FILTER2;
|
||||||
|
assign good3 = i3_tdata[15:0]==FILTER3;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if(reset | clear)
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
else
|
||||||
|
case (mx_state)
|
||||||
|
MX_IDLE :
|
||||||
|
if(i0_tvalid) begin
|
||||||
|
mx_state <= MX_0;
|
||||||
|
filter_packet <= !good0;
|
||||||
|
end
|
||||||
|
else if(i1_tvalid) begin
|
||||||
|
mx_state <= MX_1;
|
||||||
|
filter_packet <= !good1;
|
||||||
|
end
|
||||||
|
else if(i2_tvalid) begin
|
||||||
|
mx_state <= MX_2;
|
||||||
|
filter_packet <= !good2;
|
||||||
|
end
|
||||||
|
else if(i3_tvalid) begin
|
||||||
|
mx_state <= MX_3;
|
||||||
|
filter_packet <= !good3;
|
||||||
|
end
|
||||||
|
|
||||||
|
MX_0 :
|
||||||
|
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||||
|
if(PRIO)
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
else if(i1_tvalid) begin
|
||||||
|
mx_state <= MX_1;
|
||||||
|
filter_packet <= !good1;
|
||||||
|
end
|
||||||
|
else if(i2_tvalid) begin
|
||||||
|
mx_state <= MX_2;
|
||||||
|
filter_packet <= !good2;
|
||||||
|
end
|
||||||
|
else if(i3_tvalid) begin
|
||||||
|
mx_state <= MX_3;
|
||||||
|
filter_packet <= !good3;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
filter_packet <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
MX_1 :
|
||||||
|
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||||
|
if(PRIO)
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
else if(i2_tvalid) begin
|
||||||
|
mx_state <= MX_2;
|
||||||
|
filter_packet <= !good2;
|
||||||
|
end
|
||||||
|
else if(i3_tvalid) begin
|
||||||
|
mx_state <= MX_3;
|
||||||
|
filter_packet <= !good3;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
filter_packet <= 0;
|
||||||
|
end
|
||||||
|
MX_2 :
|
||||||
|
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||||
|
if(PRIO)
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
else if(i3_tvalid) begin
|
||||||
|
mx_state <= MX_3;
|
||||||
|
filter_packet <= !good3;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
filter_packet <= 0;
|
||||||
|
end
|
||||||
|
MX_3 :
|
||||||
|
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||||
|
begin
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
filter_packet <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
default :
|
||||||
|
mx_state <= MX_IDLE;
|
||||||
|
endcase // case (mx_state)
|
||||||
|
|
||||||
|
assign {i3_tready, i2_tready, i1_tready, i0_tready} = mx_state & {4{o_tready_int}};
|
||||||
|
|
||||||
|
assign o_tvalid_int = |(mx_state & ({i3_tvalid, i2_tvalid, i1_tvalid, i0_tvalid}));
|
||||||
|
|
||||||
|
assign {o_tlast_int, o_tdata_int} = mx_state[3] ? {i3_tlast, i3_tdata} :
|
||||||
|
mx_state[2] ? {i2_tlast, i2_tdata} :
|
||||||
|
mx_state[1] ? {i1_tlast, i1_tdata} :
|
||||||
|
{i0_tlast, i0_tdata};
|
||||||
|
|
||||||
|
generate
|
||||||
|
if(BUFFER == 0)
|
||||||
|
begin
|
||||||
|
assign o_tdata = o_tdata_int;
|
||||||
|
assign o_tlast = o_tlast_int;
|
||||||
|
assign o_tvalid = o_tvalid_int & !filter_packet;
|
||||||
|
assign o_tready_int = o_tready | filter_packet;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
wire o_tready_int_fifo;
|
||||||
|
assign o_tready_int = o_tready_int_fifo | filter_packet;
|
||||||
|
|
||||||
|
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short
|
||||||
|
(.clk(clk), .reset(reset), .clear(clear),
|
||||||
|
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int & !filter_packet), .i_tready(o_tready_int_fifo),
|
||||||
|
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
|
||||||
|
.space(), .occupied());
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
endmodule // axi__mux4
|
||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Hold packets in fifo until they are complete. This prevents slowly-built packets
|
// Hold packets in fifo until they are complete. This prevents slowly-built packets
|
||||||
// from clogging up the downstream. This block will hold up to 255 packets.
|
// from clogging up the downstream. This block will hold up to 255 packets.
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This module is instantiated in parallel with a FIFO with AXI4-STREAM interfaces.
|
// This module is instantiated in parallel with a FIFO with AXI4-STREAM interfaces.
|
||||||
|
|||||||
+1
-13
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011 Ettus Research LLC
|
// Copyright 2011 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
module shortfifo
|
module shortfifo
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012-2013 Ettus Research LLC
|
// Copyright 2012-2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
module fifo64_to_gpif2
|
module fifo64_to_gpif2
|
||||||
#(
|
#(
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2011-2013 Ettus Research LLC
|
// Copyright 2011-2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012-2013 Ettus Research LLC
|
// Copyright 2012-2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
module gpif2_to_fifo64
|
module gpif2_to_fifo64
|
||||||
#(
|
#(
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- File: LvFpga_Chinch_Interface.vhd
|
||||||
|
-- Author: Ashish Chaudhari
|
||||||
|
-- Original Project: EttusUsrpB250Top
|
||||||
|
-- Date: 1 Oct 2013
|
||||||
|
--
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- (c) 2013 Copyright National Instruments Corporation
|
||||||
|
-- All Rights Reserved
|
||||||
|
-- National Instruments Internal Information
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
`include "LvFpga_Chinch_Interface.vh"
|
||||||
|
|
||||||
|
module LvFpga_Chinch_Interface
|
||||||
|
(
|
||||||
|
input aIoResetIn_n,
|
||||||
|
output bBusReset,
|
||||||
|
|
||||||
|
input BusClk,
|
||||||
|
input Rio40Clk,
|
||||||
|
input IDelayRefClk,
|
||||||
|
input aRioClkPllLocked,
|
||||||
|
output aRioClkPllReset,
|
||||||
|
|
||||||
|
output aIoReadyOut,
|
||||||
|
input aIoReadyIn,
|
||||||
|
output aIoPort2Restart,
|
||||||
|
|
||||||
|
input IoRxClock,
|
||||||
|
input IoRxClock_n,
|
||||||
|
input [`LVFPGA_IFACE_LINK_WIDTH-1:0] irIoRxData,
|
||||||
|
input [`LVFPGA_IFACE_LINK_WIDTH-1:0] irIoRxData_n,
|
||||||
|
input irIoRxHeader,
|
||||||
|
input irIoRxHeader_n,
|
||||||
|
|
||||||
|
output IoTxClock,
|
||||||
|
output IoTxClock_n,
|
||||||
|
output [`LVFPGA_IFACE_LINK_WIDTH-1:0] itIoTxData,
|
||||||
|
output [`LVFPGA_IFACE_LINK_WIDTH-1:0] itIoTxData_n,
|
||||||
|
output itIoTxHeader,
|
||||||
|
output itIoTxHeader_n,
|
||||||
|
|
||||||
|
input [(`LVFPGA_IFACE_NUM_RX_DMA_CNT*`LVFPGA_IFACE_DMA_CHAN_WIDTH)-1:0] bDmaRxData,
|
||||||
|
input [`LVFPGA_IFACE_NUM_RX_DMA_CNT-1:0] bDmaRxValid,
|
||||||
|
output [`LVFPGA_IFACE_NUM_RX_DMA_CNT-1:0] bDmaRxReady,
|
||||||
|
output [`LVFPGA_IFACE_NUM_RX_DMA_CNT-1:0] bDmaRxEnabled,
|
||||||
|
output [(`LVFPGA_IFACE_NUM_RX_DMA_CNT*`LVFPGA_IFACE_DMA_SIZE_WIDTH)-1:0] bDmaRxFifoFreeCnt,
|
||||||
|
|
||||||
|
output [(`LVFPGA_IFACE_NUM_TX_DMA_CNT*`LVFPGA_IFACE_DMA_CHAN_WIDTH)-1:0] bDmaTxData,
|
||||||
|
output [`LVFPGA_IFACE_NUM_TX_DMA_CNT-1:0] bDmaTxValid,
|
||||||
|
input [`LVFPGA_IFACE_NUM_TX_DMA_CNT-1:0] bDmaTxReady,
|
||||||
|
output [`LVFPGA_IFACE_NUM_TX_DMA_CNT-1:0] bDmaTxEnabled,
|
||||||
|
output [(`LVFPGA_IFACE_NUM_TX_DMA_CNT*`LVFPGA_IFACE_DMA_SIZE_WIDTH)-1:0] bDmaTxFifoFullCnt,
|
||||||
|
|
||||||
|
output bUserRegPortInWt,
|
||||||
|
output bUserRegPortInRd,
|
||||||
|
output [`LVFPGA_IFACE_UREG_ADDR_WIDTH-1:0] bUserRegPortInAddr,
|
||||||
|
output [`LVFPGA_IFACE_UREG_DATA_WIDTH-1:0] bUserRegPortInData,
|
||||||
|
output [`LVFPGA_IFACE_UREG_SIZE_WIDTH-1:0] bUserRegPortInSize,
|
||||||
|
input [`LVFPGA_IFACE_UREG_DATA_WIDTH-1:0] bUserRegPortOutData,
|
||||||
|
input bUserRegPortOutDataValid,
|
||||||
|
input bUserRegPortOutReady,
|
||||||
|
|
||||||
|
input bChinchRegPortOutWt,
|
||||||
|
input bChinchRegPortOutRd,
|
||||||
|
input [`LVFPGA_IFACE_CREG_ADDR_WIDTH-1:0] bChinchRegPortOutAddr,
|
||||||
|
input [`LVFPGA_IFACE_CREG_DATA_WIDTH-1:0] bChinchRegPortOutData,
|
||||||
|
input [`LVFPGA_IFACE_CREG_SIZE_WIDTH-1:0] bChinchRegPortOutSize,
|
||||||
|
output [`LVFPGA_IFACE_CREG_DATA_WIDTH-1:0] bChinchRegPortInData,
|
||||||
|
output bChinchRegPortInDataValid,
|
||||||
|
output bChinchRegPortInReady,
|
||||||
|
|
||||||
|
output aIrq
|
||||||
|
) /* synthesis syn_black_box syn_noprune=1 */;
|
||||||
|
// This module serves as an API wrapper for LvFpga_Chinch_Interface.ngc and we don't want
|
||||||
|
// the tool to accidentally prune out it contents. Hence the syn_black_box syn_noprune=1 directives.
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- File: LvFpga_Chinch_Interface.vh
|
||||||
|
-- Author: Ashish Chaudhari
|
||||||
|
-- Original Project: EttusUsrpB250Top
|
||||||
|
-- Date: 1 Oct 2013
|
||||||
|
--
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- (c) 2013 Copyright National Instruments Corporation
|
||||||
|
-- All Rights Reserved
|
||||||
|
-- National Instruments Internal Information
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Physical link width for the IoPort2 interface to the STC3
|
||||||
|
`define LVFPGA_IFACE_LINK_WIDTH 16
|
||||||
|
|
||||||
|
//DMA Related Constants
|
||||||
|
`define LVFPGA_IFACE_DMA_CHAN_WIDTH 64 //DMA data bus width
|
||||||
|
`define LVFPGA_IFACE_DMA_SIZE_WIDTH 11 //DMA FIFO fullness count width
|
||||||
|
`define LVFPGA_IFACE_NUM_RX_DMA_CNT 6 //Number of RX DMA channels
|
||||||
|
`define LVFPGA_IFACE_NUM_TX_DMA_CNT 6 //Number of TX DMA channels
|
||||||
|
`define LVFPGA_IFACE_RX_DMA_INDEX 0 //Index for the first RX DMA channel
|
||||||
|
`define LVFPGA_IFACE_TX_DMA_INDEX 6 //Index for the first TX DMA channel
|
||||||
|
|
||||||
|
//User register port constants
|
||||||
|
`define LVFPGA_IFACE_UREG_ADDR_WIDTH 20 //Address width
|
||||||
|
`define LVFPGA_IFACE_UREG_DATA_WIDTH 32 //Payload width
|
||||||
|
`define LVFPGA_IFACE_UREG_SIZE_WIDTH 2 //Transaction size width
|
||||||
|
|
||||||
|
//Chinch register port constants
|
||||||
|
`define LVFPGA_IFACE_CREG_ADDR_WIDTH 32 //Address width
|
||||||
|
`define LVFPGA_IFACE_CREG_DATA_WIDTH 64 //Payload width
|
||||||
|
`define LVFPGA_IFACE_CREG_SIZE_WIDTH 2 //Transaction size width
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2012-2013 Ettus Research LLC
|
||||||
|
#
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# io_port2
|
||||||
|
##################################################
|
||||||
|
IOPORT2_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/io_port2/, \
|
||||||
|
./LvFpga_Chinch_Interface.v \
|
||||||
|
./LvFpga_Chinch_Interface.ngc \
|
||||||
|
./ioport2_msg_codec.v \
|
||||||
|
./pcie_pkt_route_specifier.v \
|
||||||
|
./pcie_axi_wb_conv.v \
|
||||||
|
./pcie_wb_reg_core.v \
|
||||||
|
./pcie_iop2_msg_arbiter.v \
|
||||||
|
./pcie_basic_regs.v \
|
||||||
|
./pcie_dma_ctrl.v \
|
||||||
|
./data_swapper_64.v \
|
||||||
|
))
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
from collections import namedtuple
|
||||||
|
import optparse
|
||||||
|
import base64
|
||||||
|
import md5
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Parse options
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option("--device", type="string", dest="device_type", help="Device Type. (Has to match the LVFPGA target plugin)", default=None)
|
||||||
|
parser.add_option("--input-bin", type="string", dest="input_bin", help="Path to bin file that needs to be merged with the LVBITX before exporting", default=None)
|
||||||
|
parser.add_option("--output-bin", type="string", dest="output_bin", help="Create a binary configuration bitstream", default=None)
|
||||||
|
parser.add_option("--output-lvbitx", type="string", dest="output_lvbitx_path", help="Output path for autogenerated LVBITX file", default=None)
|
||||||
|
parser.add_option("--output-src-path", type="string", dest="output_src_path", help="Output path for autogenerated src file", default=None)
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
# Args
|
||||||
|
if (len(args) < 1):
|
||||||
|
print 'ERROR: Please specify the input LVBITX file name'
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
lvbitx_filename = args[0]
|
||||||
|
input_filename = os.path.abspath(lvbitx_filename)
|
||||||
|
|
||||||
|
if (not os.path.isfile(input_filename)):
|
||||||
|
print 'ERROR: LVBITX File ' + input_filename + ' could not be accessed or is not a file.'
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
if (options.input_bin is not None and not os.path.isfile(os.path.abspath(options.input_bin))):
|
||||||
|
print 'ERROR: FPGA Bin File ' + options.input_bin + ' could not be accessed or is not a file.'
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
if (options.output_lvbitx_path is not None and input_filename == options.output_lvbitx_path):
|
||||||
|
print 'ERROR: Input and output LVBITX files were the same. Choose a difference input or output file.'
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Get XML Tree Node
|
||||||
|
tree = ElementTree.parse(input_filename)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
# Update device type
|
||||||
|
if (options.device_type is not None):
|
||||||
|
root.find('Project').find('TargetClass').text += '; ' + options.device_type
|
||||||
|
|
||||||
|
# Merge bitstream into LVBITX
|
||||||
|
if (options.input_bin is not None):
|
||||||
|
with open(os.path.abspath(options.input_bin), 'rb') as bin_file:
|
||||||
|
bitstream = bin_file.read()
|
||||||
|
bitstream_md5 = md5.new(bitstream).hexdigest()
|
||||||
|
bitstream_b64 = base64.b64encode(bitstream)
|
||||||
|
bitstream_b64_lb = ''
|
||||||
|
for i in range(0, len(bitstream_b64), 76):
|
||||||
|
bitstream_b64_lb += bitstream_b64[i:i+76] + '\n'
|
||||||
|
|
||||||
|
root.find('Bitstream').text = bitstream_b64_lb
|
||||||
|
root.find('BitstreamMD5').text = bitstream_md5
|
||||||
|
|
||||||
|
# Write BIN file
|
||||||
|
bitstream = base64.b64decode(root.find('Bitstream').text)
|
||||||
|
if (options.output_lvbitx_path is not None and md5.new(bitstream).hexdigest() != root.find('BitstreamMD5').text):
|
||||||
|
print 'ERROR: The MD5 sum for the output LVBITX was incorrect. Make sure that the bitstream in the input LVBITX or BIN file is valid.'
|
||||||
|
sys.exit(1)
|
||||||
|
if (options.output_bin is not None):
|
||||||
|
fpga_bin_file = open(options.output_bin, 'w')
|
||||||
|
fpga_bin_file.write(bitstream)
|
||||||
|
fpga_bin_file.close()
|
||||||
|
|
||||||
|
# Save LVBITX
|
||||||
|
if (options.output_lvbitx_path is not None):
|
||||||
|
tree.write(options.output_lvbitx_path, encoding="utf-8", xml_declaration=True, default_namespace=None, method="xml")
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
module data_swapper_64 (
|
||||||
|
input [2:0] swap_lanes,
|
||||||
|
|
||||||
|
input [63:0] i_tdata,
|
||||||
|
output [63:0] o_tdata
|
||||||
|
);
|
||||||
|
localparam SWAP_32B = 3'b100;
|
||||||
|
localparam SWAP_16B = 3'b010;
|
||||||
|
localparam SWAP_8B = 3'b001;
|
||||||
|
|
||||||
|
wire [63:0] data_p1, data_p2;
|
||||||
|
|
||||||
|
assign data_p1 = (|(swap_lanes & SWAP_32B)) ? { i_tdata[31:0], i_tdata[63:32] } : i_tdata;
|
||||||
|
assign data_p2 = (|(swap_lanes & SWAP_16B)) ? { data_p1[47:32], data_p1[63:48], data_p1[15:0], data_p1[31:16] } : data_p1;
|
||||||
|
assign o_tdata = (|(swap_lanes & SWAP_8B)) ? { data_p2[55:48], data_p2[63:56], data_p2[39:32], data_p2[47:40],
|
||||||
|
data_p2[23:16], data_p2[31:24], data_p2[7:0], data_p2[15:8] } : data_p2;
|
||||||
|
|
||||||
|
endmodule // data_swapper_64
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//Message format:
|
||||||
|
// msg[63]: Completion {1 -> Read Completion, 0 -> Transaction Request}
|
||||||
|
// msg[62]: Write request*
|
||||||
|
// msg[61]: Read request*
|
||||||
|
// msg[60]: Half word {1 -> 16-bit transaction, 0 -> 32-bit transaction}*
|
||||||
|
// msg[59:52]: Reserved
|
||||||
|
// msg[51:32]: Address*
|
||||||
|
// msg[31:0]: Data
|
||||||
|
//
|
||||||
|
// * Field only valid when the word is a transaction request.
|
||||||
|
|
||||||
|
module ioport2_msg_decode(
|
||||||
|
input [63:0] message,
|
||||||
|
output rd_response,
|
||||||
|
output wr_request,
|
||||||
|
output rd_request,
|
||||||
|
output half_word,
|
||||||
|
output [19:0] address,
|
||||||
|
output [31:0] data,
|
||||||
|
output [31:0] control
|
||||||
|
);
|
||||||
|
assign rd_response = message[63];
|
||||||
|
assign wr_request = message[62];
|
||||||
|
assign rd_request = message[61];
|
||||||
|
assign half_word = message[60];
|
||||||
|
assign address = message[51:32];
|
||||||
|
assign data = message[31:0];
|
||||||
|
assign control = message[63:32];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module ioport2_msg_encode(
|
||||||
|
input rd_response,
|
||||||
|
input wr_request,
|
||||||
|
input rd_request,
|
||||||
|
input half_word,
|
||||||
|
input [19:0] address,
|
||||||
|
input [31:0] data,
|
||||||
|
output [31:0] control,
|
||||||
|
output [63:0] message
|
||||||
|
);
|
||||||
|
assign control = rd_response ? {rd_response, 31'h0} : {rd_response, wr_request, rd_request, half_word, 8'h00, address};
|
||||||
|
assign message = {control, data};
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module pcie_axi_wb_conv #(
|
||||||
|
parameter WB_ADDRW = 16,
|
||||||
|
parameter WB_DATAW = 32
|
||||||
|
)(
|
||||||
|
input clk,
|
||||||
|
input rst,
|
||||||
|
|
||||||
|
input wb_stb_i,
|
||||||
|
input wb_we_i,
|
||||||
|
input [WB_ADDRW-1:0] wb_adr_i,
|
||||||
|
input [WB_DATAW-1:0] wb_dat_i,
|
||||||
|
output wb_ack_o,
|
||||||
|
output [WB_DATAW-1:0] wb_dat_o,
|
||||||
|
|
||||||
|
input [63:0] msgi_tdata,
|
||||||
|
input msgi_tvalid,
|
||||||
|
output msgi_tready,
|
||||||
|
|
||||||
|
output [63:0] msgo_tdata,
|
||||||
|
output msgo_tvalid,
|
||||||
|
input msgo_tready,
|
||||||
|
|
||||||
|
output wb_monitor_active,
|
||||||
|
output reg wb_req_pending,
|
||||||
|
output reg wb_resp_pending,
|
||||||
|
output reg pcie_resp_pending
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam SB_ADDRW = 4;
|
||||||
|
localparam SB_DATAW = 32;
|
||||||
|
localparam MONITOR_TIMEOUTW = 20; //20bits@175MHz ~ 6ms
|
||||||
|
|
||||||
|
localparam SR_PCIE_DATA_REG = 4'd0;
|
||||||
|
localparam SR_PCIE_CTRL_REG = 4'd1;
|
||||||
|
localparam RB_PCIE_DATA_REG = 4'd0;
|
||||||
|
localparam RB_PCIE_CTRL_REG = 4'd1;
|
||||||
|
localparam RB_PCIE_RESP_DATA_REG = 4'd2;
|
||||||
|
localparam RB_PCIE_STATUS_REG = 4'd3;
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Settings and readback bus
|
||||||
|
//
|
||||||
|
wire [SB_DATAW-1:0] set_data, rb_data;
|
||||||
|
wire [SB_ADDRW-1:0] set_addr, rb_addr;
|
||||||
|
wire set_stb, rb_stb;
|
||||||
|
|
||||||
|
settings_bus #(.AWIDTH(WB_ADDRW), .DWIDTH(WB_DATAW)) settings_bus (
|
||||||
|
.wb_clk(clk), .wb_rst(rst),
|
||||||
|
.wb_adr_i(wb_adr_i), .wb_dat_i(wb_dat_i),
|
||||||
|
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_ack_o(wb_ack_o),
|
||||||
|
.strobe(set_stb), .addr(set_addr), .data(set_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
settings_readback #(.AWIDTH(WB_ADDRW), .DWIDTH(WB_DATAW), .RB_ADDRW(SB_ADDRW)) settings_readback (
|
||||||
|
.wb_clk(clk), .wb_rst(rst),
|
||||||
|
.wb_adr_i(wb_adr_i), .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i),
|
||||||
|
.rb_data(rb_data), .rb_addr(rb_addr), .rb_rd_stb(rb_stb),
|
||||||
|
.wb_dat_o(wb_dat_o)
|
||||||
|
);
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Settings/Readback Registers
|
||||||
|
//
|
||||||
|
wire [31:0] axi_out_data, axi_out_ctrl;
|
||||||
|
wire axi_out_stb;
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(SR_PCIE_DATA_REG), .awidth(SB_ADDRW), .width(SB_DATAW)) set_pcie_out_data_reg (
|
||||||
|
.clk(clk), .rst(rst),
|
||||||
|
.strobe(set_stb), .addr(set_addr), .in(set_data),
|
||||||
|
.out(axi_out_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
setting_reg #(.my_addr(SR_PCIE_CTRL_REG), .awidth(SB_ADDRW), .width(SB_DATAW)) set_pcie_out_ctrl_reg (
|
||||||
|
.clk(clk), .rst(rst),
|
||||||
|
.strobe(set_stb), .addr(set_addr), .in(set_data),
|
||||||
|
.out(axi_out_ctrl), .changed(axi_out_stb)
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [31:0] axi_in_data_reg, axi_in_ctrl_reg, axi_in_resp_reg;
|
||||||
|
wire msgo_fifo_tready;
|
||||||
|
|
||||||
|
// Readback MUX
|
||||||
|
assign rb_data = (
|
||||||
|
(rb_addr == RB_PCIE_STATUS_REG) ? {27'h0, ~msgo_fifo_tready, 1'b0, wb_resp_pending, wb_req_pending, pcie_resp_pending} : (
|
||||||
|
(rb_addr == RB_PCIE_RESP_DATA_REG) ? axi_in_resp_reg : (
|
||||||
|
(rb_addr == RB_PCIE_DATA_REG) ? axi_in_data_reg : (
|
||||||
|
(rb_addr == RB_PCIE_CTRL_REG) ? axi_in_ctrl_reg : 32'h0))));
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Output message handler
|
||||||
|
//
|
||||||
|
wire [63:0] msgo_fifo_tdata;
|
||||||
|
wire axi_out_rd, axi_out_wr, axi_out_rr;
|
||||||
|
|
||||||
|
assign msgo_fifo_tdata = {axi_out_ctrl, axi_out_data};
|
||||||
|
|
||||||
|
axi_fifo_short #(.WIDTH(64)) wb_out_msg_fifo (
|
||||||
|
.clk(clk), .reset(rst), .clear(1'b0),
|
||||||
|
.i_tdata(msgo_fifo_tdata), .i_tvalid(axi_out_stb), .i_tready(msgo_fifo_tready),
|
||||||
|
.o_tdata(msgo_tdata), .o_tvalid(msgo_tvalid), .o_tready(msgo_tready),
|
||||||
|
.space(), .occupied());
|
||||||
|
|
||||||
|
ioport2_msg_decode axi_out_decoder (
|
||||||
|
.message(msgo_fifo_tdata),
|
||||||
|
.rd_response(axi_out_rr), .wr_request(axi_out_wr), .rd_request(axi_out_rd)
|
||||||
|
);
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Input message handler
|
||||||
|
//
|
||||||
|
wire [63:0] msgi_fifo_tdata;
|
||||||
|
wire axi_in_valid, axi_in_stb;
|
||||||
|
|
||||||
|
wire [31:0] axi_in_data, axi_in_ctrl;
|
||||||
|
wire axi_in_rd, axi_in_wr, axi_in_rr;
|
||||||
|
|
||||||
|
axi_fifo_short #(.WIDTH(64)) wb_in_msg_fifo (
|
||||||
|
.clk(clk), .reset(rst), .clear(1'b0),
|
||||||
|
.i_tdata(msgi_tdata), .i_tvalid(msgi_tvalid), .i_tready(msgi_tready),
|
||||||
|
.o_tdata(msgi_fifo_tdata), .o_tvalid(axi_in_valid), .o_tready(axi_in_stb),
|
||||||
|
.space(), .occupied());
|
||||||
|
|
||||||
|
ioport2_msg_decode axi_in_decoder (
|
||||||
|
.message(msgi_fifo_tdata),
|
||||||
|
.rd_response(axi_in_rr), .wr_request(axi_in_wr), .rd_request(axi_in_rd),
|
||||||
|
.data(axi_in_data), .control(axi_in_ctrl)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign axi_in_stb = axi_in_valid & (axi_in_rr | ((axi_in_wr | axi_in_rd) & ~(wb_req_pending | wb_resp_pending)));
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
axi_in_data_reg <= 32'h0;
|
||||||
|
axi_in_ctrl_reg <= 32'h0;
|
||||||
|
axi_in_resp_reg <= 32'h0;
|
||||||
|
end else begin
|
||||||
|
if (axi_in_stb & axi_in_rr) begin
|
||||||
|
axi_in_resp_reg <= axi_in_data;
|
||||||
|
end else if (axi_in_stb & (axi_in_wr | axi_in_rd)) begin
|
||||||
|
axi_in_data_reg <= axi_in_data;
|
||||||
|
axi_in_ctrl_reg <= axi_in_ctrl;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// State handler
|
||||||
|
//
|
||||||
|
//wb_monitor_active
|
||||||
|
reg [MONITOR_TIMEOUTW-1:0] wb_monitor_timeout;
|
||||||
|
assign wb_monitor_active = (wb_monitor_timeout != {(MONITOR_TIMEOUTW){1'b0}});
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst)
|
||||||
|
wb_monitor_timeout <= {(MONITOR_TIMEOUTW){1'b0}}; //Monitor disabled on rst
|
||||||
|
else if (rb_stb && (rb_addr == RB_PCIE_STATUS_REG))
|
||||||
|
wb_monitor_timeout <= {(MONITOR_TIMEOUTW){1'b1}}; //Reset counter when the ZPU queries the status reg
|
||||||
|
else if (wb_monitor_active)
|
||||||
|
wb_monitor_timeout <= wb_monitor_timeout - 1; //Decrement counter when idle
|
||||||
|
end
|
||||||
|
|
||||||
|
//wb_req_pending
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst || (rb_stb && (rb_addr == RB_PCIE_CTRL_REG)))
|
||||||
|
wb_req_pending <= 1'b0;
|
||||||
|
else if (axi_in_stb & (axi_in_rd | axi_in_wr))
|
||||||
|
wb_req_pending <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
//wb_resp_pending
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst | (axi_out_stb & msgo_fifo_tready & axi_out_rr))
|
||||||
|
wb_resp_pending <= 1'b0;
|
||||||
|
else if (axi_in_stb & axi_in_rd)
|
||||||
|
wb_resp_pending <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
//pcie_resp_pending
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst | (axi_in_stb & axi_in_rr))
|
||||||
|
pcie_resp_pending <= 1'b0;
|
||||||
|
else if (axi_out_stb & msgo_fifo_tready & axi_out_rd)
|
||||||
|
pcie_resp_pending <= 1'b1;
|
||||||
|
end
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module pcie_basic_regs (
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
input [63:0] regi_tdata,
|
||||||
|
input regi_tvalid,
|
||||||
|
output regi_tready,
|
||||||
|
output [63:0] rego_tdata,
|
||||||
|
output rego_tvalid,
|
||||||
|
input rego_tready,
|
||||||
|
|
||||||
|
input [31:0] misc_status
|
||||||
|
);
|
||||||
|
localparam PCIE_FPGA_SIG_VAL = 32'h58333030; //X300 (ASCII)
|
||||||
|
localparam PCIE_FPGA_COUNTER_FREQ = 32'h0A6E49C0; //175MHz
|
||||||
|
|
||||||
|
localparam PCIE_REG_ADDR_MASK = 20'h001FF;
|
||||||
|
|
||||||
|
localparam PCIE_FPGA_SIG_REG_ADDR = 20'h00000; //32-bit
|
||||||
|
localparam PCIE_FPGA_COUNTER_LO_REG_ADDR = 20'h00004; //32-bit
|
||||||
|
localparam PCIE_FPGA_COUNTER_HI_REG_ADDR = 20'h00008; //32-bit
|
||||||
|
localparam PCIE_FPGA_COUNTER_FREQ_ADDR = 20'h0000C; //32-bit
|
||||||
|
localparam PCIE_FPGA_SCRATCH0_ADDR = 20'h00010; //32-bit
|
||||||
|
localparam PCIE_FPGA_SCRATCH1_ADDR = 20'h00014; //32-bit
|
||||||
|
localparam PCIE_FPGA_MISC_STATUS_ADDR = 20'h00020; //32-bit
|
||||||
|
localparam PCIE_FPGA_USR_SIG_REG_ADDR = 20'h00030; //128-bit
|
||||||
|
|
||||||
|
wire regi_wr, regi_rd;
|
||||||
|
wire [19:0] regi_addr, regi_addr_local;
|
||||||
|
wire [31:0] regi_payload;
|
||||||
|
reg [31:0] rego_payload;
|
||||||
|
|
||||||
|
ioport2_msg_decode regi_decoder (
|
||||||
|
.message(regi_tdata), .wr_request(regi_wr), .rd_request(regi_rd),
|
||||||
|
.address(regi_addr), .data(regi_payload)
|
||||||
|
);
|
||||||
|
|
||||||
|
ioport2_msg_encode rego_encoder (
|
||||||
|
.rd_response(1'b1), .data(rego_payload), .message(rego_tdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign regi_tready = (regi_tvalid & regi_wr) | rego_tready;
|
||||||
|
assign rego_tvalid = regi_tvalid & regi_rd;
|
||||||
|
assign regi_addr_local = regi_addr & PCIE_REG_ADDR_MASK;
|
||||||
|
|
||||||
|
//Counter counting bus_clk cycles
|
||||||
|
reg [63:0] bus_counter;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset) bus_counter <= 64'h0;
|
||||||
|
else bus_counter <= bus_counter + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
//Scratch registers
|
||||||
|
reg [63:0] scratch;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset)
|
||||||
|
scratch <= 64'h0;
|
||||||
|
else if (regi_tvalid & regi_tready & regi_wr)
|
||||||
|
if (regi_addr_local == PCIE_FPGA_SCRATCH0_ADDR)
|
||||||
|
scratch[31:0] <= regi_payload;
|
||||||
|
else if (regi_addr_local == PCIE_FPGA_SCRATCH1_ADDR)
|
||||||
|
scratch[63:32] <= regi_payload;
|
||||||
|
end
|
||||||
|
|
||||||
|
//User signature register
|
||||||
|
reg [127:0] usr_signature;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset)
|
||||||
|
usr_signature <= 128'h0;
|
||||||
|
else if (regi_tvalid & regi_tready & regi_wr)
|
||||||
|
if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00000))
|
||||||
|
usr_signature[31:0] <= regi_payload;
|
||||||
|
else if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00004))
|
||||||
|
usr_signature[63:32] <= regi_payload;
|
||||||
|
else if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00008))
|
||||||
|
usr_signature[95:64] <= regi_payload;
|
||||||
|
else if (regi_addr_local == (PCIE_FPGA_USR_SIG_REG_ADDR + 20'h0000C))
|
||||||
|
usr_signature[127:96] <= regi_payload;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
case (regi_addr_local)
|
||||||
|
PCIE_FPGA_SIG_REG_ADDR: rego_payload = PCIE_FPGA_SIG_VAL;
|
||||||
|
PCIE_FPGA_COUNTER_LO_REG_ADDR: rego_payload = bus_counter[31:0];
|
||||||
|
PCIE_FPGA_COUNTER_HI_REG_ADDR: rego_payload = bus_counter[63:32];
|
||||||
|
PCIE_FPGA_COUNTER_FREQ_ADDR: rego_payload = PCIE_FPGA_COUNTER_FREQ;
|
||||||
|
PCIE_FPGA_SCRATCH0_ADDR: rego_payload = scratch[31:0];
|
||||||
|
PCIE_FPGA_SCRATCH1_ADDR: rego_payload = scratch[63:32];
|
||||||
|
PCIE_FPGA_MISC_STATUS_ADDR: rego_payload = misc_status;
|
||||||
|
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00000: rego_payload = usr_signature[31:0];
|
||||||
|
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00004: rego_payload = usr_signature[63:32];
|
||||||
|
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h00008: rego_payload = usr_signature[95:64];
|
||||||
|
PCIE_FPGA_USR_SIG_REG_ADDR + 20'h0000C: rego_payload = usr_signature[127:96];
|
||||||
|
default: rego_payload = 32'hFFFFFFFF;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
`define BIT_WIDTH(N) (\
|
||||||
|
N <= 2 ? 1 : \
|
||||||
|
N <= 4 ? 2 : \
|
||||||
|
N <= 8 ? 3 : \
|
||||||
|
N <= 16 ? 4 : \
|
||||||
|
N <= 32 ? 5 : \
|
||||||
|
N <= 64 ? 6 : \
|
||||||
|
N <= 128 ? 7 : \
|
||||||
|
N <= 256 ? 8 : \
|
||||||
|
N <= 512 ? 9 : \
|
||||||
|
10)
|
||||||
|
`define GET_REG_OFFSET(reg_addr, chan_idx) (((chan_idx * (1<<DMA_REG_GRP_W)) + reg_addr) + REG_BASE_ADDR)
|
||||||
|
`define EXTRACT_CHAN_NUM(reg_addr) regi_addr[`BIT_WIDTH(NUM_STREAMS)+DMA_REG_GRP_W-1:DMA_REG_GRP_W]
|
||||||
|
|
||||||
|
module pcie_dma_ctrl #(
|
||||||
|
parameter NUM_STREAMS = 4,
|
||||||
|
parameter FRAME_SIZE_W = 16,
|
||||||
|
parameter REG_BASE_ADDR = 20'h00000,
|
||||||
|
parameter ENABLE_ROUTER = 0,
|
||||||
|
parameter ROUTER_SID_W = 8,
|
||||||
|
parameter ROUTER_DST_W = 2
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
input [63:0] regi_tdata,
|
||||||
|
input regi_tvalid,
|
||||||
|
output regi_tready,
|
||||||
|
output [63:0] rego_tdata,
|
||||||
|
output rego_tvalid,
|
||||||
|
input rego_tready,
|
||||||
|
|
||||||
|
output reg [NUM_STREAMS-1:0] set_clear,
|
||||||
|
output [(NUM_STREAMS*FRAME_SIZE_W)-1:0] set_frame_size,
|
||||||
|
output [(NUM_STREAMS*3)-1:0] swap_lanes,
|
||||||
|
|
||||||
|
input [NUM_STREAMS-1:0] packet_stb,
|
||||||
|
input [NUM_STREAMS-1:0] sample_stb,
|
||||||
|
input [NUM_STREAMS-1:0] stream_err,
|
||||||
|
|
||||||
|
input [ROUTER_SID_W-1:0] rtr_sid,
|
||||||
|
output [ROUTER_DST_W-1:0] rtr_dst
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam DMA_REG_GRP_W = 4;
|
||||||
|
localparam DMA_CTRL_STATUS_REG = 4'h0; //[RW] R: Stream Error, W: Reset stream
|
||||||
|
localparam DMA_FSIZE_REG = 4'h4; //[RW] R: Frame Size, W: Frame Size
|
||||||
|
localparam DMA_SAMP_CNT_REG = 4'h8; //[RW] R: Sample Count, W: Reset Count to 0
|
||||||
|
localparam DMA_PKT_CNT_REG = 4'hC; //[RW] R: Packet Count, W: Reset Count to 0
|
||||||
|
|
||||||
|
localparam DEFAULT_FSIZE = 32;
|
||||||
|
|
||||||
|
//NOTE: Although this module supports these, the 8 and 16 bit modes will be disabled for efficiency
|
||||||
|
localparam DMA_CTRL_BUF_SIZE_8 = 2'b00; // 8-bit wide SW buffer
|
||||||
|
localparam DMA_CTRL_BUF_SIZE_16 = 2'b01; //16-bit wide SW buffer
|
||||||
|
localparam DMA_CTRL_BUF_SIZE_32 = 2'b10; //32-bit wide SW buffer
|
||||||
|
localparam DMA_CTRL_BUF_SIZE_64 = 2'b11; //64-bit wide SW buffer
|
||||||
|
|
||||||
|
wire regi_wr, regi_rd;
|
||||||
|
wire [19:0] regi_addr;
|
||||||
|
wire [31:0] regi_payload;
|
||||||
|
wire [31:0] rego_payload;
|
||||||
|
|
||||||
|
ioport2_msg_decode regi_decoder (
|
||||||
|
.message(regi_tdata), .wr_request(regi_wr), .rd_request(regi_rd),
|
||||||
|
.address(regi_addr), .data(regi_payload)
|
||||||
|
);
|
||||||
|
|
||||||
|
ioport2_msg_encode rego_encoder (
|
||||||
|
.rd_response(1'b1), .data(rego_payload), .message(rego_tdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [31:0] pkt_count_mem[0:NUM_STREAMS-1];
|
||||||
|
reg [31:0] samp_count_mem[0:NUM_STREAMS-1];
|
||||||
|
reg [FRAME_SIZE_W-1:0] frame_size_mem[0:NUM_STREAMS-1];
|
||||||
|
reg [NUM_STREAMS-1:0] sw_buf_width_mem;
|
||||||
|
|
||||||
|
genvar i;
|
||||||
|
generate
|
||||||
|
for (i=0; i<NUM_STREAMS; i=i+1) begin: dma_ctrl_logic_generator
|
||||||
|
//Memory -> output translations
|
||||||
|
assign set_frame_size[(FRAME_SIZE_W*(i+1))-1:(FRAME_SIZE_W*i)] = frame_size_mem[i];
|
||||||
|
assign swap_lanes[(3*(i+1))-1:(3*i)] = { ~(sw_buf_width_mem[i]), 2'b00 }; //Optimized for only 2 modes
|
||||||
|
|
||||||
|
//Setting registers
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
frame_size_mem[i] <= DEFAULT_FSIZE;
|
||||||
|
set_clear[i] <= 0;
|
||||||
|
sw_buf_width_mem[i] <= 1;
|
||||||
|
end else if (regi_tready & regi_tvalid & regi_wr) begin
|
||||||
|
if (regi_addr == `GET_REG_OFFSET(DMA_CTRL_STATUS_REG, i)) begin
|
||||||
|
set_clear[i] <= regi_payload[0]; //DMA_CTRL_STATUS_REG[0] == Clear DMA queues
|
||||||
|
sw_buf_width_mem[i] <= regi_payload[4]; //DMA_CTRL_STATUS_REG[5:4] == SW Buffer Size (See note above)
|
||||||
|
end else if (regi_addr == `GET_REG_OFFSET(DMA_FSIZE_REG, i)) begin
|
||||||
|
frame_size_mem[i] <= regi_payload[FRAME_SIZE_W-1:0]; //DMA_FSIZE_REG[14:0] == DMA Frame size
|
||||||
|
set_clear[i] <= 1;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
set_clear[i] <= 0; //set_clear should be "self-clearing"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//Packet counter
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_PKT_CNT_REG, i)))) begin
|
||||||
|
pkt_count_mem[i] <= 0;
|
||||||
|
end else if (packet_stb[i]) begin
|
||||||
|
pkt_count_mem[i] <= pkt_count_mem[i] + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
//Sample counter
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_SAMP_CNT_REG, i)))) begin
|
||||||
|
samp_count_mem[i] <= 0;
|
||||||
|
end else if (sample_stb[i]) begin
|
||||||
|
samp_count_mem[i] <= samp_count_mem[i] + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
//Readback
|
||||||
|
assign rego_payload =
|
||||||
|
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_PKT_CNT_REG) ? pkt_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : (
|
||||||
|
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_SAMP_CNT_REG) ? samp_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : (
|
||||||
|
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_FSIZE_REG) ? frame_size_mem[`EXTRACT_CHAN_NUM(regi_addr)] : (
|
||||||
|
(regi_addr[DMA_REG_GRP_W-1:0] == DMA_CTRL_STATUS_REG) ? {31'h0, stream_err[`EXTRACT_CHAN_NUM(regi_addr)]} : (
|
||||||
|
32'hFFFFFFFF))));
|
||||||
|
|
||||||
|
assign rego_tvalid = regi_tvalid && regi_rd;
|
||||||
|
assign regi_tready = rego_tready || (regi_tvalid && regi_wr);
|
||||||
|
|
||||||
|
//Optional router
|
||||||
|
if (ENABLE_ROUTER == 1) begin
|
||||||
|
pcie_pkt_route_specifier #(
|
||||||
|
.BASE_ADDR((1<<ROUTER_SID_W) + REG_BASE_ADDR), .ADDR_MASK(20'hFFFFF^((1<<ROUTER_SID_W)-1)),
|
||||||
|
.SID_WIDTH(ROUTER_SID_W), .DST_WIDTH(ROUTER_DST_W)
|
||||||
|
) route_specifier (
|
||||||
|
.clk(clk), .reset(reset),
|
||||||
|
.regi_tdata(regi_tdata), .regi_tvalid(regi_tvalid), .regi_tready(),
|
||||||
|
.local_sid(rtr_sid), .fifo_dst(rtr_dst)
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
`undef EXTRACT_CHAN_NUM
|
||||||
|
`undef GET_REG_OFFSET
|
||||||
|
`undef BIT_WIDTH
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
`timescale 500ps/1ps
|
||||||
|
|
||||||
|
module pcie_dma_ctrl_tb();
|
||||||
|
reg clk = 0;
|
||||||
|
reg reset = 1;
|
||||||
|
|
||||||
|
always #10 clk = ~clk;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#100 reset = 0;
|
||||||
|
#200000;
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
function [63:0] iop2_msg_write;
|
||||||
|
input [19:0] address;
|
||||||
|
input [31:0] data;
|
||||||
|
input half_wd;
|
||||||
|
begin
|
||||||
|
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
|
||||||
|
iop2_msg_write = {1'b0, 1'b1, 1'b0, half_wd, 8'h00, address, data};
|
||||||
|
end
|
||||||
|
endfunction // iop2_msg_write
|
||||||
|
|
||||||
|
function [63:0] iop2_msg_read;
|
||||||
|
input [19:0] address;
|
||||||
|
input half_wd;
|
||||||
|
begin
|
||||||
|
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
|
||||||
|
iop2_msg_read = {1'b0, 1'b0, 1'b1, half_wd, 8'h00, address, 32'h0};
|
||||||
|
end
|
||||||
|
endfunction // iop2_msg_read
|
||||||
|
|
||||||
|
wire [3:0] clear;
|
||||||
|
wire [63:0] frame_size;
|
||||||
|
reg [3:0] pkt_stb = 0;
|
||||||
|
reg [3:0] samp_stb = 0;
|
||||||
|
reg [3:0] error = 0;
|
||||||
|
reg [7:0] rtr_sid = 4;
|
||||||
|
wire [3:0] rtr_dst;
|
||||||
|
|
||||||
|
reg [63:0] regi_tdata;
|
||||||
|
reg regi_tvalid;
|
||||||
|
wire regi_tready;
|
||||||
|
wire [63:0] rego_tdata;
|
||||||
|
wire rego_tvalid;
|
||||||
|
reg rego_tready;
|
||||||
|
reg [31:0] rego_payload;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (rego_tdata[63] & rego_tvalid & rego_tready)
|
||||||
|
rego_payload <= rego_tdata[31:0];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
regi_tvalid <= 0;
|
||||||
|
rego_tready <= 0;
|
||||||
|
while (reset) @(posedge clk);
|
||||||
|
|
||||||
|
rego_tready <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
regi_tdata <= iop2_msg_write(20'h304, 32'hA, 0);
|
||||||
|
regi_tvalid <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~regi_tready) @(posedge clk);
|
||||||
|
regi_tvalid <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
end // initial begin
|
||||||
|
|
||||||
|
pcie_dma_ctrl #(
|
||||||
|
.NUM_STREAMS(4), .FRAME_SIZE_W(16),
|
||||||
|
.REG_BASE_ADDR(20'h00200), .ENABLE_ROUTER(1),
|
||||||
|
.ROUTER_SID_W(8), .ROUTER_DST_W(4)
|
||||||
|
) dut (
|
||||||
|
.clk(clk), .reset(reset),
|
||||||
|
.regi_tdata(regi_tdata), .regi_tvalid(regi_tvalid), .regi_tready(regi_tready),
|
||||||
|
.rego_tdata(rego_tdata), .rego_tvalid(rego_tvalid), .rego_tready(rego_tready),
|
||||||
|
.set_clear(clear), .set_frame_size(frame_size), .sample_stb(samp_stb), .packet_stb(pkt_stb),
|
||||||
|
.stream_err(error), .rtr_sid(rtr_sid), .rtr_dst(rtr_dst)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module pcie_iop2_msg_arbiter #(
|
||||||
|
parameter E0_ADDR = 20'h0,
|
||||||
|
parameter E0_MASK = 20'h0,
|
||||||
|
parameter E1_ADDR = 20'h0,
|
||||||
|
parameter E1_MASK = 20'h0,
|
||||||
|
parameter E2_ADDR = 20'h0,
|
||||||
|
parameter E2_MASK = 20'h0,
|
||||||
|
parameter E3_ADDR = 20'h0,
|
||||||
|
parameter E3_MASK = 20'h0
|
||||||
|
) (
|
||||||
|
//Clocks and resets
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
input [63:0] regi_tdata,
|
||||||
|
input regi_tvalid,
|
||||||
|
output regi_tready,
|
||||||
|
output [63:0] rego_tdata,
|
||||||
|
output rego_tvalid,
|
||||||
|
input rego_tready,
|
||||||
|
|
||||||
|
output [63:0] e0_regi_tdata,
|
||||||
|
output e0_regi_tvalid,
|
||||||
|
input e0_regi_tready,
|
||||||
|
input [63:0] e0_rego_tdata,
|
||||||
|
input e0_rego_tvalid,
|
||||||
|
output e0_rego_tready,
|
||||||
|
|
||||||
|
output [63:0] e1_regi_tdata,
|
||||||
|
output e1_regi_tvalid,
|
||||||
|
input e1_regi_tready,
|
||||||
|
input [63:0] e1_rego_tdata,
|
||||||
|
input e1_rego_tvalid,
|
||||||
|
output e1_rego_tready,
|
||||||
|
|
||||||
|
output [63:0] e2_regi_tdata,
|
||||||
|
output e2_regi_tvalid,
|
||||||
|
input e2_regi_tready,
|
||||||
|
input [63:0] e2_rego_tdata,
|
||||||
|
input e2_rego_tvalid,
|
||||||
|
output e2_rego_tready,
|
||||||
|
|
||||||
|
output [63:0] e3_regi_tdata,
|
||||||
|
output e3_regi_tvalid,
|
||||||
|
input e3_regi_tready,
|
||||||
|
input [63:0] e3_rego_tdata,
|
||||||
|
input e3_rego_tvalid,
|
||||||
|
output e3_rego_tready
|
||||||
|
);
|
||||||
|
|
||||||
|
//*******************************************************************************
|
||||||
|
// PCIe output message arbiter
|
||||||
|
//
|
||||||
|
axi_mux4 #(.PRIO(0), .WIDTH(64), .BUFFER(0)) rego_arbiter_mux (
|
||||||
|
.clk(clk), .reset(reset), .clear(1'b0),
|
||||||
|
.i0_tdata(e0_rego_tdata), .i0_tlast(e0_rego_tvalid), .i0_tvalid(e0_rego_tvalid), .i0_tready(e0_rego_tready),
|
||||||
|
.i1_tdata(e1_rego_tdata), .i1_tlast(e1_rego_tvalid), .i1_tvalid(e1_rego_tvalid), .i1_tready(e1_rego_tready),
|
||||||
|
.i2_tdata(e2_rego_tdata), .i2_tlast(e2_rego_tvalid), .i2_tvalid(e2_rego_tvalid), .i2_tready(e2_rego_tready),
|
||||||
|
.i3_tdata(e3_rego_tdata), .i3_tlast(e3_rego_tvalid), .i3_tvalid(e3_rego_tvalid), .i3_tready(e3_rego_tready),
|
||||||
|
.o_tdata(rego_tdata), .o_tlast(), .o_tvalid(rego_tvalid), .o_tready(rego_tready)
|
||||||
|
);
|
||||||
|
//
|
||||||
|
//*******************************************************************************
|
||||||
|
|
||||||
|
//*******************************************************************************
|
||||||
|
// PCIe input message arbiter
|
||||||
|
//
|
||||||
|
wire [63:0] regi_msg;
|
||||||
|
wire regi_rc;
|
||||||
|
wire [19:0] regi_addr;
|
||||||
|
wire e0_rego_rd, e1_rego_rd, e2_rego_rd, e3_rego_rd;
|
||||||
|
|
||||||
|
ioport2_msg_decode e0_rego_decoder (.message(e0_rego_tdata), .rd_request(e0_rego_rd));
|
||||||
|
ioport2_msg_decode e1_rego_decoder (.message(e1_rego_tdata), .rd_request(e1_rego_rd));
|
||||||
|
ioport2_msg_decode e2_rego_decoder (.message(e2_rego_tdata), .rd_request(e2_rego_rd));
|
||||||
|
ioport2_msg_decode e3_rego_decoder (.message(e3_rego_tdata), .rd_request(e3_rego_rd));
|
||||||
|
|
||||||
|
localparam DEST_E0 = 2'd0;
|
||||||
|
localparam DEST_E1 = 2'd1;
|
||||||
|
localparam DEST_E2 = 2'd2;
|
||||||
|
localparam DEST_E3 = 2'd3;
|
||||||
|
|
||||||
|
reg [1:0] regi_resp_dest;
|
||||||
|
wire [1:0] regi_req_dest, regi_dest;
|
||||||
|
|
||||||
|
assign regi_req_dest =
|
||||||
|
((regi_addr & E0_MASK) == E0_ADDR) ? DEST_E0 : (
|
||||||
|
((regi_addr & E1_MASK) == E1_ADDR) ? DEST_E1 : (
|
||||||
|
((regi_addr & E2_MASK) == E2_ADDR) ? DEST_E2 : (
|
||||||
|
((regi_addr & E3_MASK) == E3_ADDR) ? DEST_E3 : (
|
||||||
|
DEST_E0))));
|
||||||
|
|
||||||
|
//A response must be routed to the port with the last read request
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset)
|
||||||
|
regi_resp_dest <= DEST_E0; //Default 0
|
||||||
|
else if (e0_rego_tvalid & e0_rego_tready & e0_rego_rd)
|
||||||
|
regi_resp_dest <= DEST_E0;
|
||||||
|
else if (e1_rego_tvalid & e1_rego_tready & e1_rego_rd)
|
||||||
|
regi_resp_dest <= DEST_E1;
|
||||||
|
else if (e2_rego_tvalid & e2_rego_tready & e2_rego_rd)
|
||||||
|
regi_resp_dest <= DEST_E2;
|
||||||
|
else if (e3_rego_tvalid & e3_rego_tready & e3_rego_rd)
|
||||||
|
regi_resp_dest <= DEST_E3;
|
||||||
|
end
|
||||||
|
|
||||||
|
ioport2_msg_decode regi_decoder (
|
||||||
|
.message(regi_msg), .rd_response(regi_rc), .address(regi_addr));
|
||||||
|
|
||||||
|
//If request, get destination from msg.
|
||||||
|
//If response, get destination from last read location.
|
||||||
|
assign regi_dest = regi_rc ? regi_resp_dest : regi_req_dest;
|
||||||
|
|
||||||
|
axi_demux4 #(.ACTIVE_CHAN(4'b1111), .WIDTH(64), .BUFFER(0)) regi_arbiter_demux (
|
||||||
|
.clk(clk), .reset(reset), .clear(1'b0),
|
||||||
|
.header(regi_msg), .dest(regi_dest),
|
||||||
|
.i_tdata(regi_tdata), .i_tlast(regi_tvalid), .i_tvalid(regi_tvalid), .i_tready(regi_tready),
|
||||||
|
.o0_tdata(e0_regi_tdata), .o0_tlast(), .o0_tvalid(e0_regi_tvalid), .o0_tready(e0_regi_tready),
|
||||||
|
.o1_tdata(e1_regi_tdata), .o1_tlast(), .o1_tvalid(e1_regi_tvalid), .o1_tready(e1_regi_tready),
|
||||||
|
.o2_tdata(e2_regi_tdata), .o2_tlast(), .o2_tvalid(e2_regi_tvalid), .o2_tready(e2_regi_tready),
|
||||||
|
.o3_tdata(e3_regi_tdata), .o3_tlast(), .o3_tvalid(e3_regi_tvalid), .o3_tready(e3_regi_tready)
|
||||||
|
);
|
||||||
|
//
|
||||||
|
//*******************************************************************************
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
`timescale 500ps/1ps
|
||||||
|
|
||||||
|
module pcie_iop2_msg_arbiter_tb();
|
||||||
|
reg clk = 0;
|
||||||
|
reg reset = 1;
|
||||||
|
|
||||||
|
always #10 clk = ~clk;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#100 reset = 0;
|
||||||
|
#200000;
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
function [63:0] iop2_msg_write;
|
||||||
|
input [19:0] address;
|
||||||
|
input [31:0] data;
|
||||||
|
input half_wd;
|
||||||
|
begin
|
||||||
|
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
|
||||||
|
iop2_msg_write = {1'b0, 1'b1, 1'b0, half_wd, 8'h00, address, data};
|
||||||
|
end
|
||||||
|
endfunction // iop2_msg_write
|
||||||
|
|
||||||
|
function [63:0] iop2_msg_read;
|
||||||
|
input [19:0] address;
|
||||||
|
input half_wd;
|
||||||
|
begin
|
||||||
|
// {rd_response, wr_request, rd_request, half_word, 8'h00, address, data};
|
||||||
|
iop2_msg_read = {1'b0, 1'b0, 1'b1, half_wd, 8'h00, address, 32'h0};
|
||||||
|
end
|
||||||
|
endfunction // iop2_msg_read
|
||||||
|
|
||||||
|
reg [63:0] msgi_tdata;
|
||||||
|
wire [63:0] msgo_tdata;
|
||||||
|
wire msgo_tvalid, msgi_tready;
|
||||||
|
reg msgo_tready, msgi_tvalid;
|
||||||
|
|
||||||
|
wire [63:0] basic_regi_tdata, zpu_regi_tdata;
|
||||||
|
wire basic_regi_tvalid, zpu_regi_tvalid;
|
||||||
|
reg basic_regi_tready, zpu_regi_tready;
|
||||||
|
reg [63:0] basic_rego_tdata, zpu_rego_tdata;
|
||||||
|
reg basic_rego_tvalid, zpu_rego_tvalid;
|
||||||
|
wire basic_rego_tready, zpu_rego_tready;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
//@TODO: Make this a self-checking TB
|
||||||
|
while (reset) @(posedge clk);
|
||||||
|
|
||||||
|
msgo_tready <= 1;
|
||||||
|
basic_regi_tready <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
|
||||||
|
msgi_tdata <= iop2_msg_write(20'h0, 32'hDEAD, 0);
|
||||||
|
msgi_tvalid <= 1;
|
||||||
|
while (~msgi_tready) @(posedge clk);
|
||||||
|
msgi_tvalid <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
|
||||||
|
msgi_tdata <= iop2_msg_read(20'h00000, 0);
|
||||||
|
msgi_tvalid <= 1;
|
||||||
|
while (~msgi_tready) @(posedge clk);
|
||||||
|
msgi_tvalid <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
zpu_rego_tdata <= {1, 31'h0, 32'h12345678};
|
||||||
|
zpu_rego_tvalid <= 1;
|
||||||
|
while (~zpu_rego_tready) @(posedge clk);
|
||||||
|
zpu_rego_tvalid <= 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end // initial begin
|
||||||
|
|
||||||
|
pcie_iop2_msg_arbiter #(
|
||||||
|
.E0_ADDR(20'h00000), .E0_MASK(20'hFFF00), //0x00000 - 0x000FF: Basic PCIe registers
|
||||||
|
.E1_ADDR(20'h00100), .E1_MASK(20'hFFF00), //0x00100 - 0x001FF: PCIe router registers
|
||||||
|
.E2_ADDR(20'h00200), .E2_MASK(20'hFFE00), //0x00200 - 0x003FF: DMA stream registers
|
||||||
|
.E3_ADDR(20'h40000), .E3_MASK(20'hC0000) //0x40000 - 0x7FFFF: Client address space
|
||||||
|
) iop2_msg_arbiter (
|
||||||
|
.clk(clk), .reset(reset),
|
||||||
|
//Master
|
||||||
|
.regi_tdata(msgi_tdata), .regi_tvalid(msgi_tvalid), .regi_tready(msgi_tready),
|
||||||
|
.rego_tdata(msgo_tdata), .rego_tvalid(msgo_tvalid), .rego_tready(msgo_tready),
|
||||||
|
//Endpoint 0
|
||||||
|
.e0_regi_tdata(basic_regi_tdata), .e0_regi_tvalid(basic_regi_tvalid), .e0_regi_tready(basic_regi_tready),
|
||||||
|
.e0_rego_tdata(basic_rego_tdata), .e0_rego_tvalid(basic_rego_tvalid), .e0_rego_tready(basic_rego_tready),
|
||||||
|
//Endpoint 1
|
||||||
|
.e1_regi_tdata(), .e1_regi_tvalid(), .e1_regi_tready(1'b1),
|
||||||
|
.e1_rego_tdata(64'h0), .e1_rego_tvalid(1'b0), .e1_rego_tready(),
|
||||||
|
//Endpoint 2
|
||||||
|
.e2_regi_tdata(), .e2_regi_tvalid(), .e2_regi_tready(1'b1),
|
||||||
|
.e2_rego_tdata(64'h0), .e2_rego_tvalid(1'b0), .e2_rego_tready(),
|
||||||
|
//Endpoint 3
|
||||||
|
.e3_regi_tdata(zpu_regi_tdata), .e3_regi_tvalid(zpu_regi_tvalid), .e3_regi_tready(zpu_regi_tready),
|
||||||
|
.e3_rego_tdata(zpu_rego_tdata), .e3_rego_tvalid(zpu_rego_tvalid), .e3_rego_tready(zpu_rego_tready)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module pcie_pkt_route_specifier #(
|
||||||
|
parameter BASE_ADDR = 20'h0,
|
||||||
|
parameter ADDR_MASK = 20'hFFF00,
|
||||||
|
parameter SID_WIDTH = 8,
|
||||||
|
parameter DST_WIDTH = 4
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
input [63:0] regi_tdata,
|
||||||
|
input regi_tvalid,
|
||||||
|
output regi_tready,
|
||||||
|
|
||||||
|
input [SID_WIDTH-1:0] local_sid,
|
||||||
|
output [DST_WIDTH-1:0] fifo_dst
|
||||||
|
);
|
||||||
|
// Routing table
|
||||||
|
reg [DST_WIDTH-1:0] routing_table[0:(1<<SID_WIDTH)-1];
|
||||||
|
assign fifo_dst = routing_table[local_sid];
|
||||||
|
|
||||||
|
wire reg_wr;
|
||||||
|
wire [19:0] reg_addr;
|
||||||
|
wire [31:0] reg_data;
|
||||||
|
|
||||||
|
// Routing table configuration
|
||||||
|
ioport2_msg_decode config_message_decoder (
|
||||||
|
.message(regi_tdata), .wr_request(reg_wr), .rd_request(reg_rd), .address(reg_addr), .data(reg_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (regi_tvalid && regi_tready && reg_wr && ((reg_addr & ADDR_MASK) == BASE_ADDR)) begin
|
||||||
|
routing_table[reg_data[SID_WIDTH+15:16]] <= reg_data[DST_WIDTH-1:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign regi_tready = 1;
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
module pcie_wb_reg_core #(
|
||||||
|
parameter WB_ADDRW = 16,
|
||||||
|
parameter WB_DATAW = 32
|
||||||
|
)(
|
||||||
|
input clk,
|
||||||
|
input rst,
|
||||||
|
|
||||||
|
input wb_stb_i,
|
||||||
|
input wb_we_i,
|
||||||
|
input [WB_ADDRW-1:0] wb_adr_i,
|
||||||
|
input [WB_DATAW-1:0] wb_dat_i,
|
||||||
|
output wb_ack_o,
|
||||||
|
output [WB_DATAW-1:0] wb_dat_o,
|
||||||
|
|
||||||
|
input [63:0] msgi_tdata,
|
||||||
|
input msgi_tvalid,
|
||||||
|
output msgi_tready,
|
||||||
|
|
||||||
|
output [63:0] msgo_tdata,
|
||||||
|
output msgo_tvalid,
|
||||||
|
input msgo_tready,
|
||||||
|
|
||||||
|
output [31:0] debug
|
||||||
|
);
|
||||||
|
// Parameters
|
||||||
|
localparam PCIE_REGPORT_ADDR_MASK = 20'h0FFFF;
|
||||||
|
localparam PCIE_REGPORT_DATA_ADDR = 20'h70000;
|
||||||
|
localparam PCIE_REGPORT_READ_ADDR = 20'h60000;
|
||||||
|
localparam PCIE_REGPORT_STATUS_ADDR = 20'h60000;
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// WB AXI interface
|
||||||
|
//
|
||||||
|
wire [63:0] wb_msgi_tdata, wb_msgo_tdata;
|
||||||
|
wire wb_msgi_tvalid, wb_msgi_tready, wb_msgo_tvalid, wb_msgo_tready;
|
||||||
|
wire wb_monitor_active, wb_req_pending, wb_resp_pending;
|
||||||
|
|
||||||
|
pcie_axi_wb_conv #( .WB_ADDRW(WB_ADDRW), .WB_DATAW(WB_DATAW) ) axi_wb_translator (
|
||||||
|
.clk(clk), .rst(rst),
|
||||||
|
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_adr_i(wb_adr_i),
|
||||||
|
.wb_dat_i(wb_dat_i), .wb_ack_o(wb_ack_o), .wb_dat_o(wb_dat_o),
|
||||||
|
.msgi_tdata(wb_msgo_tdata), .msgi_tvalid(wb_msgo_tvalid), .msgi_tready(wb_msgo_tready),
|
||||||
|
.msgo_tdata(wb_msgi_tdata), .msgo_tvalid(wb_msgi_tvalid), .msgo_tready(wb_msgi_tready),
|
||||||
|
.wb_monitor_active(wb_monitor_active), .wb_req_pending(wb_req_pending), .wb_resp_pending(wb_resp_pending)
|
||||||
|
);
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// PCIe In -> WB Out
|
||||||
|
//
|
||||||
|
wire pcie_in_wr, pcie_in_rd, wb_out_wr, wb_out_rd;
|
||||||
|
wire pcie2wb_rr, pcie2wb_hword;
|
||||||
|
wire pcie_in_status_read, pcie_in_data_read;
|
||||||
|
wire [19:0] pcie_in_addr;
|
||||||
|
wire [31:0] pcie2wb_payload;
|
||||||
|
|
||||||
|
ioport2_msg_decode pcie_in_decoder (
|
||||||
|
.message(msgi_tdata),
|
||||||
|
.rd_response(pcie2wb_rr), .wr_request(pcie_in_wr), .rd_request(pcie_in_rd),
|
||||||
|
.half_word(pcie2wb_hword), .address(pcie_in_addr), .data(pcie2wb_payload)
|
||||||
|
);
|
||||||
|
|
||||||
|
ioport2_msg_encode wb_out_decoder (
|
||||||
|
.rd_response(pcie2wb_rr), .wr_request(wb_out_wr), .rd_request(wb_out_rd),
|
||||||
|
.half_word(pcie2wb_hword), .address(pcie_in_addr & PCIE_REGPORT_ADDR_MASK), .data(pcie2wb_payload),
|
||||||
|
.message(wb_msgo_tdata)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign wb_out_wr = pcie_in_wr && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_DATA_ADDR);
|
||||||
|
assign wb_out_rd = pcie_in_wr && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_READ_ADDR);
|
||||||
|
assign wb_msgo_tvalid = msgi_tvalid & (wb_out_wr | wb_out_rd | pcie2wb_rr);
|
||||||
|
assign msgi_tready = pcie_out_auto_resp_valid ? pcie_out_auto_resp_ready : wb_msgo_tready;
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// WB In -> PCIe Out
|
||||||
|
//
|
||||||
|
assign pcie_in_status_read = pcie_in_rd && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_STATUS_ADDR);
|
||||||
|
assign pcie_in_data_read = pcie_in_rd && ((pcie_in_addr & ~PCIE_REGPORT_ADDR_MASK) == PCIE_REGPORT_DATA_ADDR);
|
||||||
|
|
||||||
|
reg [31:0] wb_in_resp_payload_reg;
|
||||||
|
|
||||||
|
wire wb_in_rr, wb_msgi_tready_int;
|
||||||
|
wire [63:0] pcie_out_auto_resp_data;
|
||||||
|
wire pcie_out_auto_resp_valid, pcie_out_auto_resp_ready;
|
||||||
|
wire [31:0] wb_in_resp_payload;
|
||||||
|
|
||||||
|
ioport2_msg_decode wb_in_decoder (
|
||||||
|
.message(wb_msgi_tdata), .rd_response(wb_in_rr), .data(wb_in_resp_payload)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign pcie_out_auto_resp_valid = (msgi_tvalid & (pcie_in_status_read | pcie_in_data_read));
|
||||||
|
|
||||||
|
ioport2_msg_encode auto_response_encoder (
|
||||||
|
.rd_response(1'b1),
|
||||||
|
.data(pcie_in_data_read ? wb_in_resp_payload_reg : {~wb_monitor_active, 30'h0, (wb_req_pending | wb_resp_pending)}),
|
||||||
|
.message(pcie_out_auto_resp_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst)
|
||||||
|
wb_in_resp_payload_reg <= 32'h0;
|
||||||
|
else if (wb_msgi_tvalid & wb_msgi_tready & wb_in_rr)
|
||||||
|
wb_in_resp_payload_reg <= wb_in_resp_payload;
|
||||||
|
end
|
||||||
|
|
||||||
|
axi_mux4 #(.PRIO(0), .WIDTH(64), .BUFFER(1)) msgo_arbiter_mux (
|
||||||
|
.clk(clk), .reset(rst), .clear(1'b0),
|
||||||
|
.i0_tdata(wb_msgi_tdata), .i0_tlast(1'b1), .i0_tvalid(wb_msgi_tvalid & ~wb_in_rr), .i0_tready(wb_msgi_tready_int),
|
||||||
|
.i1_tdata(pcie_out_auto_resp_data), .i1_tlast(1'b1), .i1_tvalid(pcie_out_auto_resp_valid), .i1_tready(pcie_out_auto_resp_ready),
|
||||||
|
.i2_tdata(0), .i2_tlast(1'b0), .i2_tvalid(1'b0), .i2_tready(),
|
||||||
|
.i3_tdata(0), .i3_tlast(1'b0), .i3_tvalid(1'b0), .i3_tready(),
|
||||||
|
.o_tdata(msgo_tdata), .o_tlast(), .o_tvalid(msgo_tvalid), .o_tready(msgo_tready)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign wb_msgi_tready = wb_msgi_tready_int | (wb_msgi_tvalid & wb_in_rr);
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2013 Ettus Research LLC
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
`timescale 500ps/1ps
|
||||||
|
`define CHECK_VALUE(val, expected, report) \
|
||||||
|
if (val == expected) \
|
||||||
|
$display("%s...Passed",report); \
|
||||||
|
else \
|
||||||
|
$display("%s...FAILED!!! (Val=0x%x, Exp=0x%x)",report,val,expected); \
|
||||||
|
|
||||||
|
module pcie_wb_reg_core_tb();
|
||||||
|
reg clk = 0, reset = 1;
|
||||||
|
reg wb_stb_i = 0;
|
||||||
|
reg wb_we_i = 0;
|
||||||
|
reg [15:0] wb_adr_i = 0;
|
||||||
|
reg [31:0] wb_dat_i = 0;
|
||||||
|
wire wb_ack_o;
|
||||||
|
wire [31:0] wb_dat_o;
|
||||||
|
|
||||||
|
wire [63:0] msgo_data;
|
||||||
|
wire msgo_valid;
|
||||||
|
reg msgo_ready = 0;
|
||||||
|
reg [63:0] msgi_data = 0;
|
||||||
|
reg msgi_valid = 0;
|
||||||
|
wire msgi_ready;
|
||||||
|
|
||||||
|
reg [31:0] msgo_payload = 32'h0;
|
||||||
|
reg [31:0] msgo_ctrl = 32'h0;
|
||||||
|
|
||||||
|
reg [31:0] it;
|
||||||
|
|
||||||
|
always #10 clk = ~clk;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#100 reset = 0;
|
||||||
|
#200000;
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
localparam READ = 3'b001;
|
||||||
|
localparam WRITE = 3'b010;
|
||||||
|
localparam RESPONSE = 3'b100;
|
||||||
|
|
||||||
|
task pcie_send;
|
||||||
|
input [2:0] op;
|
||||||
|
input [19:0] address;
|
||||||
|
input [31:0] data;
|
||||||
|
begin
|
||||||
|
//{rd_resp, wr_request, rd_request, half_word, 8'h00, address, data};
|
||||||
|
msgi_data <= {op, 1'b0, 8'h00, address, data};
|
||||||
|
msgi_valid <= 1'b1;
|
||||||
|
|
||||||
|
@(posedge clk);
|
||||||
|
while (~msgi_ready) @(posedge clk);
|
||||||
|
|
||||||
|
msgi_valid <= 1'b0;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
endtask // pcie_send
|
||||||
|
|
||||||
|
task pcie_recv;
|
||||||
|
input [2:0] op;
|
||||||
|
input [19:0] address;
|
||||||
|
input [31:0] data;
|
||||||
|
begin
|
||||||
|
while (~msgo_valid) @(posedge clk);
|
||||||
|
|
||||||
|
msgo_ready <= 1'b1;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
if (msgo_data[63] == op[2] || (msgo_data[62:61] == op[1:0] && msgo_data[51:32] == address))
|
||||||
|
msgo_payload <= msgo_data[31:0];
|
||||||
|
msgo_ctrl <= msgo_data[63:32];
|
||||||
|
|
||||||
|
msgo_ready <= 1'b0;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
endtask // pcie_recv
|
||||||
|
|
||||||
|
task wb_send;
|
||||||
|
input [2:0] op;
|
||||||
|
input [15:0] address;
|
||||||
|
input [31:0] data;
|
||||||
|
begin
|
||||||
|
wb_adr_i <= address;
|
||||||
|
wb_dat_i <= data;
|
||||||
|
wb_we_i <= op[1];
|
||||||
|
wb_stb_i <= 1'b1;
|
||||||
|
|
||||||
|
@(posedge clk);
|
||||||
|
while (~wb_ack_o) @(posedge clk);
|
||||||
|
|
||||||
|
wb_stb_i <= 1'b0;
|
||||||
|
end
|
||||||
|
endtask // pcie_send
|
||||||
|
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
msgo_ready <= 1'b0;
|
||||||
|
msgi_valid <= 1'b0;
|
||||||
|
while (reset) @(posedge clk);
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
$display("\n[TEST] ZPU Read from PCIe");
|
||||||
|
pcie_send(WRITE, 20'h6a000, 32'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe readback before initiating read request");
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status after initiating read");
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status after initiating second read");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h6, "Verify WB status after PCIe read request");
|
||||||
|
wb_send(READ, 16'h4, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h2000a000, "Verify WB control value after PCIe read request");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h4, "Verify WB status value after consuming PCIe read request");
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status after WB consumes request only");
|
||||||
|
wb_send(WRITE, 16'h0, 32'hDEADBEEF);
|
||||||
|
wb_send(WRITE, 16'h4, 32'h80000000);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after responding to PCIe read request");
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status after WB responds to read request");
|
||||||
|
pcie_send(READ, 20'h7a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'hdeadbeef, "Verify PCIe read data");
|
||||||
|
|
||||||
|
$display("\n[TEST] ZPU Write from PCIe");
|
||||||
|
pcie_send(WRITE, 20'h7b000, 32'h12345678);
|
||||||
|
pcie_send(READ, 20'h7a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'hdeadbeef, "Verify that PCIe read data is still intact after write");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h2, "Verify WB status value after PCIe write request");
|
||||||
|
wb_send(READ, 16'h0, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h12345678, "Verify WB data value after PCIe read request");
|
||||||
|
wb_send(READ, 16'h4, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h4000b000, "Verify WB control value after PCIe read request");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after consuming PCIe write request");
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status after WB consumes request");
|
||||||
|
|
||||||
|
$display("\n[TEST] Chinch Write from ZPU");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value before initiating write request");
|
||||||
|
wb_send(WRITE, 16'h0, 32'h00beef00);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after writing just the data reg");
|
||||||
|
wb_send(WRITE, 16'h4, 32'h40000200);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after initiating write");
|
||||||
|
pcie_recv(WRITE, 20'h200, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h00beef00, "Verify received PCIe data");
|
||||||
|
`CHECK_VALUE(msgo_ctrl, 32'h40000200, "Verify received PCIe control");
|
||||||
|
wb_send(WRITE, 16'h0, 32'h00feeb00);
|
||||||
|
wb_send(WRITE, 16'h4, 32'h400002fc);
|
||||||
|
pcie_recv(WRITE, 20'h200, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h00feeb00, "Verify second received PCIe data");
|
||||||
|
`CHECK_VALUE(msgo_ctrl, 32'h400002fc, "Verify second received PCIe control");
|
||||||
|
|
||||||
|
$display("\n[TEST] Chinch Read from ZPU");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value before initiating read request");
|
||||||
|
wb_send(WRITE, 16'h0, 32'hffffffff);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after writing just the data reg");
|
||||||
|
wb_send(WRITE, 16'h4, 32'h20000400);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h1, "Verify WB status value after initiating read request");
|
||||||
|
pcie_recv(READ, 20'h400, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'hffffffff, "Verify received PCIe data");
|
||||||
|
`CHECK_VALUE(msgo_ctrl, 32'h20000400, "Verify received PCIe control");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h1, "Verify WB status value before PCIe responds");
|
||||||
|
pcie_send(RESPONSE, 20'h000, 32'hace06666);
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status value after PCIe responds");
|
||||||
|
wb_send(READ, 16'h8, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'hace06666, "Verify WB read value after PCIe responds");
|
||||||
|
|
||||||
|
$display("\n[TEST] WB Outbound flood");
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h0, "Verify WB status before request flood");
|
||||||
|
for (it = 0; it < 64; it = it + 1) begin
|
||||||
|
wb_send(WRITE, 16'h4, 32'h20000400);
|
||||||
|
end
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h11, "Verify WB status after request flood");
|
||||||
|
for (it = 0; it < 64; it = it + 1) begin
|
||||||
|
pcie_recv(READ, 20'h400, 20'h0);
|
||||||
|
end
|
||||||
|
wb_send(READ, 16'hC, 32'h0);
|
||||||
|
`CHECK_VALUE(wb_dat_o, 32'h1, "Verify WB status after consuming requests");
|
||||||
|
|
||||||
|
$display("\n[TEST] PCIe Transaction Status");
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status before multiple reads");
|
||||||
|
pcie_send(WRITE, 20'h6a000, 32'h0);
|
||||||
|
pcie_send(WRITE, 20'h6a000, 32'h0);
|
||||||
|
pcie_send(WRITE, 20'h6a000, 32'h0);
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h1, "Verify PCIe status before multiple read requests and status queries");
|
||||||
|
wb_send(READ, 16'h4, 32'h0);
|
||||||
|
wb_send(WRITE, 16'h0, 32'hDEADBEEF);
|
||||||
|
wb_send(WRITE, 16'h4, 32'h80000000);
|
||||||
|
pcie_send(READ, 20'h6a000, 32'h0);
|
||||||
|
pcie_recv(RESPONSE, 20'h0, 20'h0);
|
||||||
|
`CHECK_VALUE(msgo_payload, 32'h0, "Verify PCIe status after response");
|
||||||
|
|
||||||
|
$display("\n[DONE]");
|
||||||
|
|
||||||
|
|
||||||
|
end // initial begin
|
||||||
|
|
||||||
|
pcie_wb_reg_core #(.WB_ADDRW(16), .WB_DATAW(32)) dut (
|
||||||
|
.clk(clk), .rst(reset),
|
||||||
|
.wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_adr_i(wb_adr_i),
|
||||||
|
.wb_dat_i(wb_dat_i), .wb_ack_o(wb_ack_o), .wb_dat_o(wb_dat_o),
|
||||||
|
.msgi_tdata(msgi_data), .msgi_tvalid(msgi_valid), .msgi_tready(msgi_ready),
|
||||||
|
.msgo_tdata(msgo_data), .msgo_tvalid(msgo_valid), .msgo_tready(msgo_ready),
|
||||||
|
.debug());
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// Quantize cvita packets to a configurable quantum value. o_tlast and
|
// Quantize cvita packets to a configurable quantum value. o_tlast and
|
||||||
// i_tready will be held off until the entire quantized packet is xferred.
|
// i_tready will be held off until the entire quantized packet is xferred.
|
||||||
// If quantum is changed, it is the responsibility of the client to clear
|
// If quantum is changed, it is the responsibility of the client to clear
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
`timescale 500ps/1ps
|
`timescale 500ps/1ps
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
module cvita_dechunker # (
|
module cvita_dechunker # (
|
||||||
parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF
|
parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2013 Ettus Research LLC
|
// Copyright 2013 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
`timescale 500ps/1ps
|
`timescale 500ps/1ps
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012 Ettus Research LLC
|
// Copyright 2012 Ettus Research LLC
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
`timescale 1 ps / 1 ps
|
`timescale 1 ps / 1 ps
|
||||||
|
|
||||||
module eth_dispatch_tb();
|
module eth_dispatch_tb();
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI stream input
|
||||||
|
//
|
||||||
|
reg [63:0] i_tdata;
|
||||||
|
reg i_tlast;
|
||||||
|
reg i_tvalid;
|
||||||
|
wire i_tready;
|
||||||
|
//
|
||||||
|
// CHDR friendly AXI Stream output
|
||||||
|
//
|
||||||
|
wire [63:0] o_tdata;
|
||||||
|
wire o_tlast;
|
||||||
|
wire o_tvalid;
|
||||||
|
reg o_tready;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// This task sends a burst of CHDR packets with populated headers.
|
||||||
|
// The burst payload contains a ramp of incrementing amplitude strating at 0.
|
||||||
|
//
|
||||||
|
task send_ramp;
|
||||||
|
input [31:0] burst_count; // Number of CHDR packets in burst.
|
||||||
|
input [31:0] len; // Length of each CHDR packet in 32bit words.
|
||||||
|
input [63:0] send_time; // Optional 64 VITA time for first packet of burst.
|
||||||
|
input [11:0] start_seqnum; // Seeds initial seqnum of this burst.
|
||||||
|
input send_at; // Set this to include VITA time on first poacket in burst.
|
||||||
|
input [31:0] sid; // SID value for all CHDR packets in burst
|
||||||
|
|
||||||
|
reg [31:0] data;
|
||||||
|
reg [11:0] seqno;
|
||||||
|
|
||||||
|
begin
|
||||||
|
seqno = start_seqnum;
|
||||||
|
data = 0;
|
||||||
|
send_packet(len, data, send_time, seqno, (burst_count==1), send_at, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
data <= data + len;
|
||||||
|
|
||||||
|
if(burst_count > 2)
|
||||||
|
repeat (burst_count - 2)
|
||||||
|
begin
|
||||||
|
send_packet(len, data, 64'h0, seqno, 0, 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
data <= data + len;
|
||||||
|
end
|
||||||
|
if(burst_count > 1)
|
||||||
|
send_packet(len, data, 64'h0, seqno, 1, 0, sid);
|
||||||
|
end
|
||||||
|
endtask // send_ramp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// This task sends a burst of CHDR packets with populated headers
|
||||||
|
// Each packets payload is an incrementing count re-starting at the start value.
|
||||||
|
//
|
||||||
|
task send_burst;
|
||||||
|
input [31:0] burst_count; // Number of CHDR packets in burst.
|
||||||
|
input [31:0] len; // Length of each CHDR packet in 32bit words.
|
||||||
|
input [31:0] start_data; // Seed initial sample magnitude.
|
||||||
|
input [63:0] send_time; // Optional 64 VITA time for first packet of burst.
|
||||||
|
input [11:0] start_seqnum; // Seeds initial seqnum of this burst.
|
||||||
|
input send_at; // Set this to include VITA time on first packet in burst.
|
||||||
|
input [31:0] sid; // SID value for all CHDR packets in burst
|
||||||
|
|
||||||
|
reg [11:0] seqno;
|
||||||
|
|
||||||
|
begin
|
||||||
|
seqno = start_seqnum;
|
||||||
|
send_packet(len, {seqno,start_data[15:0]}, send_time, seqno, (burst_count==1), send_at, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
|
||||||
|
if(burst_count > 2)
|
||||||
|
repeat (burst_count - 2)
|
||||||
|
begin
|
||||||
|
send_packet(len, {seqno,start_data[15:0]}, 64'h0, seqno, 0, 0, sid);
|
||||||
|
seqno = seqno + 1;
|
||||||
|
end
|
||||||
|
if(burst_count > 1)
|
||||||
|
send_packet(len, {seqno,start_data[15:0]}, 64'h0, seqno, 1, 0, sid);
|
||||||
|
end
|
||||||
|
endtask // send_burst
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sends a single CHDR packet. Has valid CHDR headers and incrementing sample payload.
|
||||||
|
// Alter this with care, many other tasks depend on this task.
|
||||||
|
//
|
||||||
|
task send_packet;
|
||||||
|
input [31:0] len;
|
||||||
|
input [31:0] start_data;
|
||||||
|
input [63:0] send_time;
|
||||||
|
input [11:0] pkt_seqnum;
|
||||||
|
input eob;
|
||||||
|
input send_at;
|
||||||
|
input [31:0] sid;
|
||||||
|
|
||||||
|
reg [31:0] samp0, samp1;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Send a packet
|
||||||
|
samp0 <= start_data;
|
||||||
|
samp1 <= start_data + 1;
|
||||||
|
@(posedge clk);
|
||||||
|
|
||||||
|
i_tlast <= 0;
|
||||||
|
i_tdata <= { 1'b0, 1'b0 /*trl*/, send_at, eob, pkt_seqnum, len[15:0]+16'd2+send_at+send_at, sid };
|
||||||
|
i_tvalid <= 1;
|
||||||
|
@(posedge clk)
|
||||||
|
if(send_at)
|
||||||
|
begin
|
||||||
|
i_tdata <= send_time;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
|
||||||
|
repeat (len[31:1]+len[0]-1)
|
||||||
|
begin
|
||||||
|
i_tdata <= {samp0,samp1};
|
||||||
|
samp0 <= samp0 + 2;
|
||||||
|
samp1 <= samp1 + 2;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
|
||||||
|
i_tdata <= {samp0,samp1};
|
||||||
|
i_tlast <= 1'b1;
|
||||||
|
@(posedge clk);
|
||||||
|
i_tvalid <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
endtask // send_packet
|
||||||
|
|
||||||
|
//
|
||||||
|
// These 2 tasks stuff an incrementing count and then check for a match
|
||||||
|
// on Egress to test CHDR blocks for transparaent data pass through.
|
||||||
|
// CHDR fields are not inteligently populated by these tasks.
|
||||||
|
//
|
||||||
|
task send_raw_packet;
|
||||||
|
input [31:0] len;
|
||||||
|
|
||||||
|
reg [63:0] data;
|
||||||
|
|
||||||
|
begin
|
||||||
|
data = 0;
|
||||||
|
@(posedge clk);
|
||||||
|
repeat (len-1) begin
|
||||||
|
i_tlast <= 0;
|
||||||
|
i_tdata <= data;
|
||||||
|
i_tvalid <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~i_tready) @(posedge clk);
|
||||||
|
data = data + 1;
|
||||||
|
end
|
||||||
|
i_tlast <= 1;
|
||||||
|
i_tdata <= data;
|
||||||
|
i_tvalid <= 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~i_tready) @(posedge clk);
|
||||||
|
i_tvalid <= 0;
|
||||||
|
@(posedge clk);
|
||||||
|
end
|
||||||
|
endtask // send_raw_packet
|
||||||
|
|
||||||
|
task receive_raw_packet;
|
||||||
|
input [31:0] len;
|
||||||
|
output fail;
|
||||||
|
reg [63:0] data;
|
||||||
|
|
||||||
|
begin
|
||||||
|
data = 0;
|
||||||
|
fail = 0;
|
||||||
|
|
||||||
|
@(posedge clk);
|
||||||
|
repeat (len-1) begin
|
||||||
|
o_tready = 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~o_tvalid) @(posedge clk);
|
||||||
|
//$display("Data = %d, o_tdata = %d, o_tlast = %d",data,o_tdata,o_tlast);
|
||||||
|
|
||||||
|
fail = fail || (data != o_tdata);
|
||||||
|
fail = fail || (o_tlast == 1);
|
||||||
|
data = data + 1;
|
||||||
|
|
||||||
|
end
|
||||||
|
o_tready = 1;
|
||||||
|
@(posedge clk);
|
||||||
|
while (~o_tvalid) @(posedge clk);
|
||||||
|
//$display("Data = %d, o_tdata = %d, o_tlast = %d",data,o_tdata,o_tlast);
|
||||||
|
fail = fail || (data != o_tdata);
|
||||||
|
fail = fail || (o_tlast == 0);
|
||||||
|
o_tready = 0;
|
||||||
|
@(posedge clk);
|
||||||
|
if (fail) $display("receive_raw_packet size %d failed",len);
|
||||||
|
|
||||||
|
end
|
||||||
|
endtask // receive_raw_packet
|
||||||
|
|
||||||
|
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
iverilog \
|
||||||
|
-s axi_crossbar_tb \
|
||||||
|
-y ~/XILINX_verilog/ISE/verilog/src/unisims \
|
||||||
|
-o axi_crossbar_tb \
|
||||||
|
~/XILINX_verilog/ISE/verilog/src/glbl.v \
|
||||||
|
../../control/axi_crossbar_tb.v \
|
||||||
|
../../control/axi_crossbar.v \
|
||||||
|
../../control/axi_slave_mux.v \
|
||||||
|
../../control/axi_fifo_header.v \
|
||||||
|
../../control/arb_qualify_master.v \
|
||||||
|
../../control/setting_reg.v \
|
||||||
|
../../fifo/monitor_axi_fifo.v \
|
||||||
|
../../fifo/axi_fifo_short.v
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#fuse work.axi_crossbar_tb work.glbl -L unisims_ver -L xilinxcorelib_ver -o axi_crossbar_tb.exe
|
||||||
|
|
||||||
|
# run the simulation scrip
|
||||||
|
#./axi_crossbar_tb.exe -gui #-tclbatch simcmds.tcl
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user