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
4336698a
Commit
4336698a
authored
Jan 09, 2016
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
finished initial code for ahci_fis_transmit module
parent
892ec17c
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
101 additions
and
102 deletions
+101
-102
ahci_fis_transmit.v
ahci/ahci_fis_transmit.v
+101
-102
No files found.
ahci/ahci_fis_transmit.v
View file @
4336698a
...
...
@@ -21,32 +21,32 @@
`timescale
1
ns
/
1
ps
module
ahci_fis_transmit
#(
parameter
PREFETCH_ALWAYS
=
0
,
parameter
READ_REG_LATENCY
=
2
,
// 0 if reg_rdata is available with reg_re/reg_addr
parameter
READ_CT_LATENCY
=
2
,
// 0 if reg_rdata is available with reg_re/reg_addr
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
hba_rst
,
// @posedge mclk -
when port is reset (even COMINIT)?
input
mclk
,
// for command/status
// 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
output
pCmdToIssue
,
// AHCI port variable
output
dmaCntrZero
,
// DmA counter is zero (first command)
output
reg
fetch_cmd_busy
,
// does not include prefetching CT
// input fetch_ct, // fetch command table (ch_ctba[31:7] should be valid by now)
input
cfis_xmit
,
// transmit command (wait for dma_ct_busy == 0)
input
dx_transmit
,
// send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
input
atapi_xmit
,
// tarsmit ATAPI command FIS
output
reg
done
,
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
input
syncesc_recv
,
// These two inputs interrupt transmit
input
xmit_err
,
//
output
dx_busy
,
output
dx_done
,
// single-clock dx_transmit is finished, check dx_err
output
[
1
:
0
]
dx_err
,
// bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command)
input
atapi_xmit
,
// tarsmit ATAPI command FIS
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
...
...
@@ -56,39 +56,30 @@ module ahci_fis_transmit #(
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 [31:7] ch_ctba, // command table base address - use reg_rdata[31:7] - outside
output
reg
[
11
:
2
]
dwords_sent
,
// number of DWORDs transmitted (up to 2048)
// register memory interface
output
reg
[
ADDRESS_BITS
-
1
:
0
]
reg_addr
,
output
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
output
dma_ctba_ld
,
// load command table
base address
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
dma_prd_start
,
// at or after cmd_start - enable reading PRD/data (if any) ch_prdtl should be valid
// output cmd_abort, // try to abort a command TODO: Implement
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
cmd_abort
,
// try to abort a command TODO: Implement
// reading out command table data from DMA module
output
reg
[
4
:
0
]
ct_addr
,
// DWORD address
output
ct_re
,
//
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
...
...
@@ -122,8 +113,12 @@ module ahci_fis_transmit #(
reg
ch_p_r
;
reg
ch_w_r
;
reg
ch_a_r
;
reg
[
4
:
0
]
ch_cfl_r
;
reg
[
4
:
0
]
ch_cfl_out_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
...
...
@@ -135,17 +130,14 @@ module ahci_fis_transmit #(
reg
chead_bsy
;
// busy reading command header
reg
chead_bsy_re
;
// busy sending read command header
reg
pCmdToIssue_r
;
wire
clearCmdToIssue
;
// TODO: assign - clear pCmdToIssue
// reg fetch_ct_r;
reg
cfis_xmit_pend_r
;
//
reg
cfis_xmit_start_r
;
reg
cfis_xmit_busy_r
;
//
reg
dmaCntrZero_r
;
// first command
// wire start_sync_escape_w = cfis_xmit && ch_r_r; - no, it should be instead of a ct_fetch
// TODO: Start FIS transmit when all FIS is in FIFO or data and >half(too slow, need minimum to be able to send wait primitive) or less?
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
cfis_xmit_start_w
=
(
dx_transmit
||
cfis_xmit_pend_r
)
&&
!
dma_ct_busy
&&
!
fetch_cmd_busy
;
// dma_ct_busy no gaps with fetch_cmd_busy
wire
cfis_xmit_end
;
wire
acfis_xmit_start_w
=
(
cfis_xmit
||
atapi_xmit
||
a
cfis_xmit_pend_r
)
&&
!
dma_ct_busy
&&
!
fetch_cmd_busy
;
// 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
;
...
...
@@ -159,8 +151,9 @@ module ahci_fis_transmit #(
wire
dx_dma_last_w
;
// sending last adat word
reg
dx_busy_r
;
reg
[
1
:
0
]
dx_err_r
;
reg
dx_done_r
;
wire
any_cmd_start
=
fetch_cmd
||
cfis_xmit
||
dx_transmit
||
atapi_xmit
;
wire
done_w
=
dx_dma_last_w
||
((
|
dx_err_r
)
&&
dx_busy_r
)
||
chead_done_w
||
acfis_xmit_end
;
// done on last transmit or error
assign
todev_valid
=
todev_full_r
;
assign
dma_re
=
dma_re_w
;
...
...
@@ -173,27 +166,23 @@ module ahci_fis_transmit #(
assign
ch_p
=
ch_p_r
;
assign
ch_w
=
ch_w_r
;
assign
ch_a
=
ch_a_r
;
assign
ch_cfl
=
ch_cfl_r
;
// assign ch_ctba = ch_ctba_r[31:7];
assign
ch_cfl
=
cfis_acmd_left_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 dmaCntrZero = dmaCntrZero_r;
assign
ct_re
=
ct_re_r
[
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
assign
ct_re_w
=
todev_ready
&&
((
c
h_cfl_r
[
4
:
1
]
!=
0
)
||
(
ch_cfl
_r
[
0
]
&&
!
ct_re_r
[
0
]))
;
// Later add more sources
assign
fis_dw_last
=
(
c
h_cfl
_out_r
==
1
)
;
assign
ct_re_w
=
todev_ready
&&
((
c
fis_acmd_left_r
[
4
:
1
]
!=
0
)
||
(
cfis_acmd_left
_r
[
0
]
&&
!
ct_re_r
[
0
]))
;
// Later add more sources
assign
fis_dw_last
=
(
c
fis_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
:
2
]
==
1
)
;
assign
dx_busy
=
dx_busy_r
;
assign
dx_done
=
dx_done_r
;
assign
dx_err
=
dx_err_r
;
assign
dma_dev_wr
=
ch_w_r
;
always
@
(
posedge
mclk
)
begin
// Mutliplex between DMA and FIS output to the output routed to transmit FIFO
...
...
@@ -207,7 +196,9 @@ module ahci_fis_transmit #(
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
;
if
(
hba_rst
)
fetch_chead_r
<=
0
;
// Read 3 DWORDs from the command header
if
(
hba_rst
)
fetch_chead_r
<=
0
;
// running 1
else
if
(
fetch_cmd
)
fetch_chead_r
<=
1
;
else
fetch_chead_r
<=
fetch_chead_r
<<
1
;
...
...
@@ -223,7 +214,7 @@ module ahci_fis_transmit #(
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
;
if
(
hba_rst
)
reg_re_r
<=
0
;
// [0] -> reg_re output
else
if
(
reg_re_w
)
reg_re_r
<=
1
;
else
reg_re_r
<=
reg_re_r
<<
1
;
...
...
@@ -239,7 +230,7 @@ module ahci_fis_transmit #(
ch_p_r
<=
reg_rdata
[
7
]
;
ch_w_r
<=
reg_rdata
[
6
]
;
ch_a_r
<=
reg_rdata
[
5
]
;
ch_c
fl_r
<=
reg_rdata
[
4
:
0
]
;
ch_c
md_len_r
<=
reg_rdata
[
4
:
0
]
;
end
if
(
hba_rst
)
pCmdToIssue_r
<=
0
;
...
...
@@ -250,39 +241,41 @@ module ahci_fis_transmit #(
else
if
(
fetch_cmd
)
fetch_cmd_busy
<=
1
;
else
if
(
dma_start
)
fetch_cmd_busy
<=
0
;
// fetch and send command fis
if
(
hba_rst
||
cfis_xmit_start_w
)
cfis_xmit_pend_r
<=
0
;
else
if
(
cfis_xmit
)
cfis_xmit_pend_r
<=
1
;
//CFIS/ATAPI common
cfis_xmit_start_r
<=
!
hba_rst
&&
cfis_xmit_start_w
;
// if (hba_rst || cfis_xmit) anc_fis_r <= 0;
// else if (atapi_xmit) anc_fis_r <= 1;
if
(
hba_rst
)
cfis_xmit_busy_r
<=
0
;
else
if
(
cfis_xmit_start_r
)
cfis_xmit_busy_r
<=
1
;
else
if
(
cfis_xmit
_end
)
cfis_xmit_busy_r
<=
0
;
// fetch and send command/atapi FIS
if
(
hba_rst
||
acfis_xmit_start_w
)
acfis_xmit_pend_r
<=
0
;
else
if
(
cfis_xmit
||
atapi_xmit
)
acfis_xmit_pend_r
<=
1
;
if
(
fetch_chead_stb_r
[
0
])
ch_cfl_r
<=
reg_rdata
[
4
:
0
]
;
// Will assume that there is room for ...
else
if
(
cfis_xmit_busy_r
&&
ct_re_r
[
0
])
ch_cfl_r
<=
ch_cfl_r
-
1
;
acfis_xmit_start_r
<=
!
hba_rst
&&
acfis_xmit_start_w
;
// Counting CFIS dwords sent to TL
if
(
cfis_xmit_start_w
)
ch_cfl_out_r
<=
ch_cfl_r
;
else
if
(
ct_stb
)
ch_cfl_out_r
<=
ch_cfl_out_r
-
1
;
if
(
hba_rst
)
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
;
ct_re_r
<=
{
ct_re_r
[
READ_CT_LATENCY
-
1
:
0
]
,
ct_re_w
};
if
(
cfis_xmit
)
ct_addr
<=
0
;
else
if
(
ch_cfl_r
[
0
])
ct_addr
<=
ct_addr
+
1
;
else
if
(
atapi_xmit
)
ct_addr
<=
'h10
;
// start of ATAPI area
else
if
(
cfis_acmd_left_r
[
0
])
ct_addr
<=
ct_addr
+
1
;
// first/last dword in FIS
if
(
!
cfis_xmit_busy_r
)
fis_dw_first
<=
1
;
if
(
!
a
cfis_xmit_busy_r
)
fis_dw_first
<=
1
;
else
if
(
ct_stb
)
fis_dw_first
<=
0
;
//
TODO: Implement ATAPI command, other FIS to send?
//
TODO: update xfer length, prdtl (only after R_OK) - yes, do it outside
// Send Data FIS TODO: abort on errors, and busy (or done) output
// input syncesc_recv, // These two inputs interrupt transmit
// input xmit_err, //
//TODO: update xfer length, prdtl (only after R_OK)?
if
(
dx_transmit
)
dx_dwords_left
[
11
:
2
]
<=
(
|
xfer_cntr
[
31
:
11
])
?
10'h200
:{
1'b0
,
xfer_cntr
[
10
:
2
]
};
else
if
(
dma_re_w
)
dx_dwords_left
[
11
:
2
]
<=
dx_dwords_left
[
11
:
2
]
-
1
;
...
...
@@ -306,15 +299,21 @@ module ahci_fis_transmit #(
if
(
hba_rst
)
dx_busy_r
<=
0
;
else
if
(
dx_transmit
)
dx_busy_r
<=
1
;
else
if
(
dx_dma_last_w
||
(
|
dx_err_r
))
dx_busy_r
<=
0
;
// done on last transmit or error
if
(
hba_rst
)
dx_done_r
<=
0
;
else
dx_done_r
<=
dx_dma_last_w
||
((
|
dx_err_r
)
&&
dx_busy_r
)
;
// TODO: Make commmon done for all commands?
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)
end
if
(
hba_rst
)
done
<=
0
;
else
done
<=
done_w
;
if
(
hba_rst
)
busy
<=
0
;
else
if
(
any_cmd_start
)
busy
<=
1
;
else
if
(
done_w
)
busy
<=
0
;
cmd_abort
<=
done_w
&&
(
|
dx_err_r
)
;
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