Commit 17e832f8 authored by Andrey Filippov's avatar Andrey Filippov

Working on AHCI FSM code generator

parent 4bf4f348
......@@ -124,7 +124,7 @@ module ahci_ctrl_stat #(
input ssts_det_ndnp, // no device detected, phy communication not established
input ssts_det_dnp, // device detected, but phy communication not established
input ssts_det_dp, // device detected, phy communication established
input ssts_det_offline, // device offline
input ssts_det_offline, // device offline or BIST
output [3:0] ssts_det, // current value of PxSSTS.DET
// SCR2:SControl (written by software only)
......
......@@ -65,11 +65,11 @@ module ahci_dma (
// After the first 0x80 bytes of the Command Table are read out, this module will read/process PRDs,
// not forwarding them to the output
output prd_done, // prd done (regardless of the interrupt) - data transfer of one PRD is finished (any direction)
output prd_irq, // prd interrupt, if enabled
output prd_done, // @mclk prd done (regardless of the interrupt) - data transfer of one PRD is finished (any direction)
input prd_irq_clear, // reset pending prd_irq
output reg prd_irq_pend, // prd interrupt pending. This is just a condition for irq - actual will be generated after FIS OK
output reg cmd_busy, // all commands
output cmd_done,
output cmd_done, // @ mclk
// Data System memory -> HBA interface @ mclk
output [31:0] sys_out, // 32-bit data from the system memory to HBA (dma data)
......@@ -81,6 +81,8 @@ module ahci_dma (
output sys_nfull, // internal FIFO has room for more data (will decide - how big reserved space to keep)
input sys_we,
output extra_din, // all DRDs are transferred to memory, but FIFO has some data. Valid when transfer is stopped
// axi_hp signals write channel
// write address
output [31:0] afi_awaddr,
......@@ -228,8 +230,10 @@ module ahci_dma (
reg [3:0] dev_rd_id;
reg [5:0] afi_id; // common for 3 channels
assign prd_done = done_dev_wr || done_dev_rd;
assign prd_irq = data_irq && prd_done;
wire fifo_nempty_mclk;
reg en_extra_din_r;
// assign prd_done = done_dev_wr || done_dev_rd;
assign cmd_done_hclk = ((ct_busy_r==2'b10) && (prdtl_mclk == 0)) || done_flush || done_dev_rd;
assign ct_done = (ct_busy_r == 2'b10);
assign first_prd_fetch = ct_over_prd_enabled == 2'b01;
......@@ -269,7 +273,7 @@ module ahci_dma (
assign afi_arburst = 2'h1;
assign afi_arqos = 4'h0;
assign afi_rdissuecap1en = 1'b0;
assign extra_din = en_extra_din_r && fifo_nempty_mclk;
always @ (posedge mclk) begin
if (ct_re) ct_data <= ct_data_ram[ct_addr];
if (ctba_ld) ctba_r <= ctba[31:7];
......@@ -291,6 +295,13 @@ module ahci_dma (
else if (set_axi_wr_cache_mode) afi_awcache <= axi_wr_cache_mode;
prd_start_r <= prd_start;
if (mrst || prd_irq_clear ||cmd_start || cmd_abort) prd_irq_pend <= 0;
else if (data_irq && prd_done) prd_irq_pend <= 1;
if (mrst || cmd_start || cmd_abort) en_extra_din_r <= 0;
else if (cmd_done) en_extra_din_r <= 1;
end
......@@ -472,6 +483,7 @@ module ahci_dma (
.dout_wstb (afi_wstb4), // output[3:0] reg
.done (done_dev_rd), // output reg
.busy (), // output
.fifo_nempty_mclk (fifo_nempty_mclk), // output reg
.din (sys_in), // input[31:0]
.din_rdy (sys_nfull), // output
.din_avail (sys_we) // input
......@@ -535,5 +547,19 @@ module ahci_dma (
.busy() // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) prd_done_mclk_i (
.rst (hrst), // input
.src_clk (hclk), // input
.dst_clk (mclk), // input
.in_pulse (done_dev_wr || done_dev_rd), // input
.out_pulse (prd_done), // output
.busy() // output
);
endmodule
......@@ -59,7 +59,7 @@ module ahci_dma_wr_fifo#(
// last_prd was not set
output busy,
// output done_flush, // finished last PRD (indicated by last_prd @ start), data left module
output reg fifo_nempty_mclk, // to detect extra data from FIS, has some latency - only valid after read is stopped
// mclk domain
input [31:0] din,
output din_rdy, // can accept data from HBA (multiple dwords, so reasonable latency is OK)
......@@ -268,6 +268,8 @@ module ahci_dma_wr_fifo#(
if (fifo_wr && !waddr[0]) fifo0_ram[waddr[ADDRESS_BITS:1]] <= din;
if (fifo_wr && waddr[0]) fifo1_ram[waddr[ADDRESS_BITS:1]] <= din;
fifo_nempty_mclk <= (fifo_full [raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS]); // only valid after read is stopped
end
......
......@@ -35,7 +35,10 @@ module ahci_fis_receive#(
input hba_rst, // @posedge mclk - sync reset
input mclk, // for command/status
// Control Interface
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_*
// Debug features
output fis_first_invalid, // Some data available from FIFO, but not FIS head
input fis_first_flush, // Skip FIFO data until empty or FIS head
// Receiving FIS
input get_dsfis,
input get_psfis,
......@@ -49,6 +52,8 @@ module ahci_fis_receive#(
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 fis_ferr, // FIS done, fatal error - FIS too long
input dma_prds_done, // dma is done - check if FIS is done (some data may get stuck in dma FIFO - reported separately)
output fis_extra, // all wanted data got, FIS may have extra data (non-fatal). Does not deny fis_ok
input set_update_sig,// when set, enables update_sig (and resets itself)
output pUpdateSig, // state variable
output reg sig_available, // device signature a ailable
......@@ -74,13 +79,14 @@ module ahci_fis_receive#(
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 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 or DMA Setup FIS
output reg sdb_n, // value of "N" field in received SDB FIS
output reg dma_a, // value of "A" field in received DMA Setup FIS
output reg dma_d, // value of "D" field in received DMA Setup FIS
output reg pio_i, // value of "I" field in received PIO Setup FIS
output reg pio_d, // value of "D" field in received PIO Setup FIS
output [7:0] pio_es, // value of PIO E_Status
output reg sactive0, // bit 0 of sActive DWORD received in SDB FIS
// Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed
output [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc
output reg xfer_cntr_zero,// valid next cycle
......@@ -144,6 +150,7 @@ localparam DATA_TYPE_ERR = 3;
wire dma_in_start;
wire dma_in_stop;
wire dma_skipping_extra; // skipping extra FIS data not needed for DMA
reg dma_in;
reg [1:0] was_data_in;
reg [11:0] data_in_dwords_r;
......@@ -160,7 +167,8 @@ localparam DATA_TYPE_ERR = 3;
reg fis_rec_run; // running received FIS
reg is_data_fis;
wire is_FIS_HEAD = data_in_ready && (hba_data_in_type == DATA_TYPE_FIS_HEAD);
wire is_FIS_HEAD = data_in_ready && (hba_data_in_type == DATA_TYPE_FIS_HEAD);
wire is_FIS_NOT_HEAD = data_in_ready && (hba_data_in_type != DATA_TYPE_FIS_HEAD);
wire data_in_ready = hba_data_in_valid && (hba_data_in_many || !(|was_data_in || hba_data_in_ready) );
......@@ -173,7 +181,7 @@ localparam DATA_TYPE_ERR = 3;
reg [5:0] reg_ds;
reg [4:0] reg_ps;
reg reg_d2h;
reg reg_sdb;
reg [1:0] reg_sdb;
reg [31:2] xfer_cntr_r;
reg [31:2] prdbc_r;
......@@ -192,15 +200,23 @@ localparam DATA_TYPE_ERR = 3;
reg pUpdateSig_r = 1; // state variable
reg [31:0] sig_r; // signature register, save at
reg fis_extra_r;
reg fis_first_invalid_r;
reg fis_first_flushing_r;
// Forward data to DMA (dev->mem) engine
assign dma_in_valid = dma_in_ready && (hba_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err;
assign dma_in_stop = dma_in && data_in_ready && (hba_data_in_type != DATA_TYPE_DMA); // ||
assign dma_in_valid = dma_in_ready && (hba_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err;
// Will also try to skip to the end of too long FIS
assign dma_skipping_extra = (fis_extra_r || too_long_err) && (hba_data_in_type == DATA_TYPE_DMA) && data_in_ready ;
assign dma_in_stop = dma_in && data_in_ready && (hba_data_in_type != DATA_TYPE_DMA); // ||
assign reg_we_w = wreg_we_r && !dwords_over && fis_save;
assign dma_in_start = is_data_fis && wreg_we_r;
assign hba_data_in_ready = dma_in_valid || wreg_we_r || fis_end_r[0];
assign hba_data_in_ready = dma_in_valid || dma_skipping_extra || wreg_we_r || fis_end_r[0] || (is_FIS_NOT_HEAD && fis_first_flushing_r);
assign fis_ferr = too_long_err;
......@@ -214,6 +230,11 @@ localparam DATA_TYPE_ERR = 3;
assign pio_es = pio_es_r;
assign pUpdateSig = pUpdateSig_r;
assign fis_extra = fis_extra_r;
assign fis_first_invalid = fis_first_invalid_r;
always @ (posedge mclk) begin
if (hba_rst || dma_in_stop) dma_in <= 0;
else if (dma_in_start) dma_in <= 1;
......@@ -227,6 +248,11 @@ localparam DATA_TYPE_ERR = 3;
if (hba_rst) too_long_err <= 0; // it is a fatal error, only reset
else if ((dma_in_valid && data_in_dwords_r[11]) ||
(wreg_we_r && dwords_over)) too_long_err <= 1;
if (hba_rst || dma_in_start) fis_extra_r <= 0;
else if (data_in_ready && (hba_data_in_type == DATA_TYPE_DMA) && dma_prds_done) fis_extra_r <= 1;
if (get_fis) begin
reg_addr_r <= ({ADDRESS_BITS{get_dsfis}} & (FB_OFFS32 + DSFIS32)) |
......@@ -243,7 +269,7 @@ localparam DATA_TYPE_ERR = 3;
({4{get_ignore}} & IGNORE_LENM1 );
// save signature FIS to memory if waiting (if not - ignore FIS)
// for non-signature /non-data - obey pcmd_fre
fis_save <= (pUpdateSig_r || get_rfis) || (pcmd_fre && !get_data_fis && !get_ignore);
fis_save <= (pUpdateSig_r && get_rfis) || (pcmd_fre && !get_data_fis && !get_ignore);
is_data_fis <= get_data_fis;
store_sig <= (get_rfis)? 1 : 0;
......@@ -258,7 +284,7 @@ localparam DATA_TYPE_ERR = 3;
reg_ds <= reg_ds << 1;
reg_ps <= reg_ps << 1;
reg_d2h <= 0;
reg_sdb <= 0;
reg_sdb <= reg_sdb << 1;
end
......@@ -303,7 +329,7 @@ localparam DATA_TYPE_ERR = 3;
// Updates PxTFD.STS.ERR with pPioErr[pPmpCur] ??
else if (reg_ps[0]) tf_err_sts <= {hba_data_in[31:24],hba_data_in[23:16]};
else if (update_pio) tf_err_sts <= {pio_err_r, pio_es_r};
else if (reg_sdb) tf_err_sts <= {hba_data_in[15:8], tf_err_sts[7], hba_data_in[6:4], tf_err_sts[3],hba_data_in[2:0]};
else if (reg_sdb[0]) tf_err_sts <= {hba_data_in[15:8], tf_err_sts[7], hba_data_in[6:4], tf_err_sts[3],hba_data_in[2:0]};
else if (clear_bsy_drq || set_bsy || clear_bsy_set_drq)
tf_err_sts <= tf_err_sts & {8'hff,clear_bsy_drq,3'h7,clear_bsy_drq,3'h7} | {8'h0,set_bsy,3'h0,clear_bsy_set_drq,3'h0};
else if (set_sts_7f || set_sts_80) tf_err_sts <= {tf_err_sts[15:8],set_sts_80,{7{set_sts_7f}}} ;
......@@ -315,24 +341,26 @@ localparam DATA_TYPE_ERR = 3;
else if (update_sig_r) reg_addr <= PXSIG_OFFS32;
else if (update_prdbc_r) reg_addr <= CLB_OFFS32 + 1; // location of PRDBC
if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hba_data_in[14];
if (reg_d2h || reg_sdb[0] || reg_ds[0]) fis_i <= hba_data_in[14];
if (reg_sdb) sdb_n <= hba_data_in[15];
if (reg_ds[0]) {dma_a,dma_d} <= {hba_data_in[15],hba_data_in[13]};
if (reg_ps[0]) {pio_i,pio_d} <= {hba_data_in[14],hba_data_in[13]};
if (hba_rst) pio_err_r <= 0;
else if (reg_ps[0]) pio_err_r <= hba_data_in[31:24];
if (hba_rst) pio_err_r <= 0;
else if (reg_ps[0]) pio_err_r <= hba_data_in[31:24];
if (hba_rst) pio_es_r <= 0;
else if (reg_ps[3]) pio_es_r <= hba_data_in[31:24];
if (hba_rst) pio_es_r <= 0;
else if (reg_ps[3]) pio_es_r <= hba_data_in[31:24];
if (reg_sdb[1]) sactive0 <= hba_data_in[0];
if (hba_rst || reg_sdb || clear_xfer_cntr) xfer_cntr_r[31:2] <= 0;
if (hba_rst || reg_sdb[0] || clear_xfer_cntr) xfer_cntr_r[31:2] <= 0;
else if (reg_ps[4] || reg_ds[5]) xfer_cntr_r[31:2] <= {reg_ds[5]?hba_data_in[31:16]:16'b0, hba_data_in[15:2]} + hba_data_in[1]; // round up
else if (decr_dwc) xfer_cntr_r[31:2] <= {xfer_cntr_r[31:2]} - {18'b0, decr_DXC_dw[11:0]};
if (hba_rst || reg_sdb || reg_ps[4] || reg_ds[5]) prdbc_r[31:2] <= 0;
else if (decr_dwc) prdbc_r[31:2] <= {prdbc_r[31:2]} + {18'b0, decr_DXC_dw[11:0]};
if (hba_rst || reg_sdb[0] || reg_ps[4] || reg_ds[5]) prdbc_r[31:2] <= 0;
else if (decr_dwc) prdbc_r[31:2] <= {prdbc_r[31:2]} + {18'b0, decr_DXC_dw[11:0]};
xfer_cntr_zero <= xfer_cntr_r[31:2] == 0;
......@@ -352,6 +380,12 @@ localparam DATA_TYPE_ERR = 3;
// Maybe it is not needed if the fsm will send this pulse?
// data_in_words_apply <= dma_in_stop && (hba_data_in_type == DATA_TYPE_OK);
if (hba_rst || get_fis_busy_r) fis_first_invalid_r <= 0;
else fis_first_invalid_r <= is_FIS_NOT_HEAD;
if (!fis_first_invalid_r) fis_first_flushing_r <= 0;
else if (fis_first_flush) fis_first_flushing_r <= 1;
end
endmodule
......@@ -75,7 +75,7 @@ module ahci_fis_transmit #(
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
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 dma_cmd_abort, // try to abort a command TODO: Implement
output reg dma_cmd_abort, // try to abort a command
// reading out command table data from DMA module
output reg [ 4:0] ct_addr, // DWORD address
......
......@@ -148,11 +148,16 @@ module ahci_fsm
// inputs from the DMA engine
input dma_prd_done, // output (finished next prd)
input dma_prd_irq, // output (finished next prd and prd irq is enabled)
output dma_prd_irq_clear, // reset pending prd_irq
input dma_prd_irq_pend, // prd interrupt pending. This is just a condition for irq - actual will be generated after FIS OK
input dma_cmd_busy, // output reg (DMA engine is processing PRDs)
input dma_cmd_done, // output (last PRD is over)
// Communication with ahci_fis_receive (some are unused
// Communication with ahci_fis_receive (some are unused)
// Debug features
input fis_first_invalid, // Some data available from FIFO, but not FIS head
output fis_first_flush, // Skip FIFO data until empty or FIS head
input fis_first_vld, // fis_first contains valid FIS header, reset by 'get_*'
input [7:0] fis_type, // FIS type (low byte in the first FIS DWORD), valid with 'fis_first_vld'
input [7:0] bist_bits, // bits that define built-in self test
......@@ -170,6 +175,7 @@ module ahci_fsm
input fis_ok, // FIS done, checksum OK reset by starting a new get FIS
input fis_err, // FIS done, checksum ERROR reset by starting a new get FIS
input fis_ferr, // FIS done, fatal error - FIS too long
input fis_extra, // more data got from FIS than DMA can accept. Does not deny fis_ok. May have latency
output set_update_sig, // when set, enables get_sig (and resets itself)
input pUpdateSig, // state variable
......@@ -204,6 +210,7 @@ module ahci_fsm
input pio_i, // value of "I" field in received PIO Setup FIS
input pio_d, // value of "D" field in received PIO Setup FIS
input [7:0] pio_es, // value of PIO E_Status
input sactive0, // bit 0 of sActive DWORD received in SDB FIS
// Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed
input [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc
input xfer_cntr_zero,// valid next cycle
......
......@@ -212,7 +212,8 @@ module ahci_top#(
wire [ 1:0] dma_ct_re; // input
wire [31:0] dma_ct_data; // output[31:0] reg
wire dma_prd_done; // output (finished next prd)
wire dma_prd_irq; // output (finished next prd and prd irq is enabled)
wire dma_prd_irq_clear; // reset pending prd_irq
wire dma_prd_irq_pend; // prd interrupt pending. This is just a condition for irq - actual will be generated after FIS OK
wire dma_cmd_busy; // output reg (DMA engine is processing PRDs)
wire dma_cmd_done; // output (last PRD is over)
wire [31:0] dma_dout; // output[31:0]
......@@ -220,10 +221,17 @@ module ahci_top#(
wire dma_re; // input
wire dma_in_ready; // output
wire dma_we; // input
wire dma_extra_din; // all DRDs are transferred to memory, but FIFO has some data. Valid when transfer is stopped
// ---------------------------------------
// fsm <-> ahc_fis_receive
// fsm ->
wire frcv_first_vld;
// To debug/recover -
wire frcv_first_invalid; // Some data available from FIFO, but not FIS head
wire frcv_first_flush; // Skip FIFO data until empty or FIS head
wire frcv_get_dsfis;
wire frcv_get_psfis;
wire frcv_get_rfis;
......@@ -252,7 +260,8 @@ module ahci_top#(
wire frcv_ok; // FIS done, checksum OK reset by starting a new get FIS
wire frcv_err; // FIS done, checksum ERROR reset by starting a new get FIS
wire frcv_ferr; // FIS done, fatal error - FIS too long
wire frcv_extra; // DMA all transferred, but some data is still in left. . Does not deny frcv_ok
wire frcv_set_update_sig; // when set, enables get_sig (and resets itself)
wire frcv_pUpdateSig; // state variable
wire frcv_sig_available; // signature data available
......@@ -270,8 +279,8 @@ module ahci_top#(
wire pio_i; // value of "I" field in received PIO Setup FIS
wire pio_d; // value of "D" field in received PIO Setup FIS
wire [7:0] pio_es; // value of PIO E_Status
wire pPioXfer;
wire sactive0; // bit 0 of sActive DWORD received in SDB FIS
// Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed
wire [31:0] xfer_cntr;
......@@ -502,11 +511,16 @@ module ahci_top#(
.pxci0_clear (pxci0_clear), // output
.pxci0 (pxci0), // input
.dma_prd_done (dma_prd_done), // input
.dma_prd_irq (dma_prd_irq), // input
.dma_prd_done (dma_prd_done), // input
.dma_prd_irq_clear (dma_prd_irq_clear), // output
.dma_prd_irq_pend (dma_prd_irq_pend), // input
.dma_cmd_busy (dma_cmd_busy), // input
.dma_cmd_done (dma_cmd_done), // input
.fis_first_invalid (frcv_first_invalid),// input
.fis_first_flush (frcv_first_flush), // output
.fis_first_vld (frcv_first_vld), // input
.fis_type (d2h_data[7:0]), // input[7:0] FIS type (low byte in the first FIS DWORD), valid with 'fis_first_vld'
.bist_bits (d2h_data[23:16]), // bits that define built-in self test
......@@ -523,6 +537,7 @@ module ahci_top#(
.fis_ok (frcv_ok), // input
.fis_err (frcv_err), // input
.fis_ferr (frcv_ferr), // input
.fis_extra (frcv_extra || dma_extra_din), // input // more data got from FIS than DMA can accept. Does not deny fis_ok. May have latency
.set_update_sig (frcv_set_update_sig),// output
.pUpdateSig (frcv_pUpdateSig), // input
......@@ -552,6 +567,7 @@ module ahci_top#(
.dma_d (dma_d), // input
.pio_i (pio_i), // input
.pio_d (pio_d), // input
.sactive0 (sactive0), // input
.pio_es (pio_es), // input[7:0]
.xfer_cntr (xfer_cntr[31:2]), // input[31:2]
.xfer_cntr_zero (xfer_cntr_zero), // input
......@@ -746,7 +762,10 @@ module ahci_top#(
.ct_re (dma_ct_re[0]), // input
.ct_data (dma_ct_data), // output[31:0] reg
.prd_done (dma_prd_done), // output
.prd_irq (dma_prd_irq), // output
.prd_irq_clear (dma_prd_irq_clear),// input
.prd_irq_pend (dma_prd_irq_pend), // output reg
.cmd_busy (dma_cmd_busy), // output reg
.cmd_done (dma_cmd_done), // output
.sys_out (dma_dout), // output[31:0]
......@@ -755,7 +774,7 @@ module ahci_top#(
.sys_in (d2h_data), // input[31:0]
.sys_nfull (dma_in_ready), // output
.sys_we (dma_we), // input
.extra_din (dma_extra_din), // output reg
.afi_awaddr (afi_awaddr), // output[31:0]
.afi_awvalid (afi_awvalid), // output
.afi_awready (afi_awready), // input
......@@ -809,6 +828,8 @@ module ahci_top#(
.mclk (mclk), // input
.fis_first_vld (frcv_first_vld), // output reg
.fis_first_invalid (frcv_first_invalid), // output
.fis_first_flush (frcv_first_flush), // input
.get_dsfis (frcv_get_dsfis), // input
.get_psfis (frcv_get_psfis), // input
......@@ -824,6 +845,9 @@ module ahci_top#(
.fis_err (frcv_err), // output reg
.fis_ferr (frcv_ferr), // output
.dma_prds_done (dma_cmd_done), // input
.fis_extra (frcv_extra), // output
.set_update_sig (frcv_set_update_sig), // input
.pUpdateSig (frcv_pUpdateSig), // output
.sig_available (frcv_sig_available), // output reg
......@@ -855,6 +879,7 @@ module ahci_top#(
.pio_i (pio_i), // output reg
.pio_d (pio_d), // output reg
.pio_es (pio_es), // output[7:0] reg
.sactive0 (sactive0), // output reg
.xfer_cntr (xfer_cntr[31:2]), // output[31:2]
.xfer_cntr_zero (xfer_cntr_zero), // output reg
.data_in_dwords (data_in_dwords), // output[11:0]
......
/*******************************************************************************
* Module: action_decoder
* Date:2016-01-18
* Author: auto-generated file, see ahci_fsm_sequence.py
* Description: Decode sequencer code to 1-hot actions
*******************************************************************************/
`timescale 1ns/1ps
module action_decoder (
input clk,
input enable,
input [10:0] data,
output reg PXSERR_DIAG_X,
output reg SIRQ_DHR,
output reg SIRQ_DP,
output reg SIRQ_DS,
output reg SIRQ_IF,
output reg SIRQ_PS,
output reg SIRQ_SDB,
output reg SIRQ_TFE,
output reg SIRQ_UF,
output reg PFSM_STARTED,
output reg PCMD_CR_CLEAR,
output reg PCMD_CR_SET,
output reg PXCI0_CLEAR,
output reg PXSSTS_DET_1,
output reg SSTS_DET_OFFLINE,
output reg SET_UPDATE_SIG,
output reg UPDATE_SIG,
output reg UPDATE_ERR_STS,
output reg UPDATE_PIO,
output reg UPDATE_PRDBC,
output reg CLEAR_BSY_DRQ,
output reg CLEAR_BSY_SET_DRQ,
output reg SET_BSY,
output reg SET_STS_7F,
output reg SET_STS_80,
output reg XFER_CNTR_CLEAR,
output reg DECR_DWC,
output reg FIS_FIRST_FLUSH,
output reg CLEAR_CMD_TO_ISSUE,
output reg DMA_ABORT,
output reg DMA_PRD_IRQ_CLEAR,
output reg XMIT_COMRESET,
output reg SEND_SYNC_ESC,
output reg SET_OFFLINE,
output reg R_OK,
output reg R_ERR,
output reg FETCH_CMD,
output reg ATAPI_XMIT,
output reg CFIS_XMIT,
output reg DX_XMIT,
output reg GET_DATA_FIS,
output reg GET_DSFIS,
output reg GET_IGNORE,
output reg GET_PSFIS,
output reg GET_RFIS,
output reg GET_SDBFIS,
output reg GET_UFIS);
always @(posedge clk) begin
PXSERR_DIAG_X <= enable && data[ 2] && data[ 0];
SIRQ_DHR <= enable && data[ 3] && data[ 0];
SIRQ_DP <= enable && data[ 4] && data[ 0];
SIRQ_DS <= enable && data[ 5] && data[ 0];
SIRQ_IF <= enable && data[ 6] && data[ 0];
SIRQ_PS <= enable && data[ 7] && data[ 0];
SIRQ_SDB <= enable && data[ 8] && data[ 0];
SIRQ_TFE <= enable && data[ 9] && data[ 0];
SIRQ_UF <= enable && data[10] && data[ 0];
PFSM_STARTED <= enable && data[ 2] && data[ 1];
PCMD_CR_CLEAR <= enable && data[ 3] && data[ 1];
PCMD_CR_SET <= enable && data[ 4] && data[ 1];
PXCI0_CLEAR <= enable && data[ 5] && data[ 1];
PXSSTS_DET_1 <= enable && data[ 6] && data[ 1];
SSTS_DET_OFFLINE <= enable && data[ 7] && data[ 1];
SET_UPDATE_SIG <= enable && data[ 8] && data[ 1];
UPDATE_SIG <= enable && data[ 9] && data[ 1];
UPDATE_ERR_STS <= enable && data[10] && data[ 1];
UPDATE_PIO <= enable && data[ 3] && data[ 2];
UPDATE_PRDBC <= enable && data[ 4] && data[ 2];
CLEAR_BSY_DRQ <= enable && data[ 5] && data[ 2];
CLEAR_BSY_SET_DRQ <= enable && data[ 6] && data[ 2];
SET_BSY <= enable && data[ 7] && data[ 2];
SET_STS_7F <= enable && data[ 8] && data[ 2];
SET_STS_80 <= enable && data[ 9] && data[ 2];
XFER_CNTR_CLEAR <= enable && data[10] && data[ 2];
DECR_DWC <= enable && data[ 4] && data[ 3];
FIS_FIRST_FLUSH <= enable && data[ 5] && data[ 3];
CLEAR_CMD_TO_ISSUE <= enable && data[ 6] && data[ 3];
DMA_ABORT <= enable && data[ 7] && data[ 3];
DMA_PRD_IRQ_CLEAR <= enable && data[ 8] && data[ 3];
XMIT_COMRESET <= enable && data[ 9] && data[ 3];
SEND_SYNC_ESC <= enable && data[10] && data[ 3];
SET_OFFLINE <= enable && data[ 5] && data[ 4];
R_OK <= enable && data[ 6] && data[ 4];
R_ERR <= enable && data[ 7] && data[ 4];
FETCH_CMD <= enable && data[ 8] && data[ 4];
ATAPI_XMIT <= enable && data[ 9] && data[ 4];
CFIS_XMIT <= enable && data[10] && data[ 4];
DX_XMIT <= enable && data[ 6] && data[ 5];
GET_DATA_FIS <= enable && data[ 7] && data[ 5];
GET_DSFIS <= enable && data[ 8] && data[ 5];
GET_IGNORE <= enable && data[ 9] && data[ 5];
GET_PSFIS <= enable && data[10] && data[ 5];
GET_RFIS <= enable && data[ 7] && data[ 6];
GET_SDBFIS <= enable && data[ 8] && data[ 6];
GET_UFIS <= enable && data[ 9] && data[ 6];
end
endmodule
/*******************************************************************************
* Module: condition_mux
* Date:2016-01-18
* Author: auto-generated file, see ahci_fsm_sequence.py
* Description: Select condition
*******************************************************************************/
`timescale 1ns/1ps
module condition_mux (
input clk,
input [ 7:0] sel,
output condition,
input ST_NB_ND,
input PXCI0_NOT_CMDTOISSUE,
input PCTI_CTBAR_XCZ,
input PCTI_XCZ,
input NST_D2HR,
input NPD_NCA,
input CHW_DMAA,
input SCTL_DET_CHANGED_TO_4,
input SCTL_DET_CHANGED_TO_1,
input PXSSTS_DET_NE_3,
input PXSSTS_DET_EQ_1,
input NPCMD_FRE,
input FIS_OK,
input FIS_ERR,
input FIS_FERR,
input FIS_EXTRA,
input FIS_FIRST_INVALID,
input FR_D2HR,
input FIS_DATA,
input FIS_ANY,
input NB_ND_D2HR_PIO,
input D2HR,
input SDB,
input DMA_ACT,
input DMA_SETUP,
input BIST_ACT_FE,
input BIST_ACT,
input PIO_SETUP,
input NB_ND,
input TFD_STS_ERR,
input FIS_I,
input PIO_I,
input NPD,
input PIOX,
input XFER0,
input PIOX_XFER0,
input CTBAA_CTBAP,
input CTBAP,
input CTBA_B,
input CTBA_C,
input TX_ERR,
input SYNCESC_ERR,
input DMA_PRD_IRQ_PEND,
input X_RDY_COLLISION);
wire [43:0] masked;
reg [ 5:0] cond_r;
assign condition = |cond_r;
assign masked[ 0] = ST_NB_ND && sel[ 2] && sel[ 1] && sel[ 0];
assign masked[ 1] = PXCI0_NOT_CMDTOISSUE && sel[ 3] && sel[ 1] && sel[ 0];
assign masked[ 2] = PCTI_CTBAR_XCZ && sel[ 4] && sel[ 1] && sel[ 0];
assign masked[ 3] = PCTI_XCZ && sel[ 5] && sel[ 1] && sel[ 0];
assign masked[ 4] = NST_D2HR && sel[ 6] && sel[ 1] && sel[ 0];
assign masked[ 5] = NPD_NCA && sel[ 7] && sel[ 1] && sel[ 0];
assign masked[ 6] = CHW_DMAA && sel[ 3] && sel[ 2] && sel[ 0];
assign masked[ 7] = SCTL_DET_CHANGED_TO_4 && sel[ 4] && sel[ 2] && sel[ 0];
assign masked[ 8] = SCTL_DET_CHANGED_TO_1 && sel[ 5] && sel[ 2] && sel[ 0];
assign masked[ 9] = PXSSTS_DET_NE_3 && sel[ 6] && sel[ 2] && sel[ 0];
assign masked[10] = PXSSTS_DET_EQ_1 && sel[ 7] && sel[ 2] && sel[ 0];
assign masked[11] = NPCMD_FRE && sel[ 4] && sel[ 3] && sel[ 0];
assign masked[12] = FIS_OK && sel[ 5] && sel[ 3] && sel[ 0];
assign masked[13] = FIS_ERR && sel[ 6] && sel[ 3] && sel[ 0];
assign masked[14] = FIS_FERR && sel[ 7] && sel[ 3] && sel[ 0];
assign masked[15] = FIS_EXTRA && sel[ 5] && sel[ 4] && sel[ 0];
assign masked[16] = FIS_FIRST_INVALID && sel[ 6] && sel[ 4] && sel[ 0];
assign masked[17] = FR_D2HR && sel[ 7] && sel[ 4] && sel[ 0];
assign masked[18] = FIS_DATA && sel[ 6] && sel[ 5] && sel[ 0];
assign masked[19] = FIS_ANY && sel[ 7] && sel[ 5] && sel[ 0];
assign masked[20] = NB_ND_D2HR_PIO && sel[ 7] && sel[ 6] && sel[ 0];
assign masked[21] = D2HR && sel[ 3] && sel[ 2] && sel[ 1];
assign masked[22] = SDB && sel[ 4] && sel[ 2] && sel[ 1];
assign masked[23] = DMA_ACT && sel[ 5] && sel[ 2] && sel[ 1];
assign masked[24] = DMA_SETUP && sel[ 6] && sel[ 2] && sel[ 1];
assign masked[25] = BIST_ACT_FE && sel[ 7] && sel[ 2] && sel[ 1];
assign masked[26] = BIST_ACT && sel[ 4] && sel[ 3] && sel[ 1];
assign masked[27] = PIO_SETUP && sel[ 5] && sel[ 3] && sel[ 1];
assign masked[28] = NB_ND && sel[ 6] && sel[ 3] && sel[ 1];
assign masked[29] = TFD_STS_ERR && sel[ 7] && sel[ 3] && sel[ 1];
assign masked[30] = FIS_I && sel[ 5] && sel[ 4] && sel[ 1];
assign masked[31] = PIO_I && sel[ 6] && sel[ 4] && sel[ 1];
assign masked[32] = NPD && sel[ 7] && sel[ 4] && sel[ 1];
assign masked[33] = PIOX && sel[ 6] && sel[ 5] && sel[ 1];
assign masked[34] = XFER0 && sel[ 7] && sel[ 5] && sel[ 1];
assign masked[35] = PIOX_XFER0 && sel[ 7] && sel[ 6] && sel[ 1];
assign masked[36] = CTBAA_CTBAP && sel[ 4] && sel[ 3] && sel[ 2];
assign masked[37] = CTBAP && sel[ 5] && sel[ 3] && sel[ 2];
assign masked[38] = CTBA_B && sel[ 6] && sel[ 3] && sel[ 2];
assign masked[39] = CTBA_C && sel[ 7] && sel[ 3] && sel[ 2];
assign masked[40] = TX_ERR && sel[ 5] && sel[ 4] && sel[ 2];
assign masked[41] = SYNCESC_ERR && sel[ 6] && sel[ 4] && sel[ 2];
assign masked[42] = DMA_PRD_IRQ_PEND && sel[ 7] && sel[ 4] && sel[ 2];
assign masked[43] = X_RDY_COLLISION && sel[ 6] && sel[ 5] && sel[ 2];
always @(posedge clk) begin
cond_r[ 0] <= |masked[ 7: 0];
cond_r[ 1] <= |masked[15: 8];
cond_r[ 2] <= |masked[23:16];
cond_r[ 3] <= |masked[31:24];
cond_r[ 4] <= |masked[39:32];
cond_r[ 5] <= |masked[43:40];
end
endmodule
......@@ -25,24 +25,72 @@ __maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
import sys
import os
import datetime
LBL= "Label"
ACT="Action"
IF="If"
GOTO= "Goto"
ADR = "Address"
ADDR = "Address"
NOP = "NOP"
sequence = [{LBL:'POR', ADR: 0x0, ACT: NOP},
actions_cnk = (11,2) # 2 hot of 8
conditions_cnk = (8,3) # 3 hot of 11
#action_decoder_verilog_path=None
action_decoder_verilog_path= '../generated/action_decoder.v'
action_decoder_module_name= 'action_decoder'
condition_mux_verilog_path= '../generated/condition_mux.v'
condition_mux_module_name= 'condition_mux'
condition_mux_fanout = 8
#Set actions, conditions to empty string to rebuild list. Then edit order and put here
actions = ['NOP',
# CTRL_STAT
'PXSERR_DIAG_X', 'SIRQ_DHR', 'SIRQ_DP', 'SIRQ_DS', 'SIRQ_IF', 'SIRQ_PS', 'SIRQ_SDB', 'SIRQ_TFE', 'SIRQ_UF',
'PFSM_STARTED', 'PCMD_CR_CLEAR', 'PCMD_CR_SET', 'PXCI0_CLEAR', 'PXSSTS_DET_1', 'SSTS_DET_OFFLINE',
# FIS RECEIVE
'SET_UPDATE_SIG', 'UPDATE_SIG', 'UPDATE_ERR_STS', 'UPDATE_PIO', 'UPDATE_PRDBC', 'CLEAR_BSY_DRQ',
'CLEAR_BSY_SET_DRQ', 'SET_BSY', 'SET_STS_7F', 'SET_STS_80', 'XFER_CNTR_CLEAR', 'DECR_DWC', 'FIS_FIRST_FLUSH',
# FIS_TRANSMIT
'CLEAR_CMD_TO_ISSUE',
# DMA
'DMA_ABORT', 'DMA_PRD_IRQ_CLEAR',
# SATA TRANSPORT/LINK/PHY
'XMIT_COMRESET', 'SEND_SYNC_ESC', 'SET_OFFLINE', 'R_OK', 'R_ERR',
# FIS TRANSMIT/WAIT DONE
'FETCH_CMD*', 'ATAPI_XMIT*', 'CFIS_XMIT*', 'DX_XMIT*',
#FIS RECEIVE/WAIT DONE
'GET_DATA_FIS*', 'GET_DSFIS*', 'GET_IGNORE*', 'GET_PSFIS*', 'GET_RFIS*', 'GET_SDBFIS*', 'GET_UFIS*']
conditions = [
#COMPOSITE
'ST_NB_ND', 'PXCI0_NOT_CMDTOISSUE', 'PCTI_CTBAR_XCZ', 'PCTI_XCZ', 'NST_D2HR', 'NPD_NCA', 'CHW_DMAA',
# CTRL_STAT
'SCTL_DET_CHANGED_TO_4', 'SCTL_DET_CHANGED_TO_1', 'PXSSTS_DET_NE_3', 'PXSSTS_DET_EQ_1', 'NPCMD_FRE',
# FIS RECEIVE
'FIS_OK', 'FIS_ERR', 'FIS_FERR', 'FIS_EXTRA', 'FIS_FIRST_INVALID', 'FR_D2HR', 'FIS_DATA', 'FIS_ANY',
'NB_ND_D2HR_PIO', 'D2HR', 'SDB', 'DMA_ACT', 'DMA_SETUP', 'BIST_ACT_FE', 'BIST_ACT', 'PIO_SETUP',
'NB_ND', 'TFD_STS_ERR', 'FIS_I', 'PIO_I', 'NPD', 'PIOX', 'XFER0', 'PIOX_XFER0',
# FIS_TRANSMIT
'CTBAA_CTBAP', 'CTBAP', 'CTBA_B', 'CTBA_C', 'TX_ERR', 'SYNCESC_ERR',
# DMA
'DMA_PRD_IRQ_PEND',
# SATA TRANSPORT/LINK/PHY
'X_RDY_COLLISION'] # TODO: set/reset
#actions = []
#conditions = []
sequence = [{LBL:'POR', ADDR: 0x0, ACT: NOP},
{ GOTO:'H:Init'},
{LBL:'HBA_RST', ADR: 0x2, ACT: NOP},
{LBL:'HBA_RST', ADDR: 0x2, ACT: NOP},
{ GOTO:'H:Init'},
{LBL:'PORT_RST', ADR: 0x4, ACT: NOP},
{LBL:'PORT_RST', ADDR: 0x4, ACT: NOP},
{ GOTO:'H:Init'},
{LBL:'COMINIT', ADR: 0x6, ACT: NOP},
{LBL:'COMINIT', ADDR: 0x6, ACT: NOP},
{ GOTO:'P:Cominit'},
{LBL:'ST_CLEARED',ADR: 0x6, ACT: NOP}, # TODO: make sure this jump is not from P:Init
{LBL:'ST_CLEARED',ADDR: 0x8,ACT: NOP}, # TODO: make sure this jump is not from P:Init
{ GOTO:'P:StartBitCleared'},
......@@ -55,231 +103,596 @@ sequence = [{LBL:'POR', ADR: 0x0, ACT: NOP},
{LBL:'H:Idle', ACT: NOP},
{ GOTO:'P:Init'}, #All required actions for H* are done in hardware, just go to port initialization
{LBL:'P:Init', ACT: 'PFSM'}, # pfsm_started HBA init done, port FSM started
{ ACT: 'PSCI0'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{ ACT: 'CLEAR_BSY_SET_DRQ'}, # clear_bsy_set_drq
{ ACT: 'SET_STS_7F'}, # set_sts_7f
{ ACT: 'SET_UPDATE_SIG'}, # set_update_sig
{ ACT: 'XMIT_COMRESET'}, # Now does it on reset. See if it is possible to transmit COMRESET w/o reset
{LBL:'P:Init', ACT: 'PFSM_STARTED'}, # pfsm_started HBA init done, port FSM started
{ ACT: 'PXCI0_CLEAR'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{ ACT: 'CLEAR_BSY_SET_DRQ'}, # clear_bsy_set_drq
{ ACT: 'SET_STS_7F'}, # set_sts_7f
{ ACT: 'SET_UPDATE_SIG'}, # set_update_sig
{ ACT: 'XMIT_COMRESET'}, # Now does it on reset. See if it is possible to transmit COMRESET w/o reset
{ GOTO:'P:NotRunning'},
{LBL:'P:NotRunningGarbage', ACT: 'FIS_FIRST_FLUSH'}, # fis_first_flush (FIFO output has data, but not FIS head
#TODO - add to some error? Now silently skips
{ GOTO:'P:NotRunning'},
{LBL:'P:NotRunning', ACT: 'NOP'}, # 'PSCI0'}, # pxci0_clear, - should not be here as it updates soft registers?
{IF:'SCTL_DET_CHANGED_TO_4',GOTO:'P:Offline'}, #4
{IF:'SCTL_DET_CHANGED_TO_1',GOTO:'P:StartComm'}, #5
{LBL:'P:NotRunning', ACT: 'NOP'}, # 'PXCI0_CLEAR'}, # pxci0_clear, - should not be here as it updates soft registers?
{IF: 'FIS_FIRST_INVALID', GOTO:'P:NotRunningGarbage'},
{IF:'SCTL_DET_CHANGED_TO_4',GOTO:'P:Offline'}, #4
{IF:'SCTL_DET_CHANGED_TO_1',GOTO:'P:StartComm'}, #5
# Transition 8. PxCMD.FRE written to ‘1’ from a ‘0’ and previously processed Register FIS is in receive FIFO and PxSERR.DIAG.X = ‘0’
# can not be implemented - it is too late, FIS is already gone. So as we do not move FIS receive area, there is no sense to disable FIS,
# and for the signature we'll always assume FRE is on
{IF:'ST_NB_ND', GOTO:'P:Idle'}, #12 : PxCMD.ST & !PxTBD.STS.BSY & !PxTBD.STS.DRQ
{IF:'FR_D2HR', GOTO:'NDR:Entry'}, #13 fis_first_vld & fis_type == 0x34 (D2H Register)
{ GOTO:'P:NotRunning'},#14
{IF:'ST_NB_ND', GOTO:'P:Idle'}, #12 : PxCMD.ST & !PxTBD.STS.BSY & !PxTBD.STS.DRQ
{IF:'FR_D2HR', GOTO:'NDR:Entry'}, #13 fis_first_vld & fis_type == 0x34 (D2H Register)
{ GOTO:'P:NotRunning'}, #14
{LBL:'P:Cominit', ACT: 'NOP'}, # got here asynchronously from COMINIT label
{ ACT: 'SET_STS_80'}, # frcv_set_sts_80 (Not clear 0xff or 0x80 should be here?)
{ ACT: 'PXSSTS_DET_1'}, # ssts_det_dnp, // device detected, but phy communication not established
{ ACT: 'PXSERR_DIAG_X'}, # sirq_PC, // RO: Port Connect Change Status (pulse to set)
# {IF:'PXIE_PCE', GOTO:'P:CominitSetIS'}, # Not needed, interrupt
{ ACT: 'SET_STS_80'}, # frcv_set_sts_80 (Not clear 0xff or 0x80 should be here?)
{ ACT: 'PXSSTS_DET_1'}, # ssts_det_dnp, // device detected, but phy communication not established
{ ACT: 'PXSERR_DIAG_X'}, # sirq_PC, // RO: Port Connect Change Status (pulse to set)
# {IF:'PXIE_PCE', GOTO:'P:CominitSetIS'}, # Not needed, interrupt
{ GOTO:'P:NotRunning'},
{LBL:'P:RegFisUpdate', ACT: 'GET_RFIS'}, #get_rfis
{ ACT: 'UPDATE_SIG'}, # update_sig
# {IF: 'PCMD_FRE', GOTO:'P:RegFisPostToMem'}, # pcmd_fre hardware always copies signature FIS to 'memory' if expected
{ GOTO:'P:NotRunning'},
{LBL:'P:RegFisUpdate', ACT: 'GET_RFIS*'}, # get_rfis
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'P:RegFisAccept'},
{LBL:'P:RegFisPostToMem', ACT: 'NOP'}, # Probably not needed, handled at lower level
{LBL:'P:RegFisAccept', ACT: 'R_OK'}, # send R_OK
{ ACT: 'UPDATE_SIG'}, # update_sig
{ ACT: 'UPDATE_ERR_STS'}, # update_err_sts
{ GOTO:'P:NotRunning'},
{LBL:'P:Offline', ACT: 'SET_OFFLINE'}, # set_offline
# {IF: 'PCMD_FRE', GOTO:'P:RegFisPostToMem'}, # pcmd_fre hardware always copies signature FIS to 'memory' if expected
# {LBL:'P:RegFisPostToMem', ACT: 'NOP'}, # Probably not needed, handled at lower level
# { GOTO:'P:NotRunning'},
{LBL:'P:Offline', ACT: 'SET_OFFLINE'}, # set_offline
{ GOTO:'P:NotRunning'},
{LBL:'P:StartBitCleared', ACT: 'PXCI0_CLEAR'}, # pxci0_clear
{ ACT: 'DMA_ABORT'}, # dma_cmd_abort (should eventually clear PxCMD.CR)?
{ ACT: 'PCMD_CR_CLEAR'}, # pcmd_cr_reset
{ ACT: 'XFER_CNTR_CLEAR'}, # clear_xfer_cntr
{LBL:'P:Idle', ACT: 'PCMD_CR_SET'}, # pcmd_cr_set
{IF: 'PXSSTS_DET_NE_3', GOTO:'P:NotRunning' }, # 1. ssts_det!=3, // device detected, phy communication not established
{IF: 'PXCI0_NOT_CMDTOISSUE',GOTO:'P:FetchCmd' }, # 2. pxci0 && !pCmdToIssue was pIssueSlot==32, -> p:SelectCmd
{IF: 'PCTI_CTBAR_XCZ', GOTO:'CFIS:SyncEscape'}, # 3. pCmdToIssue && ch_r && xfer_cntr_zero
{IF: 'FIS_DATA', GOTO:'DR:Entry'}, # 4. fis_first_vld && (fis_type == 'h46)
{IF: 'FIS', GOTO:'NDR:Entry'}, # 5. fis_first_vld # already assumed && ((fis_type != 'h46)
{IF: 'PCTI_XCZ', GOTO:'CFIS:Xmit'}, # 6. pCmdToIssue && xfer_cntr_zero
{ GOTO:'P:Idle'}, #10. (#7-#9 PM, not implemented)
{LBL:'P:StartBitCleared', ACT: 'PXCI0_CLEAR'}, # pxci0_clear
{ ACT: 'DMA_ABORT'}, # dma_cmd_abort (should eventually clear PxCMD.CR)?
{ ACT: 'PCMD_CR_CLEAR'}, # pcmd_cr_reset
{ ACT: 'XFER_CNTR_CLEAR'}, # clear_xfer_cntr
{LBL:'P:IdleGarbage', ACT: 'FIS_FIRST_FLUSH'}, # fis_first_flush (FIFO output has data, but not FIS head
#TODO - add to some error? Now silently skips
{ GOTO:'P:Idle'},
{LBL:'P:Idle', ACT: 'PCMD_CR_SET'}, # pcmd_cr_set
{IF: 'PXSSTS_DET_NE_3', GOTO:'P:NotRunning' }, # 1. ssts_det!=3, // device detected, phy communication not established
{IF: 'PXCI0_NOT_CMDTOISSUE',GOTO:'P:FetchCmd' }, # 2. pxci0 && !pCmdToIssue was pIssueSlot==32, -> p:SelectCmd
{IF: 'PCTI_CTBAR_XCZ', GOTO:'CFIS:SyncEscape'}, # 3. pCmdToIssue && ch_r && xfer_cntr_zero
{IF: 'FIS_FIRST_INVALID', GOTO:'P:IdleGarbage'},
{IF: 'FIS_DATA', GOTO:'DR:Entry'}, # 4. fis_first_vld && (fis_type == 'h46)
{IF: 'FIS_ANY', GOTO:'NDR:Entry'}, # 5. fis_first_vld # already assumed && ((fis_type != 'h46)
{IF: 'PCTI_XCZ', GOTO:'CFIS:Xmit'}, # 6. pCmdToIssue && xfer_cntr_zero
{ GOTO:'P:Idle'}, #10. (#7-#9 PM, not implemented)
#P:SelectCmd not implemented, using single slot
{LBL:'P:FetchCmd', ACT: 'FETCH_CMD'}, # fetch_cmd (other actions included in ahci_fis_transmit)
{LBL:'P:FetchCmd', ACT: 'FETCH_CMD*'}, # fetch_cmd (other actions included in ahci_fis_transmit)
#ahci_fis_transmit already processes ch_p. ATAPI data is always preloaded, prd - if ch_p
{IF: 'CTBAA_CTBAP', GOTO:'CFIS:PrefetchACMD'},#1. ch_a && ch_p # Note ch_p may be ignored or transition may be ignored
{IF: 'CTBAP', GOTO:'CFIS:PrefetchPRD'}, #2. ch_p # Note ch_p may be ignored or transition may be ignored
{ GOTO:'P:Idle'}, #3. PxTFD.STS.BSY must be set before issuing a command (or now if predicted)
{IF: 'CTBAA_CTBAP', GOTO:'CFIS:PrefetchACMD'}, # 1. ch_a && ch_p # Note ch_p may be ignored or transition may be ignored
{IF: 'CTBAP', GOTO:'CFIS:PrefetchPRD'}, # 2. ch_p # Note ch_p may be ignored or transition may be ignored
{ GOTO:'P:Idle'}, # 3. PxTFD.STS.BSY must be set before issuing a command (or now if predicted)
{LBL:'P:StartComm', ACT: 'SET_STS_7F'}, # frcv_set_sts_7f
{ ACT: 'SET_UPDATE_SIG'}, # #frcv_set_update_sig
{ ACT: 'XMIT_COMRESET'}, # Now does it on reset. See if it is possible to transmit COMRESET w/o reset
{LBL:'P:StartComm', ACT: 'SET_STS_7F'}, # frcv_set_sts_7f
{ ACT: 'SET_UPDATE_SIG'}, # #frcv_set_update_sig
{ ACT: 'XMIT_COMRESET'}, # Now does it on reset. See if it is possible to transmit COMRESET w/o reset
{IF: 'PXSSTS_DET_EQ_1', GOTO:'P:StartComm'},
{ GOTO:'P:NotRunning'},
#New states, because FIS needs to be read in befor R_OK
{LBL:'P:OkIdle', ACT: 'R_OK'}, # send_R_OK to device
{ GOTO:'P:Idle'}, # (was directly from NDR:Accept.4
{LBL:'P:OkNotRunning', ACT: 'R_OK'}, # send_R_OK to device
{ GOTO:'P:NotRunning'}, # (was directly from NDR:Accept.4
#P:PowerOn, P;PwerOff,P:PhyListening - not implemented
#FB:* - Not implemented
#PM:* - Not implemented
{LBL:'PM:Aggr', ACT: 'NOP'}, # Just as a placeholder
{ GOTO:'P:Idle'}, #1
{LBL:'PM:Aggr', ACT: 'NOP'}, # Just as a placeholder
{ GOTO:'P:Idle'}, #1
{LBL:'NDR:Entry', ACT: 'NOP'},
{IF: 'FIS_ERR', GOTO:'ERR:Non-fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'NDR:Accept'}, # 4.
{LBL:'NDR:IgnoreNR', ACT: 'FIS_IOGNORE'}, # get_ignore This one is not in docs, just to empty FIS FIFO
{ GOTO:'P:NotRunning'}, # (was directly from NDR:Accept.4
{LBL:'NDR:IgnoreIdle', ACT: 'FIS_IOGNORE'}, # get_ignore This one is not in docs, just to empty FIS FIFO
{ GOTO:'P:Idle'}, # (was directly from NDR:Accept.4
{LBL:'NDR:Accept', ACT: 'R_OK'}, # send_R_OK to device
{IF:'NB_ND_D2HR_PIO', GOTO:'NDR:IgnoreIdle'}, # 2 :((FIS == FIS_D2HR) || (FIS == FIS_PIO)) && !PxTBD.STS.BSY & !PxTBD.STS.DRQ
{IF:'NST_D2HR', GOTO:'P:RegFisUpdate'}, # 3 :!ST && (FIS == FIS_D2HR) TODO: does it mean either BSY or DRQ are 1?
{IF:'NPCMD_FRE', GOTO:'NDR:IgnoreNR' }, # 4 !pcmd_fre (docs: goto P:NotRunning, but we need to clear FIFO)
{IF:'D2HR', GOTO:'RegFIS:Entry' }, # 5 FIS == FIS_D2HR
{IF:'SDB', GOTO:'SDB:Entry' }, # 7 (# 6 skipped)
{IF:'DMA_ACT', GOTO:'DX:Entry' }, # 8 FIS == FIS_DMA_ACT
{IF:'DMA_SETUP', GOTO:'DmaSet:Entry' }, # 9 FIS == FIS_DMA_SETUP
{IF:'BIST_ACT_FE', GOTO:'BIST:FarEndLoopback'},#10 FIS == FIS_BIST_ACT && |bist_bits TODO:get_ignore to read in FIS
{IF:'BIST_ACT', GOTO:'BIST:TestOngoing'},# 11 FIS == FIS_BIST_ACT && |bist_bits TODO:get_ignore to read in FIS
{IF:'PIO_SETUP', GOTO:'PIO:Entry' }, # 12 FIS == FIS_PIO_SETUP
{ GOTO:'UFIS:Entry' }, # 13 Unknown FIS (else)
# {IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
# {IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'NDR:Accept'}, # 4.
{LBL:'NDR:IgnoreNR', ACT: 'GET_IGNORE*'}, # get_ignore This one is not in docs, just to empty FIS FIFO
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'P:OkIdle'}, #
{LBL:'NDR:IgnoreIdle', ACT: 'GET_IGNORE*'}, # get_ignore This one is not in docs, just to empty FIS FIFO
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'P:OkNotRunning'}, #
{LBL:'NDR:Accept', ACT: 'NOP'}, # ******** # send R_OK after reading in FIS: ACT: 'R_OK'}, # send_R_OK to device
{IF:'NB_ND_D2HR_PIO', GOTO:'NDR:IgnoreIdle'}, # 2 :((FIS == FIS_D2HR) || (FIS == FIS_PIO)) && !PxTBD.STS.BSY & !PxTBD.STS.DRQ
{IF:'NST_D2HR', GOTO:'P:RegFisUpdate'}, # 3 :!ST && (FIS == FIS_D2HR) TODO: does it mean either BSY or DRQ are 1?
{IF:'NPCMD_FRE', GOTO:'NDR:IgnoreNR' }, # 4 !pcmd_fre (docs: goto P:NotRunning, but we need to clear FIFO)
{IF:'D2HR', GOTO:'RegFIS:Entry' }, # 5 FIS == FIS_D2HR
{IF:'SDB', GOTO:'SDB:Entry' }, # 7 (# 6 skipped)
{IF:'DMA_ACT', GOTO:'DX:EntryIgnore' }, # 8 FIS == FIS_DMA_ACT
{IF:'DMA_SETUP', GOTO:'DmaSet:Entry' }, # 9 FIS == FIS_DMA_SETUP
{IF:'BIST_ACT_FE', GOTO:'BIST:FarEndLoopback'}, #10 FIS == FIS_BIST_ACT && |bist_bits TODO:get_ignore to read in FIS
{IF:'BIST_ACT', GOTO:'BIST:TestOngoing'}, # 11 FIS == FIS_BIST_ACT && |bist_bits TODO:get_ignore to read in FIS
{IF:'PIO_SETUP', GOTO:'PIO:Entry' }, # 12 FIS == FIS_PIO_SETUP
{ GOTO:'UFIS:Entry' }, # 13 Unknown FIS (else)
#5.3.6. Command Transfer State
{LBL:'CFIS:SyncEscape', ACT: 'SEND_SYNC_ESC'}, # syncesc_send, should wait (for syncesc_send_done)
{ ACT: 'SET_UPDATE_SIG'}, # set_update_sig
{ GOTO:'CFIS:Xmit' }, # 1
{LBL:'CFIS:Xmit', ACT: 'SET_BSY'}, # set_bsy
{ ACT: 'CFIS_XMIT'}, # cfis_xmit
{IF: 'X_RDY_COLLISION', GOTO:'P:Idle'}, # 2. x_rdy_collision_pend
{IF: 'SYNCESC_RECV', GOTO:'ERR:SyncEscapeRecv'}, # 4. syncesc_recv
{IF: 'FIS_OK', GOTO:'CFIS:SUCCESS'}, # 5. fis_ok
{ GOTO:'ERR:Non-fatal'}, # 6
{LBL:'CFIS:Success', ACT: 'CLEAR_CMD_TO_ISSUE'}, # clearCmdToIssue
{IF: 'CTBA_B', GOTO:'BIST:TestOngoing'}, # 1. ch_b
{IF: 'CTBA_C', GOTO:'CFIS:ClearCI'}, # 2. ch_c
{IF: 'CTBAA_CTBAP', GOTO:'CFIS:PrefetchACMD'},# 3. ch_a && ch_p # Note ch_p may be ignored or transition may be ignored
{IF: 'CTBAP', GOTO:'CFIS:PrefetchPRD'}, # 4. ch_p # Note ch_p may be ignored or transition may be ignored
{ GOTO:'P:Idle'}, # 6.
{LBL:'CFIS:CLearCI', ACT: 'PSCI0'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{ ACT: 'CLEAR_BSY_DRQ'}, # clear_bsy_drq
{ GOTO:'PM:Aggr' }, # 1
{LBL:'CFIS:SyncEscape', ACT: 'SEND_SYNC_ESC'}, # syncesc_send, should wait (for syncesc_send_done)
{ ACT: 'SET_UPDATE_SIG'}, # set_update_sig
{ GOTO:'CFIS:Xmit' }, # 1
{LBL:'CFIS:Xmit', ACT: 'SET_BSY'}, # set_bsy
{ ACT: 'CFIS_XMIT*'}, # cfis_xmit
{IF: 'X_RDY_COLLISION', GOTO:'P:Idle'}, # 2. x_rdy_collision_pend
{IF: 'SYNCESC_ERR', GOTO:'ERR:SyncEscapeRecv'}, # 4. dx_err[0] (reset by new command)
{IF: 'FIS_OK', GOTO:'CFIS:Success'}, # 5. fis_ok
{ GOTO:'ERR:Non-Fatal'}, # 6
{LBL:'CFIS:Success', ACT: 'CLEAR_CMD_TO_ISSUE'}, # clearCmdToIssue
{IF: 'CTBA_B', GOTO:'BIST:TestOngoing'}, # 1. ch_b
{IF: 'CTBA_C', GOTO:'CFIS:ClearCI'}, # 2. ch_c
{IF: 'CTBAA_CTBAP', GOTO:'CFIS:PrefetchACMD'}, # 3. ch_a && ch_p # Note ch_p may be ignored or transition may be ignored
{IF: 'CTBAP', GOTO:'CFIS:PrefetchPRD'}, # 4. ch_p # Note ch_p may be ignored or transition may be ignored
{ GOTO:'P:Idle'}, # 6.
{LBL:'CFIS:ClearCI', ACT: 'PXCI0_CLEAR'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{ ACT: 'CLEAR_BSY_DRQ'}, # clear_bsy_drq
{ GOTO:'PM:Aggr' }, # 1
# As ahci_fis_transmit processes ch_p, GOTO:'CFIS:Prefetch*' can be shortcut to GOTO:'P:Idle'
{LBL:'CFIS:PrefetchACMD', ACT: 'NOP'}, # Nothing to do as it is already in memory, fetched together with command
{IF: 'CTBAP', GOTO:'CFIS:PrefetchPRD'}, # 1. ch_p Note ch_p may be ignored or transition may be ignored
{ GOTO:'P:Idle'}, # 3.
{LBL:'CFIS:PrefetchACMD', ACT: 'NOP'}, # Nothing to do as it is already in memory, fetched together with command
{IF: 'CTBAP', GOTO:'CFIS:PrefetchPRD'}, # 1. ch_p Note ch_p may be ignored or transition may be ignored
{ GOTO:'P:Idle'}, # 3.
{LBL:'CFIS:PrefetchPRD', ACT: 'NOP'}, # ahci_fis_transmit processes ch_p, no more actions needed
{ GOTO:'P:Idle'}, # 1.
{LBL:'CFIS:PrefetchPRD', ACT: 'NOP'}, # ahci_fis_transmit processes ch_p, no more actions needed
{ GOTO:'P:Idle'}, # 1.
{LBL:'CFIS:PrefetchData', ACT: 'NOP'}, # ahci_fis_transmit-> ahci_dma prefetches data if possible
{ GOTO:'P:Idle'}, # 1.
# {LBL:'CFIS:PrefetchData', ACT: 'NOP'}, # ahci_fis_transmit-> ahci_dma prefetches data if possible
# { GOTO:'P:Idle'}, # 1.
#5.3.7 ATAPI Command Transfer States
{LBL:'ATAPI:Entry', ACT: 'ATAPI_XMIT'}, # atapi_xmit, '0->pXferAtapi[pPmpCur]' is done ahci_fis_transmit.
{IF: 'TX_ERR', GOTO:'ERR:Fatal'}, # 1. dx_err[1] (reset by new command)
{ GOTO:'PIO:Update'}, # 2.
{LBL:'ATAPI:Entry', ACT: 'ATAPI_XMIT*'}, # atapi_xmit, '0->pXferAtapi[pPmpCur]' is done ahci_fis_transmit.
{IF: 'TX_ERR', GOTO:'ERR:Fatal'}, # 1. dx_err[1] (reset by new command)
{ GOTO:'PIO:Update'}, # 2.
#5.3.8 D2H Register FIS Receive States
{LBL:'RegFIS:Entry', ACT: 'GET_RFIS'}, # get_rfis
{IF: 'TFD_STS_ERR', GOTO:'ERR:FatalTaskfile'},# 1. tfd_sts[0]
{IF: 'NB_ND', GOTO:'RegFIS:ClearCI'}, # 2. PxTFD.STS.BSY =’0’ and PxTFD.STS.DRQ =’0’
{ GOTO:'RegFIS:UpdateSig'}, # 3.
{LBL:'RegFIS:ClearCI', ACT: 'UPDATE_PRDBC'}, # update_prdbc
{ ACT: 'PSCI0'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{IF: 'FIS_I', GOTO:'RegFIS:SetIntr'}, # 2. fis_i
{ GOTO:'RegFIS:UpdateSig'}, # 3.
{LBL:'RegFIS:SetIntr', ACT: 'SIRQ_DHR'}, # sirq_DHR
{ GOTO:'RegFIS:UpdateSig'}, # 2. (PxIE/IRQ is handled)
{LBL:'RegFIS:Entry', ACT: 'GET_RFIS*'}, # get_rfis
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'RegFIS:Accept'}, #
{LBL:'RegFIS:Accept', ACT: 'R_OK'}, # send R_OK
{ ACT: 'UPDATE_ERR_STS'}, # update_err_sts
{IF: 'TFD_STS_ERR', GOTO:'ERR:FatalTaskfile'}, # 1. tfd_sts[0]
{IF: 'NB_ND', GOTO:'RegFIS:ClearCI'}, # 2. PxTFD.STS.BSY =’0’ and PxTFD.STS.DRQ =’0’
{ GOTO:'RegFIS:UpdateSig'}, # 3.
{LBL:'RegFIS:ClearCI', ACT: 'UPDATE_PRDBC'}, # update_prdbc
{ ACT: 'PXCI0_CLEAR'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{IF: 'FIS_I', GOTO:'RegFIS:SetIntr'}, # 2. fis_i
{ GOTO:'RegFIS:UpdateSig'}, # 3.
{LBL:'RegFIS:SetIntr', ACT: 'SIRQ_DHR'}, # sirq_DHR
{ GOTO:'RegFIS:UpdateSig'}, # 2. (PxIE/IRQ is handled)
#RegFIS:SetIS, RegFIS:GenIntr are handled by hardware, skipping
{LBL:'RegFIS:UpdateSig', ACT: 'UPDATE_SIG'}, # update_sig will only update if pUpdateSig
{ GOTO:'PM:Aggr' }, # 1
{LBL:'RegFIS:UpdateSig', ACT: 'UPDATE_SIG'}, # update_sig will only update if pUpdateSig
{ GOTO:'PM:Aggr' }, # 1
#RegFIS:SetSig skipped, done in RegFIS:UpdateSig
#5.3.9 PIO Setup Receive States
{LBL:'PIO:Entry', ACT: 'GET_PSFIS'}, # get_psfis, includes all steps 1..9
{IF: 'TFD_STS_ERR', GOTO:'ERR:FatalTaskfile'},# 1. tfd_sts[0]
{IF: 'NPD_NCA', GOTO:'DX:Entry'}, # 2. pio_d = 0 && ch_a == 0
{IF: 'NPD', GOTO:'ATAPI:Entry'}, # 3. pio_d = 0 , "ch_a == 1" is not needed
{ GOTO:'P:Idle' }, # 4
{LBL:'PIO:Entry', ACT: 'GET_PSFIS*'}, # get_psfis, includes all steps 1..9
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'PIO:Accept' },
{LBL:'PIO:Accept', ACT: 'R_OK'}, # get_psfis, includes all steps 1..9
{IF: 'TFD_STS_ERR', GOTO:'ERR:FatalTaskfile'}, # 1. tfd_sts[0]
{IF: 'NPD_NCA', GOTO:'DX:Entry'}, # 2. pio_d = 0 && ch_a == 0
{IF: 'NPD', GOTO:'ATAPI:Entry'}, # 3. pio_d = 0 , "ch_a == 1" is not needed
{ GOTO:'P:Idle' }, # 5.
{LBL:'PIO:Update', ACT: 'UPDATE_PIO'}, # update_pio - update PxTFD.STS and PxTFD.ERR from pio_*
{IF: 'TFD_STS_ERR', GOTO:'ERR:FatalTaskfile'}, # 1. tfd_sts[0]
{IF: 'NB_ND', GOTO:'PIO:ClearCI'}, # 2. PxTFD.STS.BSY =’0’ and PxTFD.STS.DRQ =’0’
{IF: 'PIO_I', GOTO:'PIO:SetIntr'}, # 3. pio_i
{ GOTO:'P:Idle' }, # 5.
{LBL:'PIO:ClearCI', ACT: 'UPDATE_PRDBC'}, # update_prdbc
{ ACT: 'PXCI0_CLEAR'}, # pxci0_clear, reset both (pIssueSlot:=32) and PxCI[0]
{IF: 'PIO_I', GOTO:'PIO:SetIntr'}, # 2. pio_i
{ GOTO:'PM:Aggr' }, # 3.
#PIO:Ccc - not implemented
{LBL:'PIO:SetIntr', ACT: 'SIRQ_PS'}, # sirq_PS
{ GOTO:'PM:Aggr'}, # 1. (PxIE/IRQ is handled)
#PIO:SetIS, PIO:GenIntr are handled by hardware, skipping
#5.3.10 Data Transmit States
{LBL:'DX:EntryIgnore', ACT: 'GET_IGNORE*'}, # Read/Ignore FIS in FIFO (not in docs)
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'DX:Accept'}, #
{LBL:'DX:Accept', ACT: 'R_OK'}, # send R_OK
{ GOTO:'DX:Entry'}, #
{LBL:'DX:Entry', ACT: 'DMA_PRD_IRQ_CLEAR'}, # dma_prd_irq_clear (FIS should be accepted/confirmed)
{IF: 'PIOX_XFER0', GOTO:'PIO:Update'}, # 1. pPioXfer && xfer_cntr_zero
{IF: 'XFER0', GOTO:'P:Idle'}, # 3. xfer_cntr_zero # && !pPioXfer (implied)
{ GOTO:'DX:Transmit'}, # 4.
{LBL:'DX:Transmit', ACT: 'DX_XMIT*'}, # dx_transmit
{IF: 'SYNCESC_ERR', GOTO:'ERR:SyncEscapeRecv'}, # 1. dx_err[0] (reset by new command)
{IF: 'TX_ERR', GOTO:'ERR:Fatal'}, # 1. dx_err[1] (reset by new command)
{ GOTO:'DX:UpdateByteCount'}, # 3. (#2 - skipped PxFBS.EN==1)
{LBL:'DX:UpdateByteCount', ACT: 'DECR_DWC'}, # decr_dwc - decrement remaining DWORDS count, increment transferred
{ ACT: 'UPDATE_PRDBC'}, # update_prdbc
{IF: 'DMA_PRD_IRQ_PEND', GOTO:'DX:PrdSetIntr'}, # 1. dma_prd_irq_pend
{IF: 'PIOX', GOTO:'PIO:Update'}, # 2. pPioXfer
{ GOTO:'P:Idle'}, # 4.
{LBL:'DX:PrdSetIntr', ACT: 'SIRQ_DP'}, # sirq_DP (if any PRD for this FIS requested PRD interrupt)
{ ACT: 'DMA_PRD_IRQ_CLEAR'}, # dma_prd_irq_clear
#DX:PrdSetIS, DX:PrdGenIntr skipped as they are handled at lower level
{IF: 'PIOX', GOTO:'PIO:Update'}, # 2. pPioXfer (#1 ->DX:PrdSetIS is handled by hardware)
{ GOTO:'P:Idle'}, # 4.
# 5.3.11 Data Receive States
{LBL:'DR:Entry', ACT: 'DMA_PRD_IRQ_CLEAR'}, # dma_prd_irq_clear
{ GOTO:'DR:Receive'},
{LBL:'DR:Receive', ACT: 'GET_DATA_FIS*'}, # get_data_fis
{IF: 'FIS_ERR', GOTO:'ERR:Fatal'}, # 3. fis_err - checking for errors first to give some time for fis_extra
# to reveal itself from the ahci_dma module (ahci_fis_receive does not need it)
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 3a. fis_ferr
{IF: 'FIS_EXTRA', GOTO:'ERR:Non-Fatal'}, # 1. fis_extra
{ GOTO:'DR:UpdateByteCount'}, # 2. fis_ok implied
{LBL:'DR:UpdateByteCount', ACT: 'R_OK'}, # send_R_OK to device
{ ACT: 'DECR_DWC'}, # decr_dwc - decrement remaining DWORDS count, increment transferred
{ ACT: 'UPDATE_PRDBC'}, # update_prdbc
{IF: 'DMA_PRD_IRQ_PEND', GOTO:'DX:PrdSetIntr'}, # 1. dma_prd_irq_pend
{IF: 'PIOX', GOTO:'PIO:Update'}, # 2. pPioXfer (#1 ->DX:PrdSetIS is handled by hardware)
{ GOTO:'P:Idle'}, # 4.
# 5.3.12 DMA Setup Receive States
{LBL:'DmaSet:Entry', ACT: 'GET_DSFIS*'}, # get_dsfis
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'DmaSet:Accept'}, #
{LBL:'DmaSet:Accept', ACT: 'R_OK'}, # send R_OK
{IF: 'FIS_I', GOTO:'DmaSet:SetIntr'}, # 1. fis_i
{ GOTO:'DmaSet:AutoActivate'}, # 2.
{LBL:'DmaSet:SetIntr', ACT: 'SIRQ_DS'}, # sirq_DS DMA Setup FIS received with 'I' bit set
{ GOTO:'DmaSet:AutoActivate'}, # 2. (interrupt is handled by hardware)
#DmaSet:SetIS, DmaSet:GenIntr skipped as they are handled at lower level
{LBL:'DmaSet:AutoActivate', ACT: 'NOP'}, #
{IF: 'CHW_DMAA', GOTO:'DmaSet:SetIntr'}, # 1. ch_w && dma_a
{ GOTO:'P:Idle' }, # 3.
#5.3.13 Set Device Bits States
{LBL:'SDB:Entry', ACT: 'GET_SDBFIS*'}, # get_sdbfis Is in only for Native CC ?
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'SDB:Accept' }, # 3.
{LBL:'SDB:Accept', ACT: 'R_OK'}, # get_sdbfis Is in only for Native CC ?
{ ACT: 'UPDATE_ERR_STS'}, # update_err_sts
{IF: 'TFD_STS_ERR', GOTO:'ERR:FatalTaskfile'}, # 1. tfd_sts[0]
{IF: 'FIS_I', GOTO:'SDB:SetIntr'}, # 3. fis_i
{ GOTO:'PM:Aggr' }, # 4.
{LBL:'SDB:SetIntr', ACT: 'SIRQ_SDB'}, # sirq_SDB
{ GOTO:'PM:Aggr' }, # 5.
#5.3.14 Unknown FIS Receive States
{LBL:'UFIS:Entry', ACT: 'GET_UFIS*'}, # get_ufis
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'UFIS:Accept' }, #
{LBL:'UFIS:Accept', ACT: 'R_OK'}, # get_ufis
{ ACT: 'SIRQ_UF'}, # sirq_UF
{ GOTO:'P:Idle' }, # 1. (IRQ states are handled)
#UFIS:SetIS, UFIS:GenIntr are handled by hardware, skipping
#5.3.15 BIST States
{LBL:'BIST:FarEndLoopback', ACT: 'GET_IGNORE*'}, # get_ignore
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'BIST:FarEndLoopbackAccept'}, # 1. (IRQ states are handled)
{LBL:'BIST:FarEndLoopbackAccept', ACT: 'R_OK'}, # send R_OK
{ ACT: 'SSTS_DET_OFFLINE'}, # ssts_det_offline
{ GOTO:'BIST:TestLoop'}, # 1.
{LBL:'BIST:TestOngoing', ACT: 'GET_IGNORE*'}, # get_ignore
{IF: 'FIS_ERR', GOTO:'ERR:Non-Fatal'}, # 1. fis_err
{IF: 'FIS_FERR', GOTO:'ERR:Fatal'}, # 2. fis_ferr
{ GOTO:'BIST:TestLoopAccept'}, #
{LBL:'BIST:TestLoopAccept', ACT: 'R_OK'}, #
{ GOTO:'BIST:TestLoop'}, #
{LBL:'BIST:TestLoop', ACT: 'NOP'}, #
{ GOTO:'BIST:TestLoop'}, #
#5.3.16 Error States
{LBL:'ERR:SyncEscapeRecv', ACT: 'CLEAR_BSY_DRQ'}, # clear_bsy_drq
{ ACT: 'SIRQ_IF'}, # sirq_IF
{ GOTO:'ERR:WaitForClear' },
{LBL:'ERR:Fatal', ACT: 'R_ERR'}, # Send R_ERR to device
{ ACT: 'SIRQ_IF'}, # sirq_IF
{ GOTO:'ERR:WaitForClear' },
{LBL:'ERR:FatalTaskfile', ACT: 'SIRQ_TFE'}, # sirq_TFE
{ GOTO:'ERR:WaitForClear' },
{LBL:'ERR:WaitForClear', ACT: 'NOP'}, #
{ GOTO:'ERR:WaitForClear' }, # Loop until PxCMD.ST is cleared by software
{LBL:'ERR:Non-Fatal', ACT: 'NOP'}, # Do anything else here?
{ GOTO:'P:Idle'}, #
]
def get_cnk (start,end,level):
result = []
for i in range (start,end+1-level):
if level == 1:
result.append([i])
else:
l = get_cnk(i+1, end,level - 1)
for r in l:
result.append ([i]+r)
return result
def bin_cnk (n,k):
bits = get_cnk (0, n, k)
result = []
for l in bits:
d=0
for b in l:
d |= (1 << b)
result.append(d)
return result
def condition_mux_verilog(conditions, condition_vals, module_name, fanout, file=None):
header_template="""/*******************************************************************************
* Module: %s
* Date:%s
* Author: auto-generated file, see %s
* Description: Select condition
*******************************************************************************/
"""
output reg pio_i, // value of "I" field in received PIO Setup FIS
output reg pio_d, // value of "D" field in received PIO Setup FIS
output [7:0] pio_es, // value of PIO E_Status
`timescale 1ns/1ps
sirq_DHR
fis_i
update_prdbc, // update PRDBC in registers
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
module %s (
input clk,
input [%2d:0] sel,
output condition,"""
v=max(condition_vals.values())
num_inputs = 0;
while v:
num_inputs += 1
v >>= 1
maximal_length = max([len(n) for n in conditions])
numregs = (len(conditions) + fanout - 1) // fanout
header = header_template%(module_name, datetime.date.today().isoformat(), os.path.basename(__file__), module_name, num_inputs-1)
print(header,file=file)
for input_name in conditions[:len(conditions)-1]:
print(" input %s,"%(input_name),file=file)
print(" input %s);\n"%(conditions[-1]),file=file)
print(" wire [%2d:0] masked;"%(len(conditions)-1),file=file)
if numregs > 1:
print(" reg [%2d:0] cond_r;\n"%(numregs-1),file=file)
else:
print(" reg cond_r;\n",file=file)
if numregs > 1:
print(" assign condition = |cond_r;\n",file=file)
else:
print(" assign condition = cond_r;\n",file=file)
{LBL:'P:RegFisUpdate', ACT: 'GET_SIG'}, # update_sig
for b in range (len(conditions)):
print(" assign masked[%2d] = %s %s"%(b, conditions[b] , " "*(maximal_length - len(conditions[b]))),end="",file=file)
d = condition_vals[conditions[b]]
for nb in range(num_inputs-1,-1,-1):
if d & (1 << nb):
print (" && sel[%2d]"%(nb), end="", file=file)
print (";", file=file)
print ("\n always @(posedge clk) begin", file=file)
for nb in range (numregs):
ll = nb * fanout
hl = min(ll + fanout, len(conditions)) -1
if numregs > 1:
print (" cond_r[%2d] <= "%(nb), end="", file=file)
else:
print (" cond_r <= ", end="", file=file)
if hl > ll:
print ("|masked[%2d:%2d];"%(hl,ll), file=file)
else:
print (" masked[%2d];"%(ll), file=file)
print (" end", file=file)
print("endmodule",file=file)
input [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command)
{IF: 'CTBAA_CTBAP', ACT:'CFIS:PrefetchACMD'},#1. ch_a && ch_p # Note ch_p may be ignored or transition may be ignored
{IF: 'CTBAP', ACT:'CFIS:PrefetchPRD'}, #2. ch_p # Note ch_p may be ignored or transition may be ignored
def action_decoder_verilog(actions, action_vals, module_name, file=None):
header_template="""/*******************************************************************************
* Module: %s
* Date:%s
* Author: auto-generated file, see %s
* Description: Decode sequencer code to 1-hot actions
*******************************************************************************/
`timescale 1ns/1ps
input ch_c, // Clear busy upon R_OK for this FIS
input ch_b, // Built-in self test command
input ch_r, // reset - may need to send SYNC escape before this command
input ch_p, // prefetchable - only used with non-zero PRDTL or ATAPI bit set
input ch_w, // Write: system memory -> device
input ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command
input [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal,
module %s (
input clk,
input enable,
input [%2d:0] data,"""
v=max(action_vals.values())
num_inputs = 0;
while v:
num_inputs += 1
v >>= 1
names= []
for a in actions[1:]:
if a.endswith("*"):
names.append(a[0:-1])
else:
names.append(a)
maximal_length = max([len(n) for n in names])
header = header_template%(module_name, datetime.date.today().isoformat(), os.path.basename(__file__), module_name, num_inputs-1)
print(header,file=file)
for output_name in names[:len(names)-1]:
print(" output reg %s,"%(output_name),file=file)
print(" output reg %s);\n"%(names[-1]),file=file)
print (" always @(posedge clk) begin", file=file)
for i, name in enumerate(names): # i is one less than action_vals index
d = action_vals[actions[i+1]]
print(" %s"%(name + " <= "+(" "*(maximal_length-len(name)))), end="", file=file)
print ("enable", end="", file=file)
for nb in range(num_inputs-1,-1,-1):
if d & (1 << nb):
print (" && data[%2d]"%(nb), end="", file=file)
print (";", file=file)
print (" end", file=file)
print("endmodule",file=file)
#print (sequence)
ln = 0
while ln < len(sequence):
if ADDR in sequence[ln]:
while ln < sequence[ln][ADDR]:
sequence.insert(ln,{})
ln += 1
if sequence[ln][ADDR] < ln:
print ("Can not place '%s' at line # %d, it is already %d"%(sequence[ln],sequence[ln][ADDR],ln))
ln += 1
fis_ok
syncesc_recv
x_rdy_collision_pend
input cfis_xmit, // transmit command (wait for dma_ct_busy == 0)
labels = {}
jumps = set()
for ln, line in enumerate(sequence):
if LBL in line:
label=line[LBL]
if label in labels:
print ("Duplicate label '%s': line #%d and line # %d"%(label, labels[label], ln))
else:
labels[label]=ln
if GOTO in line:
jumps.add(line[GOTO])
input syncesc_send_done, // "SYNC escape until the interface is quiescent..."
#Using lists, not sets to preserve order
sort_actions = False
sort_conditions = False
if not actions:
sort_actions = True
for ln, line in enumerate(sequence):
if ACT in line:
if not line[ACT] in actions:
actions.append(line[ACT])
if not conditions:
sort_conditions = True
for ln, line in enumerate(sequence):
if IF in line:
if not line[IF] in conditions:
conditions.append(line[IF])
set_update_sig
bist_bits (use get_ignore to read in BIST FIS)
get_ignore
output send_R_OK, // Should it be originated in this layer SM?
output send_R_ERR,
print ("Checking for undefined labels:")
undef_jumps = []
for label in jumps:
if not label in labels:
undef_jumps.append(label)
if undef_jumps:
print ("Undefined jumps:")
for i,jump in enumerate(undef_jumps):
print("%d: '%s'"%(i,jump))
else:
print ("All jumps are to defined labels")
print ("Checking for unused labels:")
unused_labels = []
for label in labels:
if not label in jumps:
unused_labels.append(label)
if unused_labels:
print ("Unused labels:")
for i,label in enumerate(unused_labels):
print("%d: '%s'"%(i,label))
else:
print ("All labels are used")
wait_actions=[]
fast_actions=[]
for a in actions:
if a.endswith("*"):
# wait_actions.append(a[:len(a)-1])
wait_actions.append(a)
else:
fast_actions.append(a)
if sort_actions:
wait_actions.sort()
fast_actions.sort()
if 'NOP' in fast_actions:
nop = fast_actions.pop(fast_actions.index('NOP'))
fast_actions = [nop]+fast_actions
actions = fast_actions + wait_actions
if sort_conditions:
conditions.sort()
#Assign values to actions
action_vals={}
vals = bin_cnk (*actions_cnk)
for i, v in enumerate (actions):
action_vals[v]= vals[i]
#Assign values to conditions
condition_vals={}
vals = bin_cnk (*conditions_cnk)
for i, v in enumerate (conditions):
condition_vals[v]= vals[i]
print ("Number of lines : %d"%(len(sequence)))
print ("Number of labels : %d"%(len(labels)))
print ("Number of actions : %d"%(len(actions)))
print ("Number of conditions : %d"%(len(conditions)))
#print ("\nActions:")
#for i,a in enumerate(actions):
# print ("%02d: %s"%(i,a))
print ("\nActions that do not wait for done (%d):"%(len(fast_actions)))
for i,a in enumerate(fast_actions):
# print ("%02d: %s"%(i,a))
print ("%s"%(a))
print ("\nActions that wait for done (%d):"%(len(wait_actions)))
for i,a in enumerate(wait_actions):
# print ("%02d: %s"%(i,a))
print ("%s"%(a))
input fis_ok, // FIS done, checksum OK reset by starting a new get FIS
input fis_err, // FIS done, checksum ERROR reset by starting a new get FIS
input fis_ferr, // FIS done, fatal error - FIS too long
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
print ("\nConditions(%d):"%(len(conditions)))
for i,c in enumerate(conditions):
# print ("%02d: %s"%(i,c))
print ("%s"%(c))
input fis_first_vld, // fis_first contains valid FIS header, reset by 'get_*'
input [7:0] fis_type, // FIS type (low byte in the first FIS DWORD), valid with 'fis_first_vld'
print ("action_vals=", action_vals)
print ("condition_vals=",condition_vals)
pcmd_cr_set, // command list run set
clear_xfer_cntr
pcmd_cr_reset
frcv_clear_xfer_cntr
dma_cmd_abort
input fis_first_vld, // fis_first contains valid FIS header, reset by 'get_*'
input [7:0] fis_type, // FIS type (low byte in the first FIS DWORD), valid with 'fis_first_vld'
#for i, line in enumerate(sequence):
# print ("%03x: %s"%(i,line))
serr_diag_X ==0 , fis_first_vld,
(pIssueSlot==32) is the same as (pxci0 == 0), use pxci0_clear (pIssueSlot:=32)
localparam LABEL_POR = 11'h0;
localparam LABEL_HBA_RST = 11'h10;
localparam LABEL_PORT_RST = 11'h20;
if not action_decoder_verilog_path:
action_decoder_verilog(actions, action_vals, action_decoder_module_name)
else:
with open(os.path.abspath(os.path.join(os.path.dirname(__file__), action_decoder_verilog_path)),"w") as out_file:
action_decoder_verilog(actions, action_vals, action_decoder_module_name, out_file)
print ("AHCI FSM actions decoder is written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), action_decoder_verilog_path))))
if not condition_mux_verilog_path:
condition_mux_verilog(conditions, condition_vals, condition_mux_module_name, condition_mux_fanout)
else:
with open(os.path.abspath(os.path.join(os.path.dirname(__file__), condition_mux_verilog_path)),"w") as out_file:
condition_mux_verilog(conditions, condition_vals,condition_mux_module_name, condition_mux_fanout, out_file)
print ("AHCI FSM conditions multiplexer is written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), condition_mux_verilog_path))))
"""
\ No newline at end of file
#condition_mux_verilog(conditions, condition_vals, 'condition_mux',100, file=None)
\ No newline at end of file
......@@ -722,7 +722,7 @@ begin
HOST_LINK_TITLE = "From device - received data";
HOST_LINK_DATA = data_out;
$display("[Host] LINK: %s = %h @%t", HOST_LINK_TITLE, HOST_LINK_DATA, $time);
`endif
//`endif
end
......
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