Commit ce85dcb3 authored by Andrey Filippov's avatar Andrey Filippov

Continue on AHCI implementation - processing received FIS

parent aa0b3a4e
...@@ -41,7 +41,7 @@ so *.editor_defines* is now just for the editor (which branches to parse). No re ...@@ -41,7 +41,7 @@ so *.editor_defines* is now just for the editor (which branches to parse). No re
# Current step in try2 branch: # Current step in try2 branch:
Not yet tested in hardware, started AHCI implementation (currently coded registers and DMA engine, that processes command table/PRD list, Not yet tested in hardware, started AHCI implementation (currently coded registers and DMA engine, that processes command table/PRD list,
Transfers data between clock domains, re-aligns between WORD size granularity, HAB 32-bit data and 64-bit AXI accesses. Transfers data between clock domains, re-aligns between WORD size granularity, HBA 32-bit data and 64-bit AXI accesses.
# Current step in main branch: # Current step in main branch:
Testing basic functionallity of a host. Testing basic functionallity of a host.
Trying out pio access. Trying out pio access.
......
...@@ -25,6 +25,27 @@ __maintainer__ = "Andrey Filippov" ...@@ -25,6 +25,27 @@ __maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com" __email__ = "andrey@elphel.com"
__status__ = "Development" __status__ = "Development"
import sys import sys
# All unspecified ranges/fields default to fT:RO, fC:0 (readonly, reset value = 0)
VID = 0xfffe # What to use for non-PCI "vendorID"?
DID = 0x0001
SSVID = 0xfffe
SSID = 0x0001
IPIN = 0x01 # TODO: Put a real number for "Interrupt pin"
ILINE = 0x00 # Interrupt line - software is supposed to fill it - maybe here we need to put some predefined value?
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
PCIHEAD = 0x180
PMCAP = 0x1C0
AXI_BASEADDR = 0x80000000
reg_defaults_path= "../includes/ahci_defaults.vh"
reg_types_path= "../includes/ahci_types.vh"
localparams_path= "../includes/ahci_localparams.vh"
gN = "groupName" gN = "groupName"
gS = "groupStart" gS = "groupStart"
gE = "groupEnd" gE = "groupEnd"
...@@ -47,23 +68,6 @@ RW = "RW" ...@@ -47,23 +68,6 @@ RW = "RW"
RO= "RO" RO= "RO"
RWC = "RWC" RWC = "RWC"
RW1 = "RW1" RW1 = "RW1"
# All unspecified ranges/fields default to fT:RO, fC:0 (readonly, reset value = 0)
VID = 0xfffe # What to use for non-PCI "vendorID"?
DID = 0x0001
SSVID = 0xfffe
SSID = 0x0001
IPIN = 0x01 # TODO: Put a real number for "Interrupt pin"
ILINE = 0x00 # Interrupt line - software is supposed to fill it - maybe here we need to put some predefined value?
HBA_OFFS = 0x0
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
PCIHEAD = 0x180
PMCAP = 0x1C0
AXI_BASEADDR = 0x80000000
reg_defaults_path= "../includes/ahci_defaults.vh"
reg_types_path= "../includes/ahci_types.vh"
ABAR = AXI_BASEADDR + HBA_OFFS ABAR = AXI_BASEADDR + HBA_OFFS
...@@ -197,9 +201,9 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w ...@@ -197,9 +201,9 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w
[{fN:"IPS", fT:RWC,fC:0, fD:"Interrupt Pending Status (per port)"}]}, [{fN:"IPS", fT:RWC,fC:0, fD:"Interrupt Pending Status (per port)"}]},
{rN:"PI", rS:0x0c, rE:0x0f, rD:"Interrupt Status Register", rC: {rN:"PI", rS:0x0c, rE:0x0f, rD:"Interrupt Status Register", rC:
[{fN:"PI", fT:RO, fC:1, fD:"Ports Implemented"}]}, [{fN:"PI", fT:RO, fC:1, fD:"Ports Implemented"}]},
{rN:"VS", rS:0x10, rE:0x13, rD:"AHCI Verion", rC: {rN:"VS", rS:0x10, rE:0x13, rD:"AHCI Version", rC:
[{fN:"MJR", fS:16, fE:31, fT:RO, fC:0x0001, fD:"AHCI Major Verion 1."}, [{fN:"MJR", fS:16, fE:31, fT:RO, fC:0x0001, fD:"AHCI Major Version 1."},
{fN:"MNR", fS: 0, fE:15, fT:RO, fC:0x0301, fD:"AHCI Minor Verion 3.1"}]}, {fN:"MNR", fS: 0, fE:15, fT:RO, fC:0x0301, fD:"AHCI Minor Version 3.1"}]},
{rN:"CCC_CTL", rS:0x14, rE:0x17, rD:"Command Completion Coalescing Control", rC: {rN:"CCC_CTL", rS:0x14, rE:0x17, rD:"Command Completion Coalescing Control", rC:
[{ fT:RO, fC:0, fD:"Not Implemented"}]}, [{ fT:RO, fC:0, fD:"Not Implemented"}]},
{rN:"CCC_PORTS", rS:0x18, rE:0x1b, rD:"Command Completion Coalescing Ports", rC: {rN:"CCC_PORTS", rS:0x18, rE:0x1b, rD:"Command Completion Coalescing Ports", rC:
...@@ -308,12 +312,17 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w ...@@ -308,12 +312,17 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w
{rN:"PxTFD", rS:0x20, rE:0x23, rD:"Port x Task File Data (copy of error/status from device)", rC: {rN:"PxTFD", rS:0x20, rE:0x23, rD:"Port x Task File Data (copy of error/status from device)", rC:
[{ fS:16, fE:31, fT:RO, fC:0, fD:"Reserved"}, [{ fS:16, fE:31, fT:RO, fC:0, fD:"Reserved"},
{fN:"ERR", fS: 8, fE:15, fT:RO, fC:0, fD:"Latest Copy of Task File Error Register"}, {fN:"ERR", fS: 8, fE:15, fT:RO, fC:0, fD:"Latest Copy of Task File Error Register"},
{fN:"STS", fS: 0, fE: 7, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register"}, # {fN:"STS", fS: 0, fE: 7, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register"},
# bit 7 - BSY # # bit 7 - BSY
# bits 6..4 - command-specific # # bits 6..4 - command-specific
# bit 3 - DRQ # # bit 3 - DRQ
# bits 1..2 - command-specific # # bits 1..2 - command-specific
# bit 0 - ERR # # bit 0 - ERR
{fN:"STS.BSY", fS: 7, fE: 7, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register: BSY"},
{fN:"STS.64", fS: 4, fE: 6, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register: command-specific bits 4..6 "},
{fN:"STS.DRQ", fS: 3, fE: 3, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register: DRQ"},
{fN:"STS.12", fS: 1, fE: 2, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register: command-specific bits 1..2 "},
{fN:"STS.ERR", fS: 0, fE: 0, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register: ERR"}
]}, ]},
{rN:"PxSIG", rS:0x24, rE:0x27, rD:"Port x Signature (first D2H data after reset)", rC: {rN:"PxSIG", rS:0x24, rE:0x27, rD:"Port x Signature (first D2H data after reset)", rC:
[{fN:"SIG", fS: 0, fE:31, fT:RO, fC:0xffffffff, fD:"Data in the first D2H Register FIS"}, [{fN:"SIG", fS: 0, fE:31, fT:RO, fC:0xffffffff, fD:"Data in the first D2H Register FIS"},
...@@ -322,7 +331,7 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w ...@@ -322,7 +331,7 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w
# bits 8..15 - LBA Low Register # bits 8..15 - LBA Low Register
# bits 0.. 7 - Sector Count Register # bits 0.. 7 - Sector Count Register
]}, ]},
{rN:"PxSIG", rS:0x28, rE:0x2b, rD:"Port x SATA Status (SCR0:SStatus)", rC: {rN:"PxSSTS", rS:0x28, rE:0x2b, rD:"Port x SATA Status (SCR0:SStatus)", rC:
[{ fS:12, fE:31, fT:RO, fC:0, fD:"Reserved"}, [{ fS:12, fE:31, fT:RO, fC:0, fD:"Reserved"},
{fN:"IPM", fS: 8, fE:11, fT:RO, fC:0, fD:"Interface Power Management"}, {fN:"IPM", fS: 8, fE:11, fT:RO, fC:0, fD:"Interface Power Management"},
# 0 - Device not present or communication not established # 0 - Device not present or communication not established
...@@ -365,17 +374,17 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w ...@@ -365,17 +374,17 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w
]}, ]},
{rN:"PxSERR", rS:0x30, rE:0x34, rD:"Port x SATA Error (SCR1:SError)", rC: {rN:"PxSERR", rS:0x30, rE:0x34, rD:"Port x SATA Error (SCR1:SError)", rC:
[{ fS:27, fE:31, fT:RO, fC:0, fD:"Reserved"}, [{ fS:27, fE:31, fT:RO, fC:0, fD:"Reserved"},
{fN:"DIAD.X",fS:26, fT:RWC,fC:0, fD:"Exchanged (set on COMINIT), reflected in PxIS.PCS"}, {fN:"DIAG.X",fS:26, fT:RWC,fC:0, fD:"Exchanged (set on COMINIT), reflected in PxIS.PCS"},
{fN:"DIAD.F",fS:25, fT:RWC,fC:0, fD:"Unknown FIS"}, {fN:"DIAG.F",fS:25, fT:RWC,fC:0, fD:"Unknown FIS"},
{fN:"DIAD.T",fS:24, fT:RWC,fC:0, fD:"Transport state transition error"}, {fN:"DIAG.T",fS:24, fT:RWC,fC:0, fD:"Transport state transition error"},
{fN:"DIAD.S",fS:23, fT:RWC,fC:0, fD:"Link sequence error"}, {fN:"DIAG.S",fS:23, fT:RWC,fC:0, fD:"Link sequence error"},
{fN:"DIAD.H",fS:22, fT:RWC,fC:0, fD:"Handshake Error (i.e. Device got CRC error)"}, {fN:"DIAG.H",fS:22, fT:RWC,fC:0, fD:"Handshake Error (i.e. Device got CRC error)"},
{fN:"DIAD.C",fS:21, fT:RWC,fC:0, fD:"CRC error in Link layer"}, {fN:"DIAG.C",fS:21, fT:RWC,fC:0, fD:"CRC error in Link layer"},
{fN:"DIAD.D",fS:20, fT:RWC,fC:0, fD:"Disparity Error - not used by AHCI"}, {fN:"DIAG.D",fS:20, fT:RWC,fC:0, fD:"Disparity Error - not used by AHCI"},
{fN:"DIAD.B",fS:19, fT:RWC,fC:0, fD:"10B to 8B decode error"}, {fN:"DIAG.B",fS:19, fT:RWC,fC:0, fD:"10B to 8B decode error"},
{fN:"DIAD.W",fS:18, fT:RWC,fC:0, fD:"COMMWAKE signal was detected"}, {fN:"DIAG.W",fS:18, fT:RWC,fC:0, fD:"COMMWAKE signal was detected"},
{fN:"DIAD.I",fS:17, fT:RWC,fC:0, fD:"PHY Internal Error"}, {fN:"DIAG.I",fS:17, fT:RWC,fC:0, fD:"PHY Internal Error"},
{fN:"DIAD.N",fS:16, fT:RWC,fC:0, fD:"PhyRdy changed. Reflected in PxIS.PRCS bit."}, {fN:"DIAG.N",fS:16, fT:RWC,fC:0, fD:"PhyRdy changed. Reflected in PxIS.PRCS bit."},
{ fS:12, fE:15, fT:RO, fC:0, fD:"Reserved"}, { fS:12, fE:15, fT:RO, fC:0, fD:"Reserved"},
{fN:"ERR.E", fS:11, fT:RWC,fC:0, fD:"Internal Error"}, {fN:"ERR.E", fS:11, fT:RWC,fC:0, fD:"Internal Error"},
{fN:"ERR.P", fS:10, fT:RWC,fC:0, fD:"Protocol Error - a violation of SATA protocol detected"}, {fN:"ERR.P", fS:10, fT:RWC,fC:0, fD:"Protocol Error - a violation of SATA protocol detected"},
...@@ -383,7 +392,7 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w ...@@ -383,7 +392,7 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w
{fN:"ERR.T", fS: 8, fT:RWC,fC:0, fD:"Transient Data Integrity Error (error not recovered by the interface)"}, {fN:"ERR.T", fS: 8, fT:RWC,fC:0, fD:"Transient Data Integrity Error (error not recovered by the interface)"},
{ fS: 2, fE: 7, fT:RO, fC:0, fD:"Reserved"}, { fS: 2, fE: 7, fT:RO, fC:0, fD:"Reserved"},
{fN:"ERR.M", fS: 1, fT:RWC,fC:0, fD:"Communication between the device and host was lost but re-established"}, {fN:"ERR.M", fS: 1, fT:RWC,fC:0, fD:"Communication between the device and host was lost but re-established"},
{fN:"ERR.I", fS: 1, fT:RWC,fC:0, fD:"Recovered Data integrity Error"} {fN:"ERR.I", fS: 0, fT:RWC,fC:0, fD:"Recovered Data integrity Error"}
]}, ]},
{rN:"PxSACT", rS:0x34, rE:0x37, rD:"Port x SATA Active (SCR3:SActive), only set when PxCMD.ST==1", rC: {rN:"PxSACT", rS:0x34, rE:0x37, rD:"Port x SATA Active (SCR3:SActive), only set when PxCMD.ST==1", rC:
[{fN:"DS", fT:RW1,fC:0, fD:"Device Status: bit per Port, for TAG in native queued command"} [{fN:"DS", fT:RW1,fC:0, fD:"Device Status: bit per Port, for TAG in native queued command"}
...@@ -428,7 +437,7 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w ...@@ -428,7 +437,7 @@ src=[{gN:"PCI_Header", gS: PCIHEAD, gE:PCIHEAD+0x3f, gD:" PCI header emulation w
reg_defaults = [0]*4096 # array of bytes, default value = 0 reg_defaults = [0]*4096 # array of bytes, default value = 0
bit_types = [0]*2048 # array of words, default value = 0 bit_types = [0]*2048 # array of words, default value = 0
localparams =[]
for group in src: for group in src:
groupName = group[gN] groupName = group[gN]
groupStart = group[gS] groupStart = group[gS]
...@@ -544,7 +553,27 @@ for group in src: ...@@ -544,7 +553,27 @@ for group in src:
if (offs+b) < len(bit_types): if (offs+b) < len(bit_types):
bit_types[offs+b] = ((bit_types[offs+b] ^ bt) & bm16) ^ bit_types[offs+b] bit_types[offs+b] = ((bit_types[offs+b] ^ bt) & bm16) ^ bit_types[offs+b]
print ("bit_types[0x%x] = 0x%x"%(offs+b,bit_types[offs+b])) print ("bit_types[0x%x] = 0x%x"%(offs+b,bit_types[offs+b]))
fullName=("%s__%s__%s"%(groupName,rangeName,fieldName)).replace(".","__") # no dots in field names
comment= "%s: %s"%(dataField[fT], fieldDescription)
dwas = (offs*8 + fieldStart) // 32 # 32-bit address
dwae = (offs*8 + fieldEnd) // 32 # 32-bit address
fe=fieldEnd
if dwae > dwas:
print ("***** WARNING: Field %s spans several DWORDs, truncating to the first one"%(fullName))
fe = 32*dwas +31 - offs*8 # Later AND fieldValue with field mask
fieldMask = ((1 << (fe - fieldStart + 1)) -1) << ((offs % 4) * 8 + fieldStart)
fieldShiftedValue = fieldValue << ((offs % 4) * 8 + fieldStart)
fieldShiftedValue &= fieldMask
if fieldName: # Skip reserved fields
localparams.append("// %s"%(comment))
localparams.append(" localparam %s__ADDR = 'h%x;"%(fullName, dwas))
localparams.append(" localparam %s__MASK = 'h%x;"%(fullName, fieldMask))
localparams.append(" localparam %s__DFLT = 'h%x;"%(fullName, fieldShiftedValue))
localparams.append("")
localparams_txt="\n".join(localparams)
#print(localparams_txt)
def create_no_parity (init_data, # numeric data def create_no_parity (init_data, # numeric data
num_bits, # number of bits in item num_bits, # number of bits in item
start_bit, # bit number to start filling from start_bit, # bit number to start filling from
...@@ -574,6 +603,7 @@ def print_params(data,out_file_name): ...@@ -574,6 +603,7 @@ def print_params(data,out_file_name):
for i, v in enumerate(data['data_p']): for i, v in enumerate(data['data_p']):
if v: if v:
print (", .INITP_%02X (256'h%064X)"%(i,v), file=out_file) print (", .INITP_%02X (256'h%064X)"%(i,v), file=out_file)
import os import os
#print (os.path.abspath(__file__)) #print (os.path.abspath(__file__))
#print (os.path.dirname(__file__)) #print (os.path.dirname(__file__))
...@@ -591,3 +621,8 @@ print_params(create_no_parity(reg_defaults, 8, 0, True),os.path.abspath(os.path. ...@@ -591,3 +621,8 @@ print_params(create_no_parity(reg_defaults, 8, 0, True),os.path.abspath(os.path.
print ("AHCI register defaults are written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), reg_defaults_path)))) print ("AHCI register defaults are written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), reg_defaults_path))))
print_params(create_no_parity(bit_types, 16, 0, True),os.path.abspath(os.path.join(os.path.dirname(__file__), reg_types_path))) print_params(create_no_parity(bit_types, 16, 0, True),os.path.abspath(os.path.join(os.path.dirname(__file__), reg_types_path)))
print ("AHCI register bit field types are written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), reg_types_path)))) print ("AHCI register bit field types are written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), reg_types_path))))
#print(localparams_txt)
with open(os.path.abspath(os.path.join(os.path.dirname(__file__), localparams_path)),"w") as out_file:
print(localparams_txt, file=out_file)
print ("AHCI localparam definitions are written to %s"%(os.path.abspath(os.path.join(os.path.dirname(__file__), localparams_path))))
...@@ -514,7 +514,7 @@ always @ (posedge clk) ...@@ -514,7 +514,7 @@ always @ (posedge clk)
if (ll_data_val_in) if (ll_data_val_in)
begin begin
if (dword_cnt == 14'd2049) if (dword_cnt == 14'd2049)
// if too much data for a data FIS TODO handle this excpetion properly // if too much data for a data FIS TODO handle this exception properly
state <= STATE_IDLE; state <= STATE_IDLE;
else else
// continuing receiving data // continuing receiving data
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
, .INIT_10 (256'h0000000000000000555555555555000000000000000000005555555555500000) , .INIT_10 (256'h0000000000000000555555555555000000000000000000005555555555500000)
, .INIT_11 (256'h000000000000000055054004000001C15551400000000455AAA28000000008AA) , .INIT_11 (256'h000000000000000055054004000001C15551400000000455AAA28000000008AA)
, .INIT_12 (256'h0000000000550000000000000000000000000000000000000000000000000000) , .INIT_12 (256'h0000000000550000000000000000000000000000000000000000000000000000)
, .INIT_13 (256'h00000000AAAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF002AAAAA00AA0008) , .INIT_13 (256'h00000000AAAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF002AAAAA00AA000A)
, .INIT_14 (256'h000000000000000000000000000000000001555555555550000000000055000D) , .INIT_14 (256'h000000000000000000000000000000000001555555555550000000000055000D)
, .INIT_17 (256'h5555555555555555555555555555555555555555555555555555555555555555) , .INIT_17 (256'h5555555555555555555555555555555555555555555555555555555555555555)
, .INIT_18 (256'h00000000000055550000000000000000AA820000001000140000000000000000) , .INIT_18 (256'h00000000000055550000000000000000AA820000001000140000000000000000)
......
/******************************************************************************* /*******************************************************************************
* Module: ahci_dma * Module: ahci_dma
* Date:2016-01-01 * Date:2016-01-01
* Author: andrey * Author: Andrey Filippov
* Description: DMA R/W over 64-AXI channel for AHCI implementation * Description: DMA R/W over 64-AXI channel for AHCI implementation
* *
* Copyright (c) 2016 Elphel, Inc . * Copyright (c) 2016 Elphel, Inc .
......
/*******************************************************************************
* 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
// Control Interface
// Receiving FIS
input get_sig, // update signature
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 data in the
output reg get_fis_busy, // busy processing FIS
output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_*
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 update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h
output [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields)
output [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB)
output reg fis_i, // value of "I" field in received regsD2H or SDB FIS
output reg 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 reg [7:0] pio_es, // value of PIO E_Status
output reg [31:1] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits)
// 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] hda_data_in, // FIFO output data
input [ 1:0] hda_data_in_type, // 0 - data, 1 - FIS head, 2 - R_OK, 3 - R_ERR
input hba_data_in_avalid, // 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
);
//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
*/
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;
wire dma_in_start;
wire dma_in_stop;
reg dma_in;
reg [1:0] was_data_in;
reg [12:0] data_in_words;
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 fis_end = (hda_data_in_type == DATA_TYPE_OK) || (hda_data_in_type == DATA_TYPE_ERR);
wire fis_end_w = data_in_ready && fis_end & ~(|fis_end_r);
reg [1:0] fis_end_r;
reg fis_rec_run; // running received FIS
reg is_data_fis;
wire is_FIS_HEAD = data_in_ready && (hda_data_in_type == DATA_TYPE_FIS_HEAD);
wire data_in_ready = hba_data_in_avalid && (hba_data_in_many || !(|was_data_in || hba_data_in_ready) );
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] update_sig;
reg [5:0] reg_ds;
reg [4:0] reg_ps;
reg reg_d2h;
reg reg_sdb;
reg [15:0] tf_err_sts;
// Forward data to DMA (dev->mem) engine
assign dma_in_valid = dma_in_ready && (hda_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err;
assign dma_in_stop = dma_in && data_in_ready && (hda_data_in_type != DATA_TYPE_DMA); // ||
assign reg_we_w = wreg_we_r && !dwords_over && fis_save;
assign dma_in_start = is_data_fis && wreg_we_r;
assign hba_data_in_ready = dma_in_valid || wreg_we_r || fis_end_r[0];
assign fis_ferr = too_long_err;
assign tfd_sts = tf_err_sts[ 7:0];
assign tfd_err = tf_err_sts[15:8];
always @ (posedge mclk) begin
if (hba_rst || dma_in_stop) 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_words <= 0;
else if (dma_in_valid) data_in_words <= data_in_words + 1;
if (hba_rst) too_long_err <= 0; // it is a fatal error, only reset
else if ((dma_in_valid && data_in_words[12]) ||
(wreg_we_r && dwords_over)) too_long_err <= 1;
if (get_fis) begin
reg_addr_r <= ({ADDRESS_BITS{get_sig}} & (PXSIG_OFFS32)) |
({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_sig}} & RFIS32_LENM1) |
({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 );
fis_save <= !get_data_fis && !get_ignore && !get_sig;
is_data_fis <= get_data_fis;
update_sig <= get_sig? 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;
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
update_sig <= update_sig << 1;
reg_ds <= reg_ds << 1;
reg_ps <= reg_ps << 1;
reg_d2h <= 0;
reg_sdb <= 0;
end
if (hba_rst) fis_rec_run <= 0;
else if (get_fis) fis_rec_run <= 1;
else if (fis_end && data_in_ready) fis_rec_run <= 0;
if (hba_rst) 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 && !fis_end && !dwords_over && (|fis_dcount || !wreg_we_r);
fis_end_r <= {fis_end_r[0], fis_end_w};
if (hba_rst) get_fis_busy <= 0;
else if (get_fis) get_fis_busy <= 1;
else if (too_long_err || fis_end_w) get_fis_busy <= 0;
if (hba_rst || get_fis) fis_first_vld <= 0;
else if (is_FIS_HEAD) fis_first_vld <= 1;
if (hba_rst || get_fis) fis_ok <= 0;
else if (fis_end_w) fis_ok <= hda_data_in_type == DATA_TYPE_OK;
if (hba_rst || get_fis) fis_err <= 0;
else if (fis_end_w) fis_err <= hda_data_in_type != DATA_TYPE_OK;
if (reg_we_w) reg_data[31:8] <= hda_data_in[31:8];
else if (update_sig[1]) reg_data[31:8] <= hda_data_in[23:0];
else if (update_err_sts) reg_data[31:8] <= {16'b0,tf_err_sts[15:8]};
if (reg_we_w) reg_data[ 7:0] <= hda_data_in[ 7:0];
else if (update_sig[3]) reg_data[ 7:0] <= hda_data_in[ 7:0];
else if (update_err_sts) reg_data[ 7:0] <= tf_err_sts [ 7:0];
if (reg_d2h || update_sig[0]) tf_err_sts <= hda_data_in[15:0];
else if (reg_sdb) tf_err_sts <= {hda_data_in[15:8], tf_err_sts[7], hda_data_in[6:4], tf_err_sts[3],hda_data_in[2:0]};
reg_we <= reg_we_w || update_sig[3] || update_err_sts;
if (reg_we_w || update_sig[3]) reg_addr <= reg_addr_r;
else if (update_err_sts) reg_addr <= PXTFD_OFFS32;
if (reg_d2h || reg_sdb || reg_ds[0]) fis_i <= hda_data_in[14];
if (reg_sdb) sdb_n <= hda_data_in[15];
if (reg_ds[0]) {dma_a,dma_d} <= {hda_data_in[15],hda_data_in[13]};
if (reg_ps[0]) {pio_i,pio_d} <= {hda_data_in[14],hda_data_in[13]};
if (reg_ps[3]) pio_es <= hda_data_in[31:24];
if (reg_ps[4] || reg_ds[5]) xfer_cntr[31:1] <= {reg_ds[5]?hda_data_in[31:16]:16'b0,hda_data_in[15:1]};
end
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