URL
https://opencores.org/ocsvn/nysa_sata/nysa_sata/trunk
Subversion Repositories nysa_sata
Compare Revisions
- This comparison shows the changes necessary to convert path
/nysa_sata
- from Rev 2 to Rev 3
- ↔ Reverse comparison
Rev 2 → Rev 3
/trunk/test/llw_states.txt
0,0 → 1,5
0 IDLE |
1 WRITE_START |
2 WRITE |
3 WRITE_END |
4 WAIT_RESPONSE |
/trunk/test/model/sata_model.py
23,9 → 23,11
@cocotb.coroutine |
def reset(self): |
self.dut.rst = 0 |
self.dut.write_data_en = 0 |
self.dut.read_data_en = 0 |
self.dut.soft_reset_en = 0 |
#self.dut.write_data_stb = 0 |
self.dut.hard_drive_command = 0x00 |
self.dut.execute_command_stb = 0 |
#self.dut.read_data_stb = 0 |
self.dut.command_layer_reset = 0 |
self.dut.sector_count = 0 |
self.dut.sector_address = 0 |
self.dut.fifo_reset = 0 |
52,9 → 54,6
self.dut.platform_ready = 1 |
|
yield(self.wait_clocks(10)) |
self.dut.soft_reset_en = 1 |
yield(self.wait_clocks(10)) |
self.dut.soft_reset_en = 0 |
|
def ready(self): |
if self.dut.sata_ready == 1: |
63,27 → 62,38
|
@cocotb.coroutine |
def wait_for_idle(self): |
yield(cocotb.triggers.FallingEdge(self.dut.busy)) |
yield(cocotb.triggers.RisingEdge(self.dut.sata_ready)) |
print "Wait for idle..." |
if self.dut.sata_busy.value == 1: |
yield(cocotb.triggers.FallingEdge(self.dut.sata_busy)) |
if self.dut.sata_ready.value == 0: |
yield(cocotb.triggers.RisingEdge(self.dut.sata_ready)) |
print "Idle!" |
|
@cocotb.coroutine |
def write_to_hard_drive(self, length, address): |
self.dut.u2h_write_enable = 1 |
#self.dut.u2h_write_enable = 1 |
self.dut.u2h_write_count = length |
#self.dut.h2u_read_enable = 1 |
self.dut.sector_address = address |
#What does this do? |
self.dut.sector_count = 0 |
self.dut.write_data_en = 1 |
self.dut.sector_count = (length / 8192) + 1 |
self.dut.hard_drive_command = 0x35 |
print "Write!" |
|
|
yield(self.wait_clocks(10)) |
self.dut.execute_command_stb = 1 |
#self.dut.write_data_stb = 1 |
yield(self.wait_clocks(1)) |
self.dut.write_data_en = 0 |
#self.dut.write_data_stb = 0 |
self.dut.execute_command_stb = 0 |
yield(self.wait_for_idle()) |
yield(self.wait_clocks(100)) |
#self.dut.h2u_read_enable = 0 |
self.dut.hard_drive_command = 0x00 |
|
@cocotb.coroutine |
def read_from_hard_drive(self, length, address): |
self.dut.read_data_en = 1 |
self.dut.sector_address = address |
sector_count = (length / 0x800) + 1 |
self.dut.sector_count = sector_count |
91,10 → 101,26
#Also tell the reader to analyze the incomming data |
self.dut.h2u_read_enable = 1 |
yield(self.wait_clocks(10)) |
|
print "Read..." |
#self.dut.read_data_stb = 1 |
self.dut.hard_drive_command = 0x25 |
self.dut.execute_command_stb = 1 |
yield(self.wait_clocks(1)) |
#self.dut.read_data_stb = 0 |
self.dut.execute_command_stb = 0 |
yield(self.wait_clocks(100)) |
while (self.dut.h2u_read_total_count.value < length): |
if self.dut.sata_ready.value == 1: |
#self.dut.read_data_stb = 1 |
self.dut.execute_command_stb = 1 |
yield(self.wait_clocks(1)) |
#self.dut.read_data_stb = 0 |
self.dut.execute_command_stb = 0 |
yield(self.wait_clocks(10)) |
|
yield(self.wait_clocks(100)) |
self.dut.log.info("count: %d" % self.dut.h2u_read_total_count.value) |
yield(self.wait_clocks(100)) |
|
self.dut.h2u_read_enable = 0 |
self.dut.read_data_en = 0 |
|
/trunk/test/scl_commands.txt
0,0 → 1,6
0 IDLE |
1 WAIT_FOR_DMA_ACT |
2 WAIT_FOR_WRITE_DATA |
3 SEND_DATA |
4 WAIT_FOR_STATUS |
|
/trunk/test/waveforms.gtkw
0,0 → 1,187
[*] |
[*] GTKWave Analyzer v3.3.62 (w)1999-2014 BSI |
[*] Fri Jun 19 14:57:18 2015 |
[*] |
[dumpfile] "/home/cospan/Projects/nysa-sata/test/design.vcd" |
[dumpfile_mtime] "Fri Jun 19 14:47:16 2015" |
[dumpfile_size] 12294345 |
[savefile] "/home/cospan/Projects/nysa-sata/test/waveforms.gtkw" |
[timestart] 7530 |
[size] 1918 1059 |
[pos] -1 -1 |
*-11.048740 13340 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[treeopen] tb_cocotb. |
[treeopen] tb_cocotb.fshd. |
[treeopen] tb_cocotb.fshd.fcl. |
[treeopen] tb_cocotb.fshd.fsll. |
[treeopen] tb_cocotb.ss. |
[treeopen] tb_cocotb.ss.scl.fifo_out. |
[treeopen] tb_cocotb.ss.sll. |
[treeopen] tb_cocotb.ss.sll.slr. |
[sst_width] 213 |
[signals_width] 246 |
[sst_expanded] 1 |
[sst_vpaned_height] 313 |
@22 |
tb_cocotb.test_id[31:0] |
@28 |
tb_cocotb.hd_ready |
tb_cocotb.linkup |
tb_cocotb.phy_ready |
tb_cocotb.platform_ready |
tb_cocotb.ss.sata_ready |
@200 |
- |
@800200 |
-SATA Stack |
@28 |
[color] 5 |
tb_cocotb.ss.clk |
[color] 5 |
tb_cocotb.ss.rst |
@200 |
- |
@28 |
tb_cocotb.ss.sll.slr.data_valid |
tb_cocotb.ss.sll.slr.send_r_ok |
tb_cocotb.ss.sll.slr.send_r_ip |
tb_cocotb.ss.sll.slr.send_r_err |
@c00200 |
-SATA Commands |
@28 |
tb_cocotb.ss.sata_ready |
tb_cocotb.ss.scl.sata_busy |
@22 |
tb_cocotb.ss.sector_count[15:0] |
tb_cocotb.ss.sector_address[47:0] |
tb_cocotb.ss.sector_count[15:0] |
@28 |
tb_cocotb.ss.send_command_stb |
tb_cocotb.ss.scl.t_d2h_reg_stb |
tb_cocotb.ss.scl.t_d2h_data_stb |
@22 |
tb_cocotb.fshd.fcl.sector_size[15:0] |
tb_cocotb.fshd.fcl.sector_count[15:0] |
tb_cocotb.ss.scl.sector_count[15:0] |
@200 |
- |
@28 |
tb_cocotb.ss.scl.d2h_error_abrt |
tb_cocotb.ss.scl.d2h_error_amnf |
tb_cocotb.ss.scl.d2h_error_bbk |
tb_cocotb.ss.scl.d2h_error_idnf |
tb_cocotb.ss.scl.d2h_error_mc |
tb_cocotb.ss.scl.d2h_error_mcr |
tb_cocotb.ss.scl.d2h_error_tk0nf |
tb_cocotb.ss.scl.d2h_error_unc |
@200 |
- |
@28 |
tb_cocotb.ss.scl.d2h_status_bsy |
tb_cocotb.ss.scl.d2h_status_corr |
tb_cocotb.ss.scl.d2h_status_drdy |
tb_cocotb.ss.scl.d2h_status_drq |
tb_cocotb.ss.scl.d2h_status_dsc |
tb_cocotb.ss.scl.d2h_status_dwf |
tb_cocotb.ss.scl.d2h_status_err |
tb_cocotb.ss.scl.d2h_status_idx |
@1401200 |
-SATA Commands |
@200 |
- |
@c00200 |
-raw signals |
@2022 |
^1 /tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/primitives.txt |
tb_cocotb.ss.sll.rx_din[31:0] |
^1 /tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/../../../../../tmp/../home/cospan/Projects/nysa-sata/test/primitives.txt |
tb_cocotb.ss.sll.tx_dout[31:0] |
@1401200 |
-raw signals |
@200 |
- |
@800200 |
-Write Data Path |
@28 |
tb_cocotb.ss.scl.execute_command_stb |
@22 |
[color] 2 |
+{SCL Write State} tb_cocotb.ss.scl.write_state[3:0] |
@28 |
tb_cocotb.ss.scl.transport_layer_ready |
@c02022 |
[color] 2 |
^2 /tmp/../home/cospan/Projects/nysa-sata/test/transport_states.txt |
+{Transport State} tb_cocotb.ss.stl.state[3:0] |
@28 |
[color] 2 |
(0)tb_cocotb.ss.stl.state[3:0] |
[color] 2 |
(1)tb_cocotb.ss.stl.state[3:0] |
[color] 2 |
(2)tb_cocotb.ss.stl.state[3:0] |
[color] 2 |
(3)tb_cocotb.ss.stl.state[3:0] |
@1401200 |
-group_end |
@22 |
+{Transport State} tb_cocotb.ss.stl.state[3:0] |
@28 |
tb_cocotb.ss.stl.dma_activate_stb |
@2022 |
[color] 2 |
^3 /tmp/../home/cospan/Projects/nysa-sata/test/llw_states.txt |
+{Link Layer Write State} tb_cocotb.ss.sll.slw.state[3:0] |
@22 |
+{Link Layer Write State} tb_cocotb.ss.sll.slw.state[3:0] |
@28 |
tb_cocotb.ss.sll.slw.detect_r_ok |
tb_cocotb.ss.sll.slw.detect_r_err |
@1000200 |
-Write Data Path |
-SATA Stack |
@800200 |
-Hard Drive |
@28 |
[color] 5 |
tb_cocotb.fshd.clk |
[color] 5 |
tb_cocotb.fshd.rst |
@200 |
- |
@22 |
+{Faux HD Command Layer State} tb_cocotb.fshd.fcl.state[3:0] |
@28 |
tb_cocotb.fshd.fcl.send_data_stb |
tb_cocotb.fshd.fcl.transport_layer_ready |
@200 |
- |
@1000200 |
-Hard Drive |
@200 |
- |
@28 |
tb_cocotb.user_2_hd_reader.enable |
tb_cocotb.user_2_hd_reader.hd_read_from_host |
@22 |
tb_cocotb.user_2_hd_reader.hd_data_from_host[31:0] |
tb_cocotb.user_2_hd_reader.test_data[31:0] |
@28 |
[color] 1 |
tb_cocotb.user_2_hd_reader.error |
tb_cocotb.hold |
@200 |
- |
@28 |
tb_cocotb.hd_2_user_reader.strobe |
@22 |
tb_cocotb.hd_2_user_reader.count[23:0] |
@28 |
tb_cocotb.hd_2_user_reader.enable |
tb_cocotb.hd_write_to_host |
tb_cocotb.hd_2_user_reader.ready |
tb_cocotb.hd_2_user_reader.activate |
@22 |
tb_cocotb.hd_data_to_host[31:0] |
[pattern_trace] 1 |
[pattern_trace] 0 |
/trunk/test/Makefile
39,7 → 39,6
|
VERILOG_SOURCES += $(TOPDIR)/sim/tb_cocotb.v |
|
|
TOPLEVEL = tb_cocotb |
|
GPI_IMPL := vpi |
/trunk/test/transport_states.txt
0,0 → 1,12
0 IDLE |
1 CHECK_FIS_TYPE |
2 WRITE_H2D_REG |
3 RETRY |
4 READ_D2H_REG |
5 READ_PIO_SETUP |
6 READ_SET_DEVICE_BITS |
7 DMA_ACTIVATE |
8 SEND_DATA |
9 READ_DATA |
|
|
/trunk/test/test_sata.py
31,6 → 31,7
dut.log.info("Sata is Ready") |
|
|
|
@cocotb.test(skip = True) |
def short_write_test(dut): |
""" |
88,14 → 89,17
-Number of data should be the same as the write amount |
""" |
dut.test_id = 3 |
data_count = 400 |
data_count = 2048 |
sata = SataController(dut, CLK_PERIOD) |
yield(sata.reset()) |
|
yield(sata.wait_for_idle()) |
yield(sata.write_to_hard_drive(data_count, 0x00)) |
yield(sata.wait_clocks(100)) |
|
yield(sata.write_to_hard_drive(data_count, 0x00)) |
dut.u2h_write_enable = 1 |
yield(sata.wait_clocks(10000)) |
|
dut.log.info("Wrote %d piece of data to SATA" % data_count) |
|
|
141,14 → 145,18
|
length = 400 |
address = 0x00 |
dut.u2h_write_enable = 1 |
yield(sata.wait_clocks(800)) |
|
dut.write_count = length |
dut.write_enable = 1 |
dut.u2h_write_enable = 1 |
dut.u2h_write_count = length |
#dut.h2u_read_enable = 1 |
dut.sector_address = address |
#What does this do? |
#dut.write_count = length |
#dut.write_enable = 1 |
#dut.u2h_write_enable = 1 |
#dut.u2h_write_count = length |
##dut.h2u_read_enable = 1 |
#dut.sector_address = address |
##What does this do? |
yield(sata.write_to_hard_drive(length, address)) |
|
dut.sector_count = 0 |
dut.write_data_en = 1 |
yield(sata.wait_clocks(1)) |
157,7 → 165,7
dut.hold = 1 |
yield(sata.wait_clocks(200)) |
dut.hold = 0 |
yield(sata.wait_clocks(400)) |
yield(sata.wait_clocks(200)) |
dut.hold = 1 |
yield(sata.wait_clocks(300)) |
dut.hold = 0 |
165,11 → 173,11
|
dut.write_enable = 0 |
dut.write_count = 0 |
yield(sata.wait_clocks(100)) |
yield(sata.wait_clocks(2000)) |
#dut.h2u_read_enable = 0 |
dut.log.info("Wrote %d piece of data to SATA" % length) |
|
@cocotb.test(skip = True) |
@cocotb.test(skip = False) |
def long_write_with_hard_back_preassure_test(dut): |
""" |
Description: |
192,21 → 200,21
dut.write_count = length |
dut.write_enable = 1 |
dut.u2h_write_enable = 1 |
dut.u2h_write_count = length |
yield(sata.wait_clocks(1000)) |
#dut.u2h_write_count = length |
#dut.h2u_read_enable = 1 |
dut.sector_address = address |
#What does this do? |
dut.sector_count = 0 |
dut.write_data_en = 1 |
yield(sata.wait_clocks(1)) |
dut.write_data_en = 0 |
#dut.write_data_en = 1 |
yield(sata.write_to_hard_drive(length, address)) |
yield(sata.wait_clocks(2500)) |
dut.hold = 1 |
yield(sata.wait_clocks(1)) |
dut.hold = 0 |
yield(sata.wait_clocks(400)) |
yield(sata.wait_clocks(394)) |
dut.hold = 1 |
yield(sata.wait_clocks(10)) |
yield(sata.wait_clocks(9)) |
dut.hold = 0 |
yield(sata.wait_clocks(400)) |
dut.hold = 1 |
225,7 → 233,7
#dut.h2u_read_enable = 0 |
dut.log.info("Wrote %d piece of data to SATA" % length) |
|
@cocotb.test(skip = False) |
@cocotb.test(skip = True) |
def long_write_long_read_back_preassure_test(dut): |
""" |
Description: |
/trunk/rtl/phy/oob_controller.v
31,21 → 31,24
input clk, |
|
input platform_ready, //the underlying physical platform is |
output reg platform_error, //Underlyaing physal platform received an error, this should probably be a reset |
output reg linkup, //link is finished |
|
output reg tx_comm_reset, //send a init OOB signal |
output reg tx_comm_wake, //send a wake OOB signal |
input tx_oob_complete, //Phy has said we are finished with this OOB transaction |
|
input comm_init_detect, //detected an init |
input comm_wake_detect, //detected a wake on the rx lines |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
input rx_is_elec_idle, |
input rx_byte_is_aligned, |
input phy_error, |
|
output reg [31:0] tx_dout, |
output reg tx_isk, |
output reg tx_is_k, |
output reg tx_set_elec_idle, |
output [3:0] lax_state |
|
65,15 → 68,17
parameter SEND_WAKE = 4'h5; |
parameter WAIT_FOR_WAKE = 4'h6; |
parameter WAIT_FOR_NO_WAKE = 4'h7; |
parameter WAIT_FOR_ALIGN = 4'h8; |
parameter SEND_ALIGN = 4'h9; |
parameter DETECT_SYNC = 4'hA; |
parameter READY = 4'hB; |
parameter WAIT_FOR_IDLE = 4'h8; |
parameter WAIT_FOR_ALIGN = 4'h9; |
parameter SEND_ALIGN = 4'hA; |
parameter DETECT_SYNC = 4'hB; |
parameter READY = 4'hC; |
|
//Registers/Wires |
reg [3:0] state; |
reg [31:0] timer; |
reg [1:0] no_align_count; |
reg [3:0] retries; |
|
//timer used to send 'INITs', WAKEs' and read them |
wire timeout; |
83,8 → 88,10
//Submodules |
//Asynchronous Logic |
assign timeout = (timer == 0); |
assign align_detected = ((rx_isk > 0) && (rx_din == `PRIM_ALIGN) && rx_byte_is_aligned); |
assign sync_detected = ((rx_isk > 0) && (rx_din == `PRIM_SYNC)); |
//assign align_detected = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN) && !phy_error); |
//assign align_detected = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN)); |
assign align_detected = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN) && rx_byte_is_aligned); |
assign sync_detected = ((rx_is_k > 0) && (rx_din == `PRIM_SYNC)); |
assign lax_state = state; |
|
//Synchronous Logic |
97,12 → 104,14
state <= IDLE; |
linkup <= 0; |
timer <= 0; |
tx_comm_reset <= 1; |
tx_comm_reset <= 0; |
tx_comm_wake <= 0; |
tx_dout <= 0; |
tx_isk <= 0; |
tx_is_k <= 0; |
tx_set_elec_idle <= 1; |
no_align_count <= 0; |
platform_error <= 0; |
retries <= 0; |
end |
else begin |
//to support strobes, continuously reset the following signals |
109,7 → 118,7
tx_comm_reset <= 0; |
tx_comm_wake <= 0; |
|
tx_isk <= 0; |
tx_is_k <= 0; |
|
|
//timer (when reache 0 timeout has occured) |
120,6 → 129,7
//main state machine, if this reaches ready an initialization sequence has completed |
case (state) |
IDLE: begin |
platform_error <= 0; |
linkup <= 0; |
tx_set_elec_idle <= 1; |
if (platform_ready) begin |
129,6 → 139,7
// DCM has generated the correct clocks |
timer <= 32'h000000A2; |
state <= SEND_RESET; |
tx_comm_reset <= 1; |
end |
end |
SEND_RESET: begin |
137,9 → 148,8
//SATA hard drive, or reset it so that it can be initiated to state |
|
//strobe the comm init so that the platform will send an INIT OOB signal |
tx_comm_reset <= 1; |
if (timeout) begin |
timer <= 32'd`INITIALIZE_TIMEOUT; |
if (timeout || tx_oob_complete) begin |
timer <= `INITIALIZE_TIMEOUT; |
state <= WAIT_FOR_INIT; |
$display ("oob_controller: wait for INIT"); |
end |
149,7 → 159,8
//go back to the SEND_RESET state |
if (comm_init_detect) begin |
//HD said 'sup' go to a wake |
timer <= 0; |
//timer <= 0; |
timer <= 32'h00001000; |
state <= WAIT_FOR_NO_INIT; |
$display ("oob_controller: wait for INIT to go low"); |
end |
160,7 → 171,7
end |
WAIT_FOR_NO_INIT: begin |
//wait for the init signal to go low from the device |
if (!comm_init_detect) begin |
if (!comm_init_detect && (timeout || tx_oob_complete)) begin |
$display ("oob_controller: INIT deasserted"); |
$display ("oob_controller: start configuration"); |
state <= WAIT_FOR_CONFIGURE_END; |
170,15 → 181,15
$display ("oob_controller: System is configured"); |
state <= SEND_WAKE; |
timer <= 32'h0000009B; |
tx_comm_wake <= 1; |
//end |
end |
SEND_WAKE: begin |
//XXX: In the groundhog COMM WAKE was continuously send for a long period of time |
//Send the WAKE sequence to the hard drive to initiate a wakeup sequence |
tx_comm_wake <= 1; |
//XXX: Is this timeout correct? |
//880uS |
if (timeout) begin |
if (timeout || tx_oob_complete) begin |
//timer <= 32'd`INITIALIZE_TIMEOUT; |
timer <= 32'h000203AD; |
state <= WAIT_FOR_WAKE; |
206,10 → 217,30
$display ("oob_controller: detected WAKE deasserted"); |
$display ("oob_controller: Send Dialtone, wait for ALIGN"); |
//Going to add more timeout |
timer <= 32'h203AD; |
state <= WAIT_FOR_ALIGN; |
//timer <= 32'h0203AD; |
timer <= 32'h0203AD; |
state <= WAIT_FOR_ALIGN; |
//state <= WAIT_FOR_IDLE; |
retries <= 4; |
end |
end |
/* |
WAIT_FOR_IDLE: begin |
if (!rx_is_elec_idle) begin |
state <= WAIT_FOR_ALIGN; |
timer <= 32'h0101D0; |
end |
else if (timeout) begin |
if (retries > 0) begin |
timer <= 32'h0203AD; |
retries <= retries - 1; |
end |
if (retries == 0) begin |
state <= IDLE; |
end |
end |
end |
*/ |
WAIT_FOR_ALIGN: begin |
//transmit the 'dialtone' continuously |
//since we need to start sending actual data (not OOB signals, get out |
217,7 → 248,8
tx_set_elec_idle <= 0; |
//a sequence of 0's and 1's |
tx_dout <= `DIALTONE; |
tx_isk <= 0; |
tx_is_k <= 0; |
//$display ("rx din: %h, k: %h", rx_din, rx_is_k); |
if (align_detected) begin |
//we got something from the device! |
timer <= 0; |
235,7 → 267,7
end |
SEND_ALIGN: begin |
tx_dout <= `PRIM_ALIGN; |
tx_isk <= 1; |
tx_is_k <= 1; |
if (!align_detected) begin |
$display ("oob_controller: detected ALIGN deasserted"); |
//XXX: Groundhog detects the SYNC primitve before declaring linkup |
244,7 → 276,7
state <= READY; |
end |
else begin |
no_align_count <= no_align_count + 1; |
no_align_count <= no_align_count + 2'b01; |
end |
end |
end |
254,13 → 286,18
end |
end |
READY: begin |
linkup <= 1; |
linkup <= 1; |
/* |
if (phy_error) begin |
platform_error <= 1; |
end |
*/ |
if (comm_init_detect) begin |
state <= IDLE; |
end |
end |
default: begin |
state <= IDLE; |
state <= IDLE; |
end |
endcase |
|
/trunk/rtl/phy/sata_phy_layer.v
31,27 → 31,29
input clk, |
|
input platform_ready, //the underlying physical platform is |
output platform_error, |
output linkup, //link is finished |
|
output [31:0] tx_dout, |
output tx_isk, |
output tx_is_k, |
output tx_comm_reset, |
output tx_comm_wake, |
output tx_elec_idle, |
input tx_oob_complete, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
input rx_elec_idle, |
input rx_byte_is_aligned, |
|
input comm_init_detect, |
input comm_wake_detect, |
|
output phy_ready, |
input phy_error, |
output [3:0] lax_state |
|
); |
|
|
//Parameters |
parameter NOT_READY = 4'h0; |
parameter SEND_FIRST_ALIGN = 4'h1; |
64,90 → 66,94
|
//OOB Control |
wire [31:0] oob_tx_dout; |
wire oob_tx_isk; |
wire oob_tx_is_k; |
|
//Phy Control |
wire [31:0] phy_tx_dout; |
wire phy_tx_isk; |
wire align_detected; |
wire phy_tx_is_k; |
//wire align_detected; |
wire oob_platform_error; |
reg phy_platform_error; |
|
|
|
//Submodules |
oob_controller oob ( |
.rst (rst), |
.clk (clk), |
.rst (rst ), |
.clk (clk ), |
|
//OOB controller |
.platform_ready (platform_ready), |
.linkup (linkup), |
.phy_error (phy_error ), |
.platform_ready (platform_ready ), |
.platform_error (oob_platform_error ), |
.linkup (linkup ), |
|
//Platform Control |
.tx_dout (oob_tx_dout), |
.tx_isk (oob_tx_isk), |
.tx_comm_reset (tx_comm_reset), |
.tx_comm_wake (tx_comm_wake), |
.tx_set_elec_idle (tx_elec_idle), |
.tx_dout (oob_tx_dout ), |
.tx_is_k (oob_tx_is_k ), |
.tx_comm_reset (tx_comm_reset ), |
.tx_comm_wake (tx_comm_wake ), |
.tx_set_elec_idle (tx_elec_idle ), |
.tx_oob_complete (tx_oob_complete ), |
|
.rx_din (rx_din), |
.rx_isk (rx_isk), |
.comm_init_detect (comm_init_detect), |
.comm_wake_detect (comm_wake_detect), |
.rx_byte_is_aligned (rx_byte_is_aligned), |
.rx_is_elec_idle (rx_elec_idle), |
.lax_state (lax_state) |
.rx_din (rx_din ), |
.rx_is_k (rx_is_k ), |
.comm_init_detect (comm_init_detect ), |
.comm_wake_detect (comm_wake_detect ), |
.rx_is_elec_idle (rx_elec_idle ), |
.rx_byte_is_aligned (rx_byte_is_aligned ), |
.lax_state (lax_state ) |
|
); |
|
//Asynchronous Logic |
assign tx_dout = !linkup ? oob_tx_dout : phy_tx_dout; |
assign tx_isk = !linkup ? oob_tx_isk : phy_tx_isk; |
assign tx_is_k = !linkup ? oob_tx_is_k : phy_tx_is_k; |
|
assign phy_tx_dout = `PRIM_ALIGN; |
assign phy_tx_isk = 1; |
assign phy_tx_is_k = 1; |
|
assign align_detected = ((rx_isk > 0) && (rx_din == `PRIM_ALIGN) && rx_byte_is_aligned); |
//assign align_detected = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN) && !phy_error); |
//assign phy_ready = ((state == READY) && (!align_detected)); |
assign phy_ready = (state == READY); |
assign platform_error = oob_platform_error || phy_platform_error; |
|
|
|
//Synchronous Logic |
always @ (posedge clk) begin |
if (rst) begin |
state <= NOT_READY; |
align_count <= 0; |
phy_platform_error<= 0; |
end |
else begin |
if (state == READY) begin |
align_count <= align_count + 1; |
align_count <= align_count + 8'h01; |
end |
case (state) |
NOT_READY: begin |
align_count <= 0; |
align_count <= 0; |
phy_platform_error <= 0; |
if (linkup) begin |
`ifdef VERBOSE |
$display ("sata_phy_layer: linkup! send aligns"); |
`endif |
state <= SEND_FIRST_ALIGN; |
state <= SEND_FIRST_ALIGN; |
end |
end |
SEND_FIRST_ALIGN: begin |
state <= SEND_SECOND_ALIGN; |
state <= SEND_SECOND_ALIGN; |
end |
SEND_SECOND_ALIGN: begin |
state <= READY; |
state <= READY; |
end |
READY: begin |
if (align_count == 255) begin |
state <= SEND_FIRST_ALIGN; |
state <= SEND_FIRST_ALIGN; |
`ifdef VERBOSE |
$display ("sata_phy_layer: linkup! send alignment dwords"); |
`else |
$display ("sata_phy_layer: ."); |
`endif |
//Send an align primitive |
end |
if (phy_error) begin |
phy_platform_error <= 1; |
end |
end |
default: begin |
end |
/trunk/rtl/sata_stack.v
33,29 → 33,30
input data_out_clk_valid, |
|
input platform_ready, //the underlying physical platform is |
output wire linkup, //link is finished |
output sata_ready, |
output sata_init, |
output platform_error, //Underlying platform errored out, the |
//clock is misaligned, stack should |
//probably be reset |
output linkup, //link is finished |
|
input send_sync_escape, |
input [15:0] user_features, |
input [15:0] user_features, |
|
//User Interface |
output busy, |
output error, |
output sata_ready, |
output sata_busy, |
|
output hard_drive_error, |
|
input write_data_en, |
input single_rdwr, |
input read_data_en, |
// input write_data_stb, |
// input read_data_stb, |
|
input send_user_command_stb, |
input soft_reset_en, |
input [7:0] command, |
input execute_command_stb, |
input command_layer_reset, |
input [7:0] hard_drive_command, |
output pio_data_ready, |
|
input [15:0] sector_count, |
input [47:0] sector_address, |
input [15:0] sector_count, |
input [47:0] sector_address, |
|
|
output dma_activate_stb, |
63,32 → 64,30
output pio_setup_stb, |
output d2h_data_stb, |
output dma_setup_stb, |
output wire set_device_bits_stb, |
output set_device_bits_stb, |
|
output dbg_send_command_stb, |
output dbg_send_control_stb, |
output dbg_send_data_stb, |
|
output [7:0] d2h_fis, |
output d2h_interrupt, |
output d2h_notification, |
output [3:0] d2h_port_mult, |
output [7:0] d2h_device, |
output [47:0] d2h_lba, |
output [15:0] d2h_sector_count, |
output [7:0] d2h_status, |
output [7:0] d2h_error, |
output [3:0] d2h_port_mult, |
output [7:0] d2h_device, |
output [47:0] d2h_lba, |
output [15:0] d2h_sector_count, |
output [7:0] d2h_status, |
output [7:0] d2h_error, |
|
input [31:0] user_din, |
input [31:0] user_din, |
input user_din_stb, |
output [1:0] user_din_ready, |
input [1:0] user_din_activate, |
output [23:0] user_din_size, |
output [1:0] user_din_ready, |
input [1:0] user_din_activate, |
output [23:0] user_din_size, |
output user_din_empty, |
|
output [31:0] user_dout, |
output [31:0] user_dout, |
output user_dout_ready, |
input user_dout_activate, |
input user_dout_stb, |
output [23:0] user_dout_size, |
output [23:0] user_dout_size, |
|
|
output transport_layer_ready, |
98,65 → 97,33
//Buffer |
//Platform Interface |
output [31:0] tx_dout, |
output tx_isk, |
output tx_is_k, //Connect All 4 'tx_is_k'to this signal |
output tx_comm_reset, |
output tx_comm_wake, |
output tx_elec_idle, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
input rx_elec_idle, |
input rx_byte_is_aligned, |
input comm_init_detect, |
input comm_wake_detect, |
input rx_byte_is_aligned, |
input tx_oob_complete, |
input phy_error, |
|
|
//Debug |
output dbg_remote_abort, |
output dbg_xmit_error, |
output dbg_read_crc_error, |
|
//PIO |
output dbg_pio_response, |
output dbg_pio_direction, |
output [15:0] dbg_pio_transfer_count, |
output [7:0] dbg_pio_e_status, |
|
//Host dbg_ to Device Regster Values |
output [7:0] dbg_h2d_command, |
output [15:0] dbg_h2d_features, |
output [7:0] dbg_h2d_control, |
output [3:0] dbg_h2d_port_mult, |
output [7:0] dbg_h2d_device, |
output [47:0] dbg_h2d_lba, |
output [15:0] dbg_h2d_sector_count, |
|
//DMA Specific Control |
|
//Data Control |
output dbg_cl_if_ready, |
output dbg_cl_if_activate, |
output [23:0] dbg_cl_if_size, |
output dbg_cl_if_strobe, |
output [31:0] dbg_cl_if_data, |
output [3:0] dbg_cc_lax_state, |
output [3:0] dbg_cw_lax_state, |
|
output [1:0] dbg_cl_of_ready, |
output [1:0] dbg_cl_of_activate, |
output dbg_cl_of_strobe, |
output [31:0] dbg_cl_of_data, |
output [23:0] dbg_cl_of_size, |
output [3:0] dbg_t_lax_state, |
|
output [3:0] dbg_cc_lax_state, |
output [3:0] dbg_cr_lax_state, |
output [3:0] dbg_cw_lax_state, |
output [3:0] dbg_li_lax_state, |
output [3:0] dbg_lr_lax_state, |
output [3:0] dbg_lw_lax_state, |
output [3:0] dbg_lw_lax_fstate, |
|
output [3:0] dbg_t_lax_state, |
|
output [3:0] dbg_li_lax_state, |
output [3:0] dbg_lr_lax_state, |
output [3:0] dbg_lw_lax_state, |
output [3:0] dbg_lw_lax_fstate, |
|
//Link Layer |
input prim_scrambler_en, |
input data_scrambler_en, |
163,26 → 130,11
|
output dbg_ll_write_ready, |
output dbg_ll_paw, |
output dbg_ll_write_start, |
output dbg_ll_write_strobe, |
output dbg_ll_write_finished, |
output [31:0] dbg_ll_write_data, |
output [31:0] dbg_ll_write_size, |
output dbg_ll_write_hold, |
output dbg_ll_write_abort, |
|
output dbg_ll_read_start, |
output dbg_ll_read_strobe, |
output [31:0] dbg_ll_read_data, |
output dbg_ll_read_ready, |
output dbg_ll_read_finished, |
output dbg_ll_remote_abort, |
output dbg_ll_xmit_error, |
|
output dbg_ll_send_crc, |
|
//Phy Layer |
output [3:0] lax_state, |
output [3:0] oob_state, |
|
//Primative Detection |
output dbg_detect_sync, |
204,10 → 156,10
|
output dbg_send_holda, |
|
output [23:0] slw_in_data_addra, |
output [12:0] slw_d_count, |
output [12:0] slw_write_count, |
output [3:0] slw_buffer_pos |
output [23:0] slw_in_data_addra, |
output [12:0] slw_d_count, |
output [12:0] slw_write_count, |
output [3:0] slw_buffer_pos |
); |
|
//Parameters |
237,7 → 189,7
wire ll_write_strobe; |
wire ll_write_finished; |
wire [31:0] ll_write_data; |
wire [31:0] ll_write_size; |
wire [23:0] ll_write_size; |
wire ll_write_hold; |
wire ll_write_abort; |
|
252,11 → 204,11
wire ll_xmit_error; |
|
wire [31:0] ll_tx_dout; |
wire ll_tx_isk; |
wire ll_tx_is_k; |
|
//Phy Layer |
wire [31:0] phy_tx_dout; |
wire phy_tx_isk; |
wire phy_tx_is_k; |
|
//User Interface state machine |
|
271,7 → 223,6
wire [47:0] h2d_lba; |
wire [15:0] h2d_sector_count; |
|
|
wire remote_abort; |
wire xmit_error; |
wire read_crc_error; |
295,7 → 246,6
wire [31:0] cl_of_data; |
wire [23:0] cl_of_size; |
|
|
//Link Layer Interface |
wire t_sync_escape; |
wire t_write_start; |
302,7 → 252,7
wire t_write_strobe; |
wire t_write_finished; |
wire [31:0] t_write_data; |
wire [31:0] t_write_size; |
wire [23:0] t_write_size; |
wire t_write_hold; |
wire t_write_abort; |
wire t_xmit_error; |
314,7 → 264,6
wire t_read_finished; |
wire t_read_crc_ok; |
wire t_remote_abort; |
|
//Comand Layer registers |
|
//Submodules |
328,20 → 277,18
.data_out_clk_valid (data_out_clk_valid ), |
|
//Application Interface |
.sata_init (sata_init ), |
.command_layer_ready (sata_ready ), |
.busy (busy ), |
.dev_error (error ), |
.sata_busy (sata_busy ), |
.hard_drive_error (hard_drive_error ), |
.send_sync_escape (send_sync_escape ), |
.user_features (user_features ), |
|
.write_data_en (write_data_en ), |
.single_rdwr (single_rdwr ), |
.read_data_en (read_data_en ), |
// .write_data_stb (write_data_stb ), |
// .read_data_stb (read_data_stb ), |
.execute_command_stb (execute_command_stb ), |
|
.send_user_command_stb(send_user_command_stb ), |
.soft_reset_en (soft_reset_en ), |
.command (command ), |
.command_layer_reset (command_layer_reset ), |
.hard_drive_command (hard_drive_command ), |
.pio_data_ready (pio_data_ready ), |
|
.sector_count (sector_count ), |
352,6 → 299,7
.user_din_ready (user_din_ready ), |
.user_din_activate (user_din_activate ), |
.user_din_size (user_din_size ), |
.user_din_empty (user_din_empty ), |
|
.user_dout (user_dout ), |
.user_dout_ready (user_dout_ready ), |
418,15 → 366,10
.t_of_size (of_size ), |
|
.cl_c_state (dbg_cc_lax_state ), |
.cl_r_state (dbg_cr_lax_state ), |
.cl_w_state (dbg_cw_lax_state ) |
|
|
|
); |
|
|
|
//Transport Layer |
sata_transport_layer stl ( |
.rst (rst | !linkup ), |
468,6 → 411,7
.h2d_sector_count (h2d_sector_count ), |
|
//Device to Host Register Values |
.d2h_fis (d2h_fis ), |
.d2h_interrupt (d2h_interrupt ), |
.d2h_notification (d2h_notification ), |
.d2h_port_mult (d2h_port_mult ), |
552,10 → 496,10
.phy_ready (phy_ready ), |
.platform_ready (platform_ready ), |
.tx_dout (ll_tx_dout ), |
.tx_isk (ll_tx_isk ), |
.tx_is_k (ll_tx_is_k ), |
|
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
.is_device (1'b0 ), |
|
//Primative Detection |
603,23 → 547,26
|
//Control/Status |
.platform_ready (platform_ready ), |
.platform_error (platform_error ), |
.linkup (linkup ), |
|
//Platform Interface |
.tx_dout (phy_tx_dout ), |
.tx_isk (phy_tx_isk ), |
.tx_is_k (phy_tx_is_k ), |
.tx_comm_reset (tx_comm_reset ), |
.tx_comm_wake (tx_comm_wake ), |
.tx_elec_idle (tx_elec_idle ), |
.tx_oob_complete (tx_oob_complete ), |
|
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
.comm_init_detect (comm_init_detect ), |
.comm_wake_detect (comm_wake_detect ), |
.rx_elec_idle (rx_elec_idle ), |
.rx_byte_is_aligned (rx_byte_is_aligned ), |
.phy_error (phy_error ), |
|
.lax_state (lax_state ), |
.lax_state (oob_state ), |
.phy_ready (phy_ready ) |
); |
|
628,41 → 575,25
//Asynchronous Logic |
|
//control of data to the platform controller |
//In order to send align primitives the phy must sometimes take over the bus |
assign tx_dout = (phy_ready) ? ll_tx_dout : phy_tx_dout; |
assign tx_isk = (phy_ready) ? ll_tx_isk : phy_tx_isk; |
assign tx_is_k = (phy_ready) ? ll_tx_is_k : phy_tx_is_k; |
|
//no activity on the stack |
|
//Debug |
assign ll_write_start = t_write_start; |
assign dbg_ll_write_start = t_write_start; |
assign ll_write_data = t_write_data; |
assign dbg_ll_write_data = t_write_data; |
assign ll_write_hold = t_write_hold; |
assign dbg_ll_write_hold = t_write_hold; |
assign ll_write_size = t_write_size; |
assign dbg_ll_write_size = t_write_size; |
assign ll_write_abort = t_write_abort; |
assign dbg_ll_write_abort = t_write_abort; |
|
assign ll_read_ready = t_read_ready; |
assign dbg_ll_read_ready = t_read_ready; |
assign ll_sync_escape = t_sync_escape; |
|
assign dbg_ll_write_strobe = ll_write_strobe; |
assign t_write_strobe = ll_write_strobe; |
|
assign dbg_ll_write_finished = ll_write_finished; |
assign t_write_finished = ll_write_finished; |
|
|
assign dbg_ll_read_strobe = ll_read_strobe; |
assign dbg_ll_read_start = ll_read_start; |
assign dbg_ll_read_finished = ll_read_finished; |
assign dbg_ll_read_data = ll_read_data; |
assign dbg_ll_remote_abort = ll_remote_abort; |
assign dbg_ll_xmit_error = ll_xmit_error; |
|
assign t_read_strobe = ll_read_strobe; |
assign t_read_start = ll_read_start; |
assign t_read_finished = ll_read_finished; |
671,44 → 602,17
assign t_xmit_error = ll_xmit_error; |
assign t_read_crc_ok = ll_read_crc_ok; |
|
assign dbg_send_command_stb = send_command_stb; |
assign dbg_send_control_stb = send_control_stb; |
assign dbg_send_data_stb = send_data_stb; |
|
assign dbg_remote_abort = remote_abort; |
assign dbg_xmit_error = xmit_error; |
assign dbg_read_crc_error = read_crc_error; |
|
assign dbg_h2d_command = h2d_command; |
assign dbg_h2d_features = h2d_features; |
assign dbg_h2d_control = h2d_control; |
assign dbg_h2d_port_mult = h2d_port_mult; |
assign dbg_h2d_device = h2d_device; |
assign dbg_h2d_sector_count = h2d_sector_count; |
|
|
assign cl_if_ready = if_ready; |
assign dbg_cl_if_activate = cl_if_activate; |
assign if_activate = cl_if_activate; |
assign dbg_cl_if_size = if_size; |
assign cl_if_size = if_size; |
assign dbg_cl_if_strobe = cl_if_strobe; |
assign if_strobe = cl_if_strobe; |
assign dbg_cl_if_data = if_data; |
assign cl_if_data = if_data; |
|
assign cl_of_ready = of_ready; |
assign dbg_cl_of_ready = of_ready; |
assign of_activate = cl_of_activate; |
assign dbg_cl_of_activate = cl_of_activate; |
assign of_strobe = cl_of_strobe; |
assign dbg_cl_of_strobe = cl_of_strobe; |
assign of_data = cl_of_data; |
assign dbg_cl_of_data = cl_of_data; |
assign cl_of_size = of_size; |
assign dbg_cl_of_size = of_size; |
|
|
|
//Synchronous Logic |
endmodule |
/trunk/rtl/sata_defines.v
26,7 → 26,7
`define __SATA_DEFINES__ |
|
//Presuming 75MHz clock |
`define CLOCK_RATE (75000000) |
`define SATA_CLOCK_RATE (75000000) |
// 1 / 880uS = 1136 times per seconds |
`define NORMAL_TIMEOUT (1000000) / 880 |
|
36,7 → 36,7
`define FIFO_ADDRESS_WIDTH 11 |
|
//880uS |
//`define INITIALIZE_TIMEOUT ((`CLOCK_RATE) / (`NORMAL_TIMEOUT)) |
//`define INITIALIZE_TIMEOUT ((`SATA_CLOCK_RATE) / (`NORMAL_TIMEOUT)) |
`define INITIALIZE_TIMEOUT 66000 |
//`define SEND_WAKE_TIMEOUT 4E |
|
/trunk/rtl/generic/ppfifo.v
58,7 → 58,6
localparam FIFO_DEPTH = (1 << ADDRESS_WIDTH); |
|
//Local Registers/Wires |
assign write_fifo_size = FIFO_DEPTH; |
|
//Write Side |
wire ppfifo_ready; // The write side only needs to |
86,27 → 85,6
reg [4:0] w_reset_timeout; |
wire ready; |
|
//assign r_wselect = (write_activate == 2'b00) ? 1'b0 : |
// (write_activate == 2'b01) ? 1'b0 : |
// (write_activate == 2'b10) ? 1'b1 : |
// reset ? 1'b0 : |
// r_wselect; |
// //I know this can be shortened down but it's more |
// //readible thi way |
|
assign addr_in = {r_wselect, write_address}; |
//assign write_enable = (write_activate > 0) && write_strobe; |
assign ppfifo_ready = !(w_reset || r_reset); |
assign ready = ppfifo_ready; |
|
//assign wcc_tie_select = (wcc_read_ready == 2'b00) ? 1'b0 : |
// (wcc_read_ready == 2'b01) ? 1'b0 : |
// (wcc_read_ready == 2'b10) ? 1'b1 : |
// wcc_tie_select; |
// If the first FIFO is ready, |
// then both FIFOs are ready then |
// keep the first FIFO |
|
//Read Side |
wire [ADDRESS_WIDTH: 0] addr_out; //Actual address to the BRAM |
reg r_reset; |
140,24 → 118,49
wire [DATA_WIDTH - 1: 0] w_read_data; //data from the read FIFO |
reg [DATA_WIDTH - 1: 0] r_read_data; //data from the read FIFO |
|
|
|
//assign r_wselect = (write_activate == 2'b00) ? 1'b0 : |
// (write_activate == 2'b01) ? 1'b0 : |
// (write_activate == 2'b10) ? 1'b1 : |
// reset ? 1'b0 : |
// r_wselect; |
// //I know this can be shortened down but it's more |
// //readible thi way |
|
assign write_fifo_size = FIFO_DEPTH; |
|
assign addr_in = {r_wselect, write_address}; |
//assign write_enable = (write_activate > 0) && write_strobe; |
assign ppfifo_ready = !(w_reset || r_reset); |
assign ready = ppfifo_ready; |
|
//assign wcc_tie_select = (wcc_read_ready == 2'b00) ? 1'b0 : |
// (wcc_read_ready == 2'b01) ? 1'b0 : |
// (wcc_read_ready == 2'b10) ? 1'b1 : |
// wcc_tie_select; |
// If the first FIFO is ready, |
// then both FIFOs are ready then |
// keep the first FIFO |
|
assign addr_out = {r_rselect, r_address}; |
|
|
//Debug |
wire [23:0] debug_f0_w_count; |
wire [23:0] debug_f1_w_count; |
//wire [23:0] debug_f0_w_count; |
//wire [23:0] debug_f1_w_count; |
|
wire [23:0] debug_f0_r_size; |
wire [23:0] debug_f1_r_size; |
//wire [23:0] debug_f0_r_size; |
//wire [23:0] debug_f1_r_size; |
|
//wire [23:0] debug_f0_r_count; |
//wire [23:0] debug_f1_r_count; |
|
assign debug_f0_w_count = w_count[0]; |
assign debug_f1_w_count = w_count[1]; |
//assign debug_f0_w_count = w_count[0]; |
//assign debug_f1_w_count = w_count[1]; |
|
assign debug_f0_r_size = r_size[0]; |
assign debug_f1_r_size = r_size[1]; |
//assign debug_f0_r_size = r_size[0]; |
//assign debug_f1_r_size = r_size[1]; |
|
assign inactive = (w_count[0] == 0) && |
(w_count[1] == 0) && |
291,8 → 294,8
w_reset_timeout <= 0; |
end |
else begin |
if (w_reset && (w_reset_timeout < 4'h4)) begin |
w_reset_timeout <= w_reset_timeout + 1; |
if (w_reset && (w_reset_timeout < 5'h4)) begin |
w_reset_timeout <= w_reset_timeout + 5'h1; |
end |
else begin |
w_reset <= 0; |
306,8 → 309,8
r_reset_timeout <= 0; |
end |
else begin |
if (r_reset && (r_reset_timeout < 4'h4)) begin |
r_reset_timeout <= r_reset_timeout + 1; |
if (r_reset && (r_reset_timeout < 5'h4)) begin |
r_reset_timeout <= r_reset_timeout + 5'h1; |
end |
else begin |
r_reset <= 0; |
/trunk/rtl/transport/sata_transport_layer.v
66,6 → 66,7
input [15:0] h2d_sector_count, |
|
//Device to Host Registers |
output reg [7:0] d2h_fis, |
output reg d2h_interrupt, |
output reg d2h_notification, |
output reg [3:0] d2h_port_mult, |
100,7 → 101,7
input ll_write_strobe, |
input ll_write_finished, |
output [31:0] ll_write_data, |
output [31:0] ll_write_size, |
output [23:0] ll_write_size, |
output ll_write_hold, |
output ll_write_abort, |
input ll_xmit_error, |
136,9 → 137,9
|
//Registers/Wires |
reg [3:0] fis_id_state; |
reg [7:0] current_fis; |
reg [3:0] state; |
reg detect_fis; |
reg [7:0] current_fis; |
wire processing_fis; |
|
//data direction |
159,7 → 160,7
|
reg reg_write_start; |
wire [31:0] reg_write_data; |
wire [31:0] reg_write_size; |
wire [23:0] reg_write_size; |
reg reg_write_ready; |
wire reg_write_hold; |
wire reg_write_abort; |
177,7 → 178,7
reg data_write_start; |
wire data_write_strobe; |
wire data_read_strobe; |
wire [31:0] data_write_size; |
wire [23:0] data_write_size; |
wire [31:0] data_write_data; |
wire data_write_hold; |
wire data_write_abort; |
185,8 → 186,10
reg data_read_ready; |
reg send_data_fis_id; |
|
reg ll_write_finished_en; |
|
|
|
//Asnchronous Logic |
assign lax_state = state; |
assign transport_layer_ready = (state == IDLE) && link_layer_ready; |
199,26 → 202,25
assign ll_write_start = (reg_write) ? reg_write_start : data_write_start; |
assign ll_write_data = (reg_write) ? register_fis[register_fis_ptr] : data_write_data; |
assign ll_write_size = (reg_write) ? reg_write_size : data_write_size; |
assign ll_write_hold = (reg_write) ? 0 : data_write_hold; |
assign ll_write_abort = (reg_write) ? 0 : data_write_abort; |
assign cl_if_strobe = (reg_write) ? 0 : (!send_data_fis_id && data_write_strobe); |
assign ll_write_hold = (reg_write) ? 1'b0 : data_write_hold; |
assign ll_write_abort = (reg_write) ? 1'b0 : data_write_abort; |
assign cl_if_strobe = (reg_write) ? 1'b0 : (!send_data_fis_id && data_write_strobe); |
|
//Read Control |
assign ll_read_ready = (reg_read) ? 1 : data_read_ready; |
assign cl_of_strobe = (reg_read) ? 0 : ((state == READ_DATA) && data_read_strobe); |
assign ll_read_ready = (reg_read) ? 1'b1 : data_read_ready; |
assign cl_of_strobe = (reg_read) ? 1'b0 : ((state == READ_DATA) && data_read_strobe); |
assign cl_of_data = ll_read_data; |
|
//Data Register Write Control Signals |
assign data_write_data = (send_data_fis_id) ? `FIS_DATA : cl_if_data; |
assign data_write_data = (send_data_fis_id) ? {24'h000, `FIS_DATA} : cl_if_data; |
//the first DWORD is the FIS ID |
assign data_write_size = (cl_if_size + 1); |
//assign data_write_size = cl_if_size; |
assign data_write_size = cl_if_size + 24'h1; |
//Add 1 to the size so that there is room for the FIS ID |
assign data_write_strobe = ll_write_strobe; |
assign data_read_strobe = ll_read_strobe; |
assign data_write_hold = 0; |
assign data_write_hold = 1'b0; |
//There should never be a hold on the data becuase the CL will set it up |
assign data_write_abort = 0; |
assign data_write_abort = 1'b0; |
assign read_crc_error = !ll_read_crc_ok; |
|
|
225,8 → 227,8
//H2D Register Write control signals |
assign reg_write_strobe = ll_write_strobe; |
assign reg_write_size = `FIS_H2D_REG_SIZE; |
assign reg_write_hold = 0; |
assign reg_write_abort = 0; |
assign reg_write_hold = 1'b0; |
assign reg_write_abort = 1'b0; |
assign reg_write = (state == WRITE_H2D_REG) || (send_command_stb || send_control_stb); |
|
//D2H Register Read control signals |
258,41 → 260,43
//FIS ID State machine |
always @ (posedge clk) begin |
if (rst) begin |
fis_id_state <= IDLE; |
detect_fis <= 0; |
current_fis <= 0; |
fis_id_state <= IDLE; |
detect_fis <= 0; |
current_fis <= 0; |
d2h_fis <= 0; |
end |
else begin |
//in order to set all the detect_* high when the actual fis is detected send this strobe |
if(ll_read_finished) begin |
current_fis <= 0; |
fis_id_state <= IDLE; |
current_fis <= 0; |
fis_id_state <= IDLE; |
end |
else begin |
case (fis_id_state) |
IDLE: begin |
current_fis <= 0; |
detect_fis <= 0; |
current_fis <= 0; |
detect_fis <= 0; |
if (ll_read_start) begin |
detect_fis <= 1; |
fis_id_state <= READ_FIS; |
detect_fis <= 1; |
fis_id_state <= READ_FIS; |
end |
end |
READ_FIS: begin |
if (ll_read_strobe) begin |
detect_fis <= 0; |
detect_fis <= 0; |
current_fis <= ll_read_data[7:0]; |
d2h_fis <= ll_read_data[7:0]; |
fis_id_state <= WAIT_FOR_END; |
end |
end |
WAIT_FOR_END: begin |
if (ll_read_finished) begin |
current_fis <= 0; |
fis_id_state <= IDLE; |
current_fis <= 0; |
fis_id_state <= IDLE; |
end |
end |
default: begin |
fis_id_state <= IDLE; |
fis_id_state <= IDLE; |
end |
endcase |
end |
347,11 → 351,12
|
data_write_start <= 0; |
|
ll_write_finished_en <= 0; |
end |
else begin |
//Strobed signals |
if (phy_ready) begin |
//only deassert a link layer strobe when Phy is ready |
//only deassert a link layer strobe when Phy is ready and not sending aligns |
data_write_start <= 0; |
reg_write_start <= 0; |
end |
388,11 → 393,16
cl_if_activate <= 1; |
end |
|
if (ll_write_finished) begin |
ll_write_finished_en <= 1; |
end |
|
case (state) |
IDLE: begin |
register_fis_ptr <= 0; |
reg_read_count <= 0; |
cmd_bit <= 0; |
ll_write_finished_en <= 0; |
//Detect a FIS |
if(ll_read_start) begin |
//detect the start of a frame |
424,13 → 434,13
CHECK_FIS_TYPE: begin |
if (detect_dma_setup) begin |
//XXX: Future work! |
reg_read_count <= reg_read_count + 1; |
reg_read_count <= reg_read_count + 8'h1; |
state <= IDLE; |
end |
else if (detect_dma_activate) begin |
//hard drive is ready to receive data |
state <= DMA_ACTIVATE; |
reg_read_count <= reg_read_count + 1; |
reg_read_count <= reg_read_count + 8'h1; |
//state <= IDLE; |
end |
else if (detect_d2h_data) begin |
445,7 → 455,7
d2h_port_mult <= ll_read_data[11:8]; |
|
state <= READ_D2H_REG; |
reg_read_count <= reg_read_count + 1; |
reg_read_count <= reg_read_count + 8'h1; |
end |
else if (detect_pio_setup) begin |
//store the error, status, direction interrupt from this read |
458,7 → 468,7
d2h_port_mult <= ll_read_data[11:8]; |
|
state <= READ_PIO_SETUP; |
reg_read_count <= reg_read_count + 1; |
reg_read_count <= reg_read_count + 8'h1; |
end |
else if (detect_set_device_bits) begin |
//store the error, a subset of the status bit and the interrupt |
480,10 → 490,10
WRITE_H2D_REG: begin |
if (register_fis_ptr < `FIS_H2D_REG_SIZE) begin |
if (reg_write_strobe) begin |
register_fis_ptr <= register_fis_ptr + 1; |
register_fis_ptr <= register_fis_ptr + 8'h1; |
end |
end |
if (ll_write_finished) begin |
if (ll_write_finished_en) begin |
if (ll_xmit_error) begin |
state <= RETRY; |
end |
494,6 → 504,7
end |
RETRY: begin |
if (link_layer_ready) begin |
ll_write_finished_en <= 0; |
reg_write_start <= 1; |
register_fis_ptr <= 0; |
state <= WRITE_H2D_REG; |
517,7 → 528,7
end |
endcase |
if (reg_read_stb) begin |
reg_read_count <= reg_read_count + 1; |
reg_read_count <= reg_read_count + 8'h1; |
end |
if (ll_read_finished) begin |
d2h_reg_stb <= 1; |
544,7 → 555,7
end |
endcase |
if (reg_read_stb) begin |
reg_read_count <= reg_read_count + 1; |
reg_read_count <= reg_read_count + 8'h1; |
end |
if (ll_read_finished) begin |
pio_setup_stb <= 1; |
563,7 → 574,7
if (ll_write_strobe && send_data_fis_id) begin |
send_data_fis_id <= 0; |
end |
if (ll_write_finished) begin |
if (ll_write_finished_en) begin |
cl_if_activate <= 0; |
state <= IDLE; |
if (pio_response) begin |
/trunk/rtl/link/sata_link_layer_write.v
24,8 → 24,6
|
|
|
//THERE APPEARS TO BE AN ERROR WHEN WRITING TO A HARDDRIVE, IT MANIFESTS AS A CRC ERROR |
|
`include "sata_defines.v" |
|
`define MIN_HOLDA_TIMEOUT 4 |
58,15 → 56,15
output reg send_holda, |
|
output [31:0] tx_dout, |
output tx_isk, |
output tx_is_k, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
|
input write_start, |
output reg write_strobe, |
input [31:0] write_data, |
input [31:0] write_size, //maximum 2048 |
input [23:0] write_size, //maximum 2048 |
input write_hold, |
output reg write_finished, |
output reg xmit_error, |
94,8 → 92,9
//fstate |
parameter FIRST_DATA = 4'h1; |
parameter ENQUEUE = 4'h2; |
parameter WRITE_CRC = 4'h3; |
parameter WAIT = 4'h4; |
parameter LAST_DATA = 4'h3; |
parameter WRITE_CRC = 4'h4; |
parameter WAIT = 4'h5; |
|
//state |
parameter WRITE_START = 4'h1; |
135,7 → 134,6
//CRC |
//XXX: Tie the CRC_EN to the read strobe |
wire [31:0] crc_dout; |
reg [31:0] crc_data; |
|
//Scrambler |
reg scr_rst; |
209,7 → 207,7
(send_sync) ? `PRIM_SYNC: |
bump_buffer[buffer_pos]; |
|
assign tx_isk = ( send_x_rdy || |
assign tx_is_k = ( send_x_rdy || |
send_sof || |
send_eof || |
send_wtrm || |
233,7 → 231,7
|
|
//Synchronous Logic |
//Incomming buffer (this is the buffer afte the scrambler and CRC) |
//Incomming buffer (this is the buffer after the scrambler and CRC) |
always @ (posedge clk) begin |
if (rst) begin |
fstate <= IDLE; |
244,7 → 242,6
scr_rst <= 1; |
wr_en <= 0; |
write_strobe <= 0; |
crc_data <= 0; |
end |
else begin |
//Strobes |
267,46 → 264,44
end |
end |
FIRST_DATA: begin |
//$display ("LLW: Data Size: %d", data_size); |
write_strobe <= 1; |
wr_en <= 1; |
scr_en <= 1; |
scr_din <= write_data; |
fstate <= ENQUEUE; |
if (data_size == 1) begin |
fstate <= LAST_DATA; |
end |
else begin |
fstate <= ENQUEUE; |
end |
end |
ENQUEUE: begin |
if (data_size == 1) begin |
in_data_addra <= in_data_addra + 1; |
wr_en <= 1; |
scr_en <= 1; |
scr_din <= crc_dout; |
fstate <= WRITE_CRC; |
in_data_addra <= in_data_addra + 24'h1; |
wr_en <= 1; |
scr_en <= 1; |
scr_din <= write_data; |
//write_strobe <= 1; |
if (in_data_addra < data_size - 2) begin |
write_strobe <= 1; |
end |
else begin |
if (in_data_addra < data_size - 1) begin |
// if (in_data_addra < data_size) begin |
//Put all the data into the FIFO |
write_strobe <= 1; |
wr_en <= 1; |
scr_en <= 1; |
in_data_addra <= in_data_addra + 1; |
scr_din <= write_data; |
end |
else begin |
//put the CRC into the FIFO |
//in_data_addra <= in_data_addra + 1; |
wr_en <= 1; |
scr_en <= 1; |
in_data_addra <= in_data_addra + 1; |
scr_din <= crc_dout; |
fstate <= WRITE_CRC; |
end |
fstate <= LAST_DATA; |
end |
end |
LAST_DATA: begin |
in_data_addra <= in_data_addra + 24'h1; |
wr_en <= 1; |
scr_en <= 1; |
scr_din <= crc_dout; |
fstate <= WRITE_CRC; |
end |
WRITE_CRC: begin |
fstate <= WAIT; |
fstate <= WAIT; |
end |
WAIT: begin |
scr_rst <= 1; |
scr_rst <= 1; |
if (state == WRITE) begin |
//Because a transaction is in progress and our write buffer is full we can reset the in address to 0 |
in_data_addra <= 0; |
338,7 → 333,7
else begin |
|
if (dhold_delay_cnt < `DHOLD_DELAY) begin |
dhold_delay_cnt <= dhold_delay_cnt + 1; |
dhold_delay_cnt <= dhold_delay_cnt + 4'h1; |
end |
else begin |
dhold_delay <= 1; |
394,6 → 389,7
|
end |
else begin |
//XXX: Remove Bump Buffer |
if ((state == WRITE_START) || ((state != IDLE) && (d_count != write_count))) begin |
bump_buffer[3] <= bump_buffer[2]; |
bump_buffer[2] <= bump_buffer[1]; |
401,6 → 397,7
bump_buffer[0] <= rd_dout; |
d_count <= write_count; |
end |
//XXX: End Remove Bump Buffer |
|
//write_strobe <= 0; |
write_finished <= 0; |
418,7 → 415,7
`endif |
|
if (min_holda_count < `MIN_HOLDA_TIMEOUT) begin |
min_holda_count <= min_holda_count + 1; |
min_holda_count <= min_holda_count + 4'h1; |
end |
|
if (phy_ready) begin |
456,7 → 453,7
state <= WRITE; |
send_sof <= 1; |
//bump_buffer[buffer_pos] <= rd_dout; |
write_count <= write_count + 1; |
write_count <= write_count + 13'h1; |
//Send First Read |
//read the first packet of data |
end |
468,7 → 465,7
WRITE: begin |
if (!write_ready) begin |
if (neg_phy_ready && (buffer_pos == 0)) begin |
buffer_pos <= buffer_pos + 1; |
buffer_pos <= buffer_pos + 4'h1; |
end |
|
`ifdef DHOLD_DELAY_EN |
491,15 → 488,15
end |
|
else begin |
if (write_count <= data_size + 1) begin |
if (write_count <= data_size + 1) begin //is this data_size + 1 for the CRC? |
if (buffer_pos > 0) begin |
buffer_pos <= buffer_pos - 1; |
if (buffer_pos == 1) begin |
write_count <= write_count + 1; |
write_count <= write_count + 13'h1; |
end |
end |
else begin |
write_count <= write_count + 1; |
write_count <= write_count + 13'h1; |
end |
end |
else begin |
516,7 → 513,7
`endif |
min_holda_count <= 0; |
//XXX: I may need this to capture holds at the end of a trnasfer |
buffer_pos <= buffer_pos + 1; |
buffer_pos <= buffer_pos + 4'h1; |
send_holda <= 1; |
end |
end |
/trunk/rtl/link/sata_link_layer_read.v
49,10 → 49,10
input detect_xrdy_xrdy, |
|
output [31:0] tx_dout, |
output tx_isk, |
output tx_is_k, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
|
output reg read_strobe, |
output reg [31:0] read_data, |
91,11 → 91,7
|
//CRC |
//XXX: Tie the CRC_EN to an incomming data dword |
wire crc_en; |
wire [31:0] crc_din; |
wire [31:0] crc_dout; |
reg crc_data; |
reg crc_check; |
|
reg [31:0] prev_crc; |
reg [31:0] prev_data; |
110,18 → 106,10
wire [31:0] descr_dout; |
|
//SubModules |
crc c ( |
.rst (rst || idle ), |
.clk (clk ), |
.en (crc_en ), |
.din (crc_din ), |
.dout (crc_dout ) |
); |
|
scrambler descr ( |
.rst (rst || idle), |
.clk (clk ), |
.prim_scrambler (0 ), |
.prim_scrambler (1'b0 ), |
.en (descr_en ), |
.din (rx_din ), |
.dout (descr_dout ) |
140,7 → 128,7
(send_holda) ? `PRIM_HOLDA : |
`PRIM_SYNC; |
|
assign tx_isk = ( send_r_rdy || |
assign tx_is_k = ( send_r_rdy || |
send_r_ip || |
send_r_err || |
send_r_ok || |
153,12 → 141,11
assign read_finished = detect_eof; |
assign read_start = detect_sof; |
assign data_valid = (state == READ) && |
(rx_isk == 0) && |
(rx_is_k == 0) && |
(!detect_hold) && |
(!detect_holda) && |
(!detect_align); |
|
assign crc_en = data_valid; |
assign descr_en = (data_scrambler_en && (detect_sof || data_valid)); |
assign descr_din = (data_valid) ? rx_din : 32'h00000000; |
//assign crc_ok = (prev_data == prev_crc); |
/trunk/rtl/link/sata_link_layer.v
42,15 → 42,15
|
//XXX: I probably need some feedback to indicate that there is room to write |
output [31:0] tx_dout, |
output tx_isk, |
output tx_is_k, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
|
input write_start, |
output write_strobe, |
input [31:0] write_data, |
input [31:0] write_size, |
input [23:0] write_size, |
input write_hold, |
output write_finished, |
input write_abort, |
122,20 → 122,20
|
wire sli_idle; |
wire [31:0] sli_tx_dout; |
wire sli_tx_isk; |
wire sli_tx_is_k; |
|
reg write_en; |
wire write_idle; |
wire [31:0] slw_tx_dout; |
wire slw_tx_isk; |
wire slw_tx_is_k; |
|
reg read_en; |
wire read_idle; |
wire [31:0] slr_tx_dout; |
wire slr_tx_isk; |
wire slr_tx_is_k; |
|
wire [31:0] ll_tx_dout; |
wire ll_tx_isk; |
wire ll_tx_is_k; |
|
wire last_prim; |
|
155,13 → 155,13
.last_prim (last_prim ), |
|
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
|
.ll_tx_din (ll_tx_dout ), |
.ll_tx_isk (ll_tx_isk ), |
.ll_tx_is_k (ll_tx_is_k ), |
|
.cont_tx_dout (tx_dout ), |
.cont_tx_isk (tx_isk ), |
.cont_tx_is_k (tx_is_k ), |
|
.detect_sync (detect_sync ), |
.detect_r_rdy (detect_r_rdy ), |
216,9 → 216,9
.post_align_write (post_align_write ), |
|
.tx_dout (slw_tx_dout ), |
.tx_isk (slw_tx_isk ), |
.tx_is_k (slw_tx_is_k ), |
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
|
.xmit_error (xmit_error ), |
.wsize_z_error (wsize_z_error ), |
255,9 → 255,9
.detect_xrdy_xrdy (detect_xrdy_xrdy ), |
|
.tx_dout (slr_tx_dout ), |
.tx_isk (slr_tx_isk ), |
.tx_is_k (slr_tx_is_k ), |
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
|
.read_ready (read_ready ), |
.read_strobe (read_strobe ), |
275,7 → 275,7
|
//Asynchronous logic |
assign ll_tx_dout = (!read_idle) ? slr_tx_dout : (!write_idle) ? slw_tx_dout : sli_tx_dout; |
assign ll_tx_isk = (!read_idle) ? slr_tx_isk : (!write_idle) ? slw_tx_isk : sli_tx_isk; |
assign ll_tx_is_k = (!read_idle) ? slr_tx_is_k : (!write_idle) ? slw_tx_is_k : sli_tx_is_k; |
|
|
assign sli_tx_dout = (send_pmnack) ? `PRIM_PMNACK : |
282,7 → 282,7
(send_pmack) ? `PRIM_PMACK : |
`PRIM_SYNC; |
|
assign sli_tx_isk = 1; |
assign sli_tx_is_k = 1; |
|
assign link_layer_ready = (state == IDLE) && read_idle && write_idle; |
|
/trunk/rtl/link/cont_controller.v
36,13 → 36,13
|
|
input [31:0] ll_tx_din, |
input ll_tx_isk, |
input ll_tx_is_k, |
|
output [31:0] cont_tx_dout, |
output cont_tx_isk, |
output cont_tx_is_k, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
|
output detect_sync, |
output detect_r_rdy, |
118,39 → 118,39
); |
|
//Asynchronous Logic |
assign detect_sync = ((rx_isk[0]) && (rx_din == `PRIM_SYNC )) || sync_cont; //sync (normal) == sync(cont) |
assign detect_r_rdy = ((rx_isk[0]) && (rx_din == `PRIM_R_RDY )) || r_rdy_cont; |
assign detect_r_ip = ((rx_isk[0]) && (rx_din == `PRIM_R_IP )) || r_ip_cont; |
assign detect_r_err = ((rx_isk[0]) && (rx_din == `PRIM_R_ERR )) || r_err_cont; |
assign detect_r_ok = ((rx_isk[0]) && (rx_din == `PRIM_R_OK )) || r_ok_cont; |
assign detect_x_rdy = ((rx_isk[0]) && (rx_din == `PRIM_X_RDY )) || x_rdy_cont; |
assign detect_sof = (rx_isk[0]) && (rx_din == `PRIM_SOF ); |
assign detect_eof = (rx_isk[0]) && (rx_din == `PRIM_EOF ); |
assign detect_wtrm = ((rx_isk[0]) && (rx_din == `PRIM_WTRM )) || wtrm_cont; |
assign detect_cont = (rx_isk[0]) && (rx_din == `PRIM_CONT ); |
assign detect_hold = ((rx_isk[0]) && (rx_din == `PRIM_HOLD )) || hold_cont; //hold (normal) == hold (cont) |
assign detect_holda = ((rx_isk[0]) && (rx_din == `PRIM_HOLDA )) || holda_cont; //holda (normal) == holda (cont) |
assign detect_preq_s = ((rx_isk[0]) && (rx_din == `PRIM_PREQ_S )) || pmreq_s_cont; |
assign detect_preq_p = ((rx_isk[0]) && (rx_din == `PRIM_PREQ_P )) || pmreq_p_cont; |
assign detect_align = (rx_isk[0]) && (rx_din == `PRIM_ALIGN ); |
assign detect_sync = ((rx_is_k[0]) && (rx_din == `PRIM_SYNC )) || sync_cont; //sync (normal) == sync(cont) |
assign detect_r_rdy = ((rx_is_k[0]) && (rx_din == `PRIM_R_RDY )) || r_rdy_cont; |
assign detect_r_ip = ((rx_is_k[0]) && (rx_din == `PRIM_R_IP )) || r_ip_cont; |
assign detect_r_err = ((rx_is_k[0]) && (rx_din == `PRIM_R_ERR )) || r_err_cont; |
assign detect_r_ok = ((rx_is_k[0]) && (rx_din == `PRIM_R_OK )) || r_ok_cont; |
assign detect_x_rdy = ((rx_is_k[0]) && (rx_din == `PRIM_X_RDY )) || x_rdy_cont; |
assign detect_sof = (rx_is_k[0]) && (rx_din == `PRIM_SOF ); |
assign detect_eof = (rx_is_k[0]) && (rx_din == `PRIM_EOF ); |
assign detect_wtrm = ((rx_is_k[0]) && (rx_din == `PRIM_WTRM )) || wtrm_cont; |
assign detect_cont = (rx_is_k[0]) && (rx_din == `PRIM_CONT ); |
assign detect_hold = ((rx_is_k[0]) && (rx_din == `PRIM_HOLD )) || hold_cont; //hold (normal) == hold (cont) |
assign detect_holda = ((rx_is_k[0]) && (rx_din == `PRIM_HOLDA )) || holda_cont; //holda (normal) == holda (cont) |
assign detect_preq_s = ((rx_is_k[0]) && (rx_din == `PRIM_PREQ_S )) || pmreq_s_cont; |
assign detect_preq_p = ((rx_is_k[0]) && (rx_din == `PRIM_PREQ_P )) || pmreq_p_cont; |
assign detect_align = (rx_is_k[0]) && (rx_din == `PRIM_ALIGN ); |
|
assign detect_xrdy_xrdy = ((((rx_isk[0])&& (rx_din == `PRIM_X_RDY )) || x_rdy_cont) && ll_tx_isk && (ll_tx_din == `PRIM_X_RDY)); |
assign detect_xrdy_xrdy = ((((rx_is_k[0])&& (rx_din == `PRIM_X_RDY )) || x_rdy_cont) && ll_tx_is_k && (ll_tx_din == `PRIM_X_RDY)); |
|
assign sync_cont = sync_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign hold_cont = hold_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign holda_cont = holda_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign pmreq_p_cont = pmreq_p_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign pmreq_s_cont = pmreq_s_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign r_err_cont = r_err_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign r_ip_cont = r_ip_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign r_ok_cont = r_ok_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign r_rdy_cont = r_rdy_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign wtrm_cont = wtrm_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign x_rdy_cont = x_rdy_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_isk[0] || detect_align)); |
assign sync_cont = sync_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign hold_cont = hold_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign holda_cont = holda_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign pmreq_p_cont = pmreq_p_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign pmreq_s_cont = pmreq_s_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign r_err_cont = r_err_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign r_ip_cont = r_ip_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign r_ok_cont = r_ok_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign r_rdy_cont = r_rdy_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign wtrm_cont = wtrm_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
assign x_rdy_cont = x_rdy_cont_ready && ((rx_din == `PRIM_CONT) || (!rx_is_k[0] || detect_align)); |
|
|
assign cont_tx_dout = (!xmit_cont_en) ? ll_tx_din : //when transmit cont gen is disable |
((tx_prev_prim != ll_tx_din) && ll_tx_isk) ? ll_tx_din : //if the prev != curr (exit) |
((tx_prev_prim != ll_tx_din) && ll_tx_is_k) ? ll_tx_din : //if the prev != curr (exit) |
(last_prim) ? ll_tx_din: |
(tx_cont_enable) ? //if the cont is enabled |
send_cont ? `PRIM_CONT : //need to first send the cont |
157,13 → 157,13
scram_dout : //send the junk |
ll_tx_din; //tx cont is not enabled |
|
assign cont_tx_isk = (!xmit_cont_en) ? ll_tx_isk : |
((tx_prev_prim != ll_tx_din) && ll_tx_isk) ? ll_tx_isk ://if the prev != curr (exit) |
(last_prim) ?ll_tx_isk: |
(tx_cont_enable) ? //if the cont is enabled |
send_cont ? 1 : //need to first send the cont |
0 : //send the junk |
ll_tx_isk; //tx cont is not enabled |
assign cont_tx_is_k = (!xmit_cont_en) ? ll_tx_is_k : |
((tx_prev_prim != ll_tx_din) && ll_tx_is_k) ? ll_tx_is_k ://if the prev != curr (exit) |
(last_prim) ?ll_tx_is_k: |
(tx_cont_enable) ? //if the cont is enabled |
send_cont ? 1'b1 : //need to first send the cont |
1'b0 : //send the junk |
ll_tx_is_k; //tx cont is not enabled |
assign scram_en = tx_cont_enable; |
|
//Synchronous logic |
188,7 → 188,7
end |
else begin |
if (!detect_align) begin |
if (rx_isk) begin |
if (rx_is_k) begin |
if (rx_din == `PRIM_CONT) begin |
cont_detect <= 1; |
end |
275,7 → 275,7
|
end |
end |
if (!rx_isk[0] && !cont_detect) begin |
if (!rx_is_k[0] && !cont_detect) begin |
cont_detect <= 0; |
hold_cont_ready <= 0; |
holda_cont_ready <= 0; |
307,7 → 307,7
|
send_cont <= 0; |
|
if (ll_tx_isk) begin |
if (ll_tx_is_k) begin |
|
//reset everything because the previous primative is not equal to the current one |
if (tx_prev_prim != ll_tx_din) begin |
/trunk/rtl/command/sata_command_layer.v
37,23 → 37,21
input data_out_clk_valid, |
|
//User Interface |
output sata_init, |
output command_layer_ready, |
output reg busy, |
output reg sata_busy, |
input send_sync_escape, |
input [15:0] user_features, |
|
//XXX: New Stb |
input write_data_en, |
input single_rdwr, |
input read_data_en, |
output dev_error, |
// input write_data_stb, |
// input read_data_stb, |
output hard_drive_error, |
|
input send_user_command_stb, |
input soft_reset_en, |
input execute_command_stb, |
input command_layer_reset, |
|
output reg pio_data_ready, |
input [7:0] command, |
input [7:0] hard_drive_command, |
|
input [15:0] sector_count, |
input [47:0] sector_address, |
63,6 → 61,7
output [1:0] user_din_ready, |
input [1:0] user_din_activate, |
output [23:0] user_din_size, |
output user_din_empty, |
|
output [31:0] user_dout, |
output user_dout_ready, |
116,7 → 115,26
input [7:0] d2h_status, |
input [7:0] d2h_error, |
|
output d2h_error_bbk, //Bad Block |
output d2h_error_unc, //Uncorrectable Error |
output d2h_error_mc, //Removable Media Error |
output d2h_error_idnf, //request sector's ID Field could not be found |
output d2h_error_mcr, //Removable Media Error |
output d2h_error_abrt, //Abort (from invalid command, drive not ready, write fault) |
output d2h_error_tk0nf, //Track 0 not found |
output d2h_error_amnf, //Data Address Mark is not found after finding correct ID |
|
output d2h_status_bsy, //Set to 1 when drive has access to command block, no other bits are valid when 1 |
// Set after reset |
// Set after soft reset (srst) |
// Set immediately after host writes to command register |
output d2h_status_drdy, //Drive is ready to accept command |
output d2h_status_dwf, //Drive Write Fault |
output d2h_status_dsc, //Drive Seek Complete |
output d2h_status_drq, //Data Request, Drive is ready to send data to the host |
output d2h_status_corr, //Correctable Data bit (an error that was encountered but was corrected) |
output d2h_status_idx, //once per disc revolution this bit is set to one then back to zero |
output d2h_status_err, //error bit, if this bit is high check the error flags |
|
//command layer data interface |
input t_if_strobe, |
134,8 → 152,7
|
//Debug |
output [3:0] cl_c_state, |
output [3:0] cl_w_state, |
output [3:0] cl_r_state |
output [3:0] cl_w_state |
|
); |
|
145,12 → 162,9
parameter PIO_WAIT_FOR_DATA = 4'h1; |
parameter PIO_WRITE_DATA = 4'h2; |
|
parameter WAIT_FOR_DATA = 4'h1; |
|
parameter WAIT_FOR_DMA_ACT = 4'h1; |
parameter WAIT_FOR_WRITE_DATA = 4'h2; |
parameter SEND_DATA = 4'h3; |
parameter WAIT_FOR_STATUS = 4'h4; |
|
//Registers/Wires |
reg [3:0] cntrl_state; |
159,31 → 173,16
wire idle; |
reg cntrl_send_data_stb; |
reg send_command_stb; |
reg prev_send_command; |
|
wire dev_busy; |
wire dev_data_req; |
|
reg [31:0] reset_count; |
wire reset_timeout; |
|
//Read State Machine |
reg [3:0] read_state; |
reg read_data_stb; |
reg single_read_prev; |
|
//Write State Machine |
reg [3:0] write_state; |
reg write_data_stb; |
reg single_write_prev; |
|
reg dma_send_data_stb; |
reg dma_act_detected; |
reg dma_act_detected_en; |
|
wire write_data_available; |
reg first_write; |
reg first_read; |
|
reg enable_tl_data_ready; |
|
//Ping Pong FIFOs |
191,7 → 190,6
wire [1:0] if_write_activate; |
wire [23:0] if_write_size; |
wire if_write_strobe; |
wire if_starved; |
wire [31:0] if_write_data; |
|
wire if_read_strobe; |
233,7 → 231,8
.write_activate (if_write_activate ), |
.write_fifo_size (if_write_size ), |
.write_strobe (if_write_strobe ), |
.starved (if_starved ), |
//.starved (if_starved ), |
.starved (user_din_empty ), |
|
//read side |
//XXX: This can be different clocks |
242,7 → 241,8
.read_ready (if_read_ready ), |
.read_activate (if_read_activate ), |
.read_count (if_read_size ), |
.read_data (if_read_data ) |
.read_data (if_read_data ), |
.inactive ( ) |
); |
|
|
262,7 → 262,8
.write_activate (of_write_activate ), |
.write_fifo_size (of_write_size ), |
.write_strobe (of_write_strobe ), |
.starved (out_fifo_starved ), |
//.starved (out_fifo_starved ), |
.starved ( ), |
|
//read side |
//XXX: This can be different clocks |
271,7 → 272,8
.read_ready (of_read_ready ), |
.read_activate (of_read_activate ), |
.read_count (of_read_size ), |
.read_data (of_read_data ) |
.read_data (of_read_data ), |
.inactive ( ) |
); |
|
|
302,10 → 304,7
assign if_write_strobe = user_din_stb; |
assign user_din_ready = if_write_ready; |
assign if_write_activate = user_din_activate; |
//assign user_din_size = if_write_size; |
assign user_din_size = 24'h00800; |
//assign user_din_size = 24'h00400; |
//assign user_din_size = 24'h00200; |
assign user_din_size = if_write_size; |
|
assign user_dout = of_read_data; |
assign user_dout_ready = of_read_ready; |
313,32 → 312,39
assign user_dout_size = of_read_size; |
assign of_read_strobe = user_dout_stb; |
|
assign d2h_status_bsy = d2h_status[7]; |
assign d2h_status_drdy = d2h_status[6]; |
assign d2h_status_dwf = d2h_status[5]; |
assign d2h_status_dsc = d2h_status[4]; |
assign d2h_status_drq = d2h_status[3]; |
assign d2h_status_corr = d2h_status[2]; |
assign d2h_status_idx = d2h_status[1]; |
assign d2h_status_err = d2h_status[0]; |
|
assign write_data_available = (if_read_ready || if_read_activate) || (if_write_ready != 2'b11); |
assign d2h_error_bbk = d2h_error[7]; |
assign d2h_error_unc = d2h_error[6]; |
assign d2h_error_mc = d2h_error[5]; |
assign d2h_error_idnf = d2h_error[4]; |
assign d2h_error_mcr = d2h_error[3]; |
assign d2h_error_abrt = d2h_error[2]; |
assign d2h_error_tk0nf = d2h_error[1]; |
assign d2h_error_amnf = d2h_error[0]; |
|
|
//Strobes |
assign t_send_command_stb = read_data_stb || write_data_stb || send_command_stb; |
//assign t_send_command_stb = read_data_stb || write_data_stb || execute_command_stb; |
assign t_send_command_stb = execute_command_stb; |
assign t_send_data_stb = dma_send_data_stb ||cntrl_send_data_stb; |
|
//IDLE |
assign idle = (cntrl_state == IDLE) && |
(read_state == IDLE) && |
(write_state == IDLE) && |
transport_layer_ready; |
|
assign command_layer_ready = idle; |
assign sata_init = reset_timeout; |
|
assign h2d_command = (write_data_en) ? `COMMAND_DMA_WRITE_EX : |
(read_data_en) ? `COMMAND_DMA_READ_EX : |
(send_user_command_stb) ? command : |
h2d_command; |
|
assign h2d_command = hard_drive_command; |
assign h2d_sector_count = sector_count; |
assign h2d_lba = (write_data_en) ? (!single_rdwr && !first_write) ? d2h_lba + 1 : sector_address : |
(read_data_en) ? (!single_rdwr && !first_read) ? d2h_lba + 1 : sector_address : |
sector_address; |
assign h2d_lba = sector_address; |
|
//XXX: The individual bits should be controlled directly |
assign h2d_control = {5'h00, srst, 2'b00}; |
349,14 → 355,11
|
assign dev_busy = status[`STATUS_BUSY_BIT]; |
assign dev_data_req = status[`STATUS_DRQ_BIT]; |
assign dev_error = status[`STATUS_ERR_BIT]; |
assign hard_drive_error = status[`STATUS_ERR_BIT]; |
|
assign cl_c_state = cntrl_state; |
assign cl_r_state = read_state; |
assign cl_w_state = write_state; |
assign cl_c_state = cntrl_state; |
assign cl_w_state = write_state; |
|
assign reset_timeout = (reset_count >= `RESET_TIMEOUT); |
|
//Synchronous Logic |
|
//Control State Machine |
373,54 → 376,37
pio_data_ready <= 0; |
status <= 0; |
|
prev_send_command <= 0; |
send_command_stb <= 0; |
|
reset_count <= 0; |
busy <= 1; |
sata_busy <= 0; |
sync_escape <= 0; |
end |
else begin |
t_send_control_stb <= 0; |
cntrl_send_data_stb <= 0; |
pio_data_ready <= 0; |
send_command_stb <= 0; |
|
//Reset Count |
if (reset_count < `RESET_TIMEOUT) begin |
reset_count <= reset_count + 1; |
end |
if (!reset_timeout) begin |
cntrl_state <= IDLE; |
end |
|
//detected the first a user attempting to send a command |
if (send_user_command_stb && !prev_send_command) begin |
prev_send_command <= 1; |
send_command_stb <= 1; |
end |
if (!send_user_command_stb) begin |
prev_send_command <= 0; |
end |
|
if (t_d2h_reg_stb) begin |
busy <= 0; |
//Receiving a register strobe from the device |
sata_busy <= 0; |
h2d_features <= `D2H_REG_FEATURES; |
end |
if (t_send_command_stb || t_send_control_stb || send_user_command_stb) begin |
busy <= 1; |
if (send_user_command_stb) begin |
h2d_features <= user_features; |
end |
/* |
if (t_send_command_stb || t_send_control_stb) begin |
sata_busy <= 1; |
end |
*/ |
if (execute_command_stb) begin |
h2d_features <= user_features; |
sata_busy <= 1; |
end |
|
case (cntrl_state) |
IDLE: begin |
|
//Soft Reset will break out of any flow |
if ((soft_reset_en) && !srst) begin |
if (command_layer_reset && !srst) begin |
srst <= 1; |
t_send_control_stb <= 1; |
reset_count <= 0; |
end |
|
if (idle) begin |
427,7 → 413,7
//The only way to transition to another state is if CL is IDLE |
|
//User Initiated commands |
if (!soft_reset_en && srst && reset_timeout) begin |
if (!command_layer_reset && srst) begin |
srst <= 0; |
t_send_control_stb <= 1; |
end |
475,146 → 461,43
|
if (send_sync_escape) begin |
cntrl_state <= IDLE; |
busy <= 0; |
sync_escape <= 1; |
sata_busy <= 0; |
end |
end |
end |
|
//Read State Machine |
always @ (posedge clk) begin |
if (rst || (!linkup)) begin |
read_state <= IDLE; |
sync_escape <= 0; |
read_data_stb <= 0; |
single_read_prev <= 0; |
first_read <= 1; |
end |
else begin |
read_data_stb <= 0; |
sync_escape <= 0; |
|
if (!read_data_en) begin |
single_read_prev <= 0; |
end |
|
case (read_state) |
IDLE: begin |
if (idle) begin |
sync_escape <= 0; |
//The only way to transition to another state is if CL is IDLE |
if (read_data_en) begin |
if (single_rdwr) begin |
if (!single_read_prev) begin |
single_read_prev <= 1; |
read_data_stb <= 1; |
read_state <= WAIT_FOR_DATA; |
end |
end |
else begin |
//send a request to read data |
read_data_stb <= 1; |
read_state <= WAIT_FOR_DATA; |
end |
end |
else begin |
first_read <= 1; |
end |
end |
end |
WAIT_FOR_DATA: begin |
//This state seems useless because it only sets a value but the state is used to indicate the system is idle or not |
if (t_d2h_data_stb) begin |
first_read <= 0; |
end |
/* |
if (soft_reset_en) begin |
//XXX: Issue a SYNC ESCAPE to cancel a large read request otherwise let it play out |
//sync_escape <= 1; |
end |
*/ |
end |
default: begin |
read_state <= IDLE; |
end |
endcase |
|
if (soft_reset_en || !reset_timeout || send_sync_escape) begin |
if (read_state != IDLE) begin |
sync_escape <= 1; |
end |
if (send_sync_escape) begin |
sync_escape <= 1; |
end |
read_state <= IDLE; |
end |
|
//If this is received go back to IDLE |
if (t_d2h_reg_stb) begin |
read_state <= IDLE; |
end |
end |
end |
|
//Write State Machine |
always @ (posedge clk) begin |
if (rst || (!linkup)) begin |
if (rst || !linkup) begin |
write_state <= IDLE; |
|
dma_send_data_stb <= 0; |
|
write_data_stb <= 0; |
single_write_prev <= 0; |
first_write <= 1; |
enable_tl_data_ready <= 0; |
|
dma_act_detected <= 0; |
dma_act_detected_en <= 0; |
end |
else begin |
dma_send_data_stb <= 0; |
write_data_stb <= 0; |
|
if (enable_tl_data_ready && if_read_activate) begin |
//Closes the loop on the data write feedback |
enable_tl_data_ready <= 0; |
end |
|
if (!write_data_en) begin |
single_write_prev <= 0; |
end |
|
if (t_dma_activate_stb) begin |
//Set an enable signal instead of a strobe so that there is no chance of missing this signal |
dma_act_detected <= 1; |
dma_act_detected_en <= 1; |
end |
|
case (write_state) |
IDLE: begin |
enable_tl_data_ready <= 0; |
if (idle) begin |
//The only way to transition to another state is if CL is IDLE |
if (write_data_en) begin |
if (single_rdwr) begin |
if (!single_write_prev) begin |
single_write_prev <= 1; |
write_state <= WAIT_FOR_DMA_ACT; |
write_data_stb <= 1; |
end |
end |
else begin |
//send a request to write data |
write_state <= WAIT_FOR_DMA_ACT; |
write_data_stb <= 1; |
end |
//if (write_data_stb) begin |
if (dma_act_detected_en) begin |
//send a request to write data |
write_state <= WAIT_FOR_DMA_ACT; |
end |
else begin |
//reset the the first write when the user deassertes the write_data_en |
first_write <= 1; |
end |
end |
end |
WAIT_FOR_DMA_ACT: begin |
if (dma_act_detected) begin |
dma_act_detected <= 0; |
first_write <= 0; |
if (dma_act_detected_en) begin |
dma_act_detected_en <= 0; |
enable_tl_data_ready <= 1; |
write_state <= WAIT_FOR_WRITE_DATA; |
end |
621,6 → 504,7
end |
WAIT_FOR_WRITE_DATA: begin |
if (if_read_activate) begin |
enable_tl_data_ready <= 0; |
write_state <= SEND_DATA; |
end |
end |
628,11 → 512,7
if (transport_layer_ready) begin |
//Send the Data FIS |
dma_send_data_stb <= 1; |
write_state <= WAIT_FOR_DMA_ACT; |
end |
end |
WAIT_FOR_STATUS: begin |
if (t_d2h_reg_stb) begin |
dma_act_detected_en <= 0; |
write_state <= IDLE; |
end |
end |
642,7 → 522,8
endcase |
|
|
if (soft_reset_en || !reset_timeout) begin |
//if (command_layer_reset || !reset_timeout) begin |
if (command_layer_reset) begin |
//Break out of the normal flow and return to IDLE |
write_state <= IDLE; |
end |
656,8 → 537,5
end |
end |
|
|
|
endmodule |
|
|
/trunk/sim/tb_cocotb.v
11,12 → 11,14
|
output linkup, //link is finished |
output sata_ready, |
output busy, |
output sata_busy, |
|
input write_data_en, |
input read_data_en, |
//input write_data_stb, |
//input read_data_stb, |
input [7:0] hard_drive_command, |
input execute_command_stb, |
|
input soft_reset_en, |
input command_layer_reset, |
input [15:0] sector_count, |
input [47:0] sector_address, |
|
61,23 → 63,21
reg [31:0] test_id = 0; |
|
wire [31:0] tx_dout; |
wire tx_isk; |
wire tx_is_k; |
wire tx_comm_reset; |
wire tx_comm_wake; |
wire tx_elec_idle; |
|
wire [31:0] rx_din; |
wire [3:0] rx_isk; |
wire [3:0] rx_is_k; |
wire rx_elec_idle; |
wire comm_init_detect; |
wire comm_wake_detect; |
|
wire rx_byte_is_aligned; |
|
reg r_rst; |
reg r_write_data_en; |
reg r_read_data_en; |
reg r_soft_reset_en; |
reg r_write_data_stb; |
reg r_read_data_stb; |
reg r_command_layer_reset; |
reg [15:0] r_sector_count; |
reg [47:0] r_sector_address; |
reg r_prim_scrambler_en; |
85,24 → 85,26
reg r_platform_ready; |
reg r_dout_count; |
reg r_hold; |
reg r_single_rdwr; |
|
reg r_u2h_write_enable; |
reg [23:0] r_u2h_write_count; |
reg [23:0] r_u2h_write_count; |
reg r_h2u_read_enable; |
|
reg [7:0] r_hard_drive_command; |
reg r_execute_command_stb; |
|
wire hd_read_from_host; |
wire [31:0] hd_data_from_host; |
|
|
wire [31:0] hd_data_from_host; |
|
|
wire hd_write_to_host; |
wire [31:0] hd_data_to_host; |
wire [31:0] hd_data_to_host; |
|
wire [31:0] user_dout; |
wire [31:0] user_dout; |
wire user_dout_ready; |
wire user_dout_activate; |
wire user_dout_stb; |
wire [23:0] user_dout_size; |
wire [23:0] user_dout_size; |
|
|
wire [31:0] user_din; |
111,11 → 113,24
wire [1:0] user_din_activate; |
wire [23:0] user_din_size; |
|
wire dma_activate_stb; |
wire d2h_reg_stb; |
wire pio_setup_stb; |
wire d2h_data_stb; |
wire dma_setup_stb; |
wire set_device_bits_stb; |
wire [7:0] d2h_fis; |
wire i_rx_byte_is_aligned; |
|
|
|
|
|
//There is a bug in COCOTB when stiumlating a signal, sometimes it can be corrupted if not registered |
always @ (*) r_rst = rst; |
always @ (*) r_write_data_en = write_data_en; |
always @ (*) r_read_data_en = read_data_en; |
always @ (*) r_soft_reset_en = soft_reset_en; |
//always @ (*) r_write_data_stb = write_data_stb; |
//always @ (*) r_read_data_stb = read_data_stb; |
always @ (*) r_command_layer_reset= command_layer_reset; |
always @ (*) r_sector_count = sector_count; |
always @ (*) r_sector_address = sector_address; |
always @ (*) r_prim_scrambler_en = prim_scrambler_en; |
122,7 → 137,6
always @ (*) r_data_scrambler_en = data_scrambler_en; |
always @ (*) r_platform_ready = platform_ready; |
always @ (*) r_hold = hold; |
always @ (*) r_single_rdwr = single_rdwr; |
|
always @ (*) r_u2h_write_enable = u2h_write_enable; |
always @ (*) r_u2h_write_count = u2h_write_count; |
129,6 → 143,9
|
always @ (*) r_h2u_read_enable = h2u_read_enable; |
|
always @ (*) r_hard_drive_command = hard_drive_command; |
always @ (*) r_execute_command_stb= execute_command_stb; |
|
//Submodules |
|
//User Generated Test Data |
187,37 → 204,49
sata_stack ss ( |
.rst (r_rst ), //reset |
.clk (clk ), //clock used to run the stack |
.data_in_clk (clk ), |
.data_in_clk_valid (1'b1 ), |
.data_out_clk (clk ), |
.data_out_clk_valid (1'b1 ), |
.command_layer_reset (r_command_layer_reset), |
|
.platform_ready (platform_ready ), //the underlying physical platform is |
.platform_error ( ), |
.linkup (linkup ), //link is finished |
|
.sata_ready (sata_ready ), |
.sata_busy (sata_busy ), |
|
.busy (busy ), |
.send_sync_escape (1'b0 ), |
.hard_drive_error ( ), |
|
.write_data_en (r_write_data_en ), |
.single_rdwr (r_single_rdwr ), |
.read_data_en (r_read_data_en ), |
.pio_data_ready ( ), |
|
.send_user_command_stb (1'b0 ), |
.soft_reset_en (r_soft_reset_en ), |
.command (1'b0 ), |
|
//Host to Device Control |
// .write_data_stb (r_write_data_stb ), |
// .read_data_stb (r_read_data_stb ), |
.hard_drive_command (r_hard_drive_command ), |
.execute_command_stb (r_execute_command_stb), |
.user_features (16'h0000 ), |
.sector_count (r_sector_count ), |
.sector_address (r_sector_address ), |
|
.d2h_interrupt (d2h_interrupt ), |
.d2h_notification (d2h_notification ), |
.d2h_port_mult (d2h_port_mult ), |
.d2h_device (d2h_device ), |
.d2h_lba (d2h_lba ), |
.d2h_sector_count (d2h_sector_count ), |
.d2h_status (d2h_status ), |
.d2h_error (d2h_error ), |
.dma_activate_stb (dma_activate_stb ), |
.d2h_reg_stb (d2h_reg_stb ), |
.pio_setup_stb (pio_setup_stb ), |
.d2h_data_stb (d2h_data_stb ), |
.dma_setup_stb (dma_setup_stb ), |
.set_device_bits_stb (set_device_bits_stb ), |
|
.d2h_fis (d2h_fis ), |
.d2h_interrupt (d2h_interrupt ), |
.d2h_notification (d2h_notification ), |
.d2h_port_mult (d2h_port_mult ), |
.d2h_device (d2h_device ), |
.d2h_lba (d2h_lba ), |
.d2h_sector_count (d2h_sector_count ), |
.d2h_status (d2h_status ), |
.d2h_error (d2h_error ), |
|
//Data from host to the hard drive path |
.data_in_clk (clk ), |
.data_in_clk_valid (1'b1 ), |
.user_din (user_din ), //User Data Here |
.user_din_stb (user_din_stb ), //Strobe Each Data word in here |
.user_din_ready (user_din_ready ), //Using PPFIFO Ready Signal |
224,6 → 253,9
.user_din_activate (user_din_activate ), //Activate PPFIFO Channel |
.user_din_size (user_din_size ), //Find the size of the data to write to the device |
|
//Data from hard drive to host path |
.data_out_clk (clk ), |
.data_out_clk_valid (1'b1 ), |
.user_dout (user_dout ), |
.user_dout_ready (user_dout_ready ), |
.user_dout_activate (user_dout_activate ), |
233,23 → 265,27
.transport_layer_ready (transport_layer_ready), |
.link_layer_ready (link_layer_ready ), |
.phy_ready (phy_ready ), |
.phy_error (1'b0 ), |
|
.tx_dout (tx_dout ), |
.tx_isk (tx_isk ), |
.tx_is_k (tx_is_k ), |
.tx_comm_reset (tx_comm_reset ), |
.tx_comm_wake (tx_comm_wake ), |
.tx_elec_idle (tx_elec_idle ), |
.tx_oob_complete (1'b1 ), |
|
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
.rx_elec_idle (rx_elec_idle ), |
.rx_byte_is_aligned (i_rx_byte_is_aligned ), |
.comm_init_detect (comm_init_detect ), |
.comm_wake_detect (comm_wake_detect ), |
.rx_byte_is_aligned (rx_byte_is_aligned ), |
|
|
.prim_scrambler_en (r_prim_scrambler_en ), |
.data_scrambler_en (r_data_scrambler_en ) |
//.prim_scrambler_en (r_prim_scrambler_en ), |
.prim_scrambler_en (1'b1 ), |
//.data_scrambler_en (r_data_scrambler_en ) |
.data_scrambler_en (1'b1 ) |
); |
|
faux_sata_hd fshd ( |
256,12 → 292,12
.rst (r_rst ), |
.clk (clk ), |
.tx_dout (rx_din ), |
.tx_isk (rx_isk ), |
.tx_is_k (rx_is_k ), |
|
.rx_din (tx_dout ), |
.rx_isk ({3'b000, tx_isk} ), |
.rx_is_k ({3'b000, tx_is_k} ), |
.rx_is_elec_idle (tx_elec_idle ), |
.rx_byte_is_aligned (rx_byte_is_aligned ), |
.rx_byte_is_aligned (i_rx_byte_is_aligned ), |
|
.comm_reset_detect (tx_comm_reset ), |
.comm_wake_detect (tx_comm_wake ), |
273,43 → 309,45
// .phy_ready (phy_ready ), |
|
|
.dbg_data_scrambler_en (r_data_scrambler_en ), |
//.dbg_data_scrambler_en (r_data_scrambler_en ), |
.dbg_data_scrambler_en (1'b1 ), |
|
.dbg_hold (r_hold ), |
|
.dbg_ll_write_start (0 ), |
.dbg_ll_write_data (0 ), |
.dbg_ll_write_start (1'b0 ), |
.dbg_ll_write_data (32'h0 ), |
.dbg_ll_write_size (0 ), |
.dbg_ll_write_hold (0 ), |
.dbg_ll_write_abort (0 ), |
.dbg_ll_write_hold (1'b0 ), |
.dbg_ll_write_abort (1'b0 ), |
|
.dbg_ll_read_ready (0 ), |
.dbg_t_en (0 ), |
.dbg_ll_read_ready (1'b0 ), |
.dbg_t_en (1'b0 ), |
|
.dbg_send_reg_stb (0 ), |
.dbg_send_dma_act_stb (0 ), |
.dbg_send_data_stb (0 ), |
.dbg_send_pio_stb (0 ), |
.dbg_send_dev_bits_stb (0 ), |
.dbg_send_reg_stb (1'b0 ), |
.dbg_send_dma_act_stb (1'b0 ), |
.dbg_send_data_stb (1'b0 ), |
.dbg_send_pio_stb (1'b0 ), |
.dbg_send_dev_bits_stb (1'b0 ), |
|
.dbg_pio_transfer_count(0 ), |
.dbg_pio_direction (0 ), |
.dbg_pio_e_status (0 ), |
.dbg_pio_transfer_count(16'h0000 ), |
.dbg_pio_direction (1'b0 ), |
.dbg_pio_e_status (8'h00 ), |
|
.dbg_d2h_interrupt (0 ), |
.dbg_d2h_notification (0 ), |
.dbg_d2h_status (0 ), |
.dbg_d2h_error (0 ), |
.dbg_d2h_port_mult (0 ), |
.dbg_d2h_device (0 ), |
.dbg_d2h_lba (0 ), |
.dbg_d2h_sector_count (0 ), |
.dbg_d2h_interrupt (1'b0 ), |
.dbg_d2h_notification (1'b0 ), |
.dbg_d2h_status (8'b0 ), |
.dbg_d2h_error (8'b0 ), |
.dbg_d2h_port_mult (4'b0000 ), |
.dbg_d2h_device (8'h00 ), |
.dbg_d2h_lba (48'h000000000000 ), |
.dbg_d2h_sector_count (16'h0000 ), |
|
.dbg_cl_if_data (0 ), |
.dbg_cl_if_ready (0 ), |
.dbg_cl_if_size (0 ), |
.dbg_cl_of_ready (0 ), |
.dbg_cl_of_size (0 ), |
.dbg_cl_if_data (32'b0 ), |
.dbg_cl_if_ready (1'b0 ), |
.dbg_cl_if_size (24'h0 ), |
|
.dbg_cl_of_ready (2'b0 ), |
.dbg_cl_of_size (24'h0 ), |
.hd_read_from_host (hd_read_from_host ), |
.hd_data_from_host (hd_data_from_host ), |
|
/trunk/sim/faux_sata_hd_command_layer.v
104,16 → 104,17
parameter READ_IN_PROGRESS = 4'h6; |
parameter SEND_STATUS = 4'h7; |
|
parameter SLEEP_LENGTH = 100; |
|
//Registers/Wires |
reg [3:0] state = SLEEP_START; |
wire idle; |
|
reg [8:0] byte_count = 0; |
reg [15:0] sector_count = 0; |
reg [15:0] sector_size = 16'h0000; |
reg [16:0] sector_count = 0; |
reg [16:0] sector_size = 16'h0000; |
|
reg [15:0] sleep_count = 0; |
reg [15:0] sleep_size = 1000; |
|
|
wire soft_reset; |
152,7 → 153,6
sector_size <= 1000; |
|
sleep_count <= 0; |
sleep_size <= 1000; |
|
|
|
181,14 → 181,16
send_dev_bits_stb <= 0; |
|
if (soft_reset) begin |
if (soft_reset) begin |
$display ("Reset from soft reset"); |
end |
state <= SLEEP_START; |
sleep_count <= 0; |
sleep_size <= 1000; |
end |
|
case (state) |
SLEEP_START: begin |
if (sleep_count < sleep_size) begin |
if (sleep_count < SLEEP_LENGTH) begin |
sleep_count <= sleep_count + 1; |
end |
else begin |
196,6 → 198,7
end |
end |
SEND_DIAGNOSTICS: begin |
$display ("Send Diagnostics"); |
send_reg_stb <= 1; |
state <= IDLE; |
end |
205,19 → 208,22
d2h_lba <= h2d_lba; |
d2h_sector_count <= h2d_sector_count; |
|
sector_size <= h2d_sector_count; |
if (h2d_sector_count == 0) begin |
sector_size <= 17'h10000; |
end |
else begin |
sector_size <= h2d_sector_count; |
end |
|
case (h2d_command) |
`COMMAND_DMA_READ_EX: begin |
//send_data_stb <= 1; |
sector_count <= 0; |
sector_size <= h2d_sector_count; |
state <= SEND_DATA; |
end |
`COMMAND_DMA_WRITE_EX: begin |
send_dma_act_stb <= 1; |
sector_count <= 0; |
sector_size <= h2d_sector_count; |
state <= DMA_READY; |
end |
default: begin |
285,7 → 291,6
$display ("fcl: Entered illegal state, restart"); |
state <= SLEEP_START; |
sleep_count <= 0; |
sleep_size <= 1000; |
end |
endcase |
end |
/trunk/sim/sata_defines.v
26,7 → 26,7
`define __SATA_DEFINES__ |
|
//Presuming 75MHz clock |
`define CLOCK_RATE (75000000) |
`define SATA_CLOCK_RATE (75000000) |
// 1 / 880uS = 1136 times per seconds |
`define NORMAL_TIMEOUT (1000000) / 880 |
|
36,7 → 36,7
`define FIFO_ADDRESS_WIDTH 11 |
|
//880uS |
//`define INITIALIZE_TIMEOUT ((`CLOCK_RATE) / (`NORMAL_TIMEOUT)) |
//`define INITIALIZE_TIMEOUT ((`SATA_CLOCK_RATE) / (`NORMAL_TIMEOUT)) |
`define INITIALIZE_TIMEOUT 66000 |
//`define SEND_WAKE_TIMEOUT 4E |
|
/trunk/sim/faux_sata_hd.v
31,12 → 31,12
|
//Data Interface |
output [31:0] tx_dout, |
output [3:0] tx_isk, |
output [3:0] tx_is_k, |
output tx_set_elec_idle, |
output rx_byte_is_aligned, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
input rx_is_elec_idle, |
|
input comm_reset_detect, |
143,10 → 143,10
//Parameters |
//Registers/Wires |
wire [31:0] phy_tx_dout; |
wire phy_tx_isk; |
wire phy_tx_is_k; |
|
wire [31:0] sll_tx_dout; |
wire sll_tx_isk; |
wire sll_tx_is_k; |
|
wire ll_ready; |
wire ll_write_start; |
280,11 → 280,11
|
//incomming/output data |
.tx_dout (phy_tx_dout ), |
.tx_isk (phy_tx_isk ), |
.tx_is_k (phy_tx_is_k ), |
.tx_set_elec_idle (tx_set_elec_idle ), |
|
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.rx_is_k (rx_is_k ), |
.rx_is_elec_idle (rx_is_elec_idle ), |
.rx_byte_is_aligned (rx_byte_is_aligned ), |
|
303,11 → 303,11
sata_link_layer fsll ( |
.rst (rst || !hd_ready ), |
.clk (clk ), |
.prim_scrambler_en (1 ), |
.prim_scrambler_en (1'b1 ), |
.data_scrambler_en (data_scrambler_en ), |
|
.link_layer_ready (ll_ready ), |
.sync_escape (0 ), |
.sync_escape (1'b0 ), |
.hold (dbg_hold ), |
|
//Transport Layer Interface |
332,11 → 332,11
.phy_ready (phy_ready ), |
.platform_ready (hd_ready ), |
.tx_dout (sll_tx_dout ), |
.tx_isk (sll_tx_isk ), |
.tx_is_k (sll_tx_is_k ), |
|
.rx_din (rx_din ), |
.rx_isk (rx_isk ), |
.is_device (1 ) |
.rx_is_k (rx_is_k ), |
.is_device (1'b1 ) |
); |
|
faux_sata_hd_transport ftl ( |
419,7 → 419,7
); |
|
faux_hd_command_layer fcl( |
.rst (rst ), |
.rst (rst || !hd_ready ), |
.clk (clk ), |
|
.command_layer_ready (command_layer_ready ), |
486,8 → 486,8
); |
|
assign tx_dout = !phy_ready ? phy_tx_dout : sll_tx_dout; |
assign tx_isk[3:1] = 3'b000; |
assign tx_isk[0] = !phy_ready ? phy_tx_isk : sll_tx_isk; |
assign tx_is_k[3:1] = 3'b000; |
assign tx_is_k[0] = !phy_ready ? phy_tx_is_k : sll_tx_is_k; |
|
|
//Debug |
/trunk/sim/faux_sata_hd_phy.v
31,12 → 31,12
|
//Data Interface |
output reg [31:0] tx_dout, |
output reg tx_isk, |
output reg tx_is_k, |
output reg tx_set_elec_idle, |
output reg rx_byte_is_aligned, |
|
input [31:0] rx_din, |
input [3:0] rx_isk, |
input [3:0] rx_is_k, |
input rx_is_elec_idle, |
|
input comm_reset_detect, |
87,8 → 87,8
//Asynchronous Logic |
|
assign lax_state = state; |
assign align_detected = ((rx_isk > 0) && (rx_din == `PRIM_ALIGN)); |
assign dialtone_detected = ((rx_isk == 0) && (rx_din == `DIALTONE)); |
assign align_detected = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN)); |
assign dialtone_detected = ((rx_is_k == 0) && (rx_din == `DIALTONE)); |
assign timeout = (timer == 0); |
assign phy_ready = (state == READY); |
|
97,7 → 97,7
if (rst) begin |
state <= IDLE; |
tx_dout <= 0; |
tx_isk <= 0; |
tx_is_k <= 0; |
tx_set_elec_idle <= 1; |
timer <= 0; |
hd_ready <= 0; |
118,12 → 118,14
|
if ((comm_reset_detect) && (state > WAIT_FOR_NO_RESET)) begin |
$display("faux_sata_hd: Asynchronous RESET detected"); |
state <= IDLE; |
align_count <= 0; |
hd_ready <= 0; |
state <= WAIT_FOR_NO_RESET; |
end |
|
case (state) |
IDLE: begin |
align_count <= 0; |
align_count <= 0; |
hd_ready <= 0; |
tx_set_elec_idle <= 1; |
if (comm_reset_detect) begin |
136,8 → 138,7
if (!comm_reset_detect) begin |
//host stopped sending reset |
$display("faux_sata_hd: RESET deasserted"); |
hd_ready <= 0; |
tx_set_elec_idle <= 1; |
hd_ready <= 0; |
state <= SEND_INIT; |
end |
end |
170,26 → 171,30
end |
WAIT_FOR_DIALTONE: begin |
if (dialtone_detected) begin |
$display ("faul_sata_hd: detected dialtone"); |
$display ("faux_sata_hd: detected dialtone"); |
state <= SEND_ALIGN; |
end |
end |
SEND_ALIGN: begin |
$display ("faul_sata_hd: send aligns"); |
$display ("faux_sata_hd: send aligns"); |
tx_set_elec_idle <= 0; |
tx_dout <= `PRIM_ALIGN; |
tx_isk <= 1; |
tx_is_k <= 1; |
state <= WAIT_FOR_ALIGN; |
timer <= 32'h`INITIALIZE_TIMEOUT; |
rx_byte_is_aligned <= 1; |
end |
WAIT_FOR_ALIGN: begin |
tx_is_k <= 1; |
tx_dout <= `PRIM_ALIGN; |
rx_byte_is_aligned <= 1; |
//$display ("faux_sata_hd: waiting for aligns..."); |
//$display ("rx din: %h, k: %h", rx_din, rx_is_k); |
if (align_detected) begin |
$display ("faux_sata_hd: detected ALIGN primitive from host"); |
$display ("faux_sata_hd: Ready"); |
tx_dout <= `PRIM_ALIGN; |
tx_isk <= 1; |
tx_is_k <= 1; |
timer <= 0; |
state <= READY; |
end |
201,7 → 206,7
READY: begin |
hd_ready <= 1; |
rx_byte_is_aligned <= 1; |
tx_isk <= 1; |
tx_is_k <= 1; |
tx_dout <= `PRIM_SYNC; |
if (align_count == 255) begin |
tx_dout <= `PRIM_ALIGN; |
210,13 → 215,13
end |
SEND_FIRST_ALIGNMENT: begin |
rx_byte_is_aligned <= 1; |
tx_isk <= 1; |
tx_is_k <= 1; |
tx_dout <= `PRIM_ALIGN; |
state <= SEND_SECOND_ALIGNMENT; |
end |
SEND_SECOND_ALIGNMENT: begin |
rx_byte_is_aligned <= 1; |
tx_isk <= 1; |
tx_is_k <= 1; |
tx_dout <= `PRIM_ALIGN; |
state <= READY; |
end |
/trunk/README.md
7,12 → 7,6
|
This code was written a long time ago and I've learned much more about verilog and project organization |
since then. It has been proven in a Virtex 6 FPGA reading and writing to/from four Sata 2 hard drives at |
the same time. There were some issues found when the internal buffers inside the hard drives began to |
fill up requiring a lot of starting and stopping of this stack. It lead to some dropped data. There was |
a horrible fix for it in the sata_link_write.v involving a small buffer. This made if very difficult to |
debug because the stack wouldn't allow me to read the non-scrambled data within the logic analyzer. |
There should be a more elegant solution to it. |
|
Most of the license is MIT but some of the licenses are GPL |
|
TODO: Fix Link layer... there is a small FIFO in there that is used to handle all starting and stopping |