Commit 3dddcdb1 authored by Andrey Filippov's avatar Andrey Filippov

added files copied from x393_sata

parent 7f98f78f
, .INIT_00 (256'h0000000000000000000000000001030100000001000000008000000000240020)
, .INIT_08 (256'h000000000024000600000000000000000000000080000C000000000080000800)
, .INIT_09 (256'h000000000000000000000000000000000000000000000000FFFFFFFF00000000)
, .INIT_0B (256'h0000000000000000000000000000003300000000000000000000000000000000)
, .INIT_0C (256'h000000000000000000000000000000000000000001010002001000000001FFFE)
, .INIT_0D (256'h000001000000000000000040000000000001FFFE000000008000000000000000)
, .INIT_0E (256'h0000000000000000000000000000000000000000000000000000000040000001)
// RO: Device ID
localparam PCI_Header__ID__DID__ADDR = 'h60;
localparam PCI_Header__ID__DID__MASK = 'hffff0000;
localparam PCI_Header__ID__DID__DFLT = 'h10000;
// RO: Vendor ID
localparam PCI_Header__ID__VID__ADDR = 'h60;
localparam PCI_Header__ID__VID__MASK = 'hffff;
localparam PCI_Header__ID__VID__DFLT = 'hfffe;
// RW: HBA Interrupt Disable
localparam PCI_Header__CMD__ID__ADDR = 'h61;
localparam PCI_Header__CMD__ID__MASK = 'h400;
localparam PCI_Header__CMD__ID__DFLT = 'h0;
// RO: Fast Back-to-Back Enable
localparam PCI_Header__CMD__FBE__ADDR = 'h61;
localparam PCI_Header__CMD__FBE__MASK = 'h200;
localparam PCI_Header__CMD__FBE__DFLT = 'h0;
// RO: SERR Enable
localparam PCI_Header__CMD__SEE__ADDR = 'h61;
localparam PCI_Header__CMD__SEE__MASK = 'h100;
localparam PCI_Header__CMD__SEE__DFLT = 'h0;
// RO: Reserved
localparam PCI_Header__CMD__WCC__ADDR = 'h61;
localparam PCI_Header__CMD__WCC__MASK = 'h80;
localparam PCI_Header__CMD__WCC__DFLT = 'h0;
// RO: Parity Error Response Enable
localparam PCI_Header__CMD__PEE__ADDR = 'h61;
localparam PCI_Header__CMD__PEE__MASK = 'h40;
localparam PCI_Header__CMD__PEE__DFLT = 'h0;
// RO: Reserved
localparam PCI_Header__CMD__VGA__ADDR = 'h61;
localparam PCI_Header__CMD__VGA__MASK = 'h20;
localparam PCI_Header__CMD__VGA__DFLT = 'h0;
// RO: Reserved
localparam PCI_Header__CMD__MWIE__ADDR = 'h61;
localparam PCI_Header__CMD__MWIE__MASK = 'h10;
localparam PCI_Header__CMD__MWIE__DFLT = 'h0;
// RO: Reserved
localparam PCI_Header__CMD__SCE__ADDR = 'h61;
localparam PCI_Header__CMD__SCE__MASK = 'h8;
localparam PCI_Header__CMD__SCE__DFLT = 'h0;
// RW: Bus Master Enable (0 - stops any DMA)
localparam PCI_Header__CMD__BME__ADDR = 'h61;
localparam PCI_Header__CMD__BME__MASK = 'h4;
localparam PCI_Header__CMD__BME__DFLT = 'h0;
// RW: Memory Space enable (here - always?)
localparam PCI_Header__CMD__MSE__ADDR = 'h61;
localparam PCI_Header__CMD__MSE__MASK = 'h2;
localparam PCI_Header__CMD__MSE__DFLT = 'h0;
// RO: Enable IO space access (only for legacy IDE)
localparam PCI_Header__CMD__IOSE__ADDR = 'h61;
localparam PCI_Header__CMD__IOSE__MASK = 'h1;
localparam PCI_Header__CMD__IOSE__DFLT = 'h0;
// RWC: Detected Parity Error
localparam PCI_Header__STS__DPE__ADDR = 'h61;
localparam PCI_Header__STS__DPE__MASK = 'h80000000;
localparam PCI_Header__STS__DPE__DFLT = 'h0;
// RWC: Signaled System Error (HBA SERR)
localparam PCI_Header__STS__SSE__ADDR = 'h61;
localparam PCI_Header__STS__SSE__MASK = 'h40000000;
localparam PCI_Header__STS__SSE__DFLT = 'h0;
// RWC: Received Master Abort
localparam PCI_Header__STS__RMA__ADDR = 'h61;
localparam PCI_Header__STS__RMA__MASK = 'h20000000;
localparam PCI_Header__STS__RMA__DFLT = 'h0;
// RWC: Received Target Abort
localparam PCI_Header__STS__RTA__ADDR = 'h61;
localparam PCI_Header__STS__RTA__MASK = 'h10000000;
localparam PCI_Header__STS__RTA__DFLT = 'h0;
// RWC: Signaled Target Abort
localparam PCI_Header__STS__STA__ADDR = 'h61;
localparam PCI_Header__STS__STA__MASK = 'h8000000;
localparam PCI_Header__STS__STA__DFLT = 'h0;
// RO: PCI DEVSEL Timing
localparam PCI_Header__STS__DEVT__ADDR = 'h61;
localparam PCI_Header__STS__DEVT__MASK = 'h6000000;
localparam PCI_Header__STS__DEVT__DFLT = 'h0;
// RWC: Master Data Parity Error Detected
localparam PCI_Header__STS__DPD__ADDR = 'h61;
localparam PCI_Header__STS__DPD__MASK = 'h1000000;
localparam PCI_Header__STS__DPD__DFLT = 'h0;
// RO: Fast Back-To-Back Capable
localparam PCI_Header__STS__FBC__ADDR = 'h61;
localparam PCI_Header__STS__FBC__MASK = 'h800000;
localparam PCI_Header__STS__FBC__DFLT = 'h0;
// RO: 66 MHz Capable
localparam PCI_Header__STS__C66__ADDR = 'h61;
localparam PCI_Header__STS__C66__MASK = 'h200000;
localparam PCI_Header__STS__C66__DFLT = 'h0;
// RO: Capabilities List (PCI power management mandatory)
localparam PCI_Header__STS__CL__ADDR = 'h61;
localparam PCI_Header__STS__CL__MASK = 'h100000;
localparam PCI_Header__STS__CL__DFLT = 'h100000;
// RO: Interrupt Status (1 - asserted)
localparam PCI_Header__STS__IS__ADDR = 'h61;
localparam PCI_Header__STS__IS__MASK = 'h80000;
localparam PCI_Header__STS__IS__DFLT = 'h0;
// RO: HBA Revision ID
localparam PCI_Header__RID__RID__ADDR = 'h62;
localparam PCI_Header__RID__RID__MASK = 'hff;
localparam PCI_Header__RID__RID__DFLT = 'h2;
// RO: Base Class Code: 1 - Mass Storage Device
localparam PCI_Header__CC__BCC__ADDR = 'h62;
localparam PCI_Header__CC__BCC__MASK = 'hff000000;
localparam PCI_Header__CC__BCC__DFLT = 'h1000000;
// RO: Sub Class Code: 0x06 - SATA Device
localparam PCI_Header__CC__SCC__ADDR = 'h62;
localparam PCI_Header__CC__SCC__MASK = 'hff0000;
localparam PCI_Header__CC__SCC__DFLT = 'h60000;
// RO: Programming Interface: 1 - AHCI HBA major rev 1
localparam PCI_Header__CC__PI__ADDR = 'h62;
localparam PCI_Header__CC__PI__MASK = 'hff0000;
localparam PCI_Header__CC__PI__DFLT = 'h10000;
// RW: Cache Line Size
localparam PCI_Header__CLS__CLS__ADDR = 'h63;
localparam PCI_Header__CLS__CLS__MASK = 'hff;
localparam PCI_Header__CLS__CLS__DFLT = 'h0;
// RW: Master Latency Timer
localparam PCI_Header__MLT__MLT__ADDR = 'h63;
localparam PCI_Header__MLT__MLT__MASK = 'hff00;
localparam PCI_Header__MLT__MLT__DFLT = 'h0;
// RO: Multi-Function Device
localparam PCI_Header__HTYPE__MFDT__ADDR = 'h63;
localparam PCI_Header__HTYPE__MFDT__MASK = 'h8000;
localparam PCI_Header__HTYPE__MFDT__DFLT = 'h0;
// RO: Header Layout 0 - HBA uses a target device layout
localparam PCI_Header__HTYPE__HL__ADDR = 'h63;
localparam PCI_Header__HTYPE__HL__MASK = 'h7f00;
localparam PCI_Header__HTYPE__HL__DFLT = 'h0;
// RO: AHCI Base Address high bits, normally RW, but here RO to get to MAXIGP1 space
localparam PCI_Header__ABAR__BA__ADDR = 'h69;
localparam PCI_Header__ABAR__BA__MASK = 'hfffffff0;
localparam PCI_Header__ABAR__BA__DFLT = 'h80000000;
// RO: Prefetchable (this is not)
localparam PCI_Header__ABAR__PF__ADDR = 'h69;
localparam PCI_Header__ABAR__PF__MASK = 'h8;
localparam PCI_Header__ABAR__PF__DFLT = 'h0;
// RO: Type (0 - any 32-bit address, here it is hard-mapped
localparam PCI_Header__ABAR__TP__ADDR = 'h69;
localparam PCI_Header__ABAR__TP__MASK = 'h6;
localparam PCI_Header__ABAR__TP__DFLT = 'h0;
// RO: Resource Type Indicator: 0 - memory address
localparam PCI_Header__ABAR__RTE__ADDR = 'h69;
localparam PCI_Header__ABAR__RTE__MASK = 'h1;
localparam PCI_Header__ABAR__RTE__DFLT = 'h0;
// RO: SubSystem ID
localparam PCI_Header__SS__SSID__ADDR = 'h6b;
localparam PCI_Header__SS__SSID__MASK = 'hffff0000;
localparam PCI_Header__SS__SSID__DFLT = 'h10000;
// RO: SubSystem Vendor ID
localparam PCI_Header__SS__SSVID__ADDR = 'h6b;
localparam PCI_Header__SS__SSVID__MASK = 'hffff;
localparam PCI_Header__SS__SSVID__DFLT = 'hfffe;
// RO: ROM Base Address
localparam PCI_Header__EROM__RBA__ADDR = 'h6c;
localparam PCI_Header__EROM__RBA__MASK = 'hffffffff;
localparam PCI_Header__EROM__RBA__DFLT = 'h0;
// RO: Capabilities pointer
localparam PCI_Header__CAP__CAP__ADDR = 'h6d;
localparam PCI_Header__CAP__CAP__MASK = 'hff;
localparam PCI_Header__CAP__CAP__DFLT = 'h40;
// RO: Interrupt pin
localparam PCI_Header__INTR__IPIN__ADDR = 'h6f;
localparam PCI_Header__INTR__IPIN__MASK = 'hff00;
localparam PCI_Header__INTR__IPIN__DFLT = 'h100;
// RW: Interrupt Line
localparam PCI_Header__INTR__ILINE__ADDR = 'h6f;
localparam PCI_Header__INTR__ILINE__MASK = 'hff;
localparam PCI_Header__INTR__ILINE__DFLT = 'h0;
// RO: Minimal Grant
localparam PCI_Header__MGNT__MGNT__ADDR = 'h6f;
localparam PCI_Header__MGNT__MGNT__MASK = 'hff0000;
localparam PCI_Header__MGNT__MGNT__DFLT = 'h0;
// RO: Maximal Latency
localparam PCI_Header__MLAT__MLAT__ADDR = 'h6f;
localparam PCI_Header__MLAT__MLAT__MASK = 'hff000000;
localparam PCI_Header__MLAT__MLAT__DFLT = 'h0;
// RO: Next Capability pointer
localparam PMCAP__PID__NEXT__ADDR = 'h70;
localparam PMCAP__PID__NEXT__MASK = 'hff00;
localparam PMCAP__PID__NEXT__DFLT = 'h0;
// RO: This is PCI Power Management Capability
localparam PMCAP__PID__CID__ADDR = 'h70;
localparam PMCAP__PID__CID__MASK = 'hff;
localparam PMCAP__PID__CID__DFLT = 'h1;
// RO: PME_SUPPORT bits:'b01000
localparam PMCAP__PC__PSUP__ADDR = 'h70;
localparam PMCAP__PC__PSUP__MASK = 'hf8000000;
localparam PMCAP__PC__PSUP__DFLT = 'h40000000;
// RO: D2 Support - no
localparam PMCAP__PC__D2S__ADDR = 'h70;
localparam PMCAP__PC__D2S__MASK = 'h4000000;
localparam PMCAP__PC__D2S__DFLT = 'h0;
// RO: D1 Support - no
localparam PMCAP__PC__D1S__ADDR = 'h70;
localparam PMCAP__PC__D1S__MASK = 'h2000000;
localparam PMCAP__PC__D1S__DFLT = 'h0;
// RO: Maximal D3cold current
localparam PMCAP__PC__AUXC__ADDR = 'h70;
localparam PMCAP__PC__AUXC__MASK = 'h1c00000;
localparam PMCAP__PC__AUXC__DFLT = 'h0;
// RO: Device-specific initialization required
localparam PMCAP__PC__DSI__ADDR = 'h70;
localparam PMCAP__PC__DSI__MASK = 'h200000;
localparam PMCAP__PC__DSI__DFLT = 'h0;
// RO: PCI clock required to generate PME
localparam PMCAP__PC__PMEC__ADDR = 'h70;
localparam PMCAP__PC__PMEC__MASK = 'h80000;
localparam PMCAP__PC__PMEC__DFLT = 'h0;
// RO: Revision of Power Management Specification support version
localparam PMCAP__PC__VS__ADDR = 'h70;
localparam PMCAP__PC__VS__MASK = 'h70000;
localparam PMCAP__PC__VS__DFLT = 'h0;
// RWC: PME Status, set by hardware when HBA generates PME
localparam PMCAP__PMCS__PMES__ADDR = 'h71;
localparam PMCAP__PMCS__PMES__MASK = 'h8000;
localparam PMCAP__PMCS__PMES__DFLT = 'h0;
// RW: PME Enable
localparam PMCAP__PMCS__PMEE__ADDR = 'h71;
localparam PMCAP__PMCS__PMEE__MASK = 'h100;
localparam PMCAP__PMCS__PMEE__DFLT = 'h0;
// RW: Power State
localparam PMCAP__PMCS__PS__ADDR = 'h71;
localparam PMCAP__PMCS__PS__MASK = 'h3;
localparam PMCAP__PMCS__PS__DFLT = 'h0;
// RO: Supports 64-bit Addressing - no
localparam GHC__CAP__S64A__ADDR = 'h0;
localparam GHC__CAP__S64A__MASK = 'h80000000;
localparam GHC__CAP__S64A__DFLT = 'h0;
// RO: Supports Native Command Queuing - no
localparam GHC__CAP__SNCQ__ADDR = 'h0;
localparam GHC__CAP__SNCQ__MASK = 'h40000000;
localparam GHC__CAP__SNCQ__DFLT = 'h0;
// RO: Supports SNotification Register - no
localparam GHC__CAP__SSNTF__ADDR = 'h0;
localparam GHC__CAP__SSNTF__MASK = 'h20000000;
localparam GHC__CAP__SSNTF__DFLT = 'h0;
// RO: Supports Mechanical Presence Switch - no
localparam GHC__CAP__SMPS__ADDR = 'h0;
localparam GHC__CAP__SMPS__MASK = 'h10000000;
localparam GHC__CAP__SMPS__DFLT = 'h0;
// RO: Supports Staggered Spin-up - no
localparam GHC__CAP__SSS__ADDR = 'h0;
localparam GHC__CAP__SSS__MASK = 'h8000000;
localparam GHC__CAP__SSS__DFLT = 'h0;
// RO: Supports Aggressive Link Power Management - no
localparam GHC__CAP__SALP__ADDR = 'h0;
localparam GHC__CAP__SALP__MASK = 'h4000000;
localparam GHC__CAP__SALP__DFLT = 'h0;
// RO: Supports Activity LED - no
localparam GHC__CAP__SAL__ADDR = 'h0;
localparam GHC__CAP__SAL__MASK = 'h2000000;
localparam GHC__CAP__SAL__DFLT = 'h0;
// RO: Supports Command List Override - no (not capable of clearing BSY and DRQ bits, needs soft reset
localparam GHC__CAP__SCLO__ADDR = 'h0;
localparam GHC__CAP__SCLO__MASK = 'h1000000;
localparam GHC__CAP__SCLO__DFLT = 'h0;
// RO: Interface Maximal speed: 2 - Gen2, 3 - Gen3
localparam GHC__CAP__ISS__ADDR = 'h0;
localparam GHC__CAP__ISS__MASK = 'hf00000;
localparam GHC__CAP__ISS__DFLT = 'h200000;
// RO: AHCI only (0 - legacy too)
localparam GHC__CAP__SAM__ADDR = 'h0;
localparam GHC__CAP__SAM__MASK = 'h40000;
localparam GHC__CAP__SAM__DFLT = 'h40000;
// RO: Supports Port Multiplier - no
localparam GHC__CAP__SPM__ADDR = 'h0;
localparam GHC__CAP__SPM__MASK = 'h20000;
localparam GHC__CAP__SPM__DFLT = 'h0;
// RO: Supports FIS-based switching of the Port Multiplier - no
localparam GHC__CAP__FBSS__ADDR = 'h0;
localparam GHC__CAP__FBSS__MASK = 'h10000;
localparam GHC__CAP__FBSS__DFLT = 'h0;
// RO: PIO Multiple DRQ block - no
localparam GHC__CAP__PMD__ADDR = 'h0;
localparam GHC__CAP__PMD__MASK = 'h8000;
localparam GHC__CAP__PMD__DFLT = 'h0;
// RO: Slumber State Capable - no
localparam GHC__CAP__SSC__ADDR = 'h0;
localparam GHC__CAP__SSC__MASK = 'h4000;
localparam GHC__CAP__SSC__DFLT = 'h0;
// RO: Partial State Capable - no
localparam GHC__CAP__PSC__ADDR = 'h0;
localparam GHC__CAP__PSC__MASK = 'h2000;
localparam GHC__CAP__PSC__DFLT = 'h0;
// RO: Number of Command Slots, 0-based (0 means 1?)
localparam GHC__CAP__NSC__ADDR = 'h0;
localparam GHC__CAP__NSC__MASK = 'h1f00;
localparam GHC__CAP__NSC__DFLT = 'h0;
// RO: Command Completion Coalescing - no
localparam GHC__CAP__CCCS__ADDR = 'h0;
localparam GHC__CAP__CCCS__MASK = 'h80;
localparam GHC__CAP__CCCS__DFLT = 'h0;
// RO: Enclosure Management - no
localparam GHC__CAP__EMS__ADDR = 'h0;
localparam GHC__CAP__EMS__MASK = 'h40;
localparam GHC__CAP__EMS__DFLT = 'h0;
// RO: External SATA connector - yes
localparam GHC__CAP__SXS__ADDR = 'h0;
localparam GHC__CAP__SXS__MASK = 'h20;
localparam GHC__CAP__SXS__DFLT = 'h20;
// RO: Number of Ports, 0-based (0 means 1?)
localparam GHC__CAP__NP__ADDR = 'h0;
localparam GHC__CAP__NP__MASK = 'h1f;
localparam GHC__CAP__NP__DFLT = 'h0;
// RO: AHCI enable (0 - legacy)
localparam GHC__GHC__AE__ADDR = 'h1;
localparam GHC__GHC__AE__MASK = 'h80000000;
localparam GHC__GHC__AE__DFLT = 'h80000000;
// RO: MSI Revert to Single Message
localparam GHC__GHC__MRSM__ADDR = 'h1;
localparam GHC__GHC__MRSM__MASK = 'h4;
localparam GHC__GHC__MRSM__DFLT = 'h0;
// RW: Interrupt Enable (all ports)
localparam GHC__GHC__IE__ADDR = 'h1;
localparam GHC__GHC__IE__MASK = 'h2;
localparam GHC__GHC__IE__DFLT = 'h0;
// RW1: HBA reset (COMINIT, ...). Set by software, cleared by hardware, section 10.4.3
localparam GHC__GHC__HR__ADDR = 'h1;
localparam GHC__GHC__HR__MASK = 'h1;
localparam GHC__GHC__HR__DFLT = 'h0;
// RWC: Interrupt Pending Status (per port)
localparam GHC__IS__IPS__ADDR = 'h2;
localparam GHC__IS__IPS__MASK = 'hffffffff;
localparam GHC__IS__IPS__DFLT = 'h0;
// RO: Ports Implemented
localparam GHC__PI__PI__ADDR = 'h3;
localparam GHC__PI__PI__MASK = 'hffffffff;
localparam GHC__PI__PI__DFLT = 'h1;
// RO: AHCI Major Version 1.
localparam GHC__VS__MJR__ADDR = 'h4;
localparam GHC__VS__MJR__MASK = 'hffff0000;
localparam GHC__VS__MJR__DFLT = 'h10000;
// RO: AHCI Minor Version 3.1
localparam GHC__VS__MNR__ADDR = 'h4;
localparam GHC__VS__MNR__MASK = 'hffff;
localparam GHC__VS__MNR__DFLT = 'h301;
// RO: DevSleep Entrance from Slumber Only
localparam GHC__CAP2__DESO__ADDR = 'h9;
localparam GHC__CAP2__DESO__MASK = 'h20;
localparam GHC__CAP2__DESO__DFLT = 'h0;
// RO: Supports Aggressive Device Sleep Management
localparam GHC__CAP2__SADM__ADDR = 'h9;
localparam GHC__CAP2__SADM__MASK = 'h10;
localparam GHC__CAP2__SADM__DFLT = 'h0;
// RO: Supports Device Sleep
localparam GHC__CAP2__SDS__ADDR = 'h9;
localparam GHC__CAP2__SDS__MASK = 'h8;
localparam GHC__CAP2__SDS__DFLT = 'h0;
// RO: Automatic Partial to Slumber Transitions
localparam GHC__CAP2__APST__ADDR = 'h9;
localparam GHC__CAP2__APST__MASK = 'h4;
localparam GHC__CAP2__APST__DFLT = 'h0;
// RO: NVMHCI Present (section 10.15)
localparam GHC__CAP2__NVMP__ADDR = 'h9;
localparam GHC__CAP2__NVMP__MASK = 'h2;
localparam GHC__CAP2__NVMP__DFLT = 'h0;
// RO: BIOS/OS Handoff - not supported
localparam GHC__CAP2__BOH__ADDR = 'h9;
localparam GHC__CAP2__BOH__MASK = 'h1;
localparam GHC__CAP2__BOH__DFLT = 'h0;
// RW: Command List Base Address (1KB aligned)
localparam HBA_PORT__PxCLB__CLB__ADDR = 'h40;
localparam HBA_PORT__PxCLB__CLB__MASK = 'hfffffc00;
localparam HBA_PORT__PxCLB__CLB__DFLT = 'h80000800;
// RW: Command List Base Address (1KB aligned)
localparam HBA_PORT__PxFB__CLB__ADDR = 'h42;
localparam HBA_PORT__PxFB__CLB__MASK = 'hffffff00;
localparam HBA_PORT__PxFB__CLB__DFLT = 'h80000c00;
// RWC: Cold Port Detect Status
localparam HBA_PORT__PxIS__CPDS__ADDR = 'h44;
localparam HBA_PORT__PxIS__CPDS__MASK = 'h80000000;
localparam HBA_PORT__PxIS__CPDS__DFLT = 'h0;
// RWC: Task File Error Status
localparam HBA_PORT__PxIS__TFES__ADDR = 'h44;
localparam HBA_PORT__PxIS__TFES__MASK = 'h40000000;
localparam HBA_PORT__PxIS__TFES__DFLT = 'h0;
// RWC: Host Bus (PCI) Fatal error
localparam HBA_PORT__PxIS__HBFS__ADDR = 'h44;
localparam HBA_PORT__PxIS__HBFS__MASK = 'h20000000;
localparam HBA_PORT__PxIS__HBFS__DFLT = 'h0;
// RWC: ECC error R/W system memory
localparam HBA_PORT__PxIS__HBDS__ADDR = 'h44;
localparam HBA_PORT__PxIS__HBDS__MASK = 'h10000000;
localparam HBA_PORT__PxIS__HBDS__DFLT = 'h0;
// RWC: Interface Fatal Error Status (sect. 6.1.2)
localparam HBA_PORT__PxIS__IFS__ADDR = 'h44;
localparam HBA_PORT__PxIS__IFS__MASK = 'h8000000;
localparam HBA_PORT__PxIS__IFS__DFLT = 'h0;
// RWC: Interface Non-Fatal Error Status (sect. 6.1.2)
localparam HBA_PORT__PxIS__INFS__ADDR = 'h44;
localparam HBA_PORT__PxIS__INFS__MASK = 'h4000000;
localparam HBA_PORT__PxIS__INFS__DFLT = 'h0;
// RWC: Overflow Status
localparam HBA_PORT__PxIS__OFS__ADDR = 'h44;
localparam HBA_PORT__PxIS__OFS__MASK = 'h1000000;
localparam HBA_PORT__PxIS__OFS__DFLT = 'h0;
// RWC: Incorrect Port Multiplier Status
localparam HBA_PORT__PxIS__IPMS__ADDR = 'h44;
localparam HBA_PORT__PxIS__IPMS__MASK = 'h800000;
localparam HBA_PORT__PxIS__IPMS__DFLT = 'h0;
// RO: PhyRdy changed Status
localparam HBA_PORT__PxIS__PRCS__ADDR = 'h44;
localparam HBA_PORT__PxIS__PRCS__MASK = 'h400000;
localparam HBA_PORT__PxIS__PRCS__DFLT = 'h0;
// RWC: Device Mechanical Presence Status
localparam HBA_PORT__PxIS__DMPS__ADDR = 'h44;
localparam HBA_PORT__PxIS__DMPS__MASK = 'h80;
localparam HBA_PORT__PxIS__DMPS__DFLT = 'h0;
// RO: Port Connect Change Status
localparam HBA_PORT__PxIS__PCS__ADDR = 'h44;
localparam HBA_PORT__PxIS__PCS__MASK = 'h40;
localparam HBA_PORT__PxIS__PCS__DFLT = 'h0;
// RWC: Descriptor Processed
localparam HBA_PORT__PxIS__DPS__ADDR = 'h44;
localparam HBA_PORT__PxIS__DPS__MASK = 'h20;
localparam HBA_PORT__PxIS__DPS__DFLT = 'h0;
// RO: Unknown FIS
localparam HBA_PORT__PxIS__UFS__ADDR = 'h44;
localparam HBA_PORT__PxIS__UFS__MASK = 'h10;
localparam HBA_PORT__PxIS__UFS__DFLT = 'h0;
// RWC: Set Device Bits Interrupt - Set Device bits FIS with 'I' bit set
localparam HBA_PORT__PxIS__SDBS__ADDR = 'h44;
localparam HBA_PORT__PxIS__SDBS__MASK = 'h8;
localparam HBA_PORT__PxIS__SDBS__DFLT = 'h0;
// RWC: DMA Setup FIS Interrupt - DMA Setup FIS received with 'I' bit set
localparam HBA_PORT__PxIS__DSS__ADDR = 'h44;
localparam HBA_PORT__PxIS__DSS__MASK = 'h4;
localparam HBA_PORT__PxIS__DSS__DFLT = 'h0;
// RWC: PIO Setup FIS Interrupt - PIO Setup FIS received with 'I' bit set
localparam HBA_PORT__PxIS__PSS__ADDR = 'h44;
localparam HBA_PORT__PxIS__PSS__MASK = 'h2;
localparam HBA_PORT__PxIS__PSS__DFLT = 'h0;
// RWC: D2H Register FIS Interrupt - D2H Register FIS received with 'I' bit set
localparam HBA_PORT__PxIS__DHRS__ADDR = 'h44;
localparam HBA_PORT__PxIS__DHRS__MASK = 'h1;
localparam HBA_PORT__PxIS__DHRS__DFLT = 'h0;
// RW: Cold Port Detect Enable
localparam HBA_PORT__PxIE__CPDE__ADDR = 'h45;
localparam HBA_PORT__PxIE__CPDE__MASK = 'h80000000;
localparam HBA_PORT__PxIE__CPDE__DFLT = 'h0;
// RW: Task File Error Enable
localparam HBA_PORT__PxIE__TFEE__ADDR = 'h45;
localparam HBA_PORT__PxIE__TFEE__MASK = 'h40000000;
localparam HBA_PORT__PxIE__TFEE__DFLT = 'h0;
// RW: Host Bus (PCI) Fatal Error Enable
localparam HBA_PORT__PxIE__HBFE__ADDR = 'h45;
localparam HBA_PORT__PxIE__HBFE__MASK = 'h20000000;
localparam HBA_PORT__PxIE__HBFE__DFLT = 'h0;
// RW: ECC Error R/W System Memory Enable
localparam HBA_PORT__PxIE__HBDE__ADDR = 'h45;
localparam HBA_PORT__PxIE__HBDE__MASK = 'h10000000;
localparam HBA_PORT__PxIE__HBDE__DFLT = 'h0;
// RW: Interface Fatal Error Enable (sect. 6.1.2)
localparam HBA_PORT__PxIE__IFE__ADDR = 'h45;
localparam HBA_PORT__PxIE__IFE__MASK = 'h8000000;
localparam HBA_PORT__PxIE__IFE__DFLT = 'h0;
// RW: Interface Non-Fatal Error Enable (sect. 6.1.2)
localparam HBA_PORT__PxIE__INFE__ADDR = 'h45;
localparam HBA_PORT__PxIE__INFE__MASK = 'h4000000;
localparam HBA_PORT__PxIE__INFE__DFLT = 'h0;
// RW: Overflow Enable
localparam HBA_PORT__PxIE__OFE__ADDR = 'h45;
localparam HBA_PORT__PxIE__OFE__MASK = 'h1000000;
localparam HBA_PORT__PxIE__OFE__DFLT = 'h0;
// RW: Incorrect Port Multiplier Enable
localparam HBA_PORT__PxIE__IPME__ADDR = 'h45;
localparam HBA_PORT__PxIE__IPME__MASK = 'h800000;
localparam HBA_PORT__PxIE__IPME__DFLT = 'h0;
// RW: PhyRdy changed Enable
localparam HBA_PORT__PxIE__PRCE__ADDR = 'h45;
localparam HBA_PORT__PxIE__PRCE__MASK = 'h400000;
localparam HBA_PORT__PxIE__PRCE__DFLT = 'h0;
// RO: Device Mechanical Presence Interrupt Enable
localparam HBA_PORT__PxIE__DMPE__ADDR = 'h45;
localparam HBA_PORT__PxIE__DMPE__MASK = 'h80;
localparam HBA_PORT__PxIE__DMPE__DFLT = 'h0;
// RW: Port Connect Change Interrupt Enable
localparam HBA_PORT__PxIE__PCE__ADDR = 'h45;
localparam HBA_PORT__PxIE__PCE__MASK = 'h40;
localparam HBA_PORT__PxIE__PCE__DFLT = 'h0;
// RW: Descriptor Processed Interrupt Enable
localparam HBA_PORT__PxIE__DPE__ADDR = 'h45;
localparam HBA_PORT__PxIE__DPE__MASK = 'h20;
localparam HBA_PORT__PxIE__DPE__DFLT = 'h0;
// RW: Unknown FIS
localparam HBA_PORT__PxIE__UFE__ADDR = 'h45;
localparam HBA_PORT__PxIE__UFE__MASK = 'h10;
localparam HBA_PORT__PxIE__UFE__DFLT = 'h0;
// RW: Device Bits Interrupt Enable
localparam HBA_PORT__PxIE__SDBE__ADDR = 'h45;
localparam HBA_PORT__PxIE__SDBE__MASK = 'h8;
localparam HBA_PORT__PxIE__SDBE__DFLT = 'h0;
// RW: DMA Setup FIS Interrupt Enable
localparam HBA_PORT__PxIE__DSE__ADDR = 'h45;
localparam HBA_PORT__PxIE__DSE__MASK = 'h4;
localparam HBA_PORT__PxIE__DSE__DFLT = 'h0;
// RW: PIO Setup FIS Interrupt Enable
localparam HBA_PORT__PxIE__PSE__ADDR = 'h45;
localparam HBA_PORT__PxIE__PSE__MASK = 'h2;
localparam HBA_PORT__PxIE__PSE__DFLT = 'h0;
// RW: D2H Register FIS Interrupt Enable
localparam HBA_PORT__PxIE__DHRE__ADDR = 'h45;
localparam HBA_PORT__PxIE__DHRE__MASK = 'h1;
localparam HBA_PORT__PxIE__DHRE__DFLT = 'h0;
// RW: Interface Communication Control
localparam HBA_PORT__PxCMD__ICC__ADDR = 'h46;
localparam HBA_PORT__PxCMD__ICC__MASK = 'hf0000000;
localparam HBA_PORT__PxCMD__ICC__DFLT = 'h0;
// RO: Aggressive Slumber/Partial - not implemented
localparam HBA_PORT__PxCMD__ASP__ADDR = 'h46;
localparam HBA_PORT__PxCMD__ASP__MASK = 'h8000000;
localparam HBA_PORT__PxCMD__ASP__DFLT = 'h0;
// RO: Aggressive Link Power Management Enable - not implemented
localparam HBA_PORT__PxCMD__ALPE__ADDR = 'h46;
localparam HBA_PORT__PxCMD__ALPE__MASK = 'h4000000;
localparam HBA_PORT__PxCMD__ALPE__DFLT = 'h0;
// RW: Drive LED on ATAPI enable
localparam HBA_PORT__PxCMD__DLAE__ADDR = 'h46;
localparam HBA_PORT__PxCMD__DLAE__MASK = 'h2000000;
localparam HBA_PORT__PxCMD__DLAE__DFLT = 'h0;
// RW: Device is ATAPI (for activity LED)
localparam HBA_PORT__PxCMD__ATAPI__ADDR = 'h46;
localparam HBA_PORT__PxCMD__ATAPI__MASK = 'h1000000;
localparam HBA_PORT__PxCMD__ATAPI__DFLT = 'h0;
// RW: Automatic Partial to Slumber Transitions Enabled
localparam HBA_PORT__PxCMD__APSTE__ADDR = 'h46;
localparam HBA_PORT__PxCMD__APSTE__MASK = 'h800000;
localparam HBA_PORT__PxCMD__APSTE__DFLT = 'h0;
// RO: FIS-Based Switching Capable Port - not implemented
localparam HBA_PORT__PxCMD__FBSCP__ADDR = 'h46;
localparam HBA_PORT__PxCMD__FBSCP__MASK = 'h400000;
localparam HBA_PORT__PxCMD__FBSCP__DFLT = 'h0;
// RO: External SATA port
localparam HBA_PORT__PxCMD__ESP__ADDR = 'h46;
localparam HBA_PORT__PxCMD__ESP__MASK = 'h200000;
localparam HBA_PORT__PxCMD__ESP__DFLT = 'h200000;
// RO: Cold Presence Detection
localparam HBA_PORT__PxCMD__CPD__ADDR = 'h46;
localparam HBA_PORT__PxCMD__CPD__MASK = 'h100000;
localparam HBA_PORT__PxCMD__CPD__DFLT = 'h0;
// RO: Mechanical Presence Switch Attached to Port
localparam HBA_PORT__PxCMD__MPSP__ADDR = 'h46;
localparam HBA_PORT__PxCMD__MPSP__MASK = 'h80000;
localparam HBA_PORT__PxCMD__MPSP__DFLT = 'h0;
// RO: Hot Plug Capable Port
localparam HBA_PORT__PxCMD__HPCP__ADDR = 'h46;
localparam HBA_PORT__PxCMD__HPCP__MASK = 'h40000;
localparam HBA_PORT__PxCMD__HPCP__DFLT = 'h40000;
// RW: Port Multiplier Attached - not implemented (software should write this bit)
localparam HBA_PORT__PxCMD__PMA__ADDR = 'h46;
localparam HBA_PORT__PxCMD__PMA__MASK = 'h20000;
localparam HBA_PORT__PxCMD__PMA__DFLT = 'h0;
// RO: Cold Presence State
localparam HBA_PORT__PxCMD__CPS__ADDR = 'h46;
localparam HBA_PORT__PxCMD__CPS__MASK = 'h10000;
localparam HBA_PORT__PxCMD__CPS__DFLT = 'h0;
// RO: Command List Running (section 5.3.2)
localparam HBA_PORT__PxCMD__CR__ADDR = 'h46;
localparam HBA_PORT__PxCMD__CR__MASK = 'h8000;
localparam HBA_PORT__PxCMD__CR__DFLT = 'h0;
// RO: FIS Receive Running (section 10.3.2)
localparam HBA_PORT__PxCMD__FR__ADDR = 'h46;
localparam HBA_PORT__PxCMD__FR__MASK = 'h4000;
localparam HBA_PORT__PxCMD__FR__DFLT = 'h0;
// RO: Mechanical Presence Switch State
localparam HBA_PORT__PxCMD__MPSS__ADDR = 'h46;
localparam HBA_PORT__PxCMD__MPSS__MASK = 'h2000;
localparam HBA_PORT__PxCMD__MPSS__DFLT = 'h0;
// RO: Current Command Slot (when PxCMD.ST 1-> ) should be reset to 0, when 0->1 - highest priority is 0
localparam HBA_PORT__PxCMD__CCS__ADDR = 'h46;
localparam HBA_PORT__PxCMD__CCS__MASK = 'h1f00;
localparam HBA_PORT__PxCMD__CCS__DFLT = 'h0;
// RW: FIS Receive Enable (enable after FIS memory is set)
localparam HBA_PORT__PxCMD__FRE__ADDR = 'h46;
localparam HBA_PORT__PxCMD__FRE__MASK = 'h10;
localparam HBA_PORT__PxCMD__FRE__DFLT = 'h0;
// RW1: Command List Override
localparam HBA_PORT__PxCMD__CLO__ADDR = 'h46;
localparam HBA_PORT__PxCMD__CLO__MASK = 'h8;
localparam HBA_PORT__PxCMD__CLO__DFLT = 'h0;
// RO: Power On Device (RW with Cold Presence Detection)
localparam HBA_PORT__PxCMD__POD__ADDR = 'h46;
localparam HBA_PORT__PxCMD__POD__MASK = 'h4;
localparam HBA_PORT__PxCMD__POD__DFLT = 'h4;
// RO: Spin-Up Device (RW with Staggered Spin-Up Support)
localparam HBA_PORT__PxCMD__SUD__ADDR = 'h46;
localparam HBA_PORT__PxCMD__SUD__MASK = 'h2;
localparam HBA_PORT__PxCMD__SUD__DFLT = 'h2;
// RW: Start (HBA may process commands). See section 10.3.1
localparam HBA_PORT__PxCMD__ST__ADDR = 'h46;
localparam HBA_PORT__PxCMD__ST__MASK = 'h1;
localparam HBA_PORT__PxCMD__ST__DFLT = 'h0;
// RO: Latest Copy of Task File Error Register
localparam HBA_PORT__PxTFD__ERR__ADDR = 'h48;
localparam HBA_PORT__PxTFD__ERR__MASK = 'hff00;
localparam HBA_PORT__PxTFD__ERR__DFLT = 'h0;
// RO: Latest Copy of Task File Status Register: BSY
localparam HBA_PORT__PxTFD__STS__BSY__ADDR = 'h48;
localparam HBA_PORT__PxTFD__STS__BSY__MASK = 'h80;
localparam HBA_PORT__PxTFD__STS__BSY__DFLT = 'h0;
// RO: Latest Copy of Task File Status Register: command-specific bits 4..6
localparam HBA_PORT__PxTFD__STS__64__ADDR = 'h48;
localparam HBA_PORT__PxTFD__STS__64__MASK = 'h70;
localparam HBA_PORT__PxTFD__STS__64__DFLT = 'h0;
// RO: Latest Copy of Task File Status Register: DRQ
localparam HBA_PORT__PxTFD__STS__DRQ__ADDR = 'h48;
localparam HBA_PORT__PxTFD__STS__DRQ__MASK = 'h8;
localparam HBA_PORT__PxTFD__STS__DRQ__DFLT = 'h0;
// RO: Latest Copy of Task File Status Register: command-specific bits 1..2
localparam HBA_PORT__PxTFD__STS__12__ADDR = 'h48;
localparam HBA_PORT__PxTFD__STS__12__MASK = 'h6;
localparam HBA_PORT__PxTFD__STS__12__DFLT = 'h0;
// RO: Latest Copy of Task File Status Register: ERR
localparam HBA_PORT__PxTFD__STS__ERR__ADDR = 'h48;
localparam HBA_PORT__PxTFD__STS__ERR__MASK = 'h1;
localparam HBA_PORT__PxTFD__STS__ERR__DFLT = 'h0;
// RO: Data in the first D2H Register FIS
localparam HBA_PORT__PxSIG__SIG__ADDR = 'h49;
localparam HBA_PORT__PxSIG__SIG__MASK = 'hffffffff;
localparam HBA_PORT__PxSIG__SIG__DFLT = 'hffffffff;
// RO: Interface Power Management
localparam HBA_PORT__PxSSTS__IPM__ADDR = 'h4a;
localparam HBA_PORT__PxSSTS__IPM__MASK = 'hf00;
localparam HBA_PORT__PxSSTS__IPM__DFLT = 'h0;
// RO: Interface Speed
localparam HBA_PORT__PxSSTS__SPD__ADDR = 'h4a;
localparam HBA_PORT__PxSSTS__SPD__MASK = 'hf0;
localparam HBA_PORT__PxSSTS__SPD__DFLT = 'h0;
// RO: Device Detection (should be detected if COMINIT is received)
localparam HBA_PORT__PxSSTS__DET__ADDR = 'h4a;
localparam HBA_PORT__PxSSTS__DET__MASK = 'hf;
localparam HBA_PORT__PxSSTS__DET__DFLT = 'h0;
// RO: Port Multiplier Port - not used by AHCI
localparam HBA_PORT__PxSCTL__PMP__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__PMP__MASK = 'hf0000;
localparam HBA_PORT__PxSCTL__PMP__DFLT = 'h0;
// RO: Select Power Management - not used by AHCI
localparam HBA_PORT__PxSCTL__SPM__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__SPM__MASK = 'hf000;
localparam HBA_PORT__PxSCTL__SPM__DFLT = 'h0;
// RW: Interface Power Management Transitions Allowed
localparam HBA_PORT__PxSCTL__IPM__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__IPM__MASK = 'hf00;
localparam HBA_PORT__PxSCTL__IPM__DFLT = 'h0;
// RW: Interface Highest Speed
localparam HBA_PORT__PxSCTL__SPD__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__SPD__MASK = 'hf0;
localparam HBA_PORT__PxSCTL__SPD__DFLT = 'h0;
// RW: Device Detection Initialization
localparam HBA_PORT__PxSCTL__DET__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__DET__MASK = 'hf;
localparam HBA_PORT__PxSCTL__DET__DFLT = 'h0;
// RWC: Exchanged (set on COMINIT), reflected in PxIS.PCS
localparam HBA_PORT__PxSERR__DIAG__X__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__X__MASK = 'h4000000;
localparam HBA_PORT__PxSERR__DIAG__X__DFLT = 'h0;
// RWC: Unknown FIS
localparam HBA_PORT__PxSERR__DIAG__F__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__F__MASK = 'h2000000;
localparam HBA_PORT__PxSERR__DIAG__F__DFLT = 'h0;
// RWC: Transport state transition error
localparam HBA_PORT__PxSERR__DIAG__T__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__T__MASK = 'h1000000;
localparam HBA_PORT__PxSERR__DIAG__T__DFLT = 'h0;
// RWC: Link sequence error
localparam HBA_PORT__PxSERR__DIAG__S__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__S__MASK = 'h800000;
localparam HBA_PORT__PxSERR__DIAG__S__DFLT = 'h0;
// RWC: Handshake Error (i.e. Device got CRC error)
localparam HBA_PORT__PxSERR__DIAG__H__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__H__MASK = 'h400000;
localparam HBA_PORT__PxSERR__DIAG__H__DFLT = 'h0;
// RWC: CRC error in Link layer
localparam HBA_PORT__PxSERR__DIAG__C__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__C__MASK = 'h200000;
localparam HBA_PORT__PxSERR__DIAG__C__DFLT = 'h0;
// RWC: Disparity Error - not used by AHCI
localparam HBA_PORT__PxSERR__DIAG__D__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__D__MASK = 'h100000;
localparam HBA_PORT__PxSERR__DIAG__D__DFLT = 'h0;
// RWC: 10B to 8B decode error
localparam HBA_PORT__PxSERR__DIAG__B__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__B__MASK = 'h80000;
localparam HBA_PORT__PxSERR__DIAG__B__DFLT = 'h0;
// RWC: COMMWAKE signal was detected
localparam HBA_PORT__PxSERR__DIAG__W__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__W__MASK = 'h40000;
localparam HBA_PORT__PxSERR__DIAG__W__DFLT = 'h0;
// RWC: PHY Internal Error
localparam HBA_PORT__PxSERR__DIAG__I__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__I__MASK = 'h20000;
localparam HBA_PORT__PxSERR__DIAG__I__DFLT = 'h0;
// RWC: PhyRdy changed. Reflected in PxIS.PRCS bit.
localparam HBA_PORT__PxSERR__DIAG__N__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__DIAG__N__MASK = 'h10000;
localparam HBA_PORT__PxSERR__DIAG__N__DFLT = 'h0;
// RWC: Internal Error
localparam HBA_PORT__PxSERR__ERR__E__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__ERR__E__MASK = 'h800;
localparam HBA_PORT__PxSERR__ERR__E__DFLT = 'h0;
// RWC: Protocol Error - a violation of SATA protocol detected
localparam HBA_PORT__PxSERR__ERR__P__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__ERR__P__MASK = 'h400;
localparam HBA_PORT__PxSERR__ERR__P__DFLT = 'h0;
// RWC: Persistent Communication or Data Integrity Error
localparam HBA_PORT__PxSERR__ERR__C__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__ERR__C__MASK = 'h200;
localparam HBA_PORT__PxSERR__ERR__C__DFLT = 'h0;
// RWC: Transient Data Integrity Error (error not recovered by the interface)
localparam HBA_PORT__PxSERR__ERR__T__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__ERR__T__MASK = 'h100;
localparam HBA_PORT__PxSERR__ERR__T__DFLT = 'h0;
// RWC: Communication between the device and host was lost but re-established
localparam HBA_PORT__PxSERR__ERR__M__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__ERR__M__MASK = 'h2;
localparam HBA_PORT__PxSERR__ERR__M__DFLT = 'h0;
// RWC: Recovered Data integrity Error
localparam HBA_PORT__PxSERR__ERR__I__ADDR = 'h4c;
localparam HBA_PORT__PxSERR__ERR__I__MASK = 'h1;
localparam HBA_PORT__PxSERR__ERR__I__DFLT = 'h0;
// RW1: Device Status: bit per Port, for TAG in native queued command
localparam HBA_PORT__PxSACT__DS__ADDR = 'h4d;
localparam HBA_PORT__PxSACT__DS__MASK = 'hffffffff;
localparam HBA_PORT__PxSACT__DS__DFLT = 'h0;
// RW1: Command Issued: bit per Port, only set when PxCMD.ST==1, also cleared by PxCMD.ST: 1->0 by soft
localparam HBA_PORT__PxCI__CI__ADDR = 'h4e;
localparam HBA_PORT__PxCI__CI__MASK = 'hffffffff;
localparam HBA_PORT__PxCI__CI__DFLT = 'h0;
// RWC: PM Notify (bit per PM port)
localparam HBA_PORT__PxSNTF__PMN__ADDR = 'h4f;
localparam HBA_PORT__PxSNTF__PMN__MASK = 'hffff;
localparam HBA_PORT__PxSNTF__PMN__DFLT = 'h0;
// RO: Device with Error
localparam HBA_PORT__PxFBS__DWE__ADDR = 'h50;
localparam HBA_PORT__PxFBS__DWE__MASK = 'hf0000;
localparam HBA_PORT__PxFBS__DWE__DFLT = 'h0;
// RO: Active Device Optimization
localparam HBA_PORT__PxFBS__ADO__ADDR = 'h50;
localparam HBA_PORT__PxFBS__ADO__MASK = 'hf000;
localparam HBA_PORT__PxFBS__ADO__DFLT = 'h0;
// RW: Device To Issue
localparam HBA_PORT__PxFBS__DEV__ADDR = 'h50;
localparam HBA_PORT__PxFBS__DEV__MASK = 'hf00;
localparam HBA_PORT__PxFBS__DEV__DFLT = 'h0;
// RO: Single Device Error
localparam HBA_PORT__PxFBS__SDE__ADDR = 'h50;
localparam HBA_PORT__PxFBS__SDE__MASK = 'h4;
localparam HBA_PORT__PxFBS__SDE__DFLT = 'h0;
// RW1: Device Error Clear
localparam HBA_PORT__PxFBS__DEC__ADDR = 'h50;
localparam HBA_PORT__PxFBS__DEC__MASK = 'h2;
localparam HBA_PORT__PxFBS__DEC__DFLT = 'h0;
// RW: Enable
localparam HBA_PORT__PxFBS__EN__ADDR = 'h50;
localparam HBA_PORT__PxFBS__EN__MASK = 'h1;
localparam HBA_PORT__PxFBS__EN__DFLT = 'h0;
// RO: DITO Multiplier
localparam HBA_PORT__PxDEVSLP__DM__ADDR = 'h51;
localparam HBA_PORT__PxDEVSLP__DM__MASK = 'h1e000000;
localparam HBA_PORT__PxDEVSLP__DM__DFLT = 'h0;
// RW: Device Sleep Idle Timeout (section 8.5.1.1.1)
localparam HBA_PORT__PxDEVSLP__DITO__ADDR = 'h51;
localparam HBA_PORT__PxDEVSLP__DITO__MASK = 'h1ff8000;
localparam HBA_PORT__PxDEVSLP__DITO__DFLT = 'h0;
// RW: Minimum Device Sleep Assertion Time
localparam HBA_PORT__PxDEVSLP__MDAT__ADDR = 'h51;
localparam HBA_PORT__PxDEVSLP__MDAT__MASK = 'h7c00;
localparam HBA_PORT__PxDEVSLP__MDAT__DFLT = 'h0;
// RW: Device Sleep Exit Timeout
localparam HBA_PORT__PxDEVSLP__DETO__ADDR = 'h51;
localparam HBA_PORT__PxDEVSLP__DETO__MASK = 'h3fc;
localparam HBA_PORT__PxDEVSLP__DETO__DFLT = 'h0;
// RO: Device Sleep Present
localparam HBA_PORT__PxDEVSLP__DSP__ADDR = 'h51;
localparam HBA_PORT__PxDEVSLP__DSP__MASK = 'h2;
localparam HBA_PORT__PxDEVSLP__DSP__DFLT = 'h0;
// RO: Aggressive Device Sleep Enable
localparam HBA_PORT__PxDEVSLP__ADSE__ADDR = 'h51;
localparam HBA_PORT__PxDEVSLP__ADSE__MASK = 'h1;
localparam HBA_PORT__PxDEVSLP__ADSE__DFLT = 'h0;
// RW: SAXIHP write channel cache mode
localparam HBA_PORT__AFI_CACHE__WR_CM__ADDR = 'h5c;
localparam HBA_PORT__AFI_CACHE__WR_CM__MASK = 'hf0;
localparam HBA_PORT__AFI_CACHE__WR_CM__DFLT = 'h30;
// RW: SAXIHP read channel cache mode
localparam HBA_PORT__AFI_CACHE__RD_CM__ADDR = 'h5c;
localparam HBA_PORT__AFI_CACHE__RD_CM__MASK = 'hf;
localparam HBA_PORT__AFI_CACHE__RD_CM__DFLT = 'h3;
// RW: Address/not data for programming AHCI state machine
localparam HBA_PORT__PGM_AHCI_SM__AnD__ADDR = 'h5d;
localparam HBA_PORT__PGM_AHCI_SM__AnD__MASK = 'h1000000;
localparam HBA_PORT__PGM_AHCI_SM__AnD__DFLT = 'h0;
// RW: Program address/data for programming AHCI state machine
localparam HBA_PORT__PGM_AHCI_SM__PGM_AD__ADDR = 'h5d;
localparam HBA_PORT__PGM_AHCI_SM__PGM_AD__MASK = 'h3ffff;
localparam HBA_PORT__PGM_AHCI_SM__PGM_AD__DFLT = 'h0;
// RW: 3-bit tag to add to the recorded timestamp
localparam HBA_PORT__PunchTime__TAG__ADDR = 'h5e;
localparam HBA_PORT__PunchTime__TAG__MASK = 'h7;
localparam HBA_PORT__PunchTime__TAG__DFLT = 'h0;
, .INIT_00 (256'h0000000000000000AAAAAAAAAAAAAAAA00000000000000070000000000000000)
, .INIT_10 (256'h0000000000000000555555555555000000000000000000005555555555500000)
, .INIT_11 (256'h000000000000000055054004000001C15551500000001555AAA28000000088AA)
, .INIT_12 (256'h0000000000555555000000000000000000000000000000000000000000000000)
, .INIT_13 (256'h00000000AAAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF002AAAAA00AA000A)
, .INIT_14 (256'h000000000000000000000000000000000001555555555550000000000055000D)
, .INIT_17 (256'h5555555555555555000000000000001500010005555555550000000000005555)
, .INIT_18 (256'h00000000000055550000000000000000AA820000001000140000000000000000)
, .INIT_1B (256'h0000000000005555000000000000000000000000000000000000000000000000)
, .INIT_1C (256'h0000000000000000000000000000000000000000800100050000000000000000)
, .INIT_00 (256'h00100000000E0000000C02020035000000220000000C0000000A0000000C0000)
, .INIT_01 (256'h1C3C9449543244190060001B0108001B00500402040401040022000600120000)
, .INIT_02 (256'h001BC8300014000C0210002B2507250E0180001B0003004200180000001B4455)
, .INIT_03 (256'h4C6B2C45141B0012003C01080028000A040800220410001B01020110001B0005)
, .INIT_04 (256'h0210001B14490102005004020404003CB080707D00A0003C8C6E845584C7443A)
, .INIT_05 (256'h000000512507250E0240004F2507250E0240005F0000003C0000001B0210003C)
, .INIT_06 (256'h02200204006E0402009000EEA89968FC18F518D498B058E0388564570C27045B)
, .INIT_07 (256'h003CB0800000005300840022003CB080707D307A30FC02080074D10E5104903C)
, .INIT_08 (256'h2891290A0000000000000014021000892507250E018000A2D1070120003C0000)
, .INIT_09 (256'h0CB6290A0210009D2507250E04400053000C009700050097C895002200440097)
, .INIT_0A (256'h00530081005348AE00220044003C48AE28AA290A0000000000000024003C4882)
, .INIT_0B (256'h0044008800BED1075104042000BA883C08A2003000B6021000B42507250E0240)
, .INIT_0C (256'h0048021000CEC50E2507250700C000C90030003C88A200300009003C88A250C3)
, .INIT_0D (256'h003C34DB000000DD001100DDC8DB021000D82507250E0140003C88A250C30044)
, .INIT_0E (256'h250E0480005301010053C8EC290A0000000000000014021000E42507250E0280)
, .INIT_0F (256'h01002507250E024001020082021000F92507250E0240003C0401021000F22507)
, .INIT_10 (256'h00410410010C0000010C0201010C00210410010C002100840102000001020210)
, .INIT_11 (256'h000000000000000000000000000000000000000000000000000000000000003C)
, .INITP_00 (256'h08802605C240900789C9C8888A000C25062040820809C8020188800222222222)
, .INITP_01 (256'h27209C82720A00270882271A009C86068072E22721816802A89C882068009C32)
, .INITP_02 (256'h0000000000000000000000000000000000000000000000000000000082220822)
// FIS types (low byte of the first DWORD)
localparam FIS_H2DR = 'h27;
localparam FIS_D2HR = 'h34;
localparam FIS_DMAA = 'h39;
localparam FIS_DMAS = 'h41;
localparam FIS_DATA = 'h46;
localparam FIS_BIST = 'h58;
localparam FIS_PIOS = 'h5f;
localparam FIS_SDB = 'ha1;
/*******************************************************************************
* 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)
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 differtnt 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
/*******************************************************************************
* Module: ahci_dma
* Date:2016-01-01
* Author: Andrey Filippov
* Description: DMA R/W over 64-AXI channel for AHCI implementation
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_dma.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_dma.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module ahci_dma (
// input rst,
input mrst, // @posedge mclk - sync reset
input hrst, // @posedge hclk - sync reset
input mclk, // for command/status
input hclk, // global clock to run axi_hp @ 150MHz
// Control interface (@mclk)
// Documentation insists 6 LSBs should be 0, but AHCI driver seems to ignore it. Will align to just 128 bits.
// input [31:7] ctba, // command table base address
input [31:4] ctba, // command table base address
input ctba_ld, // load command table base address
input [15:0] prdtl, // number of entries in PRD table (valid at cmd_start)
input dev_wr, // write to device (valid at start)
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: Will keep afi_rready on until RD FIFO is empty and
// afi_awvalid (slowly one by one?) until afi_wacount is empty, keeping afi_wlast on
// Optional control of the AXI cache mode, default will be set to 4'h3, 4'h3 at mrst
input [3:0] axi_wr_cache_mode,
input [3:0] axi_rd_cache_mode,
input set_axi_wr_cache_mode,
input set_axi_rd_cache_mode,
// Some data from the command table will be used internally, data will be available on the general
// sys_out[31:0] port and should be consumed
output reg ct_busy, // cleared after 0x20 DWORDs are read out
// reading out command table data
input [ 4:0] ct_addr, // DWORD address
input [ 1:0] ct_re, // [0] - re, [1]-regen
output reg [31:0] ct_data, //
// 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, // @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, // @ mclk
output abort_busy,
output abort_done,
output axi_mismatch, // axi hp counters where empty when calculated counters were not (handled, but seems to be a bug - catch it)
// Data System memory -> HBA interface @ mclk
output [31:0] sys_out, // 32-bit data from the system memory to HBA (dma data)
output sys_dav, // at least one dword is ready to be read
// output sys_dav_many, // several DWORDs are in the FIFO (TODO: decide how many)
input sys_re, // sys_out data read, advance internal FIFO
output last_h2d_data,// when active and no new data for 2 clocks - that was the last one
// Data HBA -> System memory interface @ mclk
input [31:0] sys_in, // HBA -> system memory
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,
output afi_awvalid,
input afi_awready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_awid,
output [ 1:0] afi_awlock,
output reg [ 3:0] afi_awcache,
output [ 2:0] afi_awprot,
output [ 3:0] afi_awlen,
output [ 1:0] afi_awsize,
output [ 1:0] afi_awburst,
output [ 3:0] afi_awqos,
// write data
output [63:0] afi_wdata,
output afi_wvalid,
input afi_wready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_wid,
output afi_wlast,
output [ 7:0] afi_wstrb,
// write response
input afi_bvalid, // @SuppressThisWarning VEditor unused
output afi_bready,
input [ 5:0] afi_bid, // @SuppressThisWarning VEditor unused
input [ 1:0] afi_bresp, // @SuppressThisWarning VEditor unused
// PL extra (non-AXI) signals
input [ 7:0] afi_wcount,
input [ 5:0] afi_wacount,
output afi_wrissuecap1en,
// AXI_HP signals - read channel
// read address
output [31:0] afi_araddr,
output afi_arvalid,
input afi_arready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_arid,
output [ 1:0] afi_arlock,
output reg [ 3:0] afi_arcache,
output [ 2:0] afi_arprot,
output [ 3:0] afi_arlen,
output [ 1:0] afi_arsize,
output [ 1:0] afi_arburst,
output [ 3:0] afi_arqos,
// read data
input [63:0] afi_rdata,
input afi_rvalid,
output afi_rready,
input [ 5:0] afi_rid, // @SuppressThisWarning VEditor unused
input afi_rlast, // @SuppressThisWarning VEditor unused
input [ 1:0] afi_rresp, // @SuppressThisWarning VEditor unused
// PL extra (non-AXI) signals
input [ 7:0] afi_rcount,
input [ 2:0] afi_racount,
output afi_rdissuecap1en,
output [31:0] debug_out,
output [31:0] debug_out1
,output [31:0] debug_dma_h2d
);
// Read command table
// localparam AFI_FIFO_LAT = 2; // >=2
localparam SAFE_RD_BITS = 3; //2; // 3;
reg [31:0] ct_data_ram [0:31];
reg [3:0] int_data_addr; // internal (ct,prd) data address
// reg [31:7] ctba_r;
reg [31:4] ctba_r; // Seems that AHCI driver ignores requirement to have 6 LSB==0
reg [15:0] prdtl_mclk;
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
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
wire ct_done;
wire first_prd_fetch; // CT read done, prd enabled
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) && !axi_set_raddr_r); // Most pessimistic
wire axi_set_waddr_ready = !afi_wacount[5] && !afi_wacount[4]; // What is the size of wa fifo - just 32? Using just half - safe
wire axi_set_raddr_w;
wire axi_set_waddr_w;
wire axi_set_addr_data_w;
reg axi_set_raddr_r; // [0] - actual write address to fifo
reg axi_set_waddr_r; // [0] - actual write address to fifo
reg is_ct_addr; // current address is ct address
reg is_prd_addr; // current address is prd address
reg is_data_addr; // current address is data address (r or w)
reg [31:1] data_addr; // 2 lower addresses will be used in in/out fifo modules
reg [3:0] data_len; //
reg data_irq; // interrupt at the end of this PRD
reg [21:1] wcount; // Word count
reg wcount_set;
reg [22:1] qwcount; // only [21:3] are used ([22] - carry from subtraction )
reg qwcount_done;
reg [21:3] qw_datawr_left;
reg [ 3:0] qw_datawr_burst;
reg qw_datawr_last;
wire data_afi_re;
reg [15:0] prds_left;
reg last_prd;
reg [1:0] afi_rd_ctl; // read non-data (CT or PRD)
reg [1:0] ct_busy_r;
reg prd_rd_busy; // reading PRD
reg dev_wr_mclk;
reg dev_wr_hclk;
reg prd_wr; // write PRD data to memory
reg prd_rd; // read PRD data from memory
wire [3:0] afi_wstb4;
wire done_dev_wr; // finished PRD mem -> device
wire done_dev_rd; // finished PRD device -> mem
wire prd_done_hclk = done_dev_wr || done_dev_rd;
wire done_flush; // done flushing last partial dword
wire cmd_done_hclk;
wire ct_done_mclk;
reg [3:0] afi_alen;
wire afi_wcount_many = !afi_wcount[7] && !(&afi_wcount[6:4]);
reg data_next_burst;
// wire raddr_prd_rq = (|prds_left) && (ct_done || prd_done);
wire raddr_prd_rq = (|prds_left) && (first_prd_fetch || prd_done_hclk);
reg raddr_prd_pend;
wire raddr_ct_rq = cmd_start_hclk;
reg raddr_ct_pend;
/*
wire addr_data_rq = (wcount_set || data_next_burst);
wire waddr_data_rq = !dev_wr_hclk && addr_data_rq;
wire raddr_data_rq = dev_wr_hclk && addr_data_rq;
*/
wire addr_data_rq_w = (wcount_set || data_next_burst);
reg addr_data_rq_r;
wire waddr_data_rq = !dev_wr_hclk && addr_data_rq_r;
wire raddr_data_rq = dev_wr_hclk && addr_data_rq_r;
reg waddr_data_pend;
reg raddr_data_pend;
// count different types of AXI ID separately - just for debugging
reg [3:0] ct_id;
reg [3:0] prd_id;
reg [3:0] dev_wr_id;
reg [3:0] dev_rd_id;
reg [5:0] afi_id; // common for 3 channels
wire fifo_nempty_mclk;
reg en_extra_din_r;
reg [31:0] ct_data_reg;
// reg abort_busy_hclk;
reg hrst_r;
wire abort_or_reset = cmd_abort_hclk || (hrst_r && !hrst);
// reg axi_dirty_r; // afi_wacount of afi_rcount are non-zero (assuming afi_wcount should be zero as addresses are posted first
wire afi_dirty;
reg afi_dirty_mclk;
wire abort_done_hclk;
wire abort_done_mclk;
reg abort_done_unneeded;
wire aborting;
wire afi_wvalid_data;
wire afi_wvalid_abort;
wire [5:0] afi_wid_abort;
wire afi_rready_abort;
wire afi_wlast_abort;
// wire abort_done;
reg abort_rq_mclk;
reg abort_busy_mclk;
wire [21:0] abort_debug;
reg rwaddr_rq_r; // next cycle after requesting waddr_data_rq, raddr_data_rq, raddr_ct_rq and raddr_prd_rq (*-pend is valid)
assign afi_wvalid = aborting ? afi_wvalid_abort: afi_wvalid_data;
assign afi_wid = aborting ? afi_wid_abort: afi_id;
assign afi_rready = aborting ? afi_rready_abort : (afi_rd_ctl[0] || data_afi_re);
assign afi_wlast = aborting ? afi_wlast_abort: qw_datawr_last;
assign abort_done = abort_done_mclk || abort_done_unneeded;
assign abort_busy = abort_busy_mclk;
// 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) && last_prd);
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_waddr_w = axi_set_raddr_ready && raddr_data_pend;
assign axi_set_waddr_w = 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);
assign afi_awaddr = afi_addr;
assign afi_araddr = afi_addr;
assign afi_arlen = afi_alen;
assign afi_awlen = afi_alen;
assign afi_arvalid = axi_set_raddr_r;
assign afi_awvalid = axi_set_waddr_r;
/// assign afi_rready = afi_rd_ctl[0] || data_afi_re;
assign afi_wstrb = {{2{afi_wstb4[3]}},{2{afi_wstb4[2]}},{2{afi_wstb4[1]}},{2{afi_wstb4[0]}}};
/// assign afi_wlast = qw_datawr_last;
assign afi_awid = afi_id;
// assign afi_wid = afi_id;
assign afi_arid = afi_id;
// Unused or static output signals
assign afi_bready = 1'b1;
assign afi_awlock = 2'h0;
// assign afi_awcache = 4'h3;
assign afi_awprot = 3'h0;
assign afi_awsize = 2'h3;
assign afi_awburst = 2'h1;
assign afi_awqos = 4'h0;
assign afi_wrissuecap1en = 1'b0;
assign afi_arlock = 2'h0;
// assign afi_arcache = 4'h3;
assign afi_arprot = 3'h0;
assign afi_arsize = 2'h3;
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;
// reg [31:0] ct_data_reg;
always @ (posedge mclk) begin
if (mrst) afi_dirty_mclk <= 0;
afi_dirty_mclk <=afi_dirty;
abort_rq_mclk <= cmd_abort && afi_dirty_mclk;
abort_done_unneeded <= cmd_abort && !afi_dirty_mclk;
if (mrst || abort_done) abort_busy_mclk <= 0;
else if (cmd_abort) abort_busy_mclk <= 1;
if (ct_re[0]) ct_data_reg <= ct_data_ram[ct_addr];
if (ct_re[1]) ct_data <= ct_data_reg;
// if (ctba_ld) ctba_r <= ctba[31:7];
if (ctba_ld) ctba_r <= ctba[31:4];
if (cmd_start) prdtl_mclk <= prdtl;
if (cmd_start) dev_wr_mclk <= dev_wr;
if (mrst || cmd_abort) cmd_busy <= 0;
else if (cmd_start) cmd_busy <= 1;
else if (cmd_done) cmd_busy <= 0;
if (mrst || cmd_abort) ct_busy <= 0;
else if (cmd_start) ct_busy <= 1;
else if (ct_done_mclk) ct_busy <= 0;
if (mrst) afi_arcache <= 4'h3;
else if (set_axi_rd_cache_mode) afi_arcache <= axi_rd_cache_mode;
if (mrst) afi_awcache <= 4'h3;
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
// afi_rd_ctl <= { afi_rd_ctl[0],(ct_busy_r[0] || prd_rd_busy) && ((|afi_rcount[7:SAFE_RD_BITS]) || (afi_rvalid && !(|afi_rd_ctl)))};
wire debug_01 = ct_busy_r[0] || prd_rd_busy ;
wire debug_02 =|afi_rcount[7:SAFE_RD_BITS];
wire debug_03 = (afi_rvalid && !(|afi_rd_ctl));
wire [21:1] wcount_plus_data_addr = wcount[21:1] + data_addr[2:1];
always @ (posedge hclk) begin
hrst_r <= hrst;
if (hrst) rwaddr_rq_r <= 0;
else rwaddr_rq_r <= raddr_ct_rq || raddr_prd_rq || raddr_data_rq || waddr_data_rq;
addr_data_rq_r <= addr_data_rq_w;
prd_start_hclk_r <= prd_start_hclk;
if (hrst || abort_or_reset) prd_enabled <= 0;
else if (prd_start_hclk_r) prd_enabled <= 1; // precedence 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:4];
else if (ct_done) ct_maddr[31:4] <= ct_maddr[31:4] + 8; // 16;
else if (wcount_set) ct_maddr[31:4] <= ct_maddr[31:4] + 1;
// overall sequencing makes sure that there will be no new requests until older served
// additionally they are mutuially exclusive - only one may be pending at a time
if (hrst || cmd_abort_hclk) raddr_ct_pend <= 0;
else if (raddr_ct_rq) raddr_ct_pend <= 1;
else if (axi_set_raddr_ready) raddr_ct_pend <= 0;
if (hrst || cmd_abort_hclk) raddr_prd_pend <= 0;
else if (raddr_prd_rq) raddr_prd_pend <= 1;
else if (axi_set_raddr_ready) raddr_prd_pend <= 0;
if (hrst || cmd_abort_hclk) raddr_data_pend <= 0;
else if (raddr_data_rq) raddr_data_pend <= 1;
else if (axi_set_raddr_ready) raddr_data_pend <= 0;
if (hrst || cmd_abort_hclk) waddr_data_pend <= 0;
else if (waddr_data_rq) waddr_data_pend <= 1;
else if (axi_set_waddr_ready) waddr_data_pend <= 0;
if (hrst) {is_ct_addr, is_prd_addr, is_data_addr} <= 0;
else if (raddr_ct_rq || raddr_prd_rq || wcount_set) {is_ct_addr, is_prd_addr, is_data_addr} <= {raddr_ct_rq, raddr_prd_rq, wcount_set};
/// if (axi_set_raddr_w || axi_set_waddr_w) begin
if (rwaddr_rq_r) begin // first cycle one of the *_pend is set
if (raddr_data_pend || waddr_data_pend) afi_addr <= {data_addr[31:3], 3'b0};
else afi_addr <= {ct_maddr[31:4], 4'b0};
if (raddr_data_pend || waddr_data_pend) afi_alen <= data_len;
else if (raddr_ct_pend) afi_alen <= 4'hf; // 16 QWORDS (128 bytes)
else afi_alen <= 4'h1; // 2 QWORDS
if (raddr_data_pend || waddr_data_pend) afi_id <= raddr_data_pend ? {2'h2, dev_rd_id} : {2'h3, dev_wr_id};
else afi_id <= raddr_ct_pend ? {2'h0, ct_id} : {2'h1, prd_id};
end
if (hrst) axi_set_raddr_r <= 0;
else axi_set_raddr_r <= axi_set_raddr_w;
if (hrst) axi_set_waddr_r <= 0;
else axi_set_waddr_r <= axi_set_waddr_w;
/// if (addr_data_rq) data_len <= ((|qwcount[21:7]) || (&qwcount[6:3]))? 4'hf: qwcount[6:3]; // early calculate
if (addr_data_rq_r) data_len <= ((|qwcount[21:7]) || (&qwcount[6:3]))? 4'hf: qwcount[6:3]; // early calculate
if (wcount_set) qwcount[22:7] <= {1'b0,wcount_plus_data_addr[21:7]}; // wcount[21:1] + data_addr[2:1]; //minus 1
else if (axi_set_addr_data_w) qwcount[22:7] <= qwcount[22:7] - 1; // may get negative
if (wcount_set) qwcount[ 6:1] <= wcount_plus_data_addr[6:1]; // wcount[21:1] + data_addr[2:1]; //minus 1
if (wcount_set) qwcount_done <= 0;
else if (axi_set_addr_data_w && (qwcount[21:7]==0)) qwcount_done <= 1;
//wcount_plus_data_addr
/// data_next_burst <= !qwcount[22] && axi_set_addr_data_w && (|qwcount[21:7]); // same time as afi_awvalid || afi_arvalid
data_next_burst <= !qwcount_done && axi_set_addr_data_w && (|qwcount[21:7]); // same time as afi_awvalid || afi_arvalid
// Get PRD data
// store data address from PRD, increment when needed
if (afi_rd_ctl[0] && is_prd_addr && (!int_data_addr[0])) data_addr[31:1] <= afi_rdata[31:1];
if (axi_set_addr_data_w) data_addr[31:7] <= data_addr[31:7] + 1;
if (afi_rd_ctl[0] && is_prd_addr && (int_data_addr[0])) data_irq <= afi_rdata[63];
if (afi_rd_ctl[0] && is_prd_addr && (int_data_addr[0])) wcount[21:1] <= afi_rdata[53:33];
wcount_set <= afi_rd_ctl[0] && is_prd_addr && (int_data_addr[0]);
if (cmd_start_hclk) prds_left <= prdtl_mclk;
else if (raddr_prd_rq) prds_left <= prds_left - 1;
if (raddr_prd_rq) last_prd <= prds_left[15:1] == 0;
// Set/increment address to store (internally) CT and PRD data
if (axi_set_raddr_r) int_data_addr <= 0;
else if (afi_rd_ctl[0] && !is_data_addr) int_data_addr <= int_data_addr + 1;
if (afi_rd_ctl[0] && is_ct_addr) {ct_data_ram[{int_data_addr,1'b1}],ct_data_ram[{int_data_addr,1'b0}]} <= afi_rdata; // make sure it is synthesized correctly
// generate busy for command table (CT) read
if (hrst) ct_busy_r[0] <= 0;
else if (cmd_start_hclk) ct_busy_r[0] <= 1;
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
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
if (hrst) prd_rd_busy <= 0;
// else if (prd_rd_busy) prd_rd_busy <= 1;
else if (raddr_prd_rq && axi_set_raddr_ready) prd_rd_busy <= 1;
else if (wcount_set) prd_rd_busy <= 0;
if (cmd_start_hclk) dev_wr_hclk <= dev_wr_mclk; // 1: memory -> device, 0: device -> memory
prd_wr <= wcount_set && !dev_wr_hclk;
prd_rd <= wcount_set && dev_wr_hclk;
afi_rd_ctl <= { afi_rd_ctl[0],(ct_busy_r[0] || prd_rd_busy) && ((|afi_rcount[7:SAFE_RD_BITS]) || (afi_rvalid && !(|afi_rd_ctl)))};
// calculate afi_wlast - it is (qw_datawr_burst == 0), just use register qw_datawr_last
if (prd_wr) qw_datawr_last <= (qwcount[21:3] == 0);
else if (afi_wvalid_data) qw_datawr_last <= (qw_datawr_burst == 1) || (qw_datawr_last && (qw_datawr_left[21:3] == 16)); // last case - n*16 + 1 (last burst single)
if (prd_wr) qw_datawr_burst <= (|qwcount[21:7])? 4'hf: qwcount[6:3];
else if (afi_wvalid_data && qw_datawr_last && (qw_datawr_left[21:7] == 1)) qw_datawr_burst <= qw_datawr_left[6:3]; // if not last roll over to 'hf
else if (afi_wvalid_data) qw_datawr_burst <= qw_datawr_burst - 1;
if (prd_wr) qw_datawr_left[21:3] <= qwcount[21:3];
else if (afi_wvalid_data && qw_datawr_last) qw_datawr_left[21:7] <= qw_datawr_left[21:7] - 1; // can go negative - OK?
// Count AXI IDs
if (hrst) ct_id <= 0;
else if (ct_busy_r==2'b10) ct_id <= ct_id + 1;
if (hrst) prd_id <= 0;
else if (wcount_set) prd_id <= prd_id + 1;
if (hrst) dev_wr_id <= 0;
else if (done_dev_wr) dev_wr_id <= dev_wr_id + 1;
if (hrst) dev_rd_id <= 0;
else if (done_dev_rd) dev_rd_id <= dev_rd_id + 1;
end
// Flushing AXI HP - there is no easy way to reset it, so if there was an error in SATA communication we need to read any data
// that was already requested (over AXI read adderss channel) and send junk data (with appropriate afi_wlast bit) to the write
// channel. THis module is not reset and even bitsteram relaod will not work, so hrst input is used just as disable paying attention
// to other inputs, doe s not reset anything inside.
// FPGA should not be reset /reloaded if there are any outstanding transactions not aborted
// Current implementation counts all transactions and relies on it - not on afi_*count. TODO: Implement recovering from mismatch
axi_hp_abort axi_hp_abort_i (
.hclk (hclk), // input
.hrst (hrst), // input
.abort (abort_or_reset), // input
.busy (aborting), // output
.done (abort_done_hclk), // output reg
.afi_awvalid (afi_awvalid), // input
.afi_awready (afi_awready), // input
.afi_awid (afi_awid), // input[5:0]
.afi_awlen (afi_awlen), // input[3:0]
.afi_wvalid_in (afi_wvalid), // input
.afi_wready (afi_wready), // input
.afi_wvalid (afi_wvalid_abort), // output
.afi_wid (afi_wid_abort), // output[5:0] reg
.afi_arvalid (afi_arvalid), // input
.afi_arready (afi_arready), // input
.afi_arlen (afi_arlen), // input[3:0]
.afi_rready_in (afi_rready), // input
.afi_rvalid (afi_rvalid), // input
.afi_rready (afi_rready_abort), // output
.afi_wlast (afi_wlast_abort), // output
.afi_racount (afi_racount), // input[2:0]
.afi_rcount (afi_rcount), // input[7:0]
.afi_wacount (afi_wacount), // input[5:0]
.afi_wcount (afi_wcount), // input[7:0]
.dirty (afi_dirty), // output reg
.axi_mismatch (axi_mismatch), // output_reg
.debug (abort_debug) // output[21:0]
);
ahci_dma_rd_fifo #( // memory to device
.WCNT_BITS (21),
.ADDRESS_BITS (3)
) ahci_dma_rd_fifo_i (
.mrst (mrst || abort_busy_mclk), // input
.hrst (hrst || cmd_abort_hclk), // input
.mclk (mclk), // input
.hclk (hclk), // input
.wcnt (wcount[21:1]), // input[20:0]
.woffs (data_addr[2:1]), // input[1:0]
.start (prd_rd), // input
.din (afi_rdata), // input[63:0]
.din_av (afi_rvalid), // input
.din_av_many (|afi_rcount[7:SAFE_RD_BITS]), // input
.last_prd (last_prd), // input
.din_re (data_afi_re), // output
.done (done_dev_wr), // output reg // @ hclk
.done_flush (done_flush), // output // @ hclk
.dout (sys_out), // output[31:0]
.dout_vld (sys_dav), // output
.dout_re (sys_re), // input
.last_DW (last_h2d_data) // output
,.debug_dma_h2d(debug_dma_h2d) // output[31:0]
);
ahci_dma_wr_fifo #( // device to memory
.WCNT_BITS (21),
.ADDRESS_BITS (3)
) ahci_dma_wr_fifo_i (
.mrst (mrst || abort_busy_mclk), // input
.hrst (hrst ||cmd_abort_hclk), // input
.mclk (mclk), // input
.hclk (hclk), // input
.wcnt (wcount[21:1]), // input[20:0]
.woffs (data_addr[2:1]), // input[1:0]
.init (cmd_start_hclk), // input
.start (prd_wr), // input
.dout (afi_wdata), // output[63:0] reg
// .dout_av (), // input
.dout_av_many (afi_wcount_many), // input
.last_prd (last_prd), // input
.dout_we (afi_wvalid_data), // output
.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
);
// mclk -> hclk cross-clock synchronization
pulse_cross_clock #(
.EXTRA_DLY(0)
) cmd_start_hclk_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (cmd_start), // input
.out_pulse (cmd_start_hclk), // output
.busy() // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) cmd_abort_hclk_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (abort_rq_mclk), // input
.out_pulse (cmd_abort_hclk), // 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;
pulse_cross_clock #(
.EXTRA_DLY(0)
) cmd_done_i (
.rst (hrst), // input
.src_clk (hclk), // input
.dst_clk (mclk), // input
.in_pulse (cmd_done_hclk), // input
.out_pulse (cmd_done), // output
.busy() // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) ct_done_mclk_i (
.rst (hrst), // input
.src_clk (hclk), // input
.dst_clk (mclk), // input
.in_pulse (ct_done), // input
.out_pulse (ct_done_mclk), // output
.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 (prd_done_hclk), // input
.out_pulse (prd_done), // output
.busy() // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) abort_done_i (
.rst (hrst), // input
.src_clk (hclk), // input
.dst_clk (mclk), // input
.in_pulse (abort_done_hclk), // input
.out_pulse (abort_done_mclk), // output
.busy() // output
);
//abort_done_hclk
reg [7:0] dbg_afi_awvalid_cntr;
reg [7:0] dbg_qwcount;
reg [7:0] dbg_qwcount_cntr;
reg [7:0] dbg_set_raddr_count;
reg [7:0] dbg_set_waddr_count;
reg dbg_was_mismatch;
// if (axi_set_raddr_w || axi_set_waddr_w) begin
//data_next_burst
always @ (posedge hclk) begin
if (hrst) dbg_afi_awvalid_cntr <= 0;
else if (axi_set_waddr_r) dbg_afi_awvalid_cntr <= dbg_afi_awvalid_cntr + 1;
// if (hrst) dbg_last_afi_len <= 0;
if (axi_set_raddr_w || axi_set_waddr_w) begin
end
if (wcount_set) dbg_qwcount <= wcount_plus_data_addr[14:7];
// if (wcount_set) qwcount[22:7] <= {1'b0,wcount_plus_data_addr[21:7]}; // wcount[21:1] + data_addr[2:1]; //minus 1
if (hrst) dbg_qwcount_cntr <= 0;
// else if (wcount_set) dbg_qwcount_cntr <= dbg_qwcount_cntr + 1;
// else if (data_next_burst) dbg_qwcount_cntr <= dbg_qwcount_cntr + 1;
else if (!qwcount[22] && axi_set_addr_data_w && (|qwcount[21:7])) dbg_qwcount_cntr <= dbg_qwcount_cntr + 1;
if (hrst) dbg_set_raddr_count <= 0;
// else if (axi_set_raddr_w) dbg_set_raddr_count <= dbg_set_raddr_count + 1;
else if (axi_set_raddr_ready && raddr_data_pend) dbg_set_raddr_count <= dbg_set_raddr_count + 1;
if (hrst) dbg_set_waddr_count <= 0;
// else if (axi_set_waddr_w) dbg_set_waddr_count <= dbg_set_waddr_count + 1;
// else if (axi_set_waddr_ready && waddr_data_pend) dbg_set_waddr_count <= dbg_set_waddr_count + 1; //0x14
else if (addr_data_rq_w) dbg_set_waddr_count <= dbg_set_waddr_count + 1; //0x14
if (hrst) dbg_was_mismatch <= 0;
else if (axi_mismatch) dbg_was_mismatch <= 1;
end
assign debug_out = {int_data_addr [3:0],
qwcount_done, // prd_rd_busy,
afi_racount [2:0],
//--
afi_rcount [7:0],
//--
ct_busy,
cmd_busy,
afi_wacount [5:0],
//--
afi_wcount [7:0]};
/*
assign debug_out = {
qwcount[22:7],
dev_rd_id,
dev_wr_id,
prd_id,
ct_id
};
assign debug_out = {qwcount_done,
2'b0,
dev_wr_id,
prd_id,
wcount[21:1]
};
assign debug_out1 = { //dbg_set_raddr_count[7:0],
qwcount_done,
afi_rcount[6:0],
//{qwcount[22], qwcount[13:7]},
dbg_set_waddr_count[7:0],
dbg_qwcount[3:0],
afi_alen[3:0],
dbg_qwcount_cntr[7:0]};
*/
assign debug_out1 = { //dbg_set_raddr_count[7:0]
8'b0 ,
dbg_was_mismatch,
1'b0,
abort_debug[21:0]}; // {aw_count[5:0], w_count[7:0], r_count[7:0]};
//
endmodule
/*******************************************************************************
* Module: ahci_dma_rd_fifo
* Date:2016-01-01
* Author: Andrey Filippov
* Description: cross clocks, word-realign, 64->32
* Convertion from x64 QWORD-aligned AXI data @hclk to
* 32-bit word-aligned data at mclk
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_dma_rd_fifo.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_dma_rd_fifo.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module ahci_dma_rd_fifo#(
parameter WCNT_BITS = 21,
parameter ADDRESS_BITS = 3
)(
input mrst,
input hrst,
input mclk,
input hclk,
// hclk domain
input [WCNT_BITS-1:0] wcnt, // decrementing word counter, 0- based (0 need 1, 1 - need 2, ...) valid @ start
input [1:0] woffs, // 2 LSBs of the initial word address - valid @ start
input start, // start transfer
input [63:0] din,
input din_av,
input din_av_many,
input last_prd, // last prd, flush partial dword if there were odd number of words transferred. valid @ start
// Or maybe use "last_prd"?
output din_re,
output reg done, // this PRD data sent to cross-clock FIFO (may result in only half-dword sent out),
// OK to fetch another PRD (if it was not the last)
output done_flush, // finished last PRD (indicated by last_prd @ start), data left module
// mclk domain
output [31:0] dout,
output dout_vld,
input dout_re,
output last_DW // dout contains last DW
,output [31:0] debug_dma_h2d
);
localparam ADDRESS_NUM = (1<<ADDRESS_BITS); // 8 for ADDRESS_BITS==3
reg [ADDRESS_BITS : 0] waddr; // 1 extra bit
// reg [ADDRESS_BITS+1:0] raddr; // 1 extra bit
reg [ADDRESS_BITS+1:0] raddr_r; // 1 extra bit
wire [ADDRESS_BITS+1:0] raddr_w; // 1 extra bit
reg [63:16] din_prev; // only 48 bits are needed
reg [WCNT_BITS-3:0] qwcntr;
reg busy;
wire [2:0] end_offs = wcnt[1:0] + woffs;
reg [63:0] fifo_ram [0: ADDRESS_NUM - 1];
reg [3:0] vld_ram [0: ADDRESS_NUM - 1];
reg [(1<<ADDRESS_BITS)-1:0] fifo_full; // set in write clock domain
reg [(1<<ADDRESS_BITS)-1:0] fifo_nempty;// set in read clock domain
wire fifo_wr;
wire fifo_rd;
reg [1:0] fifo_rd_r;
reg mrst_hclk;
wire [(1<<ADDRESS_BITS)-1:0] fifo_full2 = {~fifo_full[0],fifo_full[ADDRESS_NUM-1:1]};
reg fifo_dav; // @mclk
wire fifo_dav2_w;
reg fifo_dav2; // @mclk
reg fifo_half_hclk; // Half Fifo is empty, OK to write
reg [1:0] woffs_r;
wire [63:0] fifo_di= woffs_r[1]?(woffs_r[0] ? {din[47:0],din_prev[63:48]} : {din[31:0],din_prev[63:32]}):
(woffs_r[0] ? {din[15:0],din_prev[63:16]} : din[63:0]);
wire [3:0] fifo_di_vld;
// wire [63:0] fifo_do = fifo_ram [raddr[ADDRESS_BITS:1]];
// wire [3:0] fifo_do_vld = vld_ram [raddr[ADDRESS_BITS:1]];
reg [63:0] fifo_do_r;
reg [3:0] fifo_do_vld_r;
reg din_av_safe_r;
reg en_fifo_wr;
reg [3:0] last_mask;
wire done_flush_mclk;
reg flushing_hclk; // flushing data, ends when confirmed from mclk domain
reg flushing_mclk; // just registered flushing_hclk @mclk
wire last_fifo_wr;
assign din_re = busy && fifo_half_hclk && din_av_safe_r;
assign fifo_wr = en_fifo_wr && fifo_half_hclk && (din_av_safe_r || !busy);
assign fifo_di_vld = last_fifo_wr? last_mask : 4'hf;
wire [2:0] debug_waddr = waddr[2:0];
wire [2:0] debug_raddr = raddr_r[3:1];
// just for gtkwave - same names
wire [ADDRESS_BITS+1:0] raddr = raddr_r;
wire [63:0] fifo_do = fifo_do_r;
wire [3:0] fifo_do_vld = fifo_do_vld_r;
// assign fifo_dav2_w = fifo_full2[raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS+1];
/// assign fifo_dav2_w = fifo_full2[raddr_r[ADDRESS_BITS:1]] ^ raddr_r[ADDRESS_BITS+1];
assign fifo_dav2_w = fifo_full2[raddr_w[ADDRESS_BITS:1]] ^ raddr_w[ADDRESS_BITS+1];
assign last_fifo_wr = !busy || ((qwcntr == 0) && ((woffs == 0) || end_offs[2])); // ((qwcntr != 0) || ((woffs != 0) && last_prd));
always @ (posedge hclk) begin
if (hrst) mrst_hclk <= 0;
else mrst_hclk <= mrst;
if (mrst_hclk) busy <= 0;
else if (start) busy <= 1;
else if (din_re && (qwcntr == 0)) busy <= 0;
done <= busy && din_re && (qwcntr == 0);
if (mrst_hclk) en_fifo_wr <= 0;
else if (start) en_fifo_wr <= (woffs == 0);
else if (din_re || fifo_wr) en_fifo_wr <= busy && ((qwcntr != 0) || ((woffs != 0) && !end_offs[2]));
if (start) qwcntr <= wcnt[WCNT_BITS-1:2] + end_offs[2];
else if (din_re) qwcntr <= qwcntr - 1;
if (start) woffs_r <= woffs;
if (mrst_hclk) fifo_full <= 0;
else if (fifo_wr) fifo_full <= {fifo_full[ADDRESS_NUM-2:0],~waddr[ADDRESS_BITS]};
if (mrst_hclk) waddr <= 0;
else if (fifo_wr) waddr <= waddr+1;
fifo_half_hclk <= fifo_nempty [waddr[ADDRESS_BITS-1:0]] ^ waddr[ADDRESS_BITS];
if (din_re) din_prev[63:16] <= din[63:16];
if (fifo_wr) fifo_ram[waddr[ADDRESS_BITS-1:0]] <= fifo_di;
if (fifo_wr) vld_ram [waddr[ADDRESS_BITS-1:0]] <= fifo_di_vld;
// if (fifo_wr) flush_ram[waddr[ADDRESS_BITS-1:0]] <= fifo_di_flush;
if (mrst_hclk) din_av_safe_r <= 0;
else din_av_safe_r <= din_av && (din_av_many || !din_re);
if (start) last_mask <= {&wcnt[1:0], wcnt[1], |wcnt[1:0], 1'b1};
if (mrst_hclk || done_flush) flushing_hclk <= 0;
else if (fifo_wr && last_prd && (((qwcntr == 0) && ((woffs == 0) || !last_prd)) || !busy)) flushing_hclk <= 1;
end
assign raddr_w = mrst ? 0 : (raddr_r + fifo_rd);
always @ (posedge mclk) begin
fifo_rd_r <= {fifo_rd_r[0],fifo_rd};
// if (mrst) raddr <= 0;
// else if (fifo_rd) raddr <= raddr + 1;
raddr_r <= raddr_w;
if (mrst) fifo_nempty <= {{(ADDRESS_NUM>>1){1'b0}},{(ADDRESS_NUM>>1){1'b1}}};// 8'b00001111
// else if (fifo_rd && raddr[0]) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0], ~raddr[ADDRESS_BITS+1] ^ raddr[ADDRESS_BITS]};
else if (fifo_rd && raddr_r[0]) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0], ~raddr_r[ADDRESS_BITS+1] ^ raddr_r[ADDRESS_BITS]};
// fifo_dav <= fifo_full [raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS+1];
/// fifo_dav <= fifo_full [raddr_r[ADDRESS_BITS:1]] ^ raddr_r[ADDRESS_BITS+1];
fifo_dav <= fifo_full [raddr_w[ADDRESS_BITS:1]] ^ raddr_w[ADDRESS_BITS+1];
fifo_dav2 <= fifo_dav2_w; // fifo_full2[raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS+1];
if (mrst) flushing_mclk <= 0;
else flushing_mclk <= flushing_hclk;
fifo_do_r <= fifo_ram [raddr_w[ADDRESS_BITS:1]];
fifo_do_vld_r <= vld_ram [raddr_w[ADDRESS_BITS:1]];
end
ahci_dma_rd_stuff ahci_dma_rd_stuff_i (
.rst (mrst), // input
.clk (mclk), // input
.din_av (fifo_dav), // input
.din_avm_w(fifo_dav2_w), // input
.din_avm (fifo_dav2), // input
.flushing (flushing_mclk), // input
// .din (raddr[0]?fifo_do[63:32]: fifo_do[31:0]), // input[31:0]
// .dm (raddr[0]?fifo_do_vld[3:2]:fifo_do_vld[1:0]), // input[1:0]
.din (raddr_r[0]?fifo_do_r[63:32]: fifo_do_r[31:0]), // input[31:0]
.dm (raddr_r[0]?fifo_do_vld_r[3:2]:fifo_do_vld_r[1:0]), // input[1:0]
.din_re (fifo_rd), // output
.flushed (done_flush_mclk), // output reg: flush (end of last PRD is finished - data left module)
.dout (dout), // output[31:0] reg
.dout_vld (dout_vld), // output
.dout_re (dout_re), // input
.last_DW (last_DW) // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) done_flush_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (done_flush_mclk), // input
.out_pulse (done_flush), // output
.busy() // output
);
assign debug_dma_h2d = {
14'b0,
fifo_rd,
raddr_r[4:0],
fifo_do_vld_r[3:0],
fifo_dav,
fifo_dav2_w,
fifo_dav2,
flushing_mclk,
done_flush_mclk,
dout_vld,
dout_re,
last_DW
};
endmodule
/*******************************************************************************
* Module: ahci_dma_rd_stuff
* Date:2016-01-01
* Author: andrey
* Description: Stuff DWORD data with missing words into continuous 32-bit data
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_dma_rd_stuff.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_dma_rd_stuff.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module ahci_dma_rd_stuff(
input rst, // sync reset
input clk, // single clock
input din_av, // input data available
input din_avm_w,// >1 word of data available (early)
input din_avm, // >1 word of data available (registered din_avm_w)
input flushing, // output partial dword if available (should be ? cycles after last _re/ with data?)
input [31:0] din, // 32-bit input dfata
input [1:0] dm, // data mask showing which (if any) words in input dword are valid
output din_re, // read input data
output flushed, // flush (end of last PRD is finished - data left module)
output reg [31:0] dout, // output 32-bit data
output dout_vld, // output data valid
input dout_re, // consumer reads output data (should be AND-ed with dout_vld)
output last_DW
);
reg [15:0] hr; // holds 16-bit data from previous din_re if not consumed
reg hr_full;
reg [1:0] dout_vld_r;
reg din_av_safe_r;
reg din_re_r;
wire [1:0] dav_in = {2{din_av_safe_r}} & dm;
wire [1:0] drd_in = {2{din_re}} & dm;
wire [15:0] debug_din_low = din[15: 0];
wire [15:0] debug_din_high = din[31:16];
wire [15:0] debug_dout_low = dout[15: 0];
wire [15:0] debug_dout_high = dout[31:16];
// wire empty_in = din_av_safe_r && !(|dm);
// wire two_words_avail = &dav_in || (|dav_in && hr_full);
wire more_words_avail = |dav_in || hr_full;
wire [1:0] next_or_empty = {2{dout_re}} | ~dout_vld_r;
/// assign din_re = (din_av_safe_r && !(|dm)) || ((!dout_vld_r || dout_re) && (two_words_avail)) ; // flush
// ---------------
wire room_for2 = dout_re || (!(&dout_vld_r) && !hr_full) || !(|dout_vld_r);
wire room_for1 = dout_re || !hr_full || !(&dout_vld_r);
reg slow_down; // first time fifo almost empty
reg slow_dav; // enable dout_vld waiting after each read out not to miss last DWORD
reg last_DW_r;
reg last_dw_sent;
wire no_new_data_w;
reg [1:0] no_new_data_r;
assign din_re = din_av_safe_r && (!(|dm) || room_for2 || (room_for1 && !(&dm)));
/// assign dout_vld = (&dout_vld_r) || ((|dout_vld_r) && flushing);
assign dout_vld = (!slow_down && (&dout_vld_r)) || slow_dav;
assign last_DW = last_DW_r;
assign flushed = last_DW_r && dout_re;
assign no_new_data_w = !din_av && !hr_full;
// assign flushed =
always @ (posedge clk) begin
din_re_r <= din_re;
if (rst) din_av_safe_r <= 0;
else din_av_safe_r <= din_av && (din_avm || (!din_re && !din_re_r));
// set low word of the OR
if (rst) dout_vld_r[0] <= 0;
else if (next_or_empty[0]) dout_vld_r[0] <= hr_full || (din_re && (|dm));
if (next_or_empty[0]) begin
if (hr_full) dout[15: 0] <= hr;
else if (din_re) begin
if (dm[0]) dout[15: 0] <= din[15: 0];
else if (dm[1]) dout[15: 0] <= din[31:16];
end
end
// set high word of the OR
if (rst) dout_vld_r[1] <= 0;
else if (next_or_empty[1]) dout_vld_r[1] <= next_or_empty[0]?
(din_re && ((hr_full &&(|dm)) || (&dm))) :
(hr_full || (din_re && (|dm)));
if (next_or_empty[1]) begin
if (next_or_empty[0]) begin
if (din_re) begin
if (hr_full && dm[0]) dout[31:16] <= din[15: 0];
else if (dm[1] && (!hr_full || dm[0])) dout[31:16] <= din[31:16];
end
end else begin
if (hr_full) dout[31:16] <= hr;
else if (din_re) begin
if (dm[0]) dout[31:16] <= din[15: 0];
else if (dm[1]) dout[31:16] <= din[31:16];
end
end
end
// set holding register
if (rst) hr_full <= 0;
else if (((&next_or_empty) && !(&drd_in)) ||
((|next_or_empty) && !(|drd_in))) hr_full <= 0;
else if (((&drd_in) && !(&next_or_empty)) ||
((|drd_in) && !(|next_or_empty))) hr_full <= 1;
if (drd_in[1]) hr <= din[31:16];
else if (drd_in[0]) hr <= din[15: 0];
if (rst || !flushing) slow_down <= 0;
else if (!din_avm_w) slow_down <= 1;
if (rst || !flushing || last_dw_sent) slow_dav <= 0;
else slow_dav <= !dout_re && !last_dw_sent && ((!next_or_empty[1] && more_words_avail) || last_DW_r);
if (rst || !flushing) last_dw_sent <= 0;
else if (last_DW_r && dout_re) last_dw_sent <= 1;
no_new_data_r <= {no_new_data_r[0], no_new_data_w};
if (rst || !flushing) last_DW_r <= 0;
else if (slow_down && no_new_data_w && (&no_new_data_r)) last_DW_r <= 1;
else if (dout_re) last_DW_r <= 0;
end
endmodule
/*******************************************************************************
* Module: ahci_dma_wr_fifo
* Date:2016-01-02
* Author: Andrey Filippov
* Description: cross clocks, word-realign, 32 -> 64 with byte write mask
* Convertion from x32 DWORD data received from FIS-es @ mclk to QWORD-aligned
* AXI data @hclk
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_dma_wr_fifo.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_dma_wr_fifo.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module ahci_dma_wr_fifo#(
parameter WCNT_BITS = 21,
parameter ADDRESS_BITS = 3
)(
input mrst,
input hrst,
input mclk,
input hclk,
// hclk domain
input [WCNT_BITS-1:0] wcnt, // decrementing word counter, 0- based (0 need 1, 1 - need 2, ...) valid @ start
input [1:0] woffs, // 2 LSBs of the initial word address - valid @ start
input init, // initializes cross-clock 32->64 FIFO, disables FIFO read until confirmed back form mclk domain
input start, // start transfer
output reg [63:0] dout, // allow only each 3-rd wr if not many
// input dout_av, // at least one QWORD space avaiable in AXI FIFO
input dout_av_many, // several QWORD space avaiable in AXI FIFO
input last_prd, // last prd, flush partial dword if there were odd number of words transferred. valid @ start
// Or maybe use "last_prd"?
output dout_we,
output reg [3:0] dout_wstb, // word write enable (apply to wstb, 2 wstb input bits for one dout_wstb bit)
output reg done, // this PRD data sent AXI FIFO (Some partial QWORD data may be left in this module if
// 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)
input din_avail
);
localparam ADDRESS_NUM = (1<<ADDRESS_BITS); // 8 for ADDRESS_BITS==3
reg [31:0] fifo0_ram [0: ADDRESS_NUM - 1];
reg [31:0] fifo1_ram [0: ADDRESS_NUM - 1];
wire init_mclk;
wire init_confirm;
reg en_fifo_rd;
reg en_fifo_wr;
wire flush_hclk; // TODO: Define (less than 4 left to receive)?
wire flush_mclk;
// wire flush_conf;
reg [ADDRESS_BITS : 0] raddr; // 1 extra bit
reg [ADDRESS_BITS+1:0] waddr; // 1 extra bit
reg [63:16] fifo_do_prev; // only 48 bits are needed
reg [(1<<ADDRESS_BITS)-1:0] fifo_full; // set in write clock domain
reg [(1<<ADDRESS_BITS)-1:0] fifo_nempty;// set in read clock domain
wire fifo_wr = en_fifo_wr && ((din_avail && din_rdy) || (waddr[0] && flush_mclk)); // flush may add extra write of junk
// wire fifo_rd;
wire [(1<<ADDRESS_BITS)-1:0] fifo_full2 = {~fifo_full[0],fifo_full[ADDRESS_NUM-1:1]};
reg hrst_mclk;
reg fifo_dav; // @hclk
reg fifo_dav2; // @hclk - ??? at least two are available?
reg fifo_half_mclk; // Half Fifo is empty, OK to write
/// wire [63:0] fifo_do = {fifo1_ram [raddr[ADDRESS_BITS:1]], fifo0_ram [raddr[ADDRESS_BITS:1]]};
wire [63:0] fifo_do = {fifo1_ram [raddr[ADDRESS_BITS-1:0]], fifo0_ram [raddr[ADDRESS_BITS-1:0]]};
wire dout_we_w;
reg [1:0] dout_we_r;
reg [1:0] wp; // word pointer in the output (0..3)
reg [1:0] fp; // pointer in the {fifo_do,fifo_do_prev} pointer (0 - fifo_do_prev[16], ..., 3 - fifo_do[0])
reg [1:0] wl; // words left: 0: 1 word, ..., 3: >=4 words
// implementing 6 -> 23 unregistered ROM
reg [1:0] mx0; //4:1
reg [2:0] mx1; //5:1
reg [2:0] mx2; //6:1
reg [2:0] mx3; //7:1
reg [3:0] pm; // re_dout_wstb;
wire fifo_rd;
reg fifo_rd_r;
// reg [1:0] nwp; // Needed? 0 for all but first
reg [1:0] nfp; // next {fifo_do,fifo_do_prev} pointer (0 - fifo_do_prev[16], ..., 3 - fifo_do[0])
reg [2:0] swl; // subtract from words_left;
reg need_fifo; // needs reading fifo
// TODO: make separate register bits for wl == 0, wl > =4
reg busy_r;
reg is_last_prd;
reg [WCNT_BITS-1:0] wcntr;
wire [WCNT_BITS-1:0] next_wcntr = wcntr[WCNT_BITS-1:0] - swl[2:0];
reg flushing;
// wire done_w = dout_we_r[0] && !(next_wcntr[WCNT_BITS];
wire last_qword= !(|wcntr[WCNT_BITS-1:2]) &&
((wcntr[1:0] == 0) ||
swl[2] ||
(!wcntr[1] && swl[1]) ||
(!wcntr[0] && (&swl[1:0])) );
wire done_w = dout_we_w && last_qword;
// wire axi_ready = dout_av && (dout_av_many || (!dout_we_r));
wire axi_ready = dout_av_many;
wire fifo_out_ready = en_fifo_rd && (!need_fifo || (fifo_dav && (fifo_dav2 || !fifo_rd_r)));
/// assign flush_hclk = is_last_prd && !flushing && !nfp[1] && last_qword && waddr[0]; // waddr[0] - other clock domain, but OK here,
assign flush_hclk = busy && is_last_prd && !flushing && !nfp[1] && last_qword && waddr[0]; // waddr[0] - other clock domain, but OK here,
// it was last 1->0 before previous FIFO read. flush_hclk will only be generated for odd number of dwords
assign din_rdy = en_fifo_wr && fifo_half_mclk;
assign dout_we = dout_we_r[0]; // dout_we_r[0] - write to dout, use dout_av && (!(|dout_we_r) || dout_av_many) to enable dout_we_r[0]<=
assign busy = busy_r || dout_we_r[0];
assign dout_we_w = axi_ready && fifo_out_ready && busy_r;
assign fifo_rd = dout_we_w && need_fifo;
always @ (posedge hclk) begin
if (hrst || init) en_fifo_rd <= 0;
else if (init_confirm) en_fifo_rd <= 1;
else if (done_w && is_last_prd) en_fifo_rd <= 0;
done <= done_w;
fifo_rd_r <= fifo_rd;
if (hrst || init) raddr <= 0;
else if (fifo_rd) raddr <= raddr + 1; // increment for 64-bit words
// reg [ADDRESS_BITS : 0] raddr; // 1 extra bit
if (hrst || init) fifo_nempty <= {{(ADDRESS_NUM>>1){1'b0}},{(ADDRESS_NUM>>1){1'b1}}};// 8'b00001111
/// else if (fifo_rd && raddr[0]) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0],raddr[ADDRESS_BITS] ^ raddr[ADDRESS_BITS-1]};
else if (fifo_rd) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0],~raddr[ADDRESS_BITS] ^ raddr[ADDRESS_BITS-1]};
/// fifo_dav <= !init && en_fifo_rd && (fifo_full [raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS]);
fifo_dav <= !init && en_fifo_rd && (fifo_full [raddr[ADDRESS_BITS-1:0]] ^ raddr[ADDRESS_BITS]);
/// fifo_dav2 <= !init && en_fifo_rd && (fifo_full2[raddr[ADDRESS_BITS:1]]); //?^ raddr[ADDRESS_BITS]); // FIXME
fifo_dav2 <= !init && en_fifo_rd && (fifo_full2[raddr[ADDRESS_BITS-1:0]] ^ raddr[ADDRESS_BITS]); //?^ raddr[ADDRESS_BITS]); // FIXME
if (fifo_rd) fifo_do_prev[63:16] <= fifo_do[63:16];
if (start) is_last_prd <= last_prd;
// flushing will only be set for the last dword in last PRD if total number of dwords is ODD.
// Odd number of words should be handled outside of this module (before)
if (hrst || init || start) flushing <= 0;
else if (flush_hclk) flushing <= 1;
else if (done_w) flushing <= 0;
if (hrst || init) busy_r <= 0;
else if (start) busy_r <= 1;
else if (done_w) busy_r <= 0;
dout_we_r <= {dout_we_r[0], dout_we_w};
if (start) wcntr <= wcnt;
else if (dout_we_w) wcntr <= next_wcntr; // wcntr - swl[2:0];
if (start) wp <= woffs;
else if (dout_we_w) wp <= 0; // all but possibly wirst QWORD are aligned to th low word
if (init) fp <= 3; // only reset for the first PRD, points to the beginning of the fifo_do (fifo_do_prev - empty)
else if (dout_we_w) fp <= nfp;
// words left: 0: 1 word, ..., 3: >=4 words
if (start) wl <= wcnt[1:0] | {2{|wcnt[WCNT_BITS-1:2]}};
else if (dout_we_w) wl <= next_wcntr[1:0] | {2{|wcntr[WCNT_BITS-1:3] | next_wcntr[2]}};
if (dout_we_w) begin
dout_wstb <= pm;
case (mx0)
2'h0: dout[15: 0] <= fifo_do_prev[31:16];
2'h1: dout[15: 0] <= fifo_do_prev[47:32];
2'h2: dout[15: 0] <= fifo_do_prev[63:48];
2'h3: dout[15: 0] <= fifo_do [15: 0];
endcase
case (mx1)
3'h0: dout[31:16] <= fifo_do_prev[31:16];
3'h1: dout[31:16] <= fifo_do_prev[47:32];
3'h2: dout[31:16] <= fifo_do_prev[63:48];
3'h3: dout[31:16] <= fifo_do [15: 0];
3'h4: dout[31:16] <= fifo_do [31:16];
default: dout[31:16] <= 16'bx; // should never get here
endcase
case (mx2)
3'h0: dout[47:32] <= fifo_do_prev[31:16];
3'h1: dout[47:32] <= fifo_do_prev[47:32];
3'h2: dout[47:32] <= fifo_do_prev[63:48];
3'h3: dout[47:32] <= fifo_do [15: 0];
3'h4: dout[47:32] <= fifo_do [31:16];
3'h5: dout[47:32] <= fifo_do [47:32];
default: dout[47:32] <= 16'bx; // should never get here
endcase
case (mx3)
3'h0: dout[63:48] <= fifo_do_prev[31:16];
3'h1: dout[63:48] <= fifo_do_prev[47:32];
3'h2: dout[63:48] <= fifo_do_prev[63:48];
3'h3: dout[63:48] <= fifo_do [15: 0];
3'h4: dout[63:48] <= fifo_do [31:16];
3'h5: dout[63:48] <= fifo_do [47:32];
3'h6: dout[63:48] <= fifo_do [63:48];
default: dout[63:48] <= 16'bx; // should never get here
endcase
end
end
/*
output reg [63:0] dout, // allow only each 3-rd wr if not many
input dout_av, // at least one QWORD space avaiable in AXI FIFO
input dout_av_many, // several QWORD space avaiable in AXI FIFO
input last_prd, // last prd, flush partial dword if there were odd number of words transferred. valid @ start
// Or maybe use "last_prd"?
output dout_we,
output reg [3:0] dout_wstb, // word write enable (apply to wstb, 2 wstb input bits for one dout_wstb bit)
output reg done, // this PRD data sent AXI FIFO (Some partial QWORD data may be left in this module if
wl3[2:0]
always @* case ({wp, fp, wl})
6'h00: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0001; fifo_rd <= 0; nfp <= 1; swl <= 1; end
*/
// mclk domain
always @ (posedge mclk) begin
hrst_mclk <= hrst;
if (mrst || hrst_mclk) en_fifo_wr <= 0;
else if (init_mclk) en_fifo_wr <= 1;
else if (flush_mclk) en_fifo_wr <= 0;
if (hrst_mclk || init_mclk) waddr <= 0;
else if (fifo_wr) waddr <= waddr + 1;
if (hrst_mclk || init_mclk) fifo_full <= 0;
/// else if (fifo_wr) fifo_full <= {fifo_full[ADDRESS_NUM-2:0], waddr[ADDRESS_BITS+1]};
else if (fifo_wr && waddr[0]) fifo_full <= {fifo_full[ADDRESS_NUM-2:0], ~waddr[ADDRESS_BITS+1]};
fifo_half_mclk <= en_fifo_wr && fifo_nempty [waddr[ADDRESS_BITS:1]] ^ waddr[ADDRESS_BITS+1];
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
fifo_nempty_mclk <= (fifo_full [raddr[ADDRESS_BITS-1:0]] ^ raddr[ADDRESS_BITS]); // only valid after read is stopped
end
// hclk -> mclk cross-clock synchronization
pulse_cross_clock #(
.EXTRA_DLY(0)
) init_mclk_i (
.rst (hrst), // input
.src_clk (hclk), // input
.dst_clk (mclk), // input
.in_pulse (init), // input
.out_pulse (init_mclk), // output
.busy() // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) flush_mclk_i (
.rst (hrst), // input
.src_clk (hclk), // input
.dst_clk (mclk), // input
.in_pulse (flush_hclk), // input
.out_pulse (flush_mclk), // output
.busy() // output
);
// mclk -> hclk cross-clock synchronization
pulse_cross_clock #(
.EXTRA_DLY(0)
) init_confirm_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (init_mclk), // input
.out_pulse (init_confirm), // output
.busy() // output
);
/*
pulse_cross_clock #(
.EXTRA_DLY(0)
) flush_conf_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (flush_mclk), // input
.out_pulse (flush_conf), // output
.busy() // output
);
*/
/*
wl: 0: left 1 word, 1: left 2 words, 2: left 3 words, 3: left >=4 words
wp (pointer in the output qword, only first in PRD can be non-zero) 0: word 0 of output QW, ...
mx0 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0];
mx1 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0], 4:fifo_do[16];
mx2 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0], 4:fifo_do[16], 5:fifo_do[32];
mx3 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0], 4:fifo_do[16], 5:fifo_do[32], 6:fifo_do[48];
fp/nfp: 0 - pointer to fifo_do_prev[16], 1 : fifo_do_prev[32], 2: fifo_do_prev[48], 3: fifo_do[0]
*/
always @* case ({wp, fp, wl})
6'h00: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0001; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h01: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0011; need_fifo <= 0; nfp <= 2; swl <= 2; end
6'h02: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0111; need_fifo <= 0; nfp <= 3; swl <= 3; end
6'h03: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1111; need_fifo <= 1; nfp <= 0; swl <= 4; end
6'h04: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b0001; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h05: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b0011; need_fifo <= 0; nfp <= 3; swl <= 2; end
6'h06: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b0111; need_fifo <= 1; nfp <= 0; swl <= 3; end
6'h07: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b1111; need_fifo <= 1; nfp <= 1; swl <= 4; end
6'h08: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b0001; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h09: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b0011; need_fifo <= 1; nfp <= 0; swl <= 2; end
6'h0a: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b0111; need_fifo <= 1; nfp <= 1; swl <= 3; end
6'h0b: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b1111; need_fifo <= 1; nfp <= 2; swl <= 4; end
6'h0c: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3 <= 6; pm <= 4'b0001; need_fifo <= 1; nfp <= 0; swl <= 1; end
6'h0d: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3 <= 6; pm <= 4'b0011; need_fifo <= 1; nfp <= 1; swl <= 2; end
6'h0e: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3 <= 6; pm <= 4'b0111; need_fifo <= 1; nfp <= 2; swl <= 3; end
6'h0f: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3 <= 6; pm <= 4'b1111; need_fifo <= 1; nfp <= 3; swl <= 4; end
6'h10: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b0010; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h11: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b0110; need_fifo <= 0; nfp <= 2; swl <= 2; end
6'h12: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1110; need_fifo <= 0; nfp <= 3; swl <= 3; end
6'h13: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1110; need_fifo <= 0; nfp <= 3; swl <= 3; end
6'h14: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0010; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h15: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0110; need_fifo <= 0; nfp <= 3; swl <= 2; end
6'h16: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1110; need_fifo <= 1; nfp <= 0; swl <= 3; end
6'h17: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1110; need_fifo <= 1; nfp <= 0; swl <= 3; end
6'h18: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b0010; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h19: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b0110; need_fifo <= 1; nfp <= 0; swl <= 2; end
6'h1a: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b1110; need_fifo <= 1; nfp <= 1; swl <= 3; end
6'h1b: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b1110; need_fifo <= 1; nfp <= 1; swl <= 3; end
6'h1c: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b0010; need_fifo <= 1; nfp <= 0; swl <= 1; end
6'h1d: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b0110; need_fifo <= 1; nfp <= 1; swl <= 2; end
6'h1e: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b1110; need_fifo <= 1; nfp <= 2; swl <= 3; end
6'h1f: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3 <= 5; pm <= 4'b1110; need_fifo <= 1; nfp <= 2; swl <= 3; end
6'h20: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b0100; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h21: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1100; need_fifo <= 0; nfp <= 2; swl <= 2; end
6'h22: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1100; need_fifo <= 0; nfp <= 2; swl <= 2; end
6'h23: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1100; need_fifo <= 0; nfp <= 2; swl <= 2; end
6'h24: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b0100; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h25: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1100; need_fifo <= 0; nfp <= 3; swl <= 2; end
6'h26: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1100; need_fifo <= 0; nfp <= 3; swl <= 2; end
6'h27: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1100; need_fifo <= 0; nfp <= 3; swl <= 2; end
6'h28: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b0100; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h29: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1100; need_fifo <= 1; nfp <= 0; swl <= 2; end
6'h2a: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1100; need_fifo <= 1; nfp <= 0; swl <= 2; end
6'h2b: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1100; need_fifo <= 1; nfp <= 0; swl <= 2; end
6'h2c: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b0100; need_fifo <= 1; nfp <= 0; swl <= 1; end
6'h2d: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b1100; need_fifo <= 1; nfp <= 1; swl <= 2; end
6'h2e: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b1100; need_fifo <= 1; nfp <= 1; swl <= 2; end
6'h2f: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3 <= 4; pm <= 4'b1100; need_fifo <= 1; nfp <= 1; swl <= 2; end
6'h30: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h31: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h32: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h33: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
6'h34: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h35: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h36: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h37: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3 <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
6'h38: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h39: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h3a: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h3b: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3 <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
6'h3c: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
6'h3d: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
6'h3e: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
6'h3f: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3 <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
endcase
endmodule
/*******************************************************************************
* Module: ahci_fis_receive
* Date:2016-01-06
* Author: Andrey Filippov
* Description: Receives incoming FIS-es, forwards DMA ones to DMA engine
* Stores received FIS-es if requested
*
* 'fis_first_vld' is asserted when the FIFO output contains first DWORD
* of the received FIS (low byte - FIS type). FIS type is decoded
* outside of this module, and the caller pulses one of the get_* inputs
* to initiate incoming FIS processing (or ignoring it).
* 'get_fis_busy' is high until the fis is being received/stored,
* one of the 3 states (fis_ok, fis_err and fis_ferr) are raised
* This module also receives/updates device signature and PxTFD ERR and STS.
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_fis_receive.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_fis_receive.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_fis_receive#(
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 hba_rst, // @posedge mclk - sync reset
input mclk, // for command/status
input pcmd_st_cleared, // ~= hba_rst?
// Control Interface
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,
input get_rfis,
input get_sdbfis,
input get_ufis,
input get_data_fis,
input get_ignore, // ignore whatever FIS (use for DMA activate too?)
output get_fis_busy, // busy processing FIS
output reg get_fis_done, // done processing FIS (see fis_ok, fis_err, fis_ferr)
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
// next commands use register address/data/we for 1 clock cycle - after next to command (commnd - t0, we - t2)
input update_sig, // update signature - now after get_rfis, after FIS is already received
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 clear_prdbc, // save resources - clear prdbc for every command - discard what is written there
input clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update
input clear_bsy_set_drq, // clear PxTFD.STS.BSY and sets PxTFD.STS.DRQ, update
input set_bsy, // set PxTFD.STS.BSY, 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 clear_xfer_cntr, // clear pXferCntr (is it needed as a separate input)?
input decr_dwcr, // decrement DMA Xfer counter after read (in this module) // need pulse to 'update_prdbc' to write to registers
input decr_dwcw, // decrement DMA Xfer counter after write (from decr_DXC_dw)// need pulse to 'update_prdbc' to write to registers
input [11:0] decr_DXC_dw, // decrement value (in DWORDs)
input pcmd_fre, // control bit enables saving FIS to memory (will be ignored for signature)
// TODO: Add writing PRDBC here? Yes, the following. B ut data may be discarded as only 0 is supposed to be written
// 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
output reg pPioXfer, // state variable
output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields)
// tfd_sts[7] - BSY, tfd_sts[3] - 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 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 xfer_cntr_zero,// valid next cycle
output [11:0] data_in_dwords, // number of data dwords received (valid with 'done')
// FSM will send this pulse
// output reg data_in_words_apply, // apply data_in_words
// Registers interface
// 2. HBA R/W registers, may be added external register layer
output reg [ADDRESS_BITS-1:0] reg_addr,
output reg reg_we,
output reg [31:0] reg_data,
input [31:0] hba_data_in, // FIFO output data
input [ 1:0] hba_data_in_type, // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR
input hba_data_in_valid, // Data available from the transport layer in FIFO
input hba_data_in_many, // Multiple DWORDs available from the transport layer in FIFO
output hba_data_in_ready, // This module or DMA consumes DWORD
// Forwarding data to the DMA engine
input dma_in_ready, // DMA engine ready to accept data
output dma_in_valid // Write data to DMA dev->memory channel
,output debug_data_in_ready,
output debug_fis_end_w,
output [1:0] debug_fis_end_r,
output [1:0] debug_get_fis_busy_r
);
//localparam FA_BITS = 6; // number of bits in received FIS address
//localparam CLB_OFFS32 = 'h200; // # In the second half of the register space (0x800..0xbff - 1KB)
/*
HBA_OFFS = 0x0 # All offsets are in bytes
CLB_OFFS = 0x800 # In the second half of the register space (0x800..0xbff - 1KB)
FB_OFFS = 0xc00 # Needs 0x100 bytes
#HBA_PORT0 = 0x100 Not needed, always HBA_OFFS + 0x100
*/
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
localparam CLB_OFFS32 = 'h200; // # In the second half of the register space (0x800..0xbff - 1KB)
localparam HBA_OFFS32 = 0;
localparam HBA_PORT0_OFFS32 = 'h40;
localparam PXSIG_OFFS32 = HBA_OFFS32 + HBA_PORT0_OFFS32 + 'h9;
localparam PXTFD_OFFS32 = HBA_OFFS32 + HBA_PORT0_OFFS32 + 'h8;
localparam FB_OFFS32 = 'h300; // # Needs 0x100 bytes
localparam DSFIS32 = 'h0; // DMA Setup FIS
localparam PSFIS32 = 'h8; // PIO Setup FIS
localparam RFIS32 = 'h10; // D2H Register FIS
localparam SDBFIS32 = 'h16; // Set device bits FIS
localparam UFIS32 = 'h18; // Unknown FIS
localparam DSFIS32_LENM1 = 'h6; // DMA Setup FIS
localparam PSFIS32_LENM1 = 'h4; // PIO Setup FIS
localparam RFIS32_LENM1 = 'h4; // D2H Register FIS
localparam SDBFIS32_LENM1 = 'h1;
localparam UFIS32_LENM1 = 'hf;
localparam DMAH_LENM1 = 'h0; // just one word
localparam IGNORE_LENM1 = 'hf;
localparam DATA_TYPE_DMA = 0;
localparam DATA_TYPE_FIS_HEAD = 1;
localparam DATA_TYPE_OK = 2;
localparam DATA_TYPE_ERR = 3;
reg xfer_cntr_zero_r;
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;
reg dwords_over;
reg too_long_err;
reg [ADDRESS_BITS-1:0] reg_addr_r;
reg [3:0] fis_dcount; // number of DWORDS left to be written to the "memory"
reg fis_save; // save FIS data
wire is_fis_end = (hba_data_in_type == DATA_TYPE_OK) || (hba_data_in_type == DATA_TYPE_ERR);
wire fis_end_w = data_in_ready && is_fis_end & ~(|fis_end_r);
reg [1:0] fis_end_r;
reg fis_rec_run; // running received FIS
reg is_data_fis;
reg is_ignore;
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));
wire data_in_ready = hba_data_in_valid && (hba_data_in_many || !(|was_data_in));
wire get_fis = get_dsfis || get_psfis || get_rfis || get_sdbfis || get_ufis || get_data_fis || get_ignore;
reg wreg_we_r;
wire reg_we_w;
reg [3:0] store_sig;
reg [5:0] reg_ds; //Unused?
reg [4:0] reg_ps;
reg reg_d2h; //unused?
reg [1:0] reg_sdb; //unused?
reg [31:2] xfer_cntr_r;
reg [31:2] prdbc_r;
reg [15:0] tf_err_sts;
reg update_err_sts_r;
reg update_sig_r;
// reg update_pio_r;
reg update_prdbc_r;
reg [1:0] get_fis_busy_r;
reg [7:0] pio_es_r; // value of PIO E_Status
reg [7:0] pio_err_r;
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;
assign xfer_cntr_zero = xfer_cntr_zero_r;
// Forward data to DMA (dev->mem) engine
assign dma_in_valid = dma_in && 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 = dma_in && (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 || dma_skipping_extra || wreg_we_r || fis_end_r[0] || (is_FIS_NOT_HEAD && fis_first_flushing_r);
assign fis_ferr = too_long_err;
assign tfd_sts = tf_err_sts[ 7:0];
assign tfd_err = tf_err_sts[15:8];
assign xfer_cntr = xfer_cntr_r[31:2];
assign get_fis_busy = get_fis_busy_r[0];
// assign data_in_dwords = data_out_dwords_r;
assign data_in_dwords = data_in_dwords_r;
assign pio_es = pio_es_r;
assign pUpdateSig = pUpdateSig_r;
assign fis_extra = fis_extra_r;
assign fis_first_invalid = fis_first_invalid_r;
//debug:
assign debug_data_in_ready = data_in_ready;
assign debug_fis_end_w = fis_end_w;
assign debug_fis_end_r = fis_end_r;
assign debug_get_fis_busy_r = get_fis_busy_r;
always @ (posedge mclk) begin
if (hba_rst || dma_in_stop || pcmd_st_cleared) dma_in <= 0;
else if (dma_in_start) dma_in <= 1;
if (hba_rst) was_data_in <= 0;
else was_data_in <= {was_data_in[0], hba_data_in_ready};
if (dma_in_start) data_in_dwords_r <= 0;
else if (dma_in_valid) data_in_dwords_r <= data_in_dwords_r + 1;
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 || pcmd_st_cleared) 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)) |
({ADDRESS_BITS{get_psfis}} & (FB_OFFS32 + PSFIS32)) |
({ADDRESS_BITS{get_rfis}} & (FB_OFFS32 + RFIS32)) |
({ADDRESS_BITS{get_sdbfis}} & (FB_OFFS32 + SDBFIS32)) |
({ADDRESS_BITS{get_ufis}} & (FB_OFFS32 + UFIS32));
fis_dcount <= ({4{get_dsfis}} & DSFIS32_LENM1) |
({4{get_psfis}} & PSFIS32_LENM1) |
({4{get_rfis}} & RFIS32_LENM1) |
({4{get_sdbfis}} & SDBFIS32_LENM1) |
({4{get_ufis}} & UFIS32_LENM1 ) |
({4{get_data_fis}} & DMAH_LENM1) |
({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);
is_data_fis <= get_data_fis;
store_sig <= (get_rfis)? 1 : 0;
reg_ds <= get_dsfis ? 1 : 0;
reg_ps <= get_psfis ? 1 : 0;
reg_d2h <= get_rfis ? 1 : 0;
reg_sdb <= get_rfis ? 1 : 0;
is_ignore <= get_ignore ? 1 : 0;
end else if (wreg_we_r && !dwords_over) begin
fis_dcount <= fis_dcount - 1; // update even if not writing to registers
if (fis_save) reg_addr_r <= reg_addr_r + 1; // update only when writing to registers
store_sig <= store_sig << 1;
reg_ds <= reg_ds << 1;
reg_ps <= reg_ps << 1;
reg_d2h <= 0;
reg_sdb <= reg_sdb << 1;
end
if (hba_rst || pcmd_st_cleared) fis_rec_run <= 0;
else if (get_fis) fis_rec_run <= 1;
else if (is_fis_end && data_in_ready) fis_rec_run <= 0;
if (hba_rst ||get_fis || pcmd_st_cleared) dwords_over <= 0;
else if (wreg_we_r && !(|fis_dcount)) dwords_over <= 1;
if (hba_rst) wreg_we_r <= 0;
else wreg_we_r <= fis_rec_run && data_in_ready && !is_fis_end && !dwords_over && (|fis_dcount || !wreg_we_r) &&
(!is_ignore || !wreg_we_r); // Ignore - unknown length, ned to look for is_fis_end with latency
fis_end_r <= {fis_end_r[0], fis_end_w};
if (hba_rst || pcmd_st_cleared) get_fis_busy_r[0] <= 0;
else if (get_fis) get_fis_busy_r[0] <= 1;
else if (too_long_err || fis_end_w) get_fis_busy_r[0] <= 0;
get_fis_busy_r[1] <=get_fis_busy_r[0];
get_fis_done <= get_fis_busy_r[0] && (too_long_err || fis_end_w);
if (hba_rst || (|get_fis_busy_r) || pcmd_st_cleared) fis_first_vld <= 0; // is_FIS_HEAD stays on longer than just get_fis
else if (is_FIS_HEAD) fis_first_vld <= 1;
if (hba_rst || get_fis) fis_ok <= 0;
else if (fis_end_w) fis_ok <= hba_data_in_type == DATA_TYPE_OK;
if (hba_rst || get_fis) fis_err <= 0;
else if (fis_end_w) fis_err <= hba_data_in_type != DATA_TYPE_OK;
if (reg_we_w) reg_data <= hba_data_in;
else if (update_err_sts_r) reg_data <= {16'b0,tf_err_sts};
else if (update_sig_r) reg_data <= sig_r;
else if (update_prdbc_r) reg_data <= {prdbc_r[31:2],2'b0}; // xfer_cntr_r[31:2],2'b0};
if (store_sig[1]) sig_r[31:8] <= hba_data_in[23:0];
if (store_sig[3]) sig_r[ 7:0] <= hba_data_in[ 7:0];
if (hba_rst) tf_err_sts <= 0;
else if (reg_d2h) tf_err_sts <= hba_data_in[31:16]; // 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[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}}} ;
if (hba_rst) reg_we <= 0;
else reg_we <= reg_we_w || update_sig_r || update_err_sts_r || update_prdbc_r;
if (reg_we_w) reg_addr <= reg_addr_r;
else if (update_err_sts_r) reg_addr <= PXTFD_OFFS32;
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[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_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[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_dwcw || decr_dwcr) && !xfer_cntr_zero_r) xfer_cntr_r[31:2] <= {xfer_cntr_r[31:2]} -
{18'b0, decr_dwcr? data_in_dwords: decr_DXC_dw[11:0]};
// no - it should only be updated when written by software
//CLB_OFFS32 + 1; // location of PRDBC
/*
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
*/
// if (hba_rst || reg_sdb[0] || reg_ps[4] || reg_ds[5]) prdbc_r[31:2] <= 0;
// if (soft_write_en && (soft_write_addr == (CLB_OFFS32 + 1))) prdbc_r[31:2] <= soft_write_data[31:2];
if (clear_prdbc || hba_rst) prdbc_r[31:2] <= 0;
else if (decr_dwcw || decr_dwcr) prdbc_r[31:2] <= {prdbc_r[31:2]} + {18'b0, decr_dwcr? data_in_dwords: decr_DXC_dw[11:0]};
xfer_cntr_zero_r <= xfer_cntr_r[31:2] == 0;
update_err_sts_r <= update_pio || 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
update_sig_r <= update_sig && pUpdateSig_r; // do not update if not requested
if (hba_rst || update_pio) pPioXfer <= 0;
else if (reg_ps[4]) pPioXfer <= 1;
if (hba_rst || set_update_sig) pUpdateSig_r <= 1;
else if (update_sig) pUpdateSig_r <= 0;
if (hba_rst || update_sig) sig_available <= 0;
else if (store_sig[3]) sig_available <= 1;
// Maybe it is not needed if the fsm will send this pulse?
if (hba_rst || (|get_fis_busy_r) ||pcmd_st_cleared) 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
/*******************************************************************************
* Module: ahci_fis_transmit
* Date:2016-01-07
* Author: andrey
* Description: Fetches commands, command tables, creates/sends FIS
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_fis_transmit.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_fis_transmit.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_fis_transmit #(
parameter PREFETCH_ALWAYS = 0,
parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
// parameter READ_CT_LATENCY = 1, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
parameter READ_CT_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 hba_rst, // @posedge mclk - when port is reset (even COMINIT)?
input mclk, // for command/status
input pcmd_st_cleared, // ~= hba_rst?
// Command pulses to execute states
input fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS)
// wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd
input cfis_xmit, // transmit command (wait for dma_ct_busy == 0)
input dx_xmit, // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
input atapi_xmit, // trasmit ATAPI command FIS
output reg done, // for fetch_cmd - dma_start, for *_xmit - xmit_ok, xmit_err, syncesc_recv or xrdy_collision
output reg busy,
input clearCmdToIssue, // From CFIS:SUCCESS
output pCmdToIssue, // AHCI port variable
// output dmaCntrZero, // DMA counter is zero - would be a duplicate to the one in receive module and dwords_sent output
// output reg fetch_cmd_busy, // does not include prefetching CT - now just use busy/done
// Should wait for xmit_ok? Timeout? Timeout will be handled by software, so just wait for OK or some error
input xmit_ok, // FIS transmission acknowledged OK
input xmit_err, //
input syncesc_recv, // These two inputs interrupt transmit
input xrdy_collision,
output [ 2:0] dx_err, // bit 0 - syncesc_recv, 1 - R_ERR (was xmit_err), 2 - collision (valid @ xmit_err and later, reset by new command)
output [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0)
output ch_c, // Clear busy upon R_OK for this FIS
output ch_b, // Built-in self test command
output ch_r, // reset - may need to send SYNC escape before this command
output ch_p, // prefetchable - only used with non-zero PRDTL or ATAPI bit set
output ch_w, // Write: system memory -> device
output ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command
output [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal,
// maximal is 16 (0x10)
output reg [11:0] dwords_sent, // number of DWORDs transmitted (up to 2048)
// register memory interface
output reg [ADDRESS_BITS-1:0] reg_addr,
output [ 1:0] reg_re,
input [31:0] reg_rdata,
// ahci_fis_receive interface
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, // transfer counter was not set
output dma_ctba_ld, // load command table address from
output dma_start, // start processing command table, reset prdbc (next cycle after dma_ctba_ld, bits prdtl valid)
output dma_dev_wr, // write to device (valid at start)
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
// reading out command table data from DMA module
output reg [ 4:0] ct_addr, // DWORD address
output [ 1:0] ct_re, // [0] - re, [1] - regen
input [31:0] ct_data, //
// DMA (memory -> device) interface
input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port
input dma_dav, // at least one dword is ready to be read from DMA module
output dma_re, // read dword from DMA module to the output register
input last_h2d_data,// last dword in dma_out
// Data System memory or FIS -> device
output reg [31:0] todev_data, // 32-bit data from the system memory to HBA (dma data)
output reg [ 1:0] todev_type, // 0 - data, 1 - FIS head, 2 - FIS LAST)
output todev_valid, // output register full
input todev_ready // send FIFO has room for data (>= 8? dwords)
,output [9:0] debug_01
// Add a possiblity to flush any data to FIFO if error was detected after data went there?
);
localparam CLB_OFFS32 = 'h200; // # In the second half of the register space (0x800..0xbff - 1KB)
localparam DATA_FIS = 32'h46;
reg todev_full_r;
reg dma_en_r;
wire fis_data_valid;
wire [1:0] fis_data_type;
wire [31:0] fis_data_out;
wire write_or_w;
// for fis_data_valid - longer latency
// wire fis_out_w = !dma_en_r && fis_data_valid && todev_ready;
wire dma_re_w = dma_en_r && dma_dav && todev_ready;
/// wire dma_re_w = dma_en_r && dma_dav && todev_ready && (!todev_full_r || !watch_prd_end_w);
reg [15:0] ch_prdtl_r;
reg ch_c_r;
reg ch_b_r;
reg ch_r_r;
reg ch_p_r;
reg ch_w_r;
reg ch_a_r;
reg [4:0] ch_cmd_len_r;
reg [4:0] cfis_acmd_left_r; // number of DWORDS in CFIS or ACMD area of the command table left to be fetched from ahci_dma module BRAM
// For CFIS this register is set from ch_cmd_len_r, for ACMD - from the xfer_cntr input
// (stored in the ahci_fis_receive module)
reg [4:0] cfis_acmd_left_out_r; // Same, just with latency of the data available from the ahci_dma module
// reg [31:7] ch_ctba_r;
reg [READ_REG_LATENCY:0] reg_re_r;
wire reg_re_w; // combined conditions to read register memory
/// wire reg_stb = reg_re_r[READ_REG_LATENCY];
/// wire reg_stb = reg_re_r[READ_REG_LATENCY-1];
wire pre_reg_stb = reg_re_r[READ_REG_LATENCY-1] && !reg_re_r[READ_REG_LATENCY]; // only first, to make running 1
reg [3:0] fetch_chead_r;
reg [3:0] fetch_chead_stb_r;
wire chead_done_w = fetch_chead_stb_r[2]; // done fetching command header
reg chead_bsy; // busy reading command header
reg chead_bsy_re; // busy sending read command header
reg pCmdToIssue_r;
// reg fetch_ct_r;
reg acfis_xmit_pend_r; //
reg acfis_xmit_start_r;
reg acfis_xmit_busy_r; //
// reg anc_fis_r; // This is ATAPI FIS, not Command FIS
wire acfis_xmit_start_w = (cfis_xmit || atapi_xmit || acfis_xmit_pend_r) && !dma_ct_busy && !fetch_cmd_busy_r; // dma_ct_busy no gaps with fetch_cmd_busy
wire acfis_xmit_end = ct_stb && fis_dw_last;
wire ct_re_w; // next cycle will be ct_re;
reg [READ_CT_LATENCY:0] ct_re_r;
wire ct_stb = ct_re_r[READ_CT_LATENCY];
reg fis_dw_first;
wire fis_dw_last;
reg [11:0] dx_dwords_left;
reg dx_fis_pend_r; // waiting to send first DWORD of the H2D data transfer
wire dx_dma_last_w; // sending last data word
reg dx_busy_r;
reg [ 2:0] dx_err_r;
reg xmit_ok_r;
wire any_cmd_start = fetch_cmd || cfis_xmit || dx_xmit || atapi_xmit;
// wire done_w = dx_dma_last_w || ((|dx_err_r) && dx_busy_r) || chead_done_w || acfis_xmit_end || dma_start; // done on last transmit or error
// dma_start ends 'fetch_cmd'
wire done_w = xmit_ok_r || ((|dx_err_r) && dx_busy_r) || dma_start; // done on last transmit or error
reg fetch_cmd_busy_r;
// now ahci_dma watches for the last data DWORD and generates last_h2d_data, so transmission will end if either of xfer counter or DMA data (defined by total prd size)
// if xfer_cntr wazs 0, it will never be decremented and never equal to 1, will not generate last)
// reg xfer_cntr_is_set;
// reg watch_prd_end;
// wire masked_last_h2d_data = xfer_cntr_not_set && last_h2d_data; // otherwise use xfer counter to find FIS end
// wire watch_prd_end_w = masked_last_h2d_data || watch_prd_end; // Maybe not needed - just use watch_prd_end
// reg [1:0] was_dma_re; // previous values of dma_re
// reg [2:0] was_dma_ndav; // inverted/masked previous values of dma_dav
// wire send_last_w = was_dma_ndav[2];
assign todev_valid = todev_full_r;
// assign todev_valid = todev_full_r && (!watch_prd_end_w || dma_dav || send_last_w);
assign dma_re = dma_re_w;
assign reg_re = reg_re_r[1:0];
assign ch_prdtl = ch_prdtl_r;
assign ch_c = ch_c_r;
assign ch_b = ch_b_r;
assign ch_r = ch_r_r;
assign ch_p = ch_p_r;
assign ch_w = ch_w_r;
assign ch_a = ch_a_r;
// assign ch_cfl = cfis_acmd_left_r;
assign ch_cfl = ch_cmd_len_r;
assign reg_re_w = fetch_cmd || chead_bsy_re;
assign dma_ctba_ld = fetch_chead_stb_r[2];
assign dma_start = fetch_chead_stb_r[3]; // next cycle after dma_ctba_ld
assign pCmdToIssue = pCmdToIssue_r;
// assign dmaCntrZero = dmaCntrZero_r;
assign ct_re = ct_re_r[1:0];
/// assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability
// What else to wait for when
assign fis_data_valid = ct_stb || (!dma_ct_busy && dx_fis_pend_r); // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability
/// assign ct_re_w = todev_ready && ((cfis_acmd_left_r[4:1] != 0) || (cfis_acmd_left_r[0] && !ct_re_r[0])); // Later add more sources
assign ct_re_w = todev_ready && acfis_xmit_busy_r && ((cfis_acmd_left_r[4:1] != 0) || (cfis_acmd_left_r[0] && !ct_re_r[0])); // Later add more sources
//
assign fis_dw_last = (cfis_acmd_left_out_r == 1);
assign fis_data_type = {fis_dw_last, (write_or_w && dx_fis_pend_r) | (fis_dw_first && ct_stb)};
assign fis_data_out = ({32{dx_fis_pend_r}} & DATA_FIS) | ({32{ct_stb}} & ct_data) ;
assign dx_dma_last_w = dma_en_r && dma_re_w && ((dx_dwords_left[11:0] == 1) || last_h2d_data);
assign dx_err = dx_err_r;
assign dma_dev_wr = ch_w_r;
/// assign write_or_w = (dma_en_r?(dma_dav && todev_ready ):fis_data_valid); // do not fill the buffer if FIFO is not ready for DMA,
/// assign write_or_w = (dma_en_r?(dma_dav && todev_ready && (!todev_full_r || !watch_prd_end_w)):fis_data_valid); // do not fill the buffer if FIFO is not ready for DMA,
assign write_or_w = dma_re_w || fis_data_valid;
// When watching for FIS end, do not fill/use output register in the same cycle
reg [3:0] dbg_was_ct_re_r;
reg [4:0] dbg_was_cfis_acmd_left_r;
always @ (posedge mclk) begin
// Mutliplex between DMA and FIS output to the output routed to transmit FIFO
// Count bypassing DMA dwords to generate FIS_last condition?
if (hba_rst || pcmd_st_cleared) todev_full_r <= 0;
else if (write_or_w) todev_full_r <= 1; // do not fill the buffer if FIFO is not ready
else if (todev_ready) todev_full_r <= 0;
if (write_or_w) todev_data <= dma_en_r? dma_out: fis_data_out;
if (hba_rst) todev_type <= 3; // invalid? - no, now first and last word in command FIS (impossible?)
else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w , 1'b0} : fis_data_type;
// Read 3 DWORDs from the command header
if (hba_rst) fetch_chead_r <= 0; // running 1
else fetch_chead_r <= {fetch_chead_r[2:0], fetch_cmd};
if (hba_rst) fetch_chead_stb_r <= 0;
else fetch_chead_stb_r <= {fetch_chead_stb_r[2:0], pre_reg_stb && chead_bsy};
if (hba_rst) chead_bsy <= 0;
else if (fetch_cmd) chead_bsy <= 1;
else if (chead_done_w) chead_bsy <= 0;
if (hba_rst) chead_bsy_re <= 0;
else if (fetch_cmd) chead_bsy_re <= 1;
else if (fetch_chead_r[1]) chead_bsy_re <= 0; // read 3 dwords
if (hba_rst) reg_re_r <= 0; // [0] -> reg_re output
else reg_re_r <= {reg_re[1:0], reg_re_w};
if (fetch_cmd) reg_addr <= CLB_OFFS32; // there will be more conditions
else if (reg_re_r[0]) reg_addr <= reg_addr + 1;
// save command header data to registers
if (fetch_chead_stb_r[0]) begin
ch_prdtl_r <= reg_rdata[31:16];
ch_c_r <= reg_rdata[ 10];
ch_b_r <= reg_rdata[ 9];
ch_r_r <= reg_rdata[ 8];
ch_p_r <= reg_rdata[ 7];
ch_w_r <= reg_rdata[ 6];
// ch_a_r <= reg_rdata[ 5];
ch_cmd_len_r<= reg_rdata[ 4: 0];
end
//ch_a
if (hba_rst || atapi_xmit) ch_a_r <= 0;
else if (fetch_chead_stb_r[0]) ch_a_r <= reg_rdata[ 5];
if (hba_rst) pCmdToIssue_r <= 0;
else if (chead_done_w) pCmdToIssue_r <= 1;
else if (clearCmdToIssue) pCmdToIssue_r <= 0;
if (hba_rst || pcmd_st_cleared) fetch_cmd_busy_r <= 0;
else if (fetch_cmd) fetch_cmd_busy_r <= 1;
else if (dma_start) fetch_cmd_busy_r <= 0;
//CFIS/ATAPI common
// fetch and send command/atapi FIS
if (hba_rst || acfis_xmit_start_w || pcmd_st_cleared) acfis_xmit_pend_r <= 0;
else if (cfis_xmit || atapi_xmit) acfis_xmit_pend_r <= 1;
acfis_xmit_start_r <= !hba_rst && acfis_xmit_start_w;
if (hba_rst || pcmd_st_cleared) acfis_xmit_busy_r <= 0;
else if (acfis_xmit_start_r) acfis_xmit_busy_r <= 1;
else if (acfis_xmit_end) acfis_xmit_busy_r <= 0;
if (cfis_xmit) cfis_acmd_left_r <= ch_cmd_len_r[ 4: 0]; // Will assume that there is room for ...
else if (atapi_xmit) cfis_acmd_left_r <= (|xfer_cntr[31:4]) ? 5'h4 : {3'b0,xfer_cntr[3:2]};
else if (acfis_xmit_busy_r && ct_re_r[0]) cfis_acmd_left_r <= cfis_acmd_left_r - 1;
// Counting CFIS/ATAPI FIS dwords sent to TL
if (acfis_xmit_start_r) cfis_acmd_left_out_r <= cfis_acmd_left_r;
else if (ct_stb) cfis_acmd_left_out_r <= cfis_acmd_left_out_r - 1;
if (hba_rst || acfis_xmit_start_w) ct_re_r <= 0;
else ct_re_r <= {ct_re_r[READ_CT_LATENCY-1:0], ct_re_w};
if (cfis_xmit) ct_addr <= 0;
else if (atapi_xmit) ct_addr <= 'h10; // start of ATAPI area
// else if (cfis_acmd_left_r[0]) ct_addr <= ct_addr + 1;
else if (ct_re_r[0]) ct_addr <= ct_addr + 1;
//
// first/last dword in FIS
if (!acfis_xmit_busy_r) fis_dw_first <= 1;
else if (ct_stb) fis_dw_first <= 0;
//TODO: update xfer length, prdtl (only after R_OK) - yes, do it outside
if (dx_xmit) dx_dwords_left[11:0] <= (xfer_cntr_zero || (|xfer_cntr[31:13])) ? 12'h800 : {1'b0,xfer_cntr[12:2]};
else if (dma_re_w) dx_dwords_left[11:0] <= dx_dwords_left[11:0] - 1;
if (dx_xmit) dwords_sent <= 0;
else if (dma_re_w) dwords_sent <= dwords_sent + 1;
// send FIS header
if (hba_rst || write_or_w ||pcmd_st_cleared) dx_fis_pend_r <= 0;
else if (dx_xmit) dx_fis_pend_r <= 1;
if (hba_rst || dx_dma_last_w || (|dx_err_r) || pcmd_st_cleared) dma_en_r <= 0;
else if (dx_fis_pend_r && write_or_w) dma_en_r <= 1;
// Abort on transmit errors
if (hba_rst || any_cmd_start) dx_err_r[0] <= 0;
else if (syncesc_recv) dx_err_r[0] <= 1;
if (hba_rst || any_cmd_start) dx_err_r[1] <= 0;
else if (xmit_err) dx_err_r[1] <= 1;
if (hba_rst || any_cmd_start) dx_err_r[2] <= 0;
else if (xrdy_collision) dx_err_r[2] <= 1;
if (hba_rst || pcmd_st_cleared) dx_busy_r <= 0; // sending CFIS, AFIS or data FIS (until error or R_OK)
else if (dx_xmit || acfis_xmit_start_r) dx_busy_r <= 1;
else if (xmit_ok || (|dx_err_r)) dx_busy_r <= 0;
dma_prd_start <= (dma_start && (PREFETCH_ALWAYS || ch_p_r || !ch_w_r)) || // device read may prefetch just prd addresses
(dx_fis_pend_r && write_or_w); // enable PRD read now (if it was not already done)
if (hba_rst) done <= 0;
else done <= done_w;
if (hba_rst || pcmd_st_cleared) busy <= 0;
else if (any_cmd_start) busy <= 1;
else if (done_w) busy <= 0;
if (hba_rst) xmit_ok_r <= 0;
else xmit_ok_r <= dx_busy_r && !(|dx_err_r) && xmit_ok;
dma_cmd_abort <= done_w && (|dx_err_r);
if (cfis_xmit) dbg_was_ct_re_r <= {ct_re_r, ct_re_w};
if (cfis_xmit) dbg_was_cfis_acmd_left_r <= cfis_acmd_left_r;
end
assign debug_01 = {dx_fis_pend_r, ct_re_r, ct_re_w, cfis_acmd_left_r}; // 1,2,5
// assign debug_01 = {acfis_xmit_start_w, acfis_xmit_pend_r, dma_ct_busy, fetch_cmd_busy_r, ct_re_w, dbg_was_cfis_acmd_left_r}; // 1,2,5
// wire acfis_xmit_start_w = (cfis_xmit || atapi_xmit || acfis_xmit_pend_r) && !dma_ct_busy && !fetch_cmd_busy_r; // dma_ct_busy no gaps with fetch_cmd_busy
endmodule
/*******************************************************************************
* Module: ahci_fsm
* Date:2016-01-10
* Author: andrey
* Description: AHCI host+port0 state machine
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_fsm.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_fsm.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_fsm
/*#(
// parameter PREFETCH_ALWAYS = 0,
parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
// parameter READ_CT_LATENCY = 1, // 0 if ct_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 hba_rst, // @posedge mclk
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
// Writing FSM program memory
input aclk,
input arst,
input [17:0] pgm_ad, // @aclk, address/data to program the AHCI FSM
input pgm_wa, // @aclk, address strobe to program the AHCI FSM
input pgm_wd, // @aclk, data strobe to program the AHCI FSM
// direct communication with transposrt, link and phy layers
input [1:0] phy_ready, // goes up after comreset,cominit, align, ..., showing speed
output syncesc_send, // Send sync escape
input syncesc_send_done, // "SYNC escape until the interface is quiescent..."
output comreset_send, // Not possible yet?
input cominit_got, // asynchronously jumps to P:Cominit state
output set_offline, // electrically idle
// input x_rdy_collision, // X_RDY/X_RDY collision on interface
output send_R_OK, // Should it be originated in this layer SM?
output send_R_ERR,
// Other signals....
// Communication with ahci_ctrl_stat (some are not needed)
// update register inputs (will write to register memory current value of the corresponding register)
output pfsm_started, // H: FSM done, P: FSM started (enable sensing pcmd_st_cleared)
// update register inputs (will write to register memory current value of the corresponding register)
// Removing - such updates are always done when startimng new state
/// input update_pending,
output update_all, // =fsm_jump[0]
input update_busy, // valid same cycle as update_all
// output update_gis, // these following individual may be unneeded - just use universal update_all
// output update_pis,
// output update_ssts,
// output update_serr,
// output update_pcmd,
// output update_pci,
/// input st01_pending, // software turned PxCMD.ST from 0 to 1 - detected in the loop
/// input st10_pending, // software turned PxCMD.ST from 1 to 0 - generates port reset
/// output st_pending_reset,// reset both st01_pending and st10_pending
// PxCMD
/// output pcmd_clear_icc, // clear PxCMD.ICC field
/// output pcmd_esp, // external SATA port (just forward value)
/// input pcmd_cr, // command list run - current
output pcmd_cr_set, // command list run set
output pcmd_cr_reset, // command list run reset
// output pcmd_fr, // ahci_fis_receive:get_fis_busy
/// output pcmd_clear_bsy_drq, // == ahci_fis_receive:clear_bsy_drq
// Command List override, not yet implemented (optional), keeping @SuppressWarnings VEditor
input pcmd_clo, //RW1, causes ahci_fis_receive:clear_bsy_drq, that in turn resets this bit
/// output pcmd_clear_st, // RW clear ST (start) bit Seems it is software controlled only
input pcmd_st, // current value
input pcmd_st_cleared,// ST bit cleared by software;
//clear_bsy_drq
// Interrupt inputs
output sirq_TFE, // RWC: Task File Error Status
output sirq_IF, // RWC: Interface Fatal Error Status (sect. 6.1.2)
output sirq_INF, // RWC: Interface Non-Fatal Error Status (sect. 6.1.2)
output sirq_OF, // RWC: Overflow Status
output sirq_PRC, // RO: PhyRdy changed Status
output sirq_PC, // RO: Port Connect Change Status
output sirq_DP, // RWC: Descriptor Processed with "I" bit on
output sirq_UF, // RO: Unknown FIS
output sirq_SDB, // RWC: Set Device Bits Interrupt - Set Device bits FIS with 'I' bit set
output sirq_DS, // RWC: DMA Setup FIS Interrupt - DMA Setup FIS received with 'I' bit set
output sirq_PS, // RWC: PIO Setup FIS Interrupt - PIO Setup FIS received with 'I' bit set
output 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
// 5.3.2.3 P:NotRunning.8 - can not be implemented now, keeping @SuppressWarnings VEditor
input serr_diag_X, // value of PxSERR.DIAG.X
// SCR0: SStatus
output ssts_ipm_dnp, // device not present or communication not established
output ssts_ipm_active, // device in active state
output ssts_ipm_part, // device in partial state
output ssts_ipm_slumb, // device in slumber state
output ssts_ipm_devsleep, // device in DevSleep state
output ssts_spd_dnp, // device not present or communication not established
output ssts_spd_gen1, // Gen 1 rate negotiated
output ssts_spd_gen2, // Gen 2 rate negotiated
output ssts_spd_gen3, // Gen 3 rate negotiated
output ssts_det_ndnp, // no device detected, phy communication not established
output ssts_det_dnp, // device detected, but phy communication not established
output ssts_det_dp, // device detected, phy communication established
output ssts_det_offline, // device detected, phy communication established
input [3:0] ssts_det, // current value of PxSSTS.DET
// SCR2:SControl (written by software only)
/// input [3:0] sctl_ipm, // Interface power management transitions allowed
/// input [3:0] sctl_spd, // Interface maximal speed
input [3:0] sctl_det, // Device detection initialization requested
input sctl_det_changed, // Software had written new value to sctl_det
output sctl_det_reset, // clear sctl_det_changed
output hba_rst_done, // reset GHC.HR and other bits
output pxci0_clear, // PxCI clear
input pxci0, // pxCI current value
// inputs from the DMA engine
/// input dma_prd_done, // output (finished next prd)
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)
output dma_cmd_abort, // try to abort a command
input dma_abort_done, // if abort is not needed, will generate dma_abort_done just next cycle
// 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
// Receiving FIS
output get_dsfis,
output get_psfis,
output get_rfis,
output get_sdbfis,
output get_ufis,
output get_data_fis,
output get_ignore, // ignore whatever FIS (use for DMA activate too?)
// input get_fis_busy, // busy processing FIS
input get_fis_done, // done processing FIS (see fis_ok, fis_err, fis_ferr)
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
/// input sig_available, // device signature available
output update_sig, // update signature
// 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_pio, // update PxTFD.STS and PxTFD.ERR from pio_* (entry PIO:Update)
output update_prdbc, // update PRDBC in registers
output clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update
output clear_bsy_set_drq, // clear PxTFD.STS.BSY and sets PxTFD.STS.DRQ, update
output set_bsy, // set PxTFD.STS.BSY, update
output set_sts_7f, // set PxTFD.STS = 0x7f, update
output set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update
output clear_xfer_cntr, // clear pXferCntr (is it needed as a separate input)?
output decr_dwcr, // decrement DMA Xfer counter after read // need pulse to 'update_prdbc' to write to registers
output decr_dwcw, // decrement DMA Xfer counter after write // need pulse to 'update_prdbc' to write to registers
// output [11:0] decr_DXC_dw, // decrement value (in DWORDs)
input pxcmd_fre, // control bit enables saving FIS to memory
input pPioXfer, // state variable
input [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields)
// tfd_sts[7] - BSY, tfd_sts[3] - DRQ, tfd_sts[0] - ERR
/// input [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB)
input fis_i, // value of "I" field in received regsD2H or SDB FIS
/// input sdb_n, // value of "N" field in received SDB FIS
input dma_a, // value of "A" field in received DMA Setup FIS
/// input dma_d, // value of "D" field in received DMA Setup FIS
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
// Communication with ahci_fis_transmit
// Command pulses to execute states
output fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS)
// wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd
output cfis_xmit, // transmit command (wait for dma_ct_busy == 0)
output dx_xmit, // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
output atapi_xmit, // tarsmit ATAPI command FIS
input xmit_done,
// input xmit_busy,
output clearCmdToIssue, // From CFIS:SUCCESS
input pCmdToIssue, // AHCI port variable
// output dmaCntrZero, // DMA counter is zero - would be a duplicate to the one in receive module and dwords_sent output
// input syncesc_recv, // These two inputs interrupt transmit
// input xmit_err, //
input [ 2:0] dx_err, // bit 0 - syncesc_recv, 1 - R_ERR (was xmit_err), 2 - X_RDY/X_RDY collision (valid @ xmit_err and later, reset by new command)
/// input [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0)
input ch_c, // Clear busy upon R_OK for this FIS
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 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 [ 9:0] last_jump_addr // debug feature
/// input [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal,
// maximal is 16 (0x10)
/// input [11:0] dwords_sent // number of DWORDs transmitted (up to 2048)
);
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
`include "includes/fis_types.vh" // @SuppressThisWarning VEditor : Some localparams unused
// Reset addresses - later use generated
localparam LABEL_POR = 11'h000;
localparam LABEL_HBA_RST = 11'h002;
localparam LABEL_PORT_RST = 11'h004;
localparam LABEL_COMINIT = 11'h006;
localparam LABEL_ST_CLEARED = 11'h008;
wire tfd_bsy = tfd_sts[7];
wire tfd_drq = tfd_sts[3];
wire tfd_sts_err = tfd_sts[0];
reg [ 9:0] pgm_waddr;
// wire pgm_ren;
// wire pgm_regen;
wire cond_met_w; // calculated from signals and program conditions decoder
reg [ 9:0] pgm_jump_addr;
reg [ 9:0] pgm_addr;
wire [17:0] pgm_data;
reg was_rst;
// reg jump_r;
reg [2:0] fsm_jump;
wire fsm_next;
// reg fsm_next_r;
reg fsm_actions; // processing actions
reg dis_actions; // disable actions during async jump
reg fsm_act_busy;
reg [1:0] fsm_transitions; // processing transitions
reg fsm_preload; // read first sequence data (2 cycles for regen)
// wire [7:0] precond_w = pgm_data[17:10]; // select what to use - cond_met_w valis after precond_w, same time as conditions
// reg [7:0] conditions;
// wire pre_jump_w = (|async_pend_r) ? async_ackn : |(cond_met_w & fsm_transitions[1]);
wire pre_jump_w = (|async_pend_r) ? async_ackn : (cond_met_w & fsm_transitions[1]);
wire fsm_act_done_w = get_fis_done ||
xmit_done ||
(syncesc_send_pend && syncesc_send_done) ||
dma_abort_done ||
asynq_rq; // cominit_got || pcmd_st_cleared
reg fsm_act_done; // made later by 1 cycle so the new conditions are latched // TODO:check is enough ? Adding 1 extra
reg fsm_act_pre_done;
wire fsm_wait_act_w = pgm_data[16]; // this action requires waiting for done
wire fsm_last_act_w = pgm_data[17];
wire fsm_pre_act_w = !dis_actions && fsm_actions && fsm_next; // use it as CS for generated actions (registered)
reg [1:0] async_pend_r; // waiting to process cominit_got
reg async_from_st; // change to multi-bit if there will be more sources for async transitions
// wire asynq_rq = (cominit_got && unsolicited_cominit_en) || pcmd_st_cleared;
wire asynq_rq = (cominit_got && unsolicited_en) || pcmd_st_cleared;
// OK to wait for some time fsm_act_busy is supposed to never hang up
wire async_ackn = !fsm_preload && async_pend_r[0] && ((fsm_actions && !update_busy && !fsm_act_busy) || fsm_transitions[0]); // OK to process async jump
// reg x_rdy_collision_pend;
reg syncesc_send_pend; // waiting for 'syncesc_send' confiramtion 'syncesc_send_done'
reg [1:0] phy_ready_prev; // previous state of phy_ready / speed
reg phy_ready_chng_r; // pulse when phy_ready changes
wire phy_ready_chng_w = !hba_rst && !was_rst && (phy_ready != phy_ready_prev);
reg was_last_action_r; // delay last action if it was fsm_wait_act;
wire fsm_transitions_w = // next will be transitions processing
(fsm_last_act_w && fsm_actions && fsm_next && !fsm_wait_act_w) ||
(fsm_act_busy && fsm_act_done && was_last_action_r);
wire conditions_ce = // copy all conditions to the register so they will not change while iterating through them
!fsm_transitions_w && !fsm_transitions[0];
// reg unsolicited_cominit_en; // allow unsolicited COMINITs
// wire en_cominit; // en_cominit
// New variable:
reg pisn32; // pIssueSlot != 32
wire clear_pisn32; // additional clear when in P:NotRunning state
assign fsm_next = (fsm_preload || (fsm_actions && !update_busy && !fsm_act_busy) || fsm_transitions[0]) && !async_pend_r[0]; // quiet if received cominit is pending
assign update_all = fsm_jump[0];
assign ssts_ipm_dnp = phy_ready_chng_r && (phy_ready_prev == 0); // device not present or communication not established
assign ssts_ipm_active = phy_ready_chng_r && (phy_ready_prev != 0); // device in active state
assign ssts_ipm_part = 0; // device in partial state
assign ssts_ipm_slumb = 0; // device in slumber state
assign ssts_ipm_devsleep = 0; // device in DevSleep state
assign ssts_spd_dnp = phy_ready_chng_r && (phy_ready_prev == 0); // device not present or communication not established
assign ssts_spd_gen1 = phy_ready_chng_r && (phy_ready_prev == 1); // Gen 1 rate negotiated
assign ssts_spd_gen2 = phy_ready_chng_r && (phy_ready_prev == 2); // Gen 2 rate negotiated
assign ssts_spd_gen3 = phy_ready_chng_r && (phy_ready_prev == 3); // Gen 3 rate negotiated
assign ssts_det_ndnp = phy_ready_chng_r && (phy_ready_prev == 0); // no device detected, phy communication not established
// assign ssts_det_dnp = 0; // device detected, but phy communication not established
assign ssts_det_dp = phy_ready_chng_r && (phy_ready_prev != 0); // device detected, phy communication established
assign sirq_OF = 0; // RWC: Overflow Status (buffer overrun - should not happen, add?)
assign sirq_PRC = phy_ready_chng_r; // RO: PhyRdy changed Status
// Writing to the FSM program memory
always @ (posedge aclk) begin
if (arst) pgm_waddr <= 0;
else if (pgm_wa) pgm_waddr <= pgm_ad[ 9:0];
else if (pgm_wd) pgm_waddr <= pgm_waddr + 1;
end
always @ (posedge mclk) begin
if (hba_rst || pxci0_clear || clear_pisn32) pisn32 <= 0;
else if (fetch_cmd) pisn32 <= 1;
end
always @ (posedge mclk) begin
/// if (hba_rst) unsolicited_cominit_en <= !was_port_rst;
// else if (en_cominit || comreset_send) unsolicited_cominit_en <= en_cominit;
if (hba_rst) pgm_jump_addr <= (was_hba_rst || was_port_rst) ? (was_hba_rst? LABEL_HBA_RST:LABEL_PORT_RST) : LABEL_POR;
// else if (async_pend_r[1]) pgm_jump_addr <= async_from_st? LABEL_ST_CLEARED : LABEL_COMINIT;
else if (async_pend_r[0]) pgm_jump_addr <= async_from_st? LABEL_ST_CLEARED : LABEL_COMINIT;
else if (fsm_transitions[0] && (!cond_met_w || !fsm_transitions[1])) pgm_jump_addr <= pgm_data[9:0];
was_rst <= hba_rst;
/// fsm_act_done <= fsm_act_done_w; // delay by 1 clock cycle
fsm_act_pre_done <= fsm_act_done_w; // delay by 1 clock cycle
fsm_act_done <= fsm_act_pre_done; // TODO - verify delay by 2 is needed to latch
fsm_jump <= {fsm_jump[1:0], pre_jump_w | (was_rst & ~hba_rst)};
if (fsm_jump[0]) pgm_addr <= pgm_jump_addr;
else if (fsm_next) pgm_addr <= pgm_addr + 1;
if (fsm_jump[0]) last_jump_addr <= pgm_jump_addr; // debug feature
// if (hba_rst) conditions <= 0;
// if (fsm_transitions[0]) conditions <= precond_w;
if (hba_rst) fsm_actions <= 0;
else if (fsm_jump[2]) fsm_actions <= 1;
else if (fsm_last_act_w && fsm_next) fsm_actions <= 0;
if (hba_rst) dis_actions <= 0;
else if (|async_pend_r) dis_actions <= 1;
else if (fsm_jump[2]) dis_actions <= 0;
if (fsm_actions && fsm_next) was_last_action_r <= fsm_last_act_w;
if (hba_rst || pre_jump_w) fsm_transitions <= 0;
else if (fsm_transitions_w) fsm_transitions <= 1;
// else if ((fsm_last_act_w && fsm_actions && fsm_next && !fsm_wait_act_w) ||
// (fsm_act_busy && fsm_act_done && was_last_action_r) ) fsm_transitions <= 1;
else fsm_transitions <= {fsm_transitions[0],fsm_transitions[0]};
if (hba_rst) fsm_preload <= 0;
else fsm_preload <= |fsm_jump[1:0];
if (hba_rst) fsm_act_busy <= 0;
else if (fsm_pre_act_w) fsm_act_busy <= fsm_wait_act_w;
else if (fsm_act_done) fsm_act_busy <= 0;
if (hba_rst) async_from_st <= 0;
else if (pcmd_st_cleared) async_from_st <= 1;
else if (asynq_rq) async_from_st <= 0;
if (hba_rst) async_pend_r <= 0;
/// else async_pend_r <= {async_pend_r[0], asynq_rq | (async_pend_r[0] & ~async_ackn)};
else async_pend_r <= {async_pend_r[0], (asynq_rq | async_pend_r[0]) & ~async_ackn};
// if (hba_rst || pcmd_cr_set) x_rdy_collision_pend <= 0;
// else if (x_rdy_collision) x_rdy_collision_pend <= 1;
if (hba_rst || syncesc_send_done) syncesc_send_pend <= 0;
else if (syncesc_send) syncesc_send_pend <= 1;
if (was_rst && !hba_rst && !was_hba_rst && !was_port_rst) phy_ready_prev <= 0;
else if (phy_ready_chng_w) phy_ready_prev <= phy_ready;
phy_ready_chng_r <= phy_ready_chng_w;
end
ram18p_var_w_var_r #(
.REGISTERS(1),
.LOG2WIDTH_WR(4),
.LOG2WIDTH_RD(4)
`include "includes/ahxi_fsm_code.vh"
) fsm_pgm_mem_i (
.rclk (mclk), // input
.raddr (pgm_addr), // input[10:0]
.ren (fsm_next), // input
.regen (fsm_next), // input
.data_out (pgm_data), // output[17:0]
.wclk (aclk), // input
.waddr (pgm_waddr), // input[10:0]
.we (pgm_wd), // input
.web (4'hf), // input[7:0]
.data_in (pgm_ad) // input[17:0]
);
action_decoder action_decoder_i (
.clk (mclk), // input
.enable (fsm_pre_act_w), // input
.data (pgm_data[10:0]), // input[10:0]
// CTRL_STAT
.PXSERR_DIAG_X (sirq_PC), // output reg
.SIRQ_DHR (sirq_DHR), // output reg
.SIRQ_DP (sirq_DP), // output reg
.SIRQ_DS (sirq_DS), // output reg
.SIRQ_IF (sirq_IF), // output reg
.SIRQ_INF (sirq_INF), // output reg
.SIRQ_PS (sirq_PS), // output reg
.SIRQ_SDB (sirq_SDB), // output reg
.SIRQ_TFE (sirq_TFE), // output reg
.SIRQ_UF (sirq_UF), // output reg
.PFSM_STARTED (pfsm_started), // output reg
.PCMD_CR_CLEAR (pcmd_cr_reset), // output reg
.PCMD_CR_SET (pcmd_cr_set), // output reg
.PXCI0_CLEAR (pxci0_clear), // output reg
.PXSSTS_DET_1 (ssts_det_dnp), // output reg
.SSTS_DET_OFFLINE (ssts_det_offline), // output reg
.SCTL_DET_CLEAR (sctl_det_reset), // output reg
.HBA_RST_DONE (hba_rst_done), // output reg
// FIS RECEIVE
.SET_UPDATE_SIG (set_update_sig), // output reg
.UPDATE_SIG (update_sig), // output reg
.UPDATE_ERR_STS (update_err_sts), // output reg
.UPDATE_PIO (update_pio), // output reg
.UPDATE_PRDBC (update_prdbc), // output reg
.CLEAR_BSY_DRQ (clear_bsy_drq), // output reg
.CLEAR_BSY_SET_DRQ (clear_bsy_set_drq), // output reg
.SET_BSY (set_bsy), // output reg
.SET_STS_7F (set_sts_7f), // output reg
.SET_STS_80 (set_sts_80), // output reg
.XFER_CNTR_CLEAR (clear_xfer_cntr), // output reg
.DECR_DWCR (decr_dwcr), // output reg
.DECR_DWCW (decr_dwcw), // output reg
.FIS_FIRST_FLUSH (fis_first_flush), // output reg
// FIS_TRANSMIT
.CLEAR_CMD_TO_ISSUE (clearCmdToIssue), // output reg
// DMA
.DMA_ABORT (dma_cmd_abort), // output reg
.DMA_PRD_IRQ_CLEAR (dma_prd_irq_clear), // output reg
// SATA TRANSPORT/LINK/PHY
.XMIT_COMRESET (comreset_send), // output reg
.SEND_SYNC_ESC (syncesc_send), // output reg
.SET_OFFLINE (set_offline), // output reg
.R_OK (send_R_OK), // output reg
.R_ERR (send_R_ERR), // output reg
// .EN_COMINIT (en_cominit), // output reg
.EN_COMINIT (clear_pisn32), // output reg
// FIS TRANSMIT/WAIT DONE
.FETCH_CMD (fetch_cmd), // output reg
.ATAPI_XMIT (atapi_xmit), // output reg
.CFIS_XMIT (cfis_xmit), // output reg
.DX_XMIT (dx_xmit), // output reg
//FIS RECEIVE/WAIT DONE
.GET_DATA_FIS (get_data_fis), // output reg
.GET_DSFIS (get_dsfis), // output reg
.GET_IGNORE (get_ignore), // output reg
.GET_PSFIS (get_psfis), // output reg
.GET_RFIS (get_rfis), // output reg
.GET_SDBFIS (get_sdbfis), // output reg
.GET_UFIS (get_ufis) // output reg
);
// Condition inputs may be registered if needed
condition_mux condition_mux_i (
.clk (mclk), // input
.ce (conditions_ce), // input
.sel (pgm_data[17:10]), // input[7:0]
.condition (cond_met_w), // output
//COMPOSITE
.ST_NB_ND (pcmd_st && !tfd_bsy &&!tfd_drq), // input PxCMD.ST & !PxTFD.STS.BSY & !PxTFD.STS.DRQ
// .PXCI0_NOT_CMDTOISSUE (pxci0 && !pCmdToIssue), // input pxci0 && !pCmdToIssue was pIssueSlot==32, -> p:SelectCmd
.PXCI0_NOT_CMDTOISSUE (pxci0 && !pisn32), // input pxci0 && !pCmdToIssue was pIssueSlot==32, -> p:SelectCmd
.PCTI_CTBAR_XCZ (pCmdToIssue && xfer_cntr_zero && ch_r ), // input pCmdToIssue && ch_r && xfer_cntr_zero
.PCTI_XCZ (pCmdToIssue && xfer_cntr_zero), // input pCmdToIssue && xfer_cntr_zero
.NST_D2HR (!pcmd_st && (fis_type == FIS_D2HR)), // input !ST && (FIS == FIS_D2HR) TODO: does it mean either BSY or DRQ are 1?
.NPD_NCA (!pio_d && !ch_a), // input pio_d = 0 && ch_a == 0
.CHW_DMAA (ch_w && dma_a), // input ch_w && dma_a
// CTRL_STAT
.SCTL_DET_CHANGED_TO_4 (sctl_det_changed && (sctl_det == 4)), // input (requires sctl_det_reset after)
.SCTL_DET_CHANGED_TO_1 (sctl_det_changed && (sctl_det == 1)), // input (requires sctl_det_reset after)
.PXSSTS_DET_NE_3 (ssts_det != 3), // input ssts_det!=3, // device detected, phy communication not established
.PXSSTS_DET_EQ_1 (ssts_det == 1), // input
.NPCMD_FRE (!pxcmd_fre), // input !pcmd_fre (docs: goto P:NotRunning, but we need to clear FIFO)
// FIS RECEIVE
.FIS_OK (fis_ok), // input
.FIS_ERR (fis_err), // input
.FIS_FERR (fis_ferr), // input
.FIS_EXTRA (fis_extra), // input
.FIS_FIRST_INVALID (fis_first_invalid), // input
.FR_D2HR (fis_first_vld && (fis_type == FIS_D2HR)), // input fis_first_vld & fis_type == 0x34 (D2H Register)
.FIS_DATA (fis_first_vld && (fis_type == FIS_DATA)), // input fis_first_vld && (fis_type == 'h46)
.FIS_ANY (fis_first_vld), // input
.NB_ND_D2HR_PIO (((fis_type == FIS_D2HR) || (fis_type == FIS_PIOS)) && !tfd_bsy && !tfd_drq), // input ((FIS == FIS_D2HR) || (FIS == FIS_PIOS)) && !PxTFD.STS.BSY & !PxTFD.STS.DRQ
.D2HR ( fis_type == FIS_D2HR), // input FIS == FIS_D2HR
.SDB ( fis_type == FIS_SDB), // input
.DMA_ACT ( fis_type == FIS_DMAA), // input
.DMA_SETUP ( fis_type == FIS_DMAS), // input
.BIST_ACT_FE (( fis_type == FIS_BIST) && (|bist_bits)), // input FIS == FIS_BIST && |bist_bits
.BIST_ACT (( fis_type == FIS_BIST)), // input FIS == FIS_BIST# && !(|bist_bits)
.PIO_SETUP ( fis_type == FIS_PIOS), // input
.NB_ND (!tfd_bsy &&!tfd_drq), // input PxTFD.STS.BSY =’0’ and PxTFD.STS.DRQ =’0’
.TFD_STS_ERR ( tfd_sts_err), // input tfd_sts[0]
.FIS_I (fis_i), // input
.PIO_I (pio_i), // input
.NPD (!pio_d), // input pio_d = 0 , "ch_a == 1" is not needed
.PIOX (pPioXfer), // input
.XFER0 (xfer_cntr_zero && !dma_cmd_busy), // input xfer_cntr_zero
.PIOX_XFER0 (pPioXfer && xfer_cntr_zero &&!dma_cmd_busy), // input pPioXfer && xfer_cntr_zero
// FIS_TRANSMIT
.CTBAA_CTBAP (ch_a && ch_p), // input
.CTBAP (ch_p), // input
.CTBA_B (ch_b), // input
.CTBA_C (ch_c), // input
.TX_ERR (dx_err[1]), // input dx_err[1] (reset by new command)
.SYNCESC_ERR (dx_err[0]), // input
// DMA
.DMA_PRD_IRQ_PEND (dma_prd_irq_pend), // input
// SATA TRANSPORT/LINK/PHY
.X_RDY_COLLISION (dx_err[2]) //x_rdy_collision_pend) // input
);
/*
output update_all,
input update_busy, // valid same cycle as update_all
Notes:
Implement sync esc request/ackn in TL (available in LL)
*/
endmodule
/*******************************************************************************
* Module: ahci_sata_layers
* Date:2016-01-19
* Author: andrey
* Description: Link and PHY SATA layers
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_sata_layers.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_sata_layers.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_sata_layers #(
`ifdef USE_DATASCOPE
parameter ADDRESS_BITS = 10, //for datascope
parameter DATASCOPE_START_BIT = 14, // bit of DRP "other_control" to start recording after 0->1 (needs DRP)
parameter DATASCOPE_POST_MEAS = 16, // number of measurements to perform after event
`endif
parameter BITS_TO_START_XMIT = 6, // wait H2D FIFO to have 1 << BITS_TO_START_XMIT to start FIS transmission (or all FIS fits)
parameter DATA_BYTE_WIDTH = 4,
parameter ELASTIC_DEPTH = 4, //5, With 4/7 got infrequent overflows!
parameter ELASTIC_OFFSET = 7, // 5 //10
parameter FREQ_METER_WIDTH = 12
)(
input exrst, // master reset that resets PLL and GTX
input reliable_clk, // use aclk that runs independently of the GTX
output rst, // PHY-generated reset after PLL lock
output clk, // PHY-generated clock, 75MHz for SATA2
// Data/type FIFO, host -> device
// Data System memory or FIS -> device
input [31:0] h2d_data, // 32-bit data from the system memory to HBA (dma data)
input [ 1:0] h2d_mask, // set to 2'b11
input [ 1:0] h2d_type, // 0 - data, 1 - FIS head, 2 - FIS LAST
input h2d_valid, // output register full
output h2d_ready, // h2d FIFO has room for data (>= 8? dwords)
// Data/type FIFO, device -> host
output [31:0] d2h_data, // FIFO input data
output [ 1:0] d2h_mask, // set to 2'b11
output [ 1:0] d2h_type, // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR (last two - after data, so ignore data with R_OK/R_ERR)
output d2h_valid, // Data available from the transport layer in FIFO
output d2h_many, // Multiple DWORDs available from the transport layer in FIFO
input d2h_ready, // This module or DMA consumes DWORD
// communication with link/phys layers
output [ 1:0] phy_speed, // 0 - not ready, 1..3 - negotiated speed (Now 0/2)
output gtx_ready, // How to use it?
output xmit_ok, // received R_OK after transmission
output xmit_err, // Error during/after sending of a FIS (got R_ERR)
output x_rdy_collision, // X_RDY/X_RDY collision on interface
output syncesc_recv, // Where to get it?
input pcmd_st_cleared, // PxCMD.ST 1->0 transition by software
input syncesc_send, // Send sync escape
output syncesc_send_done, // "SYNC escape until the interface is quiescent..."
input comreset_send, // Not possible yet?
output cominit_got,
input set_offline, // electrically idle
input send_R_OK, // Should it be originated in this layer SM?
input send_R_ERR,
// additional errors from SATA layers (single-clock pulses):
output serr_DT, // RWC: Transport state transition error
output serr_DS, // RWC: Link sequence error
output serr_DH, // RWC: Handshake Error (i.e. Device got CRC error)
output serr_DC, // RWC: CRC error in Link layer
output serr_DB, // RWC: 10B to 8B decode error
output serr_DW, // RWC: COMMWAKE signal was detected
output serr_DI, // RWC: PHY Internal Error
// sirq_PRC,
output serr_EE, // RWC: Internal error (such as elastic buffer overflow or primitive mis-alignment)
output serr_EP, // RWC: Protocol Error - a violation of SATA protocol detected
output serr_EC, // RWC: Persistent Communication or Data Integrity Error
output serr_ET, // RWC: Transient Data Integrity Error (error not recovered by the interface)
output serr_EM, // RWC: Communication between the device and host was lost but re-established
output serr_EI, // RWC: Recovered Data integrity Error
// additional control signals for SATA layers
input [3:0] sctl_ipm, // Interface power management transitions allowed // @SuppressThisWarning Veditor Unused (yet)
input [3:0] sctl_spd, // Interface maximal speed // @SuppressThisWarning Veditor Unused (yet)
// Device high speed pads and clock inputs
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in,
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
output datascope_clk,
output [ADDRESS_BITS-1:0] datascope_waddr,
output datascope_we,
output [31:0] datascope_di,
`endif
`ifdef USE_DRP
input drp_rst,
input drp_clk,
input drp_en, // @aclk strobes drp_ad
input drp_we,
input [14:0] drp_addr,
input [15:0] drp_di,
output drp_rdy,
output [15:0] drp_do ,
`endif
output [FREQ_METER_WIDTH - 1:0] xclk_period, // relative (to 2*clk) xclk period
output [31:0] debug_phy,
output [31:0] debug_link,
input hclk // just for testing
);
localparam PHY_SPEED = 2; // SATA2
localparam FIFO_ADDR_WIDTH = 9;
localparam D2H_TYPE_DMA = 0;
localparam D2H_TYPE_FIS_HEAD = 1;
localparam D2H_TYPE_OK = 2;
localparam D2H_TYPE_ERR = 3;
localparam H2D_TYPE_FIS_DATA = 0; // @SuppressThisWarning VEditor unused
localparam H2D_TYPE_FIS_HEAD = 1;
localparam H2D_TYPE_FIS_LAST = 2;
wire phy_ready; // active when GTX gets aligned output
wire link_established; // Received 3 back-to-back non-ALIGNp
wire [31:0] ll_h2d_data_in;
wire [1:0] ll_h2d_mask_in;
wire ll_strobe_out;
wire ll_h2d_last;
wire [1:0] h2d_type_out;
wire [31:0] ll_d2h_data_out;
wire [ 1:0] ll_d2h_mask_out;
wire ll_d2h_valid;
wire ll_d2h_almost_full;
reg [1:0] d2h_type_in;
reg fis_over_r; // push 1 more DWORD (ignore) + type (ERR/OK) when received FIS is done/error
reg ll_frame_req; // -> link // request for a new frame transition
wire ll_frame_ackn; // acknowledge for ll_frame_req
wire ll_incom_start; // link -> // if started an incoming transaction assuming this and next 2 are single-cycle
wire ll_incom_done; // link -> // if incoming transition was completed
wire ll_incom_invalidate; // link -> // if incoming transition had errors
reg ll_incom_invalidate_r; // error delayed by 1 clock - if eof was incorrect (because of earlier data error)
// let last data dword to pass through
wire ll_link_reset = ~phy_ready; // -> link // oob sequence is reinitiated and link now is not established or rxelecidle //TODO Alexey:mb it shall be independent
wire [DATA_BYTE_WIDTH*8 - 1:0] ph2ll_data_out;
wire [DATA_BYTE_WIDTH - 1:0] ph2ll_charisk_out; // charisk
wire [DATA_BYTE_WIDTH - 1:0] ph2ll_err_out; // disperr | notintable
wire [DATA_BYTE_WIDTH*8 - 1:0] ll2ph_data_in;
wire [DATA_BYTE_WIDTH - 1:0] ll2ph_charisk_in; // charisk
wire [FIFO_ADDR_WIDTH-1:0] h2d_raddr;
wire [1:0] h2d_fifo_re_regen;
wire [FIFO_ADDR_WIDTH-1:0] h2d_waddr;
wire [FIFO_ADDR_WIDTH:0] h2d_fill;
wire h2d_nempty;
wire [FIFO_ADDR_WIDTH-1:0] d2h_raddr;
wire [1:0] d2h_fifo_re_regen;
wire [FIFO_ADDR_WIDTH-1:0] d2h_waddr;
wire [FIFO_ADDR_WIDTH:0] d2h_fill;
wire d2h_nempty;
wire h2d_fifo_rd = h2d_nempty && ll_strobe_out; // TODO: check latency in link.v
wire h2d_fifo_wr = h2d_valid;
wire d2h_fifo_rd = d2h_valid && d2h_ready;
wire d2h_fifo_wr = ll_d2h_valid || fis_over_r; // fis_over_r will push FIS end to FIFO
reg h2d_pending; // HBA started sending FIS to fifo
wire rxelsfull;
wire rxelsempty;
wire xclk; // output receive clock, just to measure frequency
wire debug_detected_alignp; // oob detects ALIGNp, but not the link layer
wire [31:0] debug_phy0;
`ifdef USE_DATASCOPE
wire [31:0] datascope0_di;
`endif
assign ll_h2d_last = (h2d_type_out == H2D_TYPE_FIS_LAST);
assign d2h_valid = d2h_nempty;
assign d2h_many = |d2h_fill[FIFO_ADDR_WIDTH:3]; //
assign h2d_ready = !h2d_fill[FIFO_ADDR_WIDTH] && !(&h2d_fill[FIFO_ADDR_WIDTH:3]);
assign ll_d2h_almost_full = d2h_fill[FIFO_ADDR_WIDTH] || &d2h_fill[FIFO_ADDR_WIDTH-1:6]; // 63 dwords (maybe use :5?) - time to tell device to stop
// assign ll_frame_req_w = !ll_frame_busy && h2d_pending && (((h2d_type == H2D_TYPE_FIS_LAST) && h2d_fifo_wr ) || (|h2d_fill[FIFO_ADDR_WIDTH : BITS_TO_START_XMIT]));
// Separating different types of errors, sync_escape from other problems. TODO: route individual errors to set SERR bits
//assign incom_invalidate = state_rcvr_eof & crc_bad & ~alignes_pair | state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP];
// assign phy_speed = phy_ready ? PHY_SPEED:0;
// assign serr_DB = phy_ready && (|ph2ll_err_out);
// assign serr_DH = phy_ready && (xmit_err);
assign phy_speed = link_established ? PHY_SPEED:0;
assign serr_DB = link_established && (|ph2ll_err_out);
assign serr_DH = link_established && (xmit_err);
//
// not yet assigned errors
/// assign serr_DT = phy_ready && (comreset_send); // RWC: Transport state transition error
/// assign serr_DS = phy_ready && (cominit_got); // RWC: Link sequence error
/// assign serr_DC = phy_ready && (serr_DW); // RWC: CRC error in Link layer
assign serr_DT = phy_ready && (0); // RWC: Transport state transition error
// assign serr_DS = phy_ready && (0); // RWC: Link sequence error
// assign serr_DC = phy_ready && (0); // RWC: CRC error in Link layer
// assign serr_DB = phy_ready && (0); // RWC: 10B to 8B decode error
assign serr_EE = phy_ready && (rxelsfull || rxelsempty);
assign serr_DI = phy_ready && (0); // rxelsfull); // RWC: PHY Internal Error // just debugging
assign serr_EP = phy_ready && (0); // rxelsempty); // RWC: Protocol Error - a violation of SATA protocol detected // just debugging
assign serr_EC = phy_ready && (0); // RWC: Persistent Communication or Data Integrity Error
assign serr_ET = phy_ready && (0); // RWC: Transient Data Integrity Error (error not recovered by the interface)
assign serr_EM = phy_ready && (0); // RWC: Communication between the device and host was lost but re-established
assign serr_EI = phy_ready && (0); // RWC: Recovered Data integrity Error
reg [1:0] debug_last_d2h_type_in;
reg [1:0] debug_last_d2h_type;
always @ (posedge clk) begin
if (d2h_fifo_wr) debug_last_d2h_type_in<= d2h_type_in;
if (d2h_fifo_rd) debug_last_d2h_type<= d2h_type;
end
assign debug_phy = debug_phy0;
`ifdef USE_DATASCOPE
`ifdef DATASCOPE_INCOMING_RAW
assign datascope_di = {5'b0,debug_link[5],datascope0_di[25:0]};// aligns_pair tx
`else
// Mix transmitted alignes pair, but only to the closest group of 6 primitives
reg dbg_was_link5; // alignes pair sent
wire dbg_was_link5_xclk; // alignes pair sent
always @ (posedge datascope_clk) begin
if (dbg_was_link5_xclk) dbg_was_link5 <= 1;
else if (datascope_we) dbg_was_link5 <= 0;
end
pulse_cross_clock #(
.EXTRA_DLY(0)
) dbg_was_link5_i (
.rst (rst), // input
.src_clk (clk), // input
.dst_clk (datascope_clk), // input
.in_pulse (debug_link[5]), // input// is actually a two-cycle
.out_pulse (dbg_was_link5_xclk), // output
.busy() // output
);
assign datascope_di = {dbg_was_link5,datascope0_di[30:0]};// aligns_pair tx
`endif
`endif
link #(
.DATA_BYTE_WIDTH(4)
) link (
.rst (rst), // input wire
.clk (clk), // input wire
// data inputs from transport layer
.data_in (ll_h2d_data_in), // input[31:0] wire // input data stream (if any data during OOB setting => ignored)
// TODO, for now not supported, all mask bits are assumed to be set
.data_mask_in (ll_h2d_mask_in), // input[1:0] wire
.data_strobe_out (ll_strobe_out), // output wire // buffer read strobe
.data_last_in (ll_h2d_last), // input wire // transaction's last data budle pulse
.data_val_in (h2d_nempty), // input wire // read data is valid (if 0 while last pulse wasn't received => need to hold the line)
.data_out (ll_d2h_data_out), // output[31:0] wire // read data, same as related inputs
.data_mask_out (ll_d2h_mask_out), // output[1:0] wire // same thing - all 1s for now. TODO
.data_val_out (ll_d2h_valid), // output wire // count every data bundle read by transport layer, even if busy flag is set // let the transport layer handle oveflows by himself
.data_busy_in (ll_d2h_almost_full), // input wire // transport layer tells if its inner buffer is almost full
.data_last_out (), // ll_d2h_last), // output wire not used
.frame_req (ll_frame_req), // input wire // request for a new frame transmission
.frame_busy (), // ll_frame_busy), // output wire // a little bit of overkill with the cound of response signals, think of throwing out 1 of them // LL tells back if it cant handle the request for now
.frame_ack (ll_frame_ackn), // ll_frame_ack), // output wire // LL tells if the request is transmitting
.frame_rej (x_rdy_collision), // output wire // or if it was cancelled because of simultanious incoming transmission
.frame_done_good (xmit_ok), // output wire // TL tell if the outcoming transaction is done and how it was done
.frame_done_bad (xmit_err), // output wire
.incom_start (ll_incom_start), // output wire // if started an incoming transaction
.incom_done (ll_incom_done), // output wire // if incoming transition was completed
.incom_invalidate (ll_incom_invalidate), // output wire // if incoming transition had errors
.incom_sync_escape(syncesc_recv), // output wire - received sync escape
.incom_ack_good (send_R_OK), // input wire // transport layer responds on a completion of a FIS
.incom_ack_bad (send_R_ERR), // input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.link_reset (ll_link_reset), // input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.sync_escape_req (syncesc_send), // input wire // TL demands to brutally cancel current transaction
.sync_escape_ack (syncesc_send_done), // output wire // acknowlegement of a successful reception?
.incom_stop_req (pcmd_st_cleared), // input wire // TL demands to stop current receiving session
.link_established (link_established), // output wire
.link_bad_crc (serr_DC), // output wire // Bad CRC at EOF
// inputs from phy
.phy_ready (phy_ready), // input wire // phy is ready - link is established
// data-primitives stream from phy
.phy_data_in (ph2ll_data_out), // input[31:0] wire // phy_data_in
.phy_isk_in (ph2ll_charisk_out), // input[3:0] wire // charisk
.phy_err_in (ph2ll_err_out), // input[3:0] wire // disperr | notintable
// to phy
.phy_data_out (ll2ph_data_in), // output[31:0] wire
.phy_isk_out (ll2ph_charisk_in), // output[3:0] wire // charisk
.debug_out (debug_link)
);
always @ (posedge clk) begin
ll_incom_invalidate_r <= ll_incom_invalidate;
// FIS receive D2H
// add head if ll_d2h_valid and (d2h_type_in == D2H_TYPE_OK) || (d2h_type_in == D2H_TYPE_ERR)? Or signal some internal error
if (rst || ll_incom_start) d2h_type_in <= D2H_TYPE_FIS_HEAD; // FIS head
else if (ll_d2h_valid) d2h_type_in <= D2H_TYPE_DMA; // FIS BODY
else if (ll_incom_done || ll_incom_invalidate_r) d2h_type_in <= ll_incom_invalidate_r ? D2H_TYPE_ERR: D2H_TYPE_OK;
if (rst) fis_over_r <= 0;
else fis_over_r <= (ll_incom_done || ll_incom_invalidate_r) && (d2h_type_in == D2H_TYPE_DMA); // make sure it is only once
// Second - generate internal error?
// FIS transmit H2D
// Start if all FIS is in FIFO (last word received) or at least that many is in FIFO
if (rst || ll_frame_req) h2d_pending <= 0; // ?
else if ((h2d_type == H2D_TYPE_FIS_HEAD) && h2d_fifo_wr) h2d_pending <= 1;
if (rst) ll_frame_req <= 0;
// else ll_frame_req <= ll_frame_req_w;
else if (h2d_pending &&
(((h2d_type == H2D_TYPE_FIS_LAST) && h2d_fifo_wr ) ||
(|h2d_fill[FIFO_ADDR_WIDTH : BITS_TO_START_XMIT]))) ll_frame_req <= 1;
else if (ll_frame_ackn) ll_frame_req <= 0;
end
sata_phy #(
`ifdef USE_DATASCOPE
.ADDRESS_BITS (ADDRESS_BITS), // for datascope
.DATASCOPE_START_BIT (DATASCOPE_START_BIT),
.DATASCOPE_POST_MEAS (DATASCOPE_POST_MEAS),
`endif
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.ELASTIC_DEPTH (ELASTIC_DEPTH),
.ELASTIC_OFFSET (ELASTIC_OFFSET)
) phy (
.extrst (exrst), // input wire
.clk (clk), // output wire
.rst (rst), // output wire
.reliable_clk (reliable_clk), // input wire
.phy_ready (phy_ready), // output wire
.gtx_ready (gtx_ready), // output wire
.debug_cnt (), // output[11:0] wire
.extclk_p (extclk_p), // input wire
.extclk_n (extclk_n), // input wire
.txp_out (txp_out), // output wire
.txn_out (txn_out), // output wire
.rxp_in (rxp_in), // input wire
.rxn_in (rxn_in), // input wire
.ll_data_out (ph2ll_data_out), // output[31:0] wire
.ll_charisk_out (ph2ll_charisk_out), // output[3:0] wire
.ll_err_out (ph2ll_err_out), // output[3:0] wire
.ll_data_in (ll2ph_data_in), // input[31:0] wire
.ll_charisk_in (ll2ph_charisk_in), // input[3:0] wire
.set_offline (set_offline), // input
.comreset_send (comreset_send), // input
.cominit_got (cominit_got), // output wire
.comwake_got (serr_DW), // output wire
.rxelsfull (rxelsfull), // output wire
.rxelsempty (rxelsempty), // output wire
.cplllock_debug (),
.usrpll_locked_debug (),
.re_aligned (serr_DS), // output reg
.xclk (xclk), // output receive clock, just to measure frequency
`ifdef USE_DATASCOPE
.datascope_clk (datascope_clk), // output
.datascope_waddr (datascope_waddr), // output[9:0]
.datascope_we (datascope_we), // output
.datascope_di (datascope0_di), // output[31:0]
.datascope_trig (ll_incom_invalidate ), // ll_frame_ackn), // input datascope external trigger
// .datascope_trig (debug_link[4:0] == 'h0a), // state_send_eof // input datascope external trigger
/// .datascope_trig (debug_link[4:0] == 'h02), // state_rcvr_goodcrc // input datascope external trigger
//debug_link
`endif
`ifdef USE_DRP
.drp_rst (drp_rst), // input
.drp_clk (drp_clk), // input
.drp_en (drp_en), // input
.drp_we (drp_we), // input
.drp_addr (drp_addr), // input[14:0]
.drp_di (drp_di), // input[15:0]
.drp_rdy (drp_rdy), // output
.drp_do (drp_do), // output[15:0]
`endif
.debug_sata (debug_phy0)
,.debug_detected_alignp(debug_detected_alignp)
);
fifo_sameclock_control #(
.WIDTH(9)
) fifo_h2d_control_i (
.clk (clk), // input
.rst (rst || pcmd_st_cleared), // input
.wr (h2d_fifo_wr), // input
.rd (h2d_fifo_rd), // input
.nempty (h2d_nempty), // output
.fill_in (h2d_fill), // output[9:0]
.mem_wa (h2d_waddr), // output[8:0] reg
.mem_ra (h2d_raddr), // output[8:0] reg
.mem_re (h2d_fifo_re_regen[0]), // output
.mem_regen(h2d_fifo_re_regen[1]), // output
.over (), // output reg
.under () //h2d_under) // output reg
);
ram18p_var_w_var_r #(
.REGISTERS (1),
.LOG2WIDTH_WR (5),
.LOG2WIDTH_RD (5)
) fifo_h2d_i (
.rclk (clk), // input
.raddr (h2d_raddr), // input[8:0]
.ren (h2d_fifo_re_regen[0]), // input
.regen (h2d_fifo_re_regen[1]), // input
.data_out ({h2d_type_out, ll_h2d_mask_in, ll_h2d_data_in}), // output[35:0]
.wclk (clk), // input
.waddr (h2d_waddr), // input[8:0]
.we (h2d_fifo_wr), // input
.web (4'hf), // input[3:0]
.data_in ({h2d_type,h2d_mask,h2d_data}) // input[35:0]
);
fifo_sameclock_control #(
.WIDTH(9)
) fifo_d2h_control_i (
.clk (clk), // input
.rst (rst || pcmd_st_cleared), // input
.wr (d2h_fifo_wr), // input
.rd (d2h_fifo_rd), // input
.nempty (d2h_nempty), // output
.fill_in (d2h_fill), // output[9:0]
.mem_wa (d2h_waddr), // output[8:0] reg
.mem_ra (d2h_raddr), // output[8:0] reg
.mem_re (d2h_fifo_re_regen[0]), // output
.mem_regen(d2h_fifo_re_regen[1]), // output
.over (), //d2h_over), // output reg
.under () // output reg
);
ram18p_var_w_var_r #(
.REGISTERS (1),
.LOG2WIDTH_WR (5),
.LOG2WIDTH_RD (5)
) fifo_d2h_i (
.rclk (clk), // input
.raddr (d2h_raddr), // input[8:0]
.ren (d2h_fifo_re_regen[0]), // input
.regen (d2h_fifo_re_regen[1]), // input
.data_out ({d2h_type, d2h_mask, d2h_data}), // output[35:0]
.wclk (clk), // input
.waddr (d2h_waddr), // input[8:0]
.we (d2h_fifo_wr), // input
.web (4'hf), // input[3:0]
.data_in ({d2h_type_in, ll_d2h_mask_out, ll_d2h_data_out}) // input[35:0]
);
freq_meter #(
.WIDTH (FREQ_METER_WIDTH),
.PRESCALE (1)
) freq_meter_i (
.rst (rst), // input
.clk (clk), // input
.xclk (xclk), // hclk), //xclk), // input
.dout (xclk_period) // output[11:0] reg
);
endmodule
/*******************************************************************************
* Module: ahci_top
* Date:2016-01-09
* Author: Andrey Filippov
* Description: Top module of the AHCI implementation
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_top.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_top.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_top#(
parameter PREFETCH_ALWAYS = 0,
parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
// parameter READ_CT_LATENCY = 1, // 0 if ct_rdata is available with reg_re/reg_addr, 2 with re/regen
parameter READ_CT_LATENCY = 2, // 0 if ct_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)
parameter HBA_RESET_BITS = 9, // duration of HBA reset in aclk periods (9: ~10usec)
parameter RESET_TO_FIRST_ACCESS = 1, // keep port reset until first R/W any register by software
parameter FREQ_METER_WIDTH = 12
)(
input aclk, // clock - should be buffered
input arst, // @aclk sync reset, active high
input mclk, // SATA system clock (current 75MHz for SATA2)
input mrst, // reset in mclk clock domain (after SATA PLL is on)
// async reset for SATA (mrst will be response to it)
output hba_arst, // hba async reset (currently does ~ the same as port reset)
output port_arst, // port0 async set by software (does not include arst)
output port_arst_any, // port0 async set by software and by arst
input hclk, // AXI HP interface clock for 64-bit DMA (current - 150MHz
input hrst, // reset in hclk clock domain
// MAXIGP1
// AXI Write Address
input [31:0] awaddr, // AWADDR[31:0], input
input awvalid, // AWVALID, input
output awready, // AWREADY, output
input [11:0] awid, // AWID[11:0], input
input [ 3:0] awlen, // AWLEN[3:0], input
input [ 1:0] awsize, // AWSIZE[1:0], input
input [ 1:0] awburst, // AWBURST[1:0], input
// AXI PS Master GP0: Write Data
input [31:0] wdata, // WDATA[31:0], input
input wvalid, // WVALID, input
output wready, // WREADY, output
input [11:0] wid, // WID[11:0], input
input wlast, // WLAST, input
input [ 3:0] wstb, // WSTRB[3:0], input
// AXI PS Master GP0: Write response
output bvalid, // BVALID, output
input bready, // BREADY, input
output [11:0] bid, // BID[11:0], output
output [ 1:0] bresp, // BRESP[1:0], output
// AXI Read Address
input [31:0] araddr, // ARADDR[31:0], input
input arvalid, // ARVALID, input
output arready, // ARREADY, output
input [11:0] arid, // ARID[11:0], input
input [ 3:0] arlen, // ARLEN[3:0], input
input [ 1:0] arsize, // ARSIZE[1:0], input
input [ 1:0] arburst, // ARBURST[1:0], input
// AXI Read Data
output [31:0] rdata, // RDATA[31:0], output
output rvalid, // RVALID, output
input rready, // RREADY, input
output [11:0] rid, // RID[11:0], output
output rlast, // RLAST, output
output [ 1:0] rresp, // RRESP
// SAXIHP3
// axi_hp signals write channel
// write address
output [31:0] afi_awaddr,
output afi_awvalid,
input afi_awready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_awid,
output [ 1:0] afi_awlock,
output [ 3:0] afi_awcache,
output [ 2:0] afi_awprot,
output [ 3:0] afi_awlen,
output [ 1:0] afi_awsize,
output [ 1:0] afi_awburst,
output [ 3:0] afi_awqos,
// write data
output [63:0] afi_wdata,
output afi_wvalid,
input afi_wready, // @ SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_wid,
output afi_wlast,
output [ 7:0] afi_wstrb,
// write response
input afi_bvalid, // @SuppressThisWarning VEditor unused
output afi_bready,
input [ 5:0] afi_bid, // @SuppressThisWarning VEditor unused
input [ 1:0] afi_bresp, // @SuppressThisWarning VEditor unused
// PL extra (non-AXI) signals
input [ 7:0] afi_wcount,
input [ 5:0] afi_wacount,
output afi_wrissuecap1en,
// AXI_HP signals - read channel
// read address
output [31:0] afi_araddr,
output afi_arvalid,
input afi_arready, // @SuppressThisWarning VEditor unused - used FIF0 level
output [ 5:0] afi_arid,
output [ 1:0] afi_arlock,
output [ 3:0] afi_arcache,
output [ 2:0] afi_arprot,
output [ 3:0] afi_arlen,
output [ 1:0] afi_arsize,
output [ 1:0] afi_arburst,
output [ 3:0] afi_arqos,
// read data
input [63:0] afi_rdata,
input afi_rvalid,
output afi_rready,
input [ 5:0] afi_rid, // @SuppressThisWarning VEditor unused
input afi_rlast, // @SuppressThisWarning VEditor unused
input [ 1:0] afi_rresp, // @SuppressThisWarning VEditor unused
// PL extra (non-AXI) signals
input [ 7:0] afi_rcount,
input [ 2:0] afi_racount,
output afi_rdissuecap1en,
// Data/type FIFO, host -> device
// Data System memory or FIS -> device
output [31:0] h2d_data, // 32-bit data from the system memory to HBA (dma data)
output [ 1:0] h2d_type, // 0 - data, 1 - FIS head, 2 - FIS END (make FIS_Last?)
output h2d_valid, // output register full
input h2d_ready, // send FIFO has room for data (>= 8? dwords)
// Data/type FIFO, device -> host
input [31:0] d2h_data, // FIFO output data
input [ 1:0] d2h_type, // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR
input d2h_valid, // Data available from the transport layer in FIFO
input d2h_many, // Multiple DWORDs available from the transport layer in FIFO
output d2h_ready, // This module or DMA consumes DWORD
// communication with transport/link/phys layers
// input phy_rst, // frome phy, as a response to hba_arst || port_arst. It is deasserted when clock is stable
input [ 1:0] phy_ready, // 0 - not ready, 1..3 - negotiated speed
input xmit_ok, // FIS transmission acknowledged OK
input xmit_err, // Error during sending of a FIS
input syncesc_recv, // These two inputs interrupt transmit
output pcmd_st_cleared, // bit was cleared by software
output syncesc_send, // Send sync escape
input syncesc_send_done, // "SYNC escape until the interface is quiescent..."
output comreset_send, // Not possible yet?
input cominit_got,
output set_offline, // electrically idle
input x_rdy_collision, // X_RDY/X_RDY collision on interface
output send_R_OK, // Should it be originated in this layer SM?
output send_R_ERR,
// additional errors from SATA layers (single-clock pulses):
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
// additional control signals for SATA layers
output [3:0] sctl_ipm, // Interface power management transitions allowed
output [3:0] sctl_spd, // Interface maximal speed
output irq, // CPU interrupt request
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
input datascope1_clk,
input [ADDRESS_BITS-1:0] datascope1_waddr,
input datascope1_we,
input [31:0] datascope1_di,
`endif
`ifdef USE_DRP
output drp_en, // @aclk strobes drp_ad
output drp_we,
output [14:0] drp_addr,
output [15:0] drp_di,
input drp_rdy,
input [15:0] drp_do,
`endif
input [FREQ_METER_WIDTH - 1:0] xclk_period, // relative (to 2*clk) xclk period
input [31:0] debug_in_phy,
input [31:0] debug_in_link
);
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
wire datascope_clk;
wire [ADDRESS_BITS-1:0] datascope_waddr;
wire datascope_we;
wire [31:0] datascope_di;
`endif
// axi_ahci_regs signals:
// 1. Notification of data written @ hba_clk
wire [ADDRESS_BITS-1:0] soft_write_addr; // register address written by software
wire [31:0] soft_write_data; // register data written (after applying wstb and type (RO, RW, RWC, RW1)
wire soft_write_en; // write enable for data write
// wire hba_arst; // hba async reset (currently does ~ the same as port reset)
// wire port_arst; // port0 async reset by software
// 2. HBA R/W registers, use hba clock
// wire hba_rst;
wire regs_we_acs;
// wire [1:0] regs_re_fsm;
wire [31:0] regs_din_from_acs; // from fsm
wire regs_we_freceive;
wire [1:0] regs_re_ftransmit; // [0] - re, [1] - regen
wire [ADDRESS_BITS-1:0] regs_saddr; // read/write adderss from ahci_fsm
wire [ADDRESS_BITS-1:0] regs_waddr;
wire [ADDRESS_BITS-1:0] regs_raddr;
wire [31:0] regs_din_from_freceive;
wire [31:0] regs_dout;
reg en_port;
wire [1:0] regs_re = en_port ? regs_re_ftransmit : 2'b0; // [0] - re, [1] - regen
wire regs_we = en_port ? ( regs_we_freceive | regs_we_acs) : 1'b0;
wire [ADDRESS_BITS-1:0] regs_addr = ({ADDRESS_BITS{regs_we_freceive}} & regs_waddr) |
({ADDRESS_BITS{regs_re_ftransmit[0]}} & regs_raddr) |
({ADDRESS_BITS{regs_we_acs}} & regs_saddr);
/*
wire [ADDRESS_BITS-1:0] regs_addr = ({ADDRESS_BITS{en_port & regs_we_freceive}} & regs_waddr) |
({ADDRESS_BITS{en_port & regs_re_ftransmit[0]}} & regs_raddr) |
({ADDRESS_BITS{en_port & regs_we_acs}} & regs_saddr);
*/
wire [31:0] regs_din = ({32{regs_we_freceive}} & regs_din_from_freceive) |
({32{regs_we_acs}} & regs_din_from_acs);
// wire [1:0] regs_re = regs_re_ftransmit | regs_re_fsm; // [0] - re, [1] - regen
//---------------------
// wire [31:7] ctba; // input[31:7]
wire ctba_ld; // input
wire [15:0] prdtl; // input[15:0]
wire dev_wr; // input
wire dma_cmd_start; // input
wire dma_prd_start; // input
wire dma_cmd_abort_xmit; // input
wire dma_cmd_abort_fsm; // abort from FSM (also from ahci_fis_transmit)
// Use some of the custom registers in the address space?
wire [17:0] fsm_pgm_ad; // @aclk, address/data to program the AHCI FSM
wire fsm_pgm_wa; // @aclk, address strobe to program the AHCI FSM
wire fsm_pgm_wd; // @aclk, data strobe to program the AHCI FSM
wire [ 3:0] axi_wr_cache_mode; // input[3:0]
wire [ 3:0] axi_rd_cache_mode; // input[3:0]
wire set_axi_cache_mode; // input (both axi_wr_cache_mode and axi_rd_cache_mode)
wire dma_ct_busy; // output reg
wire [ 4:0] dma_ct_addr; // input[4:0]
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_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 dma_abort_busy;
wire dma_abort_done;
wire axi_mismatch;
wire [31:0] dma_dout; // output[31:0]
wire dma_dav; // output
wire dma_re; // input
wire last_h2d_data;// when active and no new data for 2 clocks - that was the last one
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;
wire frcv_get_sdbfis;
wire frcv_get_ufis;
wire frcv_get_data_fis;
wire frcv_get_ignore; // ignore whatever FIS (use for DMA activate too?)
// short commands:
// 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_pio; // update PxTFD.STS and PxTFD.ERR from pio_* (entry PIO:Update)
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_set_drq; // clear PxTFD.STS.BSY and sets PxTFD.STS.DRQ, update
wire frcv_set_bsy; // set PxTFD.STS.BSY, update
wire frcv_set_sts_7f; // set PxTFD.STS = 0x7f, update
wire frcv_set_sts_80; // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update
wire frcv_decr_dwcr; // decrement DMA Xfer counter after read // need pulse to 'update_prdbc' to write to registers
wire frcv_decr_dwcw; // decrement DMA Xfer counter after write // need pulse to 'update_prdbc' to write to registers
wire frcv_clear_xfer_cntr; // Clear pXferCntr to 0
// fsm <-
wire frcv_busy; // busy processing FIS
wire frcv_done; // done processing FIS (see fis_ok, fis_err, fis_ferr)
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
wire frcv_update_sig; // update signature
// fsm <- state variables that are maintained inside 'ahc_fis_receive'
wire [7:0] tfd_sts; // Current PxTFD status field (updated after regFIS and SDB - certain fields)
// tfd_sts[7] - BSY, tfd_sts[3] - DRQ, tfd_sts[0] - ERR
// wire [7:0] tfd_err; // Current PxTFD error field (updated after regFIS and SDB)
wire fis_i; // value of "I" field in received regsD2H or SDB FIS
/// wire sdb_n; // value of "N" field in received SDB FIS
wire dma_a; // value of "A" field in received DMA Setup FIS
/// wire dma_d; // value of "D" field in received DMA 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 [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:2] xfer_cntr;
wire xfer_cntr_zero;
/// wire [11:0] data_in_dwords; // number of DWORDs received in data FIS (can be updated internally). Is it needed?
// fsm <-> ahc_fis_transmit
// Command pulses to execute states fsm -> ahc_fis_transmit
wire fsnd_fetch_cmd; // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS)
// wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd
wire fsnd_cfis_xmit; // transmit command (wait for dma_ct_busy == 0)
wire fsnd_dx_xmit; // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
wire fsnd_atapi_xmit; // tarsmit ATAPI command FIS
// responses fsm <- ahc_fis_transmit
wire fsnd_done;
/// wire fsnd_busy;
// Short action pulses fsm -> ahc_fis_transmit
wire fsnd_clearCmdToIssue; // From CFIS:SUCCESS
// State variables fsm <- ahc_fis_transmit
wire fsnd_pCmdToIssue; // AHCI port variable
wire [ 2:0] fsnd_dx_err; // bit 0 - syncesc_recv, 1 - R_ERR (was xmit_err) 2 - X-RDY/X_RDY collision (valid @ xmit_err and later, reset by new command)
wire fsnd_ch_c; // Clear busy upon R_OK for this FIS
wire fsnd_ch_b; // Built-in self test command
wire fsnd_ch_r; // reset - may need to send SYNC escape before this command
wire fsnd_ch_p; // prefetchable - only used with non-zero PRDTL or ATAPI bit set
wire fsnd_ch_w; // Write: system memory -> device
wire fsnd_ch_a; // ATAPI: 1 means device should send PIO setup FIS for ATAPI command
/// wire [4:0] fsnd_ch_cfl; // length of the command FIS in DW, 0 means none. 0 and 1 - illegal, ... Maybe not needed outside ahc_fis_transmit
wire [11:0] data_out_dwords; // number of DWORDs sent in data FIS
wire was_hba_rst;
wire was_port_rst;
// signals between ahci_fsm and ahci_ctrl_stat
/// wire update_regs_pending;
wire update_all_regs;
wire update_regs_busy; // valid same cycle as update_all_regs
/// wire st01_pending; // software turned PxCMD.ST from 0 to 1
/// wire st10_pending; // software turned PxCMD.ST from 1 to 0
/// wire st_pending_reset;// reset both st01_pending and st10_pending
// these following individual signals may be unneded - use update_all_regs -> update_regs_busy
// wire update_GHC__IS;
// wire update_HBA_PORT__PxIS;
// wire update_HBA_PORT__PxSSTS;
// wire update_HBA_PORT__PxSERR;
// wire update_HBA_PORT__PxCMD;
// wire update_HBA_PORT__PxCI;
// PxCMD
// wire pcmd_clear_icc; // clear PxCMD.ICC field
wire pcmd_esp = 1'b0; // external SATA port (just forward value)
/// wire pcmd_cr; // command list run - current - read only by software (set by HBA)
wire pcmd_cr_set; // command list run set
wire pcmd_cr_reset; // command list run reset
// wire pcmd_fr; // ahci_fis_receive:get_fis_busy - use frcv_busy
wire pcmd_fre0; // FIS enable copy to memory
wire pcmd_fre = pcmd_fre0 || 1; // FIS enable copy to memory
// wire pcmd_clear_bsy_drq; // == ahci_fis_receive:clear_bsy_drq
wire pcmd_clo; // RW1, causes ahci_fis_receive:clear_bsy_drq, that in turn resets this bit
// wire pcmd_clear_st; // RW clear ST (start) bit
wire pcmd_st; // current value
wire pfsm_started; // H: FSM done, P: FSM started (enable sensing pcmd_st_cleared)
//clear_bsy_drq
// Interrupt inputs
wire sirq_TFE; // RWC: Task File Error Status
wire sirq_IF; // RWC: Interface Fatal Error Status (sect. 6.1.2)
wire sirq_INF; // RWC: Interface Non-Fatal Error Status (sect. 6.1.2)
wire sirq_OF; // RWC: Overflow Status
wire sirq_PRC; // RO: PhyRdy changed Status
wire sirq_PC; // RO: Port Connect Change Status
wire sirq_DP; // RWC: Descriptor Processed with "I" bit on
wire sirq_UF; // RO: Unknown FIS
wire sirq_SDB; // RWC: Set Device Bits Interrupt - Set Device bits FIS with 'I' bit set
wire sirq_DS; // RWC: DMA Setup FIS Interrupt - DMA Setup FIS received with 'I' bit set
wire sirq_PS; // RWC: PIO Setup FIS Interrupt - PIO Setup FIS received with 'I' bit set
wire 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
wire serr_diag_X; // value of PxSERR.DIAG.X
// SCR0: SStatus
wire ssts_ipm_dnp; // device not present or communication not established
wire ssts_ipm_active; // device in active state
wire ssts_ipm_part; // device in partial state
wire ssts_ipm_slumb; // device in slumber state
wire ssts_ipm_devsleep; // device in DevSleep state
wire ssts_spd_dnp; // device not present or communication not established
wire ssts_spd_gen1; // Gen 1 rate negotiated
wire ssts_spd_gen2; // Gen 2 rate negotiated
wire ssts_spd_gen3; // Gen 3 rate negotiated
wire ssts_det_ndnp; // no device detected, phy communication not established
wire ssts_det_dnp; // device detected, but phy communication not established
wire ssts_det_dp; // device detected, phy communication established
wire ssts_det_offline; // device detected, phy communication established
wire [3:0] ssts_det; // current value of PxSSTS.DET
// SCR2:SControl (written by software only)
wire [3:0] sctl_det; // Device detection initialization requested
wire sctl_det_changed; // Software had written new value to sctl_det
wire sctl_det_reset; // clear sctl_det_changed
wire pxci0_clear; // PxCI clear
wire pxci0; // pxCI current value
wire hba_rst_done; // HBA reset done - clear GHC.HR (and some other regs)
wire comreset_send0; // just disabling it
wire [9:0] last_jump_addr;
wire [31:0] debug_dma;
wire [31:0] debug_dma1;
wire [31:0] debug_dma_h2d;
wire 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
assign comreset_send = comreset_send0 && 0;
// Async FF
always @ (posedge mrst or posedge mclk) begin
if (mrst) en_port <= 0;
else en_port <= 1;
end
/*
reg [1:0] port_en; //disable port signals until initialized from the hardware (currently - PLL)
wire ports_rst = ~port_en[1];
always @ (posedge mclk) begin
if (port_arst_any) port_en[0] <= 0;
else if (mrst) port_en[0] <= 1;
if (port_arst_any) port_en[1] <= 0;
else if (!mrst && port_en[0]) port_en[1] <= 1;
end
*/
ahci_fsm// #(
// .READ_REG_LATENCY(2),
// .ADDRESS_BITS(10)
// )
ahci_fsm_i (
.hba_rst (mrst), // input
.mclk (mclk), // input
.was_hba_rst (was_hba_rst), // input
.was_port_rst (was_port_rst), // input
.aclk (aclk), // input
.arst (arst), // input
.pgm_ad (fsm_pgm_ad), // input[17:0]
.pgm_wa (fsm_pgm_wa), // input
.pgm_wd (fsm_pgm_wd), // input
.phy_ready (phy_ready), // input
.syncesc_send (syncesc_send), // output
.comreset_send (comreset_send0), // output
.syncesc_send_done (syncesc_send_done), // input
.cominit_got (cominit_got), // input
.set_offline (set_offline), // output
// .x_rdy_collision (x_rdy_collision), // input
.send_R_OK (send_R_OK), // output
.send_R_ERR (send_R_ERR), // output
/// .update_pending (update_regs_pending),// input
.update_all (update_all_regs), // output
.update_busy (update_regs_busy), // input
/// .update_gis (update_GHC__IS), // output
/// .update_pis (update_HBA_PORT__PxIS), // output
/// .update_ssts (update_HBA_PORT__PxSSTS), // output
/// .update_serr (update_HBA_PORT__PxSERR), // output
/// .update_pcmd (update_HBA_PORT__PxCMD), // output
/// .update_pci (update_HBA_PORT__PxCI), // output
/// .st01_pending (st01_pending), // input
/// .st10_pending (st10_pending), // input
/// .st_pending_reset (st_pending_reset), // output
// .pcmd_clear_icc (pcmd_clear_icc), // output
// .pcmd_esp (pcmd_esp), // output
// .pcmd_cr (pcmd_cr), // input
.pcmd_cr_set (pcmd_cr_set), // output
.pcmd_cr_reset (pcmd_cr_reset), // output
// .pcmd_fr (pcmd_fr), // output
// .pcmd_clear_bsy_drq (pcmd_clear_bsy_drq),// output
.pcmd_clo (pcmd_clo), // input
// .pcmd_clear_st (pcmd_clear_st), // output
.pcmd_st (pcmd_st), // input
.pfsm_started (pfsm_started), // output
.pcmd_st_cleared (pcmd_st_cleared), // input
.sirq_TFE (sirq_TFE), // output
.sirq_IF (sirq_IF), // output
.sirq_INF (sirq_INF), // output
.sirq_OF (sirq_OF), // output
.sirq_PRC (sirq_PRC), // output
.sirq_PC (sirq_PC), // output
.sirq_DP (sirq_DP), // output
.sirq_UF (sirq_UF), // output
.sirq_SDB (sirq_SDB), // output
.sirq_DS (sirq_DS), // output
.sirq_PS (sirq_PS), // output
.sirq_DHR (sirq_DHR), // output
.serr_diag_X (serr_diag_X), // input
.ssts_ipm_dnp (ssts_ipm_dnp), // output
.ssts_ipm_active (ssts_ipm_active), // output
.ssts_ipm_part (ssts_ipm_part), // output
.ssts_ipm_slumb (ssts_ipm_slumb), // output
.ssts_ipm_devsleep (ssts_ipm_devsleep), // output
.ssts_spd_dnp (ssts_spd_dnp), // output
.ssts_spd_gen1 (ssts_spd_gen1), // output
.ssts_spd_gen2 (ssts_spd_gen2), // output
.ssts_spd_gen3 (ssts_spd_gen3), // output
.ssts_det_ndnp (ssts_det_ndnp), // output
.ssts_det_dnp (ssts_det_dnp), // output
.ssts_det_dp (ssts_det_dp), // output
.ssts_det_offline (ssts_det_offline), // output
.ssts_det (ssts_det), // input[3:0]
/// .sctl_ipm (sctl_ipm), // input[3:0]
/// .sctl_spd (sctl_spd), // input[3:0]
.sctl_det (sctl_det), // input[3:0]
.sctl_det_changed (sctl_det_changed), // input
.sctl_det_reset (sctl_det_reset), // output
.hba_rst_done (hba_rst_done), // output
.pxci0_clear (pxci0_clear), // output
.pxci0 (pxci0), // 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
.dma_cmd_abort (dma_cmd_abort_fsm), // output
.dma_abort_done (dma_abort_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
.get_dsfis (frcv_get_dsfis), // output
.get_psfis (frcv_get_psfis), // output
.get_rfis (frcv_get_rfis), // output
.get_sdbfis (frcv_get_sdbfis), // output
.get_ufis (frcv_get_ufis), // output
.get_data_fis (frcv_get_data_fis), // output
.get_ignore (frcv_get_ignore), // output
/// .get_fis_busy (frcv_busy), // input
.get_fis_done (frcv_done), // input
.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
/// .sig_available (frcv_sig_available), // input
.update_sig (frcv_update_sig), // output
.update_err_sts (frcv_update_err_sts),// output
.update_pio (frcv_update_pio), // output
.update_prdbc (frcv_update_prdbc), // output
.clear_bsy_drq (frcv_clear_bsy_drq), // output
.clear_bsy_set_drq (frcv_clear_bsy_set_drq), //output
.set_bsy (frcv_set_bsy), // output
.set_sts_7f (frcv_set_sts_7f), // output
.set_sts_80 (frcv_set_sts_80), // output
.clear_xfer_cntr (frcv_clear_xfer_cntr), //output Clear pXferCntr
.decr_dwcr (frcv_decr_dwcr), // output increment pXferCntr after transmit by data transmitted)
.decr_dwcw (frcv_decr_dwcw), // output increment pXferCntr after transmit by data transmitted)
// .decr_DXC_dw (data_out_dwords), // output[11:2] **** Probably not needed
.pxcmd_fre ( pcmd_fre), // input
.pPioXfer (pPioXfer), // input
.tfd_sts (tfd_sts), // input[7:0]
/// .tfd_err (tfd_err), // input[7:0]
.fis_i (fis_i), // input
/// .sdb_n (sdb_n), // input
.dma_a (dma_a), // input
/// .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
.fetch_cmd (fsnd_fetch_cmd), // output
.cfis_xmit (fsnd_cfis_xmit), // output
.dx_xmit (fsnd_dx_xmit), // output
.atapi_xmit (fsnd_atapi_xmit), // output
.xmit_done (fsnd_done), // input
/// .xmit_busy (fsnd_busy), // input
.clearCmdToIssue (fsnd_clearCmdToIssue),// output // From CFIS:SUCCESS
.pCmdToIssue (fsnd_pCmdToIssue), // input
.dx_err (fsnd_dx_err), // input[2:0]
/// .ch_prdtl (prdtl), // input[15:0]
.ch_c (fsnd_ch_c), // input
.ch_b (fsnd_ch_b), // input
.ch_r (fsnd_ch_r), // input
.ch_p (fsnd_ch_p), // input
.ch_w (fsnd_ch_w), // input
.ch_a (fsnd_ch_a), // input
/// .ch_cfl (fsnd_ch_cfl), // input[4:0]
/// .dwords_sent (data_out_dwords) // input[11:0] ????
.unsolicited_en (unsolicited_en), // input
.last_jump_addr (last_jump_addr)
);
wire debug_data_in_ready; // output
wire debug_fis_end_w; // output
wire[1:0] debug_fis_end_r; // output[1:0]
wire[1:0] debug_get_fis_busy_r; // output[1:0]
localparam DATA_TYPE_DMA = 0;
localparam DATA_TYPE_FIS_HEAD = 1;
localparam DATA_TYPE_OK = 2;
localparam DATA_TYPE_ERR = 3;
reg [12:0] debug_d2h_length;
reg [12:0] debug_d2h_length_prev;
reg was_good_bad;
reg was_good_bad_prev;
always @(posedge mclk) if (d2h_ready && d2h_valid) begin
if (d2h_type == DATA_TYPE_FIS_HEAD) debug_d2h_length_prev <= debug_d2h_length;
if (d2h_type == DATA_TYPE_FIS_HEAD) debug_d2h_length <= 0;
else if (d2h_type == DATA_TYPE_DMA) debug_d2h_length <= debug_d2h_length + 1;
if (d2h_type == DATA_TYPE_FIS_HEAD) was_good_bad_prev <= was_good_bad;
if ((d2h_type == DATA_TYPE_OK) || (d2h_type == DATA_TYPE_ERR)) was_good_bad <= (d2h_type == DATA_TYPE_OK);
end
axi_ahci_regs #(
.ADDRESS_BITS (ADDRESS_BITS),
.HBA_RESET_BITS (HBA_RESET_BITS),
.RESET_TO_FIRST_ACCESS (RESET_TO_FIRST_ACCESS)
) axi_ahci_regs_i (
.aclk (aclk), // input
.arst (arst), // input
.awaddr (awaddr), // input[31:0]
.awvalid (awvalid), // input
.awready (awready), // output
.awid (awid), // input[11:0]
.awlen (awlen), // input[3:0]
.awsize (awsize), // input[1:0]
.awburst (awburst), // input[1:0]
.wdata (wdata), // input[31:0]
.wvalid (wvalid), // input
.wready (wready), // output
.wid (wid), // input[11:0]
.wlast (wlast), // input
.wstb (wstb), // input[3:0]
.bvalid (bvalid), // output
.bready (bready), // input
.bid (bid), // output[11:0]
.bresp (bresp), // output[1:0]
.araddr (araddr), // input[31:0]
.arvalid (arvalid), // input
.arready (arready), // output
.arid (arid), // input[11:0]
.arlen (arlen), // input[3:0]
.arsize (arsize), // input[1:0]
.arburst (arburst), // input[1:0]
.rdata (rdata), // output[31:0]
.rvalid (rvalid), // output
.rready (rready), // input
.rid (rid), // output[11:0]
.rlast (rlast), // output
.rresp (rresp), // output[1:0]
.soft_write_addr (soft_write_addr), // output[9:0]
.soft_write_data (soft_write_data), // output[31:0]
.soft_write_en (soft_write_en), // output
.hba_arst (hba_arst), // output // does not include arst
.port_arst_any (port_arst_any), // async set by arst
.port_arst (port_arst), // output // does not include arst
.hba_clk (mclk), // input
.hba_rst (mrst), // input // deasserted when mclk is stable
.hba_addr (regs_addr), // input[9:0]
.hba_we (regs_we), // input
.hba_re (regs_re), // input[1:0]
.hba_din (regs_din), // input[31:0]
.hba_dout (regs_dout), // output[31:0]
.pgm_ad (fsm_pgm_ad), // output[17:0] reg
.pgm_wa (fsm_pgm_wa), // output reg
.pgm_wd (fsm_pgm_wd), // output reg
.afi_wcache (axi_wr_cache_mode),// output[3:0] reg
.afi_rcache (axi_rd_cache_mode),// output[3:0] reg
.afi_cache_set (set_axi_cache_mode), // output
.was_hba_rst (was_hba_rst), // output
.was_port_rst (was_port_rst), // output
.debug_in0 ({ 2'b0,
was_good_bad_prev,
debug_d2h_length_prev[12:0],
2'b0,
was_good_bad,
debug_d2h_length[12:0]
}),
// .debug_in1 ({xclk_period[7:0], // lower 8 bits of 12-bit value. Same frequency would be 0x800 (msb opposite to 3 next bits)
// debug_dma1[23:0]}), // debug_in_link), // input[31:0]
.debug_in1 ({debug_in_link[15:8],
debug_dma1[23:0]}), // debug_in_link), // input[31:0]
.debug_in2 (debug_in_phy), // input[31:0] // debug from phy/link
// .debug_in3 ({22'b0, last_jump_addr[9:0]}) // input[31:0]// Last jump address in the AHDCI sequencer
.debug_in3 ({debug_in_link[7:0],
frcv_busy,frcv_ok, // 2'b0,
`ifdef USE_DATASCOPE
datascope_waddr[9:0],
`else
10'b0,
`endif
frcv_err,frcv_ferr, // 2'b0,
last_jump_addr[9:0]}) // input[31:0]// Last jump address in the AHDCI sequencer
`ifdef USE_DRP
,.drp_en (drp_en), // output reg
.drp_we (drp_we), // output reg
.drp_addr (drp_addr), // output[14:0] reg
.drp_di (drp_di), // output[15:0] reg
.drp_rdy (drp_rdy), // input
.drp_do (drp_do) // input[15:0]
`endif
`ifdef USE_DATASCOPE
,.datascope_clk (datascope_clk), // input
.datascope_waddr (datascope_waddr), // input[9:0]
.datascope_we (datascope_we), // input
.datascope_di (datascope_di), // input[31:0]
.datascope1_clk (datascope1_clk), // input
.datascope1_waddr (datascope1_waddr),// input[9:0]
.datascope1_we (datascope1_we), // input
.datascope1_di (datascope1_di) // input[31:0]
`endif
/// .debug_in (debug_in[31:0])
);
ahci_ctrl_stat #(
.ADDRESS_BITS (ADDRESS_BITS)
) ahci_ctrl_stat_i (
.mrst (mrst), // 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_data (soft_write_data), // input[31:0]
.soft_write_en (soft_write_en), // input
.regs_addr (regs_saddr), // output[9:0] reg
.regs_we (regs_we_acs), // output reg
.regs_din (regs_din_from_acs), // output[31:0] reg
.update_pending (), /// update_regs_pending), // output
.update_all (update_all_regs), // input
.update_busy (update_regs_busy), // output
/// .st01_pending (st01_pending), // output reg
/// .st10_pending (st10_pending), // output reg
/// .st_pending_reset (st_pending_reset), // input
.update_gis (1'b0), // update_GHC__IS), // input
.update_pis (1'b0), // update_HBA_PORT__PxIS), // input
.update_ssts (1'b0), // update_HBA_PORT__PxSSTS), // input
.update_serr (1'b0), // update_HBA_PORT__PxSERR), // input
.update_pcmd (1'b0), // update_HBA_PORT__PxCMD), // input
.update_pci (1'b0), // update_HBA_PORT__PxCI), // input
.update_ghc (1'b0), // update _GHC_GHC, // input
// .pcmd_clear_icc (1'b0), // pcmd_clear_icc), // input
.pcmd_esp (pcmd_esp), // input
.pcmd_cr (), //pcmd_cr), // output
.pcmd_cr_set (pcmd_cr_set), // input
.pcmd_cr_reset (pcmd_cr_reset), // input
.pcmd_fr (frcv_busy), // input
.pcmd_fre (pcmd_fre0), // output
.pcmd_clear_bsy_drq (frcv_clear_bsy_drq), // input
.pcmd_clo (pcmd_clo), // output
.pcmd_clear_st (1'b0), // pcmd_clear_st), // input
.pcmd_st (pcmd_st), // output
.pfsm_started (pfsm_started), // input
.pcmd_st_cleared (pcmd_st_cleared), // output reg
.sirq_TFE (sirq_TFE), // input
.sirq_IF (sirq_IF), // input
.sirq_INF (sirq_INF), // input
.sirq_OF (sirq_OF), // input
.sirq_PRC (sirq_PRC), // input
.sirq_PC (sirq_PC), // input
.sirq_DP (sirq_DP), // input
.sirq_UF (sirq_UF), // input
.sirq_SDB (sirq_SDB), // input
.sirq_DS (sirq_DS), // input
.sirq_PS (sirq_PS), // input
.sirq_DHR (sirq_DHR), // input
.serr_DT (serr_DT), // input
.serr_DS (serr_DS), // input
.serr_DH (serr_DH), // input
.serr_DC (serr_DC), // input
.serr_DB (serr_DB), // input
.serr_DW (serr_DW), // input
.serr_DI (serr_DI), // input
.serr_EE (serr_EE), // input
.serr_EP (serr_EP), // input
.serr_EC (serr_EC), // input
.serr_ET (serr_ET), // input
.serr_EM (serr_EM), // input
.serr_EI (serr_EI), // input
.serr_diag_X (serr_diag_X), // output
.ssts_ipm_dnp (ssts_ipm_dnp), // input
.ssts_ipm_active (ssts_ipm_active), // input
.ssts_ipm_part (ssts_ipm_part), // input
.ssts_ipm_slumb (ssts_ipm_slumb), // input
.ssts_ipm_devsleep (ssts_ipm_devsleep), // input
.ssts_spd_dnp (ssts_spd_dnp), // input
.ssts_spd_gen1 (ssts_spd_gen1), // input
.ssts_spd_gen2 (ssts_spd_gen2), // input
.ssts_spd_gen3 (ssts_spd_gen3), // input
.ssts_det_ndnp (ssts_det_ndnp), // input
.ssts_det_dnp (ssts_det_dnp), // input
.ssts_det_dp (ssts_det_dp), // input
.ssts_det_offline (ssts_det_offline), // input
.ssts_det (ssts_det), // output[3:0]
.sctl_ipm (sctl_ipm), // output[3:0] reg
.sctl_spd (sctl_spd), // output[3:0] reg
.sctl_det (sctl_det), // output[3:0] reg
.sctl_det_changed (sctl_det_changed), // output reg
.sctl_det_reset (sctl_det_reset), // input
.pxci0_clear (pxci0_clear), // input
.pxci0 (pxci0), // output
.hba_reset_done (hba_rst_done), // input
.unsolicited_en (unsolicited_en), // output
.irq (irq) // output reg
);
ahci_dma ahci_dma_i (
.mrst (mrst), // input
.hrst (hrst), // input
.mclk (mclk), // input
.hclk (hclk), // input
// .ctba (regs_dout[31:7]),// input[31:7]
.ctba (regs_dout[31:4]),// input[31:4]
.ctba_ld (ctba_ld), // input
.prdtl (prdtl), // input[15:0]
.dev_wr (dev_wr), // input
.cmd_start (dma_cmd_start), // input
.prd_start (dma_prd_start), // input
.cmd_abort (dma_cmd_abort_xmit || dma_cmd_abort_fsm), // input
.axi_wr_cache_mode (axi_wr_cache_mode), // input[3:0]
.axi_rd_cache_mode (axi_rd_cache_mode), // input[3:0]
.set_axi_wr_cache_mode (set_axi_cache_mode), // input
.set_axi_rd_cache_mode (set_axi_cache_mode), // input
.ct_busy (dma_ct_busy), // output reg
.ct_addr (dma_ct_addr), // input[4:0]
.ct_re (dma_ct_re), // input[1:0]
.ct_data (dma_ct_data), // output[31:0] reg
.prd_done (), /// dma_prd_done), // output
.prd_irq_clear (dma_prd_irq_clear),// input
.prd_irq_pend (dma_prd_irq_pend), // output reg
.cmd_busy (dma_cmd_busy), // dma_cmd_busy), // output reg Some data to transmit!
.cmd_done (dma_cmd_done), // output
.abort_busy (dma_abort_busy),
.abort_done (dma_abort_done),
.axi_mismatch (axi_mismatch), // handled, but may report as an error - axi counters are 0, but calculated ones are not
.sys_out (dma_dout), // output[31:0]
.sys_dav (dma_dav), // output
.sys_re (dma_re), // input
.last_h2d_data (last_h2d_data), // output
.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
.afi_awid (afi_awid), // output[5:0]
.afi_awlock (afi_awlock), // output[1:0]
.afi_awcache (afi_awcache), // output[3:0] reg
.afi_awprot (afi_awprot), // output[2:0]
.afi_awlen (afi_awlen), // output[3:0]
.afi_awsize (afi_awsize), // output[1:0]
.afi_awburst (afi_awburst), // output[1:0]
.afi_awqos (afi_awqos), // output[3:0]
.afi_wdata (afi_wdata), // output[63:0]
.afi_wvalid (afi_wvalid), // output
.afi_wready (afi_wready), // input
.afi_wid (afi_wid), // output[5:0]
.afi_wlast (afi_wlast), // output
.afi_wstrb (afi_wstrb), // output[7:0]
.afi_bvalid (afi_bvalid), // input
.afi_bready (afi_bready), // output
.afi_bid (afi_bid), // input[5:0]
.afi_bresp (afi_bresp), // input[1:0]
.afi_wcount (afi_wcount), // input[7:0]
.afi_wacount (afi_wacount), // input[5:0]
.afi_wrissuecap1en (afi_wrissuecap1en), // output
.afi_araddr (afi_araddr), // output[31:0]
.afi_arvalid (afi_arvalid), // output
.afi_arready (afi_arready), // input
.afi_arid (afi_arid), // output[5:0]
.afi_arlock (afi_arlock), // output[1:0]
.afi_arcache (afi_arcache), // output[3:0] reg
.afi_arprot (afi_arprot), // output[2:0]
.afi_arlen (afi_arlen), // output[3:0]
.afi_arsize (afi_arsize), // output[1:0]
.afi_arburst (afi_arburst), // output[1:0]
.afi_arqos (afi_arqos), // output[3:0]
.afi_rdata (afi_rdata), // input[63:0]
.afi_rvalid (afi_rvalid), // input
.afi_rready (afi_rready), // output
.afi_rid (afi_rid), // input[5:0]
.afi_rlast (afi_rlast), // input
.afi_rresp (afi_rresp), // input[1:0]
.afi_rcount (afi_rcount), // input[7:0]
.afi_racount (afi_racount), // input[2:0]
.afi_rdissuecap1en (afi_rdissuecap1en), // output
.debug_out (debug_dma), // output[31:0]
.debug_out1 (debug_dma1) // output[31:0]
,.debug_dma_h2d (debug_dma_h2d)
);
ahci_fis_receive #(
.ADDRESS_BITS (ADDRESS_BITS)
) ahci_fis_receive_i (
.hba_rst (mrst), // input
.mclk (mclk), // input
.pcmd_st_cleared (pcmd_st_cleared), // 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
.get_rfis (frcv_get_rfis), // input
.get_sdbfis (frcv_get_sdbfis), // input
.get_ufis (frcv_get_ufis), // input
.get_data_fis (frcv_get_data_fis), // input
.get_ignore (frcv_get_ignore), // input
.get_fis_busy (frcv_busy), // output reg
.get_fis_done (frcv_done), // output reg
.fis_ok (frcv_ok), // output reg
.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
.update_sig (frcv_update_sig), // 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
.clear_prdbc (fsnd_fetch_cmd), // input save resources - clear prdbc for every commnad
.clear_bsy_drq (frcv_clear_bsy_drq), // input
.clear_bsy_set_drq (frcv_clear_bsy_set_drq), // input
.set_bsy (frcv_set_bsy), // input
.set_sts_7f (frcv_set_sts_7f), // input
.set_sts_80 (frcv_set_sts_80), // input
.clear_xfer_cntr (frcv_clear_xfer_cntr), // input Clear pXferCntr
.decr_dwcr (frcv_decr_dwcr), // input
.decr_dwcw (frcv_decr_dwcw), // input
.decr_DXC_dw (data_out_dwords), // input[11:2]
.pcmd_fre (pcmd_fre), // input
.pPioXfer (pPioXfer), // output reg
.tfd_sts (tfd_sts), // output[7:0]
.tfd_err (), /// tfd_err), // output[7:0]
.fis_i (fis_i), // output reg
.sdb_n (), /// sdb_n), // output reg
.dma_a (dma_a), // output reg
.dma_d (), /// dma_d), // output reg
.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]
.reg_addr (regs_waddr), // output[9:0] reg
.reg_we (regs_we_freceive), // output reg
.reg_data (regs_din_from_freceive), // output[31:0] reg
.hba_data_in (d2h_data), // input[31:0]
.hba_data_in_type (d2h_type), // input[1:0]
.hba_data_in_valid (d2h_valid), // input
.hba_data_in_many (d2h_many), // input
.hba_data_in_ready (d2h_ready), // output
.dma_in_ready (dma_in_ready), // input
.dma_in_valid (dma_we) // output
,.debug_data_in_ready (debug_data_in_ready), // output
.debug_fis_end_w (debug_fis_end_w), // output
.debug_fis_end_r (debug_fis_end_r), // output[1:0]
.debug_get_fis_busy_r (debug_get_fis_busy_r) // output[1:0]
);
wire ahci_fis_transmit_busy;
wire [9:0] xmit_dbg_01;
ahci_fis_transmit #(
.PREFETCH_ALWAYS (PREFETCH_ALWAYS),
.READ_REG_LATENCY (READ_REG_LATENCY),
.READ_CT_LATENCY (READ_CT_LATENCY),
.ADDRESS_BITS (ADDRESS_BITS)
) ahci_fis_transmit_i (
// .hba_rst (mrst), // input TODO: Reset when !PxCMD.ST? pcmd_st
.hba_rst (mrst || !pcmd_st), // input TODO: Reset when !PxCMD.ST? pcmd_st
.mclk (mclk), // input
.pcmd_st_cleared (pcmd_st_cleared), // input
.fetch_cmd (fsnd_fetch_cmd), // input
.cfis_xmit (fsnd_cfis_xmit), // input
.dx_xmit (fsnd_dx_xmit), // input
.atapi_xmit (fsnd_atapi_xmit), // input
.done (fsnd_done), // output reg
.busy (ahci_fis_transmit_busy), /// fsnd_busy), // output reg
.clearCmdToIssue (fsnd_clearCmdToIssue), // input
.pCmdToIssue (fsnd_pCmdToIssue), // output
.xmit_ok (xmit_ok), // input
.xmit_err (xmit_err), // input
.syncesc_recv (syncesc_recv), // input
.xrdy_collision (x_rdy_collision), // input
.dx_err (fsnd_dx_err), // output[1:0]
.ch_prdtl (prdtl), // output[15:0]
.ch_c (fsnd_ch_c), // output
.ch_b (fsnd_ch_b), // output
.ch_r (fsnd_ch_r), // output
.ch_p (fsnd_ch_p), // output
.ch_w (fsnd_ch_w), // output
.ch_a (fsnd_ch_a), // output
.ch_cfl (), /// fsnd_ch_cfl), // output[4:0]
.dwords_sent (data_out_dwords), // output[11:0] reg
.reg_addr (regs_raddr), // output[9:0] reg
.reg_re (regs_re_ftransmit), // output[1:0]
.reg_rdata (regs_dout), // input[31:0]
.xfer_cntr (xfer_cntr[31:2]), // input[31:2]
.xfer_cntr_zero (xfer_cntr_zero), // input
.dma_ctba_ld (ctba_ld), // output
.dma_start (dma_cmd_start), // output
.dma_dev_wr (dev_wr), // output
.dma_ct_busy (dma_ct_busy), // input
.dma_prd_start (dma_prd_start), // output reg
.dma_cmd_abort (dma_cmd_abort_xmit), // output reg
.ct_addr (dma_ct_addr), // output[4:0] reg
.ct_re (dma_ct_re), // output[1:0]
.ct_data (dma_ct_data), // input[31:0]
.dma_out (dma_dout), // input[31:0]
.dma_dav (dma_dav), // input
.dma_re (dma_re), // output
.last_h2d_data (last_h2d_data), // input
.todev_data (h2d_data), // output[31:0] reg
.todev_type (h2d_type), // output[1:0] reg
.todev_valid (h2d_valid), // output
.todev_ready (h2d_ready) // input
,.debug_01(xmit_dbg_01)
);
// Datascope code
//`define DATASCOPE_V2
// Datascope interface (write to memory that can be software-read)
`define DATASCOPE_FIS_DATA 1
`ifdef USE_DATASCOPE
`ifdef DATASCOPE_V2
reg [ADDRESS_BITS-1:0] datascope_waddr_r;
reg [1:0] datascope_run;
// reg [1:0] datascope_run;
assign datascope_we = datascope_run[1];
assign datascope_clk = mclk;
assign datascope_waddr = datascope_waddr_r;
assign datascope_di = {
debug_dma_h2d[3], // done_flush_mclk,
debug_dma_h2d[2], // dout_vld,
debug_dma_h2d[1], // dout_re,
debug_dma_h2d[0], // last_DW,
dma_dout[27:16],
debug_dma_h2d[19:18], // 2'b0
debug_dma_h2d[17], // fifo_rd
debug_dma_h2d[16:12], // raddr[4:0]
debug_dma_h2d[11:8], //fifo_do_vld[3:0]
debug_dma_h2d[7], // fifo_dav
debug_dma_h2d[6], // fifo_dav2_w
debug_dma_h2d[5], // fifo_dav2
debug_dma_h2d[4] // flushing_mclk
};
// dma_dout[
always @ (posedge mclk) begin
if (mrst) datascope_run[0] <= 0;
else if (dma_cmd_start) datascope_run[0] <= 1;
else if (dma_cmd_done) datascope_run[0] <= 0;
if (mrst || !datascope_run[0]) datascope_run[1] <= 0;
else if (dma_dav) datascope_run[1] <= 1;
if (fsnd_cfis_xmit) datascope_waddr_r <= 0;
else if (datascope_we) datascope_waddr_r <= datascope_waddr_r + 1;
end
//`endif // DATASCOPE_V2
`else
//`ifdef DATASCOPE_V1
`ifdef DATASCOPE_FIS_DATA
datascope_timing #(
.ADDRESS_BITS(10),
.FIS_LEN(5)
) datascope_timing_i (
.clk (mclk), // input
.rst (mrst), // input
.soft_write_addr (soft_write_addr), // input[9:0]
.soft_write_data (soft_write_data), // input[31:0]
.soft_write_en (soft_write_en), // input
.h2d_data (h2d_data), // input[31:0]
.h2d_type (h2d_type), // input[1:0]
.h2d_valid (h2d_valid), // input
.h2d_ready (h2d_ready), // input
.d2h_data (d2h_data), // input[31:0]
.d2h_type (d2h_type), // input[1:0]
.d2h_valid (d2h_valid), // input
.d2h_ready (d2h_ready), // input
.datascope_clk (datascope_clk), // output
.datascope_waddr (datascope_waddr), // output[9:0] reg
.datascope_we (datascope_we), // output
.datascope_di (datascope_di) // output[31:0] reg
);
`else // DATASCOPE_FIS_DATA
localparam DATASCOPE_CFIS_START=0;
localparam DATASCOPE_INCOMING_POST=32;
reg [ADDRESS_BITS-1:0] datascope_waddr_r=0;
reg [1:0] datascope_run;
reg datascope_link_run;
wire datascope_is_state_send_ready = (debug_in_link[4:0] == 16);
wire datascope_is_state_idle = (debug_in_link[4:0] == 22);
reg datascope_was_state_send_ready;
reg [3:0] datascope_id;
wire datascope_incoming_start = debug_in_link[22]; // set_rcvr_wait; // start logging
wire datascope_incoming_started = debug_in_phy[21:20] == 1; //
wire datascope_incomining_preend = debug_in_phy[21]; // d2h_type_in[1
reg [2:0] datascope_incoming_run;
reg [7:0] datascope_incoming_cntr;
reg datascope_receive_fis;
reg [9:0] datascope_last_jump_addr=0;
reg [1:0] datascope_new_jump = 0;
reg [15:0] datascope_jump_cntr = 0;
//last_jump_addr[9:0]
always @(posedge mclk) begin
if (mrst) datascope_new_jump[0] <= 0;
else datascope_new_jump[0] <= datascope_last_jump_addr != last_jump_addr;
if (mrst) datascope_new_jump[1] <= 0;
else datascope_new_jump[1] <= datascope_new_jump[0];
if (mrst) datascope_last_jump_addr <= 0;
if (datascope_new_jump) datascope_last_jump_addr <= last_jump_addr;
if (datascope_we) datascope_jump_cntr <= datascope_jump_cntr+1;
if (mrst) datascope_receive_fis <= 0;
else if (datascope_incoming_start) datascope_receive_fis <= 1;
else if (frcv_get_dsfis ||
frcv_get_psfis ||
frcv_get_rfis ||
frcv_get_sdbfis ||
frcv_get_ufis ||
frcv_get_data_fis ||
frcv_get_ignore) datascope_receive_fis <= 0;
if (mrst) datascope_incoming_run[0] <= 0;
else if (datascope_incoming_start || datascope_receive_fis) datascope_incoming_run[0] <= 1;
else if (datascope_incoming_cntr == 0) datascope_incoming_run[0] <= 0;
if (mrst || datascope_incoming_start) datascope_incoming_run[1] <= 0;
else if (datascope_incoming_run[0] && datascope_incoming_started) datascope_incoming_run[1] <= 1;
else if (datascope_incoming_run[2]) datascope_incoming_run[1] <= 0;
if (mrst || datascope_incoming_start) datascope_incoming_run[2] <= 0;
else if (datascope_incoming_run[1] && datascope_incomining_preend) datascope_incoming_run[2] <= 1;
else if (datascope_incoming_cntr == 0) datascope_incoming_run[2] <= 0;
if (mrst || !datascope_incoming_run[2] ||
datascope_incoming_start ||
datascope_receive_fis) datascope_incoming_cntr <= DATASCOPE_INCOMING_POST;
else if (|datascope_incoming_cntr) datascope_incoming_cntr <= datascope_incoming_cntr - 1;
end
assign datascope_clk = mclk;
assign datascope_waddr = last_jump_addr;
assign datascope_we = &datascope_new_jump;
assign datascope_di = {2'h3, fsnd_pCmdToIssue, xfer_cntr_zero, 2'b0, last_jump_addr[9:0],datascope_jump_cntr};
always @(posedge mclk) begin
if (mrst) datascope_run[0] <= 0;
else if (fsnd_cfis_xmit) datascope_run[0] <= 1;
else if (h2d_valid && h2d_ready && (h2d_type == 2)) datascope_run[0] <= 0;
if (mrst) datascope_link_run <= 0;
else if (datascope_is_state_send_ready && !datascope_was_state_send_ready) datascope_link_run <= 1; // state_send_sof
else if (datascope_is_state_idle) datascope_link_run <= 0; // state_idle
datascope_was_state_send_ready <= datascope_is_state_send_ready;
datascope_run[1] <= datascope_run[0];
if (mrst) datascope_id <= 0;
else if (fsnd_cfis_xmit) datascope_id <= datascope_id + 1;
end
`endif // DATASCOPE_FIS_DATA
`endif // DATASCOPE_V1
`endif // USE_DATASCOPE
endmodule
module datascope_timing #(
parameter ADDRESS_BITS = 10, // for datascope
parameter FIS_LEN = 5 // Record this number of DWORDS in each FIS
)(
input clk,
input rst,
// receiving time punch command and 3-bit tag
input [ADDRESS_BITS-1:0] soft_write_addr,
input [31:0] soft_write_data,
input soft_write_en,
// outgoing FISes
input [31:0] h2d_data, // 32-bit data from the system memory to HBA (dma data)
input [ 1:0] h2d_type, // 0 - data, 1 - FIS head, 2 - FIS END (make FIS_Last?)
input h2d_valid, // output register full
input h2d_ready, // send FIFO has room for data (>= 8? dwords)
// Incoming FISes
// Data/type FIFO, device -> host
input [31:0] d2h_data, // FIFO output data
input [ 1:0] d2h_type, // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR
input d2h_valid, // Data available from the transport layer in FIFO
input d2h_ready, // This module or DMA consumes DWORD
output datascope_clk,
output reg [ADDRESS_BITS-1:0] datascope_waddr,
output datascope_we,
output reg [31:0] datascope_di
);
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
reg [2:0] punch_tag;
wire write_tag_w = soft_write_en && (soft_write_addr[ADDRESS_BITS-1:0] == HBA_PORT__PunchTime__TAG__ADDR);
reg pend_punch_time;
wire write_punch_time = pend_punch_time && !fis_start && !fis_run && !fis_run_d;
reg fis_run;
reg fis_run_d;
reg fis_we; // recording FIS data (until end or max len)
reg [12:0] fis_len;
reg [12:0] fis_left;
reg [31:0] fis_data;
reg [27:0] cur_time;
reg was_h2d_last;
wire fis_start = (h2d_valid && h2d_ready && (h2d_type == 1)) ||
(d2h_valid && d2h_ready && (d2h_type == 1));
wire fis_end = (d2h_valid? (d2h_valid && d2h_ready && d2h_type[1]): was_h2d_last);
// wire fis_end_we = (fis_left == 0) || fis_end;
wire pre_we_w = fis_run && (d2h_valid?(d2h_valid && d2h_ready):(h2d_valid && h2d_ready));
reg pre_we_r;
reg we_r;
assign datascope_we = we_r;
assign datascope_clk = clk;
always @ (posedge clk) begin
was_h2d_last <= h2d_type[1] && h2d_valid && h2d_ready;
if (rst) cur_time <= 0;
else cur_time <= cur_time + 1;
if (write_tag_w) punch_tag <= soft_write_data[2:0];
if (rst) pend_punch_time <= 0;
else if (write_tag_w) pend_punch_time <= 1;
else if (write_punch_time) pend_punch_time <= 0;
if (write_punch_time || fis_start) datascope_di <= {write_punch_time?{1'b1,punch_tag}:{3'b0,d2h_valid},cur_time};
else if (fis_we) datascope_di <= fis_data;
else if (!fis_run && fis_run_d) datascope_di <= {19'h7fff8, fis_len};
pre_we_r <= pre_we_w || fis_start ;
we_r <= write_punch_time || fis_start || (fis_we ? pre_we_r : (!fis_run && fis_run_d));
if (fis_start) fis_left <= FIS_LEN - 1;
else if (pre_we_w) fis_left <= fis_left - 1;
if (rst) fis_we <= 0;
else if (fis_start) fis_we <= 1;
else if ((fis_left == 0) || fis_end) fis_we <= 0;
if (rst) fis_run <= 0;
else if (fis_start) fis_run <= 1;
else if (fis_end) fis_run <= 0;
fis_run_d <= fis_run;
if (fis_start) fis_len <= d2h_valid? 0 : 1;
else if (pre_we_w) fis_len <= fis_len + 1;
if (fis_start || pre_we_w) fis_data <= d2h_valid ? d2h_data : h2d_data;
if (rst) datascope_waddr <= 0;
else if (we_r) datascope_waddr <= datascope_waddr + 1;
end
endmodule
/*******************************************************************************
* Module: axi_ahci_regs
* Date:2015-12-29
* Author: Andrey Filippov
* Description: Registers for single-port AHCI over AXI implementation
* Combination of PCI Headers, PCI power management, and HBA memory
* 128 DWORD registers
* Registers, with bits being RO, RW, RWC, RW1
*
* Copyright (c) 2015 Elphel, Inc .
* axi_ahci_regs.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.
*
* axi_ahci_regs.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module axi_ahci_regs#(
// parameter ADDRESS_BITS = 8 // number of memory address bits
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)
parameter HBA_RESET_BITS = 9, // duration of HBA reset in aclk periods (9: ~10usec)
parameter RESET_TO_FIRST_ACCESS = 1 // keep port reset until first R/W any register by software
)(
input aclk, // clock - should be buffered
input arst, // @aclk sync reset, active high
// AXI Write Address
input [31:0] awaddr, // AWADDR[31:0], input
input awvalid, // AWVALID, input
output awready, // AWREADY, output
input [11:0] awid, // AWID[11:0], input
input [ 3:0] awlen, // AWLEN[3:0], input
input [ 1:0] awsize, // AWSIZE[1:0], input
input [ 1:0] awburst, // AWBURST[1:0], input
// AXI PS Master GP0: Write Data
input [31:0] wdata, // WDATA[31:0], input
input wvalid, // WVALID, input
output wready, // WREADY, output
input [11:0] wid, // WID[11:0], input
input wlast, // WLAST, input
input [ 3:0] wstb, // WSTRB[3:0], input
// AXI PS Master GP0: Write response
output bvalid, // BVALID, output
input bready, // BREADY, input
output [11:0] bid, // BID[11:0], output
output [ 1:0] bresp, // BRESP[1:0], output
// AXI Read Address
input [31:0] araddr, // ARADDR[31:0], input
input arvalid, // ARVALID, input
output arready, // ARREADY, output
input [11:0] arid, // ARID[11:0], input
input [ 3:0] arlen, // ARLEN[3:0], input
input [ 1:0] arsize, // ARSIZE[1:0], input
input [ 1:0] arburst, // ARBURST[1:0], input
// AXI Read Data
output [31:0] rdata, // RDATA[31:0], output
output rvalid, // RVALID, output
input rready, // RREADY, input
output [11:0] rid, // RID[11:0], output
output rlast, // RLAST, output
output [ 1:0] rresp, // RRESP
// HBA interface
// 1. Notification of data written @ hba_clk
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 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 port_arst, // port0 async reset by software
output port_arst_any, // port0 async reset by POR or software
// 2. HBA R/W registers, use hba clock
input hba_clk, // SATA clock, now 75MHz
input hba_rst, // when PLL locked, SATA PHY reset is over, this signal is released
input [ADDRESS_BITS-1:0] hba_addr,
input hba_we,
// input [3:0] hba_wstb, Needed?
input [1:0] hba_re, // [0] - re, [1] - regen
input [31:0] hba_din,
output [31:0] hba_dout,
// Program FSM memory
output reg [17:0] pgm_ad, // @aclk, address/data to program the AHCI FSM
output reg pgm_wa, // @aclk, address strobe to program the AHCI FSM
output reg pgm_wd, // @aclk, data strobe to program the AHCI FSM
// other control signals
output reg [ 3:0] afi_wcache,
output reg [ 3:0] afi_rcache,
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
input [31:0] debug_in0,
input [31:0] debug_in1,
input [31:0] debug_in2,
input [31:0] debug_in3
`ifdef USE_DRP
,output reg drp_en, // @aclk strobes drp_ad
output reg drp_we,
output reg [14:0] drp_addr,
output reg [15:0] drp_di,
input drp_rdy,
input [15:0] drp_do
`endif
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
,input datascope_clk,
input [ADDRESS_BITS-1:0] datascope_waddr,
input datascope_we,
input [31:0] datascope_di,
input datascope1_clk,
input [ADDRESS_BITS-1:0] datascope1_waddr,
input datascope1_we,
input [31:0] datascope1_di
`endif
);
`ifdef USE_DRP
localparam DRP_ADDR = 'h3fb;
reg [15:0] drp_read_data;
reg drp_read_r;
reg drp_ready_r;
`endif
`ifdef USE_DATASCOPE
// localparam AXIBRAM_BITS = ADDRESS_BITS + 1; // number of axi address outputs (one more than ADDRESS_BITS when using datascope)
localparam AXIBRAM_BITS = ADDRESS_BITS + 2; // number of axi address outputs (one more than ADDRESS_BITS when using datascope)
wire [31:0] datascope_rdata;
reg [1:0] datascope_sel; // read datascope memory instead of the registers
wire [31:0] datascope1_rdata;
reg [1:0] datascope1_sel; // read datascope memory instead of the registers
always @ (posedge aclk) begin
datascope_sel <= {datascope_sel[0], ~bram_raddr[ADDRESS_BITS+1] & bram_raddr[ADDRESS_BITS]};
datascope1_sel <= {datascope1_sel[0], bram_raddr[ADDRESS_BITS+1] & ~bram_raddr[ADDRESS_BITS]};
end
`else
localparam AXIBRAM_BITS = ADDRESS_BITS; // number of axi address outputs (one more than ADDRESS_BITS when using datascope)
`endif
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
wire [AXIBRAM_BITS-1:0] bram_waddr;
// wire [ADDRESS_BITS-1:0] pre_awaddr;
wire [AXIBRAM_BITS-1:0] bram_raddr;
wire [31:0] bram_rdata;
wire pre_bram_wen; // one cycle ahead of bram_wen, nut not masked by dev_ready
wire bram_wen;
wire [ 3:0] bram_wstb;
wire [31:0] bram_wdata;
wire [ADDRESS_BITS-1:0] bram_addr;
wire [1:0] bram_ren;
reg write_busy_r;
wire write_start_burst;
// wire nowrite; // delay write in read-modify-write register accesses
/// wire write_busy_w = write_busy_r || write_start_burst;
wire write_busy_w = write_busy_r || write_start_burst || bram_wen_r;
reg [31:0] bram_wdata_r;
reg [31:0] bram_rdata_r;
// reg bram_wen_d;
wire [63:0] regbit_type;
wire [31:0] ahci_regs_di;
reg [ 3:0] bram_wstb_r;
reg bram_wen_r;
// wire [31:0] wmask = {{8{bram_wstb[3]}},{8{bram_wstb[2]}},{8{bram_wstb[1]}},{8{bram_wstb[0]}}};
wire [31:0] wmask = {{8{bram_wstb_r[3]}},{8{bram_wstb_r[2]}},{8{bram_wstb_r[1]}},{8{bram_wstb_r[0]}}};
reg [ADDRESS_BITS-1:0] bram_waddr_r;
reg [HBA_RESET_BITS-1:0] hba_reset_cntr; // time to keep hba_reset_r active after writing to GHC.HR
reg hba_rst_r; // hba _reset (currently does ~ the same as port reset)
reg port_rst_r; // port _reset by software
reg port_arst_any_r = 1; // port _reset by software or POR
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 pgm_fsm_set_w = bram_wen_r && !high_sel && (bram_addr == HBA_PORT__PGM_AHCI_SM__PGM_AD__ADDR);
wire pgm_fsm_and_w = |(ahci_regs_di & HBA_PORT__PGM_AHCI_SM__AnD__MASK);
wire set_hba_rst = bram_wen_r && !high_sel && (bram_addr == GHC__GHC__HR__ADDR) && (ahci_regs_di & GHC__GHC__HR__MASK);
localparam HBA_PORT__PxSCTL__DET__MASK01 = HBA_PORT__PxSCTL__DET__MASK & ~1; // == 'he
wire set_port_rst = bram_wen_r && !high_sel && (bram_addr == HBA_PORT__PxSCTL__DET__ADDR) &&
((ahci_regs_di & HBA_PORT__PxSCTL__DET__MASK01) == 0); // 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
reg [2:0] arst_r = ~0; // previous state of arst
reg wait_first_access = RESET_TO_FIRST_ACCESS; // keep port reset until first access
wire any_access = bram_wen_r || bram_ren[0];
reg debug_rd_r = 0;
reg [31:0] debug_r;
assign bram_addr = bram_ren[0] ? bram_raddr[ADDRESS_BITS-1:0] : (bram_wen_r ? bram_waddr_r : bram_waddr[ADDRESS_BITS-1:0]);
assign hba_arst = hba_rst_r; // hba _reset (currently does ~ the same as port reset)
assign port_arst = port_rst_r; // port _reset by software
assign port_arst_any = port_arst_any_r;
assign was_hba_rst = was_hba_rst_r[0];
assign was_port_rst = was_port_rst_r[0];
always @(posedge aclk) begin
`ifdef USE_DRP
if (bram_waddr == DRP_ADDR) begin
drp_di <= bram_wdata[15: 0];
drp_addr <= bram_wdata[30:16];
// drp_we <= bram_wdata[31];
end
drp_en <= (bram_waddr == DRP_ADDR);
drp_we <= (bram_waddr == DRP_ADDR) && bram_wdata[31];
if (arst || (bram_waddr == DRP_ADDR)) drp_ready_r <= 0;
else if (drp_rdy) drp_ready_r <= 1;
if (drp_rdy) drp_read_data <= drp_do;
if (bram_ren[0]) drp_read_r <= (bram_raddr == DRP_ADDR);
`endif
if (arst) write_busy_r <= 0;
else if (write_start_burst) write_busy_r <= 1;
else if (!pre_bram_wen) write_busy_r <= 0;
if (bram_wen) bram_wdata_r <= bram_wdata;
bram_wstb_r <= {4{bram_wen}} & bram_wstb;
bram_wen_r <= bram_wen;
if (bram_wen) bram_waddr_r <= bram_waddr[ADDRESS_BITS-1:0];
`ifndef NO_DEBUG_OUT
`ifdef USE_DATASCOPE
if (bram_ren[0]) debug_rd_r <= (&bram_raddr[ADDRESS_BITS-1:4]) &&
// (bram_raddr[3:2] == 0) &&
!bram_raddr[ADDRESS_BITS]; //
`else
if (bram_ren[0]) debug_rd_r <= (&bram_raddr[ADDRESS_BITS-1:4]); // &&
// (bram_raddr[3:2] == 0); //
`endif
`endif // `else `ifdef NO_DEBUG_OUT
if (bram_ren[0]) debug_r <= bram_raddr[1]? (bram_raddr[0] ? debug_in3: debug_in2):
(bram_raddr[0] ? debug_in1: debug_in0);
`ifdef USE_DRP
if (bram_ren[1]) bram_rdata_r <= drp_read_r? {drp_ready_r, 15'b0,drp_read_data}:
(debug_rd_r? debug_r : bram_rdata);
`else
if (bram_ren[1]) bram_rdata_r <= debug_rd_r? debug_r : bram_rdata;
`endif
end
//debug_rd_r
generate
genvar i;
for (i=0; i < 32; i=i+1) begin: bit_type_block
assign ahci_regs_di[i] = (regbit_type[2*i+1] && wmask[i] && !high_sel)?
((regbit_type[2*i] && wmask[i])?
(bram_rdata[i] || bram_wdata_r[i]): // 3: RW1
(bram_rdata[i] && !bram_wdata_r[i])): // 2: RWC
(((regbit_type[2*i] && wmask[i]) || high_sel)?
(bram_wdata_r[i]): // 1: RW write new data - get here for high_sel
(bram_rdata[i])); // 0: R0 (keep old data)
end
endgenerate
// always @ (posedge aclk or posedge arst) begin
always @ (posedge aclk) begin
if (arst) wait_first_access <= RESET_TO_FIRST_ACCESS;
else if (any_access) wait_first_access <= 0;
if (arst) port_arst_any_r <= 1;
else if (set_port_rst) port_arst_any_r <= ahci_regs_di[0]; // write "1" - reset on, write 0 - reset off
else if (wait_first_access && any_access) port_arst_any_r <= 0;
else if (arst_r[2] && !arst_r[1]) port_arst_any_r <= wait_first_access;
end
always @(posedge aclk) begin
if (arst) hba_reset_cntr <= 0; // 1; no HBA reset at arst
else if (set_hba_rst) hba_reset_cntr <= {HBA_RESET_BITS{1'b1}};
else if (|hba_reset_cntr) hba_reset_cntr <= hba_reset_cntr - 1;
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 || set_hba_rst) was_port_rst_aclk <= 0;
else if (port_rst_on) was_port_rst_aclk <= 1;
if (arst) arst_r <= ~0;
else arst_r <= arst_r << 1;
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
always @(posedge aclk) begin
if (arst) {afi_wcache,afi_rcache} <= 8'h33;
else if (afi_cache_set_w) {afi_wcache,afi_rcache} <= ahci_regs_di[7:0];
end
always @(posedge aclk) begin
if (arst) {pgm_wa,pgm_wd} <= 0;
else {pgm_wa,pgm_wd} <= {2{pgm_fsm_set_w}} & {pgm_fsm_and_w, ~pgm_fsm_and_w};
if (pgm_fsm_set_w) pgm_ad <= ahci_regs_di[17:0];
end
/*
Will generate async reset on both HBA reset(for some time) and port reset (until released)
until it is more clear about GTX reset options. Such reset will be applied to both PLL and GTX,
sata_phy_rst_out will be released after the sata clock is stable
output soft_arst, // reset SATA PHY not relying on SATA clock
// TODO: Decode from {bram_addr, ahci_regs_di}, bram_wen_d
input sata_phy_rst_out, // when PLL locked, SATA PHY reset is over, this signal is released
localparam GHC__GHC__HR__ADDR = 'h1;
localparam GHC__GHC__HR__MASK = 'h1;
localparam GHC__GHC__HR__DFLT = 'h0;
reg [HBA_RESET_BITS-1:0] hba_reset_cntr; // time to keep hba_reset_r active after writing to GHC.HR
reg hba_rst_r; // hba reset (currently does ~ the same as port reset)
reg port_rst_r; // port reset by software
.rst (1'b0), // input
.rrst (hba_rst), // input
.wrst (arst), // input
.rclk (hba_clk), // input
.wclk (aclk), // input
.we (bram_wen_r && !high_sel), // input
.re (soft_write_en), // input
.data_in ({bram_addr, ahci_regs_di}), // input[15:0]
.data_out ({soft_write_addr,soft_write_data}), // output[15:0]
.nempty (soft_write_en), // output
.half_empty () // output
// RO: Device Detection Initialization
localparam HBA_PORT__PxSCTL__DET__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__DET__MASK = 'hf;
localparam HBA_PORT__PxSCTL__DET__DFLT = 'h0;
*/
axibram_write #(
.ADDRESS_BITS(AXIBRAM_BITS) // in debug mode - 1 bit more than ADDERSS_BITS
) axibram_write_i (
.aclk (aclk), // input
.arst (arst), // input
.awaddr (awaddr), // input[31:0]
.awvalid (awvalid), // input
.awready (awready), // output
.awid (awid), // input[11:0]
.awlen (awlen), // input[3:0]
.awsize (awsize), // input[1:0]
.awburst (awburst), // input[1:0]
.wdata (wdata), // input[31:0]
.wvalid (wvalid), // input
.wready (wready), // output
.wid (wid), // input[11:0]
.wlast (wlast), // input
.wstb (wstb), // input[3:0]
.bvalid (bvalid), // output
.bready (bready), // input
.bid (bid), // output[11:0]
.bresp (bresp), // output[1:0]
.pre_awaddr (), //pre_awaddr), // output[9:0]
.start_burst (write_start_burst), // output
// .dev_ready (!nowrite && !bram_ren[0]), // input
.dev_ready (!bram_wen), // input There will be no 2 bram_wen in a row
.bram_wclk (), // output
.bram_waddr (bram_waddr), // output[9:0]
.pre_bram_wen(pre_bram_wen), // output
.bram_wen (bram_wen), // output
.bram_wstb (bram_wstb), // output[3:0]
.bram_wdata (bram_wdata) // output[31:0]
);
axibram_read #(
.ADDRESS_BITS(AXIBRAM_BITS) // in debug mode - 1 bit more than ADDERSS_BITS
) axibram_read_i (
.aclk (aclk), // input
.arst (arst), // input
.araddr (araddr), // input[31:0]
.arvalid (arvalid), // input
.arready (arready), // output
.arid (arid), // input[11:0]
.arlen (arlen), // input[3:0]
.arsize (arsize), // input[1:0]
.arburst (arburst), // input[1:0]
.rdata (rdata), // output[31:0]
.rvalid (rvalid), // output reg
.rready (rready), // input
.rid (rid), // output[11:0] reg
.rlast (rlast), // output reg
.rresp (rresp), // output[1:0]
.pre_araddr (), // output[9:0]
.start_burst (), // output
.dev_ready (!write_busy_w), // input
.bram_rclk (), // output
.bram_raddr (bram_raddr), // output[9:0]
.bram_ren (bram_ren[0]), // output
.bram_regen (bram_ren[1]), // output
`ifdef USE_DATASCOPE
.bram_rdata ((datascope_sel[1] | datascope1_sel[1]) ?
(datascope1_sel[1]? datascope1_rdata : datascope_rdata) :
bram_rdata_r) // input[31:0]
`else
.bram_rdata (bram_rdata_r) // input[31:0]
`endif
);
// Register memory, lower half uses read-modify-write using bit type from ahci_regs_type_i ROM, 2 aclk cycles/per write and
// high addresses half are just plain write registers, they heve single-cycle write
// Only low registers write generates cross-clock writes over the FIFO.
// All registers can be accessed in byte/word/dword mode over the AXI
// Lower registers are used as AHCI memory registers, high - for AHCI command list(s), to eliminate the need to update transfer count
// in the system memory.
ramt_var_wb_var_r #(
.REGISTERS_A (0),
.REGISTERS_B (1),
.LOG2WIDTH_A (5),
.LOG2WIDTH_B (5),
.WRITE_MODE_A("NO_CHANGE"),
.WRITE_MODE_B("NO_CHANGE")
`include "includes/ahci_defaults.vh"
) ahci_regs_i (
.clk_a (aclk), // input
.addr_a (bram_addr), // input[9:0]
.en_a (bram_ren[0] || bram_wen || bram_wen_r), // input
.regen_a (1'b0), // input
.we_a (bram_wstb_r), // input[3:0]
//
.data_out_a (bram_rdata), // output[31:0]
.data_in_a (ahci_regs_di), // input[31:0]
.clk_b (hba_clk), // input
.addr_b (hba_addr), // input[9:0]
.en_b (hba_we || hba_re[0]), // input
.regen_b (hba_re[1]), // input
.we_b ({4{hba_we}}), // input
.data_out_b (hba_dout), // output[31:0]
.data_in_b (hba_din) // input[31:0]
);
ram_var_w_var_r #(
.REGISTERS (0),
.LOG2WIDTH_WR (6),
.LOG2WIDTH_RD (6),
.DUMMY(0)
`include "includes/ahci_types.vh"
) ahci_regs_type_i (
.rclk (aclk), // input
.raddr (bram_addr[8:0]), // input[8:0]
.ren (bram_wen && !bram_addr[9]), // input
.regen (1'b0), // input
.data_out (regbit_type), // output[63:0]
.wclk (1'b0), // input
.waddr (9'b0), // input[8:0]
.we (1'b0), // input
.web (8'b0), // input[7:0]
.data_in (64'b0) // input[63:0]
);
`ifdef USE_DATASCOPE
ram_var_w_var_r #(
.REGISTERS (0),
.LOG2WIDTH_WR (5),
.LOG2WIDTH_RD (5),
.DUMMY(0)
) datascope_mem_i (
.rclk (aclk), // input
.raddr (bram_raddr[9:0]), // input[9:0]
.ren (bram_ren[0]), // input
.regen (bram_ren[1]), // input
.data_out (datascope_rdata), // output[31:0]
.wclk (datascope_clk), // input
.waddr (datascope_waddr), // input[9:0]
.we (datascope_we), // input
.web (8'hff), // input[7:0]
.data_in (datascope_di) // input[31:0]
);
ram_var_w_var_r #(
.REGISTERS (0),
.LOG2WIDTH_WR (5),
.LOG2WIDTH_RD (5),
.DUMMY(0)
) datascope1_mem_i (
.rclk (aclk), // input
.raddr (bram_raddr[9:0]), // input[9:0]
.ren (bram_ren[0]), // input
.regen (bram_ren[1]), // input
.data_out (datascope1_rdata), // output[31:0]
.wclk (datascope1_clk), // input
.waddr (datascope1_waddr), // input[9:0]
.we (datascope1_we), // input
.web (8'hff), // input[7:0]
.data_in (datascope1_di) // input[31:0]
);
`endif
fifo_cross_clocks #(
.DATA_WIDTH(ADDRESS_BITS+32),
.DATA_DEPTH(4)
) ahci_regs_set_i (
.rst (1'b0), // input
.rrst (hba_rst), // input
.wrst (arst), // input
.rclk (hba_clk), // input
.wclk (aclk), // input
.we (bram_wen_r && !high_sel), // input
.re (soft_write_en), // input
.data_in ({bram_addr, ahci_regs_di}), // input[15:0]
.data_out ({soft_write_addr,soft_write_data}), // output[15:0]
.nempty (soft_write_en), // output
.half_empty () // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) afi_cache_set_i (
.rst (arst), // input
.src_clk (aclk), // input
.dst_clk (hba_clk), // input
.in_pulse (afi_cache_set_w), // input
.out_pulse (afi_cache_set), // output
.busy() // output
);
endmodule
/*******************************************************************************
* Module: axi_hp_abort
* Date:2016-02-07
* Author: andrey
* Description: Trying to gracefully reset AXI HP after aborted transmission
* For read channel - just keep afi_rready on until RD FIFO is empty (afi_rcount ==0)
* For write - keep track aof all what was sent so far, assuming aw is always ahead of w
* Reset only by global reset (system POR) - probably it is not possible to just
* reset PL or relaod bitfile,
*
* Copyright (c) 2016 Elphel, Inc .
* axi_hp_abort.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.
*
* axi_hp_abort.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 axi_hp_abort(
input hclk,
input hrst, // just disables processing inputs
input abort,
output busy, // should disable control of afi_wvalid, afi_awid
output reg done,
input afi_awvalid, // afi_awready is supposed to be always on when afi_awvalid (caller uses fifo counetrs) ?
input afi_awready, //
input [ 5:0] afi_awid,
input [3:0] afi_awlen,
input afi_wvalid_in,
input afi_wready,
output afi_wvalid,
output reg [ 5:0] afi_wid,
input afi_arvalid,
input afi_arready,
input [ 3:0] afi_arlen,
input afi_rready_in,
input afi_rvalid,
output afi_rready,
output afi_wlast,
// TODO: Try to resolve problems when afi_racount, afi_wacount afi_wcount do not match expected
input [ 2:0] afi_racount,
input [ 7:0] afi_rcount,
input [ 5:0] afi_wacount,
input [ 7:0] afi_wcount,
output reg dirty, // single bit to be sampled in different clock domain to see if flushing is needed
output reg axi_mismatch, // calculated as 'dirty' but axi hp counters are 0
output [21:0] debug
);
reg busy_r;
wire done_w = busy_r && !dirty ;
reg [3:0] aw_lengths_ram[0:31];
reg [4:0] aw_lengths_waddr = 0;
reg [4:0] aw_lengths_raddr = 0;
reg [5:0] aw_count = 0;
reg [7:0] w_count = 0;
reg [7:0] r_count = 0;
reg adav = 0;
wire arwr = !hrst && afi_arvalid && afi_arready;
wire drd = !hrst && afi_rvalid && afi_rready_in;
wire awr = !hrst && afi_awvalid && afi_awready;
reg ard_r = 0; // additional length read if not much data
wire ard = adav && ((|w_count[7:4]) || ard_r);
wire wwr = !hrst && afi_wready && afi_wvalid_in;
reg afi_rready_r;
reg afi_wlast_r; // wait one cycle after last in each burst (just to ease timing)
reg busy_aborting; // actually aborting
wire reset_counters = busy_r && !busy_aborting;
assign busy = busy_r;
assign afi_rready = busy_aborting && (|r_count) && ((|afi_rcount[7:1]) || (!afi_rready_r && afi_rcount[0]));
assign afi_wlast = busy_aborting && adav && (w_count[3:0] == aw_lengths_ram[aw_lengths_raddr]);
assign afi_wvalid = busy_aborting && adav && !afi_wlast_r;
assign debug = {aw_count[5:0], w_count[7:0], r_count[7:0]};
// Watch for transactios performed by others (and this one too)
always @ (posedge hclk) begin
// read channel
if (reset_counters) r_count <= 0;
else if (drd)
if (arwr) r_count <= r_count + {4'b0, afi_arlen};
else r_count <= r_count - 1;
else
if (arwr) r_count <= w_count + {4'b0, afi_arlen} + 1;
// write channel
if (awr) afi_wid <= afi_awid; // one command is supposed to use just one awid/wid
if (awr) aw_lengths_ram [aw_lengths_waddr] <= afi_awlen;
if (reset_counters) aw_lengths_waddr <= 0;
else if (awr) aw_lengths_waddr <= aw_lengths_waddr + 1;
if (reset_counters) aw_lengths_raddr <= 0;
else if (ard) aw_lengths_raddr <= aw_lengths_raddr + 1;
if (reset_counters) aw_count <= 0;
else if ( awr && !ard) aw_count <= aw_count + 1;
else if (!awr && ard) aw_count <= aw_count - 1;
adav <= !reset_counters && (|aw_count[5:1]) || ((awr || aw_count[0]) && !ard) || (awr && aw_count[0]);
ard_r <= !ard && adav && (w_count[3:0] > aw_lengths_ram[aw_lengths_raddr]);
if (reset_counters) w_count <= 0;
else if (wwr)
if (ard) w_count <= w_count - {4'b0, aw_lengths_ram[aw_lengths_raddr]};
else w_count <= w_count + 1;
else
if (ard) w_count <= w_count - {4'b0, aw_lengths_ram[aw_lengths_raddr]} - 1;
dirty <= (|r_count) || (|aw_count); // assuming w_count can never be non-zero? - no
end
// flushing part
always @ (posedge hclk) begin
if (abort) busy_r <= 1;
else if (done_w) busy_r <= 0;
if (abort && ((|afi_racount) || (|afi_rcount) || (|afi_wacount) || (|afi_wcount))) busy_aborting <= 1;
else if (done_w) busy_aborting <= 0;
done <= done_w;
afi_rready_r <= afi_rready;
afi_wlast_r <= afi_wlast;
axi_mismatch <= busy && !busy_aborting && dirty; //
end
endmodule
/*******************************************************************************
* Module: freq_meter
* Date:2016-02-13
* Author: andrey
* Description: Measure device clock frequency to set the local clock
*
* Copyright (c) 2016 Elphel, Inc .
* freq_meter.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.
*
* freq_meter.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 freq_meter#(
parameter WIDTH = 12, // width of the result
parameter PRESCALE = 1 // 0 same frequency, +1 - xclk is tvice faster, -1 - twice slower
)(
input rst,
input clk,
input xclk,
output reg [WIDTH - 1:0] dout
);
localparam TIMER_WIDTH = WIDTH - PRESCALE;
reg [TIMER_WIDTH - 1 :0] timer;
reg [WIDTH - 1 :0] counter;
wire restart;
reg [3:0] run_xclk;
always @ (posedge clk) begin
if (rst || restart) timer <= 0;
else if (!timer[TIMER_WIDTH - 1]) timer <= timer + 1;
if (restart) dout <= counter; // it is stopped before copying
end
always @ (posedge xclk) begin
run_xclk <= {run_xclk[2:0], ~timer[TIMER_WIDTH - 1] & ~rst};
if (run_xclk[2]) counter <= counter + 1;
else if (run_xclk[1]) counter <= 0;
end
pulse_cross_clock #(
.EXTRA_DLY(0)
) xclk2clk_i (
.rst (rst), // input
.src_clk (xclk), // input
.dst_clk (clk), // input
.in_pulse (!run_xclk[2] && run_xclk[3]), // input
.out_pulse (restart), // output
.busy () // output
);
endmodule
/*******************************************************************************
* Module: sata_ahci_top
* Date: 2015-07-11
* Author: Alexey
* Description: sata for z7nq top-level module
*
* Copyright (c) 2015 Elphel, Inc.
* sata_ahci_top.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.
*
* sata_ahci_top.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
/*
* Takes commands from axi iface as a slave, transfers data with another axi iface as a master
*/
module sata_ahci_top#(
parameter PREFETCH_ALWAYS = 0,
// parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
// parameter READ_CT_LATENCY = 1, // 0 if ct_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)
`ifdef USE_DATASCOPE
parameter DATASCOPE_START_BIT = 14, // bit of DRP "other_control" to start recording after 0->1 (needs DRP)
parameter DATASCOPE_POST_MEAS = 256, // 16, // number of measurements to perform after event
`endif
parameter HBA_RESET_BITS = 9, // duration of HBA reset in aclk periods (9: ~10usec)
parameter RESET_TO_FIRST_ACCESS = 1, // keep port reset until first R/W any register by software
parameter BITS_TO_START_XMIT = 6, // wait H2D FIFO to have 1 << BITS_TO_START_XMIT to start FIS transmission (or all FIS fits)
parameter DATA_BYTE_WIDTH = 4,
parameter ELASTIC_DEPTH = 4, // 4, //5, With 4/7 got infrequent overflows!
parameter ELASTIC_OFFSET = 7, // 5 //10
parameter FREQ_METER_WIDTH = 16
)(
output wire sata_clk,
output wire sata_rst,
input wire arst, // extrst,
// reliable clock to source drp and cpll lock det circuits
input wire reliable_clk,
input wire hclk,
/*
* Commands interface
*/
input wire ACLK, // AXI PS Master GP1 Clock , input
input wire ARESETN, // AXI PS Master GP1 Reset, output // @SuppressThisWarning VEditor unused (arst instead)
// AXI PS Master GP1: Read Address
input wire [31:0] ARADDR, // AXI PS Master GP1 ARADDR[31:0], output
input wire ARVALID, // AXI PS Master GP1 ARVALID, output
output wire ARREADY, // AXI PS Master GP1 ARREADY, input
input wire [11:0] ARID, // AXI PS Master GP1 ARID[11:0], output
input wire [3:0] ARLEN, // AXI PS Master GP1 ARLEN[3:0], output
input wire [1:0] ARSIZE, // AXI PS Master GP1 ARSIZE[1:0], output
input wire [1:0] ARBURST, // AXI PS Master GP1 ARBURST[1:0], output
// AXI PS Master GP1: Read Data
output wire [31:0] RDATA, // AXI PS Master GP1 RDATA[31:0], input
output wire RVALID, // AXI PS Master GP1 RVALID, input
input wire RREADY, // AXI PS Master GP1 RREADY, output
output wire [11:0] RID, // AXI PS Master GP1 RID[11:0], input
output wire RLAST, // AXI PS Master GP1 RLAST, input
output wire [1:0] RRESP, // AXI PS Master GP1 RRESP[1:0], input
// AXI PS Master GP1: Write Address
input wire [31:0] AWADDR, // AXI PS Master GP1 AWADDR[31:0], output
input wire AWVALID, // AXI PS Master GP1 AWVALID, output
output wire AWREADY, // AXI PS Master GP1 AWREADY, input
input wire [11:0] AWID, // AXI PS Master GP1 AWID[11:0], output
input wire [3:0] AWLEN, // AXI PS Master GP1 AWLEN[3:0], outpu:t
input wire [1:0] AWSIZE, // AXI PS Master GP1 AWSIZE[1:0], output
input wire [1:0] AWBURST, // AXI PS Master GP1 AWBURST[1:0], output
// AXI PS Master GP1: Write Data
input wire [31:0] WDATA, // AXI PS Master GP1 WDATA[31:0], output
input wire WVALID, // AXI PS Master GP1 WVALID, output
output wire WREADY, // AXI PS Master GP1 WREADY, input
input wire [11:0] WID, // AXI PS Master GP1 WID[11:0], output
input wire WLAST, // AXI PS Master GP1 WLAST, output
input wire [3:0] WSTRB, // AXI PS Master GP1 WSTRB[3:0], output
// AXI PS Master GP1: Write response
output wire BVALID, // AXI PS Master GP1 BVALID, input
input wire BREADY, // AXI PS Master GP1 BREADY, output
output wire [11:0] BID, // AXI PS Master GP1 BID[11:0], input
output wire [1:0] BRESP, // AXI PS Master GP1 BRESP[1:0], input
/*
* Data interface
*/
output wire [31:0] afi_awaddr,
output wire afi_awvalid,
input wire afi_awready,
output wire [5:0] afi_awid,
output wire [1:0] afi_awlock,
output wire [3:0] afi_awcache,
output wire [2:0] afi_awprot,
output wire [3:0] afi_awlen,
output wire [1:0] afi_awsize,
output wire [1:0] afi_awburst,
output wire [3:0] afi_awqos,
// write data
output wire [63:0] afi_wdata,
output wire afi_wvalid,
input wire afi_wready,
output wire [5:0] afi_wid,
output wire afi_wlast,
output wire [7:0] afi_wstrb,
// write response
input wire afi_bvalid,
output wire afi_bready,
input wire [5:0] afi_bid,
input wire [1:0] afi_bresp,
// PL extra (non-AXI) signals
input wire [7:0] afi_wcount,
input wire [5:0] afi_wacount,
output wire afi_wrissuecap1en,
// AXI_HP signals - read channel
// read address
output wire [31:0] afi_araddr,
output wire afi_arvalid,
input wire afi_arready,
output wire [5:0] afi_arid,
output wire [1:0] afi_arlock,
output wire [3:0] afi_arcache,
output wire [2:0] afi_arprot,
output wire [3:0] afi_arlen,
output wire [1:0] afi_arsize,
output wire [1:0] afi_arburst,
output wire [3:0] afi_arqos,
// read data
input wire [63:0] afi_rdata,
input wire afi_rvalid,
output wire afi_rready,
input wire [5:0] afi_rid,
input wire afi_rlast,
input wire [1:0] afi_rresp,
// PL extra (non-AXI) signals
input wire [7:0] afi_rcount,
input wire [2:0] afi_racount,
output wire afi_rdissuecap1en,
output wire irq,
/*
* PHY
*/
output wire TXN,
output wire TXP,
input wire RXN,
input wire RXP,
input wire EXTCLK_P,
input wire EXTCLK_N
);
// wire sata_clk;
// wire sata_rst;
wire hba_arst; // @S uppressThisWarning VEditor unused
wire port_arst; // @SuppressThisWarning VEditor unused
wire port_arst_any;
// wire exrst = port_arst_any; // now both hba_arst and port_arst are the same?
wire exrst = port_arst_any || hba_arst; // now both hba_arst and port_arst are the same (only difference in fsm)
// Data/type FIFO, host -> device
// Data System memory or FIS -> device
wire [31:0] h2d_data; // 32-bit data from the system memory to HBA (dma data)
wire [ 1:0] h2d_type; // 0 - data, 1 - FIS head, 2 - FIS END (make FIS_Last?)
wire h2d_valid; // output register full
wire h2d_ready; // send FIFO has room for data (>= 8? dwords)
// Data/type FIFO, device -> host
wire [31:0] d2h_data; // FIFO output data
wire [ 1:0] d2h_type; // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR
wire d2h_valid; // Data available from the transport layer in FIFO
wire d2h_many; // Multiple DWORDs available from the transport layer in FIFO
wire d2h_ready; // This module or DMA consumes DWORD
// communication with transport/link/phys layers
// wire phy_rst; // frome phy, as a response to hba_arst || port_arst. It is deasserted when clock is stable
wire [ 1:0] phy_speed; // 0 - not ready, 1..3 - negotiated speed
wire xmit_ok; // FIS transmission acknowledged OK
wire xmit_err; // Error during sending of a FIS
wire syncesc_recv; // These two inputs interrupt transmit
wire pcmd_st_cleared; // bit was cleared by software
wire syncesc_send; // Send sync escape
wire syncesc_send_done; // "SYNC escape until the interface is quiescent..."
wire comreset_send; // Not possible yet?
wire cominit_got;
wire set_offline; // electrically idle
wire x_rdy_collision; // X_RDY/X_RDY collision on interface
wire send_R_OK; // Should it be originated in this layer SM?
wire send_R_ERR;
// additional errors from SATA layers (single-clock pulses):
wire serr_DT; // RWC: Transport state transition error
wire serr_DS; // RWC: Link sequence error
wire serr_DH; // RWC: Handshake Error (i.e. Device got CRC error)
wire serr_DC; // RWC: CRC error in Link layer
wire serr_DB; // RWC: 10B to 8B decode error
wire serr_DW; // RWC: COMMWAKE signal was detected
wire serr_DI; // RWC: PHY Internal Error
// sirq_PRC,
wire serr_EE; // RWC: Internal error (such as elastic buffer overflow or primitive mis-alignment)
wire serr_EP; // RWC: Protocol Error - a violation of SATA protocol detected
wire serr_EC; // RWC: Persistent Communication or Data Integrity Error
wire serr_ET; // RWC: Transient Data Integrity Error (error not recovered by the interface)
wire serr_EM; // RWC: Communication between the device and host was lost but re-established
wire serr_EI; // RWC: Recovered Data integrity Error
// additional control signals for SATA layers
wire [3:0] sctl_ipm; // Interface power management transitions allowed
wire [3:0] sctl_spd; // Interface maximal speed
reg [2:0] nhrst_r;
wire hrst = !nhrst_r[2];
wire [FREQ_METER_WIDTH-1:0] xclk_period;
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
wire datascope_clk;
wire [ADDRESS_BITS-1:0] datascope_waddr;
wire datascope_we;
wire [31:0] datascope_di;
`endif
`ifdef USE_DRP
wire drp_en;
wire drp_we;
wire [14:0] drp_addr;
wire [15:0] drp_di;
wire drp_rdy;
wire [15:0] drp_do;
`endif
wire [31:0] debug_phy;
wire [31:0] debug_link;
always @ (posedge hclk or posedge arst) begin
if (arst) nhrst_r <= 0;
else nhrst_r <= (nhrst_r << 1) | 1;
end
ahci_top #(
.PREFETCH_ALWAYS (PREFETCH_ALWAYS),
// .READ_REG_LATENCY (READ_REG_LATENCY),
// .READ_CT_LATENCY (READ_CT_LATENCY),
.ADDRESS_BITS (ADDRESS_BITS),
.HBA_RESET_BITS (HBA_RESET_BITS),
.RESET_TO_FIRST_ACCESS (RESET_TO_FIRST_ACCESS),
.FREQ_METER_WIDTH (FREQ_METER_WIDTH)
) ahci_top_i (
.aclk (ACLK), // input
.arst (arst), // input
.mclk (sata_clk), // input
.mrst (sata_rst), // input
.hba_arst (hba_arst), // output
.port_arst (port_arst), // output
.port_arst_any (port_arst_any), // port0 async set by software and by arst
.hclk (hclk), // input
.hrst (hrst), // input
.awaddr (AWADDR), // input[31:0]
.awvalid (AWVALID), // input
.awready (AWREADY), // output
.awid (AWID), // input[11:0]
.awlen (AWLEN), // input[3:0]
.awsize (AWSIZE), // input[1:0]
.awburst (AWBURST), // input[1:0]
.wdata (WDATA), // input[31:0]
.wvalid (WVALID), // input
.wready (WREADY), // output
.wid (WID), // input[11:0]
.wlast (WLAST), // input
.wstb (WSTRB), // input[3:0]
.bvalid (BVALID), // output
.bready (BREADY), // input
.bid (BID), // output[11:0]
.bresp (BRESP), // output[1:0]
.araddr (ARADDR), // input[31:0]
.arvalid (ARVALID), // input
.arready (ARREADY), // output
.arid (ARID), // input[11:0]
.arlen (ARLEN), // input[3:0]
.arsize (ARSIZE), // input[1:0]
.arburst (ARBURST), // input[1:0]
.rdata (RDATA), // output[31:0]
.rvalid (RVALID), // output
.rready (RREADY), // input
.rid (RID), // output[11:0]
.rlast (RLAST), // output
.rresp (RRESP), // output[1:0]
.afi_awaddr (afi_awaddr), // output[31:0]
.afi_awvalid (afi_awvalid), // output
.afi_awready (afi_awready), // input
.afi_awid (afi_awid), // output[5:0]
.afi_awlock (afi_awlock), // output[1:0]
.afi_awcache (afi_awcache), // output[3:0]
.afi_awprot (afi_awprot), // output[2:0]
.afi_awlen (afi_awlen), // output[3:0]
.afi_awsize (afi_awsize), // output[1:0]
.afi_awburst (afi_awburst), // output[1:0]
.afi_awqos (afi_awqos), // output[3:0]
.afi_wdata (afi_wdata), // output[63:0]
.afi_wvalid (afi_wvalid), // output
.afi_wready (afi_wready), // input
.afi_wid (afi_wid), // output[5:0]
.afi_wlast (afi_wlast), // output
.afi_wstrb (afi_wstrb), // output[7:0]
.afi_bvalid (afi_bvalid), // input
.afi_bready (afi_bready), // output
.afi_bid (afi_bid), // input[5:0]
.afi_bresp (afi_bresp), // input[1:0]
.afi_wcount (afi_wcount), // input[7:0]
.afi_wacount (afi_wacount), // input[5:0]
.afi_wrissuecap1en (afi_wrissuecap1en), // output
.afi_araddr (afi_araddr), // output[31:0]
.afi_arvalid (afi_arvalid), // output
.afi_arready (afi_arready), // input
.afi_arid (afi_arid), // output[5:0]
.afi_arlock (afi_arlock), // output[1:0]
.afi_arcache (afi_arcache), // output[3:0]
.afi_arprot (afi_arprot), // output[2:0]
.afi_arlen (afi_arlen), // output[3:0]
.afi_arsize (afi_arsize), // output[1:0]
.afi_arburst (afi_arburst), // output[1:0]
.afi_arqos (afi_arqos), // output[3:0]
.afi_rdata (afi_rdata), // input[63:0]
.afi_rvalid (afi_rvalid), // input
.afi_rready (afi_rready), // output
.afi_rid (afi_rid), // input[5:0]
.afi_rlast (afi_rlast), // input
.afi_rresp (afi_rresp), // input[1:0]
.afi_rcount (afi_rcount), // input[7:0]
.afi_racount (afi_racount), // input[2:0]
.afi_rdissuecap1en (afi_rdissuecap1en), // output
.h2d_data (h2d_data), // output[31:0]
.h2d_type (h2d_type), // output[1:0]
.h2d_valid (h2d_valid), // output
.h2d_ready (h2d_ready), // input
.d2h_data (d2h_data), // input[31:0]
.d2h_type (d2h_type), // input[1:0]
.d2h_valid (d2h_valid), // input
.d2h_many (d2h_many), // input
.d2h_ready (d2h_ready), // output
.phy_ready (phy_speed), // input[1:0]
.xmit_ok (xmit_ok), // input
.xmit_err (xmit_err), // input
.syncesc_recv (syncesc_recv), // input
.pcmd_st_cleared (pcmd_st_cleared), // output
.syncesc_send (syncesc_send), // output
.syncesc_send_done (syncesc_send_done), // input
.comreset_send (comreset_send), // output
.cominit_got (cominit_got), // input
.set_offline (set_offline), // output
.x_rdy_collision (x_rdy_collision), // input
.send_R_OK (send_R_OK), // output
.send_R_ERR (send_R_ERR), // output
.serr_DT (serr_DT), // input
.serr_DS (serr_DS), // input
.serr_DH (serr_DH), // input
.serr_DC (serr_DC), // input
.serr_DB (serr_DB), // input
.serr_DW (serr_DW), // input
.serr_DI (serr_DI), // input
.serr_EE (serr_EE), // input
.serr_EP (serr_EP), // input
.serr_EC (serr_EC), // input
.serr_ET (serr_ET), // input
.serr_EM (serr_EM), // input
.serr_EI (serr_EI), // input
.sctl_ipm (sctl_ipm), // output[3:0]
.sctl_spd (sctl_spd), // output[3:0]
.irq (irq), // output
`ifdef USE_DATASCOPE
.datascope1_clk (datascope_clk), // input
.datascope1_waddr (datascope_waddr), // input[9:0]
.datascope1_we (datascope_we), // input
.datascope1_di (datascope_di), // input[31:0]
`endif
`ifdef USE_DRP
.drp_en (drp_en), // output reg
.drp_we (drp_we), // output reg
.drp_addr (drp_addr), // output[14:0] reg
.drp_di (drp_di), // output[15:0] reg
.drp_rdy (drp_rdy), // input
.drp_do (drp_do), // input[15:0]
`endif
.xclk_period (xclk_period), // input[11:0]
.debug_in_phy (debug_phy), // input[31:0]
.debug_in_link (debug_link) // input[31:0]
);
ahci_sata_layers #(
`ifdef USE_DATASCOPE
.ADDRESS_BITS (ADDRESS_BITS), // for datascope
.DATASCOPE_START_BIT (DATASCOPE_START_BIT), // bit of DRP "other_control" to start recording after 0->1 (needs DRP)
.DATASCOPE_POST_MEAS (DATASCOPE_POST_MEAS), // number of measurements to perform after event
`endif
.BITS_TO_START_XMIT (BITS_TO_START_XMIT),
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.ELASTIC_DEPTH (ELASTIC_DEPTH),
.ELASTIC_OFFSET (ELASTIC_OFFSET),
.FREQ_METER_WIDTH (FREQ_METER_WIDTH)
) ahci_sata_layers_i (
.exrst (exrst), // input
.reliable_clk (reliable_clk), // input
.rst (sata_rst), // output
.clk (sata_clk), // output
.h2d_data (h2d_data), // input[31:0]
.h2d_mask (2'h3), //h2d_mask), // input[1:0]
.h2d_type (h2d_type), // input[1:0]
.h2d_valid (h2d_valid), // input
.h2d_ready (h2d_ready), // output
.d2h_data (d2h_data), // output[31:0]
.d2h_mask (), // 2h_mask), // output[1:0]
.d2h_type (d2h_type), // output[1:0]
.d2h_valid (d2h_valid), // output
.d2h_many (d2h_many), // output
.d2h_ready (d2h_ready), // input
.phy_speed (phy_speed), // output[1:0]
.gtx_ready(), // output
.xmit_ok (xmit_ok), // output
.xmit_err (xmit_err), // output
.x_rdy_collision (x_rdy_collision), // output
.syncesc_recv (syncesc_recv), // output
.pcmd_st_cleared (pcmd_st_cleared), // input
.syncesc_send (syncesc_send), // input
.syncesc_send_done (syncesc_send_done), // output
.comreset_send (comreset_send), // input
.cominit_got (cominit_got), // output
.set_offline (set_offline), // input
.send_R_OK (send_R_OK), // input
.send_R_ERR (send_R_ERR), // input
.serr_DT (serr_DT), // output
.serr_DS (serr_DS), // output
.serr_DH (serr_DH), // output
.serr_DC (serr_DC), // output
.serr_DB (serr_DB), // output
.serr_DW (serr_DW), // output
.serr_DI (serr_DI), // output
.serr_EE (serr_EE), // output
.serr_EP (serr_EP), // output
.serr_EC (serr_EC), // output
.serr_ET (serr_ET), // output
.serr_EM (serr_EM), // output
.serr_EI (serr_EI), // output
.sctl_ipm (sctl_ipm), // input[3:0]
.sctl_spd (sctl_spd), // input[3:0]
.extclk_p (EXTCLK_P), // input wire
.extclk_n (EXTCLK_N), // input wire
.txp_out (TXP), // output wire
.txn_out (TXN), // output wire
.rxp_in (RXP), // input wire
.rxn_in (RXN), // input wire
`ifdef USE_DATASCOPE
.datascope_clk (datascope_clk), // output
.datascope_waddr (datascope_waddr), // output[9:0]
.datascope_we (datascope_we), // output
.datascope_di (datascope_di), // output[31:0]
`endif
`ifdef USE_DRP
.drp_rst (arst), // input
.drp_clk (ACLK), // input
.drp_en (drp_en), // input
.drp_we (drp_we), // input
.drp_addr (drp_addr), // input[14:0]
.drp_di (drp_di), // input[15:0]
.drp_rdy (drp_rdy), // output
.drp_do (drp_do), // output[15:0]
`endif
.xclk_period (xclk_period), // output[11:0]
.debug_phy (debug_phy), // output[31:0]
.debug_link (debug_link) // output[31:0]
,.hclk(hclk)
);
endmodule
# clock, received via FCLK input from PS7
# barely used for now
create_clock -name axi_aclk0 -period 20.000 -waveform {0.000 10.000} [get_nets axi_aclk0]
# external clock 150Mhz
create_clock -name gtrefclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/gtrefclk]
# after plls inside of GTX:
#create_clock -name txoutclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/txoutclk]
#create_clock -name txoutclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/gtx_wrap/bufg_txoutclk/valid_reg]
###create_clock -name txoutclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/gtx_wrap/bufg_txoutclk/txoutclk_gtx]
# recovered sata parallel clock
##create_clock -name xclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/gtx_wrap/xclk]
create_clock -name xclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/gtx_wrap/xclk_gtx]
###sata_top/ahci_sata_layers_i/phy/gtx_wrap/xclk_gtx sata_top/ahci_sata_layers_i/phy/gtx_wrap/gtxe2_channel_wrapper/xclk_gtx
create_clock -name txoutclk -period 6.666 -waveform {0.000 3.333} [get_nets sata_top/ahci_sata_layers_i/phy/gtx_wrap/txoutclk_gtx]
# txoutclk -> userpll, which gives us 2 clocks: userclk (150MHz) and userclk2 (75MHz) . The second one is sata host clk
###create_generated_clock -name usrclk [get_nets sata_top/ahci_sata_layers_i/phy/CLK]
#create_generated_clock -name sclk [get_nets sata_top/ahci_sata_layers_i/phy/clk]
###create_generated_clock -name sclk [get_nets sata_top_n_173]
###These clocks are already automatically extracted
#create_generated_clock -name usrclk [get_nets sata_top/ahci_sata_layers_i/phy/usrclk]
#create_generated_clock -name usrclk2 [get_nets sata_top/ahci_sata_layers_i/phy/usrclk2]
#create_clock -name usrclk2 -period 15.333 -waveform {0.000 6.666} [get_nets sata_top/ahci_sata_layers_i/phy/bufg_sclk/usrclk2_r]
#create_clock -name usrclk2 -period 15.333 -waveform {0.000 6.666} [get_nets sata_top/ahci_sata_layers_i/phy/bufg_sclk/rclk]
create_clock -name usrclk2 -period 13.333 -waveform {0.000 6.666} [get_nets sata_top/ahci_sata_layers_i/phy/usrclk2_r]
#
#create_generated_clock -name usrclk2 [get_nets sata_top/ahci_sata_layers_i/phy/usrclk2_r]
#puts [get_nets sata_top/ahci_sata_layers_i/phy/usrclk2_r]
#set_clock_groups -name async_clocks -asynchronous \
#-group {gtrefclk} \
#-group {axi_aclk0} \
#-group {xclk} \
#-group {usrclk} \
#-group {usrclk2} \
#-group {clk_axihp_pre} \
#-group {txoutclk}
set_clock_groups -name async_clocks -asynchronous \
-group {gtrefclk} \
-group {axi_aclk0} \
-group {xclk} \
-group {usrclk2} \
-group {clk_axihp_pre} \
-group {txoutclk}
###-group {sclk} \
/*******************************************************************************
* Module: oob
* Date: 2015-07-11
* Author: Alexey
* Description: sata oob unit implementation
*
* Copyright (c) 2015 Elphel, Inc.
* oob.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.
*
* oob.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
/*
* For now both device and host shall be set up to SATA2 speeds.
* Need to think how to change speed grades on fly (either to broaden
* data iface width or to change RXRATE/TXRATE)
*/
// All references to doc = to SerialATA_Revision_2_6_Gold.pdf
module oob_dev #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 2 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
// sata clk = usrclk2
input wire clk,
// reset oob
input wire rst,
input wire gtx_ready,
// oob responses
input wire rxcominitdet_in,
input wire rxcomwakedet_in,
input wire rxelecidle_in,
// oob issues
output reg txcominit,
output reg txcomwake,
output reg txelecidle,
output wire txpcsreset_req,
input wire recal_tx_done,
// output data stream to gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out,
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out,
// input data from gtx
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in,
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in,
output wire link_up
);
localparam STATE_RESET = 0;
localparam STATE_COMINIT = 1;
localparam STATE_AWAITCOMWAKE = 2;
localparam STATE_AWAITNOCOMWAKE = 3;
localparam STATE_CALIBRATE = 4;
localparam STATE_COMWAKE = 5;
localparam STATE_RECAL = 55;
localparam STATE_SENDALIGN = 6;
localparam STATE_READY = 7;
localparam STATE_PARTIAL = 8;
localparam STATE_SLUMBER = 9;
localparam STATE_REDUCESPEED = 10;
localparam STATE_ERROR = 11;
reg [9:0] state;
wire retry_interval_elapsed;
wire wait_interval_elapsed;
wire nocomwake;
wire [31:0] align;
wire [31:0] sync;
assign align = {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}; // {D27.3, D10.2, D10.2, K28.5}
assign sync = {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}; // {D21.5, D21.5, D21.4, K28.3}
reg [31:0] nocomwake_timer;
assign nocomwake = nocomwake_timer == 32'd38;
always @ (posedge clk)
nocomwake_timer <= rst | rxcomwakedet_in ? 32'h0 : nocomwake ? nocomwake_timer : nocomwake_timer + 1'b1;
reg [31:0] retry_timer;
assign retry_interval_elapsed = retry_timer == 32'd1000;
always @ (posedge clk)
retry_timer <= rst | ~(state == STATE_AWAITCOMWAKE) ? 32'h0 : retry_timer + 1'b1;
reg [31:0] wait_timer;
assign wait_interval_elapsed = wait_timer == 32'd4096;
always @ (posedge clk)
wait_timer <= rst | ~(state == STATE_SENDALIGN) ? 32'h0 : wait_timer + 1'b1;
reg [31:0] data;
reg [3:0] isk;
assign link_up = state == STATE_READY;
assign txdata_out = data;
assign txcharisk_out = isk;
// buf inputs from gtx
reg rxcominitdet;
reg rxcomwakedet;
reg rxelecidle;
reg [31:0] rxdata;
reg [3:0] rxcharisk;
always @ (posedge clk)
begin
rxcominitdet <= rxcominitdet_in;
rxcomwakedet <= rxcomwakedet_in;
rxelecidle <= rxelecidle_in;
rxdata <= rxdata_in;
rxcharisk <= rxcharisk_in;
end
reg [9:0] txelecidle_cnt;
wire aligndet;
wire syncdet;
assign aligndet = ~|(rxdata ^ {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 4'h1); // {D27.3, D10.2, D10.2, K28.5}
assign syncdet = ~|(rxdata ^ {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 4'h1); // {D21.5, D21.5, D21.4, K28.3}
assign txpcsreset_req = state == STATE_RECAL & (txelecidle_cnt == 10'd160);
always @ (posedge clk)
if (rst | (~gtx_ready & ~(state == STATE_RECAL)))
begin
state <= STATE_RESET;
txelecidle <= 1'b1;
txcominit <= 1'b0;
txcomwake <= 1'b0;
txelecidle_cnt <= 10'h0;
end
else
case (state)
STATE_RESET:
begin
if (rxcominitdet) begin
txelecidle_cnt <= 10'h0;
state <= STATE_COMINIT;
txelecidle <= 1'b1;
txcominit <= 1'b0;
txcomwake <= 1'b0;
end
end
STATE_COMINIT:
begin
state <= STATE_AWAITCOMWAKE;
txcominit <= 1'b1;
end
STATE_AWAITCOMWAKE:
begin
txcominit <= 1'b0;
if (rxcomwakedet)
state <= STATE_AWAITNOCOMWAKE;
else
if (retry_interval_elapsed)
state <= STATE_RESET;
else
state <= STATE_AWAITCOMWAKE;
end
STATE_AWAITNOCOMWAKE:
begin
if (nocomwake)
begin
state <= STATE_CALIBRATE;
end
end
STATE_CALIBRATE:
begin
state <= STATE_COMWAKE;
end
STATE_COMWAKE:
begin
txcomwake <= 1'b1;
state <= STATE_RECAL;
txelecidle_cnt <= 10'h0;
end
STATE_RECAL:
begin
data <= align;
isk <= 4'h1;
txcomwake <= 1'b0;
// txcomwake period = 213.333 ns times let's say 10 pulses => 2133.333 ns = 160 cycles of 75Mhz
if (txelecidle_cnt == 10'd160) begin
txelecidle <= 1'b0;
end
else begin
txelecidle_cnt <= txelecidle_cnt + 1'b1;
end
if (recal_tx_done) begin
state <= STATE_SENDALIGN;
end
end
STATE_SENDALIGN:
begin
data <= align;
isk <= 4'h1;
if (aligndet)
state <= STATE_READY;
else
if (wait_interval_elapsed)
state <= STATE_ERROR;
else
state <= STATE_SENDALIGN;
end
STATE_READY:
begin
txelecidle <= 1'b0;
data <= sync;
isk <= 4'h1;
if (rxelecidle_in)
state <= STATE_ERROR;
end
STATE_ERROR:
begin
txelecidle <= 1'b0;
state <= STATE_RESET;
end
endcase
/*
// 873.8 us error timer
// = 2621400 SATA2 serial ticks (period = 0.000333 us)
// = 131070 ticks @ 150Mhz
// = 65535 ticks @ 75Mhz
localparam [19:0] CLK_TO_TIMER_CONTRIB = CLK_SPEED_GRADE == 1 ? 20'h4 :
CLK_SPEED_GRADE == 2 ? 20'h2 :
CLK_SPEED_GRADE == 4 ? 20'h1 : 20'h1;
`ifdef SIMULATION
localparam [19:0] TIMER_LIMIT = 19'd200;
`else
localparam [19:0] TIMER_LIMIT = 19'd262140;
`endif
reg [19:0] timer;
wire timer_clr;
wire timer_fin;
// latching inputs from gtx
reg rxcominitdet;
reg rxcomwakedet;
reg rxelecidle;
reg [DATA_BYTE_WIDTH*8 - 1:0] rxdata;
reg [DATA_BYTE_WIDTH - 1:0] rxcharisk;
// primitives detection
wire detected_alignp;
wire detected_syncp;
// fsm, doc p265,266
wire state_idle;
reg state_wait_cominit;
reg state_wait_comwake;
reg state_wait_align;
reg state_wait_synp;
reg state_wait_linkup;
reg state_error;
wire set_wait_cominit;
wire set_wait_comwake;
wire set_wait_align;
wire set_wait_synp;
wire set_wait_linkup;
wire set_error;
wire clr_wait_cominit;
wire clr_wait_comwake;
wire clr_wait_align;
wire clr_wait_synp;
wire clr_wait_linkup;
wire clr_error;
assign state_idle = ~state_wait_cominit & ~state_wait_comwake & ~state_wait_align & ~state_wait_synp & ~state_wait_linkup & ~state_error;
always @ (posedge clk)
begin
state_wait_cominit <= (state_wait_cominit | set_wait_cominit) & ~clr_wait_cominit & ~rst;
state_wait_comwake <= (state_wait_comwake | set_wait_comwake) & ~clr_wait_comwake & ~rst;
state_wait_align <= (state_wait_align | set_wait_align ) & ~clr_wait_align & ~rst;
state_wait_synp <= (state_wait_synp | set_wait_synp ) & ~clr_wait_synp & ~rst;
state_wait_linkup <= (state_wait_linkup | set_wait_linkup ) & ~clr_wait_linkup & ~rst;
state_error <= (state_error | set_error ) & ~clr_error & ~rst;
end
assign set_wait_cominit = state_idle & oob_start & ~cominit_req;
assign set_wait_comwake = state_idle & cominit_req & cominit_allow | state_wait_cominit & rxcominitdet;
assign set_wait_align = state_wait_comwake & rxcomwakedet;
assign set_wait_synp = state_wait_align & detected_alignp;
assign set_wait_linkup = state_wait_synp & detected_syncp;
assign set_error = timer_fin & (state_wait_cominit | state_wait_comwake | state_wait_align | state_wait_synp);
assign clr_wait_cominit = set_wait_comwake | set_error;
assign clr_wait_comwake = set_wait_align | set_error;
assign clr_wait_align = set_wait_synp | set_error;
assign clr_wait_synp = set_wait_linkup | set_error;
assign clr_wait_linkup = state_wait_linkup; //TODO not so important, but still have to trace 3 back-to-back non alignp primitives
assign clr_error = state_error;
// waiting timeout timer
assign timer_fin = timer == TIMER_LIMIT;
assign timer_clr = set_error | state_error | state_idle;
always @ (posedge clk)
timer <= rst | timer_clr ? 20'h0 : timer + CLK_TO_TIMER_CONTRIB;
// something is wrong with speed grades if the host cannot lock to device's alignp stream
assign oob_incompatible = state_wait_align & set_error;
// oob sequence is done, everything is okay
assign oob_done = set_wait_linkup;
// noone responds to cominits
assign oob_silence = set_error & state_wait_cominit;
// other timeouts
assign oob_error = set_error & ~oob_silence & ~oob_incompatible;
// obvioud
assign oob_busy = ~state_idle;
// set gtx controls
reg txelecidle_r;
always @ (posedge clk)
txelecidle_r <= rst ? 1'b1 : clr_wait_cominit ? 1'b0 : set_wait_cominit ? 1'b1 : txelecidle_r;
assign txcominit = set_wait_cominit;
assign txcomwake = set_wait_comwake;
assign txelecidle = set_wait_cominit | txelecidle_r;
// indicate if link up condition was made
assign link_up = clr_wait_linkup;
// link goes down when line is idle
reg rxelecidle_r;
reg rxelecidle_rr;
always @ (posedge clk)
begin
rxelecidle_rr <= rxelecidle_r;
rxelecidle_r <= rxelecidle;
end
assign link_down = rxelecidle_rr;
// indicate that device is requesting for oob
reg cominit_req_r;
wire cominit_req_set;
assign cominit_req_set = state_idle & rxcominitdet;
always @ (posedge clk)
cominit_req_r <= (cominit_req_r | cominit_req_set) & ~(cominit_allow & cominit_req) & ~rst;
assign cominit_req = cominit_req_set | cominit_req_r;
// detect which primitives sends the device after comwake was done
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg detected_alignp_f;
always @ (posedge clk)
detected_alignp_f <= rst | ~state_wait_align ? 1'b0 :
~|(rxdata ^ {8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 2'b01); // {D10.2, K28.5}
assign detected_alignp = detected_alignp_f & ~|(rxdata ^ {8'b01111011, 8'b01001010}) & ~|(rxcharisk ^ 2'b00); // {D27.3, D10.2}
reg detected_syncp_f;
always @ (posedge clk)
detected_syncp_f <= rst | ~state_wait_synp ? 1'b0 :
~|(rxdata ^ {8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 2'b01); // {D21.4, K28.3}
assign detected_syncp = detected_syncp_f & ~|(rxdata ^ {8'b10110101, 8'b10110101}) & ~|(rxcharisk ^ 2'b00); // {D21.5, D21.5}
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign detected_alignp = ~|(rxdata ^ {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}) & ~|(rxcharisk ^ 4'h1); // {D27.3, D10.2, D10.2, K28.5}
assign detected_syncp = ~|(rxdata ^ {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}) & ~|(rxcharisk ^ 4'h1); // {D21.5, D21.5, D21.4, K28.3}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign detected_alignp = ~|(rxdata ^ {2{8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}}) & ~|(rxcharisk ^ 8'h11); // {D27.3, D10.2, D10.2, K28.5}
assign detected_syncp = ~|(rxdata ^ {2{8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100}}) & ~|(rxcharisk ^ 8'h11); // {D21.5, D21.5, D21.4, K28.3}
end
else
begin
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
end
endgenerate
// buf inputs from gtx
always @ (posedge clk)
begin
rxcominitdet <= rxcominitdet_in;
rxcomwakedet <= rxcomwakedet_in;
rxelecidle <= rxelecidle_in;
rxdata <= rxdata_in;
rxcharisk <= rxcharisk_in;
end
// set data outputs to upper levels
assign rxdata_out = rxdata;
assign rxcharisk_out = rxcharisk;
// as depicted @ doc, p264, figure 163, have to insert D10.2 and align primitives after
// getting comwake from device
reg [DATA_BYTE_WIDTH*8 - 1:0] txdata;
reg [DATA_BYTE_WIDTH - 1:0] txcharisk;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_d102;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_d102;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_align;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_align;
always @ (posedge clk)
begin
txdata <= state_wait_align ? txdata_d102 :
state_wait_synp ? txdata_align : txdata_in;
txcharisk <= state_wait_align ? txcharisk_d102 :
state_wait_synp ? txcharisk_align : txcharisk_in;
end
// Continious D10.2 primitive
assign txcharisk_d102 = {DATA_BYTE_WIDTH{1'b0}};
assign txdata_d102 = {DATA_BYTE_WIDTH{8'b01001010}};
// Align primitive: K28.5 + D10.2 + D10.2 + D27.3
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg align_odd;
always @ (posedge clk)
align_odd <= rst | ~state_wait_synp ? 1'b0 : ~align_odd;
assign txcharisk_align = align_odd ? 2'b01 : 2'b00;
assign txdata_align = align_odd ? {8'b01001010, 8'b10111100} : // {D10.2, K28.5}
{8'b01111011, 8'b01001010}; // {D27.3, D10.2}
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign txcharisk_align = 4'h1;
assign txdata_align = {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}; // {D27.3, D10.2, D10.2, K28.5}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign txcharisk_align = 8'h11;
assign txdata_align = {2{8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100}}; // 2x{D27.3, D10.2, D10.2, K28.5}
end
else
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
endgenerate
// set data outputs to gtx
assign txdata_out = txdata;
assign txcharisk_out = txcharisk;
*/
endmodule
/*******************************************************************************
* Module: sata_phy
* Date: 2015-07-11
* Author: Alexey
* Description: phy-level, including oob, clock generation and GTXE2
*
* Copyright (c) 2015 Elphel, Inc.
* sata_phy.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.
*
* sata_phy.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
//`include "oob_dev.v"
module sata_phy_dev #(
parameter DATA_BYTE_WIDTH = 4
)
(
// initial reset, resets PLL. After pll is locked, an internal sata reset is generated.
input wire extrst,
// sata clk, generated in pll as usrclk2
output wire clk,
output wire rst,
// state
output wire phy_ready,
// top-level ifaces
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in,
// to link layer
output wire [31:0] ll_data_out,
output wire [3:0] ll_charisk_out,
output wire [3:0] ll_err_out, // TODO!!!
// from link layer
input wire [31:0] ll_data_in,
input wire [3:0] ll_charisk_in,
input [4:0] serial_delay // delay output to check host alignment
);
wire [31:0] txdata;
wire [31:0] txdata_oob;
wire [3:0] txcharisk;
wire [3:0] txcharisk_oob;
wire [63:0] rxdata;
wire [63:0] rxdata_gtx;
wire [7:0] rxcharisk;
wire [7:0] rxcharisk_gtx;
wire [7:0] rxchariscomma;
wire [7:0] rxchariscomma_gtx;
wire [7:0] rxdisperr;
wire [7:0] rxdisperr_gtx;
wire [7:0] rxnotintable;
wire [7:0] rxnotintable_gtx;
//wire [31:0] rxdata_out;
//wire [31:0] txdata_in;
//wire [3:0] txcharisk_in;
//wire [3:0] rxcharisk_out;
wire rxcomwakedet;
wire rxcominitdet;
wire cplllock;
wire txcominit;
wire txcomwake;
wire rxreset;
wire rxelecidle;
wire txelecidle;
wire rxbyteisaligned;
wire txpcsreset_req;
wire recal_tx_done;
wire gtx_ready;
assign txdata = phy_ready ? ll_data_in : txdata_oob;
assign txcharisk = phy_ready ? ll_charisk_in : txcharisk_oob;
assign ll_err_out = 4'h0;
assign ll_charisk_out = rxcharisk[3:0];
assign ll_data_out = rxdata[31:0];
oob_dev oob_dev(
// sata clk = usrclk2
.clk (clk),
// reset oob
.rst (rst),
// gtx is ready = all resets are done
.gtx_ready (gtx_ready),
// oob responses
.rxcominitdet_in (rxcominitdet),
.rxcomwakedet_in (rxcomwakedet),
.rxelecidle_in (rxelecidle),
// oob issues
.txcominit (txcominit),
.txcomwake (txcomwake),
.txelecidle (txelecidle),
.txpcsreset_req (txpcsreset_req),
.recal_tx_done (recal_tx_done),
// output data stream to gtx
.txdata_out (txdata_oob),
.txcharisk_out (txcharisk_oob),
// input data from gtx
.rxdata_in (rxdata[31:0]),
.rxcharisk_in (rxcharisk[3:0]),
// shows if channel is ready
.link_up (phy_ready)
);
wire cplllockdetclk; // TODO
wire drpclk; // TODO
wire cpllreset;
wire gtrefclk;
wire rxresetdone;
wire txresetdone;
wire txpcsreset;
wire txreset;
wire txuserrdy;
wire rxuserrdy;
wire txusrclk;
wire txusrclk2;
wire rxusrclk;
wire rxusrclk2;
wire txp;
wire txn;
wire rxp;
wire rxn;
wire txoutclk;
wire txpmareset_done;
wire rxeyereset_done;
// tx reset sequence; waves @ ug476 p67
localparam TXPMARESET_TIME = 5'h1;
reg [2:0] txpmareset_cnt;
assign txpmareset_done = txpmareset_cnt == TXPMARESET_TIME;
always @ (posedge gtrefclk)
txpmareset_cnt <= txreset ? 3'h0 : txpmareset_done ? txpmareset_cnt : txpmareset_cnt + 1'b1;
// rx reset sequence; waves @ ug476 p77
localparam RXPMARESET_TIME = 5'h11;
localparam RXCDRPHRESET_TIME = 5'h1;
localparam RXCDRFREQRESET_TIME = 5'h1;
localparam RXDFELPMRESET_TIME = 7'hf;
localparam RXISCANRESET_TIME = 5'h1;
localparam RXEYERESET_TIME = 7'h0 + RXPMARESET_TIME + RXCDRPHRESET_TIME + RXCDRFREQRESET_TIME + RXDFELPMRESET_TIME + RXISCANRESET_TIME;
reg [6:0] rxeyereset_cnt;
assign rxeyereset_done = rxeyereset_cnt == RXEYERESET_TIME;
always @ (posedge gtrefclk)
rxeyereset_cnt <= rxreset ? 7'h0 : rxeyereset_done ? rxeyereset_cnt : rxeyereset_cnt + 1'b1;
/*
* Resets
*/
wire usrpll_locked;
assign cpllreset = extrst;
assign rxreset = ~cplllock | cpllreset;
assign txreset = ~cplllock | cpllreset;
assign rxuserrdy = usrpll_locked & cplllock & ~cpllreset & ~rxreset & rxeyereset_done;
assign txuserrdy = usrpll_locked & cplllock & ~cpllreset & ~txreset & txpmareset_done;
assign gtx_ready = rxuserrdy & txuserrdy & rxresetdone & txresetdone;
// issue partial tx reset to restore functionality after oob sequence. Let it lasts 8 clock lycles
reg [3:0] txpcsreset_cnt;
wire txpcsreset_stop;
assign txpcsreset_stop = txpcsreset_cnt[3];
assign txpcsreset = txpcsreset_req & ~txpcsreset_stop;
assign recal_tx_done = txpcsreset_stop & gtx_ready;
always @ (posedge clk or posedge extrst)
txpcsreset_cnt <= extrst | rst | ~txpcsreset_req ? 4'h0 : txpcsreset_stop ? txpcsreset_cnt : txpcsreset_cnt + 1'b1;
// generate internal reset after a clock is established
// !!!ATTENTION!!!
// async rst block
reg [7:0] rst_timer;
reg rst_r;
localparam [7:0] RST_TIMER_LIMIT = 8'b1000;
always @ (posedge clk or posedge extrst)
rst_timer <= extrst | ~cplllock | ~usrpll_locked ? 8'h0 : rst_timer == RST_TIMER_LIMIT ? rst_timer : rst_timer + 1'b1;
assign rst = rst_r;
always @ (posedge clk or posedge extrst)
rst_r <= extrst | ~|rst_timer ? 1'b0 : rst_timer[3] ? 1'b0 : 1'b1;
/*
* USRCLKs generation. USRCLK @ 150MHz, same as TXOUTCLK; USRCLK2 @ 75Mhz -> sata_clk === sclk
* It's recommended to use MMCM instead of PLL, whatever
*/
wire usrpll_fb_clk;
wire usrclk;
wire usrclk2;
assign txusrclk = usrclk;
assign txusrclk2 = usrclk2;
assign rxusrclk = usrclk;
assign rxusrclk2 = usrclk2;
PLLE2_ADV #(
.BANDWIDTH ("OPTIMIZED"),
.CLKFBOUT_MULT (8),
.CLKFBOUT_PHASE (0.000),
.CLKIN1_PERIOD (6.666),
.CLKIN2_PERIOD (0.000),
.CLKOUT0_DIVIDE (8),
.CLKOUT0_DUTY_CYCLE (0.500),
.CLKOUT0_PHASE (0.000),
.CLKOUT1_DIVIDE (16),
.CLKOUT1_DUTY_CYCLE (0.500),
.CLKOUT1_PHASE (0.000),
/* .CLKOUT2_DIVIDE = 1,
.CLKOUT2_DUTY_CYCLE = 0.500,
.CLKOUT2_PHASE = 0.000,
.CLKOUT3_DIVIDE = 1,
.CLKOUT3_DUTY_CYCLE = 0.500,
.CLKOUT3_PHASE = 0.000,
.CLKOUT4_DIVIDE = 1,
.CLKOUT4_DUTY_CYCLE = 0.500,
.CLKOUT4_PHASE = 0.000,
.CLKOUT5_DIVIDE = 1,
.CLKOUT5_DUTY_CYCLE = 0.500,
.CLKOUT5_PHASE = 0.000,*/
.COMPENSATION ("ZHOLD"),
.DIVCLK_DIVIDE (1),
.IS_CLKINSEL_INVERTED (1'b0),
.IS_PWRDWN_INVERTED (1'b0),
.IS_RST_INVERTED (1'b0),
.REF_JITTER1 (0.010),
.REF_JITTER2 (0.010),
.STARTUP_WAIT ("FALSE")
)
usrclk_pll(
.CLKFBOUT (usrpll_fb_clk),
.CLKOUT0 (usrclk),
.CLKOUT1 (usrclk2),
.CLKOUT2 (),
.CLKOUT3 (),
.CLKOUT4 (),
.CLKOUT5 (),
.DO (),
.DRDY (),
.LOCKED (usrpll_locked),
.CLKFBIN (usrpll_fb_clk),
.CLKIN1 (txoutclk),
.CLKIN2 (1'b0),
.CLKINSEL (1'b1),
.DADDR (7'h0),
.DCLK (drpclk),
.DEN (1'b0),
.DI (16'h0),
.DWE (1'b0),
.PWRDWN (1'b0),
.RST (~cplllock)
);
/*
* Padding for an external input clock @ 150 MHz
*/
localparam [1:0] CLKSWING_CFG = 2'b11;
IBUFDS_GTE2 #(
.CLKRCV_TRST ("TRUE"),
.CLKCM_CFG ("TRUE"),
.CLKSWING_CFG (CLKSWING_CFG)
)
ext_clock_buf(
.I (extclk_p),
.IB (extclk_n),
.CEB (1'b0),
.O (gtrefclk),
.ODIV2 ()
);
gtxe2_channel_wrapper #(
.SIM_RECEIVER_DETECT_PASS ("TRUE"),
.SIM_TX_EIDLE_DRIVE_LEVEL ("X"),
.SIM_RESET_SPEEDUP ("FALSE"),
.SIM_CPLLREFCLK_SEL (3'b001),
.SIM_VERSION ("4.0"),
.ALIGN_COMMA_DOUBLE ("FALSE"),
.ALIGN_COMMA_ENABLE (10'b1111111111),
.ALIGN_COMMA_WORD (1),
.ALIGN_MCOMMA_DET ("TRUE"),
.ALIGN_MCOMMA_VALUE (10'b1010000011),
.ALIGN_PCOMMA_DET ("TRUE"),
.ALIGN_PCOMMA_VALUE (10'b0101111100),
.SHOW_REALIGN_COMMA ("TRUE"),
.RXSLIDE_AUTO_WAIT (7),
.RXSLIDE_MODE ("OFF"),
.RX_SIG_VALID_DLY (10),
.RX_DISPERR_SEQ_MATCH ("TRUE"),
.DEC_MCOMMA_DETECT ("TRUE"),
.DEC_PCOMMA_DETECT ("TRUE"),
.DEC_VALID_COMMA_ONLY ("FALSE"),
.CBCC_DATA_SOURCE_SEL ("DECODED"),
.CLK_COR_SEQ_2_USE ("FALSE"),
.CLK_COR_KEEP_IDLE ("FALSE"),
.CLK_COR_MAX_LAT (9),
.CLK_COR_MIN_LAT (7),
.CLK_COR_PRECEDENCE ("TRUE"),
.CLK_COR_REPEAT_WAIT (0),
.CLK_COR_SEQ_LEN (1),
.CLK_COR_SEQ_1_ENABLE (4'b1111),
.CLK_COR_SEQ_1_1 (10'b0100000000),
.CLK_COR_SEQ_1_2 (10'b0000000000),
.CLK_COR_SEQ_1_3 (10'b0000000000),
.CLK_COR_SEQ_1_4 (10'b0000000000),
.CLK_CORRECT_USE ("FALSE"),
.CLK_COR_SEQ_2_ENABLE (4'b1111),
.CLK_COR_SEQ_2_1 (10'b0100000000),
.CLK_COR_SEQ_2_2 (10'b0000000000),
.CLK_COR_SEQ_2_3 (10'b0000000000),
.CLK_COR_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_KEEP_ALIGN ("FALSE"),
.CHAN_BOND_MAX_SKEW (1),
.CHAN_BOND_SEQ_LEN (1),
.CHAN_BOND_SEQ_1_1 (10'b0000000000),
.CHAN_BOND_SEQ_1_2 (10'b0000000000),
.CHAN_BOND_SEQ_1_3 (10'b0000000000),
.CHAN_BOND_SEQ_1_4 (10'b0000000000),
.CHAN_BOND_SEQ_1_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_1 (10'b0000000000),
.CHAN_BOND_SEQ_2_2 (10'b0000000000),
.CHAN_BOND_SEQ_2_3 (10'b0000000000),
.CHAN_BOND_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_SEQ_2_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_USE ("FALSE"),
.FTS_DESKEW_SEQ_ENABLE (4'b1111),
.FTS_LANE_DESKEW_CFG (4'b1111),
.FTS_LANE_DESKEW_EN ("FALSE"),
.ES_CONTROL (6'b000000),
.ES_ERRDET_EN ("FALSE"),
.ES_EYE_SCAN_EN ("TRUE"),
.ES_HORZ_OFFSET (12'h000),
.ES_PMA_CFG (10'b0000000000),
.ES_PRESCALE (5'b00000),
.ES_QUALIFIER (80'h00000000000000000000),
.ES_QUAL_MASK (80'h00000000000000000000),
.ES_SDATA_MASK (80'h00000000000000000000),
.ES_VERT_OFFSET (9'b000000000),
.RX_DATA_WIDTH (40),
.OUTREFCLK_SEL_INV (2'b11),
.PMA_RSV (32'h00018480),
.PMA_RSV2 (16'h2050),
.PMA_RSV3 (2'b00),
.PMA_RSV4 (32'h00000000),
.RX_BIAS_CFG (12'b000000000100),
.DMONITOR_CFG (24'h000A00),
.RX_CM_SEL (2'b11),
.RX_CM_TRIM (3'b010),
.RX_DEBUG_CFG (12'b000000000000),
.RX_OS_CFG (13'b0000010000000),
.TERM_RCAL_CFG (5'b10000),
.TERM_RCAL_OVRD (1'b0),
.TST_RSV (32'h00000000),
.RX_CLK25_DIV (6),
.TX_CLK25_DIV (6),
.UCODEER_CLR (1'b0),
.PCS_PCIE_EN ("FALSE"),
.PCS_RSVD_ATTR (48'h0100),
.RXBUF_ADDR_MODE ("FAST"),
.RXBUF_EIDLE_HI_CNT (4'b1000),
.RXBUF_EIDLE_LO_CNT (4'b0000),
.RXBUF_EN ("TRUE"),
.RX_BUFFER_CFG (6'b000000),
.RXBUF_RESET_ON_CB_CHANGE ("TRUE"),
.RXBUF_RESET_ON_COMMAALIGN ("FALSE"),
.RXBUF_RESET_ON_EIDLE ("FALSE"),
.RXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.RXBUFRESET_TIME (5'b00001),
.RXBUF_THRESH_OVFLW (61),
.RXBUF_THRESH_OVRD ("FALSE"),
.RXBUF_THRESH_UNDFLW (4),
.RXDLY_CFG (16'h001F),
.RXDLY_LCFG (9'h030),
.RXDLY_TAP_CFG (16'h0000),
.RXPH_CFG (24'h000000),
.RXPHDLY_CFG (24'h084020),
.RXPH_MONITOR_SEL (5'b00000),
.RX_XCLK_SEL ("RXREC"),
.RX_DDI_SEL (6'b000000),
.RX_DEFER_RESET_BUF_EN ("TRUE"),
.RXCDR_CFG (72'h03000023ff10200020),
.RXCDR_FR_RESET_ON_EIDLE (1'b0),
.RXCDR_HOLD_DURING_EIDLE (1'b0),
.RXCDR_PH_RESET_ON_EIDLE (1'b0),
.RXCDR_LOCK_CFG (6'b010101),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXPCSRESET_TIME (5'b00001),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXOOB_CFG (7'b0000110),
.RXGEARBOX_EN ("FALSE"),
.GEARBOX_MODE (3'b000),
.RXPRBS_ERR_LOOPBACK (1'b0),
.PD_TRANS_TIME_FROM_P2 (12'h03c),
.PD_TRANS_TIME_NONE_P2 (8'h3c),
.PD_TRANS_TIME_TO_P2 (8'h64),
.SAS_MAX_COM (64),
.SAS_MIN_COM (36),
.SATA_BURST_SEQ_LEN (4'b0111),
.SATA_BURST_VAL (3'b110),
.SATA_EIDLE_VAL (3'b110),
.SATA_MAX_BURST (8),
.SATA_MAX_INIT (21),
.SATA_MAX_WAKE (7),
.SATA_MIN_BURST (4),
.SATA_MIN_INIT (12),
.SATA_MIN_WAKE (4),
.TRANS_TIME_RATE (8'h0E),
.TXBUF_EN ("TRUE"),
.TXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.TXDLY_CFG (16'h001F),
.TXDLY_LCFG (9'h030),
.TXDLY_TAP_CFG (16'h0000),
.TXPH_CFG (16'h0780),
.TXPHDLY_CFG (24'h084020),
.TXPH_MONITOR_SEL (5'b00000),
.TX_XCLK_SEL ("TXOUT"),
.TX_DATA_WIDTH (40),
.TX_DEEMPH0 (5'b00000),
.TX_DEEMPH1 (5'b00000),
.TX_EIDLE_ASSERT_DELAY (3'b110),
.TX_EIDLE_DEASSERT_DELAY (3'b100),
.TX_LOOPBACK_DRIVE_HIZ ("FALSE"),
.TX_MAINCURSOR_SEL (1'b0),
.TX_DRIVE_MODE ("DIRECT"),
.TX_MARGIN_FULL_0 (7'b1001110),
.TX_MARGIN_FULL_1 (7'b1001001),
.TX_MARGIN_FULL_2 (7'b1000101),
.TX_MARGIN_FULL_3 (7'b1000010),
.TX_MARGIN_FULL_4 (7'b1000000),
.TX_MARGIN_LOW_0 (7'b1000110),
.TX_MARGIN_LOW_1 (7'b1000100),
.TX_MARGIN_LOW_2 (7'b1000010),
.TX_MARGIN_LOW_3 (7'b1000000),
.TX_MARGIN_LOW_4 (7'b1000000),
.TXGEARBOX_EN ("FALSE"),
.TXPCSRESET_TIME (5'b00001),
.TXPMARESET_TIME (TXPMARESET_TIME),
.TX_RXDETECT_CFG (14'h1832),
.TX_RXDETECT_REF (3'b100),
.CPLL_CFG (24'hBC07DC),
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_INIT_CFG (24'h00001E),
.CPLL_LOCK_CFG (16'h01E8),
.CPLL_REFCLK_DIV (1),
.RXOUT_DIV (2),
.TXOUT_DIV (2),
.SATA_CPLL_CFG ("VCO_3000MHZ"),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXLPM_HF_CFG (14'b00000011110000),
.RXLPM_LF_CFG (14'b00000011110000),
.RX_DFE_GAIN_CFG (23'h020FEA),
.RX_DFE_H2_CFG (12'b000000000000),
.RX_DFE_H3_CFG (12'b000001000000),
.RX_DFE_H4_CFG (11'b00011110000),
.RX_DFE_H5_CFG (11'b00011100000),
.RX_DFE_KL_CFG (13'b0000011111110),
.RX_DFE_LPM_CFG (16'h0954),
.RX_DFE_LPM_HOLD_DURING_EIDLE (1'b0),
.RX_DFE_UT_CFG (17'b10001111000000000),
.RX_DFE_VP_CFG (17'b00011111100000011),
.RX_CLKMUX_PD (1'b1),
.TX_CLKMUX_PD (1'b1),
.RX_INT_DATAWIDTH (0),
.TX_INT_DATAWIDTH (0),
.TX_QPI_STATUS_EN (1'b0),
.RX_DFE_KL_CFG2 (32'h301148AC),
.RX_DFE_XYD_CFG (13'b0000000000000),
.TX_PREDRIVER_MODE (1'b0)
)
gtx_wrapper(
.CPLLFBCLKLOST (),
.CPLLLOCK (cplllock),
.CPLLLOCKDETCLK (cplllockdetclk),
.CPLLLOCKEN (1'b1),
.CPLLPD (1'b0),
.CPLLREFCLKLOST (),
.CPLLREFCLKSEL (3'b001),
.CPLLRESET (cpllreset),
.GTRSVD (16'b0),
.PCSRSVDIN (16'b0),
.PCSRSVDIN2 (5'b0),
.PMARSVDIN (5'b0),
.PMARSVDIN2 (5'b0),
.TSTIN (20'b1),
.TSTOUT (),
.CLKRSVD (4'b0000),
.GTGREFCLK (1'b0),
.GTNORTHREFCLK0 (1'b0),
.GTNORTHREFCLK1 (1'b0),
.GTREFCLK0 (gtrefclk),
.GTREFCLK1 (1'b0),
.GTSOUTHREFCLK0 (1'b0),
.GTSOUTHREFCLK1 (1'b0),
.DRPADDR (9'b0),
.DRPCLK (drpclk),
.DRPDI (16'b0),
.DRPDO (),
.DRPEN (1'b0),
.DRPRDY (),
.DRPWE (1'b0),
.GTREFCLKMONITOR (),
.QPLLCLK (gtrefclk),
.QPLLREFCLK (gtrefclk),
.RXSYSCLKSEL (2'b00),
.TXSYSCLKSEL (2'b00),
.DMONITOROUT (),
.TX8B10BEN (1'b1),
.LOOPBACK (3'd0),
.PHYSTATUS (),
.RXRATE (3'd0),
.RXVALID (),
.RXPD (2'b00),
.TXPD (2'b00),
.SETERRSTATUS (1'b0),
.EYESCANRESET (1'b0),//rxreset), // p78
.RXUSERRDY (rxuserrdy),
.EYESCANDATAERROR (),
.EYESCANMODE (1'b0),
.EYESCANTRIGGER (1'b0),
.RXCDRFREQRESET (1'b0),
.RXCDRHOLD (1'b0),
.RXCDRLOCK (),
.RXCDROVRDEN (1'b0),
.RXCDRRESET (1'b0),
.RXCDRRESETRSV (1'b0),
.RXCLKCORCNT (),
.RX8B10BEN (1'b1),
.RXUSRCLK (rxusrclk),
.RXUSRCLK2 (rxusrclk2),
.RXDATA (rxdata_gtx),
.RXPRBSERR (),
.RXPRBSSEL (3'd0),
.RXPRBSCNTRESET (1'b0),
.RXDFEXYDEN (1'b1),
.RXDFEXYDHOLD (1'b0),
.RXDFEXYDOVRDEN (1'b0),
.RXDISPERR (rxdisperr_gtx),
.RXNOTINTABLE (rxnotintable_gtx),
.GTXRXP (rxp),
.GTXRXN (rxn),
.RXBUFRESET (1'b0),
.RXBUFSTATUS (),
.RXDDIEN (1'b0),
.RXDLYBYPASS (1'b1),
.RXDLYEN (1'b0),
.RXDLYOVRDEN (1'b0),
.RXDLYSRESET (1'b0),
.RXDLYSRESETDONE (),
.RXPHALIGN (1'b0),
.RXPHALIGNDONE (),
.RXPHALIGNEN (1'b0),
.RXPHDLYPD (1'b0),
.RXPHDLYRESET (1'b0),
.RXPHMONITOR (),
.RXPHOVRDEN (1'b0),
.RXPHSLIPMONITOR (),
.RXSTATUS (),
.RXBYTEISALIGNED (rxbyteisaligned),
.RXBYTEREALIGN (),
.RXCOMMADET (),
.RXCOMMADETEN (1'b1),
.RXMCOMMAALIGNEN (1'b1),
.RXPCOMMAALIGNEN (1'b1),
.RXCHANBONDSEQ (),
.RXCHBONDEN (1'b0),
.RXCHBONDLEVEL (3'd0),
.RXCHBONDMASTER (1'b0),
.RXCHBONDO (),
.RXCHBONDSLAVE (1'b0),
.RXCHANISALIGNED (),
.RXCHANREALIGN (),
.RXLPMHFHOLD (1'b0),
.RXLPMHFOVRDEN (1'b0),
.RXLPMLFHOLD (1'b0),
.RXDFEAGCHOLD (1'b0),
.RXDFEAGCOVRDEN (1'b0),
.RXDFECM1EN (1'b0),
.RXDFELFHOLD (1'b0),
.RXDFELFOVRDEN (1'b1),
.RXDFELPMRESET (rxreset),
.RXDFETAP2HOLD (1'b0),
.RXDFETAP2OVRDEN (1'b0),
.RXDFETAP3HOLD (1'b0),
.RXDFETAP3OVRDEN (1'b0),
.RXDFETAP4HOLD (1'b0),
.RXDFETAP4OVRDEN (1'b0),
.RXDFETAP5HOLD (1'b0),
.RXDFETAP5OVRDEN (1'b0),
.RXDFEUTHOLD (1'b0),
.RXDFEUTOVRDEN (1'b0),
.RXDFEVPHOLD (1'b0),
.RXDFEVPOVRDEN (1'b0),
// .RXDFEVSEN (1'b0),
.RXLPMLFKLOVRDEN (1'b0),
.RXMONITOROUT (),
.RXMONITORSEL (2'b01),
.RXOSHOLD (1'b0),
.RXOSOVRDEN (1'b0),
.RXRATEDONE (),
.RXOUTCLK (),
.RXOUTCLKFABRIC (),
.RXOUTCLKPCS (),
.RXOUTCLKSEL (3'b010),
.RXDATAVALID (),
.RXHEADER (),
.RXHEADERVALID (),
.RXSTARTOFSEQ (),
.RXGEARBOXSLIP (1'b0),
.GTRXRESET (rxreset),
.RXOOBRESET (1'b0),
.RXPCSRESET (1'b0),
.RXPMARESET (1'b0),//rxreset), // p78
.RXLPMEN (1'b0),
.RXCOMSASDET (),
.RXCOMWAKEDET (rxcomwakedet),
.RXCOMINITDET (rxcominitdet),
.RXELECIDLE (rxelecidle),
.RXELECIDLEMODE (2'b00),
.RXPOLARITY (1'b0),
.RXSLIDE (1'b0),
.RXCHARISCOMMA (rxchariscomma_gtx),
.RXCHARISK (rxcharisk_gtx),
.RXCHBONDI (5'b00000),
.RXRESETDONE (rxresetdone),
.RXQPIEN (1'b0),
.RXQPISENN (),
.RXQPISENP (),
.TXPHDLYTSTCLK (1'b0),
.TXPOSTCURSOR (5'b00000),
.TXPOSTCURSORINV (1'b0),
.TXPRECURSOR (5'd0),
.TXPRECURSORINV (1'b0),
.TXQPIBIASEN (1'b0),
.TXQPISTRONGPDOWN (1'b0),
.TXQPIWEAKPUP (1'b0),
.CFGRESET (1'b0),
.GTTXRESET (txreset),
.PCSRSVDOUT (),
.TXUSERRDY (txuserrdy),
.GTRESETSEL (1'b0),
.RESETOVRD (1'b0),
.TXCHARDISPMODE (8'd0),
.TXCHARDISPVAL (8'd0),
.TXUSRCLK (txusrclk),
.TXUSRCLK2 (txusrclk2),
.TXELECIDLE (txelecidle),
.TXMARGIN (3'd0),
.TXRATE (3'd0),
.TXSWING (1'b0),
.TXPRBSFORCEERR (1'b0),
.TXDLYBYPASS (1'b1),
.TXDLYEN (1'b0),
.TXDLYHOLD (1'b0),
.TXDLYOVRDEN (1'b0),
.TXDLYSRESET (1'b0),
.TXDLYSRESETDONE (),
.TXDLYUPDOWN (1'b0),
.TXPHALIGN (1'b0),
.TXPHALIGNDONE (),
.TXPHALIGNEN (1'b0),
.TXPHDLYPD (1'b0),
.TXPHDLYRESET (1'b0),
.TXPHINIT (1'b0),
.TXPHINITDONE (),
.TXPHOVRDEN (1'b0),
.TXBUFSTATUS (),
.TXBUFDIFFCTRL (3'b100),
.TXDEEMPH (1'b0),
.TXDIFFCTRL (4'b1000),
.TXDIFFPD (1'b0),
.TXINHIBIT (1'b0),
.TXMAINCURSOR (7'b0000000),
.TXPISOPD (1'b0),
.TXDATA ({32'h0, txdata}),
.GTXTXN (txn),
.GTXTXP (txp),
.TXOUTCLK (txoutclk),
.TXOUTCLKFABRIC (),
.TXOUTCLKPCS (),
.TXOUTCLKSEL (3'b010),
.TXRATEDONE (),
.TXCHARISK ({4'b0, txcharisk}),
.TXGEARBOXREADY (),
.TXHEADER (3'd0),
.TXSEQUENCE (7'd0),
.TXSTARTSEQ (1'b0),
.TXPCSRESET (txpcsreset),
.TXPMARESET (1'b0),
.TXRESETDONE (txresetdone),
.TXCOMFINISH (),
.TXCOMINIT (txcominit),
.TXCOMSAS (1'b0),
.TXCOMWAKE (txcomwake),
.TXPDELECIDLEMODE (1'b0),
.TXPOLARITY (1'b0),
.TXDETECTRX (1'b0),
.TX8B10BBYPASS (8'd0),
.TXPRBSSEL (3'd0),
.TXQPISENN (),
.TXQPISENP ()/*,
.TXSYNCMODE (1'b0),
.TXSYNCALLIN (1'b0),
.TXSYNCIN (1'b0)*/
);
// Serial data bit shift to check host alignment
wire tx_serial_clk=gtx_wrapper.gtx_gpl.channel.tx_serial_clk;
//reg [4:0] serial_delay = 0;
reg [31:0] txp_r;
reg [31:0] txn_r;
always @(posedge tx_serial_clk) begin
txp_r = {txp_r[30:0],txp};
txn_r = {txn_r[30:0],txn};
end
// align to 4-byte boundary
reg twobytes_shift;
always @ (posedge clk)
twobytes_shift <= rst ? 1'b0 : rxchariscomma_gtx[0] === 1'bx ? 1'b0 : rxchariscomma_gtx[2] === 1'bx ? 1'b0 : rxchariscomma_gtx[2] ? 1'b1 : rxchariscomma_gtx[0] ? 1'b0 : twobytes_shift;
assign rxdata = twobytes_shift ? {rxdata_gtx[63:32] , rxdata_gtx[15:0] , rxdata_gtx[31:16] } : rxdata_gtx;
assign rxcharisk = twobytes_shift ? {rxcharisk_gtx[7:4] , rxcharisk_gtx[1:0] , rxcharisk_gtx[3:2] } : rxcharisk_gtx;
assign rxchariscomma = twobytes_shift ? {rxchariscomma_gtx[7:4], rxchariscomma_gtx[1:0], rxchariscomma_gtx[3:2]} : rxchariscomma_gtx;
assign rxdisperr = twobytes_shift ? {rxdisperr_gtx[7:4] , rxdisperr_gtx[1:0] , rxdisperr_gtx[3:2] } : rxdisperr_gtx;
assign rxnotintable = twobytes_shift ? {rxnotintable_gtx[7:4] , rxnotintable_gtx[1:0] , rxnotintable_gtx[3:2] } : rxnotintable_gtx;
assign ll_err_out = rxdisperr[3:0] | rxnotintable[3:0];
/*
* Interfaces
*/
assign cplllockdetclk = gtrefclk; //TODO
assign drpclk = gtrefclk;
assign clk = usrclk2;
assign rxn = rxn_in;
assign rxp = rxp_in;
///assign txn_out = txn;
///assign txp_out = txp;
assign txn_out = txn_r[serial_delay];
assign txp_out = txp_r[serial_delay];
//assign ll_data_out = rxdata_out;
//assign ll_charisk_out = rxcharisk_out;
//assign txdata_in = ll_data_in;
//assign txcharisk_in = ll_charisk_in;
endmodule
/*******************************************************************************
* Module: action_decoder
* Date:2016-03-12
* Author: auto-generated file, see ahci_fsm_sequence_old.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_INF,
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 SCTL_DET_CLEAR,
output reg HBA_RST_DONE,
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_DWCR,
output reg DECR_DWCW,
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 EN_COMINIT,
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[ 1] && data[ 0];
SIRQ_DHR <= enable && data[ 2] && data[ 0];
SIRQ_DP <= enable && data[ 3] && data[ 0];
SIRQ_DS <= enable && data[ 4] && data[ 0];
SIRQ_IF <= enable && data[ 5] && data[ 0];
SIRQ_INF <= 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];
SCTL_DET_CLEAR <= enable && data[ 8] && data[ 1];
HBA_RST_DONE <= enable && data[ 9] && data[ 1];
SET_UPDATE_SIG <= enable && data[10] && data[ 1];
UPDATE_SIG <= enable && data[ 3] && data[ 2];
UPDATE_ERR_STS <= enable && data[ 4] && data[ 2];
UPDATE_PIO <= enable && data[ 5] && data[ 2];
UPDATE_PRDBC <= enable && data[ 6] && data[ 2];
CLEAR_BSY_DRQ <= enable && data[ 7] && data[ 2];
CLEAR_BSY_SET_DRQ <= enable && data[ 8] && data[ 2];
SET_BSY <= enable && data[ 9] && data[ 2];
SET_STS_7F <= enable && data[10] && data[ 2];
SET_STS_80 <= enable && data[ 4] && data[ 3];
XFER_CNTR_CLEAR <= enable && data[ 5] && data[ 3];
DECR_DWCR <= enable && data[ 6] && data[ 3];
DECR_DWCW <= enable && data[ 7] && data[ 3];
FIS_FIRST_FLUSH <= enable && data[ 8] && data[ 3];
CLEAR_CMD_TO_ISSUE <= enable && data[ 9] && data[ 3];
DMA_ABORT <= enable && data[10] && data[ 3];
DMA_PRD_IRQ_CLEAR <= enable && data[ 5] && data[ 4];
XMIT_COMRESET <= enable && data[ 6] && data[ 4];
SEND_SYNC_ESC <= enable && data[ 7] && data[ 4];
SET_OFFLINE <= enable && data[ 8] && data[ 4];
R_OK <= enable && data[ 9] && data[ 4];
R_ERR <= enable && data[10] && data[ 4];
EN_COMINIT <= enable && data[ 6] && data[ 5];
FETCH_CMD <= enable && data[ 7] && data[ 5];
ATAPI_XMIT <= enable && data[ 8] && data[ 5];
CFIS_XMIT <= enable && data[ 9] && data[ 5];
DX_XMIT <= enable && data[10] && data[ 5];
GET_DATA_FIS <= enable && data[ 7] && data[ 6];
GET_DSFIS <= enable && data[ 8] && data[ 6];
GET_IGNORE <= enable && data[ 9] && data[ 6];
GET_PSFIS <= enable && data[10] && data[ 6];
GET_RFIS <= enable && data[ 8] && data[ 7];
GET_SDBFIS <= enable && data[ 9] && data[ 7];
GET_UFIS <= enable && data[10] && data[ 7];
end
endmodule
/*******************************************************************************
* Module: condition_mux
* Date:2016-03-12
* Author: auto-generated file, see ahci_fsm_sequence_old.py
* Description: Select condition
*******************************************************************************/
`timescale 1ns/1ps
module condition_mux (
input clk,
input ce, // enable recording all conditions
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 [44:0] masked;
reg [43:0] registered;
reg [ 5:0] cond_r;
assign condition = |cond_r;
assign masked[ 0] = registered[ 0] && sel[ 2] && sel[ 1] && sel[ 0];
assign masked[ 1] = registered[ 1] && sel[ 3] && sel[ 1] && sel[ 0];
assign masked[ 2] = registered[ 2] && sel[ 4] && sel[ 1] && sel[ 0];
assign masked[ 3] = registered[ 3] && sel[ 5] && sel[ 1] && sel[ 0];
assign masked[ 4] = registered[ 4] && sel[ 6] && sel[ 1] && sel[ 0];
assign masked[ 5] = registered[ 5] && sel[ 7] && sel[ 1] && sel[ 0];
assign masked[ 6] = registered[ 6] && sel[ 3] && sel[ 2] && sel[ 0];
assign masked[ 7] = registered[ 7] && sel[ 4] && sel[ 2] && sel[ 0];
assign masked[ 8] = registered[ 8] && sel[ 5] && sel[ 2] && sel[ 0];
assign masked[ 9] = registered[ 9] && sel[ 6] && sel[ 2] && sel[ 0];
assign masked[10] = registered[10] && sel[ 7] && sel[ 2] && sel[ 0];
assign masked[11] = registered[11] && sel[ 4] && sel[ 3] && sel[ 0];
assign masked[12] = registered[12] && sel[ 5] && sel[ 3] && sel[ 0];
assign masked[13] = registered[13] && sel[ 6] && sel[ 3] && sel[ 0];
assign masked[14] = registered[14] && sel[ 7] && sel[ 3] && sel[ 0];
assign masked[15] = registered[15] && sel[ 5] && sel[ 4] && sel[ 0];
assign masked[16] = registered[16] && sel[ 6] && sel[ 4] && sel[ 0];
assign masked[17] = registered[17] && sel[ 7] && sel[ 4] && sel[ 0];
assign masked[18] = registered[18] && sel[ 6] && sel[ 5] && sel[ 0];
assign masked[19] = registered[19] && sel[ 7] && sel[ 5] && sel[ 0];
assign masked[20] = registered[20] && sel[ 7] && sel[ 6] && sel[ 0];
assign masked[21] = registered[21] && sel[ 3] && sel[ 2] && sel[ 1];
assign masked[22] = registered[22] && sel[ 4] && sel[ 2] && sel[ 1];
assign masked[23] = registered[23] && sel[ 5] && sel[ 2] && sel[ 1];
assign masked[24] = registered[24] && sel[ 6] && sel[ 2] && sel[ 1];
assign masked[25] = registered[25] && sel[ 7] && sel[ 2] && sel[ 1];
assign masked[26] = registered[26] && sel[ 4] && sel[ 3] && sel[ 1];
assign masked[27] = registered[27] && sel[ 5] && sel[ 3] && sel[ 1];
assign masked[28] = registered[28] && sel[ 6] && sel[ 3] && sel[ 1];
assign masked[29] = registered[29] && sel[ 7] && sel[ 3] && sel[ 1];
assign masked[30] = registered[30] && sel[ 5] && sel[ 4] && sel[ 1];
assign masked[31] = registered[31] && sel[ 6] && sel[ 4] && sel[ 1];
assign masked[32] = registered[32] && sel[ 7] && sel[ 4] && sel[ 1];
assign masked[33] = registered[33] && sel[ 6] && sel[ 5] && sel[ 1];
assign masked[34] = registered[34] && sel[ 7] && sel[ 5] && sel[ 1];
assign masked[35] = registered[35] && sel[ 7] && sel[ 6] && sel[ 1];
assign masked[36] = registered[36] && sel[ 4] && sel[ 3] && sel[ 2];
assign masked[37] = registered[37] && sel[ 5] && sel[ 3] && sel[ 2];
assign masked[38] = registered[38] && sel[ 6] && sel[ 3] && sel[ 2];
assign masked[39] = registered[39] && sel[ 7] && sel[ 3] && sel[ 2];
assign masked[40] = registered[40] && sel[ 5] && sel[ 4] && sel[ 2];
assign masked[41] = registered[41] && sel[ 6] && sel[ 4] && sel[ 2];
assign masked[42] = registered[42] && sel[ 7] && sel[ 4] && sel[ 2];
assign masked[43] = registered[43] && sel[ 6] && sel[ 5] && sel[ 2];
assign masked[44] = !(|sel); // always TRUE condition (sel ==0)
always @(posedge clk) begin
if (ce) begin
registered[ 0] <= ST_NB_ND;
registered[ 1] <= PXCI0_NOT_CMDTOISSUE;
registered[ 2] <= PCTI_CTBAR_XCZ;
registered[ 3] <= PCTI_XCZ;
registered[ 4] <= NST_D2HR;
registered[ 5] <= NPD_NCA;
registered[ 6] <= CHW_DMAA;
registered[ 7] <= SCTL_DET_CHANGED_TO_4;
registered[ 8] <= SCTL_DET_CHANGED_TO_1;
registered[ 9] <= PXSSTS_DET_NE_3;
registered[10] <= PXSSTS_DET_EQ_1;
registered[11] <= NPCMD_FRE;
registered[12] <= FIS_OK;
registered[13] <= FIS_ERR;
registered[14] <= FIS_FERR;
registered[15] <= FIS_EXTRA;
registered[16] <= FIS_FIRST_INVALID;
registered[17] <= FR_D2HR;
registered[18] <= FIS_DATA;
registered[19] <= FIS_ANY;
registered[20] <= NB_ND_D2HR_PIO;
registered[21] <= D2HR;
registered[22] <= SDB;
registered[23] <= DMA_ACT;
registered[24] <= DMA_SETUP;
registered[25] <= BIST_ACT_FE;
registered[26] <= BIST_ACT;
registered[27] <= PIO_SETUP;
registered[28] <= NB_ND;
registered[29] <= TFD_STS_ERR;
registered[30] <= FIS_I;
registered[31] <= PIO_I;
registered[32] <= NPD;
registered[33] <= PIOX;
registered[34] <= XFER0;
registered[35] <= PIOX_XFER0;
registered[36] <= CTBAA_CTBAP;
registered[37] <= CTBAP;
registered[38] <= CTBA_B;
registered[39] <= CTBA_C;
registered[40] <= TX_ERR;
registered[41] <= SYNCESC_ERR;
registered[42] <= DMA_PRD_IRQ_PEND;
registered[43] <= X_RDY_COLLISION;
end
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[44:40];
end
endmodule
/*******************************************************************************
* Module: crc
* Date: 2015-07-11
* Author: Alexey
* Description: crc calculations for the link layer
*
* Copyright (c) 2015 Elphel, Inc.
* crc.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.
*
* crc.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
/* same as for a scrambler, @ doc p.561 */
// TODO make it parallel, make another widths support
module crc #(
parameter DATA_BYTE_WIDTH = 4
)
(
input wire clk,
input wire rst,
input wire val_in,
input wire [DATA_BYTE_WIDTH*8 - 1:0] data_in,
output wire [DATA_BYTE_WIDTH*8 - 1:0] crc_out
);
reg [31:0] crc;
wire[31:0] crc_bit;
reg [31:0] new_bit;
always @ (posedge clk)
crc <= rst ? 32'h52325032 : val_in ? new_bit : crc;
assign crc_bit = crc ^ data_in;
assign crc_out = crc;
always @ (*)
begin
new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[5];
new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4];
new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3];
new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2];
new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1];
new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
crc_bit[0];
new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2];
new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1];
new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0];
new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5];
new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4];
new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3];
new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2];
new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1];
new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0];
new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^
crc_bit[3];
new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
crc_bit[2];
new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^
crc_bit[2] ^ crc_bit[1];
new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^
crc_bit[2] ^ crc_bit[1] ^ crc_bit[0];
new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^
crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1];
new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^
crc_bit[2] ^ crc_bit[0];
new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^
crc_bit[1];
new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^
crc_bit[0];
new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^
crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^
crc_bit[1];
new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^
crc_bit[1] ^ crc_bit[0];
new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
new_bit[0] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[0];
end
endmodule
/*******************************************************************************
* Module: drp_other_registers
* Date:2016-03-13
* Author: andrey
* Description: Additional registers controlled/read back over DRP
*
* Copyright (c) 2016 Elphel, Inc .
* drp_other_registers.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.
*
* drp_other_registers.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 drp_other_registers#(
parameter DRP_ABITS = 8,
parameter DRP_REG0 = 8,
parameter DRP_REG1 = 9,
parameter DRP_REG2 = 10,
parameter DRP_REG3 = 11
)(
input drp_rst,
input drp_clk,
input drp_en, // @aclk strobes drp_ad
input drp_we,
input [DRP_ABITS-1:0] drp_addr,
input [15:0] drp_di,
output reg drp_rdy,
output reg [15:0] drp_do,
output [15:0] drp_register0,
output [15:0] drp_register1,
output [15:0] drp_register2,
output [15:0] drp_register3
);
reg [DRP_ABITS-1:0] drp_addr_r;
reg drp_wr_r;
reg [ 1:0] drp_rd_r;
reg [15:0] drp_di_r;
reg drp_reg0_set;
reg drp_reg1_set;
reg drp_reg2_set;
reg drp_reg3_set;
reg drp_reg0_get;
reg drp_reg1_get;
reg drp_reg2_get;
reg drp_reg3_get;
reg [15:0] drp_register0_r;
reg [15:0] drp_register1_r;
reg [15:0] drp_register2_r;
reg [15:0] drp_register3_r;
assign drp_register0 = drp_register0_r;
assign drp_register1 = drp_register1_r;
assign drp_register2 = drp_register2_r;
assign drp_register3 = drp_register3_r;
// DRP interface
always @ (posedge drp_clk) begin
drp_addr_r <= drp_addr;
drp_wr_r <= drp_we && drp_en;
drp_rd_r <= {drp_rd_r[0],~drp_we & drp_en};
drp_di_r <= drp_di;
drp_reg0_set <= drp_wr_r && (drp_addr_r == DRP_REG0);
drp_reg1_set <= drp_wr_r && (drp_addr_r == DRP_REG1);
drp_reg2_set <= drp_wr_r && (drp_addr_r == DRP_REG2);
drp_reg3_set <= drp_wr_r && (drp_addr_r == DRP_REG3);
drp_reg0_get <= drp_rd_r[0] && (drp_addr_r == DRP_REG0);
drp_reg1_get <= drp_rd_r[0] && (drp_addr_r == DRP_REG1);
drp_reg2_get <= drp_rd_r[0] && (drp_addr_r == DRP_REG2);
drp_reg3_get <= drp_rd_r[0] && (drp_addr_r == DRP_REG3);
drp_rdy <= drp_wr_r || drp_rd_r[1];
drp_do <= ({16{drp_reg0_get}} & drp_register0_r) |
({16{drp_reg1_get}} & drp_register1_r) |
({16{drp_reg2_get}} & drp_register2_r) |
({16{drp_reg3_get}} & drp_register3_r);
if (drp_rst) drp_register0_r <= 0;
else if (drp_reg0_set) drp_register0_r <= drp_di_r;
if (drp_rst) drp_register1_r <= 0;
else if (drp_reg1_set) drp_register1_r <= drp_di_r;
if (drp_rst) drp_register2_r <= 0;
else if (drp_reg2_set) drp_register2_r <= drp_di_r;
if (drp_rst) drp_register3_r <= 0;
else if (drp_reg3_set) drp_register3_r <= drp_di_r;
end
endmodule
/*******************************************************************************
* Module: elastic1632
* Date:2016-02-03
* Author: andrey
* Description: Elastic buffer with 16-bit data input and 32-bit output
*
* Copyright (c) 2016 Elphel, Inc .
* elastic1632.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.
*
* elastic1632.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 elastic1632#(
parameter DEPTH_LOG2 = 4, // => 16 total rows x16 is for free in Xilinx, but keep it asymmetrical to reduce
// latency
parameter OFFSET = 7 // 5 // distance between read and write pointers, = wr_ptr - rd_ptr
)(
input wclk,
input rclk,
input isaligned_in,
input [1:0] charisk_in,
input [1:0] notintable_in,
input [1:0] disperror_in,
input [15:0] data_in,
output isaligned_out,
output reg [3:0] charisk_out,
output reg [3:0] notintable_out,
output reg [3:0] disperror_out,
output reg [31:0] data_out,
// status outputs, just in case
output full,
output empty
);
localparam ALIGN_PRIM = 32'h7B4A4ABC;
localparam FIFO_DEPTH = 1 << DEPTH_LOG2;
localparam CORR_OFFSET = OFFSET - 0;
reg [15:0] data_in_r;
reg [1:0] charisk_in_r;
reg [1:0] notintable_in_r;
reg [1:0] disperror_in_r;
reg aligned32_in_r; // input data is word-aligned and got ALIGNp
reg msb_in_r; // input contains MSB
reg inc_waddr;
reg [DEPTH_LOG2:0] waddr;
wire [DEPTH_LOG2-1:0] waddr_minus = waddr[DEPTH_LOG2-1:0] - 1;
wire [DEPTH_LOG2:0] raddr_w;
reg [DEPTH_LOG2:0] raddr_r;
reg [44:0] fifo_ram [0: FIFO_DEPTH -1];
reg [0:0] prealign_ram[0: FIFO_DEPTH -1];
reg [FIFO_DEPTH-1:0] fill;
wire [FIFO_DEPTH-1:0] fill_out;
wire [FIFO_DEPTH-1:0] fill_out_more; // "pessimistic"
wire [FIFO_DEPTH-1:0] fill_out_less; // "optimistic"
wire [FIFO_DEPTH-1:0] fill_1;
reg [2:0] aligned_rclk;
reg [1:0] dav_rclk; // FIFO has more than level
reg [1:0] dav_rclk_more; // FIFO has more than (level + 1)
reg [1:0] dav_rclk_less; // FIFO has more than (level - 1)
wire skip_rclk; // skip 1 align primitive
wire skip_rclk2; // skip 2 align primitives
//wire add_rclk; // insert 1 align primitive (to add2 - do this twice)
//wire add_rclk2; // skip 2 ALIGNp (just twice using add_rclk || add_rclk2_r
reg [1:0] add_rclk_r;
reg [44:0] rdata_r;
wire align_out = rdata_r[44];
reg pre_align_out_r;
// reg align_out_r;
reg [2:0] correct_r;
//wire correct = align_out && (!align_out_r || (pre_align_out_r && !correct_r[2]));
wire correct_stream = align_out && pre_align_out_r && !correct_r[2]; // correct during continuous align steram - by 1 only
wire correct_first = pre_align_out_r && !align_out; // next will be ALIGNp, may skip both
wire correct = correct_stream || correct_first;
reg [1:0] full_0; // full at waddr = waddr
reg [1:0] full_1; // full at waddr = raddr+1
wire is_alignp_w = ({data_in, data_in_r} == ALIGN_PRIM) &&
({charisk_in, charisk_in_r} == 4'h1) &&
({notintable_in, notintable_in_r} == 0) &&
({disperror_in, disperror_in_r} == 0);
`ifdef SIMULATION
wire [DEPTH_LOG2:0] dbg_diff = waddr-raddr_r; // SuppressThisWarning VEditor Not used, just for viewing in simulator
wire dbg_dav1 = dav_rclk[1]; // SuppressThisWarning VEditor Not used, just for viewing in simulator
wire dbg_full0 = full_0[1]; // SuppressThisWarning VEditor Not used, just for viewing in simulator
wire dbg_full1 = full_1[1]; // SuppressThisWarning VEditor Not used, just for viewing in simulator
reg [31:0] dbg_di; // SuppressThisWarning VEditor Not used, just for viewing in simulator
always @(posedge wclk) begin
if (msb_in_r) dbg_di<= {data_in,data_in_r};
end
`endif
genvar ii;
generate
for (ii = 0; ii < FIFO_DEPTH; ii = ii + 1)
begin: gen_fill_out
assign fill_out[ii] = fill[(ii + CORR_OFFSET ) & (FIFO_DEPTH - 1)] ^ ((ii + CORR_OFFSET ) >= FIFO_DEPTH);
assign fill_out_more[ii] = fill[(ii + CORR_OFFSET + 1) & (FIFO_DEPTH - 1)] ^ ((ii + CORR_OFFSET + 1) >= FIFO_DEPTH);
assign fill_out_less[ii] = fill[(ii + CORR_OFFSET - 1) & (FIFO_DEPTH - 1)] ^ ((ii + CORR_OFFSET - 1) >= FIFO_DEPTH);
assign fill_1[ii] = fill[(ii + 1) & (FIFO_DEPTH - 1)] ^ ((ii + 1) >= FIFO_DEPTH);
end
endgenerate
// FIFO write clock domain - read data synchronous, 150MHz for SATA2
always @(posedge wclk) begin
data_in_r <= data_in;
charisk_in_r <= charisk_in;
notintable_in_r <= notintable_in;
disperror_in_r <= disperror_in;
if (!isaligned_in) aligned32_in_r <= 0;
else if (is_alignp_w) aligned32_in_r <= 1;
if (!aligned32_in_r && !is_alignp_w) msb_in_r <= 1;
else msb_in_r <= !msb_in_r;
inc_waddr <= !msb_in_r || (is_alignp_w && !aligned32_in_r);
if (!aligned32_in_r) waddr <= 0;
else if (inc_waddr) waddr <= waddr + 1;
// write will be active before aligned32_in_r too
if (msb_in_r) fifo_ram[waddr[DEPTH_LOG2-1:0]] <= {is_alignp_w,
disperror_in, disperror_in_r,
notintable_in, notintable_in_r,
charisk_in, charisk_in_r,
data_in, data_in_r};
if (msb_in_r) prealign_ram[waddr_minus] <= is_alignp_w;
if (!aligned32_in_r) fill <= 0;
else if (msb_in_r) fill <={fill[FIFO_DEPTH-2:0],~waddr[DEPTH_LOG2]};
end
// FIFO read clock domain - system synchronous, 75MHz for SATA2
localparam [DEPTH_LOG2:0] SIZED0 = 0;
localparam [DEPTH_LOG2:0] SIZED1 = 1;
localparam [DEPTH_LOG2:0] SIZED2 = 2;
localparam [DEPTH_LOG2:0] SIZED3 = 3;
assign raddr_w = aligned_rclk[1]? ( raddr_r + (add_rclk_r[0]? SIZED0 : (skip_rclk ? (skip_rclk2 ? SIZED3 : SIZED2) : SIZED1))) : SIZED0;
always @(posedge rclk) begin
raddr_r <= raddr_w;
rdata_r <= fifo_ram[raddr_w[DEPTH_LOG2-1:0]];
pre_align_out_r <= prealign_ram[raddr_w[DEPTH_LOG2-1:0]];
if (!aligned32_in_r) aligned_rclk <= 0;
else aligned_rclk <= {aligned_rclk[1:0],fill[OFFSET-2] | aligned_rclk[0]};
if (!aligned32_in_r) dav_rclk <= 0;
else dav_rclk <= {dav_rclk[0],fill_out[raddr_r[DEPTH_LOG2-1:0]] ^ raddr_r[DEPTH_LOG2]};
if (!aligned32_in_r) dav_rclk_more <= 0;
else dav_rclk_more <= {dav_rclk_more[0],fill_out_more[raddr_r[DEPTH_LOG2-1:0]] ^ raddr_r[DEPTH_LOG2]};
if (!aligned32_in_r) dav_rclk_less <= 0;
else dav_rclk_less <= {dav_rclk_less[0],fill_out_less[raddr_r[DEPTH_LOG2-1:0]] ^ raddr_r[DEPTH_LOG2]};
if (!aligned32_in_r) full_0 <= 1;
else full_0 <= {full_0[0], fill[raddr_r[DEPTH_LOG2-1:0]] ^ raddr_r[DEPTH_LOG2]};
if (!aligned32_in_r) full_1 <= 1;
else full_1 <= {full_1[0], fill_1[raddr_r[DEPTH_LOG2-1:0]] ^ raddr_r[DEPTH_LOG2]};
disperror_out <= rdata_r[43:40];
notintable_out <= rdata_r[39:36];
charisk_out <= rdata_r[35:32];
data_out <= rdata_r[31: 0];
// align_out_r <= align_out;
if (correct || !aligned_rclk) correct_r <= ~0;
else correct_r <= correct_r << 1;
// add_rclk2_r <=add_rclk2;
if (correct_first) add_rclk_r <= {~dav_rclk_less[1], ~dav_rclk[1]};
else if (correct_stream) add_rclk_r <= {1'b0, ~dav_rclk[1]};
else add_rclk_r <= add_rclk_r >> 1;
end
//assign skip_rclk = correct && dav_rclk[1];
//assign add_rclk = correct && !dav_rclk[1];
assign skip_rclk = correct && dav_rclk[1];
assign skip_rclk2 = correct_first && dav_rclk_more[1];
//assign add_rclk = correct && !dav_rclk[1];
//assign add_rclk2 = correct_first && !dav_rclk_less[1];
assign isaligned_out = aligned_rclk[2];
assign full = aligned_rclk && full_1[1] && !full_0[1];
assign empty = aligned_rclk && !full_1[1] && full_0[1];
endmodule
/*******************************************************************************
* Module: gtx_10x8dec
* Date: 2015-07-11
* Author: Alexey
* Description: 8x10 encoder implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_10x8dec.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.
*
* gtx_10x8dec.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
module gtx_10x8dec(
input wire rst,
input wire clk,
input wire [19:0] indata,
output wire [15:0] outdata,
output wire [1:0] outisk,
output wire [1:0] notintable,
output wire [1:0] disperror
/* uncomment if necessary
input wire [0:0] inaux,
output wire [0:0] outaux, */
);
/*
uncomment if necessary
// bypass auxilary informational signals
reg [0:0] aux_r;
reg [0:0] aux_rr;
always @ (posedge clk)
begin
aux_r <= inaux;
aux_rr <= aux_r;
end
assign outaux = aux_rr;
*/
// split incoming data in 2 bytes
wire [9:0] addr0;
wire [9:0] addr1;
assign addr0 = indata[9:0];
assign addr1 = indata[19:10];
// get decoded values after 2 clock cycles, all '1's = cannot be decoded
wire [15:0] table0_out;
wire [15:0] table1_out;
wire [10:0] table0;
wire [10:0] table1;
assign table0 = table0_out[10:0];
assign table1 = table1_out[10:0];
assign outdata = {table1[7:0], table0[7:0]};
assign outisk = {table1[8], table0[8]};
assign notintable = {&table1, &table0};
// disparity control
// last clock disparity
reg disparity;
// disparity after 1st byte
wire disparity_interm;
// delayed ones
reg disp0_r;
reg disp0_rr;
reg disp1_r;
reg disp1_rr;
always @ (posedge clk)
begin
disp0_r <= disparity;
disp0_rr <= disp0_r;
disp1_r <= disparity_interm;
disp1_rr <= disp1_r;
end
// overall expected disparity when the table values would apper - disp0_r.
// disp1_rr shows expected after 0st byte would be considered
reg correct_table_disp;
wire expected_disparity;
wire expected_disparity_interm;
assign expected_disparity = disp0_rr ^ correct_table_disp;
assign expected_disparity_interm = disp1_rr ^ correct_table_disp;
// invert disparity after a byte
// if current encoded word containg an equal amount of 1s and 0s (i.e. 5 x '1'), disp shall stay the same
// if amounts are unequal, there are either 4 or 6 '1's. in either case disp shall be inverted
wire inv_disp0;
wire inv_disp1;
assign inv_disp0 = ~^(indata[9:0]);
assign inv_disp1 = ~^(indata[19:10]);
assign disparity_interm = inv_disp0 ? ~disparity : disparity;
always @ (posedge clk)
disparity <= rst ? 1'b0 : inv_disp1 ^ inv_disp0 ? ~disparity : disparity;
// to correct disparity if once an error occured
always @ (posedge clk)
correct_table_disp <= rst ? 1'b0 : disperror[1] ? ~correct_table_disp : correct_table_disp;
// calculate disparity on table values
wire table_pos_disp0;
wire table_neg_disp0;
wire table_pos_disp1;
wire table_neg_disp1;
// table_pos_disp - for current 10-bit word disparity can be positive
// _neg_ - can be negative
// neg & pos - can be either of them
assign table_pos_disp0 = table0[10];
assign table_neg_disp0 = table0[9];
assign table_pos_disp1 = table1[10];
assign table_neg_disp1 = table1[9];
assign disperror = ~{table_pos_disp0 & expected_disparity | table_neg_disp0 & ~expected_disparity, table_pos_disp1 & expected_disparity_interm | table_neg_disp1 & ~expected_disparity_interm};
// TODO change mem to 18 instead of 36, so the highest address bit could be dropped
ramt_var_w_var_r #(
.REGISTERS_A (1),
.REGISTERS_B (1),
.LOG2WIDTH_A (4),
.LOG2WIDTH_B (4)
`include "gtx_10x8dec_init.v"
)
decoding_table(
.clk_a (clk),
.addr_a ({1'b0, addr0}),
.en_a (1'b1),
.regen_a (1'b1),
.we_a (1'b0),
.data_out_a (table0_out),
.data_in_a (16'h0),
.clk_b (clk),
.addr_b ({1'b0, addr1}),
.en_b (1'b1),
.regen_b (1'b1),
.we_b (1'b0),
.data_out_b (table1_out),
.data_in_b (16'h0)
);
endmodule
, .INIT_00 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_01 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_02 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_03 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_04 (256'h000004EE04ED000004EB00000000000000000000000000000000000000000000)
, .INIT_05 (256'h000003FE03FD000003FB00000000000003F70000000000000000000000000000)
, .INIT_06 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_07 (256'h00000000000003FC000000000000000000000000000000000000000000000000)
, .INIT_08 (256'h0000040E040D0000040B00000000000000000000000000000000000000000000)
, .INIT_09 (256'h0000021E021D041C021B041A0419000002170416041500000413000000000000)
, .INIT_0A (256'h000002010202040C0204040A0409000002080406040500000403000000000000)
, .INIT_0B (256'h000000000000031C0000020F0200040700000210021F04140218041204110000)
, .INIT_0C (256'h0000026E026D0478026B047F0470000002670460046F0000057C000000000000)
, .INIT_0D (256'h000000000000027C0000027A0279046800000276027504640273046204610000)
, .INIT_0E (256'h000000000000026C0000026A02690477000002660265047B0263047D047E0000)
, .INIT_0F (256'h0000000000000000000000000000000000000000000002740000027202710000)
, .INIT_10 (256'h0000048E048D0000048B00000000000000000000000000000000000000000000)
, .INIT_11 (256'h0000029E029D049C029B049A0499000002970496049500000493000000000000)
, .INIT_12 (256'h000002810282048C0284048A0489000002880486048500000483000000000000)
, .INIT_13 (256'h000000000000039C0000028F0280048700000290029F04940298049204910000)
, .INIT_14 (256'h000006AE06AD04B806AB04BF04B0000002A704A004AF0000055C000000000000)
, .INIT_15 (256'h000002BE02BD06BC02BB06BA06B904A802B706B606B504A406B304A204A10000)
, .INIT_16 (256'h000002A102A206AC02A406AA06A904B702A806A606A504BB06A304BD04BE0000)
, .INIT_17 (256'h00000000000003BC000002AF02A004A7000002B002BF06B402B806B206B10000)
, .INIT_18 (256'h000006CE06CD04D806CB04DF04D0000002C704C004CF0000053C000000000000)
, .INIT_19 (256'h000002DE02DD06DC02DB06DA06D904C802D706D606D504C406D304C204C10000)
, .INIT_1A (256'h000002C102C206CC02C406CA06C904D702C806C606C504DB06C304DD04DE0000)
, .INIT_1B (256'h00000000000003DC000002CF02C004C7000002D002DF06D402D806D206D10000)
, .INIT_1C (256'h000002EE02ED04F802EB04FF04F0000002E704E004EF00000000000000000000)
, .INIT_1D (256'h00000000000002FC000002FA02F904E8000002F602F504E402F304E204E10000)
, .INIT_1E (256'h00000000000002EC000002EA02E904F7000002E602E504FB02E304FD04FE0000)
, .INIT_1F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_20 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_21 (256'h000002FE02FD04FC02FB04FA04F9000002F704F604F5000004F3000000000000)
, .INIT_22 (256'h000002E102E204EC02E404EA04E9000002E804E604E5000004E3000000000000)
, .INIT_23 (256'h0000000000000000000002EF02E004E7000002F002FF04F402F804F204F10000)
, .INIT_24 (256'h0000062E062D0438062B043F0430000002270420042F000005DC000000000000)
, .INIT_25 (256'h0000023E023D063C023B063A0639042802370636063504240633042204210000)
, .INIT_26 (256'h000002210222062C0224062A06290437022806260625043B0623043D043E0000)
, .INIT_27 (256'h000000000000033C0000022F0220042700000230023F06340238063206310000)
, .INIT_28 (256'h0000064E064D0458064B045F0450000002470440044F000005BC000000000000)
, .INIT_29 (256'h0000025E025D065C025B065A0659044802570656065504440653044204410000)
, .INIT_2A (256'h000002410242064C0244064A06490457024806460645045B0643045D045E0000)
, .INIT_2B (256'h000000000000035C0000024F0240044700000250025F06540258065206510000)
, .INIT_2C (256'h0000028E028D0498028B049F0490000002870480048F0000059C000000000000)
, .INIT_2D (256'h000000000000029C0000029A0299048800000296029504840293048204810000)
, .INIT_2E (256'h000000000000028C0000028A02890497000002860285049B0283049D049E0000)
, .INIT_2F (256'h0000000000000000000000000000000000000000000002940000029202910000)
, .INIT_30 (256'h0000046E046D0000046B00000000000000000000000000000000000000000000)
, .INIT_31 (256'h0000027E027D047C027B047A0479000002770476047500000473000000000000)
, .INIT_32 (256'h000002610262046C0264046A0469000002680466046500000463000000000000)
, .INIT_33 (256'h000000000000037C0000026F0260046700000270027F04740278047204710000)
, .INIT_34 (256'h0000020E020D0418020B041F0410000002070400040F0000051C000000000000)
, .INIT_35 (256'h000000000000021C0000021A0219040800000216021504040213040204010000)
, .INIT_36 (256'h000000000000020C0000020A02090417000002060205041B0203041D041E0000)
, .INIT_37 (256'h0000000000000000000000000000000000000000000002140000021202110000)
, .INIT_38 (256'h00000000000000000000000000000000000000000000000005FC000000000000)
, .INIT_39 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3A (256'h000000000000000000000000000005F700000000000005FB000005FD05FE0000)
, .INIT_3B (256'h0000000000000000000000000000000000000000000002F4000002F202F10000)
, .INIT_3C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_40 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_41 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_42 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_43 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_44 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_45 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_46 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_47 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_48 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_49 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_50 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_51 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_52 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_53 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_54 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_55 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_56 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_57 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_58 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_59 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_60 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_61 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_62 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_63 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_64 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_65 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_66 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_67 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_68 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_69 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_70 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_71 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_72 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_73 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_74 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_75 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_76 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_77 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_78 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_79 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7F (256'h0000000000000000000000000000000000000000000000000000000000000000)
0000000000 1001110100
1000000000 0110001011
0000000001 0111010100
1000000001 1000101011
0000000010 1011010100
1000000010 0100101011
0000000011 1100011011
1000000011 1100010100
0000000100 1101010100
1000000100 0010101011
0000000101 1010011011
1000000101 1010010100
0000000110 0110011011
1000000110 0110010100
0000000111 1110001011
1000000111 0001110100
0000001000 1110010100
1000001000 0001101011
0000001001 1001011011
1000001001 1001010100
0000001010 0101011011
1000001010 0101010100
0000001011 1101001011
1000001011 1101000100
0000001100 0011011011
1000001100 0011010100
0000001101 1011001011
1000001101 1011000100
0000001110 0111001011
1000001110 0111000100
0000001111 0101110100
1000001111 1010001011
0000010000 0110110100
1000010000 1001001011
0000010001 1000111011
1000010001 1000110100
0000010010 0100111011
1000010010 0100110100
0000010011 1100101011
1000010011 1100100100
0000010100 0010111011
1000010100 0010110100
0000010101 1010101011
1000010101 1010100100
0000010110 0110101011
1000010110 0110100100
0000010111 1110100100
1000010111 0001011011
0000011000 1100110100
1000011000 0011001011
0000011001 1001101011
1000011001 1001100100
0000011010 0101101011
1000011010 0101100100
0000011011 1101100100
1000011011 0010011011
0000011100 0011101011
1000011100 0011100100
0000011101 1011100100
1000011101 0100011011
0000011110 0111100100
1000011110 1000011011
0000011111 1010110100
1000011111 0101001011
0000100000 1001111001
1000100000 0110001001
0000100001 0111011001
1000100001 1000101001
0000100010 1011011001
1000100010 0100101001
0000100011 1100011001
1000100011 1100011001
0000100100 1101011001
1000100100 0010101001
0000100101 1010011001
1000100101 1010011001
0000100110 0110011001
1000100110 0110011001
0000100111 1110001001
1000100111 0001111001
0000101000 1110011001
1000101000 0001101001
0000101001 1001011001
1000101001 1001011001
0000101010 0101011001
1000101010 0101011001
0000101011 1101001001
1000101011 1101001001
0000101100 0011011001
1000101100 0011011001
0000101101 1011001001
1000101101 1011001001
0000101110 0111001001
1000101110 0111001001
0000101111 0101111001
1000101111 1010001001
0000110000 0110111001
1000110000 1001001001
0000110001 1000111001
1000110001 1000111001
0000110010 0100111001
1000110010 0100111001
0000110011 1100101001
1000110011 1100101001
0000110100 0010111001
1000110100 0010111001
0000110101 1010101001
1000110101 1010101001
0000110110 0110101001
1000110110 0110101001
0000110111 1110101001
1000110111 0001011001
0000111000 1100111001
1000111000 0011001001
0000111001 1001101001
1000111001 1001101001
0000111010 0101101001
1000111010 0101101001
0000111011 1101101001
1000111011 0010011001
0000111100 0011101001
1000111100 0011101001
0000111101 1011101001
1000111101 0100011001
0000111110 0111101001
1000111110 1000011001
0000111111 1010111001
1000111111 0101001001
0001000000 1001110101
1001000000 0110000101
0001000001 0111010101
1001000001 1000100101
0001000010 1011010101
1001000010 0100100101
0001000011 1100010101
1001000011 1100010101
0001000100 1101010101
1001000100 0010100101
0001000101 1010010101
1001000101 1010010101
0001000110 0110010101
1001000110 0110010101
0001000111 1110000101
1001000111 0001110101
0001001000 1110010101
1001001000 0001100101
0001001001 1001010101
1001001001 1001010101
0001001010 0101010101
1001001010 0101010101
0001001011 1101000101
1001001011 1101000101
0001001100 0011010101
1001001100 0011010101
0001001101 1011000101
1001001101 1011000101
0001001110 0111000101
1001001110 0111000101
0001001111 0101110101
1001001111 1010000101
0001010000 0110110101
1001010000 1001000101
0001010001 1000110101
1001010001 1000110101
0001010010 0100110101
1001010010 0100110101
0001010011 1100100101
1001010011 1100100101
0001010100 0010110101
1001010100 0010110101
0001010101 1010100101
1001010101 1010100101
0001010110 0110100101
1001010110 0110100101
0001010111 1110100101
1001010111 0001010101
0001011000 1100110101
1001011000 0011000101
0001011001 1001100101
1001011001 1001100101
0001011010 0101100101
1001011010 0101100101
0001011011 1101100101
1001011011 0010010101
0001011100 0011100101
1001011100 0011100101
0001011101 1011100101
1001011101 0100010101
0001011110 0111100101
1001011110 1000010101
0001011111 1010110101
1001011111 0101000101
0001100000 1001110011
1001100000 0110001100
0001100001 0111010011
1001100001 1000101100
0001100010 1011010011
1001100010 0100101100
0001100011 1100011100
1001100011 1100010011
0001100100 1101010011
1001100100 0010101100
0001100101 1010011100
1001100101 1010010011
0001100110 0110011100
1001100110 0110010011
0001100111 1110001100
1001100111 0001110011
0001101000 1110010011
1001101000 0001101100
0001101001 1001011100
1001101001 1001010011
0001101010 0101011100
1001101010 0101010011
0001101011 1101001100
1001101011 1101000011
0001101100 0011011100
1001101100 0011010011
0001101101 1011001100
1001101101 1011000011
0001101110 0111001100
1001101110 0111000011
0001101111 0101110011
1001101111 1010001100
0001110000 0110110011
1001110000 1001001100
0001110001 1000111100
1001110001 1000110011
0001110010 0100111100
1001110010 0100110011
0001110011 1100101100
1001110011 1100100011
0001110100 0010111100
1001110100 0010110011
0001110101 1010101100
1001110101 1010100011
0001110110 0110101100
1001110110 0110100011
0001110111 1110100011
1001110111 0001011100
0001111000 1100110011
1001111000 0011001100
0001111001 1001101100
1001111001 1001100011
0001111010 0101101100
1001111010 0101100011
0001111011 1101100011
1001111011 0010011100
0001111100 0011101100
1001111100 0011100011
0001111101 1011100011
1001111101 0100011100
0001111110 0111100011
1001111110 1000011100
0001111111 1010110011
1001111111 0101001100
0010000000 1001110010
1010000000 0110001101
0010000001 0111010010
1010000001 1000101101
0010000010 1011010010
1010000010 0100101101
0010000011 1100011101
1010000011 1100010010
0010000100 1101010010
1010000100 0010101101
0010000101 1010011101
1010000101 1010010010
0010000110 0110011101
1010000110 0110010010
0010000111 1110001101
1010000111 0001110010
0010001000 1110010010
1010001000 0001101101
0010001001 1001011101
1010001001 1001010010
0010001010 0101011101
1010001010 0101010010
0010001011 1101001101
1010001011 1101000010
0010001100 0011011101
1010001100 0011010010
0010001101 1011001101
1010001101 1011000010
0010001110 0111001101
1010001110 0111000010
0010001111 0101110010
1010001111 1010001101
0010010000 0110110010
1010010000 1001001101
0010010001 1000111101
1010010001 1000110010
0010010010 0100111101
1010010010 0100110010
0010010011 1100101101
1010010011 1100100010
0010010100 0010111101
1010010100 0010110010
0010010101 1010101101
1010010101 1010100010
0010010110 0110101101
1010010110 0110100010
0010010111 1110100010
1010010111 0001011101
0010011000 1100110010
1010011000 0011001101
0010011001 1001101101
1010011001 1001100010
0010011010 0101101101
1010011010 0101100010
0010011011 1101100010
1010011011 0010011101
0010011100 0011101101
1010011100 0011100010
0010011101 1011100010
1010011101 0100011101
0010011110 0111100010
1010011110 1000011101
0010011111 1010110010
1010011111 0101001101
0010100000 1001111010
1010100000 0110001010
0010100001 0111011010
1010100001 1000101010
0010100010 1011011010
1010100010 0100101010
0010100011 1100011010
1010100011 1100011010
0010100100 1101011010
1010100100 0010101010
0010100101 1010011010
1010100101 1010011010
0010100110 0110011010
1010100110 0110011010
0010100111 1110001010
1010100111 0001111010
0010101000 1110011010
1010101000 0001101010
0010101001 1001011010
1010101001 1001011010
0010101010 0101011010
1010101010 0101011010
0010101011 1101001010
1010101011 1101001010
0010101100 0011011010
1010101100 0011011010
0010101101 1011001010
1010101101 1011001010
0010101110 0111001010
1010101110 0111001010
0010101111 0101111010
1010101111 1010001010
0010110000 0110111010
1010110000 1001001010
0010110001 1000111010
1010110001 1000111010
0010110010 0100111010
1010110010 0100111010
0010110011 1100101010
1010110011 1100101010
0010110100 0010111010
1010110100 0010111010
0010110101 1010101010
1010110101 1010101010
0010110110 0110101010
1010110110 0110101010
0010110111 1110101010
1010110111 0001011010
0010111000 1100111010
1010111000 0011001010
0010111001 1001101010
1010111001 1001101010
0010111010 0101101010
1010111010 0101101010
0010111011 1101101010
1010111011 0010011010
0010111100 0011101010
1010111100 0011101010
0010111101 1011101010
1010111101 0100011010
0010111110 0111101010
1010111110 1000011010
0010111111 1010111010
1010111111 0101001010
0011000000 1001110110
1011000000 0110000110
0011000001 0111010110
1011000001 1000100110
0011000010 1011010110
1011000010 0100100110
0011000011 1100010110
1011000011 1100010110
0011000100 1101010110
1011000100 0010100110
0011000101 1010010110
1011000101 1010010110
0011000110 0110010110
1011000110 0110010110
0011000111 1110000110
1011000111 0001110110
0011001000 1110010110
1011001000 0001100110
0011001001 1001010110
1011001001 1001010110
0011001010 0101010110
1011001010 0101010110
0011001011 1101000110
1011001011 1101000110
0011001100 0011010110
1011001100 0011010110
0011001101 1011000110
1011001101 1011000110
0011001110 0111000110
1011001110 0111000110
0011001111 0101110110
1011001111 1010000110
0011010000 0110110110
1011010000 1001000110
0011010001 1000110110
1011010001 1000110110
0011010010 0100110110
1011010010 0100110110
0011010011 1100100110
1011010011 1100100110
0011010100 0010110110
1011010100 0010110110
0011010101 1010100110
1011010101 1010100110
0011010110 0110100110
1011010110 0110100110
0011010111 1110100110
1011010111 0001010110
0011011000 1100110110
1011011000 0011000110
0011011001 1001100110
1011011001 1001100110
0011011010 0101100110
1011011010 0101100110
0011011011 1101100110
1011011011 0010010110
0011011100 0011100110
1011011100 0011100110
0011011101 1011100110
1011011101 0100010110
0011011110 0111100110
1011011110 1000010110
0011011111 1010110110
1011011111 0101000110
0011100000 1001110001
1011100000 0110001110
0011100001 0111010001
1011100001 1000101110
0011100010 1011010001
1011100010 0100101110
0011100011 1100011110
1011100011 1100010001
0011100100 1101010001
1011100100 0010101110
0011100101 1010011110
1011100101 1010010001
0011100110 0110011110
1011100110 0110010001
0011100111 1110001110
1011100111 0001110001
0011101000 1110010001
1011101000 0001101110
0011101001 1001011110
1011101001 1001010001
0011101010 0101011110
1011101010 0101010001
0011101011 1101001110
1011101011 1101001000
0011101100 0011011110
1011101100 0011010001
0011101101 1011001110
1011101101 1011001000
0011101110 0111001110
1011101110 0111001000
0011101111 0101110001
1011101111 1010001110
0011110000 0110110001
1011110000 1001001110
0011110001 1000110111
1011110001 1000110001
0011110010 0100110111
1011110010 0100110001
0011110011 1100101110
1011110011 1100100001
0011110100 0010110111
1011110100 0010110001
0011110101 1010101110
1011110101 1010100001
0011110110 0110101110
1011110110 0110100001
0011110111 1110100001
1011110111 0001011110
0011111000 1100110001
1011111000 0011001110
0011111001 1001101110
1011111001 1001100001
0011111010 0101101110
1011111010 0101100001
0011111011 1101100001
1011111011 0010011110
0011111100 0011101110
1011111100 0011100001
0011111101 1011100001
1011111101 0100011110
0011111110 0111100001
1011111110 1000011110
0011111111 1010110001
1011111111 0101001110
0100011100 0011110100
1100011100 1100001011
0100111100 0011111001
1100111100 1100000110
0101011100 0011110101
1101011100 1100001010
0101111100 0011110011
1101111100 1100001100
0110011100 0011110010
1110011100 1100001101
0110111100 0011111010
1110111100 1100000101
0111011100 0011110110
1111011100 1100001001
0111111100 0011111000
1111111100 1100000111
0111110111 1110101000
1111110111 0001010111
0111111011 1101101000
1111111011 0010010111
0111111101 1011101000
1111111101 0100010111
0111111110 0111101000
1111111110 1000010111
/*******************************************************************************
* Module: gtx_8x10enc
* Date: 2015-07-11
* Author: Alexey
* Description: 8x10 encoder implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_8x10enc.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.
*
* gtx_8x10enc.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
module gtx_8x10enc(
input wire rst,
input wire clk,
input wire [1:0] inisk,
input wire [15:0] indata,
output wire [19:0] outdata
);
// addresses to reference an encoding table
wire [8:0] addr0;
wire [8:0] addr1;
assign addr0 = {inisk[0], indata[7:0]};
assign addr1 = {inisk[1], indata[15:8]};
// possible encoded data - both disparities, for both bytes
// due to registered memory output, this values will be valid after 2 clock cycles
// table[i] [9:0] in case of current disparity +, [19:10] in case of -
wire [31:0] table0_out;
wire [31:0] table1_out;
reg [19:0] table0_r;
reg [19:0] table1_r;
wire [19:0] table0;
wire [19:0] table1;
assign table0 = table0_out[19:0];
assign table1 = table1_out[19:0];
always @ (posedge clk)
begin
table0_r <= table0;
table1_r <= table1;
end
// encoded bytes
wire [9:0] enc0;
wire [9:0] enc1;
//reg [9:0] enc0_r;
//reg [9:0] enc1_r;
// running displarity, 0 = -, 1 = +
reg disparity;
// running disparity after encoding 1st byte
wire disparity_interm;
// invert disparity after a byte
// if current encoded word containg an equal amount of 1s and 0s (i.e. 5 x '1'), disp shall stay the same
// if amounts are unequal, there are either 4 or 6 '1's. in either case disp shall be inverted
wire inv_disp0;
wire inv_disp1;
assign inv_disp0 = ~^enc0;
assign inv_disp1 = ~^enc1;
assign disparity_interm = inv_disp0 ? ~disparity : disparity;
always @ (posedge clk)
disparity <= rst ? 1'b0 : inv_disp1 ^ inv_disp0 ? ~disparity : disparity;
// select encoded bytes depending on a previous disparity
assign enc0 = {10{~disparity}} & table0_r[19:10] | {10{disparity}} & table0_r[9:0];
assign enc1 = {10{~disparity_interm}} & table1_r[19:10] | {10{disparity_interm}} & table1_r[9:0];
// latch output data
reg [19:0] outdata_l;
assign outdata = outdata_l;
always @ (posedge clk)
outdata_l <= {enc1, enc0};
ramt_var_w_var_r #(
.REGISTERS_A (1),
.REGISTERS_B (1),
.LOG2WIDTH_A (5),
.LOG2WIDTH_B (5)
`include "gtx_8x10enc_init.v"
)
encoding_table(
.clk_a (clk),
.addr_a ({1'b0, addr0}),
.en_a (1'b1),
.regen_a (1'b1),
.we_a (1'b0),
.data_out_a (table0_out),
.data_in_a (32'h0),
.clk_b (clk),
.addr_b ({1'b0, addr1}),
.en_b (1'b1),
.regen_b (1'b1),
.we_b (1'b0),
.data_out_b (table1_out),
.data_in_b (32'h0)
);
`ifdef CHECKERS_ENABLED
reg [8:0] addr0_r;
reg [8:0] addr1_r;
reg [8:0] addr0_rr;
reg [8:0] addr1_rr;
always @ (posedge clk)
begin
addr0_r <= addr0;
addr1_r <= addr1;
addr0_rr <= addr0_r;
addr1_rr <= addr1_r;
end
always @ (posedge clk)
if (~rst)
if (|table0 | |table1) begin
// all good
end
else begin
// got xxxx or 0000, both cases tell us addresses were bad
$display("Error in %m: bad incoming data: 1) K = %h, Data = %h 2) K = %h, Data = %h", addr0_rr[8], addr0_rr[7:0], addr1_rr[8], addr1_rr[7:0]);
repeat (10) @(posedge clk);
$finish;
end
`endif // CHECKERS_ENABLED
endmodule
, .INIT_00 (256'h0002E34700029B6600029765000D50AB00028F63000D48AD000D44AE000D18B9)
, .INIT_01 (256'h000D14BA00023B4E0002374D0002B36C00022F4B0002AB6A0002A769000D60A7)
, .INIT_02 (256'h000DA09700025B56000257550002D37400024F530002CB720002C771000D24B6)
, .INIT_03 (256'h000D28B5000D849E000D889D0002735C000D909B00026B5A00026759000D30B3)
, .INIT_04 (256'h0009E24700099A66000996650009526B00098E6300094A6D0009466E00091A79)
, .INIT_05 (256'h0009167A00093A4E0009364D0009B26C00092E4B0009AA6A0009A66900096267)
, .INIT_06 (256'h0009A25700095A56000956550009D27400094E530009CA720009C67100092676)
, .INIT_07 (256'h00092A750009865E00098A5D0009725C0009925B00096A5A0009665900093273)
, .INIT_08 (256'h000AE287000A9AA6000A96A5000A52AB000A8EA3000A4AAD000A46AE000A1AB9)
, .INIT_09 (256'h000A16BA000A3A8E000A368D000AB2AC000A2E8B000AAAAA000AA6A9000A62A7)
, .INIT_0A (256'h000AA297000A5A96000A5695000AD2B4000A4E93000ACAB2000AC6B1000A26B6)
, .INIT_0B (256'h000A2AB5000A869E000A8A9D000A729C000A929B000A6A9A000A6699000A32B3)
, .INIT_0C (256'h000CE0C7000C98E6000C94E50003532B000C8CE300034B2D0003472E00031B39)
, .INIT_0D (256'h0003173A000C38CE000C34CD000CB0EC000C2CCB000CA8EA000CA4E900036327)
, .INIT_0E (256'h0003A317000C58D6000C54D5000CD0F4000C4CD3000CC8F2000CC4F100032736)
, .INIT_0F (256'h00032B350003871E00038B1D000C70DC0003931B000C68DA000C64D900033333)
, .INIT_10 (256'h0004E2C700049AE6000496E5000B512B00048EE3000B492D000B452E000B1939)
, .INIT_11 (256'h000B153A00043ACE000436CD0004B2EC00042ECB0004AAEA0004A6E9000B6127)
, .INIT_12 (256'h000BA11700045AD6000456D50004D2F400044ED30004CAF20004C6F1000B2536)
, .INIT_13 (256'h000B2935000B851E000B891D000472DC000B911B00046ADA000466D9000B3133)
, .INIT_14 (256'h0005E14700059966000595650005516B00058D630005496D0005456E00051979)
, .INIT_15 (256'h0005157A0005394E0005354D0005B16C00052D4B0005A96A0005A56900056167)
, .INIT_16 (256'h0005A15700055956000555550005D17400054D530005C9720005C57100052576)
, .INIT_17 (256'h000529750005855E0005895D0005715C0005915B0005695A0005655900053173)
, .INIT_18 (256'h0006E187000699A6000695A5000651AB00068DA3000649AD000645AE000619B9)
, .INIT_19 (256'h000615BA0006398E0006358D0006B1AC00062D8B0006A9AA0006A5A9000661A7)
, .INIT_1A (256'h0006A19700065996000655950006D1B400064D930006C9B20006C5B1000625B6)
, .INIT_1B (256'h000629B50006859E0006899D0006719C0006919B0006699A00066599000631B3)
, .INIT_1C (256'h0008E1C7000899E6000895E50007522B00088DE300074A2D0007462E00071A39)
, .INIT_1D (256'h0007163A000139CE000135CD0008B1EC00012DCB0008A9EA0008A5E900076227)
, .INIT_1E (256'h0007A217000859D6000855D50008D3B400084DD30008CBB20008C7B100072636)
, .INIT_1F (256'h00072A350007861E00078A1D000871DC0007921B000869DA000865D900073233)
, .INIT_20 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_21 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_22 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_23 (256'h000000000000000000000000000D0CBC00000000000000000000000000000000)
, .INIT_24 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_25 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_26 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_27 (256'h00000000000000000000000000060E7C00000000000000000000000000000000)
, .INIT_28 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_29 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2B (256'h00000000000000000000000000050EBC00000000000000000000000000000000)
, .INIT_2C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_2F (256'h00000000000000000000000000030F3C00000000000000000000000000000000)
, .INIT_30 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_31 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_32 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_33 (256'h000000000000000000000000000B0D3C00000000000000000000000000000000)
, .INIT_34 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_35 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_36 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_37 (256'h000000000000000000000000000A0D7C00000000000000000000000000000000)
, .INIT_38 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_39 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3B (256'h00000000000000000000000000090DBC00000000000000000000000000000000)
, .INIT_3C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_3E (256'h000EA05700000000000000000000000000000000000000000000000000000000)
, .INIT_3F (256'h00000000000E845E000E885D000E0C7C000E905B000000000000000000000000)
, .INIT_40 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_41 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_42 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_43 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_44 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_45 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_46 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_47 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_48 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_49 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_4F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_50 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_51 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_52 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_53 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_54 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_55 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_56 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_57 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_58 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_59 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_5F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_60 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_61 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_62 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_63 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_64 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_65 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_66 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_67 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_68 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_69 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_6F (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_70 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_71 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_72 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_73 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_74 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_75 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_76 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_77 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_78 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_79 (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7A (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7B (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7C (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7D (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7E (256'h0000000000000000000000000000000000000000000000000000000000000000)
, .INIT_7F (256'h0000000000000000000000000000000000000000000000000000000000000000)
000000000 0010111001 1101000110 non-inverted values: 1001110100 0110001011
000000001 0010101110 1101010001 0111010100 1000101011
000000010 0010101101 1101010010 1011010100 0100101011
000000011 1101100011 0010100011 1100011011 1100010100
000000100 0010101011 1101010100 1101010100 0010101011
000000101 1101100101 0010100101 1010011011 1010010100
000000110 1101100110 0010100110 0110011011 0110010100
000000111 1101000111 0010111000 1110001011 0001110100
000001000 0010100111 1101011000 1110010100 0001101011
000001001 1101101001 0010101001 1001011011 1001010100
000001010 1101101010 0010101010 0101011011 0101010100
000001011 1101001011 0010001011 1101001011 1101000100
000001100 1101101100 0010101100 0011011011 0011010100
000001101 1101001101 0010001101 1011001011 1011000100
000001110 1101001110 0010001110 0111001011 0111000100
000001111 0010111010 1101000101 0101110100 1010001011
000010000 0010110110 1101001001 0110110100 1001001011
000010001 1101110001 0010110001 1000111011 1000110100
000010010 1101110010 0010110010 0100111011 0100110100
000010011 1101010011 0010010011 1100101011 1100100100
000010100 1101110100 0010110100 0010111011 0010110100
000010101 1101010101 0010010101 1010101011 1010100100
000010110 1101010110 0010010110 0110101011 0110100100
000010111 0010010111 1101101000 1110100100 0001011011
000011000 0010110011 1101001100 1100110100 0011001011
000011001 1101011001 0010011001 1001101011 1001100100
000011010 1101011010 0010011010 0101101011 0101100100
000011011 0010011011 1101100100 1101100100 0010011011
000011100 1101011100 0010011100 0011101011 0011100100
000011101 0010011101 1101100010 1011100100 0100011011
000011110 0010011110 1101100001 0111100100 1000011011
000011111 0010110101 1101001010 1010110100 0101001011
000100000 1001111001 1001000110 1001111001 0110001001
000100001 1001101110 1001010001 0111011001 1000101001
000100010 1001101101 1001010010 1011011001 0100101001
000100011 1001100011 1001100011 1100011001 1100011001
000100100 1001101011 1001010100 1101011001 0010101001
000100101 1001100101 1001100101 1010011001 1010011001
000100110 1001100110 1001100110 0110011001 0110011001
000100111 1001000111 1001111000 1110001001 0001111001
000101000 1001100111 1001011000 1110011001 0001101001
000101001 1001101001 1001101001 1001011001 1001011001
000101010 1001101010 1001101010 0101011001 0101011001
000101011 1001001011 1001001011 1101001001 1101001001
000101100 1001101100 1001101100 0011011001 0011011001
000101101 1001001101 1001001101 1011001001 1011001001
000101110 1001001110 1001001110 0111001001 0111001001
000101111 1001111010 1001000101 0101111001 1010001001
000110000 1001110110 1001001001 0110111001 1001001001
000110001 1001110001 1001110001 1000111001 1000111001
000110010 1001110010 1001110010 0100111001 0100111001
000110011 1001010011 1001010011 1100101001 1100101001
000110100 1001110100 1001110100 0010111001 0010111001
000110101 1001010101 1001010101 1010101001 1010101001
000110110 1001010110 1001010110 0110101001 0110101001
000110111 1001010111 1001101000 1110101001 0001011001
000111000 1001110011 1001001100 1100111001 0011001001
000111001 1001011001 1001011001 1001101001 1001101001
000111010 1001011010 1001011010 0101101001 0101101001
000111011 1001011011 1001100100 1101101001 0010011001
000111100 1001011100 1001011100 0011101001 0011101001
000111101 1001011101 1001100010 1011101001 0100011001
000111110 1001011110 1001100001 0111101001 1000011001
000111111 1001110101 1001001010 1010111001 0101001001
001000000 1010111001 1010000110 1001110101 0110000101
001000001 1010101110 1010010001 0111010101 1000100101
001000010 1010101101 1010010010 1011010101 0100100101
001000011 1010100011 1010100011 1100010101 1100010101
001000100 1010101011 1010010100 1101010101 0010100101
001000101 1010100101 1010100101 1010010101 1010010101
001000110 1010100110 1010100110 0110010101 0110010101
001000111 1010000111 1010111000 1110000101 0001110101
001001000 1010100111 1010011000 1110010101 0001100101
001001001 1010101001 1010101001 1001010101 1001010101
001001010 1010101010 1010101010 0101010101 0101010101
001001011 1010001011 1010001011 1101000101 1101000101
001001100 1010101100 1010101100 0011010101 0011010101
001001101 1010001101 1010001101 1011000101 1011000101
001001110 1010001110 1010001110 0111000101 0111000101
001001111 1010111010 1010000101 0101110101 1010000101
001010000 1010110110 1010001001 0110110101 1001000101
001010001 1010110001 1010110001 1000110101 1000110101
001010010 1010110010 1010110010 0100110101 0100110101
001010011 1010010011 1010010011 1100100101 1100100101
001010100 1010110100 1010110100 0010110101 0010110101
001010101 1010010101 1010010101 1010100101 1010100101
001010110 1010010110 1010010110 0110100101 0110100101
001010111 1010010111 1010101000 1110100101 0001010101
001011000 1010110011 1010001100 1100110101 0011000101
001011001 1010011001 1010011001 1001100101 1001100101
001011010 1010011010 1010011010 0101100101 0101100101
001011011 1010011011 1010100100 1101100101 0010010101
001011100 1010011100 1010011100 0011100101 0011100101
001011101 1010011101 1010100010 1011100101 0100010101
001011110 1010011110 1010100001 0111100101 1000010101
001011111 1010110101 1010001010 1010110101 0101000101
001100000 1100111001 0011000110 1001110011 0110001100
001100001 1100101110 0011010001 0111010011 1000101100
001100010 1100101101 0011010010 1011010011 0100101100
001100011 0011100011 1100100011 1100011100 1100010011
001100100 1100101011 0011010100 1101010011 0010101100
001100101 0011100101 1100100101 1010011100 1010010011
001100110 0011100110 1100100110 0110011100 0110010011
001100111 0011000111 1100111000 1110001100 0001110011
001101000 1100100111 0011011000 1110010011 0001101100
001101001 0011101001 1100101001 1001011100 1001010011
001101010 0011101010 1100101010 0101011100 0101010011
001101011 0011001011 1100001011 1101001100 1101000011
001101100 0011101100 1100101100 0011011100 0011010011
001101101 0011001101 1100001101 1011001100 1011000011
001101110 0011001110 1100001110 0111001100 0111000011
001101111 1100111010 0011000101 0101110011 1010001100
001110000 1100110110 0011001001 0110110011 1001001100
001110001 0011110001 1100110001 1000111100 1000110011
001110010 0011110010 1100110010 0100111100 0100110011
001110011 0011010011 1100010011 1100101100 1100100011
001110100 0011110100 1100110100 0010111100 0010110011
001110101 0011010101 1100010101 1010101100 1010100011
001110110 0011010110 1100010110 0110101100 0110100011
001110111 1100010111 0011101000 1110100011 0001011100
001111000 1100110011 0011001100 1100110011 0011001100
001111001 0011011001 1100011001 1001101100 1001100011
001111010 0011011010 1100011010 0101101100 0101100011
001111011 1100011011 0011100100 1101100011 0010011100
001111100 0011011100 1100011100 0011101100 0011100011
001111101 1100011101 0011100010 1011100011 0100011100
001111110 1100011110 0011100001 0111100011 1000011100
001111111 1100110101 0011001010 1010110011 0101001100
010000000 0100111001 1011000110 1001110010 0110001101
010000001 0100101110 1011010001 0111010010 1000101101
010000010 0100101101 1011010010 1011010010 0100101101
010000011 1011100011 0100100011 1100011101 1100010010
010000100 0100101011 1011010100 1101010010 0010101101
010000101 1011100101 0100100101 1010011101 1010010010
010000110 1011100110 0100100110 0110011101 0110010010
010000111 1011000111 0100111000 1110001101 0001110010
010001000 0100100111 1011011000 1110010010 0001101101
010001001 1011101001 0100101001 1001011101 1001010010
010001010 1011101010 0100101010 0101011101 0101010010
010001011 1011001011 0100001011 1101001101 1101000010
010001100 1011101100 0100101100 0011011101 0011010010
010001101 1011001101 0100001101 1011001101 1011000010
010001110 1011001110 0100001110 0111001101 0111000010
010001111 0100111010 1011000101 0101110010 1010001101
010010000 0100110110 1011001001 0110110010 1001001101
010010001 1011110001 0100110001 1000111101 1000110010
010010010 1011110010 0100110010 0100111101 0100110010
010010011 1011010011 0100010011 1100101101 1100100010
010010100 1011110100 0100110100 0010111101 0010110010
010010101 1011010101 0100010101 1010101101 1010100010
010010110 1011010110 0100010110 0110101101 0110100010
010010111 0100010111 1011101000 1110100010 0001011101
010011000 0100110011 1011001100 1100110010 0011001101
010011001 1011011001 0100011001 1001101101 1001100010
010011010 1011011010 0100011010 0101101101 0101100010
010011011 0100011011 1011100100 1101100010 0010011101
010011100 1011011100 0100011100 0011101101 0011100010
010011101 0100011101 1011100010 1011100010 0100011101
010011110 0100011110 1011100001 0111100010 1000011101
010011111 0100110101 1011001010 1010110010 0101001101
010100000 0101111001 0101000110 1001111010 0110001010
010100001 0101101110 0101010001 0111011010 1000101010
010100010 0101101101 0101010010 1011011010 0100101010
010100011 0101100011 0101100011 1100011010 1100011010
010100100 0101101011 0101010100 1101011010 0010101010
010100101 0101100101 0101100101 1010011010 1010011010
010100110 0101100110 0101100110 0110011010 0110011010
010100111 0101000111 0101111000 1110001010 0001111010
010101000 0101100111 0101011000 1110011010 0001101010
010101001 0101101001 0101101001 1001011010 1001011010
010101010 0101101010 0101101010 0101011010 0101011010
010101011 0101001011 0101001011 1101001010 1101001010
010101100 0101101100 0101101100 0011011010 0011011010
010101101 0101001101 0101001101 1011001010 1011001010
010101110 0101001110 0101001110 0111001010 0111001010
010101111 0101111010 0101000101 0101111010 1010001010
010110000 0101110110 0101001001 0110111010 1001001010
010110001 0101110001 0101110001 1000111010 1000111010
010110010 0101110010 0101110010 0100111010 0100111010
010110011 0101010011 0101010011 1100101010 1100101010
010110100 0101110100 0101110100 0010111010 0010111010
010110101 0101010101 0101010101 1010101010 1010101010
010110110 0101010110 0101010110 0110101010 0110101010
010110111 0101010111 0101101000 1110101010 0001011010
010111000 0101110011 0101001100 1100111010 0011001010
010111001 0101011001 0101011001 1001101010 1001101010
010111010 0101011010 0101011010 0101101010 0101101010
010111011 0101011011 0101100100 1101101010 0010011010
010111100 0101011100 0101011100 0011101010 0011101010
010111101 0101011101 0101100010 1011101010 0100011010
010111110 0101011110 0101100001 0111101010 1000011010
010111111 0101110101 0101001010 1010111010 0101001010
011000000 0110111001 0110000110 1001110110 0110000110
011000001 0110101110 0110010001 0111010110 1000100110
011000010 0110101101 0110010010 1011010110 0100100110
011000011 0110100011 0110100011 1100010110 1100010110
011000100 0110101011 0110010100 1101010110 0010100110
011000101 0110100101 0110100101 1010010110 1010010110
011000110 0110100110 0110100110 0110010110 0110010110
011000111 0110000111 0110111000 1110000110 0001110110
011001000 0110100111 0110011000 1110010110 0001100110
011001001 0110101001 0110101001 1001010110 1001010110
011001010 0110101010 0110101010 0101010110 0101010110
011001011 0110001011 0110001011 1101000110 1101000110
011001100 0110101100 0110101100 0011010110 0011010110
011001101 0110001101 0110001101 1011000110 1011000110
011001110 0110001110 0110001110 0111000110 0111000110
011001111 0110111010 0110000101 0101110110 1010000110
011010000 0110110110 0110001001 0110110110 1001000110
011010001 0110110001 0110110001 1000110110 1000110110
011010010 0110110010 0110110010 0100110110 0100110110
011010011 0110010011 0110010011 1100100110 1100100110
011010100 0110110100 0110110100 0010110110 0010110110
011010101 0110010101 0110010101 1010100110 1010100110
011010110 0110010110 0110010110 0110100110 0110100110
011010111 0110010111 0110101000 1110100110 0001010110
011011000 0110110011 0110001100 1100110110 0011000110
011011001 0110011001 0110011001 1001100110 1001100110
011011010 0110011010 0110011010 0101100110 0101100110
011011011 0110011011 0110100100 1101100110 0010010110
011011100 0110011100 0110011100 0011100110 0011100110
011011101 0110011101 0110100010 1011100110 0100010110
011011110 0110011110 0110100001 0111100110 1000010110
011011111 0110110101 0110001010 1010110110 0101000110
011100000 1000111001 0111000110 1001110001 0110001110
011100001 1000101110 0111010001 0111010001 1000101110
011100010 1000101101 0111010010 1011010001 0100101110
011100011 0111100011 1000100011 1100011110 1100010001
011100100 1000101011 0111010100 1101010001 0010101110
011100101 0111100101 1000100101 1010011110 1010010001
011100110 0111100110 1000100110 0110011110 0110010001
011100111 0111000111 1000111000 1110001110 0001110001
011101000 1000100111 0111011000 1110010001 0001101110
011101001 0111101001 1000101001 1001011110 1001010001
011101010 0111101010 1000101010 0101011110 0101010001
011101011 0111001011 0001001011 1101001110 1101001000
011101100 0111101100 1000101100 0011011110 0011010001
011101101 0111001101 0001001101 1011001110 1011001000
011101110 0111001110 0001001110 0111001110 0111001000
011101111 1000111010 0111000101 0101110001 1010001110
011110000 1000110110 0111001001 0110110001 1001001110
011110001 1110110001 1000110001 1000110111 1000110001
011110010 1110110010 1000110010 0100110111 0100110001
011110011 0111010011 1000010011 1100101110 1100100001
011110100 1110110100 1000110100 0010110111 0010110001
011110101 0111010101 1000010101 1010101110 1010100001
011110110 0111010110 1000010110 0110101110 0110100001
011110111 1000010111 0111101000 1110100001 0001011110
011111000 1000110011 0111001100 1100110001 0011001110
011111001 0111011001 1000011001 1001101110 1001100001
011111010 0111011010 1000011010 0101101110 0101100001
011111011 1000011011 0111100100 1101100001 0010011110
011111100 0111011100 1000011100 0011101110 0011100001
011111101 1000011101 0111100010 1011100001 0100011110
011111110 1000011110 0111100001 0111100001 1000011110
011111111 1000110101 0111001010 1010110001 0101001110
100011100 0010111100 1101000011 0011110100 1100001011
100111100 1001111100 0110000011 0011111001 1100000110
101011100 1010111100 0101000011 0011110101 1100001010
101111100 1100111100 0011000011 0011110011 1100001100
110011100 0100111100 1011000011 0011110010 1100001101
110111100 0101111100 1010000011 0011111010 1100000101
111011100 0110111100 1001000011 0011110110 1100001001
111111100 0001111100 1110000011 0011111000 1100000111
111110111 0001010111 1110101000 1110101000 0001010111
111111011 0001011011 1110100100 1101101000 0010010111
111111101 0001011101 1110100010 1011101000 0100010111
111111110 0001011110 1110100001 0111101000 1000010111
/*******************************************************************************
* Module: gtx_comma_align
* Date: 2015-07-11
* Author: Alexey
* Description: comma aligner implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_comma_align.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.
*
* gtx_comma_align.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
module gtx_comma_align(
input wire rst,
input wire clk,
// input data comes this way (standart 8/10 bit notation)
// cycle 0: {[hgfedcba]=1st byte,[hgfedcba]=0st byte}
// cycle 1: {[hgfedcba]=3rd byte,[hgfedcba]=2dn byte}
// => {[cycle1 data], [cycle0 data]} = as if we were reading by dwords
input wire [19:0] indata,
output wire [19:0] outdata,
// outdata contains comma
output wire comma,
// pulse, indicating that stream was once again adjusted to a comma
// if asserted after link was down - OK
// if asserted during a work - most likely indicates an error in a stream
output wire realign
// asserted when input stream looks like comma, but it is not
// later on after 10/8 it would get something link NOTINTHETABLE error anyways
// output wire error
);
// only comma character = K28.5, has 5 '1's or 5 '0's in a row.
// after we met it, call it a comma group, we could compare other symbols
/*
// create a window
reg [19:0] indata_r;
wire [23:0] window;
always @ (posedge clk)
indata_r <= indata;
assign window = {indata_r[17:0], indata[19:14]};
// search for a comma group - parallel 24-bit window into 20 5-bit words
// transposed -> 5 x 20-bit words
wire [19:0] lane0;
wire [19:0] lane1;
wire [19:0] lane2;
wire [19:0] lane3;
wire [19:0] lane4;
assign lane0 = window[19:0];
assign lane1 = window[20:1];
assign lane2 = window[21:2];
assign lane3 = window[22:3];
assign lane4 = window[23:4];
// calcute at what position in a window comma group is detected,
// so the position in actual {indata_r, indata} would be +2 from the left side
wire [19:0] comma_pos;
assign comma_pos = lane0 & lane1 & lane2 & lane3 & lane4;
*/
// seach for a comma
// TODO make it less expensive
reg [19:0] indata_r;
wire [38:0] window;
always @ (posedge clk)
indata_r <= indata;
assign window = {indata[18:0], indata_r};
// there is only 1 matched subwindow due to 20-bit comma's non-repetative pattern
wire [19:0] subwindow [19:0];
wire [19:0] comma_match;
wire [19:0] comma_match_p;
reg [19:0] aligned_data;
reg [19:0] comma_match_prev;
wire comma_detected;
wire [19:0] comma_p = 20'b10101010100101111100;
wire [19:0] comma_n = 20'b10101010101010000011;
genvar ii;
generate
for (ii = 0; ii < 20; ii = ii + 1)
begin: look_for_comma
assign subwindow[ii] = window[ii + 19:ii];
// assign comma_match[ii] = subwindow[ii] == 20'b01010101010011111010 | subwindow[ii] == 20'b01010101011100000101;
// stream comes inverted
assign comma_match_p[ii] = subwindow[ii] == comma_p;
assign comma_match[ii] = comma_match_p[ii] | subwindow[ii] == comma_n;
end
endgenerate
assign comma_detected = |comma_match;
// save the shift count
always @ (posedge clk)
comma_match_prev <= rst ? 20'h1 : comma_detected ? comma_match : comma_match_prev;
// shift
/* TODO
wire [38:0] shifted_window;
assign shifted_window = comma_detected ? {window >> (comma_match - 1)} : {window >> (comma_match_prev - 1)};
*/
// temp shift
wire [19:0] shifted_window;
wire [19:0] ored_subwindow [19:0];
wire [19:0] ored_subwindow_comdet [19:0];
assign ored_subwindow_comdet[0] = {20{comma_match_p[0]}} & comma_p | {20{~comma_match_p[0] & comma_match[0]}} & comma_n;
assign ored_subwindow[0] = {20{comma_match_prev[0]}} & subwindow[0];
generate
for (ii = 1; ii < 20; ii = ii + 1)
begin: or_all_possible_windows
assign ored_subwindow_comdet[ii] = {20{comma_match_p[ii]}} & comma_p | {20{~comma_match_p[ii] & comma_match[ii]}} & comma_n | ored_subwindow_comdet[ii-1]; // SuppressThisWarning VEditor -warning would be fixed in future releases
assign ored_subwindow[ii] = {20{comma_match_prev[ii]}} & subwindow[ii] | ored_subwindow[ii-1]; // SuppressThisWarning VEditor -warning would be fixed in future releases
end
endgenerate
assign shifted_window = comma_detected ? ored_subwindow_comdet[19] : ored_subwindow[19];
always @ (posedge clk)
// aligned_data <= comma_detected ? {window >> (comma_match - 1)}[19:0] : {window >> (comma_match_prev - 1)}[19:0];
aligned_data <= shifted_window[19:0];
// form outputs
assign comma = comma_detected;
assign realign = comma_detected & |(comma_match_prev ^ comma_match);
assign outdata = aligned_data;
endmodule
/*******************************************************************************
* Module: gtx_elastic
* Date: 2015-07-11
* Author: Alexey
* Description: elastic buffer implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_elastic.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.
*
* gtx_elastic.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
module gtx_elastic #(
parameter DEPTH_LOG2 = 4, // 3, // => 8 total rows
parameter OFFSET = 8 // 4 // distance between read and write pointers, = wr_ptr - rd_ptr
)
(
input wire rst,
input wire wclk,
input wire rclk,
input wire isaligned_in,
input wire [1:0] charisk_in,
input wire [1:0] notintable_in,
input wire [1:0] disperror_in,
input wire [15:0] data_in,
output wire isaligned_out,
output wire [1:0] charisk_out,
output wire [1:0] notintable_out,
output wire [1:0] disperror_out,
output wire [15:0] data_out,
// strobes LAST word in a dword primitive
output wire lword_strobe,
// status outputs, just in case
output wire full,
output wire empty
);
// gather inputs and outputs
wire [22:0] indata;
wire [22:0] outdata;
assign indata = {isaligned_in, notintable_in, disperror_in, charisk_in, data_in};
assign isaligned_out = outdata[22];
assign notintable_out = outdata[21:20];
assign disperror_out = outdata[19:18];
assign charisk_out = outdata[17:16];
assign data_out = outdata[15:0];
localparam HI = DEPTH_LOG2 - 1; // hi bus index
/*
* buffer itself
*/
// data storage
reg [22:0] ram [(1 << DEPTH_LOG2) - 1:0];
// data to/from fifo
wire [22:0] inram;
reg [22:0] outram;
// adresses in their natural clock domains
reg [HI:0] rd_addr;
reg [HI:0] wr_addr;
// incremened addresses
wire [HI:0] wr_next_addr;
wire [HI:0] rd_next_addr;
// gray coded addresses
reg [HI:0] rd_addr_gr;
reg [HI:0] wr_addr_gr;
// anti-metastability shift registers for gray-coded addresses
reg [HI:0] rd_addr_gr_r;
reg [HI:0] wr_addr_gr_r;
reg [HI:0] rd_addr_gr_rr;
reg [HI:0] wr_addr_gr_rr;
// resynced to opposite clks addresses
wire [HI:0] rd_addr_r;
wire [HI:0] wr_addr_r;
// fifo states
//wire full; // MAY BE full. ~full -> MUST NOT be full
//wire empty; // MAY BE empty. ~empty -> MUST NOT be empty
wire re;
wire we;
assign wr_next_addr = wr_addr + 1'b1;
assign rd_next_addr = rd_addr + 1'b1;
// wclk domain counters
always @ (posedge wclk)
begin
wr_addr <= rst ? {DEPTH_LOG2{1'b0}} : we ? wr_next_addr : wr_addr;
wr_addr_gr <= rst ? {DEPTH_LOG2{1'b0}} : we ? wr_next_addr ^ {1'b0, wr_next_addr[HI:1]} : wr_addr_gr;
end
// rclk domain counters
always @ (posedge rclk)
begin
rd_addr <= rst ? {DEPTH_LOG2{1'b0}} : re ? rd_next_addr : rd_addr;
rd_addr_gr <= rst ? {DEPTH_LOG2{1'b0}} : re ? rd_next_addr ^ {1'b0, rd_next_addr[HI:1]} : rd_addr_gr;
end
// write address -> rclk (rd) domain to compare
always @ (posedge rclk)
begin
wr_addr_gr_r <= rst ? {DEPTH_LOG2{1'b0}} : wr_addr_gr;
wr_addr_gr_rr <= rst ? {DEPTH_LOG2{1'b0}} : wr_addr_gr_r;
end
// read address -> wclk (wr) domain to compare
always @ (posedge wclk)
begin
rd_addr_gr_r <= rst ? {DEPTH_LOG2{1'b0}} : rd_addr_gr;
rd_addr_gr_rr <= rst ? {DEPTH_LOG2{1'b0}} : rd_addr_gr_r;
end
// translate resynced write address into ordinary (non-gray) address
genvar ii;
generate
for (ii = 0; ii <= HI; ii = ii + 1)
begin: wr_antigray
assign wr_addr_r[ii] = ^wr_addr_gr_rr[HI:ii];
end
endgenerate
// translate resynced read address into ordinary (non-gray) address
generate
for (ii = 0; ii <= HI; ii = ii + 1)
begin: rd_antigray
assign rd_addr_r[ii] = ^rd_addr_gr_rr[HI:ii];
end
endgenerate
// so we've got the following:
// wclk domain: wr_addr - current write address
// rd_addr_r - read address some wclk ticks ago
// => we can say if the fifo have the possibility to be full
// since actual rd_addr could only be incremented
//
// rclk domain: rd_addr - current read address
// wr_addr_r - write address some rclk ticks ago
// => we can say if the fifo have the possibility to be empty
// since actual wr_addr could only be incremented
assign full = wr_addr == rd_addr_r + 1'b1;
assign empty = wr_addr_r == rd_addr;
always @ (posedge rclk)
outram <= ram[rd_addr];
always @ (posedge wclk)
if (we)
ram[wr_addr] <= inram;
// elactic part
// control fifo state @ rclk domain
// sends a pulse to wclk domain for every necessary ALIGNP removal
// waits for response from wclk domain of a successful removal
// pauses fifo read and inserts ALIGNP
// @ rclk
// calculating an offset - a distance between write and read pointers
wire [HI:0] current_offset;
assign current_offset = wr_addr_r - rd_addr;
// more records in fifo than expected on 1 primitive = 2 words = 2 records
wire offset_more_on_1;
// more records in fifo than expected on 2 primitives or more = 4 words + = 4 records +
wire offset_more_on_2;
// less records than expected - can insert a lot of alignes instantly, so exact count is not important
wire offset_less;
// doesnt bother if offset is more on 1 word.
assign offset_more_on_1 = current_offset == (OFFSET + 2) | current_offset == (OFFSET + 3);
assign offset_more_on_2 = (current_offset > (OFFSET + 1)) & ~offset_more_on_1;
assign offset_less = current_offset < OFFSET;
`ifdef ENABLE_CHECKERS
always @ (posedge clk)
if (offset_less & (offset_more_on_1 | offset_more_on_1)) begin
$display("Error in %m. Wrong offset calculations");
$finish;
end
`endif
/*
* Case when we need to get rid of extra elements in fifo
*/
// control part @ rclk
wire rmv_ack_rclk;
wire state_idle_rmv;
reg state_rmv1_req;
reg state_rmv2_req;
reg state_wait_ack;
wire set_rmv1_req;
wire set_rmv2_req;
wire set_wait_ack;
wire clr_rmv1_req;
wire clr_rmv2_req;
wire clr_wait_ack;
assign state_idle_rmv = ~state_rmv1_req & ~state_rmv2_req & ~state_wait_ack;
assign set_rmv1_req = state_idle_rmv & offset_more_on_1;
assign set_rmv2_req = state_idle_rmv & offset_more_on_2;
assign set_wait_ack = state_rmv1_req | state_rmv2_req;
assign clr_rmv1_req = set_wait_ack;
assign clr_rmv2_req = set_wait_ack;
assign clr_wait_ack = rmv_ack_rclk;
always @ (posedge rclk)
begin
state_rmv1_req <= (state_rmv1_req | set_rmv1_req) & ~clr_rmv1_req & ~rst;
state_rmv2_req <= (state_rmv2_req | set_rmv2_req) & ~clr_rmv2_req & ~rst;
state_wait_ack <= (state_wait_ack | set_wait_ack) & ~clr_wait_ack & ~rst;
end
`ifdef ENABLE_CHECKERS
always @ (posedge rclk)
if (~rst)
if ((4'h0
+ state_rmv1_req
+ state_rmv2_req
+ state_wait_ack
+ state_idle_rmv
) == 4'h1) begin
// all good
end
else
begin
$display("Error in %m: wrong fsm states: %b", {state_rmv1_req, state_rmv2_req, state_wait_ack, state_idle_rmv});
$finish;
end
`endif
// align removal logic @ wclk
// we MUST compare current and next data pack even if the current one is a comma because
// the next data word could be either valid ALIGNP's or any other 2 bytes, which shall tell
// link layer that incorrect primitive has been received, so it can't be skipped
// also NO DISPARITY ERROR would be dropped
reg [22:0] indata_r;
always @ (posedge wclk)
indata_r <= indata;
// align is stored in a buffer right now
// ALIGNP = 7B4A4ABC
// charisk : 0 0 0 1
// notintbl: 0 0 0 0
// disperr: 0 0 0 0
wire align_det;
assign align_det = {indata[15:0], indata_r[15:0]} == 32'h7B4A4ABC
& {indata[17:16], indata_r[17:16]} == 4'b0001
& {indata[19:18], indata_r[19:18]} == 4'b0000
& {indata[21:20], indata_r[21:20]} == 4'b0000;
// fsm
/*
* bypass --req1--> wait for align --------------------------------------------------------> skip 1 primitive -> send ack -> bypass
* \ | /\
* req2--> wait for align -> skip 1 primitive -> wait until next ------align in buf--+ |
* prim is in buffer --not align in buf------------------------------+
*/
wire skip_write;
wire rmv1_req_wclk;
wire rmv2_req_wclk;
reg next_prim_loaded;
wire state_bypass_rmv;
reg state_wait1_align;
reg state_skip1_align;
reg state_wait2_align;
reg state_skip2_align;
reg state_wait_next_p;
reg state_send_ack;
wire set_wait1_align;
wire set_skip1_align;
wire set_wait2_align;
wire set_skip2_align;
wire set_wait_next_p;
wire set_send_ack;
wire clr_wait1_align;
wire clr_skip1_align;
wire clr_wait2_align;
wire clr_skip2_align;
wire clr_wait_next_p;
wire clr_send_ack;
always @ (posedge wclk)
next_prim_loaded <= state_wait_next_p;
assign state_bypass_rmv = ~state_wait1_align & ~state_skip1_align & ~state_wait2_align & ~state_skip2_align & ~state_wait_next_p & ~state_send_ack;
assign set_wait1_align = state_bypass_rmv & rmv1_req_wclk & ~rmv2_req_wclk;
assign set_skip1_align = state_wait1_align & align_det | state_wait_next_p & next_prim_loaded & align_det;
assign set_wait2_align = state_bypass_rmv & rmv2_req_wclk;
assign set_skip2_align = state_wait2_align & align_det;
assign set_wait_next_p = state_skip2_align;
assign set_send_ack = state_skip1_align | state_wait_next_p & next_prim_loaded & ~align_det; // 1 cycle skip - while set_skip1, 2nd cycle - while state_skip1
assign clr_wait1_align = set_skip1_align;
assign clr_skip1_align = set_send_ack;
assign clr_wait2_align = set_skip2_align;
assign clr_skip2_align = set_wait_next_p;
assign clr_wait_next_p = set_send_ack | set_skip1_align;
assign clr_send_ack = state_send_ack;
always @ (posedge wclk)
begin
state_wait1_align <= (state_wait1_align | set_wait1_align) & ~clr_wait1_align & ~rst;
state_skip1_align <= (state_skip1_align | set_skip1_align) & ~clr_skip1_align & ~rst;
state_wait2_align <= (state_wait2_align | set_wait2_align) & ~clr_wait2_align & ~rst;
state_skip2_align <= (state_skip2_align | set_skip2_align) & ~clr_skip2_align & ~rst;
state_wait_next_p <= (state_wait_next_p | set_wait_next_p) & ~clr_wait_next_p & ~rst;
state_send_ack <= (state_send_ack | set_send_ack ) & ~clr_send_ack & ~rst;
end
assign skip_write = set_skip1_align | state_skip1_align;
assign inram = indata_r;
assign we = ~skip_write;
// cross-domain messaging
// just to simplify an algorithm, we don't serialize a request to remove 2 ALIGNP,
// instead make 2 independent request lines
pulse_cross_clock remove1_req(
.rst (rst),
.src_clk (rclk),
.dst_clk (wclk),
.in_pulse (state_rmv1_req),
.out_pulse (rmv1_req_wclk),
.busy ()
);
pulse_cross_clock remove2_req(
.rst (rst),
.src_clk (rclk),
.dst_clk (wclk),
.in_pulse (state_rmv2_req),
.out_pulse (rmv2_req_wclk),
.busy ()
);
// removal request ack
pulse_cross_clock remove_ack(
.rst (rst),
.src_clk (wclk),
.dst_clk (rclk),
.in_pulse (state_send_ack),
.out_pulse (rmv_ack_rclk),
.busy ()
);
// insert additional ALINGPs to head @ rclk
// 1 way to implement - search for align primitive at the head of fifo, and insert enough alignes right after detected one
// 2nd way - continiously send a pulse, indicating 1st word of each primitive.
// Choosing the 1st way
// start algorithm after fifo gets in a stable state - let it fill to predefined offset count
reg fifo_stable;
always @ (posedge rclk)
fifo_stable <= rst ? 1'b0 : ~fifo_stable & ~offset_less | fifo_stable;
// once again check if the current half-primitive is a part of an align
// no need to latch the whole outram
// indicator, that @ previous clock cycle there was a first word of ALIGNP
reg align_1st;
always @ (posedge rclk)
align_1st <= outram[15:0] == 16'h4ABC
& outram[17:16] == 2'b01
& outram[19:18] == 2'b00
& outram[21:20] == 2'b00;
// indicates that current word is a second word of ALIGNP
wire align_2nd;
assign align_2nd = outram[15:0] == 16'h7B4A
& outram[17:16] == 2'b00
& outram[19:18] == 2'b00
& outram[21:20] == 2'b00;
// whole align primitive is the last thing we read from fifo
reg read_align;
wire pause_read;
always @ (posedge rclk)
read_align <= rst ? 1'b0 : pause_read | align_1st & align_2nd;
// just to alternate alignp's words, = 0 => 1st word, = 1 => 2nd word
reg align_altern;
// also pause when offset gets ok, but only 1st word of alignp is sent - need to send 2nd word
assign pause_read = read_align & offset_less & fifo_stable | align_altern;
always @ (posedge rclk)
align_altern <= rst | ~pause_read ? 1'b0 : ~align_altern;
// choose 1 of 2 words of ALIGNP
wire [22:0] align_word;
assign align_word = {outram[22], 22'h007B4A} & {23{align_altern}} | {outram[22], 22'h014ABC} & {23{~align_altern}};
// output data would be valid the next clock they are issued
reg pause_read_r;
always @ (posedge rclk)
pause_read_r <= pause_read;
// read when compensation is not issued and when fifo gets required fullfillment
assign re = ~pause_read & fifo_stable;
assign outdata = {23{~pause_read_r}} & outram | {23{pause_read_r}} & align_word;
// indicates last cycle before the next primitive
wire fword_strobe_correction;
reg fword_strobe;
`ifdef SIMULATION
assign fword_strobe_correction = (align_1st === 1'bx || align_2nd === 1'bx) ? 1'b0 : align_1st & align_2nd ;
`else
assign fword_strobe_correction = align_1st & align_2nd;
`endif
always @ (posedge rclk)
fword_strobe <= rst ? 1'b0 : fword_strobe_correction ? 1'b1 : lword_strobe;
assign lword_strobe = ~fword_strobe;
endmodule
/*******************************************************************************
* Module: gtx_wrap
* Date: 2015-08-24
* Author: Alexey
* Description: shall replace gtx's PCS part functions, bypassing PCS itself in gtx
*
* Copyright (c) 2015 Elphel, Inc.
* gtx_wrap.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.
*
* gtx_wrap.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
//`include "gtx_8x10enc.v"
//`include "gtx_10x8dec.v"
//`include "gtx_comma_align.v"
//`include "gtx_elastic.v"
// All computations have been done in assumption of GTX interface being 20 bits wide!
//`include "system_defines.v"
//`define DEBUG_ELASTIC
module gtx_wrap #(
`ifdef USE_DATASCOPE
parameter ADDRESS_BITS = 10, // for datascope
parameter DATASCOPE_START_BIT = 14, // bit of DRP "other_control" to start recording after 0->1 (needs DRP)
parameter DATASCOPE_POST_MEAS = 16, // number of measurements to perform after event
`endif
parameter DATA_BYTE_WIDTH = 4,
parameter TXPMARESET_TIME = 5'h1,
parameter RXPMARESET_TIME = 5'h11,
parameter RXCDRPHRESET_TIME = 5'h1,
parameter RXCDRFREQRESET_TIME = 5'h1,
parameter RXDFELPMRESET_TIME = 7'hf,
parameter RXISCANRESET_TIME = 5'h1,
parameter ELASTIC_DEPTH = 4, //5, With 4/7 got infrequent overflows!
parameter ELASTIC_OFFSET = 7 // 5 //10
)
(
output reg debug = 0,
output wire cplllock,
input wire cplllockdetclk,
input wire cpllreset,
input wire gtrefclk,
input wire rxuserrdy,
input wire txuserrdy,
// input wire rxusrclk,
input wire rxusrclk2,
input wire rxp,
input wire rxn,
output wire rxbyteisaligned,
input wire rxreset,
output wire rxcomwakedet,
output wire rxcominitdet,
output wire rxelecidle,
output wire rxresetdone,
input wire clk_phase_align_req,
output wire clk_phase_align_ack,
input wire txreset,
input wire txusrclk,
input wire txusrclk2,
input wire txelecidle,
output wire txp,
output wire txn,
output wire txoutclk, // global clock
input wire txpcsreset,
output wire txresetdone,
input wire txcominit,
input wire txcomwake,
output wire txcomfinish, // @txusrclk2
// elastic buffer status
output wire rxelsfull,
output wire rxelsempty,
input wire [DATA_BYTE_WIDTH * 8 - 1:0] txdata,
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk,
output wire [DATA_BYTE_WIDTH * 8 - 1:0] rxdata,
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk,
output wire [DATA_BYTE_WIDTH - 1:0] rxnotintable,
output wire [DATA_BYTE_WIDTH - 1:0] rxdisperr,
output wire dbg_rxphaligndone,
output wire dbg_rx_clocks_aligned,
output wire dbg_rxcdrlock,
output wire dbg_rxdlysresetdone,
output wire [1:0] txbufstatus,
output xclk // just to measure frequency to set the local clock (global clock)
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
,output datascope_clk,
output [ADDRESS_BITS-1:0] datascope_waddr,
output datascope_we,
// output reg [31:0] datascope_di,
output [31:0] datascope_di,
input datascope_trig // external trigger event for the datascope
`endif
`ifdef USE_DRP
,input drp_rst,
input drp_clk,
input drp_en, // @aclk strobes drp_ad
input drp_we,
input [14:0] drp_addr,
input [15:0] drp_di,
output drp_rdy,
output [15:0] drp_do
`endif
`ifdef DEBUG_ELASTIC
,output reg [15:0] dbg_data_cntr // 4 MSB - got other primitives during data receive
`endif
);
wire rxresetdone_gtx;
wire txresetdone_gtx;
reg wrap_rxreset_;
reg wrap_txreset_;
// resets while PCS resets, active low
always @ (posedge rxusrclk2) wrap_rxreset_ <= rxuserrdy & rxresetdone_gtx;
always @ (posedge txusrclk2) wrap_txreset_ <= txuserrdy & txresetdone_gtx;
wire [63:0] rxdata_gtx;
wire [7:0] rxcharisk_gtx;
wire [7:0] rxdisperr_gtx;
wire [63:0] txdata_gtx;
wire [7:0] txcharisk_gtx;
wire [7:0] txchardispval_gtx;
wire [7:0] txchardispmode_gtx;
// 8/10 encoder ifaces
wire [19:0] txdata_enc_out;
wire [15:0] txdata_enc_in;
wire [1:0] txcharisk_enc_in;
/*
* TX PCS, minor changes: 8/10 encoder + user interface resync
*/
// assuming GTX interface width = 20 bits
assign txdata_gtx = {48'h0, txdata_enc_out[17:10], txdata_enc_out[7:0]};
assign txcharisk_gtx = 8'h0; // 8/10 encoder is bypassed in gtx
assign txchardispmode_gtx = {6'h0, txdata_enc_out[19], txdata_enc_out[9]};
assign txchardispval_gtx = {6'h0, txdata_enc_out[18], txdata_enc_out[8]};
// Interface part
// @ gtx iface clk
wire txcominit_gtx;
wire txcomwake_gtx;
wire txelecidle_gtx;
`ifdef USE_DRP
wire [1:0] drp_en_w; // [0] - select GTX, [1] - select drp_other_registers
wire [1:0] drp_we_w; // [0] - select GTX, [1] - select drp_other_registers
reg [1:0] drp_sel; // [0] - select GTX, [1] - select drp_other_registers
wire [15:0] drp_do_gtx;
wire [15:0] drp_do_meas;
wire drp_rdy_gtx;
wire drp_rdy_meas;
wire [15:0] other_control; // control bits programmed over DRP interface
assign drp_rdy = (drp_sel[0] & drp_rdy_gtx) | (drp_sel[1] & drp_rdy_meas);
assign drp_do = ({16{drp_sel[0]}} & drp_do_gtx) | ({16{drp_sel[1]}} & drp_do_meas);
assign drp_en_w = {2{drp_en & ~(|drp_addr[14:10])}} & {drp_addr[9],~drp_addr[9]};
assign drp_we_w = {2{drp_we & ~(|drp_addr[14:10])}} & {drp_addr[9],~drp_addr[9]};
always @ (posedge drp_clk) drp_sel <= {2{~(|drp_addr[14:10])}} & {drp_addr[9],~drp_addr[9]};
`endif
// insert resync if it's necessary
generate
if (DATA_BYTE_WIDTH == 4) begin
// resync to txusrclk
// 2*Fin = Fout => WIDTHin = 2*WIDTHout
// Andrey:
reg txdata_resync_strobe;
reg [15:0] txdata_enc_in_r; // TODO: remove async reset
reg [ 1:0] txcharisk_enc_in_r; // TODO: remove async reset
wire [38:0] txdata_resync_out;
wire txdata_resync_valid;
reg [1:0] txcomwake_gtx_f; // 2 registers just to match latency (data to the 3 next) in Alexey's code, probably not needed
reg [1:0] txcominit_gtx_f;
reg [1:0] txelecidle_gtx_f;
resync_data #( // TODO: update output register.. OK as it is
.DATA_WIDTH(39),
.DATA_DEPTH(3),
.INITIAL_VALUE(39'h4000000000) // All 0 but txelecidle_gtx
) txdata_resynchro (
.arst (txreset), // input
.srst (~wrap_txreset_), // input
.wclk (txusrclk2), // input
.rclk (txusrclk), // input
.we (1'b1), // input
.re (txdata_resync_strobe), // input
.data_in ({txelecidle, txcominit, txcomwake, txcharisk, txdata}), // input[15:0]
.data_out (txdata_resync_out), // output[15:0] reg
.valid (txdata_resync_valid) // output reg
);
always @ (posedge txreset or posedge txusrclk) begin
if (txreset) txdata_resync_strobe <= 0;
else if (txdata_resync_valid) txdata_resync_strobe <= ~txdata_resync_strobe;
if (txreset) begin
txcomwake_gtx_f <= 0;
txcominit_gtx_f <= 0;
txelecidle_gtx_f <= ~0;
end else begin
txcomwake_gtx_f <= {txdata_resync_out[36],txcomwake_gtx_f[1]};
txcominit_gtx_f <= {txdata_resync_out[37],txcominit_gtx_f[1]};
txelecidle_gtx_f <= {txdata_resync_out[38],txelecidle_gtx_f[1]};
end
end
// Changing to sync reset (otherwise WARNING: [DRC 23-20] Rule violation (REQP-1839) RAMB36 async control check ...)
always @ (posedge txusrclk) begin
if (txreset) begin
txdata_enc_in_r <= 0;
txcharisk_enc_in_r <= 0;
end else if (txdata_resync_valid) begin
txdata_enc_in_r <= txdata_resync_strobe? txdata_resync_out[31:16]: txdata_resync_out[15:0];
txcharisk_enc_in_r <= txdata_resync_strobe? txdata_resync_out[35:34]: txdata_resync_out[33:32];
end
end
assign txdata_enc_in = txdata_enc_in_r;
assign txcharisk_enc_in = txcharisk_enc_in_r;
assign txcominit_gtx = txcominit_gtx_f[0];
assign txcomwake_gtx = txcomwake_gtx_f[0];
assign txelecidle_gtx = txelecidle_gtx_f[0];
end
else
if (DATA_BYTE_WIDTH == 2) begin
// no resync is needed => straightforward assignments
assign txdata_enc_in = txdata[15:0];
assign txcharisk_enc_in = txcharisk[1:0];
assign txcominit_gtx = txcominit;
assign txcomwake_gtx = txcomwake;
assign txelecidle_gtx = txelecidle;
end
else begin
// unconsidered case
always @ (posedge txusrclk)
begin
$display("Wrong width set in %m, value is %d", DATA_BYTE_WIDTH);
end
end
endgenerate
// 8/10 encoder @ txusrclk, 16 + 1 bits -> 20
gtx_8x10enc gtx_8x10enc(
.rst (~wrap_txreset_),
.clk (txusrclk),
.indata (txdata_enc_in),
.inisk (txcharisk_enc_in),
.outdata (txdata_enc_out)
);
// Adjust RXOUTCLK so RXUSRCLK (==xclk) matches SIPO output data
`ifdef CLK_ADJUST_VARIANT_1
wire rxcdrlock; // Marked as "reserved" - maybe not use it, only rxelecidle?
reg rxdlysreset = 0;
wire rxphaligndone;
wire rxdlysresetdone; // gtx output
reg rx_clocks_aligned = 0;
reg [2:0] rxdlysreset_cntr = 7;
reg rxdlysresetdone_r;
assign dbg_rxphaligndone = rxphaligndone; // never gets up?
assign dbg_rx_clocks_aligned = rx_clocks_aligned;
assign dbg_rxcdrlock = rxcdrlock; //goes in/out (because of the SS ?
assign dbg_rxdlysresetdone = rxdlysresetdone_r;
always @ (posedge xclk) begin
// if (rxelecidle || !rxcdrlock) rxdlysreset_cntr <= 5;
if (rxelecidle) rxdlysreset_cntr <= 5;
else if (|rxdlysreset_cntr) rxdlysreset_cntr <= rxdlysreset_cntr - 1;
// if (rxelecidle || !rxcdrlock) rxdlysreset <= 0;
if (rxelecidle) rxdlysreset <= 0;
else rxdlysreset <= |rxdlysreset_cntr;
// if (rxelecidle || !rxcdrlock || rxdlysreset || |rxdlysreset_cntr) rx_clocks_aligned <= 0;
// if (rxelecidle || rxdlysreset || |rxdlysreset_cntr) rx_clocks_aligned <= 0;
if (rxelecidle) rx_clocks_aligned <= 0;
// else if (rxphaligndone) rx_clocks_aligned <= 1;
else if (rxphaligndone) rx_clocks_aligned <= 1;
if (rxelecidle || rxdlysreset || |rxdlysreset_cntr) rxdlysresetdone_r <= 0;
else if (rxdlysresetdone) rxdlysresetdone_r <= 1;
end
`else
// time to first rxphaligndone ~450ns, time to second (that should stay - 4.9 usec, still much less than allowed ALIGNp response time)
wire rxdlysreset = clk_phase_align_req;
reg rxphaligndone1_r = 0; // first time rxphaligndone gets active
reg rxphaligndone2_r = 0; // rxphaligndone deasserted
reg rx_clocks_aligned = 0; // second time rxphaligndone gets active (and is supposed to stay)
reg rxdlysresetdone_r; // debug only
wire rxphaligndone;
wire rxdlysresetdone;
wire rxcdrlock; // Marked as "reserved" - maybe not use it, only rxelecidle? (seems alternating 0/1 forever- SS?)
assign clk_phase_align_ack = rx_clocks_aligned;
assign dbg_rxphaligndone = rxphaligndone; // never gets up?
assign dbg_rx_clocks_aligned = rx_clocks_aligned;
assign dbg_rxcdrlock = rxcdrlock; //goes in/out (because of the SS ?
assign dbg_rxdlysresetdone = rxdlysresetdone_r;
wire bypass_aligned;
`ifdef USE_DRP
assign bypass_aligned = other_control[0];
`else
assign bypass_aligned = 0;
`endif
`ifdef ALIGN_CLOCKS
wire first_confirm = rxphaligndone || (bypass_aligned && clk_phase_align_req);
always @ (posedge xclk) begin
if (rxelecidle) rxphaligndone1_r <= 0;
else if (first_confirm) rxphaligndone1_r <= 1;
if (rxelecidle) rxphaligndone2_r <= 0;
else if (rxphaligndone1_r && !first_confirm) rxphaligndone2_r <= 1;
if (rxelecidle) rx_clocks_aligned <= 0;
else if (rxphaligndone2_r && (rxphaligndone || bypass_aligned)) rx_clocks_aligned <= 1;
if (rxelecidle || rxdlysreset) rxdlysresetdone_r <= 0; // debug only
else if (rxdlysresetdone) rxdlysresetdone_r <= 1;
end
`else // ALIGN_CLOCKS - just bypassing
always @ (posedge xclk) begin
if (rxelecidle) rxphaligndone1_r <= 0;
else if (clk_phase_align_req) rxphaligndone1_r <= 1;
if (rxelecidle) rxphaligndone2_r <= 0;
else if (rxphaligndone1_r && !clk_phase_align_req) rxphaligndone2_r <= 1;
if (rxelecidle) rx_clocks_aligned <= 0;
else if (rxphaligndone2_r) rx_clocks_aligned <= 1;
if (rxelecidle || rxdlysreset) rxdlysresetdone_r <= 0;
else if (rxphaligndone2_r) rxdlysresetdone_r <= 1;
end
`endif
`endif
/*
* RX PCS part: comma detect + align module, 10/8 decoder, elastic buffer, interface resynchronisation
* all modules before elastic buffer shall work on a restored clock - xclk
*/
// wire xclk; make it output to measure frequency
// assuming GTX interface width = 20 bits
// comma aligner
wire [19:0] rxdata_comma_out;
wire [19:0] gtx_rx_data20 = {rxdisperr_gtx[1], rxcharisk_gtx[1], rxdata_gtx[15:8], rxdisperr_gtx[0], rxcharisk_gtx[0], rxdata_gtx[7:0]};
wire [19:0] rxdata_comma_in;
// TODO: Add timing constraints on gtx_rx_data20 to reduce spread between bits?
//`ifndef USE_DRP
// `define USE_DRP
//`endif
// asynchronous signals to be controlled by external programmable bits
wire RXPHDLYRESET; // 1 (1'b0),
wire RXPHALIGN; // 2 (1'b0),
wire RXPHALIGNEN; // 3 (1'b0),
wire RXPHDLYPD; // 4 (1'b0),
wire RXPHOVRDEN; // 5 (1'b0),
wire RXDLYSRESET; // 6 (rxdlysreset),
wire RXDLYBYPASS; // 7 (1'b0), // Andrey: p.243: "0: Uses the RX delay alignment circuit."
wire RXDLYEN; // 8 (1'b0),
wire RXDLYOVRDEN; // 9 (1'b0),
wire RXDDIEN; // 10 (1'b1), // Andrey: p.243: "Set high in RX buffer bypass mode"
wire RXLPMEN; // 11 (1'b0) 1 - enable LP, 0 - DXE
reg [19:0] rxdata_comma_in_r;
assign rxdata_comma_in = rxdata_comma_in_r;
always @ (posedge xclk)
rxdata_comma_in_r <= gtx_rx_data20;
`ifdef USE_DRP
drp_other_registers #(
.DRP_ABITS(8),
.DRP_REG0(8),
.DRP_REG1(9),
.DRP_REG2(10),
.DRP_REG3(11)
) drp_other_registers_i (
.drp_rst (drp_rst), // input
.drp_clk (drp_clk), // input
.drp_en (drp_en_w[1]), // input
.drp_we (drp_we_w[1]), // input
.drp_addr (drp_addr[7:0]), // input[7:0]
.drp_di (drp_di), // input[15:0]
.drp_rdy (drp_rdy_meas), // output reg
.drp_do (drp_do_meas), // output[15:0] reg
.drp_register0 (), // output[15:0] // reserved for future use
.drp_register1 (), // output[15:0] // reserved for future use
.drp_register2 (), // output[15:0] // reserved for future use
.drp_register3 (other_control) // output[15:0] // reserved for future use
);
assign RXPHDLYRESET = other_control[ 1]; // 1 (1'b0),
assign RXPHALIGN = other_control[ 2]; // 2 (1'b0),
assign RXPHALIGNEN = other_control[ 3]; // 3 (1'b0),
assign RXPHDLYPD = other_control[ 4]; // 4 (1'b0),
assign RXPHOVRDEN = other_control[ 5]; // 5 (1'b0),
assign RXDLYSRESET = other_control[ 6]; // 6 (rxdlysreset),
assign RXDLYBYPASS = other_control[ 7]; // 7 (1'b0), // Andrey: p.243: "0: Uses the RX delay alignment circuit."
assign RXDLYEN = other_control[ 8]; // 8 (1'b0),
assign RXDLYOVRDEN = other_control[ 9]; // 9 (1'b0),
assign RXDDIEN = other_control[10]; // 10 (1'b1), // Andrey: p.243: "Set high in RX buffer bypass mode"
assign RXLPMEN = other_control[11]; // 11 (1'b0) 1 - enable LP, 0 - DXE
`else
// VDT bug - considered USE_DRP undefined during closure, temporary including unconnected module
drp_other_registers #(
.DRP_ABITS (8),
.DRP_REG0 (8),
.DRP_REG1 (9),
.DRP_REG2 (10),
.DRP_REG3 (11)
) drp_other_registers_i (
.drp_rst (1'b0), // input
.drp_clk (1'b0), // input
.drp_en (1'b0), // input
.drp_we (1'b0), // input
.drp_addr (8'b0), // input[7:0]
.drp_di (16'b0),// input[15:0]
.drp_rdy (), // output reg
.drp_do (), // output[15:0] reg
.drp_register0 (), // output[15:0] // reserved for future use
.drp_register1 (), // output[15:0] // reserved for future use
.drp_register2 (), // output[15:0] // reserved for future use
.drp_register3 () // output[15:0] // reserved for future use
);
assign RXPHDLYRESET = 1'b0;; // 1 (1'b0),
assign RXPHALIGN = 1'b0;; // 2 (1'b0),
assign RXPHALIGNEN = 1'b0;; // 3 (1'b0),
assign RXPHDLYPD = 1'b0;; // 4 (1'b0),
assign RXPHOVRDEN = 1'b0;; // 5 (1'b0),
assign RXDLYSRESET = 1'b0;; // 6 (rxdlysreset),
`ifdef ALIGN_CLOCKS
assign RXDLYBYPASS = 1'b0; // 7 (1'b0), // Andrey: p.243: "0: Uses the RX delay alignment circuit."
`else
assign RXDLYBYPASS = 1'b1; // 7 (1'b0), // Andrey: p.243: "0: Uses the RX delay alignment circuit."
`endif
assign RXDLYEN = 1'b0; // 8 (1'b0),
assign RXDLYOVRDEN = 1'b0; // 9 (1'b0),
`ifdef ALIGN_CLOCKS
assign RXDDIEN = 1'b1; // Andrey: p.243: "Set high in RX buffer bypass mode"
`else
assign RXDDIEN = 1'b0; // 10 (1'b1), // Andrey: p.243: "Set high in RX buffer bypass mode"
`endif
assign RXLPMEN = 1'b0; // 11 (1'b0) 1 - enable LP, 0 - DXE
`endif
// aligner status generation
// if we detected comma & there was 1st realign after non-aligned state -> triggered, we wait until the next comma
// if no realign would be issued, assumes, that we've aligned to the stream otherwise go back to non-aligned state
wire comma;
wire realign;
wire state_nonaligned;
reg state_aligned;
reg state_triggered;
wire set_aligned;
wire set_triggered;
wire clr_aligned;
wire clr_triggered;
assign state_nonaligned = ~state_aligned & ~state_triggered;
assign set_aligned = state_triggered & comma & ~realign;
assign set_triggered = state_nonaligned & comma;
assign clr_aligned = realign;
assign clr_triggered = realign;
always @ (posedge xclk)
begin
state_aligned <= (set_aligned | state_aligned ) & wrap_rxreset_ & ~clr_aligned;
state_triggered <= (set_triggered | state_triggered) & wrap_rxreset_ & ~clr_triggered;
end
gtx_comma_align gtx_comma_align(
// .rst (~rx_clocks_aligned), // ~wrap_rxreset_),
.rst (~wrap_rxreset_),
.clk (xclk),
.indata (rxdata_comma_in),
.outdata (rxdata_comma_out),
.comma (comma),
.realign (realign)
);
//
// 10x8 decoder
wire [15:0] rxdata_dec_out;
wire [1:0] rxcharisk_dec_out;
wire [1:0] rxnotintable_dec_out;
wire [1:0] rxdisperr_dec_out;
gtx_10x8dec gtx_10x8dec(
// .rst (~rx_clocks_aligned), // ~wrap_rxreset_),
.rst (~wrap_rxreset_),
.clk (xclk),
.indata (rxdata_comma_out),
.outdata (rxdata_dec_out),
.outisk (rxcharisk_dec_out),
.notintable (rxnotintable_dec_out),
.disperror (rxdisperr_dec_out)
);
// iface resync
wire rxcomwakedet_gtx;
wire rxcominitdet_gtx;
elastic1632 #(
.DEPTH_LOG2 (ELASTIC_DEPTH), // 16 //4),
.OFFSET (ELASTIC_OFFSET) // 10 //5)
) elastic1632_i (
.wclk (xclk), // input 150MHz, recovered
.rclk (rxusrclk2), // input 75 MHz, system
.isaligned_in (state_aligned), // input Moved clock phase reset/align to OOB module to handle
.charisk_in (rxcharisk_dec_out), // input[1:0]
.notintable_in (rxnotintable_dec_out), // input[1:0]
.disperror_in (rxdisperr_dec_out), // input[1:0]
.data_in (rxdata_dec_out), // input[15:0]
.isaligned_out (rxbyteisaligned), // output
.charisk_out (rxcharisk), // output[3:0] reg
.notintable_out (rxnotintable), // output[3:0] reg
.disperror_out (rxdisperr), // output[3:0] reg
.data_out (rxdata), // output[31:0] reg
.full (rxelsfull), // output
.empty (rxelsempty) // output
);
`ifdef DEBUG_ELASTIC
localparam ALIGN_PRIM = 32'h7B4A4ABC;
localparam SOF_PRIM = 32'h3737b57c;
localparam EOF_PRIM = 32'hd5d5b57c;
localparam CONT_PRIM = 32'h9999aa7c;
localparam HOLD_PRIM = 32'hd5d5aa7c;
localparam HOLDA_PRIM = 32'h9595aa7c;
localparam WTRM_PRIM = 32'h5858b57c;
reg [15:0] dbg_data_in_r;
reg [1:0] dbg_charisk_in_r;
reg dbg_aligned32_in_r; // input data is word-aligned and got ALIGNp
reg dbg_msb_in_r; // input contains MSB
reg [11:0] dbg_data_cntr_r;
reg [3:0] got_prims_r;
reg dbg_frun;
reg dbg_is_sof_r;
reg dbg_is_eof_r;
reg dbg_is_data_r;
wire dbg_is_alignp_w = ({rxdata_dec_out, dbg_data_in_r} == ALIGN_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_sof_w = ({rxdata_dec_out, dbg_data_in_r} == SOF_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_eof_w = ({rxdata_dec_out, dbg_data_in_r} == EOF_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_cont_w = ({rxdata_dec_out, dbg_data_in_r} == CONT_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_hold_w = ({rxdata_dec_out, dbg_data_in_r} == HOLD_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_holda_w = ({rxdata_dec_out, dbg_data_in_r} == HOLDA_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_wrtm_w = ({rxdata_dec_out, dbg_data_in_r} == WTRM_PRIM) && ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h1);
wire dbg_is_data_w = ({rxcharisk_dec_out, dbg_charisk_in_r} == 4'h0);
always @ (posedge xclk) begin
dbg_data_in_r <= rxdata_dec_out;
dbg_charisk_in_r <= rxcharisk_dec_out;
dbg_is_sof_r <= dbg_is_sof_w;
dbg_is_eof_r <= dbg_is_eof_w;
dbg_is_data_r <=dbg_is_data_w && dbg_msb_in_r;
if (!dbg_aligned32_in_r && !dbg_is_alignp_w) dbg_msb_in_r <= 1;
else dbg_msb_in_r <= !dbg_msb_in_r;
if (!state_aligned) dbg_aligned32_in_r <= 0;
else if (dbg_is_alignp_w) dbg_aligned32_in_r <= 1;
if (!dbg_aligned32_in_r || dbg_is_sof_r) got_prims_r <= 0;
else if (dbg_frun) got_prims_r <= got_prims_r | {dbg_is_cont_w, dbg_is_hold_w, dbg_is_holda_w, dbg_is_wrtm_w};
if (!dbg_aligned32_in_r || dbg_is_eof_r) dbg_frun <= 0;
else if (dbg_is_sof_r) dbg_frun <= 1;
if (!dbg_aligned32_in_r || dbg_is_sof_r) dbg_data_cntr_r <= 0;
else if (dbg_frun && dbg_is_data_r) dbg_data_cntr_r <= dbg_data_cntr_r + 1;
if (!dbg_aligned32_in_r || dbg_is_sof_r) dbg_data_cntr <= {got_prims_r, dbg_data_cntr_r}; // copy previous value
end
`endif // DEBUG_ELASATIC
reg rxresetdone_r;
reg txresetdone_r;
always @ (posedge rxusrclk2) rxresetdone_r <= rxresetdone_gtx;
always @ (posedge txusrclk2) txresetdone_r <= txresetdone_gtx;
assign rxresetdone = rxresetdone_r;
assign txresetdone = txresetdone_r;
pulse_cross_clock #(
.EXTRA_DLY(0)
) pulse_cross_clock_rxcominitdet_i (
.rst (~wrap_rxreset_), // input
.src_clk (xclk), // input
.dst_clk (rxusrclk2), // input
.in_pulse (rxcominitdet_gtx), // input
.out_pulse (rxcominitdet), // output
.busy () // output
);
pulse_cross_clock #(
.EXTRA_DLY(0)
) pulse_cross_clock_rxcomwakedet_i (
.rst (~wrap_rxreset_), // input
.src_clk (xclk), // input
.dst_clk (rxusrclk2), // input
.in_pulse (rxcomwakedet_gtx), // input
.out_pulse (rxcomwakedet), // output
.busy () // output
);
wire txoutclk_gtx;
wire xclk_gtx;
select_clk_buf #(
.BUFFER_TYPE("BUFG")
) bufg_txoutclk (
.o (txoutclk), // output
.i (txoutclk_gtx), // input
.clr (1'b0) // input
);
select_clk_buf #(
.BUFFER_TYPE("BUFG")
) bug_xclk (
.o (xclk), // output
.i (xclk_gtx), // input
.clr (1'b0) // input
);
gtxe2_channel_wrapper #(
.SIM_RECEIVER_DETECT_PASS ("TRUE"),
.SIM_TX_EIDLE_DRIVE_LEVEL ("X"),
.SIM_RESET_SPEEDUP ("FALSE"),
.SIM_CPLLREFCLK_SEL (3'b001),
.SIM_VERSION ("4.0"),
.ALIGN_COMMA_DOUBLE ("FALSE"),
.ALIGN_COMMA_ENABLE (10'b1111111111),
.ALIGN_COMMA_WORD (1),
.ALIGN_MCOMMA_DET ("TRUE"),
.ALIGN_MCOMMA_VALUE (10'b1010000011),
.ALIGN_PCOMMA_DET ("TRUE"),
.ALIGN_PCOMMA_VALUE (10'b0101111100),
.SHOW_REALIGN_COMMA ("TRUE"),
.RXSLIDE_AUTO_WAIT (7),
.RXSLIDE_MODE ("OFF"),
.RX_SIG_VALID_DLY (10),
.RX_DISPERR_SEQ_MATCH ("TRUE"),
.DEC_MCOMMA_DETECT ("TRUE"),
.DEC_PCOMMA_DETECT ("TRUE"),
.DEC_VALID_COMMA_ONLY ("FALSE"),
.CBCC_DATA_SOURCE_SEL ("DECODED"),
.CLK_COR_SEQ_2_USE ("FALSE"),
.CLK_COR_KEEP_IDLE ("FALSE"),
.CLK_COR_MAX_LAT (9),
.CLK_COR_MIN_LAT (7),
.CLK_COR_PRECEDENCE ("TRUE"),
.CLK_COR_REPEAT_WAIT (0),
.CLK_COR_SEQ_LEN (1),
.CLK_COR_SEQ_1_ENABLE (4'b1111),
.CLK_COR_SEQ_1_1 (10'b0100000000),
.CLK_COR_SEQ_1_2 (10'b0000000000),
.CLK_COR_SEQ_1_3 (10'b0000000000),
.CLK_COR_SEQ_1_4 (10'b0000000000),
.CLK_CORRECT_USE ("FALSE"),
.CLK_COR_SEQ_2_ENABLE (4'b1111),
.CLK_COR_SEQ_2_1 (10'b0100000000),
.CLK_COR_SEQ_2_2 (10'b0000000000),
.CLK_COR_SEQ_2_3 (10'b0000000000),
.CLK_COR_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_KEEP_ALIGN ("FALSE"),
.CHAN_BOND_MAX_SKEW (1),
.CHAN_BOND_SEQ_LEN (1),
.CHAN_BOND_SEQ_1_1 (10'b0000000000),
.CHAN_BOND_SEQ_1_2 (10'b0000000000),
.CHAN_BOND_SEQ_1_3 (10'b0000000000),
.CHAN_BOND_SEQ_1_4 (10'b0000000000),
.CHAN_BOND_SEQ_1_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_1 (10'b0000000000),
.CHAN_BOND_SEQ_2_2 (10'b0000000000),
.CHAN_BOND_SEQ_2_3 (10'b0000000000),
.CHAN_BOND_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_SEQ_2_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_USE ("FALSE"),
.FTS_DESKEW_SEQ_ENABLE (4'b1111),
.FTS_LANE_DESKEW_CFG (4'b1111),
.FTS_LANE_DESKEW_EN ("FALSE"),
.ES_CONTROL (6'b000000),
.ES_ERRDET_EN ("FALSE"),
.ES_EYE_SCAN_EN ("TRUE"),
.ES_HORZ_OFFSET (12'h000),
.ES_PMA_CFG (10'b0000000000),
.ES_PRESCALE (5'b00000),
.ES_QUALIFIER (80'h00000000000000000000),
.ES_QUAL_MASK (80'h00000000000000000000),
.ES_SDATA_MASK (80'h00000000000000000000),
.ES_VERT_OFFSET (9'b000000000),
.RX_DATA_WIDTH (20),
.OUTREFCLK_SEL_INV (2'b11),
.PMA_RSV (32'h00018480),
.PMA_RSV2 (16'h2050),
.PMA_RSV3 (2'b00),
.PMA_RSV4 (32'h00000000),
.RX_BIAS_CFG (12'b000000000100),
.DMONITOR_CFG (24'h000A00),
// .RX_CM_SEL (2'b11),
.RX_CM_SEL (2'b00), // Andrey
.RX_CM_TRIM (3'b010),
.RX_DEBUG_CFG (12'b000000000000),
.RX_OS_CFG (13'b0000010000000),
.TERM_RCAL_CFG (5'b10000),
.TERM_RCAL_OVRD (1'b0),
.TST_RSV (32'h00000000),
.RX_CLK25_DIV (6),
.TX_CLK25_DIV (6),
.UCODEER_CLR (1'b0),
.PCS_PCIE_EN ("FALSE"),
.PCS_RSVD_ATTR (48'h0100),
.RXBUF_ADDR_MODE ("FAST"),
.RXBUF_EIDLE_HI_CNT (4'b1000),
.RXBUF_EIDLE_LO_CNT (4'b0000),
.RXBUF_EN ("FALSE"),
.RX_BUFFER_CFG (6'b000000),
.RXBUF_RESET_ON_CB_CHANGE ("TRUE"),
.RXBUF_RESET_ON_COMMAALIGN ("FALSE"),
.RXBUF_RESET_ON_EIDLE ("FALSE"),
.RXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.RXBUFRESET_TIME (5'b00001),
.RXBUF_THRESH_OVFLW (61),
.RXBUF_THRESH_OVRD ("FALSE"),
.RXBUF_THRESH_UNDFLW (4),
.RXDLY_CFG (16'h001F),
.RXDLY_LCFG (9'h030),
.RXDLY_TAP_CFG (16'h0000),
.RXPH_CFG (24'h000000),
.RXPHDLY_CFG (24'h084020),
.RXPH_MONITOR_SEL (5'b00000),
`ifdef ALIGN_CLOCKS
// .RX_XCLK_SEL ("RXUSR"), // ("RXREC"), // Andrey: Now they are the same, just using p.247 "Using RX Buffer Bypass..."
.RX_XCLK_SEL ("RXREC"), // Andrey: Does not align clocks if in this mode
`else
.RX_XCLK_SEL ("RXREC"), // Andrey: Does not align clocks if in this mode
`endif
.RX_DDI_SEL (6'b000000),
.RX_DEFER_RESET_BUF_EN ("TRUE"),
/// .RXCDR_CFG (72'h03_0000_23ff_1020_0020),// 1.6G - 6.25G, No SS, RXOUT_DIV=2
.RXCDR_CFG (72'h03_8800_8BFF_4020_0008),// http://www.xilinx.com/support/answers/53364.html - SATA-2, div=2
.RXCDR_FR_RESET_ON_EIDLE (1'b0),
.RXCDR_HOLD_DURING_EIDLE (1'b0),
.RXCDR_PH_RESET_ON_EIDLE (1'b0),
.RXCDR_LOCK_CFG (6'b010101),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXPCSRESET_TIME (5'b00001),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXOOB_CFG (7'b0000110),
.RXGEARBOX_EN ("FALSE"),
.GEARBOX_MODE (3'b000),
.RXPRBS_ERR_LOOPBACK (1'b0),
.PD_TRANS_TIME_FROM_P2 (12'h03c),
.PD_TRANS_TIME_NONE_P2 (8'h3c),
.PD_TRANS_TIME_TO_P2 (8'h64),
.SAS_MAX_COM (64),
.SAS_MIN_COM (36),
.SATA_BURST_SEQ_LEN (4'b0101),
.SATA_BURST_VAL (3'b100),
.SATA_EIDLE_VAL (3'b100),
.SATA_MAX_BURST (8),
.SATA_MAX_INIT (21),
.SATA_MAX_WAKE (7),
.SATA_MIN_BURST (4),
.SATA_MIN_INIT (12),
.SATA_MIN_WAKE (4),
.TRANS_TIME_RATE (8'h0E),
.TXBUF_EN ("TRUE"),
.TXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.TXDLY_CFG (16'h001F),
.TXDLY_LCFG (9'h030),
.TXDLY_TAP_CFG (16'h0000),
.TXPH_CFG (16'h0780),
.TXPHDLY_CFG (24'h084020),
.TXPH_MONITOR_SEL (5'b00000),
.TX_XCLK_SEL ("TXOUT"),
.TX_DATA_WIDTH (20),
.TX_DEEMPH0 (5'b00000),
.TX_DEEMPH1 (5'b00000),
.TX_EIDLE_ASSERT_DELAY (3'b110),
.TX_EIDLE_DEASSERT_DELAY (3'b100),
.TX_LOOPBACK_DRIVE_HIZ ("FALSE"),
.TX_MAINCURSOR_SEL (1'b0),
.TX_DRIVE_MODE ("DIRECT"),
.TX_MARGIN_FULL_0 (7'b1001110),
.TX_MARGIN_FULL_1 (7'b1001001),
.TX_MARGIN_FULL_2 (7'b1000101),
.TX_MARGIN_FULL_3 (7'b1000010),
.TX_MARGIN_FULL_4 (7'b1000000),
.TX_MARGIN_LOW_0 (7'b1000110),
.TX_MARGIN_LOW_1 (7'b1000100),
.TX_MARGIN_LOW_2 (7'b1000010),
.TX_MARGIN_LOW_3 (7'b1000000),
.TX_MARGIN_LOW_4 (7'b1000000),
.TXGEARBOX_EN ("FALSE"),
.TXPCSRESET_TIME (5'b00001),
.TXPMARESET_TIME (TXPMARESET_TIME),
.TX_RXDETECT_CFG (14'h1832),
.TX_RXDETECT_REF (3'b100),
.CPLL_CFG (24'hBC07DC),
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_INIT_CFG (24'h00001E),
.CPLL_LOCK_CFG (16'h01E8),
.CPLL_REFCLK_DIV (1),
.RXOUT_DIV (2),
.TXOUT_DIV (2),
.SATA_CPLL_CFG ("VCO_3000MHZ"),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXLPM_HF_CFG (14'b00000011110000),
.RXLPM_LF_CFG (14'b00000011110000),
.RX_DFE_GAIN_CFG (23'h020FEA),
.RX_DFE_H2_CFG (12'b000000000000),
.RX_DFE_H3_CFG (12'b000001000000),
.RX_DFE_H4_CFG (11'b00011110000),
.RX_DFE_H5_CFG (11'b00011100000),
.RX_DFE_KL_CFG (13'b0000011111110),
/// .RX_DFE_LPM_CFG (16'h0954),
.RX_DFE_LPM_CFG (16'h0904),
.RX_DFE_LPM_HOLD_DURING_EIDLE (1'b0),
.RX_DFE_UT_CFG (17'b10001111000000000),
.RX_DFE_VP_CFG (17'b00011111100000011),
.RX_CLKMUX_PD (1'b1),
.TX_CLKMUX_PD (1'b1),
.RX_INT_DATAWIDTH (0),
.TX_INT_DATAWIDTH (0),
.TX_QPI_STATUS_EN (1'b0),
.RX_DFE_KL_CFG2 (32'h301148AC),
.RX_DFE_XYD_CFG (13'b0000000000000),
.TX_PREDRIVER_MODE (1'b0)
)
gtxe2_channel_wrapper(
.CPLLFBCLKLOST (),
.CPLLLOCK (cplllock),
.CPLLLOCKDETCLK (cplllockdetclk),
.CPLLLOCKEN (1'b1),
.CPLLPD (1'b0),
.CPLLREFCLKLOST (),
.CPLLREFCLKSEL (3'b001),
.CPLLRESET (cpllreset),
.GTRSVD (16'b0),
.PCSRSVDIN (16'b0),
.PCSRSVDIN2 (5'b0),
.PMARSVDIN (5'b0),
.PMARSVDIN2 (5'b0),
.TSTIN (20'h1),
.TSTOUT (),
.CLKRSVD (4'b0000),
.GTGREFCLK (1'b0),
.GTNORTHREFCLK0 (1'b0),
.GTNORTHREFCLK1 (1'b0),
.GTREFCLK0 (gtrefclk),
.GTREFCLK1 (1'b0),
.GTSOUTHREFCLK0 (1'b0),
.GTSOUTHREFCLK1 (1'b0),
`ifdef USE_DRP
.DRPADDR (drp_addr[8:0]),
.DRPCLK (drp_clk),
.DRPDI (drp_di),
.DRPDO (drp_do_gtx),
.DRPEN (drp_en_w[0]),
.DRPRDY (drp_rdy_gtx),
.DRPWE (drp_we_w[0]),
`else
.DRPADDR (9'b0),
.DRPCLK (1'b0),
.DRPDI (16'b0),
.DRPDO (),
.DRPEN (1'b0),
.DRPRDY (),
.DRPWE (1'b0),
`endif
.GTREFCLKMONITOR (),
.QPLLCLK (1'b0/*gtrefclk*/),
.QPLLREFCLK (1'b0/*gtrefclk*/),
.RXSYSCLKSEL (2'b00),
.TXSYSCLKSEL (2'b00),
.DMONITOROUT (),
.TX8B10BEN (1'b0),
.LOOPBACK (3'd0),
.PHYSTATUS (),
.RXRATE (3'd0),
.RXVALID (),
.RXPD (2'b00),
.TXPD (2'b00),
.SETERRSTATUS (1'b0),
.EYESCANRESET (1'b0),//rxreset), // p78
.RXUSERRDY (rxuserrdy),
.EYESCANDATAERROR (),
.EYESCANMODE (1'b0),
.EYESCANTRIGGER (1'b0),
.RXCDRFREQRESET (1'b0),
.RXCDRHOLD (1'b0),
.RXCDRLOCK (rxcdrlock),
.RXCDROVRDEN (1'b0),
.RXCDRRESET (1'b0),
.RXCDRRESETRSV (1'b0),
.RXCLKCORCNT (),
.RX8B10BEN (1'b0),
/// .RXUSRCLK (rxusrclk),
/// .RXUSRCLK2 (rxusrclk),
/// When internal elastic buffer is bypassed, these clocks should be restored clock synchronous
.RXUSRCLK (xclk),
.RXUSRCLK2 (xclk),
.RXDATA (rxdata_gtx),
.RXPRBSERR (),
.RXPRBSSEL (3'd0),
.RXPRBSCNTRESET (1'b0),
.RXDFEXYDEN (1'b1),
.RXDFEXYDHOLD (1'b0),
.RXDFEXYDOVRDEN (1'b0),
.RXDISPERR (rxdisperr_gtx),
.RXNOTINTABLE (),
.GTXRXP (rxp),
.GTXRXN (rxn),
.RXBUFRESET (1'b0),
.RXBUFSTATUS (),
`ifdef ALIGN_CLOCKS
.RXDDIEN (RXDDIEN), // (1'b1), // Andrey: p.243: "Set high in RX buffer bypass mode"
.RXDLYBYPASS (RXDLYBYPASS), // (1'b0), // Andrey: p.243: "0: Uses the RX delay alignment circuit."
`else
.RXDDIEN (RXDDIEN), // (1'b0),
.RXDLYBYPASS (RXDLYBYPASS), // (1'b1),
`endif
.RXDLYEN (RXDLYEN), // (1'b0),
.RXDLYOVRDEN (RXDLYOVRDEN), // (1'b0),
.RXDLYSRESET (RXDLYSRESET || rxdlysreset),
.RXDLYSRESETDONE (rxdlysresetdone),
.RXPHALIGN (RXPHALIGN), // (1'b0),
.RXPHALIGNDONE (rxphaligndone),
.RXPHALIGNEN (RXPHALIGNEN), // (1'b0),
.RXPHDLYPD (RXPHDLYPD), // (1'b0),
.RXPHDLYRESET (RXPHDLYRESET), // (1'b0),
.RXPHMONITOR (),
.RXPHOVRDEN (RXPHOVRDEN), // (1'b0),
.RXPHSLIPMONITOR (),
.RXSTATUS (),
.RXBYTEISALIGNED (),
.RXBYTEREALIGN (),
.RXCOMMADET (),
.RXCOMMADETEN (1'b0),
.RXMCOMMAALIGNEN (1'b0),
.RXPCOMMAALIGNEN (1'b0),
.RXCHANBONDSEQ (),
.RXCHBONDEN (1'b0),
.RXCHBONDLEVEL (3'd0),
.RXCHBONDMASTER (1'b0),
.RXCHBONDO (),
.RXCHBONDSLAVE (1'b0),
.RXCHANISALIGNED (),
.RXCHANREALIGN (),
.RXLPMHFHOLD (1'b0),
.RXLPMHFOVRDEN (1'b0),
.RXLPMLFHOLD (1'b0),
.RXDFEAGCHOLD (1'b0),
.RXDFEAGCOVRDEN (1'b0),
.RXDFECM1EN (1'b0),
.RXDFELFHOLD (1'b0),
.RXDFELFOVRDEN (1'b1),
.RXDFELPMRESET (rxreset),
.RXDFETAP2HOLD (1'b0),
.RXDFETAP2OVRDEN (1'b0),
.RXDFETAP3HOLD (1'b0),
.RXDFETAP3OVRDEN (1'b0),
.RXDFETAP4HOLD (1'b0),
.RXDFETAP4OVRDEN (1'b0),
.RXDFETAP5HOLD (1'b0),
.RXDFETAP5OVRDEN (1'b0),
.RXDFEUTHOLD (1'b0),
.RXDFEUTOVRDEN (1'b0),
.RXDFEVPHOLD (1'b0),
.RXDFEVPOVRDEN (1'b0),
// .RXDFEVSEN (1'b0),
.RXLPMLFKLOVRDEN (1'b0),
.RXMONITOROUT (),
.RXMONITORSEL (2'b01),
.RXOSHOLD (1'b0),
.RXOSOVRDEN (1'b0),
.RXRATEDONE (),
.RXOUTCLK (xclk_gtx),
.RXOUTCLKFABRIC (),
.RXOUTCLKPCS (),
.RXOUTCLKSEL (3'b010),
.RXDATAVALID (),
.RXHEADER (),
.RXHEADERVALID (),
.RXSTARTOFSEQ (),
.RXGEARBOXSLIP (1'b0),
.GTRXRESET (rxreset),
.RXOOBRESET (1'b0),
.RXPCSRESET (1'b0),
.RXPMARESET (1'b0),//rxreset), // p78
.RXLPMEN (RXLPMEN), // 1'b0),
.RXCOMSASDET (),
.RXCOMWAKEDET (rxcomwakedet_gtx),
.RXCOMINITDET (rxcominitdet_gtx),
.RXELECIDLE (rxelecidle),
.RXELECIDLEMODE (2'b00),
.RXPOLARITY (1'b0),
.RXSLIDE (1'b0),
.RXCHARISCOMMA (),
.RXCHARISK (rxcharisk_gtx),
.RXCHBONDI (5'b00000),
.RXRESETDONE (rxresetdone_gtx),
.RXQPIEN (1'b0),
.RXQPISENN (),
.RXQPISENP (),
.TXPHDLYTSTCLK (1'b0),
.TXPOSTCURSOR (5'b00000),
.TXPOSTCURSORINV (1'b0),
.TXPRECURSOR (5'd0),
.TXPRECURSORINV (1'b0),
.TXQPIBIASEN (1'b0),
.TXQPISTRONGPDOWN (1'b0),
.TXQPIWEAKPUP (1'b0),
.CFGRESET (1'b0),
.GTTXRESET (txreset),
.PCSRSVDOUT (),
.TXUSERRDY (txuserrdy),
.GTRESETSEL (1'b0),
.RESETOVRD (1'b0),
.TXCHARDISPMODE (txchardispmode_gtx),
.TXCHARDISPVAL (txchardispval_gtx),
.TXUSRCLK (txusrclk),
.TXUSRCLK2 (txusrclk),
.TXELECIDLE (txelecidle_gtx),
.TXMARGIN (3'd0),
.TXRATE (3'd0),
.TXSWING (1'b0),
.TXPRBSFORCEERR (1'b0),
.TXDLYBYPASS (1'b1),
.TXDLYEN (1'b0),
.TXDLYHOLD (1'b0),
.TXDLYOVRDEN (1'b0),
.TXDLYSRESET (1'b0),
.TXDLYSRESETDONE (),
.TXDLYUPDOWN (1'b0),
.TXPHALIGN (1'b0),
.TXPHALIGNDONE (),
.TXPHALIGNEN (1'b0),
.TXPHDLYPD (1'b0),
.TXPHDLYRESET (1'b0),
.TXPHINIT (1'b0),
.TXPHINITDONE (),
.TXPHOVRDEN (1'b0),
.TXBUFSTATUS (txbufstatus[1:0]), // Andrey
.TXBUFDIFFCTRL (3'b100),
.TXDEEMPH (1'b0),
.TXDIFFCTRL (4'b1000),
.TXDIFFPD (1'b0),
.TXINHIBIT (1'b0),
.TXMAINCURSOR (7'b0000000),
.TXPISOPD (1'b0),
.TXDATA (txdata_gtx),
.GTXTXN (txn),
.GTXTXP (txp),
.TXOUTCLK (txoutclk_gtx),
.TXOUTCLKFABRIC (),
.TXOUTCLKPCS (),
.TXOUTCLKSEL (3'b010),
.TXRATEDONE (),
.TXCHARISK (txcharisk_gtx),
.TXGEARBOXREADY (),
.TXHEADER (3'd0),
.TXSEQUENCE (7'd0),
.TXSTARTSEQ (1'b0),
.TXPCSRESET (txpcsreset),
.TXPMARESET (1'b0),
.TXRESETDONE (txresetdone_gtx),
.TXCOMFINISH (txcomfinish),
.TXCOMINIT (txcominit_gtx),
.TXCOMSAS (1'b0),
.TXCOMWAKE (txcomwake_gtx),
.TXPDELECIDLEMODE (1'b0),
.TXPOLARITY (1'b0),
.TXDETECTRX (1'b0),
.TX8B10BBYPASS (8'd0),
.TXPRBSSEL (3'd0),
.TXQPISENN (),
.TXQPISENP ()
);
`ifdef USE_DATASCOPE
`ifdef DATASCOPE_INCOMING_RAW
datascope_incoming_raw #(
.ADDRESS_BITS (ADDRESS_BITS),
.DATASCOPE_POST_MEAS (DATASCOPE_POST_MEAS)
) datascope_incoming_i (
.clk (xclk), // input
.charisk (rxcharisk_dec_out[1:0]), // input[1:0]
.rxdata (rxdata_dec_out[15:0]), // input[15:0]
.realign (realign), // input
.comma (comma), // input
.aligned (state_aligned), // input
.not_in_table (rxnotintable_dec_out[1:0]), // input[1:0]
.disp_err (rxdisperr_dec_out[1:0]), // input[1:0]
.datascope_arm (other_control[DATASCOPE_START_BIT]), // input
.datascope_clk (datascope_clk), // output
.datascope_waddr (datascope_waddr), // output[9:0]
.datascope_we (datascope_we), // output
.datascope_di (datascope_di), // output[31:0] reg
.datascope_trig (datascope_trig) // input
);
`else // DATASCOPE_INCOMING_RAW
datascope_incoming #(
.ADDRESS_BITS (ADDRESS_BITS),
.DATASCOPE_POST_MEAS (DATASCOPE_POST_MEAS)
) datascope_incoming_i (
.clk (xclk), // input
.charisk (rxcharisk_dec_out[1:0]), // input[1:0]
.rxdata (rxdata_dec_out[15:0]), // input[15:0]
.aligned (state_aligned), // input
.not_in_table (rxnotintable_dec_out[1:0]), // input[1:0]
.disp_err (rxdisperr_dec_out[1:0]), // input[1:0]
.datascope_arm (other_control[DATASCOPE_START_BIT]), // input
.datascope_clk (datascope_clk), // output
.datascope_waddr (datascope_waddr), // output[9:0]
.datascope_we (datascope_we), // output
.datascope_di (datascope_di), // output[31:0] reg
.datascope_trig (datascope_trig) // input
);
`endif // not DATASCOPE_INCOMING_RAW
`endif
always @ (posedge gtrefclk)
debug <= ~rxelecidle | debug;
endmodule
module datascope_incoming_raw#(
parameter ADDRESS_BITS = 10, // for datascope
parameter DATASCOPE_POST_MEAS = 16 // number of measurements to perform after event
)(
input clk, // source-synchronous clock (150MHz)
input [1:0] charisk,
input [15:0] rxdata,
input realign,
input comma,
input aligned,
input [1:0] not_in_table,
input [1:0] disp_err,
input datascope_arm,
output datascope_clk,
output [ADDRESS_BITS-1:0] datascope_waddr,
output datascope_we,
output reg [31:0] datascope_di,
input datascope_trig // external trigger event for the datascope
);
reg [ADDRESS_BITS - 1:0 ] datascope_post_cntr;
reg [ADDRESS_BITS - 1:0 ] datascope_waddr_r;
reg [2:0] datascope_start_r;
wire datascope_event;
reg datascope_event_r;
reg datascope_run;
reg datascope_post_run;
// wire datascope_start_w = other_control[DATASCOPE_START_BIT]; // datascope requires USE_DRP to be defined
wire datascope_stop = (DATASCOPE_POST_MEAS == 0) ? datascope_event: (datascope_post_cntr == 0);
reg [2:0] datascope_trig_r;
assign datascope_waddr = datascope_waddr_r;
assign datascope_we = datascope_run;
assign datascope_clk = clk;
assign datascope_event = (not_in_table) || (disp_err) || realign || (datascope_trig_r[1] && !datascope_trig_r[2]) ;
always @ (posedge clk) begin
datascope_trig_r <= {datascope_trig_r[1:0], datascope_trig};
datascope_start_r <= {datascope_start_r[1:0],datascope_arm};
datascope_event_r <=datascope_event;
if (!datascope_start_r[1]) datascope_run <= 0;
else if (!datascope_start_r[2]) datascope_run <= 1;
else if (datascope_stop) datascope_run <= 0;
if (!datascope_run) datascope_post_run <= 0;
else if (datascope_event_r) datascope_post_run <= 1;
if (!datascope_post_run) datascope_post_cntr <= DATASCOPE_POST_MEAS;
else datascope_post_cntr <= datascope_post_cntr - 1;
if (!datascope_start_r[1] && datascope_start_r[0]) datascope_waddr_r <= 0; // for simulator
else if (datascope_run) datascope_waddr_r <= datascope_waddr_r + 1;
if (datascope_start_r[1]) datascope_di <= {
6'b0,
realign, // 25
comma, // 24
1'b0, // 23
aligned, // 22
not_in_table[1:0], // 21:20
disp_err[1:0], // 19:18
charisk[1:0], // 17:16
rxdata[15:0]}; // 15: 0
end
endmodule
module datascope_incoming#(
parameter ADDRESS_BITS = 10, // for datascope
parameter DATASCOPE_POST_MEAS = 16 // number of measurements to perform after event
)(
input clk, // source-synchronous clock (150MHz)
input [1:0] charisk,
input [15:0] rxdata,
input aligned,
input [1:0] not_in_table,
input [1:0] disp_err,
input datascope_arm,
output datascope_clk,
output [ADDRESS_BITS-1:0] datascope_waddr,
output datascope_we,
output [31:0] datascope_di,
input datascope_trig // external trigger event for the datascope
);
localparam ALIGN_PRIM = 32'h7b4a4abc;
localparam CONT_PRIM = 32'h9999aa7c;
localparam DMAT_PRIM = 32'h3636b57c;
localparam EOF_PRIM = 32'hd5d5b57c;
localparam HOLD_PRIM = 32'hd5d5aa7c;
localparam HOLDA_PRIM = 32'h9595aa7c;
localparam PMACK_PRIM = 32'h9595957c;
localparam PMNAK_PRIM = 32'hf5f5957c;
localparam PMREQ_P_PRIM = 32'h1717b57c;
localparam PMREQ_S_PRIM = 32'h7575957c;
localparam R_ERR_PRIM = 32'h5656b57c;
localparam R_IP_PRIM = 32'h5555b57c;
localparam R_OK_PRIM = 32'h3535b57c;
localparam R_RDY_PRIM = 32'h4a4a957c;
localparam SOF_PRIM = 32'h3737b57c;
localparam SYNC_PRIM = 32'hb5b5957c;
localparam WTRM_PRIM = 32'h5858b57c;
localparam X_RDY_PRIM = 32'h5757b57c;
localparam NUM_NIBBLES = 6;
reg [15:0] rxdata_r;
reg [ 1:0] charisk_r;
wire is_alignp = ({rxdata, rxdata_r} == ALIGN_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_cont = ({rxdata, rxdata_r} == CONT_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_dmat = ({rxdata, rxdata_r} == DMAT_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_eof = ({rxdata, rxdata_r} == EOF_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_hold = ({rxdata, rxdata_r} == HOLD_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_holda = ({rxdata, rxdata_r} == HOLDA_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_pmack = ({rxdata, rxdata_r} == PMACK_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_pmnak = ({rxdata, rxdata_r} == PMNAK_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_pmreq_p = ({rxdata, rxdata_r} == PMREQ_P_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_pmreq_s = ({rxdata, rxdata_r} == PMREQ_S_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_r_err = ({rxdata, rxdata_r} == R_ERR_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_r_ip = ({rxdata, rxdata_r} == R_IP_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_r_ok = ({rxdata, rxdata_r} == R_OK_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_r_rdy = ({rxdata, rxdata_r} == R_RDY_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_sof = ({rxdata, rxdata_r} == SOF_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_sync = ({rxdata, rxdata_r} == SYNC_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_wrtm = ({rxdata, rxdata_r} == WTRM_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_xrdy = ({rxdata, rxdata_r} == X_RDY_PRIM) && ({charisk, charisk_r} == 4'h1);
wire is_data_w = {charisk, charisk_r} == 4'h0;
wire [17:0] is_prim_w = {is_alignp,
is_cont,
is_dmat,
is_eof,
is_hold,
is_holda,
is_pmack,
is_pmnak,
is_pmreq_p,
is_pmreq_s,
is_r_err,
is_r_ip,
is_r_ok,
is_r_rdy,
is_sof,
is_sync,
is_wrtm,
is_xrdy};
wire [ 2:0] is_err_w = {~aligned, |not_in_table, |disp_err};
reg [17:0] is_prim_r;
reg is_data_r;
reg [ 2:0] is_err_r;
reg [17:0] is_prim_r2;
reg is_data_r2;
reg [ 3:0] is_err_r2;
wire [31:0] states = {9'b0, is_err_r2[3:0], is_prim_r2[17:0], is_data_r2}; // to add more states ?
wire [ 4:0] encoded_states_w ={(|states[31:16]),
(|states[31:24]) | (|states[15:8]),
(|states[31:28]) | (|states[23:20]) | (|states[15:12]) | (|states[7:4]),
(|states[31:30]) | (|states[27:26]) | (|states[23:22]) | (|states[19:18]) | (|states[15:14]) | (|states[11:10]) | (|states[7:6]) | (|states[3:2]),
states[31] | states[29] | states[27] | states[25] | states[23] | states[21] | states[19] | states[17] |
states[15] | states[13] | states[11] | states[9] | states[7] | states[5] | states[3] | states[1]};
// wire stop = (DATASCOPE_POST_MEAS == 0) ? datascope_trig: (post_cntr == 0);
reg [5*NUM_NIBBLES-1:0] encoded_states_r3;
reg [ADDRESS_BITS - 1:0 ] post_cntr;
reg post_run;
reg [ADDRESS_BITS - 1:0 ] waddr_r;
reg [2:0] arm_r;
reg [2:0] trig_r;
reg [NUM_NIBBLES-1:0] wen;
reg run_r = 0;
wire event_w = trig_r[1] && !trig_r[2]; // re-clocked single-cycle external trigger
reg event_r;
wire stop = (DATASCOPE_POST_MEAS == 0) ? event_w: (post_cntr == 0);
reg [1:0] we_r=0;
reg msb_in_r;
reg is_aligned_r; // input aligned and got ALIGNp
assign datascope_clk = clk;
assign datascope_waddr = waddr_r;
assign datascope_we = we_r[1];
assign datascope_di = {1'b0, post_run, encoded_states_r3};
always @ (posedge clk) begin
if (!aligned) is_aligned_r <= 0;
else if (is_alignp) is_aligned_r <= 1;
if (!is_aligned_r && !is_alignp) msb_in_r <= 1;
else msb_in_r <= !msb_in_r;
rxdata_r <= rxdata;
charisk_r <= charisk;
arm_r <= {arm_r[1:0], datascope_arm};
trig_r <= {trig_r[1:0],datascope_trig};
if (!arm_r[1]) run_r <= 0;
else if (!arm_r[2]) run_r <= 1;
else if (stop) run_r <= 0;
event_r <= event_w;
if (!run_r) post_run <= 0;
else if (event_r) post_run <= 1;
if (msb_in_r) begin
is_prim_r <= is_prim_w;
is_err_r <= is_err_w;
is_data_r <= is_data_w;
is_prim_r2 <= {18{~(|is_err_r)}} & is_prim_r;
is_err_r2 <= {is_err_r[2],is_err_r[1] & ~is_err_r[2],is_err_r[0] & ~(|is_err_r[2:1]), ~(|is_prim_r) & ~is_data_r & ~(|is_err_r)}; // make errors 1-hot by priority
is_data_r2 <= is_data_r & ~(|is_err_r);
encoded_states_r3 <= {encoded_states_w, encoded_states_r3[5*NUM_NIBBLES-1:5]};
if (!run_r) wen <= 0;
else wen <= {wen[NUM_NIBBLES-2:0],~(|wen[NUM_NIBBLES-2:0])};
we_r[0] <= run_r && wen[NUM_NIBBLES-1];
end
we_r[1] <=we_r[0] && !msb_in_r;
if (!arm_r[1] && arm_r[0]) waddr_r <= 0; // for simulator
else if (we_r[1]) waddr_r <= waddr_r + 1;
if (!post_run) post_cntr <= DATASCOPE_POST_MEAS;
else if (we_r[1]) post_cntr <= post_cntr - 1;
end
endmodule
/*******************************************************************************
* Module: link
* Date: 2015-07-11
* Author: Alexey
* Description: sata link layer implementation
*
* Copyright (c) 2015 Elphel, Inc.
* link.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.
*
* link.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
//`include "scrambler.v"
//`include "crc.v"
module link #(
// 4 = dword. 4-bytes aligned data transfers TODO 2 = word - easy, 8 = qword - difficult
parameter DATA_BYTE_WIDTH = 4,
`ifdef SIMULATION
// parameter ALIGNES_PERIOD = 10 // period of sending ALIGNp pairs
parameter ALIGNES_PERIOD = 100 // period of sending ALIGNp pairs
`else
parameter ALIGNES_PERIOD = 252 // period of sending ALIGNp pairs
`endif
)
(
// TODO insert watchdogs
input wire rst,
input wire clk,
// data inputs from transport layer
// input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH*8 - 1:0] data_in,
// in case of strange data aligments and size (1st mentioned @ doc, p.310, odd number of words case)
// Actually, only last data bundle shall be masked, others are always valid.
// Mask could be encoded into 3 bits instead of 4 for qword, but encoding+decoding aren't worth the bit
input wire [DATA_BYTE_WIDTH/2 - 1:0] data_mask_in, // TODO, for now not supported, all mask bits are assumed to be set
output wire data_strobe_out, // buffer read strobe
input wire data_last_in, // transaction's last data budle pulse
input wire data_val_in, // read data is valid (if 0 while last pulse wasn't received => need to hold the line)
// data outputs to transport layer
output wire [DATA_BYTE_WIDTH*8 - 1:0] data_out, // read data, same as related inputs
output wire [DATA_BYTE_WIDTH/2 - 1:0] data_mask_out, // same thing - all 1s for now. TODO
output wire data_val_out, // count every data bundle read by transport layer, even if busy flag is set
// let the transport layer handle oveflows by itself
input wire data_busy_in, // transport layer tells if its inner buffer is almost full
output wire data_last_out,
input wire frame_req, // request for a new frame transition
// a little bit of overkill with the cound of response signals, think of throwing out 1 of them
output wire frame_busy, // LL tells back if it cant handle the request for now
output wire frame_ack, // LL tells if the request is transmitting
output wire frame_rej, // or if it was cancelled because of simultanious incoming transmission
output wire frame_done_good, // Tell TL if the outcoming transaction is done and how it was done
output wire frame_done_bad,
output wire incom_start, // if started an incoming transaction
output wire incom_done, // if incoming transition was completed
output wire incom_invalidate, // if incoming transition had errors
output wire incom_sync_escape, // particular type - got sync escape
input wire incom_ack_good, // transport layer responds on a completion of a FIS
input wire incom_ack_bad, // Reject frame even if it had good CRC (Bad will be responded automatically)
// It is OK to send extra incom_ack_bad from transport - it will be discarded
input wire link_reset, // oob sequence is reinitiated and link now is not established or rxelecidle
input wire sync_escape_req, // TL demands to brutally cancel current transaction
output wire sync_escape_ack, // acknowlegement of a successful reception
input wire incom_stop_req, // TL demands to stop current recieving session
output link_established, // received 3 back-to-back non-align primitives.
output reg link_bad_crc, // got bad crc at EOF
// inputs from phy
input wire phy_ready, // phy is ready - link is established
input wire [DATA_BYTE_WIDTH*8 - 1:0] phy_data_in, // data-primitives stream from phy
input wire [DATA_BYTE_WIDTH - 1:0] phy_isk_in, // charisk
input wire [DATA_BYTE_WIDTH - 1:0] phy_err_in, // disperr | notintable
// to phy
output wire [DATA_BYTE_WIDTH*8 - 1:0] phy_data_out,
output wire [DATA_BYTE_WIDTH - 1:0] phy_isk_out, // charisk
// debug
output [31:0] debug_out //
);
`ifdef SIMULATION
reg [639:0] HOST_LINK_TITLE; // to show human-readable state in the GTKWave
reg [31:0] HOST_LINK_DATA;
`endif
// latching data-primitives stream from phy
reg [DATA_BYTE_WIDTH*8 - 1:0] phy_data_in_r;
reg [DATA_BYTE_WIDTH - 1:0] phy_isk_in_r; // charisk
reg [DATA_BYTE_WIDTH - 1:0] phy_err_in_r; // disperr | notintable
//one extra layer to process CONTp
reg [DATA_BYTE_WIDTH*8 - 1:0] phy_data_in_r0;
reg [DATA_BYTE_WIDTH - 1:0] phy_isk_in_r0; // charisk
reg [DATA_BYTE_WIDTH - 1:0] phy_err_in_r0; // disperr | notintable
reg [DATA_BYTE_WIDTH*8 - 1:0] last_not_cont_di; // last primitive dword, but not CONTp
reg rcv_junk; // receiving CONTp junk data
wire is_non_cont_non_align_p_w; // got primitive other than CONTp and ALIGNp (early by 1)
wire is_cont_p_w; // got CONTp primitive (early by 1)
wire is_align_p_w; // got ALIGNp primitive (early by 1)
//CONTp should pass ALIGNp
wire frame_done;
// scrambled data
wire [DATA_BYTE_WIDTH*8 - 1:0] scrambler_out;
wire dec_err; // doc, p.311
// while receiving session shows crc check status
wire crc_good;
wire crc_bad;
// current crc
wire [31:0] crc_dword;
// Removing - state_align is handled by OOB
///reg link_established_r; // received 3 back-to-back non-align primitives.
///reg [1:0] non_align_cntr;
///assign link_established = link_established_r;
assign link_established = phy_ready;
// send primitives variety count, including CRC and DATA as primitives
localparam PRIM_NUM = 16; // 15;
wire [PRIM_NUM - 1:0] rcvd_dword; // shows current processing primitive (or just data dword)
wire dword_val; // any valid primitive/data
wire dword_val_na; // any valid primitive but ALIGNp
// list of bits of rcvd_dword
localparam CODE_DATA = 0; // DATA
localparam CODE_CRC = 1; // CRC
localparam CODE_SYNCP = 2; // SYNCp
localparam CODE_ALIGNP = 3; // ALIGNp PHY layer control
localparam CODE_XRDYP = 4; // X_RDYp Transmission data ready
localparam CODE_SOFP = 5; // SOFp Start of Frame
localparam CODE_HOLDAP = 6; // HOLDAp HOLD acknowledge
localparam CODE_HOLDP = 7; // HOLDp Hold data transmission
localparam CODE_EOFP = 8; // EOFp End Of Frame
localparam CODE_WTRMP = 9; // WTRMp Wait for frame termination
localparam CODE_RRDYP = 10; // R_RDYp Receiver ready
localparam CODE_IPP = 11; // R_IPp - Reception in progress
localparam CODE_DMATP = 12; // DMATp - DMA terminate
localparam CODE_OKP = 13; // R_OKp - Reception with no error
localparam CODE_ERRP = 14; // R_ERRp - Reception with Error
localparam CODE_CONTP = 15; // CONTp - Continue repeating
// processing CONTp/junk, delaying everything by 1 clock
always @ (posedge clk) begin
phy_data_in_r0 <= phy_data_in;
phy_isk_in_r0 <= phy_isk_in;
phy_err_in_r0 <= phy_err_in;
if (is_non_cont_non_align_p_w) last_not_cont_di <= phy_data_in_r0; // last_not_cont_di - primitive to repeat instead of junk
if (rst || is_non_cont_non_align_p_w) rcv_junk <= 0;
else if (is_cont_p_w) rcv_junk <= 1;
if (is_cont_p_w || (rcv_junk && !(is_non_cont_non_align_p_w || is_align_p_w))) begin
phy_data_in_r <= last_not_cont_di; // last non-cont/non-align primitive will be sent instead of junk
phy_isk_in_r <= 1; // it was always primitive (4'b0001)
end else begin
phy_data_in_r <= phy_data_in_r0; // data and ALIGNp will go through
phy_isk_in_r <= phy_isk_in_r0; // data and ALIGNp will go through
end
phy_err_in_r <= phy_err_in_r0;
end
// When switching from state_rcvr_shold to state_rcvr_data we need to know that it will be data 1 cycle ahead
wire next_will_be_data = !(is_cont_p_w || (rcv_junk && !(is_non_cont_non_align_p_w || is_align_p_w))) && !(|phy_isk_in_r0);
reg data_txing_r; // if there are still some data to transmit and the transaction wasn't cancelled
wire data_txing = data_txing_r & ~state_send_crc;
// Make it safe
always @ (posedge clk) begin
if (rst) data_txing_r <= 0;
else if (frame_req) data_txing_r <= 1;
else if (state_send_crc) data_txing_r <= 0;
end
// states and transitions are taken from the doc, "Link Layer State Machine" chapter
// power mode states are not implemented. TODO insert them as an additional branch of fsm
// !!!IMPORTANT!!! If add/remove any states, dont forget to change this parameter value
localparam STATES_COUNT = 23;
// idle state
wire state_idle;
reg state_sync_esc; // SyncEscape
reg state_nocommerr; // NoComErr
reg state_nocomm; // NoComm
reg state_align; // SendAlign - not used, handled by OOB
reg state_reset; // RESET
// tranmitter branch
reg state_send_rdy; // SendChkRdy
reg state_send_sof; // SendSOF
reg state_send_data; // SendData
reg state_send_rhold; // RcvrHold - hold initiated by current data reciever
reg state_send_shold; // SendHold - hold initiated by current data sender
reg state_send_crc; // SendCVC
reg state_send_eof; // SendEOF
reg state_wait; // Wait
// receiver branch
reg state_rcvr_wait; // RcvWaitFifo
reg state_rcvr_rdy; // RcvChkRdy
reg state_rcvr_data; // RcvData
reg state_rcvr_rhold; // Hold - hold initiated by current data reciever
reg state_rcvr_shold; // RcvHold - hold initiated by current data sender
reg state_rcvr_eof; // RcvEOF
reg state_rcvr_goodcrc; // GoodCRC
reg state_rcvr_goodend; // GoodEnd
reg state_rcvr_badend; // BadEnd
// handling single-cycle incom_ack_good/incom_ack_bad when they arrive at alignes_pair
reg incom_ack_good_pend;
reg incom_ack_bad_pend;
wire incom_ack_good_or_pend = incom_ack_good || incom_ack_good_pend;
wire incom_ack_bad_or_pend = incom_ack_bad || incom_ack_bad_pend;
wire set_sync_esc;
wire set_nocommerr;
wire set_nocomm;
wire set_align;
wire set_reset;
wire set_send_rdy;
wire set_send_sof;
wire set_send_data;
wire set_send_rhold;
wire set_send_shold;
wire set_send_crc;
wire set_send_eof;
wire set_wait;
wire set_rcvr_wait;
wire set_rcvr_rdy;
wire set_rcvr_data;
wire set_rcvr_rhold;
wire set_rcvr_shold;
wire set_rcvr_eof;
wire set_rcvr_goodcrc;
wire set_rcvr_goodend;
wire set_rcvr_badend;
wire clr_sync_esc;
wire clr_nocommerr;
wire clr_nocomm;
wire clr_align;
wire clr_reset;
wire clr_send_rdy;
wire clr_send_sof;
wire clr_send_data;
wire clr_send_rhold;
wire clr_send_shold;
wire clr_send_crc;
wire clr_send_eof;
wire clr_wait;
wire clr_rcvr_wait;
wire clr_rcvr_rdy;
wire clr_rcvr_data;
wire clr_rcvr_rhold;
wire clr_rcvr_shold;
wire clr_rcvr_eof;
wire clr_rcvr_goodcrc;
wire clr_rcvr_goodend;
wire clr_rcvr_badend;
assign state_idle = ~state_sync_esc
& ~state_nocommerr
& ~state_nocomm
& ~state_align
& ~state_reset
& ~state_send_rdy
& ~state_send_sof
& ~state_send_data
& ~state_send_rhold
& ~state_send_shold
& ~state_send_crc
& ~state_send_eof
& ~state_wait
& ~state_rcvr_wait
& ~state_rcvr_rdy
& ~state_rcvr_data
& ~state_rcvr_rhold
& ~state_rcvr_shold
& ~state_rcvr_eof
& ~state_rcvr_goodcrc
& ~state_rcvr_goodend
& ~state_rcvr_badend;
// got an escaping primitive = request to cancel the transmission
// may be 1 cycle, need to extend over alignes_pair
wire got_escape = dword_val & rcvd_dword[CODE_SYNCP]; // can wait over alignes pair
reg sync_escape_req_r; // ahci sends 1 single-clock pulse, it may hit alignes_pair
always @ (posedge clk) begin
sync_escape_req_r <= alignes_pair && (sync_escape_req || sync_escape_req_r);
end
// escaping is done
assign sync_escape_ack = state_sync_esc;
reg alignes_pair; // pauses every state go give a chance to insert 2 align primitives on a line at least every 256 dwords due to spec
reg [8:0] alignes_timer;
reg alignes_pair_0; // time for 1st align primitive
always @ (posedge clk) begin
if (!phy_ready || select_prim[CODE_ALIGNP]) alignes_timer <= ALIGNES_PERIOD;
else alignes_timer <= alignes_timer -1;
alignes_pair_0 <= alignes_timer == 0;
alignes_pair <= phy_ready && ((alignes_timer == 0) || alignes_pair_0);
end
always @ (posedge clk) begin
link_bad_crc <= state_rcvr_eof & crc_bad;
if (incom_ack_good) incom_ack_good_pend <= 1;
else if (!state_rcvr_goodcrc) incom_ack_good_pend <= 0;
if (incom_ack_bad) incom_ack_bad_pend <= 1;
else if (!state_rcvr_goodcrc) incom_ack_bad_pend <= 0; // didn't like it even with good crc
end
// Whole transitions table, literally from doc pages 311-328 (Andrey: now modified, may be not true)
assign set_sync_esc = sync_escape_req || sync_escape_req_r; // extended over alignes_pair
assign set_nocommerr = ~phy_ready & ~state_nocomm & ~state_reset;
assign set_nocomm = state_nocommerr;
assign set_align = 0; // never, as this state is handled by OOB
assign set_reset = link_reset;
assign set_send_rdy = state_idle & frame_req;
assign set_send_sof = state_send_rdy & phy_ready & dword_val & rcvd_dword[CODE_RRDYP];
assign set_send_data = state_send_sof & phy_ready
| state_send_rhold & data_txing & ~dec_err & dword_val_na & ~rcvd_dword[CODE_HOLDP] & ~rcvd_dword[CODE_SYNCP] & ~rcvd_dword[CODE_DMATP]
| state_send_shold & data_txing & data_val_in & dword_val_na & ~rcvd_dword[CODE_HOLDP] & ~rcvd_dword[CODE_SYNCP];
assign set_send_rhold = state_send_data & data_txing & data_val_in & ~data_last_in & dword_val & rcvd_dword[CODE_HOLDP]
| state_send_shold & data_txing & data_val_in & dword_val & rcvd_dword[CODE_HOLDP];
assign set_send_shold = state_send_data & data_txing & ~data_val_in & dword_val & ~rcvd_dword[CODE_SYNCP];
assign set_send_crc = state_send_data & data_txing & data_val_in & data_last_in & dword_val & ~rcvd_dword[CODE_SYNCP]
| state_send_data & dword_val & rcvd_dword[CODE_DMATP];
assign set_send_eof = state_send_crc & phy_ready & dword_val & ~rcvd_dword[CODE_SYNCP];
assign set_wait = state_send_eof & phy_ready & dword_val & ~rcvd_dword[CODE_SYNCP];
// receiver's branch
assign set_rcvr_wait = state_idle & dword_val & rcvd_dword[CODE_XRDYP]
| state_send_rdy & dword_val & rcvd_dword[CODE_XRDYP];
assign set_rcvr_rdy = state_rcvr_wait & dword_val & rcvd_dword[CODE_XRDYP] & ~data_busy_in;
assign set_rcvr_data = state_rcvr_rdy & dword_val & rcvd_dword[CODE_SOFP]
| state_rcvr_rhold & next_will_be_data & ~data_busy_in
| state_rcvr_shold & next_will_be_data // So it will not be align
| state_rcvr_data & next_will_be_data; // to skip over single-cycle CODE_HOLDP
//next_will_be_data
assign set_rcvr_rhold = state_rcvr_data & dword_val & rcvd_dword[CODE_DATA] & data_busy_in;
assign set_rcvr_shold = state_rcvr_data & dword_val & (rcvd_dword[CODE_HOLDP] & ~next_will_be_data)
| state_rcvr_rhold & dword_val & (rcvd_dword[CODE_HOLDP] & ~next_will_be_data) & ~data_busy_in;
assign set_rcvr_eof = state_rcvr_data & dword_val & rcvd_dword[CODE_EOFP]
| state_rcvr_rhold & dword_val & rcvd_dword[CODE_EOFP]
| state_rcvr_shold & dword_val & rcvd_dword[CODE_EOFP];
assign set_rcvr_goodcrc = state_rcvr_eof & crc_good;
assign set_rcvr_goodend = state_rcvr_goodcrc& incom_ack_good_or_pend; // incom_ack_good; // may arrive at aligns_pair
assign set_rcvr_badend = state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP] // Missed EOF
| state_rcvr_eof & crc_bad // Got bad CRC
| state_rcvr_goodcrc& incom_ack_bad_or_pend; // incom_ack_bad; // Transport didn't like it (may arrive at aligns_pair)
assign clr_sync_esc = set_nocommerr | set_reset | dword_val & (rcvd_dword[CODE_RRDYP] | rcvd_dword[CODE_SYNCP]);
assign clr_nocommerr = set_reset | set_nocomm;
assign clr_nocomm = set_reset | set_align;
///assign clr_align = set_nocommerr | set_reset | phy_ready;
///assign clr_align = set_nocommerr | set_reset | link_established_r; // Not phy_ready !!!
assign clr_align = 0; // never - this state is handled in OOB
assign clr_reset = ~link_reset;
///assign clr_reset = set_align;
assign clr_send_rdy = set_nocommerr | set_reset | set_sync_esc | set_send_sof | set_rcvr_wait;
assign clr_send_sof = set_nocommerr | set_reset | set_sync_esc | set_send_data; // | got_escape;
assign clr_send_data = set_nocommerr | set_reset | set_sync_esc | set_send_rhold | set_send_shold | set_send_crc; // | got_escape;
assign clr_send_rhold = set_nocommerr | set_reset | set_sync_esc | set_send_data | set_send_crc; // | got_escape;
assign clr_send_shold = set_nocommerr | set_reset | set_sync_esc | set_send_data | set_send_rhold | set_send_crc; // | got_escape;
assign clr_send_crc = set_nocommerr | set_reset | set_sync_esc | set_send_eof; // | got_escape;
assign clr_send_eof = set_nocommerr | set_reset | set_sync_esc | set_wait; // | got_escape;
assign clr_wait = set_nocommerr | set_reset | set_sync_esc | frame_done; // | got_escape;
assign clr_rcvr_wait = set_nocommerr | set_reset | set_sync_esc /*| set_rcvr_rdy */ | (dword_val_na & ~rcvd_dword[CODE_XRDYP]);
assign clr_rcvr_rdy = set_nocommerr | set_reset | set_sync_esc /*| set_rcvr_data */ | (dword_val_na & ~rcvd_dword[CODE_XRDYP] & ~rcvd_dword[CODE_SOFP]);
assign clr_rcvr_data = set_nocommerr | set_reset | set_sync_esc /*| set_rcvr_rhold | set_rcvr_shold | set_rcvr_eof */ | set_rcvr_badend; // | got_escape;
assign clr_rcvr_rhold = set_nocommerr | set_reset | set_sync_esc /*| set_rcvr_data | set_rcvr_eof | set_rcvr_shold */; // | got_escape;
assign clr_rcvr_shold = set_nocommerr | set_reset | set_sync_esc /*| set_rcvr_data | set_rcvr_eof */; // | got_escape;
assign clr_rcvr_eof = set_nocommerr | set_reset | set_sync_esc /*|set_rcvr_goodcrc | set_rcvr_badend*/;
assign clr_rcvr_goodcrc = set_nocommerr | set_reset | set_sync_esc /*set_rcvr_goodend | set_rcvr_badend |*/; // | got_escape;
assign clr_rcvr_goodend = set_nocommerr | set_reset | set_sync_esc; // | got_escape; // can be 1 cycle only
assign clr_rcvr_badend = set_nocommerr | set_reset | set_sync_esc; // | got_escape;
// the only truely asynchronous transaction between states is -> state_ reset. It shall not be delayed by sending alignes
// Luckily, while in that state, the line is off, so we dont need to care about merging alignes and state-bounded primitives
// Others transitions are straightforward
always @ (posedge clk)
begin
state_sync_esc <= (state_sync_esc | set_sync_esc & ~alignes_pair) & ~(clr_sync_esc & ~alignes_pair) & ~rst;
state_nocommerr <= (state_nocommerr | set_nocommerr & ~alignes_pair) & ~(clr_nocommerr & ~alignes_pair) & ~rst;
state_nocomm <= (state_nocomm | set_nocomm & ~alignes_pair) & ~(clr_nocomm & ~alignes_pair) & ~rst;
// state_align is not used, it is handled by OOB
state_align <= (state_align | set_align & ~alignes_pair) & ~(clr_align & ~alignes_pair) & ~rst;
state_reset <= (state_reset | set_reset ) & ~ clr_reset & ~rst;
state_send_rdy <= (state_send_rdy | set_send_rdy & ~alignes_pair) & ~(clr_send_rdy & ~alignes_pair) & ~rst;
state_send_sof <= (state_send_sof | set_send_sof & ~alignes_pair) & ~(got_escape | (clr_send_sof & ~alignes_pair)) & ~rst;
state_send_data <= (state_send_data | set_send_data & ~alignes_pair) & ~(got_escape | (clr_send_data & ~alignes_pair)) & ~rst;
state_send_rhold <= (state_send_rhold | set_send_rhold & ~alignes_pair) & ~(got_escape | (clr_send_rhold & ~alignes_pair)) & ~rst;
state_send_shold <= (state_send_shold | set_send_shold & ~alignes_pair) & ~(got_escape | (clr_send_shold & ~alignes_pair)) & ~rst;
state_send_crc <= (state_send_crc | set_send_crc & ~alignes_pair) & ~(got_escape | (clr_send_crc & ~alignes_pair)) & ~rst;
state_send_eof <= (state_send_eof | set_send_eof & ~alignes_pair) & ~(got_escape | (clr_send_eof & ~alignes_pair)) & ~rst;
state_wait <= (state_wait | set_wait & ~alignes_pair) & ~(got_escape | (clr_wait & ~alignes_pair)) & ~rst;
// Andrey: most receiver states can not wait for transmitting aligns_pair. What host sends in this states matters when confirmed by the device
// So it seems OK if alignes_pair will just overwrite whatever host was going to send in these state.
// Care should be taken only for transitions between these states and others (transmit) that need to wait for alignes_pair to finish
// set_* are considered fast (no wait), clr_* - slow (to non-receive states), next opeartors use OR-ed "set_*" in immediate transitions
// to other states, clr_* - to other states
// rdy->data, data->eof
state_rcvr_wait <= (state_rcvr_wait | (set_rcvr_wait & ~alignes_pair)) & ~(set_rcvr_rdy | (clr_rcvr_wait & ~alignes_pair)) & ~rst;
state_rcvr_rdy <= (state_rcvr_rdy | set_rcvr_rdy ) & ~(set_rcvr_data | (clr_rcvr_rdy & ~alignes_pair)) & ~rst;
state_rcvr_data <= (state_rcvr_data | set_rcvr_data ) & ~(set_rcvr_shold |
set_rcvr_shold |
set_rcvr_eof |
got_escape | (clr_rcvr_data & ~alignes_pair)) & ~rst;
state_rcvr_rhold <= (state_rcvr_rhold | set_rcvr_rhold ) & ~(set_rcvr_data |
set_rcvr_shold |
set_rcvr_eof |
got_escape | (clr_rcvr_rhold & ~alignes_pair)) & ~rst;
state_rcvr_shold <= (state_rcvr_shold | set_rcvr_shold ) & ~(set_rcvr_data |
set_rcvr_eof |
got_escape | (clr_rcvr_shold & ~alignes_pair)) & ~rst;
state_rcvr_eof <= (state_rcvr_eof | set_rcvr_eof ) & ~(set_rcvr_goodcrc |
state_rcvr_badend |(clr_rcvr_eof & ~alignes_pair)) & ~rst;
state_rcvr_goodcrc <= (state_rcvr_goodcrc | set_rcvr_goodcrc ) & ~(set_rcvr_goodend |
set_rcvr_badend |
got_escape | (clr_rcvr_goodcrc & ~alignes_pair)) & ~rst;
state_rcvr_goodend <= (state_rcvr_goodend | set_rcvr_goodend ) & ~(got_escape | (clr_rcvr_goodend & ~alignes_pair)) & ~rst;
state_rcvr_badend <= (state_rcvr_badend | set_rcvr_badend ) & ~(got_escape | (clr_rcvr_badend & ~alignes_pair)) & ~rst;
end
// flag if incoming request to terminate current transaction came from TL
reg incom_stop_f;
always @ (posedge clk)
// incom_stop_f <= rst | incom_done | ~frame_busy ? 1'b0 : incom_stop_req ? 1'b1 : incom_stop_f;
if (rst) incom_stop_f <= 0;
else if (incom_stop_req) incom_stop_f <= 1;
else if (incom_done | ~frame_busy) incom_stop_f <= 0;
// form data to phy
reg [DATA_BYTE_WIDTH*8 - 1:0] to_phy_data;
reg [DATA_BYTE_WIDTH - 1:0] to_phy_isk;
// TODO implement CONTP
localparam [15:0] PRIM_SYNCP_HI = {3'd5, 5'd21, 3'd5, 5'd21};
localparam [15:0] PRIM_SYNCP_LO = {3'd4, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_ALIGNP_HI = {3'd3, 5'd27, 3'd2, 5'd10};
localparam [15:0] PRIM_ALIGNP_LO = {3'd2, 5'd10, 3'd5, 5'd28};
localparam [15:0] PRIM_XRDYP_HI = {3'd2, 5'd23, 3'd2, 5'd23};
localparam [15:0] PRIM_XRDYP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_SOFP_HI = {3'd1, 5'd23, 3'd1, 5'd23};
localparam [15:0] PRIM_SOFP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_HOLDAP_HI = {3'd4, 5'd21, 3'd4, 5'd21};
localparam [15:0] PRIM_HOLDAP_LO = {3'd5, 5'd10, 3'd3, 5'd28};
localparam [15:0] PRIM_HOLDP_HI = {3'd6, 5'd21, 3'd6, 5'd21};
localparam [15:0] PRIM_HOLDP_LO = {3'd5, 5'd10, 3'd3, 5'd28};
localparam [15:0] PRIM_EOFP_HI = {3'd6, 5'd21, 3'd6, 5'd21};
localparam [15:0] PRIM_EOFP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_WTRMP_HI = {3'd2, 5'd24, 3'd2, 5'd24};
localparam [15:0] PRIM_WTRMP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_RRDYP_HI = {3'd2, 5'd10, 3'd2, 5'd10};
localparam [15:0] PRIM_RRDYP_LO = {3'd4, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_IPP_HI = {3'd2, 5'd21, 3'd2, 5'd21};
localparam [15:0] PRIM_IPP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_DMATP_HI = {3'd1, 5'd22, 3'd1, 5'd22};
localparam [15:0] PRIM_DMATP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_OKP_HI = {3'd1, 5'd21, 3'd1, 5'd21};
localparam [15:0] PRIM_OKP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
localparam [15:0] PRIM_ERRP_HI = {3'd2, 5'd22, 3'd2, 5'd22};
localparam [15:0] PRIM_ERRP_LO = {3'd5, 5'd21, 3'd3, 5'd28};
//The transmission of CONTp is optional, but the ability to receive and properly process CONTp is required.
localparam [15:0] PRIM_CONTP_HI = {3'd4, 5'd25, 3'd4, 5'd25};
localparam [15:0] PRIM_CONTP_LO = {3'd5, 5'd10, 3'd3, 5'd28};
wire [DATA_BYTE_WIDTH*8 - 1:0] prim_data [PRIM_NUM - 1:0];
// fill all possible output primitives to choose from them after
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg prim_word; // word counter in a primitive TODO logic
assign prim_data[CODE_SYNCP] [15:0] = prim_word ? PRIM_SYNCP_HI : PRIM_SYNCP_LO;
assign prim_data[CODE_ALIGNP][15:0] = prim_word ? PRIM_ALIGNP_HI : PRIM_ALIGNP_LO;
assign prim_data[CODE_XRDYP] [15:0] = prim_word ? PRIM_XRDYP_HI : PRIM_XRDYP_LO;
assign prim_data[CODE_SOFP] [15:0] = prim_word ? PRIM_SOFP_HI : PRIM_SOFP_LO;
assign prim_data[CODE_DATA] [15:0] = scrambler_out[15:0];
assign prim_data[CODE_HOLDAP][15:0] = prim_word ? PRIM_HOLDAP_HI : PRIM_HOLDAP_LO;
assign prim_data[CODE_HOLDP] [15:0] = prim_word ? PRIM_HOLDP_HI : PRIM_HOLDP_LO;
assign prim_data[CODE_CRC] [15:0] = scrambler_out[15:0];
assign prim_data[CODE_EOFP] [15:0] = prim_word ? PRIM_EOFP_HI : PRIM_EOFP_LO;
assign prim_data[CODE_WTRMP] [15:0] = prim_word ? PRIM_WTRMP_HI : PRIM_WTRMP_LO;
assign prim_data[CODE_RRDYP] [15:0] = prim_word ? PRIM_RRDYP_HI : PRIM_RRDYP_LO;
assign prim_data[CODE_IPP] [15:0] = prim_word ? PRIM_IPP_HI : PRIM_IPP_LO;
assign prim_data[CODE_DMATP] [15:0] = prim_word ? PRIM_DMATP_HI : PRIM_DMATP_LO;
assign prim_data[CODE_OKP] [15:0] = prim_word ? PRIM_OKP_HI : PRIM_OKP_LO;
assign prim_data[CODE_ERRP] [15:0] = prim_word ? PRIM_ERRP_HI : PRIM_ERRP_LO;
assign prim_data[CODE_CONTP] [15:0] = prim_word ? PRIM_CONTP_HI : PRIM_CONTP_LO;
always @ (posedge clk)
begin
$display("%m: unsupported data width");
$finish;
end
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign prim_data[CODE_SYNCP] = {PRIM_SYNCP_HI , PRIM_SYNCP_LO};
assign prim_data[CODE_ALIGNP] = {PRIM_ALIGNP_HI , PRIM_ALIGNP_LO};
assign prim_data[CODE_XRDYP] = {PRIM_XRDYP_HI , PRIM_XRDYP_LO};
assign prim_data[CODE_SOFP] = {PRIM_SOFP_HI , PRIM_SOFP_LO};
assign prim_data[CODE_DATA] = scrambler_out;
assign prim_data[CODE_HOLDAP] = {PRIM_HOLDAP_HI , PRIM_HOLDAP_LO};
assign prim_data[CODE_HOLDP] = {PRIM_HOLDP_HI , PRIM_HOLDP_LO};
assign prim_data[CODE_CRC] = scrambler_out;
assign prim_data[CODE_EOFP] = {PRIM_EOFP_HI , PRIM_EOFP_LO};
assign prim_data[CODE_WTRMP] = {PRIM_WTRMP_HI , PRIM_WTRMP_LO};
assign prim_data[CODE_RRDYP] = {PRIM_RRDYP_HI , PRIM_RRDYP_LO};
assign prim_data[CODE_IPP] = {PRIM_IPP_HI , PRIM_IPP_LO};
assign prim_data[CODE_DMATP] = {PRIM_DMATP_HI , PRIM_DMATP_LO};
assign prim_data[CODE_OKP] = {PRIM_OKP_HI , PRIM_OKP_LO};
assign prim_data[CODE_ERRP] = {PRIM_ERRP_HI , PRIM_ERRP_LO};
assign prim_data[CODE_CONTP] = {PRIM_CONTP_HI , PRIM_CONTP_LO};
end
else
begin
always @ (posedge clk)
begin
$display("%m: unsupported data width");
$finish;
end
end
endgenerate
// select which primitive shall be sent
wire [PRIM_NUM - 1:0] select_prim;
assign select_prim[CODE_SYNCP] = ~alignes_pair & (state_idle | state_sync_esc | state_rcvr_wait | state_reset);
assign select_prim[CODE_ALIGNP] = alignes_pair | (state_nocomm | state_nocommerr | state_align);
assign select_prim[CODE_XRDYP] = ~alignes_pair & (state_send_rdy);
assign select_prim[CODE_SOFP] = ~alignes_pair & (state_send_sof);
assign select_prim[CODE_DATA] = ~alignes_pair & (state_send_data & ~set_send_shold); // if there's no data availible for a transmission, fsm still = state_send_data. Need to explicitly count this case.
assign select_prim[CODE_HOLDAP] = ~alignes_pair & (state_send_rhold | state_rcvr_shold & ~incom_stop_f);
assign select_prim[CODE_HOLDP] = ~alignes_pair & (state_send_shold | state_rcvr_rhold | state_send_data & set_send_shold); // the case mentioned 2 lines upper
assign select_prim[CODE_CRC] = ~alignes_pair & (state_send_crc);
assign select_prim[CODE_EOFP] = ~alignes_pair & (state_send_eof);
assign select_prim[CODE_WTRMP] = ~alignes_pair & (state_wait);
assign select_prim[CODE_RRDYP] = ~alignes_pair & (state_rcvr_rdy);
assign select_prim[CODE_IPP] = ~alignes_pair & (state_rcvr_data & ~incom_stop_f | state_rcvr_eof | state_rcvr_goodcrc);
assign select_prim[CODE_DMATP] = ~alignes_pair & (state_rcvr_data & incom_stop_f | state_rcvr_shold & incom_stop_f);
assign select_prim[CODE_OKP] = ~alignes_pair & (state_rcvr_goodend);
assign select_prim[CODE_ERRP] = ~alignes_pair & (state_rcvr_badend);
// No sending of CONTp
// primitive selector MUX
always @ (posedge clk)
to_phy_data <= rst ? {DATA_BYTE_WIDTH*8{1'b0}}:
{DATA_BYTE_WIDTH*8{select_prim[CODE_SYNCP]}} & prim_data[CODE_SYNCP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_ALIGNP]}} & prim_data[CODE_ALIGNP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_RRDYP]}} & prim_data[CODE_RRDYP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_SOFP]}} & prim_data[CODE_SOFP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_HOLDAP]}} & prim_data[CODE_HOLDAP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_HOLDP]}} & prim_data[CODE_HOLDP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_EOFP]}} & prim_data[CODE_EOFP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_WTRMP]}} & prim_data[CODE_WTRMP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_XRDYP]}} & prim_data[CODE_XRDYP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_IPP]}} & prim_data[CODE_IPP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_DMATP]}} & prim_data[CODE_DMATP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_OKP]}} & prim_data[CODE_OKP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_ERRP]}} & prim_data[CODE_ERRP] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_CRC]}} & prim_data[CODE_CRC] |
{DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} & prim_data[CODE_DATA];
always @ (posedge clk)
to_phy_isk <= rst | ~select_prim[CODE_DATA] & ~select_prim[CODE_CRC] ? {{(DATA_BYTE_WIDTH - 1){1'b0}}, 1'b1} : {DATA_BYTE_WIDTH{1'b0}} ;
// incoming data is data
wire inc_is_data;
assign inc_is_data = dword_val & rcvd_dword[CODE_DATA] & (state_rcvr_data | state_rcvr_rhold);
//wire inc_is_crc = dword_val_na & rcvd_dword[CODE_CRC] & (state_rcvr_data | state_rcvr_rhold);
/*
* Scrambler can work both as a scrambler and a descramler, because data stream could be
* one direction at a time
*/
scrambler scrambler(
.rst (select_prim[CODE_SOFP] | dword_val & rcvd_dword[CODE_SOFP]),
.clk (clk),
.val_in (select_prim[CODE_DATA] | inc_is_data | select_prim[CODE_CRC]),
.data_in (crc_dword & {DATA_BYTE_WIDTH*8{select_prim[CODE_CRC]}} |
data_in & {DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} |
phy_data_in_r & {DATA_BYTE_WIDTH*8{inc_is_data}}),
.data_out (scrambler_out)
);
/*
* Same as for scrambler, crc computation for both directions
*/
crc crc(
.clk (clk),
.rst (select_prim[CODE_SOFP] | dword_val & rcvd_dword[CODE_SOFP]),
.val_in (select_prim[CODE_DATA] | inc_is_data),
.data_in (data_in & {DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} | scrambler_out & {DATA_BYTE_WIDTH*8{inc_is_data}}),
.crc_out (crc_dword)
);
// the output of crc module shall be 0 if 1 tick later reciever got a crc checksum and no errors occured
assign crc_good = ~|crc_dword & state_rcvr_eof;
assign crc_bad = |crc_dword & state_rcvr_eof;
// to TL data outputs assigment
// delay outputs so the last data would be marked
reg [31:0] data_out_r;
reg data_val_out_r;
reg [31:0] data_out_rr;
reg data_val_out_rr;
// if current == EOF => _r == CRC and _rr == last data piece
reg data_held; // some data is held in data_out_r over primitives - to be restored if not EOF
// no need to check for set_rcvr_eof - last dword will be always lost
always @ (posedge clk) begin
if (dword_val & rcvd_dword[CODE_SOFP]) data_held <= 0;
else if (inc_is_data) data_held <= 1;
if (inc_is_data) data_out_r <= scrambler_out;
if (data_val_out_r) data_out_rr <= data_out_r;
data_val_out_r <= inc_is_data;
data_val_out_rr <= inc_is_data && data_held;
end
assign data_out = data_out_rr;
assign data_mask_out = 2'b11;//{DATA_BYTE_WIDTH/2{1'b1}};
assign data_val_out = data_val_out_rr;
assign data_last_out = set_rcvr_eof;
// from TL data
// gives a strobe everytime data is present and we're at a corresponding state.
assign data_strobe_out = select_prim[CODE_DATA];
// Just to make output signals single-cycel regardless of alignes_pair and remove dependence on SM code
wire frame_rej_w;
wire incom_start_w;
wire incom_done_w;
wire incom_invalidate_w;
reg frame_rej_r;
reg incom_start_r;
reg incom_done_r;
reg incom_invalidate_r;
assign frame_rej = frame_rej_w && !frame_rej_r;
assign incom_start = incom_start_w && ! incom_start_r;
assign incom_done = incom_done_w && ! incom_done_r;
assign incom_invalidate = incom_invalidate_w && ! incom_invalidate_r;
always @ (posedge clk) begin
frame_rej_r <= frame_rej_w;
incom_start_r <= incom_start_w;
incom_done_r <= incom_done_w;
incom_invalidate_r <= incom_invalidate_w;
end
// assign phy data outputs
assign phy_data_out = to_phy_data;
assign phy_isk_out = to_phy_isk;
assign frame_busy = ~state_idle;
assign frame_ack = state_send_sof;
assign frame_rej_w = set_rcvr_wait & state_send_rdy; // & ~alignes_pair; // OK to mask with
// incoming fises detected
assign incom_start_w = set_rcvr_wait; // & ~alignes_pair;
// ... and processed
assign incom_done_w = set_rcvr_goodcrc; // & ~alignes_pair;
// or the FIS had errors
// Separating different types of errors, sync_escape from other problems. TODO: route individual errors to set SERR bits
assign incom_invalidate_w = (state_rcvr_eof & crc_bad) | // CRC mismatch
(state_rcvr_data & dword_val & rcvd_dword[CODE_WTRMP]); // missed EOF?
assign incom_sync_escape = (state_rcvr_wait | state_rcvr_rdy | state_rcvr_data | state_rcvr_rhold |
state_rcvr_shold | state_rcvr_eof | state_rcvr_goodcrc) & got_escape;
// shows that incoming primitive or data is ready to be processed // TODO somehow move alignes_pair into dword_val_na
assign dword_val = |rcvd_dword & phy_ready; // any valid primitive/data
assign dword_val_na = |rcvd_dword & phy_ready & ~rcvd_dword[CODE_ALIGNP]; // any valid primitive/data but ALIGNp
// determine imcoming primitive type
assign rcvd_dword[CODE_DATA] = ~|phy_isk_in_r;
assign rcvd_dword[CODE_CRC] = 1'b0;
assign rcvd_dword[CODE_SYNCP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_SYNCP ] == phy_data_in_r);
assign rcvd_dword[CODE_ALIGNP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_ALIGNP] == phy_data_in_r);
assign rcvd_dword[CODE_XRDYP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_XRDYP ] == phy_data_in_r);
assign rcvd_dword[CODE_SOFP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_SOFP ] == phy_data_in_r);
assign rcvd_dword[CODE_HOLDAP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_HOLDAP] == phy_data_in_r);
assign rcvd_dword[CODE_HOLDP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_HOLDP ] == phy_data_in_r);
assign rcvd_dword[CODE_EOFP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_EOFP ] == phy_data_in_r);
assign rcvd_dword[CODE_WTRMP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_WTRMP ] == phy_data_in_r);
assign rcvd_dword[CODE_RRDYP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_RRDYP ] == phy_data_in_r);
assign rcvd_dword[CODE_IPP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_IPP ] == phy_data_in_r);
assign rcvd_dword[CODE_DMATP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_DMATP ] == phy_data_in_r);
assign rcvd_dword[CODE_OKP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_OKP ] == phy_data_in_r);
assign rcvd_dword[CODE_ERRP] = phy_isk_in_r[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_ERRP ] == phy_data_in_r);
// was missing
assign rcvd_dword[CODE_CONTP] = phy_isk_in_r[0] && ~(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_CONTP ] == phy_data_in_r);
// CONTp (*_r0 is one cycle ahead of *_r)
// Following is processed one cycle ahead of the others to replace CONTp junk with the replaced repeated primitives
assign is_cont_p_w = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_CONTP ] == phy_data_in_r0);
assign is_align_p_w = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_ALIGNP ] == phy_data_in_r0);
assign is_non_cont_non_align_p_w = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_CONTP ] != phy_data_in_r0)
&& (prim_data[CODE_ALIGNP ] != phy_data_in_r0);
// phy level errors handling TODO
assign dec_err = |phy_err_in_r;
// form a response to transport layer
assign frame_done = frame_done_good | frame_done_bad;
assign frame_done_good = state_wait & dword_val & rcvd_dword[CODE_OKP];
assign frame_done_bad = state_wait & dword_val & rcvd_dword[CODE_ERRP];
// Handling 3 non-align primitives - removed, this is (should be) done by OOB
// =========== Debug code ===================
wire [PRIM_NUM - 1:0] rcvd_dword0; // at least oce received after reset
assign rcvd_dword0[CODE_DATA] = ~|phy_isk_in_r0;
assign rcvd_dword0[CODE_CRC] = 1'b0;
assign rcvd_dword0[CODE_SYNCP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_SYNCP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_ALIGNP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_ALIGNP] == phy_data_in_r0);
assign rcvd_dword0[CODE_XRDYP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_XRDYP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_SOFP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_SOFP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_HOLDAP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_HOLDAP] == phy_data_in_r0);
assign rcvd_dword0[CODE_HOLDP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_HOLDP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_EOFP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_EOFP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_WTRMP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_WTRMP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_RRDYP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_RRDYP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_IPP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_IPP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_DMATP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_DMATP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_OKP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_OKP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_ERRP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_ERRP ] == phy_data_in_r0);
assign rcvd_dword0[CODE_CONTP] = phy_isk_in_r0[0] && !(|phy_isk_in_r0[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_CONTP ] == phy_data_in_r0);
reg [PRIM_NUM - 1:0] debug_rcvd_dword; // at least once received after reset
reg debug_first_error;
reg debug_first_alignp;
reg debug_first_syncp;
reg debug_first_nonsyncp;
reg debug_first_unknown;
reg [19:0] debug_to_first_err;
reg [15:0] debug_num_aligns;
reg [15:0] debug_num_syncs;
reg [15:0] debug_num_later_aligns;
reg other_prim_r;
reg [15:0] debug_num_other; // other primitives - not aligh, sync or cont
reg [31:0] debug_unknown_dword;
wire debug_is_sync_p_w = phy_isk_in_r0[0] && !(|phy_isk_in_r[DATA_BYTE_WIDTH-1:1]) && (prim_data[CODE_SYNCP ] == phy_data_in_r0);
wire [STATES_COUNT - 1:0] debug_states_concat = {
state_idle
, state_sync_esc
, state_nocommerr
, state_nocomm
, state_align
, state_reset
, state_send_rdy
, state_send_sof
, state_send_data
, state_send_rhold
, state_send_shold
, state_send_crc
, state_send_eof
, state_wait
, state_rcvr_wait
, state_rcvr_rdy
, state_rcvr_data
, state_rcvr_rhold
, state_rcvr_shold
, state_rcvr_eof
, state_rcvr_goodcrc
, state_rcvr_goodend
, state_rcvr_badend
};
reg [4:0] debug_states_encoded;
reg [STATES_COUNT - 1:0] debug_states_visited;
always @ (posedge clk) begin
other_prim_r <= is_non_cont_non_align_p_w && !debug_is_sync_p_w;
if (rst) debug_first_alignp <= 0;
else if (is_align_p_w) debug_first_alignp <= 1;
if (rst) debug_first_syncp <= 0;
else if (debug_is_sync_p_w && debug_first_alignp) debug_first_syncp <= 1;
if (rst) debug_first_error <= 0;
else if (dec_err && debug_first_syncp) debug_first_error <= 1;
if (rst) debug_first_nonsyncp <= 0;
else if (!debug_is_sync_p_w && debug_first_syncp) debug_first_nonsyncp <= 1;
if (rst) debug_first_unknown <= 0;
else if ((rcvd_dword0 ==0) && debug_first_alignp) debug_first_unknown <= 1;
if (rst) debug_to_first_err <= 0;
else if (debug_first_alignp && !debug_first_error) debug_to_first_err <= debug_to_first_err + 1;
if (rst) debug_num_aligns <= 0;
else if (debug_first_alignp && !debug_first_syncp) debug_num_aligns <= debug_num_aligns + 1;
if (rst) debug_num_syncs <= 0;
else if (debug_first_syncp && !debug_first_nonsyncp) debug_num_syncs <= debug_num_syncs + 1;
if (rst) debug_num_later_aligns <= 0;
else if (debug_first_nonsyncp && !debug_first_error && is_align_p_w) debug_num_later_aligns <= debug_num_later_aligns + 1;
if (rst) debug_num_other <= 0;
else if (debug_first_nonsyncp && !debug_first_error && other_prim_r) debug_num_other <= debug_num_other + 1;
if (rst) debug_unknown_dword <= 0;
else if ((rcvd_dword0 ==0) && debug_first_alignp && !debug_first_unknown) debug_unknown_dword <= phy_data_in_r0;
if (rst) debug_rcvd_dword <= 0;
else if (debug_first_syncp && !debug_first_error) debug_rcvd_dword <= debug_rcvd_dword | rcvd_dword0;
if (rst) debug_states_visited <= 0;
else debug_states_visited <= debug_states_visited | debug_states_concat;
debug_states_encoded <= { |debug_states_concat[22:16],
|debug_states_concat[15: 8],
(|debug_states_concat[22:20]) | (|debug_states_concat[15:12]) | (|debug_states_concat[7:4]),
debug_states_concat[22] | (|debug_states_concat[19:18]) | (|debug_states_concat[15:14]) |
(|debug_states_concat[11:10]) | (|debug_states_concat[7:6]) | (|debug_states_concat[3:2]),
debug_states_concat[21] | debug_states_concat[19] | debug_states_concat[17] | debug_states_concat[15] |
debug_states_concat[13] | debug_states_concat[11] | debug_states_concat[ 9] | debug_states_concat[7] |
debug_states_concat[ 5] | debug_states_concat[ 3] | debug_states_concat[ 1]};
end
reg [1:0] debug_data_last_in_r;
reg [1:0] debug_alignes_pair_r;
reg [1:0] debug_state_send_data_r;
reg [1:0] debug_dword_val_na;
reg [1:0] debug_CODE_SYNCP;
reg [1:0] debug_set_send_crc;
reg [1:0] debug_data_val_in;
reg [1:0] debug_was_OK_ERR;
reg debug_was_wait;
reg debug_was_idle;
reg debug_was_ok_err;
reg debug_was_state_wait;
reg debug_was_frame_done;
reg debug_was_got_escape;
// frame_done | got_escape
always @(posedge clk) begin
if (data_strobe_out) begin
debug_data_last_in_r <= {debug_data_last_in_r[0],data_last_in};
debug_alignes_pair_r <= {debug_alignes_pair_r[0],alignes_pair};
debug_state_send_data_r <= {debug_state_send_data_r[0],state_send_data};
debug_dword_val_na <= {debug_dword_val_na[0],dword_val_na};
debug_CODE_SYNCP <= {debug_CODE_SYNCP[0],rcvd_dword[CODE_SYNCP]};
debug_set_send_crc <= {debug_set_send_crc[0],set_send_crc};
debug_data_val_in <= {debug_data_val_in[0],data_val_in};
end
debug_was_ok_err <= rcvd_dword[CODE_ERRP] | rcvd_dword[CODE_OKP];
if (frame_req) debug_was_OK_ERR <= 0;
else debug_was_OK_ERR <= debug_was_OK_ERR | {rcvd_dword[CODE_ERRP], rcvd_dword[CODE_OKP]};
if (frame_req) debug_was_state_wait <= 0;
else debug_was_state_wait <= debug_was_state_wait | state_wait;
if (state_wait && clr_wait && !alignes_pair) debug_was_frame_done <= frame_done;
if (state_wait && clr_wait && !alignes_pair) debug_was_got_escape <= got_escape;
if ((rcvd_dword[CODE_ERRP] || rcvd_dword[CODE_OKP]) && !debug_was_ok_err) begin
debug_was_wait <= state_wait;
debug_was_idle <= state_idle;
end
end
assign debug_out[ 4: 0] = debug_states_encoded;
assign debug_out[7: 5] = {
rcvd_dword[CODE_SYNCP],
rcvd_dword[CODE_OKP],
alignes_pair};
assign debug_out[31] = rcvd_dword[CODE_ALIGNP];
assign debug_out[30] = set_send_sof;
assign debug_out[29] = clr_send_rdy;
assign debug_out[28] = state_send_rdy;
assign debug_out[27] = state_send_sof;
assign debug_out[26] = state_idle;
assign debug_out[25] = state_send_data;
assign debug_out[24] = (state_send_sof | set_send_sof & ~alignes_pair);
assign debug_out[23] = (clr_send_sof & ~alignes_pair);
assign debug_out[22] = set_rcvr_wait; // start logging input
//assign debug_out[15: 5] = debug_to_first_err[14:4];
assign debug_out[21:16] = debug_rcvd_dword[5:0];
assign debug_out[15: 8] = {
debug_was_wait, // state was wait when last CODE_ERRP/CODE_OKP was received
debug_was_idle, // state was idle when last CODE_ERRP/CODE_OKP was received
debug_was_OK_ERR[1:0],
debug_was_state_wait,
debug_was_frame_done,
debug_was_got_escape,
/* debug_data_last_in_r[1],
debug_alignes_pair_r[1],
debug_state_send_data_r[1],
debug_state_send_data_r[0],
debug_data_val_in[1],
debug_data_val_in[0],
debug_set_send_crc[1],
*/
// debug_dword_val_na[1],
~debug_CODE_SYNCP[1]};
/*
state_send_sof <= (state_send_sof | set_send_sof & ~alignes_pair) & ~(clr_send_sof & ~alignes_pair) & ~rst;
_send_crc = state_send_data & data_txing & data_val_in & data_last_in & dword_val_na & ~rcvd_dword[CODE_SYNCP]
| state_send_data & dword_val_na & rcvd_dword[CODE_DMATP];
*/
//assign debug_out[STATES_COUNT - 1:0] = debug_states_visited;
/*
//assign debug_out[PRIM_NUM - 1:0] = debug_rcvd_dword;
assign debug_out[ 7: 0] = debug_rcvd_dword[7:0];
assign debug_out[15: 8] = debug_alignes;
assign debug_out[23:16] = debug_data_primitives;
assign debug_out[30:24] = debug_notaligned_primitives[6:0]; // now count state_reset _/~
assign debug_out[31] = debug_state_reset_r[0];
*/
`ifdef CHECKERS_ENABLED
// incoming primitives
always @ (posedge clk)
if (~|rcvd_dword & phy_ready)
begin
$display("%m: invalid primitive received : %h, conrol : %h, err : %h", phy_data_in_r, phy_isk_in_r, phy_err_in_r);
#500;
$finish;
end
// States checker
reg [STATES_COUNT - 1:0] sim_states_concat;
always @ (posedge clk)
if (~rst)
if (( 32'h0
+ state_idle
+ state_sync_esc
+ state_nocommerr
+ state_nocomm
+ state_align
+ state_reset
+ state_send_rdy
+ state_send_sof
+ state_send_data
+ state_send_rhold
+ state_send_shold
+ state_send_crc
+ state_send_eof
+ state_wait
+ state_rcvr_wait
+ state_rcvr_rdy
+ state_rcvr_data
+ state_rcvr_rhold
+ state_rcvr_shold
+ state_rcvr_eof
+ state_rcvr_goodcrc
+ state_rcvr_goodend
+ state_rcvr_badend
) != 1)
begin
sim_states_concat = {
state_idle
, state_sync_esc
, state_nocommerr
, state_nocomm
, state_align
, state_reset
, state_send_rdy
, state_send_sof
, state_send_data
, state_send_rhold
, state_send_shold
, state_send_crc
, state_send_eof
, state_wait
, state_rcvr_wait
, state_rcvr_rdy
, state_rcvr_data
, state_rcvr_rhold
, state_rcvr_shold
, state_rcvr_eof
, state_rcvr_goodcrc
, state_rcvr_goodend
, state_rcvr_badend
};
$display("%m: invalid states: %b", sim_states_concat);
// $finish;
end
`endif
`ifdef SIMULATION
integer sim_cnt;
always @ (posedge clk) begin
if (incom_start) begin
HOST_LINK_TITLE = "Incoming start";
$display("[Host] LINK: %s @%t", HOST_LINK_TITLE, $time);
sim_cnt = 0;
end
if (data_val_out) begin
HOST_LINK_TITLE = "From device - received data";
HOST_LINK_DATA = data_out;
$display("[Host] LINK: %s = %h (#%d)@%t", HOST_LINK_TITLE, HOST_LINK_DATA, sim_cnt, $time);
sim_cnt = sim_cnt + 1;
end
if (incom_done) begin
HOST_LINK_TITLE = "Incoming end";
$display("[Host] LINK: %s @%t", HOST_LINK_TITLE, $time);
sim_cnt = 0;
end
if (incom_invalidate) begin
HOST_LINK_TITLE = "Incoming invalidate";
$display("[Host] LINK: %s @%t", HOST_LINK_TITLE, $time);
sim_cnt = 0;
end
if (incom_sync_escape) begin
HOST_LINK_TITLE = "Incoming sync_escape";
$display("[Host] LINK: %s @%t", HOST_LINK_TITLE, $time);
sim_cnt = 0;
end
if (incom_ack_good) begin
HOST_LINK_TITLE = "Incoming ack_good";
$display("[Host] LINK: %s @%t", HOST_LINK_TITLE, $time);
sim_cnt = 0;
end
if (incom_ack_bad) begin
HOST_LINK_TITLE = "Incoming ack_bad";
$display("[Host] LINK: %s @%t", HOST_LINK_TITLE, $time);
sim_cnt = 0;
end
// if (inc_is_data) begin
// $display("[Host] LINK: From device - received raw data = %h", phy_data_in);
// end
end
`endif
endmodule
/*******************************************************************************
* Module: oob
* Date: 2015-07-11
* Author: Alexey
* Description: sata oob unit implementation
*
* Copyright (c) 2015 Elphel, Inc.
* oob.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.
*
* oob.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
/*
* For now both device and host shall be set up to SATA2 speeds.
* Need to think how to change speed grades on fly (either to broaden
* data iface width or to change RXRATE/TXRATE)
*/
// All references to doc = to SerialATA_Revision_2_6_Gold.pdf
module oob #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 1 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
output reg [11:0] debug,
input wire clk, // sata clk = usrclk2
input wire rst, // reset oob
// oob responses
input wire rxcominitdet_in,
input wire rxcomwakedet_in,
input wire rxelecidle_in,
// oob issues
output wire txcominit,
output wire txcomwake,
output wire txelecidle,
output wire txpcsreset_req, // partial tx reset
input wire recal_tx_done,
output wire rxreset_req, // rx reset (after rxelecidle -> 0)
input wire rxreset_ack,
// Andrey: adding new signal and state - after RX is operational try re-align clock
output wire clk_phase_align_req, // Request GTX to align SIPO parallel clock and user- provided RXUSRCLK
input wire clk_phase_align_ack, // GTX aligned clock phase (DEBUG - not always clear when it works or not)
input wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_in, // input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in,
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out, // output data stream to gtx
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out,
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in, // input data from gtx
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in,
output wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_out, // bypassed data from gtx
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out,
input wire oob_start, // oob sequence needs to be issued
output wire oob_done, // connection established, all further data is valid
output wire oob_busy, // oob can't handle new start request
output wire link_up, // doc p265, link is established after 3back-to-back non-ALIGNp
output wire link_down, // link goes down - if rxelecidle
output wire cominit_req, // the device itself sends cominit
input wire cominit_allow, // allow to respond to cominit
// status information to handle by a control block if any exists
output wire oob_incompatible, // incompatible host-device speed grades (host cannot lock to alignp)
output wire oob_error, // timeout in an unexpected place
output wire oob_silence // noone responds to our cominits
,output debug_detected_alignp
`ifdef OOB_MULTISPEED
//TODO
// !!Implement it later on, ref to gen.adjustment fsm in the notebook!!
// speed grade control
,
// current speed grade, dynamic instead of static parameter
input wire [2:0] speed_grade,
// clock to be adjusted to best speed
input wire adj_clk,
// ask for slower protocol clock
output wire speed_down_req,
input wire speed_down_ack,
// reset speedgrade to the fastest one
output wire speed_rst_req,
input wire speed_rst_ack
`endif //OOB_MULTISPEED
);
assign debug_detected_alignp = detected_alignp;
`ifdef SIMULATION
reg [639:0] HOST_OOB_TITLE ='bz; // to show human-readable state in the GTKWave
`endif
// 873.8 us error timer
// = 2621400 SATA2 serial ticks (period = 0.000333 us)
// = 131070 ticks @ 150Mhz
// = 65535 ticks @ 75Mhz
localparam [19:0] CLK_TO_TIMER_CONTRIB = CLK_SPEED_GRADE == 1 ? 20'h4 :
CLK_SPEED_GRADE == 2 ? 20'h2 :
CLK_SPEED_GRADE == 4 ? 20'h1 : 20'h1;
localparam RXDLYSRESET_CYCLES = 5; // minimum - 50ns
reg [RXDLYSRESET_CYCLES-1:0] rxdlysreset_r;
assign clk_phase_align_req = rxdlysreset_r[RXDLYSRESET_CYCLES-1];
`ifdef SIMULATION
localparam [19:0] TIMER_LIMIT = 19'd20000;
`else
localparam [19:0] TIMER_LIMIT = 19'd262140;
`endif
reg [19:0] timer;
wire timer_clr;
wire timer_fin;
// latching inputs from gtx
reg rxcominitdet;
reg rxcomwakedet;
reg rxelecidle;
reg [DATA_BYTE_WIDTH*8 - 1:0] rxdata;
reg [DATA_BYTE_WIDTH - 1:0] rxcharisk;
// primitives detection
wire detected_alignp;
localparam NUM_CON_ALIGNS = 2; // just for debugging 1024;
reg [1:0] detected_alignp_cntr; // count detected ALIGNp - do not respond yet
///localparam NUM_CON_ALIGNS = 1024; // just for debugging 1024;
///reg [12:0] detected_alignp_cntr; // count detected ALIGNp - do not respond yet
reg detected_alignp_r; // debugging - N-th ALIGNp primitive
wire detected_syncp;
// wait until device's cominit is done
reg cominit_req_l;
reg rxcominitdet_l;
reg rxcomwakedet_l;
wire rxcominit_done;
wire rxcomwake_done;
reg [9:0] rxcom_timer;
// for 75MHz : period of cominit = 426.7 ns = 32 ticks => need to wait x6 pulses + 1 as an insurance => 224 clock cycles. Same thoughts for comwake
localparam COMINIT_DONE_TIME = 896; // 300Mhz cycles
localparam COMWAKE_DONE_TIME = 448; // 300Mhz cycles
// wait until rxelecidle is not stable (more or less) deasserted
// let's say, if rxelecidle = 0 longer, than 2 comwake burst duration (2 * 106.7 ns), elecidle is stable and we're receiving some data
// 2 * 106.7ns = 64 clock cycles @ 300 MHz, 32 @ 150, 16 @ 75
// rxelecidle is synchronous to sata host clk, sooo some idle raises can occur insensibly. Still, it means line issues,
// not affecting the fact, oob was done and a stage when device sends alignps started
reg [7:0] eidle_timer;
wire eidle_timer_done;
// fsm, doc p265,266
wire state_idle;
reg state_wait_cominit;
reg state_wait_comwake;
reg state_recal_tx;
reg state_wait_eidle;
reg state_wait_rxrst;
reg state_wait_align;
reg state_wait_clk_align;
reg state_wait_align2; // after clocks aligned
reg state_wait_synp;
reg state_wait_linkup;
reg state_error;
wire set_wait_cominit;
wire set_wait_comwake;
wire set_recal_tx;
wire set_wait_eidle;
wire set_wait_rxrst;
wire set_wait_align;
wire set_wait_clk_align;
wire set_wait_align2;
wire set_wait_synp;
wire set_wait_linkup;
wire set_error;
wire clr_wait_cominit;
wire clr_wait_comwake;
wire clr_recal_tx;
wire clr_wait_eidle;
wire clr_wait_rxrst;
wire clr_wait_align;
wire clr_wait_clk_align;
wire clr_wait_align2;
wire clr_wait_synp;
wire clr_wait_linkup;
wire clr_error;
always @ (posedge clk) begin
if (rst || rxelecidle) rxdlysreset_r <= 0;
else if (set_wait_clk_align) rxdlysreset_r <= ~0;
else rxdlysreset_r <= rxdlysreset_r << 1;
end
assign state_idle = ~state_wait_cominit &
~state_wait_comwake &
~state_wait_align &
~state_wait_clk_align &
~state_wait_align2 &
~state_wait_synp &
~state_wait_linkup &
~state_error &
~state_recal_tx &
~state_wait_rxrst &
~state_wait_eidle;
always @ (posedge clk)
begin
state_wait_cominit <= (state_wait_cominit | set_wait_cominit ) & ~clr_wait_cominit & ~rst;
state_wait_comwake <= (state_wait_comwake | set_wait_comwake ) & ~clr_wait_comwake & ~rst;
state_recal_tx <= (state_recal_tx | set_recal_tx ) & ~clr_recal_tx & ~rst;
state_wait_eidle <= (state_wait_eidle | set_wait_eidle ) & ~clr_wait_eidle & ~rst;
state_wait_rxrst <= (state_wait_rxrst | set_wait_rxrst ) & ~clr_wait_rxrst & ~rst;
state_wait_align <= (state_wait_align | set_wait_align ) & ~clr_wait_align & ~rst;
state_wait_clk_align <= (state_wait_clk_align | set_wait_clk_align) & ~clr_wait_clk_align & ~rst;
state_wait_align2 <= (state_wait_align2 | set_wait_align2 ) & ~clr_wait_align2 & ~rst;
state_wait_synp <= (state_wait_synp | set_wait_synp ) & ~clr_wait_synp & ~rst;
state_wait_linkup <= (state_wait_linkup | set_wait_linkup ) & ~clr_wait_linkup & ~rst;
state_error <= (state_error | set_error ) & ~clr_error & ~rst;
end
assign set_wait_cominit = state_idle & oob_start & ~cominit_req;
assign set_wait_comwake = state_idle & cominit_req_l & cominit_allow & rxcominit_done | state_wait_cominit & rxcominitdet_l & rxcominit_done;
assign set_recal_tx = state_wait_comwake & rxcomwakedet_l & rxcomwake_done;
assign set_wait_eidle = state_recal_tx & recal_tx_done;
assign set_wait_rxrst = state_wait_eidle & eidle_timer_done;
assign set_wait_align = state_wait_rxrst & rxreset_ack;
assign set_wait_clk_align = state_wait_align & (detected_alignp_r);
assign set_wait_align2 = state_wait_clk_align & clk_phase_align_ack;
//assign set_wait_synp = state_wait_align & detected_alignp;
assign set_wait_synp = state_wait_align2 & (detected_alignp_r); // N previous were both ALIGNp
assign set_wait_linkup = state_wait_synp & detected_syncp;
assign set_error = timer_fin & (state_wait_cominit |
state_wait_comwake |
state_recal_tx |
state_wait_eidle |
state_wait_rxrst |
state_wait_align |
state_wait_clk_align |
state_wait_align2 |
state_wait_synp/* | state_wait_linkup*/);
assign clr_wait_cominit = set_wait_comwake | set_error;
assign clr_wait_comwake = set_recal_tx | set_error;
assign clr_recal_tx = set_wait_eidle | set_error;
assign clr_wait_eidle = set_wait_rxrst | set_error;
assign clr_wait_rxrst = set_wait_align | set_error;
assign clr_wait_align = set_wait_clk_align | set_error;
assign clr_wait_clk_align = set_wait_align2 | set_error;
assign clr_wait_align2 = set_wait_synp | set_error;
assign clr_wait_synp = set_wait_linkup | set_error;
assign clr_wait_linkup = state_wait_linkup; //TODO not so important, but still have to trace 3 back-to-back non alignp primitives
assign clr_error = state_error;
// waiting timeout timer
assign timer_fin = timer == TIMER_LIMIT;
assign timer_clr = set_error | state_error | state_idle;
always @ (posedge clk)
timer <= rst | timer_clr ? 20'h0 : timer + CLK_TO_TIMER_CONTRIB;
// something is wrong with speed grades if the host cannot lock to device's alignp stream
assign oob_incompatible = state_wait_align & set_error;
// oob sequence is done, everything is okay
assign oob_done = set_wait_linkup;
// noone responds to cominits
assign oob_silence = set_error & state_wait_cominit;
// other timeouts
assign oob_error = set_error & ~oob_silence & ~oob_incompatible;
// obvioud
assign oob_busy = ~state_idle;
// ask for recalibration
assign txpcsreset_req = state_recal_tx;
// ask for rxreset
assign rxreset_req = state_wait_rxrst;
// set gtx controls
reg txelecidle_r;
always @ (posedge clk)
txelecidle_r <= rst ? 1'b1 : /*clr_wait_cominit */ clr_wait_comwake ? 1'b0 : set_wait_cominit ? 1'b1 : txelecidle_r;
assign txcominit = set_wait_cominit;
assign txcomwake = set_wait_comwake;
assign txelecidle = set_wait_cominit | txelecidle_r;
// indicate if link up condition was made
assign link_up = clr_wait_linkup;
// link goes down when line is idle
reg rxelecidle_r;
reg rxelecidle_rr;
always @ (posedge clk)
begin
rxelecidle_rr <= rxelecidle_r;
rxelecidle_r <= rxelecidle;
end
assign link_down = rxelecidle_rr;
// indicate that device is requesting for oob
reg cominit_req_r;
wire cominit_req_set;
assign cominit_req_set = state_idle & rxcominitdet;
always @ (posedge clk)
cominit_req_r <= (cominit_req_r | cominit_req_set) & ~(cominit_allow & cominit_req) & ~rst;
assign cominit_req = cominit_req_set | cominit_req_r;
// primitives
wire [63:0] alignp = {8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100, 8'b01111011, 8'b01001010, 8'b01001010, 8'b10111100};
wire [63:0] syncp = {8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100, 8'b10110101, 8'b10110101, 8'b10010101, 8'b01111100};
// detect which primitives sends the device after comwake was done
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg detected_alignp_f;
always @ (posedge clk)
detected_alignp_f <= rst | ~state_wait_align ? 1'b0 :
~|(rxdata[15:0] ^ alignp[15:0]) & ~|(rxcharisk[1:0] ^ 2'b01); // {D10.2, K28.5}
assign detected_alignp = detected_alignp_f & ~|(rxdata[15:0] ^ alignp[31:16]) & ~|(rxcharisk[1:0] ^ 2'b00); // {D27.3, D10.2} // S uppressThisWarning VEditor -warning would be fixed in future releases
reg detected_syncp_f;
always @ (posedge clk)
detected_syncp_f <= rst | ~state_wait_synp ? 1'b0 :
~|(rxdata[15:0] ^ syncp[15:0]) & ~|(rxcharisk[1:0] ^ 2'b01); // {D21.4, K28.3}
assign detected_syncp = detected_syncp_f & ~|(rxdata[15:0] ^ syncp[31:16]) & ~|(rxcharisk[1:0] ^ 2'b00); // {D21.5, D21.5} // S uppressThisWarning VEditor -warning would be fixed in future releases
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign detected_alignp = ~|(rxdata[31:0] ^ alignp[31:0]) & ~|(rxcharisk[3:0] ^ 4'h1); // {D27.3, D10.2, D10.2, K28.5} // S uppressThisWarning VEditor -warning would be fixed in future releases
assign detected_syncp = ~|(rxdata[31:0] ^ syncp[31:0]) & ~|(rxcharisk[3:0] ^ 4'h1); // {D21.5, D21.5, D21.4, K28.3} // S uppressThisWarning VEditor -warning would be fixed in future releases
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign detected_alignp = ~|(rxdata[63:0] ^ alignp[63:0]) & ~|(rxcharisk[7:0] ^ 8'h11); // {D27.3, D10.2, D10.2, K28.5} // SuppressThisWarning VEditor -warning would be fixed in future releases
assign detected_syncp = ~|(rxdata[63:0] ^ syncp[63:0]) & ~|(rxcharisk[7:0] ^ 8'h11); // {D21.5, D21.5, D21.4, K28.3} // SuppressThisWarning VEditor -warning would be fixed in future releases
end
else
begin
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
end
endgenerate
// calculate an aproximate time when oob burst shall be done
assign rxcominit_done = rxcom_timer == COMINIT_DONE_TIME & state_wait_cominit;
assign rxcomwake_done = rxcom_timer == COMWAKE_DONE_TIME & state_wait_comwake;
always @ (posedge clk) begin
cominit_req_l <= rst | rxcominit_done | ~state_idle ? 1'b0 : cominit_req ? 1'b1 : cominit_req_l;
rxcominitdet_l <= rst | rxcominit_done | ~state_wait_cominit ? 1'b0 : rxcominitdet ? 1'b1 : rxcominitdet_l;
rxcomwakedet_l <= rst | rxcomwake_done | ~state_wait_comwake ? 1'b0 : rxcomwakedet ? 1'b1 : rxcomwakedet_l;
end
// buf inputs from gtx
always @ (posedge clk)
begin
rxcominitdet <= rxcominitdet_in;
rxcomwakedet <= rxcomwakedet_in;
rxelecidle <= rxelecidle_in;
rxdata <= rxdata_in;
rxcharisk <= rxcharisk_in;
end
// set data outputs to upper levels
assign rxdata_out = rxdata;
assign rxcharisk_out = rxcharisk;
// as depicted @ doc, p264, figure 163, have to insert D10.2 and align primitives after
// getting comwake from device
reg [DATA_BYTE_WIDTH*8 - 1:0] txdata;
reg [DATA_BYTE_WIDTH - 1:0] txcharisk;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_d102;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_d102;
wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_align;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_align;
always @ (posedge clk)
begin
txdata <= state_wait_align ? txdata_d102 :
state_wait_rxrst ? txdata_d102 :
state_wait_synp ? txdata_align : txdata_in;
txcharisk <= state_wait_align ? txcharisk_d102 :
state_wait_rxrst ? txcharisk_d102 :
state_wait_synp ? txcharisk_align : txcharisk_in;
end
// Continious D10.2 primitive
assign txcharisk_d102 = {DATA_BYTE_WIDTH{1'b0}};
assign txdata_d102 = {DATA_BYTE_WIDTH{8'b01001010}}; // SuppressThisWarning VEditor -warning would be fixed in future releases
// Align primitive: K28.5 + D10.2 + D10.2 + D27.3
generate
if (DATA_BYTE_WIDTH == 2)
begin
reg align_odd;
always @ (posedge clk)
align_odd <= rst | ~state_wait_synp ? 1'b0 : ~align_odd;
assign txcharisk_align[DATA_BYTE_WIDTH - 1:0] = align_odd ? 2'b01 : 2'b00; // SuppressThisWarning VEditor -warning would be fixed in future releases
assign txdata_align[DATA_BYTE_WIDTH*8 - 1:0] = align_odd ? alignp[15:0] : // {D10.2, K28.5} // SuppressThisWarning VEditor -warning would be fixed in future releases
alignp[31:16]; // {D27.3, D10.2} // SuppressThisWarning VEditor -warning would be fixed in future releases
end
else
if (DATA_BYTE_WIDTH == 4)
begin
assign txcharisk_align[DATA_BYTE_WIDTH - 1:0] = 4'h1;
assign txdata_align[DATA_BYTE_WIDTH*8 - 1:0] = alignp[DATA_BYTE_WIDTH*8 - 1:0]; // {D27.3, D10.2, D10.2, K28.5}
end
else
if (DATA_BYTE_WIDTH == 8)
begin
assign txcharisk_align[DATA_BYTE_WIDTH - 1:0] = 8'h11; // SuppressThisWarning VEditor -warning would be fixed in future releases
assign txdata_align[DATA_BYTE_WIDTH*8 - 1:0] = alignp[DATA_BYTE_WIDTH*8 - 1:0]; // 2x{D27.3, D10.2, D10.2, K28.5}
end
else
always @ (posedge clk)
begin
$display("%m oob module works only with 16/32/64 gtx input data width");
$finish;
end
endgenerate
`ifdef SIMULATION
// info msgs
always @ (posedge clk)
begin
if (txcominit) begin
HOST_OOB_TITLE = "Issued cominit";
$display("[Host] OOB: %s @%t",HOST_OOB_TITLE,$time);
end
if (txcomwake) begin
HOST_OOB_TITLE = "Issued comwake";
$display("[Host] OOB: %s @%t",HOST_OOB_TITLE,$time);
end
if (state_wait_linkup) begin
HOST_OOB_TITLE = "Link is up";
$display("[Host] OOB: %s @%t",HOST_OOB_TITLE,$time);
end
if (set_wait_synp) begin
HOST_OOB_TITLE = "Started continious align sending";
$display("[Host] OOB: %s @%t",HOST_OOB_TITLE,$time);
end
end
`endif
always @ (posedge clk)
rxcom_timer <= rst | rxcominit_done & state_wait_cominit | rxcomwake_done & state_wait_comwake | rxcominitdet & state_wait_cominit | rxcomwakedet & state_wait_comwake ? 10'h0 : cominit_req_l & state_idle | rxcominitdet_l & state_wait_cominit | rxcomwakedet_l & state_wait_comwake ? rxcom_timer + CLK_TO_TIMER_CONTRIB[9:0] : 10'h0;
// set data outputs to gtx
assign txdata_out = txdata;
assign txcharisk_out = txcharisk;
// rxelectidle timer logic
assign eidle_timer_done = eidle_timer == 64;
always @ (posedge clk)
eidle_timer <= rst | rxelecidle | ~state_wait_eidle ? 8'b0 : eidle_timer + CLK_TO_TIMER_CONTRIB[7:0];
always @ (posedge clk) begin
if (rst || !detected_alignp) detected_alignp_cntr <= NUM_CON_ALIGNS;
else if (|detected_alignp_cntr) detected_alignp_cntr <= detected_alignp_cntr -1;
detected_alignp_r <= detected_alignp_cntr == 0;
end
always @ (posedge clk)
debug <= rst ? 12'h000 : {
state_idle,
state_wait_cominit,
state_wait_comwake,
state_recal_tx,
state_wait_eidle,
state_wait_rxrst,
state_wait_align,
state_wait_synp,
state_wait_linkup,
state_error,
oob_start,
oob_error} | debug;
endmodule
/*******************************************************************************
* Module: oob_ctrl
* Date: 2015-07-11
* Author: Alexey
* Description: module to start oob sequences and to handle errors
*
* Copyright (c) 2015 Elphel, Inc.
* oob_ctrl.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.
*
* oob_ctrl.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
//`include "oob.v"
module oob_ctrl #(
parameter DATA_BYTE_WIDTH = 4,
parameter CLK_SPEED_GRADE = 1 // 1 - 75 Mhz, 2 - 150Mhz, 4 - 300Mhz
)
(
input wire clk, // input wire // sata clk = usrclk2
input wire rst, // input wire // reset oob
input wire gtx_ready, // input wire // gtx is ready = all resets are done
output wire [11:0] debug, // output[11:0] wire
input wire rxcominitdet_in,// input wire // oob responses
input wire rxcomwakedet_in,// input wire // oob responses
input wire rxelecidle_in, // input wire // oob responses
output wire txcominit, // output wire // oob issues
output wire txcomwake, // output wire // oob issues
output wire txelecidle, // output wire // oob issues
output wire txpcsreset_req, // output wire // partial tx reset
input wire recal_tx_done, // input wire
output wire rxreset_req, // output wire // rx reset (after rxelecidle -> 0)
input wire rxreset_ack, // input wire
// Andrey: adding new signal and state - after RX is operational try re-align clock
output wire clk_phase_align_req, // Request GTX to align SIPO parallel clock and user- provided RXUSRCLK
input wire clk_phase_align_ack, // GTX aligned clock phase (DEBUG - not always clear when it works or not)
input wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_in, // output[31:0] wire // input data stream (if any data during OOB setting => ignored)
input wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in, // output[3:0] wire // input data stream (if any data during OOB setting => ignored)
output wire [DATA_BYTE_WIDTH*8 - 1:0] txdata_out, // output[31:0] wire // output data stream to gtx
output wire [DATA_BYTE_WIDTH - 1:0] txcharisk_out, // output[3:0] wire // output data stream to gtx
input wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_in, // input[31:0] wire // input data from gtx
input wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_in, // input[3:0] wire // input data from gtx
output wire [DATA_BYTE_WIDTH*8 - 1:0] rxdata_out, // output[31:0] wire // bypassed data from gtx
output wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out, // output[3:0] wire // bypassed data from gtx
input wire rxbyteisaligned,// input wire // obvious
output wire phy_ready, // output wire // shows if channel is ready
input set_offline, // input wire // electrically idle // From
input comreset_send, // input wire // Not possible yet? // From
output reg re_aligned // re-aligned after alignment loss
,output debug_detected_alignp
);
// oob sequence needs to be issued
wire oob_start;
// connection established, all further data is valid
wire oob_done;
// doc p265, link is established after 3back-to-back non-ALIGNp
wire link_up;
wire link_down;
// the device itself sends cominit
wire cominit_req;
// allow to respond to cominit
wire cominit_allow;
// status information to handle by a control block if any exists
// incompatible host-device speed grades (host cannot lock to alignp)
wire oob_incompatible; // TODO
// timeout in an unexpected place
wire oob_error;
// noone responds to our cominits
wire oob_silence;
// obvious
wire oob_busy;
// 1 - link is up and running, 0 - probably not
reg link_state;
// 1 - connection is being established OR already established, 0 - is not
reg oob_state;
// Andrey: Force offline from AHCI
reg force_offline_r; // AHCI conrol need setting offline/sending comreset
always @ (posedge clk) begin
if (rst || comreset_send) force_offline_r <= 0;
else if (set_offline) force_offline_r <= 1;
end
// Andrey: Make phy ready not go inactive during re-aligning
///assign phy_ready = link_state & gtx_ready & rxbyteisaligned;
reg phy_ready_r;
reg was_aligned_r;
always @ (posedge clk) begin
if (!(link_state & gtx_ready)) phy_ready_r <= 0;
else if (rxbyteisaligned) phy_ready_r <= 1;
was_aligned_r <= rxbyteisaligned;
re_aligned <= phy_ready_r && rxbyteisaligned && !was_aligned_r;
end
assign phy_ready = phy_ready_r;
always @ (posedge clk)
link_state <= (link_state | link_up) & ~link_down & ~rst & ~force_offline_r;
always @ (posedge clk)
oob_state <= (oob_state | oob_start | cominit_req & cominit_allow) & ~oob_error & ~oob_silence & ~(link_down & ~oob_busy & ~oob_start) & ~rst;
// decide when to issue oob: always when gtx is ready
//assign oob_start = gtx_ready & ~oob_state & ~oob_busy;
assign oob_start = gtx_ready & ~oob_state & ~oob_busy & ~force_offline_r;
// set line to idle state before if we're waiting for a device to answer AND while oob sequence
wire txelecidle_inner;
//assign txelecidle = /*~oob_state |*/ txelecidle_inner ;
assign txelecidle = /*~oob_state |*/ txelecidle_inner || force_offline_r;
// let devices always begin oob sequence, if only it's not a glitch
assign cominit_allow = cominit_req & link_state;
oob #(
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.CLK_SPEED_GRADE (CLK_SPEED_GRADE)
)
oob
(
.debug (debug), // output [11:0] reg
.clk (clk), // input wire // sata clk = usrclk2
.rst (rst), // input wire // reset oob
.rxcominitdet_in (rxcominitdet_in), // input wire // oob responses
.rxcomwakedet_in (rxcomwakedet_in), // input wire // oob responses
.rxelecidle_in (rxelecidle_in), // input wire // oob responses
.txcominit (txcominit), // output wire // oob issues
.txcomwake (txcomwake), // output wire // oob issues
.txelecidle (txelecidle_inner),// output wire // oob issues
.txpcsreset_req (txpcsreset_req), // output wire
.recal_tx_done (recal_tx_done), // input wire
.rxreset_req (rxreset_req), // output wire
.rxreset_ack (rxreset_ack), // input wire
.clk_phase_align_req (clk_phase_align_req), // output wire
.clk_phase_align_ack (clk_phase_align_ack), // input wire
.txdata_in (txdata_in), // input [31:0] wire // input data stream (if any data during OOB setting => ignored)
.txcharisk_in (txcharisk_in), // input [3:0] wire // input data stream (if any data during OOB setting => ignored)
.txdata_out (txdata_out), // output [31:0] wire // output data stream to gtx
.txcharisk_out (txcharisk_out), // output [3:0] wire// output data stream to gtx
.rxdata_in (rxdata_in), // input [31:0] wire // input data from gtx
.rxcharisk_in (rxcharisk_in), // input [3:0] wire // input data from gtx
.rxdata_out (rxdata_out), // output [31:0] wire // bypassed data from gtx
.rxcharisk_out (rxcharisk_out), // output [3:0] wire // bypassed data from gtx
.oob_start (oob_start), // input wire // oob sequence needs to be issued
.oob_done (oob_done), // output wire // connection established, all further data is valid
.oob_busy (oob_busy), // output wire // oob can't handle new start request
.link_up (link_up), // output wire // doc p265, link is established after 3back-to-back non-ALIGNp
.link_down (link_down), // output wire
.cominit_req (cominit_req), // output wire // the device itself sends cominit
.cominit_allow (cominit_allow), // input wire // allow to respond to cominit
// status information to handle by a control block if any exists
.oob_incompatible (oob_incompatible),// output wire // incompatible host-device speed grades (host cannot lock to alignp)
.oob_error (oob_error), // output wire // timeout in an unexpected place
.oob_silence (oob_silence) // output wire // noone responds to our cominits
,.debug_detected_alignp(debug_detected_alignp)
);
endmodule
/*******************************************************************************
* Module: sata_phy
* Date: 2015-07-11
* Author: Alexey
* Description: phy-level, including oob, clock generation and GTXE2
*
* Copyright (c) 2015 Elphel, Inc.
* sata_phy.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.
*
* sata_phy.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
//`include "oob_ctrl.v"
//`include "gtx_wrap.v"
module sata_phy #(
`ifdef USE_DATASCOPE
parameter ADDRESS_BITS = 10, //for datascope
parameter DATASCOPE_START_BIT = 14, // bit of DRP "other_control" to start recording after 0->1 (needs DRP)
parameter DATASCOPE_POST_MEAS = 16, // number of measurements to perform after event
`endif
parameter DATA_BYTE_WIDTH = 4,
parameter ELASTIC_DEPTH = 4, //5, With 4/7 got infrequent overflows!
parameter ELASTIC_OFFSET = 7 // 5 //10
)
(
// initial reset, resets PLL. After pll is locked, an internal sata reset is generated.
input wire extrst,
// sata clk, generated in pll as usrclk2
output wire clk, // 75MHz, bufg
output wire rst,
// reliable clock to source drp and cpll lock det circuits
input wire reliable_clk,
// state
output wire phy_ready,
// tmp output TODO
output wire gtx_ready,
output wire [11:0] debug_cnt,
// top-level ifaces
// ref clk from an external source, shall be connected to pads
input wire extclk_p,
input wire extclk_n,
// sata link data pins
output wire txp_out,
output wire txn_out,
input wire rxp_in,
input wire rxn_in,
// to link layer
output wire [DATA_BYTE_WIDTH * 8 - 1:0] ll_data_out,
output wire [DATA_BYTE_WIDTH - 1:0] ll_charisk_out,
output wire [DATA_BYTE_WIDTH - 1:0] ll_err_out, // TODO!!!
// from link layer
input wire [DATA_BYTE_WIDTH * 8 - 1:0] ll_data_in,
input wire [DATA_BYTE_WIDTH - 1:0] ll_charisk_in,
input set_offline, // electrically idle
input comreset_send, // Not possible yet?
output wire cominit_got,
output wire comwake_got,
// elastic buffer status
output wire rxelsfull,
output wire rxelsempty,
output cplllock_debug,
output usrpll_locked_debug,
output re_aligned, // re-aligned after alignment loss
output xclk, // just to measure frequency to set the local clock
`ifdef USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
output datascope_clk,
output [ADDRESS_BITS-1:0] datascope_waddr,
output datascope_we,
output [31:0] datascope_di,
input datascope_trig, // external trigger event for the datascope
`endif
`ifdef USE_DRP
input drp_rst,
input drp_clk,
input drp_en, // @aclk strobes drp_ad
input drp_we,
input [14:0] drp_addr,
input [15:0] drp_di,
output drp_rdy,
output [15:0] drp_do,
`endif
output [31:0] debug_sata
,output debug_detected_alignp
);
wire [DATA_BYTE_WIDTH * 8 - 1:0] txdata;
wire [DATA_BYTE_WIDTH * 8 - 1:0] rxdata;
wire [DATA_BYTE_WIDTH * 8 - 1:0] rxdata_out;
wire [DATA_BYTE_WIDTH * 8 - 1:0] txdata_in;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk;
wire [DATA_BYTE_WIDTH - 1:0] rxcharisk;
wire [DATA_BYTE_WIDTH - 1:0] txcharisk_in;
wire [DATA_BYTE_WIDTH - 1:0] rxcharisk_out;
wire [DATA_BYTE_WIDTH - 1:0] rxdisperr;
wire [DATA_BYTE_WIDTH - 1:0] rxnotintable;
wire [1:0] txbufstatus;
`ifdef DEBUG_ELASTIC
wire [15:0] dbg_data_cntr; // output[11:0] reg 4 MSBs - got primitives during data receive
`endif
assign ll_err_out = rxdisperr | rxnotintable;
// once gtx_ready -> 1, gtx_configured latches
// after this point it's possible to perform additional resets and reconfigurations by higher-level logic
reg gtx_configured;
// after external rst -> 0, after sata logic resets -> 1
wire sata_reset_done;
wire rxcomwakedet;
wire rxcominitdet;
wire cplllock;
wire txcominit;
wire txcomwake;
wire rxreset;
wire rxelecidle;
wire txelecidle;
wire rxbyteisaligned;
wire txpcsreset_req;
wire recal_tx_done;
wire rxreset_req;
wire rxreset_ack;
wire clk_phase_align_req;
wire clk_phase_align_ack;
wire rxreset_oob;
// elastic buffer status signals TODO
//wire rxelsfull;
//wire rxelsempty;
wire dbg_rxphaligndone;
wire dbg_rx_clocks_aligned;
wire dbg_rxcdrlock;
wire dbg_rxdlysresetdone;
//wire gtx_ready;
assign cominit_got = rxcominitdet; // For AHCI
assign comwake_got = rxcomwakedet; // For AHCI
wire dummy;
oob_ctrl oob_ctrl(
.clk (clk), // input wire // sata clk = usrclk2
.rst (rst), // input wire // reset oob
.gtx_ready (gtx_ready), // input wire // gtx is ready = all resets are done
.debug ({dummy,debug_cnt[10:0]}),
// oob responses
.rxcominitdet_in (rxcominitdet), // input wire
.rxcomwakedet_in (rxcomwakedet), // input wire
.rxelecidle_in (rxelecidle), // input wire
// oob issues
.txcominit (txcominit), // output wire
.txcomwake (txcomwake), // output wire
.txelecidle (txelecidle), // output wire
.txpcsreset_req (txpcsreset_req), // output wire
.recal_tx_done (recal_tx_done), // input wire
.rxreset_req (rxreset_req), // output wire
.rxreset_ack (rxreset_ack), // input wire
.clk_phase_align_req (clk_phase_align_req), // output wire
.clk_phase_align_ack (clk_phase_align_ack), // input wire
.txdata_in (txdata_in), // input[31:0] wire // input data stream (if any data during OOB setting => ignored)
.txcharisk_in (txcharisk_in), // input[3:0] wire // same
.txdata_out (txdata), // output[31:0] wire // output data stream to gtx
.txcharisk_out (txcharisk), // output[3:0] wire // same
.rxdata_in (rxdata[31:0]), // input[31:0] wire // input data from gtx
.rxcharisk_in (rxcharisk[3:0]), // input[3:0] wire // same
.rxdata_out (rxdata_out), // output[31:0] wire // bypassed data from gtx
.rxcharisk_out (rxcharisk_out), // output[3:0]wire // same
.rxbyteisaligned (rxbyteisaligned), // input wire // receiving data is aligned
.phy_ready (phy_ready), // output wire // shows if channel is ready
// To/from AHCI
.set_offline (set_offline), // input
.comreset_send (comreset_send), // input
.re_aligned (re_aligned) // output reg
,.debug_detected_alignp(debug_detected_alignp) // output
);
wire cplllockdetclk; // TODO
wire cpllreset;
wire gtrefclk;
wire rxresetdone;
wire txresetdone;
wire txpcsreset;
wire txreset;
wire txuserrdy;
wire rxuserrdy;
wire txusrclk;
wire txusrclk2;
//wire rxusrclk;
wire rxusrclk2;
wire txp;
wire txn;
wire rxp;
wire rxn;
wire txoutclk; // comes out global from gtx_wrap
wire txpmareset_done;
wire rxeyereset_done;
// tx reset sequence; waves @ ug476 p67
localparam TXPMARESET_TIME = 5'h1;
reg [2:0] txpmareset_cnt;
assign txpmareset_done = txpmareset_cnt == TXPMARESET_TIME;
always @ (posedge gtrefclk)
txpmareset_cnt <= txreset ? 3'h0 : txpmareset_done ? txpmareset_cnt : txpmareset_cnt + 1'b1;
// rx reset sequence; waves @ ug476 p77
localparam RXPMARESET_TIME = 5'h11;
localparam RXCDRPHRESET_TIME = 5'h1;
localparam RXCDRFREQRESET_TIME = 5'h1;
localparam RXDFELPMRESET_TIME = 7'hf;
localparam RXISCANRESET_TIME = 5'h1;
localparam RXEYERESET_TIME = 7'h0 + RXPMARESET_TIME + RXCDRPHRESET_TIME + RXCDRFREQRESET_TIME + RXDFELPMRESET_TIME + RXISCANRESET_TIME;
reg [6:0] rxeyereset_cnt;
assign rxeyereset_done = rxeyereset_cnt == RXEYERESET_TIME;
always @ (posedge gtrefclk) begin
if (rxreset) rxeyereset_cnt <= 0;
else if (!rxeyereset_done) rxeyereset_cnt <= rxeyereset_cnt + 1;
end
/*
* Resets
*/
wire usrpll_locked;
// make tx/rxreset synchronous to gtrefclk - gather singals from different domains: async, aclk, usrclk2, gtrefclk
localparam [7:0] RST_TIMER_LIMIT = 8'b1000;
reg rxreset_f;
reg txreset_f;
reg rxreset_f_r;
reg txreset_f_r;
reg rxreset_f_rr;
reg txreset_f_rr;
//reg pre_sata_reset_done;
reg sata_areset;
reg [2:0] sata_reset_done_r;
reg [7:0] rst_timer;
//reg rst_r = 1;
assign rst = !sata_reset_done_r;
assign sata_reset_done = sata_reset_done_r[1];
assign cplllock_debug = cplllock;
assign usrpll_locked_debug = usrpll_locked;
always @ (posedge clk or posedge sata_areset) begin
if (sata_areset) sata_reset_done_r <= 0;
else sata_reset_done_r <= {sata_reset_done_r[1:0], 1'b1};
end
reg cplllock_r;
always @ (posedge gtrefclk) begin
cplllock_r <= cplllock;
rxreset_f <= ~cplllock_r | ~cplllock | cpllreset | rxreset_oob & gtx_configured;
txreset_f <= ~cplllock_r | ~cplllock | cpllreset;
txreset_f_r <= txreset_f;
rxreset_f_r <= rxreset_f;
txreset_f_rr <= txreset_f_r;
rxreset_f_rr <= rxreset_f_r;
if (!(cplllock && usrpll_locked)) rst_timer <= RST_TIMER_LIMIT;
else if (|rst_timer) rst_timer <= rst_timer - 1;
sata_areset <= !(cplllock && usrpll_locked && !(|rst_timer));
end
assign rxreset = rxreset_f_rr;
assign txreset = txreset_f_rr;
assign cpllreset = extrst;
assign rxuserrdy = usrpll_locked & cplllock & ~cpllreset & ~rxreset & rxeyereset_done & sata_reset_done;
assign txuserrdy = usrpll_locked & cplllock & ~cpllreset & ~txreset & txpmareset_done & sata_reset_done;
assign gtx_ready = rxuserrdy & txuserrdy & rxresetdone & txresetdone;
// assert gtx_configured. Once gtx_ready -> 1, gtx_configured latches
always @ (posedge clk or posedge extrst)
if (extrst) gtx_configured <= 0;
else gtx_configured <= gtx_ready | gtx_configured;
// issue partial tx reset to restore functionality after oob sequence. Let it lasts 8 clock cycles
// Not enough or too early (after txelctidle?) txbufstatus shows overflow
localparam TXPCSRESET_CYCLES = 100;
reg txpcsreset_r;
reg [7:0] txpcsreset_cntr;
reg recal_tx_done_r;
assign recal_tx_done = recal_tx_done_r;
assign txpcsreset = txpcsreset_r;
always @ (posedge clk) begin
if (rst || (txpcsreset_cntr == 0)) txpcsreset_r <= 0;
else if (txpcsreset_req) txpcsreset_r <= 1;
if (rst) txpcsreset_cntr <= 0;
else if (txpcsreset_req) txpcsreset_cntr <= TXPCSRESET_CYCLES;
else if (txpcsreset_cntr != 0) txpcsreset_cntr <= txpcsreset_cntr - 1;
if (rst || txelecidle || txpcsreset_r) recal_tx_done_r <= 0;
else if (txresetdone) recal_tx_done_r <= 1;
end
// issue rx reset to restore functionality after oob sequence. Let it last 8 clock cycles
reg [3:0] rxreset_oob_cnt;
wire rxreset_oob_stop;
assign rxreset_oob_stop = rxreset_oob_cnt[3];
assign rxreset_oob = rxreset_req & ~rxreset_oob_stop;
assign rxreset_ack = rxreset_oob_stop & gtx_ready;
always @ (posedge clk or posedge extrst)
if (extrst) rxreset_oob_cnt <= 1;
else rxreset_oob_cnt <= rst | ~rxreset_req ? 4'h0 : rxreset_oob_stop ? rxreset_oob_cnt : rxreset_oob_cnt + 1'b1;
/*
* USRCLKs generation. USRCLK @ 150MHz, same as TXOUTCLK; USRCLK2 @ 75Mhz -> sata_clk === sclk
* It's recommended to use MMCM instead of PLL, whatever
*/
wire usrclk_global;
wire usrclk2;
// divide txoutclk (global) by 2, then make global. Does not need to be phase-aligned - will use FIFO
reg usrclk2_r;
always @ (posedge txoutclk) begin
if (~cplllock) usrclk2_r <= 0;
else usrclk2_r <= ~usrclk2;
end
assign txusrclk = txoutclk; // 150MHz, was already global
assign usrclk_global = txoutclk; // 150MHz, was already global
assign usrclk2 = usrclk2_r;
assign usrpll_locked = cplllock;
assign txusrclk = usrclk_global; // 150MHz
assign txusrclk2 = clk; // usrclk2;
//assign rxusrclk = usrclk_global; // 150MHz
assign rxusrclk2 = clk; // usrclk2;
select_clk_buf #(
.BUFFER_TYPE("BUFG")
) bufg_sclk (
.o (clk), // output
.i (usrclk2), // input
.clr (1'b0) // input
);
/*
* Padding for an external input clock @ 150 MHz
*/
localparam [1:0] CLKSWING_CFG = 2'b11;
IBUFDS_GTE2 #(
.CLKRCV_TRST ("TRUE"),
.CLKCM_CFG ("TRUE"),
.CLKSWING_CFG (CLKSWING_CFG)
)
ext_clock_buf(
.I (extclk_p),
.IB (extclk_n),
.CEB (1'b0),
.O (gtrefclk),
.ODIV2 ()
);
gtx_wrap #(
`ifdef USE_DATASCOPE
.ADDRESS_BITS (ADDRESS_BITS), // for datascope
.DATASCOPE_START_BIT (DATASCOPE_START_BIT),
.DATASCOPE_POST_MEAS (DATASCOPE_POST_MEAS),
`endif
.DATA_BYTE_WIDTH (DATA_BYTE_WIDTH),
.TXPMARESET_TIME (TXPMARESET_TIME),
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.ELASTIC_DEPTH (ELASTIC_DEPTH), // with 4/7 infrequent full !
.ELASTIC_OFFSET (ELASTIC_OFFSET)
)
gtx_wrap
(
.debug (debug_cnt[11]), // output reg
.cplllock (cplllock), // output wire
.cplllockdetclk (cplllockdetclk), // input wire
.cpllreset (cpllreset), // input wire
.gtrefclk (gtrefclk), // input wire
.rxuserrdy (rxuserrdy), // input wire
.txuserrdy (txuserrdy), // input wire
// .rxusrclk (rxusrclk), // input wire
.rxusrclk2 (rxusrclk2), // input wire
.rxp (rxp), // input wire
.rxn (rxn), // input wire
.rxbyteisaligned (rxbyteisaligned), // output wire
.rxreset (rxreset), // input wire
.rxcomwakedet (rxcomwakedet), // output wire
.rxcominitdet (rxcominitdet), // output wire
.rxelecidle (rxelecidle), // output wire
.rxresetdone (rxresetdone), // output wire
.txreset (txreset), // input wire
.clk_phase_align_req(clk_phase_align_req), // output wire
.clk_phase_align_ack(clk_phase_align_ack), // input wire
.txusrclk (txusrclk), // input wire
.txusrclk2 (txusrclk2), // input wire
.txelecidle (txelecidle), // input wire
.txp (txp), // output wire
.txn (txn), // output wire
.txoutclk (txoutclk), // output wire // made global inside
.txpcsreset (txpcsreset), // input wire
.txresetdone (txresetdone), // output wire
.txcominit (txcominit), // input wire
.txcomwake (txcomwake), // input wire
.txcomfinish (), // output wire
.rxelsfull (rxelsfull), // output wire
.rxelsempty (rxelsempty), // output wire
.txdata (txdata), // input [31:0] wire
.txcharisk (txcharisk), // input [3:0] wire
.rxdata (rxdata), // output[31:0] wire
.rxcharisk (rxcharisk), // output[3:0] wire
.rxdisperr (rxdisperr), // output[3:0] wire
.rxnotintable (rxnotintable), // output[3:0] wire
.dbg_rxphaligndone (dbg_rxphaligndone),
.dbg_rx_clocks_aligned (dbg_rx_clocks_aligned),
.dbg_rxcdrlock (dbg_rxcdrlock) ,
.dbg_rxdlysresetdone (dbg_rxdlysresetdone),
.txbufstatus (txbufstatus[1:0]),
.xclk (xclk) // output receive clock, just to measure frequency // global
`ifdef USE_DATASCOPE
,.datascope_clk (datascope_clk), // output
.datascope_waddr (datascope_waddr), // output[9:0]
.datascope_we (datascope_we), // output
.datascope_di (datascope_di), // output[31:0]
.datascope_trig (datascope_trig) // input // external trigger event for the datascope
`endif
`ifdef USE_DRP
,.drp_rst (drp_rst), // input
.drp_clk (drp_clk), // input
.drp_en (drp_en), // input
.drp_we (drp_we), // input
.drp_addr (drp_addr), // input[14:0]
.drp_di (drp_di), // input[15:0]
.drp_rdy (drp_rdy), // output
.drp_do (drp_do) // output[15:0]
`endif
`ifdef DEBUG_ELASTIC
,.dbg_data_cntr (dbg_data_cntr) // output[11:0] reg
`endif
);
/*
* Interfaces
*/
assign cplllockdetclk = reliable_clk; //gtrefclk;
assign rxn = rxn_in;
assign rxp = rxp_in;
assign txn_out = txn;
assign txp_out = txp;
assign ll_data_out = rxdata_out;
assign ll_charisk_out = rxcharisk_out;
assign txdata_in = ll_data_in;
assign txcharisk_in = ll_charisk_in;
reg [3:0] debug_cntr1;
reg [3:0] debug_cntr2;
reg [3:0] debug_cntr3;
reg [3:0] debug_cntr4;
reg [15:0] debug_cntr5;
reg [15:0] debug_cntr6;
reg [1:0] debug_rxbyteisaligned_r;
reg debug_error_r;
//txoutclk
always @ (posedge gtrefclk) begin
if (extrst) debug_cntr1 <= 0;
else debug_cntr1 <= debug_cntr1 + 1;
end
always @ (posedge clk) begin
if (rst) debug_cntr2 <= 0;
else debug_cntr2 <= debug_cntr2 + 1;
end
always @ (posedge reliable_clk) begin
if (extrst) debug_cntr3 <= 0;
else debug_cntr3 <= debug_cntr3 + 1;
end
always @ (posedge txoutclk) begin
if (extrst) debug_cntr4 <= 0;
else debug_cntr4 <= debug_cntr4 + 1;
end
always @ (posedge clk) begin
debug_rxbyteisaligned_r <= {debug_rxbyteisaligned_r[0],rxbyteisaligned};
debug_error_r <= |ll_err_out;
if (rst) debug_cntr5 <= 0;
else if (debug_rxbyteisaligned_r==1) debug_cntr5 <= debug_cntr5 + 1;
if (rst) debug_cntr6 <= 0;
else if (debug_error_r) debug_cntr6 <= debug_cntr6 + 1;
end
reg [15:0] dbg_clk_align_cntr;
reg dbg_clk_align_wait;
reg [11:0] error_count;
always @ (posedge clk) begin
if (rxelecidle) error_count <= 0;
else if (phy_ready && (|ll_err_out)) error_count <= error_count + 1;
if (rxelecidle || clk_phase_align_ack) dbg_clk_align_wait <= 0;
else if (clk_phase_align_req) dbg_clk_align_wait <= 1;
if (rxelecidle) dbg_clk_align_cntr <= 0;
else if (dbg_clk_align_wait) dbg_clk_align_cntr <= dbg_clk_align_cntr +1;
end
`ifdef USE_DATASCOPE
`ifdef DEBUG_ELASTIC
assign debug_sata = {dbg_data_cntr[15:0], // latched at error from previous FIS (@sof) (otherwise overwritten by h2d rfis)
error_count[3:0],
2'b0,
datascope_waddr[9:0]};
`else //DEBUG_ELASTIC
assign debug_sata = {8'b0,
error_count[11:0],
2'b0,
datascope_waddr[9:0]};
`endif //`else DEBUG_ELASTIC
//dbg_data_cntr
`else
assign debug_sata = {8'b0, dbg_clk_align_cntr, txbufstatus[1:0], rxelecidle, dbg_rxcdrlock, rxelsfull, rxelsempty, dbg_rxphaligndone, dbg_rx_clocks_aligned};
`endif
endmodule
/*******************************************************************************
* Module: scrambler
* Date: 2015-07-11
* Author: Alexey
* Description: a scrambler for the link layer
*
* Copyright (c) 2015 Elphel, Inc.
* scrambler.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.
*
* scrambler.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
/*
* Algorithm is taken from the doc, p.565. TODO make it parallel
*/
// TODO another widths support
module scrambler #(
parameter DATA_BYTE_WIDTH = 4
)
(
input wire clk,
input wire rst,
input wire val_in,
input wire [DATA_BYTE_WIDTH*8 - 1:0] data_in,
output wire [DATA_BYTE_WIDTH*8 - 1:0] data_out
);
reg [15:0] now;
reg [31:0] next;
always @ (posedge clk)
now <= rst ? 16'hf0f6 : val_in ? next[31:16] : now;
assign data_out = val_in ? data_in ^ next : data_in;
always @ (*)
/* if (rst)
next = 32'h0;
else*/
begin
next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0];
next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0];
next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2];
next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0];
next[20] = now[15] ^ now[11] ^ now[5] ^ now[4];
next[19] = now[14] ^ now[10] ^ now[4] ^ now[3];
next[18] = now[13] ^ now[9] ^ now[3] ^ now[2];
next[17] = now[12] ^ now[8] ^ now[2] ^ now[1];
next[16] = now[11] ^ now[7] ^ now[1] ^ now[0];
next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0];
next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2];
next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1];
next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0];
next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0];
next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2];
next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1];
next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
next[0] = now[15] ^ now[13] ^ now[4] ^ now[0];
end
endmodule
// This file may be used to define same pre-processor macros to be included into each parsed file
`ifndef SYSTEM_DEFINES
`define SYSTEM_DEFINES
`define USE_DRP
`define ALIGN_CLOCKS
// `define STRAIGHT_XCLK
`define USE_DATASCOPE
// `define DATASCOPE_INCOMING_RAW
`define PRELOAD_BRAMS
// `define AHCI_SATA 1
// `define DEBUG_ELASTIC
// Enviroment-dependent options
`ifdef IVERILOG
`define SIMULATION
`define OPEN_SOURCE_ONLY
`define CHECKERS_ENABLED 1
`else
`ifdef CVC
`define SIMULATION
`define OPEN_SOURCE_ONLY
`define CHECKERS_ENABLED 1
`else
`undef OPEN_SOURCE_ONLY
`endif // CVC
`endif // IVERILOG
// will not use simultaneous reset in shift registers, just and input data with ~rst
`define SHREG_SEQUENTIAL_RESET 1
// synthesis does to recognize global clock as G input of the primitive latch
`undef INFER_LATCHES
// define when using CDC - it does not support them
`undef IGNORE_ATTR
//`define MEMBRIDGE_DEBUG_READ 1
`define use200Mhz 1
`define USE_CMD_ENCOD_TILED_32_RD 1
// It can be used to check different `ifdef branches
//`define XIL_TIMING //Simprim
`define den4096Mb 1
// `define IVERILOG
// defines for memory channels
// chn 0 is read from memory and write to memory
`define def_enable_mem_chn0
`define def_read_mem_chn0
`define def_write_mem_chn0
`undef def_scanline_chn0
`undef def_tiled_chn0
// chn 1 is scanline r+w
`define def_enable_mem_chn1
`define def_read_mem_chn1
`define def_write_mem_chn1
`define def_scanline_chn1
`undef def_tiled_chn1
// chn 2 is tiled r+w
`define def_enable_mem_chn2
`define def_read_mem_chn2
`define def_write_mem_chn2
`undef def_scanline_chn2
`define def_tiled_chn2
// chn 3 is scanline r+w (reuse later)
`define def_enable_mem_chn3
`define def_read_mem_chn3
`define def_write_mem_chn3
`define def_scanline_chn3
`undef def_tiled_chn3
// chn 4 is tiled r+w (reuse later)
`define def_enable_mem_chn4
`define def_read_mem_chn4
`define def_write_mem_chn4
`undef def_scanline_chn4
`define def_tiled_chn4
// chn 5 is disabled
`undef def_enable_mem_chn5
// chn 6 is disabled
`undef def_enable_mem_chn6
// chn 7 is disabled
`undef def_enable_mem_chn7
// chn 8 is scanline w (sensor channel 0)
`define def_enable_mem_chn8
`undef def_read_mem_chn8
`define def_write_mem_chn8
`define def_scanline_chn8
`undef def_tiled_chn8
// chn 9 is scanline w (sensor channel 1)
`define def_enable_mem_chn9
`undef def_read_mem_chn9
`define def_write_mem_chn9
`define def_scanline_chn9
`undef def_tiled_chn9
// chn 10 is scanline w (sensor channel 2)
`define def_enable_mem_chn10
`undef def_read_mem_chn10
`define def_write_mem_chn10
`define def_scanline_chn10
`undef def_tiled_chn10
// chn 11 is scanline w (sensor channel 3)
`define def_enable_mem_chn11
`undef def_read_mem_chn11
`define def_write_mem_chn11
`define def_scanline_chn11
`undef def_tiled_chn11
// chn 12 is tiled read (compressor channel 0)
`define def_enable_mem_chn12
`define def_read_mem_chn12
`undef def_write_mem_chn12
`undef def_scanline_chn12
`define def_tiled_chn12
// chn 12 is tiled read (compressor channel 1)
`define def_enable_mem_chn13
`define def_read_mem_chn13
`undef def_write_mem_chn13
`undef def_scanline_chn13
`define def_tiled_chn13
// chn 12 is tiled read (compressor channel 2)
`define def_enable_mem_chn14
`define def_read_mem_chn14
`undef def_write_mem_chn14
`undef def_scanline_chn14
`define def_tiled_chn14
// chn 12 is tiled read (compressor channel 3)
`define def_enable_mem_chn15
`define def_read_mem_chn15
`undef def_write_mem_chn15
`undef def_scanline_chn15
`define def_tiled_chn15
`endif
\ No newline at end of file
/*******************************************************************************
* Module: top
* Date: 2015-07-11
* Author: Alexey
* Description: top-level module, instantiates PS7 + sata host controller
*
* Copyright (c) 2015 Elphel, Inc.
* top.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.
*
* top.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
/*
* all signals' and modules' names and interconnections are taken from x393.v
* to make the final integration easier - just to make an instance of
* what is called now 'axi_regs' and connect it
*/
// Including system defines at the top level can distinguish between simulation and synthesis?
`include "system_defines.vh"
module top #(
`include "includes/x393_parameters.vh" // SuppressThisWarning VEditor - partially used
)
(
// sata serial data iface
input wire RXN,
input wire RXP,
output wire TXN,
output wire TXP,
// sata clocking iface
input wire EXTCLK_P,
input wire EXTCLK_N
);
wire axi_aclk0;
wire sata_clk ; // Just output from SATA subsystem SuppressThisWarning VEditor Not used
wire sata_rst; // Just output from SATA subsystem SuppressThisWarning VEditor Not used
wire extrst;
wire [3:0] fclk;
wire [3:0] frst;
//wire axi_aclk;
wire axi_rst;
wire hclk;
wire comb_rst;
reg axi_rst_pre;
reg axi_rst_pre;
wire [31:0] maxi1_araddr;
wire maxi1_arvalid;
wire maxi1_arready;
wire [11:0] maxi1_arid;
wire [3:0] maxi1_arlen;
wire [1:0] maxi1_arsize;
wire [1:0] maxi1_arburst;
wire [31:0] maxi1_rdata;
wire maxi1_rvalid;
wire maxi1_rready;
wire [11:0] maxi1_rid;
wire maxi1_rlast;
wire [1:0] maxi1_rresp;
wire [31:0] maxi1_awaddr;
wire maxi1_awvalid;
wire maxi1_awready;
wire [11:0] maxi1_awid;
wire [3:0] maxi1_awlen;
wire [1:0] maxi1_awsize;
wire [1:0] maxi1_awburst;
wire [31:0] maxi1_wdata;
wire maxi1_wvalid;
wire maxi1_wready;
wire [11:0] maxi1_wid;
wire maxi1_wlast;
wire [3:0] maxi1_wstb;
wire maxi1_bvalid;
wire maxi1_bready;
wire [11:0] maxi1_bid;
wire [1:0] maxi1_bresp;
// membridge
wire [31:0] afi3_awaddr; // output[31:0]
wire afi3_awvalid; // output
wire afi3_awready; // input
wire [ 5:0] afi3_awid; // output[5:0]
wire [ 1:0] afi3_awlock; // output[1:0]
wire [ 3:0] afi3_awcache; // output[3:0]
wire [ 2:0] afi3_awprot; // output[2:0]
wire [ 3:0] afi3_awlen; // output[3:0]
wire [ 1:0] afi3_awsize; // output[2:0]
wire [ 1:0] afi3_awburst; // output[1:0]
wire [ 3:0] afi3_awqos; // output[3:0]
wire [63:0] afi3_wdata; // output[63:0]
wire afi3_wvalid; // output
wire afi3_wready; // input
wire [ 5:0] afi3_wid; // output[5:0]
wire afi3_wlast; // output
wire [ 7:0] afi3_wstrb; // output[7:0]
wire afi3_bvalid; // input
wire afi3_bready; // output
wire [ 5:0] afi3_bid; // input[5:0]
wire [ 1:0] afi3_bresp; // input[1:0]
wire [ 7:0] afi3_wcount; // input[7:0]
wire [ 5:0] afi3_wacount; // input[5:0]
wire afi3_wrissuecap1en; // output
wire [31:0] afi3_araddr; // output[31:0]
wire afi3_arvalid; // output
wire afi3_arready; // input
wire [ 5:0] afi3_arid; // output[5:0]
wire [ 1:0] afi3_arlock; // output[1:0]
wire [ 3:0] afi3_arcache; // output[3:0]
wire [ 2:0] afi3_arprot; // output[2:0]
wire [ 3:0] afi3_arlen; // output[3:0]
wire [ 1:0] afi3_arsize; // output[2:0]
wire [ 1:0] afi3_arburst; // output[1:0]
wire [ 3:0] afi3_arqos; // output[3:0]
wire [63:0] afi3_rdata; // input[63:0]
wire afi3_rvalid; // input
wire afi3_rready; // output
wire [ 5:0] afi3_rid; // input[5:0]
wire afi3_rlast; // input
wire [ 1:0] afi3_rresp; // input[2:0]
wire [ 7:0] afi3_rcount; // input[7:0]
wire [ 2:0] afi3_racount; // input[2:0]
wire afi3_rdissuecap1en; // output
wire sata_irq; // ps7 IRQ
assign comb_rst=~frst[0] | frst[1];
always @(posedge comb_rst or posedge axi_aclk0) begin
if (comb_rst) axi_rst_pre <= 1'b1;
else axi_rst_pre <= 1'b0;
end
select_clk_buf #(
.BUFFER_TYPE("BUFG")
) bufg_axi_aclk0_i (
.o (axi_aclk0), // output
.i (fclk[0]), // input
.clr (1'b0) // input
);
select_clk_buf #(
.BUFFER_TYPE("BUFG")
) bufg_axi_rst_i (
.o (axi_rst), // output
.i (axi_rst_pre), // input
.clr (1'b0) // input
);
select_clk_buf #(
.BUFFER_TYPE("BUFG")
) bufg_extrst_i (
.o (extrst), // output
.i (axi_rst_pre), // input
.clr (1'b0) // input
);
axi_hp_clk #(
.CLKIN_PERIOD(20.000),
.CLKFBOUT_MULT_AXIHP(18),
.CLKFBOUT_DIV_AXIHP(6)
) axi_hp_clk_i (
.rst (axi_rst), // input
.clk_in (axi_aclk0), // input
.clk_axihp (hclk), // output
.locked_axihp () // output // not controlled?
);
sata_ahci_top sata_top(
.sata_clk (sata_clk),
// reliable clock to source drp and cpll lock det circuits
.reliable_clk (axi_aclk0),
.hclk (hclk),
.sata_rst (sata_rst),
.arst (extrst),
.ACLK (axi_aclk0),
.ARESETN (axi_rst/* | sata_rst*/),
// AXI PS Master GP1: Read Address
.ARADDR (maxi1_araddr),
.ARVALID (maxi1_arvalid),
.ARREADY (maxi1_arready),
.ARID (maxi1_arid),
.ARLEN (maxi1_arlen),
.ARSIZE (maxi1_arsize),
.ARBURST (maxi1_arburst),
// AXI PS Master GP1: Read Data
.RDATA (maxi1_rdata),
.RVALID (maxi1_rvalid),
.RREADY (maxi1_rready),
.RID (maxi1_rid),
.RLAST (maxi1_rlast),
.RRESP (maxi1_rresp),
// AXI PS Master GP1: Write Address
.AWADDR (maxi1_awaddr),
.AWVALID (maxi1_awvalid),
.AWREADY (maxi1_awready),
.AWID (maxi1_awid),
.AWLEN (maxi1_awlen),
.AWSIZE (maxi1_awsize),
.AWBURST (maxi1_awburst),
// AXI PS Master GP1: Write Data
.WDATA (maxi1_wdata),
.WVALID (maxi1_wvalid),
.WREADY (maxi1_wready),
.WID (maxi1_wid),
.WLAST (maxi1_wlast),
.WSTRB (maxi1_wstb),
// AXI PS Master GP1: Write response
.BVALID (maxi1_bvalid),
.BREADY (maxi1_bready),
.BID (maxi1_bid),
.BRESP (maxi1_bresp),
/*
* Data interface
*/
.afi_awaddr (afi3_awaddr),
.afi_awvalid (afi3_awvalid),
.afi_awready (afi3_awready),
.afi_awid (afi3_awid),
.afi_awlock (afi3_awlock),
.afi_awcache (afi3_awcache),
.afi_awprot (afi3_awprot),
.afi_awlen (afi3_awlen),
.afi_awsize (afi3_awsize),
.afi_awburst (afi3_awburst),
.afi_awqos (afi3_awqos),
// write data
.afi_wdata (afi3_wdata),
.afi_wvalid (afi3_wvalid),
.afi_wready (afi3_wready),
.afi_wid (afi3_wid),
.afi_wlast (afi3_wlast),
.afi_wstrb (afi3_wstrb),
// write response
.afi_bvalid (afi3_bvalid),
.afi_bready (afi3_bready),
.afi_bid (afi3_bid),
.afi_bresp (afi3_bresp),
// PL extra (non-AXI) signal
.afi_wcount (afi3_wcount),
.afi_wacount (afi3_wacount),
.afi_wrissuecap1en (afi3_wrissuecap1en),
// AXI_HP signals - read channel
// read address
.afi_araddr (afi3_araddr),
.afi_arvalid (afi3_arvalid),
.afi_arready (afi3_arready),
.afi_arid (afi3_arid),
.afi_arlock (afi3_arlock),
.afi_arcache (afi3_arcache),
.afi_arprot (afi3_arprot),
.afi_arlen (afi3_arlen),
.afi_arsize (afi3_arsize),
.afi_arburst (afi3_arburst),
.afi_arqos (afi3_arqos),
// read data
.afi_rdata (afi3_rdata),
.afi_rvalid (afi3_rvalid),
.afi_rready (afi3_rready),
.afi_rid (afi3_rid),
.afi_rlast (afi3_rlast),
.afi_rresp (afi3_rresp),
// PL extra (non-AXI) signal
.afi_rcount (afi3_rcount),
.afi_racount (afi3_racount),
.afi_rdissuecap1en (afi3_rdissuecap1en),
.irq (sata_irq), // output wire
/*
* PHY
*/
.TXN (TXN),
.TXP (TXP),
.RXN (RXN),
.RXP (RXP),
.EXTCLK_P (EXTCLK_P),
.EXTCLK_N (EXTCLK_N)
);
PS7 ps7_i (
// EMIO interface
// CAN interface
.EMIOCAN0PHYTX(), // CAN 0 TX, output
.EMIOCAN0PHYRX(), // CAN 0 RX, input
.EMIOCAN1PHYTX(), // Can 1 TX, output
.EMIOCAN1PHYRX(), // CAN 1 RX, input
// GMII 0
.EMIOENET0GMIICRS(), // GMII 0 Carrier sense, input
.EMIOENET0GMIICOL(), // GMII 0 Collision detect, input
.EMIOENET0EXTINTIN(), // GMII 0 Controller Interrupt input, input
// GMII 0 TX signals
.EMIOENET0GMIITXCLK(), // GMII 0 TX clock, input
.EMIOENET0GMIITXD(), // GMII 0 Tx Data[7:0], output
.EMIOENET0GMIITXEN(), // GMII 0 Tx En, output
.EMIOENET0GMIITXER(), // GMII 0 Tx Err, output
// GMII 0 TX timestamp signals
.EMIOENET0SOFTX(), // GMII 0 Tx Tx Start-of-Frame, output
.EMIOENET0PTPDELAYREQTX(), // GMII 0 Tx PTP delay req frame detected, output
.EMIOENET0PTPPDELAYREQTX(), // GMII 0 Tx PTP peer delay frame detect, output
.EMIOENET0PTPPDELAYRESPTX(), // GMII 0 Tx PTP pear delay response frame detected, output
.EMIOENET0PTPSYNCFRAMETX(), // GMII 0 Tx PTP sync frame detected, output
// GMII 0 RX signals
.EMIOENET0GMIIRXCLK(), // GMII 0 Rx Clock, input
.EMIOENET0GMIIRXD(), // GMII 0 Rx Data (7:0), input
.EMIOENET0GMIIRXDV(), // GMII 0 Rx Data valid, input
.EMIOENET0GMIIRXER(), // GMII 0 Rx Error, input
// GMII 0 RX timestamp signals
.EMIOENET0SOFRX(), // GMII 0 Rx Start of Frame, output
.EMIOENET0PTPDELAYREQRX(), // GMII 0 Rx PTP delay req frame detected
.EMIOENET0PTPPDELAYREQRX(), // GMII 0 Rx PTP peer delay frame detected, output
.EMIOENET0PTPPDELAYRESPRX(), // GMII 0 Rx PTP peer delay response frame detected, output
.EMIOENET0PTPSYNCFRAMERX(), // GMII 0 Rx PTP sync frame detected, output
// MDIO 0
.EMIOENET0MDIOMDC(), // MDIO 0 MD clock output, output
.EMIOENET0MDIOO(), // MDIO 0 MD data output, output
.EMIOENET0MDIOTN(), // MDIO 0 MD data 3-state, output
.EMIOENET0MDIOI(), // MDIO 0 MD data input, input
// GMII 1
.EMIOENET1GMIICRS(), // GMII 1 Carrier sense, input
.EMIOENET1GMIICOL(), // GMII 1 Collision detect, input
.EMIOENET1EXTINTIN(), // GMII 1 Controller Interrupt input, input
// GMII 1 TX signals
.EMIOENET1GMIITXCLK(), // GMII 1 TX clock, input
.EMIOENET1GMIITXD(), // GMII 1 Tx Data[7:0], output
.EMIOENET1GMIITXEN(), // GMII 1 Tx En, output
.EMIOENET1GMIITXER(), // GMII 1 Tx Err, output
// GMII 1 TX timestamp signals
.EMIOENET1SOFTX(), // GMII 1 Tx Tx Start-of-Frame, output
.EMIOENET1PTPDELAYREQTX(), // GMII 1 Tx PTP delay req frame detected, output
.EMIOENET1PTPPDELAYREQTX(), // GMII 1 Tx PTP peer delay frame detect, output
.EMIOENET1PTPPDELAYRESPTX(), // GMII 1 Tx PTP pear delay response frame detected, output
.EMIOENET1PTPSYNCFRAMETX(), // GMII 1 Tx PTP sync frame detected, output
// GMII 1 RX signals
.EMIOENET1GMIIRXCLK(), // GMII 1 Rx Clock, input
.EMIOENET1GMIIRXD(), // GMII 1 Rx Data (7:0), input
.EMIOENET1GMIIRXDV(), // GMII 1 Rx Data valid, input
.EMIOENET1GMIIRXER(), // GMII 1 Rx Error, input
// GMII 1 RX timestamp signals
.EMIOENET1SOFRX(), // GMII 1 Rx Start of Frame, output
.EMIOENET1PTPDELAYREQRX(), // GMII 1 Rx PTP delay req frame detected
.EMIOENET1PTPPDELAYREQRX(), // GMII 1 Rx PTP peer delay frame detected, output
.EMIOENET1PTPPDELAYRESPRX(), // GMII 1 Rx PTP peer delay response frame detected, output
.EMIOENET1PTPSYNCFRAMERX(), // GMII 1 Rx PTP sync frame detected, output
// MDIO 1
.EMIOENET1MDIOMDC(), // MDIO 1 MD clock output, output
.EMIOENET1MDIOO(), // MDIO 1 MD data output, output
.EMIOENET1MDIOTN(), // MDIO 1 MD data 3-state, output
.EMIOENET1MDIOI(), // MDIO 1 MD data input, input
// EMIO GPIO
.EMIOGPIOO(), // EMIO GPIO Data out[63:0], output
.EMIOGPIOI(/*gpio_in[63:0]*/), // EMIO GPIO Data in[63:0], input
.EMIOGPIOTN(), // EMIO GPIO OutputEnable[63:0], output
// EMIO I2C 0
.EMIOI2C0SCLO(), // I2C 0 SCL OUT, output // manual says input
.EMIOI2C0SCLI(), // I2C 0 SCL IN, input // manual says output
.EMIOI2C0SCLTN(), // I2C 0 SCL EN, output // manual says input
.EMIOI2C0SDAO(), // I2C 0 SDA OUT, output // manual says input
.EMIOI2C0SDAI(), // I2C 0 SDA IN, input // manual says output
.EMIOI2C0SDATN(), // I2C 0 SDA EN, output // manual says input
// EMIO I2C 1
.EMIOI2C1SCLO(), // I2C 1 SCL OUT, output // manual says input
.EMIOI2C1SCLI(), // I2C 1 SCL IN, input // manual says output
.EMIOI2C1SCLTN(), // I2C 1 SCL EN, output // manual says input
.EMIOI2C1SDAO(), // I2C 1 SDA OUT, output // manual says input
.EMIOI2C1SDAI(), // I2C 1 SDA IN, input // manual says output
.EMIOI2C1SDATN(), // I2C 1 SDA EN, output // manual says input
// JTAG
.EMIOPJTAGTCK(), // JTAG TCK, input
.EMIOPJTAGTMS(), // JTAG TMS, input
.EMIOPJTAGTDI(), // JTAG TDI, input
.EMIOPJTAGTDO(), // JTAG TDO, output
.EMIOPJTAGTDTN(), // JTAG TDO OE, output
// SDIO 0
.EMIOSDIO0CLKFB(), // SDIO 0 Clock feedback, input
.EMIOSDIO0CLK(), // SDIO 0 Clock, output
.EMIOSDIO0CMDI(), // SDIO 0 Command in, input
.EMIOSDIO0CMDO(), // SDIO 0 Command out, output
.EMIOSDIO0CMDTN(), // SDIO 0 command OE, output
.EMIOSDIO0DATAI(), // SDIO 0 Data in [3:0], input
.EMIOSDIO0DATAO(), // SDIO 0 Data out [3:0], output
.EMIOSDIO0DATATN(), // SDIO 0 Data OE [3:0], output
.EMIOSDIO0CDN(), // SDIO 0 Card detect, input
.EMIOSDIO0WP(), // SDIO 0 Write protect, input
.EMIOSDIO0BUSPOW(), // SDIO 0 Power control, output
.EMIOSDIO0LED(), // SDIO 0 LED control, output
.EMIOSDIO0BUSVOLT(), // SDIO 0 Bus voltage [2:0], output
// SDIO 1
.EMIOSDIO1CLKFB(), // SDIO 1 Clock feedback, input
.EMIOSDIO1CLK(), // SDIO 1 Clock, output
.EMIOSDIO1CMDI(), // SDIO 1 Command in, input
.EMIOSDIO1CMDO(), // SDIO 1 Command out, output
.EMIOSDIO1CMDTN(), // SDIO 1 command OE, output
.EMIOSDIO1DATAI(), // SDIO 1 Data in [3:0], input
.EMIOSDIO1DATAO(), // SDIO 1 Data out [3:0], output
.EMIOSDIO1DATATN(), // SDIO 1 Data OE [3:0], output
.EMIOSDIO1CDN(), // SDIO 1 Card detect, input
.EMIOSDIO1WP(), // SDIO 1 Write protect, input
.EMIOSDIO1BUSPOW(), // SDIO 1 Power control, output
.EMIOSDIO1LED(), // SDIO 1 LED control, output
.EMIOSDIO1BUSVOLT(), // SDIO 1 Bus voltage [2:0], output
// SPI 0
.EMIOSPI0SCLKI(), // SPI 0 CLK in , input
.EMIOSPI0SCLKO(), // SPI 0 CLK out, output
.EMIOSPI0SCLKTN(), // SPI 0 CLK OE, output
.EMIOSPI0SI(), // SPI 0 MOSI in , input
.EMIOSPI0MO(), // SPI 0 MOSI out , output
.EMIOSPI0MOTN(), // SPI 0 MOSI OE, output
.EMIOSPI0MI(), // SPI 0 MISO in, input
.EMIOSPI0SO(), // SPI 0 MISO out, output
.EMIOSPI0STN(), // SPI 0 MISO OE, output
.EMIOSPI0SSIN(), // SPI 0 Slave select 0 in, input
.EMIOSPI0SSON(), // SPI 0 Slave select [2:0] out, output
.EMIOSPI0SSNTN(), // SPI 0 Slave select OE, output
// SPI 1
.EMIOSPI1SCLKI(), // SPI 1 CLK in , input
.EMIOSPI1SCLKO(), // SPI 1 CLK out, output
.EMIOSPI1SCLKTN(), // SPI 1 CLK OE, output
.EMIOSPI1SI(), // SPI 1 MOSI in , input
.EMIOSPI1MO(), // SPI 1 MOSI out , output
.EMIOSPI1MOTN(), // SPI 1 MOSI OE, output
.EMIOSPI1MI(), // SPI 1 MISO in, input
.EMIOSPI1SO(), // SPI 1 MISO out, output
.EMIOSPI1STN(), // SPI 1 MISO OE, output
.EMIOSPI1SSIN(), // SPI 1 Slave select 0 in, input
.EMIOSPI1SSON(), // SPI 1 Slave select [2:0] out, output
.EMIOSPI1SSNTN(), // SPI 1 Slave select OE, output
// TPIU signals (Trace)
.EMIOTRACECTL(), // Trace CTL, output
.EMIOTRACEDATA(), // Trace Data[31:0], output
.EMIOTRACECLK(), // Trace CLK, input
// Timers/counters
.EMIOTTC0CLKI(), // Counter/Timer 0 clock in [2:0], input
.EMIOTTC0WAVEO(), // Counter/Timer 0 wave out[2:0], output
.EMIOTTC1CLKI(), // Counter/Timer 1 clock in [2:0], input
.EMIOTTC1WAVEO(), // Counter/Timer 1 wave out[2:0], output
//UART 0
.EMIOUART0TX(), // UART 0 Transmit, output
.EMIOUART0RX(), // UART 0 Receive, input
.EMIOUART0CTSN(), // UART 0 Clear To Send, input
.EMIOUART0RTSN(), // UART 0 Ready to Send, output
.EMIOUART0DSRN(), // UART 0 Data Set Ready , input
.EMIOUART0DCDN(), // UART 0 Data Carrier Detect, input
.EMIOUART0RIN(), // UART 0 Ring Indicator, input
.EMIOUART0DTRN(), // UART 0 Data Terminal Ready, output
//UART 1
.EMIOUART1TX(), // UART 1 Transmit, output
.EMIOUART1RX(), // UART 1 Receive, input
.EMIOUART1CTSN(), // UART 1 Clear To Send, input
.EMIOUART1RTSN(), // UART 1 Ready to Send, output
.EMIOUART1DSRN(), // UART 1 Data Set Ready , input
.EMIOUART1DCDN(), // UART 1 Data Carrier Detect, input
.EMIOUART1RIN(), // UART 1 Ring Indicator, input
.EMIOUART1DTRN(), // UART 1 Data Terminal Ready, output
// USB 0
.EMIOUSB0PORTINDCTL(), // USB 0 Port Indicator [1:0], output
.EMIOUSB0VBUSPWRFAULT(), // USB 0 Power Fault, input
.EMIOUSB0VBUSPWRSELECT(), // USB 0 Power Select, output
// USB 1
.EMIOUSB1PORTINDCTL(), // USB 1 Port Indicator [1:0], output
.EMIOUSB1VBUSPWRFAULT(), // USB 1 Power Fault, input
.EMIOUSB1VBUSPWRSELECT(), // USB 1 Power Select, output
// Watchdog Timer
.EMIOWDTCLKI(), // Watchdog Timer Clock in, input
.EMIOWDTRSTO(), // Watchdog Timer Reset out, output
// DMAC 0
.DMA0ACLK(), // DMAC 0 Clock, input
.DMA0DRVALID(), // DMAC 0 DMA Request Valid, input
.DMA0DRLAST(), // DMAC 0 DMA Request Last, input
.DMA0DRTYPE(), // DMAC 0 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA0DRREADY(), // DMAC 0 DMA Request Ready, output
.DMA0DAVALID(), // DMAC 0 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA0DAREADY(), // DMAC 0 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA0DATYPE(), // DMAC 0 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA0RSTN(), // DMAC 0 RESET output (reserved, do not use), output
// DMAC 1
.DMA1ACLK(), // DMAC 1 Clock, input
.DMA1DRVALID(), // DMAC 1 DMA Request Valid, input
.DMA1DRLAST(), // DMAC 1 DMA Request Last, input
.DMA1DRTYPE(), // DMAC 1 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA1DRREADY(), // DMAC 1 DMA Request Ready, output
.DMA1DAVALID(), // DMAC 1 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA1DAREADY(), // DMAC 1 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA1DATYPE(), // DMAC 1 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA1RSTN(), // DMAC 1 RESET output (reserved, do not use), output
// DMAC 2
.DMA2ACLK(), // DMAC 2 Clock, input
.DMA2DRVALID(), // DMAC 2 DMA Request Valid, input
.DMA2DRLAST(), // DMAC 2 DMA Request Last, input
.DMA2DRTYPE(), // DMAC 2 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA2DRREADY(), // DMAC 2 DMA Request Ready, output
.DMA2DAVALID(), // DMAC 2 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA2DAREADY(), // DMAC 2 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA2DATYPE(), // DMAC 2 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA2RSTN(), // DMAC 2 RESET output (reserved, do not use), output
// DMAC 3
.DMA3ACLK(), // DMAC 3 Clock, input
.DMA3DRVALID(), // DMAC 3 DMA Request Valid, input
.DMA3DRLAST(), // DMAC 3 DMA Request Last, input
.DMA3DRTYPE(), // DMAC 3 DMA Request Type [1:0] ()single/burst/ackn flush/reserved), input
.DMA3DRREADY(), // DMAC 3 DMA Request Ready, output
.DMA3DAVALID(), // DMAC 3 DMA Acknowledge Valid (DA_TYPE[1:0] valid), output
.DMA3DAREADY(), // DMAC 3 DMA Acknowledge (peripheral can accept DA_TYPE[1:0]), input
.DMA3DATYPE(), // DMAC 3 DMA Ackbowledge TYpe (completed single AXI, completed burst AXI, flush request), output
.DMA3RSTN(), // DMAC 3 RESET output (reserved, do not use), output
// Interrupt signals
.IRQF2P({19'b0,sata_irq}), // Interrupts, PL to PS [19:0], input
.IRQP2F(), // Interrupts, PS to PL [28:0], output
// Event Signals
.EVENTEVENTI(), // EVENT Wake up one or both CPU from WFE state, input
.EVENTEVENTO(), // EVENT Asserted when one of the COUs executed SEV instruction, output
.EVENTSTANDBYWFE(), // EVENT CPU standby mode [1:0], asserted when CPU is waiting for an event, output
.EVENTSTANDBYWFI(), // EVENT CPU standby mode [1:0], asserted when CPU is waiting for an interrupt, output
// PL Resets and clocks
.FCLKCLK(fclk[3:0]), // PL Clocks [3:0], output
.FCLKCLKTRIGN(), // PL Clock Throttle Control [3:0], input
.FCLKRESETN(frst[3:0]), // PL General purpose user reset [3:0], output (active low)
// Debug signals
.FTMTP2FDEBUG(), // Debug General purpose debug output [31:0], output
.FTMTF2PDEBUG(), // Debug General purpose debug input [31:0], input
.FTMTP2FTRIG(), // Debug Trigger PS to PL [3:0], output
.FTMTP2FTRIGACK(), // Debug Trigger PS to PL acknowledge[3:0], input
.FTMTF2PTRIG(), // Debug Trigger PL to PS [3:0], input
.FTMTF2PTRIGACK(), // Debug Trigger PL to PS acknowledge[3:0], output
.FTMDTRACEINCLOCK(), // Debug Trace PL to PS Clock, input
.FTMDTRACEINVALID(), // Debug Trace PL to PS Clock, data&id valid, input
.FTMDTRACEINDATA(), // Debug Trace PL to PS data [31:0], input
.FTMDTRACEINATID(), // Debug Trace PL to PS ID [3:0], input
// DDR Urgent
.DDRARB(), // DDR Urgent[3:0], input
// SRAM interrupt (on rising edge)
.EMIOSRAMINTIN(), // SRAM interrupt #50 shared with NAND busy, input
// AXI interfaces
.FPGAIDLEN(1'b1), //Idle PL AXI interfaces (active low), input
// AXI PS Master GP0
// AXI PS Master GP0: Clock, Reset
.MAXIGP0ACLK(/*axi_aclk*/), // AXI PS Master GP0 Clock , input
// .MAXIGP0ACLK(/*fclk[0]*/), // AXI PS Master GP0 Clock , input
// .MAXIGP0ACLK(/*~fclk[0]*/), // AXI PS Master GP0 Clock , input
// .MAXIGP0ACLK(/*axi_naclk*/), // AXI PS Master GP0 Clock , input
//
.MAXIGP0ARESETN(), // AXI PS Master GP0 Reset, output
// AXI PS Master GP0: Read Address
.MAXIGP0ARADDR (/*axi_araddr[31:0]*/), // AXI PS Master GP0 ARADDR[31:0], output
.MAXIGP0ARVALID (/*axi_arvalid*/), // AXI PS Master GP0 ARVALID, output
.MAXIGP0ARREADY (/*axi_arready*/), // AXI PS Master GP0 ARREADY, input
.MAXIGP0ARID (/*axi_arid[11:0]*/), // AXI PS Master GP0 ARID[11:0], output
.MAXIGP0ARLOCK (), // AXI PS Master GP0 ARLOCK[1:0], output
.MAXIGP0ARCACHE (),// AXI PS Master GP0 ARCACHE[3:0], output
.MAXIGP0ARPROT(), // AXI PS Master GP0 ARPROT[2:0], output
.MAXIGP0ARLEN (/*axi_arlen[3:0]*/), // AXI PS Master GP0 ARLEN[3:0], output
.MAXIGP0ARSIZE (/*axi_arsize[1:0]*/), // AXI PS Master GP0 ARSIZE[1:0], output
.MAXIGP0ARBURST (/*axi_arburst[1:0]*/),// AXI PS Master GP0 ARBURST[1:0], output
.MAXIGP0ARQOS (), // AXI PS Master GP0 ARQOS[3:0], output
// AXI PS Master GP0: Read Data
.MAXIGP0RDATA (/*axi_rdata[31:0]*/), // AXI PS Master GP0 RDATA[31:0], input
.MAXIGP0RVALID (/*axi_rvalid*/), // AXI PS Master GP0 RVALID, input
.MAXIGP0RREADY (/*axi_rready*/), // AXI PS Master GP0 RREADY, output
.MAXIGP0RID (/*axi_rid[11:0]*/), // AXI PS Master GP0 RID[11:0], input
.MAXIGP0RLAST (/*axi_rlast*/), // AXI PS Master GP0 RLAST, input
.MAXIGP0RRESP (/*axi_rresp[1:0]*/), // AXI PS Master GP0 RRESP[1:0], input
// AXI PS Master GP0: Write Address
.MAXIGP0AWADDR (/*axi_awaddr[31:0]*/), // AXI PS Master GP0 AWADDR[31:0], output
.MAXIGP0AWVALID (/*axi_awvalid*/), // AXI PS Master GP0 AWVALID, output
.MAXIGP0AWREADY (/*axi_awready*/), // AXI PS Master GP0 AWREADY, input
.MAXIGP0AWID (/*axi_awid[11:0]*/), // AXI PS Master GP0 AWID[11:0], output
.MAXIGP0AWLOCK (), // AXI PS Master GP0 AWLOCK[1:0], output
.MAXIGP0AWCACHE (),// AXI PS Master GP0 AWCACHE[3:0], output
.MAXIGP0AWPROT (), // AXI PS Master GP0 AWPROT[2:0], output
.MAXIGP0AWLEN (/*axi_awlen[3:0]*/), // AXI PS Master GP0 AWLEN[3:0], output
.MAXIGP0AWSIZE (/*axi_awsize[1:0]*/), // AXI PS Master GP0 AWSIZE[1:0], output
.MAXIGP0AWBURST (/*axi_awburst[1:0]*/),// AXI PS Master GP0 AWBURST[1:0], output
.MAXIGP0AWQOS (), // AXI PS Master GP0 AWQOS[3:0], output
// AXI PS Master GP0: Write Data
.MAXIGP0WDATA (/*axi_wdata[31:0]*/), // AXI PS Master GP0 WDATA[31:0], output
.MAXIGP0WVALID (/*axi_wvalid*/), // AXI PS Master GP0 WVALID, output
.MAXIGP0WREADY (/*axi_wready*/), // AXI PS Master GP0 WREADY, input
.MAXIGP0WID (/*axi_wid[11:0]*/), // AXI PS Master GP0 WID[11:0], output
.MAXIGP0WLAST (/*axi_wlast*/), // AXI PS Master GP0 WLAST, output
.MAXIGP0WSTRB (/*axi_wstb[3:0]*/), // AXI PS Master GP0 WSTRB[3:0], output
// AXI PS Master GP0: Write response
.MAXIGP0BVALID (/*axi_bvalid*/), // AXI PS Master GP0 BVALID, input
.MAXIGP0BREADY (/*axi_bready*/), // AXI PS Master GP0 BREADY, output
.MAXIGP0BID (/*axi_bid[11:0]*/), // AXI PS Master GP0 BID[11:0], input
.MAXIGP0BRESP (/*axi_bresp[1:0]*/), // AXI PS Master GP0 BRESP[1:0], input
// AXI PS Master GP1
// AXI PS Master GP1: Clock, Reset
.MAXIGP1ACLK (axi_aclk0), // AXI PS Master GP1 Clock , input
.MAXIGP1ARESETN (), // AXI PS Master GP1 Reset, output
// AXI PS Master GP1: Read Address
.MAXIGP1ARADDR (maxi1_araddr), // AXI PS Master GP1 ARADDR[31:0], output
.MAXIGP1ARVALID (maxi1_arvalid), // AXI PS Master GP1 ARVALID, output
.MAXIGP1ARREADY (maxi1_arready), // AXI PS Master GP1 ARREADY, input
.MAXIGP1ARID (maxi1_arid), // AXI PS Master GP1 ARID[11:0], output
.MAXIGP1ARLOCK (), // AXI PS Master GP1 ARLOCK[1:0], output
.MAXIGP1ARCACHE (), // AXI PS Master GP1 ARCACHE[3:0], output
.MAXIGP1ARPROT (), // AXI PS Master GP1 ARPROT[2:0], output
.MAXIGP1ARLEN (maxi1_arlen), // AXI PS Master GP1 ARLEN[3:0], output
.MAXIGP1ARSIZE (maxi1_arsize), // AXI PS Master GP1 ARSIZE[1:0], output
.MAXIGP1ARBURST (maxi1_arburst), // AXI PS Master GP1 ARBURST[1:0], output
.MAXIGP1ARQOS (), // AXI PS Master GP1 ARQOS[3:0], output
// AXI PS Master GP1: Read Data
.MAXIGP1RDATA (maxi1_rdata), // AXI PS Master GP1 RDATA[31:0], input
.MAXIGP1RVALID (maxi1_rvalid), // AXI PS Master GP1 RVALID, input
.MAXIGP1RREADY (maxi1_rready), // AXI PS Master GP1 RREADY, output
.MAXIGP1RID (maxi1_rid), // AXI PS Master GP1 RID[11:0], input
.MAXIGP1RLAST (maxi1_rlast), // AXI PS Master GP1 RLAST, input
.MAXIGP1RRESP (maxi1_rresp), // AXI PS Master GP1 RRESP[1:0], input
// AXI PS Master GP1: Write Address
.MAXIGP1AWADDR (maxi1_awaddr), // AXI PS Master GP1 AWADDR[31:0], output
.MAXIGP1AWVALID (maxi1_awvalid), // AXI PS Master GP1 AWVALID, output
.MAXIGP1AWREADY (maxi1_awready), // AXI PS Master GP1 AWREADY, input
.MAXIGP1AWID (maxi1_awid), // AXI PS Master GP1 AWID[11:0], output
.MAXIGP1AWLOCK (), // AXI PS Master GP1 AWLOCK[1:0], output
.MAXIGP1AWCACHE (), // AXI PS Master GP1 AWCACHE[3:0], output
.MAXIGP1AWPROT (), // AXI PS Master GP1 AWPROT[2:0], output
.MAXIGP1AWLEN (maxi1_awlen), // AXI PS Master GP1 AWLEN[3:0], output
.MAXIGP1AWSIZE (maxi1_awsize), // AXI PS Master GP1 AWSIZE[1:0], output
.MAXIGP1AWBURST (maxi1_awburst), // AXI PS Master GP1 AWBURST[1:0], output
.MAXIGP1AWQOS (), // AXI PS Master GP1 AWQOS[3:0], output
// AXI PS Master GP1: Write Data
.MAXIGP1WDATA (maxi1_wdata), // AXI PS Master GP1 WDATA[31:0], output
.MAXIGP1WVALID (maxi1_wvalid), // AXI PS Master GP1 WVALID, output
.MAXIGP1WREADY (maxi1_wready), // AXI PS Master GP1 WREADY, input
.MAXIGP1WID (maxi1_wid), // AXI PS Master GP1 WID[11:0], output
.MAXIGP1WLAST (maxi1_wlast), // AXI PS Master GP1 WLAST, output
.MAXIGP1WSTRB (maxi1_wstb), // AXI PS Master GP1 maxi1_wstb[3:0], output
// AXI PS Master GP1: Write response
.MAXIGP1BVALID (maxi1_bvalid), // AXI PS Master GP1 BVALID, input
.MAXIGP1BREADY (maxi1_bready), // AXI PS Master GP1 BREADY, output
.MAXIGP1BID (maxi1_bid), // AXI PS Master GP1 BID[11:0], input
.MAXIGP1BRESP (maxi1_bresp), // AXI PS Master GP1 BRESP[1:0], input
// AXI PS Slave GP0
// AXI PS Slave GP0: Clock, Reset
.SAXIGP0ACLK(), // AXI PS Slave GP0 Clock , input
.SAXIGP0ARESETN(), // AXI PS Slave GP0 Reset, output
// AXI PS Slave GP0: Read Address
.SAXIGP0ARADDR(), // AXI PS Slave GP0 ARADDR[31:0], input
.SAXIGP0ARVALID(), // AXI PS Slave GP0 ARVALID, input
.SAXIGP0ARREADY(), // AXI PS Slave GP0 ARREADY, output
.SAXIGP0ARID(), // AXI PS Slave GP0 ARID[5:0], input
.SAXIGP0ARLOCK(), // AXI PS Slave GP0 ARLOCK[1:0], input
.SAXIGP0ARCACHE(), // AXI PS Slave GP0 ARCACHE[3:0], input
.SAXIGP0ARPROT(), // AXI PS Slave GP0 ARPROT[2:0], input
.SAXIGP0ARLEN(), // AXI PS Slave GP0 ARLEN[3:0], input
.SAXIGP0ARSIZE(), // AXI PS Slave GP0 ARSIZE[1:0], input
.SAXIGP0ARBURST(), // AXI PS Slave GP0 ARBURST[1:0], input
.SAXIGP0ARQOS(), // AXI PS Slave GP0 ARQOS[3:0], input
// AXI PS Slave GP0: Read Data
.SAXIGP0RDATA(), // AXI PS Slave GP0 RDATA[31:0], output
.SAXIGP0RVALID(), // AXI PS Slave GP0 RVALID, output
.SAXIGP0RREADY(), // AXI PS Slave GP0 RREADY, input
.SAXIGP0RID(), // AXI PS Slave GP0 RID[5:0], output
.SAXIGP0RLAST(), // AXI PS Slave GP0 RLAST, output
.SAXIGP0RRESP(), // AXI PS Slave GP0 RRESP[1:0], output
// AXI PS Slave GP0: Write Address
.SAXIGP0AWADDR(), // AXI PS Slave GP0 AWADDR[31:0], input
.SAXIGP0AWVALID(), // AXI PS Slave GP0 AWVALID, input
.SAXIGP0AWREADY(), // AXI PS Slave GP0 AWREADY, output
.SAXIGP0AWID(), // AXI PS Slave GP0 AWID[5:0], input
.SAXIGP0AWLOCK(), // AXI PS Slave GP0 AWLOCK[1:0], input
.SAXIGP0AWCACHE(), // AXI PS Slave GP0 AWCACHE[3:0], input
.SAXIGP0AWPROT(), // AXI PS Slave GP0 AWPROT[2:0], input
.SAXIGP0AWLEN(), // AXI PS Slave GP0 AWLEN[3:0], input
.SAXIGP0AWSIZE(), // AXI PS Slave GP0 AWSIZE[1:0], input
.SAXIGP0AWBURST(), // AXI PS Slave GP0 AWBURST[1:0], input
.SAXIGP0AWQOS(), // AXI PS Slave GP0 AWQOS[3:0], input
// AXI PS Slave GP0: Write Data
.SAXIGP0WDATA(), // AXI PS Slave GP0 WDATA[31:0], input
.SAXIGP0WVALID(), // AXI PS Slave GP0 WVALID, input
.SAXIGP0WREADY(), // AXI PS Slave GP0 WREADY, output
.SAXIGP0WID(), // AXI PS Slave GP0 WID[5:0], input
.SAXIGP0WLAST(), // AXI PS Slave GP0 WLAST, input
.SAXIGP0WSTRB(), // AXI PS Slave GP0 WSTRB[3:0], input
// AXI PS Slave GP0: Write response
.SAXIGP0BVALID(), // AXI PS Slave GP0 BVALID, output
.SAXIGP0BREADY(), // AXI PS Slave GP0 BREADY, input
.SAXIGP0BID(), // AXI PS Slave GP0 BID[5:0], output //TODO: Update range !!!
.SAXIGP0BRESP(), // AXI PS Slave GP0 BRESP[1:0], output
// AXI PS Slave GP1
// AXI PS Slave GP1: Clock, Reset
.SAXIGP1ACLK(), // AXI PS Slave GP1 Clock , input
.SAXIGP1ARESETN(), // AXI PS Slave GP1 Reset, output
// AXI PS Slave GP1: Read Address
.SAXIGP1ARADDR(), // AXI PS Slave GP1 ARADDR[31:0], input
.SAXIGP1ARVALID(), // AXI PS Slave GP1 ARVALID, input
.SAXIGP1ARREADY(), // AXI PS Slave GP1 ARREADY, output
.SAXIGP1ARID(), // AXI PS Slave GP1 ARID[5:0], input
.SAXIGP1ARLOCK(), // AXI PS Slave GP1 ARLOCK[1:0], input
.SAXIGP1ARCACHE(), // AXI PS Slave GP1 ARCACHE[3:0], input
.SAXIGP1ARPROT(), // AXI PS Slave GP1 ARPROT[2:0], input
.SAXIGP1ARLEN(), // AXI PS Slave GP1 ARLEN[3:0], input
.SAXIGP1ARSIZE(), // AXI PS Slave GP1 ARSIZE[1:0], input
.SAXIGP1ARBURST(), // AXI PS Slave GP1 ARBURST[1:0], input
.SAXIGP1ARQOS(), // AXI PS Slave GP1 ARQOS[3:0], input
// AXI PS Slave GP1: Read Data
.SAXIGP1RDATA(), // AXI PS Slave GP1 RDATA[31:0], output
.SAXIGP1RVALID(), // AXI PS Slave GP1 RVALID, output
.SAXIGP1RREADY(), // AXI PS Slave GP1 RREADY, input
.SAXIGP1RID(), // AXI PS Slave GP1 RID[5:0], output
.SAXIGP1RLAST(), // AXI PS Slave GP1 RLAST, output
.SAXIGP1RRESP(), // AXI PS Slave GP1 RRESP[1:0], output
// AXI PS Slave GP1: Write Address
.SAXIGP1AWADDR(), // AXI PS Slave GP1 AWADDR[31:0], input
.SAXIGP1AWVALID(), // AXI PS Slave GP1 AWVALID, input
.SAXIGP1AWREADY(), // AXI PS Slave GP1 AWREADY, output
.SAXIGP1AWID(), // AXI PS Slave GP1 AWID[5:0], input
.SAXIGP1AWLOCK(), // AXI PS Slave GP1 AWLOCK[1:0], input
.SAXIGP1AWCACHE(), // AXI PS Slave GP1 AWCACHE[3:0], input
.SAXIGP1AWPROT(), // AXI PS Slave GP1 AWPROT[2:0], input
.SAXIGP1AWLEN(), // AXI PS Slave GP1 AWLEN[3:0], input
.SAXIGP1AWSIZE(), // AXI PS Slave GP1 AWSIZE[1:0], input
.SAXIGP1AWBURST(), // AXI PS Slave GP1 AWBURST[1:0], input
.SAXIGP1AWQOS(), // AXI PS Slave GP1 AWQOS[3:0], input
// AXI PS Slave GP1: Write Data
.SAXIGP1WDATA(), // AXI PS Slave GP1 WDATA[31:0], input
.SAXIGP1WVALID(), // AXI PS Slave GP1 WVALID, input
.SAXIGP1WREADY(), // AXI PS Slave GP1 WREADY, output
.SAXIGP1WID(), // AXI PS Slave GP1 WID[5:0], input
.SAXIGP1WLAST(), // AXI PS Slave GP1 WLAST, input
.SAXIGP1WSTRB(), // AXI PS Slave GP1 WSTRB[3:0], input
// AXI PS Slave GP1: Write response
.SAXIGP1BVALID(), // AXI PS Slave GP1 BVALID, output
.SAXIGP1BREADY(), // AXI PS Slave GP1 BREADY, input
.SAXIGP1BID(), // AXI PS Slave GP1 BID[5:0], output
.SAXIGP1BRESP(), // AXI PS Slave GP1 BRESP[1:0], output
// AXI PS Slave HP0
// AXI PS Slave HP0: Clock, Reset
.SAXIHP0ACLK(), // AXI PS Slave HP0 Clock , input
.SAXIHP0ARESETN(), // AXI PS Slave HP0 Reset, output
// AXI PS Slave HP0: Read Address
.SAXIHP0ARADDR(), // AXI PS Slave HP0 ARADDR[31:0], input
.SAXIHP0ARVALID(), // AXI PS Slave HP0 ARVALID, input
.SAXIHP0ARREADY(), // AXI PS Slave HP0 ARREADY, output
.SAXIHP0ARID(), // AXI PS Slave HP0 ARID[5:0], input
.SAXIHP0ARLOCK(), // AXI PS Slave HP0 ARLOCK[1:0], input
.SAXIHP0ARCACHE(), // AXI PS Slave HP0 ARCACHE[3:0], input
.SAXIHP0ARPROT(), // AXI PS Slave HP0 ARPROT[2:0], input
.SAXIHP0ARLEN(), // AXI PS Slave HP0 ARLEN[3:0], input
.SAXIHP0ARSIZE(), // AXI PS Slave HP0 ARSIZE[2:0], input
.SAXIHP0ARBURST(), // AXI PS Slave HP0 ARBURST[1:0], input
.SAXIHP0ARQOS(), // AXI PS Slave HP0 ARQOS[3:0], input
// AXI PS Slave HP0: Read Data
.SAXIHP0RDATA(), // AXI PS Slave HP0 RDATA[63:0], output
.SAXIHP0RVALID(), // AXI PS Slave HP0 RVALID, output
.SAXIHP0RREADY(), // AXI PS Slave HP0 RREADY, input
.SAXIHP0RID(), // AXI PS Slave HP0 RID[5:0], output
.SAXIHP0RLAST(), // AXI PS Slave HP0 RLAST, output
.SAXIHP0RRESP(), // AXI PS Slave HP0 RRESP[1:0], output
.SAXIHP0RCOUNT(), // AXI PS Slave HP0 RCOUNT[7:0], output
.SAXIHP0RACOUNT(), // AXI PS Slave HP0 RACOUNT[2:0], output
.SAXIHP0RDISSUECAP1EN(), // AXI PS Slave HP0 RDISSUECAP1EN, input
// AXI PS Slave HP0: Write Address
.SAXIHP0AWADDR(), // AXI PS Slave HP0 AWADDR[31:0], input
.SAXIHP0AWVALID(), // AXI PS Slave HP0 AWVALID, input
.SAXIHP0AWREADY(), // AXI PS Slave HP0 AWREADY, output
.SAXIHP0AWID(), // AXI PS Slave HP0 AWID[5:0], input
.SAXIHP0AWLOCK(), // AXI PS Slave HP0 AWLOCK[1:0], input
.SAXIHP0AWCACHE(), // AXI PS Slave HP0 AWCACHE[3:0], input
.SAXIHP0AWPROT(), // AXI PS Slave HP0 AWPROT[2:0], input
.SAXIHP0AWLEN(), // AXI PS Slave HP0 AWLEN[3:0], input
.SAXIHP0AWSIZE(), // AXI PS Slave HP0 AWSIZE[1:0], input
.SAXIHP0AWBURST(), // AXI PS Slave HP0 AWBURST[1:0], input
.SAXIHP0AWQOS(), // AXI PS Slave HP0 AWQOS[3:0], input
// AXI PS Slave HP0: Write Data
.SAXIHP0WDATA(), // AXI PS Slave HP0 WDATA[63:0], input
.SAXIHP0WVALID(), // AXI PS Slave HP0 WVALID, input
.SAXIHP0WREADY(), // AXI PS Slave HP0 WREADY, output
.SAXIHP0WID(), // AXI PS Slave HP0 WID[5:0], input
.SAXIHP0WLAST(), // AXI PS Slave HP0 WLAST, input
.SAXIHP0WSTRB(), // AXI PS Slave HP0 WSTRB[7:0], input
.SAXIHP0WCOUNT(), // AXI PS Slave HP0 WCOUNT[7:0], output
.SAXIHP0WACOUNT(), // AXI PS Slave HP0 WACOUNT[5:0], output
.SAXIHP0WRISSUECAP1EN(), // AXI PS Slave HP0 WRISSUECAP1EN, input
// AXI PS Slave HP0: Write response
.SAXIHP0BVALID(), // AXI PS Slave HP0 BVALID, output
.SAXIHP0BREADY(), // AXI PS Slave HP0 BREADY, input
.SAXIHP0BID(), // AXI PS Slave HP0 BID[5:0], output
.SAXIHP0BRESP(), // AXI PS Slave HP0 BRESP[1:0], output
// AXI PS Slave HP1
// AXI PS Slave 1: Clock, Reset
.SAXIHP1ACLK(), // AXI PS Slave HP1 Clock , input
.SAXIHP1ARESETN(), // AXI PS Slave HP1 Reset, output
// AXI PS Slave HP1: Read Address
.SAXIHP1ARADDR(), // AXI PS Slave HP1 ARADDR[31:0], input
.SAXIHP1ARVALID(), // AXI PS Slave HP1 ARVALID, input
.SAXIHP1ARREADY(), // AXI PS Slave HP1 ARREADY, output
.SAXIHP1ARID(), // AXI PS Slave HP1 ARID[5:0], input
.SAXIHP1ARLOCK(), // AXI PS Slave HP1 ARLOCK[1:0], input
.SAXIHP1ARCACHE(), // AXI PS Slave HP1 ARCACHE[3:0], input
.SAXIHP1ARPROT(), // AXI PS Slave HP1 ARPROT[2:0], input
.SAXIHP1ARLEN(), // AXI PS Slave HP1 ARLEN[3:0], input
.SAXIHP1ARSIZE(), // AXI PS Slave HP1 ARSIZE[2:0], input
.SAXIHP1ARBURST(), // AXI PS Slave HP1 ARBURST[1:0], input
.SAXIHP1ARQOS(), // AXI PS Slave HP1 ARQOS[3:0], input
// AXI PS Slave HP1: Read Data
.SAXIHP1RDATA(), // AXI PS Slave HP1 RDATA[63:0], output
.SAXIHP1RVALID(), // AXI PS Slave HP1 RVALID, output
.SAXIHP1RREADY(), // AXI PS Slave HP1 RREADY, input
.SAXIHP1RID(), // AXI PS Slave HP1 RID[5:0], output
.SAXIHP1RLAST(), // AXI PS Slave HP1 RLAST, output
.SAXIHP1RRESP(), // AXI PS Slave HP1 RRESP[1:0], output
.SAXIHP1RCOUNT(), // AXI PS Slave HP1 RCOUNT[7:0], output
.SAXIHP1RACOUNT(), // AXI PS Slave HP1 RACOUNT[2:0], output
.SAXIHP1RDISSUECAP1EN(), // AXI PS Slave HP1 RDISSUECAP1EN, input
// AXI PS Slave HP1: Write Address
.SAXIHP1AWADDR(), // AXI PS Slave HP1 AWADDR[31:0], input
.SAXIHP1AWVALID(), // AXI PS Slave HP1 AWVALID, input
.SAXIHP1AWREADY(), // AXI PS Slave HP1 AWREADY, output
.SAXIHP1AWID(), // AXI PS Slave HP1 AWID[5:0], input
.SAXIHP1AWLOCK(), // AXI PS Slave HP1 AWLOCK[1:0], input
.SAXIHP1AWCACHE(), // AXI PS Slave HP1 AWCACHE[3:0], input
.SAXIHP1AWPROT(), // AXI PS Slave HP1 AWPROT[2:0], input
.SAXIHP1AWLEN(), // AXI PS Slave HP1 AWLEN[3:0], input
.SAXIHP1AWSIZE(), // AXI PS Slave HP1 AWSIZE[1:0], input
.SAXIHP1AWBURST(), // AXI PS Slave HP1 AWBURST[1:0], input
.SAXIHP1AWQOS(), // AXI PS Slave HP1 AWQOS[3:0], input
// AXI PS Slave HP1: Write Data
.SAXIHP1WDATA(), // AXI PS Slave HP1 WDATA[63:0], input
.SAXIHP1WVALID(), // AXI PS Slave HP1 WVALID, input
.SAXIHP1WREADY(), // AXI PS Slave HP1 WREADY, output
.SAXIHP1WID(), // AXI PS Slave HP1 WID[5:0], input
.SAXIHP1WLAST(), // AXI PS Slave HP1 WLAST, input
.SAXIHP1WSTRB(), // AXI PS Slave HP1 WSTRB[7:0], input
.SAXIHP1WCOUNT(), // AXI PS Slave HP1 WCOUNT[7:0], output
.SAXIHP1WACOUNT(), // AXI PS Slave HP1 WACOUNT[5:0], output
.SAXIHP1WRISSUECAP1EN(), // AXI PS Slave HP1 WRISSUECAP1EN, input
// AXI PS Slave HP1: Write response
.SAXIHP1BVALID(), // AXI PS Slave HP1 BVALID, output
.SAXIHP1BREADY(), // AXI PS Slave HP1 BREADY, input
.SAXIHP1BID(), // AXI PS Slave HP1 BID[5:0], output
.SAXIHP1BRESP(), // AXI PS Slave HP1 BRESP[1:0], output
// AXI PS Slave HP2
// AXI PS Slave HP2: Clock, Reset
.SAXIHP2ACLK(), // AXI PS Slave HP2 Clock , input
.SAXIHP2ARESETN(), // AXI PS Slave HP2 Reset, output
// AXI PS Slave HP2: Read Address
.SAXIHP2ARADDR(), // AXI PS Slave HP2 ARADDR[31:0], input
.SAXIHP2ARVALID(), // AXI PS Slave HP2 ARVALID, input
.SAXIHP2ARREADY(), // AXI PS Slave HP2 ARREADY, output
.SAXIHP2ARID(), // AXI PS Slave HP2 ARID[5:0], input
.SAXIHP2ARLOCK(), // AXI PS Slave HP2 ARLOCK[1:0], input
.SAXIHP2ARCACHE(), // AXI PS Slave HP2 ARCACHE[3:0], input
.SAXIHP2ARPROT(), // AXI PS Slave HP2 ARPROT[2:0], input
.SAXIHP2ARLEN(), // AXI PS Slave HP2 ARLEN[3:0], input
.SAXIHP2ARSIZE(), // AXI PS Slave HP2 ARSIZE[2:0], input
.SAXIHP2ARBURST(), // AXI PS Slave HP2 ARBURST[1:0], input
.SAXIHP2ARQOS(), // AXI PS Slave HP2 ARQOS[3:0], input
// AXI PS Slave HP2: Read Data
.SAXIHP2RDATA(), // AXI PS Slave HP2 RDATA[63:0], output
.SAXIHP2RVALID(), // AXI PS Slave HP2 RVALID, output
.SAXIHP2RREADY(), // AXI PS Slave HP2 RREADY, input
.SAXIHP2RID(), // AXI PS Slave HP2 RID[5:0], output
.SAXIHP2RLAST(), // AXI PS Slave HP2 RLAST, output
.SAXIHP2RRESP(), // AXI PS Slave HP2 RRESP[1:0], output
.SAXIHP2RCOUNT(), // AXI PS Slave HP2 RCOUNT[7:0], output
.SAXIHP2RACOUNT(), // AXI PS Slave HP2 RACOUNT[2:0], output
.SAXIHP2RDISSUECAP1EN(), // AXI PS Slave HP2 RDISSUECAP1EN, input
// AXI PS Slave HP2: Write Address
.SAXIHP2AWADDR(), // AXI PS Slave HP2 AWADDR[31:0], input
.SAXIHP2AWVALID(), // AXI PS Slave HP2 AWVALID, input
.SAXIHP2AWREADY(), // AXI PS Slave HP2 AWREADY, output
.SAXIHP2AWID(), // AXI PS Slave HP2 AWID[5:0], input
.SAXIHP2AWLOCK(), // AXI PS Slave HP2 AWLOCK[1:0], input
.SAXIHP2AWCACHE(), // AXI PS Slave HP2 AWCACHE[3:0], input
.SAXIHP2AWPROT(), // AXI PS Slave HP2 AWPROT[2:0], input
.SAXIHP2AWLEN(), // AXI PS Slave HP2 AWLEN[3:0], input
.SAXIHP2AWSIZE(), // AXI PS Slave HP2 AWSIZE[1:0], input
.SAXIHP2AWBURST(), // AXI PS Slave HP2 AWBURST[1:0], input
.SAXIHP2AWQOS(), // AXI PS Slave HP2 AWQOS[3:0], input
// AXI PS Slave HP2: Write Data
.SAXIHP2WDATA(), // AXI PS Slave HP2 WDATA[63:0], input
.SAXIHP2WVALID(), // AXI PS Slave HP2 WVALID, input
.SAXIHP2WREADY(), // AXI PS Slave HP2 WREADY, output
.SAXIHP2WID(), // AXI PS Slave HP2 WID[5:0], input
.SAXIHP2WLAST(), // AXI PS Slave HP2 WLAST, input
.SAXIHP2WSTRB(), // AXI PS Slave HP2 WSTRB[7:0], input
.SAXIHP2WCOUNT(), // AXI PS Slave HP2 WCOUNT[7:0], output
.SAXIHP2WACOUNT(), // AXI PS Slave HP2 WACOUNT[5:0], output
.SAXIHP2WRISSUECAP1EN(), // AXI PS Slave HP2 WRISSUECAP1EN, input
// AXI PS Slave HP2: Write response
.SAXIHP2BVALID(), // AXI PS Slave HP2 BVALID, output
.SAXIHP2BREADY(), // AXI PS Slave HP2 BREADY, input
.SAXIHP2BID(), // AXI PS Slave HP2 BID[5:0], output
.SAXIHP2BRESP(), // AXI PS Slave HP2 BRESP[1:0], output
// AXI PS Slave HP3
// AXI PS Slave HP3: Clock, Reset
.SAXIHP3ACLK (hclk), // AXI PS Slave HP3 Clock , input
.SAXIHP3ARESETN(), // AXI PS Slave HP3 Reset, output
// AXI PS Slave HP3: Read Address
.SAXIHP3ARADDR (afi3_araddr), // AXI PS Slave HP3 ARADDR[31:0], input
.SAXIHP3ARVALID (afi3_arvalid), // AXI PS Slave HP3 ARVALID, input
.SAXIHP3ARREADY (afi3_arready), // AXI PS Slave HP3 ARREADY, output
.SAXIHP3ARID (afi3_arid), // AXI PS Slave HP3 ARID[5:0], input
.SAXIHP3ARLOCK (afi3_arlock), // AXI PS Slave HP3 ARLOCK[1:0], input
.SAXIHP3ARCACHE (afi3_arcache), // AXI PS Slave HP3 ARCACHE[3:0], input
.SAXIHP3ARPROT (afi3_arprot), // AXI PS Slave HP3 ARPROT[2:0], input
.SAXIHP3ARLEN (afi3_arlen), // AXI PS Slave HP3 ARLEN[3:0], input
.SAXIHP3ARSIZE (afi3_arsize), // AXI PS Slave HP3 ARSIZE[2:0], input
.SAXIHP3ARBURST (afi3_arburst), // AXI PS Slave HP3 ARBURST[1:0], input
.SAXIHP3ARQOS (afi3_arqos), // AXI PS Slave HP3 ARQOS[3:0], input
// AXI PS Slave HP3: Read Data
.SAXIHP3RDATA (afi3_rdata), // AXI PS Slave HP3 RDATA[63:0], output
.SAXIHP3RVALID (afi3_rvalid), // AXI PS Slave HP3 RVALID, output
.SAXIHP3RREADY (afi3_rready), // AXI PS Slave HP3 RREADY, input
.SAXIHP3RID (afi3_rid), // AXI PS Slave HP3 RID[5:0], output
.SAXIHP3RLAST (afi3_rlast), // AXI PS Slave HP3 RLAST, output
.SAXIHP3RRESP (afi3_rresp), // AXI PS Slave HP3 RRESP[1:0], output
.SAXIHP3RCOUNT (afi3_rcount), // AXI PS Slave HP3 RCOUNT[7:0], output
.SAXIHP3RACOUNT (afi3_racount), // AXI PS Slave HP3 RACOUNT[2:0], output
.SAXIHP3RDISSUECAP1EN (afi3_rdissuecap1en), // AXI PS Slave HP3 RDISSUECAP1EN, input
// AXI PS Slave HP3: Write Address
.SAXIHP3AWADDR (afi3_awaddr), // AXI PS Slave HP3 AWADDR[31:0], input
.SAXIHP3AWVALID (afi3_awvalid), // AXI PS Slave HP3 AWVALID, input
.SAXIHP3AWREADY (afi3_awready), // AXI PS Slave HP3 AWREADY, output
.SAXIHP3AWID (afi3_awid), // AXI PS Slave HP3 AWID[5:0], input
.SAXIHP3AWLOCK (afi3_awlock), // AXI PS Slave HP3 AWLOCK[1:0], input
.SAXIHP3AWCACHE (afi3_awcache), // AXI PS Slave HP3 AWCACHE[3:0], input
.SAXIHP3AWPROT (afi3_awprot), // AXI PS Slave HP3 AWPROT[2:0], input
.SAXIHP3AWLEN (afi3_awlen), // AXI PS Slave HP3 AWLEN[3:0], input
.SAXIHP3AWSIZE (afi3_awsize), // AXI PS Slave HP3 AWSIZE[1:0], input
.SAXIHP3AWBURST (afi3_awburst), // AXI PS Slave HP3 AWBURST[1:0], input
.SAXIHP3AWQOS (afi3_awqos), // AXI PS Slave HP3 AWQOS[3:0], input
// AXI PS Slave HP3: Write Data
.SAXIHP3WDATA (afi3_wdata), // AXI PS Slave HP3 WDATA[63:0], input
.SAXIHP3WVALID (afi3_wvalid), // AXI PS Slave HP3 WVALID, input
.SAXIHP3WREADY (afi3_wready), // AXI PS Slave HP3 WREADY, output
.SAXIHP3WID (afi3_wid), // AXI PS Slave HP3 WID[5:0], input
.SAXIHP3WLAST (afi3_wlast), // AXI PS Slave HP3 WLAST, input
.SAXIHP3WSTRB (afi3_wstrb), // AXI PS Slave HP3 WSTRB[7:0], input
.SAXIHP3WCOUNT (afi3_wcount), // AXI PS Slave HP3 WCOUNT[7:0], output
.SAXIHP3WACOUNT (afi3_wacount), // AXI PS Slave HP3 WACOUNT[5:0], output
.SAXIHP3WRISSUECAP1EN (afi3_wrissuecap1en), // AXI PS Slave HP3 WRISSUECAP1EN, input
// AXI PS Slave HP3: Write response
.SAXIHP3BVALID (afi3_bvalid), // AXI PS Slave HP3 BVALID, output
.SAXIHP3BREADY (afi3_bready), // AXI PS Slave HP3 BREADY, input
.SAXIHP3BID (afi3_bid), // AXI PS Slave HP3 BID[5:0], output
.SAXIHP3BRESP (afi3_bresp), // AXI PS Slave HP3 BRESP[1:0], output
// AXI PS Slave ACP
// AXI PS Slave ACP: Clock, Reset
.SAXIACPACLK(), // AXI PS Slave ACP Clock, input
.SAXIACPARESETN(), // AXI PS Slave ACP Reset, output
// AXI PS Slave ACP: Read Address
.SAXIACPARADDR(), // AXI PS Slave ACP ARADDR[31:0], input
.SAXIACPARVALID(), // AXI PS Slave ACP ARVALID, input
.SAXIACPARREADY(), // AXI PS Slave ACP ARREADY, output
.SAXIACPARID(), // AXI PS Slave ACP ARID[2:0], input
.SAXIACPARLOCK(), // AXI PS Slave ACP ARLOCK[1:0], input
.SAXIACPARCACHE(), // AXI PS Slave ACP ARCACHE[3:0], input
.SAXIACPARPROT(), // AXI PS Slave ACP ARPROT[2:0], input
.SAXIACPARLEN(), // AXI PS Slave ACP ARLEN[3:0], input
.SAXIACPARSIZE(), // AXI PS Slave ACP ARSIZE[2:0], input
.SAXIACPARBURST(), // AXI PS Slave ACP ARBURST[1:0], input
.SAXIACPARQOS(), // AXI PS Slave ACP ARQOS[3:0], input
.SAXIACPARUSER(), // AXI PS Slave ACP ARUSER[4:0], input
// AXI PS Slave ACP: Read Data
.SAXIACPRDATA(), // AXI PS Slave ACP RDATA[63:0], output
.SAXIACPRVALID(), // AXI PS Slave ACP RVALID, output
.SAXIACPRREADY(), // AXI PS Slave ACP RREADY, input
.SAXIACPRID(), // AXI PS Slave ACP RID[2:0], output
.SAXIACPRLAST(), // AXI PS Slave ACP RLAST, output
.SAXIACPRRESP(), // AXI PS Slave ACP RRESP[1:0], output
// AXI PS Slave ACP: Write Address
.SAXIACPAWADDR(), // AXI PS Slave ACP AWADDR[31:0], input
.SAXIACPAWVALID(), // AXI PS Slave ACP AWVALID, input
.SAXIACPAWREADY(), // AXI PS Slave ACP AWREADY, output
.SAXIACPAWID(), // AXI PS Slave ACP AWID[2:0], input
.SAXIACPAWLOCK(), // AXI PS Slave ACP AWLOCK[1:0], input
.SAXIACPAWCACHE(), // AXI PS Slave ACP AWCACHE[3:0], input
.SAXIACPAWPROT(), // AXI PS Slave ACP AWPROT[2:0], input
.SAXIACPAWLEN(), // AXI PS Slave ACP AWLEN[3:0], input
.SAXIACPAWSIZE(), // AXI PS Slave ACP AWSIZE[1:0], input
.SAXIACPAWBURST(), // AXI PS Slave ACP AWBURST[1:0], input
.SAXIACPAWQOS(), // AXI PS Slave ACP AWQOS[3:0], input
.SAXIACPAWUSER(), // AXI PS Slave ACP AWUSER[4:0], input
// AXI PS Slave ACP: Write Data
.SAXIACPWDATA(), // AXI PS Slave ACP WDATA[63:0], input
.SAXIACPWVALID(), // AXI PS Slave ACP WVALID, input
.SAXIACPWREADY(), // AXI PS Slave ACP WREADY, output
.SAXIACPWID(), // AXI PS Slave ACP WID[2:0], input
.SAXIACPWLAST(), // AXI PS Slave ACP WLAST, input
.SAXIACPWSTRB(), // AXI PS Slave ACP WSTRB[7:0], input
// AXI PS Slave ACP: Write response
.SAXIACPBVALID(), // AXI PS Slave ACP BVALID, output
.SAXIACPBREADY(), // AXI PS Slave ACP BREADY, input
.SAXIACPBID(), // AXI PS Slave ACP BID[2:0], output
.SAXIACPBRESP(), // AXI PS Slave ACP BRESP[1:0], output
// Direct connection to PS package pads
.DDRA(), // PS DDRA[14:0], inout
.DDRBA(), // PS DDRBA[2:0], inout
.DDRCASB(), // PS DDRCASB, inout
.DDRCKE(), // PS DDRCKE, inout
.DDRCKP(), // PS DDRCKP, inout
.DDRCKN(), // PS DDRCKN, inout
.DDRCSB(), // PS DDRCSB, inout
.DDRDM(), // PS DDRDM[3:0], inout
.DDRDQ(), // PS DDRDQ[31:0], inout
.DDRDQSP(), // PS DDRDQSP[3:0], inout
.DDRDQSN(), // PS DDRDQSN[3:0], inout
.DDRDRSTB(), // PS DDRDRSTB, inout
.DDRODT(), // PS DDRODT, inout
.DDRRASB(), // PS DDRRASB, inout
.DDRVRN(), // PS DDRVRN, inout
.DDRVRP(), // PS DDRVRP, inout
.DDRWEB(), // PS DDRWEB, inout
.MIO(), // PS MIO[53:0], inout // clg225 has less
.PSCLK(), // PS PSCLK, inout
.PSPORB(), // PS PSPORB, inout
.PSSRSTB() // PS PSSRSTB, inout
);
endmodule
This source diff could not be displayed because it is too large. You can view the blob instead.
/*******************************************************************************
* Module: clock_inverter
* Date:2016-02-11
* Author: andrey
* Description: Glitch-free clock controlled inverter
*
* Copyright (c) 2016 Elphel, Inc .
* clock_inverter.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.
*
* clock_inverter.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 clock_inverter(
input rst, // just for simulation
input clk_in,
input invert,
output clk_out
);
`ifdef SUPPORTED_BUFGCTRL_INVERION
BUFGCTRL #(
.INIT_OUT (0),
.IS_CE0_INVERTED (1'b0),
.IS_CE1_INVERTED (1'b0),
.IS_I0_INVERTED (1'b1),
.IS_I1_INVERTED (1'b0),
.IS_IGNORE0_INVERTED (1'b0),
.IS_IGNORE1_INVERTED (1'b0),
.IS_S0_INVERTED (1'b1),
.IS_S1_INVERTED (1'b0),
.PRESELECT_I0 ("TRUE"),
.PRESELECT_I1 ("FALSE")
) BUFGCTRL_i (
.O (clk_out), // output
.CE0 (1'b1), // input
.CE1 (1'b1), // input
.I0 (clk_in), // input
.I1 (clk_in), // input
.IGNORE0 (1'b0), // input
.IGNORE1 (1'b0), // input
.S0 (invert), // input
.S1 (invert) // input
);
`else
reg invert_r;
reg pos_r;
reg neg_r;
// poor man's ddr
always @ (posedge clk_in) begin
invert_r <= invert;
pos_r <= !rst && !pos_r;
end
always @ (negedge clk_in) begin
neg_r <= pos_r;
end
BUFGCTRL #(
.INIT_OUT (0),
.PRESELECT_I0 ("TRUE"),
.PRESELECT_I1 ("FALSE")
) BUFGCTRL_i (
.O (clk_out), // output
.CE0 (1'b1), // input
.CE1 (1'b1), // input
.I0 (pos_r ^ neg_r), // input
.I1 (pos_r == neg_r), // input
.IGNORE0 (1'b0), // input
.IGNORE1 (1'b0), // input
.S0 (!invert_r), // input
.S1 ( invert_r) // input
);
`endif
endmodule
/*******************************************************************************
* Module: gtxe2_channel_wrapper
* Date: 2015-09-07
* Author: Alexey
* Description: wrapper to switch between closed unisims primitive and open-source one
*
* Copyright (c) 2015 Elphel, Inc.
* GTXE2_GPL.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.
*
* GTXE2_GPL.v file 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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`include "system_defines.vh"
module gtxe2_channel_wrapper(
// clocking ports, UG476 p.37
input [2:0] CPLLREFCLKSEL,
input GTGREFCLK,
input GTNORTHREFCLK0,
input GTNORTHREFCLK1,
input GTREFCLK0,
input GTREFCLK1,
input GTSOUTHREFCLK0,
input GTSOUTHREFCLK1,
input [1:0] RXSYSCLKSEL,
input [1:0] TXSYSCLKSEL,
output GTREFCLKMONITOR,
// CPLL Ports, UG476 p.48
input CPLLLOCKDETCLK,
input CPLLLOCKEN,
input CPLLPD,
input CPLLRESET,
output CPLLFBCLKLOST,
output CPLLLOCK,
output CPLLREFCLKLOST,
output [9:0] TSTOUT,
input [15:0] GTRSVD,
input [15:0] PCSRSVDIN,
input [4:0] PCSRSVDIN2,
input [4:0] PMARSVDIN,
input [4:0] PMARSVDIN2,
input [19:0] TSTIN,
// Reset Mode ports, ug476 p.62
input GTRESETSEL,
input RESETOVRD,
// TX Reset ports, ug476 p.65
input CFGRESET,
input GTTXRESET,
input TXPCSRESET,
input TXPMARESET,
output TXRESETDONE,
input TXUSERRDY,
output [15:0] PCSRSVDOUT,
// RX Reset ports, UG476 p.73
input GTRXRESET,
input RXPMARESET,
input RXCDRRESET,
input RXCDRFREQRESET,
input RXDFELPMRESET,
input EYESCANRESET,
input RXPCSRESET,
input RXBUFRESET,
input RXUSERRDY,
output RXRESETDONE,
input RXOOBRESET,
// Power Down ports, ug476 p.88
input [1:0] RXPD,
input [1:0] TXPD,
input TXPDELECIDLEMODE,
input TXPHDLYPD,
input RXPHDLYPD,
// Loopback ports, ug476 p.91
input [2:0] LOOPBACK,
// Dynamic Reconfiguration Port, ug476 p.92
input [8:0] DRPADDR,
input DRPCLK,
input [15:0] DRPDI,
output [15:0] DRPDO,
input DRPEN,
output DRPRDY,
input DRPWE,
// Digital Monitor Ports, ug476 p.95
input [3:0] CLKRSVD,
output [7:0] DMONITOROUT,
// TX Interface Ports, ug476 p.110
input [7:0] TXCHARDISPMODE,
input [7:0] TXCHARDISPVAL,
input [63:0] TXDATA,
input TXUSRCLK,
input TXUSRCLK2,
// TX 8B/10B encoder ports, ug476 p.118
input [7:0] TX8B10BBYPASS,
input TX8B10BEN,
input [7:0] TXCHARISK,
// TX Gearbox ports, ug476 p.122
output TXGEARBOXREADY,
input [2:0] TXHEADER,
input [6:0] TXSEQUENCE,
input TXSTARTSEQ,
// TX BUffer Ports, ug476 p.134
output [1:0] TXBUFSTATUS,
// TX Buffer Bypass Ports, ug476 p.136
input TXDLYSRESET,
input TXPHALIGN,
input TXPHALIGNEN,
input TXPHINIT,
input TXPHOVRDEN,
input TXPHDLYRESET,
input TXDLYBYPASS,
input TXDLYEN,
input TXDLYOVRDEN,
input TXPHDLYTSTCLK,
input TXDLYHOLD,
input TXDLYUPDOWN,
output TXPHALIGNDONE,
output TXPHINITDONE,
output TXDLYSRESETDONE,
/* input TXSYNCMODE,
input TXSYNCALLIN,
input TXSYNCIN,
output TXSYNCOUT,
output TXSYNCDONE,*/
// TX Pattern Generator, ug476 p.147
input [2:0] TXPRBSSEL,
input TXPRBSFORCEERR,
// TX Polarity Control Ports, ug476 p.149
input TXPOLARITY,
// TX Fabric Clock Output Control Ports, ug476 p.152
input [2:0] TXOUTCLKSEL,
input [2:0] TXRATE,
output TXOUTCLKFABRIC,
output TXOUTCLK,
output TXOUTCLKPCS,
output TXRATEDONE,
// TX Phase Interpolator PPM Controller Ports, ug476 p.154
// GTH only
/* input TXPIPPMEN,
input TXPIPPMOVRDEN,
input TXPIPPMSEL,
input TXPIPPMPD,
input [4:0] TXPIPPMSTEPSIZE,*/
// TX Configurable Driver Ports, ug476 p.156
input [2:0] TXBUFDIFFCTRL,
input TXDEEMPH,
input [3:0] TXDIFFCTRL,
input TXELECIDLE,
input TXINHIBIT,
input [6:0] TXMAINCURSOR,
input [2:0] TXMARGIN,
input TXQPIBIASEN,
output TXQPISENN,
output TXQPISENP,
input TXQPISTRONGPDOWN,
input TXQPIWEAKPUP,
input [4:0] TXPOSTCURSOR,
input TXPOSTCURSORINV,
input [4:0] TXPRECURSOR,
input TXPRECURSORINV,
input TXSWING,
input TXDIFFPD,
input TXPISOPD,
// TX Receiver Detection Ports, ug476 p.165
input TXDETECTRX,
output PHYSTATUS,
output [2:0] RXSTATUS,
// TX OOB Signaling Ports, ug476 p.166
output TXCOMFINISH,
input TXCOMINIT,
input TXCOMSAS,
input TXCOMWAKE,
// RX AFE Ports, ug476 p.171
output RXQPISENN,
output RXQPISENP,
input RXQPIEN,
// RX OOB Signaling Ports, ug476 p.178
input [1:0] RXELECIDLEMODE,
output RXELECIDLE,
output RXCOMINITDET,
output RXCOMSASDET,
output RXCOMWAKEDET,
// RX Equalizer Ports, ug476 p.189
input RXLPMEN,
input RXOSHOLD,
input RXOSOVRDEN,
input RXLPMLFHOLD,
input RXLPMLFKLOVRDEN,
input RXLPMHFHOLD,
input RXLPMHFOVRDEN,
input RXDFEAGCHOLD,
input RXDFEAGCOVRDEN,
input RXDFELFHOLD,
input RXDFELFOVRDEN,
input RXDFEUTHOLD,
input RXDFEUTOVRDEN,
input RXDFEVPHOLD,
input RXDFEVPOVRDEN,
input RXDFETAP2HOLD,
input RXDFETAP2OVRDEN,
input RXDFETAP3HOLD,
input RXDFETAP3OVRDEN,
input RXDFETAP4HOLD,
input RXDFETAP4OVRDEN,
input RXDFETAP5HOLD,
input RXDFETAP5OVRDEN,
input RXDFECM1EN,
input RXDFEXYDHOLD,
input RXDFEXYDOVRDEN,
input RXDFEXYDEN,
input [1:0] RXMONITORSEL,
output [6:0] RXMONITOROUT,
// CDR Ports, ug476 p.202
input RXCDRHOLD,
input RXCDROVRDEN,
input RXCDRRESETRSV,
input [2:0] RXRATE,
output RXCDRLOCK,
// RX Fabric Clock Output Control Ports, ug476 p.213
input [2:0] RXOUTCLKSEL,
output RXOUTCLKFABRIC,
output RXOUTCLK,
output RXOUTCLKPCS,
output RXRATEDONE,
input RXDLYBYPASS,
// RX Margin Analysis Ports, ug476 p.220
output EYESCANDATAERROR,
input EYESCANTRIGGER,
input EYESCANMODE,
// RX Polarity Control Ports, ug476 p.224
input RXPOLARITY,
// Pattern Checker Ports, ug476 p.225
input RXPRBSCNTRESET,
input [2:0] RXPRBSSEL,
output RXPRBSERR,
// RX Byte and Word Alignment Ports, ug476 p.233
output RXBYTEISALIGNED,
output RXBYTEREALIGN,
output RXCOMMADET,
input RXCOMMADETEN,
input RXPCOMMAALIGNEN,
input RXMCOMMAALIGNEN,
input RXSLIDE,
// RX 8B/10B Decoder Ports, ug476 p.241
input RX8B10BEN,
output [7:0] RXCHARISCOMMA,
output [7:0] RXCHARISK,
output [7:0] RXDISPERR,
output [7:0] RXNOTINTABLE,
input SETERRSTATUS,
// RX Buffer Bypass Ports, ug476 p.244
input RXPHDLYRESET,
input RXPHALIGN,
input RXPHALIGNEN,
input RXPHOVRDEN,
input RXDLYSRESET,
input RXDLYEN,
input RXDLYOVRDEN,
input RXDDIEN,
output RXPHALIGNDONE,
output [4:0] RXPHMONITOR,
output [4:0] RXPHSLIPMONITOR,
output RXDLYSRESETDONE,
// RX Buffer Ports, ug476 p.259
output [2:0] RXBUFSTATUS,
// RX Clock Correction Ports, ug476 p.263
output [1:0] RXCLKCORCNT,
// RX Channel Bonding Ports, ug476 p.274
output RXCHANBONDSEQ,
output RXCHANISALIGNED,
output RXCHANREALIGN,
input [4:0] RXCHBONDI,
output [4:0] RXCHBONDO,
input [2:0] RXCHBONDLEVEL,
input RXCHBONDMASTER,
input RXCHBONDSLAVE,
input RXCHBONDEN,
// RX Gearbox Ports, ug476 p.285
output RXDATAVALID,
input RXGEARBOXSLIP,
output [2:0] RXHEADER,
output RXHEADERVALID,
output RXSTARTOFSEQ,
// FPGA RX Interface Ports, ug476 p.299
output [63:0] RXDATA,
input RXUSRCLK,
input RXUSRCLK2,
// ug476, p.323
output RXVALID,
// for correct clocking scheme in case of multilane structure
input QPLLCLK,
input QPLLREFCLK,
// Diffpairs
input GTXRXP,
input GTXRXN,
output GTXTXN,
output GTXTXP
);
// simulation common attributes, UG476 p.28
parameter SIM_RESET_SPEEDUP = "TRUE";
parameter SIM_CPLLREFCLK_SEL = 3'b001;
parameter SIM_RECEIVER_DETECT_PASS = "TRUE";
parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X";
parameter SIM_VERSION = "1.0";
// Clocking Atributes, UG476 p.38
parameter OUTREFCLK_SEL_INV = 1'b0;
// CPLL Attributes, UG476 p.49
parameter CPLL_CFG = 24'h0;
parameter CPLL_FBDIV = 4;
parameter CPLL_FBDIV_45 = 5;
parameter CPLL_INIT_CFG = 24'h0;
parameter CPLL_LOCK_CFG = 16'h0;
parameter CPLL_REFCLK_DIV = 1;
parameter RXOUT_DIV = 2;
parameter TXOUT_DIV = 2;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
parameter PMA_RSV3 = 2'b00;
// TX Initialization and Reset Attributes, ug476 p.66
parameter TXPCSRESET_TIME = 5'b00001;
parameter TXPMARESET_TIME = 5'b00001;
// RX Initialization and Reset Attributes, UG476 p.75
parameter RXPMARESET_TIME = 5'h0;
parameter RXCDRPHRESET_TIME = 5'h0;
parameter RXCDRFREQRESET_TIME = 5'h0;
parameter RXDFELPMRESET_TIME = 7'h0;
parameter RXISCANRESET_TIME = 7'h0;
parameter RXPCSRESET_TIME = 5'h0;
parameter RXBUFRESET_TIME = 5'h0;
// Power Down attributes, ug476 p.88
parameter PD_TRANS_TIME_FROM_P2 = 12'h0;
parameter PD_TRANS_TIME_NONE_P2 = 8'h0;
parameter PD_TRANS_TIME_TO_P2 = 8'h0;
parameter TRANS_TIME_RATE = 8'h0;
parameter RX_CLKMUX_PD = 1'b0;
parameter TX_CLKMUX_PD = 1'b0;
// GTX Digital Monitor Attributes, ug476 p.96
parameter DMONITOR_CFG = 24'h008101;
// TX Interface attributes, ug476 p.111
parameter TX_DATA_WIDTH = 20;
parameter TX_INT_DATAWIDTH = 0;
// TX Gearbox Attributes, ug476 p.121
parameter GEARBOX_MODE = 3'h0;
parameter TXGEARBOX_EN = "FALSE";
// TX BUffer Attributes, ug476 p.134
parameter TXBUF_EN = "TRUE";
// TX Bypass buffer, ug476 p.138
parameter TX_XCLK_SEL = "TXOUT";
parameter TXPH_CFG = 16'h0;
parameter TXPH_MONITOR_SEL = 5'h0;
parameter TXPHDLY_CFG = 24'h0;
parameter TXDLY_CFG = 16'h0;
parameter TXDLY_LCFG = 9'h0;
parameter TXDLY_TAP_CFG = 16'h0;
//parameter TXSYNC_MULTILANE = 1'b0;
//parameter TXSYNC_SKIP_DA = 1'b0;
//parameter TXSYNC_OVRD = 1'b1;
//parameter LOOPBACK_CFG = 1'b0;
// TX Pattern Generator, ug476 p.147
parameter RXPRBS_ERR_LOOPBACK = 1'b0;
// TX Fabric Clock Output Control Attributes, ug476 p. 153
parameter TXBUF_RESET_ON_RATE_CHANGE = "TRUE";
// TX Phase Interpolator PPM Controller Attributes, ug476 p.155
// GTH only
/*parameter TXPI_SYNCFREQ_PPM = 3'b001;
parameter TXPI_PPM_CFG = 8'd0;
parameter TXPI_INVSTROBE_SEL = 1'b0;
parameter TXPI_GREY_SEL = 1'b0;
parameter TXPI_PPMCLK_SEL = "12345";*/
// TX Configurable Driver Attributes, ug476 p.162
parameter TX_DEEMPH0 = 5'b10100;
parameter TX_DEEMPH1 = 5'b01101;
parameter TX_DRIVE_MODE = "DIRECT";
parameter TX_MAINCURSOR_SEL = 1'b0;
parameter TX_MARGIN_FULL_0 = 7'b0;
parameter TX_MARGIN_FULL_1 = 7'b0;
parameter TX_MARGIN_FULL_2 = 7'b0;
parameter TX_MARGIN_FULL_3 = 7'b0;
parameter TX_MARGIN_FULL_4 = 7'b0;
parameter TX_MARGIN_LOW_0 = 7'b0;
parameter TX_MARGIN_LOW_1 = 7'b0;
parameter TX_MARGIN_LOW_2 = 7'b0;
parameter TX_MARGIN_LOW_3 = 7'b0;
parameter TX_MARGIN_LOW_4 = 7'b0;
parameter TX_PREDRIVER_MODE = 1'b0;
parameter TX_QPI_STATUS_EN = 1'b0;
parameter TX_EIDLE_ASSERT_DELAY = 3'b110;
parameter TX_EIDLE_DEASSERT_DELAY = 3'b100;
parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE";
// TX Receiver Detection Attributes, ug476 p.165
parameter TX_RXDETECT_CFG = 14'h0;
parameter TX_RXDETECT_REF = 3'h0;
// TX OOB Signaling Attributes
parameter SATA_BURST_SEQ_LEN = 4'b0101;
// RX AFE Attributes, ug476 p.171
parameter RX_CM_SEL = 2'b11;
parameter TERM_RCAL_CFG = 5'b0;
parameter TERM_RCAL_OVRD = 1'b0;
parameter RX_CM_TRIM = 3'b010;
// RX OOB Signaling Attributes, ug476 p.179
parameter PCS_RSVD_ATTR = 48'h0100; // oob is up
parameter RXOOB_CFG = 7'b0000110;
parameter SATA_BURST_VAL = 3'b110;
parameter SATA_EIDLE_VAL = 3'b110;
parameter SAS_MIN_COM = 36;
parameter SATA_MIN_INIT = 12;
parameter SATA_MIN_WAKE = 4;
parameter SATA_MAX_BURST = 8;
parameter SATA_MIN_BURST = 4;
parameter SAS_MAX_COM = 64;
parameter SATA_MAX_INIT = 21;
parameter SATA_MAX_WAKE = 7;
// RX Equalizer Attributes, ug476 p.193
parameter RX_OS_CFG = 13'h0080;
parameter RXLPM_LF_CFG = 14'h00f0;
parameter RXLPM_HF_CFG = 14'h00f0;
parameter RX_DFE_LPM_CFG = 16'h0;
parameter RX_DFE_GAIN_CFG = 23'h020FEA;
parameter RX_DFE_H2_CFG = 12'h0;
parameter RX_DFE_H3_CFG = 12'h040;
parameter RX_DFE_H4_CFG = 11'h0e0;
parameter RX_DFE_H5_CFG = 11'h0e0;
parameter PMA_RSV = 32'h00018480;
parameter RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0;
parameter RX_DFE_XYD_CFG = 13'h0;
parameter PMA_RSV4 = 32'h0;
parameter PMA_RSV2 = 16'h0;
parameter RX_BIAS_CFG = 12'h040;
parameter RX_DEBUG_CFG = 12'h0;
parameter RX_DFE_KL_CFG = 13'h0;
parameter RX_DFE_KL_CFG2 = 32'h0;
parameter RX_DFE_UT_CFG = 17'h11e00;
parameter RX_DFE_VP_CFG = 17'h03f03;
// CDR Attributes, ug476 p.203
parameter RXCDR_CFG = 72'h0;
parameter RXCDR_LOCK_CFG = 6'h0;
parameter RXCDR_HOLD_DURING_EIDLE = 1'b0;
parameter RXCDR_FR_RESET_ON_EIDLE = 1'b0;
parameter RXCDR_PH_RESET_ON_EIDLE = 1'b0;
// RX Fabric Clock Output Control Attributes
parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE";
// RX Margin Analysis Attributes
parameter ES_VERT_OFFSET = 9'h0;
parameter ES_HORZ_OFFSET = 12'h0;
parameter ES_PRESCALE = 5'h0;
parameter ES_SDATA_MASK = 80'h0;
parameter ES_QUALIFIER = 80'h0;
parameter ES_QUAL_MASK = 80'h0;
parameter ES_EYE_SCAN_EN = 1'b1;
parameter ES_ERRDET_EN = 1'b0;
parameter ES_CONTROL = 6'h0;
parameter RX_DATA_WIDTH = 20;
parameter RX_INT_DATAWIDTH = 0;
parameter ES_PMA_CFG = 10'h0;
// Pattern Checker Attributes, ug476 p.226
//parameter RX_PRBS_ERR_CNT = 16'h15c;
// RX Byte and Word Alignment Attributes, ug476 p.235
parameter ALIGN_COMMA_WORD = 1;
parameter ALIGN_COMMA_ENABLE = 10'b1111111111;
parameter ALIGN_COMMA_DOUBLE = "FALSE";
parameter ALIGN_MCOMMA_DET = "TRUE";
parameter ALIGN_MCOMMA_VALUE = 10'b1010000011;
parameter ALIGN_PCOMMA_DET = "TRUE";
parameter ALIGN_PCOMMA_VALUE = 10'b0101111100;
parameter SHOW_REALIGN_COMMA = "TRUE";
parameter RXSLIDE_MODE = "OFF";
parameter RXSLIDE_AUTO_WAIT = 7;
parameter RX_SIG_VALID_DLY = 10;
//parameter COMMA_ALIGN_LATENCY = 9'h14e;
// RX 8B/10B Decoder Attributes, ug476 p.242
parameter RX_DISPERR_SEQ_MATCH = "TRUE";
parameter DEC_MCOMMA_DETECT = "TRUE";
parameter DEC_PCOMMA_DETECT = "TRUE";
parameter DEC_VALID_COMMA_ONLY = "FALSE";
parameter UCODEER_CLR = 1'b0;
// RX Buffer Bypass Attributes, ug476 p.247
parameter RXBUF_EN = "TRUE";
parameter RX_XCLK_SEL = "RXREC";
parameter RXPH_CFG = 24'h0;
parameter RXPH_MONITOR_SEL = 5'h0;
parameter RXPHDLY_CFG = 24'h0;
parameter RXDLY_CFG = 16'h0;
parameter RXDLY_LCFG = 9'h0;
parameter RXDLY_TAP_CFG = 16'h0;
parameter RX_DDI_SEL = 6'h0;
parameter TST_RSV = 32'h0;
// RX Buffer Attributes, ug476 p.259
parameter RX_BUFFER_CFG = 6'b0;
parameter RX_DEFER_RESET_BUF_EN = "TRUE";
parameter RXBUF_ADDR_MODE = "FAST";
parameter RXBUF_EIDLE_HI_CNT = 4'b0;
parameter RXBUF_EIDLE_LO_CNT = 4'b0;
parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE";
parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE";
parameter RXBUF_RESET_ON_EIDLE = "FALSE";
parameter RXBUF_THRESH_OVFLW = 0;
parameter RXBUF_THRESH_OVRD = "FALSE";
parameter RXBUF_THRESH_UNDFLW = 0;
// RX Clock Correction Attributes, ug476 p.265
parameter CBCC_DATA_SOURCE_SEL = "DECODED";
parameter CLK_CORRECT_USE = "FALSE";
parameter CLK_COR_SEQ_2_USE = "FALSE";
parameter CLK_COR_KEEP_IDLE = "FALSE";
parameter CLK_COR_MAX_LAT = 9;
parameter CLK_COR_MIN_LAT = 7;
parameter CLK_COR_PRECEDENCE = "TRUE";
parameter CLK_COR_REPEAT_WAIT = 0;
parameter CLK_COR_SEQ_LEN = 1;
parameter CLK_COR_SEQ_1_ENABLE = 4'b1111;
parameter CLK_COR_SEQ_1_1 = 10'b0;
parameter CLK_COR_SEQ_1_2 = 10'b0;
parameter CLK_COR_SEQ_1_3 = 10'b0;
parameter CLK_COR_SEQ_1_4 = 10'b0;
parameter CLK_COR_SEQ_2_ENABLE = 4'b1111;
parameter CLK_COR_SEQ_2_1 = 10'b0;
parameter CLK_COR_SEQ_2_2 = 10'b0;
parameter CLK_COR_SEQ_2_3 = 10'b0;
parameter CLK_COR_SEQ_2_4 = 10'b0;
// RX Channel Bonding Attributes, ug476 p.276
parameter CHAN_BOND_MAX_SKEW = 1;
parameter CHAN_BOND_KEEP_ALIGN = "FALSE";
parameter CHAN_BOND_SEQ_LEN = 1;
parameter CHAN_BOND_SEQ_1_1 = 10'b0;
parameter CHAN_BOND_SEQ_1_2 = 10'b0;
parameter CHAN_BOND_SEQ_1_3 = 10'b0;
parameter CHAN_BOND_SEQ_1_4 = 10'b0;
parameter CHAN_BOND_SEQ_1_ENABLE = 4'b1111;
parameter CHAN_BOND_SEQ_2_1 = 10'b0;
parameter CHAN_BOND_SEQ_2_2 = 10'b0;
parameter CHAN_BOND_SEQ_2_3 = 10'b0;
parameter CHAN_BOND_SEQ_2_4 = 10'b0;
parameter CHAN_BOND_SEQ_2_ENABLE = 4'b1111;
parameter CHAN_BOND_SEQ_2_USE = "FALSE";
parameter FTS_DESKEW_SEQ_ENABLE = 4'b1111;
parameter FTS_LANE_DESKEW_CFG = 4'b1111;
parameter FTS_LANE_DESKEW_EN = "FALSE";
parameter PCS_PCIE_EN = "FALSE";
// RX Gearbox Attributes, ug476 p.287
parameter RXGEARBOX_EN = "FALSE";
// ug476 table p.326 - undocumented parameters
parameter RX_CLK25_DIV = 6;
parameter TX_CLK25_DIV = 6;
`ifdef OPEN_SOURCE_ONLY
GTXE2_GPL #(
`else // OPEN_SOURCE_ONLY
GTXE2_CHANNEL #(
`endif // OPEN_SOURCE_ONLY
// simulation common attributes, UG476 p.28
.SIM_RESET_SPEEDUP (SIM_RESET_SPEEDUP),
.SIM_CPLLREFCLK_SEL (SIM_CPLLREFCLK_SEL),
.SIM_RECEIVER_DETECT_PASS (SIM_RECEIVER_DETECT_PASS),
.SIM_TX_EIDLE_DRIVE_LEVEL (SIM_TX_EIDLE_DRIVE_LEVEL),
.SIM_VERSION (SIM_VERSION),
// Clocking Atributes, UG476 p.38
.OUTREFCLK_SEL_INV (OUTREFCLK_SEL_INV),
// CPLL Attributes, UG476 p.49
.CPLL_CFG (CPLL_CFG),
.CPLL_FBDIV (CPLL_FBDIV),
.CPLL_FBDIV_45 (CPLL_FBDIV_45),
.CPLL_INIT_CFG (CPLL_INIT_CFG),
.CPLL_LOCK_CFG (CPLL_LOCK_CFG),
.CPLL_REFCLK_DIV (CPLL_REFCLK_DIV),
.RXOUT_DIV (RXOUT_DIV),
.TXOUT_DIV (TXOUT_DIV),
.SATA_CPLL_CFG (SATA_CPLL_CFG),
.PMA_RSV3 (PMA_RSV3),
// TX Initialization and Reset Attributes, ug476 p.66
.TXPCSRESET_TIME (TXPCSRESET_TIME),
.TXPMARESET_TIME (TXPMARESET_TIME),
// RX Initialization and Reset Attributes, UG476 p.75
.RXPMARESET_TIME (RXPMARESET_TIME),
.RXCDRPHRESET_TIME (RXCDRPHRESET_TIME),
.RXCDRFREQRESET_TIME (RXCDRFREQRESET_TIME),
.RXDFELPMRESET_TIME (RXDFELPMRESET_TIME),
.RXISCANRESET_TIME (RXISCANRESET_TIME),
.RXPCSRESET_TIME (RXPCSRESET_TIME),
.RXBUFRESET_TIME (RXBUFRESET_TIME),
// Power Down attributes, ug476 p.88
.PD_TRANS_TIME_FROM_P2 (PD_TRANS_TIME_FROM_P2),
.PD_TRANS_TIME_NONE_P2 (PD_TRANS_TIME_NONE_P2),
.PD_TRANS_TIME_TO_P2 (PD_TRANS_TIME_TO_P2),
.TRANS_TIME_RATE (TRANS_TIME_RATE),
.RX_CLKMUX_PD (RX_CLKMUX_PD),
.TX_CLKMUX_PD (TX_CLKMUX_PD),
// GTX Digital Monitor Attributes, ug476 p.96
.DMONITOR_CFG (DMONITOR_CFG),
// TX Interface attributes, ug476 p.111
.TX_DATA_WIDTH (TX_DATA_WIDTH),
.TX_INT_DATAWIDTH (TX_INT_DATAWIDTH),
// TX Gearbox Attributes, ug476 p.121
.GEARBOX_MODE (GEARBOX_MODE),
.TXGEARBOX_EN (TXGEARBOX_EN),
// TX BUffer Attributes, ug476 p.134
.TXBUF_EN (TXBUF_EN),
// TX Bypass buffer, ug476 p.138
.TX_XCLK_SEL (TX_XCLK_SEL),
.TXPH_CFG (TXPH_CFG),
.TXPH_MONITOR_SEL (TXPH_MONITOR_SEL),
.TXPHDLY_CFG (TXPHDLY_CFG),
.TXDLY_CFG (TXDLY_CFG),
.TXDLY_LCFG (TXDLY_LCFG),
.TXDLY_TAP_CFG (TXDLY_TAP_CFG),
/* .TXSYNC_MULTILANE (TXSYNC_MULTILANE),
.TXSYNC_SKIP_DA (TXSYNC_SKIP_DA),
.TXSYNC_OVRD (TXSYNC_OVRD),
.LOOPBACK_CFG (LOOPBACK_CFG),*/
// TX Pattern Generator, ug476 p.147
.RXPRBS_ERR_LOOPBACK (RXPRBS_ERR_LOOPBACK),
// TX Fabric Clock Output Control Attributes, ug476 p. 153
.TXBUF_RESET_ON_RATE_CHANGE (TXBUF_RESET_ON_RATE_CHANGE),
// TX Phase Interpolator PPM Controller Attributes, ug476 p.155
// GTH only
/* .TXPI_SYNCFREQ_PPM (TXPI_SYNCFREQ_PPM),
.TXPI_PPM_CFG (TXPI_PPM_CFG),
.TXPI_INVSTROBE_SEL (TXPI_INVSTROBE_SEL),
.TXPI_GREY_SEL (TXPI_GREY_SEL),
.TXPI_PPMCLK_SEL (TXPI_PPMCLK_SEL),*/
// TX Configurable Driver Attributes, ug476 p.162
.TX_DEEMPH0 (TX_DEEMPH0),
.TX_DEEMPH1 (TX_DEEMPH1),
.TX_DRIVE_MODE (TX_DRIVE_MODE),
.TX_MAINCURSOR_SEL (TX_MAINCURSOR_SEL),
.TX_MARGIN_FULL_0 (TX_MARGIN_FULL_0),
.TX_MARGIN_FULL_1 (TX_MARGIN_FULL_1),
.TX_MARGIN_FULL_2 (TX_MARGIN_FULL_2),
.TX_MARGIN_FULL_3 (TX_MARGIN_FULL_3),
.TX_MARGIN_FULL_4 (TX_MARGIN_FULL_4),
.TX_MARGIN_LOW_0 (TX_MARGIN_LOW_0),
.TX_MARGIN_LOW_1 (TX_MARGIN_LOW_1),
.TX_MARGIN_LOW_2 (TX_MARGIN_LOW_2),
.TX_MARGIN_LOW_3 (TX_MARGIN_LOW_3),
.TX_MARGIN_LOW_4 (TX_MARGIN_LOW_4),
.TX_PREDRIVER_MODE (TX_PREDRIVER_MODE),
.TX_QPI_STATUS_EN (TX_QPI_STATUS_EN),
.TX_EIDLE_ASSERT_DELAY (TX_EIDLE_ASSERT_DELAY),
.TX_EIDLE_DEASSERT_DELAY (TX_EIDLE_DEASSERT_DELAY),
.TX_LOOPBACK_DRIVE_HIZ (TX_LOOPBACK_DRIVE_HIZ),
// TX Receiver Detection Attributes, ug476 p.165
.TX_RXDETECT_CFG (TX_RXDETECT_CFG),
.TX_RXDETECT_REF (TX_RXDETECT_REF),
// TX OOB Signaling Attributes
.SATA_BURST_SEQ_LEN (SATA_BURST_SEQ_LEN),
// RX AFE Attributes, ug476 p.171
.RX_CM_SEL (RX_CM_SEL),
.TERM_RCAL_CFG (TERM_RCAL_CFG),
.TERM_RCAL_OVRD (TERM_RCAL_OVRD),
.RX_CM_TRIM (RX_CM_TRIM),
// RX OOB Signaling Attributes, ug476 p.179
.PCS_RSVD_ATTR (PCS_RSVD_ATTR),
.RXOOB_CFG (RXOOB_CFG),
.SATA_BURST_VAL (SATA_BURST_VAL),
.SATA_EIDLE_VAL (SATA_EIDLE_VAL),
.SAS_MIN_COM (SAS_MIN_COM),
.SATA_MIN_INIT (SATA_MIN_INIT),
.SATA_MIN_WAKE (SATA_MIN_WAKE),
.SATA_MAX_BURST (SATA_MAX_BURST),
.SATA_MIN_BURST (SATA_MIN_BURST),
.SAS_MAX_COM (SAS_MAX_COM),
.SATA_MAX_INIT (SATA_MAX_INIT),
.SATA_MAX_WAKE (SATA_MAX_WAKE),
// RX Equalizer Attributes, ug476 p.193
.RX_OS_CFG (RX_OS_CFG),
.RXLPM_LF_CFG (RXLPM_LF_CFG),
.RXLPM_HF_CFG (RXLPM_HF_CFG),
.RX_DFE_LPM_CFG (RX_DFE_LPM_CFG),
.RX_DFE_GAIN_CFG (RX_DFE_GAIN_CFG),
.RX_DFE_H2_CFG (RX_DFE_H2_CFG),
.RX_DFE_H3_CFG (RX_DFE_H3_CFG),
.RX_DFE_H4_CFG (RX_DFE_H4_CFG),
.RX_DFE_H5_CFG (RX_DFE_H5_CFG),
.PMA_RSV (PMA_RSV),
.RX_DFE_LPM_HOLD_DURING_EIDLE (RX_DFE_LPM_HOLD_DURING_EIDLE),
.RX_DFE_XYD_CFG (RX_DFE_XYD_CFG),
.PMA_RSV4 (PMA_RSV4),
.PMA_RSV2 (PMA_RSV2),
.RX_BIAS_CFG (RX_BIAS_CFG),
.RX_DEBUG_CFG (RX_DEBUG_CFG),
.RX_DFE_KL_CFG (RX_DFE_KL_CFG),
.RX_DFE_KL_CFG2 (RX_DFE_KL_CFG2),
.RX_DFE_UT_CFG (RX_DFE_UT_CFG),
.RX_DFE_VP_CFG (RX_DFE_VP_CFG),
// CDR Attributes, ug476 p.203
.RXCDR_CFG (RXCDR_CFG),
.RXCDR_LOCK_CFG (RXCDR_LOCK_CFG),
.RXCDR_HOLD_DURING_EIDLE (RXCDR_HOLD_DURING_EIDLE),
.RXCDR_FR_RESET_ON_EIDLE (RXCDR_FR_RESET_ON_EIDLE),
.RXCDR_PH_RESET_ON_EIDLE (RXCDR_PH_RESET_ON_EIDLE),
// RX Fabric Clock Output Control Attributes
.RXBUF_RESET_ON_RATE_CHANGE (RXBUF_RESET_ON_RATE_CHANGE),
// RX Margin Analysis Attributes
.ES_VERT_OFFSET (ES_VERT_OFFSET),
.ES_HORZ_OFFSET (ES_HORZ_OFFSET),
.ES_PRESCALE (ES_PRESCALE),
.ES_SDATA_MASK (ES_SDATA_MASK),
.ES_QUALIFIER (ES_QUALIFIER),
.ES_QUAL_MASK (ES_QUAL_MASK),
.ES_EYE_SCAN_EN (ES_EYE_SCAN_EN),
.ES_ERRDET_EN (ES_ERRDET_EN),
.ES_CONTROL (ES_CONTROL),
/* .es_control_status (es_control_status),
.es_rdata (es_rdata),
.es_sdata (es_sdata),
.es_error_count (es_error_count),
.es_sample_count (es_sample_count),*/
.RX_DATA_WIDTH (RX_DATA_WIDTH),
.RX_INT_DATAWIDTH (RX_INT_DATAWIDTH),
.ES_PMA_CFG (ES_PMA_CFG),
// Pattern Checker Attributes, ug476 p.226
//.RX_PRBS_ERR_CNT (RX_PRBS_ERR_CNT),
// RX Byte and Word Alignment Attributes, ug476 p.235
.ALIGN_COMMA_WORD (ALIGN_COMMA_WORD),
.ALIGN_COMMA_ENABLE (ALIGN_COMMA_ENABLE),
.ALIGN_COMMA_DOUBLE (ALIGN_COMMA_DOUBLE),
.ALIGN_MCOMMA_DET (ALIGN_MCOMMA_DET),
.ALIGN_MCOMMA_VALUE (ALIGN_MCOMMA_VALUE),
.ALIGN_PCOMMA_DET (ALIGN_PCOMMA_DET),
.ALIGN_PCOMMA_VALUE (ALIGN_PCOMMA_VALUE),
.SHOW_REALIGN_COMMA (SHOW_REALIGN_COMMA),
.RXSLIDE_MODE (RXSLIDE_MODE),
.RXSLIDE_AUTO_WAIT (RXSLIDE_AUTO_WAIT),
.RX_SIG_VALID_DLY (RX_SIG_VALID_DLY),
//.COMMA_ALIGN_LATENCY (COMMA_ALIGN_LATENCY),
// RX 8B/10B Decoder Attributes, ug476 p.242
.RX_DISPERR_SEQ_MATCH (RX_DISPERR_SEQ_MATCH),
.DEC_MCOMMA_DETECT (DEC_MCOMMA_DETECT),
.DEC_PCOMMA_DETECT (DEC_PCOMMA_DETECT),
.DEC_VALID_COMMA_ONLY (DEC_VALID_COMMA_ONLY),
.UCODEER_CLR (UCODEER_CLR),
// RX Buffer Bypass Attributes, ug476 p.247
.RXBUF_EN (RXBUF_EN),
.RX_XCLK_SEL (RX_XCLK_SEL),
.RXPH_CFG (RXPH_CFG),
.RXPH_MONITOR_SEL (RXPH_MONITOR_SEL),
.RXPHDLY_CFG (RXPHDLY_CFG),
.RXDLY_CFG (RXDLY_CFG),
.RXDLY_LCFG (RXDLY_LCFG),
.RXDLY_TAP_CFG (RXDLY_TAP_CFG),
.RX_DDI_SEL (RX_DDI_SEL),
.TST_RSV (TST_RSV),
// RX Buffer Attributes, ug476 p.259
.RX_BUFFER_CFG (RX_BUFFER_CFG),
.RX_DEFER_RESET_BUF_EN (RX_DEFER_RESET_BUF_EN),
.RXBUF_ADDR_MODE (RXBUF_ADDR_MODE),
.RXBUF_EIDLE_HI_CNT (RXBUF_EIDLE_HI_CNT),
.RXBUF_EIDLE_LO_CNT (RXBUF_EIDLE_LO_CNT),
.RXBUF_RESET_ON_CB_CHANGE (RXBUF_RESET_ON_CB_CHANGE),
.RXBUF_RESET_ON_COMMAALIGN (RXBUF_RESET_ON_COMMAALIGN),
.RXBUF_RESET_ON_EIDLE (RXBUF_RESET_ON_EIDLE),
.RXBUF_THRESH_OVFLW (RXBUF_THRESH_OVFLW),
.RXBUF_THRESH_OVRD (RXBUF_THRESH_OVRD),
.RXBUF_THRESH_UNDFLW (RXBUF_THRESH_UNDFLW),
// RX Clock Correction Attributes, ug476 p.265
.CBCC_DATA_SOURCE_SEL (CBCC_DATA_SOURCE_SEL),
.CLK_CORRECT_USE (CLK_CORRECT_USE),
.CLK_COR_SEQ_2_USE (CLK_COR_SEQ_2_USE),
.CLK_COR_KEEP_IDLE (CLK_COR_KEEP_IDLE),
.CLK_COR_MAX_LAT (CLK_COR_MAX_LAT),
.CLK_COR_MIN_LAT (CLK_COR_MIN_LAT),
.CLK_COR_PRECEDENCE (CLK_COR_PRECEDENCE),
.CLK_COR_REPEAT_WAIT (CLK_COR_REPEAT_WAIT),
.CLK_COR_SEQ_LEN (CLK_COR_SEQ_LEN),
.CLK_COR_SEQ_1_ENABLE (CLK_COR_SEQ_1_ENABLE),
.CLK_COR_SEQ_1_1 (CLK_COR_SEQ_1_1),
.CLK_COR_SEQ_1_2 (CLK_COR_SEQ_1_2),
.CLK_COR_SEQ_1_3 (CLK_COR_SEQ_1_3),
.CLK_COR_SEQ_1_4 (CLK_COR_SEQ_1_4),
.CLK_COR_SEQ_2_ENABLE (CLK_COR_SEQ_2_ENABLE),
.CLK_COR_SEQ_2_1 (CLK_COR_SEQ_2_1),
.CLK_COR_SEQ_2_2 (CLK_COR_SEQ_2_2),
.CLK_COR_SEQ_2_3 (CLK_COR_SEQ_2_3),
.CLK_COR_SEQ_2_4 (CLK_COR_SEQ_2_4),
// RX Channel Bonding Attributes, ug476 p.276
.CHAN_BOND_MAX_SKEW (CHAN_BOND_MAX_SKEW),
.CHAN_BOND_KEEP_ALIGN (CHAN_BOND_KEEP_ALIGN),
.CHAN_BOND_SEQ_LEN (CHAN_BOND_SEQ_LEN),
.CHAN_BOND_SEQ_1_1 (CHAN_BOND_SEQ_1_1),
.CHAN_BOND_SEQ_1_2 (CHAN_BOND_SEQ_1_2),
.CHAN_BOND_SEQ_1_3 (CHAN_BOND_SEQ_1_3),
.CHAN_BOND_SEQ_1_4 (CHAN_BOND_SEQ_1_4),
.CHAN_BOND_SEQ_1_ENABLE (CHAN_BOND_SEQ_1_ENABLE),
.CHAN_BOND_SEQ_2_1 (CHAN_BOND_SEQ_2_1),
.CHAN_BOND_SEQ_2_2 (CHAN_BOND_SEQ_2_2),
.CHAN_BOND_SEQ_2_3 (CHAN_BOND_SEQ_2_3),
.CHAN_BOND_SEQ_2_4 (CHAN_BOND_SEQ_2_4),
.CHAN_BOND_SEQ_2_ENABLE (CHAN_BOND_SEQ_2_ENABLE),
.CHAN_BOND_SEQ_2_USE (CHAN_BOND_SEQ_2_USE),
.FTS_DESKEW_SEQ_ENABLE (FTS_DESKEW_SEQ_ENABLE),
.FTS_LANE_DESKEW_CFG (FTS_LANE_DESKEW_CFG),
.FTS_LANE_DESKEW_EN (FTS_LANE_DESKEW_EN),
.PCS_PCIE_EN (PCS_PCIE_EN),
// RX Gearbox Attributes, ug476 p.287
.RXGEARBOX_EN (RXGEARBOX_EN),
// ug476 table p.326 - undocumented parameters
.RX_CLK25_DIV (RX_CLK25_DIV),
.TX_CLK25_DIV (TX_CLK25_DIV)
)
`ifdef OPEN_SOURCE_ONLY
gtx_gpl(
`else // OPEN_SOURCE_ONLY
gtx_unisims(
`endif // OPEN_SOURCE_ONLY
// clocking ports, UG476 p.37
.CPLLREFCLKSEL (CPLLREFCLKSEL),
.GTGREFCLK (GTGREFCLK),
.GTNORTHREFCLK0 (GTNORTHREFCLK0),
.GTNORTHREFCLK1 (GTNORTHREFCLK1),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (GTREFCLK1),
.GTSOUTHREFCLK0 (GTSOUTHREFCLK0),
.GTSOUTHREFCLK1 (GTSOUTHREFCLK1),
.RXSYSCLKSEL (RXSYSCLKSEL),
.TXSYSCLKSEL (TXSYSCLKSEL),
.GTREFCLKMONITOR (GTREFCLKMONITOR),
// CPLL Ports, UG476 p.48
.CPLLLOCKDETCLK (CPLLLOCKDETCLK),
.CPLLLOCKEN (CPLLLOCKEN),
.CPLLPD (CPLLPD),
.CPLLRESET (CPLLRESET),
.CPLLFBCLKLOST (CPLLFBCLKLOST),
.CPLLLOCK (CPLLLOCK),
.CPLLREFCLKLOST (CPLLREFCLKLOST),
.TSTOUT (TSTOUT),
.GTRSVD (GTRSVD),
.PCSRSVDIN (PCSRSVDIN),
.PCSRSVDIN2 (PCSRSVDIN2),
.PMARSVDIN (PMARSVDIN),
.PMARSVDIN2 (PMARSVDIN2),
.TSTIN (TSTIN),
// Reset Mode ports, ug476 p.62
.GTRESETSEL (GTRESETSEL),
.RESETOVRD (RESETOVRD),
// TX Reset ports, ug476 p.65
.CFGRESET (CFGRESET),
.GTTXRESET (GTTXRESET),
.TXPCSRESET (TXPCSRESET),
.TXPMARESET (TXPMARESET),
.TXRESETDONE (TXRESETDONE),
.TXUSERRDY (TXUSERRDY),
.PCSRSVDOUT (PCSRSVDOUT),
// RX Reset ports, UG476 p.73
.GTRXRESET (GTRXRESET),
.RXPMARESET (RXPMARESET),
.RXCDRRESET (RXCDRRESET),
.RXCDRFREQRESET (RXCDRFREQRESET),
.RXDFELPMRESET (RXDFELPMRESET),
.EYESCANRESET (EYESCANRESET),
.RXPCSRESET (RXPCSRESET),
.RXBUFRESET (RXBUFRESET),
.RXUSERRDY (RXUSERRDY),
.RXRESETDONE (RXRESETDONE),
.RXOOBRESET (RXOOBRESET),
// Power Down ports, ug476 p.88
.RXPD (RXPD),
.TXPD (TXPD),
.TXPDELECIDLEMODE (TXPDELECIDLEMODE),
.TXPHDLYPD (TXPHDLYPD),
.RXPHDLYPD (RXPHDLYPD),
// Loopback ports, ug476 p.91
.LOOPBACK (LOOPBACK),
// Dynamic Reconfiguration Port, ug476 p.92
.DRPADDR (DRPADDR),
.DRPCLK (DRPCLK),
.DRPDI (DRPDI),
.DRPDO (DRPDO),
.DRPEN (DRPEN),
.DRPRDY (DRPRDY),
.DRPWE (DRPWE),
// Digital Monitor Ports, ug476 p.95
.CLKRSVD (CLKRSVD),
.DMONITOROUT (DMONITOROUT),
// TX Interface Ports, ug476 p.110
.TXCHARDISPMODE (TXCHARDISPMODE),
.TXCHARDISPVAL (TXCHARDISPVAL),
.TXDATA (TXDATA),
.TXUSRCLK (TXUSRCLK),
.TXUSRCLK2 (TXUSRCLK2),
// TX 8B/10B encoder ports, ug476 p.118
.TX8B10BBYPASS (TX8B10BBYPASS),
.TX8B10BEN (TX8B10BEN),
.TXCHARISK (TXCHARISK),
// TX Gearbox ports, ug476 p.122
.TXGEARBOXREADY (TXGEARBOXREADY),
.TXHEADER (TXHEADER),
.TXSEQUENCE (TXSEQUENCE),
.TXSTARTSEQ (TXSTARTSEQ),
// TX BUffer Ports, ug476 p.134
.TXBUFSTATUS (TXBUFSTATUS),
// TX Buffer Bypass Ports, ug476 p.136
.TXDLYSRESET (TXDLYSRESET),
.TXPHALIGN (TXPHALIGN),
.TXPHALIGNEN (TXPHALIGNEN),
.TXPHINIT (TXPHINIT),
.TXPHOVRDEN (TXPHOVRDEN),
.TXPHDLYRESET (TXPHDLYRESET),
.TXDLYBYPASS (TXDLYBYPASS),
.TXDLYEN (TXDLYEN),
.TXDLYOVRDEN (TXDLYOVRDEN),
.TXPHDLYTSTCLK (TXPHDLYTSTCLK),
.TXDLYHOLD (TXDLYHOLD),
.TXDLYUPDOWN (TXDLYUPDOWN),
.TXPHALIGNDONE (TXPHALIGNDONE),
.TXPHINITDONE (TXPHINITDONE),
.TXDLYSRESETDONE (TXDLYSRESETDONE),
/* .TXSYNCMODE (TXSYNCMODE),
.TXSYNCALLIN (TXSYNCALLIN),
.TXSYNCIN (TXSYNCIN),
.TXSYNCOUT (TXSYNCOUT),
.TXSYNCDONE (TXSYNCDONE),*/
// TX Pattern Generator, ug476 p.147
.TXPRBSSEL (TXPRBSSEL),
.TXPRBSFORCEERR (TXPRBSFORCEERR),
// TX Polarity Control Ports, ug476 p.149
.TXPOLARITY (TXPOLARITY),
// TX Fabric Clock Output Control Ports, ug476 p.152
.TXOUTCLKSEL (TXOUTCLKSEL),
.TXRATE (TXRATE),
.TXOUTCLKFABRIC (TXOUTCLKFABRIC),
.TXOUTCLK (TXOUTCLK),
.TXOUTCLKPCS (TXOUTCLKPCS),
.TXRATEDONE (TXRATEDONE),
// TX Phase Interpolator PPM Controller Ports, ug476 p.154
// GTH only
/* input TXPIPPMEN,
.TXPIPPMOVRDEN (TXPIPPMOVRDEN),
.TXPIPPMSEL (TXPIPPMSEL),
.TXPIPPMPD (TXPIPPMPD),
.TXPIPPMSTEPSIZE (TXPIPPMSTEPSIZE),*/
// TX Configurable Driver Ports, ug476 p.156
.TXBUFDIFFCTRL (TXBUFDIFFCTRL),
.TXDEEMPH (TXDEEMPH),
.TXDIFFCTRL (TXDIFFCTRL),
.TXELECIDLE (TXELECIDLE),
.TXINHIBIT (TXINHIBIT),
.TXMAINCURSOR (TXMAINCURSOR),
.TXMARGIN (TXMARGIN),
.TXQPIBIASEN (TXQPIBIASEN),
.TXQPISENN (TXQPISENN),
.TXQPISENP (TXQPISENP),
.TXQPISTRONGPDOWN (TXQPISTRONGPDOWN),
.TXQPIWEAKPUP (TXQPIWEAKPUP),
.TXPOSTCURSOR (TXPOSTCURSOR),
.TXPOSTCURSORINV (TXPOSTCURSORINV),
.TXPRECURSOR (TXPRECURSOR),
.TXPRECURSORINV (TXPRECURSORINV),
.TXSWING (TXSWING),
.TXDIFFPD (TXDIFFPD),
.TXPISOPD (TXPISOPD),
// TX Receiver Detection Ports, ug476 p.165
.TXDETECTRX (TXDETECTRX),
.PHYSTATUS (PHYSTATUS),
.RXSTATUS (RXSTATUS),
// TX OOB Signaling Ports, ug476 p.166
.TXCOMFINISH (TXCOMFINISH),
.TXCOMINIT (TXCOMINIT),
.TXCOMSAS (TXCOMSAS),
.TXCOMWAKE (TXCOMWAKE),
// RX AFE Ports, ug476 p.171
.RXQPISENN (RXQPISENN),
.RXQPISENP (RXQPISENP),
.RXQPIEN (RXQPIEN),
// RX OOB Signaling Ports, ug476 p.178
.RXELECIDLEMODE (RXELECIDLEMODE),
.RXELECIDLE (RXELECIDLE),
.RXCOMINITDET (RXCOMINITDET),
.RXCOMSASDET (RXCOMSASDET),
.RXCOMWAKEDET (RXCOMWAKEDET),
// RX Equalizer Ports, ug476 p.189
.RXLPMEN (RXLPMEN),
.RXOSHOLD (RXOSHOLD),
.RXOSOVRDEN (RXOSOVRDEN),
.RXLPMLFHOLD (RXLPMLFHOLD),
.RXLPMLFKLOVRDEN (RXLPMLFKLOVRDEN),
.RXLPMHFHOLD (RXLPMHFHOLD),
.RXLPMHFOVRDEN (RXLPMHFOVRDEN),
.RXDFEAGCHOLD (RXDFEAGCHOLD),
.RXDFEAGCOVRDEN (RXDFEAGCOVRDEN),
.RXDFELFHOLD (RXDFELFHOLD),
.RXDFELFOVRDEN (RXDFELFOVRDEN),
.RXDFEUTHOLD (RXDFEUTHOLD),
.RXDFEUTOVRDEN (RXDFEUTOVRDEN),
// this signal shall be present only in GTH, but for some reason it's included in unisims gtxe2
.RXDFEVSEN (1'b0),
.RXDFEVPHOLD (RXDFEVPHOLD),
.RXDFEVPOVRDEN (RXDFEVPOVRDEN),
.RXDFETAP2HOLD (RXDFETAP2HOLD),
.RXDFETAP2OVRDEN (RXDFETAP2OVRDEN),
.RXDFETAP3HOLD (RXDFETAP3HOLD),
.RXDFETAP3OVRDEN (RXDFETAP3OVRDEN),
.RXDFETAP4HOLD (RXDFETAP4HOLD),
.RXDFETAP4OVRDEN (RXDFETAP4OVRDEN),
.RXDFETAP5HOLD (RXDFETAP5HOLD),
.RXDFETAP5OVRDEN (RXDFETAP5OVRDEN),
.RXDFECM1EN (RXDFECM1EN),
.RXDFEXYDHOLD (RXDFEXYDHOLD),
.RXDFEXYDOVRDEN (RXDFEXYDOVRDEN),
.RXDFEXYDEN (RXDFEXYDEN),
.RXMONITORSEL (RXMONITORSEL),
.RXMONITOROUT (RXMONITOROUT),
// CDR Ports, ug476 p.202
.RXCDRHOLD (RXCDRHOLD),
.RXCDROVRDEN (RXCDROVRDEN),
.RXCDRRESETRSV (RXCDRRESETRSV),
.RXRATE (RXRATE),
.RXCDRLOCK (RXCDRLOCK),
// RX Fabric Clock Output Control Ports, ug476 p.213
.RXOUTCLKSEL (RXOUTCLKSEL),
.RXOUTCLKFABRIC (RXOUTCLKFABRIC),
.RXOUTCLK (RXOUTCLK),
.RXOUTCLKPCS (RXOUTCLKPCS),
.RXRATEDONE (RXRATEDONE),
.RXDLYBYPASS (RXDLYBYPASS),
// RX Margin Analysis Ports, ug476 p.220
.EYESCANDATAERROR (EYESCANDATAERROR),
.EYESCANTRIGGER (EYESCANTRIGGER),
.EYESCANMODE (EYESCANMODE),
// RX Polarity Control Ports, ug476 p.224
.RXPOLARITY (RXPOLARITY),
// Pattern Checker Ports, ug476 p.225
.RXPRBSCNTRESET (RXPRBSCNTRESET),
.RXPRBSSEL (RXPRBSSEL),
.RXPRBSERR (RXPRBSERR),
// RX Byte and Word Alignment Ports, ug476 p.233
.RXBYTEISALIGNED (RXBYTEISALIGNED),
.RXBYTEREALIGN (RXBYTEREALIGN),
.RXCOMMADET (RXCOMMADET),
.RXCOMMADETEN (RXCOMMADETEN),
.RXPCOMMAALIGNEN (RXPCOMMAALIGNEN),
.RXMCOMMAALIGNEN (RXMCOMMAALIGNEN),
.RXSLIDE (RXSLIDE),
// RX 8B/10B Decoder Ports, ug476 p.24
.RX8B10BEN (RX8B10BEN),
.RXCHARISCOMMA (RXCHARISCOMMA),
.RXCHARISK (RXCHARISK),
.RXDISPERR (RXDISPERR),
.RXNOTINTABLE (RXNOTINTABLE),
.SETERRSTATUS (SETERRSTATUS),
// RX Buffer Bypass Ports, ug476 p.244
.RXPHDLYRESET (RXPHDLYRESET),
.RXPHALIGN (RXPHALIGN),
.RXPHALIGNEN (RXPHALIGNEN),
.RXPHOVRDEN (RXPHOVRDEN),
.RXDLYSRESET (RXDLYSRESET),
.RXDLYEN (RXDLYEN),
.RXDLYOVRDEN (RXDLYOVRDEN),
.RXDDIEN (RXDDIEN),
.RXPHALIGNDONE (RXPHALIGNDONE),
.RXPHMONITOR (RXPHMONITOR),
.RXPHSLIPMONITOR (RXPHSLIPMONITOR),
.RXDLYSRESETDONE (RXDLYSRESETDONE),
// RX Buffer Ports, ug476 p.259
.RXBUFSTATUS (RXBUFSTATUS),
// RX Clock Correction Ports, ug476 p.263
.RXCLKCORCNT (RXCLKCORCNT),
// RX Channel Bonding Ports, ug476 p.274
.RXCHANBONDSEQ (RXCHANBONDSEQ),
.RXCHANISALIGNED (RXCHANISALIGNED),
.RXCHANREALIGN (RXCHANREALIGN),
.RXCHBONDI (RXCHBONDI),
.RXCHBONDO (RXCHBONDO),
.RXCHBONDLEVEL (RXCHBONDLEVEL),
.RXCHBONDMASTER (RXCHBONDMASTER),
.RXCHBONDSLAVE (RXCHBONDSLAVE),
.RXCHBONDEN (RXCHBONDEN),
// RX Gearbox Ports, ug476 p.285
.RXDATAVALID (RXDATAVALID),
.RXGEARBOXSLIP (RXGEARBOXSLIP),
.RXHEADER (RXHEADER),
.RXHEADERVALID (RXHEADERVALID),
.RXSTARTOFSEQ (RXSTARTOFSEQ),
// FPGA RX Interface Ports, ug476 p.299
.RXDATA (RXDATA),
.RXUSRCLK (RXUSRCLK),
.RXUSRCLK2 (RXUSRCLK2),
// ug476, p.323
.RXVALID (RXVALID),
// for correct clocking scheme in case of multilane structure
.QPLLCLK (QPLLCLK),
.QPLLREFCLK (QPLLREFCLK),
// Diffpairs
.GTXRXP (GTXRXP),
.GTXRXN (GTXRXN),
.GTXTXN (GTXTXN),
.GTXTXP (GTXTXP)
);
endmodule
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