litex/litesata/core/command/__init__.py

276 lines
6.6 KiB
Python
Raw Normal View History

2015-01-16 17:52:41 -05:00
from litesata.common import *
tx_to_rx = [
("write", 1),
2015-01-06 10:48:19 -05:00
("read", 1),
2015-01-16 16:49:34 -05:00
("identify", 1),
2015-01-06 10:48:19 -05:00
("count", 16)
]
rx_to_tx = [
2015-01-20 11:14:01 -05:00
("dma_activate", 1),
("d2h_error", 1)
]
2015-01-16 17:52:41 -05:00
class LiteSATACommandTX(Module):
2015-01-06 10:48:19 -05:00
def __init__(self, transport):
2014-12-14 04:52:56 -05:00
self.sink = sink = Sink(command_tx_description(32))
self.to_rx = to_rx = Source(tx_to_rx)
self.from_rx = from_rx = Sink(rx_to_tx)
###
self.comb += [
transport.sink.pm_port.eq(0),
transport.sink.features.eq(0),
transport.sink.lba.eq(sink.sector),
transport.sink.device.eq(0xe0),
transport.sink.count.eq(sink.count),
transport.sink.icc.eq(0),
transport.sink.control.eq(0),
2015-01-14 03:19:41 -05:00
transport.sink.data.eq(sink.data)
]
2015-01-06 10:48:19 -05:00
self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
is_write = Signal()
is_read = Signal()
is_identify = Signal()
2015-01-21 04:52:56 -05:00
self.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
sink.ack.eq(0),
If(sink.stb & sink.sop,
NextState("SEND_CMD")
).Else(
sink.ack.eq(1)
)
)
2015-01-21 04:52:56 -05:00
self.sync += \
If(fsm.ongoing("IDLE"),
is_write.eq(sink.write),
is_read.eq(sink.read),
is_identify.eq(sink.identify),
2015-01-21 04:52:56 -05:00
)
fsm.act("SEND_CMD",
transport.sink.stb.eq(sink.stb),
transport.sink.sop.eq(1),
transport.sink.eop.eq(1),
transport.sink.c.eq(1),
If(transport.sink.stb & transport.sink.ack,
If(is_write,
NextState("WAIT_DMA_ACTIVATE")
).Else(
sink.ack.eq(1),
NextState("IDLE")
)
)
)
fsm.act("WAIT_DMA_ACTIVATE",
2015-01-06 10:48:19 -05:00
dwords_counter.reset.eq(1),
If(from_rx.dma_activate,
NextState("SEND_DATA")
2015-01-20 11:14:01 -05:00
).Elif(from_rx.d2h_error,
sink.ack.eq(1),
NextState("IDLE")
)
)
fsm.act("SEND_DATA",
2015-01-06 10:48:19 -05:00
dwords_counter.ce.eq(sink.stb & sink.ack),
transport.sink.stb.eq(sink.stb),
2015-01-06 10:48:19 -05:00
transport.sink.sop.eq(dwords_counter.value == 0),
transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
sink.ack.eq(transport.sink.ack),
2015-01-06 10:48:19 -05:00
If(sink.stb & sink.ack,
If(sink.eop,
NextState("IDLE")
).Elif(dwords_counter.value == (fis_max_dwords-1),
NextState("WAIT_DMA_ACTIVATE")
)
)
)
self.comb += \
If(fsm.ongoing("SEND_DATA"),
transport.sink.type.eq(fis_types["DATA"]),
2015-01-21 04:52:56 -05:00
).Else(
transport.sink.type.eq(fis_types["REG_H2D"]),
If(is_write,
transport.sink.command.eq(regs["WRITE_DMA_EXT"])
).Elif(is_read,
transport.sink.command.eq(regs["READ_DMA_EXT"]),
).Else(
transport.sink.command.eq(regs["IDENTIFY_DEVICE"]),
)
2015-01-16 16:49:34 -05:00
)
self.comb += [
If(sink.stb,
to_rx.write.eq(sink.write),
2015-01-06 10:48:19 -05:00
to_rx.read.eq(sink.read),
2015-01-16 16:49:34 -05:00
to_rx.identify.eq(sink.identify),
2015-01-06 10:48:19 -05:00
to_rx.count.eq(sink.count)
)
]
2015-01-16 17:52:41 -05:00
class LiteSATACommandRX(Module):
2015-01-06 10:48:19 -05:00
def __init__(self, transport):
2014-12-14 06:49:35 -05:00
self.source = source = Source(command_rx_description(32))
self.to_tx = to_tx = Source(rx_to_tx)
self.from_tx = from_tx = Sink(tx_to_rx)
###
2014-12-13 05:33:22 -05:00
def test_type(name):
return transport.source.type == fis_types[name]
is_identify = Signal()
is_dma_activate = Signal()
2015-01-06 10:48:19 -05:00
read_ndwords = Signal(max=sectors2dwords(2**16))
self.dwords_counter = dwords_counter = Counter(max=sectors2dwords(2**16))
read_done = Signal()
self.sync += \
If(from_tx.read,
read_ndwords.eq(from_tx.count*sectors2dwords(1)-1)
)
self.comb += read_done.eq(self.dwords_counter.value == read_ndwords)
2014-12-13 05:33:22 -05:00
2015-01-20 11:14:01 -05:00
d2h_error = Signal()
clr_d2h_error = Signal()
set_d2h_error = Signal()
self.sync += \
If(clr_d2h_error,
d2h_error.eq(0)
).Elif(set_d2h_error,
d2h_error.eq(1)
)
read_error = Signal()
clr_read_error = Signal()
set_read_error = Signal()
self.sync += \
If(clr_read_error,
read_error.eq(0)
).Elif(set_read_error,
read_error.eq(1)
)
self.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
2015-01-06 10:48:19 -05:00
self.dwords_counter.reset.eq(1),
transport.source.ack.eq(1),
2015-01-20 11:14:01 -05:00
clr_d2h_error.eq(1),
clr_read_error.eq(1),
If(from_tx.write,
2015-01-06 10:48:19 -05:00
NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
).Elif(from_tx.read,
2015-01-16 16:49:34 -05:00
NextState("WAIT_READ_DATA_OR_REG_D2H"),
).Elif(from_tx.identify,
NextState("WAIT_PIO_SETUP_D2H"),
)
)
2015-01-16 16:49:34 -05:00
self.sync += \
If(fsm.ongoing("IDLE"),
is_identify.eq(from_tx.identify)
2015-01-16 16:49:34 -05:00
)
2015-01-06 10:48:19 -05:00
fsm.act("WAIT_WRITE_ACTIVATE_OR_REG_D2H",
transport.source.ack.eq(1),
2014-12-13 05:33:22 -05:00
If(transport.source.stb,
If(test_type("DMA_ACTIVATE_D2H"),
is_dma_activate.eq(1),
2015-01-06 10:48:19 -05:00
).Elif(test_type("REG_D2H"),
2015-01-20 11:14:01 -05:00
set_d2h_error.eq(transport.source.status[reg_d2h_status["err"]]),
NextState("PRESENT_WRITE_RESPONSE")
)
)
)
fsm.act("PRESENT_WRITE_RESPONSE",
source.stb.eq(1),
source.sop.eq(1),
source.eop.eq(1),
source.write.eq(1),
source.last.eq(1),
source.failed.eq(transport.source.error | d2h_error),
If(source.stb & source.ack,
NextState("IDLE")
)
)
fsm.act("WAIT_READ_DATA_OR_REG_D2H",
transport.source.ack.eq(1),
If(transport.source.stb,
transport.source.ack.eq(0),
If(test_type("DATA"),
NextState("PRESENT_READ_DATA")
).Elif(test_type("REG_D2H"),
NextState("PRESENT_READ_RESPONSE")
2014-12-13 05:33:22 -05:00
)
)
)
2015-01-16 16:49:34 -05:00
fsm.act("WAIT_PIO_SETUP_D2H",
transport.source.ack.eq(1),
If(transport.source.stb,
transport.source.ack.eq(0),
If(test_type("PIO_SETUP_D2H"),
NextState("PRESENT_PIO_SETUP_D2H")
)
)
)
fsm.act("PRESENT_PIO_SETUP_D2H",
transport.source.ack.eq(1),
If(transport.source.stb & transport.source.eop,
NextState("WAIT_READ_DATA_OR_REG_D2H")
)
)
2015-01-14 03:19:41 -05:00
fsm.act("PRESENT_READ_DATA",
set_read_error.eq(transport.source.error),
source.stb.eq(transport.source.stb),
source.sop.eq(transport.source.sop),
source.eop.eq(transport.source.eop),
source.read.eq(~is_identify),
source.identify.eq(is_identify),
source.failed.eq(transport.source.error),
source.last.eq(is_identify),
source.data.eq(transport.source.data),
transport.source.ack.eq(source.ack),
If(source.stb & source.ack,
2015-01-06 10:48:19 -05:00
self.dwords_counter.ce.eq(~read_done),
If(source.eop,
If(is_identify,
NextState("IDLE")
2015-01-06 10:48:19 -05:00
).Else(
NextState("WAIT_READ_DATA_OR_REG_D2H")
2015-01-06 10:48:19 -05:00
)
)
)
)
fsm.act("PRESENT_READ_RESPONSE",
source.stb.eq(1),
source.sop.eq(1),
source.eop.eq(1),
source.read.eq(1),
source.last.eq(1),
source.failed.eq(~read_done | read_error | d2h_error),
If(source.stb & source.ack,
NextState("IDLE")
)
)
2014-12-13 05:33:22 -05:00
self.comb += [
to_tx.dma_activate.eq(is_dma_activate),
2015-01-20 11:14:01 -05:00
to_tx.d2h_error.eq(d2h_error)
]
2015-01-16 17:52:41 -05:00
class LiteSATACommand(Module):
2015-01-06 10:48:19 -05:00
def __init__(self, transport):
2015-01-16 17:52:41 -05:00
self.tx = LiteSATACommandTX(transport)
self.rx = LiteSATACommandRX(transport)
self.comb += [
self.rx.to_tx.connect(self.tx.from_rx),
self.tx.to_rx.connect(self.rx.from_tx)
]
2014-12-13 05:33:22 -05:00
self.sink, self.source = self.tx.sink, self.rx.source