diff options
author | Ben Hilburn <ben.hilburn@ettus.com> | 2014-02-14 12:05:07 -0800 |
---|---|---|
committer | Ben Hilburn <ben.hilburn@ettus.com> | 2014-02-14 12:05:07 -0800 |
commit | ff1546f8137f7f92bb250f685561b0c34cc0e053 (patch) | |
tree | 7fa6fd05c8828df256a1b20e2935bd3ba9899e2c /fpga/usrp3/lib/axi | |
parent | 4f691d88123784c2b405816925f1a1aef69d18c1 (diff) | |
download | uhd-ff1546f8137f7f92bb250f685561b0c34cc0e053.tar.gz uhd-ff1546f8137f7f92bb250f685561b0c34cc0e053.tar.bz2 uhd-ff1546f8137f7f92bb250f685561b0c34cc0e053.zip |
Pushing the bulk of UHD-3.7.0 code.
Diffstat (limited to 'fpga/usrp3/lib/axi')
-rw-r--r-- | fpga/usrp3/lib/axi/Makefile.srcs | 17 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_chdr_header_trigger.v | 40 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_chdr_test_pattern.v | 314 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_defs.v | 34 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_dma_master.v | 538 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_dma_master_tb.v | 165 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_dram_fifo.v | 816 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_dram_fifo_tb.v | 421 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_embed_tlast.v | 128 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_extract_tlast.v | 149 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_fast_extract_tlast.v | 187 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_fast_fifo.v | 102 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_lite_slave.v | 42 |
13 files changed, 2953 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/axi/Makefile.srcs b/fpga/usrp3/lib/axi/Makefile.srcs new file mode 100644 index 000000000..26d2e0fee --- /dev/null +++ b/fpga/usrp3/lib/axi/Makefile.srcs @@ -0,0 +1,17 @@ +# +# Copyright 2012-2013 Ettus Research LLC +# + +################################################## +# FIFO Sources +################################################## +AXI_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/axi/, \ +axi_dma_master.v \ +axi_dram_fifo.v \ +axi_embed_tlast.v \ +axi_extract_tlast.v \ +axi_chdr_test_pattern.v \ +axi_fast_fifo.v \ +axi_fast_extract_tlast.v \ +axi_chdr_header_trigger.v \ +)) diff --git a/fpga/usrp3/lib/axi/axi_chdr_header_trigger.v b/fpga/usrp3/lib/axi/axi_chdr_header_trigger.v new file mode 100644 index 000000000..e8dee3675 --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_chdr_header_trigger.v @@ -0,0 +1,40 @@ + +// Copyright 2014 Ettus Research LLC + + +module axi_chdr_header_trigger + #( + parameter WIDTH=64, + parameter SID=0 + ) + (input clk, input reset, input clear, + input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, input i_tready, + output trigger + ); + + + reg state; + localparam IDLE = 0; + localparam RUN = 1; + + + always @(posedge clk) + if(reset | clear) + state <= IDLE; + else + case (state) + IDLE : + if(i_tvalid && i_tready) + state <= RUN; + + RUN : + if(i_tready && i_tvalid && i_tlast) + state <= IDLE; + + default : + state <= IDLE; + endcase // case (state) + + assign trigger = i_tvalid && i_tready && (state == IDLE) && (i_tdata[15:0] != SID); + +endmodule // axi_chdr_header_trigger diff --git a/fpga/usrp3/lib/axi/axi_chdr_test_pattern.v b/fpga/usrp3/lib/axi/axi_chdr_test_pattern.v new file mode 100644 index 000000000..7d25f3008 --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_chdr_test_pattern.v @@ -0,0 +1,314 @@ +// +// Synthesizable test pattern generators and checkers +// for CHDR that can be used to test transparent blocks +// (FIFOs, switches, etc) +// + +//`define MTU 8192 +`define MTU 1536 + +module axi_chdr_test_pattern + ( + input clk, + input reset, + + // + // CHDR friendly AXI stream input + // + output reg [63:0] i_tdata, + output reg i_tlast, + output reg i_tvalid, + input wire i_tready, + // + // CHDR friendly AXI Stream output + // + input wire [63:0] o_tdata, + input wire o_tlast, + input wire o_tvalid, + output reg o_tready, + // + // Test flags + // + input start, + input [15:0] control, + output reg fail, + output reg done + ); + + wire [7:0] bist_rx_delay = control[7:0]; + wire [7:0] bist_tx_delay = control[15:8]; + + + reg [15:0] tx_count, rx_count; + reg [15:0] tx_data, rx_data; + reg [7:0] tx_delay, rx_delay; + + + localparam TX_IDLE = 0; + localparam TX_START = 1; + localparam TX_ACTIVE = 2; + localparam TX_GAP = 3; + localparam TX_DONE = 4; + localparam TX_WAIT = 5; + + localparam RX_IDLE = 0; + localparam RX_ACTIVE = 1; + localparam RX_FAIL = 2; + localparam RX_DONE = 3; + localparam RX_WAIT = 4; + + reg [2:0] tx_state, rx_state; + + // + // Transmitter + // + always @(posedge clk) + if (reset) + begin + tx_delay <= 0; + tx_count <= 8; + tx_data <= 0; + i_tdata <= 64'h0; + i_tlast <= 1'b0; + i_tvalid <= 1'b0; + tx_state <= TX_IDLE; + end + else + begin + case(tx_state) + TX_IDLE: begin + tx_delay <= 0; + i_tdata <= 64'h0; + i_tlast <= 1'b0; + i_tvalid <= 1'b0; + tx_data <= 0; + tx_count <= 4; + // Run whilst start asserted. + if (start) begin + tx_state <= TX_START; + // ....Go back to initialized state if start deasserted. + end else begin + tx_state <= TX_IDLE; + end + end // case: TX_IDLE + + // + // START signal is asserted. + // Now need to start transmiting a packet. + // + TX_START: begin + // At the next clock edge drive first beat of new packet onto HDR bus. + i_tlast <= 1'b0; + i_tvalid <= 1'b1; + tx_data <= tx_data + 4; + // i_tdata <= {tx_data,tx_data+16'd1,tx_data+16'd2,tx_data+16'd3}; + i_tdata <= {4{(tx_data[2]?16'hffff:16'h0000)^tx_data[15:0]}}; + tx_state <= TX_ACTIVE; + + end + + // + // Valid data is (already) being driven onto the CHDR bus. + // i_tlast may also be driven asserted if current data count has reached EOP. + // Watch i_tready to see when it's consumed. + // When packets are consumed increment data counter or transition state if + // EOP has sucsesfully concluded. + // + TX_ACTIVE: begin + i_tvalid <= 1'b1; // Always assert tvalid + if (i_tready) begin + +// i_tdata <= {tx_data,tx_data+16'd1,tx_data+16'd2,tx_data+16'd3}; + i_tdata <= {4{(tx_data[2]?16'hffff:16'h0000)^tx_data[15:0]}}; + // Will this next beat be the last in a packet? + if (tx_data == tx_count) begin + tx_data <= 0; + i_tlast <= 1'b1; + tx_state <= TX_GAP; + end else begin + tx_data <= tx_data + 4; + i_tlast <= 1'b0; + tx_state <= TX_ACTIVE; + end + end else begin + // Keep driving all CHDR bus signals as-is until i_tready is asserted. + tx_state <= TX_ACTIVE; + end + end // case: TX_ACTIVE + // + // Force an inter-packet gap between packets in a BIST sequence where tvalid is driven low. + // As we leave this state check if all packets in BIST sequence have been generated yet, + // and if so go to done state. + // + TX_GAP: begin + if (i_tready) begin + i_tvalid <= 1'b0; + i_tdata <= 64'h0; + i_tlast <= 1'b0; + tx_count <= tx_count + 4; + + if (tx_count < `MTU) begin + tx_state <= TX_WAIT; + tx_delay <= bist_tx_delay; + end else + tx_state <= TX_DONE; + end else begin // if (i_tready) + tx_state <= TX_GAP; + end + end // case: TX_GAP + // + // Simulate inter packet gap in real UHD system + TX_WAIT: begin + if (tx_delay == 0) + tx_state <= TX_START; + else begin + tx_delay <= tx_delay - 1; + tx_state <= TX_WAIT; + end + end + + // + // Complete test pattern BIST sequence has been transmitted. Sit in this + // state indefinately if START is taken low, which re-inits the whole BIST solution. + // + TX_DONE: begin + if (!start) begin + tx_state <= TX_DONE; + end else begin + tx_state <= TX_IDLE; + end + i_tvalid <= 1'b0; + i_tdata <= 64'd0; + i_tlast <= 1'b0; + + end + endcase // case (tx_state) + end + + // + // Receiver + // + always @(posedge clk) + if (reset) + begin + rx_delay <= 0; + rx_count <= 0; + rx_data <= 0; + o_tready <= 1'b0; + rx_state <= RX_IDLE; + fail <= 1'b0; + done <= 1'b0; + + end + else begin + case (rx_state) + RX_IDLE: begin + rx_delay <= 0; + o_tready <= 1'b0; + rx_data <= 0; + rx_count <= 4; + fail <= 1'b0; + done <= 1'b0; + // Not accepting data whilst Idle, + // switch to active when packet arrives + if (o_tvalid) begin + o_tready <= 1'b1; + rx_state <= RX_ACTIVE; + end else + rx_state <= RX_IDLE; + end + + RX_ACTIVE: begin + o_tready <= 1'b1; + if (o_tvalid) +// if (o_tdata != {rx_data,rx_data+16'd1,rx_data+16'd2,rx_data+16'd3}) + if (o_tdata != {4{(rx_data[2]?16'hffff:16'h0000)^rx_data[15:0]}}) + begin + $display("o_tdata: %x != expected: %x @ time: %d",o_tdata, +// {rx_data,rx_data+16'd1,rx_data+16'd2,rx_data+16'd3}, + {4{(rx_data[2]?16'hffff:16'h0000)^rx_data[15:0]}}, + $time); + rx_state <= RX_FAIL; + end + else + // Should last be asserted? + if (rx_data == rx_count) + // ...last not asserted when it should be! + if (~(o_tlast===1)) begin + $display("o_tlast not asserted when it should be @ time: %d",$time); + rx_state <= RX_FAIL; + end else begin + // End of packet, set up to RX next + rx_data <= 0; + rx_count <= rx_count + 4; + rx_delay <= bist_rx_delay; + if (rx_count == `MTU) begin + rx_state <= RX_DONE; + end else begin + rx_state <= RX_WAIT; + end + o_tready <= 1'b0; + end + else + // ...last asserted when it should not be! + if (~(o_tlast===0)) begin + $display("o_tlast asserted when it should not be @ time: %d",$time); + rx_state <= RX_FAIL; + end else begin + // Still in packet body + rx_data <= rx_data + 4; + rx_delay <= bist_rx_delay; + rx_state <= RX_WAIT; + o_tready <= 1'b0; + end + else + // Nothing to do this cycle + rx_state <= RX_ACTIVE; + end // case: RX_ACTIVE + + // To simulate the radio consuming samples at a steady rate set by the decimation + // have a programable delay here + RX_WAIT: begin + if (rx_delay == 0) begin + rx_state <= RX_ACTIVE; + o_tready <= 1'b1; + end else begin + rx_delay <= rx_delay - 1; + rx_state <= RX_WAIT; + end + end + + + RX_FAIL: begin + o_tready <= 1'b0; + done <= 1'b1; + fail <= 1'b1; + // If start is deasserted allow BIST logic to reset and rearm + if (start) + rx_state <= RX_FAIL; + else + rx_state <= RX_IDLE; + + end + + RX_DONE: begin + o_tready <= 1'b0; + done <= 1'b1; + fail <= 1'b0; + // If start is asserted allow BIST logic to reset, rearm & restart + if (!start) + rx_state <= RX_DONE; + else + rx_state <= RX_IDLE; + + end + + endcase // case (rx_state) + end + + + +endmodule + + + diff --git a/fpga/usrp3/lib/axi/axi_defs.v b/fpga/usrp3/lib/axi/axi_defs.v new file mode 100644 index 000000000..5162c20ba --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_defs.v @@ -0,0 +1,34 @@ +// +// AXI4 Burst enumeration +// +`define AXI4_BURST_FIXED 2'b00 +`define AXI4_BURST_INCR 2'b01 +`define AXI4_BURST_WRAP 2'b10 +`define AXI4_BURST_RSVD 2'b11 +// +// AXI4 response code enumeration +// +`define AXI4_RESP_OKAY 2'b00 +`define AXI4_RESP_EXOKAY 2'b01 +`define AXI4_RESP_SLVERR 2'b10 +`define AXI4_RESP_DECERR 2'b11 +// +// AXI4 lock enumeration +// +`define AXI4_LOCK_NORMAL 1'b0 +`define AXI4_LOCK_EXCLUSIVE 1'b1 +// +// AXI4 memory attrubutes +// +`define AXI4_CACHE_ALLOCATE 4'h8 +`define AXI4_CACHE_OTHER_ALLOCATE 4'h4 +`define AXI4_CACHE_MODIFIABLE 4'h2 +`define AXI4_CACHE_BUFFERABLE 4'h1 +// +// AXI4 PROT attributes +// +`define AXI4_PROT_PRIVILEDGED 3'h1 +`define AXI4_PROT_NON_SECURE 3'h2 +`define AXI4_PROT_INSTRUCTION 3'h4 + + diff --git a/fpga/usrp3/lib/axi/axi_dma_master.v b/fpga/usrp3/lib/axi/axi_dma_master.v new file mode 100644 index 000000000..8222019de --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_dma_master.v @@ -0,0 +1,538 @@ + +`include "axi_defs.v" + +`define DEBUG if (1) + +module axi_dma_master + ( + input aclk, // Global AXI clock + input areset, // Global AXI reset + // + // AXI Write address channel + // + output [0 : 0] m_axi_awid, // Write address ID. This signal is the identification tag for the write address signals + output reg [31 : 0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst + output reg [7 : 0] m_axi_awlen, // Burst length. The burst length gives the exact number of transfers in a burst. + output [2 : 0] m_axi_awsize, // Burst size. This signal indicates the size of each transfer in the burst. + output [1 : 0] m_axi_awburst, // Burst type. The burst type and the size information, determine how the address is calculated + output [0 : 0] m_axi_awlock, // Lock type. Provides additional information about the atomic characteristics of the transfer. + output [3 : 0] m_axi_awcache, // Memory type. This signal indicates how transactions are required to progress + output [2 : 0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction + output [3 : 0] m_axi_awqos, // Quality of Service, QoS. The QoS identifier sent for each write transaction + output [3 : 0] m_axi_awregion, // Region identifier. Permits a single physical interface on a slave to be re-used. + output [0 : 0] m_axi_awuser, // User signal. Optional User-defined signal in the write address channel. + output reg m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr + input m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Write data channel. + // + output [63 : 0] m_axi_wdata, // Write data + output [7 : 0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data. + output reg m_axi_wlast, // Write last. This signal indicates the last transfer in a write burst + output [0 : 0] m_axi_wuser, // User signal. Optional User-defined signal in the write data channel. + output m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available. + input m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data. + // + // AXI Write response channel signals + // + input [0 : 0] m_axi_bid, // Response ID tag. This signal is the ID tag of the write response. + input [1 : 0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction. + input [0 : 0] m_axi_buser, // User signal. Optional User-defined signal in the write response channel. + input m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response + output reg m_axi_bready, // Response ready. This signal indicates that the master can accept a write response + // + // AXI Read address channel + // + output [0 : 0] m_axi_arid, // Read address ID. This signal is the identification tag for the read address group of signals + output reg [31 : 0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst + output reg [7 : 0] m_axi_arlen, // Burst length. This signal indicates the exact number of transfers in a burst. + output [2 : 0] m_axi_arsize, // Burst size. This signal indicates the size of each transfer in the burst. + output [1 : 0] m_axi_arburst, // Burst type. The burst type and the size information determine how the address for each transfer + output [0 : 0] m_axi_arlock, // Lock type. This signal provides additional information about the atomic characteristics + output [3 : 0] m_axi_arcache, // Memory type. This signal indicates how transactions are required to progress + output [2 : 0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction + output [3 : 0] m_axi_arqos, // Quality of Service, QoS. QoS identifier sent for each read transaction. + output [3 : 0] m_axi_arregion, // Region identifier. Permits a single physical interface on a slave to be re-used + output [0 : 0] m_axi_aruser, // User signal. Optional User-defined signal in the read address channel. + output reg m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr + input m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Read data channel + // + input [0 : 0] m_axi_rid, // Read ID tag. This signal is the identification tag for the read data group of signals + input [63 : 0] m_axi_rdata, // Read data. + input [1 : 0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer + input m_axi_rlast, // Read last. This signal indicates the last transfer in a read burst. + input [0 : 0] m_axi_ruser, // User signal. Optional User-defined signal in the read data channel. + input m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data. + output m_axi_rready, // Read ready. This signal indicates that the master can accept the read data and response + // + // DMA interface for Write transaction + // + input [31:0] write_addr, // Byte address for start of write transaction (should be 64bit alligned) + input [7:0] write_count, // Count of 64bit words to write. (minus one) + input write_ctrl_valid, + output reg write_ctrl_ready, + input [63:0] write_data, + input write_data_valid, + output write_data_ready, + // + // DMA interface for Read + // + input [31:0] read_addr, // Byte address for start of read transaction (should be 64bit alligned) + input [7:0] read_count, // Count of 64bit words to read. + input read_ctrl_valid, + output reg read_ctrl_ready, + output [63:0] read_data, + output read_data_valid, + input read_data_ready, + // + // Debug Bus + // + output [31:0] debug + + ); + + + localparam AW_IDLE = 0; + localparam WAIT_AWREADY = 1; + localparam WAIT_BVALID = 2; + localparam AW_ERROR = 3; + + reg [1:0] write_addr_state; + reg [7:0] write_data_count; // Count write transfers. + reg enable_data_write; + + localparam DW_IDLE = 0; + localparam DW_RUN = 1; + localparam DW_LAST = 2; + + reg [1:0] write_data_state; + + localparam AR_IDLE = 0; + localparam WAIT_ARREADY = 1; + localparam WAIT_READ_DONE = 2; + localparam AR_ERROR = 3; + + reg [1:0] read_addr_state; + + localparam DR_IDLE = 0; + localparam DR_RUN = 1; + localparam DR_WAIT_ERROR = 2; + localparam DR_ERROR = 3; + + reg [1:0] read_data_state; + reg [7:0] read_data_count; + reg enable_data_read; + + /////////////////////////// + // DEBUG + /////////////////////////// + assign debug= {24'h0,write_addr_state[1:0],write_data_state[1:0],read_addr_state[1:0],read_data_state[1:0]}; + + + // + // + // + + + + + ///////////////////////////////////////////////////////////////////////////////// + // + // AXI Write address channel + // + ///////////////////////////////////////////////////////////////////////////////// + assign m_axi_awid = 1'b0; + assign m_axi_awsize = 3'h3; // 8 bytes. + assign m_axi_awburst = `AXI4_BURST_INCR; + assign m_axi_awlock = `AXI4_LOCK_NORMAL; + assign m_axi_awcache = `AXI4_CACHE_ALLOCATE | `AXI4_CACHE_OTHER_ALLOCATE | `AXI4_CACHE_MODIFIABLE | `AXI4_CACHE_BUFFERABLE; + assign m_axi_awprot = `AXI4_PROT_NON_SECURE; + assign m_axi_awqos = 4'h0; + assign m_axi_awregion = 4'h0; + assign m_axi_awuser = 1'b0; + + + // + // AXI Write address state machine + // + always @(posedge aclk) + if (areset) begin + write_ctrl_ready <= 1'b0; + write_addr_state <= AW_IDLE; + m_axi_awaddr[31:0] <= 32'h0; + m_axi_awlen[7:0] <= 8'h0; + m_axi_awvalid <= 1'b0; + m_axi_bready <= 1'b0; + end else + case (write_addr_state) + // + // AW_IDLE + // We are ready to accept a new write transaction. + // + AW_IDLE: begin + // Premptively accept new write transaction since we are idle. + write_ctrl_ready <= 1'b1; + // No need to be waiting for a response while idle. + m_axi_bready <= 1'b0; + // If we are offered a new transaction then..... + if (write_ctrl_valid) begin + // Drive all the relevent AXI4 write address channel signals next cycle. + m_axi_awaddr[31:0] <= write_addr[31:0]; + m_axi_awlen[7:0] <= {write_count}; + m_axi_awvalid <= 1'b1; + // If the AXI4 write channel is pre-emptively accepting the transaction... + if (m_axi_awready == 1'b1) begin + // ...go straight to looking for a transaction response... + `DEBUG $display("WRITE TRANSACTION: ADDR: %x LEN: %x @ time %d",write_addr[31:0],write_count,$time); + write_addr_state <= WAIT_BVALID; + m_axi_bready <= 1'b1; + end else begin + // ...otherwise wait to get the transaction accepted. + write_addr_state <= WAIT_AWREADY; + end + end + end + // + // WAIT_AWREADY + // Waiting for AXI4 slave to accept new write transaction. + // + WAIT_AWREADY: begin + write_ctrl_ready <= 1'b0; + // If the AXI4 write channel is accepting the transaction... + if (m_axi_awready == 1'b1) begin + // ...go to looking for a transaction response... + write_addr_state <= WAIT_BVALID; + m_axi_bready <= 1'b1; + `DEBUG $display("WRITE TRANSACTION: ADDR: %x LEN: %x @ time %d",m_axi_awaddr[31:0],m_axi_awlen[7:0],$time); + end else begin + // ...otherwise wait to get the trasaction accepted. + write_addr_state <= WAIT_AWREADY; + end + end // case: WAIT_AWREADY + // + // WAIT_BVALID + // Write transaction has been accepted, now waiting for a response to signal it's sucsesful. + // Ignoring ID tag for the moment + // + WAIT_BVALID: begin + write_ctrl_ready <= 1'b0; + m_axi_awvalid <= 1'b0; + // Wait for response channel to signal how write transaction went down.... + if (m_axi_bvalid == 1'b1) begin + if ((m_axi_bresp == `AXI4_RESP_OKAY) || (m_axi_bresp == `AXI4_RESP_EXOKAY)) begin + // ....it went well, we are ready to start something new. + write_addr_state <= AW_IDLE; + m_axi_bready <= 1'b0; + write_ctrl_ready <= 1'b1; // Ready to run again as soon as we hit idle. + end else if ((m_axi_bresp == `AXI4_RESP_SLVERR) || (m_axi_bresp == `AXI4_RESP_DECERR)) begin + // ....things got ugly, retreat to an error stat and wait for intervention. + write_addr_state <= AW_ERROR; + m_axi_bready <= 1'b0; + end + end else begin + write_addr_state <= WAIT_BVALID; + m_axi_bready <= 1'b1; + end + end // case: WAIT_BVALID + // + // AW_ERROR + // Something bad happened, going to need external intervention to restore a safe state. + // + AW_ERROR: begin + write_ctrl_ready <= 1'b0; + write_addr_state <= AW_ERROR; + m_axi_awaddr[31:0] <= 32'h0; + m_axi_awlen[7:0] <= 8'h0; + m_axi_awvalid <= 1'b0; + m_axi_bready <= 1'b0; + end + endcase // case(write_addr_state) + + ///////////////////////////////////////////////////////////////////////////////// + // + // AXI Write data channel + // + ///////////////////////////////////////////////////////////////////////////////// + assign m_axi_wstrb = 8'hff; + assign m_axi_wuser = 1'b0; + + // + // AXI Write data state machine + // + always @(posedge aclk) + if (areset) begin + write_data_state <= AW_IDLE; + write_data_count <= 1; + enable_data_write <= 1'b0; + m_axi_wlast <= 1'b0; + + end else + case (write_data_state) + // + // DW_IDLE + // Sit in this state until presented with the control details of a new write transaction. + // + DW_IDLE: begin + write_data_count <= 1; + m_axi_wlast <= 1'b0; + + if (write_ctrl_valid && write_ctrl_ready) begin + enable_data_write <= 1'b1; + if (write_count[7:0] == 8'h0) begin + // Single transfer transaction + write_data_state <= DW_LAST; + m_axi_wlast <= 1'b1; + end else begin + write_data_state <= DW_RUN; + end + end else begin + write_data_state <= DW_IDLE; + end + end + // + // DW_RUN + // + DW_RUN : begin + enable_data_write <= 1'b1; + m_axi_wlast <= 1'b0; + + if (write_data_valid && m_axi_wready) begin + // Single write transfer + write_data_count <= write_data_count + 1; + + if (write_data_count == m_axi_awlen[7:0]) begin + write_data_state <= DW_LAST; + m_axi_wlast <= 1'b1; + end else begin + write_data_state <= DW_RUN; + end + end else begin + write_data_state <= DW_RUN; + end + end + // + // DW_LAST + // + DW_LAST: begin + if (write_data_valid && m_axi_wready) begin + enable_data_write <= 1'b0; + write_data_state <= DW_IDLE; + m_axi_wlast <= 1'b0; + end else begin + enable_data_write <= 1'b1; + write_data_state <= DW_LAST; + m_axi_wlast <= 1'b1; + end + end // case: DW_LAST + // + default: + write_data_state <= DW_IDLE; + + endcase // case(write_data_state) + + + assign m_axi_wdata = write_data; + assign m_axi_wvalid = enable_data_write && write_data_valid; + assign write_data_ready = enable_data_write && m_axi_wready; + + ///////////////////////////////////////////////////////////////////////////////// + // + // AXI Read address channel + // + ///////////////////////////////////////////////////////////////////////////////// + assign m_axi_arid = 1'b0; + assign m_axi_arsize = 3'h3; // 8 bytes + assign m_axi_arburst = `AXI4_BURST_INCR; + assign m_axi_arlock = `AXI4_LOCK_NORMAL; + assign m_axi_arcache = `AXI4_CACHE_ALLOCATE | `AXI4_CACHE_OTHER_ALLOCATE | `AXI4_CACHE_MODIFIABLE | `AXI4_CACHE_BUFFERABLE; + assign m_axi_arprot = `AXI4_PROT_NON_SECURE; + assign m_axi_arqos = 4'h0; + assign m_axi_arregion = 4'h0; + assign m_axi_aruser = 1'b0; + + + // + // AXI Read address state machine + // + always @(posedge aclk) + if (areset) begin + read_ctrl_ready <= 1'b0; + read_addr_state <= AR_IDLE; + m_axi_araddr[31:0] <= 32'h0; + m_axi_arlen[7:0] <= 8'h0; + m_axi_arvalid <= 1'b0; + end else + case (read_addr_state) + // + // AR_IDLE + // We are ready to accept a new read transaction. + // + AR_IDLE: begin + // Premptively accept new read transaction since we are idle. + read_ctrl_ready <= 1'b1; + // If we are offered a new transaction then..... + if (read_ctrl_valid) begin + // Drive all the relevent AXI4 read address channel signals next cycle. + m_axi_araddr[31:0] <= read_addr[31:0]; + m_axi_arlen[7:0] <= {read_count}; + m_axi_arvalid <= 1'b1; + // If the AXI4 read channel is pre-emptively accepting the transaction... + if (m_axi_arready == 1'b1) begin + // ...go straight to looking for the transaction to complete + `DEBUG $display("READ TRANSACTION: ADDR: %x LEN: %x @ time %d",read_addr[31:0],read_count,$time); + read_addr_state <= WAIT_READ_DONE; + end else begin + // ...otherwise wait to get the transaction accepted. + read_addr_state <= WAIT_ARREADY; + end + end + end + // + // WAIT_ARREADY + // Waiting for AXI4 slave to accept new read transaction. + // + WAIT_ARREADY: begin + read_ctrl_ready <= 1'b0; + // If the AXI4 read channel is accepting the transaction... + if (m_axi_arready == 1'b1) begin + // ...go to looking for the transaction to complete... + read_addr_state <= WAIT_READ_DONE; + `DEBUG $display("READ TRANSACTION: ADDR: %x LEN: %x @ time %d",m_axi_araddr[31:0],m_axi_arlen[7:0],$time); + end else begin + // ...otherwise wait to get the trasaction accepted. + read_addr_state <= WAIT_ARREADY; + end + end // case: WAIT_ARREADY + // + // WAIT_READ_DONE + // Read transaction has been accepted, now waiting for the data transfer to complete + // Ignoring ID tag for the moment + // + WAIT_READ_DONE: begin + read_ctrl_ready <= 1'b0; + m_axi_arvalid <= 1'b0; + // Wait for read transaction to complete + if (read_data_state == DR_IDLE) begin + // ....it went well, we are ready to start something new. + read_addr_state <= AR_IDLE; + read_ctrl_ready <= 1'b1; // Ready to run again as soon as we hit idle. + end else if (read_data_state == DR_ERROR) begin + // ....things got ugly, retreat to an error stat and wait for intervention. + read_addr_state <= AR_ERROR; + end else begin + read_addr_state <= WAIT_READ_DONE; + end + end // case: WAIT_BVALID + // + // AR_ERROR + // Something bad happened, going to need external intervention to restore a safe state. + // + AR_ERROR: begin + read_ctrl_ready <= 1'b0; + read_addr_state <= AR_ERROR; + m_axi_araddr[31:0] <= 32'h0; + m_axi_arlen[7:0] <= 8'h0; + m_axi_arvalid <= 1'b0; + end + endcase // case(read_addr_state) + + ///////////////////////////////////////////////////////////////////////////////// + // + // AXI Read data channel + // + ///////////////////////////////////////////////////////////////////////////////// + + + // + // AXI Read data state machine + // + always @(posedge aclk) + if (areset) begin + read_data_state <= AR_IDLE; + read_data_count <= 0; + enable_data_read <= 1'b0; + + end else + case (read_data_state) + // + // DR_IDLE + // Sit in this state until presented with the control details of a new read transaction. + // + DR_IDLE: begin + read_data_count <= 0; + + if (read_ctrl_valid && read_ctrl_ready) begin + enable_data_read <= 1'b1; + read_data_state <= DR_RUN; + end else begin + read_data_state <= DR_IDLE; + end + end + // + // DR_RUN + // Sit here counting read transfers. If any have error's shift to error state. + // + DR_RUN : begin + enable_data_read <= 1'b1; + + if (read_data_ready && m_axi_rvalid) begin + // Single read transfer + read_data_count <= read_data_count + 1; + if ((m_axi_rresp == `AXI4_RESP_SLVERR) || (m_axi_rresp == `AXI4_RESP_DECERR)) begin + if (m_axi_rlast) begin + read_data_state <= DR_ERROR; + end else begin + read_data_state <= DR_WAIT_ERROR; + end + end else if (m_axi_rlast) begin // Implicitly good response signalled this transfer. + if (read_data_count == m_axi_arlen[7:0]) begin + read_data_state <= DR_IDLE; + end else begin + read_data_state <= DR_ERROR; + end + end else begin + read_data_state <= DR_RUN; + end + end else begin + read_data_state <= DR_RUN; + end + end + // + // DR_WAIT_ERROR + // Something bad happened, wait for last signalled in this burst + // + DR_WAIT_ERROR: begin + if (read_data_ready && m_axi_rvalid && m_axi_rlast) begin + enable_data_read <= 1'b0; + read_data_state <= DR_ERROR; + end else begin + enable_data_read <= 1'b1; + read_data_state <= DR_WAIT_ERROR; + end + end // case: DR_WAIT_ERROR + // + // DR_ERROR + // Something bad happened, going to need external intervention to restore a safe state. + // + DR_ERROR: begin + enable_data_read <= 1'b0; + read_data_state <= DR_ERROR; + end // case: DR_ERROR + + + endcase // case(read_data_state) + + + assign read_data = m_axi_rdata; + assign m_axi_rready = enable_data_read && read_data_ready; + assign read_data_valid = enable_data_read && m_axi_rvalid; + +endmodule // axi_dma_master + + + + + +
\ No newline at end of file diff --git a/fpga/usrp3/lib/axi/axi_dma_master_tb.v b/fpga/usrp3/lib/axi/axi_dma_master_tb.v new file mode 100644 index 000000000..75894fe1a --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_dma_master_tb.v @@ -0,0 +1,165 @@ +module axi_dma_master_tb; + + + + wire aclk; // Global AXI clock + wire aresetn; // Global AXI reset, active low. + // + // AXI Write address channel + // + wire [0 : 0] m_axi_awid; // Write address ID. This signal is the identification tag for the write address signals + wire [31 : 0] m_axi_awaddr; // Write address. The write address gives the address of the first transfer in a write burst + wire [7 : 0] m_axi_awlen; // Burst length. The burst length gives the exact number of transfers in a burst. + wire [2 : 0] m_axi_awsize; // Burst size. This signal indicates the size of each transfer in the burst. + wire [1 : 0] m_axi_awburst; // Burst type. The burst type and the size information, determine how the address is calculated + wire [0 : 0] m_axi_awlock; // Lock type. Provides additional information about the atomic characteristics of the transfer. + wire [3 : 0] m_axi_awcache; // Memory type. This signal indicates how transactions are required to progress + wire [2 : 0] m_axi_awprot; // Protection type. This signal indicates the privilege and security level of the transaction + wire [3 : 0] m_axi_awqos; // Quality of Service, QoS. The QoS identifier sent for each write transaction + wire [3 : 0] m_axi_awregion; // Region identifier. Permits a single physical interface on a slave to be re-used. + wire [0 : 0] m_axi_awuser; // User signal. Optional User-defined signal in the write address channel. + wire m_axi_awvalid; // Write address valid. This signal indicates that the channel is signaling valid write addr + wire m_axi_awready; // Write address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Write data channel. + // + wire [63 : 0] m_axi_wdata; // Write data + wire [7 : 0] m_axi_wstrb; // Write strobes. This signal indicates which byte lanes hold valid data. + wire m_axi_wlast; // Write last. This signal indicates the last transfer in a write burst + wire [0 : 0] m_axi_wuser; // User signal. Optional User-defined signal in the write data channel. + wire m_axi_wvalid; // Write valid. This signal indicates that valid write data and strobes are available. + wire m_axi_wready; // Write ready. This signal indicates that the slave can accept the write data. + // + // AXI Write response channel signals + // + wire [0 : 0] m_axi_bid; // Response ID tag. This signal is the ID tag of the write response. + wire [1 : 0] m_axi_bresp; // Write response. This signal indicates the status of the write transaction. + wire [0 : 0] m_axi_buser; // User signal. Optional User-defined signal in the write response channel. + wire m_axi_bvalid; // Write response valid. This signal indicates that the channel is signaling a valid response + wire m_axi_bready; // Response ready. This signal indicates that the master can accept a write response + // + // AXI Read address channel + // + wire [0 : 0] m_axi_arid; // Read address ID. This signal is the identification tag for the read address group of signals + wire [31 : 0] m_axi_araddr; // Read address. The read address gives the address of the first transfer in a read burst + wire [7 : 0] m_axi_arlen; // Burst length. This signal indicates the exact number of transfers in a burst. + wire [2 : 0] m_axi_arsize; // Burst size. This signal indicates the size of each transfer in the burst. + wire [1 : 0] m_axi_arburst; // Burst type. The burst type and the size information determine how the address for each transfer + wire [0 : 0] m_axi_arlock; // Lock type. This signal provides additional information about the atomic characteristics + wire [3 : 0] m_axi_arcache; // Memory type. This signal indicates how transactions are required to progress + wire [2 : 0] m_axi_arprot; // Protection type. This signal indicates the privilege and security level of the transaction + wire [3 : 0] m_axi_arqos; // Quality of Service, QoS. QoS identifier sent for each read transaction. + wire [3 : 0] m_axi_arregion; // Region identifier. Permits a single physical interface on a slave to be re-used + wire [0 : 0] m_axi_aruser; // User signal. Optional User-defined signal in the read address channel. + wire m_axi_arvalid; // Read address valid. This signal indicates that the channel is signaling valid read addr + wire m_axi_arready; // Read address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Read data channel + // + wire [0 : 0] m_axi_rid; // Read ID tag. This signal is the identification tag for the read data group of signals + wire [63 : 0] m_axi_rdata; // Read data. + wire [1 : 0] m_axi_rresp; // Read response. This signal indicates the status of the read transfer + wire m_axi_rlast; // Read last. This signal indicates the last transfer in a read burst. + wire [0 : 0] m_axi_ruser; // User signal. Optional User-defined signal in the read data channel. + wire m_axi_rvalid; // Read valid. This signal indicates that the channel is signaling the required read data. + wire m_axi_rready; // Read ready. This signal indicates that the master can accept the read data and response + // + // DMA interface for Write transaction + // + wire [31:0] write_addr; // Byte address for start of write transaction (should be 64bit alligned) + wire [3:0] write_count; // Count of 64 words to write. + wire write_ctrl_valid; + wire write_ctrl_ready; + wire [63:0] write_data; + wire write_data_valid; + wire write_data_ready; + // + // DMA interface for Read + // + wire [31:0] read_addr; // Byte address for start of read transaction (should be 64bit alligned) + wire [3:0] read_count; // Count of 64 words to read. + wire read_ctrl_valid; + wire read_ctrl_ready; + wire [63:0] read_data; + wire read_data_valid; + wire read_data_ready; + + + + axi_dma_master axi_dma_master_i1 + ( + .aclk(s_aclk), // input s_aclk + .aresetn(s_aresetn), // input s_aresetn + // + .s_axi_awid(s_axi_awid), // input [0 : 0] s_axi_awid + .s_axi_awaddr(s_axi_awaddr), // input [31 : 0] s_axi_awaddr + .s_axi_awlen(s_axi_awlen), // input [7 : 0] s_axi_awlen + .s_axi_awsize(s_axi_awsize), // input [2 : 0] s_axi_awsize + .s_axi_awburst(s_axi_awburst), // input [1 : 0] s_axi_awburst + .s_axi_awvalid(s_axi_awvalid), // input s_axi_awvalid + .s_axi_awready(s_axi_awready), // output s_axi_awready + // + .s_axi_wdata(s_axi_wdata), // input [63 : 0] s_axi_wdata + .s_axi_wstrb(s_axi_wstrb), // input [7 : 0] s_axi_wstrb + .s_axi_wlast(s_axi_wlast), // input s_axi_wlast + .s_axi_wvalid(s_axi_wvalid), // input s_axi_wvalid + .s_axi_wready(s_axi_wready), // output s_axi_wready + // + .s_axi_bid(s_axi_bid), // output [0 : 0] s_axi_bid + .s_axi_bresp(s_axi_bresp), // output [1 : 0] s_axi_bresp + .s_axi_bvalid(s_axi_bvalid), // output s_axi_bvalid + .s_axi_bready(s_axi_bready), // input s_axi_bready + // + .s_axi_arid(s_axi_arid), // input [0 : 0] s_axi_arid + .s_axi_araddr(s_axi_araddr), // input [31 : 0] s_axi_araddr + .s_axi_arlen(s_axi_arlen), // input [7 : 0] s_axi_arlen + .s_axi_arsize(s_axi_arsize), // input [2 : 0] s_axi_arsize + .s_axi_arburst(s_axi_arburst), // input [1 : 0] s_axi_arburst + .s_axi_arvalid(s_axi_arvalid), // input s_axi_arvalid + .s_axi_arready(s_axi_arready), // output s_axi_arready + // + .s_axi_rid(s_axi_rid), // output [0 : 0] s_axi_rid + .s_axi_rdata(s_axi_rdata), // output [63 : 0] s_axi_rdata + .s_axi_rresp(s_axi_rresp), // output [1 : 0] s_axi_rresp + .s_axi_rlast(s_axi_rlast), // output s_axi_rlast + .s_axi_rvalid(s_axi_rvalid), // output s_axi_rvalid + .s_axi_rready(s_axi_rready) // input s_axi_rready + ); + + + axi4_bram_1kx64 axi4_bram_1kx64_i1 + ( + .s_aclk(s_aclk), // input s_aclk + .s_aresetn(s_aresetn), // input s_aresetn + .s_axi_awid(s_axi_awid), // input [0 : 0] s_axi_awid + .s_axi_awaddr(s_axi_awaddr), // input [31 : 0] s_axi_awaddr + .s_axi_awlen(s_axi_awlen), // input [7 : 0] s_axi_awlen + .s_axi_awsize(s_axi_awsize), // input [2 : 0] s_axi_awsize + .s_axi_awburst(s_axi_awburst), // input [1 : 0] s_axi_awburst + .s_axi_awvalid(s_axi_awvalid), // input s_axi_awvalid + .s_axi_awready(s_axi_awready), // output s_axi_awready + .s_axi_wdata(s_axi_wdata), // input [63 : 0] s_axi_wdata + .s_axi_wstrb(s_axi_wstrb), // input [7 : 0] s_axi_wstrb + .s_axi_wlast(s_axi_wlast), // input s_axi_wlast + .s_axi_wvalid(s_axi_wvalid), // input s_axi_wvalid + .s_axi_wready(s_axi_wready), // output s_axi_wready + .s_axi_bid(s_axi_bid), // output [0 : 0] s_axi_bid + .s_axi_bresp(s_axi_bresp), // output [1 : 0] s_axi_bresp + .s_axi_bvalid(s_axi_bvalid), // output s_axi_bvalid + .s_axi_bready(s_axi_bready), // input s_axi_bready + .s_axi_arid(s_axi_arid), // input [0 : 0] s_axi_arid + .s_axi_araddr(s_axi_araddr), // input [31 : 0] s_axi_araddr + .s_axi_arlen(s_axi_arlen), // input [7 : 0] s_axi_arlen + .s_axi_arsize(s_axi_arsize), // input [2 : 0] s_axi_arsize + .s_axi_arburst(s_axi_arburst), // input [1 : 0] s_axi_arburst + .s_axi_arvalid(s_axi_arvalid), // input s_axi_arvalid + .s_axi_arready(s_axi_arready), // output s_axi_arready + .s_axi_rid(s_axi_rid), // output [0 : 0] s_axi_rid + .s_axi_rdata(s_axi_rdata), // output [63 : 0] s_axi_rdata + .s_axi_rresp(s_axi_rresp), // output [1 : 0] s_axi_rresp + .s_axi_rlast(s_axi_rlast), // output s_axi_rlast + .s_axi_rvalid(s_axi_rvalid), // output s_axi_rvalid + .s_axi_rready(s_axi_rready) // input s_axi_rready + ); + +endmodule // axi_dma_master_tb diff --git a/fpga/usrp3/lib/axi/axi_dram_fifo.v b/fpga/usrp3/lib/axi/axi_dram_fifo.v new file mode 100644 index 000000000..52626123e --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_dram_fifo.v @@ -0,0 +1,816 @@ + +// +// There are various obligations put on this code not present in regular BRAM based FIFO's +// +// 1) Bursts are way more efficient, use local small FIFO's to interact with DRAM +// 2) Never cross a 4KByte address boundry within a single transaction, this is an AXI4 rule. +// 3) 2^SIZE must be greater than 4KB so that the 4KByte page protection also deals with FIFO wrap corner case. +// +module axi_dram_fifo + // NOTE: SIZE is log2 of size of FIFO buffer in bytes. i.e 13 for 8KBytes which is 1kx64 + #(parameter BASE=0, SIZE=16, TIMEOUT=64) + ( + input bus_clk, + input bus_reset, + input clear, + input dram_clk, + input dram_reset, + // + // AXI Write address channel + // + output [0 : 0] m_axi_awid, // Write address ID. This signal is the identification tag for the write address signals + output [31 : 0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst + output [7 : 0] m_axi_awlen, // Burst length. The burst length gives the exact number of transfers in a burst. + output [2 : 0] m_axi_awsize, // Burst size. This signal indicates the size of each transfer in the burst. + output [1 : 0] m_axi_awburst, // Burst type. The burst type and the size information, determine how the address is calculated + output [0 : 0] m_axi_awlock, // Lock type. Provides additional information about the atomic characteristics of the transfer. + output [3 : 0] m_axi_awcache, // Memory type. This signal indicates how transactions are required to progress + output [2 : 0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction + output [3 : 0] m_axi_awqos, // Quality of Service, QoS. The QoS identifier sent for each write transaction + output [3 : 0] m_axi_awregion, // Region identifier. Permits a single physical interface on a slave to be re-used. + output [0 : 0] m_axi_awuser, // User signal. Optional User-defined signal in the write address channel. + output m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr + input m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Write data channel. + // + output [63 : 0] m_axi_wdata, // Write data + output [7 : 0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data. + output m_axi_wlast, // Write last. This signal indicates the last transfer in a write burst + output [0 : 0] m_axi_wuser, // User signal. Optional User-defined signal in the write data channel. + output m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available. + input m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data. + // + // AXI Write response channel signals + // + input [0 : 0] m_axi_bid, // Response ID tag. This signal is the ID tag of the write response. + input [1 : 0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction. + input [0 : 0] m_axi_buser, // User signal. Optional User-defined signal in the write response channel. + input m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response + output m_axi_bready, // Response ready. This signal indicates that the master can accept a write response + // + // AXI Read address channel + // + output [0 : 0] m_axi_arid, // Read address ID. This signal is the identification tag for the read address group of signals + output [31 : 0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst + output [7 : 0] m_axi_arlen, // Burst length. This signal indicates the exact number of transfers in a burst. + output [2 : 0] m_axi_arsize, // Burst size. This signal indicates the size of each transfer in the burst. + output [1 : 0] m_axi_arburst, // Burst type. The burst type and the size information determine how the address for each transfer + output [0 : 0] m_axi_arlock, // Lock type. This signal provides additional information about the atomic characteristics + output [3 : 0] m_axi_arcache, // Memory type. This signal indicates how transactions are required to progress + output [2 : 0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction + output [3 : 0] m_axi_arqos, // Quality of Service, QoS. QoS identifier sent for each read transaction. + output [3 : 0] m_axi_arregion, // Region identifier. Permits a single physical interface on a slave to be re-used + output [0 : 0] m_axi_aruser, // User signal. Optional User-defined signal in the read address channel. + output m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr + input m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Read data channel + // + input [0 : 0] m_axi_rid, // Read ID tag. This signal is the identification tag for the read data group of signals + input [63 : 0] m_axi_rdata, // Read data. + input [1 : 0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer + input m_axi_rlast, // Read last. This signal indicates the last transfer in a read burst. + input [0 : 0] m_axi_ruser, // User signal. Optional User-defined signal in the read data channel. + input m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data. + output m_axi_rready, // Read ready. This signal indicates that the master can accept the read data and response + // + // CHDR friendly AXI stream input + // + input [63:0] i_tdata, + input i_tlast, + input i_tvalid, + output i_tready, + // + // CHDR friendly AXI Stream output + // + output [63:0] o_tdata, + output o_tlast, + output o_tvalid, + input o_tready, + // + // + // + input [15:0] supress_threshold, + input supress_enable, + // + // Debug Bus + // + output [197:0] debug + ); + + // + // We are only solving for width 64bits here, since it's our standard CHDR quanta + // + localparam WIDTH=64; + + // + // Input side declarations + // + localparam INPUT_IDLE = 0; + localparam INPUT1 = 1; + localparam INPUT2 = 2; + localparam INPUT3 = 3; + localparam INPUT4 = 4; + localparam INPUT5 = 5; + localparam INPUT6 = 6; + + reg [2:0] input_state; + reg input_timeout_triggered; + reg input_timeout_reset; + reg [8:0] input_timeout_count; + reg [31:0] write_addr; + reg write_ctrl_valid; + wire write_ctrl_ready; + reg [7:0] write_count; + reg update_write; + wire [63:0] write_data; + wire write_data_valid; + wire write_data_ready; + + // + // Output side declarations + // + localparam OUTPUT_IDLE = 0; + localparam OUTPUT1 = 1; + localparam OUTPUT2 = 2; + localparam OUTPUT3 = 3; + localparam OUTPUT4 = 4; + localparam OUTPUT5 = 5; + localparam OUTPUT6 = 6; + + reg [2:0] output_state; + reg output_timeout_triggered; + reg output_timeout_reset; + reg [8:0] output_timeout_count; + reg [31:0] read_addr; + reg read_ctrl_valid; + wire read_ctrl_ready; + reg [7:0] read_count; + reg update_read; + wire [63:0] read_data; + wire read_data_valid; + wire read_data_ready; + + // Track main FIFO active size. + reg [SIZE-3:0] space, occupied; + wire [11:0] input_page_boundry, output_page_boundry; + + + // + // Buffer input in FIFO's. Embeded tlast signal using ESCape code. + // + wire [WIDTH-1:0] i_tdata_i0; + wire i_tvalid_i0, i_tready_i0, i_tlast_i0; + + wire [WIDTH-1:0] i_tdata_i1; + wire i_tvalid_i1, i_tready_i1; + + wire [WIDTH-1:0] i_tdata_i2; + wire i_tvalid_i2, i_tready_i2; + + wire [WIDTH-1:0] i_tdata_input; + wire i_tvalid_input, i_tready_input; + wire [15:0] space_input, occupied_input; + reg [15:0] space_input_reg; + reg supress_reads; + + /////////////////////////// + // DEBUG + /////////////////////////// + wire [31:0] debug_axi_dma_master; + + //assign debug = {18'h0, input_state[2:0], output_state[2:0], debug_axi_dma_master[7:0]}; + + /////////////////////////////////////////////////////////////////////////////// + + wire write_in, read_in, empty_in, full_in; + assign i_tready = ~full_in; + assign write_in = i_tvalid & i_tready; + assign i_tvalid_i0 = ~empty_in; + assign read_in = i_tvalid_i0 & i_tready_i0; + wire [6:0] discard_i0; + + fifo_short_2clk fifo_short_2clk_i0 + (.rst(bus_reset), + .wr_clk(bus_clk), + .din({7'h0,i_tlast,i_tdata}), // input [71 : 0] din + .wr_en(write_in), // input wr_en + .full(full_in), // output full + .wr_data_count(), // output [9 : 0] wr_data_count + + .rd_clk(dram_clk), // input rd_clk + .dout({discard_i0,i_tlast_i0,i_tdata_i0}), // output [71 : 0] dout + .rd_en(read_in), // input rd_en + .empty(empty_in), // output empty + .rd_data_count() // output [9 : 0] rd_data_count + ); + + axi_embed_tlast axi_embed_tlast_i + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(i_tdata_i0), + .i_tlast(i_tlast_i0), + .i_tvalid(i_tvalid_i0), + .i_tready(i_tready_i0), + // + .o_tdata(i_tdata_i1), + .o_tvalid(i_tvalid_i1), + .o_tready(i_tready_i1) + ); + + + axi_fast_fifo #(.WIDTH(WIDTH)) fast_fifo_i0 + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(i_tdata_i1), + .i_tvalid(i_tvalid_i1), + .i_tready(i_tready_i1), + // + .o_tdata(i_tdata_i2), + .o_tvalid(i_tvalid_i2), + .o_tready(i_tready_i2) + ); + + axi_fifo #(.WIDTH(WIDTH),.SIZE(12)) fifo_i1 + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(i_tdata_i2), + .i_tvalid(i_tvalid_i2), + .i_tready(i_tready_i2), + // + .o_tdata(i_tdata_input), + .o_tvalid(i_tvalid_input), + .o_tready(i_tready_input), + // + .space(space_input), + .occupied(occupied_input) + ); + + // + // Monitor occupied_input to deduce when DRAM FIFO is running short of bandwidth and there is a danger of backpressure + // passing upstream of the DRAM FIFO. + // In this situation supress read requests to the DRAM FIFO so that more bandwidth is available to writes. + // + + + always @(posedge dram_clk) + begin + space_input_reg <= space_input; + if ((space_input_reg < supress_threshold[15:0]) && supress_enable) + supress_reads <= 1'b1; + else + supress_reads <= 1'b0; + end + + // + // Buffer output in 32entry FIFO's. Extract embeded tlast signal. + // + wire [WIDTH-1:0] o_tdata_output; + wire o_tvalid_output, o_tready_output; + wire [15:0] space_output, occupied_output; + + wire [WIDTH-1:0] o_tdata_i0; + wire o_tvalid_i0, o_tready_i0; + + wire [WIDTH-1:0] o_tdata_i1; + wire o_tvalid_i1, o_tready_i1, o_tlast_i1; + + wire [WIDTH-1:0] o_tdata_i2; + wire o_tvalid_i2, o_tready_i2, o_tlast_i2; + + wire [WIDTH-1:0] o_tdata_i3; + wire o_tvalid_i3, o_tready_i3, o_tlast_i3; + + wire checksum_error; + + + axi_fifo #(.WIDTH(WIDTH),.SIZE(9)) fifo_i2 + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(o_tdata_output), + .i_tvalid(o_tvalid_output), + .i_tready(o_tready_output), + // + .o_tdata(o_tdata_i0), + .o_tvalid(o_tvalid_i0), + .o_tready(o_tready_i0), + // + .space(space_output), + .occupied(occupied_output) + ); + + // Place FLops straight after SRAM read access for timing. + axi_fast_fifo #(.WIDTH(WIDTH)) fast_fifo_i1 + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(o_tdata_i0), + .i_tvalid(o_tvalid_i0), + .i_tready(o_tready_i0), + // + .o_tdata(o_tdata_i1), + .o_tvalid(o_tvalid_i1), + .o_tready(o_tready_i1 && ~supress_reads) + ); + + // More pipeline flops to meet timing + axi_fast_fifo #(.WIDTH(WIDTH)) fast_fifo_i2 + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(o_tdata_i1), + .i_tvalid(o_tvalid_i1 && ~supress_reads), + .i_tready(o_tready_i1), + // + .o_tdata(o_tdata_i2), + .o_tvalid(o_tvalid_i2), + .o_tready(o_tready_i2) + ); + + axi_fast_extract_tlast axi_fast_extract_tlast_i0 + ( + .clk(dram_clk), + .reset(dram_reset), + .clear(clear), + // + .i_tdata(o_tdata_i2), + .i_tvalid(o_tvalid_i2), + .i_tready(o_tready_i2), + // + .o_tdata(o_tdata_i3), + .o_tlast(o_tlast_i3), + .o_tvalid(o_tvalid_i3), + .o_tready(o_tready_i3) + // + // .checksum_error_reg(checksum_error) + ); + + + wire write_out, read_out, empty_out, full_out; + assign o_tready_i3 = ~full_out; + assign write_out = o_tvalid_i3 & o_tready_i3; + assign o_tvalid = ~empty_out; + assign read_out = o_tvalid & o_tready; + wire [6:0] discard_i1; + + fifo_short_2clk fifo_short_2clk_i1 + ( + .rst(bus_reset), + .wr_clk(dram_clk), + .din({7'h0,o_tlast_i3,o_tdata_i3}), // input [71 : 0] din + .wr_en(write_out), // input wr_en + .full(full_out), // output full + .wr_data_count(), // output [9 : 0] wr_data_count + + .rd_clk(bus_clk), // input rd_clk + .dout({discard_i1,o_tlast,o_tdata}), // output [71 : 0] dout + .rd_en(read_out), // input rd_en + .empty(empty_out), // output empty + .rd_data_count() // output [9 : 0] rd_data_count + ); + + // + // Simple input timeout counter for now. + // Timeout count only increments when there is some data waiting to be written. + // + always @(posedge dram_clk) + if (dram_reset | clear) begin + input_timeout_count <= 0; + input_timeout_triggered <= 1'b0; + end else if (input_timeout_reset) begin + input_timeout_count <= 0; + input_timeout_triggered <= 1'b0; + end else if (input_timeout_count == TIMEOUT) begin + input_timeout_triggered <= 1'b1; + end else if (input_state == INPUT_IDLE) begin + input_timeout_count <= input_timeout_count + (occupied_input != 0); + end + + + // + // Wait for 16 entries in input FIFO to trigger DRAM write burst. + // Timeout can also trigger burst so fragments of data are not left to rot in the input FIFO. + // Also if enough data is present in the input FIFO to complete a burst upto the edge + // of a 4KByte page then immediately start the burst. + // + always @(posedge dram_clk) + if (dram_reset | clear) begin + input_state <= INPUT_IDLE; + write_addr[31:SIZE] <= BASE >> SIZE; + write_addr[SIZE-1:0] <= 0; + input_timeout_reset <= 1'b0; + write_ctrl_valid <= 1'b0; + write_count <= 8'd0; + update_write <= 1'b0; + end else + case (input_state) + // + // INPUT_IDLE. + // To start an input transfer to DRAM need: + // 1) Space in the DRAM FIFO + // and either + // 2) 256 entrys in the input FIFO + // or + // 3) Timeout waiting for more data. + // + INPUT_IDLE: begin + write_ctrl_valid <= 1'b0; + update_write <= 1'b0; + if (space > 255) begin // Space in the DRAM FIFO + if (occupied_input > 255) begin // 256 or more entrys in input FIFO + input_state <= INPUT1; + input_timeout_reset <= 1'b1; + end else if (input_timeout_triggered) begin // input FIFO timeout waiting for new data. + input_state <= INPUT2; + input_timeout_reset <= 1'b1; + end else begin + input_timeout_reset <= 1'b0; + input_state <= INPUT_IDLE; + end + end else begin + input_timeout_reset <= 1'b0; + input_state <= INPUT_IDLE; + end + end + // + // INPUT1. + // Caused by input FIFO reaching 256 entries. + // Request write burst of lesser of: + // 1) Entrys until page boundry crossed + // 2) 256. + // + INPUT1: begin + write_count <= (input_page_boundry < 255) ? input_page_boundry[7:0] : 8'd255; + write_ctrl_valid <= 1'b1; + if (write_ctrl_ready) + input_state <= INPUT4; // Pre-emptive ACK + else + input_state <= INPUT3; // Wait for ACK + end + // + // INPUT2. + // Caused by timeout of input FIFO. (occupied_input was implicitly less than 256 last cycle) + // Request write burst of lesser of: + // 1) Entries until page boundry crossed + // 2) Entries in input FIFO + // + INPUT2: begin + write_count <= (input_page_boundry < ({3'h0,occupied_input[8:0]} - 12'd1)) ? input_page_boundry[7:0] : (occupied_input[8:0] - 7'd1); + write_ctrl_valid <= 1'b1; + if (write_ctrl_ready) + input_state <= INPUT4; // Pre-emptive ACK + else + input_state <= INPUT3; // Wait for ACK + end + // + // INPUT3. + // Wait in this state for AXI4_DMA engine to accept transaction. + // + INPUT3: begin + if (write_ctrl_ready) begin + write_ctrl_valid <= 1'b0; + input_state <= INPUT4; // ACK + end else begin + write_ctrl_valid <= 1'b1; + input_state <= INPUT3; // Wait for ACK + end + end + // + // INPUT4. + // Wait here until write_ctrl_ready_deasserts. + // This is important as the next time it asserts we know that a write response was receieved. + INPUT4: begin + write_ctrl_valid <= 1'b0; + if (!write_ctrl_ready) + input_state <= INPUT5; // Move on + else + input_state <= INPUT4; // Wait for deassert + end + // + // INPUT5. + // Transaction has been accepted by AXI4 DMA engine. Now we wait for the re-assertion + // of write_ctrl_ready which signals that the AXI4 DMA engine has receieved a response + // for the whole write transaction and we assume that this means it is commited to DRAM. + // We are now free to update write_addr pointer and go back to idle state. + // + INPUT5: begin + write_ctrl_valid <= 1'b0; + if (write_ctrl_ready) begin + write_addr[SIZE-1:0] <= write_addr[SIZE-1:0] + ((write_count + 1) << 3); + input_state <= INPUT6; + update_write <= 1'b1; + end else begin + input_state <= INPUT5; + end + end + // + // INPUT6: + // Need to let space update before looking if there's more to do. + // + INPUT6: begin + input_state <= INPUT_IDLE; + update_write <= 1'b0; + end + // Ass covering. + default: input_state <= INPUT_IDLE; + + endcase // case(input_state) + + + // + // Simple output timeout counter for now + // + always @(posedge dram_clk) + if (dram_reset | clear) begin + output_timeout_count <= 0; + output_timeout_triggered <= 1'b0; + end else if (output_timeout_reset) begin + output_timeout_count <= 0; + output_timeout_triggered <= 1'b0; + end else if (output_timeout_count == TIMEOUT) begin + output_timeout_triggered <= 1'b1; + end else if (output_state == OUTPUT_IDLE) begin + output_timeout_count <= output_timeout_count + (occupied != 0 ); + end + + + // + // Wait for 64 entries in main FIFO to trigger DRAM read burst. + // Timeout can also trigger burst so fragments of data are not left to rot in the main FIFO. + // Also if enough data is present in the main FIFO to complete a burst upto the edge + // of a 4KByte page then immediately start the burst. + // + always @(posedge dram_clk) + if (dram_reset | clear) begin + output_state <= OUTPUT_IDLE; + read_addr[31:SIZE] <= BASE >> SIZE; + read_addr[SIZE-1:0] <= 0; + output_timeout_reset <= 1'b0; + read_ctrl_valid <= 1'b0; + read_count <= 8'd0; + update_read <= 1'b0; + end else + case (output_state) + // + // OUTPUT_IDLE. + // To start an output tranfer from DRAM + // 1) Space in the small output FIFO + // and either + // 2) 256 entrys in the DRAM FIFO + // or + // 3) Timeout waiting for more data. + // + OUTPUT_IDLE: begin + read_ctrl_valid <= 1'b0; + update_read <= 1'b0; + if (space_output > 255) begin // Space in the output FIFO. + if (occupied > 255) begin // 64 or more entrys in main FIFO + output_state <= OUTPUT1; + output_timeout_reset <= 1'b1; + end else if (output_timeout_triggered) begin // output FIFO timeout waiting for new data. + output_state <= OUTPUT2; + output_timeout_reset <= 1'b1; + end else begin + output_timeout_reset <= 1'b0; + output_state <= OUTPUT_IDLE; + end + end else begin + output_timeout_reset <= 1'b0; + output_state <= OUTPUT_IDLE; + end + end // case: OUTPUT_IDLE + // + // OUTPUT1. + // Caused by main FIFO reaching 256 entries. + // Request read burst of lesser of lesser of: + // 1) Entrys until page boundry crossed + // 2) 256. + // + OUTPUT1: begin + read_count <= (output_page_boundry < 255) ? output_page_boundry : 8'd255; + read_ctrl_valid <= 1'b1; + if (read_ctrl_ready) + output_state <= OUTPUT4; // Pre-emptive ACK + else + output_state <= OUTPUT3; // Wait for ACK + end + // + // OUTPUT2. + // Caused by timeout of main FIFO + // Request read burst of lesser of: + // 1) Entries until page boundry crossed + // 2) Entries in main FIFO + // + OUTPUT2: begin + read_count <= (output_page_boundry < (occupied - 1)) ? output_page_boundry : (occupied - 1); + read_ctrl_valid <= 1'b1; + if (read_ctrl_ready) + output_state <= OUTPUT4; // Pre-emptive ACK + else + output_state <= OUTPUT3; // Wait for ACK + end + // + // OUTPUT3. + // Wait in this state for AXI4_DMA engine to accept transaction. + // + OUTPUT3: begin + if (read_ctrl_ready) begin + read_ctrl_valid <= 1'b0; + output_state <= OUTPUT4; // ACK + end else begin + read_ctrl_valid <= 1'b1; + output_state <= OUTPUT3; // Wait for ACK + end + end + // + // OUTPUT4. + // Wait here unitl read_ctrl_ready_deasserts. + // This is important as the next time it asserts we know that a read response was receieved. + OUTPUT4: begin + read_ctrl_valid <= 1'b0; + if (!read_ctrl_ready) + output_state <= OUTPUT5; // Move on + else + output_state <= OUTPUT4; // Wait for deassert + end + // + // OUTPUT5. + // Transaction has been accepted by AXI4 DMA engine. Now we wait for the re-assertion + // of read_ctrl_ready which signals that the AXI4 DMA engine has receieved a last signal and good response + // for the whole read transaction. + // We are now free to update read_addr pointer and go back to idle state. + // + OUTPUT5: begin + read_ctrl_valid <= 1'b0; + if (read_ctrl_ready) begin + read_addr[SIZE-1:0] <= read_addr[SIZE-1:0] + ((read_count + 1) << 3); + output_state <= OUTPUT6; + update_read <= 1'b1; + + end else begin + output_state <= OUTPUT5; + end + end // case: OUTPUT5 + // + // OUTPUT6. + // Need to get occupied value updated before checking if there's more to do. + // + OUTPUT6: begin + update_read <= 1'b0; + output_state <= OUTPUT_IDLE; + end + // Ass covering. + default: output_state <= OUTPUT_IDLE; + + endcase // case(output_state) + + // + // Calculate number of entries remaining until next 4KB page boundry is crossed minus 1. + // Note, units of calculation are 64bit wide words. Address is always 64bit alligned. + // + assign input_page_boundry = {write_addr[31:12],9'h1ff} - write_addr[31:3]; + assign output_page_boundry = {read_addr[31:12],9'h1ff} - read_addr[31:3]; + + // + // Count number of used entries in main DRAM FIFO. + // Note that this is expressed in units of 64bit wide words. + // + always @(posedge dram_clk) + if (dram_reset | clear) + occupied <= 0; + else + occupied <= occupied + (update_write ? write_count + 1 : 0) - (update_read ? read_count + 1 : 0); + + always @(posedge dram_clk) + if (dram_reset | clear) + space <= (1 << SIZE-3) - 'd64; // Subtract 64 from space to make allowance for read/write reordering in DRAM controller confuing pointer math. + else + space <= space - (update_write ? write_count + 1 : 0) + (update_read ? read_count + 1 : 0); + + // + // Instamce of axi_dma_master + // + + + axi_dma_master axi_dma_master_i + ( + .aclk(dram_clk), // input aclk + .areset(dram_reset | clear), // input aresetn + // Write control + .m_axi_awid(m_axi_awid), // input [0 : 0] m_axi_awid + .m_axi_awaddr(m_axi_awaddr), // input [31 : 0] m_axi_awaddr + .m_axi_awlen(m_axi_awlen), // input [7 : 0] m_axi_awlen + .m_axi_awsize(m_axi_awsize), // input [2 : 0] m_axi_awsize + .m_axi_awburst(m_axi_awburst), // input [1 : 0] m_axi_awburst + .m_axi_awvalid(m_axi_awvalid), // input m_axi_awvalid + .m_axi_awready(m_axi_awready), // output m_axi_awready + .m_axi_awlock(m_axi_awlock), + .m_axi_awcache(m_axi_awcache), + .m_axi_awprot(m_axi_awprot), + .m_axi_awqos(m_axi_awqos), + .m_axi_awregion(m_axi_awregion), + .m_axi_awuser(m_axi_awuser), + // Write Data + .m_axi_wdata(m_axi_wdata), // input [63 : 0] m_axi_wdata + .m_axi_wstrb(m_axi_wstrb), // input [7 : 0] m_axi_wstrb + .m_axi_wlast(m_axi_wlast), // input m_axi_wlast + .m_axi_wvalid(m_axi_wvalid), // input m_axi_wvalid + .m_axi_wready(m_axi_wready), // output m_axi_wready + .m_axi_wuser(), + // Write Response + .m_axi_bid(m_axi_bid), // output [0 : 0] m_axi_bid + .m_axi_bresp(m_axi_bresp), // output [1 : 0] m_axi_bresp + .m_axi_bvalid(m_axi_bvalid), // output m_axi_bvalid + .m_axi_bready(m_axi_bready), // input m_axi_bready + .m_axi_buser(), + // Read Control + .m_axi_arid(m_axi_arid), // input [0 : 0] m_axi_arid + .m_axi_araddr(m_axi_araddr), // input [31 : 0] m_axi_araddr + .m_axi_arlen(m_axi_arlen), // input [7 : 0] m_axi_arlen + .m_axi_arsize(m_axi_arsize), // input [2 : 0] m_axi_arsize + .m_axi_arburst(m_axi_arburst), // input [1 : 0] m_axi_arburst + .m_axi_arvalid(m_axi_arvalid), // input m_axi_arvalid + .m_axi_arready(m_axi_arready), // output m_axi_arready + .m_axi_arlock(m_axi_arlock), + .m_axi_arcache(m_axi_arcache), + .m_axi_arprot(m_axi_arprot), + .m_axi_arqos(m_axi_arqos), + .m_axi_arregion(m_axi_arregion), + .m_axi_aruser(m_axi_aruser), + // Read Data + .m_axi_rid(m_axi_rid), // output [0 : 0] m_axi_rid + .m_axi_rdata(m_axi_rdata), // output [63 : 0] m_axi_rdata + .m_axi_rresp(m_axi_rresp), // output [1 : 0] m_axi_rresp + .m_axi_rlast(m_axi_rlast), // output m_axi_rlast + .m_axi_rvalid(m_axi_rvalid), // output m_axi_rvalid + .m_axi_rready(m_axi_rready), // input m_axi_rready + .m_axi_ruser(), + // + // DMA interface for Write transaction + // + .write_addr(write_addr), // Byte address for start of write transaction (should be 64bit alligned) + .write_count(write_count), // Count of 64bit words to write. + .write_ctrl_valid(write_ctrl_valid), + .write_ctrl_ready(write_ctrl_ready), + .write_data(i_tdata_input), + .write_data_valid(i_tvalid_input), + .write_data_ready(i_tready_input), + // + // DMA interface for Read + // + .read_addr(read_addr), // Byte address for start of read transaction (should be 64bit alligned) + .read_count(read_count), // Count of 64bit words to read. + .read_ctrl_valid(read_ctrl_valid), + .read_ctrl_ready(read_ctrl_ready), + .read_data(o_tdata_output), + .read_data_valid(o_tvalid_output), + .read_data_ready(o_tready_output), + // + // Debug + // + .debug(debug_axi_dma_master) + ); + + // + // Debug + // + assign debug = { checksum_error, + /*debug_axi_dma_master[7:0]*/ + input_timeout_triggered, // 195 + input_state[2:0], // 194-192 + output_timeout_triggered, // 191 + output_state[2:0], // 190-188 + space_output[15:0], // 187-172 + occupied[21:0], // 171-150 + occupied_input[15:0], // 149-134 + + i_tvalid_i0, // 133 + i_tready_i0, // 132 + i_tlast_i0, // 131 + i_tdata_i0[63:0],// 130-67 + o_tvalid_i1, // 66 + o_tready_i1, // 65 + o_tlast_i1, // 64 + o_tdata_i1[63:0] // 63-0 + }; + + + endmodule // axi_dram_fifo + diff --git a/fpga/usrp3/lib/axi/axi_dram_fifo_tb.v b/fpga/usrp3/lib/axi/axi_dram_fifo_tb.v new file mode 100644 index 000000000..d8d53815a --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_dram_fifo_tb.v @@ -0,0 +1,421 @@ +module axi_dram_fifo_tb; + + + + reg clk; // Global AXI clock + reg reset; // Global reset, active high. + reg clear; + wire aresetn; // Global AXI reset, active low. + // + // AXI Write address channel + // + wire [0 : 0] axi_awid; // Write address ID. This signal is the identification tag for the write address signals + wire [31 : 0] axi_awaddr; // Write address. The write address gives the address of the first transfer in a write burst + wire [7 : 0] axi_awlen; // Burst length. The burst length gives the exact number of transfers in a burst. + wire [2 : 0] axi_awsize; // Burst size. This signal indicates the size of each transfer in the burst. + wire [1 : 0] axi_awburst; // Burst type. The burst type and the size information, determine how the address is calculated + wire [0 : 0] axi_awlock; // Lock type. Provides additional information about the atomic characteristics of the transfer. + wire [3 : 0] axi_awcache; // Memory type. This signal indicates how transactions are required to progress + wire [2 : 0] axi_awprot; // Protection type. This signal indicates the privilege and security level of the transaction + wire [3 : 0] axi_awqos; // Quality of Service, QoS. The QoS identifier sent for each write transaction + wire [3 : 0] axi_awregion; // Region identifier. Permits a single physical interface on a slave to be re-used. + wire [0 : 0] axi_awuser; // User signal. Optional User-defined signal in the write address channel. + wire axi_awvalid; // Write address valid. This signal indicates that the channel is signaling valid write addr + wire axi_awready; // Write address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Write data channel. + // + wire [63 : 0] axi_wdata; // Write data + wire [7 : 0] axi_wstrb; // Write strobes. This signal indicates which byte lanes hold valid data. + wire axi_wlast; // Write last. This signal indicates the last transfer in a write burst + wire [0 : 0] axi_wuser; // User signal. Optional User-defined signal in the write data channel. + wire axi_wvalid; // Write valid. This signal indicates that valid write data and strobes are available. + wire axi_wready; // Write ready. This signal indicates that the slave can accept the write data. + // + // AXI Write response channel signals + // + wire [0 : 0] axi_bid; // Response ID tag. This signal is the ID tag of the write response. + wire [1 : 0] axi_bresp; // Write response. This signal indicates the status of the write transaction. + wire [0 : 0] axi_buser; // User signal. Optional User-defined signal in the write response channel. + wire axi_bvalid; // Write response valid. This signal indicates that the channel is signaling a valid response + wire axi_bready; // Response ready. This signal indicates that the master can accept a write response + // + // AXI Read address channel + // + wire [0 : 0] axi_arid; // Read address ID. This signal is the identification tag for the read address group of signals + wire [31 : 0] axi_araddr; // Read address. The read address gives the address of the first transfer in a read burst + wire [7 : 0] axi_arlen; // Burst length. This signal indicates the exact number of transfers in a burst. + wire [2 : 0] axi_arsize; // Burst size. This signal indicates the size of each transfer in the burst. + wire [1 : 0] axi_arburst; // Burst type. The burst type and the size information determine how the address for each transfer + wire [0 : 0] axi_arlock; // Lock type. This signal provides additional information about the atomic characteristics + wire [3 : 0] axi_arcache; // Memory type. This signal indicates how transactions are required to progress + wire [2 : 0] axi_arprot; // Protection type. This signal indicates the privilege and security level of the transaction + wire [3 : 0] axi_arqos; // Quality of Service, QoS. QoS identifier sent for each read transaction. + wire [3 : 0] axi_arregion; // Region identifier. Permits a single physical interface on a slave to be re-used + wire [0 : 0] axi_aruser; // User signal. Optional User-defined signal in the read address channel. + wire axi_arvalid; // Read address valid. This signal indicates that the channel is signaling valid read addr + wire axi_arready; // Read address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Read data channel + // + wire [0 : 0] axi_rid; // Read ID tag. This signal is the identification tag for the read data group of signals + wire [63 : 0] axi_rdata; // Read data. + wire [1 : 0] axi_rresp; // Read response. This signal indicates the status of the read transfer + wire axi_rlast; // Read last. This signal indicates the last transfer in a read burst. + wire [0 : 0] axi_ruser; // User signal. Optional User-defined signal in the read data channel. + wire axi_rvalid; // Read valid. This signal indicates that the channel is signaling the required read data. + wire axi_rready; // Read ready. This signal indicates that the master can accept the read data and response + + // + // CHDR friendly AXI stream input + // + wire [63:0] i_tdata; + wire i_tlast; + wire i_tvalid; + wire i_tready; + // + // CHDR friendly AXI Stream output + // + wire [63:0] o_tdata; + wire o_tlast; + wire o_tvalid; + wire o_tready; + + // + // These registers optionaly used + // to drive nets through procedural assignments in test bench. + // These drivers default to tri-stated. + // + + reg [63:0] i_tdata_r; + reg i_tlast_r; + reg i_tvalid_r; + reg o_tready_r; + + assign i_tdata = i_tdata_r; + assign i_tlast = i_tlast_r; + assign i_tvalid = i_tvalid_r; + assign o_tready = o_tready_r; + + initial + begin + i_tdata_r <= 64'hzzzz_zzzz_zzzz_zzzz; + i_tlast_r <= 1'bz; + i_tvalid_r <= 1'bz; + o_tready_r <= 1'bz; + end + + + + axi_dram_fifo + #(.SIZE(13)) + axi_dram_fifo_i1 + ( + .bus_clk(clk), // input s_aclk + .bus_reset(reset), // input s_aresetn + .clear(clear), + .dram_clk(clk), // input s_aclk + .dram_reset(reset), // input s_aresetn + // Write control + .m_axi_awid(axi_awid), // input [0 : 0] s_axi_awid + .m_axi_awaddr(axi_awaddr), // input [31 : 0] s_axi_awaddr + .m_axi_awlen(axi_awlen), // input [7 : 0] s_axi_awlen + .m_axi_awsize(axi_awsize), // input [2 : 0] s_axi_awsize + .m_axi_awburst(axi_awburst), // input [1 : 0] s_axi_awburst + .m_axi_awvalid(axi_awvalid), // input s_axi_awvalid + .m_axi_awready(axi_awready), // output s_axi_awready + .m_axi_awlock(), + .m_axi_awcache(), + .m_axi_awprot(), + .m_axi_awqos(), + .m_axi_awregion(), + .m_axi_awuser(), + // Write Data + .m_axi_wdata(axi_wdata), // input [63 : 0] s_axi_wdata + .m_axi_wstrb(axi_wstrb), // input [7 : 0] s_axi_wstrb + .m_axi_wlast(axi_wlast), // input s_axi_wlast + .m_axi_wvalid(axi_wvalid), // input s_axi_wvalid + .m_axi_wready(axi_wready), // output s_axi_wready + .m_axi_wuser(), + // Write Response + .m_axi_bid(axi_bid), // output [0 : 0] s_axi_bid + .m_axi_bresp(axi_bresp), // output [1 : 0] s_axi_bresp + .m_axi_bvalid(axi_bvalid), // output s_axi_bvalid + .m_axi_bready(axi_bready), // input s_axi_bready + .m_axi_buser(), + // Read Control + .m_axi_arid(axi_arid), // input [0 : 0] s_axi_arid + .m_axi_araddr(axi_araddr), // input [31 : 0] s_axi_araddr + .m_axi_arlen(axi_arlen), // input [7 : 0] s_axi_arlen + .m_axi_arsize(axi_arsize), // input [2 : 0] s_axi_arsize + .m_axi_arburst(axi_arburst), // input [1 : 0] s_axi_arburst + .m_axi_arvalid(axi_arvalid), // input s_axi_arvalid + .m_axi_arready(axi_arready), // output s_axi_arready + .m_axi_arlock(), + .m_axi_arcache(), + .m_axi_arprot(), + .m_axi_arqos(), + .m_axi_arregion(), + .m_axi_aruser(), + // Read Data + .m_axi_rid(axi_rid), // output [0 : 0] s_axi_rid + .m_axi_rdata(axi_rdata), // output [63 : 0] s_axi_rdata + .m_axi_rresp(axi_rresp), // output [1 : 0] s_axi_rresp + .m_axi_rlast(axi_rlast), // output s_axi_rlast + .m_axi_rvalid(axi_rvalid), // output s_axi_rvalid + .m_axi_rready(axi_rready), // input s_axi_rready + .m_axi_ruser(), + // CHDR in + .i_tdata(i_tdata), + .i_tlast(i_tlast), + .i_tvalid(i_tvalid), + .i_tready(i_tready), + // CHDR out + .o_tdata(o_tdata), + .o_tlast(o_tlast), + .o_tvalid(o_tvalid), + .o_tready(o_tready), + // + .supress_threshold(16'h0), + .supress_enable(1'b0) + ); + + + axi4_bram_1kx64 axi4_bram_1kx64_i1 + ( + .s_aclk(clk), // input s_aclk + .s_aresetn(aresetn), // input s_aresetn + .s_axi_awid(axi_awid), // input [0 : 0] s_axi_awid + .s_axi_awaddr(axi_awaddr), // input [31 : 0] s_axi_awaddr + .s_axi_awlen(axi_awlen), // input [7 : 0] s_axi_awlen + .s_axi_awsize(axi_awsize), // input [2 : 0] s_axi_awsize + .s_axi_awburst(axi_awburst), // input [1 : 0] s_axi_awburst + .s_axi_awvalid(axi_awvalid), // input s_axi_awvalid + .s_axi_awready(axi_awready), // output s_axi_awready + .s_axi_wdata(axi_wdata), // input [63 : 0] s_axi_wdata + .s_axi_wstrb(axi_wstrb), // input [7 : 0] s_axi_wstrb + .s_axi_wlast(axi_wlast), // input s_axi_wlast + .s_axi_wvalid(axi_wvalid), // input s_axi_wvalid + .s_axi_wready(axi_wready), // output s_axi_wready + .s_axi_bid(axi_bid), // output [0 : 0] s_axi_bid + .s_axi_bresp(axi_bresp), // output [1 : 0] s_axi_bresp + .s_axi_bvalid(axi_bvalid), // output s_axi_bvalid + .s_axi_bready(axi_bready), // input s_axi_bready + .s_axi_arid(axi_arid), // input [0 : 0] s_axi_arid + .s_axi_araddr(axi_araddr), // input [31 : 0] s_axi_araddr + .s_axi_arlen(axi_arlen), // input [7 : 0] s_axi_arlen + .s_axi_arsize(axi_arsize), // input [2 : 0] s_axi_arsize + .s_axi_arburst(axi_arburst), // input [1 : 0] s_axi_arburst + .s_axi_arvalid(axi_arvalid), // input s_axi_arvalid + .s_axi_arready(axi_arready), // output s_axi_arready + .s_axi_rid(axi_rid), // output [0 : 0] s_axi_rid + .s_axi_rdata(axi_rdata), // output [63 : 0] s_axi_rdata + .s_axi_rresp(axi_rresp), // output [1 : 0] s_axi_rresp + .s_axi_rlast(axi_rlast), // output s_axi_rlast + .s_axi_rvalid(axi_rvalid), // output s_axi_rvalid + .s_axi_rready(axi_rready) // input s_axi_rready + ); + + + // + // + // + + + task send_ramp; + input [31:0] burst_count; + input [31:0] len; + input [31:0] sid; + + reg [31:0] data; + reg [11:0] seqno; + + begin + seqno = 0; + data = 0; + send_packet(len, data, 0, seqno, (burst_count==1), 0, sid); + seqno = seqno + 1; + data <= data + len; + + if(burst_count > 2) + repeat (burst_count - 2) + begin + send_packet(len, data, 64'h0, seqno, 0, 0, sid); + seqno = seqno + 1; + data <= data + len; + end + if(burst_count > 1) + send_packet(len, data, 64'h0, seqno, 1, 0, sid); + end + endtask // send_ramp + + + task send_dc; + input [31:0] burst_count; + input [31:0] len; + input [31:0] sid; + + reg [31:0] data; + reg [11:0] seqno; + + begin + seqno = 0; + data = 1 << 14; + send_packet(len, data, 0, seqno, (burst_count==1), 0, sid); + seqno = seqno + 1; + + + if(burst_count > 2) + repeat (burst_count - 2) + begin + send_packet(len, data, 64'h0, seqno, 0, 0, sid); + seqno = seqno + 1; + + end + if(burst_count > 1) + send_packet(len, data, 64'h0, seqno, 1, 0, sid); + end + endtask // send_ramp + + + task send_burst; + input [31:0] burst_count; + input [31:0] len; + input [31:0] start_data; + input [63:0] send_time; + input [11:0] start_seqnum; + input send_at; + input [31:0] sid; + + reg [11:0] seqno; + + begin + seqno = start_seqnum; + send_packet(len, {seqno,start_data[15:0]}, send_time, seqno, (burst_count==1), send_at, sid); + seqno = seqno + 1; + + if(burst_count > 2) + repeat (burst_count - 2) + begin + send_packet(len, {seqno,start_data[15:0]}, 64'h0, seqno, 0, 0, sid); + seqno = seqno + 1; + end + if(burst_count > 1) + send_packet(len, {seqno,start_data[15:0]}, 64'h0, seqno, 1, 0, sid); + end + endtask // send_burst + + task send_packet; + input [31:0] len; + input [31:0] start_data; + input [63:0] send_time; + input [11:0] pkt_seqnum; + input eob; + input send_at; + input [31:0] sid; + + reg [31:0] samp0, samp1; + + + begin + // Send a packet + samp0 <= start_data; + samp1 <= start_data + 1; + @(posedge clk); + + i_tlast_r <= 0; + i_tdata_r <= { 1'b0, 1'b0 /*trl*/, send_at, eob, pkt_seqnum, len[15:0]+16'd2+send_at+send_at, sid }; + i_tvalid_r <= 1; + @(posedge clk) + if(send_at) + begin + i_tdata_r <= send_time; + @(posedge clk); + end + + repeat (len[31:1]+len[0]-1) + begin + i_tdata_r <= {samp0,samp1}; + samp0 <= samp0 + 2; + samp1 <= samp1 + 2; + @(posedge clk); + end + + i_tdata_r <= {samp0,samp1}; + i_tlast_r <= 1'b1; + @(posedge clk); + i_tvalid_r <= 0; + @(posedge clk); + end + endtask // send_packet + + task send_raw_packet; + input [31:0] len; + + reg [63:0] data; + + begin + data = 0; + @(posedge clk); + repeat (len-1) begin + i_tlast_r <= 0; + i_tdata_r <= data; + i_tvalid_r <= 1; + @(posedge clk); + while (~i_tready) @(posedge clk); + data = data + 1; + end + i_tlast_r <= 1; + i_tdata_r <= data; + i_tvalid_r <= 1; + @(posedge clk); + while (~i_tready) @(posedge clk); + i_tvalid_r <= 0; + @(posedge clk); + end + endtask // send_raw_packet + + task receive_raw_packet; + input [31:0] len; + output fail; + reg [63:0] data; + + begin + data = 0; + fail = 0; + + @(posedge clk); + repeat (len-1) begin + o_tready_r <= 1; + @(posedge clk); + while (~o_tvalid) @(posedge clk); + //$display("Data = %d, o_tdata = %d, o_tlast = %d",data,o_tdata,o_tlast); + + fail = fail || (data !== o_tdata); + fail = fail || ~(o_tlast === 0); + data = data + 1; + + end + o_tready_r <= 1; + @(posedge clk); + while (~o_tvalid) @(posedge clk); + //$display("Data = %d, o_tdata = %d, o_tlast = %d",data,o_tdata,o_tlast); + fail = fail || (data !== o_tdata); + fail = fail || ~(o_tlast === 1); + o_tready_r <= 0; + @(posedge clk); + if (fail) $display("receive_raw_packet size %d failed",len); + + end + endtask // receive_raw_packet + + + + assign aresetn = ~reset; + + // + // Bring in a simulation script here + // + `include "simulation_script.v" + +endmodule // axi_dram_fifo_tb diff --git a/fpga/usrp3/lib/axi/axi_embed_tlast.v b/fpga/usrp3/lib/axi/axi_embed_tlast.v new file mode 100644 index 000000000..065f59fd4 --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_embed_tlast.v @@ -0,0 +1,128 @@ +// +// AXI stream neds N+1 bits to transmit packets of N bits so that the LAST bit can be represented. +// LAST occurs relatively infrequently and can be synthesized by using an in-band ESC code to generate +// a multi-word sequence to encode it (and the escape character when it appears as data input). +// +// 0x1234567887654321 with last becomes +// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0x1234567887654321 +// +// 0xDEADBEEFFEEDCAFE with last becomes +// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0xDEADBEEFFEEDCAFE +// +// 0xDEADBEEFFEEDCAFE without last becomes +// 0xDEADBEEFFEEDCAFE 0x0000000000000000 0xDEADBEEFFEEDCAFE +// + +module axi_embed_tlast + #(parameter WIDTH=64) + ( + input clk, + input reset, + input clear, + // + input [WIDTH-1:0] i_tdata, + input i_tlast, + input i_tvalid, + output i_tready, + // + output reg [WIDTH-1:0] o_tdata, + output o_tvalid, + input o_tready + + ); + + localparam PASS = 0; + localparam ZERO = 1; + localparam ONE = 2; + localparam ESCAPE = 3; + + localparam IDLE = 0; + localparam LAST = 1; + localparam ESC = 2; + localparam FINISH = 3; + + reg [1:0] state, next_state; + + reg [1:0] select; + + reg [31:0] checksum; + + always @(posedge clk) + if (reset | clear) begin + checksum <= 0; + end else if (i_tready && i_tvalid && i_tlast) begin + checksum <= 0; + end else if (i_tready && i_tvalid) begin + checksum <= checksum + i_tdata[31:0] + i_tdata[63:32]; + end + + always @(posedge clk) + if (reset | clear) begin + state <= IDLE; + end else begin if (o_tready) + state <= next_state; + end + + always @(*) begin + case(state) + IDLE: begin + if (i_tlast && i_tvalid) + begin + next_state = LAST; + select = ESCAPE; + end + else if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) + begin + next_state = ESC; + select = ESCAPE; + end + else + begin + next_state = IDLE; + select = PASS; + end + end // case: IDLE + // + // + LAST: begin + select = ONE; + next_state = FINISH; + end + // + // + ESC: begin + select = ZERO; + next_state = FINISH; + end + // + // + FINISH: begin + select = PASS; + if (i_tvalid) + next_state = IDLE; + else + next_state = FINISH; + end + endcase // case(state) + end // always @ (*) + + // + // Muxes + // + always @* + begin + case(select) + PASS: o_tdata = i_tdata; + ZERO: o_tdata = 0; + ONE: o_tdata = {checksum[31:0],32'h1}; + ESCAPE: o_tdata = 64'hDEADBEEFFEEDCAFE; + endcase // case(select) + end + + assign o_tvalid = (select == PASS) ? i_tvalid : 1'b1; + assign i_tready = (select == PASS) ? o_tready : 1'b0; + +endmodule // axi_embed_tlast + + + diff --git a/fpga/usrp3/lib/axi/axi_extract_tlast.v b/fpga/usrp3/lib/axi/axi_extract_tlast.v new file mode 100644 index 000000000..16d6d17c2 --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_extract_tlast.v @@ -0,0 +1,149 @@ +// +// AXI stream neds N+1 bits to transmit packets of N bits so that the LAST bit can be represented. +// LAST occurs relatively infrequently and can be synthesized by using an in-band ESC code to generate +// a multi-word sequence to encode it (and the escape character when it appears as data input). +// +// 0x1234567887654321 with last becomes +// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0x1234567887654321 +// +// 0xDEADBEEFFEEDCAFE with last becomes +// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0xDEADBEEFFEEDCAFE +// +// 0xDEADBEEFFEEDCAFE without last becomes +// 0xDEADBEEFFEEDCAFE 0x0000000000000000 0xDEADBEEFFEEDCAFE +// + +module axi_extract_tlast + #(parameter WIDTH=64) + ( + input clk, + input reset, + input clear, + // + input [WIDTH-1:0] i_tdata, + input i_tvalid, + output reg i_tready, + // + output [WIDTH-1:0] o_tdata, + output reg o_tlast, + output reg o_tvalid, + input o_tready, + // + output reg checksum_error_reg + + ); + + reg [1:0] state, next_state; + + localparam IDLE = 0; + localparam EXTRACT1 = 1; + localparam EXTRACT2 = 2; + localparam EXTRACT3 = 3; + + assign o_tdata = i_tdata; + + reg [31:0] checksum, old_checksum; + reg checksum_error; + + + always @(posedge clk) + if (reset | clear) begin + checksum <= 0; + old_checksum <= 0; + end else if (o_tready && i_tvalid && o_tlast) begin + checksum <= 0; + old_checksum <= 0; + end else if (i_tready && i_tvalid && (state == IDLE)) begin + checksum <= checksum + i_tdata[31:0] + i_tdata[63:32]; + old_checksum <= checksum; + end + + always @(posedge clk) + checksum_error_reg <= checksum_error; + + always @(posedge clk) + if (reset | clear) begin + state <= IDLE; + end else begin + state <= next_state; + end + + always @(*) begin + checksum_error = 0; + case(state) + // + // Search for Escape sequence "0xDEADBEEFFEEDCAFE" + // If ESC found don't pass data downstream but transition to next state. + // else pass data downstream. + // + IDLE: begin + o_tlast = 1'b0; + if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) + begin + next_state = EXTRACT1; + o_tvalid = 1'b0; + i_tready = 1'b1; + end + else + begin + next_state = IDLE; + o_tvalid = i_tvalid; + i_tready = o_tready; + end // else: !if((i_tdata == 'hDEADBEEFFEEDCAFE) && i_tvalid) + end // case: IDLE + // + // Look at next data. If it's a 0x1 then o_tlast should be asserted with next data word. + // if it's 0x0 then it signals emulation of the Escape code in the original data stream + // and we should just pass the next data word through unchanged with no o_tlast indication. + // + EXTRACT1: begin + o_tvalid = 1'b0; + i_tready = 1'b1; + o_tlast = 1'b0; + if (i_tvalid) begin + if (i_tdata[31:0] == 'h1) + begin + if (old_checksum != i_tdata[63:32]) + checksum_error = 1'b1; + next_state = EXTRACT2; + end + else // We assume emulation and don't look for illegal codes. + begin + next_state = EXTRACT3; + end // else: !if(i_tdata == 'h1) + end else begin // if (i_tvalid) + next_state = EXTRACT1; + end // else: !if(i_tvalid) + end // case: EXTRACT1 + // + // Assert o_tlast with data word. + // + EXTRACT2: begin + o_tvalid = i_tvalid; + i_tready = o_tready; + o_tlast = 1'b1; + if (i_tvalid & o_tready) + next_state = IDLE; + else + next_state = EXTRACT2; + end + // + // Emulation, don't assert o_tlast with dataword. + // + EXTRACT3: begin + o_tvalid = i_tvalid; + i_tready = o_tready; + o_tlast = 1'b0; + if (i_tvalid & o_tready) + next_state = IDLE; + else + next_state = EXTRACT2; + end + endcase // case(state) + end + + + +endmodule // axi_extract_tlast + +
\ No newline at end of file diff --git a/fpga/usrp3/lib/axi/axi_fast_extract_tlast.v b/fpga/usrp3/lib/axi/axi_fast_extract_tlast.v new file mode 100644 index 000000000..d4f3dd26c --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_fast_extract_tlast.v @@ -0,0 +1,187 @@ +// +// Ultra fast critical path FIFO. +// Only 2 entrys but no combinatorial feed through paths +// + + +module axi_fast_extract_tlast + #(parameter WIDTH=64) + ( + input clk, + input reset, + input clear, + // + input [WIDTH-1:0] i_tdata, + input i_tvalid, + output reg i_tready, + // + output [WIDTH-1:0] o_tdata, + output o_tlast, + output reg o_tvalid, + input o_tready + ); + + reg [WIDTH:0] data_reg1, data_reg2; + + reg [1:0] fifo_state; + + localparam EMPTY = 0; + localparam HALF = 1; + localparam FULL = 2; + + reg [1:0] extract_state; + + localparam IDLE = 0; + localparam EXTRACT1 = 1; + localparam EXTRACT2 = 2; + localparam EXTRACT3 = 3; + + + always @(posedge clk) + if (reset | clear) begin + fifo_state <= EMPTY; + end else begin + case (fifo_state) + // Nothing in either register. + // Upstream can always push data to us. + // Downstream has nothing to take from us. + EMPTY: begin + if ((extract_state == IDLE) && (i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin + // Embeded escpae code received. + extract_state <= EXTRACT1; + i_tready <= 1'b1; + o_tvalid <= 1'b0; + fifo_state <= EMPTY; + end else if ((extract_state == EXTRACT1) && i_tvalid) begin + // Now work out if its a genuine embeded tlast or emulation. + i_tready <= 1'b1; + o_tvalid <= 1'b0; + fifo_state <= EMPTY; + if (i_tdata[31:0] == 'h1) begin + extract_state <= EXTRACT2; + end else begin + extract_state <= EXTRACT3; + end + end else if ((extract_state == EXTRACT2) && i_tvalid) begin + // Extract tlast. + data_reg1 <= {1'b1,i_tdata}; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + fifo_state <= HALF; + extract_state <= IDLE; + end else if (i_tvalid) begin + // Get here both for normal data and for EXTRACT3 emulation data. + data_reg1 <= {1'b0,i_tdata}; + fifo_state <= HALF; + extract_state <= IDLE; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end else begin + // Nothing to do. + fifo_state <= EMPTY; + i_tready <= 1'b1; + o_tvalid <= 1'b0; + end + end + // First Register Full. + // Upstream can always push data to us. + // Downstream can always read from us. + HALF: begin + if ((extract_state == IDLE) && (i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin + // Embeded escpae code received. + extract_state <= EXTRACT1; + if (o_tready) begin + // If meanwhile we get read then go empty... + i_tready <= 1'b1; + o_tvalid <= 1'b0; + fifo_state <= EMPTY; + end else begin + // ...else stay half full. + fifo_state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end + end else if ((extract_state == EXTRACT1) && i_tvalid) begin + // Now work out if its a genuine embeded tlast or emulation. + if (i_tdata[31:0] == 'h1) begin + extract_state <= EXTRACT2; + end else begin + extract_state <= EXTRACT3; + end + if (o_tready) begin + // If meanwhile we get read then go empty... + i_tready <= 1'b1; + o_tvalid <= 1'b0; + fifo_state <= EMPTY; + end else begin + // ...else stay half full. + fifo_state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end + end else if ((extract_state == EXTRACT2) && i_tvalid) begin + // Extract tlast. + data_reg1 <= {1'b1,i_tdata}; + extract_state <= IDLE; + if (o_tready) begin + // We get read and writen same cycle... + i_tready <= 1'b1; + o_tvalid <= 1'b1; + fifo_state <= HALF; + end else begin + // ...or we get written and go full. + data_reg2 <= data_reg1; + i_tready <= 1'b0; + o_tvalid <= 1'b1; + fifo_state <= FULL; + end + end else if (i_tvalid) begin + // Get here both for normal data and for EXTRACT3 emulation data. + data_reg1 <= {1'b0,i_tdata}; + extract_state <= IDLE; + if (o_tready) begin + // We get read and writen same cycle... + fifo_state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end else begin + // ...or we get written and go full. + data_reg2 <= data_reg1; + i_tready <= 1'b0; + o_tvalid <= 1'b1; + fifo_state <= FULL; + end + end else if (o_tready) begin // if (i_tvalid) + // Only getting read this cycle so go empty + fifo_state <= EMPTY; + i_tready <= 1'b1; + o_tvalid <= 1'b0; + end else begin + // Absolutley nothing happens, everything stays the same. + fifo_state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end + end // case: HALF + // Both Registers Full. + // Upstream can not push to us in this fifo_state. + // Downstream can always read from us. + FULL: begin + if (o_tready) begin + fifo_state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end + else begin + fifo_state <= FULL; + i_tready <= 1'b0; + o_tvalid <= 1'b1; + end + end + endcase // case(fifo_state) + end // else: !if(reset | clear) + + assign {o_tlast,o_tdata} = (fifo_state == FULL) ? data_reg2 : data_reg1; + + +endmodule // axi_fast_fifo diff --git a/fpga/usrp3/lib/axi/axi_fast_fifo.v b/fpga/usrp3/lib/axi/axi_fast_fifo.v new file mode 100644 index 000000000..a24db3cc8 --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_fast_fifo.v @@ -0,0 +1,102 @@ +// +// Ultra fast critical path FIFO. +// Only 2 entrys but no combinatorial feed through paths +// + + +module axi_fast_fifo + #(parameter WIDTH=64) + ( + input clk, + input reset, + input clear, + // + input [WIDTH-1:0] i_tdata, + input i_tvalid, + output reg i_tready, + // + output [WIDTH-1:0] o_tdata, + output reg o_tvalid, + input o_tready + ); + + reg [WIDTH-1:0] data_reg1, data_reg2; + + reg [1:0] state; + + localparam EMPTY = 0; + localparam HALF = 1; + localparam FULL = 2; + + always @(posedge clk) + if (reset | clear) begin + state <= EMPTY; + data_reg1 <= 0; + data_reg2 <= 0; + o_tvalid <= 1'b0; + i_tready <= 1'b0; + + end else begin + case (state) + // Nothing in either register. + // Upstream can always push data to us. + // Downstream has nothing to take from us. + EMPTY: begin + if (i_tvalid) begin + data_reg1 <= i_tdata; + state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end else begin + state <= EMPTY; + i_tready <= 1'b1; + o_tvalid <= 1'b0; + end + end + // First Register Full. + // Upstream can always push data to us. + // Downstream can always read from us. + HALF: begin + if (i_tvalid && o_tready) begin + data_reg1 <= i_tdata; + state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end else if (i_tvalid) begin + data_reg1 <= i_tdata; + data_reg2 <= data_reg1; + state <= FULL; + i_tready <= 1'b0; + o_tvalid <= 1'b1; + end else if (o_tready) begin + state <= EMPTY; + i_tready <= 1'b1; + o_tvalid <= 1'b0; + end else begin + state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end + end // case: HALF + // Both Registers Full. + // Upstream can not push to us in this state. + // Downstream can always read from us. + FULL: begin + if (o_tready) begin + state <= HALF; + i_tready <= 1'b1; + o_tvalid <= 1'b1; + end + else begin + state <= FULL; + i_tready <= 1'b0; + o_tvalid <= 1'b1; + end + end + endcase // case(state) + end // else: !if(reset | clear) + + assign o_tdata = (state == FULL) ? data_reg2 : data_reg1; + + +endmodule // axi_fast_fifo diff --git a/fpga/usrp3/lib/axi/axi_lite_slave.v b/fpga/usrp3/lib/axi/axi_lite_slave.v new file mode 100644 index 000000000..54cfa9c53 --- /dev/null +++ b/fpga/usrp3/lib/axi/axi_lite_slave.v @@ -0,0 +1,42 @@ +module axi_lite_slave + ( + input aclk, // Global AXI clock + input aresetn, // Global AXI reset, active low. + // + // AXI Write address channel + // + input [31 : 0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst + input [2 : 0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction + input m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr + output m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Write data channel. + // + input [31 : 0] m_axi_wdata, // Write data + input [3 : 0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data. + input m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available. + output m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data. + // + // AXI Write response channel signals + // + output [1 : 0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction. + output m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response + input m_axi_bready, // Response ready. This signal indicates that the master can accept a write response + // + // AXI Read address channel + // + input [31 : 0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst + input [2 : 0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction + input m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr + output m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address + // + // AXI Read data channel + // + output [31 : 0] m_axi_rdata, // Read data. + output [1 : 0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer + output m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data. + input m_axi_rready, // Read ready. This signal indicates that the master can accept the read data and response + // + // + // + )
\ No newline at end of file |