Commit 09386747 authored by Andrey Filippov's avatar Andrey Filippov

connecting AHCI to link/phy layers

parent 0f0cf866
......@@ -33,21 +33,25 @@ module ahci_fis_transmit #(
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
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_xmit, // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
input atapi_xmit, // trasmit ATAPI command FIS
output reg done,
output reg done, // for fetch_cmd - dma_start, for *_xmit - xmit_ok, xmit_err, syncesc_recv or xrdy_collision
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 - now just use busy/done
input syncesc_recv, // These two inputs interrupt transmit
// Should wait for xmit_ok? Timeout? Timeout will be handled by software, so just wait for OK or some error
input xmit_ok, // FIS transmission acknowledged OK
input xmit_err, //
output [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command)
input syncesc_recv, // These two inputs interrupt transmit
input xrdy_collision,
output [ 2:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err, 2 - collision (valid @ xmit_err and later, reset by new command)
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
......@@ -89,7 +93,7 @@ module ahci_fis_transmit #(
// 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 reg [ 1:0] todev_type, // 0 - data, 1 - FIS head, 2 - FIS LAST)
output todev_valid, // output register full
input todev_ready // send FIFO has room for data (>= 8? dwords)
......@@ -152,13 +156,16 @@ module ahci_fis_transmit #(
reg dx_fis_pend_r; // waiting to send first DWORD of the H2D data transfer
wire dx_dma_last_w; // sending last adat word
reg dx_busy_r;
reg [ 1:0] dx_err_r;
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 || dma_start; // done on last transmit or error
reg [ 2:0] dx_err_r;
reg xmit_ok_r;
wire any_cmd_start = fetch_cmd || cfis_xmit || dx_xmit || atapi_xmit;
// wire done_w = dx_dma_last_w || ((|dx_err_r) && dx_busy_r) || chead_done_w || acfis_xmit_end || dma_start; // done on last transmit or error
// dma_start ends 'fetch_cmd'
wire done_w = xmit_ok_r || ((|dx_err_r) && dx_busy_r) || dma_start; // done on last transmit or error
reg fetch_cmd_busy_r;
assign todev_valid = todev_full_r;
assign dma_re = dma_re_w;
assign reg_re = reg_re_r[1:0];
......@@ -283,15 +290,15 @@ module ahci_fis_transmit #(
//TODO: update xfer length, prdtl (only after R_OK) - yes, do it outside
if (dx_transmit) dx_dwords_left[11:2] <= (|xfer_cntr[31:11])?10'h200:{1'b0,xfer_cntr[10:2]};
if (dx_xmit) 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;
if (dx_transmit) dwords_sent <= 0;
if (dx_xmit) dwords_sent <= 0;
else if (dma_re_w) dwords_sent <= dwords_sent + 1;
// send FIS header
if (hba_rst || write_or_w) dx_fis_pend_r <= 0;
else if (dx_transmit) dx_fis_pend_r <= 1;
else if (dx_xmit) dx_fis_pend_r <= 1;
if (hba_rst || dx_dma_last_w || (|dx_err_r)) dma_en_r <= 0;
else if (dx_fis_pend_r && write_or_w) dma_en_r <= 1;
......@@ -303,9 +310,14 @@ module ahci_fis_transmit #(
if (hba_rst || any_cmd_start) dx_err_r[1] <= 0;
else if (xmit_err) dx_err_r[1] <= 1;
if (hba_rst) dx_busy_r <= 0;
else if (dx_transmit) dx_busy_r <= 1;
else if (dx_dma_last_w || (|dx_err_r)) dx_busy_r <= 0;
if (hba_rst || any_cmd_start) dx_err_r[2] <= 0;
else if (xrdy_collision) dx_err_r[2] <= 1;
if (hba_rst) dx_busy_r <= 0; // sending CFIS, AFIS or data FIS (until error or R_OK)
// else if (dx_xmit) dx_busy_r <= 1;
// else if (dx_dma_last_w || (|dx_err_r)) dx_busy_r <= 0;
else if (dx_xmit || acfis_xmit_start_r) dx_busy_r <= 1;
else if (xmit_ok || (|dx_err_r)) dx_busy_r <= 0;
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)
......@@ -317,6 +329,11 @@ module ahci_fis_transmit #(
else if (any_cmd_start) busy <= 1;
else if (done_w) busy <= 0;
if (hba_rst) xmit_ok_r <= 0;
else xmit_ok_r <= dx_busy_r && !(|dx_err_r) && xmit_ok;
dma_cmd_abort <= done_w && (|dx_err_r);
......
......@@ -48,7 +48,7 @@ module ahci_fsm
output comreset_send, // Not possible yet?
input cominit_got, // asynchronously jumps to P:Cominit state
output set_offline, // electrically idle
input x_rdy_collision, // X_RDY/X_RDY collision on interface
// input x_rdy_collision, // X_RDY/X_RDY collision on interface
output send_R_OK, // Should it be originated in this layer SM?
output send_R_ERR,
......@@ -213,7 +213,7 @@ module ahci_fsm
output 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
output cfis_xmit, // transmit command (wait for dma_ct_busy == 0)
output dx_transmit, // send FIS header DWORD, (just 0x46), then forward DMA data
output dx_xmit, // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
output atapi_xmit, // tarsmit ATAPI command FIS
input xmit_done,
......@@ -224,7 +224,7 @@ module ahci_fsm
// output dmaCntrZero, // DMA counter is zero - would be a duplicate to the one in receive module and dwords_sent output
// input syncesc_recv, // These two inputs interrupt transmit
// input xmit_err, //
input [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command)
input [ 2:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err, 2 - X_RDY/X_RDY collision (valid @ xmit_err and later, reset by new command)
/// input [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0)
input ch_c, // Clear busy upon R_OK for this FIS
......@@ -272,7 +272,7 @@ module ahci_fsm
reg async_from_st; // chnge to multi-bit if there will be more sources for async transitions
wire asynq_rq = cominit_got || pcmd_st_cleared;
wire async_ackn = !fsm_preload && async_pend_r[0] && ((fsm_actions && !update_busy && !fsm_act_busy) || fsm_transitions[0]); // OK to process async jump
reg x_rdy_collision_pend;
// reg x_rdy_collision_pend;
reg syncesc_send_pend; // waiting for 'syncesc_send' confiramtion 'syncesc_send_done'
reg [1:0] phy_ready_prev; // previous state of phy_ready / speed
reg phy_ready_chng_r; // pulse when phy_ready changes
......@@ -353,8 +353,8 @@ module ahci_fsm
else async_pend_r <= {async_pend_r[0], asynq_rq | (async_pend_r[0] & ~async_ackn)};
if (hba_rst || pcmd_cr_set) x_rdy_collision_pend <= 0;
else if (x_rdy_collision) x_rdy_collision_pend <= 1;
// if (hba_rst || pcmd_cr_set) x_rdy_collision_pend <= 0;
// else if (x_rdy_collision) x_rdy_collision_pend <= 1;
if (hba_rst || syncesc_send_done) syncesc_send_pend <= 0;
else if (syncesc_send) syncesc_send_pend <= 1;
......@@ -435,7 +435,7 @@ module ahci_fsm
.FETCH_CMD (fetch_cmd), // output reg
.ATAPI_XMIT (atapi_xmit), // output reg
.CFIS_XMIT (cfis_xmit), // output reg
.DX_XMIT (dx_transmit), // output reg
.DX_XMIT (dx_xmit), // output reg
//FIS RECEIVE/WAIT DONE
.GET_DATA_FIS (get_data_fis), // output reg
.GET_DSFIS (get_dsfis), // output reg
......@@ -500,7 +500,7 @@ module ahci_fsm
// DMA
.DMA_PRD_IRQ_PEND (dma_prd_irq_pend), // input
// SATA TRANSPORT/LINK/PHY
.X_RDY_COLLISION (x_rdy_collision_pend) // input
.X_RDY_COLLISION (dx_err[2]) //x_rdy_collision_pend) // input
);
......
......@@ -20,19 +20,24 @@
*******************************************************************************/
`timescale 1ns/1ps
module ahci_sata_layers(
module ahci_sata_layers #(
parameter BITS_TO_START_XMIT = 6, // wait H2D FIFO to have 1 << BITS_TO_START_XMIT to start FIS transmission (or all FIS fits)
parameter DATA_BYTE_WIDTH = 4
)(
input exrst, // master reset that resets PLL and GTX
output rst, // PHY-generated reset after PLL lock
output clk, // PHY-generated clock, 75MHz for SATA2
// Data/type FIFO, host -> device
// Data System memory or FIS -> device
input [31:0] h2d_data, // 32-bit data from the system memory to HBA (dma data)
input [ 1:0] h2d_mask, // set to 2'b11
input [ 1:0] h2d_type, // 0 - data, 1 - FIS head, 2 - FIS LAST
input h2d_valid, // input register full
output h2d_ready, // send FIFO has room for data (>= 8? dwords)
input h2d_valid, // output register full
output h2d_ready, // h2d FIFO has room for data (>= 8? dwords)
// Data/type FIFO, device -> host
output [31:0] d2h_data, // FIFO input data
output [ 1:0] d2h_mask, // set to 2'b11
output [ 1:0] d2h_type, // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR (last two - after data, so ignore data with R_OK/R_ERR)
output d2h_valid, // Data available from the transport layer in FIFO
output d2h_many, // Multiple DWORDs available from the transport layer in FIFO
......@@ -40,14 +45,16 @@ module ahci_sata_layers(
// communication with link/phys layers
output [ 1:0] phy_ready, // 0 - not ready, 1..3 - negotiated speed
output syncesc_recv, // These two **puts interrupt transmit
output xmit_err, // Error during sending of a FIS
output xmit_ok, // received R_OK after transmission
output xmit_err, // Error during/after sending of a FIS (got R_ERR)
output x_rdy_collision, // X_RDY/X_RDY collision on interface
output syncesc_recv, // Where to get it?
input syncesc_send, // Send sync escape
output syncesc_send_done, // "SYNC escape until the interface is quiescent..."
input comreset_send, // Not possible yet?
output cominit_got,
input set_offline, // electrically idle
output x_rdy_collision, // X_RDY/X_RDY collision on interface
input send_R_OK, // Should it be originated in this layer SM?
input send_R_ERR,
......@@ -69,80 +76,208 @@ module ahci_sata_layers(
output serr_EI, // RWC: Recovered Data integrity Error
// additional control signals for SATA layers
input [3:0] sctl_ipm, // Interface power management transitions allowed
input [3:0] sctl_spd // Interface maximal speed
input [3:0] sctl_spd, // Interface maximal speed
// Device high speed pads and clock inputs
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in
);
localparam FIFO_ADDR_WIDTH = 9;
localparam D2H_TYPE_DMA = 0;
localparam D2H_TYPE_FIS_HEAD = 1;
localparam D2H_TYPE_OK = 2;
localparam D2H_TYPE_ERR = 3;
localparam H2D_TYPE_FIS_DATA = 0; // @SuppressThisWarning VEditor unused
localparam H2D_TYPE_FIS_HEAD = 1;
localparam H2D_TYPE_FIS_LAST = 2;
wire [31:0] ll_h2d_data_in;
wire [1:0] ll_h2d_mask_in;
wire ll_strobe_out;
wire ll_h2d_last;
wire [1:0] h2d_type_out;
wire [31:0] ll_d2h_data_out;
wire [ 1:0] ll_d2h_mask_out;
wire ll_d2h_valid;
wire ll_d2h_almost_full;
// wire ll_d2h_last; // may loose ll timing and send 'last' after data. Now assuming no data comes next xyxle after last
// wire [1:0] d2h_type_in;
reg [1:0] d2h_type_in;
reg fis_over_r; // push 1 more DWORD (ignore) + type (ERR/OK) when received FIS is done/error
wire ll_frame_req_w; // pre ll_frame_req
reg ll_frame_req; // -> link // request for a new frame transition
wire ll_frame_busy; // link -> // a little bit of overkill with the cound of response signals, think of throwing out 1 of them // LL tells back if it cant handle the request for now
// wire ll_frame_ack; // link -> // LL tells if the request is transmitting not used
// wire ll_frame_rej; // link -> // or if it was cancelled because of simultanious incoming transmission
// wire ll_frame_done_good; // link -> // TL tell if the outcoming transaction is done and how it was done
// wire ll_frame_done_bad; // link ->
wire ll_incom_start; // link -> // if started an incoming transaction assuming this and next 2 are single-cycle
wire ll_incom_done; // link -> // if incoming transition was completed
wire ll_incom_invalidate; // link -> // if incoming transition had errors
// wire incom_ack_good = send_R_OK; // -> link // transport layer responds on a completion of a FIS
// wire incom_ack_bad = send_R_ERR; // -> link // oob sequence is reinitiated and link now is not established or rxelecidle
wire ll_link_reset; // -> link // oob sequence is reinitiated and link now is not established or rxelecidle
wire ll_incom_stop_req; // -> link // TL demands to stop current recieving session (use !PxCMD.ST)?
wire [DATA_BYTE_WIDTH*8 - 1:0] ph2ll_data_out;
wire [DATA_BYTE_WIDTH - 1:0] ph2ll_charisk_out; // charisk
wire [DATA_BYTE_WIDTH - 1:0] ph2ll_err_out; // disperr | notintable
wire [DATA_BYTE_WIDTH*8 - 1:0] ll2ph_data_in;
wire [DATA_BYTE_WIDTH - 1:0] ll2ph_charisk_in; // charisk
wire [FIFO_ADDR_WIDTH-1:0] h2d_raddr;
wire [1:0] h2d_fifo_re_regen;
wire [FIFO_ADDR_WIDTH-1:0] h2d_waddr;
wire [FIFO_ADDR_WIDTH:0] h2d_fill;
wire h2d_nempty;
wire h2d_under;
wire [FIFO_ADDR_WIDTH-1:0] d2h_raddr;
wire [1:0] d2h_fifo_re_regen;
wire [FIFO_ADDR_WIDTH-1:0] d2h_waddr;
wire [FIFO_ADDR_WIDTH:0] d2h_fill;
wire d2h_nempty;
wire d2h_over;
wire h2d_fifo_rd = h2d_nempty && ll_strobe_out; // TODO: check latency in link.v
wire h2d_fifo_wr = h2d_valid;
wire d2h_fifo_rd = d2h_valid && d2h_ready;
wire d2h_fifo_wr = ll_d2h_valid || fis_over_r; // fis_over_r will push FIS end to FIFO
reg h2d_pending; // HBA started sending FIS to fifo
assign ll_h2d_last = (h2d_type_out == H2D_TYPE_FIS_LAST);
assign d2h_valid = d2h_nempty;
assign d2h_many = |d2h_fill[FIFO_ADDR_WIDTH:3]; //
assign h2d_ready = h2d_fill[FIFO_ADDR_WIDTH] && !(&h2d_fill[FIFO_ADDR_WIDTH:3]);
assign ll_d2h_almost_full = d2h_fill[FIFO_ADDR_WIDTH] || &d2h_fill[FIFO_ADDR_WIDTH-1:6]; // 63 dwords (maybe use :5?) - time to tell device to stop
assign ll_frame_req_w = !ll_frame_busy && h2d_pending && (((h2d_type == H2D_TYPE_FIS_LAST) && h2d_fifo_wr ) || (|h2d_fill[FIFO_ADDR_WIDTH : BITS_TO_START_XMIT]));
// Separating different types of errors, sync_escape from other problems. TODO: route individual errors to set SERR bits
//assign incom_invalidate = state_rcvr_eof & crc_bad & ~alignes_pair | state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP];
link #(
.DATA_BYTE_WIDTH(4)
) link_i (
.rst (), // input wire
.clk (), // input wire
.rst (rst), // input wire
.clk (clk), // input wire
// data inputs from transport layer
.data_in (), // input[31:0] wire // input data stream (if any data during OOB setting => ignored)
// in case of strange data aligments and size (1st mentioned @ doc, p.310, odd number of words case)
// Actually, only last data bundle shall be masked, others are always valid.
// Mask could be encoded into 3 bits instead of 4 for qword, but encoding+decoding aren't worth the bit
.data_in (ll_h2d_data_in), // input[31:0] wire // input data stream (if any data during OOB setting => ignored)
// TODO, for now not supported, all mask bits are assumed to be set
.data_mask_in (), // input[1:0] wire
.data_strobe_out (), // output wire // buffer read strobe
.data_last_in (), // input wire // transaction's last data budle pulse
.data_val_in (), // input wire // read data is valid (if 0 while last pulse wasn't received => need to hold the line)
.data_out (), // output[31:0] wire // read data, same as related inputs
.data_mask_out (), // output[1:0] wire // same thing - all 1s for now. TODO
.data_val_out (), // output wire // count every data bundle read by transport layer, even if busy flag is set // let the transport layer handle oveflows by himself
.data_busy_in (), // input wire // transport layer tells if its inner buffer is almost full
.data_last_out (), // output wire
.frame_req (), // input wire // request for a new frame transition
.frame_busy (), // output wire // a little bit of overkill with the cound of response signals, think of throwing out 1 of them // LL tells back if it cant handle the request for now
.frame_ack (), // output wire // LL tells if the request is transmitting
.frame_rej (), // output wire // or if it was cancelled because of simultanious incoming transmission
.frame_done_good (), // output wire // TL tell if the outcoming transaction is done and how it was done
.frame_done_bad (), // output wire
.incom_start (), // output wire // if started an incoming transaction
.incom_done (), // output wire // if incoming transition was completed
.incom_invalidate (), // output wire // if incoming transition had errors
.incom_ack_good (), // input wire // transport layer responds on a completion of a FIS
.incom_ack_bad (), // input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.link_reset (), // input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.sync_escape_req (), // input wire // TL demands to brutally cancel current transaction
.sync_escape_ack (), // output wire // acknowlegement of a successful reception?
.incom_stop_req (), // input wire // TL demands to stop current recieving session
.data_mask_in (ll_h2d_mask_in), // input[1:0] wire
.data_strobe_out (ll_strobe_out), // output wire // buffer read strobe
.data_last_in (ll_h2d_last), // input wire // transaction's last data budle pulse
.data_val_in (h2d_nempty), // input wire // read data is valid (if 0 while last pulse wasn't received => need to hold the line)
.data_out (ll_d2h_data_out), // output[31:0] wire // read data, same as related inputs
.data_mask_out (ll_d2h_mask_out), // output[1:0] wire // same thing - all 1s for now. TODO
.data_val_out (ll_d2h_valid), // output wire // count every data bundle read by transport layer, even if busy flag is set // let the transport layer handle oveflows by himself
.data_busy_in (ll_d2h_almost_full), // input wire // transport layer tells if its inner buffer is almost full
.data_last_out (), // ll_d2h_last), // output wire not used
.frame_req (ll_frame_req), // input wire // request for a new frame transmission
.frame_busy (ll_frame_busy), // output wire // a little bit of overkill with the cound of response signals, think of throwing out 1 of them // LL tells back if it cant handle the request for now
.frame_ack (), // ll_frame_ack), // output wire // LL tells if the request is transmitting
.frame_rej (x_rdy_collision), // output wire // or if it was cancelled because of simultanious incoming transmission
.frame_done_good (xmit_ok), // output wire // TL tell if the outcoming transaction is done and how it was done
.frame_done_bad (xmit_err), // output wire
.incom_start (ll_incom_start), // output wire // if started an incoming transaction
.incom_done (ll_incom_done), // output wire // if incoming transition was completed
.incom_invalidate (ll_incom_invalidate), // output wire // if incoming transition had errors
.incom_sync_escape(syncesc_recv), // output wire - received sync escape
.incom_ack_good (send_R_OK), // input wire // transport layer responds on a completion of a FIS
.incom_ack_bad (send_R_ERR), // input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.link_reset (ll_link_reset), // input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.sync_escape_req (syncesc_send), // input wire // TL demands to brutally cancel current transaction
.sync_escape_ack (syncesc_send_done), // output wire // acknowlegement of a successful reception?
.incom_stop_req (ll_incom_stop_req), // input wire // TL demands to stop current recieving session
// inputs from phy
.phy_ready (), // input wire // phy is ready - link is established
// data-primitives stream from phy
.phy_data_in (), // input[31:0] wire // phy_data_in
.phy_isk_in (), // input[3:0] wire // charisk
.phy_err_in (), // input[3:0] wire // disperr | notintable
.phy_data_in (ph2ll_data_out), // input[31:0] wire // phy_data_in
.phy_isk_in (ph2ll_charisk_out), // input[3:0] wire // charisk
.phy_err_in (ph2ll_err_out), // input[3:0] wire // disperr | notintable
// to phy
.phy_data_out (), // output[31:0] wire
.phy_isk_out () // output[3:0] wire // charisk
.phy_data_out (ll2ph_data_in), // output[31:0] wire
.phy_isk_out (ll2ph_charisk_in) // output[3:0] wire // charisk
);
reg [8:0] h2d_raddr;
reg [8:0] h2d_waddr;
reg [8:0] d2h_raddr;
reg [8:0] d2h_waddr;
wire [1:0] dummy1;
always @ (posedge clk) begin
// FIS receive D2H
// add head if ll_d2h_valid and (d2h_type_in == D2H_TYPE_OK) || (d2h_type_in == D2H_TYPE_ERR)? Or signal some internal error
if (rst || ll_incom_start) d2h_type_in <= D2H_TYPE_FIS_HEAD; // FIS head
else if (ll_d2h_valid) d2h_type_in <= D2H_TYPE_DMA; // FIS BODY
else if (ll_incom_done || ll_incom_invalidate) d2h_type_in <= ll_incom_invalidate ? D2H_TYPE_ERR: D2H_TYPE_OK;
if (rst) fis_over_r <= 0;
else fis_over_r <= (ll_incom_done || ll_incom_invalidate) && (d2h_type_in == D2H_TYPE_DMA); // make sure it is only once
// Second - generate internal error?
// FIS transmit H2D
// Start if all FIS is in FIFO (last word received) or at least that many is in FIFO
if (rst || ll_frame_req) h2d_pending <= 0;
else if ((h2d_type == H2D_TYPE_FIS_HEAD) && h2d_fifo_wr) h2d_pending <= 1;
if (rst) ll_frame_req <= 0;
else ll_frame_req <= ll_frame_req_w;
end
sata_phy #(
.DATA_BYTE_WIDTH(4)
) sata_phy_i (
.extrst (), // input wire
.clk (), // output wire
.rst (), // output wire
.extrst (exrst), // input wire
.clk (clk), // output wire
.rst (rst), // output wire
.reliable_clk (), // input wire
.phy_ready (), // output wire
.gtx_ready (), // output wire
.debug_cnt (), // output[11:0] wire
.extclk_p (), // input wire
.extclk_n (), // input wire
.txp_out (), // output wire
.txn_out (), // output wire
.rxp_in (), // input wire
.rxn_in (), // input wire
.ll_data_out (), // output[31:0] wire
.ll_charisk_out (), // output[3:0] wire
.ll_err_out (), // output[3:0] wire
.ll_data_in (), // input[31:0] wire
.ll_charisk_in () // input[3:0] wire
.extclk_p (extclk_p), // input wire
.extclk_n (extclk_n), // input wire
.txp_out (txp_out), // output wire
.txn_out (txn_out), // output wire
.rxp_in (rxp_in), // input wire
.rxn_in (rxn_in), // input wire
.ll_data_out (ph2ll_data_out), // output[31:0] wire
.ll_charisk_out (ph2ll_charisk_out), // output[3:0] wire
.ll_err_out (ph2ll_err_out), // output[3:0] wire
.ll_data_in (ll2ph_data_in), // input[31:0] wire
.ll_charisk_in (ll2ph_charisk_in) // input[3:0] wire
);
fifo_sameclock_control #(
.WIDTH(9)
) fifo_h2d_control_i (
.clk (clk), // input
.rst (rst), // input
.wr (h2d_fifo_wr), // input
.rd (h2d_fifo_rd), // input
.nempty (h2d_nempty), // output
.fill_in (h2d_fill), // output[9:0]
.mem_wa (h2d_waddr), // output[8:0] reg
.mem_ra (h2d_raddr), // output[8:0] reg
.mem_re (h2d_fifo_re_regen[0]), // output
.mem_regen(h2d_fifo_re_regen[1]), // output
.over (), // output reg
.under (h2d_under) // output reg
);
ram18p_var_w_var_r #(
......@@ -152,14 +287,31 @@ module ahci_sata_layers(
) fifo_h2d_i (
.rclk (clk), // input
.raddr (h2d_raddr), // input[8:0]
.ren (), // input
.regen (), // input
.data_out (), // output[35:0]
.ren (h2d_fifo_re_regen[0]), // input
.regen (h2d_fifo_re_regen[1]), // input
.data_out ({h2d_type_out, ll_h2d_mask_in, ll_h2d_data_in}), // output[35:0]
.wclk (clk), // input
.waddr (h2d_waddr), // input[8:0]
.we (), // input
.we (h2d_fifo_wr), // input
.web (4'hf), // input[3:0]
.data_in ({2'b0,h2d_type,h2d_data}) // input[35:0]
.data_in ({h2d_type,h2d_mask,h2d_data}) // input[35:0]
);
fifo_sameclock_control #(
.WIDTH(9)
) fifo_d2h_control_i (
.clk (clk), // input
.rst (rst), // input
.wr (d2h_fifo_wr), // input
.rd (d2h_fifo_rd), // input
.nempty (d2h_nempty), // output
.fill_in (d2h_fill), // output[9:0]
.mem_wa (d2h_waddr), // output[8:0] reg
.mem_ra (d2h_raddr), // output[8:0] reg
.mem_re (d2h_fifo_re_regen[0]), // output
.mem_regen(d2h_fifo_re_regen[1]), // output
.over (d2h_over), // output reg
.under () // output reg
);
ram18p_var_w_var_r #(
......@@ -169,14 +321,14 @@ module ahci_sata_layers(
) fifo_d2h_i (
.rclk (clk), // input
.raddr (d2h_raddr), // input[8:0]
.ren (), // input
.regen (), // input
.data_out ({dummy1,d2h_type,d2h_data}), // output[35:0]
.ren (d2h_fifo_re_regen[0]), // input
.regen (d2h_fifo_re_regen[1]), // input
.data_out ({d2h_type, d2h_mask, d2h_data}), // output[35:0]
.wclk (clk), // input
.waddr (d2h_waddr), // input[8:0]
.we (), // input
.we (d2h_fifo_wr), // input
.web (4'hf), // input[3:0]
.data_in () // input[35:0]
.data_in ({d2h_type_in, ll_d2h_mask_out, ll_d2h_data_out}) // input[35:0]
);
endmodule
......
......@@ -143,8 +143,9 @@ module ahci_top#(
// communication with transport/link/phys layers
// input phy_rst, // frome phy, as a response to hba_arst || port_arst. It is deasserted when clock is stable
input [ 1:0] phy_ready, // 0 - not ready, 1..3 - negotiated speed
input syncesc_recv, // These two inputs interrupt transmit
input xmit_ok, // FIS transmission acknowledged OK
input xmit_err, // Error during sending of a FIS
input syncesc_recv, // These two inputs interrupt transmit
output syncesc_send, // Send sync escape
input syncesc_send_done, // "SYNC escape until the interface is quiescent..."
output comreset_send, // Not possible yet?
......@@ -317,7 +318,7 @@ module ahci_top#(
wire fsnd_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
wire fsnd_cfis_xmit; // transmit command (wait for dma_ct_busy == 0)
wire fsnd_dx_transmit; // send FIS header DWORD, (just 0x46), then forward DMA data
wire fsnd_dx_xmit; // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
wire fsnd_atapi_xmit; // tarsmit ATAPI command FIS
// responses fsm <- ahc_fis_transmit
......@@ -327,7 +328,7 @@ module ahci_top#(
wire fsnd_clearCmdToIssue; // From CFIS:SUCCESS
// State variables fsm <- ahc_fis_transmit
wire fsnd_pCmdToIssue; // AHCI port variable
wire [ 1:0] fsnd_dx_err; // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command)
wire [ 2:0] fsnd_dx_err; // bit 0 - syncesc_recv, 1 - xmit_err 2 - X-RDY/X_RDY collision (valid @ xmit_err and later, reset by new command)
wire fsnd_ch_c; // Clear busy upon R_OK for this FIS
wire fsnd_ch_b; // Built-in self test command
wire fsnd_ch_r; // reset - may need to send SYNC escape before this command
......@@ -444,7 +445,7 @@ module ahci_top#(
.syncesc_send_done (syncesc_send_done), // input
.cominit_got (cominit_got), // input
.set_offline (set_offline), // output
.x_rdy_collision (x_rdy_collision), // input
// .x_rdy_collision (x_rdy_collision), // input
.send_R_OK (send_R_OK), // output
.send_R_ERR (send_R_ERR), // output
......@@ -572,7 +573,7 @@ module ahci_top#(
.fetch_cmd (fsnd_fetch_cmd), // output
.cfis_xmit (fsnd_cfis_xmit), // output
.dx_transmit (fsnd_dx_transmit), // output
.dx_xmit (fsnd_dx_xmit), // output
.atapi_xmit (fsnd_atapi_xmit), // output
.xmit_done (fsnd_done), // input
/// .xmit_busy (fsnd_busy), // input
......@@ -901,20 +902,23 @@ module ahci_top#(
.READ_CT_LATENCY (READ_CT_LATENCY),
.ADDRESS_BITS (ADDRESS_BITS)
) ahci_fis_transmit_i (
.hba_rst (mrst), // input
// .hba_rst (mrst), // input TODO: Reset when !PxCMD.ST? pcmd_st
.hba_rst (mrst || !pcmd_st), // input TODO: Reset when !PxCMD.ST? pcmd_st
.mclk (mclk), // input
.fetch_cmd (fsnd_fetch_cmd), // input
.cfis_xmit (fsnd_cfis_xmit), // input
.dx_transmit (fsnd_dx_transmit), // input
.dx_xmit (fsnd_dx_xmit), // input
.atapi_xmit (fsnd_atapi_xmit), // input
.done (fsnd_done), // output reg
.busy (), /// fsnd_busy), // output reg
.clearCmdToIssue (fsnd_clearCmdToIssue), // input
.pCmdToIssue (fsnd_pCmdToIssue), // output
.syncesc_recv (syncesc_recv), // input
.xmit_ok (xmit_ok), // input
.xmit_err (xmit_err), // input
.syncesc_recv (syncesc_recv), // input
.xrdy_collision (x_rdy_collision), // input
.dx_err (fsnd_dx_err), // output[1:0]
.ch_prdtl (prdtl), // output[15:0]
.ch_c (fsnd_ch_c), // output
......
......@@ -88,6 +88,8 @@ module link #(
output wire incom_done,
// if incoming transition had errors
output wire incom_invalidate,
// particular type - got sync escape
output wire incom_sync_escape,
// transport layer responds on a completion of a FIS
input wire incom_ack_good,
input wire incom_ack_bad,
......@@ -611,8 +613,11 @@ assign incom_start = set_rcvr_wait & ~alignes_pair;
// ... and processed
assign incom_done = set_rcvr_goodcrc & ~alignes_pair;
// or the FIS had errors
assign incom_invalidate = state_rcvr_eof & crc_bad & ~alignes_pair | state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP]
| (state_rcvr_wait | state_rcvr_rdy | state_rcvr_data | state_rcvr_rhold | state_rcvr_shold | state_rcvr_eof | state_rcvr_goodcrc) & got_escape;
//assign incom_invalidate = state_rcvr_eof & crc_bad & ~alignes_pair | state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP]
// | (state_rcvr_wait | state_rcvr_rdy | state_rcvr_data | state_rcvr_rhold | state_rcvr_shold | state_rcvr_eof | state_rcvr_goodcrc) & got_escape;
// Separating different types of errors, sync_escape from other problems. TODO: route individual errors to set SERR bits
assign incom_invalidate = state_rcvr_eof & crc_bad & ~alignes_pair | state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP];
assign incom_sync_escape = (state_rcvr_wait | state_rcvr_rdy | state_rcvr_data | state_rcvr_rhold | state_rcvr_shold | state_rcvr_eof | state_rcvr_goodcrc) & got_escape;
// shows that incoming primitive or data is ready to be processed // TODO somehow move alignes_pair into dword_val
assign dword_val = |rcvd_dword & phy_ready & ~rcvd_dword[CODE_ALIGNP];
......
......@@ -386,6 +386,7 @@ wire ll2tl_incom_start;
wire ll2tl_incom_done;
// LL reports of errors in current FIS
wire ll2tl_incom_invalidate; // TODO
wire ll2tl_incom_sync_escape;
// TL analyzes FIS and returnes if FIS makes sense.
wire ll2tl_incom_ack_good;
// ... and if it doesn't
......@@ -452,7 +453,7 @@ transport transport(
// LL reports of a completion of an incoming frame transmission.
.incom_done (ll2tl_incom_done),
// LL reports of errors in current FIS
.incom_invalidate (ll2tl_incom_invalidate), // TODO
.incom_invalidate (ll2tl_incom_invalidate || ll2tl_incom_sync_escape), // TODO
// TL analyzes FIS and returnes if FIS makes sense.
.incom_ack_good (ll2tl_incom_ack_good),
// ... and if it doesn't
......@@ -648,6 +649,8 @@ link link(
.incom_done (ll2tl_incom_done),
// if incoming transition had errors
.incom_invalidate (ll2tl_incom_invalidate),
// if incoming got sync escape
.incom_sync_escape (ll2tl_incom_sync_escape), // output wire
// transport layer responds on a completion of a FIS
.incom_ack_good (ll2tl_incom_ack_good),
.incom_ack_bad (ll2tl_incom_ack_bad),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment