Loading utils/ahci_fis_receive.v +35 −20 Original line number Original line Diff line number Diff line Loading @@ -43,14 +43,21 @@ module ahci_fis_receive#( input get_sdbfis, input get_sdbfis, input get_ufis, input get_ufis, input get_data_fis, input get_data_fis, input get_ignore, // ignore whatever FIS data in the input get_ignore, // ignore whatever FIS (use for DMA activate too?) output reg get_fis_busy, // busy processing FIS output reg get_fis_busy, // busy processing FIS output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_* output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_* output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS output fis_ferr, // FIS done, fatal error - FIS too long output fis_ferr, // FIS done, fatal error - FIS too long input update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h input update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h input clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update input set_bsy, // set PxTFD.STS.BSY, update input set_sts_7f, // set PxTFD.STS = 0x7f, update input set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update // TODO: Add writing PRDBC here? output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) // tfd_sts[7] - BSY, tfd_sts[4] - DRQ, tfd_sts[0] - ERR output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB) output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB) output reg fis_i, // value of "I" field in received regsD2H or SDB FIS output reg fis_i, // value of "I" field in received regsD2H or SDB FIS output reg sdb_n, // value of "N" field in received SDB FIS output reg sdb_n, // value of "N" field in received SDB FIS Loading Loading @@ -86,6 +93,8 @@ CLB_OFFS = 0x800 # In the second half of the register space (0x800..0xbff - 1KB) FB_OFFS = 0xc00 # Needs 0x100 bytes FB_OFFS = 0xc00 # Needs 0x100 bytes #HBA_PORT0 = 0x100 Not needed, always HBA_OFFS + 0x100 #HBA_PORT0 = 0x100 Not needed, always HBA_OFFS + 0x100 */ */ localparam HBA_OFFS32 = 0; localparam HBA_OFFS32 = 0; localparam HBA_PORT0_OFFS32 = 'h40; localparam HBA_PORT0_OFFS32 = 'h40; Loading Loading @@ -147,6 +156,7 @@ localparam DATA_TYPE_ERR = 3; reg [15:0] tf_err_sts; reg [15:0] tf_err_sts; reg update_err_sts_r; // Forward data to DMA (dev->mem) engine // Forward data to DMA (dev->mem) engine assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err; assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err; Loading @@ -163,8 +173,6 @@ localparam DATA_TYPE_ERR = 3; assign tfd_sts = tf_err_sts[ 7:0]; assign tfd_sts = tf_err_sts[ 7:0]; assign tfd_err = tf_err_sts[15:8]; assign tfd_err = tf_err_sts[15:8]; always @ (posedge mclk) begin always @ (posedge mclk) begin if (hba_rst || dma_in_stop) dma_in <= 0; if (hba_rst || dma_in_stop) dma_in <= 0; else if (dma_in_start) dma_in <= 1; else if (dma_in_start) dma_in <= 1; Loading Loading @@ -239,28 +247,35 @@ localparam DATA_TYPE_ERR = 3; if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8]; if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8]; else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0]; else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0]; else if (update_err_sts) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]}; else if (update_err_sts_r) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]}; if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0]; if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_err_sts) reg_data[ 7:0] <= tf_err_sts [ 7:0]; else if (update_err_sts_r) reg_data[ 7:0] <= tf_err_sts [ 7:0]; if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0]; if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0]; else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]}; else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]}; else if (clear_bsy_drq || set_bsy) tf_err_sts <= tf_err_sts & {8'hff,clear_bsy_drq,3'h7,clear_bsy_drq,3'h7} | {8'h0,set_bsy,7'h0}; else if (set_sts_7f || set_sts_80) tf_err_sts <= {tf_err_sts[15:8],set_sts_80,{7{set_sts_7f}}} ; reg_we <= reg_we_w || update_sig[3] || update_err_sts_r; reg_we <= reg_we_w || update_sig[3] || update_err_sts; if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r; if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r; else if (update_err_sts) reg_addr <= PXTFD_OFFS32; else if (update_err_sts_r) reg_addr <= PXTFD_OFFS32; if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14]; if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14]; if (reg_sdb) sdb_n <= hda_data_in[15]; if (reg_sdb) sdb_n <= hda_data_in[15]; if (reg_ds[0]) {dma_a,dma_d} <= {hda_data_in[15],hda_data_in[13]}; if (reg_ds[0]) {dma_a,dma_d} <= {hda_data_in[15],hda_data_in[13]}; if (reg_ps[0]) {pio_i,pio_d} <= {hda_data_in[14],hda_data_in[13]}; if (reg_ps[0]) {pio_i,pio_d} <= {hda_data_in[14],hda_data_in[13]}; if (reg_ps[3]) pio_es <= hda_data_in[31:24]; if (hba_rst) pio_es <= 0; else if (reg_ps[3]) pio_es <= hda_data_in[31:24]; if (reg_ps[4] || reg_ds[5]) xfer_cntr[31:1] <= {reg_ds[5]?hda_data_in[31:16]:16'b0,hda_data_in[15:1]}; if (reg_ps[4] || reg_ds[5]) xfer_cntr[31:1] <= {reg_ds[5]?hda_data_in[31:16]:16'b0,hda_data_in[15:1]}; update_err_sts_r <= update_err_sts || clear_bsy_drq || set_bsy || set_sts_7f || set_sts_80; end end endmodule endmodule utils/ahci_fis_transmit.v 0 → 100644 +171 −0 Original line number Original line Diff line number Diff line /******************************************************************************* * Module: ahci_fis_transmit * Date:2016-01-07 * Author: andrey * Description: Fetches commands, command tables, creates/sends FIS * * Copyright (c) 2016 Elphel, Inc . * ahci_fis_transmit.v is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ahci_fis_transmit.v is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> . *******************************************************************************/ `timescale 1ns/1ps module ahci_fis_transmit #( parameter READ_REG_LATENCY = 2 // 0 if reg_rdata is available with reg_re/reg_addr )( input hba_rst, // @posedge mclk - sync reset input mclk, // for command/status input fetch_chead, // fetch command header (from the register memory output [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0) output ch_c, // Clear busy upon R_OK for this FIS output ch_b, // Built-in self test command output ch_r, // reset - may need to send SYNC escape before this command output ch_p, // prefetchable - only used with non-zero PRDTL or ATAPI bit set output ch_w, // Write: system memory -> device output ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command output [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal, // maximal is 16 (0x10) output [31:7] ch_ctba, // command table base address // register memory interface output reg [ADDRESS_BITS-1:0] reg_addr, output reg_re, output reg [31:0] reg_rdata, // DMA (memory -> device) interface input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port input dma_dav, // at least one dword is ready to be read from DMA module input dma_re, // read dword from DMA module to the outpu register // Data System memory or FIS -> device output reg [31:0] todev_data, // 32-bit data from the system memory to HBA (dma data) output reg [ 1:0] todev_type, // 0 - data, 1 - FIS head, 2 - FIS END (make FIS_Last?) output todev_valid, // output register full input todev_ready // send FIFO has room for data (>= ? dwords) // Add a possiblity to flush any data to FIFO if error was detected after data went there? ); localparam CLB_OFFS32 = 'h200; // # In the second half of the register space (0x800..0xbff - 1KB) reg todev_full_r; reg dma_en_r; wire fis_data_valid; wire [1:0] fis_data_type; wire [31:0] fis_data_out; wire write_or_w = (dma_en_r?dma_dav:fis_data_valid) && todev_ready; // do not fill the buffer if FIFO is not ready wire fis_out_w = !dma_en_r && fis_data_valid && todev_ready; wire dma_re_w = dma_en_r && dma_dav && todev_ready; reg [15:0] ch_prdtl_r; reg ch_c_r; reg ch_b_r; reg ch_r_r; reg ch_p_r; reg ch_w_r; reg ch_a_r; reg [4:0] ch_cfl_r; reg [31:7] ch_ctba_r; reg [READ_REG_LATENCY:0] reg_re_r; wire reg_re_w; // combined conditions to read register memory wire reg_stb = reg_re_r[READ_REG_LATENCY]; wire pre_reg_stb = reg_re_r[READ_REG_LATENCY-1]; reg [3:0] fetch_chead_r; reg [2:0] fetch_chead_stb_r; reg chead_bsy; // busy reading command header reg chead_bsy_re; // busy sending read command header assign todev_valid = todev_full_r; assign dma_re = dma_re_w; assign reg_re = reg_re_r[0]; assign ch_prdtl = ch_prdtl_r; assign ch_c = ch_c_r; assign ch_b = ch_b_r; assign ch_r = ch_r_r; assign ch_p = ch_p_r; assign ch_w = ch_w_r; assign ch_a = ch_a_r; assign ch_cfl = ch_cfl_r; assign ch_ctba = ch_ctba_r[31:7]; assign reg_re_w = fetch_chead || chead_bsy_re; always @ (posedge mclk) begin // Mutliplex between DMA and FIS output to the output routed to transmit FIFO // Count bypassing DMA dwords to generate FIS_last condition? if (hba_rst) todev_full_r <= 0; else if (write_or_w) todev_full_r <= 1; // do not fill the buffer if FIFO is not ready else if (todev_ready) todev_full_r <= 0; if (write_or_w) todev_data <= dma_en_r? dma_out: fis_data_out; if (hba_rst) todev_type <= 3; // invalid? else if (write_or_w) todev_type <= dma_en_r? 2'h0 : fis_data_type; if (hba_rst) fetch_chead_r <= 0; else if (fetch_chead) fetch_chead_r <= 1; else fetch_chead_r <= fetch_chead_r << 1; if (hba_rst) fetch_chead_stb_r <= 0; else if (pre_reg_stb && chead_bsy) fetch_chead_stb_r <= 1; else fetch_chead_stb_r <= fetch_chead_stb_r << 1; if (hba_rst) chead_bsy <= 0; else if (fetch_chead) chead_bsy <= 1; else if (fetch_chead_stb_r[2]) chead_bsy <= 0; if (hba_rst) chead_bsy_re <= 0; else if (fetch_chead) chead_bsy_re <= 1; else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords if (hba_rst) reg_re_r <= 0; else if (reg_re_w) reg_re_r <= 1; else reg_re_r <= reg_re_r << 1; if (fetch_chead) reg_addr <= CLB_OFFS32; // there will be more conditions else if (reg_re_r[0]) reg_addr <= reg_addr + 1; // save command header data to registers if (fetch_chead_stb_r[0]) begin ch_prdtl_r <= reg_rdata[31:16]; ch_c_r <= reg_rdata[ 10]; ch_b_r <= reg_rdata[ 9]; ch_r_r <= reg_rdata[ 8]; ch_p_r <= reg_rdata[ 7]; ch_w_r <= reg_rdata[ 6]; ch_a_r <= reg_rdata[ 5]; ch_cfl_r <= reg_rdata[ 4: 0]; end if (fetch_chead_stb_r[2]) ch_ctba_r[31:7] <= reg_rdata[31:7]; /* reg [3:0] fetch_chead_r; reg [3:0] fetch_chead_stb_r; reg chead_bsy; // busy reading command header */ end endmodule Loading
utils/ahci_fis_receive.v +35 −20 Original line number Original line Diff line number Diff line Loading @@ -43,14 +43,21 @@ module ahci_fis_receive#( input get_sdbfis, input get_sdbfis, input get_ufis, input get_ufis, input get_data_fis, input get_data_fis, input get_ignore, // ignore whatever FIS data in the input get_ignore, // ignore whatever FIS (use for DMA activate too?) output reg get_fis_busy, // busy processing FIS output reg get_fis_busy, // busy processing FIS output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_* output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_* output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS output fis_ferr, // FIS done, fatal error - FIS too long output fis_ferr, // FIS done, fatal error - FIS too long input update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h input update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h input clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update input set_bsy, // set PxTFD.STS.BSY, update input set_sts_7f, // set PxTFD.STS = 0x7f, update input set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update // TODO: Add writing PRDBC here? output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) // tfd_sts[7] - BSY, tfd_sts[4] - DRQ, tfd_sts[0] - ERR output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB) output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB) output reg fis_i, // value of "I" field in received regsD2H or SDB FIS output reg fis_i, // value of "I" field in received regsD2H or SDB FIS output reg sdb_n, // value of "N" field in received SDB FIS output reg sdb_n, // value of "N" field in received SDB FIS Loading Loading @@ -86,6 +93,8 @@ CLB_OFFS = 0x800 # In the second half of the register space (0x800..0xbff - 1KB) FB_OFFS = 0xc00 # Needs 0x100 bytes FB_OFFS = 0xc00 # Needs 0x100 bytes #HBA_PORT0 = 0x100 Not needed, always HBA_OFFS + 0x100 #HBA_PORT0 = 0x100 Not needed, always HBA_OFFS + 0x100 */ */ localparam HBA_OFFS32 = 0; localparam HBA_OFFS32 = 0; localparam HBA_PORT0_OFFS32 = 'h40; localparam HBA_PORT0_OFFS32 = 'h40; Loading Loading @@ -147,6 +156,7 @@ localparam DATA_TYPE_ERR = 3; reg [15:0] tf_err_sts; reg [15:0] tf_err_sts; reg update_err_sts_r; // Forward data to DMA (dev->mem) engine // Forward data to DMA (dev->mem) engine assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err; assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err; Loading @@ -163,8 +173,6 @@ localparam DATA_TYPE_ERR = 3; assign tfd_sts = tf_err_sts[ 7:0]; assign tfd_sts = tf_err_sts[ 7:0]; assign tfd_err = tf_err_sts[15:8]; assign tfd_err = tf_err_sts[15:8]; always @ (posedge mclk) begin always @ (posedge mclk) begin if (hba_rst || dma_in_stop) dma_in <= 0; if (hba_rst || dma_in_stop) dma_in <= 0; else if (dma_in_start) dma_in <= 1; else if (dma_in_start) dma_in <= 1; Loading Loading @@ -239,28 +247,35 @@ localparam DATA_TYPE_ERR = 3; if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8]; if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8]; else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0]; else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0]; else if (update_err_sts) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]}; else if (update_err_sts_r) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]}; if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0]; if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_err_sts) reg_data[ 7:0] <= tf_err_sts [ 7:0]; else if (update_err_sts_r) reg_data[ 7:0] <= tf_err_sts [ 7:0]; if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0]; if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0]; else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]}; else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]}; else if (clear_bsy_drq || set_bsy) tf_err_sts <= tf_err_sts & {8'hff,clear_bsy_drq,3'h7,clear_bsy_drq,3'h7} | {8'h0,set_bsy,7'h0}; else if (set_sts_7f || set_sts_80) tf_err_sts <= {tf_err_sts[15:8],set_sts_80,{7{set_sts_7f}}} ; reg_we <= reg_we_w || update_sig[3] || update_err_sts_r; reg_we <= reg_we_w || update_sig[3] || update_err_sts; if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r; if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r; else if (update_err_sts) reg_addr <= PXTFD_OFFS32; else if (update_err_sts_r) reg_addr <= PXTFD_OFFS32; if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14]; if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14]; if (reg_sdb) sdb_n <= hda_data_in[15]; if (reg_sdb) sdb_n <= hda_data_in[15]; if (reg_ds[0]) {dma_a,dma_d} <= {hda_data_in[15],hda_data_in[13]}; if (reg_ds[0]) {dma_a,dma_d} <= {hda_data_in[15],hda_data_in[13]}; if (reg_ps[0]) {pio_i,pio_d} <= {hda_data_in[14],hda_data_in[13]}; if (reg_ps[0]) {pio_i,pio_d} <= {hda_data_in[14],hda_data_in[13]}; if (reg_ps[3]) pio_es <= hda_data_in[31:24]; if (hba_rst) pio_es <= 0; else if (reg_ps[3]) pio_es <= hda_data_in[31:24]; if (reg_ps[4] || reg_ds[5]) xfer_cntr[31:1] <= {reg_ds[5]?hda_data_in[31:16]:16'b0,hda_data_in[15:1]}; if (reg_ps[4] || reg_ds[5]) xfer_cntr[31:1] <= {reg_ds[5]?hda_data_in[31:16]:16'b0,hda_data_in[15:1]}; update_err_sts_r <= update_err_sts || clear_bsy_drq || set_bsy || set_sts_7f || set_sts_80; end end endmodule endmodule
utils/ahci_fis_transmit.v 0 → 100644 +171 −0 Original line number Original line Diff line number Diff line /******************************************************************************* * Module: ahci_fis_transmit * Date:2016-01-07 * Author: andrey * Description: Fetches commands, command tables, creates/sends FIS * * Copyright (c) 2016 Elphel, Inc . * ahci_fis_transmit.v is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ahci_fis_transmit.v is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> . *******************************************************************************/ `timescale 1ns/1ps module ahci_fis_transmit #( parameter READ_REG_LATENCY = 2 // 0 if reg_rdata is available with reg_re/reg_addr )( input hba_rst, // @posedge mclk - sync reset input mclk, // for command/status input fetch_chead, // fetch command header (from the register memory output [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0) output ch_c, // Clear busy upon R_OK for this FIS output ch_b, // Built-in self test command output ch_r, // reset - may need to send SYNC escape before this command output ch_p, // prefetchable - only used with non-zero PRDTL or ATAPI bit set output ch_w, // Write: system memory -> device output ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command output [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal, // maximal is 16 (0x10) output [31:7] ch_ctba, // command table base address // register memory interface output reg [ADDRESS_BITS-1:0] reg_addr, output reg_re, output reg [31:0] reg_rdata, // DMA (memory -> device) interface input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port input dma_dav, // at least one dword is ready to be read from DMA module input dma_re, // read dword from DMA module to the outpu register // Data System memory or FIS -> device output reg [31:0] todev_data, // 32-bit data from the system memory to HBA (dma data) output reg [ 1:0] todev_type, // 0 - data, 1 - FIS head, 2 - FIS END (make FIS_Last?) output todev_valid, // output register full input todev_ready // send FIFO has room for data (>= ? dwords) // Add a possiblity to flush any data to FIFO if error was detected after data went there? ); localparam CLB_OFFS32 = 'h200; // # In the second half of the register space (0x800..0xbff - 1KB) reg todev_full_r; reg dma_en_r; wire fis_data_valid; wire [1:0] fis_data_type; wire [31:0] fis_data_out; wire write_or_w = (dma_en_r?dma_dav:fis_data_valid) && todev_ready; // do not fill the buffer if FIFO is not ready wire fis_out_w = !dma_en_r && fis_data_valid && todev_ready; wire dma_re_w = dma_en_r && dma_dav && todev_ready; reg [15:0] ch_prdtl_r; reg ch_c_r; reg ch_b_r; reg ch_r_r; reg ch_p_r; reg ch_w_r; reg ch_a_r; reg [4:0] ch_cfl_r; reg [31:7] ch_ctba_r; reg [READ_REG_LATENCY:0] reg_re_r; wire reg_re_w; // combined conditions to read register memory wire reg_stb = reg_re_r[READ_REG_LATENCY]; wire pre_reg_stb = reg_re_r[READ_REG_LATENCY-1]; reg [3:0] fetch_chead_r; reg [2:0] fetch_chead_stb_r; reg chead_bsy; // busy reading command header reg chead_bsy_re; // busy sending read command header assign todev_valid = todev_full_r; assign dma_re = dma_re_w; assign reg_re = reg_re_r[0]; assign ch_prdtl = ch_prdtl_r; assign ch_c = ch_c_r; assign ch_b = ch_b_r; assign ch_r = ch_r_r; assign ch_p = ch_p_r; assign ch_w = ch_w_r; assign ch_a = ch_a_r; assign ch_cfl = ch_cfl_r; assign ch_ctba = ch_ctba_r[31:7]; assign reg_re_w = fetch_chead || chead_bsy_re; always @ (posedge mclk) begin // Mutliplex between DMA and FIS output to the output routed to transmit FIFO // Count bypassing DMA dwords to generate FIS_last condition? if (hba_rst) todev_full_r <= 0; else if (write_or_w) todev_full_r <= 1; // do not fill the buffer if FIFO is not ready else if (todev_ready) todev_full_r <= 0; if (write_or_w) todev_data <= dma_en_r? dma_out: fis_data_out; if (hba_rst) todev_type <= 3; // invalid? else if (write_or_w) todev_type <= dma_en_r? 2'h0 : fis_data_type; if (hba_rst) fetch_chead_r <= 0; else if (fetch_chead) fetch_chead_r <= 1; else fetch_chead_r <= fetch_chead_r << 1; if (hba_rst) fetch_chead_stb_r <= 0; else if (pre_reg_stb && chead_bsy) fetch_chead_stb_r <= 1; else fetch_chead_stb_r <= fetch_chead_stb_r << 1; if (hba_rst) chead_bsy <= 0; else if (fetch_chead) chead_bsy <= 1; else if (fetch_chead_stb_r[2]) chead_bsy <= 0; if (hba_rst) chead_bsy_re <= 0; else if (fetch_chead) chead_bsy_re <= 1; else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords if (hba_rst) reg_re_r <= 0; else if (reg_re_w) reg_re_r <= 1; else reg_re_r <= reg_re_r << 1; if (fetch_chead) reg_addr <= CLB_OFFS32; // there will be more conditions else if (reg_re_r[0]) reg_addr <= reg_addr + 1; // save command header data to registers if (fetch_chead_stb_r[0]) begin ch_prdtl_r <= reg_rdata[31:16]; ch_c_r <= reg_rdata[ 10]; ch_b_r <= reg_rdata[ 9]; ch_r_r <= reg_rdata[ 8]; ch_p_r <= reg_rdata[ 7]; ch_w_r <= reg_rdata[ 6]; ch_a_r <= reg_rdata[ 5]; ch_cfl_r <= reg_rdata[ 4: 0]; end if (fetch_chead_stb_r[2]) ch_ctba_r[31:7] <= reg_rdata[31:7]; /* reg [3:0] fetch_chead_r; reg [3:0] fetch_chead_stb_r; reg chead_bsy; // busy reading command header */ end endmodule