Loading ahci/ahci_fis_transmit.v +101 −102 Original line number Original line Diff line number Diff line Loading @@ -21,32 +21,32 @@ `timescale 1ns/1ps `timescale 1ns/1ps module ahci_fis_transmit #( module ahci_fis_transmit #( parameter PREFETCH_ALWAYS = 0, parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter READ_CT_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter READ_CT_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle) parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle) )( )( input hba_rst, // @posedge mclk - sync reset input hba_rst, // @posedge mclk - when port is reset (even COMINIT)? input mclk, // for command/status input mclk, // for command/status // Command pulses to execute states input fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS) input fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS) // wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd // wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd output pCmdToIssue, // AHCI port variable output dmaCntrZero, // DmA counter is zero (first command) output reg fetch_cmd_busy, // does not include prefetching CT // input fetch_ct, // fetch command table (ch_ctba[31:7] should be valid by now) input cfis_xmit, // transmit command (wait for dma_ct_busy == 0) input cfis_xmit, // transmit command (wait for dma_ct_busy == 0) input dx_transmit, // send FIS header DWORD, (just 0x46), then forward DMA data input dx_transmit, // send FIS header DWORD, (just 0x46), then forward DMA data // transmit until error, 2048DWords or pDmaXferCnt // transmit until error, 2048DWords or pDmaXferCnt input atapi_xmit, // tarsmit ATAPI command FIS output reg done, output reg busy, input clearCmdToIssue, // From CFIS:SUCCESS output pCmdToIssue, // AHCI port variable // output dmaCntrZero, // DMA counter is zero - would be a duplicate to the one in receive module and dwords_sent output output reg fetch_cmd_busy, // does not include prefetching CT input syncesc_recv, // These two inputs interrupt transmit input syncesc_recv, // These two inputs interrupt transmit input xmit_err, // input xmit_err, // output dx_busy, output dx_done, // single-clock dx_transmit is finished, check dx_err output [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command) output [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command) input atapi_xmit, // tarsmit ATAPI command FIS output [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0) 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_c, // Clear busy upon R_OK for this FIS output ch_b, // Built-in self test command output ch_b, // Built-in self test command Loading @@ -56,39 +56,30 @@ module ahci_fis_transmit #( output ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command 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, output [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal, // maximal is 16 (0x10) // maximal is 16 (0x10) // output [31:7] ch_ctba, // command table base address - use reg_rdata[31:7] - outside output reg [11:2] dwords_sent, // number of DWORDs transmitted (up to 2048) output reg [11:2] dwords_sent, // number of DWORDs transmitted (up to 2048) // register memory interface // register memory interface output reg [ADDRESS_BITS-1:0] reg_addr, output reg [ADDRESS_BITS-1:0] reg_addr, output reg_re, output reg_re, input [31:0] reg_rdata, input [31:0] reg_rdata, // ahci_fis_receive interface // ahci_fis_receive interface input [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc input [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc output dma_ctba_ld, // load command table base address output dma_ctba_ld, // load command table address from output dma_start, // start processing command table, reset prdbc (next cycle after dma_ctba_ld, bits prdtl valid) output dma_start, // start processing command table, reset prdbc (next cycle after dma_ctba_ld, bits prdtl valid) output dma_dev_wr, // write to device (valid at start) output dma_dev_wr, // write to device (valid at start) input dma_ct_busy, // dma module is busy reading command table from the system memory input dma_ct_busy, // dma module is busy reading command table from the system memory // issue dma_prd_start same time as dma_start if prefetch enabled, otherwise with cfis_xmit // issue dma_prd_start same time as dma_start if prefetch enabled, otherwise with cfis_xmit output dma_prd_start, // at or after cmd_start - enable reading PRD/data (if any) ch_prdtl should be valid output reg dma_prd_start, // at or after cmd_start - enable reading PRD/data (if any) ch_prdtl should be valid, twice - OK output reg cmd_abort, // try to abort a command TODO: Implement // output cmd_abort, // try to abort a command TODO: Implement // reading out command table data from DMA module // reading out command table data from DMA module output reg [ 4:0] ct_addr, // DWORD address output reg [ 4:0] ct_addr, // DWORD address output ct_re, // output ct_re, // input [31:0] ct_data, // input [31:0] ct_data, // // DMA (memory -> device) interface // DMA (memory -> device) interface input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port 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_dav, // at least one dword is ready to be read from DMA module Loading Loading @@ -122,8 +113,12 @@ module ahci_fis_transmit #( reg ch_p_r; reg ch_p_r; reg ch_w_r; reg ch_w_r; reg ch_a_r; reg ch_a_r; reg [4:0] ch_cfl_r; reg [4:0] ch_cmd_len_r; reg [4:0] ch_cfl_out_r; reg [4:0] cfis_acmd_left_r; // number of DWORDS in CFIS or ACMD area of the command table left to be fetched from ahci_dma module BRAM // For CFIS this register is set from ch_cmd_len_r, for ACMD - from the xfer_cntr input // (stored in the ahci_fis_receive module) reg [4:0] cfis_acmd_left_out_r; // Same, just with latency of the data available from the ahci_dma module // reg [31:7] ch_ctba_r; // reg [31:7] ch_ctba_r; reg [READ_REG_LATENCY:0] reg_re_r; reg [READ_REG_LATENCY:0] reg_re_r; wire reg_re_w; // combined conditions to read register memory wire reg_re_w; // combined conditions to read register memory Loading @@ -135,17 +130,14 @@ module ahci_fis_transmit #( reg chead_bsy; // busy reading command header reg chead_bsy; // busy reading command header reg chead_bsy_re; // busy sending read command header reg chead_bsy_re; // busy sending read command header reg pCmdToIssue_r; reg pCmdToIssue_r; wire clearCmdToIssue; // TODO: assign - clear pCmdToIssue // reg fetch_ct_r; // reg fetch_ct_r; reg cfis_xmit_pend_r; // reg acfis_xmit_pend_r; // reg cfis_xmit_start_r; reg acfis_xmit_start_r; reg cfis_xmit_busy_r; // reg acfis_xmit_busy_r; // reg dmaCntrZero_r; // first command // reg anc_fis_r; // This is ATAPI FIS, not Command FIS // wire start_sync_escape_w = cfis_xmit && ch_r_r; - no, it should be instead of a ct_fetch // TODO: Start FIS transmit when all FIS is in FIFO or data and >half(too slow, need minimum to be able to send wait primitive) or less? wire cfis_xmit_start_w = (dx_transmit || cfis_xmit_pend_r) && !dma_ct_busy && !fetch_cmd_busy; // dma_ct_busy no gaps with fetch_cmd_busy wire acfis_xmit_start_w = (cfis_xmit || atapi_xmit || acfis_xmit_pend_r) && !dma_ct_busy && !fetch_cmd_busy; // dma_ct_busy no gaps with fetch_cmd_busy wire cfis_xmit_end; wire acfis_xmit_end = ct_stb && fis_dw_last; wire ct_re_w; // next cycle will be ct_re; wire ct_re_w; // next cycle will be ct_re; reg [READ_CT_LATENCY:0] ct_re_r; reg [READ_CT_LATENCY:0] ct_re_r; Loading @@ -159,8 +151,9 @@ module ahci_fis_transmit #( wire dx_dma_last_w; // sending last adat word wire dx_dma_last_w; // sending last adat word reg dx_busy_r; reg dx_busy_r; reg [ 1:0] dx_err_r; reg [ 1:0] dx_err_r; reg dx_done_r; wire any_cmd_start = fetch_cmd || cfis_xmit || dx_transmit || atapi_xmit; wire any_cmd_start = fetch_cmd || cfis_xmit || dx_transmit || atapi_xmit; wire done_w = dx_dma_last_w || ((|dx_err_r) && dx_busy_r) || chead_done_w || acfis_xmit_end; // done on last transmit or error assign todev_valid = todev_full_r; assign todev_valid = todev_full_r; assign dma_re = dma_re_w; assign dma_re = dma_re_w; Loading @@ -173,27 +166,23 @@ module ahci_fis_transmit #( assign ch_p = ch_p_r; assign ch_p = ch_p_r; assign ch_w = ch_w_r; assign ch_w = ch_w_r; assign ch_a = ch_a_r; assign ch_a = ch_a_r; assign ch_cfl = ch_cfl_r; assign ch_cfl = cfis_acmd_left_r; // assign ch_ctba = ch_ctba_r[31:7]; assign reg_re_w = fetch_cmd || chead_bsy_re; assign reg_re_w = fetch_cmd || chead_bsy_re; assign dma_ctba_ld = fetch_chead_stb_r[2]; assign dma_ctba_ld = fetch_chead_stb_r[2]; assign dma_start = fetch_chead_stb_r[3]; // next cycle after dma_ctba_ld assign dma_start = fetch_chead_stb_r[3]; // next cycle after dma_ctba_ld assign pCmdToIssue = pCmdToIssue_r; assign pCmdToIssue = pCmdToIssue_r; assign dmaCntrZero = dmaCntrZero_r; // assign dmaCntrZero = dmaCntrZero_r; assign ct_re = ct_re_r[0]; assign ct_re = ct_re_r[0]; assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability assign ct_re_w = todev_ready && ((ch_cfl_r[4:1] != 0) || (ch_cfl_r[0] && !ct_re_r[0])); // Later add more sources assign ct_re_w = todev_ready && ((cfis_acmd_left_r[4:1] != 0) || (cfis_acmd_left_r[0] && !ct_re_r[0])); // Later add more sources assign fis_dw_last = (ch_cfl_out_r == 1); assign fis_dw_last = (cfis_acmd_left_out_r == 1); assign fis_data_type = {fis_dw_last, (write_or_w && dx_fis_pend_r) | (fis_dw_first && ct_stb)}; assign fis_data_type = {fis_dw_last, (write_or_w && dx_fis_pend_r) | (fis_dw_first && ct_stb)}; assign fis_data_out = ({32{dx_fis_pend_r}} & DATA_FIS) | ({32{ct_stb}} & ct_data) ; assign fis_data_out = ({32{dx_fis_pend_r}} & DATA_FIS) | ({32{ct_stb}} & ct_data) ; assign dx_dma_last_w = dma_en_r && dma_re_w && (dx_dwords_left[11:2] == 1); assign dx_dma_last_w = dma_en_r && dma_re_w && (dx_dwords_left[11:2] == 1); assign dx_busy = dx_busy_r; assign dx_done = dx_done_r; assign dx_err = dx_err_r; assign dx_err = dx_err_r; assign dma_dev_wr = ch_w_r; always @ (posedge mclk) begin always @ (posedge mclk) begin // Mutliplex between DMA and FIS output to the output routed to transmit FIFO // Mutliplex between DMA and FIS output to the output routed to transmit FIFO Loading @@ -207,7 +196,9 @@ module ahci_fis_transmit #( if (hba_rst) todev_type <= 3; // invalid? - no, now first and last word in command FIS (impossible?) if (hba_rst) todev_type <= 3; // invalid? - no, now first and last word in command FIS (impossible?) else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w, 1'b0} : fis_data_type; else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w, 1'b0} : fis_data_type; if (hba_rst) fetch_chead_r <= 0; // Read 3 DWORDs from the command header if (hba_rst) fetch_chead_r <= 0; // running 1 else if (fetch_cmd) fetch_chead_r <= 1; else if (fetch_cmd) fetch_chead_r <= 1; else fetch_chead_r <= fetch_chead_r << 1; else fetch_chead_r <= fetch_chead_r << 1; Loading @@ -223,7 +214,7 @@ module ahci_fis_transmit #( else if (fetch_cmd) chead_bsy_re <= 1; else if (fetch_cmd) chead_bsy_re <= 1; else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords if (hba_rst) reg_re_r <= 0; if (hba_rst) reg_re_r <= 0; // [0] -> reg_re output else if (reg_re_w) reg_re_r <= 1; else if (reg_re_w) reg_re_r <= 1; else reg_re_r <= reg_re_r << 1; else reg_re_r <= reg_re_r << 1; Loading @@ -239,7 +230,7 @@ module ahci_fis_transmit #( ch_p_r <= reg_rdata[ 7]; ch_p_r <= reg_rdata[ 7]; ch_w_r <= reg_rdata[ 6]; ch_w_r <= reg_rdata[ 6]; ch_a_r <= reg_rdata[ 5]; ch_a_r <= reg_rdata[ 5]; ch_cfl_r <= reg_rdata[ 4: 0]; ch_cmd_len_r<= reg_rdata[ 4: 0]; end end if (hba_rst) pCmdToIssue_r <= 0; if (hba_rst) pCmdToIssue_r <= 0; Loading @@ -250,39 +241,41 @@ module ahci_fis_transmit #( else if (fetch_cmd) fetch_cmd_busy <= 1; else if (fetch_cmd) fetch_cmd_busy <= 1; else if (dma_start) fetch_cmd_busy <= 0; else if (dma_start) fetch_cmd_busy <= 0; // fetch and send command fis //CFIS/ATAPI common if (hba_rst || cfis_xmit_start_w) cfis_xmit_pend_r <= 0; else if (cfis_xmit) cfis_xmit_pend_r <= 1; cfis_xmit_start_r <= !hba_rst && cfis_xmit_start_w; // if (hba_rst || cfis_xmit) anc_fis_r <= 0; // else if (atapi_xmit) anc_fis_r <= 1; if (hba_rst) cfis_xmit_busy_r <= 0; // fetch and send command/atapi FIS else if (cfis_xmit_start_r) cfis_xmit_busy_r <= 1; if (hba_rst || acfis_xmit_start_w) acfis_xmit_pend_r <= 0; else if (cfis_xmit_end) cfis_xmit_busy_r <= 0; else if (cfis_xmit || atapi_xmit) acfis_xmit_pend_r <= 1; if (fetch_chead_stb_r[0]) ch_cfl_r <= reg_rdata[ 4: 0]; // Will assume that there is room for ... acfis_xmit_start_r <= !hba_rst && acfis_xmit_start_w; else if (cfis_xmit_busy_r && ct_re_r[0]) ch_cfl_r <= ch_cfl_r - 1; // Counting CFIS dwords sent to TL if (hba_rst) acfis_xmit_busy_r <= 0; if (cfis_xmit_start_w) ch_cfl_out_r <= ch_cfl_r; else if (acfis_xmit_start_r) acfis_xmit_busy_r <= 1; else if (ct_stb) ch_cfl_out_r <= ch_cfl_out_r - 1; else if (acfis_xmit_end) acfis_xmit_busy_r <= 0; if (cfis_xmit) cfis_acmd_left_r <= ch_cmd_len_r[ 4: 0]; // Will assume that there is room for ... else if (atapi_xmit) cfis_acmd_left_r <= (|xfer_cntr[31:4]) ? 5'h4 : {3'b0,xfer_cntr[3:2]}; else if (acfis_xmit_busy_r && ct_re_r[0]) cfis_acmd_left_r <= cfis_acmd_left_r - 1; // Counting CFIS/ATAPI FIS dwords sent to TL if (acfis_xmit_start_r) cfis_acmd_left_out_r <= cfis_acmd_left_r; else if (ct_stb) cfis_acmd_left_out_r <= cfis_acmd_left_out_r - 1; ct_re_r <= {ct_re_r[READ_CT_LATENCY-1:0],ct_re_w}; ct_re_r <= {ct_re_r[READ_CT_LATENCY-1:0],ct_re_w}; if (cfis_xmit) ct_addr <= 0; if (cfis_xmit) ct_addr <= 0; else if (ch_cfl_r[0]) ct_addr <= ct_addr + 1; else if (atapi_xmit) ct_addr <= 'h10; // start of ATAPI area else if (cfis_acmd_left_r[0]) ct_addr <= ct_addr + 1; // first/last dword in FIS // first/last dword in FIS if (!cfis_xmit_busy_r) fis_dw_first <= 1; if (!acfis_xmit_busy_r) fis_dw_first <= 1; else if (ct_stb) fis_dw_first <= 0; else if (ct_stb) fis_dw_first <= 0; // TODO: Implement ATAPI command, other FIS to send? //TODO: update xfer length, prdtl (only after R_OK) - yes, do it outside // Send Data FIS TODO: abort on errors, and busy (or done) output // input syncesc_recv, // These two inputs interrupt transmit // input xmit_err, // //TODO: update xfer length, prdtl (only after R_OK)? if (dx_transmit) dx_dwords_left[11:2] <= (|xfer_cntr[31:11])?10'h200:{1'b0,xfer_cntr[10:2]}; if (dx_transmit) dx_dwords_left[11:2] <= (|xfer_cntr[31:11])?10'h200:{1'b0,xfer_cntr[10:2]}; else if (dma_re_w) dx_dwords_left[11:2] <= dx_dwords_left[11:2] - 1; else if (dma_re_w) dx_dwords_left[11:2] <= dx_dwords_left[11:2] - 1; Loading @@ -306,15 +299,21 @@ module ahci_fis_transmit #( if (hba_rst) dx_busy_r <= 0; if (hba_rst) dx_busy_r <= 0; else if (dx_transmit) dx_busy_r <= 1; else if (dx_transmit) dx_busy_r <= 1; else if (dx_dma_last_w || (|dx_err_r)) dx_busy_r <= 0; else if (dx_dma_last_w || (|dx_err_r)) dx_busy_r <= 0; // done on last transmit or error if (hba_rst) dx_done_r <= 0; else dx_done_r <= dx_dma_last_w || ((|dx_err_r) && dx_busy_r); // TODO: Make commmon done for all commands? dma_prd_start <= (dma_start && (PREFETCH_ALWAYS || ch_p_r || !ch_w_r)) || // device read may prefetch just prd addresses (dx_fis_pend_r && write_or_w); // enable PRD read now (if it was not already done) end if (hba_rst) done <= 0; else done <= done_w; if (hba_rst) busy <= 0; else if (any_cmd_start) busy <= 1; else if (done_w) busy <= 0; cmd_abort <= done_w && (|dx_err_r); end endmodule endmodule Loading
ahci/ahci_fis_transmit.v +101 −102 Original line number Original line Diff line number Diff line Loading @@ -21,32 +21,32 @@ `timescale 1ns/1ps `timescale 1ns/1ps module ahci_fis_transmit #( module ahci_fis_transmit #( parameter PREFETCH_ALWAYS = 0, parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter READ_CT_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter READ_CT_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle) parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle) )( )( input hba_rst, // @posedge mclk - sync reset input hba_rst, // @posedge mclk - when port is reset (even COMINIT)? input mclk, // for command/status input mclk, // for command/status // Command pulses to execute states input fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS) input fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS) // wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd // wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd output pCmdToIssue, // AHCI port variable output dmaCntrZero, // DmA counter is zero (first command) output reg fetch_cmd_busy, // does not include prefetching CT // input fetch_ct, // fetch command table (ch_ctba[31:7] should be valid by now) input cfis_xmit, // transmit command (wait for dma_ct_busy == 0) input cfis_xmit, // transmit command (wait for dma_ct_busy == 0) input dx_transmit, // send FIS header DWORD, (just 0x46), then forward DMA data input dx_transmit, // send FIS header DWORD, (just 0x46), then forward DMA data // transmit until error, 2048DWords or pDmaXferCnt // transmit until error, 2048DWords or pDmaXferCnt input atapi_xmit, // tarsmit ATAPI command FIS output reg done, output reg busy, input clearCmdToIssue, // From CFIS:SUCCESS output pCmdToIssue, // AHCI port variable // output dmaCntrZero, // DMA counter is zero - would be a duplicate to the one in receive module and dwords_sent output output reg fetch_cmd_busy, // does not include prefetching CT input syncesc_recv, // These two inputs interrupt transmit input syncesc_recv, // These two inputs interrupt transmit input xmit_err, // input xmit_err, // output dx_busy, output dx_done, // single-clock dx_transmit is finished, check dx_err output [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command) output [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command) input atapi_xmit, // tarsmit ATAPI command FIS output [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0) 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_c, // Clear busy upon R_OK for this FIS output ch_b, // Built-in self test command output ch_b, // Built-in self test command Loading @@ -56,39 +56,30 @@ module ahci_fis_transmit #( output ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command 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, output [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal, // maximal is 16 (0x10) // maximal is 16 (0x10) // output [31:7] ch_ctba, // command table base address - use reg_rdata[31:7] - outside output reg [11:2] dwords_sent, // number of DWORDs transmitted (up to 2048) output reg [11:2] dwords_sent, // number of DWORDs transmitted (up to 2048) // register memory interface // register memory interface output reg [ADDRESS_BITS-1:0] reg_addr, output reg [ADDRESS_BITS-1:0] reg_addr, output reg_re, output reg_re, input [31:0] reg_rdata, input [31:0] reg_rdata, // ahci_fis_receive interface // ahci_fis_receive interface input [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc input [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc output dma_ctba_ld, // load command table base address output dma_ctba_ld, // load command table address from output dma_start, // start processing command table, reset prdbc (next cycle after dma_ctba_ld, bits prdtl valid) output dma_start, // start processing command table, reset prdbc (next cycle after dma_ctba_ld, bits prdtl valid) output dma_dev_wr, // write to device (valid at start) output dma_dev_wr, // write to device (valid at start) input dma_ct_busy, // dma module is busy reading command table from the system memory input dma_ct_busy, // dma module is busy reading command table from the system memory // issue dma_prd_start same time as dma_start if prefetch enabled, otherwise with cfis_xmit // issue dma_prd_start same time as dma_start if prefetch enabled, otherwise with cfis_xmit output dma_prd_start, // at or after cmd_start - enable reading PRD/data (if any) ch_prdtl should be valid output reg dma_prd_start, // at or after cmd_start - enable reading PRD/data (if any) ch_prdtl should be valid, twice - OK output reg cmd_abort, // try to abort a command TODO: Implement // output cmd_abort, // try to abort a command TODO: Implement // reading out command table data from DMA module // reading out command table data from DMA module output reg [ 4:0] ct_addr, // DWORD address output reg [ 4:0] ct_addr, // DWORD address output ct_re, // output ct_re, // input [31:0] ct_data, // input [31:0] ct_data, // // DMA (memory -> device) interface // DMA (memory -> device) interface input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port 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_dav, // at least one dword is ready to be read from DMA module Loading Loading @@ -122,8 +113,12 @@ module ahci_fis_transmit #( reg ch_p_r; reg ch_p_r; reg ch_w_r; reg ch_w_r; reg ch_a_r; reg ch_a_r; reg [4:0] ch_cfl_r; reg [4:0] ch_cmd_len_r; reg [4:0] ch_cfl_out_r; reg [4:0] cfis_acmd_left_r; // number of DWORDS in CFIS or ACMD area of the command table left to be fetched from ahci_dma module BRAM // For CFIS this register is set from ch_cmd_len_r, for ACMD - from the xfer_cntr input // (stored in the ahci_fis_receive module) reg [4:0] cfis_acmd_left_out_r; // Same, just with latency of the data available from the ahci_dma module // reg [31:7] ch_ctba_r; // reg [31:7] ch_ctba_r; reg [READ_REG_LATENCY:0] reg_re_r; reg [READ_REG_LATENCY:0] reg_re_r; wire reg_re_w; // combined conditions to read register memory wire reg_re_w; // combined conditions to read register memory Loading @@ -135,17 +130,14 @@ module ahci_fis_transmit #( reg chead_bsy; // busy reading command header reg chead_bsy; // busy reading command header reg chead_bsy_re; // busy sending read command header reg chead_bsy_re; // busy sending read command header reg pCmdToIssue_r; reg pCmdToIssue_r; wire clearCmdToIssue; // TODO: assign - clear pCmdToIssue // reg fetch_ct_r; // reg fetch_ct_r; reg cfis_xmit_pend_r; // reg acfis_xmit_pend_r; // reg cfis_xmit_start_r; reg acfis_xmit_start_r; reg cfis_xmit_busy_r; // reg acfis_xmit_busy_r; // reg dmaCntrZero_r; // first command // reg anc_fis_r; // This is ATAPI FIS, not Command FIS // wire start_sync_escape_w = cfis_xmit && ch_r_r; - no, it should be instead of a ct_fetch // TODO: Start FIS transmit when all FIS is in FIFO or data and >half(too slow, need minimum to be able to send wait primitive) or less? wire cfis_xmit_start_w = (dx_transmit || cfis_xmit_pend_r) && !dma_ct_busy && !fetch_cmd_busy; // dma_ct_busy no gaps with fetch_cmd_busy wire acfis_xmit_start_w = (cfis_xmit || atapi_xmit || acfis_xmit_pend_r) && !dma_ct_busy && !fetch_cmd_busy; // dma_ct_busy no gaps with fetch_cmd_busy wire cfis_xmit_end; wire acfis_xmit_end = ct_stb && fis_dw_last; wire ct_re_w; // next cycle will be ct_re; wire ct_re_w; // next cycle will be ct_re; reg [READ_CT_LATENCY:0] ct_re_r; reg [READ_CT_LATENCY:0] ct_re_r; Loading @@ -159,8 +151,9 @@ module ahci_fis_transmit #( wire dx_dma_last_w; // sending last adat word wire dx_dma_last_w; // sending last adat word reg dx_busy_r; reg dx_busy_r; reg [ 1:0] dx_err_r; reg [ 1:0] dx_err_r; reg dx_done_r; wire any_cmd_start = fetch_cmd || cfis_xmit || dx_transmit || atapi_xmit; wire any_cmd_start = fetch_cmd || cfis_xmit || dx_transmit || atapi_xmit; wire done_w = dx_dma_last_w || ((|dx_err_r) && dx_busy_r) || chead_done_w || acfis_xmit_end; // done on last transmit or error assign todev_valid = todev_full_r; assign todev_valid = todev_full_r; assign dma_re = dma_re_w; assign dma_re = dma_re_w; Loading @@ -173,27 +166,23 @@ module ahci_fis_transmit #( assign ch_p = ch_p_r; assign ch_p = ch_p_r; assign ch_w = ch_w_r; assign ch_w = ch_w_r; assign ch_a = ch_a_r; assign ch_a = ch_a_r; assign ch_cfl = ch_cfl_r; assign ch_cfl = cfis_acmd_left_r; // assign ch_ctba = ch_ctba_r[31:7]; assign reg_re_w = fetch_cmd || chead_bsy_re; assign reg_re_w = fetch_cmd || chead_bsy_re; assign dma_ctba_ld = fetch_chead_stb_r[2]; assign dma_ctba_ld = fetch_chead_stb_r[2]; assign dma_start = fetch_chead_stb_r[3]; // next cycle after dma_ctba_ld assign dma_start = fetch_chead_stb_r[3]; // next cycle after dma_ctba_ld assign pCmdToIssue = pCmdToIssue_r; assign pCmdToIssue = pCmdToIssue_r; assign dmaCntrZero = dmaCntrZero_r; // assign dmaCntrZero = dmaCntrZero_r; assign ct_re = ct_re_r[0]; assign ct_re = ct_re_r[0]; assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability assign ct_re_w = todev_ready && ((ch_cfl_r[4:1] != 0) || (ch_cfl_r[0] && !ct_re_r[0])); // Later add more sources assign ct_re_w = todev_ready && ((cfis_acmd_left_r[4:1] != 0) || (cfis_acmd_left_r[0] && !ct_re_r[0])); // Later add more sources assign fis_dw_last = (ch_cfl_out_r == 1); assign fis_dw_last = (cfis_acmd_left_out_r == 1); assign fis_data_type = {fis_dw_last, (write_or_w && dx_fis_pend_r) | (fis_dw_first && ct_stb)}; assign fis_data_type = {fis_dw_last, (write_or_w && dx_fis_pend_r) | (fis_dw_first && ct_stb)}; assign fis_data_out = ({32{dx_fis_pend_r}} & DATA_FIS) | ({32{ct_stb}} & ct_data) ; assign fis_data_out = ({32{dx_fis_pend_r}} & DATA_FIS) | ({32{ct_stb}} & ct_data) ; assign dx_dma_last_w = dma_en_r && dma_re_w && (dx_dwords_left[11:2] == 1); assign dx_dma_last_w = dma_en_r && dma_re_w && (dx_dwords_left[11:2] == 1); assign dx_busy = dx_busy_r; assign dx_done = dx_done_r; assign dx_err = dx_err_r; assign dx_err = dx_err_r; assign dma_dev_wr = ch_w_r; always @ (posedge mclk) begin always @ (posedge mclk) begin // Mutliplex between DMA and FIS output to the output routed to transmit FIFO // Mutliplex between DMA and FIS output to the output routed to transmit FIFO Loading @@ -207,7 +196,9 @@ module ahci_fis_transmit #( if (hba_rst) todev_type <= 3; // invalid? - no, now first and last word in command FIS (impossible?) if (hba_rst) todev_type <= 3; // invalid? - no, now first and last word in command FIS (impossible?) else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w, 1'b0} : fis_data_type; else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w, 1'b0} : fis_data_type; if (hba_rst) fetch_chead_r <= 0; // Read 3 DWORDs from the command header if (hba_rst) fetch_chead_r <= 0; // running 1 else if (fetch_cmd) fetch_chead_r <= 1; else if (fetch_cmd) fetch_chead_r <= 1; else fetch_chead_r <= fetch_chead_r << 1; else fetch_chead_r <= fetch_chead_r << 1; Loading @@ -223,7 +214,7 @@ module ahci_fis_transmit #( else if (fetch_cmd) chead_bsy_re <= 1; else if (fetch_cmd) chead_bsy_re <= 1; else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords if (hba_rst) reg_re_r <= 0; if (hba_rst) reg_re_r <= 0; // [0] -> reg_re output else if (reg_re_w) reg_re_r <= 1; else if (reg_re_w) reg_re_r <= 1; else reg_re_r <= reg_re_r << 1; else reg_re_r <= reg_re_r << 1; Loading @@ -239,7 +230,7 @@ module ahci_fis_transmit #( ch_p_r <= reg_rdata[ 7]; ch_p_r <= reg_rdata[ 7]; ch_w_r <= reg_rdata[ 6]; ch_w_r <= reg_rdata[ 6]; ch_a_r <= reg_rdata[ 5]; ch_a_r <= reg_rdata[ 5]; ch_cfl_r <= reg_rdata[ 4: 0]; ch_cmd_len_r<= reg_rdata[ 4: 0]; end end if (hba_rst) pCmdToIssue_r <= 0; if (hba_rst) pCmdToIssue_r <= 0; Loading @@ -250,39 +241,41 @@ module ahci_fis_transmit #( else if (fetch_cmd) fetch_cmd_busy <= 1; else if (fetch_cmd) fetch_cmd_busy <= 1; else if (dma_start) fetch_cmd_busy <= 0; else if (dma_start) fetch_cmd_busy <= 0; // fetch and send command fis //CFIS/ATAPI common if (hba_rst || cfis_xmit_start_w) cfis_xmit_pend_r <= 0; else if (cfis_xmit) cfis_xmit_pend_r <= 1; cfis_xmit_start_r <= !hba_rst && cfis_xmit_start_w; // if (hba_rst || cfis_xmit) anc_fis_r <= 0; // else if (atapi_xmit) anc_fis_r <= 1; if (hba_rst) cfis_xmit_busy_r <= 0; // fetch and send command/atapi FIS else if (cfis_xmit_start_r) cfis_xmit_busy_r <= 1; if (hba_rst || acfis_xmit_start_w) acfis_xmit_pend_r <= 0; else if (cfis_xmit_end) cfis_xmit_busy_r <= 0; else if (cfis_xmit || atapi_xmit) acfis_xmit_pend_r <= 1; if (fetch_chead_stb_r[0]) ch_cfl_r <= reg_rdata[ 4: 0]; // Will assume that there is room for ... acfis_xmit_start_r <= !hba_rst && acfis_xmit_start_w; else if (cfis_xmit_busy_r && ct_re_r[0]) ch_cfl_r <= ch_cfl_r - 1; // Counting CFIS dwords sent to TL if (hba_rst) acfis_xmit_busy_r <= 0; if (cfis_xmit_start_w) ch_cfl_out_r <= ch_cfl_r; else if (acfis_xmit_start_r) acfis_xmit_busy_r <= 1; else if (ct_stb) ch_cfl_out_r <= ch_cfl_out_r - 1; else if (acfis_xmit_end) acfis_xmit_busy_r <= 0; if (cfis_xmit) cfis_acmd_left_r <= ch_cmd_len_r[ 4: 0]; // Will assume that there is room for ... else if (atapi_xmit) cfis_acmd_left_r <= (|xfer_cntr[31:4]) ? 5'h4 : {3'b0,xfer_cntr[3:2]}; else if (acfis_xmit_busy_r && ct_re_r[0]) cfis_acmd_left_r <= cfis_acmd_left_r - 1; // Counting CFIS/ATAPI FIS dwords sent to TL if (acfis_xmit_start_r) cfis_acmd_left_out_r <= cfis_acmd_left_r; else if (ct_stb) cfis_acmd_left_out_r <= cfis_acmd_left_out_r - 1; ct_re_r <= {ct_re_r[READ_CT_LATENCY-1:0],ct_re_w}; ct_re_r <= {ct_re_r[READ_CT_LATENCY-1:0],ct_re_w}; if (cfis_xmit) ct_addr <= 0; if (cfis_xmit) ct_addr <= 0; else if (ch_cfl_r[0]) ct_addr <= ct_addr + 1; else if (atapi_xmit) ct_addr <= 'h10; // start of ATAPI area else if (cfis_acmd_left_r[0]) ct_addr <= ct_addr + 1; // first/last dword in FIS // first/last dword in FIS if (!cfis_xmit_busy_r) fis_dw_first <= 1; if (!acfis_xmit_busy_r) fis_dw_first <= 1; else if (ct_stb) fis_dw_first <= 0; else if (ct_stb) fis_dw_first <= 0; // TODO: Implement ATAPI command, other FIS to send? //TODO: update xfer length, prdtl (only after R_OK) - yes, do it outside // Send Data FIS TODO: abort on errors, and busy (or done) output // input syncesc_recv, // These two inputs interrupt transmit // input xmit_err, // //TODO: update xfer length, prdtl (only after R_OK)? if (dx_transmit) dx_dwords_left[11:2] <= (|xfer_cntr[31:11])?10'h200:{1'b0,xfer_cntr[10:2]}; if (dx_transmit) dx_dwords_left[11:2] <= (|xfer_cntr[31:11])?10'h200:{1'b0,xfer_cntr[10:2]}; else if (dma_re_w) dx_dwords_left[11:2] <= dx_dwords_left[11:2] - 1; else if (dma_re_w) dx_dwords_left[11:2] <= dx_dwords_left[11:2] - 1; Loading @@ -306,15 +299,21 @@ module ahci_fis_transmit #( if (hba_rst) dx_busy_r <= 0; if (hba_rst) dx_busy_r <= 0; else if (dx_transmit) dx_busy_r <= 1; else if (dx_transmit) dx_busy_r <= 1; else if (dx_dma_last_w || (|dx_err_r)) dx_busy_r <= 0; else if (dx_dma_last_w || (|dx_err_r)) dx_busy_r <= 0; // done on last transmit or error if (hba_rst) dx_done_r <= 0; else dx_done_r <= dx_dma_last_w || ((|dx_err_r) && dx_busy_r); // TODO: Make commmon done for all commands? dma_prd_start <= (dma_start && (PREFETCH_ALWAYS || ch_p_r || !ch_w_r)) || // device read may prefetch just prd addresses (dx_fis_pend_r && write_or_w); // enable PRD read now (if it was not already done) end if (hba_rst) done <= 0; else done <= done_w; if (hba_rst) busy <= 0; else if (any_cmd_start) busy <= 1; else if (done_w) busy <= 0; cmd_abort <= done_w && (|dx_err_r); end endmodule endmodule