Commit 48218bac authored by Andrey Filippov's avatar Andrey Filippov

Started ahci_ctrl_stat.v - module that maintains local hba registers and...

Started ahci_ctrl_stat.v - module that maintains local hba registers and updates their values to the software accissible ones
parent effd0f51
/*******************************************************************************
* Module: ahci_ctrl_stat
* Date:2016-01-12
* Author: andrey
* Description: Copy of significant register fields, updating them in
* axi_ahci_regs registers (software accessible)
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_ctrl_stat.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ahci_ctrl_stat.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module ahci_ctrl_stat #(
// parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle)
)(
input mrst, // @posedge mclk, generated by phy
input mclk, // for command/status
input was_hba_rst, // last reset was hba reset (not counting system reset)
input was_port_rst, // last reset was port reset(not counting system reset)
// notification from axi_ahci_regs that software has written data to register
input [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software
input [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1)
input soft_write_en, // write enable for data write
// input soft_arst, // reset SATA PHY not relying on SATA clock
// R/W access to AXI/AHCI registers, shared with ahci_fis_receive and ahci_fis_transmit modules
output reg [ADDRESS_BITS-1:0] regs_addr,
output reg regs_we,
// output [3:0] regs_wstb, Needed?
// output [1:0] regs_re, // [0] - re, [1] - regen
output reg [31:0] regs_din,
// input [31:0] regs_dout,
// update register inputs (will write to register memory current value of the corresponding register)
input update_GHC__IS,
input update_HBA_PORT__PxIS,
// Interrupt inputs
input sirq_TFE, // RWC: Task File Error Status
input sirq_IF, // RWC: Interface Fatal Error Status (sect. 6.1.2)
input sirq_INF, // RWC: Interface Non-Fatal Error Status (sect. 6.1.2)
input sirq_OF, // RWC: Overflow Status
input sirq_PRC, // RO: PhyRdy changed Status
input sirq_UF, // RO: Unknown FIS
input sirq_SDB, // RWC: Set Device Bits Interrupt - Set Device bits FIS with 'I' bit set
input sirq_DS, // RWC: DMA Setup FIS Interrupt - DMA Setup FIS received with 'I' bit set
input sirq_PS, // RWC: PIO Setup FIS Interrupt - PIO Setup FIS received with 'I' bit set
input sirq_DHR, // RWC: D2H Register FIS Interrupt - D2H Register FIS received with 'I' bit set
/*
*/
output reg irq
// Many I/Os to add
);
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
wire swr_GHC__IE = soft_write_en && (soft_write_addr == GHC__GHC__IE__ADDR);
wire swr_GHC__IS = soft_write_en && (soft_write_addr == GHC__IS__IPS__ADDR);
wire swr_HBA_PORT__PxCMD = soft_write_en && (soft_write_addr == HBA_PORT__PxCMD__ST__ADDR);
wire swr_HBA_PORT__PxIS = soft_write_en && (soft_write_addr == HBA_PORT__PxIS__CPDS__ADDR);
wire swr_HBA_PORT__PxIE = soft_write_en && (soft_write_addr == HBA_PORT__PxIE__CPDE__ADDR);
wire swr_HBA_PORT__PxSCTL = soft_write_en && (soft_write_addr == HBA_PORT__PxSCTL__SPD__ADDR);
wire swr_HBA_PORT__PxSSTS = soft_write_en && (soft_write_addr == HBA_PORT__PxSSTS__SPD__ADDR);
wire swr_HBA_PORT__PxSERR = soft_write_en && (soft_write_addr == HBA_PORT__PxSERR__DIAG__X__ADDR);
wire swr_HBA_PORT__PxCI = soft_write_en && (soft_write_addr == HBA_PORT__PxCI__CI__DFLT);
reg hba_rst_r = 1;
reg rst_por;
reg rst_hba;
reg rst_port;
reg ghc_ie_r;
reg ghc_is_r;
reg set_ghc_is_r; // active next cycle after one of individual non-masked bits in PxIS is set
reg [31:0] PxIE_r; // some bits will be unused by PxIS_MASK
reg [31:0] PxIS_r; // some bits will be unused by PxIS_MASK
wire [31:0] sirq = {32{sirq_TFE}} & HBA_PORT__PxIS__TFES__MASK | // 'h40000000;
{32{sirq_IF }} & HBA_PORT__PxIS__IFS__MASK | // 'h8000000;
{32{sirq_INF}} & HBA_PORT__PxIS__INFS__MASK | // 'h4000000;
{32{sirq_OF }} & HBA_PORT__PxIS__OFS__MASK | // 'h1000000;
{32{sirq_PRC}} & HBA_PORT__PxIS__PRCS__MASK | // 'h400000;
{32{sirq_UF }} & HBA_PORT__PxIS__UFS__MASK | // 'h10;
{32{sirq_SDB}} & HBA_PORT__PxIS__SDBS__MASK | // 'h8;
{32{sirq_DS }} & HBA_PORT__PxIS__DSS__MASK | // 'h4;
{32{sirq_PS }} & HBA_PORT__PxIS__PSS__MASK | // 'h2;
{32{sirq_DHR}} & HBA_PORT__PxIS__DHRS__MASK; // 'h1;
localparam PxIE_MASK = HBA_PORT__PxIE__TFEE__MASK | // 'h40000000;
HBA_PORT__PxIE__IFE__MASK | // 'h8000000;
HBA_PORT__PxIE__INFE__MASK | // 'h4000000;
HBA_PORT__PxIE__OFE__MASK | // 'h1000000;
HBA_PORT__PxIE__PRCE__MASK | // 'h400000;
HBA_PORT__PxIE__UFE__MASK | // 'h10;
HBA_PORT__PxIE__SDBE__MASK | // 'h8;
HBA_PORT__PxIE__DSE__MASK | // 'h4;
HBA_PORT__PxIE__PSE__MASK | // 'h2;
HBA_PORT__PxIE__DHRE__MASK; // 'h1;
localparam PxIS_MASK = HBA_PORT__PxIS__TFES__MASK | // 'h40000000;
HBA_PORT__PxIS__IFS__MASK | // 'h8000000;
HBA_PORT__PxIS__INFS__MASK | // 'h4000000;
HBA_PORT__PxIS__OFS__MASK | // 'h1000000;
HBA_PORT__PxIS__PRCS__MASK | // 'h400000;
HBA_PORT__PxIS__UFS__MASK | // 'h10;
HBA_PORT__PxIS__SDBS__MASK | // 'h8;
HBA_PORT__PxIS__DSS__MASK | // 'h4;
HBA_PORT__PxIS__PSS__MASK | // 'h2;
HBA_PORT__PxIS__DHRS__MASK; // 'h1;
always @(posedge mclk) begin
if (mrst) irq <= 0;
else irq <= ghc_ie_r && ghc_is_r;
end
// generate reset types
always @ (posedge mclk) begin
hba_rst_r <= mrst;
rst_por <= !mrst && hba_rst_r && !was_hba_rst && !was_port_rst;
rst_hba <= !mrst && hba_rst_r && was_hba_rst;
rst_port <= !mrst && hba_rst_r && was_port_rst;
end
// GHC_IE register (just one bit)
always @(posedge mclk) begin
if (rst_por) ghc_ie_r <= 0;
else if (swr_GHC__IE) ghc_ie_r <= |(soft_write_data & GHC__GHC__IE__MASK);
end
// swr_GHC__IS register (just one bit)
always @(posedge mclk) begin
if (mrst) ghc_is_r <= 0; // any reset?
else if (set_ghc_is_r) ghc_is_r <= 1;
else if (swr_GHC__IS) ghc_is_r <= soft_write_data[0];
end
// HBA_PORT__PxIE register
always @(posedge mclk) begin
if (rst_por) PxIE_r <= 0;
else if (swr_HBA_PORT__PxIE) PxIE_r <= PxIE_MASK & soft_write_data;
end
// HBA_PORT__PxIS register
always @(posedge mclk) begin
if (rst_por) PxIS_r <= 0;
else PxIS_r <= PxIS_MASK & ((swr_HBA_PORT__PxIS ? soft_write_data : PxIS_r) | sirq);
end
always @(posedge mclk) begin
if (rst_por) set_ghc_is_r <= 0;
// TODO: Not exactly clear - when ghc_is_r should be set after being RWC? After setting some not masked new individual interrupt?
else set_ghc_is_r <= |(sirq & PxIE_r);
end
// Update AXI registers with the current local data
always @ (posedge mclk) begin
regs_addr <= ({ADDRESS_BITS{update_GHC__IS}} & GHC__IS__IPS__ADDR) |
({ADDRESS_BITS{update_HBA_PORT__PxIS}} & HBA_PORT__PxIS__CPDS__ADDR); // | // TODO: add more ...
regs_din <= ({32{update_GHC__IS}} & {31'b0, ghc_is_r}) |
({32{update_HBA_PORT__PxIS}} & PxIS_r); // | // TODO: add more ...
regs_we <= update_GHC__IS || update_HBA_PORT__PxIS;
end
//
/*
sirq
*/
endmodule
...@@ -52,6 +52,7 @@ module ahci_fis_receive#( ...@@ -52,6 +52,7 @@ module ahci_fis_receive#(
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) // 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_pio, // update PxTFD.STS and PxTFD.ERR from pio_* (entry PIO:Update)
input update_prdbc, // update PRDBC in registers 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
...@@ -62,7 +63,7 @@ module ahci_fis_receive#( ...@@ -62,7 +63,7 @@ module ahci_fis_receive#(
input [11:0] decr_DXC_dw, // decrement value (in DWORDs) input [11:0] decr_DXC_dw, // decrement value (in DWORDs)
// TODO: Add writing PRDBC here? // TODO: Add writing PRDBC here?
output reg pPioXfer, // state variable
output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields)
// tfd_sts[7] - BSY, tfd_sts[4] - DRQ, tfd_sts[0] - ERR // tfd_sts[7] - BSY, tfd_sts[4] - DRQ, tfd_sts[0] - ERR
output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB) output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB)
...@@ -72,7 +73,7 @@ module ahci_fis_receive#( ...@@ -72,7 +73,7 @@ module ahci_fis_receive#(
output reg dma_d, // value of "D" 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_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 [7:0] pio_es, // value of PIO E_Status
// Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed // 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 [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 output reg xfer_cntr_zero,// valid next cycle
...@@ -172,9 +173,15 @@ localparam DATA_TYPE_ERR = 3; ...@@ -172,9 +173,15 @@ localparam DATA_TYPE_ERR = 3;
reg [15:0] tf_err_sts; reg [15:0] tf_err_sts;
reg update_err_sts_r; reg update_err_sts_r;
// reg update_pio_r;
reg update_prdbc_r; reg update_prdbc_r;
reg get_fis_busy_r; reg get_fis_busy_r;
reg [7:0] pio_es_r; // value of PIO E_Status
reg [7:0] pio_err_r;
// Forward data to DMA (dev->mem) engine // 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_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_stop = dma_in && data_in_ready && (hba_data_in_type != DATA_TYPE_DMA); // ||
...@@ -192,7 +199,10 @@ localparam DATA_TYPE_ERR = 3; ...@@ -192,7 +199,10 @@ localparam DATA_TYPE_ERR = 3;
assign xfer_cntr = xfer_cntr_r[31:2]; assign xfer_cntr = xfer_cntr_r[31:2];
assign get_fis_busy = get_fis_busy_r; assign get_fis_busy = get_fis_busy_r;
assign data_in_dwords = data_out_dwords_r; // assign data_in_dwords = data_out_dwords_r;
assign data_in_dwords = data_in_dwords_r;
assign pio_es = pio_es_r;
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;
...@@ -271,14 +281,20 @@ localparam DATA_TYPE_ERR = 3; ...@@ -271,14 +281,20 @@ localparam DATA_TYPE_ERR = 3;
if (reg_we_w) reg_data[31:8] <= hba_data_in[31:8]; if (reg_we_w) reg_data[31:8] <= hba_data_in[31:8];
else if (update_sig[1]) reg_data[31:8] <= hba_data_in[23:0]; else if (update_sig[1]) reg_data[31:8] <= hba_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_pio_r) reg_data[31:8] <= {16'b0,pio_err_r[7:0]};
else if (update_prdbc_r) reg_data[31:8] <= {xfer_cntr_r[31:8]}; else if (update_prdbc_r) reg_data[31:8] <= {xfer_cntr_r[31:8]};
if (reg_we_w) reg_data[ 7:0] <= hba_data_in[ 7:0]; if (reg_we_w) reg_data[ 7:0] <= hba_data_in[ 7:0];
else if (update_sig[3]) reg_data[ 7:0] <= hba_data_in[ 7:0]; else if (update_sig[3]) reg_data[ 7:0] <= hba_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_pio_r) reg_data[ 7:0] <= pio_es_r [ 7:0];
else if (update_prdbc_r) reg_data[ 7:0] <= {xfer_cntr_r[ 7:2],2'b0}; 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 <= hba_data_in[15:0]; if (reg_d2h || update_sig[0]) tf_err_sts <= hba_data_in[15:0];
// Sets pPioErr[pPmpCur] to Error field of the FIS
// 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) 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) 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}}} ;
...@@ -295,8 +311,11 @@ localparam DATA_TYPE_ERR = 3; ...@@ -295,8 +311,11 @@ localparam DATA_TYPE_ERR = 3;
if (reg_ps[0]) {pio_i,pio_d} <= {hba_data_in[14],hba_data_in[13]}; if (reg_ps[0]) {pio_i,pio_d} <= {hba_data_in[14],hba_data_in[13]};
if (hba_rst) pio_es <= 0; if (hba_rst) pio_err_r <= 0;
else if (reg_ps[3]) pio_es <= hba_data_in[31:24]; 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 || reg_sdb) xfer_cntr_r[31:2] <= 0; 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]?hba_data_in[31:16]:16'b0, hba_data_in[15:2]} + hba_data_in[1]; // round up 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
...@@ -307,9 +326,15 @@ localparam DATA_TYPE_ERR = 3; ...@@ -307,9 +326,15 @@ localparam DATA_TYPE_ERR = 3;
xfer_cntr_zero <= xfer_cntr_r[31:2] == 0; 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_pio || update_err_sts || clear_bsy_drq || set_bsy || set_sts_7f || set_sts_80;
// update_pio_r <= update_pio;
update_prdbc_r <= update_prdbc; // same latency as update_err_sts update_prdbc_r <= update_prdbc; // same latency as update_err_sts
if (hba_rst || update_pio) pPioXfer <= 0;
else if (reg_ps[4]) pPioXfer <= 1;
// Maybe it is not needed if the fsm will send this pulse? // 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); // data_in_words_apply <= dma_in_stop && (hba_data_in_type == DATA_TYPE_OK);
end end
......
...@@ -28,6 +28,9 @@ module ahci_fsm #( ...@@ -28,6 +28,9 @@ module ahci_fsm #(
)( )(
input hba_rst, // @posedge mclk input hba_rst, // @posedge mclk
input mclk, // for command/status input mclk, // for command/status
input was_hba_rst, // last reset was hba reset (not counting system reset)
input was_port_rst, // last reset was port reset
// notification from axi_ahci_regs that software has written data to register // notification from axi_ahci_regs that software has written data to register
input [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software input [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software
input [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1) input [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1)
...@@ -72,6 +75,8 @@ module ahci_fsm #( ...@@ -72,6 +75,8 @@ module ahci_fsm #(
input fis_ferr, // FIS done, fatal error - FIS too long input 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) // next commands use register address/data/we for 1 clock cycle - after next to command (commnd - t0, we - t2)
output update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h output update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h
output update_pio, // update PxTFD.STS and PxTFD.ERR from pio_* (entry PIO:Update)
output update_prdbc, // update PRDBC in registers output update_prdbc, // update PRDBC in registers
output clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update output clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update
output set_bsy, // set PxTFD.STS.BSY, update output set_bsy, // set PxTFD.STS.BSY, update
...@@ -79,6 +84,7 @@ module ahci_fsm #( ...@@ -79,6 +84,7 @@ module ahci_fsm #(
output set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update output set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update
output decr_dwc, // decrement DMA Xfer counter // need pulse to 'update_prdbc' to write to registers output decr_dwc, // decrement DMA Xfer counter // need pulse to 'update_prdbc' to write to registers
output [11:0] decr_DXC_dw, // decrement value (in DWORDs) output [11:0] decr_DXC_dw, // decrement value (in DWORDs)
input pPioXfer, // state variable
input [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields) input [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 // tfd_sts[7] - BSY, tfd_sts[4] - DRQ, tfd_sts[0] - ERR
input [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB) input [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB)
......
...@@ -220,6 +220,8 @@ module ahci_top#( ...@@ -220,6 +220,8 @@ module ahci_top#(
// short commands: // short commands:
// next commands use register address/data/we for 1 clock cycle - after next to command (commnd - t0, we - t2) // next commands use register address/data/we for 1 clock cycle - after next to command (commnd - t0, we - t2)
wire frcv_update_err_sts;// update PxTFD.STS and PxTFD.ERR from the last received regs d2h wire frcv_update_err_sts;// update PxTFD.STS and PxTFD.ERR from the last received regs d2h
wire frcv_update_pio; // update PxTFD.STS and PxTFD.ERR from pio_* (entry PIO:Update)
wire frcv_update_prdbc; // update PRDBC in registers wire frcv_update_prdbc; // update PRDBC in registers
wire frcv_clear_bsy_drq; // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update wire frcv_clear_bsy_drq; // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update
wire frcv_set_bsy; // set PxTFD.STS.BSY, update wire frcv_set_bsy; // set PxTFD.STS.BSY, update
...@@ -245,6 +247,8 @@ module ahci_top#( ...@@ -245,6 +247,8 @@ module ahci_top#(
wire pio_i; // value of "I" field in received PIO Setup FIS 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 pio_d; // value of "D" field in received PIO Setup FIS
wire [7:0] pio_es; // value of PIO E_Status wire [7:0] pio_es; // value of PIO E_Status
wire pPioXfer;
// Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed // Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed
wire [31:0] xfer_cntr; wire [31:0] xfer_cntr;
...@@ -278,6 +282,8 @@ module ahci_top#( ...@@ -278,6 +282,8 @@ module ahci_top#(
wire [11:0] data_out_dwords; // number of DWORDs sent in data FIS wire [11:0] data_out_dwords; // number of DWORDs sent in data FIS
wire was_hba_rst;
wire was_port_rst;
ahci_fsm #( ahci_fsm #(
.READ_REG_LATENCY(2), .READ_REG_LATENCY(2),
...@@ -285,6 +291,8 @@ module ahci_top#( ...@@ -285,6 +291,8 @@ module ahci_top#(
) ahci_fsm_i ( ) ahci_fsm_i (
.hba_rst (mrst), // input .hba_rst (mrst), // input
.mclk (mclk), // input .mclk (mclk), // input
.was_hba_rst (was_hba_rst), // input
.was_port_rst (was_port_rst), // input
.soft_write_addr (soft_write_addr), // input[9:0] .soft_write_addr (soft_write_addr), // input[9:0]
.soft_write_data (soft_write_data), // input[31:0] .soft_write_data (soft_write_data), // input[31:0]
.soft_write_en (soft_write_en), // input .soft_write_en (soft_write_en), // input
...@@ -318,6 +326,7 @@ module ahci_top#( ...@@ -318,6 +326,7 @@ module ahci_top#(
.fis_err (frcv_err), // input .fis_err (frcv_err), // input
.fis_ferr (frcv_ferr), // input .fis_ferr (frcv_ferr), // input
.update_err_sts (frcv_update_err_sts),// output .update_err_sts (frcv_update_err_sts),// output
.update_pio (frcv_update_pio), // output
.update_prdbc (frcv_update_prdbc), // output .update_prdbc (frcv_update_prdbc), // output
.clear_bsy_drq (frcv_clear_bsy_drq), // output .clear_bsy_drq (frcv_clear_bsy_drq), // output
.set_bsy (frcv_set_bsy), // output .set_bsy (frcv_set_bsy), // output
...@@ -325,6 +334,7 @@ module ahci_top#( ...@@ -325,6 +334,7 @@ module ahci_top#(
.set_sts_80 (frcv_set_sts_80), // output .set_sts_80 (frcv_set_sts_80), // output
.decr_dwc (frcv_decr_dwc), // output .decr_dwc (frcv_decr_dwc), // output
.decr_DXC_dw (data_out_dwords), // output[11:2] **** Probably not needed .decr_DXC_dw (data_out_dwords), // output[11:2] **** Probably not needed
.pPioXfer (pPioXfer), // input
.tfd_sts (tfd_sts), // input[7:0] .tfd_sts (tfd_sts), // input[7:0]
.tfd_err (tfd_err), // input[7:0] .tfd_err (tfd_err), // input[7:0]
...@@ -398,8 +408,8 @@ module ahci_top#( ...@@ -398,8 +408,8 @@ module ahci_top#(
.soft_write_addr (soft_write_addr), // output[9:0] .soft_write_addr (soft_write_addr), // output[9:0]
.soft_write_data (soft_write_data), // output[31:0] .soft_write_data (soft_write_data), // output[31:0]
.soft_write_en (soft_write_en), // output .soft_write_en (soft_write_en), // output
.hba_arst (hba_arst), // output .hba_arst (hba_arst), // output // does not include arst
.port_arst (port_arst), // output .port_arst (port_arst), // output // does not include arst
.hba_clk (mclk), // input .hba_clk (mclk), // input
.hba_rst (mrst), // input // deasserted when mclk is stable .hba_rst (mrst), // input // deasserted when mclk is stable
.hba_addr (regs_addr), // input[9:0] .hba_addr (regs_addr), // input[9:0]
...@@ -409,7 +419,10 @@ module ahci_top#( ...@@ -409,7 +419,10 @@ module ahci_top#(
.hba_dout (regs_dout), // output[31:0] .hba_dout (regs_dout), // output[31:0]
.afi_wcache (axi_wr_cache_mode),// output[3:0] reg .afi_wcache (axi_wr_cache_mode),// output[3:0] reg
.afi_rcache (axi_rd_cache_mode),// output[3:0] reg .afi_rcache (axi_rd_cache_mode),// output[3:0] reg
.afi_cache_set (set_axi_cache_mode) // output .afi_cache_set (set_axi_cache_mode), // output
.was_hba_rst (was_hba_rst), // output
.was_port_rst (was_port_rst) // output
); );
...@@ -515,6 +528,8 @@ module ahci_top#( ...@@ -515,6 +528,8 @@ module ahci_top#(
.fis_ferr (frcv_ferr), // output .fis_ferr (frcv_ferr), // output
.update_err_sts (frcv_update_err_sts), // input .update_err_sts (frcv_update_err_sts), // input
.update_pio (frcv_update_pio), // input update PxTFD.STS and PxTFD.ERR from pio_* (entry PIO:Update)
.update_prdbc (frcv_update_prdbc), // input .update_prdbc (frcv_update_prdbc), // input
.clear_bsy_drq (frcv_clear_bsy_drq), // input .clear_bsy_drq (frcv_clear_bsy_drq), // input
.set_bsy (frcv_set_bsy), // input .set_bsy (frcv_set_bsy), // input
...@@ -522,6 +537,7 @@ module ahci_top#( ...@@ -522,6 +537,7 @@ module ahci_top#(
.set_sts_80 (frcv_set_sts_80), // input .set_sts_80 (frcv_set_sts_80), // input
.decr_dwc (frcv_decr_dwc), // input .decr_dwc (frcv_decr_dwc), // input
.decr_DXC_dw (data_out_dwords), // input[11:2] .decr_DXC_dw (data_out_dwords), // input[11:2]
.pPioXfer (pPioXfer), // output reg
.tfd_sts (tfd_sts), // output[7:0] .tfd_sts (tfd_sts), // output[7:0]
.tfd_err (tfd_err), // output[7:0] .tfd_err (tfd_err), // output[7:0]
......
...@@ -86,6 +86,7 @@ module axi_ahci_regs#( ...@@ -86,6 +86,7 @@ module axi_ahci_regs#(
output [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software output [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software
output [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1) output [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1)
output soft_write_en, // write enable for data write output soft_write_en, // write enable for data write
// Apply next 2 resets and arst OR-ed to SATA.extrst
output hba_arst, // hba async reset (currently does ~ the same as port reset) output hba_arst, // hba async reset (currently does ~ the same as port reset)
output port_arst, // port0 async reset by software output port_arst, // port0 async reset by software
...@@ -102,9 +103,9 @@ module axi_ahci_regs#( ...@@ -102,9 +103,9 @@ module axi_ahci_regs#(
// other control signals // other control signals
output reg [ 3:0] afi_wcache, output reg [ 3:0] afi_wcache,
output reg [ 3:0] afi_rcache, output reg [ 3:0] afi_rcache,
output afi_cache_set output afi_cache_set,
output was_hba_rst, // last reset was hba reset (not counting system reset)
output was_port_rst // last reset was port reset
); );
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams `include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
...@@ -154,17 +155,31 @@ module axi_ahci_regs#( ...@@ -154,17 +155,31 @@ module axi_ahci_regs#(
reg [ADDRESS_BITS-1:0] bram_waddr_r; reg [ADDRESS_BITS-1:0] bram_waddr_r;
reg [HBA_RESET_BITS-1:0] hba_reset_cntr = 1; // time to keep hba_reset_r active after writing to GHC.HR reg [HBA_RESET_BITS-1:0] hba_reset_cntr = 1; // time to keep hba_reset_r active after writing to GHC.HR
reg hba_nrst_r; // hba _reset (currently does ~ the same as port reset) reg hba_rst_r; // hba _reset (currently does ~ the same as port reset)
reg port_nrst_r; // port _reset by software reg port_rst_r; // port _reset by software
wire high_sel = bram_waddr_r[ADDRESS_BITS-1]; // high addresses - use single-cycle writes without read-modify-write wire high_sel = bram_waddr_r[ADDRESS_BITS-1]; // high addresses - use single-cycle writes without read-modify-write
wire afi_cache_set_w = bram_wen_r && !high_sel && (bram_addr == HBA_PORT__AFI_CACHE__WR_CM__ADDR); wire afi_cache_set_w = bram_wen_r && !high_sel && (bram_addr == HBA_PORT__AFI_CACHE__WR_CM__ADDR);
wire set_hba_rst = bram_wen_r && !high_sel && (bram_addr == GHC__GHC__HR__ADDR) && (ahci_regs_di & GHC__GHC__HR__MASK);
wire set_port_rst = bram_wen_r && !high_sel && (bram_addr == HBA_PORT__PxSCTL__DET__ADDR) &&
((ahci_regs_di & HBA_PORT__PxSCTL__DET__MASK | 1) == HBA_PORT__PxSCTL__DET__MASK); // writing only 0/1
// in lower 4 bits
wire port_rst_on = set_port_rst && ahci_regs_di[0];
reg was_hba_rst_aclk; // last reset was hba reset (not counting system reset)
reg was_port_rst_aclk; // last reset was port reset
reg [2:0] was_hba_rst_r; // last reset was hba reset (not counting system reset)
reg [2:0] was_port_rst_r; // last reset was port reset
// assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen ? bram_waddr : pre_awaddr); // assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen ? bram_waddr : pre_awaddr);
assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen_r ? bram_waddr_r : bram_waddr); assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen_r ? bram_waddr_r : bram_waddr);
assign hba_arst = !hba_nrst_r; // hba _reset (currently does ~ the same as port reset) assign hba_arst = hba_rst_r; // hba _reset (currently does ~ the same as port reset)
assign port_arst = !port_nrst_r; // port _reset by software assign port_arst = port_rst_r; // port _reset by software
assign was_hba_rst = was_hba_rst_r[0];
assign was_port_rst = was_port_rst_r[0];
always @(posedge aclk) begin always @(posedge aclk) begin
...@@ -198,21 +213,31 @@ module axi_ahci_regs#( ...@@ -198,21 +213,31 @@ module axi_ahci_regs#(
endgenerate endgenerate
always @(posedge aclk) begin always @(posedge aclk) begin
if (arst) hba_reset_cntr <= 1; if (arst) hba_reset_cntr <= 0; // 1; no HBA reset at arst
else if (bram_wen_r && !high_sel && else if (set_hba_rst) hba_reset_cntr <= {HBA_RESET_BITS{1'b1}};
(bram_addr == GHC__GHC__HR__ADDR) &&
(ahci_regs_di & GHC__GHC__HR__MASK)) hba_reset_cntr <= {HBA_RESET_BITS{1'b1}};
else if (|hba_reset_cntr) hba_reset_cntr <= hba_reset_cntr - 1; else if (|hba_reset_cntr) hba_reset_cntr <= hba_reset_cntr - 1;
hba_nrst_r <= hba_reset_cntr == 0; hba_rst_r <= hba_reset_cntr != 0;
if (arst) port_rst_r <= 0;
else if (set_port_rst) port_rst_r <= ahci_regs_di[0]; // write "1" - reset on, write 0 - reset off
if (arst || port_rst_on) was_hba_rst_aclk <= 0;
else if (set_hba_rst) was_hba_rst_aclk <= 1;
if (arst) port_nrst_r <= 0; if (arst || set_hba_rst) was_port_rst_aclk <= 0;
else if (bram_wen_r && !high_sel && else if (port_rst_on) was_port_rst_aclk <= 1;
(bram_addr == HBA_PORT__PxSCTL__DET__ADDR) &&
((ahci_regs_di & HBA_PORT__PxSCTL__DET__MASK | 1) == HBA_PORT__PxSCTL__DET__MASK))
port_nrst_r <= !ahci_regs_di[0]; // write "1" - reset on, write 0 - reset off end
always @ (hba_clk) begin
was_hba_rst_r <= {was_hba_rst_aclk, was_hba_rst_r[2:1]};
was_port_rst_r <= {was_port_rst_aclk, was_port_rst_r[2:1]};
end end
always @(posedge aclk) begin always @(posedge aclk) begin
if (arst) {afi_wcache,afi_rcache} <= 8'h33; if (arst) {afi_wcache,afi_rcache} <= 8'h33;
else if (afi_cache_set_w) {afi_wcache,afi_rcache} <= ahci_regs_di[7:0]; else if (afi_cache_set_w) {afi_wcache,afi_rcache} <= ahci_regs_di[7:0];
......
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