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 | 
