Pushing the bulk of UHD-3.7.0 code.

Original-commit: ff1546f8137f7f92bb250f685561b0c34cc0e053
This commit is contained in:
Ben Hilburn
2014-02-14 12:05:07 -08:00
parent 29086f9001
commit fbbc991a7d
2194 changed files with 1489297 additions and 1084 deletions
+17
View File
@@ -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 \
))
+40
View File
@@ -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
+314
View File
@@ -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
+34
View File
@@ -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
+538
View File
@@ -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
+165
View File
@@ -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
+816
View File
@@ -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
+421
View File
@@ -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
+128
View File
@@ -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
+149
View File
@@ -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
+187
View File
@@ -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
+102
View File
@@ -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
+42
View File
@@ -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
//
//
//
)
+1
View File
@@ -24,4 +24,5 @@ axi_test_vfifo.v \
dram_2port.v \
cvita_uart.v \
serial_to_settings.v \
filter_bad_sid.v \
))
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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) (\
N < 2 ? 0 : \
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
module axi_crossbar_tb;
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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.
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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/>.
//
+1 -13
View File
@@ -2,19 +2,7 @@
//
// 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
+72
View File
@@ -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
View File
@@ -2,24 +2,14 @@
//
// 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
#(parameter BASE = 0,
parameter WIDTH = 32)
parameter WIDTH = 32,
parameter default_ddr = 0,
parameter default_idle = 0)
(input clk, input reset,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input rx, input tx,
@@ -32,7 +22,7 @@ module gpio_atr
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),
.out(in_idle),.changed());
@@ -48,7 +38,7 @@ module gpio_atr
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
.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),
.out(ddr),.changed());
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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 -13
View File
@@ -1,19 +1,7 @@
//
// 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/>.
//
+11 -1
View File
@@ -10,7 +10,9 @@ module serial_to_settings
// Settngs bus out
output reg set_stb,
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;
@@ -105,6 +107,14 @@ module serial_to_settings
endcase // case(state)
end // else: !if(reset)
assign debug =
{
counter[4:0],
state[2:0],
scl_reg,
sda_reg
};
+28
View File
@@ -45,6 +45,34 @@ module serial_to_settings_tb();
.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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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.
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+18 -22
View File
@@ -1,19 +1,7 @@
//
// 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
@@ -69,9 +57,9 @@ module simple_spi_core
output ready,
//spi interface, slave selects, clock, data in, data out
output [WIDTH-1:0] sen,
output reg [WIDTH-1:0] sen,
output sclk,
output mosi,
output reg mosi,
input miso,
//optional debug output
@@ -113,22 +101,30 @@ module simple_spi_core
assign sclk = sclk_reg;
//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 [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
reg [WIDTH-1:0] sen_reg;
always @(posedge clock) sen_reg <= sen24[WIDTH-1:0];
assign sen = sen_reg;
always @(posedge clock)
sen_reg <= sen24[WIDTH-1:0];
always @(posedge clock)
sen <= sen_reg;
//data output shift register
// IJB. One pipeline stage to break critical path from register in I/O pads.
reg [31:0] dataout_reg;
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
// IJB. One pipeline stage to break critical path from register in I/O pads.
reg miso_pipe;
always @(posedge clock)
miso_pipe = miso;
// IJB. Two pipeline stages to break critical path from register in I/O pads.
reg miso_pipe, miso_pipe2;
always @(posedge clock) begin
miso_pipe2 <= miso;
miso_pipe <= miso_pipe2;
end
reg [31:0] datain_reg;
wire [31:0] datain_next = {datain_reg[30:0], miso_pipe};
+1
View File
@@ -0,0 +1 @@
coregen.log
View File
+2
View File
@@ -6,6 +6,7 @@
# DSP Sources
##################################################
DSP_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/dsp/, \
ddc_chain_x300.v \
ddc_chain.v \
duc_chain.v \
sign_extend.v \
@@ -34,5 +35,6 @@ round.v \
srl.v \
acc.v \
rx_frontend.v \
tx_frontend.v \
rx_dcoffset.v \
))
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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
View File
@@ -4,19 +4,7 @@
//
// 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
View File
@@ -4,19 +4,7 @@
//
// 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
View File
@@ -4,19 +4,7 @@
//
// 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
View File
@@ -3,19 +3,7 @@
//
// 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
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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);
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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 );
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+262
View File
@@ -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
+58
View File
@@ -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
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A]
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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"
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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"
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
View File
@@ -14,8 +14,9 @@ module rx_frontend
);
reg [15:0] adc_i, adc_q;
wire [17:0] adc_i_ofs, adc_q_ofs;
wire [35:0] corr_i, corr_q; wire [17:0] mag_corr,phase_corr;
wire [23:0] adc_i_ofs, adc_q_ofs;
wire [35:0] corr_i, corr_q;
wire [17:0] mag_corr,phase_corr;
wire swap_iq;
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),
.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
if(IQCOMP_EN == 1)
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
(.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
(.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
(.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());
add2_and_clip_reg #(.WIDTH(24)) add_clip_q
(.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());
end // if (IQCOMP_EN == 1)
else
begin
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(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));
assign i_out = adc_i_ofs;
assign q_out = adc_q_ofs;
end // else: !if(IQCOMP_EN == 1)
endgenerate
endgenerate
endmodule // rx_frontend
+4 -4
View File
@@ -13,21 +13,21 @@ module rx_frontend_tb();
initial $dumpvars(0,rx_frontend_tb);
reg [15:0] adc_in;
wire [17:0] adc_out;
wire [23:0] adc_out;
always @(posedge clk)
begin
if(adc_in[13])
if(adc_in[15])
$write("-%d,",-adc_in);
else
$write("%d,",adc_in);
if(adc_out[13])
if(adc_out[23])
$write("-%d\n",-adc_out);
else
$write("%d\n",adc_out);
end
rx_frontend #(.BASE(0)) rx_frontend
rx_frontend #(.BASE(0), .IQCOMP_EN(1)) rx_frontend
(.clk(clk),.rst(rst),
.set_stb(0),.set_addr(0),.set_data(0),
.adc_a(adc_in), .adc_ovf_a(0),
+1 -13
View File
@@ -4,19 +4,7 @@
//
// 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
View File
@@ -1,19 +1,7 @@
//
// 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)
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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)
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+97
View File
@@ -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
+1
View File
@@ -17,4 +17,5 @@ axi_fifo64_to_fifo32.v \
axi_fifo32_to_fifo64.v \
axi_fifo_2clk.v \
axi_loopback.v \
axi_filter_mux4.v \
))
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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.
+154
View File
@@ -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 -13
View File
@@ -1,19 +1,7 @@
//
// 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
// from clogging up the downstream. This block will hold up to 255 packets.
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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.
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
#(
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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 -13
View File
@@ -1,19 +1,7 @@
//
// 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
#(
+1
View File
@@ -0,0 +1 @@
/build
File diff suppressed because one or more lines are too long
+81
View File
@@ -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
+35
View File
@@ -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
+19
View File
@@ -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 \
))
+76
View File
@@ -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")
+22
View File
@@ -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
+49
View File
@@ -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
+196
View File
@@ -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
+103
View File
@@ -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
+156
View File
@@ -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
+89
View File
@@ -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
+131
View File
@@ -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
+107
View File
@@ -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
+43
View File
@@ -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
+126
View File
@@ -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
+240
View File
@@ -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 -13
View File
@@ -1,19 +1,7 @@
//
// 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
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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 # (
parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
+1 -13
View File
@@ -1,19 +1,7 @@
//
// 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
module eth_dispatch_tb();
+198
View File
@@ -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
+21
View File
@@ -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