/*! * Module:ahci_ctrl_stat * @file ahci_ctrl_stat.v * @date 2016-01-12 * @author Andrey Filippov * * @brief Copy of significant register fields, updating them in * axi_ahci_regs registers (software accessible) * * @copyright Copyright (c) 2016 Elphel, Inc . * * License: * * 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 . */ `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) output update_pending, input update_all, output update_busy, // valid same cycle as update_all input update_gis, // these following individual may be unneeded - just use universal update_all input update_pis, input update_ssts, input update_serr, input update_pcmd, input update_pci, input update_ghc, /// output reg st01_pending, // software turned PxCMD.ST from 0 to 1 /// output reg st10_pending, // software turned PxCMD.ST from 1 to 0 /// input st_pending_reset,// reset both st01_pending and st10_pending // PxCMD // input pcmd_clear_icc, // clear PxCMD.ICC field (generated here) input pcmd_esp, // external SATA port (just forward value) output pcmd_cr, // command list run - current input pcmd_cr_set, // command list run set input pcmd_cr_reset, // command list run reset input pcmd_fr, // ahci_fis_receive:get_fis_busy - change to HAB set/reset (set, do, reset) output pcmd_fre, // FIS enable copy to memory input pcmd_clear_bsy_drq, // == ahci_fis_receive:clear_bsy_drq output pcmd_clo, //RW1, causes ahci_fis_receive:clear_bsy_drq, that in turn resets this bit input pcmd_clear_st, // RW clear ST (start) bit output pcmd_st, // current value input pfsm_started, // H: FSM done, P: FSM started (enable sensing pcmd_st_cleared) output reg pcmd_st_cleared,// ST bit cleared by software; TODO: check not in H:Init (5.3.2.10) //clear_bsy_drq // 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_PC, // RO: Port Connect Change Status input sirq_DP, // RWC: Descriptor Processed with "I" bit on 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 // SCR1:SError (only inputs that are not available in sirq_* ones //sirq_PC, //sirq_UF input serr_DT, // RWC: Transport state transition error input serr_DS, // RWC: Link sequence error input serr_DH, // RWC: Handshake Error (i.e. Device got CRC error) input serr_DC, // RWC: CRC error in Link layer input serr_DB, // RWC: 10B to 8B decode error input serr_DW, // RWC: COMMWAKE signal was detected input serr_DI, // RWC: PHY Internal Error // sirq_PRC, // sirq_IF || // sirq_INF input serr_EE, // RWC: Internal error (such as elastic buffer overflow or primitive mis-alignment) input serr_EP, // RWC: Protocol Error - a violation of SATA protocol detected input serr_EC, // RWC: Persistent Communication or Data Integrity Error input serr_ET, // RWC: Transient Data Integrity Error (error not recovered by the interface) input serr_EM, // RWC: Communication between the device and host was lost but re-established input serr_EI, // RWC: Recovered Data integrity Error output serr_diag_X, // value of PxSERR.DIAG.X // SCR0: SStatus input ssts_ipm_dnp, // device not present or communication not established input ssts_ipm_active, // device in active state input ssts_ipm_part, // device in partial state input ssts_ipm_slumb, // device in slumber state input ssts_ipm_devsleep, // device in DevSleep state input ssts_spd_dnp, // device not present or communication not established input ssts_spd_gen1, // Gen 1 rate negotiated input ssts_spd_gen2, // Gen 2 rate negotiated input ssts_spd_gen3, // Gen 3 rate negotiated 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 or BIST output [3:0] ssts_det, // current value of PxSSTS.DET // SCR2:SControl (written by software only) output reg [3:0] sctl_ipm, // Interface power management transitions allowed output reg [3:0] sctl_spd, // Interface maximal speed output reg [3:0] sctl_det, // Device detection initialization requested output reg sctl_det_changed, // Software had written new value to sctl_det input sctl_det_reset, // clear sctl_det_changed input pxci0_clear, // PxCI clear output pxci0, // pxCI current value input hba_reset_done, // at the end of the HBA reset, clear GHC.HR, GHC.IE output unsolicited_en, // enable processing of cominit_got and PxERR.DIAG.W interrupts from // this bit is reset at reset, set when PxSSTS.DET==3 or PxSCTL.DET==4 /* */ 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__ADDR); wire swr_GHC__GHC = soft_write_en && (soft_write_addr == GHC__GHC__HR__ADDR); reg hba_rst_r = 1; reg rst_por; reg rst_hba; // @SuppressThisWarning VEditor : Unused, maybe will be used later reg rst_port; // @SuppressThisWarning VEditor : Unused, maybe will be used later // 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 cleared_ghc; // active next cycle after ghc[1:0] is cleared 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 reg [11:0] PxSSTS_r; reg [31:0] PxSERR_r; // Assuming it is not needed for HBA, just for the software reg [31:0] PxCMD_r; reg pxci0_r; reg [ 1:0] GHC_r; // only 2 bits are used here wire ghc_ie = GHC_r[1]; // bit 1 of GHC__GHC reg cirq_PRC; // clear PRC bit when clearing PxSERR.DIAG.N reg cirq_PC; // clear PC bit when clearing PxSERR.DIAG.X wire [31:0] cirq ={32{cirq_PRC}} & HBA_PORT__PxIS__PRCS__MASK | // 'h400000; {32{cirq_PC}} & HBA_PORT__PxIS__PCS__MASK; // 'h40;;}; 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_PC & unsolicited_en}} & HBA_PORT__PxIS__PCS__MASK | // 'h40; {32{sirq_DP}} & HBA_PORT__PxIS__DPS__MASK | // 'h20; {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; // See if sirq_PC should also be enabled by unsolicited_en. Or not? wire [31:0] serr = {32{sirq_PC & unsolicited_en}} & HBA_PORT__PxSERR__DIAG__X__MASK | // 'h4000000; {32{sirq_UF }} & HBA_PORT__PxSERR__DIAG__F__MASK | // 'h2000000; {32{serr_DT }} & HBA_PORT__PxSERR__DIAG__T__MASK | // 'h1000000; {32{serr_DS }} & HBA_PORT__PxSERR__DIAG__S__MASK | // 'h800000; {32{serr_DH }} & HBA_PORT__PxSERR__DIAG__H__MASK | // 'h400000; {32{serr_DC }} & HBA_PORT__PxSERR__DIAG__C__MASK | // 'h200000; {32{serr_DB }} & HBA_PORT__PxSERR__DIAG__B__MASK | // 'h80000; {32{serr_DW & unsolicited_en}} & HBA_PORT__PxSERR__DIAG__W__MASK | // 'h40000; {32{serr_DI }} & HBA_PORT__PxSERR__DIAG__I__MASK | // 'h20000; {32{sirq_PRC}} & HBA_PORT__PxSERR__DIAG__N__MASK | // 'h10000; // {32{sirq_IF | sirq_INF }} & HBA_PORT__PxSERR__ERR__E__MASK | // 'h800; {32{serr_EE}} & HBA_PORT__PxSERR__ERR__E__MASK | // 'h800; {32{serr_EP }} & HBA_PORT__PxSERR__ERR__P__MASK | // 'h400; {32{serr_EC }} & HBA_PORT__PxSERR__ERR__C__MASK | // 'h200; {32{serr_ET }} & HBA_PORT__PxSERR__ERR__T__MASK | // 'h100; {32{serr_EM }} & HBA_PORT__PxSERR__ERR__M__MASK | // 'h2; {32{serr_EI }} & HBA_PORT__PxSERR__ERR__I__MASK; // 'h0; wire [11:8] sssts_ipm = ({4{ssts_ipm_active}} & 4'h1) | ({4{ssts_ipm_part}} & 4'h2) | ({4{ssts_ipm_slumb}} & 4'h6) | ({4{ssts_ipm_devsleep}} & 4'h8); wire [ 7:4] sssts_spd = ({4{ssts_spd_gen1}} & 4'h1) | ({4{ssts_spd_gen2}} & 4'h2) | ({4{ssts_spd_gen3}} & 4'h3); wire [ 3:0] sssts_det = ({4{ssts_det_dnp}} & 4'h1) | ({4{ssts_det_dp}} & 4'h3) | ({4{ssts_det_offline}} & 4'h4); reg pcmd_clear_icc_r; wire pcmd_clear_icc = !pcmd_clear_icc_r && ((PxCMD_r & HBA_PORT__PxCMD__ICC__MASK) == 32'h10000000) && ((PxSSTS_r & HBA_PORT__PxSSTS__IPM__MASK) == 12'h100) ; // PxSSTS_r[11:8] HBA_PORT__PxSSTS__IPM__MASK ; // to update only HBA/async changed bits (not by the software) wire set_ssts_ipm = ssts_ipm_dnp || ssts_ipm_active || ssts_ipm_part || ssts_ipm_slumb || ssts_ipm_devsleep; wire set_ssts_spd = ssts_spd_dnp || ssts_spd_gen1 || ssts_spd_gen2|| ssts_spd_gen3; wire set_ssts_det = ssts_det_ndnp || ssts_det_dnp || ssts_det_dp || ssts_det_offline; wire set_pxcmd = pcmd_clear_icc || pcmd_esp || pcmd_cr_reset || pcmd_fr || pcmd_clear_bsy_drq || pcmd_clear_st ; reg pxci_changed; reg ssts_changed; reg serr_changed; reg sirq_changed; reg pxcmd_changed; reg ghc_is_changed; reg ghc_ghc_changed; // wire [5:0] regs_changed={pxcmd_changed, serr_changed, ssts_changed, pxci_changed, sirq_changed,ghc_is_changed }; wire [6:0] regs_changed={ghc_ghc_changed, pxci_changed, pxcmd_changed, serr_changed, ssts_changed, sirq_changed,ghc_is_changed }; // wire [5:0] update; reg [6:1] updating; wire [6:0] update_first = {7{update_all}} & {regs_changed[6] && ~(|regs_changed[5:0]), regs_changed[5] && ~(|regs_changed[4:0]), regs_changed[4] && ~(|regs_changed[3:0]), regs_changed[3] && ~(|regs_changed[2:0]), regs_changed[2] && ~(|regs_changed[1:0]), regs_changed[1] && ~ regs_changed[0], regs_changed[0]}; wire [6:1] update_next = {updating[6] && ~(|updating[5:1]), updating[5] && ~(|updating[4:1]), updating[4] && ~(|updating[3:1]), updating[3] && ~(|updating[2:1]), updating[2] && ~ updating[1], updating[1]}; wire update_GHC__IS = update_gis || update_first[0]; wire update_HBA_PORT__PxIS = update_pis || update_first[1] || update_next[1]; wire update_HBA_PORT__PxSSTS = update_ssts || update_first[2] || update_next[2]; wire update_HBA_PORT__PxSERR = update_serr || update_first[3] || update_next[3]; wire update_HBA_PORT__PxCMD = update_pcmd || update_first[4] || update_next[4]; wire update_HBA_PORT__PxCI = update_pci || update_first[5] || update_next[5]; wire update_GHC_GHC = update_ghc || update_first[6] || update_next[6]; reg pfsm_started_r; reg unsolicited_en_r; assign update_busy = (update_all && (|regs_changed)) || (|updating[6:1]); assign update_pending = | regs_changed; assign pcmd_fre = |(HBA_PORT__PxCMD__FRE__MASK & PxCMD_r); assign serr_diag_X = |(HBA_PORT__PxSERR__DIAG__X__MASK & PxSERR_r); assign ssts_det = PxSSTS_r[3:0]; assign unsolicited_en = unsolicited_en_r; // assign cirq_PRC = swr_HBA_PORT__PxSERR && |(soft_write_data & HBA_PORT__PxSERR__DIAG__N__MASK); // assign cirq_PC = swr_HBA_PORT__PxSERR && |(soft_write_data & HBA_PORT__PxSERR__DIAG__X__MASK); 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__PCE__MASK | // 'h40; HBA_PORT__PxIE__DPE__MASK | // 'h20 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__PCS__MASK | // 'h40; HBA_PORT__PxIS__DPS__MASK | // 'h20 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; localparam PxSERR_MASK = HBA_PORT__PxSERR__DIAG__X__MASK | // 'h4000000; HBA_PORT__PxSERR__DIAG__F__MASK | // 'h2000000; HBA_PORT__PxSERR__DIAG__T__MASK | // 'h1000000; HBA_PORT__PxSERR__DIAG__S__MASK | // 'h800000; HBA_PORT__PxSERR__DIAG__H__MASK | // 'h400000; HBA_PORT__PxSERR__DIAG__C__MASK | // 'h200000; HBA_PORT__PxSERR__DIAG__B__MASK | // 'h80000; HBA_PORT__PxSERR__DIAG__W__MASK | // 'h40000; HBA_PORT__PxSERR__DIAG__I__MASK | // 'h20000; HBA_PORT__PxSERR__DIAG__N__MASK | // 'h10000; HBA_PORT__PxSERR__ERR__E__MASK | // 'h800; HBA_PORT__PxSERR__ERR__P__MASK | // 'h400; HBA_PORT__PxSERR__ERR__C__MASK | // 'h200; HBA_PORT__PxSERR__ERR__T__MASK | // 'h100; HBA_PORT__PxSERR__ERR__M__MASK | // 'h2; HBA_PORT__PxSERR__ERR__I__MASK; // 'h0; localparam PxCMD_DFLT = HBA_PORT__PxCMD__ICC__DFLT | // 'h0; HBA_PORT__PxCMD__ASP__DFLT | // 'h0; HBA_PORT__PxCMD__ALPE__DFLT | // 'h0; HBA_PORT__PxCMD__DLAE__DFLT | // 'h0; HBA_PORT__PxCMD__ATAPI__DFLT | // 'h0; HBA_PORT__PxCMD__APSTE__DFLT | // 'h0; HBA_PORT__PxCMD__FBSCP__DFLT | // 'h0; HBA_PORT__PxCMD__ESP__DFLT | // 'h200000; HBA_PORT__PxCMD__CPD__DFLT | // 'h0; HBA_PORT__PxCMD__MPSP__DFLT | // 'h0; HBA_PORT__PxCMD__HPCP__DFLT | // 'h40000; HBA_PORT__PxCMD__PMA__DFLT | // 'h0; HBA_PORT__PxCMD__CPS__DFLT | // 'h0; HBA_PORT__PxCMD__CR__DFLT | // 'h0; HBA_PORT__PxCMD__FR__DFLT | // 'h0; HBA_PORT__PxCMD__MPSS__DFLT | // 'h0; HBA_PORT__PxCMD__CCS__DFLT | // 'h0; HBA_PORT__PxCMD__FRE__DFLT | // 'h0; HBA_PORT__PxCMD__CLO__DFLT | // 'h0; HBA_PORT__PxCMD__POD__DFLT | // 'h4; HBA_PORT__PxCMD__SUD__DFLT | // 'h2; HBA_PORT__PxCMD__ST__DFLT; // 'h0; localparam PxCMD_MASK = HBA_PORT__PxCMD__ICC__MASK | // 'hf0000000; // HBA_PORT__PxCMD__ASP__MASK | // 'h8000000; // HBA_PORT__PxCMD__ALPE__MASK | // 'h4000000; // HBA_PORT__PxCMD__DLAE__MASK | // 'h2000000; // HBA_PORT__PxCMD__ATAPI__MASK | // 'h1000000; // HBA_PORT__PxCMD__APSTE__MASK | // 'h800000; // HBA_PORT__PxCMD__FBSCP__MASK | // 'h400000; HBA_PORT__PxCMD__ESP__MASK | // 'h200000; // HBA_PORT__PxCMD__CPD__MASK | // 'h100000; // HBA_PORT__PxCMD__MPSP__MASK | // 'h80000; // HBA_PORT__PxCMD__HPCP__MASK | // 'h40000; // HBA_PORT__PxCMD__PMA__MASK | // 'h20000; // HBA_PORT__PxCMD__CPS__MASK | // 'h10000; HBA_PORT__PxCMD__CR__MASK | // 'h8000; HBA_PORT__PxCMD__FR__MASK | // 'h4000; // HBA_PORT__PxCMD__MPSS__MASK | // 'h2000; // HBA_PORT__PxCMD__CCS__MASK | // 'h1f00; HBA_PORT__PxCMD__FRE__MASK | // 'h10; HBA_PORT__PxCMD__CLO__MASK | // 'h8; // HBA_PORT__PxCMD__POD__MASK | // 'h4; // HBA_PORT__PxCMD__SUD__MASK | // 'h2; HBA_PORT__PxCMD__ST__MASK; // 'h1; assign pxci0 = pxci0_r; assign pcmd_cr = PxCMD_r[15]; // command list run - current assign pcmd_clo = PxCMD_r[3]; // causes ahci_fis_receive:clear_bsy_drq, that in turn resets this bit assign pcmd_st = PxCMD_r[0]; // current value always @(posedge mclk) begin if (mrst) unsolicited_en_r <= 0; else if (((PxSSTS_r & HBA_PORT__PxSSTS__DET__MASK) == 3) || (sctl_det == 4)) unsolicited_en_r <= 1; end always @(posedge mclk) begin pcmd_clear_icc_r <= pcmd_clear_icc; end always @(posedge mclk) begin // Here we do not have data written by soft, only the result (cleared). If bit is 0, it is // either cleared, or was 0. If it was 0, then IS bit was also 0, so clearing will not hurt. cirq_PRC <= swr_HBA_PORT__PxSERR && |(~soft_write_data & HBA_PORT__PxSERR__DIAG__N__MASK); cirq_PC <= swr_HBA_PORT__PxSERR && |(~soft_write_data & HBA_PORT__PxSERR__DIAG__X__MASK); end always @(posedge mclk) begin if (mrst) irq <= 0; // else irq <= ghc_ie_r && ghc_is_r; else irq <= ghc_ie && 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 || hba_reset_done) 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 & ~cirq)) | sirq); end // HBA_PORT__PxIE register 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) || hba_reset_done; end // GHC__GHC register always @(posedge mclk) begin if (rst_por) cleared_ghc <= 0; else cleared_ghc <= hba_reset_done; if (rst_por) GHC_r <= 0; else if (cleared_ghc) GHC_r <= 0; else if (swr_GHC__GHC) GHC_r <= soft_write_data[1:0]; end // HBA_PORT__PxSSTS register - updated from the HOST only always @(posedge mclk) begin if (mrst) PxSSTS_r[11:8] <= 0; else if (set_ssts_ipm) PxSSTS_r[11:8] <= sssts_ipm[11:8]; if (mrst) PxSSTS_r[ 7:4] <= 0; else if (set_ssts_spd) PxSSTS_r[ 7:4] <= sssts_spd[ 7:4]; if (mrst) PxSSTS_r[ 3:0] <= 0; else if (set_ssts_det) PxSSTS_r[ 3:0] <= sssts_det[ 3:0]; end // HBA_PORT__PxSCTL register - updated by the software only always @ (posedge mclk) begin if (rst_por) {sctl_ipm, sctl_spd, sctl_det} <= 0; else if (swr_HBA_PORT__PxSCTL) {sctl_ipm, sctl_spd, sctl_det} <= soft_write_data [11:0]; if (rst_por || sctl_det_reset) sctl_det_changed <= 0; else if (swr_HBA_PORT__PxSCTL && (soft_write_data[3:0] != sctl_det)) sctl_det_changed <= 1; end // HBA_PORT__PxSERR register always @(posedge mclk) begin if (rst_por) PxSERR_r <= 0; else PxSERR_r <= PxSERR_MASK & ((swr_HBA_PORT__PxSERR ? soft_write_data : PxSERR_r) | serr); end // HBA_PORT__PxCI[0] register - cleared by HBA, set by software always @(posedge mclk) begin if (mrst || pxci0_clear) pxci0_r <= 0; else if (swr_HBA_PORT__PxCI) pxci0_r <= soft_write_data[0]; end // HBA_PORT__PxCMD register - different behaviors of different fields // use PxCMD_MASK to prevent generation of unneeded register bits always @(posedge mclk) begin if (mrst) PxCMD_r <= PxCMD_DFLT; else PxCMD_r <= (~PxCMD_MASK & PxCMD_DFLT ) | (PxCMD_MASK & ( swr_HBA_PORT__PxCMD? soft_write_data : ( (pcmd_clear_icc ? 0 : (PxCMD_r & HBA_PORT__PxCMD__ICC__MASK)) | (pcmd_esp ? HBA_PORT__PxCMD__ESP__MASK : 0) | (pcmd_cr_reset ? 0 : (HBA_PORT__PxCMD__CR__MASK & (pcmd_cr_set? (~0):(PxCMD_r)))) | (pcmd_fr? HBA_PORT__PxCMD__FR__MASK : 0 ) | (HBA_PORT__PxCMD__FRE__MASK & PxCMD_r) | // no HBA control (pcmd_clear_bsy_drq ? 0 : (PxCMD_r & HBA_PORT__PxCMD__CLO__MASK)) | (pcmd_clear_st ? 0 : (PxCMD_r & HBA_PORT__PxCMD__ST__MASK)) ))); if (mrst) pfsm_started_r <= 0; else if (pfsm_started) pfsm_started_r <= 1; if (!pfsm_started_r) pcmd_st_cleared <= 0; // else if (swr_HBA_PORT__PxCMD) pcmd_st_cleared <= |(HBA_PORT__PxCMD__ST__MASK & PxCMD_r & ~soft_write_data); else pcmd_st_cleared <= swr_HBA_PORT__PxCMD && (|(HBA_PORT__PxCMD__ST__MASK & PxCMD_r & ~soft_write_data)); 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) | ({ADDRESS_BITS{update_HBA_PORT__PxSSTS}} & HBA_PORT__PxSSTS__SPD__ADDR) | ({ADDRESS_BITS{update_HBA_PORT__PxSERR}} & HBA_PORT__PxSERR__DIAG__X__ADDR) | ({ADDRESS_BITS{update_HBA_PORT__PxCMD}} & HBA_PORT__PxCMD__ICC__ADDR) | ({ADDRESS_BITS{update_HBA_PORT__PxCI}} & HBA_PORT__PxCI__CI__ADDR) | ({ADDRESS_BITS{update_GHC_GHC}} & GHC__GHC__AE__ADDR); //update_HBA_PORT__PxCI regs_din <= ({32{update_GHC__IS}} & {31'b0, ghc_is_r}) | ({32{update_HBA_PORT__PxIS}} & PxIS_r) | ({32{update_HBA_PORT__PxSSTS}} & {20'b0, PxSSTS_r[11:0]}) | ({32{update_HBA_PORT__PxSERR}} & PxSERR_r) | ({32{update_HBA_PORT__PxCMD}} & PxCMD_r) | ({32{update_HBA_PORT__PxCI}} & {31'b0, pxci0}) | ({32{update_GHC_GHC}} & (GHC__GHC__AE__DFLT | {30'b0, GHC_r})) ; regs_we <= update_GHC__IS || update_HBA_PORT__PxIS || update_HBA_PORT__PxSSTS || update_HBA_PORT__PxSERR | update_HBA_PORT__PxCMD || update_HBA_PORT__PxCI || update_GHC_GHC; // pending updates if (mrst) pxci_changed <= 1; //0; else if (pxci0_clear) pxci_changed <= 1; else if (update_HBA_PORT__PxCI) pxci_changed <= 0; if (mrst) ssts_changed <= 1; //0; else if (set_ssts_ipm || set_ssts_spd || set_ssts_det) ssts_changed <= 1; else if (update_HBA_PORT__PxSSTS) ssts_changed <= 0; if (mrst) serr_changed <= 1; //0; else if (|serr) serr_changed <= 1; else if (update_HBA_PORT__PxSERR) serr_changed <= 0; if (mrst) sirq_changed <= 1; //0; else if ((|sirq) || (|cirq)) sirq_changed <= 1; else if (update_HBA_PORT__PxIS) sirq_changed <= 0; if (mrst) pxcmd_changed <= 1; //0; else if (set_pxcmd) pxcmd_changed <= 1; else if (update_HBA_PORT__PxCMD) pxcmd_changed <= 0; if (mrst) ghc_is_changed <= 1; //0; else if (set_ghc_is_r) ghc_is_changed <= 1; else if (update_GHC__IS) ghc_is_changed <= 0; if (mrst) ghc_ghc_changed <= 1; //0; else if (set_ghc_is_r) ghc_ghc_changed <= 1; else if (update_GHC_GHC) ghc_ghc_changed <= 0; // updating registers if needed, 0 to 6 cycles, in priority sequence if (mrst) updating[6:1] <= 0; else if (update_all) updating[6:1] <= regs_changed[6:1] & ~update_first[6:1]; else updating[6:1] <= updating[6:1] & ~ update_next[6:1]; // detect software setting for PxCMD.ST 0->1 and 1->0 /* if (mrst) st01_pending <= 0; else if (swr_HBA_PORT__PxCMD && (HBA_PORT__PxCMD__ST__MASK & soft_write_data & ~PxCMD_r)) st01_pending <= 1; if (st_pending_reset) st01_pending <= 0; if (mrst) st10_pending <= 0; else if (swr_HBA_PORT__PxCMD && (HBA_PORT__PxCMD__ST__MASK & ~soft_write_data & PxCMD_r)) st10_pending <= 1; if (st_pending_reset) st10_pending <= 0; */ end endmodule