Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
x393_sata
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
x393_sata
Commits
ce85dcb3
Commit
ce85dcb3
authored
Jan 07, 2016
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Continue on AHCI implementation - processing received FIS
parent
aa0b3a4e
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
346 additions
and
45 deletions
+346
-45
README.md
README.md
+1
-1
create_ahci_registers.py
helpers/create_ahci_registers.py
+76
-41
transport.v
host/transport.v
+1
-1
ahci_types.vh
includes/ahci_types.vh
+1
-1
ahci_dma.v
utils/ahci_dma.v
+1
-1
ahci_fis_receive.v
utils/ahci_fis_receive.v
+266
-0
No files found.
README.md
View file @
ce85dcb3
...
...
@@ -41,7 +41,7 @@ so *.editor_defines* is now just for the editor (which branches to parse). No re
# 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,
Transfers data between clock domains, re-aligns between WORD size granularity, H
AB
32-bit data and 64-bit AXI accesses.
Transfers data between clock domains, re-aligns between WORD size granularity, H
BA
32-bit data and 64-bit AXI accesses.
# Current step in main branch:
Testing basic functionallity of a host.
Trying out pio access.
...
...
helpers/create_ahci_registers.py
View file @
ce85dcb3
...
...
@@ -25,6 +25,27 @@ __maintainer__ = "Andrey Filippov"
__email__
=
"andrey@elphel.com"
__status__
=
"Development"
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"
gS
=
"groupStart"
gE
=
"groupEnd"
...
...
@@ -47,23 +68,6 @@ RW = "RW"
RO
=
"RO"
RWC
=
"RWC"
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
...
...
@@ -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)"
}]},
{
rN
:
"PI"
,
rS
:
0x0c
,
rE
:
0x0f
,
rD
:
"Interrupt Status Register"
,
rC
:
[{
fN
:
"PI"
,
fT
:
RO
,
fC
:
1
,
fD
:
"Ports Implemented"
}]},
{
rN
:
"VS"
,
rS
:
0x10
,
rE
:
0x13
,
rD
:
"AHCI Verion"
,
rC
:
[{
fN
:
"MJR"
,
fS
:
16
,
fE
:
31
,
fT
:
RO
,
fC
:
0x0001
,
fD
:
"AHCI Major Verion 1."
},
{
fN
:
"MNR"
,
fS
:
0
,
fE
:
15
,
fT
:
RO
,
fC
:
0x0301
,
fD
:
"AHCI Minor Verion 3.1"
}]},
{
rN
:
"VS"
,
rS
:
0x10
,
rE
:
0x13
,
rD
:
"AHCI Ver
s
ion"
,
rC
:
[{
fN
:
"MJR"
,
fS
:
16
,
fE
:
31
,
fT
:
RO
,
fC
:
0x0001
,
fD
:
"AHCI Major Ver
s
ion 1."
},
{
fN
:
"MNR"
,
fS
:
0
,
fE
:
15
,
fT
:
RO
,
fC
:
0x0301
,
fD
:
"AHCI Minor Ver
s
ion 3.1"
}]},
{
rN
:
"CCC_CTL"
,
rS
:
0x14
,
rE
:
0x17
,
rD
:
"Command Completion Coalescing Control"
,
rC
:
[{
fT
:
RO
,
fC
:
0
,
fD
:
"Not Implemented"
}]},
{
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
{
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"
},
{
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"
},
# bit 7 - BSY
# bits 6..4 - command-specific
# bit 3 - DRQ
# bits 1..2 - command-specific
# bit 0 - ERR
# {fN:"STS", fS: 0, fE: 7, fT:RO, fC:0, fD:"Latest Copy of Task File Status Register"},
# # bit 7 - BSY
# # bits 6..4 - command-specific
# # bit 3 - DRQ
# # bits 1..2 - command-specific
# # 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
:
[{
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
# bits 8..15 - LBA Low Register
# bits 0.. 7 - Sector Count Register
]},
{
rN
:
"PxS
IG
"
,
rS
:
0x28
,
rE
:
0x2b
,
rD
:
"Port x SATA Status (SCR0:SStatus)"
,
rC
:
{
rN
:
"PxS
STS
"
,
rS
:
0x28
,
rE
:
0x2b
,
rD
:
"Port x SATA Status (SCR0:SStatus)"
,
rC
:
[{
fS
:
12
,
fE
:
31
,
fT
:
RO
,
fC
:
0
,
fD
:
"Reserved"
},
{
fN
:
"IPM"
,
fS
:
8
,
fE
:
11
,
fT
:
RO
,
fC
:
0
,
fD
:
"Interface Power Management"
},
# 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
]},
{
rN
:
"PxSERR"
,
rS
:
0x30
,
rE
:
0x34
,
rD
:
"Port x SATA Error (SCR1:SError)"
,
rC
:
[{
fS
:
27
,
fE
:
31
,
fT
:
RO
,
fC
:
0
,
fD
:
"Reserved"
},
{
fN
:
"DIA
D
.X"
,
fS
:
26
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Exchanged (set on COMINIT), reflected in PxIS.PCS"
},
{
fN
:
"DIA
D
.F"
,
fS
:
25
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Unknown FIS"
},
{
fN
:
"DIA
D
.T"
,
fS
:
24
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Transport state transition error"
},
{
fN
:
"DIA
D
.S"
,
fS
:
23
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Link sequence error"
},
{
fN
:
"DIA
D
.H"
,
fS
:
22
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Handshake Error (i.e. Device got CRC error)"
},
{
fN
:
"DIA
D
.C"
,
fS
:
21
,
fT
:
RWC
,
fC
:
0
,
fD
:
"CRC error in Link layer"
},
{
fN
:
"DIA
D
.D"
,
fS
:
20
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Disparity Error - not used by AHCI"
},
{
fN
:
"DIA
D
.B"
,
fS
:
19
,
fT
:
RWC
,
fC
:
0
,
fD
:
"10B to 8B decode error"
},
{
fN
:
"DIA
D
.W"
,
fS
:
18
,
fT
:
RWC
,
fC
:
0
,
fD
:
"COMMWAKE signal was detected"
},
{
fN
:
"DIA
D
.I"
,
fS
:
17
,
fT
:
RWC
,
fC
:
0
,
fD
:
"PHY Internal Error"
},
{
fN
:
"DIA
D
.N"
,
fS
:
16
,
fT
:
RWC
,
fC
:
0
,
fD
:
"PhyRdy changed. Reflected in PxIS.PRCS bit."
},
{
fN
:
"DIA
G
.X"
,
fS
:
26
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Exchanged (set on COMINIT), reflected in PxIS.PCS"
},
{
fN
:
"DIA
G
.F"
,
fS
:
25
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Unknown FIS"
},
{
fN
:
"DIA
G
.T"
,
fS
:
24
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Transport state transition error"
},
{
fN
:
"DIA
G
.S"
,
fS
:
23
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Link sequence error"
},
{
fN
:
"DIA
G
.H"
,
fS
:
22
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Handshake Error (i.e. Device got CRC error)"
},
{
fN
:
"DIA
G
.C"
,
fS
:
21
,
fT
:
RWC
,
fC
:
0
,
fD
:
"CRC error in Link layer"
},
{
fN
:
"DIA
G
.D"
,
fS
:
20
,
fT
:
RWC
,
fC
:
0
,
fD
:
"Disparity Error - not used by AHCI"
},
{
fN
:
"DIA
G
.B"
,
fS
:
19
,
fT
:
RWC
,
fC
:
0
,
fD
:
"10B to 8B decode error"
},
{
fN
:
"DIA
G
.W"
,
fS
:
18
,
fT
:
RWC
,
fC
:
0
,
fD
:
"COMMWAKE signal was detected"
},
{
fN
:
"DIA
G
.I"
,
fS
:
17
,
fT
:
RWC
,
fC
:
0
,
fD
:
"PHY Internal Error"
},
{
fN
:
"DIA
G
.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"
},
{
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"
},
...
...
@@ -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)"
},
{
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.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
:
[{
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
reg_defaults
=
[
0
]
*
4096
# array of bytes, default value = 0
bit_types
=
[
0
]
*
2048
# array of words, default value = 0
localparams
=
[]
for
group
in
src
:
groupName
=
group
[
gN
]
groupStart
=
group
[
gS
]
...
...
@@ -544,7 +553,27 @@ for group in src:
if
(
offs
+
b
)
<
len
(
bit_types
):
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
]))
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
num_bits
,
# number of bits in item
start_bit
,
# bit number to start filling from
...
...
@@ -574,6 +603,7 @@ def print_params(data,out_file_name):
for
i
,
v
in
enumerate
(
data
[
'data_p'
]):
if
v
:
print
(
", .INITP_
%02
X (256'h
%064
X)"
%
(
i
,
v
),
file
=
out_file
)
import
os
#print (os.path.abspath(__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.
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
(
"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
))))
host/transport.v
View file @
ce85dcb3
...
...
@@ -514,7 +514,7 @@ always @ (posedge clk)
if
(
ll_data_val_in
)
begin
if
(
dword_cnt
==
14'd2049
)
// if too much data for a data FIS TODO handle this exc
pe
tion properly
// if too much data for a data FIS TODO handle this exc
ep
tion properly
state
<=
STATE_IDLE
;
else
// continuing receiving data
...
...
includes/ahci_types.vh
View file @
ce85dcb3
...
...
@@ -2,7 +2,7 @@
, .INIT_10 (256'h0000000000000000555555555555000000000000000000005555555555500000)
, .INIT_11 (256'h000000000000000055054004000001C15551400000000455AAA28000000008AA)
, .INIT_12 (256'h0000000000550000000000000000000000000000000000000000000000000000)
, .INIT_13 (256'h00000000AAAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF002AAAAA00AA000
8
)
, .INIT_13 (256'h00000000AAAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF002AAAAA00AA000
A
)
, .INIT_14 (256'h000000000000000000000000000000000001555555555550000000000055000D)
, .INIT_17 (256'h5555555555555555555555555555555555555555555555555555555555555555)
, .INIT_18 (256'h00000000000055550000000000000000AA820000001000140000000000000000)
...
...
utils/ahci_dma.v
View file @
ce85dcb3
/*******************************************************************************
* Module: ahci_dma
* Date:2016-01-01
* Author:
andrey
* Author:
Andrey Filippov
* Description: DMA R/W over 64-AXI channel for AHCI implementation
*
* Copyright (c) 2016 Elphel, Inc .
...
...
utils/ahci_fis_receive.v
0 → 100644
View file @
ce85dcb3
/*******************************************************************************
* 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
1
ns
/
1
ps
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment