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/axi_dma_master.v | |
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/axi_dma_master.v')
-rw-r--r-- | fpga/usrp3/lib/axi/axi_dma_master.v | 538 |
1 files changed, 538 insertions, 0 deletions
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 |