Commit 80f4866b authored by Andrey Filippov's avatar Andrey Filippov

continue on ahci_fis_transmit.v

parent f81326a9
...@@ -46,6 +46,7 @@ module ahci_dma ( ...@@ -46,6 +46,7 @@ module ahci_dma (
input [15:0] prdtl, // number of entries in PRD table (valid at cmd_start) input [15:0] prdtl, // number of entries in PRD table (valid at cmd_start)
input dev_wr, // write to device (valid at start) input dev_wr, // write to device (valid at start)
input cmd_start, // start processing command table, reset prdbc input cmd_start, // start processing command table, reset prdbc
input prd_start, // at or after cmd_start - enable reading PRD/data (if any)
input cmd_abort, // try to abort a command TODO: Implement input cmd_abort, // try to abort a command TODO: Implement
// Optional control of the AXI cache mode, default will be set to 4'h3, 4'h3 at mrst // Optional control of the AXI cache mode, default will be set to 4'h3, 4'h3 at mrst
...@@ -145,9 +146,16 @@ module ahci_dma ( ...@@ -145,9 +146,16 @@ module ahci_dma (
reg [31:7] ctba_r; reg [31:7] ctba_r;
reg [15:0] prdtl_mclk; reg [15:0] prdtl_mclk;
wire cmd_start_hclk; wire cmd_start_hclk;
reg prd_start_r;
wire prd_start_hclk;
reg prd_start_hclk_r; // to make sure it is with/after prd_start_hclk if in mclk they are in the same cycle
wire cmd_abort_hclk; // TODO: Implement as graceful as possible command abort wire cmd_abort_hclk; // TODO: Implement as graceful as possible command abort
reg prd_enabled;
reg [1:0] ct_over_prd_enabled; // prd read and data r/w enabled, command table fetch done
reg [31:4] ct_maddr; // granularity matches PRDT entry - 4xDWORD, 2xQWORD reg [31:4] ct_maddr; // granularity matches PRDT entry - 4xDWORD, 2xQWORD
wire ct_done; wire ct_done;
wire first_prd_fetch; // CT read done, prd enabled
reg [31:0] afi_addr; // common for afi_araddr and afi_awaddr reg [31:0] afi_addr; // common for afi_araddr and afi_awaddr
wire axi_set_raddr_ready = !(|afi_racount[2:1]) && (!axi_set_raddr_r || !afi_racount[0]); // What is the size of ra fifo - just 4? Latency? wire axi_set_raddr_ready = !(|afi_racount[2:1]) && (!axi_set_raddr_r || !afi_racount[0]); // What is the size of ra fifo - just 4? Latency?
// wire axi_set_raddr_ready = !(|afi_racount) && !axi_set_raddr_r); // Most pessimistic // wire axi_set_raddr_ready = !(|afi_racount) && !axi_set_raddr_r); // Most pessimistic
...@@ -198,7 +206,9 @@ module ahci_dma ( ...@@ -198,7 +206,9 @@ module ahci_dma (
reg data_next_burst; reg data_next_burst;
wire raddr_prd_rq = (|prds_left) && (ct_done || prd_done); // wire raddr_prd_rq = (|prds_left) && (ct_done || prd_done);
wire raddr_prd_rq = (|prds_left) && (first_prd_fetch || prd_done);
reg raddr_prd_pend; reg raddr_prd_pend;
wire raddr_ct_rq = cmd_start_hclk; wire raddr_ct_rq = cmd_start_hclk;
...@@ -222,6 +232,7 @@ module ahci_dma ( ...@@ -222,6 +232,7 @@ module ahci_dma (
assign prd_irq = data_irq && prd_done; assign prd_irq = data_irq && prd_done;
assign cmd_done_hclk = ((ct_busy_r==2'b10) && (prdtl_mclk == 0)) || done_flush || 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 ct_done = (ct_busy_r == 2'b10);
assign first_prd_fetch = ct_over_prd_enabled == 2'b01;
assign axi_set_raddr_w = axi_set_raddr_ready && (raddr_ct_pend || raddr_prd_pend || raddr_data_pend); assign axi_set_raddr_w = axi_set_raddr_ready && (raddr_ct_pend || raddr_prd_pend || raddr_data_pend);
assign axi_set_waddr_w = axi_set_raddr_ready && raddr_data_pend; assign axi_set_waddr_w = axi_set_raddr_ready && raddr_data_pend;
assign axi_set_addr_data_w = (axi_set_raddr_ready && raddr_data_pend) || (axi_set_waddr_ready && waddr_data_pend); assign axi_set_addr_data_w = (axi_set_raddr_ready && raddr_data_pend) || (axi_set_waddr_ready && waddr_data_pend);
...@@ -278,12 +289,21 @@ module ahci_dma ( ...@@ -278,12 +289,21 @@ module ahci_dma (
if (mrst) afi_awcache <= 4'h3; if (mrst) afi_awcache <= 4'h3;
else if (set_axi_wr_cache_mode) afi_awcache <= axi_wr_cache_mode; else if (set_axi_wr_cache_mode) afi_awcache <= axi_wr_cache_mode;
prd_start_r <= prd_start;
end end
always @ (posedge hclk) begin always @ (posedge hclk) begin
prd_start_hclk_r <= prd_start_hclk;
if (hrst || cmd_abort_hclk) prd_enabled <= 0;
else if (prd_start_hclk_r) prd_enabled <= 1; // presedence over cmd_start_hclk
else if (cmd_start_hclk) prd_enabled <= 0;
if (cmd_start_hclk) ct_maddr[31:4] <= {ctba_r[31:7],3'b0}; if (cmd_start_hclk) ct_maddr[31:4] <= {ctba_r[31:7],3'b0};
else if (ct_done) ct_maddr[31:4] <= ct_maddr[31:4] + 16; else if (ct_done) ct_maddr[31:4] <= ct_maddr[31:4] + 16;
else if (wcount_set) ct_maddr[31:4] <= ct_maddr[31:4] + 1; else if (wcount_set) ct_maddr[31:4] <= ct_maddr[31:4] + 1;
...@@ -364,6 +384,10 @@ module ahci_dma ( ...@@ -364,6 +384,10 @@ module ahci_dma (
else if (afi_rd_ctl[0] && is_ct_addr && (&int_data_addr)) ct_busy_r[0] <= 0; else if (afi_rd_ctl[0] && is_ct_addr && (&int_data_addr)) ct_busy_r[0] <= 0;
ct_busy_r[1] <= ct_busy_r[0]; // delayed version to detect end of command ct_busy_r[1] <= ct_busy_r[0]; // delayed version to detect end of command
if (hrst || ct_busy_r[0]) ct_over_prd_enabled[0] <= 0;
else if (prd_enabled) ct_over_prd_enabled[0] <= 1;
ct_over_prd_enabled[1] <= ct_over_prd_enabled[0]; // detecting 0->1 transition
// generate busy for PRD table entry read // generate busy for PRD table entry read
if (hrst) prd_rd_busy <= 0; if (hrst) prd_rd_busy <= 0;
else if (prd_rd_busy) prd_rd_busy <= 1; else if (prd_rd_busy) prd_rd_busy <= 1;
...@@ -475,6 +499,18 @@ module ahci_dma ( ...@@ -475,6 +499,18 @@ module ahci_dma (
.out_pulse (cmd_abort_hclk), // output .out_pulse (cmd_abort_hclk), // output
.busy() // output .busy() // output
); );
pulse_cross_clock #(
.EXTRA_DLY(0)
) prd_start_hclk_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (prd_start_r), // input
.out_pulse (prd_start_hclk), // output
.busy() // output
);
// hclk -> mclk; // hclk -> mclk;
pulse_cross_clock #( pulse_cross_clock #(
......
...@@ -45,7 +45,7 @@ module ahci_dma_rd_stuff( ...@@ -45,7 +45,7 @@ module ahci_dma_rd_stuff(
output reg flushed, // flush (end of last PRD is finished - data left module) output reg flushed, // flush (end of last PRD is finished - data left module)
output reg [31:0] dout, // output 32-bit data output reg [31:0] dout, // output 32-bit data
output dout_vld, // output data valid output dout_vld, // output data valid
input dout_re // consumer reads output data (should be anded with dout_vld) input dout_re // consumer reads output data (should be AND-ed with dout_vld)
); );
reg [15:0] hr; // holds 16-bit data from previous din_re if not consumed reg [15:0] hr; // holds 16-bit data from previous din_re if not consumed
reg hr_full; reg hr_full;
......
...@@ -49,11 +49,17 @@ module ahci_fis_receive#( ...@@ -49,11 +49,17 @@ module ahci_fis_receive#(
output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS
output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS
output fis_ferr, // FIS done, fatal error - FIS too long output fis_ferr, // FIS done, fatal error - FIS too long
// next commands use register address/data/we for 1 clock cycle - after next to command (commnd - t0, we - t2)
input update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h input update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h
input update_prdbc, // update PRDBC in registers
input clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update input clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update
input set_bsy, // set PxTFD.STS.BSY, update input set_bsy, // set PxTFD.STS.BSY, update
input set_sts_7f, // set PxTFD.STS = 0x7f, update input set_sts_7f, // set PxTFD.STS = 0x7f, update
input set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update input set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update
input decr_dwc, // decrement DMA Xfer counter // need pulse to 'update_prdbc' to write to registers
input [11:2] decr_DXC_dw, // decrement value (in DWORDs)
// TODO: Add writing PRDBC here? // TODO: Add writing PRDBC here?
output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields)
...@@ -66,7 +72,9 @@ module ahci_fis_receive#( ...@@ -66,7 +72,9 @@ module ahci_fis_receive#(
output reg pio_i, // value of "I" field in received PIO 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 reg pio_d, // value of "D" field in received PIO Setup FIS
output reg [7:0] pio_es, // value of PIO E_Status output reg [7:0] pio_es, // value of PIO E_Status
output reg [31:1] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits) // 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
// Registers interface // Registers interface
// 2. HBA R/W registers, may be added external register layer // 2. HBA R/W registers, may be added external register layer
...@@ -96,6 +104,7 @@ FB_OFFS = 0xc00 # Needs 0x100 bytes ...@@ -96,6 +104,7 @@ FB_OFFS = 0xc00 # Needs 0x100 bytes
*/ */
localparam CLB_OFFS32 = 'h200; // # In the second half of the register space (0x800..0xbff - 1KB)
localparam HBA_OFFS32 = 0; localparam HBA_OFFS32 = 0;
localparam HBA_PORT0_OFFS32 = 'h40; localparam HBA_PORT0_OFFS32 = 'h40;
localparam PXSIG_OFFS32 = HBA_OFFS32 + HBA_PORT0_OFFS32 + 'h9; localparam PXSIG_OFFS32 = HBA_OFFS32 + HBA_PORT0_OFFS32 + 'h9;
...@@ -153,10 +162,13 @@ localparam DATA_TYPE_ERR = 3; ...@@ -153,10 +162,13 @@ localparam DATA_TYPE_ERR = 3;
reg [4:0] reg_ps; reg [4:0] reg_ps;
reg reg_d2h; reg reg_d2h;
reg reg_sdb; reg reg_sdb;
reg [31:2] xfer_cntr_r;
reg [31:2] prdbc_r;
reg [15:0] tf_err_sts; reg [15:0] tf_err_sts;
reg update_err_sts_r; reg update_err_sts_r;
reg update_prdbc_r;
// Forward data to DMA (dev->mem) engine // Forward data to DMA (dev->mem) engine
assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err; assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err;
...@@ -172,6 +184,9 @@ localparam DATA_TYPE_ERR = 3; ...@@ -172,6 +184,9 @@ localparam DATA_TYPE_ERR = 3;
assign tfd_sts = tf_err_sts[ 7:0]; assign tfd_sts = tf_err_sts[ 7:0];
assign tfd_err = tf_err_sts[15:8]; assign tfd_err = tf_err_sts[15:8];
assign xfer_cntr = xfer_cntr_r[31:2];
always @ (posedge mclk) begin always @ (posedge mclk) begin
if (hba_rst || dma_in_stop) dma_in <= 0; if (hba_rst || dma_in_stop) dma_in <= 0;
...@@ -248,20 +263,23 @@ localparam DATA_TYPE_ERR = 3; ...@@ -248,20 +263,23 @@ localparam DATA_TYPE_ERR = 3;
if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8]; if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8];
else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0]; else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0];
else if (update_err_sts_r) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]}; else if (update_err_sts_r) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]};
else if (update_prdbc_r) reg_data[31:8] <= {xfer_cntr_r[31:8]};
if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0]; if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0];
else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0]; else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0];
else if (update_err_sts_r) reg_data[ 7:0] <= tf_err_sts [ 7:0]; else if (update_err_sts_r) reg_data[ 7:0] <= tf_err_sts [ 7:0];
else if (update_prdbc_r) reg_data[ 7:0] <= {xfer_cntr_r[ 7:2],2'b0};
if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0]; if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0];
else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]}; else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]};
else if (clear_bsy_drq || set_bsy) tf_err_sts <= tf_err_sts & {8'hff,clear_bsy_drq,3'h7,clear_bsy_drq,3'h7} | {8'h0,set_bsy,7'h0}; else if (clear_bsy_drq || set_bsy) tf_err_sts <= tf_err_sts & {8'hff,clear_bsy_drq,3'h7,clear_bsy_drq,3'h7} | {8'h0,set_bsy,7'h0};
else if (set_sts_7f || set_sts_80) tf_err_sts <= {tf_err_sts[15:8],set_sts_80,{7{set_sts_7f}}} ; else if (set_sts_7f || set_sts_80) tf_err_sts <= {tf_err_sts[15:8],set_sts_80,{7{set_sts_7f}}} ;
reg_we <= reg_we_w || update_sig[3] || update_err_sts_r; reg_we <= reg_we_w || update_sig[3] || update_err_sts_r || update_prdbc_r;
if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r; if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r;
else if (update_err_sts_r) reg_addr <= PXTFD_OFFS32; else if (update_err_sts_r) reg_addr <= PXTFD_OFFS32;
else if (update_prdbc_r) reg_addr <= CLB_OFFS32 + 1; // location of PRDBC
if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14]; if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14];
if (reg_sdb) sdb_n <= hda_data_in[15]; if (reg_sdb) sdb_n <= hda_data_in[15];
...@@ -272,9 +290,19 @@ localparam DATA_TYPE_ERR = 3; ...@@ -272,9 +290,19 @@ localparam DATA_TYPE_ERR = 3;
if (hba_rst) pio_es <= 0; if (hba_rst) pio_es <= 0;
else if (reg_ps[3]) pio_es <= hda_data_in[31:24]; else if (reg_ps[3]) pio_es <= hda_data_in[31:24];
if (reg_ps[4] || reg_ds[5]) xfer_cntr[31:1] <= {reg_ds[5]?hda_data_in[31:16]:16'b0,hda_data_in[15:1]}; if (hba_rst || reg_sdb) xfer_cntr_r[31:2] <= 0;
else if (reg_ps[4] || reg_ds[5]) xfer_cntr_r[31:2] <= {reg_ds[5]?hda_data_in[31:16]:16'b0, hda_data_in[15:2]} + hda_data_in[1]; // round up
else if (decr_dwc) xfer_cntr_r[31:2] <= {xfer_cntr_r[31:2]} - {20'b0, decr_DXC_dw[11:2]};
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]} + {20'b0, decr_DXC_dw[11:2]};
xfer_cntr_zero <= xfer_cntr_r[31:2] == 0;
update_err_sts_r <= update_err_sts || clear_bsy_drq || set_bsy || set_sts_7f || set_sts_80; update_err_sts_r <= update_err_sts || clear_bsy_drq || set_bsy || set_sts_7f || set_sts_80;
update_prdbc_r <= update_prdbc; // same latency as update_err_sts
end end
......
This diff is collapsed.
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