Removed copy of FPGA source files.
Original-commit: fd3e84941de463fa1a7ebab0a69515b4bf2614cd
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
#
|
||||
# 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 \
|
||||
))
|
||||
@@ -1,40 +0,0 @@
|
||||
|
||||
// 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
|
||||
@@ -1,314 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,538 +0,0 @@
|
||||
|
||||
`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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
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
|
||||
@@ -1,816 +0,0 @@
|
||||
|
||||
//
|
||||
// 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
|
||||
|
||||
@@ -1,421 +0,0 @@
|
||||
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
|
||||
@@ -1,128 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@@ -1,102 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@@ -1,42 +0,0 @@
|
||||
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,28 +0,0 @@
|
||||
#
|
||||
# Copyright 2013 Ettus Research LLC
|
||||
#
|
||||
|
||||
##################################################
|
||||
# Control Lib Sources
|
||||
##################################################
|
||||
CONTROL_LIB_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/control/, \
|
||||
reset_sync.v \
|
||||
por_gen.v \
|
||||
gpio_atr.v \
|
||||
simple_spi_core.v \
|
||||
simple_i2c_core.v \
|
||||
setting_reg.v \
|
||||
settings_bus_crossclock.v \
|
||||
radio_ctrl_proc.v \
|
||||
ram_2port.v \
|
||||
axi_crossbar.v \
|
||||
axi_slave_mux.v \
|
||||
axi_fifo_header.v \
|
||||
arb_qualify_master.v \
|
||||
axi_forwarding_cam.v \
|
||||
axi_test_vfifo.v \
|
||||
dram_2port.v \
|
||||
cvita_uart.v \
|
||||
serial_to_settings.v \
|
||||
filter_bad_sid.v \
|
||||
))
|
||||
@@ -1,88 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// This module forms the qualification engine for a single master as
|
||||
// part of a larger arbitration engine for a slave. It would typically
|
||||
// be instantiated from arb_select_master.v to form a complete arbitor solution.
|
||||
//
|
||||
|
||||
module arb_qualify_master
|
||||
#(
|
||||
parameter WIDTH=16 // Bit width of destination field.
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
// Header signals
|
||||
input [WIDTH-1:0] header,
|
||||
input header_valid,
|
||||
// Slave Confg Signals
|
||||
input [WIDTH-1:0] slave_addr,
|
||||
input [WIDTH-1:0] slave_mask,
|
||||
input slave_valid,
|
||||
// Arbitration flags
|
||||
output reg master_valid,
|
||||
input master_ack
|
||||
);
|
||||
|
||||
localparam WAIT_HEADER_VALID = 0;
|
||||
localparam MATCH = 1;
|
||||
localparam WAIT_HEADER_NOT_VALID = 2;
|
||||
|
||||
|
||||
reg [1:0] state, next_state;
|
||||
|
||||
|
||||
// Does masked slave address match header field for dest from master?
|
||||
assign header_match = ((header & slave_mask) == (slave_addr & slave_mask)) && slave_valid;
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
state <= WAIT_HEADER_VALID;
|
||||
master_valid <= 0;
|
||||
end else
|
||||
begin
|
||||
case(state)
|
||||
//
|
||||
// Wait here until Masters FIFO presents a valid header word.
|
||||
//
|
||||
WAIT_HEADER_VALID: begin
|
||||
if (header_valid)
|
||||
if (header_match) begin
|
||||
state <= MATCH;
|
||||
master_valid <= 1;
|
||||
end else
|
||||
next_state <= WAIT_HEADER_NOT_VALID;
|
||||
end
|
||||
//
|
||||
// There should only ever be one match across various arbitors
|
||||
// if they are configured correctly and since the backing FIFO in the
|
||||
// master should not start to drain until the arbitration is won
|
||||
// by that master, master_ack should always preceed de-assertion of
|
||||
// header_valid so we don't check for the other order of deassertion.
|
||||
//
|
||||
MATCH: begin
|
||||
if (master_ack) begin
|
||||
master_valid <= 0;
|
||||
state <= WAIT_HEADER_NOT_VALID;
|
||||
end
|
||||
end
|
||||
//
|
||||
// Wait here until this master starts to drain this packet from his FIFO.
|
||||
//
|
||||
WAIT_HEADER_NOT_VALID: begin
|
||||
if (!header_valid) begin
|
||||
state <= WAIT_HEADER_VALID;
|
||||
end
|
||||
end
|
||||
endcase // case(state)
|
||||
end // else: !if(reset | clear)
|
||||
|
||||
endmodule // arb_qualify_master
|
||||
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
`define LOG2(N) (\
|
||||
N < 2 ? 0 : \
|
||||
N < 4 ? 1 : \
|
||||
N < 8 ? 2 : \
|
||||
N < 16 ? 3 : \
|
||||
N < 32 ? 4 : \
|
||||
N < 64 ? 5 : \
|
||||
N < 128 ? 6 : \
|
||||
N < 256 ? 7 : \
|
||||
N < 512 ? 8 : \
|
||||
N < 1024 ? 9 : \
|
||||
10)
|
||||
|
||||
module axi_crossbar
|
||||
#(
|
||||
parameter FIFO_WIDTH = 64, // AXI4-STREAM data bus width
|
||||
parameter DST_WIDTH = 16, // Width of DST field we are routing on.
|
||||
parameter NUM_INPUTS = 2, // number of input AXI4-STREAM buses
|
||||
parameter NUM_OUTPUTS = 2 // number of output AXI4-STREAM buses
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
input [7:0] local_addr,
|
||||
// Inputs
|
||||
input [(FIFO_WIDTH*NUM_INPUTS)-1:0] i_tdata,
|
||||
input [NUM_INPUTS-1:0] i_tvalid,
|
||||
input [NUM_INPUTS-1:0] i_tlast,
|
||||
output [NUM_INPUTS-1:0] i_tready,
|
||||
input [NUM_INPUTS-1:0] pkt_present,
|
||||
// Setting Bus
|
||||
input set_stb,
|
||||
input [15:0] set_addr,
|
||||
input [31:0] set_data,
|
||||
// Output
|
||||
output [(FIFO_WIDTH*NUM_OUTPUTS)-1:0] o_tdata,
|
||||
output [NUM_OUTPUTS-1:0] o_tvalid,
|
||||
output [NUM_OUTPUTS-1:0] o_tlast,
|
||||
input [NUM_OUTPUTS-1:0] o_tready,
|
||||
// readback bus
|
||||
input rb_rd_stb,
|
||||
input [`LOG2(NUM_OUTPUTS)+`LOG2(NUM_INPUTS)-1:0] rb_addr,
|
||||
output [31:0] rb_data
|
||||
);
|
||||
|
||||
genvar m,n;
|
||||
|
||||
wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_valid_in;
|
||||
wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_ack_in;
|
||||
wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_valid_out;
|
||||
wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_ack_out;
|
||||
|
||||
wire [NUM_INPUTS-1:0] i_tready_slave [0:NUM_OUTPUTS-1];
|
||||
|
||||
//
|
||||
// Instantiate an axi_slave_mux for every slave/output of the Crossbar switch.
|
||||
// Each axi_slave_mux contains logic to maux and resolve arbitration
|
||||
// for this particular slave/output.
|
||||
//
|
||||
|
||||
generate
|
||||
for (m = 0; m < NUM_OUTPUTS; m = m + 1) begin: instantiate_slave_mux
|
||||
|
||||
wire [NUM_INPUTS-1:0] i_tready_tmp;
|
||||
|
||||
axi_slave_mux
|
||||
#(
|
||||
.FIFO_WIDTH(FIFO_WIDTH), // AXI4-STREAM data bus width
|
||||
.DST_WIDTH(DST_WIDTH), // Width of DST field we are routing on.
|
||||
.NUM_INPUTS(NUM_INPUTS) // number of input AXI buses
|
||||
) axi_slave_mux_i
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(clear),
|
||||
// Inputs
|
||||
.i_tdata(i_tdata),
|
||||
.i_tvalid(i_tvalid),
|
||||
.i_tlast(i_tlast),
|
||||
.i_tready(i_tready_tmp),
|
||||
// Forwarding flags (One from each Input/Master)
|
||||
.forward_valid(forward_valid_in[(m+1)*NUM_INPUTS-1:m*NUM_INPUTS]),
|
||||
.forward_ack(forward_ack_out[(m+1)*NUM_INPUTS-1:m*NUM_INPUTS]),
|
||||
// Output
|
||||
.o_tdata(o_tdata[(m*FIFO_WIDTH)+FIFO_WIDTH-1:m*FIFO_WIDTH]),
|
||||
.o_tvalid(o_tvalid[m]),
|
||||
.o_tlast(o_tlast[m]),
|
||||
.o_tready(o_tready[m])
|
||||
);
|
||||
|
||||
if (m==0)
|
||||
assign i_tready_slave[0] = i_tready_tmp;
|
||||
else
|
||||
assign i_tready_slave[m] = i_tready_tmp | i_tready_slave[m-1] ;
|
||||
|
||||
end // block: instantiate_slave_mux
|
||||
endgenerate
|
||||
|
||||
assign i_tready = i_tready_slave[NUM_OUTPUTS-1];
|
||||
|
||||
//
|
||||
// Permute the forwarding flag buses
|
||||
//
|
||||
|
||||
generate
|
||||
for (m = 0; m < NUM_OUTPUTS; m = m + 1) begin: permute_outer
|
||||
for (n = 0; n < NUM_INPUTS; n = n + 1) begin: permute_inner
|
||||
assign forward_valid_in[n*NUM_OUTPUTS+m] = forward_valid_out[n+m*NUM_INPUTS];
|
||||
assign forward_ack_in[n+m*NUM_INPUTS] = forward_ack_out[n*NUM_OUTPUTS+m];
|
||||
end
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
|
||||
//
|
||||
// Instantiate an axi_forwarding_cam for every Input/Master of the Crossbar switch.
|
||||
// Each contains a TCAM like lookup that allocates an egress port.
|
||||
//
|
||||
|
||||
wire [31:0] rb_data_mux[0:NUM_INPUTS-1];
|
||||
|
||||
generate
|
||||
for (m = 0; m < NUM_INPUTS; m = m + 1) begin: instantiate_cam
|
||||
axi_forwarding_cam
|
||||
#(
|
||||
.BASE(0),
|
||||
.WIDTH(FIFO_WIDTH), // Bit width of FIFO word.
|
||||
.NUM_OUTPUTS(NUM_OUTPUTS)
|
||||
) axi_forwarding_cam_i
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(clear),
|
||||
// Monitored FIFO signals
|
||||
.o_tdata(i_tdata[(m*FIFO_WIDTH)+FIFO_WIDTH-1:m*FIFO_WIDTH]),
|
||||
.o_tvalid(i_tvalid[m]),
|
||||
.o_tready(i_tready[m]),
|
||||
.o_tlast(i_tlast[m]),
|
||||
.pkt_present(pkt_present[m]),
|
||||
// Configuration
|
||||
.local_addr(local_addr),
|
||||
// Setting Bus
|
||||
.set_stb(set_stb),
|
||||
.set_addr(set_addr),
|
||||
.set_data(set_data),
|
||||
// Header signals
|
||||
.forward_valid(forward_valid_out[(m+1)*NUM_OUTPUTS-1:m*NUM_OUTPUTS]),
|
||||
.forward_ack(forward_ack_in[(m+1)*NUM_OUTPUTS-1:m*NUM_OUTPUTS]),
|
||||
// Readback bus
|
||||
.rb_rd_stb(rb_rd_strobe && (rb_addr[`LOG2(NUM_OUTPUTS)+`LOG2(NUM_INPUTS)-1:`LOG2(NUM_OUTPUTS)] == m)),
|
||||
.rb_addr(rb_addr[`LOG2(NUM_OUTPUTS)-1:0]),
|
||||
.rb_data(rb_data_mux[m])
|
||||
);
|
||||
end // block: instantiate_fifo_header
|
||||
endgenerate
|
||||
|
||||
assign rb_data = rb_data_mux[rb_addr[`LOG2(NUM_OUTPUTS)+`LOG2(NUM_INPUTS)-1:`LOG2(NUM_OUTPUTS)]];
|
||||
|
||||
|
||||
endmodule // axi_crossbar
|
||||
@@ -1,214 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
`timescale 1 ps / 1 ps
|
||||
|
||||
module axi_crossbar_tb;
|
||||
|
||||
|
||||
localparam STREAM_WIDTH = 64;
|
||||
|
||||
// Currently support simulations upto 8x8 configurations
|
||||
localparam MAX_NUM_INPUTS = 8;
|
||||
localparam MAX_NUM_OUTPUTS = 8;
|
||||
|
||||
wire [(MAX_NUM_INPUTS*STREAM_WIDTH)-1:0] i_tdata;
|
||||
wire [STREAM_WIDTH-1:0] i_tdata_array [0:MAX_NUM_INPUTS-1];
|
||||
wire [MAX_NUM_INPUTS-1:0] i_tvalid;
|
||||
wire [MAX_NUM_INPUTS-1:0] i_tready;
|
||||
wire [MAX_NUM_INPUTS-1:0] i_tlast;
|
||||
wire [MAX_NUM_INPUTS-1:0] pkt_present;
|
||||
|
||||
reg [STREAM_WIDTH-1:0] data_in [0:MAX_NUM_INPUTS-1];
|
||||
reg [MAX_NUM_INPUTS-1:0] valid_in;
|
||||
wire [MAX_NUM_INPUTS-1:0] ready_in;
|
||||
reg [MAX_NUM_INPUTS-1:0] last_in;
|
||||
|
||||
wire [(MAX_NUM_OUTPUTS*STREAM_WIDTH)-1:0] o_tdata;
|
||||
wire [STREAM_WIDTH-1:0] o_tdata_array [0:MAX_NUM_OUTPUTS-1];
|
||||
wire [MAX_NUM_OUTPUTS-1:0] o_tvalid;
|
||||
wire [MAX_NUM_OUTPUTS-1:0] o_tready;
|
||||
wire [MAX_NUM_OUTPUTS-1:0] o_tlast;
|
||||
|
||||
|
||||
wire [STREAM_WIDTH-1:0] data_out [0:MAX_NUM_OUTPUTS-1];
|
||||
wire [MAX_NUM_OUTPUTS-1:0] valid_out;
|
||||
reg [MAX_NUM_OUTPUTS-1:0] ready_out;
|
||||
wire [MAX_NUM_OUTPUTS-1:0] last_out;
|
||||
|
||||
|
||||
genvar m;
|
||||
|
||||
reg clk;
|
||||
reg reset;
|
||||
reg clear;
|
||||
reg set_stb;
|
||||
reg [15:0] set_addr;
|
||||
reg [31:0] set_data;
|
||||
|
||||
// reg reset;
|
||||
|
||||
//
|
||||
// Simulation specific testbench is included here
|
||||
//
|
||||
`include "task_library.v"
|
||||
`include "simulation_script.v"
|
||||
|
||||
|
||||
//
|
||||
// Define Clocks
|
||||
//
|
||||
initial begin
|
||||
clk = 1'b1;
|
||||
end
|
||||
|
||||
// 125MHz clock
|
||||
always #4000 clk = ~clk;
|
||||
|
||||
//
|
||||
// Good starting state
|
||||
//
|
||||
initial begin
|
||||
reset <= 0;
|
||||
clear <= 0;
|
||||
set_stb <= 0;
|
||||
set_addr <= 0;
|
||||
set_data <= 0;
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
data_in[0] <= 0;
|
||||
valid_in[0] <= 0;
|
||||
last_in[0] <= 0;
|
||||
|
||||
data_in[1] <= 0;
|
||||
valid_in[1] <= 0;
|
||||
last_in[1] <= 0;
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
//
|
||||
// AXI Crossbar instance
|
||||
//
|
||||
localparam SR_AWIDTH = 16;
|
||||
localparam SR_XB_LOCAL = 512;
|
||||
|
||||
wire [7:0] local_addr;
|
||||
|
||||
setting_reg #(.my_addr(SR_XB_LOCAL), .awidth(SR_AWIDTH), .width(8)) sr_local_addr
|
||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
|
||||
.in(set_data),.out(local_addr),.changed());
|
||||
|
||||
axi_crossbar
|
||||
#(
|
||||
.FIFO_WIDTH(STREAM_WIDTH), // AXI4-STREAM data bus width
|
||||
.DST_WIDTH(16), // Width of DST field we are routing on.
|
||||
.NUM_INPUTS(NUM_INPUTS), // number of input AXI4-STREAM buses
|
||||
.NUM_OUTPUTS(NUM_OUTPUTS) // number of output AXI4-STREAM buses
|
||||
) axi_crossbar_i
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(clear),
|
||||
.local_addr(local_addr),
|
||||
// Inputs
|
||||
.i_tdata(i_tdata[(NUM_INPUTS*STREAM_WIDTH)-1:0]),
|
||||
.i_tvalid(i_tvalid[NUM_INPUTS-1:0]),
|
||||
.i_tlast(i_tlast[NUM_INPUTS-1:0]),
|
||||
.i_tready(i_tready[NUM_INPUTS-1:0]),
|
||||
.pkt_present(pkt_present[NUM_INPUTS-1:0]),
|
||||
// Settings bus
|
||||
.set_stb(set_stb),
|
||||
.set_addr(set_addr),
|
||||
.set_data(set_data),
|
||||
// Output
|
||||
.o_tdata(o_tdata[(NUM_OUTPUTS*STREAM_WIDTH)-1:0]),
|
||||
.o_tvalid(o_tvalid[NUM_OUTPUTS-1:0]),
|
||||
.o_tlast(o_tlast[NUM_OUTPUTS-1:0]),
|
||||
.o_tready(o_tready[NUM_OUTPUTS-1:0]),
|
||||
// Readback Bus
|
||||
.rb_rd_stb(1'b0),
|
||||
.rb_addr(0),
|
||||
.rb_data()
|
||||
);
|
||||
|
||||
//
|
||||
// Input FIFOs
|
||||
//
|
||||
generate
|
||||
for (m=0;m<NUM_INPUTS;m=m+1)
|
||||
begin: input_fifos
|
||||
|
||||
assign i_tdata[(STREAM_WIDTH*m)+STREAM_WIDTH-1:STREAM_WIDTH*m] = i_tdata_array[m];
|
||||
|
||||
axi_fifo_short
|
||||
#(.WIDTH(STREAM_WIDTH+1)) axi_fifo_short_in
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(clear),
|
||||
.o_tdata({i_tlast[m],i_tdata_array[m]}),
|
||||
.o_tvalid(i_tvalid[m]),
|
||||
.o_tready(i_tready[m]),
|
||||
.i_tdata({last_in[m],data_in[m]}),
|
||||
.i_tvalid(valid_in[m]),
|
||||
.i_tready(ready_in[m]),
|
||||
.space(),
|
||||
.occupied()
|
||||
);
|
||||
|
||||
monitor_axi_fifo
|
||||
#(
|
||||
.COUNT_BITS(8)
|
||||
) monitor_axi_fifo_in
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(clear),
|
||||
// Monitored FIFO signals
|
||||
.i_tvalid(valid_in[m]),
|
||||
.i_tready(ready_in[m]),
|
||||
.i_tlast(last_in[m]),
|
||||
.o_tvalid(i_tvalid[m]),
|
||||
.o_tready(i_tready[m]),
|
||||
.o_tlast(i_tlast[m]),
|
||||
// FIFO status output
|
||||
.pkt_present(pkt_present[m]), // Flags any whole packets present
|
||||
.pkt_count()
|
||||
);
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
//
|
||||
// Output FIFO's
|
||||
//
|
||||
generate
|
||||
for (m=0;m<NUM_OUTPUTS;m=m+1)
|
||||
begin: output_fifos
|
||||
|
||||
assign o_tdata_array[m] = o_tdata[(STREAM_WIDTH*m)+STREAM_WIDTH-1:STREAM_WIDTH*m];
|
||||
|
||||
axi_fifo_short
|
||||
#(.WIDTH(STREAM_WIDTH+1)) axi_fifo_short_out
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(clear),
|
||||
.i_tdata({o_tlast[m],o_tdata_array[m]}),
|
||||
.i_tvalid(o_tvalid[m]),
|
||||
.i_tready(o_tready[m]),
|
||||
.o_tdata({last_out[m],data_out[m]}),
|
||||
.o_tvalid(valid_out[m]),
|
||||
.o_tready(ready_out[m]),
|
||||
.space(),
|
||||
.occupied()
|
||||
);
|
||||
end
|
||||
endgenerate // block: output_fifos
|
||||
|
||||
endmodule // axi_crossbar_tb
|
||||
@@ -1,84 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// This module is connected to the output port of an AXI4-STREAM FIFO that is used to move packetized data.
|
||||
// It extracts and indicates the header (first word) of a packet in the FIFO. The header and flag are pipelined
|
||||
// for timing closure.
|
||||
//
|
||||
|
||||
module axi_fifo_header
|
||||
#(
|
||||
parameter WIDTH=64 // Bit width of FIFO word.
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
// Monitored FIFO signals
|
||||
input [WIDTH-1:0] o_tdata,
|
||||
input o_tvalid,
|
||||
input o_tready,
|
||||
input o_tlast,
|
||||
input pkt_present,
|
||||
// Header signals
|
||||
output reg [WIDTH-1:0] header,
|
||||
output reg header_valid
|
||||
);
|
||||
|
||||
localparam WAIT_SOF = 0;
|
||||
localparam WAIT_EOF = 1;
|
||||
|
||||
reg out_state;
|
||||
|
||||
|
||||
//
|
||||
// Monitor packets leaving FIFO
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
out_state <= WAIT_SOF;
|
||||
end else
|
||||
case(out_state)
|
||||
//
|
||||
// After RESET or the EOF of previous packet, the first cycle with
|
||||
// output valid asserted is the SOF and presents the Header word.
|
||||
// The cycle following the concurrent presentation of asserted output
|
||||
// valid and output ready presents the word following the header.
|
||||
//
|
||||
WAIT_SOF:
|
||||
if (o_tvalid && o_tready) begin
|
||||
out_state <= WAIT_EOF;
|
||||
end else begin
|
||||
out_state <= WAIT_SOF;
|
||||
end
|
||||
//
|
||||
// EOF is signalled by o_tlast asserted whilst output valid and ready asserted.
|
||||
//
|
||||
WAIT_EOF:
|
||||
if (o_tlast && o_tvalid && o_tready) begin
|
||||
out_state <= WAIT_SOF;
|
||||
end else begin
|
||||
out_state <= WAIT_EOF;
|
||||
end
|
||||
endcase // case(in_state)
|
||||
|
||||
//
|
||||
// Pipeline Header signals
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
header <= 0;
|
||||
header_valid <= 0;
|
||||
end else if (o_tvalid && (out_state == WAIT_SOF) && pkt_present) begin
|
||||
// Header will remian valid until o_tready is asserted as this will cause a state transition.
|
||||
header <= o_tdata;
|
||||
header_valid <= 1;
|
||||
end else begin
|
||||
header_valid <= 0;
|
||||
end
|
||||
|
||||
|
||||
endmodule // axi_fifo_header
|
||||
@@ -1,232 +0,0 @@
|
||||
//
|
||||
// Copyright 2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// This module implements a highly customized TCAM that enbales forwarding
|
||||
// decisions to be made on a 16bit field from a VITA SID field.
|
||||
// The 16bits are allocated by convention as 8 bits of Network address
|
||||
// (Addresses USRP's etc) and 8 bits of Host address (adresses endpoints in
|
||||
// a USRP). By definition if the DEST field in the SID addresses a different
|
||||
// USRP than this one then we don't care about the Host field, only the Network Field.
|
||||
// We only look at the Host Field when the Network field addresses us.
|
||||
// Thus Need TCAM of 256+256 entries with Log2(N) bits, where N is the number of
|
||||
// slave(output) ports on the crossbar switch.
|
||||
//
|
||||
//
|
||||
//
|
||||
// SID format:
|
||||
//
|
||||
// |--------|---------|--------|---------|
|
||||
// | SOURCE | DEST | DEST |
|
||||
// | ADDRESS | NETWORK| HOST |
|
||||
// |--------|---------|--------|---------|
|
||||
// 8 8 8 8
|
||||
//
|
||||
|
||||
|
||||
`define LOG2(N) (\
|
||||
N < 2 ? 0 : \
|
||||
N < 4 ? 1 : \
|
||||
N < 8 ? 2 : \
|
||||
N < 16 ? 3 : \
|
||||
N < 32 ? 4 : \
|
||||
N < 64 ? 5 : \
|
||||
N < 128 ? 6 : \
|
||||
N < 256 ? 7 : \
|
||||
N < 512 ? 8 : \
|
||||
N < 1024 ? 9 : \
|
||||
10)
|
||||
|
||||
module axi_forwarding_cam
|
||||
#(
|
||||
parameter BASE = 0, // BASE address for setting registers in this block. (512 addrs used)
|
||||
parameter WIDTH=64, // Bit width of FIFO word.
|
||||
parameter NUM_OUTPUTS=2 // Number of outputs (destinations) in crossbar.
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
// Monitored FIFO signals
|
||||
input [WIDTH-1:0] o_tdata,
|
||||
input o_tvalid,
|
||||
input o_tready,
|
||||
input o_tlast,
|
||||
input pkt_present,
|
||||
// Configuration
|
||||
input [7:0] local_addr,
|
||||
// Setting Bus
|
||||
input set_stb,
|
||||
input [15:0] set_addr,
|
||||
input [31:0] set_data,
|
||||
// Forwarding Flags
|
||||
output reg [NUM_OUTPUTS-1:0] forward_valid,
|
||||
input [NUM_OUTPUTS-1:0] forward_ack,
|
||||
// readback bus
|
||||
input rb_rd_stb,
|
||||
input [`LOG2(NUM_OUTPUTS)-1:0] rb_addr,
|
||||
output [31:0] rb_data
|
||||
);
|
||||
|
||||
|
||||
localparam WAIT_SOF = 0;
|
||||
localparam WAIT_EOF = 1;
|
||||
reg state;
|
||||
|
||||
localparam IDLE = 0;
|
||||
localparam FORWARD = 1;
|
||||
localparam WAIT = 2;
|
||||
|
||||
reg [1:0] demux_state;
|
||||
|
||||
reg [15:0] dst;
|
||||
reg dst_valid, dst_valid_reg;
|
||||
wire local_dst;
|
||||
wire [8:0] read_addr;
|
||||
|
||||
//
|
||||
// Monitor packets leaving FIFO
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
state <= WAIT_SOF;
|
||||
end else
|
||||
case(state)
|
||||
//
|
||||
// After RESET or the EOF of previous packet, the first cycle with
|
||||
// output valid asserted is the SOF and presents the Header word.
|
||||
// The cycle following the concurrent presentation of asserted output
|
||||
// valid and output ready presents the word following the header.
|
||||
//
|
||||
WAIT_SOF:
|
||||
if (o_tvalid && o_tready) begin
|
||||
state <= WAIT_EOF;
|
||||
end else begin
|
||||
state <= WAIT_SOF;
|
||||
end
|
||||
//
|
||||
// EOF is signalled by o_tlast asserted whilst output valid and ready asserted.
|
||||
//
|
||||
WAIT_EOF:
|
||||
if (o_tlast && o_tvalid && o_tready) begin
|
||||
state <= WAIT_SOF;
|
||||
end else begin
|
||||
state <= WAIT_EOF;
|
||||
end
|
||||
endcase // case(in_state)
|
||||
|
||||
//
|
||||
// Extract Destination fields(s) from SID
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
dst <= 0;
|
||||
dst_valid <= 0;
|
||||
dst_valid_reg <= 0;
|
||||
end else if (o_tvalid && (state == WAIT_SOF) && pkt_present) begin
|
||||
// SID will remain valid until o_tready is asserted as this will cause a state transition.
|
||||
dst <= o_tdata[15:0];
|
||||
dst_valid <= 1;
|
||||
dst_valid_reg <= dst_valid;
|
||||
end else begin
|
||||
dst_valid <= 0;
|
||||
dst_valid_reg <= dst_valid;
|
||||
end
|
||||
|
||||
//
|
||||
// Is Network field in DST our local address?
|
||||
//
|
||||
assign local_dst = (dst[15:8] == local_addr) && dst_valid;
|
||||
|
||||
|
||||
//
|
||||
// Mux address to RAM so that it searches CAM for Network field or Host field.
|
||||
// Network addresses are stored in the lower 256 locations, host addresses the upper 256.
|
||||
//
|
||||
assign read_addr = {local_dst,(local_dst ? dst[7:0] : dst[15:8])};
|
||||
|
||||
//
|
||||
// Imply a block RAM here, 512xCeil(Log2(NUM_OUTPUTS))
|
||||
//
|
||||
//synthesis attribute ram_style of mem is block
|
||||
reg [(`LOG2(NUM_OUTPUTS))-1 : 0] mem [0:511];
|
||||
reg [8:0] read_addr_reg;
|
||||
wire write;
|
||||
wire [`LOG2(NUM_OUTPUTS)-1:0] read_data;
|
||||
|
||||
assign write = (set_addr[15:9] == (BASE >>9)) && set_stb; // Addr decode.
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
read_addr_reg <= read_addr;
|
||||
|
||||
if (write) begin
|
||||
mem[set_addr[8:0]] <= set_data[`LOG2(NUM_OUTPUTS)-1:0];
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
assign read_data = mem[read_addr_reg];
|
||||
|
||||
|
||||
//
|
||||
// State machine to manage forwarding flags.
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
demux_state <= IDLE;
|
||||
end else
|
||||
case(demux_state)
|
||||
|
||||
// Wait for Valid DST which indicates a new packet lookup in the CAM.
|
||||
IDLE: begin
|
||||
if (dst_valid_reg == 1) begin
|
||||
forward_valid <= 1 << read_data;
|
||||
demux_state <= FORWARD;
|
||||
end
|
||||
end
|
||||
// When Slave/Output thats forwarding ACK's the forward flag, clear request and wait for packet to be transfered
|
||||
FORWARD: begin
|
||||
if ((forward_ack & forward_valid) != 0) begin
|
||||
forward_valid <= 0;
|
||||
demux_state <= WAIT;
|
||||
end
|
||||
end
|
||||
// When packet transfered go back to idle.
|
||||
WAIT: begin
|
||||
if (forward_ack == 0)
|
||||
demux_state <= IDLE;
|
||||
end
|
||||
|
||||
endcase // case (demux_state)
|
||||
|
||||
//
|
||||
// Compile forwarding statistics
|
||||
// (This uses a lot of registers!)
|
||||
//
|
||||
genvar m;
|
||||
reg [31:0] statistics [0:NUM_OUTPUTS-1];
|
||||
|
||||
generate
|
||||
for (m = 0; m < NUM_OUTPUTS; m = m + 1) begin: generate_stats
|
||||
always @(posedge clk)
|
||||
if (reset | clear)
|
||||
statistics[m] <= 0;
|
||||
else if ((rb_addr == m) && rb_rd_stb)
|
||||
statistics[m] <= 0;
|
||||
else if (forward_ack[m] & forward_valid[m])
|
||||
statistics[m] <= statistics[m] + 1;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign rb_data = statistics[rb_addr];
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
`define LOG2(N) (\
|
||||
N < 2 ? 0 : \
|
||||
N < 4 ? 1 : \
|
||||
N < 8 ? 2 : \
|
||||
N < 16 ? 3 : \
|
||||
N < 32 ? 4 : \
|
||||
N < 64 ? 5 : \
|
||||
N < 128 ? 6 : \
|
||||
N < 256 ? 7 : \
|
||||
N < 512 ? 8 : \
|
||||
N < 1024 ? 9 : \
|
||||
10)
|
||||
|
||||
|
||||
module axi_slave_mux
|
||||
#(
|
||||
parameter FIFO_WIDTH = 64, // AXI4-STREAM data bus width
|
||||
parameter DST_WIDTH = 16, // Width of DST field we are routing on.
|
||||
parameter NUM_INPUTS = 2 // number of input AXI buses
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
// Inputs
|
||||
input [(FIFO_WIDTH*NUM_INPUTS)-1:0] i_tdata,
|
||||
input [NUM_INPUTS-1:0] i_tvalid,
|
||||
input [NUM_INPUTS-1:0] i_tlast,
|
||||
output [NUM_INPUTS-1:0] i_tready,
|
||||
// Forwarding Flags
|
||||
input [NUM_INPUTS-1:0] forward_valid,
|
||||
output reg [NUM_INPUTS-1:0] forward_ack,
|
||||
// Output
|
||||
output [FIFO_WIDTH-1:0] o_tdata,
|
||||
output o_tvalid,
|
||||
output o_tlast,
|
||||
input o_tready
|
||||
);
|
||||
|
||||
wire [FIFO_WIDTH-1:0] i_tdata_array [0:NUM_INPUTS-1];
|
||||
|
||||
reg [`LOG2(NUM_INPUTS):0] select;
|
||||
reg enable;
|
||||
|
||||
|
||||
reg state;
|
||||
|
||||
localparam CHECK_THIS_INPUT = 0;
|
||||
localparam WAIT_LAST = 1;
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
state <= CHECK_THIS_INPUT;
|
||||
select <= 0;
|
||||
enable <= 0;
|
||||
forward_ack <= 0;
|
||||
end else begin
|
||||
case(state)
|
||||
// Is the currently selected input addressing this slave with a ready packet?
|
||||
CHECK_THIS_INPUT: begin
|
||||
if (forward_valid[select]) begin
|
||||
enable <= 1;
|
||||
forward_ack[select] <= 1;
|
||||
state <= WAIT_LAST;
|
||||
end else if (select == NUM_INPUTS - 1 ) begin
|
||||
select <= 0;
|
||||
end else begin
|
||||
select <= select + 1;
|
||||
end
|
||||
end
|
||||
// Assert ACK immediately to forwarding logic and then wait for end of packet.
|
||||
WAIT_LAST: begin
|
||||
|
||||
if (i_tlast[select] && i_tvalid[select] && o_tready) begin
|
||||
if (select == NUM_INPUTS - 1 ) begin
|
||||
select <= 0;
|
||||
end else begin
|
||||
select <= select + 1;
|
||||
end
|
||||
state <= CHECK_THIS_INPUT;
|
||||
forward_ack <= 0;
|
||||
enable <= 0;
|
||||
end else begin
|
||||
forward_ack[select] <= 1;
|
||||
enable <= 1;
|
||||
end
|
||||
end
|
||||
endcase // case(state)
|
||||
end
|
||||
|
||||
//
|
||||
// Combinatorial mux
|
||||
//
|
||||
genvar m;
|
||||
|
||||
generate
|
||||
for (m = 0; m < NUM_INPUTS; m = m + 1) begin: form_buses
|
||||
assign i_tdata_array[m] = i_tdata[(m*FIFO_WIDTH)+FIFO_WIDTH-1:m*FIFO_WIDTH];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign o_tdata = i_tdata_array[select];
|
||||
assign o_tvalid = enable && i_tvalid[select];
|
||||
assign o_tlast = enable && i_tlast[select];
|
||||
// assign i_tready = {NUM_INPUTS{o_tready}} & (enable << select);
|
||||
|
||||
generate
|
||||
for (m = 0; m < NUM_INPUTS; m = m + 1) begin: form_ready
|
||||
assign i_tready[m] = o_tready && enable && (select == m);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
endmodule // axi_slave_mux
|
||||
@@ -1,139 +0,0 @@
|
||||
//
|
||||
// Test Virtual FIFO's by streaming modulo 2^32 counter (replicated in upper
|
||||
// and lower 32bits). Test result by tracking count on receive and using
|
||||
// sticky flag for error indication.
|
||||
// Also provide signal from MSB of 32bit count to blink LED.
|
||||
//
|
||||
|
||||
module axi_test_vfifo
|
||||
#(parameter PACKET_SIZE = 128)
|
||||
(
|
||||
input aclk,
|
||||
input aresetn,
|
||||
input enable,
|
||||
// AXI Stream Out
|
||||
output reg out_axis_tvalid,
|
||||
input out_axis_tready,
|
||||
output [63 : 0] out_axis_tdata,
|
||||
output reg [7 : 0] out_axis_tstrb,
|
||||
output reg [7 : 0] out_axis_tkeep,
|
||||
output reg out_axis_tlast,
|
||||
output reg [0 : 0] out_axis_tid,
|
||||
output reg [0 : 0] out_axis_tdest,
|
||||
input vfifo_full,
|
||||
// AXI Stream In
|
||||
input in_axis_tvalid,
|
||||
output reg in_axis_tready,
|
||||
input [63 : 0] in_axis_tdata,
|
||||
input [7 : 0] in_axis_tstrb,
|
||||
input [7 : 0] in_axis_tkeep,
|
||||
input in_axis_tlast,
|
||||
input [0 : 0] in_axis_tid,
|
||||
input [0 : 0] in_axis_tdest,
|
||||
// Flags
|
||||
output reg flag_error,
|
||||
output heartbeat_in,
|
||||
output heartbeat_out,
|
||||
output [31:0] expected_count
|
||||
);
|
||||
|
||||
|
||||
reg [31:0] out_count;
|
||||
reg [31:0] in_count;
|
||||
reg [63:0] in_axis_tdata_reg;
|
||||
reg in_data_valid;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Output
|
||||
//
|
||||
always @(posedge aclk)
|
||||
if (!aresetn) begin
|
||||
out_count <= 0;
|
||||
out_axis_tvalid <= 0;
|
||||
out_axis_tid <= 0; // Don't care.
|
||||
out_axis_tdest <= 0; // Only use port 0 of VFIFO.
|
||||
out_axis_tstrb <= 0; // Unused in VFIFO
|
||||
out_axis_tkeep <= 8'hFF; // Always use every byte of data
|
||||
out_axis_tlast <= 1'b0;
|
||||
end else if (enable) begin
|
||||
if (~vfifo_full) begin
|
||||
// Always ready to output new count value.
|
||||
out_axis_tvalid <= 1;
|
||||
if (out_axis_tready)
|
||||
out_count <= out_count + 1;
|
||||
// Assert TLAST every PACKET_SIZE beats.
|
||||
if (out_count[15:0] == PACKET_SIZE)
|
||||
out_axis_tlast <= 1'b1;
|
||||
else
|
||||
out_axis_tlast <= 1'b0;
|
||||
end else begin
|
||||
out_axis_tvalid <= 0;
|
||||
end
|
||||
end else begin
|
||||
out_axis_tlast <= 1'b0;
|
||||
out_axis_tvalid <= 0;
|
||||
end
|
||||
|
||||
assign out_axis_tdata = {out_count,out_count};
|
||||
|
||||
assign heartbeat_out = out_count[28];
|
||||
|
||||
|
||||
//
|
||||
// Input (Ignore TLAST signal)
|
||||
//
|
||||
always @(posedge aclk)
|
||||
if (!aresetn) begin
|
||||
in_axis_tready <= 0;
|
||||
in_axis_tdata_reg <= 0;
|
||||
in_data_valid <= 0;
|
||||
|
||||
end else if (enable) begin
|
||||
in_axis_tready <= 1;
|
||||
in_axis_tdata_reg <= in_axis_tdata;
|
||||
if (in_axis_tvalid)
|
||||
in_data_valid <= 1;
|
||||
else
|
||||
in_data_valid <= 0;
|
||||
end else begin
|
||||
in_data_valid <= 0;
|
||||
in_axis_tready <= 0;
|
||||
end // else: !if(enable)
|
||||
|
||||
|
||||
assign heartbeat_in = in_count[28];
|
||||
|
||||
//
|
||||
// Input Checker
|
||||
//
|
||||
always @(posedge aclk)
|
||||
if (!aresetn) begin
|
||||
in_count <= 0;
|
||||
flag_error <= 0;
|
||||
end else if (enable) begin
|
||||
if (in_data_valid) begin
|
||||
|
||||
if ((in_axis_tdata_reg[63:32] != in_count) || (in_axis_tdata_reg[31:0] != in_count))
|
||||
begin
|
||||
flag_error <= 1;
|
||||
in_count <= in_axis_tdata_reg[63:32] + 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
flag_error <= 0;
|
||||
in_count <= in_count + 1;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
assign expected_count = in_count;
|
||||
|
||||
|
||||
endmodule // axi_test_vfifo
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
|
||||
`define LOG2(N) (\
|
||||
N < 2 ? 0 : \
|
||||
N < 4 ? 1 : \
|
||||
N < 8 ? 2 : \
|
||||
N < 16 ? 3 : \
|
||||
N < 32 ? 4 : \
|
||||
N < 64 ? 5 : \
|
||||
N < 128 ? 6 : \
|
||||
N < 256 ? 7 : \
|
||||
N < 512 ? 8 : \
|
||||
N < 1024 ? 9 : \
|
||||
10)
|
||||
|
||||
module binary_encoder
|
||||
#(
|
||||
parameter SIZE = 16
|
||||
)
|
||||
(
|
||||
input [SIZE-1:0] in,
|
||||
output [`LOG2(SIZE)-1:0] out
|
||||
);
|
||||
|
||||
genvar m,n;
|
||||
|
||||
generate
|
||||
// Loop enough times to represent the total number of input bits as an encoded value
|
||||
for (m = 0; m <= `log2(SIZE-1); m = m + 1) begin: expand_or_tree
|
||||
wire [SIZE-1:0] encoding;
|
||||
// Build enable mask by iterating through every input bit.
|
||||
for (n = 0; n < SIZE ; n = n + 1) begin: encode_this_bit
|
||||
assign encoding[n] = n[m];
|
||||
end
|
||||
// OR tree for this output bit with appropraite bits enabled.
|
||||
assign out[m] = |(encoding & in);
|
||||
end
|
||||
endgenerate
|
||||
endmodule // binary_encoder
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
|
||||
//
|
||||
// Copyright 2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//create a compressed vita based uart data interface
|
||||
|
||||
module cvita_uart
|
||||
#(
|
||||
parameter SIZE = 0
|
||||
)
|
||||
(
|
||||
//clocking interface
|
||||
input clk, input rst,
|
||||
|
||||
//uart interface
|
||||
input rxd, output txd,
|
||||
|
||||
//chdr fifo input
|
||||
input [63:0] i_tdata,
|
||||
input i_tlast,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
|
||||
//chdr fifo output
|
||||
output [63:0] o_tdata,
|
||||
output o_tlast,
|
||||
output o_tvalid,
|
||||
input o_tready
|
||||
);
|
||||
|
||||
reg [31:0] sid;
|
||||
|
||||
//baud clock divider
|
||||
reg [15:0] clkdiv;
|
||||
|
||||
//hold rx in disable until a tx event
|
||||
reg rxd_enable;
|
||||
|
||||
//==================================================================
|
||||
//== RXD capture and packet generation interface
|
||||
//==================================================================
|
||||
wire [7:0] rx_char;
|
||||
wire fifo_empty;
|
||||
wire fifo_read;
|
||||
reg [11:0] seqnum;
|
||||
wire pgen_trigger;
|
||||
wire pgen_done;
|
||||
|
||||
//rx uart capture
|
||||
simple_uart_rx #(.SIZE(SIZE)) simple_uart_rx
|
||||
(
|
||||
.clk(clk), .rst(rst),
|
||||
.fifo_out(rx_char), .fifo_read(fifo_read), .fifo_level(), .fifo_empty(fifo_empty),
|
||||
.clkdiv(clkdiv), .rx(rxd)
|
||||
);
|
||||
|
||||
//packet generation - holds rx character
|
||||
context_packet_gen context_packet_gen
|
||||
(
|
||||
.clk(clk), .reset(rst), .clear(1'b0),
|
||||
.trigger(pgen_trigger),
|
||||
.seqnum(seqnum),
|
||||
.sid({sid[15:0], sid[31:16]}),
|
||||
.body({56'b0, rx_char}),
|
||||
.vita_time(64'b0),
|
||||
|
||||
.done(pgen_done),
|
||||
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
|
||||
);
|
||||
|
||||
//state machine to manage pgen and rx uart
|
||||
reg [1:0] rxd_state;
|
||||
localparam RXD_STATE_RECV_CHAR = 0;
|
||||
localparam RXD_STATE_PGEN_TRIG = 1;
|
||||
localparam RXD_STATE_WAIT_DONE = 2;
|
||||
localparam RXD_STATE_READ_FIFO = 3;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
seqnum <= 12'b0;
|
||||
rxd_state <= RXD_STATE_RECV_CHAR;
|
||||
end
|
||||
else case (rxd_state)
|
||||
|
||||
RXD_STATE_RECV_CHAR: begin
|
||||
if (!fifo_empty && rxd_enable) rxd_state <= RXD_STATE_PGEN_TRIG;
|
||||
end
|
||||
|
||||
RXD_STATE_PGEN_TRIG: begin
|
||||
rxd_state <= RXD_STATE_WAIT_DONE;
|
||||
end
|
||||
|
||||
RXD_STATE_WAIT_DONE: begin
|
||||
if (pgen_done) rxd_state <= RXD_STATE_READ_FIFO;
|
||||
end
|
||||
|
||||
RXD_STATE_READ_FIFO: begin
|
||||
rxd_state <= RXD_STATE_RECV_CHAR;
|
||||
seqnum <= seqnum + 1'b1;
|
||||
end
|
||||
|
||||
endcase //rxd_state
|
||||
end
|
||||
|
||||
assign fifo_read = (rxd_state == RXD_STATE_READ_FIFO) || (!rxd_enable);
|
||||
assign pgen_trigger = (rxd_state == RXD_STATE_PGEN_TRIG);
|
||||
|
||||
//==================================================================
|
||||
//== TXD generation and packet control interface
|
||||
//==================================================================
|
||||
wire [7:0] tx_char;
|
||||
wire fifo_write;
|
||||
wire fifo_full;
|
||||
|
||||
simple_uart_tx #(.SIZE(SIZE)) simple_uart_tx
|
||||
(
|
||||
.clk(clk), .rst(rst),
|
||||
.fifo_in(tx_char), .fifo_write(fifo_write), .fifo_level(), .fifo_full(fifo_full),
|
||||
.clkdiv(clkdiv), .baudclk(), .tx(txd)
|
||||
);
|
||||
|
||||
//state machine to manage control and tx uart
|
||||
reg [1:0] txd_state;
|
||||
localparam TXD_STATE_RECV_CHDR = 0;
|
||||
localparam TXD_STATE_RECV_TIME = 1;
|
||||
localparam TXD_STATE_RECV_BODY = 2;
|
||||
localparam TXD_STATE_DROP_FIFO = 3;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin;
|
||||
txd_state <= TXD_STATE_RECV_CHDR;
|
||||
rxd_enable <= 1'b0;
|
||||
end
|
||||
if (i_tvalid && i_tready) case (txd_state)
|
||||
|
||||
TXD_STATE_RECV_CHDR: begin
|
||||
txd_state <= (i_tdata[61])? TXD_STATE_RECV_TIME : TXD_STATE_RECV_BODY;
|
||||
sid <= i_tdata[31:0];
|
||||
end
|
||||
|
||||
TXD_STATE_RECV_TIME: begin
|
||||
txd_state <= TXD_STATE_RECV_BODY;
|
||||
end
|
||||
|
||||
TXD_STATE_RECV_BODY: begin
|
||||
txd_state <= (i_tlast)? TXD_STATE_RECV_CHDR : TXD_STATE_DROP_FIFO;
|
||||
clkdiv <= i_tdata[47:32];
|
||||
rxd_enable <= 1'b1;
|
||||
end
|
||||
|
||||
TXD_STATE_DROP_FIFO: begin
|
||||
if (i_tlast) txd_state <= TXD_STATE_RECV_CHDR;
|
||||
end
|
||||
|
||||
endcase //txd_state
|
||||
end
|
||||
|
||||
assign tx_char = i_tdata[7:0];
|
||||
assign fifo_write = (txd_state == TXD_STATE_RECV_BODY) && i_tvalid && i_tready;
|
||||
assign i_tready = !fifo_full;
|
||||
|
||||
endmodule // cvita_uart
|
||||
@@ -1,27 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Copyright Ettus Research LLC
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module dram_2port
|
||||
#(parameter DWIDTH=32,
|
||||
parameter AWIDTH=9)
|
||||
(input clk,
|
||||
input write,
|
||||
input [AWIDTH-1:0] raddr,
|
||||
input [AWIDTH-1:0] waddr,
|
||||
input [DWIDTH-1:0] wdata,
|
||||
output [DWIDTH-1:0] rdata);
|
||||
|
||||
reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
|
||||
integer i;
|
||||
initial
|
||||
for(i=0;i<(1<<AWIDTH);i=i+1)
|
||||
ram[i] <= {DWIDTH{1'b0}};
|
||||
|
||||
assign rdata = ram[raddr];
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (write) ram[waddr] <= wdata;
|
||||
end
|
||||
|
||||
endmodule //dram_2port
|
||||
@@ -1,72 +0,0 @@
|
||||
// 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
|
||||
@@ -1,66 +0,0 @@
|
||||
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module gpio_atr
|
||||
#(parameter BASE = 0,
|
||||
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,
|
||||
inout [WIDTH-1:0] gpio,
|
||||
output reg [31:0] gpio_readback
|
||||
);
|
||||
|
||||
wire [WIDTH-1:0] ddr, in_idle, in_tx, in_rx, in_fdx;
|
||||
reg [WIDTH-1:0] rgpio, igpio;
|
||||
reg [WIDTH-1:0] gpio_pipe;
|
||||
|
||||
|
||||
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());
|
||||
|
||||
setting_reg #(.my_addr(BASE+1), .width(WIDTH)) reg_rx
|
||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
||||
.out(in_rx),.changed());
|
||||
|
||||
setting_reg #(.my_addr(BASE+2), .width(WIDTH)) reg_tx
|
||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
||||
.out(in_tx),.changed());
|
||||
|
||||
setting_reg #(.my_addr(BASE+3), .width(WIDTH)) reg_fdx
|
||||
(.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), .at_reset(default_ddr)) reg_ddr
|
||||
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
|
||||
.out(ddr),.changed());
|
||||
|
||||
always @(posedge clk)
|
||||
case({tx,rx})
|
||||
2'b00: rgpio <= in_idle;
|
||||
2'b01: rgpio <= in_rx;
|
||||
2'b10: rgpio <= in_tx;
|
||||
2'b11: rgpio <= in_fdx;
|
||||
endcase // case ({tx,rx})
|
||||
|
||||
integer n;
|
||||
always @*
|
||||
for(n=0;n<WIDTH;n=n+1)
|
||||
igpio[n] <= ddr[n] ? rgpio[n] : 1'bz;
|
||||
|
||||
assign gpio = igpio;
|
||||
|
||||
// Double pipeline stage for timing, first flop is in IOB, second in core logic.
|
||||
always @(posedge clk) begin
|
||||
gpio_pipe <= gpio;
|
||||
gpio_readback <= gpio_pipe;
|
||||
end
|
||||
|
||||
endmodule // gpio_atr
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Copyright 2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module por_gen
|
||||
(input clk,
|
||||
output reset_out);
|
||||
|
||||
reg por_rst;
|
||||
reg [7:0] por_counter = 8'h0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (por_counter != 8'h55)
|
||||
begin
|
||||
por_counter <= por_counter + 8'h1;
|
||||
por_rst <= 1'b1;
|
||||
end
|
||||
else
|
||||
por_rst <= 1'b0;
|
||||
|
||||
assign reset_out = por_rst;
|
||||
|
||||
endmodule // por_gen
|
||||
@@ -1,143 +0,0 @@
|
||||
|
||||
|
||||
// Radio Control Processor
|
||||
// Accepts compressed vita extension context packets of the following form:
|
||||
// { VITA Compressed Header, Stream ID }
|
||||
// { Optional 64 bit time }
|
||||
// { 16'h0, setting bus address [15:0], setting [31:0] }
|
||||
//
|
||||
// If there is a timestamp, packet is held until that time comes.
|
||||
// Goes immediately if there is no timestamp or if time has passed.
|
||||
// Sends out setting to setting bus, and then generates a response packet
|
||||
// with the same sequence number, the src/dest swapped streamid, and the actual time
|
||||
// the setting was sent.
|
||||
//
|
||||
// Note -- if t0 is the requested time, the actual send time on the setting bus is t0 + 1 cycle.
|
||||
// Note 2 -- if t1 is the actual time the setting bus, t1+2 is the reported time.
|
||||
|
||||
module radio_ctrl_proc
|
||||
(input clk, input reset, input clear,
|
||||
|
||||
input [63:0] ctrl_tdata, input ctrl_tlast, input ctrl_tvalid, output reg ctrl_tready,
|
||||
output reg [63:0] resp_tdata, output reg resp_tlast, output resp_tvalid, input resp_tready,
|
||||
|
||||
input [63:0] vita_time,
|
||||
|
||||
output set_stb, output [7:0] set_addr, output [31:0] set_data,
|
||||
input ready,
|
||||
|
||||
input [63:0] readback,
|
||||
|
||||
output [31:0] debug);
|
||||
|
||||
localparam RC_HEAD = 4'd0;
|
||||
localparam RC_TIME = 4'd1;
|
||||
localparam RC_DATA = 4'd2;
|
||||
localparam RC_DUMP = 4'd3;
|
||||
localparam RC_RESP_HEAD = 4'd4;
|
||||
localparam RC_RESP_TIME = 4'd5;
|
||||
localparam RC_RESP_DATA = 4'd6;
|
||||
|
||||
wire IS_EC = ctrl_tdata[63];
|
||||
wire HAS_TIME = ctrl_tdata[61];
|
||||
reg HAS_TIME_reg;
|
||||
|
||||
reg [3:0] rc_state;
|
||||
reg [63:0] cmd_time;
|
||||
|
||||
wire now, late, go;
|
||||
reg [11:0] seqnum;
|
||||
reg [31:0] sid;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
begin
|
||||
rc_state <= RC_HEAD;
|
||||
HAS_TIME_reg <= 1'b0;
|
||||
sid <= 32'd0;
|
||||
seqnum <= 12'd0;
|
||||
end
|
||||
else
|
||||
case(rc_state)
|
||||
RC_HEAD :
|
||||
if(ctrl_tvalid)
|
||||
begin
|
||||
sid <= ctrl_tdata[31:0];
|
||||
seqnum <= ctrl_tdata[59:48];
|
||||
HAS_TIME_reg <= HAS_TIME;
|
||||
if(IS_EC)
|
||||
if(HAS_TIME)
|
||||
rc_state <= RC_TIME;
|
||||
else
|
||||
rc_state <= RC_DATA;
|
||||
else
|
||||
if(~ctrl_tlast)
|
||||
rc_state <= RC_DUMP;
|
||||
end
|
||||
|
||||
RC_TIME :
|
||||
if(ctrl_tvalid)
|
||||
if(ctrl_tlast)
|
||||
rc_state <= RC_RESP_HEAD;
|
||||
else if(go)
|
||||
rc_state <= RC_DATA;
|
||||
|
||||
RC_DATA :
|
||||
if(ctrl_tvalid)
|
||||
if(ready)
|
||||
if(ctrl_tlast)
|
||||
rc_state <= RC_RESP_HEAD;
|
||||
else
|
||||
rc_state <= RC_DUMP;
|
||||
|
||||
RC_DUMP :
|
||||
if(ctrl_tvalid)
|
||||
if(ctrl_tlast)
|
||||
rc_state <= RC_RESP_HEAD;
|
||||
|
||||
RC_RESP_HEAD :
|
||||
if(resp_tready)
|
||||
rc_state <= RC_RESP_TIME;
|
||||
|
||||
RC_RESP_TIME :
|
||||
if(resp_tready)
|
||||
rc_state <= RC_RESP_DATA;
|
||||
|
||||
RC_RESP_DATA:
|
||||
if(resp_tready)
|
||||
rc_state <= RC_HEAD;
|
||||
|
||||
default :
|
||||
rc_state <= RC_HEAD;
|
||||
endcase // case (rc_state)
|
||||
|
||||
always @*
|
||||
case (rc_state)
|
||||
RC_HEAD : ctrl_tready <= 1'b1;
|
||||
RC_TIME : ctrl_tready <= ctrl_tlast | go;
|
||||
RC_DATA : ctrl_tready <= ready;
|
||||
RC_DUMP : ctrl_tready <= 1'b1;
|
||||
default : ctrl_tready <= 1'b0;
|
||||
endcase // case (rc_state)
|
||||
|
||||
time_compare time_compare
|
||||
(.clk(clk), .reset(reset), .time_now(vita_time), .trigger_time(ctrl_tdata), .now(now), .early(), .late(late), .too_early());
|
||||
|
||||
assign go = now | late;
|
||||
|
||||
assign set_stb = (rc_state == RC_DATA) & ready & ctrl_tvalid;
|
||||
assign set_addr = ctrl_tdata[39:32];
|
||||
assign set_data = ctrl_tdata[31:0];
|
||||
|
||||
always @*
|
||||
case (rc_state)
|
||||
RC_RESP_HEAD : { resp_tlast, resp_tdata } <= {1'b0, 4'hA, seqnum, 16'd24, sid[15:0], sid[31:16] };
|
||||
RC_RESP_TIME : { resp_tlast, resp_tdata } <= {1'b0, vita_time};
|
||||
RC_RESP_DATA : { resp_tlast, resp_tdata } <= {1'b1, readback};
|
||||
default : { resp_tlast, resp_tdata } <= 65'h0;
|
||||
endcase // case (rc_state)
|
||||
|
||||
assign resp_tvalid = (rc_state == RC_RESP_HEAD) | (rc_state == RC_RESP_TIME) | (rc_state == RC_RESP_DATA);
|
||||
|
||||
endmodule // radio_ctrl_proc
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module radio_ctrl_proc_tb();
|
||||
|
||||
reg clk = 0;
|
||||
reg reset = 1;
|
||||
|
||||
always #10 clk = ~clk;
|
||||
|
||||
initial $dumpfile("radio_ctrl_proc_tb.vcd");
|
||||
initial $dumpvars(0,radio_ctrl_proc_tb);
|
||||
|
||||
initial
|
||||
begin
|
||||
#1000 reset = 0;
|
||||
#20000;
|
||||
$finish;
|
||||
end
|
||||
|
||||
reg [63:0] vita_time = 64'd0;
|
||||
always @(posedge clk)
|
||||
if(reset) vita_time <= 64'd0;
|
||||
else vita_time <= vita_time + 64'd1;
|
||||
|
||||
reg [63:0] tdata;
|
||||
wire [63:0] tdata_int;
|
||||
reg tlast;
|
||||
wire tlast_int;
|
||||
reg tvalid = 1'b0;
|
||||
wire tvalid_int;
|
||||
wire tready, tready_int;
|
||||
|
||||
wire [7:0] set_addr;
|
||||
wire [31:0] set_data;
|
||||
wire set_stb;
|
||||
wire ready = 1'b1;
|
||||
|
||||
task send_packet;
|
||||
input ec;
|
||||
input timed;
|
||||
input [11:0] seqnum;
|
||||
input [31:0] sid;
|
||||
input [63:0] vtime;
|
||||
input [15:0] addr;
|
||||
input [31:0] data;
|
||||
|
||||
begin
|
||||
// Send a packet
|
||||
@(posedge clk);
|
||||
tlast <= 1'b0;
|
||||
tdata <= { ec, 1'b0, timed, 1'b0, seqnum, timed ? 16'd6 : 16'd4, sid };
|
||||
tvalid <= 1;
|
||||
@(posedge clk);
|
||||
if(timed)
|
||||
begin
|
||||
tdata <= vtime;
|
||||
@(posedge clk);
|
||||
end
|
||||
tlast <= 1'b1;
|
||||
tdata <= { 16'h0, addr, data };
|
||||
@(posedge clk);
|
||||
tvalid <= 0;
|
||||
@(posedge clk);
|
||||
end
|
||||
endtask // send_packet
|
||||
|
||||
initial
|
||||
begin
|
||||
tvalid <= 1'b0;
|
||||
while(reset)
|
||||
@(posedge clk);
|
||||
send_packet(1'b1,1'b0,12'h5,32'hDEAD_BEEF,64'h0,16'hB,32'hF00D_1234);
|
||||
send_packet(1'b1,1'b1,12'h6,32'hDEAD_6789,64'h20,16'hC,32'hABCD_4321);
|
||||
send_packet(1'b1,1'b1,12'h7,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
|
||||
//send_packet(.ec(1), .timed(0), .seqnum(5), .sid(32'hDEAD_BEEF), .vtime(0), .addr(16'hB), .data(32'hF00D_1234));
|
||||
end
|
||||
|
||||
axi_fifo_short #(.WIDTH(65)) axi_fifo_short
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({tlast,tdata}), .i_tvalid(tvalid), .i_tready(tready),
|
||||
.o_tdata({tlast_int,tdata_int}), .o_tvalid(tvalid_int), .o_tready(tready_int));
|
||||
|
||||
wire [63:0] resp_tdata;
|
||||
wire resp_tlast, resp_tvalid, resp_tready;
|
||||
|
||||
radio_ctrl_proc radio_ctrl_proc
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.ctrl_tdata(tdata_int), .ctrl_tlast(tlast_int), .ctrl_tvalid(tvalid_int), .ctrl_tready(tready_int),
|
||||
.resp_tdata(resp_tdata), .resp_tlast(resp_tlast), .resp_tvalid(resp_tvalid), .resp_tready(resp_tready),
|
||||
.vita_time(vita_time), .ready(ready),
|
||||
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
|
||||
.debug()
|
||||
);
|
||||
|
||||
assign resp_tready = 1'b1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(resp_tvalid & resp_tready)
|
||||
begin
|
||||
$display("%x",resp_tdata);
|
||||
if(resp_tlast)
|
||||
$display("TLAST");
|
||||
end
|
||||
endmodule // radio_ctrl_proc_tb
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module ram_2port
|
||||
#(parameter DWIDTH=32,
|
||||
parameter AWIDTH=9)
|
||||
(input clka,
|
||||
input ena,
|
||||
input wea,
|
||||
input [AWIDTH-1:0] addra,
|
||||
input [DWIDTH-1:0] dia,
|
||||
output reg [DWIDTH-1:0] doa,
|
||||
|
||||
input clkb,
|
||||
input enb,
|
||||
input web,
|
||||
input [AWIDTH-1:0] addrb,
|
||||
input [DWIDTH-1:0] dib,
|
||||
output reg [DWIDTH-1:0] dob);
|
||||
|
||||
reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
|
||||
/*
|
||||
integer i;
|
||||
initial
|
||||
for(i=0;i<(1<<AWIDTH);i=i+1)
|
||||
ram[i] <= {DWIDTH{1'b0}};
|
||||
*/
|
||||
|
||||
always @(posedge clka) begin
|
||||
if (ena)
|
||||
begin
|
||||
if (wea)
|
||||
ram[addra] <= dia;
|
||||
doa <= ram[addra];
|
||||
end
|
||||
end
|
||||
always @(posedge clkb) begin
|
||||
if (enb)
|
||||
begin
|
||||
if (web)
|
||||
ram[addrb] <= dib;
|
||||
dob <= ram[addrb];
|
||||
end
|
||||
end
|
||||
endmodule // ram_2port
|
||||
@@ -1,28 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module reset_sync
|
||||
(input clk,
|
||||
input reset_in,
|
||||
output reset_out);
|
||||
|
||||
reg reset_int;
|
||||
|
||||
reg reset_out_tmp;
|
||||
|
||||
//synthesis attribute async_reg of reset_out_tmp is "true";
|
||||
//synthesis attribute async_reg of reset_int is "true";
|
||||
always @(posedge clk or posedge reset_in)
|
||||
if(reset_in)
|
||||
{reset_out_tmp,reset_int} <= 2'b11;
|
||||
else
|
||||
{reset_out_tmp,reset_int} <= {reset_int,1'b0};
|
||||
|
||||
assign reset_out = reset_out_tmp;
|
||||
|
||||
|
||||
endmodule // reset_sync
|
||||
@@ -1,121 +0,0 @@
|
||||
|
||||
|
||||
module serial_to_settings
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
// Serial signals (async)
|
||||
input scl,
|
||||
input sda,
|
||||
// Settngs bus out
|
||||
output reg set_stb,
|
||||
output reg [7:0] set_addr,
|
||||
output reg [31:0] set_data,
|
||||
// Debug
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
reg [2:0] state;
|
||||
|
||||
localparam SEARCH = 3'h0;
|
||||
localparam ADDRESS = 3'h1;
|
||||
localparam DATA = 3'h2;
|
||||
localparam STOP1 = 3'h3;
|
||||
localparam STOP2 = 3'h4;
|
||||
|
||||
reg scl_pre_reg, scl_reg, scl_reg2;
|
||||
reg sda_pre_reg, sda_reg, sda_reg2;
|
||||
reg [4:0] counter;
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
scl_reg2 <= scl_reg;
|
||||
scl_reg <= scl_pre_reg;
|
||||
scl_pre_reg <= scl;
|
||||
sda_reg2 <= sda_reg;
|
||||
sda_reg <= sda_pre_reg;
|
||||
sda_pre_reg <= sda;
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
if (reset) begin
|
||||
state <= SEARCH;
|
||||
counter <= 0;
|
||||
set_addr <= 0;
|
||||
set_data <= 0;
|
||||
set_stb <= 0;
|
||||
end else begin
|
||||
case(state)
|
||||
//
|
||||
// Search for I2C like start indication: SDA goes low whilst clock is high.
|
||||
//
|
||||
SEARCH: begin
|
||||
set_stb <= 0;
|
||||
// Look for START.
|
||||
if (scl_reg && scl_reg2 && !sda_reg && sda_reg2) begin
|
||||
state <= ADDRESS;
|
||||
counter <= 0;
|
||||
end
|
||||
end
|
||||
//
|
||||
// Count 8 Address bits.
|
||||
// Master changes SDA on falling edge of SCL, we sample on the rising edge.
|
||||
//
|
||||
ADDRESS: begin
|
||||
if (scl_reg && !scl_reg2) begin
|
||||
set_addr[7:0] <= {set_addr[6:0],sda_reg};
|
||||
if (counter == 7) begin
|
||||
state <= DATA;
|
||||
counter <= 0;
|
||||
end else
|
||||
counter <= counter + 1;
|
||||
end
|
||||
end
|
||||
//
|
||||
// Count 32 data bits.
|
||||
// Master changes SDA on falling edge of SCL, we sample on the rising edge.
|
||||
//
|
||||
DATA: begin
|
||||
if (scl_reg && !scl_reg2) begin
|
||||
set_data[31:0] <= {set_data[30:0],sda_reg};
|
||||
if (counter == 31) begin
|
||||
state <= STOP1;
|
||||
counter <= 0;
|
||||
end else
|
||||
counter <= counter + 1;
|
||||
end
|
||||
end
|
||||
//
|
||||
// Looks for rising SCL edge before STOP bit.
|
||||
//
|
||||
STOP1: begin
|
||||
if (scl_reg && !scl_reg2) begin
|
||||
state <= STOP2;
|
||||
end
|
||||
end
|
||||
//
|
||||
// Looks for STOP bit
|
||||
//
|
||||
STOP2: begin
|
||||
if (scl_reg && scl_reg2 && sda_reg && !sda_reg2) begin
|
||||
state <= SEARCH;
|
||||
counter <= 0;
|
||||
set_stb <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
endcase // case(state)
|
||||
end // else: !if(reset)
|
||||
|
||||
assign debug =
|
||||
{
|
||||
counter[4:0],
|
||||
state[2:0],
|
||||
scl_reg,
|
||||
sda_reg
|
||||
};
|
||||
|
||||
|
||||
|
||||
endmodule // serial_to_settings
|
||||
@@ -1,82 +0,0 @@
|
||||
|
||||
|
||||
module serial_to_settings_tb();
|
||||
|
||||
|
||||
|
||||
reg clk;
|
||||
reg reset;
|
||||
|
||||
wire scl;
|
||||
wire sda;
|
||||
wire set_stb;
|
||||
wire [7:0] set_addr;
|
||||
wire [31:0] set_data;
|
||||
|
||||
//
|
||||
// These registers optionaly used
|
||||
// to drive nets through procedural assignments in test bench.
|
||||
// These drivers default to tri-stated.
|
||||
//
|
||||
reg scl_r;
|
||||
reg sda_r;
|
||||
|
||||
assign scl = scl_r;
|
||||
assign sda = sda_r;
|
||||
|
||||
initial
|
||||
begin
|
||||
scl_r <= 1'bz;
|
||||
sda_r <= 1'bz;
|
||||
end
|
||||
|
||||
|
||||
|
||||
serial_to_settings serial_to_settings_i
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
// Serial signals (async)
|
||||
.scl(scl),
|
||||
.sda(sda),
|
||||
// Settngs bus out
|
||||
.set_stb(set_stb),
|
||||
.set_addr(set_addr),
|
||||
.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
|
||||
//
|
||||
`include "simulation_script.v"
|
||||
|
||||
endmodule
|
||||
@@ -1,35 +0,0 @@
|
||||
//
|
||||
// Copyright 2011-2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//-- A settings register is a peripheral for the settings register bus.
|
||||
//-- When the settings register sees strobe abd a matching address,
|
||||
//-- the outputs will be become registered to the given input bus.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
module setting_reg
|
||||
#(parameter my_addr = 0,
|
||||
parameter awidth = 8,
|
||||
parameter width = 32,
|
||||
parameter at_reset=0)
|
||||
(input clk, input rst, input strobe, input wire [awidth-1:0] addr,
|
||||
input wire [31:0] in, output reg [width-1:0] out, output reg changed);
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
begin
|
||||
out <= at_reset;
|
||||
changed <= 1'b0;
|
||||
end
|
||||
else
|
||||
if(strobe & (my_addr==addr))
|
||||
begin
|
||||
out <= in[width-1:0];
|
||||
changed <= 1'b1;
|
||||
end
|
||||
else
|
||||
changed <= 1'b0;
|
||||
|
||||
endmodule // setting_reg
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// Copyright 2011-2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
// This module takes the settings bus on one clock domain and crosses it over to another domain
|
||||
// Typically it will be used with the input settings bus on the wishbone clock, and either
|
||||
// the system or dsp clock on the output side
|
||||
|
||||
module settings_bus_crossclock
|
||||
#(parameter FLOW_CTRL=0, parameter AWIDTH=8, parameter DWIDTH=32)
|
||||
(input clk_i, input rst_i, input set_stb_i, input [AWIDTH-1:0] set_addr_i, input [DWIDTH-1:0] set_data_i,
|
||||
input clk_o, input rst_o, output set_stb_o, output [AWIDTH-1:0] set_addr_o, output [DWIDTH-1:0] set_data_o, input blocked);
|
||||
|
||||
wire nfull, nempty;
|
||||
|
||||
axi_fifo_2clk #(.WIDTH(AWIDTH + DWIDTH), .SIZE(0)) settings_fifo
|
||||
(.reset(rst_i),
|
||||
.i_aclk(clk_i), .i_tdata({set_addr_i,set_data_i}), .i_tvalid(set_stb_i), .i_tready(nfull),
|
||||
.o_aclk(clk_o), .o_tdata({set_addr_o,set_data_o}), .o_tready(set_stb_o), .o_tvalid(nempty));
|
||||
|
||||
assign set_stb_o = nempty & (~blocked | ~FLOW_CTRL);
|
||||
|
||||
endmodule // settings_bus_crossclock
|
||||
@@ -1,104 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// Simple I2C core
|
||||
|
||||
// Settings reg map:
|
||||
//
|
||||
// BASE+0 control register
|
||||
// byte0 - control bits, data byte, or command bits, prescaler
|
||||
// byte1 - what to do? (documented in cpp file)
|
||||
// write prescaler lo
|
||||
// write prescaler hi
|
||||
// write control
|
||||
// write data
|
||||
// write command
|
||||
// read data
|
||||
// read status
|
||||
//
|
||||
|
||||
// Readback:
|
||||
//
|
||||
// byte0 has readback value based on the last read command
|
||||
//
|
||||
|
||||
module simple_i2c_core
|
||||
#(
|
||||
//settings register base address
|
||||
parameter BASE = 0,
|
||||
|
||||
//i2c line level at reset
|
||||
parameter ARST_LVL = 1
|
||||
)
|
||||
(
|
||||
//clock and synchronous reset
|
||||
input clock, input reset,
|
||||
|
||||
//32-bit settings bus inputs
|
||||
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||
|
||||
//32-bit data readback
|
||||
output reg [31:0] readback,
|
||||
|
||||
//read is high when i2c core can begin another transaction
|
||||
output reg ready,
|
||||
|
||||
// I2C signals
|
||||
// i2c clock line
|
||||
input scl_pad_i, // SCL-line input
|
||||
output scl_pad_o, // SCL-line output (always 1'b0)
|
||||
output scl_padoen_o, // SCL-line output enable (active low)
|
||||
|
||||
// i2c data line
|
||||
input sda_pad_i, // SDA-line input
|
||||
output sda_pad_o, // SDA-line output (always 1'b0)
|
||||
output sda_padoen_o, // SDA-line output enable (active low)
|
||||
|
||||
//optional debug output
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
//declare command settings register
|
||||
wire [7:0] sr_what, sr_data;
|
||||
wire sr_changed;
|
||||
setting_reg #(.my_addr(BASE+0),.width(16)) i2c_cmd_sr(
|
||||
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
|
||||
.out({sr_what, sr_data}),.changed(sr_changed));
|
||||
|
||||
//declare wb interface signals
|
||||
wire [2:0] wb_addr;
|
||||
wire [7:0] wb_data_mosi;
|
||||
wire [7:0] wb_data_miso;
|
||||
wire wb_we, wb_stb, wb_cyc;
|
||||
wire wb_ack;
|
||||
|
||||
//create wishbone-based i2c core
|
||||
i2c_master_top #(.ARST_LVL(ARST_LVL)) i2c
|
||||
(.wb_clk_i(clock),.wb_rst_i(reset),.arst_i(1'b0),
|
||||
.wb_adr_i(wb_addr),.wb_dat_i(wb_data_mosi),.wb_dat_o(wb_data_miso),
|
||||
.wb_we_i(wb_we),.wb_stb_i(wb_stb),.wb_cyc_i(wb_cyc),
|
||||
.wb_ack_o(wb_ack),.wb_inta_o(),
|
||||
.scl_pad_i(scl_pad_i),.scl_pad_o(scl_pad_o),.scl_padoen_o(scl_padoen_o),
|
||||
.sda_pad_i(sda_pad_i),.sda_pad_o(sda_pad_o),.sda_padoen_o(sda_padoen_o) );
|
||||
|
||||
//not ready between setting register and wishbone ack
|
||||
always @(posedge clock) begin
|
||||
if (reset || wb_ack) ready <= 1;
|
||||
else if (sr_changed) ready <= 0;
|
||||
end
|
||||
|
||||
//register wishbone data on every ack
|
||||
always @(posedge clock) begin
|
||||
if (wb_ack) readback <= {24'b0, wb_data_miso};
|
||||
end
|
||||
|
||||
//assign wishbone signals
|
||||
assign wb_addr = sr_what[2:0];
|
||||
assign wb_stb = sr_changed;
|
||||
assign wb_we = wb_stb && sr_what[3];
|
||||
assign wb_cyc = wb_stb;
|
||||
assign wb_data_mosi = sr_data;
|
||||
|
||||
endmodule //simple_i2c_core
|
||||
@@ -1,215 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// Simple SPI core, the simplest, yet complete spi core I can think of
|
||||
|
||||
// Settings register controlled.
|
||||
// 2 settings regs, control and data
|
||||
// 1 32-bit readback and status signal
|
||||
|
||||
// Settings reg map:
|
||||
//
|
||||
// BASE+0 divider setting
|
||||
// bits [15:0] spi clock divider
|
||||
//
|
||||
// BASE+1 configuration input
|
||||
// bits [23:0] slave select, bit0 = slave0 enabled
|
||||
// bits [29:24] num bits (1 through 32)
|
||||
// bit [30] data input edge = in data bit latched on rising edge of clock
|
||||
// bit [31] data output edge = out data bit latched on rising edge of clock
|
||||
//
|
||||
// BASE+2 input data
|
||||
// Writing this register begins a spi transaction.
|
||||
// Bits are latched out from bit 0.
|
||||
// Therefore, load this register in reverse.
|
||||
//
|
||||
// Readback
|
||||
// Bits are latched into bit 0.
|
||||
// Therefore, data will be in-order.
|
||||
|
||||
module simple_spi_core
|
||||
#(
|
||||
//settings register base address
|
||||
parameter BASE = 0,
|
||||
|
||||
//width of serial enables (up to 24 is possible)
|
||||
parameter WIDTH = 8,
|
||||
|
||||
//idle state of the spi clock
|
||||
parameter CLK_IDLE = 0,
|
||||
|
||||
//idle state of the serial enables
|
||||
parameter SEN_IDLE = 24'hffffff
|
||||
)
|
||||
(
|
||||
//clock and synchronous reset
|
||||
input clock, input reset,
|
||||
|
||||
//32-bit settings bus inputs
|
||||
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||
|
||||
//32-bit data readback
|
||||
output [31:0] readback,
|
||||
|
||||
//read is high when spi core can begin another transaction
|
||||
output ready,
|
||||
|
||||
//spi interface, slave selects, clock, data in, data out
|
||||
output reg [WIDTH-1:0] sen,
|
||||
output sclk,
|
||||
output reg mosi,
|
||||
input miso,
|
||||
|
||||
//optional debug output
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
wire [15:0] sclk_divider;
|
||||
setting_reg #(.my_addr(BASE+0),.width(16)) divider_sr(
|
||||
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
|
||||
.out(sclk_divider),.changed());
|
||||
|
||||
wire [23:0] slave_select;
|
||||
wire [5:0] num_bits;
|
||||
wire datain_edge, dataout_edge;
|
||||
setting_reg #(.my_addr(BASE+1),.width(32)) config_sr(
|
||||
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
|
||||
.out({dataout_edge, datain_edge, num_bits, slave_select}),.changed());
|
||||
|
||||
wire [31:0] mosi_data;
|
||||
wire trigger_spi;
|
||||
setting_reg #(.my_addr(BASE+2),.width(32)) data_sr(
|
||||
.clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
|
||||
.out(mosi_data),.changed(trigger_spi));
|
||||
|
||||
localparam WAIT_TRIG = 0;
|
||||
localparam PRE_IDLE = 1;
|
||||
localparam CLK_REG = 2;
|
||||
localparam CLK_INV = 3;
|
||||
localparam POST_IDLE = 4;
|
||||
localparam IDLE_SEN = 5;
|
||||
|
||||
reg [2:0] state;
|
||||
|
||||
reg ready_reg;
|
||||
assign ready = ready_reg && ~trigger_spi;
|
||||
|
||||
//serial clock either idles or is in one of two clock states
|
||||
reg sclk_reg;
|
||||
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];
|
||||
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};
|
||||
|
||||
always @(posedge clock)
|
||||
mosi <= dataout_reg[31];
|
||||
|
||||
//data input shift register
|
||||
// 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};
|
||||
assign readback = datain_reg;
|
||||
|
||||
//counter for spi clock
|
||||
reg [15:0] sclk_counter;
|
||||
wire sclk_counter_done = (sclk_counter == sclk_divider);
|
||||
wire [15:0] sclk_counter_next = (sclk_counter_done)? 0 : sclk_counter + 1;
|
||||
|
||||
//counter for latching bits miso/mosi
|
||||
reg [6:0] bit_counter;
|
||||
wire [6:0] bit_counter_next = bit_counter + 1;
|
||||
wire bit_counter_done = (bit_counter_next == num_bits);
|
||||
|
||||
always @(posedge clock) begin
|
||||
if (reset) begin
|
||||
state <= WAIT_TRIG;
|
||||
sclk_reg <= CLK_IDLE;
|
||||
ready_reg <= 0;
|
||||
end
|
||||
else begin
|
||||
case (state)
|
||||
|
||||
WAIT_TRIG: begin
|
||||
if (trigger_spi) state <= PRE_IDLE;
|
||||
ready_reg <= ~trigger_spi;
|
||||
dataout_reg <= mosi_data;
|
||||
sclk_counter <= 0;
|
||||
bit_counter <= 0;
|
||||
sclk_reg <= CLK_IDLE;
|
||||
end
|
||||
|
||||
PRE_IDLE: begin
|
||||
if (sclk_counter_done) state <= CLK_REG;
|
||||
sclk_counter <= sclk_counter_next;
|
||||
sclk_reg <= CLK_IDLE;
|
||||
end
|
||||
|
||||
CLK_REG: begin
|
||||
if (sclk_counter_done) begin
|
||||
state <= CLK_INV;
|
||||
if (datain_edge != CLK_IDLE) datain_reg <= datain_next;
|
||||
if (dataout_edge != CLK_IDLE && bit_counter != 0) dataout_reg <= dataout_next;
|
||||
sclk_reg <= ~CLK_IDLE; //transition to rising when CLK_IDLE == 0
|
||||
end
|
||||
sclk_counter <= sclk_counter_next;
|
||||
end
|
||||
|
||||
CLK_INV: begin
|
||||
if (sclk_counter_done) begin
|
||||
state <= (bit_counter_done)? POST_IDLE : CLK_REG;
|
||||
bit_counter <= bit_counter_next;
|
||||
if (datain_edge == CLK_IDLE) datain_reg <= datain_next;
|
||||
if (dataout_edge == CLK_IDLE && ~bit_counter_done) dataout_reg <= dataout_next;
|
||||
sclk_reg <= CLK_IDLE; //transition to falling when CLK_IDLE == 0
|
||||
end
|
||||
sclk_counter <= sclk_counter_next;
|
||||
end
|
||||
|
||||
POST_IDLE: begin
|
||||
if (sclk_counter_done) state <= IDLE_SEN;
|
||||
sclk_counter <= sclk_counter_next;
|
||||
sclk_reg <= CLK_IDLE;
|
||||
end
|
||||
|
||||
IDLE_SEN: begin
|
||||
if (sclk_counter_done) state <= WAIT_TRIG;
|
||||
sclk_counter <= sclk_counter_next;
|
||||
sclk_reg <= CLK_IDLE;
|
||||
end
|
||||
|
||||
default: state <= WAIT_TRIG;
|
||||
|
||||
endcase //state
|
||||
end
|
||||
end
|
||||
|
||||
assign debug = {
|
||||
trigger_spi, state, //4
|
||||
sclk, mosi, miso, ready, //4
|
||||
//sen[7:0], //8
|
||||
1'b0, bit_counter[6:0], //8
|
||||
sclk_counter_done, bit_counter_done, //2
|
||||
sclk_counter[5:0] //6
|
||||
};
|
||||
|
||||
endmodule //simple_spi_core
|
||||
@@ -1 +0,0 @@
|
||||
coregen.log
|
||||
@@ -1,40 +0,0 @@
|
||||
#
|
||||
# Copyright 2013 Ettus Research LLC
|
||||
#
|
||||
|
||||
##################################################
|
||||
# DSP Sources
|
||||
##################################################
|
||||
DSP_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/dsp/, \
|
||||
ddc_chain_x300.v \
|
||||
ddc_chain.v \
|
||||
duc_chain.v \
|
||||
sign_extend.v \
|
||||
cordic_z24.v \
|
||||
clip_reg.v \
|
||||
cordic_stage.v \
|
||||
clip.v \
|
||||
cic_strober.v \
|
||||
cic_decim.v \
|
||||
cic_interp.v \
|
||||
cic_dec_shifter.v \
|
||||
cic_int_shifter.v \
|
||||
small_hb_dec.v \
|
||||
small_hb_int.v \
|
||||
hb_dec.v \
|
||||
hb_interp.v \
|
||||
round_sd.v \
|
||||
add2_and_clip_reg.v \
|
||||
add2_and_clip.v \
|
||||
add2.v \
|
||||
add2_reg.v \
|
||||
add2_and_round_reg.v \
|
||||
add2_and_round.v \
|
||||
round_reg.v \
|
||||
round.v \
|
||||
srl.v \
|
||||
acc.v \
|
||||
rx_frontend.v \
|
||||
tx_frontend.v \
|
||||
rx_dcoffset.v \
|
||||
))
|
||||
@@ -1,33 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module acc
|
||||
#(parameter IWIDTH=16, OWIDTH=30)
|
||||
(input clk,
|
||||
input clear,
|
||||
input acc,
|
||||
input [IWIDTH-1:0] in,
|
||||
output reg [OWIDTH-1:0] out);
|
||||
|
||||
wire [OWIDTH-1:0] in_signext;
|
||||
sign_extend #(.bits_in(IWIDTH),.bits_out(OWIDTH))
|
||||
acc_signext (.in(in),.out(in_signext));
|
||||
|
||||
// CLEAR & ~ACC --> clears the accumulator
|
||||
// CLEAR & ACC --> loads the accumulator
|
||||
// ~CLEAR & ACC --> accumulates
|
||||
// ~CLEAR & ~ACC --> hold
|
||||
|
||||
wire [OWIDTH-1:0] addend1 = clear ? 0 : out;
|
||||
wire [OWIDTH-1:0] addend2 = ~acc ? 0 : in_signext;
|
||||
wire [OWIDTH-1:0] sum_int = addend1 + addend2;
|
||||
|
||||
always @(posedge clk)
|
||||
out <= sum_int;
|
||||
|
||||
endmodule // acc
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module add2
|
||||
#(parameter WIDTH=16)
|
||||
(input [WIDTH-1:0] in1,
|
||||
input [WIDTH-1:0] in2,
|
||||
output [WIDTH-1:0] sum);
|
||||
|
||||
wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
|
||||
assign sum = sum_int[WIDTH:1]; // Note -- will have some bias
|
||||
|
||||
endmodule // add2
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
module add2_and_clip
|
||||
#(parameter WIDTH=16)
|
||||
(input [WIDTH-1:0] in1,
|
||||
input [WIDTH-1:0] in2,
|
||||
output [WIDTH-1:0] sum);
|
||||
|
||||
wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
|
||||
clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip
|
||||
(.in(sum_int),.out(sum));
|
||||
|
||||
endmodule // add2_and_clip
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
module add2_and_clip_reg
|
||||
#(parameter WIDTH=16)
|
||||
(input clk,
|
||||
input rst,
|
||||
input [WIDTH-1:0] in1,
|
||||
input [WIDTH-1:0] in2,
|
||||
input strobe_in,
|
||||
output reg [WIDTH-1:0] sum,
|
||||
output reg strobe_out);
|
||||
|
||||
wire [WIDTH-1:0] sum_int;
|
||||
|
||||
add2_and_clip #(.WIDTH(WIDTH)) add2_and_clip (.in1(in1),.in2(in2),.sum(sum_int));
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
sum <= 0;
|
||||
else if(strobe_in)
|
||||
sum <= sum_int;
|
||||
|
||||
always @(posedge clk)
|
||||
strobe_out <= strobe_in;
|
||||
|
||||
endmodule // add2_and_clip_reg
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module add2_and_round
|
||||
#(parameter WIDTH=16)
|
||||
(input [WIDTH-1:0] in1,
|
||||
input [WIDTH-1:0] in2,
|
||||
output [WIDTH-1:0] sum);
|
||||
|
||||
wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2};
|
||||
assign sum = sum_int[WIDTH:1] + (sum_int[WIDTH] & sum_int[0]);
|
||||
|
||||
endmodule // add2_and_round
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module add2_and_round_reg
|
||||
#(parameter WIDTH=16)
|
||||
(input clk,
|
||||
input [WIDTH-1:0] in1,
|
||||
input [WIDTH-1:0] in2,
|
||||
output reg [WIDTH-1:0] sum);
|
||||
|
||||
wire [WIDTH-1:0] sum_int;
|
||||
|
||||
add2_and_round #(.WIDTH(WIDTH)) add2_n_rnd (.in1(in1),.in2(in2),.sum(sum_int));
|
||||
|
||||
always @(posedge clk)
|
||||
sum <= sum_int;
|
||||
|
||||
endmodule // add2_and_round_reg
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module add2_reg
|
||||
#(parameter WIDTH=16)
|
||||
(input clk,
|
||||
input [WIDTH-1:0] in1,
|
||||
input [WIDTH-1:0] in2,
|
||||
output reg [WIDTH-1:0] sum);
|
||||
|
||||
wire [WIDTH-1:0] sum_int;
|
||||
|
||||
add2 #(.WIDTH(WIDTH)) add2 (.in1(in1),.in2(in2),.sum(sum_int));
|
||||
|
||||
always @(posedge clk)
|
||||
sum <= sum_int;
|
||||
|
||||
endmodule // add2_reg
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
|
||||
// NOTE This only works for N=4, max decim rate of 128
|
||||
// NOTE signal "rate" is EQUAL TO the actual rate, no more -1 BS
|
||||
|
||||
module cic_dec_shifter(rate,signal_in,signal_out);
|
||||
parameter bw = 16;
|
||||
parameter maxbitgain = 28;
|
||||
|
||||
input [7:0] rate;
|
||||
input wire [bw+maxbitgain-1:0] signal_in;
|
||||
output reg [bw-1:0] signal_out;
|
||||
|
||||
function [4:0] bitgain;
|
||||
input [7:0] rate;
|
||||
case(rate)
|
||||
// Exact Cases -- N*log2(rate)
|
||||
8'd1 : bitgain = 0;
|
||||
8'd2 : bitgain = 4;
|
||||
8'd4 : bitgain = 8;
|
||||
8'd8 : bitgain = 12;
|
||||
8'd16 : bitgain = 16;
|
||||
8'd32 : bitgain = 20;
|
||||
8'd64 : bitgain = 24;
|
||||
8'd128 : bitgain = 28;
|
||||
|
||||
// Nearest without overflow -- ceil(N*log2(rate))
|
||||
8'd3 : bitgain = 7;
|
||||
8'd5 : bitgain = 10;
|
||||
8'd6 : bitgain = 11;
|
||||
8'd7 : bitgain = 12;
|
||||
8'd9 : bitgain = 13;
|
||||
8'd10,8'd11 : bitgain = 14;
|
||||
8'd12,8'd13 : bitgain = 15;
|
||||
8'd14,8'd15 : bitgain = 16;
|
||||
8'd17,8'd18,8'd19 : bitgain = 17;
|
||||
8'd20,8'd21,8'd22 : bitgain = 18;
|
||||
8'd23,8'd24,8'd25,8'd26 : bitgain = 19;
|
||||
8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 20;
|
||||
8'd33,8'd34,8'd35,8'd36,8'd37,8'd38 : bitgain = 21;
|
||||
8'd39,8'd40,8'd41,8'd42,8'd43,8'd44,8'd45 : bitgain = 22;
|
||||
8'd46,8'd47,8'd48,8'd49,8'd50,8'd51,8'd52,8'd53 : bitgain = 23;
|
||||
8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 24;
|
||||
8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76 : bitgain = 25;
|
||||
8'd77,8'd78,8'd79,8'd80,8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90 : bitgain = 26;
|
||||
8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101,8'd102,8'd103,8'd104,8'd105,8'd106,8'd107 : bitgain = 27;
|
||||
default : bitgain = 28;
|
||||
endcase // case(rate)
|
||||
endfunction // bitgain
|
||||
|
||||
wire [4:0] shift = bitgain(rate);
|
||||
|
||||
// We should be able to do this, but can't ....
|
||||
// assign signal_out = signal_in[shift+bw-1:shift];
|
||||
|
||||
always @*
|
||||
case(shift)
|
||||
5'd0 : signal_out = signal_in[0+bw-1:0];
|
||||
5'd4 : signal_out = signal_in[4+bw-1:4];
|
||||
5'd7 : signal_out = signal_in[7+bw-1:7];
|
||||
5'd8 : signal_out = signal_in[8+bw-1:8];
|
||||
5'd10 : signal_out = signal_in[10+bw-1:10];
|
||||
5'd11 : signal_out = signal_in[11+bw-1:11];
|
||||
5'd12 : signal_out = signal_in[12+bw-1:12];
|
||||
5'd13 : signal_out = signal_in[13+bw-1:13];
|
||||
5'd14 : signal_out = signal_in[14+bw-1:14];
|
||||
5'd15 : signal_out = signal_in[15+bw-1:15];
|
||||
5'd16 : signal_out = signal_in[16+bw-1:16];
|
||||
5'd17 : signal_out = signal_in[17+bw-1:17];
|
||||
5'd18 : signal_out = signal_in[18+bw-1:18];
|
||||
5'd19 : signal_out = signal_in[19+bw-1:19];
|
||||
5'd20 : signal_out = signal_in[20+bw-1:20];
|
||||
5'd21 : signal_out = signal_in[21+bw-1:21];
|
||||
5'd22 : signal_out = signal_in[22+bw-1:22];
|
||||
5'd23 : signal_out = signal_in[23+bw-1:23];
|
||||
5'd24 : signal_out = signal_in[24+bw-1:24];
|
||||
5'd25 : signal_out = signal_in[25+bw-1:25];
|
||||
5'd26 : signal_out = signal_in[26+bw-1:26];
|
||||
5'd27 : signal_out = signal_in[27+bw-1:27];
|
||||
5'd28 : signal_out = signal_in[28+bw-1:28];
|
||||
|
||||
default : signal_out = signal_in[28+bw-1:28];
|
||||
endcase // case(shift)
|
||||
|
||||
endmodule // cic_dec_shifter
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
|
||||
module cic_decim
|
||||
#(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7)
|
||||
(input clock,
|
||||
input reset,
|
||||
input enable,
|
||||
input [7:0] rate,
|
||||
input strobe_in,
|
||||
input strobe_out,
|
||||
input [bw-1:0] signal_in,
|
||||
output reg [bw-1:0] signal_out);
|
||||
|
||||
localparam maxbitgain = N * log2_of_max_rate;
|
||||
|
||||
wire [bw+maxbitgain-1:0] signal_in_ext;
|
||||
reg [bw+maxbitgain-1:0] integrator [0:N-1];
|
||||
reg [bw+maxbitgain-1:0] differentiator [0:N-1];
|
||||
reg [bw+maxbitgain-1:0] pipeline [0:N-1];
|
||||
reg [bw+maxbitgain-1:0] sampler;
|
||||
|
||||
integer i;
|
||||
|
||||
sign_extend #(bw,bw+maxbitgain)
|
||||
ext_input (.in(signal_in),.out(signal_in_ext));
|
||||
|
||||
always @(posedge clock)
|
||||
if(~enable)
|
||||
for(i=0;i<N;i=i+1)
|
||||
integrator[i] <= 0;
|
||||
else if (strobe_in)
|
||||
begin
|
||||
integrator[0] <= integrator[0] + signal_in_ext;
|
||||
for(i=1;i<N;i=i+1)
|
||||
integrator[i] <= integrator[i] + integrator[i-1];
|
||||
end
|
||||
|
||||
always @(posedge clock)
|
||||
if(~enable)
|
||||
begin
|
||||
sampler <= 0;
|
||||
for(i=0;i<N;i=i+1)
|
||||
begin
|
||||
pipeline[i] <= 0;
|
||||
differentiator[i] <= 0;
|
||||
end
|
||||
end
|
||||
else if (strobe_out)
|
||||
begin
|
||||
sampler <= integrator[N-1];
|
||||
differentiator[0] <= sampler;
|
||||
pipeline[0] <= sampler - differentiator[0];
|
||||
for(i=1;i<N;i=i+1)
|
||||
begin
|
||||
differentiator[i] <= pipeline[i-1];
|
||||
pipeline[i] <= pipeline[i-1] - differentiator[i];
|
||||
end
|
||||
end // if (enable && strobe_out)
|
||||
|
||||
wire [bw-1:0] signal_out_unreg;
|
||||
|
||||
cic_dec_shifter #(bw)
|
||||
cic_dec_shifter(rate,pipeline[N-1],signal_out_unreg);
|
||||
|
||||
always @(posedge clock)
|
||||
signal_out <= signal_out_unreg;
|
||||
|
||||
endmodule // cic_decim
|
||||
@@ -1,88 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
|
||||
// NOTE This only works for N=4, max interp rate of 128
|
||||
// NOTE signal "rate" is EQUAL TO the actual rate (no more -1 BS)
|
||||
|
||||
module cic_int_shifter(rate,signal_in,signal_out);
|
||||
parameter bw = 16;
|
||||
parameter maxbitgain = 21;
|
||||
|
||||
input [7:0] rate;
|
||||
input wire [bw+maxbitgain-1:0] signal_in;
|
||||
output reg [bw-1:0] signal_out;
|
||||
|
||||
function [4:0] bitgain;
|
||||
input [7:0] rate;
|
||||
case(rate)
|
||||
// Exact Cases
|
||||
8'd1 : bitgain = 0;
|
||||
8'd2 : bitgain = 3;
|
||||
8'd4 : bitgain = 6;
|
||||
8'd8 : bitgain = 9;
|
||||
8'd16 : bitgain = 12;
|
||||
8'd32 : bitgain = 15;
|
||||
8'd64 : bitgain = 18;
|
||||
8'd128 : bitgain = 21;
|
||||
|
||||
// Nearest without overflow
|
||||
8'd3 : bitgain = 5;
|
||||
8'd5 : bitgain = 7;
|
||||
8'd6 : bitgain = 8;
|
||||
8'd7 : bitgain = 9;
|
||||
8'd9,8'd10 : bitgain = 10;
|
||||
8'd11,8'd12 : bitgain = 11;
|
||||
8'd13,8'd14,8'd15 : bitgain = 12;
|
||||
8'd17,8'd18,8'd19,8'd20 : bitgain = 13;
|
||||
8'd21,8'd22,8'd23,8'd24,8'd25 : bitgain = 14;
|
||||
8'd26,8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 15;
|
||||
8'd33,8'd34,8'd35,8'd36,8'd37,8'd38,8'd39,8'd40 : bitgain = 16;
|
||||
8'd41,8'd42,8'd43,8'd44,8'd45,8'd46,8'd47,8'd48,8'd49,8'd50 : bitgain = 17;
|
||||
8'd51,8'd52,8'd53,8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 18;
|
||||
8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76,8'd77,8'd78,8'd79,8'd80 : bitgain = 19;
|
||||
8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90,8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101 : bitgain = 20;
|
||||
|
||||
default : bitgain = 21;
|
||||
endcase // case(rate)
|
||||
endfunction // bitgain
|
||||
|
||||
wire [4:0] shift = bitgain(rate);
|
||||
|
||||
// We should be able to do this, but can't ....
|
||||
// assign signal_out = signal_in[shift+bw-1:shift];
|
||||
|
||||
always @*
|
||||
case(shift)
|
||||
5'd0 : signal_out = signal_in[0+bw-1:0];
|
||||
5'd3 : signal_out = signal_in[3+bw-1:3];
|
||||
5'd6 : signal_out = signal_in[6+bw-1:6];
|
||||
5'd9 : signal_out = signal_in[9+bw-1:9];
|
||||
5'd12 : signal_out = signal_in[12+bw-1:12];
|
||||
5'd15 : signal_out = signal_in[15+bw-1:15];
|
||||
5'd18 : signal_out = signal_in[18+bw-1:18];
|
||||
5'd21 : signal_out = signal_in[21+bw-1:21];
|
||||
|
||||
5'd5 : signal_out = signal_in[5+bw-1:5];
|
||||
5'd7 : signal_out = signal_in[7+bw-1:7];
|
||||
5'd8 : signal_out = signal_in[8+bw-1:8];
|
||||
5'd10 : signal_out = signal_in[10+bw-1:10];
|
||||
5'd11 : signal_out = signal_in[11+bw-1:11];
|
||||
5'd13 : signal_out = signal_in[13+bw-1:13];
|
||||
5'd14 : signal_out = signal_in[14+bw-1:14];
|
||||
5'd16 : signal_out = signal_in[16+bw-1:16];
|
||||
5'd17 : signal_out = signal_in[17+bw-1:17];
|
||||
5'd19 : signal_out = signal_in[19+bw-1:19];
|
||||
5'd20 : signal_out = signal_in[20+bw-1:20];
|
||||
|
||||
default : signal_out = signal_in[21+bw-1:21];
|
||||
endcase // case(shift)
|
||||
|
||||
endmodule // cic_int_shifter
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
|
||||
module cic_interp
|
||||
#(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7)
|
||||
(input clock,
|
||||
input reset,
|
||||
input enable,
|
||||
input [7:0] rate,
|
||||
input strobe_in,
|
||||
input strobe_out,
|
||||
input [bw-1:0] signal_in,
|
||||
output reg [bw-1:0] signal_out);
|
||||
|
||||
integer i;
|
||||
localparam maxbitgain = (N-1)*log2_of_max_rate;
|
||||
|
||||
wire [bw+maxbitgain-1:0] signal_in_ext;
|
||||
reg [bw+maxbitgain-1:0] integrator [0:N-1];
|
||||
reg [bw+maxbitgain-1:0] differentiator [0:N-1];
|
||||
reg [bw+maxbitgain-1:0] pipeline [0:N-1];
|
||||
|
||||
sign_extend #(bw,bw+maxbitgain)
|
||||
ext_input (.in(signal_in),.out(signal_in_ext));
|
||||
|
||||
//FIXME Note that this section has pipe and diff reversed
|
||||
// It still works, but is confusing
|
||||
always @(posedge clock)
|
||||
if(reset | ~enable)
|
||||
for(i=0;i<N;i=i+1)
|
||||
integrator[i] <= 0;
|
||||
else if (enable & strobe_out)
|
||||
begin
|
||||
if(strobe_in)
|
||||
integrator[0] <= integrator[0] + pipeline[N-1];
|
||||
for(i=1;i<N;i=i+1)
|
||||
integrator[i] <= integrator[i] + integrator[i-1];
|
||||
end
|
||||
|
||||
always @(posedge clock)
|
||||
if(reset | ~enable)
|
||||
begin
|
||||
for(i=0;i<N;i=i+1)
|
||||
begin
|
||||
differentiator[i] <= 0;
|
||||
pipeline[i] <= 0;
|
||||
end
|
||||
end
|
||||
else if (enable && strobe_in)
|
||||
begin
|
||||
differentiator[0] <= signal_in_ext;
|
||||
pipeline[0] <= signal_in_ext - differentiator[0];
|
||||
for(i=1;i<N;i=i+1)
|
||||
begin
|
||||
differentiator[i] <= pipeline[i-1];
|
||||
pipeline[i] <= pipeline[i-1] - differentiator[i];
|
||||
end
|
||||
end
|
||||
|
||||
wire [bw-1:0] signal_out_unreg;
|
||||
cic_int_shifter #(bw)
|
||||
cic_int_shifter(rate,integrator[N-1],signal_out_unreg);
|
||||
|
||||
always @(posedge clock)
|
||||
signal_out <= signal_out_unreg;
|
||||
|
||||
endmodule // cic_interp
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
//
|
||||
// USRP2 - Universal Software Radio Peripheral Mk II
|
||||
//
|
||||
// Copyright (C) 2008 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
module cic_strober
|
||||
#(parameter WIDTH=8)
|
||||
( input clock,
|
||||
input reset,
|
||||
input enable,
|
||||
input [WIDTH-1:0] rate, // Rate should EQUAL to your desired divide ratio, no more -1 BS
|
||||
input strobe_fast,
|
||||
output wire strobe_slow );
|
||||
|
||||
reg [WIDTH-1:0] counter;
|
||||
wire now = (counter==1);
|
||||
assign strobe_slow = now && enable && strobe_fast;
|
||||
|
||||
always @(posedge clock)
|
||||
if(reset)
|
||||
counter <= 0;
|
||||
else if (~enable)
|
||||
counter <= rate;
|
||||
else if(strobe_fast)
|
||||
if(now)
|
||||
counter <= rate;
|
||||
else
|
||||
counter <= counter - 1;
|
||||
|
||||
endmodule // cic_strober
|
||||
@@ -1,24 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2008 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
// Clipping "macro", keeps the bottom bits
|
||||
|
||||
module clip
|
||||
#(parameter bits_in=0,
|
||||
parameter bits_out=0)
|
||||
(input [bits_in-1:0] in,
|
||||
output [bits_out-1:0] out);
|
||||
|
||||
wire overflow = |in[bits_in-1:bits_out-1] & ~(&in[bits_in-1:bits_out-1]);
|
||||
assign out = overflow ?
|
||||
(in[bits_in-1] ? {1'b1,{(bits_out-1){1'b0}}} : {1'b0,{(bits_out-1){1'b1}}}) :
|
||||
in[bits_out-1:0];
|
||||
|
||||
endmodule // clip
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2008 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
// Clipping "macro", keeps the bottom bits
|
||||
|
||||
module clip_reg
|
||||
#(parameter bits_in=0,
|
||||
parameter bits_out=0,
|
||||
parameter STROBED=1'b0)
|
||||
(input clk,
|
||||
input [bits_in-1:0] in,
|
||||
output reg [bits_out-1:0] out,
|
||||
input strobe_in,
|
||||
output reg strobe_out);
|
||||
|
||||
wire [bits_out-1:0] temp;
|
||||
|
||||
clip #(.bits_in(bits_in),.bits_out(bits_out)) clip (.in(in),.out(temp));
|
||||
|
||||
always @(posedge clk)
|
||||
strobe_out <= strobe_in;
|
||||
|
||||
always @(posedge clk)
|
||||
if(strobe_in | ~STROBED)
|
||||
out <= temp;
|
||||
|
||||
endmodule // clip_reg
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
module cordic_stage( clock, reset, enable, xi,yi,zi,constant,xo,yo,zo);
|
||||
parameter bitwidth = 16;
|
||||
parameter zwidth = 16;
|
||||
parameter shift = 1;
|
||||
|
||||
input clock;
|
||||
input reset;
|
||||
input enable;
|
||||
input [bitwidth-1:0] xi,yi;
|
||||
input [zwidth-1:0] zi;
|
||||
input [zwidth-1:0] constant;
|
||||
output [bitwidth-1:0] xo,yo;
|
||||
output [zwidth-1:0] zo;
|
||||
|
||||
wire z_is_pos = ~zi[zwidth-1];
|
||||
|
||||
reg [bitwidth-1:0] xo,yo;
|
||||
reg [zwidth-1:0] zo;
|
||||
|
||||
always @(posedge clock)
|
||||
if(reset)
|
||||
begin
|
||||
xo <= 0;
|
||||
yo <= 0;
|
||||
zo <= 0;
|
||||
end
|
||||
else //if(enable)
|
||||
begin
|
||||
xo <= z_is_pos ?
|
||||
xi - {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]} :
|
||||
xi + {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]};
|
||||
yo <= z_is_pos ?
|
||||
yi + {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]} :
|
||||
yi - {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]};
|
||||
zo <= z_is_pos ?
|
||||
zi - constant :
|
||||
zi + constant;
|
||||
end
|
||||
endmodule
|
||||
@@ -1,112 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003, 2007 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo );
|
||||
parameter bitwidth = 16;
|
||||
parameter stages = 19;
|
||||
localparam zwidth = 24;
|
||||
|
||||
input clock;
|
||||
input reset;
|
||||
input enable;
|
||||
input [bitwidth-1:0] xi, yi;
|
||||
output [bitwidth-1:0] xo, yo;
|
||||
input [zwidth-1:0] zi;
|
||||
output [zwidth-1:0] zo;
|
||||
|
||||
reg [bitwidth+1:0] x0,y0;
|
||||
reg [zwidth-2:0] z0;
|
||||
wire [bitwidth+1:0] x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20;
|
||||
wire [bitwidth+1:0] y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12,y13,y14,y15,y16,y17,y18,y19,y20;
|
||||
wire [zwidth-2:0] z1,z2,z3,z4,z5,z6,z7,z8,z9,z10,z11,z12,z13,z14,z15,z16,z17,z18,z19,z20;
|
||||
|
||||
wire [bitwidth+1:0] xi_ext = {{2{xi[bitwidth-1]}},xi};
|
||||
wire [bitwidth+1:0] yi_ext = {{2{yi[bitwidth-1]}},yi};
|
||||
|
||||
// Compute consts. Would be easier if vlog had atan...
|
||||
// see gen_cordic_consts.py
|
||||
|
||||
// constants for 24 bit wide phase
|
||||
localparam c00 = 23'd2097152;
|
||||
localparam c01 = 23'd1238021;
|
||||
localparam c02 = 23'd654136;
|
||||
localparam c03 = 23'd332050;
|
||||
localparam c04 = 23'd166669;
|
||||
localparam c05 = 23'd83416;
|
||||
localparam c06 = 23'd41718;
|
||||
localparam c07 = 23'd20860;
|
||||
localparam c08 = 23'd10430;
|
||||
localparam c09 = 23'd5215;
|
||||
localparam c10 = 23'd2608;
|
||||
localparam c11 = 23'd1304;
|
||||
localparam c12 = 23'd652;
|
||||
localparam c13 = 23'd326;
|
||||
localparam c14 = 23'd163;
|
||||
localparam c15 = 23'd81;
|
||||
localparam c16 = 23'd41;
|
||||
localparam c17 = 23'd20;
|
||||
localparam c18 = 23'd10;
|
||||
localparam c19 = 23'd5;
|
||||
localparam c20 = 23'd3;
|
||||
localparam c21 = 23'd1;
|
||||
localparam c22 = 23'd1;
|
||||
localparam c23 = 23'd0;
|
||||
|
||||
always @(posedge clock)
|
||||
if(reset)
|
||||
begin
|
||||
x0 <= 0; y0 <= 0; z0 <= 0;
|
||||
end
|
||||
else// if(enable)
|
||||
begin
|
||||
z0 <= zi[zwidth-2:0];
|
||||
case (zi[zwidth-1:zwidth-2])
|
||||
2'b00, 2'b11 :
|
||||
begin
|
||||
x0 <= xi_ext;
|
||||
y0 <= yi_ext;
|
||||
end
|
||||
2'b01, 2'b10 :
|
||||
begin
|
||||
x0 <= -xi_ext;
|
||||
y0 <= -yi_ext;
|
||||
end
|
||||
endcase // case(zi[zwidth-1:zwidth-2])
|
||||
end // else: !if(reset)
|
||||
|
||||
// FIXME need to handle variable number of stages
|
||||
// This would be easier if arrays worked better in vlog...
|
||||
|
||||
cordic_stage #(bitwidth+2,zwidth-1,0) cordic_stage0 (clock,reset,enable,x0,y0,z0,c00,x1,y1,z1);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,1) cordic_stage1 (clock,reset,enable,x1,y1,z1,c01,x2,y2,z2);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,2) cordic_stage2 (clock,reset,enable,x2,y2,z2,c02,x3,y3,z3);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,3) cordic_stage3 (clock,reset,enable,x3,y3,z3,c03,x4,y4,z4);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,4) cordic_stage4 (clock,reset,enable,x4,y4,z4,c04,x5,y5,z5);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,5) cordic_stage5 (clock,reset,enable,x5,y5,z5,c05,x6,y6,z6);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,6) cordic_stage6 (clock,reset,enable,x6,y6,z6,c06,x7,y7,z7);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,7) cordic_stage7 (clock,reset,enable,x7,y7,z7,c07,x8,y8,z8);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,8) cordic_stage8 (clock,reset,enable,x8,y8,z8,c08,x9,y9,z9);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,9) cordic_stage9 (clock,reset,enable,x9,y9,z9,c09,x10,y10,z10);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,10) cordic_stage10 (clock,reset,enable,x10,y10,z10,c10,x11,y11,z11);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,11) cordic_stage11 (clock,reset,enable,x11,y11,z11,c11,x12,y12,z12);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,12) cordic_stage12 (clock,reset,enable,x12,y12,z12,c12,x13,y13,z13);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,13) cordic_stage13 (clock,reset,enable,x13,y13,z13,c13,x14,y14,z14);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,14) cordic_stage14 (clock,reset,enable,x14,y14,z14,c14,x15,y15,z15);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,15) cordic_stage15 (clock,reset,enable,x15,y15,z15,c15,x16,y16,z16);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,16) cordic_stage16 (clock,reset,enable,x16,y16,z16,c16,x17,y17,z17);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,17) cordic_stage17 (clock,reset,enable,x17,y17,z17,c17,x18,y18,z18);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,18) cordic_stage18 (clock,reset,enable,x18,y18,z18,c18,x19,y19,z19);
|
||||
cordic_stage #(bitwidth+2,zwidth-1,19) cordic_stage19 (clock,reset,enable,x19,y19,z19,c19,x20,y20,z20);
|
||||
|
||||
assign xo = x20[bitwidth:1];
|
||||
assign yo = y20[bitwidth:1];
|
||||
assign zo = z20;
|
||||
|
||||
endmodule // cordic
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
//
|
||||
// Copyright 2011-2014 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//! The USRP digital down-conversion chain
|
||||
|
||||
module ddc_chain
|
||||
#(
|
||||
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 [WIDTH-1:0] i_hb1, q_hb1;
|
||||
wire [WIDTH-1:0] i_hb2, q_hb2;
|
||||
|
||||
wire strobe_cic, strobe_hb1, strobe_hb2;
|
||||
wire enable_hb1, enable_hb2;
|
||||
wire [7:0] cic_decim_rate;
|
||||
|
||||
reg [WIDTH-1:0] rx_fe_i_mux, rx_fe_q_mux;
|
||||
wire realmode;
|
||||
wire swap_iq;
|
||||
wire invert_i;
|
||||
wire invert_q;
|
||||
|
||||
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({enable_hb1, enable_hb2, cic_decim_rate}),.changed());
|
||||
|
||||
setting_reg #(.my_addr(BASE+3), .width(4)) sr_3
|
||||
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||
.in(set_data),.out({invert_i,inver_q,realmode,swap_iq}),.changed());
|
||||
|
||||
// MUX so we can do realmode signals on either input
|
||||
|
||||
always @(posedge clk)
|
||||
if(swap_iq)
|
||||
begin
|
||||
rx_fe_i_mux <= invert_i ? ~rx_fe_q + 1 : rx_fe_q;
|
||||
rx_fe_q_mux <= realmode ? 0 : invert_q ? ~rx_fe_i + 1 : rx_fe_i;
|
||||
end
|
||||
else
|
||||
begin
|
||||
rx_fe_i_mux <= invert_i ? ~rx_fe_i + 1 : rx_fe_i;
|
||||
rx_fe_q_mux <= realmode ? 0 : invert_i ? ~rx_fe_q + 1 : 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_i
|
||||
(.clk(clk), .in(i_cordic), .strobe_in(1'b1), .out(i_cordic_clip));
|
||||
clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_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),.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));
|
||||
|
||||
// First (small) halfband 24 bit I/O
|
||||
small_hb_dec #(.WIDTH(WIDTH)) small_hb_i
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
|
||||
.stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1));
|
||||
|
||||
small_hb_dec #(.WIDTH(WIDTH)) small_hb_q
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run),
|
||||
.stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1));
|
||||
|
||||
// Second (large) halfband 24 bit I/O
|
||||
wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate};
|
||||
hb_dec #(.WIDTH(WIDTH)) hb_i
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
|
||||
.stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2));
|
||||
|
||||
hb_dec #(.WIDTH(WIDTH)) hb_q
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb),
|
||||
.stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2));
|
||||
|
||||
//scalar operation (gain of 6 bits)
|
||||
wire [35:0] prod_i, prod_q;
|
||||
|
||||
MULT18X18S mult_i
|
||||
(.P(prod_i), .A(i_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) );
|
||||
MULT18X18S mult_q
|
||||
(.P(prod_q), .A(q_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) );
|
||||
|
||||
//pipeline for the multiplier (gain of 10 bits)
|
||||
reg [WIDTH-1:0] prod_reg_i, prod_reg_q;
|
||||
reg strobe_mult;
|
||||
|
||||
always @(posedge clk) begin
|
||||
strobe_mult <= strobe_hb2;
|
||||
prod_reg_i <= prod_i[33:34-WIDTH];
|
||||
prod_reg_q <= prod_q[33:34-WIDTH];
|
||||
end
|
||||
|
||||
// Round final answer to 16 bits
|
||||
round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_i
|
||||
(.clk(clk),.reset(rst), .in(prod_reg_i),.strobe_in(strobe_mult), .out(sample[31:16]), .strobe_out(strobe));
|
||||
|
||||
round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_q
|
||||
(.clk(clk),.reset(rst), .in(prod_reg_q),.strobe_in(strobe_mult), .out(sample[15:0]), .strobe_out());
|
||||
|
||||
assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2};
|
||||
|
||||
endmodule // ddc_chain
|
||||
@@ -1,262 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@@ -1,58 +0,0 @@
|
||||
`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,146 +0,0 @@
|
||||
//
|
||||
// Copyright 2011-2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//! The USRP digital up-conversion chain
|
||||
|
||||
module duc_chain
|
||||
#(
|
||||
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,
|
||||
|
||||
// To TX frontend
|
||||
output [WIDTH-1:0] tx_fe_i,
|
||||
output [WIDTH-1:0] tx_fe_q,
|
||||
|
||||
// From TX control
|
||||
input [31:0] sample,
|
||||
input run,
|
||||
output strobe,
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
wire [17:0] scale_factor;
|
||||
wire [31:0] phase_inc;
|
||||
reg [31:0] phase;
|
||||
wire [7:0] interp_rate;
|
||||
wire [3:0] tx_femux_a, tx_femux_b;
|
||||
wire enable_hb1, enable_hb2;
|
||||
wire rate_change;
|
||||
|
||||
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({enable_hb1, enable_hb2, interp_rate}),.changed(rate_change));
|
||||
|
||||
// Strobes are all now delayed by 1 cycle for timing reasons
|
||||
wire strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre;
|
||||
reg strobe_cic = 1;
|
||||
reg strobe_hb1 = 1;
|
||||
reg strobe_hb2 = 1;
|
||||
|
||||
assign strobe = strobe_hb1;
|
||||
|
||||
cic_strober #(.WIDTH(8))
|
||||
cic_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate),
|
||||
.strobe_fast(1),.strobe_slow(strobe_cic_pre) );
|
||||
cic_strober #(.WIDTH(2))
|
||||
hb2_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb2 ? 2 : 1),
|
||||
.strobe_fast(strobe_cic_pre),.strobe_slow(strobe_hb2_pre) );
|
||||
cic_strober #(.WIDTH(2))
|
||||
hb1_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb1 ? 2 : 1),
|
||||
.strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) );
|
||||
|
||||
always @(posedge clk) strobe_hb1 <= strobe_hb1_pre;
|
||||
always @(posedge clk) strobe_hb2 <= strobe_hb2_pre;
|
||||
always @(posedge clk) strobe_cic <= strobe_cic_pre;
|
||||
|
||||
// NCO
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
phase <= 0;
|
||||
else if(~run)
|
||||
phase <= 0;
|
||||
else
|
||||
phase <= phase + phase_inc;
|
||||
|
||||
wire signed [17:0] da, db;
|
||||
wire signed [35:0] prod_i, prod_q;
|
||||
|
||||
assign tx_fe_i = prod_i[33:34-WIDTH];
|
||||
assign tx_fe_q = prod_q[33:34-WIDTH];
|
||||
|
||||
wire [17:0] i_interp, q_interp;
|
||||
|
||||
wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q;
|
||||
|
||||
wire [7:0] cpo = enable_hb2 ? ({interp_rate,1'b0}) : interp_rate;
|
||||
// Note that max CIC rate is 128, which would give an overflow on cpo if enable_hb2 is true,
|
||||
// but the default case inside hb_interp handles this
|
||||
|
||||
hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_i
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({sample[31:16], 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_i));
|
||||
hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_q
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({sample[15:0], 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_q));
|
||||
|
||||
small_hb_int #(.WIDTH(18)) small_hb_interp_i
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_i),
|
||||
.output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_i));
|
||||
small_hb_int #(.WIDTH(18)) small_hb_interp_q
|
||||
(.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_q),
|
||||
.output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q));
|
||||
|
||||
cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
|
||||
cic_interp_i(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate),
|
||||
.strobe_in(strobe_cic),.strobe_out(1),
|
||||
.signal_in(hb2_i),.signal_out(i_interp));
|
||||
|
||||
cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7))
|
||||
cic_interp_q(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate),
|
||||
.strobe_in(strobe_cic),.strobe_out(1),
|
||||
.signal_in(hb2_q),.signal_out(q_interp));
|
||||
|
||||
localparam cwidth = WIDTH; // was 18
|
||||
localparam zwidth = 24; // was 16
|
||||
|
||||
wire [cwidth-1:0] da_c, db_c;
|
||||
|
||||
cordic_z24 #(.bitwidth(cwidth))
|
||||
cordic(.clock(clk), .reset(rst), .enable(run),
|
||||
.xi({i_interp,{(cwidth-18){1'b0}}}),.yi({q_interp,{(cwidth-18){1'b0}}}),
|
||||
.zi(phase[31:32-zwidth]),
|
||||
.xo(da_c),.yo(db_c),.zo() );
|
||||
|
||||
MULT18X18S MULT18X18S_inst
|
||||
(.P(prod_i), // 36-bit multiplier output
|
||||
.A(da_c[cwidth-1:cwidth-18]), // 18-bit multiplier input
|
||||
.B(scale_factor), // 18-bit multiplier input
|
||||
.C(clk), // Clock input
|
||||
.CE(1), // Clock enable input
|
||||
.R(rst) // Synchronous reset input
|
||||
);
|
||||
|
||||
MULT18X18S MULT18X18S_inst_2
|
||||
(.P(prod_q), // 36-bit multiplier output
|
||||
.A(db_c[cwidth-1:cwidth-18]), // 18-bit multiplier input
|
||||
.B(scale_factor), // 18-bit multiplier input
|
||||
.C(clk), // Clock input
|
||||
.CE(1), // Clock enable input
|
||||
.R(rst) // Synchronous reset input
|
||||
);
|
||||
|
||||
assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run};
|
||||
|
||||
endmodule // duc_chain
|
||||
@@ -1,177 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// 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]
|
||||
// Strobe in cannot come faster than every 2nd clock cycle
|
||||
// These taps designed by halfgen4 from ldoolittle
|
||||
// myfilt = round(2^18 * halfgen4(.7/4,8))
|
||||
|
||||
module hb_dec
|
||||
#(parameter WIDTH=24)
|
||||
(input clk,
|
||||
input rst,
|
||||
input bypass,
|
||||
input run,
|
||||
input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block
|
||||
input stb_in,
|
||||
input [WIDTH-1:0] data_in,
|
||||
output reg stb_out,
|
||||
output reg [WIDTH-1:0] data_out);
|
||||
|
||||
localparam INTWIDTH = 17;
|
||||
localparam ACCWIDTH = WIDTH + 3;
|
||||
|
||||
// Round off inputs to 17 bits because of 18 bit multipliers
|
||||
wire [INTWIDTH-1:0] data_rnd;
|
||||
wire stb_rnd;
|
||||
|
||||
round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
|
||||
(.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
|
||||
|
||||
// Control
|
||||
reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d;
|
||||
wire write_odd, write_even, do_mult;
|
||||
reg odd;
|
||||
reg [2:0] phase, phase_d1;
|
||||
reg stb_out_int;
|
||||
wire clear, do_acc;
|
||||
assign do_mult = 1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst | ~run)
|
||||
odd <= 0;
|
||||
else if(stb_rnd)
|
||||
odd <= ~odd;
|
||||
|
||||
assign write_odd = stb_rnd & odd;
|
||||
assign write_even = stb_rnd & ~odd;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst | ~run)
|
||||
phase <= 0;
|
||||
else if(stb_rnd & odd)
|
||||
phase <= 1;
|
||||
else if(phase == 4)
|
||||
phase <= 0;
|
||||
else if(phase != 0)
|
||||
phase <= phase + 1;
|
||||
|
||||
always @(posedge clk)
|
||||
phase_d1 <= phase;
|
||||
|
||||
reg [15:0] stb_out_pre;
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
stb_out_pre <= 0;
|
||||
else
|
||||
stb_out_pre <= {stb_out_pre[14:0],(stb_rnd & odd)};
|
||||
|
||||
always @*
|
||||
case(phase)
|
||||
1 : begin addr_odd_a = 0; addr_odd_b = 15; end
|
||||
2 : begin addr_odd_a = 1; addr_odd_b = 14; end
|
||||
3 : begin addr_odd_a = 2; addr_odd_b = 13; end
|
||||
4 : begin addr_odd_a = 3; addr_odd_b = 12; end
|
||||
default : begin addr_odd_a = 0; addr_odd_b = 15; end
|
||||
endcase // case(phase)
|
||||
|
||||
always @*
|
||||
case(phase)
|
||||
1 : begin addr_odd_c = 4; addr_odd_d = 11; end
|
||||
2 : begin addr_odd_c = 5; addr_odd_d = 10; end
|
||||
3 : begin addr_odd_c = 6; addr_odd_d = 9; end
|
||||
4 : begin addr_odd_c = 7; addr_odd_d = 8; end
|
||||
default : begin addr_odd_c = 4; addr_odd_d = 11; end
|
||||
endcase // case(phase)
|
||||
|
||||
assign do_acc = |stb_out_pre[6:3];
|
||||
assign clear = stb_out_pre[3];
|
||||
|
||||
// Data
|
||||
wire [INTWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d;
|
||||
reg [INTWIDTH:0] sum1, sum2; // these are 18-bit inputs to mult
|
||||
reg [WIDTH:0] final_sum;
|
||||
wire [WIDTH-1:0] final_sum_clip;
|
||||
reg [17:0] coeff1, coeff2;
|
||||
wire [35:0] prod1, prod2;
|
||||
|
||||
always @* // Outer coeffs
|
||||
case(phase_d1)
|
||||
1 : coeff1 = -107;
|
||||
2 : coeff1 = 445;
|
||||
3 : coeff1 = -1271;
|
||||
4 : coeff1 = 2959;
|
||||
default : coeff1 = -107;
|
||||
endcase // case(phase)
|
||||
|
||||
always @* // Inner coeffs
|
||||
case(phase_d1)
|
||||
1 : coeff2 = -6107;
|
||||
2 : coeff2 = 11953;
|
||||
3 : coeff2 = -24706;
|
||||
4 : coeff2 = 82359;
|
||||
default : coeff2 = -6107;
|
||||
endcase // case(phase)
|
||||
|
||||
srl #(.WIDTH(INTWIDTH)) srl_odd_a
|
||||
(.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_a),.out(data_odd_a));
|
||||
srl #(.WIDTH(INTWIDTH)) srl_odd_b
|
||||
(.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_b),.out(data_odd_b));
|
||||
srl #(.WIDTH(INTWIDTH)) srl_odd_c
|
||||
(.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_c),.out(data_odd_c));
|
||||
srl #(.WIDTH(INTWIDTH)) srl_odd_d
|
||||
(.clk(clk),.write(write_odd),.in(data_rnd),.addr(addr_odd_d),.out(data_odd_d));
|
||||
|
||||
always @(posedge clk) sum1 <= {data_odd_a[INTWIDTH-1],data_odd_a} + {data_odd_b[INTWIDTH-1],data_odd_b};
|
||||
always @(posedge clk) sum2 <= {data_odd_c[INTWIDTH-1],data_odd_c} + {data_odd_d[INTWIDTH-1],data_odd_d};
|
||||
|
||||
wire [INTWIDTH-1:0] data_even;
|
||||
reg [3:0] addr_even;
|
||||
|
||||
always @(posedge clk)
|
||||
case(cpi)
|
||||
// 1 is an error
|
||||
2 : addr_even <= 9; // Maximum speed (overall decim by 4)
|
||||
3, 4, 5, 6, 7 : addr_even <= 8;
|
||||
default : addr_even <= 7;
|
||||
endcase // case(cpi)
|
||||
|
||||
srl #(.WIDTH(INTWIDTH)) srl_even
|
||||
(.clk(clk),.write(write_even),.in(data_rnd),.addr(addr_even),.out(data_even));
|
||||
|
||||
MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) );
|
||||
MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) );
|
||||
|
||||
reg [35:0] sum_of_prod;
|
||||
always @(posedge clk) sum_of_prod <= prod1 + prod2; // Can't overflow
|
||||
|
||||
wire [ACCWIDTH-1:0] acc_out;
|
||||
acc #(.IWIDTH(ACCWIDTH-2),.OWIDTH(ACCWIDTH))
|
||||
acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod[35:38-ACCWIDTH]),.out(acc_out));
|
||||
|
||||
wire [ACCWIDTH-1:0] data_even_signext;
|
||||
|
||||
localparam SHIFT_FACTOR = 6;
|
||||
|
||||
sign_extend #(.bits_in(INTWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR)) signext_data_even
|
||||
(.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR]));
|
||||
assign data_even_signext[SHIFT_FACTOR-1:0] = 0;
|
||||
|
||||
always @(posedge clk) final_sum <= acc_out + data_even_signext;
|
||||
|
||||
clip #(.bits_in(WIDTH+1), .bits_out(WIDTH)) clip (.in(final_sum), .out(final_sum_clip));
|
||||
|
||||
// Output MUX to allow for bypass
|
||||
wire selected_stb = bypass ? stb_in : stb_out_pre[8];
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
stb_out <= selected_stb;
|
||||
if(selected_stb)
|
||||
data_out <= bypass ? data_in : final_sum_clip;
|
||||
end
|
||||
|
||||
endmodule // hb_dec
|
||||
@@ -1,165 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// 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]
|
||||
// Strobe in cannot come faster than every 4th clock cycle,
|
||||
// Strobe out cannot come faster than every 2nd clock cycle
|
||||
|
||||
// These taps designed by halfgen4 from ldoolittle
|
||||
// myfilt = round(2^18 * halfgen4(.7/4,8))
|
||||
|
||||
module hb_interp
|
||||
#(parameter IWIDTH=18, OWIDTH=18, ACCWIDTH=24)
|
||||
(input clk,
|
||||
input rst,
|
||||
input bypass,
|
||||
input [7:0] cpo, // Clocks per output, must be at least 2
|
||||
input stb_in,
|
||||
input [IWIDTH-1:0] data_in,
|
||||
input stb_out,
|
||||
output reg [OWIDTH-1:0] data_out);
|
||||
|
||||
localparam MWIDTH = ACCWIDTH-2;
|
||||
localparam CWIDTH = 18;
|
||||
|
||||
reg [CWIDTH-1:0] coeff1, coeff2;
|
||||
reg [3:0] addr_a, addr_b, addr_c, addr_d, addr_e;
|
||||
wire [IWIDTH-1:0] data_a, data_b, data_c, data_d, data_e, sum1, sum2;
|
||||
wire [35:0] prod1, prod2;
|
||||
|
||||
reg [2:0] phase, phase_d1, phase_d2, phase_d3, phase_d4, phase_d5;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
phase <= 0;
|
||||
else
|
||||
if(stb_in)
|
||||
phase <= 1;
|
||||
else if(phase==4)
|
||||
phase <= 0;
|
||||
else if(phase!=0)
|
||||
phase <= phase + 1;
|
||||
always @(posedge clk) phase_d1 <= phase;
|
||||
always @(posedge clk) phase_d2 <= phase_d1;
|
||||
always @(posedge clk) phase_d3 <= phase_d2;
|
||||
always @(posedge clk) phase_d4 <= phase_d3;
|
||||
always @(posedge clk) phase_d5 <= phase_d4;
|
||||
|
||||
srl #(.WIDTH(IWIDTH)) srl_a
|
||||
(.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_a),.out(data_a));
|
||||
srl #(.WIDTH(IWIDTH)) srl_b
|
||||
(.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_b),.out(data_b));
|
||||
srl #(.WIDTH(IWIDTH)) srl_c
|
||||
(.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_c),.out(data_c));
|
||||
srl #(.WIDTH(IWIDTH)) srl_d
|
||||
(.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_d),.out(data_d));
|
||||
srl #(.WIDTH(IWIDTH)) srl_e
|
||||
(.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_e),.out(data_e));
|
||||
|
||||
always @*
|
||||
case(phase)
|
||||
1 : begin addr_a = 0; addr_b = 15; end
|
||||
2 : begin addr_a = 1; addr_b = 14; end
|
||||
3 : begin addr_a = 2; addr_b = 13; end
|
||||
4 : begin addr_a = 3; addr_b = 12; end
|
||||
default : begin addr_a = 0; addr_b = 15; end
|
||||
endcase // case(phase)
|
||||
|
||||
always @*
|
||||
case(phase)
|
||||
1 : begin addr_c = 4; addr_d = 11; end
|
||||
2 : begin addr_c = 5; addr_d = 10; end
|
||||
3 : begin addr_c = 6; addr_d = 9; end
|
||||
4 : begin addr_c = 7; addr_d = 8; end
|
||||
default : begin addr_c = 4; addr_d = 11; end
|
||||
endcase // case(phase)
|
||||
|
||||
always @*
|
||||
case(cpo)
|
||||
2 : addr_e <= 9;
|
||||
3,4,5,6,7,8 : addr_e <= 8;
|
||||
default : addr_e <= 7; // This case works for 256, which = 0 due to overflow outside this block
|
||||
endcase // case(cpo)
|
||||
|
||||
always @* // Outer coeffs
|
||||
case(phase_d1)
|
||||
1 : coeff1 = -107;
|
||||
2 : coeff1 = 445;
|
||||
3 : coeff1 = -1271;
|
||||
4 : coeff1 = 2959;
|
||||
default : coeff1 = -107;
|
||||
endcase // case(phase)
|
||||
|
||||
always @* // Inner coeffs
|
||||
case(phase_d1)
|
||||
1 : coeff2 = -6107;
|
||||
2 : coeff2 = 11953;
|
||||
3 : coeff2 = -24706;
|
||||
4 : coeff2 = 82359;
|
||||
default : coeff2 = -6107;
|
||||
endcase // case(phase)
|
||||
|
||||
add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_a),.in2(data_b),.sum(sum1));
|
||||
add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_c),.in2(data_d),.sum(sum2));
|
||||
// sum1, sum2 available on phase_d1
|
||||
|
||||
wire do_mult = 1;
|
||||
MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) );
|
||||
MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) );
|
||||
// prod1, prod2 available on phase_d2
|
||||
|
||||
wire [MWIDTH-1:0] sum_of_prod;
|
||||
|
||||
add2_and_round_reg #(.WIDTH(MWIDTH))
|
||||
add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod));
|
||||
// sum_of_prod available on phase_d3
|
||||
|
||||
wire [ACCWIDTH-1:0] acc_out;
|
||||
|
||||
wire clear = (phase_d3 == 1);
|
||||
wire do_acc = (phase_d3 != 0);
|
||||
|
||||
acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH)) //IJB rst
|
||||
acc (.clk(clk),.clear(rst|clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out));
|
||||
// acc_out available on phase_d4
|
||||
|
||||
wire [ACCWIDTH-6:0] clipped_acc;
|
||||
clip #(.bits_in(ACCWIDTH),.bits_out(ACCWIDTH-5)) final_clip(.in(acc_out),.out(clipped_acc));
|
||||
|
||||
reg [ACCWIDTH-6:0] clipped_reg;
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
clipped_reg <= 0;
|
||||
else if(phase_d4 == 4)
|
||||
clipped_reg <= clipped_acc;
|
||||
// clipped_reg available on phase_d5
|
||||
|
||||
wire [OWIDTH-1:0] data_out_round;
|
||||
round #(.bits_in(ACCWIDTH-5),.bits_out(OWIDTH)) final_round (.in(clipped_reg),.out(data_out_round));
|
||||
|
||||
reg odd;
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
odd <= 0;
|
||||
else if(stb_in)
|
||||
odd <= 0;
|
||||
else if(stb_out)
|
||||
odd <= 1;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
data_out <= 0;
|
||||
else if(bypass)
|
||||
data_out <= data_in;
|
||||
else if(stb_out)
|
||||
if(odd)
|
||||
data_out <= data_e;
|
||||
else
|
||||
data_out <= data_out_round;
|
||||
|
||||
// data_out available on phase_d6
|
||||
|
||||
endmodule // hb_interp
|
||||
@@ -1,47 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2011 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
// Rounding "macro"
|
||||
// Keeps the topmost bits, does proper 2s comp round to zero (unbiased truncation)
|
||||
|
||||
module round
|
||||
#(parameter bits_in=0,
|
||||
parameter bits_out=0,
|
||||
parameter round_to_zero=0, // original behavior
|
||||
parameter round_to_nearest=1, // lowest noise
|
||||
parameter trunc=0) // round to negative infinity
|
||||
(input [bits_in-1:0] in,
|
||||
output [bits_out-1:0] out,
|
||||
output [bits_in-bits_out:0] err);
|
||||
|
||||
wire round_corr,round_corr_trunc,round_corr_rtz,round_corr_nearest,round_corr_nearest_safe;
|
||||
|
||||
assign round_corr_trunc = 0;
|
||||
assign round_corr_rtz = (in[bits_in-1] & |in[bits_in-bits_out-1:0]);
|
||||
assign round_corr_nearest = in[bits_in-bits_out-1];
|
||||
|
||||
generate
|
||||
if(bits_in-bits_out > 1)
|
||||
assign round_corr_nearest_safe = (~in[bits_in-1] & (&in[bits_in-2:bits_out])) ? 0 :
|
||||
round_corr_nearest;
|
||||
else
|
||||
assign round_corr_nearest_safe = round_corr_nearest;
|
||||
endgenerate
|
||||
|
||||
|
||||
assign round_corr = round_to_nearest ? round_corr_nearest_safe :
|
||||
trunc ? round_corr_trunc :
|
||||
round_to_zero ? round_corr_rtz :
|
||||
0; // default to trunc
|
||||
|
||||
assign out = in[bits_in-1:bits_in-bits_out] + round_corr;
|
||||
|
||||
assign err = in - {out,{(bits_in-bits_out){1'b0}}};
|
||||
|
||||
endmodule // round
|
||||
@@ -1,32 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2008 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
// Rounding "macro"
|
||||
// Keeps the topmost bits, does proper 2s comp rounding (round-to-zero)
|
||||
|
||||
module round_reg
|
||||
#(parameter bits_in=0,
|
||||
parameter bits_out=0)
|
||||
(input clk,
|
||||
input [bits_in-1:0] in,
|
||||
output reg [bits_out-1:0] out,
|
||||
output reg [bits_in-bits_out:0] err);
|
||||
|
||||
wire [bits_out-1:0] temp;
|
||||
wire [bits_in-bits_out:0] err_temp;
|
||||
|
||||
round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp), .err(err_temp));
|
||||
|
||||
always @(posedge clk)
|
||||
out <= temp;
|
||||
|
||||
always @(posedge clk)
|
||||
err <= err_temp;
|
||||
|
||||
endmodule // round_reg
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
|
||||
module round_sd
|
||||
#(parameter WIDTH_IN=18,
|
||||
parameter WIDTH_OUT=16,
|
||||
parameter DISABLE_SD=0)
|
||||
(input clk, input reset,
|
||||
input [WIDTH_IN-1:0] in, input strobe_in,
|
||||
output [WIDTH_OUT-1:0] out, output strobe_out);
|
||||
|
||||
localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1;
|
||||
|
||||
wire [ERR_WIDTH-1:0] err;
|
||||
wire [WIDTH_IN-1:0] err_ext, sum;
|
||||
|
||||
sign_extend #(.bits_in(ERR_WIDTH),.bits_out(WIDTH_IN)) ext_err (.in(err), .out(err_ext));
|
||||
|
||||
add2_and_clip_reg #(.WIDTH(WIDTH_IN)) add2_and_clip_reg
|
||||
(.clk(clk), .rst(reset), .in1(in), .in2((DISABLE_SD == 0) ? err_ext : 0), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_out));
|
||||
|
||||
round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out), .err(err));
|
||||
|
||||
endmodule // round_sd
|
||||
@@ -1,46 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
module rx_dcoffset
|
||||
#(parameter WIDTH=16,
|
||||
parameter ADDR=8'd0,
|
||||
parameter alpha_shift=20)
|
||||
(input clk, input rst,
|
||||
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||
input [WIDTH-1:0] in, output [WIDTH-1:0] out);
|
||||
|
||||
wire set_now = set_stb & (ADDR == set_addr);
|
||||
|
||||
reg fixed; // uses fixed offset
|
||||
wire [WIDTH-1:0] fixed_dco;
|
||||
|
||||
localparam int_width = WIDTH + alpha_shift;
|
||||
reg [int_width-1:0] integrator;
|
||||
wire [WIDTH-1:0] quantized;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
begin
|
||||
fixed <= 0;
|
||||
integrator <= {int_width{1'b0}};
|
||||
end
|
||||
else if(set_now)
|
||||
begin
|
||||
fixed <= set_data[31];
|
||||
if(set_data[30])
|
||||
integrator <= {set_data[29:0],{(int_width-30){1'b0}}};
|
||||
end
|
||||
else if(~fixed)
|
||||
integrator <= integrator + {{(alpha_shift){out[WIDTH-1]}},out};
|
||||
|
||||
round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd
|
||||
(.clk(clk), .reset(rst), .in(integrator), .strobe_in(1'b1), .out(quantized), .strobe_out());
|
||||
|
||||
add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg
|
||||
(.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(1'b1), .sum(out), .strobe_out());
|
||||
|
||||
endmodule // rx_dcoffset
|
||||
@@ -1,74 +0,0 @@
|
||||
|
||||
module rx_frontend
|
||||
#(parameter BASE = 0,
|
||||
parameter IQCOMP_EN = 1)
|
||||
(input clk, input rst,
|
||||
input set_stb, input [7:0] set_addr, input [31:0] set_data,
|
||||
|
||||
input [15:0] adc_a, input adc_ovf_a,
|
||||
input [15:0] adc_b, input adc_ovf_b,
|
||||
|
||||
output [23:0] i_out, output [23:0] q_out,
|
||||
input run,
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
reg [15:0] adc_i, adc_q;
|
||||
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
|
||||
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||
.in(set_data),.out(swap_iq),.changed());
|
||||
|
||||
always @(posedge clk)
|
||||
if(swap_iq) // Swap
|
||||
{adc_i,adc_q} <= {adc_b,adc_a};
|
||||
else
|
||||
{adc_i,adc_q} <= {adc_a,adc_b};
|
||||
|
||||
setting_reg #(.my_addr(BASE+1),.width(18)) sr_1
|
||||
(.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
|
||||
.in(set_data),.out(mag_corr),.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(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
|
||||
MULT18X18S mult_mag_corr
|
||||
(.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[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), .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), .in2(corr_q[35:12]), .strobe_in(1'b1),
|
||||
.sum(q_out), .strobe_out());
|
||||
end // if (IQCOMP_EN == 1)
|
||||
else
|
||||
begin
|
||||
assign i_out = adc_i_ofs;
|
||||
assign q_out = adc_q_ofs;
|
||||
end // else: !if(IQCOMP_EN == 1)
|
||||
endgenerate
|
||||
|
||||
endmodule // rx_frontend
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
`timescale 1ns/1ns
|
||||
module rx_frontend_tb();
|
||||
|
||||
reg clk, rst;
|
||||
|
||||
initial rst = 1;
|
||||
initial #1000 rst = 0;
|
||||
initial clk = 0;
|
||||
always #5 clk = ~clk;
|
||||
|
||||
initial $dumpfile("rx_frontend_tb.vcd");
|
||||
initial $dumpvars(0,rx_frontend_tb);
|
||||
|
||||
reg [15:0] adc_in;
|
||||
wire [23:0] adc_out;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if(adc_in[15])
|
||||
$write("-%d,",-adc_in);
|
||||
else
|
||||
$write("%d,",adc_in);
|
||||
if(adc_out[23])
|
||||
$write("-%d\n",-adc_out);
|
||||
else
|
||||
$write("%d\n",adc_out);
|
||||
end
|
||||
|
||||
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),
|
||||
.adc_b(0), .adc_ovf_b(0),
|
||||
.i_out(adc_out),.q_out(),
|
||||
.run(), .debug());
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
adc_in <= 0;
|
||||
else
|
||||
adc_in <= adc_in + 4;
|
||||
//adc_in <= (($random % 473) + 23)/4;
|
||||
|
||||
endmodule // rx_frontend_tb
|
||||
@@ -1,23 +0,0 @@
|
||||
// -*- verilog -*-
|
||||
//
|
||||
// USRP - Universal Software Radio Peripheral
|
||||
//
|
||||
// Copyright (C) 2003 Matt Ettus
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
|
||||
// Sign extension "macro"
|
||||
// bits_out should be greater than bits_in
|
||||
|
||||
module sign_extend (in,out);
|
||||
parameter bits_in=0; // FIXME Quartus insists on a default
|
||||
parameter bits_out=0;
|
||||
|
||||
input [bits_in-1:0] in;
|
||||
output [bits_out-1:0] out;
|
||||
|
||||
assign out = {{(bits_out-bits_in){in[bits_in-1]}},in};
|
||||
|
||||
endmodule
|
||||
@@ -1,124 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// Short halfband decimator (intended to be followed by another stage)
|
||||
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
|
||||
//
|
||||
// These taps designed by halfgen4 from ldoolittle:
|
||||
// 2 * 131072 * halfgen4(.75/8,2)
|
||||
module small_hb_dec
|
||||
#(parameter WIDTH=18)
|
||||
(input clk,
|
||||
input rst,
|
||||
input bypass,
|
||||
input run,
|
||||
input stb_in,
|
||||
input [WIDTH-1:0] data_in,
|
||||
output reg stb_out,
|
||||
output reg [WIDTH-1:0] data_out);
|
||||
|
||||
// Round off inputs to 17 bits because of 18 bit multipliers
|
||||
localparam INTWIDTH = 17;
|
||||
wire [INTWIDTH-1:0] data_rnd;
|
||||
wire stb_rnd;
|
||||
|
||||
round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in
|
||||
(.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd));
|
||||
|
||||
|
||||
reg stb_rnd_d1;
|
||||
reg [INTWIDTH-1:0] data_rnd_d1;
|
||||
always @(posedge clk) stb_rnd_d1 <= stb_rnd;
|
||||
always @(posedge clk) data_rnd_d1 <= data_rnd;
|
||||
|
||||
wire go;
|
||||
reg phase, go_d1, go_d2, go_d3, go_d4;
|
||||
always @(posedge clk)
|
||||
if(rst | ~run)
|
||||
phase <= 0;
|
||||
else if(stb_rnd_d1)
|
||||
phase <= ~phase;
|
||||
assign go = stb_rnd_d1 & phase;
|
||||
always @(posedge clk)
|
||||
if(rst | ~run)
|
||||
begin
|
||||
go_d1 <= 0;
|
||||
go_d2 <= 0;
|
||||
go_d3 <= 0;
|
||||
go_d4 <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
go_d1 <= go;
|
||||
go_d2 <= go_d1;
|
||||
go_d3 <= go_d2;
|
||||
go_d4 <= go_d3;
|
||||
end
|
||||
|
||||
wire [17:0] coeff_a = -10690;
|
||||
wire [17:0] coeff_b = 75809;
|
||||
|
||||
reg [INTWIDTH-1:0] d1, d2, d3, d4 , d5, d6;
|
||||
always @(posedge clk)
|
||||
if(stb_rnd_d1 | rst)
|
||||
begin
|
||||
d1 <= data_rnd_d1;
|
||||
d2 <= d1;
|
||||
d3 <= d2;
|
||||
d4 <= d3;
|
||||
d5 <= d4;
|
||||
d6 <= d5;
|
||||
end
|
||||
|
||||
reg [17:0] sum_a, sum_b, middle, middle_d1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(go)
|
||||
begin
|
||||
sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6};
|
||||
sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4};
|
||||
//middle <= {d3[INTWIDTH-1],d3};
|
||||
middle <= {d3,1'b0};
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
if(go_d1)
|
||||
middle_d1 <= middle;
|
||||
|
||||
wire [17:0] sum = go_d1 ? sum_b : sum_a;
|
||||
wire [17:0] coeff = go_d1 ? coeff_b : coeff_a;
|
||||
wire [35:0] prod;
|
||||
MULT18X18S mult(.C(clk), .CE(go_d1 | go_d2), .R(rst), .P(prod), .A(coeff), .B(sum) );
|
||||
|
||||
localparam ACCWIDTH = 30;
|
||||
reg [ACCWIDTH-1:0] accum;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
accum <= 0;
|
||||
else if(go_d2)
|
||||
accum <= {middle_d1[17],middle_d1[17],middle_d1,{(16+ACCWIDTH-36){1'b0}}} + {prod[35:36-ACCWIDTH]};
|
||||
else if(go_d3)
|
||||
accum <= accum + {prod[35:36-ACCWIDTH]};
|
||||
|
||||
wire [WIDTH:0] accum_rnd;
|
||||
wire [WIDTH-1:0] accum_rnd_clip;
|
||||
|
||||
wire stb_round;
|
||||
|
||||
round_sd #(.WIDTH_IN(ACCWIDTH),.WIDTH_OUT(WIDTH+1)) round_acc
|
||||
(.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round));
|
||||
|
||||
clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip));
|
||||
|
||||
// Output
|
||||
always @(posedge clk)
|
||||
begin
|
||||
stb_out <= bypass ? stb_in : stb_round;
|
||||
data_out <= bypass ? data_in : accum_rnd_clip;
|
||||
end
|
||||
|
||||
|
||||
endmodule // small_hb_dec
|
||||
@@ -1,99 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// Short halfband decimator (intended to be followed by another stage)
|
||||
// Implements impulse responses of the form [A 0 B 0.5 B 0 A]
|
||||
//
|
||||
// These taps designed by halfgen4 from ldoolittle:
|
||||
// 2 * 131072 * halfgen4(.75/8,2)
|
||||
|
||||
module small_hb_int
|
||||
#(parameter WIDTH=18)
|
||||
(input clk,
|
||||
input rst,
|
||||
input bypass,
|
||||
input stb_in,
|
||||
input [WIDTH-1:0] data_in,
|
||||
input [7:0] output_rate,
|
||||
input stb_out,
|
||||
output reg [WIDTH-1:0] data_out);
|
||||
|
||||
|
||||
reg [WIDTH-1:0] d1, d2, d3, d4, d5, d6;
|
||||
|
||||
localparam MWIDTH = 36;
|
||||
wire [MWIDTH-1:0] prod;
|
||||
|
||||
reg [6:0] stbin_d;
|
||||
|
||||
always @(posedge clk)
|
||||
stbin_d <= {stbin_d[5:0],stb_in};
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
begin
|
||||
d1 <= 0;
|
||||
d2 <= 0;
|
||||
d3 <= 0;
|
||||
d4 <= 0;
|
||||
d5 <= 0;
|
||||
d6 <= 0;
|
||||
end
|
||||
else if(stb_in)
|
||||
begin
|
||||
d1 <= data_in;
|
||||
d2 <= d1;
|
||||
d3 <= d2;
|
||||
d4 <= d3;
|
||||
d5 <= d4;
|
||||
d6 <= d5;
|
||||
end
|
||||
|
||||
wire [WIDTH-1:0] sum_outer, sum_inner;
|
||||
add2_and_round_reg #(.WIDTH(WIDTH)) add_outer (.clk(clk),.in1(d1),.in2(d4),.sum(sum_outer));
|
||||
add2_and_round_reg #(.WIDTH(WIDTH)) add_inner (.clk(clk),.in1(d2),.in2(d3),.sum(sum_inner));
|
||||
|
||||
wire [17:0] coeff_outer = -10690;
|
||||
wire [17:0] coeff_inner = 75809;
|
||||
|
||||
MULT18X18S mult(.C(clk), .CE(1), .R(rst), .P(prod), .A(stbin_d[1] ? coeff_outer : coeff_inner),
|
||||
.B(stbin_d[1] ? sum_outer : sum_inner) );
|
||||
|
||||
wire [MWIDTH:0] accum;
|
||||
acc #(.IWIDTH(MWIDTH),.OWIDTH(MWIDTH+1))
|
||||
acc (.clk(clk),.clear(stbin_d[2]),.acc(|stbin_d[3:2]),.in(prod),.out(accum));
|
||||
|
||||
wire [WIDTH+2:0] accum_rnd;
|
||||
round_reg #(.bits_in(MWIDTH+1),.bits_out(WIDTH+3))
|
||||
final_round (.clk(clk),.in(accum),.out(accum_rnd));
|
||||
|
||||
wire [WIDTH-1:0] clipped;
|
||||
clip_reg #(.bits_in(WIDTH+3),.bits_out(WIDTH)) final_clip
|
||||
(.clk(clk),.in(accum_rnd),.strobe_in(1'b1), .out(clipped));
|
||||
|
||||
reg [WIDTH-1:0] saved, saved_d3;
|
||||
always @(posedge clk)
|
||||
if(stbin_d[6])
|
||||
saved <= clipped;
|
||||
|
||||
always @(posedge clk)
|
||||
if(stbin_d[3])
|
||||
saved_d3 <= d3;
|
||||
|
||||
always @(posedge clk)
|
||||
if(bypass)
|
||||
data_out <= data_in;
|
||||
else if(stb_in & stb_out)
|
||||
case(output_rate)
|
||||
1 : data_out <= d6;
|
||||
2 : data_out <= d4;
|
||||
3, 4, 5, 6, 7 : data_out <= d3;
|
||||
default : data_out <= d2;
|
||||
endcase // case(output_rate)
|
||||
else if(stb_out)
|
||||
data_out <= saved;
|
||||
|
||||
endmodule // small_hb_int
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module srl
|
||||
#(parameter WIDTH=18)
|
||||
(input clk,
|
||||
input rst,
|
||||
input write,
|
||||
input [WIDTH-1:0] in,
|
||||
input [3:0] addr,
|
||||
output [WIDTH-1:0] out);
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i=0;i<WIDTH;i=i+1)
|
||||
begin : gen_srl
|
||||
SRL16E
|
||||
srl16e(.Q(out[i]),
|
||||
.A0(addr[0]),.A1(addr[1]),.A2(addr[2]),.A3(addr[3]),
|
||||
.CE(write|rst),.CLK(clk),.D(in[i]));
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule // srl
|
||||
@@ -1,97 +0,0 @@
|
||||
|
||||
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,21 +0,0 @@
|
||||
#
|
||||
# Copyright 2012-2013 Ettus Research LLC
|
||||
#
|
||||
|
||||
##################################################
|
||||
# FIFO Sources
|
||||
##################################################
|
||||
FIFO_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/fifo/, \
|
||||
axi_mux4.v \
|
||||
axi_mux8.v \
|
||||
axi_demux4.v \
|
||||
axi_demux8.v \
|
||||
axi_fifo_short.v \
|
||||
axi_packet_gate.v \
|
||||
axi_fifo.v \
|
||||
axi_fifo64_to_fifo32.v \
|
||||
axi_fifo32_to_fifo64.v \
|
||||
axi_fifo_2clk.v \
|
||||
axi_loopback.v \
|
||||
axi_filter_mux4.v \
|
||||
))
|
||||
@@ -1,77 +0,0 @@
|
||||
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
// axi_demux -- takes one AXI stream, sends to one of 4 output channels
|
||||
// Choice of output channel is by external logic based on first line of packet ("header" port)
|
||||
// If compressed vita data, this line contains vita header and streamid.
|
||||
|
||||
module axi_demux4
|
||||
#(parameter ACTIVE_CHAN = 4'b1111, // ACTIVE_CHAN is a map of connected outputs
|
||||
parameter WIDTH = 64,
|
||||
parameter BUFFER=0)
|
||||
(input clk, input reset, input clear,
|
||||
output [WIDTH-1:0] header, input [1:0] dest,
|
||||
input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
|
||||
output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
|
||||
output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
|
||||
output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
|
||||
output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready);
|
||||
|
||||
wire [WIDTH-1:0] i_tdata_int;
|
||||
wire i_tlast_int, i_tvalid_int, i_tready_int;
|
||||
|
||||
generate
|
||||
if(BUFFER == 0)
|
||||
begin
|
||||
assign i_tdata_int = i_tdata;
|
||||
assign i_tlast_int = i_tlast;
|
||||
assign i_tvalid_int = i_tvalid;
|
||||
assign i_tready = i_tready_int;
|
||||
end
|
||||
else
|
||||
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short
|
||||
(.clk(clk), .reset(reset), .clear(clear),
|
||||
.i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o_tdata({i_tlast_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int),
|
||||
.space(), .occupied());
|
||||
endgenerate
|
||||
|
||||
reg [3:0] dm_state;
|
||||
localparam DM_IDLE = 4'b0000;
|
||||
localparam DM_0 = 4'b0001;
|
||||
localparam DM_1 = 4'b0010;
|
||||
localparam DM_2 = 4'b0100;
|
||||
localparam DM_3 = 4'b1000;
|
||||
|
||||
assign header = i_tdata_int;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
dm_state <= DM_IDLE;
|
||||
else
|
||||
case (dm_state)
|
||||
DM_IDLE :
|
||||
if(i_tvalid_int)
|
||||
case(dest)
|
||||
2'b00 : dm_state <= DM_0;
|
||||
2'b01 : dm_state <= DM_1;
|
||||
2'b10 : dm_state <= DM_2;
|
||||
2'b11 : dm_state <= DM_3;
|
||||
endcase // case (i_tdata[1:0])
|
||||
|
||||
DM_0, DM_1, DM_2, DM_3 :
|
||||
if(i_tvalid_int & i_tready_int & i_tlast_int)
|
||||
dm_state <= DM_IDLE;
|
||||
|
||||
default :
|
||||
dm_state <= DM_IDLE;
|
||||
endcase // case (dm_state)
|
||||
|
||||
assign {o3_tvalid, o2_tvalid, o1_tvalid, o0_tvalid} = dm_state & {4{i_tvalid_int}};
|
||||
assign i_tready_int = |(dm_state & ({o3_tready, o2_tready, o1_tready, o0_tready} | ~ACTIVE_CHAN));
|
||||
|
||||
assign {o0_tlast, o0_tdata} = {i_tlast_int, i_tdata_int};
|
||||
assign {o1_tlast, o1_tdata} = {i_tlast_int, i_tdata_int};
|
||||
assign {o2_tlast, o2_tdata} = {i_tlast_int, i_tdata_int};
|
||||
assign {o3_tlast, o3_tdata} = {i_tlast_int, i_tdata_int};
|
||||
|
||||
endmodule // axi_demux4
|
||||
@@ -1,60 +0,0 @@
|
||||
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
// axi_demux -- takes one AXI stream, sends to one of 8 output channels
|
||||
// Choice of output channel is by external logic based on first line of packet ("header" port)
|
||||
// If compressed vita data, this line contains vita header and streamid.
|
||||
|
||||
module axi_demux8 #(
|
||||
parameter ACTIVE_CHAN = 8'b11111111, // ACTIVE_CHAN is a map of connected outputs
|
||||
parameter WIDTH = 64,
|
||||
parameter BUFFER=0
|
||||
) (
|
||||
input clk, input reset, input clear,
|
||||
output [WIDTH-1:0] header, input [2:0] dest,
|
||||
input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
|
||||
output [WIDTH-1:0] o0_tdata, output o0_tlast, output o0_tvalid, input o0_tready,
|
||||
output [WIDTH-1:0] o1_tdata, output o1_tlast, output o1_tvalid, input o1_tready,
|
||||
output [WIDTH-1:0] o2_tdata, output o2_tlast, output o2_tvalid, input o2_tready,
|
||||
output [WIDTH-1:0] o3_tdata, output o3_tlast, output o3_tvalid, input o3_tready,
|
||||
output [WIDTH-1:0] o4_tdata, output o4_tlast, output o4_tvalid, input o4_tready,
|
||||
output [WIDTH-1:0] o5_tdata, output o5_tlast, output o5_tvalid, input o5_tready,
|
||||
output [WIDTH-1:0] o6_tdata, output o6_tlast, output o6_tvalid, input o6_tready,
|
||||
output [WIDTH-1:0] o7_tdata, output o7_tlast, output o7_tvalid, input o7_tready
|
||||
);
|
||||
|
||||
wire [WIDTH-1:0] i_tdata_int0, i_tdata_int1;
|
||||
wire i_tlast_int0, i_tlast_int1;
|
||||
wire i_tvalid_int0, i_tvalid_int1;
|
||||
wire i_tready_int0, i_tready_int1;
|
||||
|
||||
axi_demux4 #(.ACTIVE_CHAN({2'b00, (|(ACTIVE_CHAN[7:4])), (|(ACTIVE_CHAN[3:0]))}), .WIDTH(WIDTH), .BUFFER(BUFFER)) demux2 (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.header(header), .dest({1'b0, dest[2]}),
|
||||
.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o0_tdata(i_tdata_int0), .o0_tlast(i_tlast_int0), .o0_tvalid(i_tvalid_int0), .o0_tready(i_tready_int0),
|
||||
.o1_tdata(i_tdata_int1), .o1_tlast(i_tlast_int1), .o1_tvalid(i_tvalid_int1), .o1_tready(i_tready_int1),
|
||||
.o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b0),
|
||||
.o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b0)
|
||||
);
|
||||
|
||||
axi_demux4 #(.ACTIVE_CHAN(ACTIVE_CHAN[3:0]), .WIDTH(WIDTH), .BUFFER(0)) demux4_int0 (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.header(), .dest(dest[1:0]),
|
||||
.i_tdata(i_tdata_int0), .i_tlast(i_tlast_int0), .i_tvalid(i_tvalid_int0), .i_tready(i_tready_int0),
|
||||
.o0_tdata(o0_tdata), .o0_tlast(o0_tlast), .o0_tvalid(o0_tvalid), .o0_tready(o0_tready),
|
||||
.o1_tdata(o1_tdata), .o1_tlast(o1_tlast), .o1_tvalid(o1_tvalid), .o1_tready(o1_tready),
|
||||
.o2_tdata(o2_tdata), .o2_tlast(o2_tlast), .o2_tvalid(o2_tvalid), .o2_tready(o2_tready),
|
||||
.o3_tdata(o3_tdata), .o3_tlast(o3_tlast), .o3_tvalid(o3_tvalid), .o3_tready(o3_tready)
|
||||
);
|
||||
|
||||
axi_demux4 #(.ACTIVE_CHAN(ACTIVE_CHAN[7:4]), .WIDTH(WIDTH), .BUFFER(0)) demux4_int1 (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.header(), .dest(dest[1:0]),
|
||||
.i_tdata(i_tdata_int1), .i_tlast(i_tlast_int1), .i_tvalid(i_tvalid_int1), .i_tready(i_tready_int1),
|
||||
.o0_tdata(o4_tdata), .o0_tlast(o4_tlast), .o0_tvalid(o4_tvalid), .o0_tready(o4_tready),
|
||||
.o1_tdata(o5_tdata), .o1_tlast(o5_tlast), .o1_tvalid(o5_tvalid), .o1_tready(o5_tready),
|
||||
.o2_tdata(o6_tdata), .o2_tlast(o6_tlast), .o2_tvalid(o6_tvalid), .o2_tready(o6_tready),
|
||||
.o3_tdata(o7_tdata), .o3_tlast(o7_tlast), .o3_tvalid(o7_tvalid), .o3_tready(o7_tready)
|
||||
);
|
||||
|
||||
endmodule // axi_demux4
|
||||
@@ -1,169 +0,0 @@
|
||||
//
|
||||
// Copyright 2012-2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
// Block RAM AXI fifo
|
||||
|
||||
// Special case SIZE <= 5 uses a short fifo
|
||||
|
||||
module axi_fifo
|
||||
#(parameter WIDTH=32, SIZE=9)
|
||||
(input clk, input reset, input clear,
|
||||
input [WIDTH-1:0] i_tdata,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
output [WIDTH-1:0] o_tdata,
|
||||
output o_tvalid,
|
||||
input o_tready,
|
||||
|
||||
output reg [15:0] space,
|
||||
output reg [15:0] occupied);
|
||||
|
||||
generate
|
||||
if(SIZE<=5) begin
|
||||
wire [5:0] space_short, occupied_short;
|
||||
axi_fifo_short #(.WIDTH(WIDTH)) fifo_short
|
||||
(
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
|
||||
.space(space_short), .occupied(occupied_short)
|
||||
);
|
||||
always @* space <= {10'b0, space_short};
|
||||
always @* occupied <= {10'b0, occupied_short};
|
||||
end
|
||||
else begin
|
||||
|
||||
wire write = i_tvalid & i_tready;
|
||||
wire read = o_tvalid & o_tready;
|
||||
wire full, empty;
|
||||
|
||||
assign i_tready = ~full;
|
||||
assign o_tvalid = ~empty;
|
||||
|
||||
// Read side states
|
||||
localparam EMPTY = 0;
|
||||
localparam PRE_READ = 1;
|
||||
localparam READING = 2;
|
||||
|
||||
reg [SIZE-1:0] wr_addr, rd_addr;
|
||||
reg [1:0] read_state;
|
||||
|
||||
reg empty_reg, full_reg;
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
wr_addr <= 0;
|
||||
else if(clear)
|
||||
wr_addr <= 0;
|
||||
else if(write)
|
||||
wr_addr <= wr_addr + 1;
|
||||
|
||||
ram_2port #(.DWIDTH(WIDTH),.AWIDTH(SIZE))
|
||||
ram (.clka(clk),
|
||||
.ena(1'b1),
|
||||
.wea(write),
|
||||
.addra(wr_addr),
|
||||
.dia(i_tdata),
|
||||
.doa(),
|
||||
|
||||
.clkb(clk),
|
||||
.enb((read_state==PRE_READ)|read),
|
||||
.web(1'b0),
|
||||
.addrb(rd_addr),
|
||||
.dib({WIDTH{1'b1}}),
|
||||
.dob(o_tdata));
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
begin
|
||||
read_state <= EMPTY;
|
||||
rd_addr <= 0;
|
||||
empty_reg <= 1;
|
||||
end
|
||||
else
|
||||
if(clear)
|
||||
begin
|
||||
read_state <= EMPTY;
|
||||
rd_addr <= 0;
|
||||
empty_reg <= 1;
|
||||
end
|
||||
else
|
||||
case(read_state)
|
||||
EMPTY :
|
||||
if(write)
|
||||
begin
|
||||
//rd_addr <= wr_addr;
|
||||
read_state <= PRE_READ;
|
||||
end
|
||||
PRE_READ :
|
||||
begin
|
||||
read_state <= READING;
|
||||
empty_reg <= 0;
|
||||
rd_addr <= rd_addr + 1;
|
||||
end
|
||||
|
||||
READING :
|
||||
if(read)
|
||||
if(rd_addr == wr_addr)
|
||||
begin
|
||||
empty_reg <= 1;
|
||||
if(write)
|
||||
read_state <= PRE_READ;
|
||||
else
|
||||
read_state <= EMPTY;
|
||||
end
|
||||
else
|
||||
rd_addr <= rd_addr + 1;
|
||||
endcase // case(read_state)
|
||||
|
||||
wire [SIZE-1:0] dont_write_past_me = rd_addr - 2;
|
||||
wire becoming_full = wr_addr == dont_write_past_me;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
full_reg <= 0;
|
||||
else if(clear)
|
||||
full_reg <= 0;
|
||||
else if(read & ~write)
|
||||
full_reg <= 0;
|
||||
//else if(write & ~read & (wr_addr == (rd_addr-3)))
|
||||
else if(write & ~read & becoming_full)
|
||||
full_reg <= 1;
|
||||
|
||||
//assign empty = (read_state != READING);
|
||||
assign empty = empty_reg;
|
||||
|
||||
// assign full = ((rd_addr - 1) == wr_addr);
|
||||
assign full = full_reg;
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// space and occupied are for diagnostics only
|
||||
// not guaranteed exact
|
||||
|
||||
localparam NUMLINES = (1<<SIZE);
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
space <= NUMLINES;
|
||||
else if(clear)
|
||||
space <= NUMLINES;
|
||||
else if(read & ~write)
|
||||
space <= space + 16'b1;
|
||||
else if(write & ~read)
|
||||
space <= space - 16'b1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
occupied <= 16'b0;
|
||||
else if(clear)
|
||||
occupied <= 16'b0;
|
||||
else if(read & ~write)
|
||||
occupied <= occupied - 16'b1;
|
||||
else if(write & ~read)
|
||||
occupied <= occupied + 16'b1;
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule // fifo_long
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
module axi_fifo32_to_fifo64
|
||||
(input clk, input reset, input clear,
|
||||
input [31:0] i_tdata, input [1:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
|
||||
output [63:0] o_tdata, output [2:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
|
||||
);
|
||||
|
||||
reg [31:0] holding;
|
||||
|
||||
reg state;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
state <= 0;
|
||||
else
|
||||
if(i_tvalid & i_tready)
|
||||
case(state)
|
||||
0 : if(~i_tlast) state <= 1'b1;
|
||||
1 : state <= 1'b0;
|
||||
default : state <= 1'b0;
|
||||
endcase // case (state)
|
||||
|
||||
always @(posedge clk)
|
||||
if(i_tvalid & i_tready)
|
||||
holding <= i_tdata;
|
||||
|
||||
assign i_tready = (state == 0 && !i_tlast)? 1'b1 : o_tready;
|
||||
assign o_tvalid = (state == 0 && !i_tlast)? 1'b0 : i_tvalid;
|
||||
|
||||
assign o_tdata = (state == 0) ? {i_tdata, 32'h0} : { holding, i_tdata };
|
||||
assign o_tlast = i_tlast;
|
||||
|
||||
wire [2:0] occ_in = (i_tuser == 0) ? 3'd4 : {1'b0, i_tuser};
|
||||
wire [2:0] occ_out = (state == 0) ? occ_in : (occ_in + 3'd4);
|
||||
|
||||
assign o_tuser = ~o_tlast ? 3'd0 : occ_out;
|
||||
|
||||
endmodule // axi_fifo32_to_fifo64
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
module axi_fifo64_to_fifo32
|
||||
(input clk, input reset, input clear,
|
||||
input [63:0] i_tdata, input [2:0] i_tuser, input i_tlast, input i_tvalid, output i_tready,
|
||||
output [31:0] o_tdata, output [1:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
|
||||
);
|
||||
|
||||
wire short_last = i_tlast & ((i_tuser == 3'd1) | (i_tuser == 3'd2) | (i_tuser == 3'd3) | (i_tuser == 3'd4));
|
||||
|
||||
reg state;
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
state <= 1'b0;
|
||||
else
|
||||
if(i_tvalid & o_tready)
|
||||
case(state)
|
||||
1'b0 :
|
||||
if(~short_last)
|
||||
state <= 1'b1;
|
||||
1'b1 :
|
||||
state <= 1'b0;
|
||||
endcase // case (state)
|
||||
|
||||
assign o_tdata = (state == 0) ? i_tdata[63:32] : i_tdata[31:0];
|
||||
assign o_tuser = o_tlast ? i_tuser[1:0] : 2'd0;
|
||||
assign o_tlast = i_tlast & ((state == 1'b1) | short_last);
|
||||
|
||||
assign o_tvalid = i_tvalid;
|
||||
assign i_tready = o_tready & ((state == 1'b1) | short_last);
|
||||
|
||||
endmodule // axi_fifo64_to_fifo32
|
||||
@@ -1,88 +0,0 @@
|
||||
//
|
||||
// Copyright 2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// Special case SIZE <= 5 uses a short fifo
|
||||
|
||||
module axi_fifo_2clk
|
||||
#(parameter WIDTH=69, SIZE=9)
|
||||
(input reset,
|
||||
input i_aclk,
|
||||
input [WIDTH-1:0] i_tdata,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
input o_aclk,
|
||||
output [WIDTH-1:0] o_tdata,
|
||||
output o_tvalid,
|
||||
input o_tready);
|
||||
|
||||
wire write, read, empty, full;
|
||||
assign i_tready = ~full;
|
||||
assign write = i_tvalid & i_tready;
|
||||
|
||||
wire [71:0] tdata_int;
|
||||
wire tvalid_int, tready_int;
|
||||
assign tvalid_int = ~empty;
|
||||
assign read = tvalid_int & tready_int;
|
||||
|
||||
wire [71:0] wr_data;
|
||||
assign wr_data[WIDTH-1:0] = i_tdata;
|
||||
wire [71:0] rd_data;
|
||||
assign tdata_int = rd_data[WIDTH-1:0];
|
||||
|
||||
generate
|
||||
if(WIDTH<72) begin
|
||||
assign wr_data[71:WIDTH] = 0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if(SIZE<=5)
|
||||
fifo_short_2clk fifo_short_2clk
|
||||
(.rst(reset),
|
||||
.wr_clk(i_aclk),
|
||||
.din(wr_data), // input [71 : 0] din
|
||||
.wr_en(write), // input wr_en
|
||||
.full(full), // output full
|
||||
.wr_data_count(), // output [9 : 0] wr_data_count
|
||||
|
||||
.rd_clk(o_aclk), // input rd_clk
|
||||
.dout(rd_data), // output [71 : 0] dout
|
||||
.rd_en(read), // input rd_en
|
||||
.empty(empty), // output empty
|
||||
.rd_data_count() // output [9 : 0] rd_data_count
|
||||
);
|
||||
else
|
||||
fifo_4k_2clk fifo_4k_2clk
|
||||
(.rst(reset),
|
||||
.wr_clk(i_aclk),
|
||||
.din(wr_data), // input [71 : 0] din
|
||||
.wr_en(write), // input wr_en
|
||||
.full(full), // output full
|
||||
.wr_data_count(), // output [9 : 0] wr_data_count
|
||||
|
||||
.rd_clk(o_aclk), // input rd_clk
|
||||
.dout(rd_data), // output [71 : 0] dout
|
||||
.rd_en(read), // input rd_en
|
||||
.empty(empty), // output empty
|
||||
.rd_data_count() // output [9 : 0] rd_data_count
|
||||
);
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
if(SIZE>9)
|
||||
axi_fifo #(.WIDTH(WIDTH), .SIZE(SIZE)) fifo_1clk
|
||||
(.clk(o_aclk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata(tdata_int), .i_tvalid(tvalid_int), .i_tready(tready_int),
|
||||
.o_tdata(o_tdata), .o_tvalid(o_tvalid), .o_tready(o_tready),
|
||||
.space(), .occupied());
|
||||
else
|
||||
begin
|
||||
assign o_tdata = tdata_int;
|
||||
assign o_tvalid = tvalid_int;
|
||||
assign tready_int = o_tready;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule // axi_fifo_2clk
|
||||
@@ -1,114 +0,0 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module axi_fifo_32_64_tb();
|
||||
|
||||
reg clk = 0;
|
||||
reg reset = 1;
|
||||
|
||||
always #10 clk = ~clk;
|
||||
|
||||
initial $dumpfile("axi_fifo_32_64_tb.vcd");
|
||||
initial $dumpvars(0,axi_fifo_32_64_tb);
|
||||
|
||||
task send_packet;
|
||||
input [63:0] data_start;
|
||||
input [2:0] user;
|
||||
input [31:0] len;
|
||||
|
||||
begin
|
||||
@(posedge clk);
|
||||
{i_tuser, i_tlast, i_tdata} <= { 3'd0, 1'b0, data_start };
|
||||
repeat(len-1)
|
||||
begin
|
||||
i_tvalid <= 1;
|
||||
@(posedge clk);
|
||||
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
|
||||
end
|
||||
i_tuser <= user;
|
||||
i_tlast <= 1;
|
||||
@(posedge clk);
|
||||
i_tvalid <= 1'b0;
|
||||
@(posedge clk);
|
||||
end
|
||||
endtask // send_packet
|
||||
|
||||
initial
|
||||
begin
|
||||
#1000 reset = 0;
|
||||
#200000;
|
||||
$finish;
|
||||
end
|
||||
|
||||
reg [63:0] i_tdata;
|
||||
reg [2:0] i_tuser;
|
||||
reg i_tlast;
|
||||
reg i_tvalid;
|
||||
wire i_tready;
|
||||
|
||||
wire [63:0] i_tdata_int;
|
||||
wire [2:0] i_tuser_int;
|
||||
wire i_tlast_int, i_tvalid_int, i_tready_int;
|
||||
|
||||
wire [63:0] o_tdata;
|
||||
wire [31:0] o_tdata_int, o_tdata_int2;
|
||||
wire [2:0] o_tuser;
|
||||
wire [1:0] o_tuser_int, o_tuser_int2;
|
||||
wire o_tlast, o_tlast_int, o_tvalid, o_tvalid_int, o_tready, o_tready_int;
|
||||
wire o_tlast_int2, o_tvalid_int2, o_tready_int2;
|
||||
|
||||
localparam RPT_COUNT = 16;
|
||||
|
||||
initial
|
||||
begin
|
||||
i_tvalid <= 0;
|
||||
|
||||
while(reset)
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
|
||||
send_packet(64'hA0000000_A0000001, 3'd7, 4);
|
||||
@(posedge clk);
|
||||
end // initial begin
|
||||
|
||||
axi_fifo #(.WIDTH(68), .SIZE(10)) fifo
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({i_tlast,i_tuser,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o_tdata({i_tlast_int,i_tuser_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int));
|
||||
|
||||
axi_fifo64_to_fifo32 dut
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata(i_tdata_int), .i_tuser(i_tuser_int), .i_tlast(i_tlast_int), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
|
||||
.o_tdata(o_tdata_int), .o_tuser(o_tuser_int), .o_tlast(o_tlast_int), .o_tvalid(o_tvalid_int), .o_tready(o_tready_int));
|
||||
|
||||
/*
|
||||
axi_fifo #(.WIDTH(35), .SIZE(10)) fifo_middle
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({o_tlast_int,o_tuser_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
|
||||
.o_tdata({o_tlast_int2,o_tuser_int2,o_tdata_int2}), .o_tvalid(o_tvalid_int2), .o_tready(o_tready_int2));
|
||||
*/
|
||||
assign o_tdata_int2 = o_tdata_int;
|
||||
assign o_tlast_int2 = o_tlast_int;
|
||||
assign o_tuser_int2 = o_tuser_int;
|
||||
assign o_tvalid_int2 = o_tvalid_int;
|
||||
assign o_tready_int = o_tready_int2;
|
||||
|
||||
axi_fifo32_to_fifo64 dut2
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata(o_tdata_int2), .i_tuser(o_tuser_int2), .i_tlast(o_tlast_int2), .i_tvalid(o_tvalid_int2), .i_tready(o_tready_int2),
|
||||
.o_tdata(o_tdata), .o_tuser(o_tuser), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));
|
||||
|
||||
assign o_tready = 1'b1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(i_tvalid & i_tready)
|
||||
$display("IN: TUSER %x\tTLAST %x\tTDATA %x", i_tuser, i_tlast, i_tdata);
|
||||
|
||||
always @(posedge clk)
|
||||
if(o_tvalid_int & o_tready_int)
|
||||
$display("\t\t\t\t\t\tMIDDLE: TUSER %x\tTLAST %x\tTDATA %x", o_tuser_int, o_tlast_int, o_tdata_int);
|
||||
|
||||
always @(posedge clk)
|
||||
if(o_tvalid & o_tready)
|
||||
$display("\t\t\t\t\t\t\t\t\t\t\tOUT: TUSER %x\tTLAST %x\tTDATA %x", o_tuser, o_tlast, o_tdata);
|
||||
|
||||
endmodule // axi_fifo_32_64_tb
|
||||
@@ -1,110 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// 32 word FIFO with AXI4-STREAM interface.
|
||||
//
|
||||
// NOTE: This module uses the SRLC32E primitive explicitly and as such
|
||||
// can only be used with Xilinx technology of the VIRTEX-6/SPARTAN-6/SIERIES-7 or newer.
|
||||
//
|
||||
|
||||
module axi_fifo_short
|
||||
#(parameter WIDTH=32)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
input [WIDTH-1:0] i_tdata,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
output [WIDTH-1:0] o_tdata,
|
||||
output o_tvalid,
|
||||
input o_tready,
|
||||
|
||||
output reg [5:0] space,
|
||||
output reg [5:0] occupied
|
||||
);
|
||||
|
||||
reg full, empty;
|
||||
wire write = i_tvalid & i_tready;
|
||||
wire read = o_tready & o_tvalid;
|
||||
|
||||
assign i_tready = ~full;
|
||||
assign o_tvalid = ~empty;
|
||||
|
||||
reg [4:0] a;
|
||||
genvar i;
|
||||
|
||||
generate
|
||||
for (i=0;i<WIDTH;i=i+1)
|
||||
begin : gen_srlc32e
|
||||
SRLC32E
|
||||
srlc32e(.Q(o_tdata[i]), .Q31(),
|
||||
.A(a), //.A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),.A4(a[4]),
|
||||
.CE(write),.CLK(clk),.D(i_tdata[i]));
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
begin
|
||||
a <= 0;
|
||||
empty <= 1;
|
||||
full <= 0;
|
||||
end
|
||||
else if(clear)
|
||||
begin
|
||||
a <= 0;
|
||||
empty <= 1;
|
||||
full<= 0;
|
||||
end
|
||||
else if(read & ~write)
|
||||
begin
|
||||
full <= 0;
|
||||
if(a==0)
|
||||
empty <= 1;
|
||||
else
|
||||
a <= a - 1;
|
||||
end
|
||||
else if(write & ~read)
|
||||
begin
|
||||
empty <= 0;
|
||||
if(~empty)
|
||||
a <= a + 1;
|
||||
if(a == 30)
|
||||
full <= 1;
|
||||
end
|
||||
|
||||
// NOTE will fail if you write into a full fifo or read from an empty one
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// space and occupied are used for diagnostics, not
|
||||
// guaranteed correct
|
||||
|
||||
//assign space = full ? 0 : empty ? 16 : 15-a;
|
||||
//assign occupied = empty ? 0 : full ? 16 : a+1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
space <= 6'd32;
|
||||
else if(clear)
|
||||
space <= 6'd32;
|
||||
else if(read & ~write)
|
||||
space <= space + 6'd1;
|
||||
else if(write & ~read)
|
||||
space <= space - 6'd1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset)
|
||||
occupied <= 6'd0;
|
||||
else if(clear)
|
||||
occupied <= 6'd0;
|
||||
else if(read & ~write)
|
||||
occupied <= occupied - 6'd1;
|
||||
else if(write & ~read)
|
||||
occupied <= occupied + 6'd1;
|
||||
|
||||
endmodule // axi_fifo_short
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
//
|
||||
// Copyright 2012-2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
module axi_fifo_tb();
|
||||
|
||||
reg clk, reset;
|
||||
reg read_flag, write_flag;
|
||||
|
||||
reg error;
|
||||
reg [7:0] i_tdata, o_tdata_ref;
|
||||
wire [7:0] o_tdata;
|
||||
reg i_tvalid, o_tready;
|
||||
wire o_tvalid, i_tready;
|
||||
wire [15:0] space, occupied;
|
||||
|
||||
always
|
||||
#100 clk = ~clk;
|
||||
|
||||
initial clk = 0;
|
||||
|
||||
|
||||
axi_fifo
|
||||
#(
|
||||
.WIDTH(8),
|
||||
.SIZE(8)
|
||||
)
|
||||
dut
|
||||
(.clk(clk),
|
||||
.reset(reset),
|
||||
.clear(1'b0),
|
||||
.i_tdata(i_tdata),
|
||||
.i_tvalid(i_tvalid),
|
||||
.i_tready(i_tready),
|
||||
.o_tdata(o_tdata),
|
||||
.o_tvalid(o_tvalid),
|
||||
.o_tready(o_tready),
|
||||
.space(space),
|
||||
.occupied(occupied)
|
||||
);
|
||||
|
||||
|
||||
task write;
|
||||
begin
|
||||
write_flag <= 1;
|
||||
i_tvalid <= 1'b1;
|
||||
#1;
|
||||
while (i_tready != 1'b1)
|
||||
@(posedge clk);
|
||||
#1;
|
||||
@(posedge clk);
|
||||
write_flag <= 0;
|
||||
i_tvalid <= 1'b0;
|
||||
i_tdata <= i_tdata + 8'h1;
|
||||
end
|
||||
endtask // write
|
||||
|
||||
task read;
|
||||
begin
|
||||
read_flag <= 1;
|
||||
o_tready <= 1'b1;
|
||||
#1;
|
||||
while (o_tvalid != 1'b1)
|
||||
@(posedge clk);
|
||||
#1;
|
||||
@(posedge clk);
|
||||
read_flag <= 0;
|
||||
o_tready <= 1'b0;
|
||||
if (o_tdata_ref != o_tdata) begin
|
||||
$display("ERROR: Expected %d, got %d, at time %d",o_tdata_ref,o_tdata,$time);
|
||||
error <= 1'b1;
|
||||
end else
|
||||
error <= 1'b0;
|
||||
o_tdata_ref = o_tdata_ref + 8'h1;
|
||||
end
|
||||
endtask // read
|
||||
|
||||
initial
|
||||
begin
|
||||
reset <= 1'b0;
|
||||
error <= 1'b0;
|
||||
i_tdata <= 8'b00;
|
||||
o_tdata_ref <= 8'b00;
|
||||
i_tvalid <= 1'b0;
|
||||
o_tready <= 1'b0;
|
||||
read_flag <= 0;
|
||||
write_flag <= 0;
|
||||
|
||||
repeat(10) @(posedge clk);
|
||||
reset <= 1'b1;
|
||||
repeat(10) @(posedge clk);
|
||||
reset <= 1'b0;
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
|
||||
// FIFO Should be empty now, check avail space
|
||||
if (space != 16'd256)
|
||||
begin $display("ERROR: FIFO is empty, space should read 256 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd0)
|
||||
begin $display("ERROR: FIFO is empty, occupied should read 0 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b1)
|
||||
begin $display("ERROR: FIFO is empty, o_tvalid should be 0 at time %d",$time); error <= 1; end
|
||||
@(posedge clk);
|
||||
// Push 1 item onto FIFO, check fullness updates accordingly
|
||||
write();
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
if (space != 16'd255)
|
||||
begin $display("ERROR: FIFO space should read 255 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd1)
|
||||
begin $display("ERROR: FIFO occupied should read 1 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b0)
|
||||
begin $display("ERROR: FIFO is not empty, o_tvalid should be 1 at time %d",$time); error <= 1; end
|
||||
// Pop FIFO once, check it goes back empty OK.
|
||||
@(posedge clk);
|
||||
read();
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
if (space != 16'd256)
|
||||
begin $display("ERROR: FIFO is empty, space should read 256 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd0)
|
||||
begin $display("ERROR: FIFO is empty, occupied should read 0 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b1)
|
||||
begin $display("ERROR: FIFO is empty, o_tvalid should be 0 at time %d",$time); error <= 1; end
|
||||
// Push FIFO 255 times and see if it goes full incorrectly
|
||||
repeat(255) begin
|
||||
@(posedge clk);
|
||||
write();
|
||||
end
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
if (space != 16'd1)
|
||||
begin $display("ERROR: FIFO is nearly full, space should read 1 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd255)
|
||||
begin $display("ERROR: FIFO is nearly full, occupied should read 255 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b0)
|
||||
begin $display("ERROR: FIFO is nearly full, o_tvalid should be 1 at time %d",$time); error <= 1; end
|
||||
if (i_tready == 1'b0)
|
||||
begin $display("ERROR: FIFO is nearly full, i_tready should be 1 at time %d",$time); error <= 1; end
|
||||
// Push FIFO one more time, now it should be full
|
||||
@(posedge clk);
|
||||
write();
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
if (space != 16'd0)
|
||||
begin $display("ERROR: FIFO is full, space should read 0 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd256)
|
||||
begin $display("ERROR: FIFO is full, occupied should read 256 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b0)
|
||||
begin $display("ERROR: FIFO is full, o_tvalid should be 1 at time %d",$time); error <= 1; end
|
||||
if (i_tready == 1'b1)
|
||||
begin $display("ERROR: FIFO is full, i_tready should be 0 at time %d",$time); error <= 1; end
|
||||
// POP FIFO once, check it went nonfull.
|
||||
@(posedge clk);
|
||||
read();
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
if (space != 16'd1)
|
||||
begin $display("ERROR: FIFO is nearly full, space should read 1 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd255)
|
||||
begin $display("ERROR: FIFO is nearly full, occupied should read 255 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b0)
|
||||
begin $display("ERROR: FIFO is nearly full, o_tvalid should be 1 at time %d",$time); error <= 1; end
|
||||
if (i_tready == 1'b0)
|
||||
begin $display("ERROR: FIFO is nearly full, i_tready should be 1 at time %d",$time); error <= 1; end
|
||||
// Take FIFO to empty state
|
||||
repeat(255) begin
|
||||
@(posedge clk);
|
||||
read();
|
||||
end
|
||||
@(posedge clk);
|
||||
@(negedge clk);
|
||||
if (space != 16'd256)
|
||||
begin $display("ERROR: FIFO is empty, space should read 256 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd0)
|
||||
begin $display("ERROR: FIFO is empty, occupied should read 0 not %d at time %d",occupied,$time); error <= 1; end
|
||||
if (o_tvalid == 1'b1)
|
||||
begin $display("ERROR: FIFO is empty, o_tvalid should be 0 at time %d",$time); error <= 1; end
|
||||
// Push 1 item onto FIFO
|
||||
@(posedge clk);
|
||||
write();
|
||||
@(posedge clk);
|
||||
// Now write twice as fast as we read, and write 256 times, which should leave, 129 elements in FIFO.
|
||||
fork
|
||||
repeat(256) begin
|
||||
write();
|
||||
@(posedge clk);
|
||||
end
|
||||
repeat(128) begin
|
||||
read();
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
end
|
||||
join
|
||||
@(posedge clk);
|
||||
if (space != 16'd127)
|
||||
begin $display("ERROR: FIFO space should read 127 not %d at time %d",space,$time); error <= 1; end
|
||||
if (occupied != 16'd129)
|
||||
begin $display("ERROR: FIFO occupied should read 129 not %d at time %d",occupied,$time); error <= 1; end
|
||||
|
||||
|
||||
|
||||
//
|
||||
// END
|
||||
//
|
||||
repeat(10) @(posedge clk);
|
||||
$finish;
|
||||
end // initial begin
|
||||
|
||||
endmodule // axi_fifo_tb
|
||||
@@ -1,154 +0,0 @@
|
||||
// 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,71 +0,0 @@
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
|
||||
//
|
||||
// axi_loopback.v
|
||||
//
|
||||
// Loopback all data assuming it's in CHDR format, and swap SRC/DST in the SID in the process
|
||||
// thus reflecting it back to it's origin...in theory!
|
||||
//
|
||||
|
||||
module axi_loopback
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
// Input AXIS
|
||||
input [WIDTH-1:0] i_tdata,
|
||||
input i_tlast,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
// Output AXIS
|
||||
output [WIDTH-1:0] o_tdata,
|
||||
output o_tlast,
|
||||
output o_tvalid,
|
||||
input o_tready
|
||||
);
|
||||
|
||||
|
||||
localparam WIDTH=64;
|
||||
|
||||
wire [WIDTH-1:0] fifoin_tdata,fifoout_tdata,dmux_tdata;
|
||||
wire fifoin_tlast,dmux_tlast;
|
||||
wire fifoin_tvalid,dmux_tvalid;
|
||||
wire fifoin_tready,dmux_tready;
|
||||
|
||||
// Since most real endpoints go via Demux4 place one in here to look for bugs.
|
||||
axi_demux4 #(.ACTIVE_CHAN(4'b0001), .WIDTH(WIDTH)) demux
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.header(), .dest(2'b00),
|
||||
.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o0_tdata(dmux_tdata), .o0_tlast(dmux_tlast), .o0_tvalid(dmux_tvalid), .o0_tready(dmux_tready),
|
||||
.o1_tdata(), .o1_tlast(), .o1_tvalid(), .o1_tready(1'b1),
|
||||
.o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b1),
|
||||
.o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b1));
|
||||
|
||||
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short1
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({dmux_tlast,dmux_tdata}), .i_tvalid(dmux_tvalid), .i_tready(dmux_tready),
|
||||
.o_tdata({fifoin_tlast,fifoin_tdata}), .o_tvalid(fifoin_tvalid), .o_tready(fifoin_tready),
|
||||
.space(), .occupied());
|
||||
|
||||
reg header;
|
||||
always @(posedge clk) begin
|
||||
if(reset) begin
|
||||
header <= 1'b1;
|
||||
end else if (header) begin
|
||||
if(fifoin_tvalid & fifoin_tready & ~fifoin_tlast) header <= 1'b0;
|
||||
end else begin
|
||||
if(fifoin_tvalid & fifoin_tready & fifoin_tlast) header <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
assign fifoout_tdata = header ?
|
||||
{fifoin_tdata[63:32] ,fifoin_tdata[15:0],fifoin_tdata[31:16]} :
|
||||
fifoin_tdata;
|
||||
|
||||
axi_fifo_short #(.WIDTH(WIDTH+1)) axi_fifo_short2
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({fifoin_tlast,fifoout_tdata}), .i_tvalid(fifoin_tvalid), .i_tready(fifoin_tready),
|
||||
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
|
||||
.space(), .occupied());
|
||||
|
||||
endmodule // axi_loopback
|
||||
@@ -1,112 +0,0 @@
|
||||
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
// axi_mux -- takes 4 64-bit AXI stream, 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
|
||||
|
||||
module axi_mux4
|
||||
#(parameter PRIO=0,
|
||||
parameter WIDTH=64,
|
||||
parameter BUFFER=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;
|
||||
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;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
mx_state <= MX_IDLE;
|
||||
else
|
||||
case (mx_state)
|
||||
MX_IDLE :
|
||||
if(i0_tvalid)
|
||||
mx_state <= MX_0;
|
||||
else if(i1_tvalid)
|
||||
mx_state <= MX_1;
|
||||
else if(i2_tvalid)
|
||||
mx_state <= MX_2;
|
||||
else if(i3_tvalid)
|
||||
mx_state <= MX_3;
|
||||
|
||||
MX_0 :
|
||||
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||
if(PRIO)
|
||||
mx_state <= MX_IDLE;
|
||||
else if(i1_tvalid)
|
||||
mx_state <= MX_1;
|
||||
else if(i2_tvalid)
|
||||
mx_state <= MX_2;
|
||||
else if(i3_tvalid)
|
||||
mx_state <= MX_3;
|
||||
else
|
||||
mx_state <= MX_IDLE;
|
||||
|
||||
MX_1 :
|
||||
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||
if(PRIO)
|
||||
mx_state <= MX_IDLE;
|
||||
else if(i2_tvalid)
|
||||
mx_state <= MX_2;
|
||||
else if(i3_tvalid)
|
||||
mx_state <= MX_3;
|
||||
else
|
||||
mx_state <= MX_IDLE;
|
||||
|
||||
MX_2 :
|
||||
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||
if(PRIO)
|
||||
mx_state <= MX_IDLE;
|
||||
else if(i3_tvalid)
|
||||
mx_state <= MX_3;
|
||||
else
|
||||
mx_state <= MX_IDLE;
|
||||
|
||||
MX_3 :
|
||||
if(o_tready_int & o_tvalid_int & o_tlast_int)
|
||||
if(PRIO)
|
||||
mx_state <= MX_IDLE;
|
||||
else
|
||||
mx_state <= MX_IDLE;
|
||||
|
||||
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;
|
||||
assign o_tready_int = o_tready;
|
||||
end
|
||||
else
|
||||
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), .i_tready(o_tready_int),
|
||||
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
|
||||
.space(), .occupied());
|
||||
endgenerate
|
||||
|
||||
endmodule // axi__mux4
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
// axi_mux -- takes 8 64-bit AXI stream, 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
|
||||
|
||||
module axi_mux8 #(
|
||||
parameter PRIO=0,
|
||||
parameter WIDTH=64,
|
||||
parameter BUFFER=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,
|
||||
input [WIDTH-1:0] i4_tdata, input i4_tlast, input i4_tvalid, output i4_tready,
|
||||
input [WIDTH-1:0] i5_tdata, input i5_tlast, input i5_tvalid, output i5_tready,
|
||||
input [WIDTH-1:0] i6_tdata, input i6_tlast, input i6_tvalid, output i6_tready,
|
||||
input [WIDTH-1:0] i7_tdata, input i7_tlast, input i7_tvalid, output i7_tready,
|
||||
output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
|
||||
);
|
||||
|
||||
wire [WIDTH-1:0] o_tdata_int0, o_tdata_int1;
|
||||
wire o_tlast_int0, o_tlast_int1;
|
||||
wire o_tvalid_int0, o_tvalid_int1;
|
||||
wire o_tready_int0, o_tready_int1;
|
||||
|
||||
axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(0)) mux4_int0 (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i0_tdata(i0_tdata), .i0_tlast(i0_tlast), .i0_tvalid(i0_tvalid), .i0_tready(i0_tready),
|
||||
.i1_tdata(i1_tdata), .i1_tlast(i1_tlast), .i1_tvalid(i1_tvalid), .i1_tready(i1_tready),
|
||||
.i2_tdata(i2_tdata), .i2_tlast(i2_tlast), .i2_tvalid(i2_tvalid), .i2_tready(i2_tready),
|
||||
.i3_tdata(i3_tdata), .i3_tlast(i3_tlast), .i3_tvalid(i3_tvalid), .i3_tready(i3_tready),
|
||||
.o_tdata(o_tdata_int0), .o_tlast(o_tlast_int0), .o_tvalid(o_tvalid_int0), .o_tready(o_tready_int0)
|
||||
);
|
||||
|
||||
axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(0)) mux4_int1 (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i0_tdata(i4_tdata), .i0_tlast(i4_tlast), .i0_tvalid(i4_tvalid), .i0_tready(i4_tready),
|
||||
.i1_tdata(i5_tdata), .i1_tlast(i5_tlast), .i1_tvalid(i5_tvalid), .i1_tready(i5_tready),
|
||||
.i2_tdata(i6_tdata), .i2_tlast(i6_tlast), .i2_tvalid(i6_tvalid), .i2_tready(i6_tready),
|
||||
.i3_tdata(i7_tdata), .i3_tlast(i7_tlast), .i3_tvalid(i7_tvalid), .i3_tready(i7_tready),
|
||||
.o_tdata(o_tdata_int1), .o_tlast(o_tlast_int1), .o_tvalid(o_tvalid_int1), .o_tready(o_tready_int1)
|
||||
);
|
||||
|
||||
axi_mux4 #(.PRIO(PRIO), .WIDTH(WIDTH), .BUFFER(BUFFER)) mux2 (
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i0_tdata(o_tdata_int0), .i0_tlast(o_tlast_int0), .i0_tvalid(o_tvalid_int0), .i0_tready(o_tready_int0),
|
||||
.i1_tdata(o_tdata_int1), .i1_tlast(o_tlast_int1), .i1_tvalid(o_tvalid_int1), .i1_tready(o_tready_int1),
|
||||
.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(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
|
||||
);
|
||||
|
||||
endmodule // axi_mux8
|
||||
@@ -1,78 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
// 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.
|
||||
// Will permanently block if a single packet is bigger than the fifo.
|
||||
// Will also drop any packet with an error signalled on the last line.
|
||||
// This is useful after an ethernet interface to drop packets with bad CRCs.
|
||||
|
||||
module axi_packet_gate
|
||||
#(parameter WIDTH=68,
|
||||
parameter SIZE=10)
|
||||
(input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
input [WIDTH-1:0] i_tdata,
|
||||
input i_tlast,
|
||||
input i_terror,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
output [WIDTH-1:0] o_tdata,
|
||||
output o_tlast,
|
||||
output o_tvalid,
|
||||
input o_tready
|
||||
);
|
||||
|
||||
reg [7:0] num_packets;
|
||||
reg dump;
|
||||
|
||||
wire o_tvalid_int, o_tready_int, i_tvalid_int, i_tready_int;
|
||||
|
||||
assign i_tvalid_int = (~dump & (num_packets != 8'hFF)) ? i_tvalid : 1'b0;
|
||||
assign i_tready = (~dump & (num_packets != 8'hFF)) ? i_tready_int : 1'b0;
|
||||
|
||||
assign o_tvalid = (num_packets != 8'h0) ? o_tvalid_int : 1'b0;
|
||||
assign o_tready_int = (num_packets != 8'h0) ? o_tready : 1'b0;
|
||||
|
||||
wire last_in = i_tvalid_int & i_tready_int & i_tlast;
|
||||
wire last_out = o_tvalid_int & o_tready_int & o_tlast;
|
||||
|
||||
always @(posedge clk)
|
||||
if(reset | clear)
|
||||
begin
|
||||
num_packets <= 8'd0;
|
||||
dump <= 1'b0;
|
||||
end
|
||||
else
|
||||
if(dump)
|
||||
if(num_packets != 8'd0)
|
||||
if(last_out)
|
||||
num_packets <= num_packets - 8'd1;
|
||||
else
|
||||
;
|
||||
else
|
||||
dump <= 1'b0;
|
||||
else
|
||||
if(last_in)
|
||||
if(i_terror)
|
||||
begin
|
||||
dump <= 1'b1;
|
||||
if(last_out)
|
||||
num_packets <= num_packets - 8'd1;
|
||||
end
|
||||
else if(~last_out)
|
||||
num_packets <= num_packets + 8'd1;
|
||||
else
|
||||
;
|
||||
else if(last_out)
|
||||
num_packets <= num_packets - 8'd1;
|
||||
|
||||
axi_fifo #(.SIZE(SIZE), .WIDTH(WIDTH+1)) axi_fifo
|
||||
(.clk(clk), .reset(reset), .clear(clear | (dump & (num_packets == 8'd0))),
|
||||
.i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
|
||||
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid_int), .o_tready(o_tready_int));
|
||||
|
||||
endmodule // axi_packet_gate
|
||||
@@ -1,106 +0,0 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module axi_packet_gate_tb();
|
||||
|
||||
reg clk = 0;
|
||||
reg reset = 1;
|
||||
|
||||
always #10 clk = ~clk;
|
||||
|
||||
initial $dumpfile("axi_packet_gate_tb.vcd");
|
||||
initial $dumpvars(0,axi_packet_gate_tb);
|
||||
|
||||
task send_packet;
|
||||
input [63:0] data_start;
|
||||
input [2:0] user;
|
||||
input [31:0] len;
|
||||
input error;
|
||||
|
||||
begin
|
||||
// Send a packet
|
||||
@(posedge clk);
|
||||
{i_terror, i_tuser, i_tlast, i_tdata} <= { 1'b0, user, 1'b0, data_start };
|
||||
repeat(len-1)
|
||||
begin
|
||||
i_tvalid <= 1;
|
||||
@(posedge clk);
|
||||
i_tdata <= i_tdata + 1;
|
||||
end
|
||||
i_tlast <= 1;
|
||||
i_terror <= error;
|
||||
i_tdata <= i_tdata + 1;
|
||||
@(posedge clk);
|
||||
i_tvalid <= 1'b0;
|
||||
|
||||
@(posedge clk);
|
||||
end
|
||||
endtask // send_packet
|
||||
|
||||
|
||||
initial
|
||||
begin
|
||||
#1000 reset = 0;
|
||||
#200000;
|
||||
$finish;
|
||||
end
|
||||
|
||||
wire [63:0] o_tdata;
|
||||
reg [63:0] i_tdata;
|
||||
wire [2:0] o_tuser;
|
||||
reg [2:0] i_tuser;
|
||||
reg i_tlast;
|
||||
wire o_tlast;
|
||||
wire o_tvalid, i_tready;
|
||||
reg i_tvalid, o_tready;
|
||||
reg i_terror;
|
||||
|
||||
localparam RPT_COUNT = 16;
|
||||
|
||||
initial
|
||||
begin
|
||||
i_tvalid <= 0;
|
||||
o_tready <= 0;
|
||||
|
||||
while(reset)
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
|
||||
send_packet(64'hA0,3'd0, 16, 0);
|
||||
send_packet(64'hB0,3'd0, 16, 0);
|
||||
o_tready <= 1;
|
||||
send_packet(64'hC0,3'd0, 16, 1);
|
||||
send_packet(64'hD0,3'd0, 16, 0);
|
||||
send_packet(64'hE0,3'd0, 16, 0);
|
||||
send_packet(64'hF0,3'd0, 16, 0);
|
||||
|
||||
@(posedge clk);
|
||||
|
||||
end // initial begin
|
||||
|
||||
wire i_terror_int, i_tlast_int, i_tready_int, i_tvalid_int;
|
||||
wire [2:0] i_tuser_int;
|
||||
wire [63:0] i_tdata_int;
|
||||
wire o_tlast_int, o_tready_int, o_tvalid_int;
|
||||
wire [2:0] o_tuser_int;
|
||||
wire [63:0] o_tdata_int;
|
||||
|
||||
axi_fifo #(.WIDTH(69), .SIZE(10)) fifo
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({i_terror,i_tlast,i_tuser,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o_tdata({i_terror_int,i_tlast_int,i_tuser_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int));
|
||||
|
||||
axi_packet_gate #(.WIDTH(67), .SIZE(10)) dut
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({i_tuser_int,i_tdata_int}), .i_terror(i_terror_int), .i_tlast(i_tlast_int), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
|
||||
.o_tdata({o_tuser_int,o_tdata_int}), .o_tlast(o_tlast_int), .o_tvalid(o_tvalid_int), .o_tready(o_tready_int));
|
||||
|
||||
axi_fifo #(.WIDTH(68), .SIZE(10)) fifo_out
|
||||
(.clk(clk), .reset(reset), .clear(1'b0),
|
||||
.i_tdata({o_tlast_int,o_tuser_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
|
||||
.o_tdata({o_tlast,o_tuser,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready));
|
||||
|
||||
always @(posedge clk)
|
||||
if(o_tvalid & o_tready)
|
||||
$display("TUSER %x\tTLAST %x\tTDATA %x",o_tuser,o_tlast, o_tdata);
|
||||
|
||||
endmodule // axi_packet_gate_tb
|
||||
@@ -1,123 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// This module is instantiated in parallel with a FIFO with AXI4-STREAM interfaces.
|
||||
// It tracks how many complete packets are contained within the FIFO, and also indicates
|
||||
// when the first word of a packet is presented on the FIFO outputs.
|
||||
//
|
||||
|
||||
|
||||
module monitor_axi_fifo
|
||||
#(
|
||||
parameter COUNT_BITS=8
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input clear,
|
||||
// Monitored FIFO signals
|
||||
input i_tvalid,
|
||||
input i_tready,
|
||||
input i_tlast,
|
||||
input o_tvalid,
|
||||
input o_tready,
|
||||
input o_tlast,
|
||||
// FIFO status outputs
|
||||
output reg [COUNT_BITS-1:0] pkt_count, // Exact whole packet count
|
||||
output pkt_present // Flags any whole packets present
|
||||
|
||||
);
|
||||
|
||||
localparam WAIT_SOF = 0;
|
||||
localparam WAIT_EOF = 1;
|
||||
|
||||
|
||||
reg in_state, out_state;
|
||||
reg pause_tx;
|
||||
|
||||
//
|
||||
// Count packets arriving into large FIFO
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
in_state <= WAIT_SOF;
|
||||
end else
|
||||
case(in_state)
|
||||
//
|
||||
// After RESET or the EOF of previous packet, the first cycle with
|
||||
// input valid and input ready asserted is the SOF.
|
||||
//
|
||||
WAIT_SOF:
|
||||
if (i_tvalid && i_tready) begin
|
||||
in_state <= WAIT_EOF;
|
||||
end else begin
|
||||
in_state <= WAIT_SOF;
|
||||
end
|
||||
//
|
||||
// EOF is signalled by the assertion i_tlast whilst input valid and ready are asserted.
|
||||
//
|
||||
WAIT_EOF:
|
||||
if (i_tlast && i_tvalid && i_tready) begin
|
||||
in_state <= WAIT_SOF;
|
||||
end else begin
|
||||
in_state <= WAIT_EOF;
|
||||
end
|
||||
endcase // case(in_state)
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Count packets leaving large FIFO
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear) begin
|
||||
out_state <= WAIT_SOF;
|
||||
end else
|
||||
case(out_state)
|
||||
//
|
||||
// After RESET or the EOF of previous packet, the first cycle with
|
||||
// output valid and output ready asserted is the SOF.
|
||||
//
|
||||
WAIT_SOF:
|
||||
if (o_tvalid && o_tready) begin
|
||||
out_state <= WAIT_EOF;
|
||||
end else begin
|
||||
out_state <= WAIT_SOF;
|
||||
end
|
||||
//
|
||||
// EOF is signalled by o_tlast asserted whilst output valid and ready asserted.
|
||||
//
|
||||
WAIT_EOF:
|
||||
if (o_tlast && o_tvalid && o_tready) begin
|
||||
out_state <= WAIT_SOF;
|
||||
end else begin
|
||||
out_state <= WAIT_EOF;
|
||||
end
|
||||
endcase // case(in_state)
|
||||
|
||||
|
||||
//
|
||||
// Count packets in FIFO.
|
||||
// No protection on counter wrap,
|
||||
// unclear how to gracefully deal with it.
|
||||
// Perhaps generate Error IRQ so that S/W could clean up?
|
||||
// Configure so that the pkt_count is ample for the application.
|
||||
//
|
||||
always @(posedge clk)
|
||||
if (reset | clear)
|
||||
pkt_count <= 0;
|
||||
else if (((out_state==WAIT_EOF) && o_tlast && o_tvalid && o_tready ) &&
|
||||
((in_state==WAIT_EOF) && i_tlast && i_tvalid && i_tready))
|
||||
pkt_count <= pkt_count;
|
||||
else if ((out_state==WAIT_EOF) && o_tlast && o_tvalid && o_tready)
|
||||
pkt_count <= pkt_count - 1;
|
||||
else if ((in_state==WAIT_EOF) && i_tlast && i_tvalid && i_tready)
|
||||
pkt_count <= pkt_count + 1;
|
||||
|
||||
// Non-zero packet count indicates packet(s) present.
|
||||
assign pkt_present = |pkt_count;
|
||||
|
||||
endmodule // count_tx_packets
|
||||
@@ -1,92 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
|
||||
module shortfifo
|
||||
#(parameter WIDTH=32)
|
||||
(input clk, input rst,
|
||||
input [WIDTH-1:0] datain,
|
||||
output [WIDTH-1:0] dataout,
|
||||
input read,
|
||||
input write,
|
||||
input clear,
|
||||
output reg full,
|
||||
output reg empty,
|
||||
output reg [4:0] space,
|
||||
output reg [4:0] occupied);
|
||||
|
||||
reg [3:0] a;
|
||||
genvar i;
|
||||
|
||||
generate
|
||||
for (i=0;i<WIDTH;i=i+1)
|
||||
begin : gen_srl16
|
||||
SRL16E
|
||||
srl16e(.Q(dataout[i]),
|
||||
.A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),
|
||||
.CE(write),.CLK(clk),.D(datain[i]));
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
begin
|
||||
a <= 0;
|
||||
empty <= 1;
|
||||
full <= 0;
|
||||
end
|
||||
else if(clear)
|
||||
begin
|
||||
a <= 0;
|
||||
empty <= 1;
|
||||
full<= 0;
|
||||
end
|
||||
else if(read & ~write)
|
||||
begin
|
||||
full <= 0;
|
||||
if(a==0)
|
||||
empty <= 1;
|
||||
else
|
||||
a <= a - 1;
|
||||
end
|
||||
else if(write & ~read)
|
||||
begin
|
||||
empty <= 0;
|
||||
if(~empty)
|
||||
a <= a + 1;
|
||||
if(a == 14)
|
||||
full <= 1;
|
||||
end
|
||||
|
||||
// NOTE will fail if you write into a full fifo or read from an empty one
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// space and occupied are used for diagnostics, not
|
||||
// guaranteed correct
|
||||
|
||||
//assign space = full ? 0 : empty ? 16 : 15-a;
|
||||
//assign occupied = empty ? 0 : full ? 16 : a+1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
space <= 16;
|
||||
else if(clear)
|
||||
space <= 16;
|
||||
else if(read & ~write)
|
||||
space <= space + 1;
|
||||
else if(write & ~read)
|
||||
space <= space - 1;
|
||||
|
||||
always @(posedge clk)
|
||||
if(rst)
|
||||
occupied <= 0;
|
||||
else if(clear)
|
||||
occupied <= 0;
|
||||
else if(read & ~write)
|
||||
occupied <= occupied - 1;
|
||||
else if(write & ~read)
|
||||
occupied <= occupied + 1;
|
||||
|
||||
endmodule // shortfifo
|
||||
@@ -1,13 +0,0 @@
|
||||
#
|
||||
# Copyright 2010-2013 Ettus Research LLC
|
||||
#
|
||||
|
||||
##################################################
|
||||
# SERDES Sources
|
||||
##################################################
|
||||
GPIF2_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/gpif2/, \
|
||||
gpif2_slave_fifo32.v \
|
||||
gpif2_to_fifo64.v \
|
||||
fifo64_to_gpif2.v \
|
||||
gpif2_error_checker.v \
|
||||
))
|
||||
@@ -1,64 +0,0 @@
|
||||
//
|
||||
// Copyright 2012-2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
module fifo64_to_gpif2
|
||||
#(
|
||||
parameter FIFO_SIZE = 9
|
||||
)
|
||||
(
|
||||
//input fifo interface
|
||||
input fifo_clk, input fifo_rst,
|
||||
input [63:0] i_tdata,
|
||||
input i_tlast,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
|
||||
//output interface
|
||||
input gpif_clk, input gpif_rst,
|
||||
output [31:0] o_tdata,
|
||||
output o_tlast,
|
||||
output o_tvalid,
|
||||
input o_tready
|
||||
);
|
||||
|
||||
wire [31:0] i32_tdata;
|
||||
wire i32_tlast;
|
||||
wire i32_tvalid, i32_tready;
|
||||
|
||||
axi_fifo64_to_fifo32 fifo64_to_fifo32
|
||||
(
|
||||
.clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
|
||||
.i_tdata(i_tdata), .i_tuser(3'b0/*done care*/), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
|
||||
.o_tdata(i32_tdata), .o_tuser(/*ignored cuz vita has len*/), .o_tlast(i32_tlast), .o_tvalid(i32_tvalid), .o_tready(i32_tready)
|
||||
);
|
||||
|
||||
wire [31:0] gate_tdata;
|
||||
wire gate_tlast;
|
||||
wire gate_tvalid, gate_tready;
|
||||
|
||||
axi_fifo_2clk #(.WIDTH(33), .SIZE(0/*SRL*/)) cross_clock_fifo
|
||||
(
|
||||
.reset(fifo_rst | gpif_rst),
|
||||
.i_aclk(fifo_clk), .i_tdata({i32_tlast, i32_tdata}), .i_tvalid(i32_tvalid), .i_tready(i32_tready),
|
||||
.o_aclk(gpif_clk), .o_tdata({gate_tlast, gate_tdata}), .o_tvalid(gate_tvalid), .o_tready(gate_tready)
|
||||
);
|
||||
|
||||
wire [31:0] int0_tdata; wire int0_tlast, int0_tvalid, int0_tready;
|
||||
|
||||
axi_packet_gate #(.WIDTH(32), .SIZE(FIFO_SIZE)) buffer_whole_pkt
|
||||
(
|
||||
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
|
||||
.i_tdata(gate_tdata), .i_tlast(gate_tlast), .i_terror(1'b0), .i_tvalid(gate_tvalid), .i_tready(gate_tready),
|
||||
.o_tdata(int0_tdata), .o_tlast(int0_tlast), .o_tvalid(int0_tvalid), .o_tready(int0_tready)
|
||||
);
|
||||
|
||||
axi_fifo #(.WIDTH(33), .SIZE(0)) outgress_timing_fifo
|
||||
(
|
||||
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
|
||||
.i_tdata({int0_tlast, int0_tdata}), .i_tvalid(int0_tvalid), .i_tready(int0_tready), .space(),
|
||||
.o_tdata({o_tlast, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready), .occupied()
|
||||
);
|
||||
|
||||
endmodule //fifo_to_gpmc16
|
||||
@@ -1,126 +0,0 @@
|
||||
|
||||
// Copyright 2013 Ettus Research LLC
|
||||
|
||||
// inspect the input for invalid conditions
|
||||
// when bad - drain input, flag error, and insert error msg packet
|
||||
//
|
||||
// Packets alignment errors are searched for in two different ways:
|
||||
// 1) Blatently illegal values in what is assumed to be the PACKET_LENGTH field
|
||||
// in the CHDR header
|
||||
// (We could probably improve this by looking at other fields of the header that
|
||||
// have a limited range of values)
|
||||
// 2) Packet length indicating an EOF word that doesn't have TLAST set in the FIFO.
|
||||
// (Upstream can howvever legally insert TLAST in the FIFO for words that are not EOF)
|
||||
//
|
||||
// Packet allignment recovery strategy is to wait for TLAST asserted and then decode the
|
||||
// following data assuming it is the start of new CHDR headers.
|
||||
//
|
||||
//TODO - insert bad packet
|
||||
|
||||
module gpif2_error_checker
|
||||
#(parameter SIZE = 9)
|
||||
(input clk, input reset, input clear,
|
||||
input [31:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
|
||||
output [31:0] o_tdata, output o_tlast, output o_tvalid, input o_tready,
|
||||
output bus_error, output [63:0] debug);
|
||||
|
||||
wire [31:0] gate_tdata;
|
||||
wire gate_tlast, gate_terror;
|
||||
wire gate_tvalid, gate_tready;
|
||||
|
||||
localparam STATE_HDR = 0;
|
||||
localparam STATE_FWD = 1;
|
||||
localparam STATE_EOF = 2;
|
||||
localparam STATE_WAIT = 3;
|
||||
reg [1:0] state;
|
||||
|
||||
reg [15:0] lines32;
|
||||
reg [11:0] seq_id_ref;
|
||||
reg seq_id_bad;
|
||||
reg seq_id_wayoff;
|
||||
|
||||
|
||||
wire [15:0] hdr_bytes = i_tdata[15:0] + 3; //round up to multiple of 4
|
||||
wire [15:0] hdr_lines32 = {2'b0, hdr_bytes[15:2]}; //convert to lines32 count
|
||||
wire [11:0] seq_id_actual = i_tdata[27:16];
|
||||
|
||||
|
||||
wire obviously_bad_hdr = (hdr_lines32 == 16'h0) || (hdr_lines32 > (1 << SIZE));
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (reset | clear) begin
|
||||
state <= STATE_HDR;
|
||||
lines32 <= 16'b0;
|
||||
seq_id_ref <= 12'h0;
|
||||
seq_id_bad <= 0;
|
||||
seq_id_wayoff <= 0;
|
||||
|
||||
|
||||
end
|
||||
else case (state)
|
||||
|
||||
STATE_HDR: begin //forward header and grab vita length
|
||||
if (i_tvalid && i_tready) begin
|
||||
if (obviously_bad_hdr) state <= STATE_WAIT;
|
||||
else if (hdr_lines32 == 16'h1) state <= STATE_HDR;
|
||||
else if (hdr_lines32 == 16'h2) state <= STATE_EOF;
|
||||
else state <= STATE_FWD;
|
||||
seq_id_bad <= (seq_id_actual != seq_id_ref);
|
||||
seq_id_wayoff <= (seq_id_actual != seq_id_ref) |
|
||||
(seq_id_actual != seq_id_ref+1) |
|
||||
(seq_id_actual != seq_id_ref+2) |
|
||||
(seq_id_actual != seq_id_ref+3);
|
||||
if (seq_id_actual != seq_id_ref)
|
||||
seq_id_ref <= seq_id_actual + 1;
|
||||
else
|
||||
seq_id_ref <= seq_id_ref + 1;
|
||||
end
|
||||
lines32 <= hdr_lines32;
|
||||
|
||||
end
|
||||
|
||||
STATE_FWD: begin //forward the rest of vita packet
|
||||
if (i_tvalid && i_tready) begin
|
||||
if (lines32 == 16'h3) state <= STATE_EOF;
|
||||
lines32 <= lines32 - 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_EOF: begin //do last line of vita frame + eof
|
||||
if (i_tvalid && i_tready)
|
||||
if (gate_tlast) state <= STATE_HDR;
|
||||
else state <= STATE_WAIT; // Try somehow to get synchronized again.
|
||||
end
|
||||
|
||||
STATE_WAIT: begin //drop until idle
|
||||
if (i_tvalid && i_tready && i_tlast) state <= STATE_HDR;
|
||||
end
|
||||
|
||||
endcase //state
|
||||
end
|
||||
|
||||
assign bus_error = (gate_terror && gate_tvalid && gate_tready) || ((state == STATE_HDR) && i_tvalid && i_tready && obviously_bad_hdr);
|
||||
assign gate_tlast = (state == STATE_HDR)? (hdr_lines32 == 16'h1) : (state == STATE_EOF);
|
||||
assign gate_tdata = i_tdata;
|
||||
assign gate_tvalid = i_tvalid && ((state == STATE_HDR)? !obviously_bad_hdr : (state != STATE_WAIT));
|
||||
assign i_tready = gate_tready;
|
||||
|
||||
axi_packet_gate #(.WIDTH(32), .SIZE(SIZE)) gate_xfer
|
||||
(
|
||||
.clk(clk), .reset(reset), .clear(clear),
|
||||
.i_tdata(gate_tdata), .i_tlast(gate_tlast), .i_terror(1'b0), .i_tvalid(gate_tvalid), .i_tready(gate_tready),
|
||||
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
|
||||
);
|
||||
assign debug = {13'b0,
|
||||
seq_id_wayoff, //[50] [114]
|
||||
gate_terror, // [49] [113]
|
||||
obviously_bad_hdr, // [48] [112]
|
||||
seq_id_bad, // [47] [111]
|
||||
seq_id_ref, // [46:35] [110:99]
|
||||
i_tlast, // [34] [98]
|
||||
i_tready, // [33] [97]
|
||||
i_tvalid, // [32] [96]
|
||||
i_tdata}; // [31:0] [95:64]
|
||||
|
||||
|
||||
endmodule // cvita_insert_tlast
|
||||
@@ -1,324 +0,0 @@
|
||||
//
|
||||
// Copyright 2011-2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//this is a FIFO master interface for the FX3 in "slave fifo" mode.
|
||||
|
||||
module gpif2_slave_fifo32
|
||||
#(
|
||||
//sizes for fifo64 2 clock cascade fifos
|
||||
parameter DATA_RX_FIFO_SIZE = 12, //max vita pkt size
|
||||
parameter DATA_TX_FIFO_SIZE = 12, //max vita pkt size
|
||||
parameter CTRL_RX_FIFO_SIZE = 5, //small resp packets
|
||||
parameter CTRL_TX_FIFO_SIZE = 5, //small ctrl packets
|
||||
|
||||
//address constants for the endpoints
|
||||
parameter ADDR_DATA_TX = 2'b00,
|
||||
parameter ADDR_DATA_RX = 2'b01,
|
||||
parameter ADDR_CTRL_TX = 2'b10,
|
||||
parameter ADDR_CTRL_RX = 2'b11,
|
||||
|
||||
parameter END_WITH_COMMA = 0
|
||||
)
|
||||
(
|
||||
// GPIF signals
|
||||
input gpif_clk,
|
||||
input gpif_rst,
|
||||
input gpif_enb,
|
||||
inout [31:0] gpif_d,
|
||||
input [3:0] gpif_ctl,
|
||||
output reg sloe,
|
||||
output reg slrd,
|
||||
output reg slwr,
|
||||
output slcs,
|
||||
output reg pktend,
|
||||
output reg [1:0] fifoadr,
|
||||
// FIFO interfaces
|
||||
input fifo_clk,
|
||||
input fifo_rst,
|
||||
// TX Data interface to DSP
|
||||
output [63:0] tx_tdata, output tx_tlast, output tx_tvalid, input tx_tready,
|
||||
// RX Data interface to DSP
|
||||
input [63:0] rx_tdata, input rx_tlast, input rx_tvalid, output rx_tready,
|
||||
// Incomming control interface
|
||||
output [63:0] ctrl_tdata, output ctrl_tlast, output ctrl_tvalid, input ctrl_tready,
|
||||
// Outgoing control interface
|
||||
input [63:0] resp_tdata, input resp_tlast, input resp_tvalid, output resp_tready,
|
||||
// Debug Signals
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
reg fifo_nearly_full;
|
||||
wire ctrl_tx_fifo_nearly_full, data_tx_fifo_nearly_full;
|
||||
wire ctrl_tx_fifo_has_space, data_tx_fifo_has_space;
|
||||
|
||||
|
||||
assign slcs = 1'b0;
|
||||
|
||||
//DMA FIFO ready and watermark flags
|
||||
reg EP_READY, EP_READY1, EP_WMARK, EP_WMARK1;
|
||||
always @(posedge gpif_clk) EP_READY <= gpif_ctl[0];
|
||||
always @(posedge gpif_clk) EP_WMARK <= gpif_ctl[1];
|
||||
always @(posedge gpif_clk) EP_READY1 <= EP_READY;
|
||||
always @(posedge gpif_clk) EP_WMARK1 <= EP_WMARK;
|
||||
|
||||
// GPIF output data lines, tristate
|
||||
reg [31:0] gpif_data_in, gpif_data_out;
|
||||
always @(posedge gpif_clk) gpif_data_in <= gpif_d;
|
||||
assign gpif_d = sloe ? gpif_data_out[31:0] : 32'bz;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// GPIF bus master state machine
|
||||
|
||||
wire wr_fifo_xfer, wr_fifo_eof;
|
||||
wire [31:0] wr_fifo_data;
|
||||
reg read_ready_go, write_ready_go;
|
||||
reg wr_one, rd_one;
|
||||
|
||||
reg [3:0] state; //state machine current state
|
||||
localparam STATE_IDLE = 0;
|
||||
localparam STATE_THINK = 1;
|
||||
localparam STATE_READ = 2;
|
||||
localparam STATE_WRITE = 3;
|
||||
localparam STATE_WAIT = 4;
|
||||
|
||||
reg [2:0] idle_cycles;
|
||||
reg [1:0] last_addr, next_addr;
|
||||
wire local_fifo_ready;
|
||||
|
||||
reg slrd1, slrd2, slrd3;
|
||||
|
||||
always @(posedge gpif_clk)
|
||||
if (gpif_rst) begin
|
||||
slrd1 <= 1;
|
||||
slrd2 <= 1;
|
||||
slrd3 <= 1;
|
||||
end else begin
|
||||
slrd1 <= slrd;
|
||||
slrd2 <= slrd1;
|
||||
slrd3 <= slrd2;
|
||||
end
|
||||
|
||||
wire RD_VALID = ~slrd3;
|
||||
wire RD_LAST = slrd2;
|
||||
wire WR_VALID = (EP_WMARK1 || !wr_one);
|
||||
|
||||
// //////////////////////////////////////////////////////////////
|
||||
// FX2 slave FIFO bus master state machine
|
||||
//
|
||||
always @(posedge gpif_clk)
|
||||
if(gpif_rst) begin
|
||||
state <= STATE_IDLE;
|
||||
sloe <= 0;
|
||||
slrd <= 1;
|
||||
slwr <= 1;
|
||||
pktend <= 1;
|
||||
gpif_data_out <= 32'b0;
|
||||
idle_cycles <= 0;
|
||||
fifoadr <= 0;
|
||||
wr_one <= 1'b0;
|
||||
rd_one <= 1'b0;
|
||||
last_addr <= 2'b0;
|
||||
end
|
||||
else if (gpif_enb) begin
|
||||
case (state)
|
||||
|
||||
//
|
||||
// Increment fifoadr to point at next thread, set all strobes to idle,
|
||||
//
|
||||
STATE_IDLE: begin
|
||||
sloe <= 0;
|
||||
slrd <= 1;
|
||||
slwr <= 1;
|
||||
pktend <= 1;
|
||||
gpif_data_out <= 32'b0;
|
||||
fifoadr <= next_addr;
|
||||
state <= STATE_WAIT;
|
||||
idle_cycles <= 0;
|
||||
end
|
||||
|
||||
//
|
||||
// If the current thread we are pointing at (fifoadr) can not immediately proceed
|
||||
// then quickly move to the next thread. Once we are pointing at a thread that can proceed locally
|
||||
// wait for 8 clock cycles to allow fifoadr to propogate to FX3, and corresponding flag state to
|
||||
// propogate back to FPGA and through resampling flops. At this point transition to STATE_THINK
|
||||
// to evaluate remote flag.
|
||||
//
|
||||
STATE_WAIT: begin
|
||||
// Current thread can proceed locally
|
||||
if (local_fifo_ready) begin
|
||||
idle_cycles <= idle_cycles + 1'b1;
|
||||
if (idle_cycles == 3'b111) state <= STATE_THINK;
|
||||
end
|
||||
// ....move onto next thread.
|
||||
else begin
|
||||
idle_cycles <= 3'b0;
|
||||
fifoadr <= fifoadr + 2'b1;
|
||||
end
|
||||
end
|
||||
|
||||
//
|
||||
// If there is a read to start, assert SLRD and SLOE and transition to STATE_READ.
|
||||
// If there is a write to perform, set flags that says there is the possibility to do at least
|
||||
// one write (wr_one) and transition to STATE_WRITE.
|
||||
// If the FX3 has nothing ready for this thread return immediately to STATE_IDLE.
|
||||
//
|
||||
STATE_THINK: begin
|
||||
if (EP_READY1 && read_ready_go) begin
|
||||
state <= STATE_READ;
|
||||
slrd <= 0;
|
||||
rd_one <= 0;
|
||||
end
|
||||
else if (EP_READY1 && write_ready_go) begin
|
||||
state <= STATE_WRITE;
|
||||
sloe <= 1;
|
||||
wr_one <= 1'b0;
|
||||
end
|
||||
else begin
|
||||
state <= STATE_IDLE;
|
||||
end
|
||||
|
||||
idle_cycles <= 0;
|
||||
last_addr <= fifoadr;
|
||||
end
|
||||
|
||||
// If flag rd_one is set (armed 5 cycles after slrd goes initialy assrted) and RD_VALID has gone deasserted
|
||||
// (meaning that the watermark deasserted 5 clock cycles ago) transition to STATE_IDLE.
|
||||
// If watermark deasserted 2 cycles ago de-assert slrd ...read data is still traveling in the pipeline.
|
||||
// Whilst RD_VALID stays asserted keep the rd_one flag armed.
|
||||
STATE_READ: begin
|
||||
if (rd_one && ~RD_VALID) state <= STATE_IDLE;
|
||||
if (~EP_WMARK1 | fifo_nearly_full) slrd <= 1;
|
||||
if (RD_VALID) rd_one <= 1'b1;
|
||||
end
|
||||
|
||||
// If local FIFO goes empty or tlast is set then transition to STATE_IDLE
|
||||
// Push local FIFO data out onto GPIF data bus.
|
||||
// if local FIFO has valid data then assert slwr
|
||||
// if local FIFO assertes tlast then assert pktend
|
||||
// If WR_VALID asserted (because wr_one already asserted in the first cycle in this state)
|
||||
// now clear wr_one (watermark will keep WR_VALID asserted from now on if this is a burst).
|
||||
//
|
||||
STATE_WRITE: begin
|
||||
if (~wr_fifo_xfer || wr_fifo_eof) state <= STATE_IDLE;
|
||||
gpif_data_out <= wr_fifo_data;
|
||||
slwr <= ~wr_fifo_xfer;
|
||||
pktend <= ~wr_fifo_eof;
|
||||
if (WR_VALID) wr_one <= 1'b1;
|
||||
end
|
||||
|
||||
default: state <= STATE_IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
// ///////////////////////////////////////////////////////////////////
|
||||
// fifo signal assignments and enables
|
||||
|
||||
//output from fifos - ready to xfer
|
||||
wire data_tx_tready, ctrl_tx_tready;
|
||||
wire ctrl_rx_tvalid, data_rx_tvalid;
|
||||
|
||||
//Priority encoding for the the next address to service:
|
||||
//The next address to service is based on the readiness
|
||||
//of the internal fifos and last serviced fairness metric.
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
always @(posedge gpif_clk) next_addr <=
|
||||
((ctrl_rx_tvalid && (last_addr != ADDR_CTRL_RX))? ADDR_CTRL_RX :
|
||||
((ctrl_tx_fifo_has_space && (last_addr != ADDR_CTRL_TX))? ADDR_CTRL_TX :
|
||||
((data_rx_tvalid && (last_addr != ADDR_DATA_RX))? ADDR_DATA_RX :
|
||||
((data_tx_fifo_has_space && (last_addr != ADDR_DATA_TX))? ADDR_DATA_TX :
|
||||
(fifoadr + 2'b1)
|
||||
))));
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
always @(posedge gpif_clk) next_addr <= (fifoadr + 2'b1);
|
||||
|
||||
|
||||
//Help the FPGA search to only look for addrs that the FPGA is ready for
|
||||
assign local_fifo_ready =
|
||||
(ctrl_rx_tvalid && (fifoadr == ADDR_CTRL_RX)) ||
|
||||
(ctrl_tx_fifo_has_space && (fifoadr == ADDR_CTRL_TX)) ||
|
||||
(data_rx_tvalid && (fifoadr == ADDR_DATA_RX)) ||
|
||||
(data_tx_fifo_has_space && (fifoadr == ADDR_DATA_TX));
|
||||
|
||||
always @(posedge gpif_clk) fifo_nearly_full <=
|
||||
(ctrl_tx_fifo_nearly_full && (fifoadr == ADDR_CTRL_TX)) ||
|
||||
(data_tx_fifo_nearly_full && (fifoadr == ADDR_DATA_TX));
|
||||
|
||||
always @(posedge gpif_clk) read_ready_go <=
|
||||
(ctrl_tx_fifo_has_space && (fifoadr == ADDR_CTRL_TX)) ||
|
||||
(data_tx_fifo_has_space && (fifoadr == ADDR_DATA_TX));
|
||||
|
||||
always @(posedge gpif_clk) write_ready_go <=
|
||||
(ctrl_rx_tvalid && (fifoadr == ADDR_CTRL_RX)) ||
|
||||
(data_rx_tvalid && (fifoadr == ADDR_DATA_RX));
|
||||
|
||||
//fifo xfer enable
|
||||
wire data_rx_tready = (state == STATE_WRITE) && (fifoadr == ADDR_DATA_RX) && WR_VALID;
|
||||
wire ctrl_rx_tready = (state == STATE_WRITE) && (fifoadr == ADDR_CTRL_RX) && WR_VALID;
|
||||
wire data_tx_tvalid = (state == STATE_READ) && (fifoadr == ADDR_DATA_TX) && RD_VALID;
|
||||
wire ctrl_tx_tvalid = (state == STATE_READ) && (fifoadr == ADDR_CTRL_TX) && RD_VALID;
|
||||
|
||||
//outputs from rx fifo paths
|
||||
wire ctrl_rx_tlast, data_rx_tlast;
|
||||
wire [31:0] ctrl_rx_tdata, data_rx_tdata;
|
||||
|
||||
//mux rx outputs for gpif state machine
|
||||
assign wr_fifo_xfer = (fifoadr == ADDR_CTRL_RX)? (ctrl_rx_tvalid && ctrl_rx_tready) : (data_rx_tvalid && data_rx_tready);
|
||||
assign wr_fifo_eof = wr_fifo_xfer && ((fifoadr == ADDR_CTRL_RX)? ctrl_rx_tlast : data_rx_tlast);
|
||||
assign wr_fifo_data = (fifoadr == ADDR_CTRL_RX)? ctrl_rx_tdata : data_rx_tdata;
|
||||
|
||||
wire ctrl_bus_error, tx_bus_error;
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// TX Data Path
|
||||
|
||||
gpif2_to_fifo64 #(.FIFO_SIZE(DATA_TX_FIFO_SIZE)) gpif2_to_fifo64_tx(
|
||||
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
|
||||
.i_tdata(gpif_data_in), .i_tlast(RD_LAST), .i_tvalid(data_tx_tvalid), .i_tready(data_tx_tready),
|
||||
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
|
||||
.fifo_nearly_full(data_tx_fifo_nearly_full), .fifo_has_space(data_tx_fifo_has_space),
|
||||
.o_tdata(tx_tdata), .o_tlast(tx_tlast), .o_tvalid(tx_tvalid), .o_tready(tx_tready),
|
||||
.bus_error(tx_bus_error), .debug()
|
||||
);
|
||||
|
||||
// ////////////////////////////////////////////
|
||||
// RX Data Path
|
||||
|
||||
fifo64_to_gpif2 #(.FIFO_SIZE(DATA_RX_FIFO_SIZE)) fifo64_to_gpif2_rx(
|
||||
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
|
||||
.i_tdata(rx_tdata), .i_tlast(rx_tlast), .i_tvalid(rx_tvalid), .i_tready(rx_tready),
|
||||
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
|
||||
.o_tdata(data_rx_tdata), .o_tlast(data_rx_tlast), .o_tvalid(data_rx_tvalid), .o_tready(data_rx_tready)
|
||||
);
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// CTRL path
|
||||
|
||||
gpif2_to_fifo64 #(.FIFO_SIZE(CTRL_TX_FIFO_SIZE)) gpif2_to_fifo64_ctrl(
|
||||
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
|
||||
.i_tdata(gpif_data_in), .i_tlast(RD_LAST), .i_tvalid(ctrl_tx_tvalid), .i_tready(ctrl_tx_tready),
|
||||
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
|
||||
.fifo_nearly_full(ctrl_tx_fifo_nearly_full), .fifo_has_space(ctrl_tx_fifo_has_space),
|
||||
.o_tdata(ctrl_tdata), .o_tlast(ctrl_tlast), .o_tvalid(ctrl_tvalid), .o_tready(ctrl_tready),
|
||||
.bus_error(ctrl_bus_error), .debug()
|
||||
);
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////
|
||||
// RESP path
|
||||
|
||||
fifo64_to_gpif2 #(.FIFO_SIZE(CTRL_RX_FIFO_SIZE)) fifo64_to_gpif2_resp(
|
||||
.fifo_clk(fifo_clk), .fifo_rst(fifo_rst),
|
||||
.i_tdata(resp_tdata), .i_tlast(resp_tlast), .i_tvalid(resp_tvalid), .i_tready(resp_tready),
|
||||
.gpif_clk(gpif_clk), .gpif_rst(gpif_rst),
|
||||
.o_tdata(ctrl_rx_tdata), .o_tlast(ctrl_rx_tlast), .o_tvalid(ctrl_rx_tvalid), .o_tready(ctrl_rx_tready)
|
||||
);
|
||||
|
||||
// ////////////////////////////////////////////
|
||||
// DEBUG
|
||||
|
||||
|
||||
|
||||
endmodule // gpif2_slave_fifo32
|
||||
@@ -1,124 +0,0 @@
|
||||
//
|
||||
// Copyright 2012-2013 Ettus Research LLC
|
||||
//
|
||||
|
||||
|
||||
module gpif2_to_fifo64
|
||||
#(
|
||||
parameter FIFO_SIZE = 9
|
||||
)
|
||||
(
|
||||
//input interface
|
||||
input gpif_clk,
|
||||
input gpif_rst,
|
||||
input [31:0] i_tdata,
|
||||
input i_tlast,
|
||||
input i_tvalid,
|
||||
output i_tready,
|
||||
output fifo_has_space,
|
||||
output fifo_nearly_full,
|
||||
|
||||
//output fifo interface
|
||||
input fifo_clk,
|
||||
input fifo_rst,
|
||||
output [63:0] o_tdata,
|
||||
output o_tlast,
|
||||
output o_tvalid,
|
||||
input o_tready,
|
||||
|
||||
output bus_error,
|
||||
output [31:0] debug
|
||||
);
|
||||
|
||||
wire [31:0] int_tdata;
|
||||
wire int_tlast;
|
||||
wire int_tvalid, int_tready;
|
||||
|
||||
wire [31:0] int0_tdata;
|
||||
wire int0_tlast, int0_tvalid, int0_tready;
|
||||
|
||||
//
|
||||
// Generate flags that show if initial FIFO's can accept a maximum sized burst from the FX3
|
||||
// or if the FIFO is about to fill.
|
||||
//
|
||||
localparam BURST_SIZE = (FIFO_SIZE < 8)? FIFO_SIZE : 8;
|
||||
wire [15:0] space;
|
||||
assign fifo_has_space = space >= (1 << BURST_SIZE);
|
||||
assign fifo_nearly_full = (space < 6); // 5 spaces left.
|
||||
|
||||
//
|
||||
// This FIFO is provdied purely to easy FPGA timing closure as data is comming from I/O pins.
|
||||
//
|
||||
axi_fifo #(.WIDTH(33), .SIZE(0)) ingress_timing_fifo
|
||||
(
|
||||
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
|
||||
.i_tdata({i_tlast, i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready), .space(),
|
||||
.o_tdata({int0_tlast, int0_tdata}), .o_tvalid(int0_tvalid), .o_tready(int0_tready), .occupied()
|
||||
);
|
||||
|
||||
//
|
||||
// This FIFO provides space to accept a single burst from FX3 and it's fullness drives flags to GPIF2 logic
|
||||
//
|
||||
axi_fifo #(.WIDTH(33), .SIZE(BURST_SIZE)) min_read_buff
|
||||
(
|
||||
.clk(gpif_clk), .reset(gpif_rst), .clear(1'b0),
|
||||
.i_tdata({int0_tlast, int0_tdata}), .i_tvalid(int0_tvalid), .i_tready(int0_tready), .space(space),
|
||||
.o_tdata({int_tlast, int_tdata}), .o_tvalid(int_tvalid), .o_tready(int_tready), .occupied()
|
||||
);
|
||||
|
||||
//
|
||||
// This logic allows signals to cross from the GPIF2 clock domain to the BUS clock domain.
|
||||
// It may now be obselete if bus_clk and gpif_clk are merged
|
||||
//
|
||||
wire [31:0] chk_tdata;
|
||||
wire chk_tlast;
|
||||
wire chk_tvalid, chk_tready;
|
||||
|
||||
axi_fifo_2clk #(.WIDTH(33), .SIZE(0/*SRL*/)) cross_clock_fifo
|
||||
(
|
||||
.reset(fifo_rst | gpif_rst),
|
||||
.i_aclk(gpif_clk), .i_tdata({int_tlast, int_tdata}), .i_tvalid(int_tvalid), .i_tready(int_tready),
|
||||
.o_aclk(fifo_clk), .o_tdata({chk_tlast, chk_tdata}), .o_tvalid(chk_tvalid), .o_tready(chk_tready)
|
||||
);
|
||||
|
||||
//
|
||||
// Performs basic tests on incomming packets such as testing if size on the wire patches
|
||||
// the internal size field. Uses axi_packet_gate internally so can back pressure upstream if
|
||||
// packet needs to be dropped.
|
||||
//
|
||||
wire [31:0] o32_tdata;
|
||||
wire o32_tlast;
|
||||
wire o32_tvalid, o32_tready;
|
||||
|
||||
gpif2_error_checker #(.SIZE(FIFO_SIZE)) checker
|
||||
(
|
||||
.clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
|
||||
.i_tdata(chk_tdata), .i_tlast(chk_tlast), .i_tvalid(chk_tvalid), .i_tready(chk_tready),
|
||||
.o_tdata(o32_tdata), .o_tlast(o32_tlast), .o_tvalid(o32_tvalid), .o_tready(o32_tready),
|
||||
.bus_error(bus_error), .debug()
|
||||
);
|
||||
|
||||
//assign o32_tdata = chk_tdata;
|
||||
//assign o32_tlast = chk_tlast;
|
||||
//assign o32_tvalid = chk_tvalid;
|
||||
//assign chk_tready = o32_tready;
|
||||
|
||||
//
|
||||
// Convert 32bit AXIS bus to 64bit
|
||||
//
|
||||
axi_fifo32_to_fifo64 fifo32_to_fifo64
|
||||
(
|
||||
.clk(fifo_clk), .reset(fifo_rst), .clear(1'b0),
|
||||
.i_tdata(o32_tdata), .i_tuser(2'b0/*always 32 bits*/), .i_tlast(o32_tlast), .i_tvalid(o32_tvalid), .i_tready(o32_tready),
|
||||
.o_tdata(o_tdata), .o_tuser(/*ignored cuz vita has len*/), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready)
|
||||
);
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
// Debug logic only
|
||||
//
|
||||
/////////////////////////////////////////////
|
||||
|
||||
|
||||
endmodule //fifo_to_gpif2
|
||||
@@ -1 +0,0 @@
|
||||
/build
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user