CURDIR = ../lite-sata
PYTHON = python3
TOOLCHAIN = vivado
-PLATFORM = kc705
PROGRAMMER = vivado
-CMD = $(PYTHON) make.py -X $(CURDIR) -Op toolchain $(TOOLCHAIN) -Op programmer $(PROGRAMMER) -p $(PLATFORM) -t bist
+CMD = $(PYTHON) make.py -X $(CURDIR) -Op toolchain $(TOOLCHAIN) -Op programmer $(PROGRAMMER) -t bist_kc705
csv:
cd $(MSCDIR) && $(CMD) --csr_csv $(CURDIR)/test/csr.csv build-csr-csv -Ot export_mila True
Copyright 2014-2015 / Florent Kermarrec / florent@enjoy-digital.fr
- A lite open-source SATA1/2/3 controller
- developed in partnership with M-Labs Ltd & HKU
+ A generic and configurable SATA1/2/3 core
+ developed in partnership with M-Labs Ltd & HKU
+
+[> Features
+------------------
+PHY:
+ - OOB, COMWAKE, COMINIT.
+ - ALIGN inserter/remover and bytes alignment on K28.5.
+ - 8B/10B encoding/decoding in transceiver.
+ - Errors detection and reporting.
+ - 1.5 / 3.0 / 6.0GBPs supported speeds.
+ - 37.5 / 75 / 150MHz system clock.
+Core:
+ Link:
+ - CONT inserter/remover.
+ - Scrambling/Descrambling of data.
+ - CRC inserter/checker.
+ - HOLD insertion/detection.
+ - Errors detection and reporting.
+ Transport/Command:
+ - Easy to use user interface (Can be used with or without CPU).
+ - 48 bits sector addressing.
+ - 3 supported commands: READ_DMA(_EXT), WRITE_DMA(_EXT), IDENTIFY_DEVICE.
+ - Errors detection and reporting.
+
+Frontend:
+ - Configurable crossbar (simply use core.crossbar.get_port() to add a new port!)
+ - Ports arbitration transparent to the user.
+ - Synthetizable BIST.
[> Getting started
------------------
make all
7. Test design:
- go to test directory
+ go to test directory and run:
python3 bist.py
[> Simulations :
- Simulation are avalaible in ./lib/sata/test:
+ Simulations are avalaible in ./lib/sata/test:
- crc_tb
- scrambler_tb
- phy_datapath_tb
- command_tb
- bist_tb
hdd.py is a HDD model implementing all SATA layers.
- To run a simulation, move to the simulation directory and run:
+ To run a simulation, move to ./lib/sata/test and run:
make simulation_name
[> Tests :
- A synthetisable BIST is provided. It can be controled with ./test/bist.py
- Using Miscope and the provided example ./test/test_link.py you are able to
- visualize every event of the design and even inject your data in the HDD
- model!
+ A synthetisable BIST is provided and can be controlled with ./test/bist.py
+ By using Miscope and the provided ./test/test_link.py example you are able to
+ visualize the internal logic of the design and even inject the captured data in
+ the HDD model!
[> Contact
E-mail: florent@enjoy-digital.fr
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link import SATALink
-from lib.sata.transport import SATATransport
-from lib.sata.command import SATACommand
-
-from lib.sata.frontend.crossbar import SATACrossbar
-
-class SATACON(Module):
- def __init__(self, phy):
- ###
- # core
- self.link = SATALink(phy)
- self.transport = SATATransport(self.link)
- self.command = SATACommand(self.transport)
-
- # frontend
- self.crossbar = SATACrossbar(32)
- self.comb += [
- Record.connect(self.crossbar.master.source, self.command.sink),
- Record.connect(self.command.source, self.crossbar.master.sink)
- ]
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link.scrambler import Scrambler
-
-from migen.fhdl.decorators import ModuleDecorator
-from migen.bank.description import *
-
-class SATABISTGenerator(Module):
- def __init__(self, sata_master_port):
- self.start = Signal()
- self.sector = Signal(48)
- self.count = Signal(16)
- self.random = Signal()
-
- self.done = Signal()
- self.errors = Signal(32) # Note: Not used for writes
-
- ###
-
- source, sink = sata_master_port.source, sata_master_port.sink
-
- self.counter = counter = Counter(bits_sign=32)
-
- self.scrambler = scrambler = InsertReset(Scrambler())
- self.comb += [
- scrambler.reset.eq(counter.reset),
- scrambler.ce.eq(counter.ce)
- ]
-
- self.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- self.done.eq(1),
- counter.reset.eq(1),
- If(self.start,
- NextState("SEND_CMD_AND_DATA")
- )
- )
- self.comb += [
- source.sop.eq(counter.value == 0),
- source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
- source.write.eq(1),
- source.sector.eq(self.sector),
- source.count.eq(self.count),
- If(self.random,
- source.data.eq(scrambler.value)
- ).Else(
- source.data.eq(counter.value)
- )
- ]
- fsm.act("SEND_CMD_AND_DATA",
- source.stb.eq(1),
- If(source.stb & source.ack,
- counter.ce.eq(1),
- If(source.eop,
- NextState("WAIT_ACK")
- )
- )
- )
- fsm.act("WAIT_ACK",
- sink.ack.eq(1),
- If(sink.stb,
- NextState("IDLE")
- )
- )
-
-class SATABISTChecker(Module):
- def __init__(self, sata_master_port):
- self.start = Signal()
- self.sector = Signal(48)
- self.count = Signal(16)
- self.random = Signal()
-
- self.done = Signal()
- self.errors = Signal(32)
-
- ###
-
- source, sink = sata_master_port.source, sata_master_port.sink
-
- self.counter = counter = Counter(bits_sign=32)
- self.error_counter = Counter(self.errors, bits_sign=32)
-
- self.scrambler = scrambler = InsertReset(Scrambler())
- self.comb += [
- scrambler.reset.eq(counter.reset),
- scrambler.ce.eq(counter.ce)
- ]
-
- self.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- self.done.eq(1),
- counter.reset.eq(1),
- If(self.start,
- self.error_counter.reset.eq(1),
- NextState("SEND_CMD")
- )
- )
- self.comb += [
- source.sop.eq(1),
- source.eop.eq(1),
- source.read.eq(1),
- source.sector.eq(self.sector),
- source.count.eq(self.count),
- ]
- fsm.act("SEND_CMD",
- source.stb.eq(1),
- If(source.ack,
- counter.reset.eq(1),
- NextState("WAIT_ACK")
- )
- )
- fsm.act("WAIT_ACK",
- If(sink.stb & sink.read,
- NextState("RECEIVE_DATA")
- )
- )
- expected_data = Signal(32)
- self.comb += \
- If(self.random,
- expected_data.eq(scrambler.value)
- ).Else(
- expected_data.eq(counter.value)
- )
- fsm.act("RECEIVE_DATA",
- sink.ack.eq(1),
- If(sink.stb,
- counter.ce.eq(1),
- If(sink.data != expected_data,
- self.error_counter.ce.eq(1)
- ),
- If(sink.eop,
- If(sink.last,
- NextState("IDLE")
- ).Else(
- NextState("WAIT_ACK")
- )
- )
- )
- )
-
-class SATABISTUnitControl(Module, AutoCSR):
- def __init__(self, bist_unit):
- self._start = CSR()
- self._sector = CSRStorage(48)
- self._count = CSRStorage(16)
- self._random = CSRStorage()
- self._done = CSRStatus()
- self._errors = CSRStatus(32)
- self._cycles = CSRStatus(32)
-
- ###
- self.bist_unit = bist_unit
- self.comb += [
- bist_unit.start.eq(self._start.r & self._start.re),
- bist_unit.sector.eq(self._sector.storage),
- bist_unit.count.eq(self._count.storage),
- bist_unit.random.eq(self._random.storage),
-
- self._done.status.eq(bist_unit.done),
- self._errors.status.eq(bist_unit.errors)
- ]
-
- self.cycles_counter = Counter(self._cycles.status)
- self.sync += [
- self.cycles_counter.reset.eq(bist_unit.start),
- self.cycles_counter.ce.eq(~bist_unit.done)
- ]
-
-class SATABISTIdentify(Module):
- def __init__(self, sata_master_port):
- self.start = Signal()
- self.done = Signal()
-
- self.fifo = fifo = SyncFIFO([("data", 32)], 512, buffered=True)
- self.source = self.fifo.source
-
- ###
-
- source, sink = sata_master_port.source, sata_master_port.sink
-
- self.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- self.done.eq(1),
- If(self.start,
- NextState("SEND_CMD")
- )
- )
- self.comb += [
- source.sop.eq(1),
- source.eop.eq(1),
- source.identify.eq(1),
- ]
- fsm.act("SEND_CMD",
- source.stb.eq(1),
- If(source.stb & source.ack,
- NextState("WAIT_ACK")
- )
- )
- fsm.act("WAIT_ACK",
- If(sink.stb & sink.identify,
- NextState("RECEIVE_DATA")
- )
- )
- self.comb += fifo.sink.data.eq(sink.data)
- fsm.act("RECEIVE_DATA",
- sink.ack.eq(fifo.sink.ack),
- If(sink.stb,
- fifo.sink.stb.eq(1),
- If(sink.eop,
- NextState("IDLE")
- )
- )
- )
-
-class SATABISTIdentifyControl(Module, AutoCSR):
- def __init__(self, bist_identify):
- self._start = CSR()
- self._done = CSRStatus()
- self._source_stb = CSRStatus()
- self._source_ack = CSR()
- self._source_data = CSRStatus(32)
-
- ###
- self.bist_identify = bist_identify
- self.comb += [
- bist_identify.start.eq(self._start.r & self._start.re),
- self._done.status.eq(bist_identify.done),
-
- self._source_stb.status.eq(bist_identify.source.stb),
- self._source_data.status.eq(bist_identify.source.data),
- bist_identify.source.ack.eq(self._source_ack.r & self._source_ack.re)
- ]
-
-class SATABIST(Module, AutoCSR):
- def __init__(self, sata_master_ports, with_control=False):
- generator = SATABISTGenerator(sata_master_ports[0])
- checker = SATABISTChecker(sata_master_ports[1])
- identify = SATABISTIdentify(sata_master_ports[2])
- if with_control:
- self.generator = SATABISTUnitControl(generator)
- self.checker = SATABISTUnitControl(checker)
- self.identify = SATABISTIdentifyControl(identify)
- else:
- self.generator = generator
- self.checker = checker
- self.identify = identify
+++ /dev/null
-from lib.sata.common import *
-
-tx_to_rx = [
- ("write", 1),
- ("read", 1),
- ("identify", 1),
- ("count", 16)
-]
-
-rx_to_tx = [
- ("dma_activate", 1)
-]
-
-class SATACommandTX(Module):
- def __init__(self, transport):
- 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),
- transport.sink.data.eq(sink.data)
- ]
-
- self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
-
- self.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- sink.ack.eq(0),
- If(sink.stb & sink.sop,
- If(sink.write,
- NextState("SEND_WRITE_DMA_CMD")
- ).Elif(sink.read,
- NextState("SEND_READ_DMA_CMD")
- ).Elif(sink.identify,
- NextState("SEND_IDENTIFY_CMD")
- ).Else(
- sink.ack.eq(1)
- )
- ).Else(
- sink.ack.eq(1)
- )
- )
- fsm.act("SEND_WRITE_DMA_CMD",
- transport.sink.stb.eq(sink.stb),
- transport.sink.sop.eq(1),
- transport.sink.eop.eq(1),
- transport.sink.type.eq(fis_types["REG_H2D"]),
- transport.sink.c.eq(1),
- transport.sink.command.eq(regs["WRITE_DMA_EXT"]),
- If(sink.stb & transport.sink.ack,
- NextState("WAIT_DMA_ACTIVATE")
- )
- )
- fsm.act("WAIT_DMA_ACTIVATE",
- dwords_counter.reset.eq(1),
- If(from_rx.dma_activate,
- NextState("SEND_DATA")
- )
- )
- fsm.act("SEND_DATA",
- dwords_counter.ce.eq(sink.stb & sink.ack),
-
- transport.sink.stb.eq(sink.stb),
- transport.sink.sop.eq(dwords_counter.value == 0),
- transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
-
- transport.sink.type.eq(fis_types["DATA"]),
- sink.ack.eq(transport.sink.ack),
- If(sink.stb & sink.ack,
- If(sink.eop,
- NextState("IDLE")
- ).Elif(dwords_counter.value == (fis_max_dwords-1),
- NextState("WAIT_DMA_ACTIVATE")
- )
- )
- )
- fsm.act("SEND_READ_DMA_CMD",
- transport.sink.stb.eq(sink.stb),
- transport.sink.sop.eq(1),
- transport.sink.eop.eq(1),
- transport.sink.type.eq(fis_types["REG_H2D"]),
- transport.sink.c.eq(1),
- transport.sink.command.eq(regs["READ_DMA_EXT"]),
- sink.ack.eq(transport.sink.ack),
- If(sink.stb & sink.ack,
- NextState("IDLE")
- )
- )
- fsm.act("SEND_IDENTIFY_CMD",
- transport.sink.stb.eq(sink.stb),
- transport.sink.sop.eq(1),
- transport.sink.eop.eq(1),
- transport.sink.type.eq(fis_types["REG_H2D"]),
- transport.sink.c.eq(1),
- transport.sink.command.eq(regs["IDENTIFY_DEVICE"]),
- sink.ack.eq(transport.sink.ack),
- If(sink.stb & sink.ack,
- NextState("IDLE")
- )
- )
-
- self.comb += [
- If(sink.stb,
- to_rx.write.eq(sink.write),
- to_rx.read.eq(sink.read),
- to_rx.identify.eq(sink.identify),
- to_rx.count.eq(sink.count)
- )
- ]
-
-class SATACommandRX(Module):
- def __init__(self, transport):
- 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)
-
- ###
-
- cmd_buffer = Buffer(command_rx_cmd_description(32))
- cmd_buffer.sink, cmd_buffer.source = cmd_buffer.d, cmd_buffer.q
- data_buffer = InsertReset(SyncFIFO(command_rx_data_description(32), fis_max_dwords, buffered=True))
- self.submodules += cmd_buffer, data_buffer
-
- def test_type(name):
- return transport.source.type == fis_types[name]
-
- identify = Signal()
- dma_activate = Signal()
- 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)
-
- self.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- self.dwords_counter.reset.eq(1),
- transport.source.ack.eq(1),
- If(from_tx.write,
- NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
- ).Elif(from_tx.read,
- NextState("WAIT_READ_DATA_OR_REG_D2H"),
- ).Elif(from_tx.identify,
- NextState("WAIT_PIO_SETUP_D2H"),
- )
- )
- self.sync += \
- If(fsm.ongoing("IDLE"),
- identify.eq(from_tx.identify)
- )
- fsm.act("WAIT_WRITE_ACTIVATE_OR_REG_D2H",
- transport.source.ack.eq(1),
- If(transport.source.stb,
- If(test_type("DMA_ACTIVATE_D2H"),
- dma_activate.eq(1),
- ).Elif(test_type("REG_D2H"),
- # XXX: use status and error fields of REG_D2H
- NextState("PRESENT_WRITE_RESPONSE")
- )
- )
- )
- fsm.act("PRESENT_WRITE_RESPONSE",
- cmd_buffer.sink.stb.eq(1),
- cmd_buffer.sink.write.eq(1),
- cmd_buffer.sink.last.eq(1),
- cmd_buffer.sink.success.eq(~transport.source.error),
- cmd_buffer.sink.failed.eq(transport.source.error),
- If(cmd_buffer.sink.stb & cmd_buffer.sink.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"),
- # XXX: use status and error fields of REG_D2H
- NextState("PRESENT_READ_RESPONSE")
- )
- )
- )
- 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),
- # XXX : Check error/ status
- If(transport.source.stb & transport.source.eop,
- NextState("WAIT_READ_DATA_OR_REG_D2H")
- )
- )
-
- self.comb += [
- data_buffer.sink.sop.eq(transport.source.sop),
- data_buffer.sink.eop.eq(transport.source.eop),
- data_buffer.sink.data.eq(transport.source.data)
- ]
- fsm.act("PRESENT_READ_DATA",
- data_buffer.sink.stb.eq(transport.source.stb),
- transport.source.ack.eq(data_buffer.sink.ack),
- If(data_buffer.sink.stb & data_buffer.sink.ack,
- self.dwords_counter.ce.eq(~read_done),
- If(data_buffer.sink.eop,
- If(read_done & ~identify,
- NextState("WAIT_READ_DATA_OR_REG_D2H")
- ).Else(
- NextState("PRESENT_READ_RESPONSE")
- )
- )
- )
- )
- read_error = Signal()
- self.sync += \
- If(fsm.before_entering("PRESENT_READ_DATA"),
- read_error.eq(1)
- ).Elif(transport.source.stb & transport.source.ack & transport.source.eop,
- read_error.eq(transport.source.error)
- )
- fsm.act("PRESENT_READ_RESPONSE",
- cmd_buffer.sink.stb.eq(1),
- cmd_buffer.sink.read.eq(~identify),
- cmd_buffer.sink.identify.eq(identify),
- cmd_buffer.sink.last.eq(read_done | identify),
- cmd_buffer.sink.success.eq(~read_error),
- cmd_buffer.sink.failed.eq(read_error),
- If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
- If(cmd_buffer.sink.failed,
- data_buffer.reset.eq(1)
- ),
- If(read_done | identify,
- NextState("IDLE")
- ).Else(
- NextState("WAIT_READ_DATA_OR_REG_D2H")
- )
- )
- )
-
- self.out_fsm = out_fsm = FSM(reset_state="IDLE")
- out_fsm.act("IDLE",
- If(cmd_buffer.source.stb,
- If((cmd_buffer.source.read | cmd_buffer.source.identify) & cmd_buffer.source.success,
- NextState("PRESENT_RESPONSE_WITH_DATA"),
- ).Else(
- NextState("PRESENT_RESPONSE_WITHOUT_DATA"),
- )
- )
- )
-
- self.comb += [
- source.write.eq(cmd_buffer.source.write),
- source.read.eq(cmd_buffer.source.read),
- source.identify.eq(cmd_buffer.source.identify),
- source.last.eq(cmd_buffer.source.last),
- source.success.eq(cmd_buffer.source.success),
- source.failed.eq(cmd_buffer.source.failed),
- source.data.eq(data_buffer.source.data)
- ]
-
- out_fsm.act("PRESENT_RESPONSE_WITH_DATA",
- source.stb.eq(data_buffer.source.stb),
- source.sop.eq(data_buffer.source.sop),
- source.eop.eq(data_buffer.source.eop),
-
- data_buffer.source.ack.eq(source.ack),
-
- If(source.stb & source.eop & source.ack,
- cmd_buffer.source.ack.eq(1),
- NextState("IDLE")
- )
- )
- out_fsm.act("PRESENT_RESPONSE_WITHOUT_DATA",
- source.stb.eq(1),
- source.sop.eq(1),
- source.eop.eq(1),
- If(source.stb & source.ack,
- cmd_buffer.source.ack.eq(1),
- NextState("IDLE")
- )
- )
-
- self.comb += [
- to_tx.dma_activate.eq(dma_activate),
- ]
-
-class SATACommand(Module):
- def __init__(self, transport):
- self.tx = SATACommandTX(transport)
- self.rx = SATACommandRX(transport)
- self.comb += [
- self.rx.to_tx.connect(self.tx.from_rx),
- self.tx.to_rx.connect(self.rx.from_tx)
- ]
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-import math
-
-from migen.fhdl.std import *
-from migen.genlib.resetsync import *
-from migen.genlib.fsm import *
-from migen.genlib.record import *
-from migen.flow.actor import *
-from migen.flow.plumbing import Buffer
-from migen.actorlib.fifo import *
-from migen.actorlib.structuring import Pipeline
-
-# PHY / Link Layers
-primitives = {
- "ALIGN" : 0x7B4A4ABC,
- "CONT" : 0X9999AA7C,
- "SYNC" : 0xB5B5957C,
- "R_RDY" : 0x4A4A957C,
- "R_OK" : 0x3535B57C,
- "R_ERR" : 0x5656B57C,
- "R_IP" : 0X5555B57C,
- "X_RDY" : 0x5757B57C,
- "CONT" : 0x9999AA7C,
- "WTRM" : 0x5858B57C,
- "SOF" : 0x3737B57C,
- "EOF" : 0xD5D5B57C,
- "HOLD" : 0xD5D5AA7C,
- "HOLDA" : 0X9595AA7C
-}
-
-def is_primitive(dword):
- for k, v in primitives.items():
- if dword == v:
- return True
- return False
-
-def decode_primitive(dword):
- for k, v in primitives.items():
- if dword == v:
- return k
- return ""
-
-def phy_description(dw):
- layout = [
- ("data", dw),
- ("charisk", dw//8),
- ]
- return EndpointDescription(layout, packetized=False)
-
-def link_description(dw):
- layout = [
- ("d", dw),
- ("error", 1)
- ]
- return EndpointDescription(layout, packetized=True)
-
-# Transport Layer
-fis_max_dwords = 2048
-
-fis_types = {
- "REG_H2D": 0x27,
- "REG_D2H": 0x34,
- "DMA_ACTIVATE_D2H": 0x39,
- "PIO_SETUP_D2H": 0x5F,
- "DATA": 0x46
-}
-
-class FISField():
- def __init__(self, dword, offset, width):
- self.dword = dword
- self.offset = offset
- self.width = width
-
-fis_reg_h2d_cmd_len = 5
-fis_reg_h2d_layout = {
- "type": FISField(0, 0, 8),
- "pm_port": FISField(0, 8, 4),
- "c": FISField(0, 15, 1),
- "command": FISField(0, 16, 8),
- "features_lsb": FISField(0, 24, 8),
-
- "lba_lsb": FISField(1, 0, 24),
- "device": FISField(1, 24, 8),
-
- "lba_msb": FISField(2, 0, 24),
- "features_msb": FISField(2, 24, 8),
-
- "count": FISField(3, 0, 16),
- "icc": FISField(3, 16, 8),
- "control": FISField(3, 24, 8)
-}
-
-fis_reg_d2h_cmd_len = 5
-fis_reg_d2h_layout = {
- "type": FISField(0, 0, 8),
- "pm_port": FISField(0, 8, 4),
- "i": FISField(0, 14, 1),
- "status": FISField(0, 16, 8),
- "error": FISField(0, 24, 8),
-
- "lba_lsb": FISField(1, 0, 24),
- "device": FISField(1, 24, 8),
-
- "lba_msb": FISField(2, 0, 24),
-
- "count": FISField(3, 0, 16)
-}
-
-fis_dma_activate_d2h_cmd_len = 1
-fis_dma_activate_d2h_layout = {
- "type": FISField(0, 0, 8),
- "pm_port": FISField(0, 8, 4)
-}
-
-fis_pio_setup_d2h_cmd_len = 5
-fis_pio_setup_d2h_layout = {
- "type": FISField(0, 0, 8),
- "pm_port": FISField(0, 8, 4),
- "d": FISField(0, 13, 1),
- "i": FISField(0, 14, 1),
- "status": FISField(0, 16, 8),
- "error": FISField(0, 24, 8),
-
- "lba_lsb": FISField(1, 0, 24),
-
- "lba_msb": FISField(2, 0, 24),
-
- "count": FISField(3, 0, 16),
-
- "transfer_count": FISField(4, 0, 16),
-}
-
-fis_data_cmd_len = 1
-fis_data_layout = {
- "type": FISField(0, 0, 8)
-}
-
-def transport_tx_description(dw):
- layout = [
- ("type", 8),
- ("pm_port", 4),
- ("c", 1),
- ("command", 8),
- ("features", 16),
- ("lba", 48),
- ("device", 8),
- ("count", 16),
- ("icc", 8),
- ("control", 8),
- ("data", dw)
- ]
- return EndpointDescription(layout, packetized=True)
-
-def transport_rx_description(dw):
- layout = [
- ("type", 8),
- ("pm_port", 4),
- ("r", 1),
- ("d", 1),
- ("i", 1),
- ("status", 8),
- ("error", 8),
- ("lba", 48),
- ("device", 8),
- ("count", 16),
- ("transfer_count", 16),
- ("data", dw),
- ("error", 1)
- ]
- return EndpointDescription(layout, packetized=True)
-
-# Command Layer
-regs = {
- "WRITE_DMA_EXT" : 0x35,
- "READ_DMA_EXT" : 0x25,
- "IDENTIFY_DEVICE" : 0xEC
-}
-
-def command_tx_description(dw):
- layout = [
- ("write", 1),
- ("read", 1),
- ("identify", 1),
- ("sector", 48),
- ("count", 16),
- ("data", dw)
- ]
- return EndpointDescription(layout, packetized=True)
-
-def command_rx_description(dw):
- layout = [
- ("write", 1),
- ("read", 1),
- ("identify", 1),
- ("last", 1),
- ("success", 1),
- ("failed", 1),
- ("data", dw)
- ]
- return EndpointDescription(layout, packetized=True)
-
-def command_rx_cmd_description(dw):
- layout = [
- ("write", 1),
- ("read", 1),
- ("identify", 1),
- ("last", 1),
- ("success", 1),
- ("failed", 1)
- ]
- return EndpointDescription(layout, packetized=False)
-
-def command_rx_data_description(dw):
- layout = [
- ("data", dw)
- ]
- return EndpointDescription(layout, packetized=True)
-
-# HDD
-logical_sector_size = 512 # constant since all HDDs use this
-
-def dwords2sectors(n):
- return math.ceil(n*4/logical_sector_size)
-
-def sectors2dwords(n):
- return n*logical_sector_size//4
-
-# Generic modules
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class Counter(Module):
- def __init__(self, signal=None, **kwargs):
- if signal is None:
- self.value = Signal(**kwargs)
- else:
- self.value = signal
- self.width = flen(self.value)
- self.sync += self.value.eq(self.value+1)
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class Timeout(Module):
- def __init__(self, length):
- self.reached = Signal()
- ###
- value = Signal(max=length)
- self.sync += value.eq(value+1)
- self.comb += [
- self.reached.eq(value == length)
- ]
-
-# XXX use ModuleDecorator
-class BufferizeEndpoints(Module):
- def __init__(self, decorated, *args):
- self.decorated = decorated
-
- endpoints = get_endpoints(decorated)
- sinks = {}
- sources = {}
- for name, endpoint in endpoints.items():
- if name in args or len(args) == 0:
- if isinstance(endpoint, Sink):
- sinks.update({name : endpoint})
- elif isinstance(endpoint, Source):
- sources.update({name : endpoint})
-
- # add buffer on sinks
- for name, sink in sinks.items():
- buf = Buffer(sink.description)
- self.submodules += buf
- setattr(self, name, buf.d)
- self.comb += Record.connect(buf.q, sink)
-
- # add buffer on sources
- for name, source in sources.items():
- buf = Buffer(source.description)
- self.submodules += buf
- self.comb += Record.connect(source, buf.d)
- setattr(self, name, buf.q)
-
- def __getattr__(self, name):
- return getattr(self.decorated, name)
-
- def __dir__(self):
- return dir(self.decorated)
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.frontend.common import *
-
-from migen.genlib.roundrobin import *
-
-class SATAArbiter(Module):
- def __init__(self, slaves, master):
- if len(slaves) == 1:
- self.comb += slaves[0].connect(master)
- else:
- self.rr = RoundRobin(len(slaves))
- self.grant = self.rr.grant
- cases = {}
- for i, slave in enumerate(slaves):
- sink, source = slave.sink, slave.source
- start = Signal()
- done = Signal()
- ongoing = Signal()
- self.comb += [
- start.eq(sink.stb & sink.sop),
- done.eq(source.stb & source.last & source.eop & source.ack)
- ]
- self.sync += \
- If(start,
- ongoing.eq(1)
- ).Elif(done,
- ongoing.eq(0)
- )
- self.comb += self.rr.request[i].eq((start | ongoing) & ~done)
- cases[i] = [slaves[i].connect(master)]
- self.comb += Case(self.grant, cases)
+++ /dev/null
-from lib.sata.common import *
-
-class SATAMasterPort:
- def __init__(self, dw):
- self.source = Source(command_tx_description(dw))
- self.sink = Sink(command_rx_description(dw))
-
- def connect(self, slave):
- return [
- Record.connect(self.source, slave.sink),
- Record.connect(slave.source, self.sink)
- ]
-
-class SATASlavePort:
- def __init__(self, dw):
- self.sink = Sink(command_tx_description(dw))
- self.source = Source(command_rx_description(dw))
-
- def connect(self, master):
- return [
- Record.connect(self.sink, master.source),
- Record.connect(master.sink, self.source)
- ]
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.frontend.common import *
-from lib.sata.frontend.arbiter import SATAArbiter
-
-class SATACrossbar(Module):
- def __init__(self, dw):
- self.dw = dw
- self.slaves = []
- self.master = SATAMasterPort(dw)
-
- def get_port(self):
- master = SATAMasterPort(self.dw)
- slave = SATASlavePort(self.dw)
- self.comb += master.connect(slave)
- self.slaves.append(slave)
- return master
-
- def get_ports(self, n):
- masters = []
- for i in range(n):
- masters.append(self.get_port())
- return masters
-
- def do_finalize(self):
- self.arbiter = SATAArbiter(self.slaves, self.master)
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link.crc import SATACRCInserter, SATACRCChecker
-from lib.sata.link.scrambler import SATAScrambler
-from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
-
-from_rx = [
- ("idle", 1),
- ("insert", 32),
- ("det", 32)
-]
-
-class SATALinkTX(Module):
- def __init__(self, phy):
- self.sink = Sink(link_description(32))
- self.from_rx = Sink(from_rx)
-
- ###
-
- self.fsm = fsm = FSM(reset_state="IDLE")
-
- # insert CRC
- crc = SATACRCInserter(link_description(32))
- self.submodules += crc
-
- # scramble
- scrambler = SATAScrambler(link_description(32))
- self.submodules += scrambler
-
- # connect CRC / scrambler
- self.comb += [
- Record.connect(self.sink, crc.sink),
- Record.connect(crc.source, scrambler.sink)
- ]
-
- # inserter CONT and scrambled data between
- # CONT and next primitive
- self.cont = cont = BufferizeEndpoints(SATACONTInserter(phy_description(32)), "source")
-
- # datas / primitives mux
- insert = Signal(32)
- self.comb += [
- If(self.from_rx.insert,
- cont.sink.stb.eq(1),
- cont.sink.data.eq(self.from_rx.insert),
- cont.sink.charisk.eq(0x0001),
- ).
- Elif(insert,
- cont.sink.stb.eq(1),
- cont.sink.data.eq(insert),
- cont.sink.charisk.eq(0x0001),
- ).Elif(fsm.ongoing("COPY"),
- cont.sink.stb.eq(scrambler.source.stb),
- cont.sink.data.eq(scrambler.source.d),
- scrambler.source.ack.eq(cont.sink.ack),
- cont.sink.charisk.eq(0)
- )
- ]
- self.comb += Record.connect(cont.source, phy.sink)
-
- # FSM
- fsm.act("IDLE",
- scrambler.reset.eq(1),
- If(self.from_rx.idle,
- insert.eq(primitives["SYNC"]),
- If(scrambler.source.stb & scrambler.source.sop,
- If(self.from_rx.det == primitives["SYNC"],
- NextState("RDY")
- )
- )
- )
- )
- fsm.act("RDY",
- insert.eq(primitives["X_RDY"]),
- If(~self.from_rx.idle,
- NextState("IDLE")
- ).Elif(self.from_rx.det == primitives["R_RDY"],
- NextState("SOF")
- )
- )
- fsm.act("SOF",
- insert.eq(primitives["SOF"]),
- If(phy.sink.ack,
- NextState("COPY")
- )
- )
- fsm.act("COPY",
- If(self.from_rx.det == primitives["HOLD"],
- insert.eq(primitives["HOLDA"]),
- ).Elif(~scrambler.source.stb,
- insert.eq(primitives["HOLD"]),
- ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
- NextState("EOF")
- )
- )
- fsm.act("EOF",
- insert.eq(primitives["EOF"]),
- If(phy.sink.ack,
- NextState("WTRM")
- )
- )
- fsm.act("WTRM",
- insert.eq(primitives["WTRM"]),
- If(self.from_rx.det == primitives["R_OK"],
- NextState("IDLE")
- ).Elif(self.from_rx.det == primitives["R_ERR"],
- NextState("IDLE")
- )
- )
-
-class SATALinkRX(Module):
- def __init__(self, phy):
- self.source = Source(link_description(32))
- self.to_tx = Source(from_rx)
-
- ###
-
- self.fsm = fsm = FSM(reset_state="IDLE")
-
- # CONT remover
- self.cont = cont = BufferizeEndpoints(SATACONTRemover(phy_description(32)), "source")
- self.comb += Record.connect(phy.source, cont.sink)
-
- # datas / primitives detection
- insert = Signal(32)
- det = Signal(32)
- self.comb += \
- If(cont.source.stb & (cont.source.charisk == 0b0001),
- det.eq(cont.source.data)
- )
-
- # descrambler
- self.scrambler = scrambler = SATAScrambler(link_description(32))
-
- # check CRC
- self.crc = crc = SATACRCChecker(link_description(32))
-
- sop = Signal()
- eop = Signal()
- self.sync += \
- If(fsm.ongoing("IDLE"),
- sop.eq(1),
- ).Elif(fsm.ongoing("COPY"),
- If(scrambler.sink.stb & scrambler.sink.ack,
- sop.eq(0)
- )
- )
- self.comb += eop.eq(det == primitives["EOF"])
-
- crc_error = Signal()
- self.sync += \
- If(crc.source.stb & crc.source.eop & crc.source.ack,
- crc_error.eq(crc.source.error)
- )
-
- # small fifo to manage HOLD
- self.fifo = SyncFIFO(link_description(32), 32)
-
- # graph
- self.comb += [
- cont.source.ack.eq(1),
- Record.connect(scrambler.source, crc.sink),
- Record.connect(crc.source, self.fifo.sink),
- Record.connect(self.fifo.source, self.source)
- ]
- cont_source_data_d = Signal(32)
- self.sync += \
- If(cont.source.stb & (det == 0),
- scrambler.sink.d.eq(cont.source.data)
- )
-
- # FSM
- fsm.act("IDLE",
- scrambler.reset.eq(1),
- If(det == primitives["X_RDY"],
- NextState("RDY")
- )
- )
- fsm.act("RDY",
- insert.eq(primitives["R_RDY"]),
- If(det == primitives["SOF"],
- NextState("WAIT_FIRST")
- )
- )
- fsm.act("WAIT_FIRST",
- insert.eq(primitives["R_IP"]),
- If(cont.source.stb & (det == 0),
- NextState("COPY")
- )
- )
- self.comb += [
- scrambler.sink.sop.eq(sop),
- scrambler.sink.eop.eq(eop)
- ]
- fsm.act("COPY",
- scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
- insert.eq(primitives["R_IP"]),
- If(det == primitives["HOLD"],
- insert.eq(primitives["HOLDA"])
- ).Elif(det == primitives["EOF"],
- NextState("WTRM")
- ).Elif(self.fifo.fifo.level > 8,
- insert.eq(primitives["HOLD"])
- )
- )
- fsm.act("EOF",
- insert.eq(primitives["R_IP"]),
- If(det == primitives["WTRM"],
- NextState("WTRM")
- )
- )
- fsm.act("WTRM",
- insert.eq(primitives["R_IP"]),
- If(~crc_error,
- NextState("R_OK")
- ).Else(
- NextState("R_ERR")
- )
- )
- fsm.act("R_OK",
- insert.eq(primitives["R_OK"]),
- If(det == primitives["SYNC"],
- NextState("IDLE")
- )
- )
- fsm.act("R_ERR",
- insert.eq(primitives["R_ERR"]),
- If(det == primitives["SYNC"],
- NextState("IDLE")
- )
- )
-
- # to TX
- self.comb += [
- self.to_tx.idle.eq(fsm.ongoing("IDLE")),
- self.to_tx.insert.eq(insert),
- self.to_tx.det.eq(det)
- ]
-
-class SATALink(Module):
- def __init__(self, phy):
- self.tx = SATALinkTX(phy)
- self.rx = SATALinkRX(phy)
- self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
- self.sink, self.source = self.tx.sink, self.rx.source
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link.scrambler import Scrambler
-
-from migen.genlib.misc import optree
-
-class SATACONTInserter(Module):
- def __init__(self, description):
- self.sink = sink = Sink(description)
- self.source = source = Source(description)
-
- ###
-
- self.counter = counter = Counter(max=4)
-
- is_data = Signal()
- was_data = Signal()
- was_hold = Signal()
- change = Signal()
- self.comb += is_data.eq(sink.charisk == 0)
-
- last_data = Signal(32)
- last_primitive = Signal(32)
- last_charisk = Signal(4)
- self.sync += [
- If(sink.stb & source.ack,
- last_data.eq(sink.data),
- last_charisk.eq(sink.charisk),
- If(~is_data,
- last_primitive.eq(sink.data),
- ),
- was_data.eq(is_data),
- was_hold.eq(last_primitive == primitives["HOLD"])
- )
- ]
- self.comb += change.eq(
- (sink.data != last_data) |
- (sink.charisk != last_charisk) |
- is_data
- )
-
- # scrambler
- self.scrambler = scrambler = InsertReset(Scrambler())
-
- # Datapath
- self.comb += [
- Record.connect(sink, source),
- If(sink.stb,
- If(~change,
- counter.ce.eq(sink.ack & (counter.value !=2)),
- # insert CONT
- If(counter.value == 1,
- source.charisk.eq(0b0001),
- source.data.eq(primitives["CONT"])
- # insert scrambled data for EMI
- ).Elif(counter.value == 2,
- scrambler.ce.eq(sink.ack),
- source.charisk.eq(0b0000),
- source.data.eq(scrambler.value)
- )
- ).Else(
- counter.reset.eq(source.ack),
- If(counter.value == 2,
- # Reinsert last primitive
- If(is_data | (~is_data & was_hold),
- source.stb.eq(1),
- sink.ack.eq(0),
- source.charisk.eq(0b0001),
- source.data.eq(last_primitive)
- )
- )
- )
- )
- ]
-
-class SATACONTRemover(Module):
- def __init__(self, description):
- self.sink = sink = Sink(description)
- self.source = source = Source(description)
-
- ###
-
- is_data = Signal()
- is_cont = Signal()
- in_cont = Signal()
- cont_ongoing = Signal()
-
- self.comb += [
- is_data.eq(sink.charisk == 0),
- is_cont.eq(~is_data & (sink.data == primitives["CONT"]))
- ]
- self.sync += \
- If(sink.stb & sink.ack,
- If(is_cont,
- in_cont.eq(1)
- ).Elif(~is_data,
- in_cont.eq(0)
- )
- )
- self.comb += cont_ongoing.eq(is_cont | (in_cont & is_data))
-
- # Datapath
- last_primitive = Signal(32)
- self.sync += [
- If(sink.stb & sink.ack,
- If(~is_data & ~is_cont,
- last_primitive.eq(sink.data)
- )
- )
- ]
- self.comb += [
- Record.connect(sink, source),
- If(cont_ongoing,
- source.charisk.eq(0b0001),
- source.data.eq(last_primitive)
- )
- ]
+++ /dev/null
-from lib.sata.common import *
-
-from migen.genlib.misc import optree
-from migen.actorlib.crc import CRCInserter, CRCChecker
-
-class CRCEngine(Module):
- """Cyclic Redundancy Check Engine
-
- Compute next CRC value from last CRC value and data input using
- an optimized asynchronous LFSR.
-
- Parameters
- ----------
- width : int
- Width of the data bus and CRC.
- polynom : int
- Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
-
- Attributes
- ----------
- d : in
- Data input.
- last : in
- last CRC value.
- next :
- next CRC value.
- """
- def __init__(self, width, polynom):
- self.d = Signal(width)
- self.last = Signal(width)
- self.next = Signal(width)
-
- ###
-
- def _optimize_eq(l):
- """
- Replace even numbers of XORs in the equation
- with an equivalent XOR
- """
- d = {}
- for e in l:
- if e in d:
- d[e] += 1
- else:
- d[e] = 1
- r = []
- for key, value in d.items():
- if value%2 != 0:
- r.append(key)
- return r
-
- new = Signal(32)
- self.comb += new.eq(self.last ^ self.d)
-
- # compute and optimize CRC's LFSR
- curval = [[("new", i)] for i in range(width)]
- for i in range(width):
- feedback = curval.pop()
- for j in range(width-1):
- if (polynom & (1<<(j+1))):
- curval[j] += feedback
- curval[j] = _optimize_eq(curval[j])
- curval.insert(0, feedback)
-
- # implement logic
- for i in range(width):
- xors = []
- for t, n in curval[i]:
- if t == "new":
- xors += [new[n]]
- self.comb += self.next[i].eq(optree("^", xors))
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class SATACRC(Module):
- """SATA CRC
-
- Implement a SATA CRC generator/checker
-
- Attributes
- ----------
- value : out
- CRC value (used for generator).
- error : out
- CRC error (used for checker).
- """
- width = 32
- polynom = 0x04C11DB7
- init = 0x52325032
- check = 0x00000000
- def __init__(self, dw=32):
- self.d = Signal(self.width)
- self.value = Signal(self.width)
- self.error = Signal()
-
- ###
-
- self.engine = CRCEngine(self.width, self.polynom)
- reg_i = Signal(self.width, reset=self.init)
- self.sync += reg_i.eq(self.engine.next)
- self.comb += [
- self.engine.d.eq(self.d),
- self.engine.last.eq(reg_i),
-
- self.value.eq(reg_i),
- self.error.eq(self.engine.next != self.check)
- ]
-
-class SATACRCInserter(CRCInserter):
- def __init__(self, description):
- CRCInserter.__init__(self, SATACRC, description)
-
-class SATACRCChecker(CRCChecker):
- def __init__(self, description):
- CRCChecker.__init__(self, SATACRC, description)
+++ /dev/null
-from lib.sata.common import *
-
-from migen.fhdl.std import *
-from migen.genlib.misc import optree
-
-@DecorateModule(InsertCE)
-class Scrambler(Module):
- """SATA Scrambler
-
- Implement a SATA Scrambler
-
- Attributes
- ----------
- value : out
- Scrambled value.
- """
- def __init__(self):
- self.value = Signal(32)
-
- ###
-
- context = Signal(16, reset=0xf0f6)
- next_value = Signal(32)
- self.sync += context.eq(next_value[16:32])
-
- # XXX: from SATA specification, replace it with
- # a generic implementation using polynoms.
- lfsr_coefs = (
- (15, 13, 4, 0), #0
- (15, 14, 13, 5, 4, 1, 0),
- (14, 13, 6, 5, 4, 2,1, 0),
- (15, 14, 7, 6, 5, 3,2, 1),
- (13, 8, 7, 6, 3, 2, 0),
- (14, 9, 8, 7, 4, 3, 1),
- (15, 10, 9, 8, 5, 4, 2),
- (15, 13, 11, 10, 9, 6, 5, 4, 3, 0),
- (15, 14, 13, 12, 11, 10,7, 6, 5, 1, 0),
- (14, 12, 11, 8, 7, 6, 4, 2, 1, 0),
- (15, 13, 12, 9, 8, 7, 5, 3, 2, 1),
- (15, 14, 10, 9, 8, 6, 3, 2, 0),
- (13, 11, 10, 9, 7, 3, 1, 0),
- (14, 12, 11, 10, 8, 4, 2, 1),
- (15, 13, 12, 11, 9, 5, 3, 2),
- (15, 14, 12, 10, 6, 3, 0),
-
- (11, 7, 1, 0), #16
- (12, 8, 2, 1),
- (13, 9, 3, 2),
- (14, 10, 4, 3),
- (15, 11, 5, 4),
- (15, 13, 12, 6, 5, 4, 0),
- (15, 14, 7, 6, 5, 4, 1, 0),
- (13, 8, 7, 6, 5, 4, 2, 1, 0),
- (14, 9, 8,7, 6, 5, 3, 2, 1),
- (15, 10, 9, 8, 7, 6, 4, 3, 2),
- (15, 13, 11, 10, 9, 8, 7, 5, 3, 0),
- (15, 14, 13, 12, 11, 10, 9, 8, 6, 1, 0),
- (14, 12, 11, 10, 9, 7, 4, 2, 1, 0),
- (15, 13, 12, 11, 10, 8, 5, 3, 2, 1),
- (15, 14, 12, 11, 9, 6, 3, 2, 0),
- (12, 10, 7, 3, 1, 0),
- )
-
- for n, coefs in enumerate(lfsr_coefs):
- eq = [context[i] for i in coefs]
- self.comb += next_value[n].eq(optree("^", eq))
-
- self.comb += self.value.eq(next_value)
-
-@DecorateModule(InsertReset)
-class SATAScrambler(Module):
- def __init__(self, description):
- self.sink = sink = Sink(description)
- self.source = source = Source(description)
-
- ###
-
- self.scrambler = Scrambler()
- self.comb += [
- self.scrambler.ce.eq(sink.stb & sink.ack),
- Record.connect(sink, source),
- source.d.eq(sink.d ^ self.scrambler.value)
- ]
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.phy.ctrl import SATAPHYHostCtrl
-from lib.sata.phy.datapath import SATAPHYDatapath
-
-class SATAPHY(Module):
- def __init__(self, pads, clk_freq, host=True, device_family="k7", speed="SATA1"):
- self.speed = speed
- # Transceiver / Clocks
- if device_family == "k7":
- from lib.sata.phy.k7.trx import K7SATAPHYTRX
- from lib.sata.phy.k7.crg import K7SATAPHYCRG
- self.trx = K7SATAPHYTRX(pads, speed)
- self.crg = K7SATAPHYCRG(pads, self.trx, clk_freq, speed)
- else:
- raise NotImplementedError(device_family + "device family not implemented")
-
- # Control
- if host:
- self.ctrl = SATAPHYHostCtrl(self.trx, self.crg, clk_freq)
- else:
- self.ctrl = SATAPHYDeviceCtrl(self.trx, self.crg, clk_freq)
-
- # Datapath
- self.datapath = SATAPHYDatapath(self.trx, self.ctrl)
- self.sink, self.source = self.datapath.sink, self.datapath.source
+++ /dev/null
-from math import ceil
-
-from lib.sata.common import *
-
-def us(t, clk_freq):
- clk_period_us = 1000000/clk_freq
- return ceil(t/clk_period_us)
-
-class SATAPHYHostCtrlTimeout(Module):
- def __init__(self, load):
- self.load = Signal()
- self.dec = Signal()
- self.reached = Signal()
-
- cnt = Signal(max=load+1)
- self.sync += \
- If(self.load,
- cnt.eq(load)
- ).Elif(self.dec & ~self.reached,
- cnt.eq(cnt-1)
- )
- self.comb += self.reached.eq(cnt == 0)
-
-class SATAPHYHostCtrl(Module):
- def __init__(self, trx, crg, clk_freq):
- self.ready = Signal()
- self.need_reset = Signal()
- self.sink = sink = Sink(phy_description(32))
- self.source = source = Source(phy_description(32))
-
- ###
- self.comb += [
- source.stb.eq(1),
- sink.ack.eq(1)
- ]
-
- retry_timeout = SATAPHYHostCtrlTimeout(us(10000, clk_freq))
- align_timeout = SATAPHYHostCtrlTimeout(us(873, clk_freq))
- self.submodules += align_timeout, retry_timeout
-
- align_detect = Signal()
- non_align_cnt = Signal(4)
-
- self.fsm = fsm = FSM(reset_state="RESET")
- fsm.act("RESET",
- trx.tx_idle.eq(1),
- retry_timeout.load.eq(1),
- align_timeout.load.eq(1),
- If(crg.ready,
- NextState("COMINIT")
- ),
- )
- fsm.act("COMINIT",
- trx.tx_idle.eq(1),
- trx.tx_cominit_stb.eq(1),
- If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
- NextState("AWAIT_COMINIT")
- ),
- )
- fsm.act("AWAIT_COMINIT",
- trx.tx_idle.eq(1),
- retry_timeout.dec.eq(1),
- If(trx.rx_cominit_stb,
- NextState("AWAIT_NO_COMINIT")
- ).Else(
- If(retry_timeout.reached,
- NextState("RESET")
- )
- ),
- )
- fsm.act("AWAIT_NO_COMINIT",
- trx.tx_idle.eq(1),
- retry_timeout.load.eq(1),
- If(~trx.rx_cominit_stb,
- NextState("CALIBRATE")
- ),
- )
- fsm.act("CALIBRATE",
- trx.tx_idle.eq(1),
- NextState("COMWAKE"),
- )
- fsm.act("COMWAKE",
- trx.tx_idle.eq(1),
- trx.tx_comwake_stb.eq(1),
- If(trx.tx_comwake_ack,
- NextState("AWAIT_COMWAKE")
- ),
- )
- fsm.act("AWAIT_COMWAKE",
- trx.tx_idle.eq(1),
- retry_timeout.dec.eq(1),
- If(trx.rx_comwake_stb,
- NextState("AWAIT_NO_COMWAKE")
- ).Else(
- If(retry_timeout.reached,
- NextState("RESET")
- )
- ),
- )
- fsm.act("AWAIT_NO_COMWAKE",
- trx.tx_idle.eq(1),
- If(~trx.rx_comwake_stb,
- NextState("AWAIT_NO_RX_IDLE")
- ),
- )
- fsm.act("AWAIT_NO_RX_IDLE",
- trx.tx_idle.eq(0),
- source.data.eq(0x4A4A4A4A), #D10.2
- source.charisk.eq(0b0000),
- If(~trx.rx_idle,
- NextState("AWAIT_ALIGN"),
- crg.reset.eq(1),
- trx.pmarxreset.eq(1)
- ),
- )
- fsm.act("AWAIT_ALIGN",
- trx.tx_idle.eq(0),
- source.data.eq(0x4A4A4A4A), #D10.2
- source.charisk.eq(0b0000),
- trx.rx_align.eq(1),
- align_timeout.dec.eq(1),
- If(align_detect & ~trx.rx_idle,
- NextState("SEND_ALIGN")
- ).Elif(align_timeout.reached,
- NextState("RESET")
- ),
- )
- fsm.act("SEND_ALIGN",
- trx.tx_idle.eq(0),
- trx.rx_align.eq(1),
- source.data.eq(primitives["ALIGN"]),
- source.charisk.eq(0b0001),
- If(non_align_cnt == 3,
- NextState("READY")
- ),
- )
- fsm.act("READY",
- trx.tx_idle.eq(0),
- trx.rx_align.eq(1),
- source.data.eq(primitives["SYNC"]),
- source.charisk.eq(0b0001),
- If(trx.rx_idle,
- NextState("RESET")
- ),
- self.ready.eq(1),
- )
-
- self.reset_timeout = Timeout(clk_freq//16)
- self.comb += [
- self.reset_timeout.ce.eq(~self.ready),
- self.need_reset.eq(self.reset_timeout.reached)
- ]
-
- self.comb += \
- align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
- self.sync += \
- If(fsm.ongoing("SEND_ALIGN"),
- If(sink.stb,
- If(sink.data[0:8] == 0x7C,
- non_align_cnt.eq(non_align_cnt + 1)
- ).Else(
- non_align_cnt.eq(0)
- )
- )
- )
+++ /dev/null
-from lib.sata.common import *
-
-from migen.genlib.misc import chooser
-from migen.flow.plumbing import Multiplexer, Demultiplexer
-from migen.actorlib.structuring import Converter
-
-class SATAPHYDatapathRX(Module):
- def __init__(self):
- self.sink = Sink(phy_description(16))
- self.source = Source(phy_description(32))
-
- ###
-
- # width convertion (16 to 32) and byte alignment
- byte_alignment = Signal()
- last_charisk = Signal(2)
- last_data = Signal(16)
- self.sync.sata_rx += \
- If(self.sink.stb & self.sink.ack,
- If(self.sink.charisk != 0,
- byte_alignment.eq(self.sink.charisk[1])
- ),
- last_charisk.eq(self.sink.charisk),
- last_data.eq(self.sink.data)
- )
- converter = Converter(phy_description(16), phy_description(32), reverse=False)
- self.converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
- self.comb += [
- self.converter.sink.stb.eq(self.sink.stb),
- If(byte_alignment,
- self.converter.sink.charisk.eq(Cat(last_charisk[1], self.sink.charisk[0])),
- self.converter.sink.data.eq(Cat(last_data[8:], self.sink.data[:8]))
- ).Else(
- self.converter.sink.charisk.eq(self.sink.charisk),
- self.converter.sink.data.eq(self.sink.data)
- ),
- self.sink.ack.eq(self.converter.sink.ack),
- self.converter.reset.eq(self.converter.source.charisk[2:] != 0)
- ]
-
- # clock domain crossing
- # (SATA3) 300MHz sata_rx clk to sys_clk
- # (SATA2) 150MHz sata_rx clk to sys_clk
- # (SATA1) 75MHz sata_rx clk to sys_clk
- # requirements:
- # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
- # source destination is always able to accept data (ack always 1)
- fifo = AsyncFIFO(phy_description(32), 4)
- self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
- self.comb += [
- Record.connect(self.converter.source, fifo.sink),
- Record.connect(fifo.source, self.source)
- ]
-
-class SATAPHYDatapathTX(Module):
- def __init__(self):
- self.sink = Sink(phy_description(32))
- self.source = Source(phy_description(16))
-
- ###
-
- # clock domain crossing
- # (SATA3) sys_clk to 300MHz sata_tx clk
- # (SATA2) sys_clk to 150MHz sata_tx clk
- # (SATA1) sys_clk to 75MHz sata_tx clk
- # requirements:
- # source destination is always able to accept data (ack always 1)
- fifo = AsyncFIFO(phy_description(32), 4)
- self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
- self.comb += Record.connect(self.sink, fifo.sink)
-
- # width convertion (32 to 16)
- converter = Converter(phy_description(32), phy_description(16), reverse=False)
- self.converter = RenameClockDomains(converter, "sata_tx")
- self.comb += [
- Record.connect(self.fifo.source, self.converter.sink),
- Record.connect(self.converter.source, self.source)
- ]
-
-class SATAPHYAlignInserter(Module):
- def __init__(self, ctrl):
- self.sink = sink = Sink(phy_description(32))
- self.source = source = Source(phy_description(32))
-
- ###
-
- # send 2 ALIGN every 256 DWORDs
- # used for clock compensation between
- # HOST and device
- cnt = Signal(8)
- send = Signal()
- self.sync += \
- If(~ctrl.ready,
- cnt.eq(0)
- ).Elif(source.stb & source.ack,
- cnt.eq(cnt+1)
- )
- self.comb += [
- send.eq(cnt < 2),
- If(send,
- source.stb.eq(1),
- source.charisk.eq(0b0001),
- source.data.eq(primitives["ALIGN"]),
- sink.ack.eq(0)
- ).Else(
- source.stb.eq(sink.stb),
- source.data.eq(sink.data),
- source.charisk.eq(sink.charisk),
- sink.ack.eq(source.ack)
- )
- ]
-
-class SATAPHYAlignRemover(Module):
- def __init__(self):
- self.sink = sink = Sink(phy_description(32))
- self.source = source = Source(phy_description(32))
-
- ###
-
- charisk_match = sink.charisk == 0b0001
- data_match = sink.data == primitives["ALIGN"]
-
- self.comb += \
- If(sink.stb & charisk_match & data_match,
- sink.ack.eq(1),
- ).Else(
- Record.connect(sink, source)
- )
-
-class SATAPHYDatapath(Module):
- def __init__(self, trx, ctrl):
- self.sink = Sink(phy_description(32))
- self.source = Source(phy_description(32))
-
- ###
-
- # TX path
- self.align_inserter = SATAPHYAlignInserter(ctrl)
- self.mux = Multiplexer(phy_description(32), 2)
- self.tx = SATAPHYDatapathTX()
- self.comb += [
- self.mux.sel.eq(ctrl.ready),
- Record.connect(self.sink, self.align_inserter.sink),
- Record.connect(ctrl.source, self.mux.sink0),
- Record.connect(self.align_inserter.source, self.mux.sink1),
- Record.connect(self.mux.source, self.tx.sink),
- Record.connect(self.tx.source, trx.sink)
- ]
-
- # RX path
- self.rx = SATAPHYDatapathRX()
- self.demux = Demultiplexer(phy_description(32), 2)
- self.align_remover = SATAPHYAlignRemover()
- self.comb += [
- self.demux.sel.eq(ctrl.ready),
- Record.connect(trx.source, self.rx.sink),
- Record.connect(self.rx.source, self.demux.sink),
- Record.connect(self.demux.source0, ctrl.sink),
- Record.connect(self.demux.source1, self.align_remover.sink),
- Record.connect(self.align_remover.source, self.source)
- ]
+++ /dev/null
-from math import ceil
-
-from lib.sata.common import *
-
-class K7SATAPHYCRG(Module):
- def __init__(self, pads, gtx, clk_freq, speed):
- self.reset = Signal()
- self.ready = Signal()
-
- self.cd_sata_tx = ClockDomain()
- self.cd_sata_rx = ClockDomain()
-
- # CPLL
- # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
- # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output dividers.
- refclk = Signal()
- self.specials += Instance("IBUFDS_GTE2",
- i_CEB=0,
- i_I=pads.refclk_p,
- i_IB=pads.refclk_n,
- o_O=refclk
- )
- self.comb += gtx.gtrefclk0.eq(refclk)
-
- # TX clocking
- # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
- # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
- # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
- mmcm_reset = Signal()
- mmcm_locked = Signal()
- mmcm_fb = Signal()
- mmcm_clk_i = Signal()
- mmcm_clk0_o = Signal()
- mmcm_div_config = {
- "SATA1" : 16.0,
- "SATA2" : 8.0,
- "SATA3" : 4.0
- }
- mmcm_div = mmcm_div_config[speed]
- self.specials += [
- Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i),
- Instance("MMCME2_ADV",
- p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked,
-
- # DRP
- i_DCLK=0, i_DEN=0, i_DWE=0, #o_DRDY=,
- i_DADDR=0, i_DI=0, #o_DO=,
-
- # VCO
- p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666,
- p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1,
- i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
-
- # CLK0
- p_CLKOUT0_DIVIDE_F=mmcm_div, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o,
- ),
- Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk),
- ]
- self.comb += [
- gtx.txusrclk.eq(self.cd_sata_tx.clk),
- gtx.txusrclk2.eq(self.cd_sata_tx.clk)
- ]
-
- # RX clocking
- # (SATA3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
- # (SATA2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
- # (SATA1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
- self.specials += [
- Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
- ]
- self.comb += [
- gtx.rxusrclk.eq(self.cd_sata_rx.clk),
- gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
- ]
-
- # Configuration Reset
- # After configuration, GTX's resets have to stay low for at least 500ns
- # See AR43482
- reset_en = Signal()
- clk_period_ns = 1000000000/clk_freq
- reset_en_cnt_max = ceil(500/clk_period_ns)
- reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
- self.sync += \
- If(self.reset,
- reset_en_cnt.eq(reset_en_cnt.reset)
- ).Elif(~reset_en,
- reset_en_cnt.eq(reset_en_cnt-1)
- )
- self.comb += reset_en.eq(reset_en_cnt == 0)
-
- # TX Reset FSM
- tx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
- self.submodules += tx_reset_fsm
- self.comb += tx_reset_fsm.reset.eq(self.reset)
- tx_reset_fsm.act("IDLE",
- If(reset_en,
- NextState("RESET_GTX"),
- )
- )
- tx_reset_fsm.act("RESET_GTX",
- gtx.gttxreset.eq(1),
- If(gtx.cplllock & mmcm_locked,
- NextState("RELEASE_GTX")
- )
- )
- tx_reset_fsm.act("RELEASE_GTX",
- gtx.txuserrdy.eq(1),
- If(gtx.txresetdone,
- NextState("READY")
- )
- )
- tx_reset_fsm.act("READY",
- gtx.txuserrdy.eq(1)
- )
-
- # RX Reset FSM
- rx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
- self.submodules += rx_reset_fsm
- self.comb += rx_reset_fsm.reset.eq(self.reset)
-
- rx_reset_fsm.act("IDLE",
- If(reset_en,
- NextState("RESET_GTX"),
- )
- )
- rx_reset_fsm.act("RESET_GTX",
- gtx.gtrxreset.eq(1),
- If(gtx.cplllock & mmcm_locked,
- NextState("RELEASE_GTX")
- )
- )
- rx_reset_fsm.act("RELEASE_GTX",
- gtx.rxuserrdy.eq(1),
- If(gtx.rxresetdone,
- NextState("READY")
- )
- )
- rx_reset_fsm.act("READY",
- gtx.rxuserrdy.eq(1)
- )
-
- # Ready
- self.tx_ready = tx_reset_fsm.ongoing("READY")
- self.rx_ready = rx_reset_fsm.ongoing("READY")
- self.comb += self.ready.eq(self.tx_ready & self.rx_ready)
-
- # Reset PLL
- self.comb += gtx.cpllreset.eq(ResetSignal() | self.reset | ~reset_en)
-
- # Reset MMCM
- self.comb += mmcm_reset.eq(ResetSignal() | self.reset | ~gtx.cplllock)
-
- # Reset for SATA TX/RX clock domains
- self.specials += [
- AsyncResetSynchronizer(self.cd_sata_tx, ~self.tx_ready),
- AsyncResetSynchronizer(self.cd_sata_rx, ~self.rx_ready),
- ]
+++ /dev/null
-from lib.sata.common import *
-
-from migen.genlib.cdc import *
-
-def ones(width):
- return 2**width-1
-
-class _PulseSynchronizer(PulseSynchronizer):
- def __init__(self, i, idomain, o, odomain):
- PulseSynchronizer.__init__(self, idomain, odomain)
- self.comb += [
- self.i.eq(i),
- o.eq(self.o)
- ]
-
-class _RisingEdge(Module):
- def __init__(self, i, o):
- i_d = Signal()
- self.sync += i_d.eq(i)
- self.comb += o.eq(i & ~i_d)
-
-class K7SATAPHYTRX(Module):
- def __init__(self, pads, speed):
- # Common signals
-
- # control
- self.tx_idle = Signal() #i
-
- self.tx_cominit_stb = Signal() #i
- self.tx_cominit_ack = Signal() #o
- self.tx_comwake_stb = Signal() #i
- self.tx_comwake_ack = Signal() #o
-
- self.rx_idle = Signal() #o
- self.rx_align = Signal() #i
-
- self.rx_cominit_stb = Signal() #o
- self.rx_comwake_stb = Signal() #o
-
- # datapath
- self.sink = Sink(phy_description(16))
- self.source = Source(phy_description(16))
-
- # K7 specific signals
- # Channel - Ref Clock Ports
- self.gtrefclk0 = Signal()
-
- # Channel PLL
- self.cplllock = Signal()
- self.cpllreset = Signal()
-
- # Receive Ports
- self.rxuserrdy = Signal()
- self.rxalign = Signal()
-
- # Receive Ports - 8b10b Decoder
- self.rxcharisk = Signal(2)
- self.rxdisperr = Signal(2)
-
- # Receive Ports - RX Data Path interface
- self.gtrxreset = Signal()
- self.pmarxreset = Signal()
- self.rxdata = Signal(16)
- self.rxoutclk = Signal()
- self.rxusrclk = Signal()
- self.rxusrclk2 = Signal()
-
- # Receive Ports - RX Driver,OOB signalling,Coupling and Eq.,CDR
- self.rxelecidle = Signal()
-
- # Receive Ports - RX PLL Ports
- self.rxresetdone = Signal()
-
- # Receive Ports - RX Ports for SATA
- self.rxcominitdet = Signal()
- self.rxcomwakedet = Signal()
-
- # Transmit Ports
- self.txuserrdy = Signal()
-
- # Transmit Ports - 8b10b Encoder Control Ports
- self.txcharisk = Signal(2)
-
- # Transmit Ports - TX Data Path interface
- self.gttxreset = Signal()
- self.txdata = Signal(16)
- self.txoutclk = Signal()
- self.txusrclk = Signal()
- self.txusrclk2 = Signal()
-
- # Transmit Ports - TX PLL Ports
- self.txresetdone = Signal()
-
- # Transmit Ports - TX Ports for PCI Express
- self.txelecidle = Signal(reset=1)
-
- # Transmit Ports - TX Ports for SATA
- self.txcomfinish = Signal()
- self.txcominit = Signal()
- self.txcomwake = Signal()
- self.txrate = Signal(3)
- self.rxcdrlock = Signal()
-
- # Config at startup
- div_config = {
- "SATA1" : 4,
- "SATA2" : 2,
- "SATA3" : 1
- }
- rxout_div = div_config[speed]
- txout_div = div_config[speed]
-
- cdr_config = {
- "SATA1" : 0x0380008BFF40100008,
- "SATA2" : 0x0388008BFF40200008,
- "SATA3" : 0X0380008BFF10200010
- }
- rxcdr_cfg = cdr_config[speed]
-
- # Specific / Generic signals encoding/decoding
- self.comb += [
- self.txelecidle.eq(self.tx_idle),
- self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish),
- self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish),
- self.rx_idle.eq(self.rxelecidle),
- self.rxalign.eq(self.rx_align),
- self.rx_cominit_stb.eq(self.rxcominitdet),
- self.rx_comwake_stb.eq(self.rxcomwakedet),
- ]
- self.submodules += [
- _RisingEdge(self.tx_cominit_stb, self.txcominit),
- _RisingEdge(self.tx_comwake_stb, self.txcomwake),
- ]
-
- self.comb += [
- self.txcharisk.eq(self.sink.charisk),
- self.txdata.eq(self.sink.data),
- self.sink.ack.eq(1),
-
- self.source.stb.eq(1),
- self.source.charisk.eq(self.rxcharisk),
- self.source.data.eq(self.rxdata)
- ]
-
- # Internals and clock domain crossing
- # sys_clk --> sata_tx clk
- txuserrdy = Signal()
- txelecidle = Signal(reset=1)
- txcominit = Signal()
- txcomwake = Signal()
- txrate = Signal(3)
-
- self.specials += [
- MultiReg(self.txuserrdy, txuserrdy, "sata_tx"),
- MultiReg(self.txelecidle, txelecidle, "sata_tx"),
- MultiReg(self.txrate, txrate, "sata_tx")
- ]
- self.submodules += [
- _PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"),
- _PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"),
- ]
-
- # sata_tx clk --> sys clk
- txresetdone = Signal()
- txcomfinish = Signal()
-
- self.specials += [
- MultiReg(txresetdone, self.txresetdone, "sys"),
- ]
-
- self.submodules += [
- _PulseSynchronizer(txcomfinish, "sata_tx", self.txcomfinish, "sys"),
- ]
-
- # sys clk --> sata_rx clk
- rxuserrdy = Signal()
-
- self.specials += [
- MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
- ]
-
- # sata_rx clk --> sys clk
- rxelecidle = Signal()
- rxelecidle_i = Signal()
- rxelecidle_cnt_i = Signal(9)
- rxresetdone = Signal()
- rxcominitdet = Signal()
- rxcomwakedet = Signal()
- rxratedone = Signal()
- rxcdrlock = Signal()
-
- self.specials += [
- MultiReg(rxelecidle, rxelecidle_i, "sys"),
- MultiReg(rxresetdone, self.rxresetdone, "sys"),
- MultiReg(rxcominitdet, self.rxcominitdet, "sys"),
- MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"),
- MultiReg(rxcdrlock, self.rxcdrlock, "sys"),
- ]
-
- self.sync += [
- If(rxelecidle_i != self.rxelecidle,
- If(rxelecidle_cnt_i == 0,
- self.rxelecidle.eq(rxelecidle_i),
- rxelecidle_cnt_i.eq(255)
- ).Else(
- rxelecidle_cnt_i.eq(rxelecidle_cnt_i-1)
- )
- ).Else(
- rxelecidle_cnt_i.eq(255)
- )
- ]
-
- self.rxbyteisaligned = Signal()
-
- # QPLL input clock
- self.qpllclk = Signal()
- self.qpllrefclk = Signal()
-
- # Instance
- gtxe2_channel_parameters = {
- # Simulation-Only Attributes
- "p_SIM_RECEIVER_DETECT_PASS":"TRUE",
- "p_SIM_TX_EIDLE_DRIVE_LEVEL":"X",
- "p_SIM_RESET_SPEEDUP":"TRUE",
- "p_SIM_CPLLREFCLK_SEL":0b001,
- "p_SIM_VERSION":"4.0",
-
- # RX Byte and Word Alignment Attributes
- "p_ALIGN_COMMA_DOUBLE":"FALSE",
- "p_ALIGN_COMMA_ENABLE":ones(10),
- "p_ALIGN_COMMA_WORD":2,
- "p_ALIGN_MCOMMA_DET":"TRUE",
- "p_ALIGN_MCOMMA_VALUE":0b1010000011,
- "p_ALIGN_PCOMMA_DET":"TRUE",
- "p_ALIGN_PCOMMA_VALUE":0b0101111100,
- "p_SHOW_REALIGN_COMMA":"FALSE",
- "p_RXSLIDE_AUTO_WAIT":7,
- "p_RXSLIDE_MODE":"PCS",
- "p_RX_SIG_VALID_DLY":10,
-
- # RX 8B/10B Decoder Attributes
- "p_RX_DISPERR_SEQ_MATCH":"TRUE",
- "p_DEC_MCOMMA_DETECT":"TRUE",
- "p_DEC_PCOMMA_DETECT":"TRUE",
- "p_DEC_VALID_COMMA_ONLY":"FALSE",
-
- # RX Clock Correction Attributes
- "p_CBCC_DATA_SOURCE_SEL":"DECODED",
- "p_CLK_COR_SEQ_2_USE":"FALSE",
- "p_CLK_COR_KEEP_IDLE":"FALSE",
- "p_CLK_COR_MAX_LAT":9,
- "p_CLK_COR_MIN_LAT":7,
- "p_CLK_COR_PRECEDENCE":"TRUE",
- "p_CLK_COR_REPEAT_WAIT":0,
- "p_CLK_COR_SEQ_LEN":1,
- "p_CLK_COR_SEQ_1_ENABLE":ones(4),
- "p_CLK_COR_SEQ_1_1":0b0100000000,
- "p_CLK_COR_SEQ_1_2":0b0000000000,
- "p_CLK_COR_SEQ_1_3":0b0000000000,
- "p_CLK_COR_SEQ_1_4":0b0000000000,
- "p_CLK_CORRECT_USE":"FALSE",
- "p_CLK_COR_SEQ_2_ENABLE":ones(4),
- "p_CLK_COR_SEQ_2_1":0b0100000000,
- "p_CLK_COR_SEQ_2_2":0,
- "p_CLK_COR_SEQ_2_3":0,
- "p_CLK_COR_SEQ_2_4":0,
-
- # RX Channel Bonding Attributes
- "p_CHAN_BOND_KEEP_ALIGN":"FALSE",
- "p_CHAN_BOND_MAX_SKEW":1,
- "p_CHAN_BOND_SEQ_LEN":1,
- "p_CHAN_BOND_SEQ_1_1":0,
- "p_CHAN_BOND_SEQ_1_1":0,
- "p_CHAN_BOND_SEQ_1_2":0,
- "p_CHAN_BOND_SEQ_1_3":0,
- "p_CHAN_BOND_SEQ_1_4":0,
- "p_CHAN_BOND_SEQ_1_ENABLE":ones(4),
- "p_CHAN_BOND_SEQ_2_1":0,
- "p_CHAN_BOND_SEQ_2_2":0,
- "p_CHAN_BOND_SEQ_2_3":0,
- "p_CHAN_BOND_SEQ_2_4":0,
- "p_CHAN_BOND_SEQ_2_ENABLE":ones(4),
- "p_CHAN_BOND_SEQ_2_USE":"FALSE",
- "p_FTS_DESKEW_SEQ_ENABLE":ones(4),
- "p_FTS_LANE_DESKEW_CFG":ones(4),
- "p_FTS_LANE_DESKEW_EN":"FALSE",
-
- # RX Margin Analysis Attributes
- "p_ES_CONTROL":0,
- "p_ES_ERRDET_EN":"FALSE",
- "p_ES_EYE_SCAN_EN":"TRUE",
- "p_ES_HORZ_OFFSET":0,
- "p_ES_PMA_CFG":0,
- "p_ES_PRESCALE":0,
- "p_ES_QUALIFIER":0,
- "p_ES_QUAL_MASK":0,
- "p_ES_SDATA_MASK":0,
- "p_ES_VERT_OFFSET":0,
-
- # FPGA RX Interface Attributes
- "p_RX_DATA_WIDTH":20,
-
- # PMA Attributes
- "p_OUTREFCLK_SEL_INV":0b11,
- "p_PMA_RSV":0x00018480,
- "p_PMA_RSV2":0x2050,
- "p_PMA_RSV3":0,
- "p_PMA_RSV4":0,
- "p_RX_BIAS_CFG":0b100,
- "p_DMONITOR_CFG":0xA00,
- "p_RX_CM_SEL":0b11,
- "p_RX_CM_TRIM":0b010,
- "p_RX_DEBUG_CFG":0,
- "p_RX_OS_CFG":0b10000000,
- "p_TERM_RCAL_CFG":0,
- "p_TERM_RCAL_OVRD":0,
- "p_TST_RSV":0,
- "p_RX_CLK25_DIV":6,
- "p_TX_CLK25_DIV":6,
- "p_UCODEER_CLR":0,
-
- # PCI Express Attributes
- "p_PCS_PCIE_EN":"FALSE",
-
- # PCS Attributes
- "p_PCS_RSVD_ATTR":0x100,
-
- # RX Buffer Attributes
- "p_RXBUF_ADDR_MODE":"FAST",
- "p_RXBUF_EIDLE_HI_CNT":0b1000,
- "p_RXBUF_EIDLE_LO_CNT":0,
- "p_RXBUF_EN":"TRUE",
- "p_RX_BUFFER_CFG":0,
- "p_RXBUF_RESET_ON_CB_CHANGE":"TRUE",
- "p_RXBUF_RESET_ON_COMMAALIGN":"FALSE",
- "p_RXBUF_RESET_ON_EIDLE":"FALSE",
- "p_RXBUF_RESET_ON_RATE_CHANGE":"TRUE",
- "p_RXBUFRESET_TIME":1,
- "p_RXBUF_THRESH_OVFLW":61,
- "p_RXBUF_THRESH_OVRD":"FALSE",
- "p_RXBUF_THRESH_UNDFLW":4,
- "p_RXDLY_CFG":0x1f,
- "p_RXDLY_LCFG":0x30,
- "p_RXDLY_TAP_CFG":0,
- "p_RXPH_CFG":0,
- "p_RXPHDLY_CFG":0x084820,
- "p_RXPH_MONITOR_SEL":0,
- "p_RX_XCLK_SEL":"RXUSR",
- "p_RX_DDI_SEL":0,
- "p_RX_DEFER_RESET_BUF_EN":"TRUE",
-
- #CDR Attributes
- "p_RXCDR_CFG":rxcdr_cfg,
- "p_RXCDR_FR_RESET_ON_EIDLE":0,
- "p_RXCDR_HOLD_DURING_EIDLE":0,
- "p_RXCDR_PH_RESET_ON_EIDLE":0,
- "p_RXCDR_LOCK_CFG":0b010101,
-
- # RX Initialization and Reset Attributes
- "p_RXCDRFREQRESET_TIME":1,
- "p_RXCDRPHRESET_TIME":1,
- "p_RXISCANRESET_TIME":1,
- "p_RXPCSRESET_TIME":1,
- "p_RXPMARESET_TIME":3,
-
- # RX OOB Signaling Attributes
- "p_RXOOB_CFG":0b0000110,
-
- # RX Gearbox Attributes
- "p_RXGEARBOX_EN":"FALSE",
- "p_GEARBOX_MODE":0,
-
- # PRBS Detection Attribute
- "p_RXPRBS_ERR_LOOPBACK":0,
-
- # Power-Down Attributes
- "p_PD_TRANS_TIME_FROM_P2":0x03c,
- "p_PD_TRANS_TIME_NONE_P2":0x3c,
- "p_PD_TRANS_TIME_TO_P2":0x64,
-
- # RX OOB Signaling Attributes
- "p_SAS_MAX_COM":64,
- "p_SAS_MIN_COM":36,
- "p_SATA_BURST_SEQ_LEN":0b0101,
- "p_SATA_BURST_VAL":0b100,
- "p_SATA_EIDLE_VAL":0b100,
- "p_SATA_MAX_BURST":8,
- "p_SATA_MAX_INIT":21,
- "p_SATA_MAX_WAKE":7,
- "p_SATA_MIN_BURST":4,
- "p_SATA_MIN_INIT":12,
- "p_SATA_MIN_WAKE":4,
-
- # RX Fabric Clock Output Control Attributes
- "p_TRANS_TIME_RATE":0x0e,
-
- # TX Buffer Attributes
- "p_TXBUF_EN":"TRUE",
- "p_TXBUF_RESET_ON_RATE_CHANGE":"TRUE",
- "p_TXDLY_CFG":0x1f,
- "p_TXDLY_LCFG":0x030,
- "p_TXDLY_TAP_CFG":0,
- "p_TXPH_CFG":0x0780,
- "p_TXPHDLY_CFG":0x084020,
- "p_TXPH_MONITOR_SEL":0,
- "p_TX_XCLK_SEL":"TXOUT",
-
- # FPGA TX Interface Attributes
- "p_TX_DATA_WIDTH":20,
-
- # TX Configurable Driver Attributes
- "p_TX_DEEMPH0":0,
- "p_TX_DEEMPH1":0,
- "p_TX_EIDLE_ASSERT_DELAY":0b110,
- "p_TX_EIDLE_DEASSERT_DELAY":0b100,
- "p_TX_LOOPBACK_DRIVE_HIZ":"FALSE",
- "p_TX_MAINCURSOR_SEL":0,
- "p_TX_DRIVE_MODE":"DIRECT",
- "p_TX_MARGIN_FULL_0":0b1001110,
- "p_TX_MARGIN_FULL_1":0b1001001,
- "p_TX_MARGIN_FULL_2":0b1000101,
- "p_TX_MARGIN_FULL_3":0b1000010,
- "p_TX_MARGIN_FULL_4":0b1000000,
- "p_TX_MARGIN_LOW_0":0b1000110,
- "p_TX_MARGIN_LOW_1":0b1000100,
- "p_TX_MARGIN_LOW_2":0b1000010,
- "p_TX_MARGIN_LOW_3":0b1000000,
- "p_TX_MARGIN_LOW_4":0b1000000,
-
- # TX Gearbox Attributes
- "p_TXGEARBOX_EN":"FALSE",
-
- # TX Initialization and Reset Attributes
- "p_TXPCSRESET_TIME":1,
- "p_TXPMARESET_TIME":1,
-
- # TX Receiver Detection Attributes
- "p_TX_RXDETECT_CFG":0x1832,
- "p_TX_RXDETECT_REF":0b100,
-
- # CPLL Attributes
- "p_CPLL_CFG":0xBC07DC,
- "p_CPLL_FBDIV":4,
- "p_CPLL_FBDIV_45":5,
- "p_CPLL_INIT_CFG":0x00001e,
- "p_CPLL_LOCK_CFG":0x01e8,
- "p_CPLL_REFCLK_DIV":1,
- "p_RXOUT_DIV":rxout_div,
- "p_TXOUT_DIV":txout_div,
- "p_SATA_CPLL_CFG":"VCO_3000MHZ",
-
- # RX Initialization and Reset Attributes
- "p_RXDFELPMRESET_TIME":0b0001111,
-
- # RX Equalizer Attributes
- "p_RXLPM_HF_CFG":0b00000011110000,
- "p_RXLPM_LF_CFG":0b00000011110000,
- "p_RX_DFE_GAIN_CFG":0x020fea,
- "p_RX_DFE_H2_CFG":0b000000000000,
- "p_RX_DFE_H3_CFG":0b000001000000,
- "p_RX_DFE_H4_CFG":0b00011110000,
- "p_RX_DFE_H5_CFG":0b00011100000,
- "p_RX_DFE_KL_CFG":0b0000011111110,
- "p_RX_DFE_LPM_CFG":0x0954,
- "p_RX_DFE_LPM_HOLD_DURING_EIDLE":0,
- "p_RX_DFE_UT_CFG":0b10001111000000000,
- "p_RX_DFE_VP_CFG":0b00011111100000011,
-
- # Power-Down Attributes
- "p_RX_CLKMUX_PD":1,
- "p_TX_CLKMUX_PD":1,
-
- # FPGA RX Interface Attribute
- "p_RX_INT_DATAWIDTH":0,
-
- # FPGA TX Interface Attribute
- "p_TX_INT_DATAWIDTH":0,
-
- # TX Configurable Driver Attributes
- "p_TX_QPI_STATUS_EN":0,
-
- # RX Equalizer Attributes
- "p_RX_DFE_KL_CFG2":0b00110011000100000001100000001100,
- "p_RX_DFE_XYD_CFG":0b0000000000000,
-
- # TX Configurable Driver Attributes
- "p_TX_PREDRIVER_MODE":0,
- }
-
- self.specials += \
- Instance("GTXE2_CHANNEL",
- # CPLL Ports
- #o_CPLLFBCLKLOST=,
- o_CPLLLOCK=self.cplllock,
- i_CPLLLOCKDETCLK=0,
- i_CPLLLOCKEN=1,
- i_CPLLPD=0,
- #o_CPLLREFCLKLOST=0,
- i_CPLLREFCLKSEL=0b001,
- i_CPLLRESET=self.cpllreset,
- i_GTRSVD=0,
- i_PCSRSVDIN=0,
- i_PCSRSVDIN2=0,
- i_PMARSVDIN=0,
- i_PMARSVDIN2=0,
- i_TSTIN=ones(20),
- #o_TSTOUT=,
-
- # Channel
- i_CLKRSVD=0,
-
- # Channel - Clocking Ports
- i_GTGREFCLK=0,
- i_GTNORTHREFCLK0=0,
- i_GTNORTHREFCLK1=0,
- i_GTREFCLK0=self.gtrefclk0,
- i_GTREFCLK1=0,
- i_GTSOUTHREFCLK0=0,
- i_GTSOUTHREFCLK1=0,
-
- # Channel - DRP Ports
- i_DRPADDR=0,
- i_DRPCLK=0,
- i_DRPDI=0,
- #o_DRPDO=,
- i_DRPEN=0,
- #o_DRPRDY=,
- i_DRPWE=0,
-
- # Clocking Ports
- #o_GTREFCLKMONITOR=,
- i_QPLLCLK=self.qpllclk,
- i_QPLLREFCLK=self.qpllrefclk,
- i_RXSYSCLKSEL=0b00,
- i_TXSYSCLKSEL=0b00,
-
- # Digital Monitor Ports
- #o_DMONITOROUT=,
-
- # FPGA TX Interface Datapath Configuration
- i_TX8B10BEN=1,
-
- # Loopback Ports
- i_LOOPBACK=0,
-
- # PCI Express Ports
- #o_PHYSTATUS=,
- i_RXRATE=0,
- #o_RXVALID=,
-
- # Power-Down Ports
- i_RXPD=0b00,
- i_TXPD=0b00,
-
- # RX 8B/10B Decoder Ports
- i_SETERRSTATUS=0,
-
- # RX Initialization and Reset Ports
- i_EYESCANRESET=0,
- i_RXUSERRDY=rxuserrdy,
-
- # RX Margin Analysis Ports
- #o_EYESCANDATAERROR=,
- i_EYESCANMODE=0,
- i_EYESCANTRIGGER=0,
-
- # Receive Ports - CDR Ports
- i_RXCDRFREQRESET=0,
- i_RXCDRHOLD=0,
- o_RXCDRLOCK=rxcdrlock,
- i_RXCDROVRDEN=0,
- i_RXCDRRESET=0,
- i_RXCDRRESETRSV=0,
-
- # Receive Ports - Clock Correction Ports
- #o_RXCLKCORCNT=,
-
- # Receive Ports - FPGA RX Interface Datapath Configuration
- i_RX8B10BEN=1,
-
- # Receive Ports - FPGA RX Interface Ports
- i_RXUSRCLK=self.rxusrclk,
- i_RXUSRCLK2=self.rxusrclk2,
-
- # Receive Ports - FPGA RX interface Ports
- o_RXDATA=self.rxdata,
-
- # Receive Ports - Pattern Checker Ports
- #o_RXPRBSERR=,
- i_RXPRBSSEL=0,
-
- # Receive Ports - Pattern Checker ports
- i_RXPRBSCNTRESET=0,
-
- # Receive Ports - RX Equalizer Ports
- i_RXDFEXYDEN=0,
- i_RXDFEXYDHOLD=0,
- i_RXDFEXYDOVRDEN=0,
-
- # Receive Ports - RX 8B/10B Decoder Ports
- #o_RXDISPERR=,
- #o_RXNOTINTABLE=,
-
- # Receive Ports - RX AFE
- i_GTXRXP=pads.rxp,
- i_GTXRXN=pads.rxn,
-
- # Receive Ports - RX Buffer Bypass Ports
- i_RXBUFRESET=0,
- #o_RXBUFSTATUS=,
- i_RXDDIEN=0,
- i_RXDLYBYPASS=1,
- i_RXDLYEN=0,
- i_RXDLYOVRDEN=0,
- i_RXDLYSRESET=0,
- #o_RXDLYSRESETDONE=0,
- i_RXPHALIGN=0,
- #o_RXPHALIGNDONE=,
- i_RXPHALIGNEN=0,
- i_RXPHDLYPD=0,
- i_RXPHDLYRESET=0,
- #o_RXPHMONITOR=,
- i_RXPHOVRDEN=0,
- #o_RXPHSLIPMONITOR=,
- #o_RXSTATUS=,
-
- # Receive Ports - RX Byte and Word Alignment Ports
- o_RXBYTEISALIGNED=self.rxbyteisaligned,
- #o_RXBYTEREALIGN=,
- #o_RXCOMMADET=,
- i_RXCOMMADETEN=1,
- i_RXMCOMMAALIGNEN=1,
- i_RXPCOMMAALIGNEN=1,
-
- # Receive Ports - RX Channel Bonding Ports
- #o_RXCHANBONDSEQ=,
- i_RXCHBONDEN=0,
- i_RXCHBONDLEVEL=0,
- i_RXCHBONDMASTER=0,
- #o_RXCHBONDO=,
- i_RXCHBONDSLAVE=0,
-
- # Receive Ports - RX Channel Bonding Ports
- #o_RXCHANISALIGNED=,
- #o_RXCHANREALIGN=,
-
- # Receive Ports - RX Equalizer Ports
- i_RXDFEAGCHOLD=0,
- i_RXDFEAGCOVRDEN=0,
- i_RXDFECM1EN=0,
- i_RXDFELFHOLD=0,
- i_RXDFELFOVRDEN=1,
- i_RXDFELPMRESET=0,
- i_RXDFETAP2HOLD=0,
- i_RXDFETAP2OVRDEN=0,
- i_RXDFETAP3HOLD=0,
- i_RXDFETAP3OVRDEN=0,
- i_RXDFETAP4HOLD=0,
- i_RXDFETAP4OVRDEN=0,
- i_RXDFETAP5HOLD=0,
- i_RXDFETAP5OVRDEN=0,
- i_RXDFEUTHOLD=0,
- i_RXDFEUTOVRDEN=0,
- i_RXDFEVPHOLD=0,
- i_RXDFEVPOVRDEN=0,
- i_RXDFEVSEN=0,
- i_RXLPMLFKLOVRDEN=0,
- #o_RXMONITOROUT=,
- i_RXMONITORSEL=0b00,
- i_RXOSHOLD=0,
- i_RXOSOVRDEN=0,
-
- # Receive Ports - RX Equilizer Ports
- i_RXLPMHFHOLD=0,
- i_RXLPMHFOVRDEN=0,
- i_RXLPMLFHOLD=0,
-
- # Receive Ports - RX Fabric ClocK Output Control Ports
- #o_RXRATEDONE=,
-
- # Receive Ports - RX Fabric Output Control Ports
- o_RXOUTCLK=self.rxoutclk,
- #o_RXOUTCLKFABRIC=,
- #o_RXOUTCLKPCS=,
- i_RXOUTCLKSEL=0b010,
-
- # Receive Ports - RX Gearbox Ports
- #o_RXDATAVALID=,
- #o_RXHEADER=,
- #o_RXHEADERVALID=,
- #o_RXSTARTOFSEQ=,
-
- # Receive Ports - RX Gearbox Ports
- i_RXGEARBOXSLIP=0,
-
- # Receive Ports - RX Initialization and Reset Ports
- i_GTRXRESET=self.gtrxreset,
- i_RXOOBRESET=0,
- i_RXPCSRESET=0,
- i_RXPMARESET=self.pmarxreset,
-
- # Receive Ports - RX Margin Analysis ports
- i_RXLPMEN=0,
-
- # Receive Ports - RX OOB Signaling ports
- #o_RXCOMSASDET=,
- o_RXCOMWAKEDET=rxcomwakedet,
-
- # Receive Ports - RX OOB Signaling ports
- o_RXCOMINITDET=rxcominitdet,
-
- # Receive Ports - RX OOB signalling Ports
- o_RXELECIDLE=rxelecidle,
- i_RXELECIDLEMODE=0b00,
-
- # Receive Ports - RX Polarity Control Ports
- i_RXPOLARITY=0,
-
- # Receive Ports - RX gearbox ports
- i_RXSLIDE=0,
-
- # Receive Ports - RX8B/10B Decoder Ports
- #o_RXCHARISCOMMA=,
- o_RXCHARISK=self.rxcharisk,
-
- # Receive Ports - Rx Channel Bonding Ports
- i_RXCHBONDI=0,
-
- # Receive Ports -RX Initialization and Reset Ports
- o_RXRESETDONE=rxresetdone,
-
- # Rx AFE Ports
- i_RXQPIEN=0,
- #o_RXQPISENN=,
- #o_RXQPISENP=,
-
- # TX Buffer Bypass Ports
- i_TXPHDLYTSTCLK=0,
-
- # TX Configurable Driver Ports
- i_TXPOSTCURSOR=0,
- i_TXPOSTCURSORINV=0,
- i_TXPRECURSOR=0,
- i_TXPRECURSORINV=0,
- i_TXQPIBIASEN=0,
- i_TXQPISTRONGPDOWN=0,
- i_TXQPIWEAKPUP=0,
-
- # TX Initialization and Reset Ports
- i_CFGRESET=0,
- i_GTTXRESET=self.gttxreset,
- #o_PCSRSVDOUT=,
- i_TXUSERRDY=txuserrdy,
-
- # Transceiver Reset Mode Operation
- i_GTRESETSEL=0,
- i_RESETOVRD=0,
-
- # Transmit Ports - 8b10b Encoder Control Ports
- i_TXCHARDISPMODE=0,
- i_TXCHARDISPVAL=0,
-
- # Transmit Ports - FPGA TX Interface Ports
- i_TXUSRCLK=self.txusrclk,
- i_TXUSRCLK2=self.txusrclk2,
-
- # Transmit Ports - PCI Express Ports
- i_TXELECIDLE=txelecidle,
- i_TXMARGIN=0,
- i_TXRATE=txrate,
- i_TXSWING=0,
-
- # Transmit Ports - Pattern Generator Ports
- i_TXPRBSFORCEERR=0,
-
- # Transmit Ports - TX Buffer Bypass Ports
- i_TXDLYBYPASS=1,
- i_TXDLYEN=0,
- i_TXDLYHOLD=0,
- i_TXDLYOVRDEN=0,
- i_TXDLYSRESET=0,
- #o_TXDLYSRESETDONE=,
- i_TXDLYUPDOWN=0,
- i_TXPHALIGN=0,
- #o_TXPHALIGNDONE=txphaligndone,
- i_TXPHALIGNEN=0,
- i_TXPHDLYPD=0,
- i_TXPHDLYRESET=0,
- i_TXPHINIT=0,
- #o_TXPHINITDONE=,
- i_TXPHOVRDEN=0,
-
- # Transmit Ports - TX Buffer Ports
- #o_TXBUFSTATUS=,
-
- # Transmit Ports - TX Configurable Driver Ports
- i_TXBUFDIFFCTRL=0b100,
- i_TXDEEMPH=0,
- i_TXDIFFCTRL=0b1000,
- i_TXDIFFPD=0,
- i_TXINHIBIT=0,
- i_TXMAINCURSOR=0,
- i_TXPISOPD=0,
-
- # Transmit Ports - TX Data Path interface
- i_TXDATA=self.txdata,
-
- # Transmit Ports - TX Driver and OOB signaling
- o_GTXTXP=pads.txp,
- o_GTXTXN=pads.txn,
-
- # Transmit Ports - TX Fabric Clock Output Control Ports
- o_TXOUTCLK=self.txoutclk,
- #o_TXOUTCLKFABRIC=,
- #o_TXOUTCLKPCS=,
- i_TXOUTCLKSEL=0b11, #??
- #o_TXRATEDONE=,
- # Transmit Ports - TX Gearbox Ports
- i_TXCHARISK=self.txcharisk,
- #o_TXGEARBOXREADY=,
- i_TXHEADER=0,
- i_TXSEQUENCE=0,
- i_TXSTARTSEQ=0,
-
- # Transmit Ports - TX Initialization and Reset Ports
- i_TXPCSRESET=0,
- i_TXPMARESET=0,
- o_TXRESETDONE=txresetdone,
-
- # Transmit Ports - TX OOB signalling Ports
- o_TXCOMFINISH=txcomfinish,
- i_TXCOMINIT=txcominit,
- i_TXCOMSAS=0,
- i_TXCOMWAKE=txcomwake,
- i_TXPDELECIDLEMODE=0,
-
- # Transmit Ports - TX Polarity Control Ports
- i_TXPOLARITY=0,
-
- # Transmit Ports - TX Receiver Detection Ports
- i_TXDETECTRX=0,
-
- # Transmit Ports - TX8b/10b Encoder Ports
- i_TX8B10BBYPASS=0,
-
- # Transmit Ports - pattern Generator Ports
- i_TXPRBSSEL=0,
-
- # Tx Configurable Driver Ports
- #o_TXQPISENN=,
- #o_TXQPISENP=,
-
- **gtxe2_channel_parameters
- )
+++ /dev/null
-MSCDIR = ../../../
-PYTHON = python3
-
-CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
-
-CC=gcc
-CFLAGS =-Wall -O0
-
-phy_datapath_tb:
- $(CMD) phy_datapath_tb.py
-
-crc_tb:
- $(CC) $(CFLAGS) $(INC) -o crc crc.c
- $(CMD) crc_tb.py
-
-scrambler_tb:
- $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
- $(CMD) scrambler_tb.py
-
-cont_tb:
- $(CMD) cont_tb.py
-
-link_tb:
- $(CMD) link_tb.py
-
-command_tb:
- $(CMD) command_tb.py
-
-bist_tb:
- $(CMD) bist_tb.py
-
-clean:
- rm crc scrambler *.vcd
+++ /dev/null
-from lib.sata.common import *
-from lib.sata import SATACON
-from lib.sata.bist import SATABISTGenerator, SATABISTChecker
-
-from lib.sata.test.hdd import *
-from lib.sata.test.common import *
-
-class TB(Module):
- def __init__(self):
- self.hdd = HDD(
- link_debug=False, link_random_level=0,
- transport_debug=False, transport_loopback=False,
- hdd_debug=True)
- self.controller = SATACON(self.hdd.phy)
- self.generator = SATABISTGenerator(self.controller.crossbar.get_port())
- self.checker = SATABISTChecker(self.controller.crossbar.get_port())
-
- def gen_simulation(self, selfp):
- hdd = self.hdd
- hdd.malloc(0, 64)
- selfp.generator.sector = 0
- selfp.generator.count = 17
- selfp.checker.sector = 0
- selfp.checker.count = 17
- while True:
- selfp.generator.start = 1
- yield
- selfp.generator.start = 0
- yield
- while selfp.generator.done == 0:
- yield
- selfp.checker.start = 1
- yield
- selfp.checker.start = 0
- yield
- while selfp.checker.done == 0:
- yield
- print("errors {}".format(selfp.checker.errors))
- selfp.generator.sector += 1
- selfp.generator.count = max((selfp.generator.count + 1)%8, 1)
- selfp.checker.sector += 1
- selfp.checker.count = max((selfp.checker.count + 1)%8, 1)
-
-if __name__ == "__main__":
- run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link import SATALink
-from lib.sata.transport import SATATransport
-from lib.sata.command import SATACommand
-
-from lib.sata.test.hdd import *
-from lib.sata.test.common import *
-
-class CommandTXPacket(list):
- def __init__(self, write=0, read=0, sector=0, count=0, data=[]):
- self.ongoing = False
- self.done = False
- self.write = write
- self.read = read
- self.sector = sector
- self.count = count
- for d in data:
- self.append(d)
-
-class CommandStreamer(PacketStreamer):
- def __init__(self):
- PacketStreamer.__init__(self, command_tx_description(32), CommandTXPacket)
-
- def do_simulation(self, selfp):
- PacketStreamer.do_simulation(self, selfp)
- selfp.source.write = self.packet.write
- selfp.source.read = self.packet.read
- selfp.source.sector = self.packet.sector
- selfp.source.count = self.packet.count
-
-class CommandRXPacket(list):
- def __init__(self):
- self.ongoing = False
- self.done = False
- self.write = 0
- self.read = 0
- self.success = 0
- self.failed = 0
-
-class CommandLogger(PacketLogger):
- def __init__(self):
- PacketLogger.__init__(self, command_rx_description(32), CommandRXPacket)
-
- def do_simulation(self, selfp):
- selfp.sink.ack = 1
- if selfp.sink.stb == 1 and selfp.sink.sop == 1:
- self.packet = CommandRXPacket()
- self.packet.write = selfp.sink.write
- self.packet.read = selfp.sink.read
- self.packet.sucess = selfp.sink.success
- self.packet.failed = selfp.sink.failed
- self.packet.append(selfp.sink.data)
- elif selfp.sink.stb:
- self.packet.append(selfp.sink.data)
- if selfp.sink.stb == 1 and selfp.sink.eop == 1:
- self.packet.done = True
-
-class TB(Module):
- def __init__(self):
- self.hdd = HDD(
- link_debug=False, link_random_level=50,
- transport_debug=False, transport_loopback=False,
- hdd_debug=True)
- self.link = SATALink(self.hdd.phy)
- self.transport = SATATransport(self.link)
- self.command = SATACommand(self.transport)
-
- self.streamer = CommandStreamer()
- self.streamer_randomizer = Randomizer(command_tx_description(32), level=50)
-
- self.logger = CommandLogger()
- self.logger_randomizer = Randomizer(command_rx_description(32), level=50)
-
- self.pipeline = Pipeline(
- self.streamer,
- self.streamer_randomizer,
- self.command,
- self.logger_randomizer,
- self.logger
- )
-
- def gen_simulation(self, selfp):
- hdd = self.hdd
- hdd.malloc(0, 64)
- write_data = [i for i in range(sectors2dwords(2))]
- write_len = dwords2sectors(len(write_data))
- write_packet = CommandTXPacket(write=1, sector=2, count=write_len, data=write_data)
- yield from self.streamer.send(write_packet)
- yield from self.logger.receive()
- read_packet = CommandTXPacket(read=1, sector=2, count=write_len)
- yield from self.streamer.send(read_packet)
- yield from self.logger.receive()
- read_data = self.logger.packet
-
- # check results
- s, l, e = check(write_data, read_data)
- print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-if __name__ == "__main__":
- run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
+++ /dev/null
-import random, copy
-
-from migen.sim.generic import run_simulation
-
-from lib.sata.common import *
-
-def seed_to_data(seed, random=True):
- if random:
- return (seed * 0x31415979 + 1) & 0xffffffff
- else:
- return seed
-
-def check(p1, p2):
- p1 = copy.deepcopy(p1)
- p2 = copy.deepcopy(p2)
- if isinstance(p1, int):
- return 0, 1, int(p1 != p2)
- else:
- if len(p1) >= len(p2):
- ref, res = p1, p2
- else:
- ref, res = p2, p1
- shift = 0
- while((ref[0] != res[0]) and (len(res)>1)):
- res.pop(0)
- shift += 1
- length = min(len(ref), len(res))
- errors = 0
- for i in range(length):
- if ref.pop(0) != res.pop(0):
- errors += 1
- return shift, length, errors
-
-def randn(max_n):
- return random.randint(0, max_n-1)
-
-class PacketStreamer(Module):
- def __init__(self, description, packet_class):
- self.source = Source(description)
- ###
- self.packets = []
- self.packet = packet_class()
- self.packet.done = 1
-
- self.source_data = 0
-
- def send(self, packet, blocking=True):
- packet = copy.deepcopy(packet)
- self.packets.append(packet)
- if blocking:
- while packet.done == 0:
- yield
-
- def do_simulation(self, selfp):
- if len(self.packets) and self.packet.done:
- self.packet = self.packets.pop(0)
- if not self.packet.ongoing and not self.packet.done:
- selfp.source.stb = 1
- if self.source.description.packetized:
- selfp.source.sop = 1
- if len(self.packet) > 0:
- self.source_data = self.packet.pop(0)
- if hasattr(selfp.source, "data"):
- selfp.source.data = self.source_data
- else:
- selfp.source.d = self.source_data
- self.packet.ongoing = True
- elif selfp.source.stb == 1 and selfp.source.ack == 1:
- if self.source.description.packetized:
- selfp.source.sop = 0
- selfp.source.eop = (len(self.packet) == 1)
- if len(self.packet) > 0:
- selfp.source.stb = 1
- self.source_data = self.packet.pop(0)
- if hasattr(selfp.source, "data"):
- selfp.source.data = self.source_data
- else:
- selfp.source.d = self.source_data
- else:
- self.packet.done = 1
- selfp.source.stb = 0
-
-class PacketLogger(Module):
- def __init__(self, description, packet_class):
- self.sink = Sink(description)
- ###
- self.packet_class = packet_class
- self.packet = packet_class()
-
- def receive(self, length=None):
- self.packet.done = 0
- if length is None:
- while self.packet.done == 0:
- yield
- else:
- while length > len(self.packet):
- yield
-
- def do_simulation(self, selfp):
- selfp.sink.ack = 1
- if self.sink.description.packetized:
- if selfp.sink.stb == 1 and selfp.sink.sop == 1:
- self.packet = self.packet_class()
- if selfp.sink.stb:
- if hasattr(selfp.sink, "data"):
- self.packet.append(selfp.sink.data)
- else:
- self.packet.append(selfp.sink.d)
- if self.sink.description.packetized:
- if selfp.sink.stb == 1 and selfp.sink.eop == 1:
- self.packet.done = True
-
-class Randomizer(Module):
- def __init__(self, description, level=0):
- self.level = level
-
- self.sink = Sink(description)
- self.source = Source(description)
-
- self.run = Signal()
-
- self.comb += \
- If(self.run,
- Record.connect(self.sink, self.source)
- ).Else(
- self.source.stb.eq(0),
- self.sink.ack.eq(0),
- )
-
- def do_simulation(self, selfp):
- n = randn(100)
- if n < self.level:
- selfp.run = 0
- else:
- selfp.run = 1
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link.cont import SATACONTInserter, SATACONTRemover
-
-from lib.sata.test.common import *
-
-class ContPacket(list):
- def __init__(self, data=[]):
- self.ongoing = False
- self.done = False
- for d in data:
- self.append(d)
-
-class ContStreamer(PacketStreamer):
- def __init__(self):
- PacketStreamer.__init__(self, phy_description(32), ContPacket)
-
- def do_simulation(self, selfp):
- PacketStreamer.do_simulation(self, selfp)
- selfp.source.charisk = 0
- # Note: for simplicity we generate charisk by detecting
- # primitives in data
- for k, v in primitives.items():
- try:
- if self.source_data == v:
- selfp.source.charisk = 0b0001
- except:
- pass
-
-class ContLogger(PacketLogger):
- def __init__(self):
- PacketLogger.__init__(self, phy_description(32), ContPacket)
-
-class TB(Module):
- def __init__(self):
- self.streamer = ContStreamer()
- self.streamer_randomizer = Randomizer(phy_description(32), level=50)
- self.inserter = SATACONTInserter(phy_description(32))
- self.remover = SATACONTRemover(phy_description(32))
- self.logger_randomizer = Randomizer(phy_description(32), level=50)
- self.logger = ContLogger()
-
- self.pipeline = Pipeline(
- self.streamer,
- self.streamer_randomizer,
- self.inserter,
- self.remover,
- self.logger_randomizer,
- self.logger
- )
-
- def gen_simulation(self, selfp):
- test_packet = ContPacket([
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["ALIGN"],
- primitives["ALIGN"],
- primitives["SYNC"],
- primitives["SYNC"],
- #primitives["SYNC"],
- 0x00000000,
- 0x00000001,
- 0x00000002,
- 0x00000003,
- 0x00000004,
- 0x00000005,
- 0x00000006,
- 0x00000007,
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["ALIGN"],
- primitives["ALIGN"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"],
- primitives["SYNC"]]*4
- )
- streamer_packet = ContPacket(test_packet)
- yield from self.streamer.send(streamer_packet)
- yield from self.logger.receive(len(test_packet))
- #for d in self.logger.packet:
- # print("%08x" %d)
-
- # check results
- s, l, e = check(streamer_packet, self.logger.packet)
- print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-
-if __name__ == "__main__":
- run_simulation(TB(), ncycles=1024, vcd_name="my.vcd", keep_files=True)
+++ /dev/null
-// Adapted from SATA specification
-/****************************************************************************/
-/* */
-/* crc.c */
-/* */
-/* This sample code reads standard in for a sequence of 32 bit values */
-/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The */
-/* code calculates the Serial ATA CRC for the input data stream. The */
-/* generator polynomial used is: */
-/* 32 26 23 22 16 12 11 10 8 7 5 4 2 */
-/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1 */
-/* */
-/* This sample code uses a parallel implementation of the CRC calculation */
-/* circuit that is suitable for implementation in hardware. A block */
-/* diagram of the circuit being emulated is shown below. */
-/* */
-/* +---+ +---+ +---+ */
-/* Data_In --------->| | | | | R | */
-/* | + |--------->| * |--------->| e |----+ */
-/* +---->| | | | | g | | */
-/* | +---+ +---+ +---+ | */
-/* | | */
-/* | | */
-/* +--------------------------------------------+ */
-/* */
-/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA */
-/* specification. */
-/* */
-/****************************************************************************/
-
-
-
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char *argv[])
-{
- int i;
- unsigned int data_count;
- unsigned int crc;
- unsigned int data_in;
- unsigned char crc_bit[32];
- unsigned char new_bit[32];
-
- crc = 0x52325032;
- data_count = 0;
-
- while((scanf(" 0x%8x", &data_in) == 1) && (!scanf("exit"))) {
- data_count++;
- /* Add the data_in value to the current value of the CRC held in the */
- /* "register". The addition is performed modulo two (XOR). */
- crc ^= data_in;
- /* Expand the value of the CRC held in the register to 32 individual */
- /* bits for easy manipulation. */
- for (i = 0; i < 32; ++i) {
- crc_bit[i] = (crc >> i) & 0x01;
- }
- /* The following 32 assignments perform the function of the box */
- /* labeled "*" in the block diagram above. The new_bit array is a */
- /* temporary holding place for the new CRC value being calculated. */
- /* Note that there are lots of shared terms in the assignments below. */
- new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
- crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[5];
- new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
- crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4];
- new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
- crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3];
- new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
- crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2];
- new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
- crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1];
- new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
- crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
- crc_bit[0];
- new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
- crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2];
- new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
- crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1];
- new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
- crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
- new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
- crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0];
- new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
- crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5];
- new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
- crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4];
- new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
- crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3];
- new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
- crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2];
- new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
- crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1];
- new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
- crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0];
- new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
- crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^
- crc_bit[3];
- new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
- crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
- crc_bit[2];
- new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
- crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^
- crc_bit[2] ^ crc_bit[1];
- new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
- crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^
- crc_bit[2] ^ crc_bit[1] ^ crc_bit[0];
- new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
- crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^
- crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
- new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
- crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
- new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
- crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1];
- new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
- crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
- new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
- crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^
- crc_bit[2] ^ crc_bit[0];
- new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
- crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^
- crc_bit[1];
- new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
- crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^
- crc_bit[0];
- new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
- crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^
- crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
- new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
- crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^
- crc_bit[1];
- new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
- crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^
- crc_bit[1] ^ crc_bit[0];
- new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
- crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
- new_bit[0] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
- crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[0];
-
- /* The new CRC value has been calculated as individual bits in the */
- /* new_bit array. Re-assembled it into a 32 bit value and "clock" it */
- /* into the "register". */
- crc = 0;
- for (i = 31; i >= 0; --i) {
- crc = crc << 1;
- crc |= new_bit[i];
- }
- }
- printf("%08x\n", crc);
- return 0;
-}
+++ /dev/null
-import subprocess
-
-from lib.sata.common import *
-from lib.sata.link.crc import *
-
-from lib.sata.test.common import *
-
-class TB(Module):
- def __init__(self, length, random):
- self.crc = SATACRC()
- self.length = length
- self.random = random
-
- def get_c_crc(self, datas):
- stdin = ""
- for data in datas:
- stdin += "0x%08x " %data
- stdin += "exit"
- with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
- process.stdin.write(stdin.encode("ASCII"))
- out, err = process.communicate()
- return int(out.decode("ASCII"), 16)
-
- def gen_simulation(self, selfp):
- # init CRC
- selfp.crc.d = 0
- selfp.crc.ce = 1
- selfp.crc.reset = 1
- yield
- selfp.crc.reset = 0
-
- # feed CRC with datas
- datas = []
- for i in range(self.length):
- data = seed_to_data(i, self.random)
- datas.append(data)
- selfp.crc.d = data
- yield
-
- # log results
- yield
- sim_crc = selfp.crc.value
-
- # stop
- selfp.crc.ce = 0
- for i in range(32):
- yield
-
- # get C core reference
- c_crc = self.get_c_crc(datas)
-
- # check results
- s, l, e = check(c_crc, sim_crc)
- print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-if __name__ == "__main__":
- from migen.sim.generic import run_simulation
- length = 8192
- run_simulation(TB(length, True), ncycles=length+100, vcd_name="my.vcd")
+++ /dev/null
-import subprocess
-import math
-
-from lib.sata.common import *
-from lib.sata.test.common import *
-
-def print_with_prefix(s, prefix=""):
- if not isinstance(s, str):
- s = s.__repr__()
- s = s.split("\n")
- for l in s:
- print(prefix + l)
-
-# PHY Layer model
-class PHYDword:
- def __init__(self, dat=0):
- self.dat = dat
- self.start = 1
- self.done = 0
-
-class PHYSource(Module):
- def __init__(self):
- self.source = Source(phy_description(32))
- ###
- self.dword = PHYDword()
-
- def send(self, dword):
- self.dword = dword
-
- def do_simulation(self, selfp):
- selfp.source.stb = 1
- selfp.source.charisk = 0b0000
- for k, v in primitives.items():
- if v == self.dword.dat:
- selfp.source.charisk = 0b0001
- selfp.source.data = self.dword.dat
-
-class PHYSink(Module):
- def __init__(self):
- self.sink = Sink(phy_description(32))
- ###
- self.dword = PHYDword()
-
- def receive(self):
- self.dword.done = 0
- while self.dword.done == 0:
- yield
-
- def do_simulation(self, selfp):
- self.dword.done = 0
- selfp.sink.ack = 1
- if selfp.sink.stb == 1:
- self.dword.done = 1
- self.dword.dat = selfp.sink.data
-
-class PHYLayer(Module):
- def __init__(self):
-
- self.rx = PHYSink()
- self.tx = PHYSource()
-
- self.source = self.tx.source
- self.sink = self.rx.sink
-
- def send(self, dword):
- packet = PHYDword(dword)
- self.tx.send(packet)
-
- def receive(self):
- yield from self.rx.receive()
-
- def __repr__(self):
- receiving = "%08x " %self.rx.dword.dat
- receiving += decode_primitive(self.rx.dword.dat)
- receiving += " "*(16-len(receiving))
-
- sending = "%08x " %self.tx.dword.dat
- sending += decode_primitive(self.tx.dword.dat)
- sending += " "*(16-len(sending))
-
- return receiving + sending
-
-# Link Layer model
-def print_link(s):
- print_with_prefix(s, "[LNK]: ")
-
-def import_scrambler_datas():
- with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
- process.stdin.write("0x10000".encode("ASCII"))
- out, err = process.communicate()
- return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
-
-class LinkPacket(list):
- def __init__(self, init=[]):
- self.ongoing = False
- self.done = False
- self.scrambled_datas = import_scrambler_datas()
- for dword in init:
- self.append(dword)
-
-class LinkRXPacket(LinkPacket):
- def descramble(self):
- for i in range(len(self)):
- self[i] = self[i] ^ self.scrambled_datas[i]
-
- def check_crc(self):
- stdin = ""
- for v in self[:-1]:
- stdin += "0x%08x " %v
- stdin += "exit"
- with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
- process.stdin.write(stdin.encode("ASCII"))
- out, err = process.communicate()
- crc = int(out.decode("ASCII"), 16)
- r = (self[-1] == crc)
- self.pop()
- return r
-
- def decode(self):
- self.descramble()
- return self.check_crc()
-
-class LinkTXPacket(LinkPacket):
- def insert_crc(self):
- stdin = ""
- for v in self:
- stdin += "0x%08x " %v
- stdin += "exit"
- with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
- process.stdin.write(stdin.encode("ASCII"))
- out, err = process.communicate()
- crc = int(out.decode("ASCII"), 16)
- self.append(crc)
-
- def scramble(self):
- for i in range(len(self)):
- self[i] = self[i] ^ self.scrambled_datas[i]
-
- def encode(self):
- self.insert_crc()
- self.scramble()
-
-class LinkLayer(Module):
- def __init__(self, phy, debug=False, random_level=0):
- self.phy = phy
- self.debug = debug
- self.random_level = random_level
- self.tx_packets = []
- self.tx_packet = LinkTXPacket()
- self.rx_packet = LinkRXPacket()
-
- self.rx_cont = False
- self.rx_last = 0
- self.tx_cont = False
- self.tx_cont_nb = -1
- self.tx_lasts = [0, 0, 0]
-
- self.scrambled_datas = import_scrambler_datas()
-
- self.transport_callback = None
-
- self.send_state = ""
- self.send_states = ["RDY", "SOF", "DATA", "EOF", "WTRM"]
-
- def set_transport_callback(self, callback):
- self.transport_callback = callback
-
- def send(self, dword):
- if self.send_state == "RDY":
- self.phy.send(primitives["X_RDY"])
- if dword == primitives["R_RDY"]:
- self.send_state = "SOF"
- elif self.send_state == "SOF":
- self.phy.send(primitives["SOF"])
- self.send_state = "DATA"
- elif self.send_state == "DATA":
- if dword == primitives["HOLD"]:
- self.phy.send(primitives["HOLDA"])
- else:
- self.phy.send(self.tx_packet.pop(0))
- if len(self.tx_packet) == 0:
- self.send_state = "EOF"
- elif self.send_state == "EOF":
- self.phy.send(primitives["EOF"])
- self.send_state = "WTRM"
- elif self.send_state == "WTRM":
- self.phy.send(primitives["WTRM"])
- if dword == primitives["R_OK"]:
- self.tx_packet.done = True
- elif dword == primitives["R_ERR"]:
- self.tx_packet.done = True
- if self.tx_packet.done:
- self.phy.send(primitives["SYNC"])
-
- def insert_cont(self):
- self.tx_lasts.pop(0)
- self.tx_lasts.append(self.phy.tx.dword.dat)
- self.tx_cont = True
- for i in range(3):
- if not is_primitive(self.tx_lasts[i]):
- self.tx_cont = False
- if self.tx_lasts[i] != self.tx_lasts[0]:
- self.tx_cont = False
- if self.tx_cont:
- if self.tx_cont_nb == 0:
- self.phy.send(primitives["CONT"])
- else:
- self.phy.send(self.scrambled_datas[self.tx_cont_nb])
- self.tx_cont_nb += 1
- else:
- self.tx_cont_nb = 0
-
- def remove_cont(self, dword):
- if dword == primitives["HOLD"]:
- if self.rx_cont:
- self.tx_lasts = [0, 0, 0]
- if dword == primitives["CONT"]:
- self.rx_cont = True
- elif is_primitive(dword):
- self.rx_last = dword
- self.rx_cont = False
- if self.rx_cont:
- dword = self.rx_last
- return dword
-
- def callback(self, dword):
- if dword == primitives["X_RDY"]:
- self.phy.send(primitives["R_RDY"])
- elif dword == primitives["WTRM"]:
- self.phy.send(primitives["R_OK"])
- if self.rx_packet.ongoing:
- self.rx_packet.decode()
- if self.transport_callback is not None:
- self.transport_callback(self.rx_packet)
- self.rx_packet.ongoing = False
- elif dword == primitives["HOLD"]:
- self.phy.send(primitives["HOLDA"])
- elif dword == primitives["EOF"]:
- pass
- elif self.rx_packet.ongoing:
- if dword != primitives["HOLD"]:
- n = randn(100)
- if n < self.random_level:
- self.phy.send(primitives["HOLD"])
- else:
- self.phy.send(primitives["R_IP"])
- if not is_primitive(dword):
- self.rx_packet.append(dword)
- elif dword == primitives["SOF"]:
- self.rx_packet = LinkRXPacket()
- self.rx_packet.ongoing = True
-
- def gen_simulation(self, selfp):
- self.tx_packet.done = True
- self.phy.send(primitives["SYNC"])
- while True:
- yield from self.phy.receive()
- if self.debug:
- print_link(self.phy)
- self.phy.send(primitives["SYNC"])
- rx_dword = self.phy.rx.dword.dat
- rx_dword = self.remove_cont(rx_dword)
- if len(self.tx_packets) != 0:
- if self.tx_packet.done:
- self.tx_packet = self.tx_packets.pop(0)
- self.tx_packet.encode()
- self.send_state = "RDY"
- if not self.tx_packet.done:
- self.send(rx_dword)
- else:
- self.callback(rx_dword)
- self.insert_cont()
-
-# Transport Layer model
-def print_transport(s):
- print_with_prefix(s, "[TRN]: ")
-
-def get_field_data(field, packet):
- return (packet[field.dword] >> field.offset) & (2**field.width-1)
-
-class FIS:
- def __init__(self, packet, description, direction="H2D"):
- self.packet = packet
- self.description = description
- self.direction = direction
- self.decode()
-
- def decode(self):
- for k, v in self.description.items():
- setattr(self, k, get_field_data(v, self.packet))
-
- def encode(self):
- for k, v in self.description.items():
- self.packet[v.dword] |= (getattr(self, k) << v.offset)
-
- def __repr__(self):
- if self.direction == "H2D":
- r = ">>>>>>>>\n"
- else:
- r = "<<<<<<<<\n"
- for k in sorted(self.description.keys()):
- r += k + " : 0x%x" %getattr(self,k) + "\n"
- return r
-
-class FIS_REG_H2D(FIS):
- def __init__(self, packet=[0]*fis_reg_h2d_cmd_len):
- FIS.__init__(self, packet, fis_reg_h2d_layout)
- self.type = fis_types["REG_H2D"]
- self.direction = "H2D"
-
- def __repr__(self):
- r = "FIS_REG_H2D\n"
- r += FIS.__repr__(self)
- return r
-
-class FIS_REG_D2H(FIS):
- def __init__(self, packet=[0]*fis_reg_d2h_cmd_len):
- FIS.__init__(self, packet, fis_reg_d2h_layout)
- self.type = fis_types["REG_D2H"]
- self.direction = "D2H"
-
- def __repr__(self):
- r = "FIS_REG_D2H\n"
- r += FIS.__repr__(self)
- return r
-
-class FIS_DMA_ACTIVATE_D2H(FIS):
- def __init__(self, packet=[0]*fis_dma_activate_d2h_cmd_len):
- FIS.__init__(self, packet, fis_dma_activate_d2h_layout)
- self.type = fis_types["DMA_ACTIVATE_D2H"]
- self.direction = "D2H"
-
- def __repr__(self):
- r = "FIS_DMA_ACTIVATE_D2H\n"
- r += FIS.__repr__(self)
- return r
-
-class FIS_DATA(FIS):
- def __init__(self, packet=[0], direction="H2D"):
- FIS.__init__(self, packet, fis_data_layout, direction)
- self.type = fis_types["DATA"]
-
- def __repr__(self):
- r = "FIS_DATA\n"
- r += FIS.__repr__(self)
- for data in self.packet[1:]:
- r += "%08x\n" %data
- return r
-
-class FIS_UNKNOWN(FIS):
- def __init__(self, packet=[0], direction="H2D"):
- FIS.__init__(self, packet, {}, direction)
-
- def __repr__(self):
- r = "UNKNOWN\n"
- if self.direction == "H2D":
- r += ">>>>>>>>\n"
- else:
- r += "<<<<<<<<\n"
- for dword in self.packet:
- r += "%08x\n" %dword
- return r
-
-class TransportLayer(Module):
- def __init__(self, link, debug=False, loopback=False):
- self.link = link
- self.debug = debug
- self.loopback = loopback
- self.link.set_transport_callback(self.callback)
-
- def set_command_callback(self, callback):
- self.command_callback = callback
-
- def send(self, fis):
- fis.encode()
- packet = LinkTXPacket(fis.packet)
- self.link.tx_packets.append(packet)
- if self.debug and not self.loopback:
- print_transport(fis)
-
- def callback(self, packet):
- fis_type = packet[0] & 0xff
- if fis_type == fis_types["REG_H2D"]:
- fis = FIS_REG_H2D(packet)
- elif fis_type == fis_types["REG_D2H"]:
- fis = FIS_REG_D2H(packet)
- elif fis_type == fis_types["DMA_ACTIVATE_D2H"]:
- fis = FIS_DMA_ACTIVATE_D2H(packet)
- elif fis_type == fis_types["DATA"]:
- fis = FIS_DATA(packet, direction="H2D")
- else:
- fis = FIS_UNKNOWN(packet, direction="H2D")
- if self.debug:
- print_transport(fis)
- if self.loopback:
- self.send(fis)
- else:
- self.command_callback(fis)
-
-# Command Layer model
-class CommandLayer(Module):
- def __init__(self, transport):
- self.transport = transport
- self.transport.set_command_callback(self.callback)
-
- self.hdd = None
-
- def set_hdd(self, hdd):
- self.hdd = hdd
-
- def callback(self, fis):
- resp = None
- if isinstance(fis, FIS_REG_H2D):
- if fis.command == regs["WRITE_DMA_EXT"]:
- resp = self.hdd.write_dma_callback(fis)
- elif fis.command == regs["READ_DMA_EXT"]:
- resp = self.hdd.read_dma_callback(fis)
- elif isinstance(fis, FIS_DATA):
- resp = self.hdd.data_callback(fis)
-
- if resp is not None:
- for packet in resp:
- self.transport.send(packet)
-
-# HDD model
-def print_hdd(s):
- print_with_prefix(s, "[HDD]: ")
-
-class HDDMemRegion:
- def __init__(self, base, count, sector_size):
- self.base = base
- self.count = count
- self.data = [0]*(count*sector_size//4)
-
-class HDD(Module):
- def __init__(self,
- link_debug=False, link_random_level=0,
- transport_debug=False, transport_loopback=False,
- hdd_debug=False,
- ):
- ###
- self.phy = PHYLayer()
- self.link = LinkLayer(self.phy, link_debug, link_random_level)
- self.transport = TransportLayer(self.link, transport_debug, transport_loopback)
- self.command = CommandLayer(self.transport)
-
- self.command.set_hdd(self)
-
- self.debug = hdd_debug
- self.mem = None
- self.wr_sector = 0
- self.wr_end_sector = 0
- self.rd_sector = 0
- self.rx_end_sector = 0
-
- def malloc(self, sector, count):
- if self.debug:
- s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count)
- s += " ({} KB)".format(count*logical_sector_size//1024)
- print_hdd(s)
- self.mem = HDDMemRegion(sector, count, logical_sector_size)
-
- def write(self, sector, data):
- n = math.ceil(dwords2sectors(len(data)))
- if self.debug:
- if n == 1:
- s = "{}".format(sector)
- else:
- s = "{s} to {e}".format(s=sector, e=sector+n-1)
- print_hdd("Writing sector " + s)
- for i in range(len(data)):
- offset = sectors2dwords(sector)
- self.mem.data[offset+i] = data[i]
-
- def read(self, sector, count):
- if self.debug:
- if count == 1:
- s = "{}".format(sector)
- else:
- s = "{s} to {e}".format(s=sector, e=sector+count-1)
- print_hdd("Reading sector " + s)
- data = []
- for i in range(sectors2dwords(count)):
- data.append(self.mem.data[sectors2dwords(sector)+i])
- return data
-
- def write_dma_callback(self, fis):
- self.wr_sector = fis.lba_lsb + (fis.lba_msb << 32)
- self.wr_end_sector = self.wr_sector + fis.count
- return [FIS_DMA_ACTIVATE_D2H()]
-
- def read_dma_callback(self, fis):
- self.rd_sector = fis.lba_lsb + (fis.lba_msb << 32)
- self.rd_end_sector = self.rd_sector + fis.count
- packets = []
- while self.rd_sector != self.rd_end_sector:
- count = min(self.rd_end_sector-self.rd_sector, (fis_max_dwords*4)//logical_sector_size)
- packet = self.read(self.rd_sector, count)
- packet.insert(0, 0)
- packets.append(FIS_DATA(packet, direction="D2H"))
- self.rd_sector += count
- packets.append(FIS_REG_D2H())
- return packets
-
- def data_callback(self, fis):
- self.write(self.wr_sector, fis.packet[1:])
- self.wr_sector += dwords2sectors(len(fis.packet[1:]))
- if self.wr_sector == self.wr_end_sector:
- return [FIS_REG_D2H()]
- else:
- return [FIS_DMA_ACTIVATE_D2H()]
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.link import SATALink
-
-from lib.sata.test.common import *
-from lib.sata.test.hdd import *
-
-class LinkStreamer(PacketStreamer):
- def __init__(self):
- PacketStreamer.__init__(self, link_description(32), LinkTXPacket)
-
-class LinkLogger(PacketLogger):
- def __init__(self):
- PacketLogger.__init__(self, link_description(32), LinkRXPacket)
-
-class TB(Module):
- def __init__(self):
- self.hdd = HDD(
- link_debug=False, link_random_level=50,
- transport_debug=False, transport_loopback=True)
- self.link = InsertReset(SATALink(self.hdd.phy))
-
- self.streamer = LinkStreamer()
- self.streamer_randomizer = Randomizer(link_description(32), level=50)
-
- self.logger_randomizer = Randomizer(link_description(32), level=50)
- self.logger = LinkLogger()
-
- self.pipeline = Pipeline(
- self.streamer,
- self.streamer_randomizer,
- self.link,
- self.logger_randomizer,
- self.logger
- )
-
- def gen_simulation(self, selfp):
- for i in range(8):
- streamer_packet = LinkTXPacket([i for i in range(64)])
- yield from self.streamer.send(streamer_packet)
- yield from self.logger.receive()
-
- # check results
- s, l, e = check(streamer_packet, self.logger.packet)
- print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-
-if __name__ == "__main__":
- run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
+++ /dev/null
-from lib.sata.common import *
-from lib.sata.phy.datapath import SATAPHYDatapath
-
-from lib.sata.test.common import *
-
-class DataPacket(list):
- def __init__(self, data=[]):
- self.ongoing = False
- self.done = False
- for d in data:
- self.append(d)
-
-class DataStreamer(PacketStreamer):
- def __init__(self):
- PacketStreamer.__init__(self, phy_description(32), DataPacket)
-
- def do_simulation(self, selfp):
- PacketStreamer.do_simulation(self, selfp)
- selfp.source.charisk = 0
- # Note: for simplicity we generate charisk by detecting
- # primitives in data
- for k, v in primitives.items():
- try:
- if self.source_data == v:
- selfp.source.charisk = 0b0001
- except:
- pass
-
-class DataLogger(PacketLogger):
- def __init__(self):
- PacketLogger.__init__(self, phy_description(32), DataPacket)
-
-class TRX(Module):
- def __init__(self):
- self.sink = Sink(phy_description(32))
- self.source = Source(phy_description(32))
- self.comb += Record.connect(self.sink, self.source)
-
-class CTRL(Module):
- def __init__(self):
- self.sink = Sink(phy_description(32))
- self.source = Source(phy_description(32))
- self.ready = Signal(reset=1)
-
-class TB(Module):
- def __init__(self):
- # use sys_clk for each clock_domain
- self.cd_sata_rx = ClockDomain()
- self.cd_sata_tx = ClockDomain()
- self.comb += [
- self.cd_sata_rx.clk.eq(ClockSignal()),
- self.cd_sata_rx.rst.eq(ResetSignal()),
- self.cd_sata_tx.clk.eq(ClockSignal()),
- self.cd_sata_tx.rst.eq(ResetSignal()),
- ]
-
- self.streamer = DataStreamer()
- self.streamer_randomizer = Randomizer(phy_description(32), level=10)
- self.trx = TRX()
- self.ctrl = CTRL()
- self.datapath = SATAPHYDatapath(self.trx, self.ctrl)
- self.logger_randomizer = Randomizer(phy_description(32), level=10)
- self.logger = DataLogger()
-
- self.pipeline = Pipeline(
- self.streamer,
- self.streamer_randomizer,
- self.datapath,
- self.logger_randomizer,
- self.logger
- )
-
- def gen_simulation(self, selfp):
- streamer_packet = DataPacket([seed_to_data(i, False) for i in range(512)])
- yield from self.streamer.send(streamer_packet)
- yield from self.logger.receive(512)
- for d in self.logger.packet:
- r = "%08x " %d
- r +=decode_primitive(d)
- print(r)
-
- # check results
- #s, l, e = check(streamer_packet, self.logger.packet)
- #print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-
-if __name__ == "__main__":
- run_simulation(TB(), ncycles=4096, vcd_name="my.vcd", keep_files=True)
+++ /dev/null
-// Adapted from SATA specification
-/****************************************************************************/
-/* */
-/* scramble.c */
-/* */
-/* This sample code generates the entire sequence of 65535 Dwords produced */
-/* by the scrambler defined in the Serial ATA specification. The */
-/* specification calls for an LFSR to generate a string of bits that will */
-/* be packaged into 32 bit Dwords to be XORed with the data Dwords. The */
-/* generator polynomial specified is: */
-/* 16 15 13 4 */
-/* G(x) = x + x + x + x + 1 */
-/* */
-/* Parallelized versions of the scrambler are initialized to a value */
-/* derived from the initialization value of 0xFFFF defined in the */
-/* specification. This implementation is initialized to 0xF0F6. Other */
-/* parallel implementations will have different initial values. The */
-/* important point is that the first Dword output of any implementation */
-/* must equal 0xC2D2768D. */
-/* This code does not represent an elegant solution for a C implementation, */
-/* but it does demonstrate a method of generating the sequence that can be */
-/* easily implemented in hardware. A block diagram of the circuit emulated */
-/* by this code is shown below. */
-/* */
-/* +-----------------------------------+ */
-/* | | */
-/* | | */
-/* | +---+ +---+ | */
-/* | | R | | * | | */
-/* +---->| e |----------+---->| M |----+----> Output(31 downto 16) */
-/* | g | | | 1 | */
-/* +---+ | +---+ */
-/* | */
-/* | +---+ */
-/* | | * | */
-/* +---->| M |---------> Output(15 downto 0) */
-/* | 2 | */
-/* +---+ */
-/* */
-/* The register shown in the block diagram is a 16 bit register. The two */
-/* boxes, *M1 and *M2, each represent a multiply by a 16 by 16 binary */
-/* matrix. A 16 by 16 matrix times a 16 bit vector yields a 16 bit vector. */
-/* The two vectors are the two halves of the 32 bit scrambler value. The */
-/* upper half of the scrambler value is stored back into the context */
-/* register to be used to generate the next value in the scrambler */
-/* */
-/****************************************************************************/
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char *argv[])
-{
- int i, j;
- unsigned int length;
- unsigned short context;
- unsigned long scrambler;
- unsigned char now[16];
- unsigned char next[32];
- context = 0xF0F6;
-
- scanf("0x%8x", &length);
-
- for (i = 0; i < length; ++i) {
- for (j = 0; j < 16; ++j) {
- now[j] = (context >> j) & 0x01;
- }
- next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
- next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
- next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
- next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
- next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0];
- next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0];
- next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2];
- next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
- next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
- next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
- next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0];
- next[20] = now[15] ^ now[11] ^ now[5] ^ now[4];
- next[19] = now[14] ^ now[10] ^ now[4] ^ now[3];
- next[18] = now[13] ^ now[9] ^ now[3] ^ now[2];
- next[17] = now[12] ^ now[8] ^ now[2] ^ now[1];
- next[16] = now[11] ^ now[7] ^ now[1] ^ now[0];
-
-
- next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0];
- next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2];
- next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1];
- next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
- next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
- next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
- next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
- next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0];
- next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0];
- next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2];
- next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1];
- next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
- next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
- next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
- next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
- next[0] = now[15] ^ now[13] ^ now[4] ^ now[0];
-
- scrambler = 0;
- for (j = 31; j >= 0; --j) {
- scrambler = scrambler << 1;
- scrambler |= next[j];
- }
- context = scrambler >> 16;
- printf("%08x\n", (unsigned int) scrambler);
-
- }
-
- return 0;
-
-}
\ No newline at end of file
+++ /dev/null
-import subprocess
-
-from lib.sata.common import *
-from lib.sata.link.scrambler import *
-
-from lib.sata.test.common import *
-
-class TB(Module):
- def __init__(self, length):
- self.scrambler = InsertReset(Scrambler())
- self.length = length
-
- def get_c_values(self, length):
- stdin = "0x%08x" %length
- with subprocess.Popen("./scrambler", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
- process.stdin.write(stdin.encode("ASCII"))
- out, err = process.communicate()
- return [int(e, 16) for e in out.decode("ASCII").split("\n")[:-1]]
-
- def gen_simulation(self, selfp):
- # init CRC
- selfp.scrambler.ce = 1
- selfp.scrambler.reset = 1
- yield
- selfp.scrambler.reset = 0
-
- # log results
- yield
- sim_values = []
- for i in range(self.length):
- sim_values.append(selfp.scrambler.value)
- yield
-
- # stop
- selfp.scrambler.ce = 0
- for i in range(32):
- yield
-
- # get C code reference
- c_values = self.get_c_values(self.length)
-
- # check results
- s, l, e = check(c_values, sim_values)
- print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
-
-if __name__ == "__main__":
- from migen.sim.generic import run_simulation
- length = 8192
- run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd")
+++ /dev/null
-from lib.sata.common import *
-
-def _get_item(obj, name, width):
- if "_lsb" in name:
- item = getattr(obj, name.replace("_lsb", ""))[:width]
- elif "_msb" in name:
- item = getattr(obj, name.replace("_msb", ""))[width:2*width]
- else:
- item = getattr(obj, name)
- return item
-
-def _encode_cmd(obj, description, signal):
- r = []
- for k, v in sorted(description.items()):
- start = v.dword*32 + v.offset
- end = start + v.width
- item = _get_item(obj, k, v.width)
- r.append(signal[start:end].eq(item))
- return r
-
-class SATATransportTX(Module):
- def __init__(self, link):
- self.sink = sink = Sink(transport_tx_description(32))
-
- ###
-
- cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_data_cmd_len)
- encoded_cmd = Signal(cmd_ndwords*32)
-
- self.counter = counter = Counter(max=cmd_ndwords+1)
-
- cmd_len = Signal(counter.width)
- cmd_with_data = Signal()
-
- cmd_send = Signal()
- data_send = Signal()
- cmd_done = Signal()
-
- def test_type(name):
- return sink.type == fis_types[name]
-
- self.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- sink.ack.eq(0),
- counter.reset.eq(1),
- If(sink.stb & sink.sop,
- If(test_type("REG_H2D"),
- NextState("SEND_REG_H2D_CMD")
- ).Elif(test_type("DATA"),
- NextState("SEND_DATA_CMD")
- ).Else(
- sink.ack.eq(1)
- )
- ).Else(
- sink.ack.eq(1)
- )
- )
- fsm.act("SEND_REG_H2D_CMD",
- _encode_cmd(sink, fis_reg_h2d_layout, encoded_cmd),
- cmd_len.eq(fis_reg_h2d_cmd_len-1),
- cmd_send.eq(1),
- If(cmd_done,
- sink.ack.eq(1),
- NextState("IDLE")
- )
- )
- fsm.act("SEND_DATA_CMD",
- sink.ack.eq(0),
- _encode_cmd(sink, fis_data_layout, encoded_cmd),
- cmd_len.eq(fis_data_cmd_len-1),
- cmd_with_data.eq(1),
- cmd_send.eq(1),
- If(cmd_done,
- NextState("SEND_DATA")
- )
- )
- fsm.act("SEND_DATA",
- data_send.eq(1),
- sink.ack.eq(link.sink.ack),
- If(sink.stb & sink.eop & sink.ack,
- NextState("IDLE")
- )
- )
-
- cmd_cases = {}
- for i in range(cmd_ndwords):
- cmd_cases[i] = [link.sink.d.eq(encoded_cmd[32*i:32*(i+1)])]
-
- self.comb += \
- If(cmd_send,
- link.sink.stb.eq(sink.stb),
- link.sink.sop.eq(counter.value == 0),
- link.sink.eop.eq((counter.value == cmd_len) & ~cmd_with_data),
- Case(counter.value, cmd_cases),
- counter.ce.eq(sink.stb & link.sink.ack),
- cmd_done.eq((counter.value == cmd_len) & link.sink.stb & link.sink.ack)
- ).Elif(data_send,
- link.sink.stb.eq(sink.stb),
- link.sink.sop.eq(0),
- link.sink.eop.eq(sink.eop),
- link.sink.d.eq(sink.data),
- )
-
-def _decode_cmd(signal, description, obj):
- r = []
- for k, v in sorted(description.items()):
- start = v.dword*32+v.offset
- end = start+v.width
- item = _get_item(obj, k, v.width)
- r.append(item.eq(signal[start:end]))
- return r
-
-class SATATransportRX(Module):
- def __init__(self, link):
- self.source = source = Source(transport_rx_description(32))
-
- ###
-
- cmd_ndwords = max(fis_reg_d2h_cmd_len, fis_dma_activate_d2h_cmd_len, fis_data_cmd_len)
- encoded_cmd = Signal(cmd_ndwords*32)
-
- self.counter = counter = Counter(max=cmd_ndwords+1)
-
- cmd_len = Signal(counter.width)
-
- cmd_receive = Signal()
- data_receive = Signal()
- cmd_done = Signal()
- data_done = Signal()
-
- def test_type(name):
- return link.source.d[:8] == fis_types[name]
-
- self.fsm = fsm = FSM(reset_state="IDLE")
-
- data_sop = Signal()
-
- fsm.act("IDLE",
- link.source.ack.eq(0),
- counter.reset.eq(1),
- If(link.source.stb & link.source.sop,
- If(test_type("REG_D2H"),
- NextState("RECEIVE_REG_D2H_CMD")
- ).Elif(test_type("DMA_ACTIVATE_D2H"),
- NextState("RECEIVE_DMA_ACTIVATE_D2H_CMD")
- ).Elif(test_type("PIO_SETUP_D2H"),
- NextState("RECEIVE_PIO_SETUP_D2H_CMD")
- ).Elif(test_type("DATA"),
- NextState("RECEIVE_DATA_CMD"),
- ).Else(
- link.source.ack.eq(1)
- )
- ).Else(
- link.source.ack.eq(1)
- )
- )
- fsm.act("RECEIVE_REG_D2H_CMD",
- cmd_len.eq(fis_reg_d2h_cmd_len-1),
- cmd_receive.eq(1),
- link.source.ack.eq(1),
- If(cmd_done,
- NextState("PRESENT_REG_D2H_CMD")
- )
- )
- fsm.act("PRESENT_REG_D2H_CMD",
- source.stb.eq(1),
- source.sop.eq(1),
- source.eop.eq(1),
- _decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
- If(source.stb & source.ack,
- NextState("IDLE")
- )
- )
- fsm.act("RECEIVE_DMA_ACTIVATE_D2H_CMD",
- cmd_len.eq(fis_dma_activate_d2h_cmd_len-1),
- cmd_receive.eq(1),
- link.source.ack.eq(1),
- If(cmd_done,
- NextState("PRESENT_DMA_ACTIVATE_D2H_CMD")
- )
- )
- fsm.act("PRESENT_DMA_ACTIVATE_D2H_CMD",
- source.stb.eq(1),
- source.sop.eq(1),
- source.eop.eq(1),
- _decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
- If(source.stb & source.ack,
- NextState("IDLE")
- )
- )
- fsm.act("RECEIVE_PIO_SETUP_D2H_CMD",
- cmd_len.eq(fis_pio_setup_d2h_cmd_len-1),
- cmd_receive.eq(1),
- link.source.ack.eq(1),
- If(cmd_done,
- NextState("PRESENT_PIO_SETUP_D2H_CMD")
- )
- )
- fsm.act("PRESENT_PIO_SETUP_D2H_CMD",
- source.stb.eq(1),
- source.sop.eq(1),
- source.eop.eq(1),
- _decode_cmd(encoded_cmd, fis_pio_setup_d2h_layout, source),
- If(source.stb & source.ack,
- NextState("IDLE")
- )
- )
- fsm.act("RECEIVE_DATA_CMD",
- cmd_len.eq(fis_data_cmd_len-1),
- cmd_receive.eq(1),
- link.source.ack.eq(1),
- If(cmd_done,
- NextState("PRESENT_DATA")
- )
- )
- fsm.act("PRESENT_DATA",
- data_receive.eq(1),
- source.stb.eq(link.source.stb),
- _decode_cmd(encoded_cmd, fis_data_layout, source),
- source.sop.eq(data_sop),
- source.eop.eq(link.source.eop),
- source.error.eq(link.source.error),
- source.data.eq(link.source.d),
- link.source.ack.eq(source.ack),
- If(source.stb & source.eop & source.ack,
- NextState("IDLE")
- )
- )
-
- self.sync += \
- If(fsm.ongoing("RECEIVE_DATA_CMD"),
- data_sop.eq(1)
- ).Elif(fsm.ongoing("PRESENT_DATA"),
- If(source.stb & source.ack,
- data_sop.eq(0)
- )
- )
-
- cmd_cases = {}
- for i in range(cmd_ndwords):
- cmd_cases[i] = [encoded_cmd[32*i:32*(i+1)].eq(link.source.d)]
-
- self.comb += \
- If(cmd_receive & link.source.stb,
- counter.ce.eq(1)
- )
- self.sync += \
- If(cmd_receive,
- Case(counter.value, cmd_cases),
- )
- self.comb += cmd_done.eq((counter.value == cmd_len) & link.source.ack)
-
-class SATATransport(Module):
- def __init__(self, link):
- self.tx = SATATransportTX(link)
- self.rx = SATATransportRX(link)
- self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+from litesata.common import *
+from litesata.phy import *
+from litesata.core import *
+from litesata.frontend import *
+
+from migen.bank.description import *
+
+class LiteSATA(Module, AutoCSR):
+ def __init__(self, phy,
+ with_crossbar=False,
+ with_bist=False, with_bist_csr=False):
+ # phy
+ self.phy = phy
+
+ # core
+ self.core = LiteSATACore(self.phy)
+
+ # frontend
+ if with_crossbar:
+ self.crossbar = LiteSATACrossbar(self.core)
+ if with_bist:
+ self.bist = LiteSATABIST(self.crossbar, with_bist_csr)
+
--- /dev/null
+import math
+
+from migen.fhdl.std import *
+from migen.genlib.resetsync import *
+from migen.genlib.fsm import *
+from migen.genlib.record import *
+from migen.genlib.misc import chooser, optree
+from migen.genlib.cdc import *
+from migen.flow.actor import *
+from migen.flow.plumbing import Multiplexer, Demultiplexer
+from migen.flow.plumbing import Buffer
+from migen.actorlib.fifo import *
+from migen.actorlib.structuring import Pipeline, Converter
+
+# PHY / Link Layers
+primitives = {
+ "ALIGN" : 0x7B4A4ABC,
+ "CONT" : 0X9999AA7C,
+ "SYNC" : 0xB5B5957C,
+ "R_RDY" : 0x4A4A957C,
+ "R_OK" : 0x3535B57C,
+ "R_ERR" : 0x5656B57C,
+ "R_IP" : 0X5555B57C,
+ "X_RDY" : 0x5757B57C,
+ "CONT" : 0x9999AA7C,
+ "WTRM" : 0x5858B57C,
+ "SOF" : 0x3737B57C,
+ "EOF" : 0xD5D5B57C,
+ "HOLD" : 0xD5D5AA7C,
+ "HOLDA" : 0X9595AA7C
+}
+
+def is_primitive(dword):
+ for k, v in primitives.items():
+ if dword == v:
+ return True
+ return False
+
+def decode_primitive(dword):
+ for k, v in primitives.items():
+ if dword == v:
+ return k
+ return ""
+
+def phy_description(dw):
+ layout = [
+ ("data", dw),
+ ("charisk", dw//8),
+ ]
+ return EndpointDescription(layout, packetized=False)
+
+def link_description(dw):
+ layout = [
+ ("d", dw),
+ ("error", 1)
+ ]
+ return EndpointDescription(layout, packetized=True)
+
+# Transport Layer
+fis_max_dwords = 2048
+
+fis_types = {
+ "REG_H2D": 0x27,
+ "REG_D2H": 0x34,
+ "DMA_ACTIVATE_D2H": 0x39,
+ "PIO_SETUP_D2H": 0x5F,
+ "DATA": 0x46
+}
+
+class FISField():
+ def __init__(self, dword, offset, width):
+ self.dword = dword
+ self.offset = offset
+ self.width = width
+
+fis_reg_h2d_cmd_len = 5
+fis_reg_h2d_layout = {
+ "type": FISField(0, 0, 8),
+ "pm_port": FISField(0, 8, 4),
+ "c": FISField(0, 15, 1),
+ "command": FISField(0, 16, 8),
+ "features_lsb": FISField(0, 24, 8),
+
+ "lba_lsb": FISField(1, 0, 24),
+ "device": FISField(1, 24, 8),
+
+ "lba_msb": FISField(2, 0, 24),
+ "features_msb": FISField(2, 24, 8),
+
+ "count": FISField(3, 0, 16),
+ "icc": FISField(3, 16, 8),
+ "control": FISField(3, 24, 8)
+}
+
+fis_reg_d2h_cmd_len = 5
+fis_reg_d2h_layout = {
+ "type": FISField(0, 0, 8),
+ "pm_port": FISField(0, 8, 4),
+ "i": FISField(0, 14, 1),
+ "status": FISField(0, 16, 8),
+ "error": FISField(0, 24, 8),
+
+ "lba_lsb": FISField(1, 0, 24),
+ "device": FISField(1, 24, 8),
+
+ "lba_msb": FISField(2, 0, 24),
+
+ "count": FISField(3, 0, 16)
+}
+
+fis_dma_activate_d2h_cmd_len = 1
+fis_dma_activate_d2h_layout = {
+ "type": FISField(0, 0, 8),
+ "pm_port": FISField(0, 8, 4)
+}
+
+fis_pio_setup_d2h_cmd_len = 5
+fis_pio_setup_d2h_layout = {
+ "type": FISField(0, 0, 8),
+ "pm_port": FISField(0, 8, 4),
+ "d": FISField(0, 13, 1),
+ "i": FISField(0, 14, 1),
+ "status": FISField(0, 16, 8),
+ "error": FISField(0, 24, 8),
+
+ "lba_lsb": FISField(1, 0, 24),
+
+ "lba_msb": FISField(2, 0, 24),
+
+ "count": FISField(3, 0, 16),
+
+ "transfer_count": FISField(4, 0, 16),
+}
+
+fis_data_cmd_len = 1
+fis_data_layout = {
+ "type": FISField(0, 0, 8)
+}
+
+def transport_tx_description(dw):
+ layout = [
+ ("type", 8),
+ ("pm_port", 4),
+ ("c", 1),
+ ("command", 8),
+ ("features", 16),
+ ("lba", 48),
+ ("device", 8),
+ ("count", 16),
+ ("icc", 8),
+ ("control", 8),
+ ("data", dw)
+ ]
+ return EndpointDescription(layout, packetized=True)
+
+def transport_rx_description(dw):
+ layout = [
+ ("type", 8),
+ ("pm_port", 4),
+ ("r", 1),
+ ("d", 1),
+ ("i", 1),
+ ("status", 8),
+ ("error", 8),
+ ("lba", 48),
+ ("device", 8),
+ ("count", 16),
+ ("transfer_count", 16),
+ ("data", dw),
+ ("error", 1)
+ ]
+ return EndpointDescription(layout, packetized=True)
+
+# Command Layer
+regs = {
+ "WRITE_DMA_EXT" : 0x35,
+ "READ_DMA_EXT" : 0x25,
+ "IDENTIFY_DEVICE" : 0xEC
+}
+
+def command_tx_description(dw):
+ layout = [
+ ("write", 1),
+ ("read", 1),
+ ("identify", 1),
+ ("sector", 48),
+ ("count", 16),
+ ("data", dw)
+ ]
+ return EndpointDescription(layout, packetized=True)
+
+def command_rx_description(dw):
+ layout = [
+ ("write", 1),
+ ("read", 1),
+ ("identify", 1),
+ ("last", 1),
+ ("success", 1),
+ ("failed", 1),
+ ("data", dw)
+ ]
+ return EndpointDescription(layout, packetized=True)
+
+def command_rx_cmd_description(dw):
+ layout = [
+ ("write", 1),
+ ("read", 1),
+ ("identify", 1),
+ ("last", 1),
+ ("success", 1),
+ ("failed", 1)
+ ]
+ return EndpointDescription(layout, packetized=False)
+
+def command_rx_data_description(dw):
+ layout = [
+ ("data", dw)
+ ]
+ return EndpointDescription(layout, packetized=True)
+
+# HDD
+logical_sector_size = 512 # constant since all HDDs use this
+
+def dwords2sectors(n):
+ return math.ceil(n*4/logical_sector_size)
+
+def sectors2dwords(n):
+ return n*logical_sector_size//4
+
+# Generic modules
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class Counter(Module):
+ def __init__(self, signal=None, **kwargs):
+ if signal is None:
+ self.value = Signal(**kwargs)
+ else:
+ self.value = signal
+ self.width = flen(self.value)
+ self.sync += self.value.eq(self.value+1)
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class Timeout(Module):
+ def __init__(self, length):
+ self.reached = Signal()
+ ###
+ value = Signal(max=length)
+ self.sync += value.eq(value+1)
+ self.comb += [
+ self.reached.eq(value == length)
+ ]
+
+# XXX use ModuleDecorator
+class BufferizeEndpoints(Module):
+ def __init__(self, decorated, *args):
+ self.decorated = decorated
+
+ endpoints = get_endpoints(decorated)
+ sinks = {}
+ sources = {}
+ for name, endpoint in endpoints.items():
+ if name in args or len(args) == 0:
+ if isinstance(endpoint, Sink):
+ sinks.update({name : endpoint})
+ elif isinstance(endpoint, Source):
+ sources.update({name : endpoint})
+
+ # add buffer on sinks
+ for name, sink in sinks.items():
+ buf = Buffer(sink.description)
+ self.submodules += buf
+ setattr(self, name, buf.d)
+ self.comb += Record.connect(buf.q, sink)
+
+ # add buffer on sources
+ for name, source in sources.items():
+ buf = Buffer(source.description)
+ self.submodules += buf
+ self.comb += Record.connect(source, buf.d)
+ setattr(self, name, buf.q)
+
+ def __getattr__(self, name):
+ return getattr(self.decorated, name)
+
+ def __dir__(self):
+ return dir(self.decorated)
--- /dev/null
+from litesata.common import *
+from litesata.core.link import LiteSATALink
+from litesata.core.transport import LiteSATATransport
+from litesata.core.command import LiteSATACommand
+
+class LiteSATACore(Module):
+ def __init__(self, phy):
+ self.link = LiteSATALink(phy)
+ self.transport = LiteSATATransport(self.link)
+ self.command = LiteSATACommand(self.transport)
+ self.sink, self.source = self.command.sink, self.command.source
--- /dev/null
+from litesata.common import *
+
+tx_to_rx = [
+ ("write", 1),
+ ("read", 1),
+ ("identify", 1),
+ ("count", 16)
+]
+
+rx_to_tx = [
+ ("dma_activate", 1)
+]
+
+class LiteSATACommandTX(Module):
+ def __init__(self, transport):
+ 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),
+ transport.sink.data.eq(sink.data)
+ ]
+
+ self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ sink.ack.eq(0),
+ If(sink.stb & sink.sop,
+ If(sink.write,
+ NextState("SEND_WRITE_DMA_CMD")
+ ).Elif(sink.read,
+ NextState("SEND_READ_DMA_CMD")
+ ).Elif(sink.identify,
+ NextState("SEND_IDENTIFY_CMD")
+ ).Else(
+ sink.ack.eq(1)
+ )
+ ).Else(
+ sink.ack.eq(1)
+ )
+ )
+ fsm.act("SEND_WRITE_DMA_CMD",
+ transport.sink.stb.eq(sink.stb),
+ transport.sink.sop.eq(1),
+ transport.sink.eop.eq(1),
+ transport.sink.type.eq(fis_types["REG_H2D"]),
+ transport.sink.c.eq(1),
+ transport.sink.command.eq(regs["WRITE_DMA_EXT"]),
+ If(sink.stb & transport.sink.ack,
+ NextState("WAIT_DMA_ACTIVATE")
+ )
+ )
+ fsm.act("WAIT_DMA_ACTIVATE",
+ dwords_counter.reset.eq(1),
+ If(from_rx.dma_activate,
+ NextState("SEND_DATA")
+ )
+ )
+ fsm.act("SEND_DATA",
+ dwords_counter.ce.eq(sink.stb & sink.ack),
+
+ transport.sink.stb.eq(sink.stb),
+ transport.sink.sop.eq(dwords_counter.value == 0),
+ transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
+
+ transport.sink.type.eq(fis_types["DATA"]),
+ sink.ack.eq(transport.sink.ack),
+ If(sink.stb & sink.ack,
+ If(sink.eop,
+ NextState("IDLE")
+ ).Elif(dwords_counter.value == (fis_max_dwords-1),
+ NextState("WAIT_DMA_ACTIVATE")
+ )
+ )
+ )
+ fsm.act("SEND_READ_DMA_CMD",
+ transport.sink.stb.eq(sink.stb),
+ transport.sink.sop.eq(1),
+ transport.sink.eop.eq(1),
+ transport.sink.type.eq(fis_types["REG_H2D"]),
+ transport.sink.c.eq(1),
+ transport.sink.command.eq(regs["READ_DMA_EXT"]),
+ sink.ack.eq(transport.sink.ack),
+ If(sink.stb & sink.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("SEND_IDENTIFY_CMD",
+ transport.sink.stb.eq(sink.stb),
+ transport.sink.sop.eq(1),
+ transport.sink.eop.eq(1),
+ transport.sink.type.eq(fis_types["REG_H2D"]),
+ transport.sink.c.eq(1),
+ transport.sink.command.eq(regs["IDENTIFY_DEVICE"]),
+ sink.ack.eq(transport.sink.ack),
+ If(sink.stb & sink.ack,
+ NextState("IDLE")
+ )
+ )
+
+ self.comb += [
+ If(sink.stb,
+ to_rx.write.eq(sink.write),
+ to_rx.read.eq(sink.read),
+ to_rx.identify.eq(sink.identify),
+ to_rx.count.eq(sink.count)
+ )
+ ]
+
+class LiteSATACommandRX(Module):
+ def __init__(self, transport):
+ 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)
+
+ ###
+
+ cmd_buffer = Buffer(command_rx_cmd_description(32))
+ cmd_buffer.sink, cmd_buffer.source = cmd_buffer.d, cmd_buffer.q
+ data_buffer = InsertReset(SyncFIFO(command_rx_data_description(32), fis_max_dwords, buffered=True))
+ self.submodules += cmd_buffer, data_buffer
+
+ def test_type(name):
+ return transport.source.type == fis_types[name]
+
+ identify = Signal()
+ dma_activate = Signal()
+ 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)
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ self.dwords_counter.reset.eq(1),
+ transport.source.ack.eq(1),
+ If(from_tx.write,
+ NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
+ ).Elif(from_tx.read,
+ NextState("WAIT_READ_DATA_OR_REG_D2H"),
+ ).Elif(from_tx.identify,
+ NextState("WAIT_PIO_SETUP_D2H"),
+ )
+ )
+ self.sync += \
+ If(fsm.ongoing("IDLE"),
+ identify.eq(from_tx.identify)
+ )
+ fsm.act("WAIT_WRITE_ACTIVATE_OR_REG_D2H",
+ transport.source.ack.eq(1),
+ If(transport.source.stb,
+ If(test_type("DMA_ACTIVATE_D2H"),
+ dma_activate.eq(1),
+ ).Elif(test_type("REG_D2H"),
+ # XXX: use status and error fields of REG_D2H
+ NextState("PRESENT_WRITE_RESPONSE")
+ )
+ )
+ )
+ fsm.act("PRESENT_WRITE_RESPONSE",
+ cmd_buffer.sink.stb.eq(1),
+ cmd_buffer.sink.write.eq(1),
+ cmd_buffer.sink.last.eq(1),
+ cmd_buffer.sink.success.eq(~transport.source.error),
+ cmd_buffer.sink.failed.eq(transport.source.error),
+ If(cmd_buffer.sink.stb & cmd_buffer.sink.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"),
+ # XXX: use status and error fields of REG_D2H
+ NextState("PRESENT_READ_RESPONSE")
+ )
+ )
+ )
+ 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),
+ # XXX : Check error/ status
+ If(transport.source.stb & transport.source.eop,
+ NextState("WAIT_READ_DATA_OR_REG_D2H")
+ )
+ )
+
+ self.comb += [
+ data_buffer.sink.sop.eq(transport.source.sop),
+ data_buffer.sink.eop.eq(transport.source.eop),
+ data_buffer.sink.data.eq(transport.source.data)
+ ]
+ fsm.act("PRESENT_READ_DATA",
+ data_buffer.sink.stb.eq(transport.source.stb),
+ transport.source.ack.eq(data_buffer.sink.ack),
+ If(data_buffer.sink.stb & data_buffer.sink.ack,
+ self.dwords_counter.ce.eq(~read_done),
+ If(data_buffer.sink.eop,
+ If(read_done & ~identify,
+ NextState("WAIT_READ_DATA_OR_REG_D2H")
+ ).Else(
+ NextState("PRESENT_READ_RESPONSE")
+ )
+ )
+ )
+ )
+ read_error = Signal()
+ self.sync += \
+ If(fsm.before_entering("PRESENT_READ_DATA"),
+ read_error.eq(1)
+ ).Elif(transport.source.stb & transport.source.ack & transport.source.eop,
+ read_error.eq(transport.source.error)
+ )
+ fsm.act("PRESENT_READ_RESPONSE",
+ cmd_buffer.sink.stb.eq(1),
+ cmd_buffer.sink.read.eq(~identify),
+ cmd_buffer.sink.identify.eq(identify),
+ cmd_buffer.sink.last.eq(read_done | identify),
+ cmd_buffer.sink.success.eq(~read_error),
+ cmd_buffer.sink.failed.eq(read_error),
+ If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
+ If(cmd_buffer.sink.failed,
+ data_buffer.reset.eq(1)
+ ),
+ If(read_done | identify,
+ NextState("IDLE")
+ ).Else(
+ NextState("WAIT_READ_DATA_OR_REG_D2H")
+ )
+ )
+ )
+
+ self.out_fsm = out_fsm = FSM(reset_state="IDLE")
+ out_fsm.act("IDLE",
+ If(cmd_buffer.source.stb,
+ If((cmd_buffer.source.read | cmd_buffer.source.identify) & cmd_buffer.source.success,
+ NextState("PRESENT_RESPONSE_WITH_DATA"),
+ ).Else(
+ NextState("PRESENT_RESPONSE_WITHOUT_DATA"),
+ )
+ )
+ )
+
+ self.comb += [
+ source.write.eq(cmd_buffer.source.write),
+ source.read.eq(cmd_buffer.source.read),
+ source.identify.eq(cmd_buffer.source.identify),
+ source.last.eq(cmd_buffer.source.last),
+ source.success.eq(cmd_buffer.source.success),
+ source.failed.eq(cmd_buffer.source.failed),
+ source.data.eq(data_buffer.source.data)
+ ]
+
+ out_fsm.act("PRESENT_RESPONSE_WITH_DATA",
+ source.stb.eq(data_buffer.source.stb),
+ source.sop.eq(data_buffer.source.sop),
+ source.eop.eq(data_buffer.source.eop),
+
+ data_buffer.source.ack.eq(source.ack),
+
+ If(source.stb & source.eop & source.ack,
+ cmd_buffer.source.ack.eq(1),
+ NextState("IDLE")
+ )
+ )
+ out_fsm.act("PRESENT_RESPONSE_WITHOUT_DATA",
+ source.stb.eq(1),
+ source.sop.eq(1),
+ source.eop.eq(1),
+ If(source.stb & source.ack,
+ cmd_buffer.source.ack.eq(1),
+ NextState("IDLE")
+ )
+ )
+
+ self.comb += [
+ to_tx.dma_activate.eq(dma_activate),
+ ]
+
+class LiteSATACommand(Module):
+ def __init__(self, transport):
+ 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)
+ ]
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+from litesata.common import *
+from litesata.core.link.crc import LiteSATACRCInserter, LiteSATACRCChecker
+from litesata.core.link.scrambler import LiteSATAScrambler
+from litesata.core.link.cont import LiteSATACONTInserter, LiteSATACONTRemover
+
+from_rx = [
+ ("idle", 1),
+ ("insert", 32),
+ ("det", 32)
+]
+
+class LiteSATALinkTX(Module):
+ def __init__(self, phy):
+ self.sink = Sink(link_description(32))
+ self.from_rx = Sink(from_rx)
+
+ ###
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+
+ # insert CRC
+ crc = LiteSATACRCInserter(link_description(32))
+ self.submodules += crc
+
+ # scramble
+ scrambler = LiteSATAScrambler(link_description(32))
+ self.submodules += scrambler
+
+ # connect CRC / scrambler
+ self.comb += [
+ Record.connect(self.sink, crc.sink),
+ Record.connect(crc.source, scrambler.sink)
+ ]
+
+ # inserter CONT and scrambled data between
+ # CONT and next primitive
+ self.cont = cont = BufferizeEndpoints(LiteSATACONTInserter(phy_description(32)), "source")
+
+ # datas / primitives mux
+ insert = Signal(32)
+ self.comb += [
+ If(self.from_rx.insert,
+ cont.sink.stb.eq(1),
+ cont.sink.data.eq(self.from_rx.insert),
+ cont.sink.charisk.eq(0x0001),
+ ).
+ Elif(insert,
+ cont.sink.stb.eq(1),
+ cont.sink.data.eq(insert),
+ cont.sink.charisk.eq(0x0001),
+ ).Elif(fsm.ongoing("COPY"),
+ cont.sink.stb.eq(scrambler.source.stb),
+ cont.sink.data.eq(scrambler.source.d),
+ scrambler.source.ack.eq(cont.sink.ack),
+ cont.sink.charisk.eq(0)
+ )
+ ]
+ self.comb += Record.connect(cont.source, phy.sink)
+
+ # FSM
+ fsm.act("IDLE",
+ scrambler.reset.eq(1),
+ If(self.from_rx.idle,
+ insert.eq(primitives["SYNC"]),
+ If(scrambler.source.stb & scrambler.source.sop,
+ If(self.from_rx.det == primitives["SYNC"],
+ NextState("RDY")
+ )
+ )
+ )
+ )
+ fsm.act("RDY",
+ insert.eq(primitives["X_RDY"]),
+ If(~self.from_rx.idle,
+ NextState("IDLE")
+ ).Elif(self.from_rx.det == primitives["R_RDY"],
+ NextState("SOF")
+ )
+ )
+ fsm.act("SOF",
+ insert.eq(primitives["SOF"]),
+ If(phy.sink.ack,
+ NextState("COPY")
+ )
+ )
+ fsm.act("COPY",
+ If(self.from_rx.det == primitives["HOLD"],
+ insert.eq(primitives["HOLDA"]),
+ ).Elif(~scrambler.source.stb,
+ insert.eq(primitives["HOLD"]),
+ ).Elif(scrambler.source.stb & scrambler.source.eop & scrambler.source.ack,
+ NextState("EOF")
+ )
+ )
+ fsm.act("EOF",
+ insert.eq(primitives["EOF"]),
+ If(phy.sink.ack,
+ NextState("WTRM")
+ )
+ )
+ fsm.act("WTRM",
+ insert.eq(primitives["WTRM"]),
+ If(self.from_rx.det == primitives["R_OK"],
+ NextState("IDLE")
+ ).Elif(self.from_rx.det == primitives["R_ERR"],
+ NextState("IDLE")
+ )
+ )
+
+class LiteSATALinkRX(Module):
+ def __init__(self, phy):
+ self.source = Source(link_description(32))
+ self.to_tx = Source(from_rx)
+
+ ###
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+
+ # CONT remover
+ self.cont = cont = BufferizeEndpoints(LiteSATACONTRemover(phy_description(32)), "source")
+ self.comb += Record.connect(phy.source, cont.sink)
+
+ # datas / primitives detection
+ insert = Signal(32)
+ det = Signal(32)
+ self.comb += \
+ If(cont.source.stb & (cont.source.charisk == 0b0001),
+ det.eq(cont.source.data)
+ )
+
+ # descrambler
+ self.scrambler = scrambler = LiteSATAScrambler(link_description(32))
+
+ # check CRC
+ self.crc = crc = LiteSATACRCChecker(link_description(32))
+
+ sop = Signal()
+ eop = Signal()
+ self.sync += \
+ If(fsm.ongoing("IDLE"),
+ sop.eq(1),
+ ).Elif(fsm.ongoing("COPY"),
+ If(scrambler.sink.stb & scrambler.sink.ack,
+ sop.eq(0)
+ )
+ )
+ self.comb += eop.eq(det == primitives["EOF"])
+
+ crc_error = Signal()
+ self.sync += \
+ If(crc.source.stb & crc.source.eop & crc.source.ack,
+ crc_error.eq(crc.source.error)
+ )
+
+ # small fifo to manage HOLD
+ self.fifo = SyncFIFO(link_description(32), 32)
+
+ # graph
+ self.comb += [
+ cont.source.ack.eq(1),
+ Record.connect(scrambler.source, crc.sink),
+ Record.connect(crc.source, self.fifo.sink),
+ Record.connect(self.fifo.source, self.source)
+ ]
+ cont_source_data_d = Signal(32)
+ self.sync += \
+ If(cont.source.stb & (det == 0),
+ scrambler.sink.d.eq(cont.source.data)
+ )
+
+ # FSM
+ fsm.act("IDLE",
+ scrambler.reset.eq(1),
+ If(det == primitives["X_RDY"],
+ NextState("RDY")
+ )
+ )
+ fsm.act("RDY",
+ insert.eq(primitives["R_RDY"]),
+ If(det == primitives["SOF"],
+ NextState("WAIT_FIRST")
+ )
+ )
+ fsm.act("WAIT_FIRST",
+ insert.eq(primitives["R_IP"]),
+ If(cont.source.stb & (det == 0),
+ NextState("COPY")
+ )
+ )
+ self.comb += [
+ scrambler.sink.sop.eq(sop),
+ scrambler.sink.eop.eq(eop)
+ ]
+ fsm.act("COPY",
+ scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
+ insert.eq(primitives["R_IP"]),
+ If(det == primitives["HOLD"],
+ insert.eq(primitives["HOLDA"])
+ ).Elif(det == primitives["EOF"],
+ NextState("WTRM")
+ ).Elif(self.fifo.fifo.level > 8,
+ insert.eq(primitives["HOLD"])
+ )
+ )
+ fsm.act("EOF",
+ insert.eq(primitives["R_IP"]),
+ If(det == primitives["WTRM"],
+ NextState("WTRM")
+ )
+ )
+ fsm.act("WTRM",
+ insert.eq(primitives["R_IP"]),
+ If(~crc_error,
+ NextState("R_OK")
+ ).Else(
+ NextState("R_ERR")
+ )
+ )
+ fsm.act("R_OK",
+ insert.eq(primitives["R_OK"]),
+ If(det == primitives["SYNC"],
+ NextState("IDLE")
+ )
+ )
+ fsm.act("R_ERR",
+ insert.eq(primitives["R_ERR"]),
+ If(det == primitives["SYNC"],
+ NextState("IDLE")
+ )
+ )
+
+ # to TX
+ self.comb += [
+ self.to_tx.idle.eq(fsm.ongoing("IDLE")),
+ self.to_tx.insert.eq(insert),
+ self.to_tx.det.eq(det)
+ ]
+
+class LiteSATALink(Module):
+ def __init__(self, phy):
+ self.tx = LiteSATALinkTX(phy)
+ self.rx = LiteSATALinkRX(phy)
+ self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+from litesata.common import *
+from litesata.core.link.scrambler import Scrambler
+
+class LiteSATACONTInserter(Module):
+ def __init__(self, description):
+ self.sink = sink = Sink(description)
+ self.source = source = Source(description)
+
+ ###
+
+ self.counter = counter = Counter(max=4)
+
+ is_data = Signal()
+ was_data = Signal()
+ was_hold = Signal()
+ change = Signal()
+ self.comb += is_data.eq(sink.charisk == 0)
+
+ last_data = Signal(32)
+ last_primitive = Signal(32)
+ last_charisk = Signal(4)
+ self.sync += [
+ If(sink.stb & source.ack,
+ last_data.eq(sink.data),
+ last_charisk.eq(sink.charisk),
+ If(~is_data,
+ last_primitive.eq(sink.data),
+ ),
+ was_data.eq(is_data),
+ was_hold.eq(last_primitive == primitives["HOLD"])
+ )
+ ]
+ self.comb += change.eq(
+ (sink.data != last_data) |
+ (sink.charisk != last_charisk) |
+ is_data
+ )
+
+ # scrambler
+ self.scrambler = scrambler = InsertReset(Scrambler())
+
+ # Datapath
+ self.comb += [
+ Record.connect(sink, source),
+ If(sink.stb,
+ If(~change,
+ counter.ce.eq(sink.ack & (counter.value !=2)),
+ # insert CONT
+ If(counter.value == 1,
+ source.charisk.eq(0b0001),
+ source.data.eq(primitives["CONT"])
+ # insert scrambled data for EMI
+ ).Elif(counter.value == 2,
+ scrambler.ce.eq(sink.ack),
+ source.charisk.eq(0b0000),
+ source.data.eq(scrambler.value)
+ )
+ ).Else(
+ counter.reset.eq(source.ack),
+ If(counter.value == 2,
+ # Reinsert last primitive
+ If(is_data | (~is_data & was_hold),
+ source.stb.eq(1),
+ sink.ack.eq(0),
+ source.charisk.eq(0b0001),
+ source.data.eq(last_primitive)
+ )
+ )
+ )
+ )
+ ]
+
+class LiteSATACONTRemover(Module):
+ def __init__(self, description):
+ self.sink = sink = Sink(description)
+ self.source = source = Source(description)
+
+ ###
+
+ is_data = Signal()
+ is_cont = Signal()
+ in_cont = Signal()
+ cont_ongoing = Signal()
+
+ self.comb += [
+ is_data.eq(sink.charisk == 0),
+ is_cont.eq(~is_data & (sink.data == primitives["CONT"]))
+ ]
+ self.sync += \
+ If(sink.stb & sink.ack,
+ If(is_cont,
+ in_cont.eq(1)
+ ).Elif(~is_data,
+ in_cont.eq(0)
+ )
+ )
+ self.comb += cont_ongoing.eq(is_cont | (in_cont & is_data))
+
+ # Datapath
+ last_primitive = Signal(32)
+ self.sync += [
+ If(sink.stb & sink.ack,
+ If(~is_data & ~is_cont,
+ last_primitive.eq(sink.data)
+ )
+ )
+ ]
+ self.comb += [
+ Record.connect(sink, source),
+ If(cont_ongoing,
+ source.charisk.eq(0b0001),
+ source.data.eq(last_primitive)
+ )
+ ]
--- /dev/null
+from litesata.common import *
+
+from migen.actorlib.crc import CRCInserter, CRCChecker
+
+class CRCEngine(Module):
+ """Cyclic Redundancy Check Engine
+
+ Compute next CRC value from last CRC value and data input using
+ an optimized asynchronous LFSR.
+
+ Parameters
+ ----------
+ width : int
+ Width of the data bus and CRC.
+ polynom : int
+ Polynom of the CRC (ex: 0x04C11DB7 for IEEE 802.3 CRC)
+
+ Attributes
+ ----------
+ d : in
+ Data input.
+ last : in
+ last CRC value.
+ next :
+ next CRC value.
+ """
+ def __init__(self, width, polynom):
+ self.d = Signal(width)
+ self.last = Signal(width)
+ self.next = Signal(width)
+
+ ###
+
+ def _optimize_eq(l):
+ """
+ Replace even numbers of XORs in the equation
+ with an equivalent XOR
+ """
+ d = {}
+ for e in l:
+ if e in d:
+ d[e] += 1
+ else:
+ d[e] = 1
+ r = []
+ for key, value in d.items():
+ if value%2 != 0:
+ r.append(key)
+ return r
+
+ new = Signal(32)
+ self.comb += new.eq(self.last ^ self.d)
+
+ # compute and optimize CRC's LFSR
+ curval = [[("new", i)] for i in range(width)]
+ for i in range(width):
+ feedback = curval.pop()
+ for j in range(width-1):
+ if (polynom & (1<<(j+1))):
+ curval[j] += feedback
+ curval[j] = _optimize_eq(curval[j])
+ curval.insert(0, feedback)
+
+ # implement logic
+ for i in range(width):
+ xors = []
+ for t, n in curval[i]:
+ if t == "new":
+ xors += [new[n]]
+ self.comb += self.next[i].eq(optree("^", xors))
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class LiteSATACRC(Module):
+ """SATA CRC
+
+ Implement a SATA CRC generator/checker
+
+ Attributes
+ ----------
+ value : out
+ CRC value (used for generator).
+ error : out
+ CRC error (used for checker).
+ """
+ width = 32
+ polynom = 0x04C11DB7
+ init = 0x52325032
+ check = 0x00000000
+ def __init__(self, dw=32):
+ self.d = Signal(self.width)
+ self.value = Signal(self.width)
+ self.error = Signal()
+
+ ###
+
+ self.engine = CRCEngine(self.width, self.polynom)
+ reg_i = Signal(self.width, reset=self.init)
+ self.sync += reg_i.eq(self.engine.next)
+ self.comb += [
+ self.engine.d.eq(self.d),
+ self.engine.last.eq(reg_i),
+
+ self.value.eq(reg_i),
+ self.error.eq(self.engine.next != self.check)
+ ]
+
+class LiteSATACRCInserter(CRCInserter):
+ def __init__(self, description):
+ CRCInserter.__init__(self, LiteSATACRC, description)
+
+class LiteSATACRCChecker(CRCChecker):
+ def __init__(self, description):
+ CRCChecker.__init__(self, LiteSATACRC, description)
--- /dev/null
+from litesata.common import *
+
+@DecorateModule(InsertCE)
+class Scrambler(Module):
+ """SATA Scrambler
+
+ Implement a SATA Scrambler
+
+ Attributes
+ ----------
+ value : out
+ Scrambled value.
+ """
+ def __init__(self):
+ self.value = Signal(32)
+
+ ###
+
+ context = Signal(16, reset=0xf0f6)
+ next_value = Signal(32)
+ self.sync += context.eq(next_value[16:32])
+
+ # XXX: from SATA specification, replace it with
+ # a generic implementation using polynoms.
+ lfsr_coefs = (
+ (15, 13, 4, 0), #0
+ (15, 14, 13, 5, 4, 1, 0),
+ (14, 13, 6, 5, 4, 2,1, 0),
+ (15, 14, 7, 6, 5, 3,2, 1),
+ (13, 8, 7, 6, 3, 2, 0),
+ (14, 9, 8, 7, 4, 3, 1),
+ (15, 10, 9, 8, 5, 4, 2),
+ (15, 13, 11, 10, 9, 6, 5, 4, 3, 0),
+ (15, 14, 13, 12, 11, 10,7, 6, 5, 1, 0),
+ (14, 12, 11, 8, 7, 6, 4, 2, 1, 0),
+ (15, 13, 12, 9, 8, 7, 5, 3, 2, 1),
+ (15, 14, 10, 9, 8, 6, 3, 2, 0),
+ (13, 11, 10, 9, 7, 3, 1, 0),
+ (14, 12, 11, 10, 8, 4, 2, 1),
+ (15, 13, 12, 11, 9, 5, 3, 2),
+ (15, 14, 12, 10, 6, 3, 0),
+
+ (11, 7, 1, 0), #16
+ (12, 8, 2, 1),
+ (13, 9, 3, 2),
+ (14, 10, 4, 3),
+ (15, 11, 5, 4),
+ (15, 13, 12, 6, 5, 4, 0),
+ (15, 14, 7, 6, 5, 4, 1, 0),
+ (13, 8, 7, 6, 5, 4, 2, 1, 0),
+ (14, 9, 8,7, 6, 5, 3, 2, 1),
+ (15, 10, 9, 8, 7, 6, 4, 3, 2),
+ (15, 13, 11, 10, 9, 8, 7, 5, 3, 0),
+ (15, 14, 13, 12, 11, 10, 9, 8, 6, 1, 0),
+ (14, 12, 11, 10, 9, 7, 4, 2, 1, 0),
+ (15, 13, 12, 11, 10, 8, 5, 3, 2, 1),
+ (15, 14, 12, 11, 9, 6, 3, 2, 0),
+ (12, 10, 7, 3, 1, 0),
+ )
+
+ for n, coefs in enumerate(lfsr_coefs):
+ eq = [context[i] for i in coefs]
+ self.comb += next_value[n].eq(optree("^", eq))
+
+ self.comb += self.value.eq(next_value)
+
+@DecorateModule(InsertReset)
+class LiteSATAScrambler(Module):
+ def __init__(self, description):
+ self.sink = sink = Sink(description)
+ self.source = source = Source(description)
+
+ ###
+
+ self.scrambler = Scrambler()
+ self.comb += [
+ self.scrambler.ce.eq(sink.stb & sink.ack),
+ Record.connect(sink, source),
+ source.d.eq(sink.d ^ self.scrambler.value)
+ ]
--- /dev/null
+from litesata.common import *
+
+def _get_item(obj, name, width):
+ if "_lsb" in name:
+ item = getattr(obj, name.replace("_lsb", ""))[:width]
+ elif "_msb" in name:
+ item = getattr(obj, name.replace("_msb", ""))[width:2*width]
+ else:
+ item = getattr(obj, name)
+ return item
+
+def _encode_cmd(obj, description, signal):
+ r = []
+ for k, v in sorted(description.items()):
+ start = v.dword*32 + v.offset
+ end = start + v.width
+ item = _get_item(obj, k, v.width)
+ r.append(signal[start:end].eq(item))
+ return r
+
+class LiteSATATransportTX(Module):
+ def __init__(self, link):
+ self.sink = sink = Sink(transport_tx_description(32))
+
+ ###
+
+ cmd_ndwords = max(fis_reg_h2d_cmd_len, fis_data_cmd_len)
+ encoded_cmd = Signal(cmd_ndwords*32)
+
+ self.counter = counter = Counter(max=cmd_ndwords+1)
+
+ cmd_len = Signal(counter.width)
+ cmd_with_data = Signal()
+
+ cmd_send = Signal()
+ data_send = Signal()
+ cmd_done = Signal()
+
+ def test_type(name):
+ return sink.type == fis_types[name]
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ sink.ack.eq(0),
+ counter.reset.eq(1),
+ If(sink.stb & sink.sop,
+ If(test_type("REG_H2D"),
+ NextState("SEND_REG_H2D_CMD")
+ ).Elif(test_type("DATA"),
+ NextState("SEND_DATA_CMD")
+ ).Else(
+ sink.ack.eq(1)
+ )
+ ).Else(
+ sink.ack.eq(1)
+ )
+ )
+ fsm.act("SEND_REG_H2D_CMD",
+ _encode_cmd(sink, fis_reg_h2d_layout, encoded_cmd),
+ cmd_len.eq(fis_reg_h2d_cmd_len-1),
+ cmd_send.eq(1),
+ If(cmd_done,
+ sink.ack.eq(1),
+ NextState("IDLE")
+ )
+ )
+ fsm.act("SEND_DATA_CMD",
+ sink.ack.eq(0),
+ _encode_cmd(sink, fis_data_layout, encoded_cmd),
+ cmd_len.eq(fis_data_cmd_len-1),
+ cmd_with_data.eq(1),
+ cmd_send.eq(1),
+ If(cmd_done,
+ NextState("SEND_DATA")
+ )
+ )
+ fsm.act("SEND_DATA",
+ data_send.eq(1),
+ sink.ack.eq(link.sink.ack),
+ If(sink.stb & sink.eop & sink.ack,
+ NextState("IDLE")
+ )
+ )
+
+ cmd_cases = {}
+ for i in range(cmd_ndwords):
+ cmd_cases[i] = [link.sink.d.eq(encoded_cmd[32*i:32*(i+1)])]
+
+ self.comb += \
+ If(cmd_send,
+ link.sink.stb.eq(sink.stb),
+ link.sink.sop.eq(counter.value == 0),
+ link.sink.eop.eq((counter.value == cmd_len) & ~cmd_with_data),
+ Case(counter.value, cmd_cases),
+ counter.ce.eq(sink.stb & link.sink.ack),
+ cmd_done.eq((counter.value == cmd_len) & link.sink.stb & link.sink.ack)
+ ).Elif(data_send,
+ link.sink.stb.eq(sink.stb),
+ link.sink.sop.eq(0),
+ link.sink.eop.eq(sink.eop),
+ link.sink.d.eq(sink.data),
+ )
+
+def _decode_cmd(signal, description, obj):
+ r = []
+ for k, v in sorted(description.items()):
+ start = v.dword*32+v.offset
+ end = start+v.width
+ item = _get_item(obj, k, v.width)
+ r.append(item.eq(signal[start:end]))
+ return r
+
+class LiteSATATransportRX(Module):
+ def __init__(self, link):
+ self.source = source = Source(transport_rx_description(32))
+
+ ###
+
+ cmd_ndwords = max(fis_reg_d2h_cmd_len, fis_dma_activate_d2h_cmd_len,
+ fis_pio_setup_d2h_cmd_len, fis_data_cmd_len)
+ encoded_cmd = Signal(cmd_ndwords*32)
+
+ self.counter = counter = Counter(max=cmd_ndwords+1)
+
+ cmd_len = Signal(counter.width)
+
+ cmd_receive = Signal()
+ data_receive = Signal()
+ cmd_done = Signal()
+ data_done = Signal()
+
+ def test_type(name):
+ return link.source.d[:8] == fis_types[name]
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+
+ data_sop = Signal()
+
+ fsm.act("IDLE",
+ link.source.ack.eq(0),
+ counter.reset.eq(1),
+ If(link.source.stb & link.source.sop,
+ If(test_type("REG_D2H"),
+ NextState("RECEIVE_REG_D2H_CMD")
+ ).Elif(test_type("DMA_ACTIVATE_D2H"),
+ NextState("RECEIVE_DMA_ACTIVATE_D2H_CMD")
+ ).Elif(test_type("PIO_SETUP_D2H"),
+ NextState("RECEIVE_PIO_SETUP_D2H_CMD")
+ ).Elif(test_type("DATA"),
+ NextState("RECEIVE_DATA_CMD"),
+ ).Else(
+ link.source.ack.eq(1)
+ )
+ ).Else(
+ link.source.ack.eq(1)
+ )
+ )
+ fsm.act("RECEIVE_REG_D2H_CMD",
+ cmd_len.eq(fis_reg_d2h_cmd_len-1),
+ cmd_receive.eq(1),
+ link.source.ack.eq(1),
+ If(cmd_done,
+ NextState("PRESENT_REG_D2H_CMD")
+ )
+ )
+ fsm.act("PRESENT_REG_D2H_CMD",
+ source.stb.eq(1),
+ source.sop.eq(1),
+ source.eop.eq(1),
+ _decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
+ If(source.stb & source.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("RECEIVE_DMA_ACTIVATE_D2H_CMD",
+ cmd_len.eq(fis_dma_activate_d2h_cmd_len-1),
+ cmd_receive.eq(1),
+ link.source.ack.eq(1),
+ If(cmd_done,
+ NextState("PRESENT_DMA_ACTIVATE_D2H_CMD")
+ )
+ )
+ fsm.act("PRESENT_DMA_ACTIVATE_D2H_CMD",
+ source.stb.eq(1),
+ source.sop.eq(1),
+ source.eop.eq(1),
+ _decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
+ If(source.stb & source.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("RECEIVE_PIO_SETUP_D2H_CMD",
+ cmd_len.eq(fis_pio_setup_d2h_cmd_len-1),
+ cmd_receive.eq(1),
+ link.source.ack.eq(1),
+ If(cmd_done,
+ NextState("PRESENT_PIO_SETUP_D2H_CMD")
+ )
+ )
+ fsm.act("PRESENT_PIO_SETUP_D2H_CMD",
+ source.stb.eq(1),
+ source.sop.eq(1),
+ source.eop.eq(1),
+ _decode_cmd(encoded_cmd, fis_pio_setup_d2h_layout, source),
+ If(source.stb & source.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("RECEIVE_DATA_CMD",
+ cmd_len.eq(fis_data_cmd_len-1),
+ cmd_receive.eq(1),
+ link.source.ack.eq(1),
+ If(cmd_done,
+ NextState("PRESENT_DATA")
+ )
+ )
+ fsm.act("PRESENT_DATA",
+ data_receive.eq(1),
+ source.stb.eq(link.source.stb),
+ _decode_cmd(encoded_cmd, fis_data_layout, source),
+ source.sop.eq(data_sop),
+ source.eop.eq(link.source.eop),
+ source.error.eq(link.source.error),
+ source.data.eq(link.source.d),
+ link.source.ack.eq(source.ack),
+ If(source.stb & source.eop & source.ack,
+ NextState("IDLE")
+ )
+ )
+
+ self.sync += \
+ If(fsm.ongoing("RECEIVE_DATA_CMD"),
+ data_sop.eq(1)
+ ).Elif(fsm.ongoing("PRESENT_DATA"),
+ If(source.stb & source.ack,
+ data_sop.eq(0)
+ )
+ )
+
+ cmd_cases = {}
+ for i in range(cmd_ndwords):
+ cmd_cases[i] = [encoded_cmd[32*i:32*(i+1)].eq(link.source.d)]
+
+ self.comb += \
+ If(cmd_receive & link.source.stb,
+ counter.ce.eq(1)
+ )
+ self.sync += \
+ If(cmd_receive,
+ Case(counter.value, cmd_cases),
+ )
+ self.comb += cmd_done.eq((counter.value == cmd_len) & link.source.ack)
+
+class LiteSATATransport(Module):
+ def __init__(self, link):
+ self.tx = LiteSATATransportTX(link)
+ self.rx = LiteSATATransportRX(link)
+ self.sink, self.source = self.tx.sink, self.rx.source
--- /dev/null
+from litesata.common import *
+from litesata.frontend.crossbar import LiteSATACrossbar
+from litesata.frontend.arbiter import LiteSATAArbiter
+from litesata.frontend.bist import LiteSATABIST
--- /dev/null
+from litesata.common import *
+from litesata.frontend.common import *
+
+from migen.genlib.roundrobin import *
+
+class LiteSATAArbiter(Module):
+ def __init__(self, slaves, master):
+ if len(slaves) == 1:
+ self.comb += slaves[0].connect(master)
+ else:
+ self.rr = RoundRobin(len(slaves))
+ self.grant = self.rr.grant
+ cases = {}
+ for i, slave in enumerate(slaves):
+ sink, source = slave.sink, slave.source
+ start = Signal()
+ done = Signal()
+ ongoing = Signal()
+ self.comb += [
+ start.eq(sink.stb & sink.sop),
+ done.eq(source.stb & source.last & source.eop & source.ack)
+ ]
+ self.sync += \
+ If(start,
+ ongoing.eq(1)
+ ).Elif(done,
+ ongoing.eq(0)
+ )
+ self.comb += self.rr.request[i].eq((start | ongoing) & ~done)
+ cases[i] = [slaves[i].connect(master)]
+ self.comb += Case(self.grant, cases)
--- /dev/null
+from litesata.common import *
+from litesata.core.link.scrambler import Scrambler
+
+from migen.fhdl.decorators import ModuleDecorator
+from migen.bank.description import *
+
+class LiteSATABISTGenerator(Module):
+ def __init__(self, sata_master_port):
+ self.start = Signal()
+ self.sector = Signal(48)
+ self.count = Signal(16)
+ self.random = Signal()
+
+ self.done = Signal()
+ self.errors = Signal(32) # Note: Not used for writes
+
+ ###
+
+ source, sink = sata_master_port.source, sata_master_port.sink
+
+ self.counter = counter = Counter(bits_sign=32)
+
+ self.scrambler = scrambler = InsertReset(Scrambler())
+ self.comb += [
+ scrambler.reset.eq(counter.reset),
+ scrambler.ce.eq(counter.ce)
+ ]
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ self.done.eq(1),
+ counter.reset.eq(1),
+ If(self.start,
+ NextState("SEND_CMD_AND_DATA")
+ )
+ )
+ self.comb += [
+ source.sop.eq(counter.value == 0),
+ source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
+ source.write.eq(1),
+ source.sector.eq(self.sector),
+ source.count.eq(self.count),
+ If(self.random,
+ source.data.eq(scrambler.value)
+ ).Else(
+ source.data.eq(counter.value)
+ )
+ ]
+ fsm.act("SEND_CMD_AND_DATA",
+ source.stb.eq(1),
+ If(source.stb & source.ack,
+ counter.ce.eq(1),
+ If(source.eop,
+ NextState("WAIT_ACK")
+ )
+ )
+ )
+ fsm.act("WAIT_ACK",
+ sink.ack.eq(1),
+ If(sink.stb,
+ NextState("IDLE")
+ )
+ )
+
+class LiteSATABISTChecker(Module):
+ def __init__(self, sata_master_port):
+ self.start = Signal()
+ self.sector = Signal(48)
+ self.count = Signal(16)
+ self.random = Signal()
+
+ self.done = Signal()
+ self.errors = Signal(32)
+
+ ###
+
+ source, sink = sata_master_port.source, sata_master_port.sink
+
+ self.counter = counter = Counter(bits_sign=32)
+ self.error_counter = Counter(self.errors, bits_sign=32)
+
+ self.scrambler = scrambler = InsertReset(Scrambler())
+ self.comb += [
+ scrambler.reset.eq(counter.reset),
+ scrambler.ce.eq(counter.ce)
+ ]
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ self.done.eq(1),
+ counter.reset.eq(1),
+ If(self.start,
+ self.error_counter.reset.eq(1),
+ NextState("SEND_CMD")
+ )
+ )
+ self.comb += [
+ source.sop.eq(1),
+ source.eop.eq(1),
+ source.read.eq(1),
+ source.sector.eq(self.sector),
+ source.count.eq(self.count),
+ ]
+ fsm.act("SEND_CMD",
+ source.stb.eq(1),
+ If(source.ack,
+ counter.reset.eq(1),
+ NextState("WAIT_ACK")
+ )
+ )
+ fsm.act("WAIT_ACK",
+ If(sink.stb & sink.read,
+ NextState("RECEIVE_DATA")
+ )
+ )
+ expected_data = Signal(32)
+ self.comb += \
+ If(self.random,
+ expected_data.eq(scrambler.value)
+ ).Else(
+ expected_data.eq(counter.value)
+ )
+ fsm.act("RECEIVE_DATA",
+ sink.ack.eq(1),
+ If(sink.stb,
+ counter.ce.eq(1),
+ If(sink.data != expected_data,
+ self.error_counter.ce.eq(1)
+ ),
+ If(sink.eop,
+ If(sink.last,
+ NextState("IDLE")
+ ).Else(
+ NextState("WAIT_ACK")
+ )
+ )
+ )
+ )
+
+class LiteSATABISTUnitCSR(Module, AutoCSR):
+ def __init__(self, bist_unit):
+ self._start = CSR()
+ self._sector = CSRStorage(48)
+ self._count = CSRStorage(16)
+ self._random = CSRStorage()
+ self._done = CSRStatus()
+ self._errors = CSRStatus(32)
+ self._cycles = CSRStatus(32)
+
+ ###
+
+ self.bist_unit = bist_unit
+ self.comb += [
+ bist_unit.start.eq(self._start.r & self._start.re),
+ bist_unit.sector.eq(self._sector.storage),
+ bist_unit.count.eq(self._count.storage),
+ bist_unit.random.eq(self._random.storage),
+
+ self._done.status.eq(bist_unit.done),
+ self._errors.status.eq(bist_unit.errors)
+ ]
+
+ self.cycles_counter = Counter(self._cycles.status)
+ self.sync += [
+ self.cycles_counter.reset.eq(bist_unit.start),
+ self.cycles_counter.ce.eq(~bist_unit.done)
+ ]
+
+class LiteSATABISTIdentify(Module):
+ def __init__(self, sata_master_port):
+ self.start = Signal()
+ self.done = Signal()
+
+ self.fifo = fifo = SyncFIFO([("data", 32)], 512, buffered=True)
+ self.source = self.fifo.source
+
+ ###
+
+ source, sink = sata_master_port.source, sata_master_port.sink
+
+ self.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ self.done.eq(1),
+ If(self.start,
+ NextState("SEND_CMD")
+ )
+ )
+ self.comb += [
+ source.sop.eq(1),
+ source.eop.eq(1),
+ source.identify.eq(1),
+ ]
+ fsm.act("SEND_CMD",
+ source.stb.eq(1),
+ If(source.stb & source.ack,
+ NextState("WAIT_ACK")
+ )
+ )
+ fsm.act("WAIT_ACK",
+ If(sink.stb & sink.identify,
+ NextState("RECEIVE_DATA")
+ )
+ )
+ self.comb += fifo.sink.data.eq(sink.data)
+ fsm.act("RECEIVE_DATA",
+ sink.ack.eq(fifo.sink.ack),
+ If(sink.stb,
+ fifo.sink.stb.eq(1),
+ If(sink.eop,
+ NextState("IDLE")
+ )
+ )
+ )
+
+class LiteSATABISTIdentifyCSR(Module, AutoCSR):
+ def __init__(self, bist_identify):
+ self._start = CSR()
+ self._done = CSRStatus()
+ self._source_stb = CSRStatus()
+ self._source_ack = CSR()
+ self._source_data = CSRStatus(32)
+
+ ###
+
+ self.bist_identify = bist_identify
+ self.comb += [
+ bist_identify.start.eq(self._start.r & self._start.re),
+ self._done.status.eq(bist_identify.done),
+
+ self._source_stb.status.eq(bist_identify.source.stb),
+ self._source_data.status.eq(bist_identify.source.data),
+ bist_identify.source.ack.eq(self._source_ack.r & self._source_ack.re)
+ ]
+
+class LiteSATABIST(Module, AutoCSR):
+ def __init__(self, crossbar, with_csr=False):
+ generator = LiteSATABISTGenerator(crossbar.get_port())
+ checker = LiteSATABISTChecker(crossbar.get_port())
+ identify = LiteSATABISTIdentify(crossbar.get_port())
+ if with_csr:
+ self.generator = LiteSATABISTUnitCSR(generator)
+ self.checker = LiteSATABISTUnitCSR(checker)
+ self.identify = LiteSATABISTIdentifyCSR(identify)
+ else:
+ self.generator = generator
+ self.checker = checker
+ self.identify = identify
--- /dev/null
+from litesata.common import *
+
+class LiteSATAMasterPort:
+ def __init__(self, dw):
+ self.source = Source(command_tx_description(dw))
+ self.sink = Sink(command_rx_description(dw))
+
+ def connect(self, slave):
+ return [
+ Record.connect(self.source, slave.sink),
+ Record.connect(slave.source, self.sink)
+ ]
+
+class LiteSATASlavePort:
+ def __init__(self, dw):
+ self.sink = Sink(command_tx_description(dw))
+ self.source = Source(command_rx_description(dw))
+
+ def connect(self, master):
+ return [
+ Record.connect(self.sink, master.source),
+ Record.connect(master.sink, self.source)
+ ]
--- /dev/null
+from litesata.common import *
+from litesata.frontend.common import *
+from litesata.frontend.arbiter import LiteSATAArbiter
+
+class LiteSATACrossbar(Module):
+ def __init__(self, core):
+ self.slaves = []
+ self.master = LiteSATAMasterPort(32)
+ self.comb += [
+ self.master.source.connect(core.sink),
+ core.source.connect(self.master.sink)
+ ]
+
+ def get_port(self):
+ master = LiteSATAMasterPort(32)
+ slave = LiteSATASlavePort(32)
+ self.comb += master.connect(slave)
+ self.slaves.append(slave)
+ return master
+
+ def get_ports(self, n):
+ masters = []
+ for i in range(n):
+ masters.append(self.get_port())
+ return masters
+
+ def do_finalize(self):
+ self.arbiter = LiteSATAArbiter(self.slaves, self.master)
--- /dev/null
+from litesata.common import *
+from litesata.phy.ctrl import *
+from litesata.phy.datapath import *
+
+class LiteSATAPHY(Module):
+ def __init__(self, device, pads, speed, clk_freq):
+ self.speed = speed
+ # Transceiver / Clocks
+ if device[:3] == "xc7": # Kintex 7
+ from litesata.phy.k7.trx import K7LiteSATAPHYTRX
+ from litesata.phy.k7.crg import K7LiteSATAPHYCRG
+ self.trx = K7LiteSATAPHYTRX(pads, speed)
+ self.crg = K7LiteSATAPHYCRG(pads, self.trx, speed, clk_freq)
+ else:
+ msg = "Device" + device + "not (yet) supported."
+ raise NotImplementedError(msg)
+
+ # Control
+ self.ctrl = LiteSATAPHYCtrl(self.trx, self.crg, clk_freq)
+
+ # Datapath
+ self.datapath = LiteSATAPHYDatapath(self.trx, self.ctrl)
+ self.sink, self.source = self.datapath.sink, self.datapath.source
--- /dev/null
+from litesata.common import *
+
+def us(t, clk_freq):
+ clk_period_us = 1000000/clk_freq
+ return math.ceil(t/clk_period_us)
+
+class LiteSATAPHYCtrl(Module):
+ def __init__(self, trx, crg, clk_freq):
+ self.ready = Signal()
+ self.need_reset = Signal()
+ self.sink = sink = Sink(phy_description(32))
+ self.source = source = Source(phy_description(32))
+
+ ###
+ self.comb += [
+ source.stb.eq(1),
+ sink.ack.eq(1)
+ ]
+
+ retry_timeout = Timeout(us(10000, clk_freq))
+ align_timeout = Timeout(us(873, clk_freq))
+ self.submodules += align_timeout, retry_timeout
+
+ align_detect = Signal()
+ non_align_cnt = Signal(4)
+
+ self.fsm = fsm = FSM(reset_state="RESET")
+ fsm.act("RESET",
+ trx.tx_idle.eq(1),
+ retry_timeout.reset.eq(1),
+ align_timeout.reset.eq(1),
+ If(crg.ready,
+ NextState("COMINIT")
+ ),
+ )
+ fsm.act("COMINIT",
+ trx.tx_idle.eq(1),
+ trx.tx_cominit_stb.eq(1),
+ If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
+ NextState("AWAIT_COMINIT")
+ ),
+ )
+ fsm.act("AWAIT_COMINIT",
+ trx.tx_idle.eq(1),
+ retry_timeout.ce.eq(1),
+ If(trx.rx_cominit_stb,
+ NextState("AWAIT_NO_COMINIT")
+ ).Else(
+ If(retry_timeout.reached,
+ NextState("RESET")
+ )
+ ),
+ )
+ fsm.act("AWAIT_NO_COMINIT",
+ trx.tx_idle.eq(1),
+ retry_timeout.reset.eq(1),
+ If(~trx.rx_cominit_stb,
+ NextState("CALIBRATE")
+ ),
+ )
+ fsm.act("CALIBRATE",
+ trx.tx_idle.eq(1),
+ NextState("COMWAKE"),
+ )
+ fsm.act("COMWAKE",
+ trx.tx_idle.eq(1),
+ trx.tx_comwake_stb.eq(1),
+ If(trx.tx_comwake_ack,
+ NextState("AWAIT_COMWAKE")
+ ),
+ )
+ fsm.act("AWAIT_COMWAKE",
+ trx.tx_idle.eq(1),
+ retry_timeout.ce.eq(1),
+ If(trx.rx_comwake_stb,
+ NextState("AWAIT_NO_COMWAKE")
+ ).Else(
+ If(retry_timeout.reached,
+ NextState("RESET")
+ )
+ ),
+ )
+ fsm.act("AWAIT_NO_COMWAKE",
+ trx.tx_idle.eq(1),
+ If(~trx.rx_comwake_stb,
+ NextState("AWAIT_NO_RX_IDLE")
+ ),
+ )
+ fsm.act("AWAIT_NO_RX_IDLE",
+ trx.tx_idle.eq(0),
+ source.data.eq(0x4A4A4A4A), #D10.2
+ source.charisk.eq(0b0000),
+ If(~trx.rx_idle,
+ NextState("AWAIT_ALIGN"),
+ crg.reset.eq(1),
+ trx.pmarxreset.eq(1)
+ ),
+ )
+ fsm.act("AWAIT_ALIGN",
+ trx.tx_idle.eq(0),
+ source.data.eq(0x4A4A4A4A), #D10.2
+ source.charisk.eq(0b0000),
+ trx.rx_align.eq(1),
+ align_timeout.ce.eq(1),
+ If(align_detect & ~trx.rx_idle,
+ NextState("SEND_ALIGN")
+ ).Elif(align_timeout.reached,
+ NextState("RESET")
+ ),
+ )
+ fsm.act("SEND_ALIGN",
+ trx.tx_idle.eq(0),
+ trx.rx_align.eq(1),
+ source.data.eq(primitives["ALIGN"]),
+ source.charisk.eq(0b0001),
+ If(non_align_cnt == 3,
+ NextState("READY")
+ ),
+ )
+ fsm.act("READY",
+ trx.tx_idle.eq(0),
+ trx.rx_align.eq(1),
+ source.data.eq(primitives["SYNC"]),
+ source.charisk.eq(0b0001),
+ If(trx.rx_idle,
+ NextState("RESET")
+ ),
+ self.ready.eq(1),
+ )
+
+ self.reset_timeout = Timeout(clk_freq//16)
+ self.comb += [
+ self.reset_timeout.ce.eq(~self.ready),
+ self.need_reset.eq(self.reset_timeout.reached)
+ ]
+
+ self.comb += \
+ align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
+ self.sync += \
+ If(fsm.ongoing("SEND_ALIGN"),
+ If(sink.stb,
+ If(sink.data[0:8] == 0x7C,
+ non_align_cnt.eq(non_align_cnt + 1)
+ ).Else(
+ non_align_cnt.eq(0)
+ )
+ )
+ )
--- /dev/null
+from litesata.common import *
+
+class LiteSATAPHYDatapathRX(Module):
+ def __init__(self):
+ self.sink = Sink(phy_description(16))
+ self.source = Source(phy_description(32))
+
+ ###
+
+ # width convertion (16 to 32) and byte alignment
+ byte_alignment = Signal()
+ last_charisk = Signal(2)
+ last_data = Signal(16)
+ self.sync.sata_rx += \
+ If(self.sink.stb & self.sink.ack,
+ If(self.sink.charisk != 0,
+ byte_alignment.eq(self.sink.charisk[1])
+ ),
+ last_charisk.eq(self.sink.charisk),
+ last_data.eq(self.sink.data)
+ )
+ converter = Converter(phy_description(16), phy_description(32), reverse=False)
+ self.converter = InsertReset(RenameClockDomains(converter, "sata_rx"))
+ self.comb += [
+ self.converter.sink.stb.eq(self.sink.stb),
+ If(byte_alignment,
+ self.converter.sink.charisk.eq(Cat(last_charisk[1], self.sink.charisk[0])),
+ self.converter.sink.data.eq(Cat(last_data[8:], self.sink.data[:8]))
+ ).Else(
+ self.converter.sink.charisk.eq(self.sink.charisk),
+ self.converter.sink.data.eq(self.sink.data)
+ ),
+ self.sink.ack.eq(self.converter.sink.ack),
+ self.converter.reset.eq(self.converter.source.charisk[2:] != 0)
+ ]
+
+ # clock domain crossing
+ # (SATA3) 300MHz sata_rx clk to sys_clk
+ # (SATA2) 150MHz sata_rx clk to sys_clk
+ # (SATA1) 75MHz sata_rx clk to sys_clk
+ # requirements:
+ # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
+ # source destination is always able to accept data (ack always 1)
+ fifo = AsyncFIFO(phy_description(32), 4)
+ self.fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
+ self.comb += [
+ Record.connect(self.converter.source, fifo.sink),
+ Record.connect(fifo.source, self.source)
+ ]
+
+class LiteSATAPHYDatapathTX(Module):
+ def __init__(self):
+ self.sink = Sink(phy_description(32))
+ self.source = Source(phy_description(16))
+
+ ###
+
+ # clock domain crossing
+ # (SATA3) sys_clk to 300MHz sata_tx clk
+ # (SATA2) sys_clk to 150MHz sata_tx clk
+ # (SATA1) sys_clk to 75MHz sata_tx clk
+ # requirements:
+ # source destination is always able to accept data (ack always 1)
+ fifo = AsyncFIFO(phy_description(32), 4)
+ self.fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
+ self.comb += Record.connect(self.sink, fifo.sink)
+
+ # width convertion (32 to 16)
+ converter = Converter(phy_description(32), phy_description(16), reverse=False)
+ self.converter = RenameClockDomains(converter, "sata_tx")
+ self.comb += [
+ Record.connect(self.fifo.source, self.converter.sink),
+ Record.connect(self.converter.source, self.source)
+ ]
+
+class LiteSATAPHYAlignInserter(Module):
+ def __init__(self, ctrl):
+ self.sink = sink = Sink(phy_description(32))
+ self.source = source = Source(phy_description(32))
+
+ ###
+
+ # send 2 ALIGN every 256 DWORDs
+ # used for clock compensation between
+ # HOST and device
+ cnt = Signal(8)
+ send = Signal()
+ self.sync += \
+ If(~ctrl.ready,
+ cnt.eq(0)
+ ).Elif(source.stb & source.ack,
+ cnt.eq(cnt+1)
+ )
+ self.comb += [
+ send.eq(cnt < 2),
+ If(send,
+ source.stb.eq(1),
+ source.charisk.eq(0b0001),
+ source.data.eq(primitives["ALIGN"]),
+ sink.ack.eq(0)
+ ).Else(
+ source.stb.eq(sink.stb),
+ source.data.eq(sink.data),
+ source.charisk.eq(sink.charisk),
+ sink.ack.eq(source.ack)
+ )
+ ]
+
+class LiteSATAPHYAlignRemover(Module):
+ def __init__(self):
+ self.sink = sink = Sink(phy_description(32))
+ self.source = source = Source(phy_description(32))
+
+ ###
+
+ charisk_match = sink.charisk == 0b0001
+ data_match = sink.data == primitives["ALIGN"]
+
+ self.comb += \
+ If(sink.stb & charisk_match & data_match,
+ sink.ack.eq(1),
+ ).Else(
+ Record.connect(sink, source)
+ )
+
+class LiteSATAPHYDatapath(Module):
+ def __init__(self, trx, ctrl):
+ self.sink = Sink(phy_description(32))
+ self.source = Source(phy_description(32))
+
+ ###
+
+ # TX path
+ self.align_inserter = LiteSATAPHYAlignInserter(ctrl)
+ self.mux = Multiplexer(phy_description(32), 2)
+ self.tx = LiteSATAPHYDatapathTX()
+ self.comb += [
+ self.mux.sel.eq(ctrl.ready),
+ Record.connect(self.sink, self.align_inserter.sink),
+ Record.connect(ctrl.source, self.mux.sink0),
+ Record.connect(self.align_inserter.source, self.mux.sink1),
+ Record.connect(self.mux.source, self.tx.sink),
+ Record.connect(self.tx.source, trx.sink)
+ ]
+
+ # RX path
+ self.rx = LiteSATAPHYDatapathRX()
+ self.demux = Demultiplexer(phy_description(32), 2)
+ self.align_remover = LiteSATAPHYAlignRemover()
+ self.comb += [
+ self.demux.sel.eq(ctrl.ready),
+ Record.connect(trx.source, self.rx.sink),
+ Record.connect(self.rx.source, self.demux.sink),
+ Record.connect(self.demux.source0, ctrl.sink),
+ Record.connect(self.demux.source1, self.align_remover.sink),
+ Record.connect(self.align_remover.source, self.source)
+ ]
--- /dev/null
+from litesata.common import *
+
+class K7LiteSATAPHYCRG(Module):
+ def __init__(self, pads, gtx, speed, clk_freq):
+ self.reset = Signal()
+ self.ready = Signal()
+
+ self.cd_sata_tx = ClockDomain()
+ self.cd_sata_rx = ClockDomain()
+
+ # CPLL
+ # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
+ # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output dividers.
+ refclk = Signal()
+ self.specials += Instance("IBUFDS_GTE2",
+ i_CEB=0,
+ i_I=pads.refclk_p,
+ i_IB=pads.refclk_n,
+ o_O=refclk
+ )
+ self.comb += gtx.gtrefclk0.eq(refclk)
+
+ # TX clocking
+ # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
+ # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
+ # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
+ mmcm_reset = Signal()
+ mmcm_locked = Signal()
+ mmcm_fb = Signal()
+ mmcm_clk_i = Signal()
+ mmcm_clk0_o = Signal()
+ mmcm_div_config = {
+ "SATA1" : 16.0,
+ "SATA2" : 8.0,
+ "SATA3" : 4.0
+ }
+ mmcm_div = mmcm_div_config[speed]
+ self.specials += [
+ Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i),
+ Instance("MMCME2_ADV",
+ p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked,
+
+ # DRP
+ i_DCLK=0, i_DEN=0, i_DWE=0, #o_DRDY=,
+ i_DADDR=0, i_DI=0, #o_DO=,
+
+ # VCO
+ p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666,
+ p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1,
+ i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb,
+
+ # CLK0
+ p_CLKOUT0_DIVIDE_F=mmcm_div, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o,
+ ),
+ Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk),
+ ]
+ self.comb += [
+ gtx.txusrclk.eq(self.cd_sata_tx.clk),
+ gtx.txusrclk2.eq(self.cd_sata_tx.clk)
+ ]
+
+ # RX clocking
+ # (SATA3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
+ # (SATA2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
+ # (SATA1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
+ self.specials += [
+ Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
+ ]
+ self.comb += [
+ gtx.rxusrclk.eq(self.cd_sata_rx.clk),
+ gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
+ ]
+
+ # Configuration Reset
+ # After configuration, GTX's resets have to stay low for at least 500ns
+ # See AR43482
+ reset_en = Signal()
+ clk_period_ns = 1000000000/clk_freq
+ reset_en_cnt_max = math.ceil(500/clk_period_ns)
+ reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1)
+ self.sync += \
+ If(self.reset,
+ reset_en_cnt.eq(reset_en_cnt.reset)
+ ).Elif(~reset_en,
+ reset_en_cnt.eq(reset_en_cnt-1)
+ )
+ self.comb += reset_en.eq(reset_en_cnt == 0)
+
+ # TX Reset FSM
+ tx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
+ self.submodules += tx_reset_fsm
+ self.comb += tx_reset_fsm.reset.eq(self.reset)
+ tx_reset_fsm.act("IDLE",
+ If(reset_en,
+ NextState("RESET_GTX"),
+ )
+ )
+ tx_reset_fsm.act("RESET_GTX",
+ gtx.gttxreset.eq(1),
+ If(gtx.cplllock & mmcm_locked,
+ NextState("RELEASE_GTX")
+ )
+ )
+ tx_reset_fsm.act("RELEASE_GTX",
+ gtx.txuserrdy.eq(1),
+ If(gtx.txresetdone,
+ NextState("READY")
+ )
+ )
+ tx_reset_fsm.act("READY",
+ gtx.txuserrdy.eq(1)
+ )
+
+ # RX Reset FSM
+ rx_reset_fsm = InsertReset(FSM(reset_state="IDLE"))
+ self.submodules += rx_reset_fsm
+ self.comb += rx_reset_fsm.reset.eq(self.reset)
+
+ rx_reset_fsm.act("IDLE",
+ If(reset_en,
+ NextState("RESET_GTX"),
+ )
+ )
+ rx_reset_fsm.act("RESET_GTX",
+ gtx.gtrxreset.eq(1),
+ If(gtx.cplllock & mmcm_locked,
+ NextState("RELEASE_GTX")
+ )
+ )
+ rx_reset_fsm.act("RELEASE_GTX",
+ gtx.rxuserrdy.eq(1),
+ If(gtx.rxresetdone,
+ NextState("READY")
+ )
+ )
+ rx_reset_fsm.act("READY",
+ gtx.rxuserrdy.eq(1)
+ )
+
+ # Ready
+ self.tx_ready = tx_reset_fsm.ongoing("READY")
+ self.rx_ready = rx_reset_fsm.ongoing("READY")
+ self.comb += self.ready.eq(self.tx_ready & self.rx_ready)
+
+ # Reset PLL
+ self.comb += gtx.cpllreset.eq(ResetSignal() | self.reset | ~reset_en)
+
+ # Reset MMCM
+ self.comb += mmcm_reset.eq(ResetSignal() | self.reset | ~gtx.cplllock)
+
+ # Reset for SATA TX/RX clock domains
+ self.specials += [
+ AsyncResetSynchronizer(self.cd_sata_tx, ~self.tx_ready),
+ AsyncResetSynchronizer(self.cd_sata_rx, ~self.rx_ready),
+ ]
--- /dev/null
+from litesata.common import *
+
+def ones(width):
+ return 2**width-1
+
+class _PulseSynchronizer(PulseSynchronizer):
+ def __init__(self, i, idomain, o, odomain):
+ PulseSynchronizer.__init__(self, idomain, odomain)
+ self.comb += [
+ self.i.eq(i),
+ o.eq(self.o)
+ ]
+
+class _RisingEdge(Module):
+ def __init__(self, i, o):
+ i_d = Signal()
+ self.sync += i_d.eq(i)
+ self.comb += o.eq(i & ~i_d)
+
+class K7LiteSATAPHYTRX(Module):
+ def __init__(self, pads, speed):
+ # Common signals
+
+ # control
+ self.tx_idle = Signal() #i
+
+ self.tx_cominit_stb = Signal() #i
+ self.tx_cominit_ack = Signal() #o
+ self.tx_comwake_stb = Signal() #i
+ self.tx_comwake_ack = Signal() #o
+
+ self.rx_idle = Signal() #o
+ self.rx_align = Signal() #i
+
+ self.rx_cominit_stb = Signal() #o
+ self.rx_comwake_stb = Signal() #o
+
+ # datapath
+ self.sink = Sink(phy_description(16))
+ self.source = Source(phy_description(16))
+
+ # K7 specific signals
+ # Channel - Ref Clock Ports
+ self.gtrefclk0 = Signal()
+
+ # Channel PLL
+ self.cplllock = Signal()
+ self.cpllreset = Signal()
+
+ # Receive Ports
+ self.rxuserrdy = Signal()
+ self.rxalign = Signal()
+
+ # Receive Ports - 8b10b Decoder
+ self.rxcharisk = Signal(2)
+ self.rxdisperr = Signal(2)
+
+ # Receive Ports - RX Data Path interface
+ self.gtrxreset = Signal()
+ self.pmarxreset = Signal()
+ self.rxdata = Signal(16)
+ self.rxoutclk = Signal()
+ self.rxusrclk = Signal()
+ self.rxusrclk2 = Signal()
+
+ # Receive Ports - RX Driver,OOB signalling,Coupling and Eq.,CDR
+ self.rxelecidle = Signal()
+
+ # Receive Ports - RX PLL Ports
+ self.rxresetdone = Signal()
+
+ # Receive Ports - RX Ports for SATA
+ self.rxcominitdet = Signal()
+ self.rxcomwakedet = Signal()
+
+ # Transmit Ports
+ self.txuserrdy = Signal()
+
+ # Transmit Ports - 8b10b Encoder Control Ports
+ self.txcharisk = Signal(2)
+
+ # Transmit Ports - TX Data Path interface
+ self.gttxreset = Signal()
+ self.txdata = Signal(16)
+ self.txoutclk = Signal()
+ self.txusrclk = Signal()
+ self.txusrclk2 = Signal()
+
+ # Transmit Ports - TX PLL Ports
+ self.txresetdone = Signal()
+
+ # Transmit Ports - TX Ports for PCI Express
+ self.txelecidle = Signal(reset=1)
+
+ # Transmit Ports - TX Ports for SATA
+ self.txcomfinish = Signal()
+ self.txcominit = Signal()
+ self.txcomwake = Signal()
+ self.txrate = Signal(3)
+ self.rxcdrlock = Signal()
+
+ # Config at startup
+ div_config = {
+ "SATA1" : 4,
+ "SATA2" : 2,
+ "SATA3" : 1
+ }
+ rxout_div = div_config[speed]
+ txout_div = div_config[speed]
+
+ cdr_config = {
+ "SATA1" : 0x0380008BFF40100008,
+ "SATA2" : 0x0388008BFF40200008,
+ "SATA3" : 0X0380008BFF10200010
+ }
+ rxcdr_cfg = cdr_config[speed]
+
+ # Specific / Generic signals encoding/decoding
+ self.comb += [
+ self.txelecidle.eq(self.tx_idle),
+ self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish),
+ self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish),
+ self.rx_idle.eq(self.rxelecidle),
+ self.rxalign.eq(self.rx_align),
+ self.rx_cominit_stb.eq(self.rxcominitdet),
+ self.rx_comwake_stb.eq(self.rxcomwakedet),
+ ]
+ self.submodules += [
+ _RisingEdge(self.tx_cominit_stb, self.txcominit),
+ _RisingEdge(self.tx_comwake_stb, self.txcomwake),
+ ]
+
+ self.comb += [
+ self.txcharisk.eq(self.sink.charisk),
+ self.txdata.eq(self.sink.data),
+ self.sink.ack.eq(1),
+
+ self.source.stb.eq(1),
+ self.source.charisk.eq(self.rxcharisk),
+ self.source.data.eq(self.rxdata)
+ ]
+
+ # Internals and clock domain crossing
+ # sys_clk --> sata_tx clk
+ txuserrdy = Signal()
+ txelecidle = Signal(reset=1)
+ txcominit = Signal()
+ txcomwake = Signal()
+ txrate = Signal(3)
+
+ self.specials += [
+ MultiReg(self.txuserrdy, txuserrdy, "sata_tx"),
+ MultiReg(self.txelecidle, txelecidle, "sata_tx"),
+ MultiReg(self.txrate, txrate, "sata_tx")
+ ]
+ self.submodules += [
+ _PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"),
+ _PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"),
+ ]
+
+ # sata_tx clk --> sys clk
+ txresetdone = Signal()
+ txcomfinish = Signal()
+
+ self.specials += [
+ MultiReg(txresetdone, self.txresetdone, "sys"),
+ ]
+
+ self.submodules += [
+ _PulseSynchronizer(txcomfinish, "sata_tx", self.txcomfinish, "sys"),
+ ]
+
+ # sys clk --> sata_rx clk
+ rxuserrdy = Signal()
+
+ self.specials += [
+ MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
+ ]
+
+ # sata_rx clk --> sys clk
+ rxelecidle = Signal()
+ rxelecidle_i = Signal()
+ rxelecidle_cnt_i = Signal(9)
+ rxresetdone = Signal()
+ rxcominitdet = Signal()
+ rxcomwakedet = Signal()
+ rxratedone = Signal()
+ rxcdrlock = Signal()
+
+ self.specials += [
+ MultiReg(rxelecidle, rxelecidle_i, "sys"),
+ MultiReg(rxresetdone, self.rxresetdone, "sys"),
+ MultiReg(rxcominitdet, self.rxcominitdet, "sys"),
+ MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"),
+ MultiReg(rxcdrlock, self.rxcdrlock, "sys"),
+ ]
+
+ self.sync += [
+ If(rxelecidle_i != self.rxelecidle,
+ If(rxelecidle_cnt_i == 0,
+ self.rxelecidle.eq(rxelecidle_i),
+ rxelecidle_cnt_i.eq(255)
+ ).Else(
+ rxelecidle_cnt_i.eq(rxelecidle_cnt_i-1)
+ )
+ ).Else(
+ rxelecidle_cnt_i.eq(255)
+ )
+ ]
+
+ self.rxbyteisaligned = Signal()
+
+ # QPLL input clock
+ self.qpllclk = Signal()
+ self.qpllrefclk = Signal()
+
+ # Instance
+ gtxe2_channel_parameters = {
+ # Simulation-Only Attributes
+ "p_SIM_RECEIVER_DETECT_PASS":"TRUE",
+ "p_SIM_TX_EIDLE_DRIVE_LEVEL":"X",
+ "p_SIM_RESET_SPEEDUP":"TRUE",
+ "p_SIM_CPLLREFCLK_SEL":0b001,
+ "p_SIM_VERSION":"4.0",
+
+ # RX Byte and Word Alignment Attributes
+ "p_ALIGN_COMMA_DOUBLE":"FALSE",
+ "p_ALIGN_COMMA_ENABLE":ones(10),
+ "p_ALIGN_COMMA_WORD":2,
+ "p_ALIGN_MCOMMA_DET":"TRUE",
+ "p_ALIGN_MCOMMA_VALUE":0b1010000011,
+ "p_ALIGN_PCOMMA_DET":"TRUE",
+ "p_ALIGN_PCOMMA_VALUE":0b0101111100,
+ "p_SHOW_REALIGN_COMMA":"FALSE",
+ "p_RXSLIDE_AUTO_WAIT":7,
+ "p_RXSLIDE_MODE":"PCS",
+ "p_RX_SIG_VALID_DLY":10,
+
+ # RX 8B/10B Decoder Attributes
+ "p_RX_DISPERR_SEQ_MATCH":"TRUE",
+ "p_DEC_MCOMMA_DETECT":"TRUE",
+ "p_DEC_PCOMMA_DETECT":"TRUE",
+ "p_DEC_VALID_COMMA_ONLY":"FALSE",
+
+ # RX Clock Correction Attributes
+ "p_CBCC_DATA_SOURCE_SEL":"DECODED",
+ "p_CLK_COR_SEQ_2_USE":"FALSE",
+ "p_CLK_COR_KEEP_IDLE":"FALSE",
+ "p_CLK_COR_MAX_LAT":9,
+ "p_CLK_COR_MIN_LAT":7,
+ "p_CLK_COR_PRECEDENCE":"TRUE",
+ "p_CLK_COR_REPEAT_WAIT":0,
+ "p_CLK_COR_SEQ_LEN":1,
+ "p_CLK_COR_SEQ_1_ENABLE":ones(4),
+ "p_CLK_COR_SEQ_1_1":0b0100000000,
+ "p_CLK_COR_SEQ_1_2":0b0000000000,
+ "p_CLK_COR_SEQ_1_3":0b0000000000,
+ "p_CLK_COR_SEQ_1_4":0b0000000000,
+ "p_CLK_CORRECT_USE":"FALSE",
+ "p_CLK_COR_SEQ_2_ENABLE":ones(4),
+ "p_CLK_COR_SEQ_2_1":0b0100000000,
+ "p_CLK_COR_SEQ_2_2":0,
+ "p_CLK_COR_SEQ_2_3":0,
+ "p_CLK_COR_SEQ_2_4":0,
+
+ # RX Channel Bonding Attributes
+ "p_CHAN_BOND_KEEP_ALIGN":"FALSE",
+ "p_CHAN_BOND_MAX_SKEW":1,
+ "p_CHAN_BOND_SEQ_LEN":1,
+ "p_CHAN_BOND_SEQ_1_1":0,
+ "p_CHAN_BOND_SEQ_1_1":0,
+ "p_CHAN_BOND_SEQ_1_2":0,
+ "p_CHAN_BOND_SEQ_1_3":0,
+ "p_CHAN_BOND_SEQ_1_4":0,
+ "p_CHAN_BOND_SEQ_1_ENABLE":ones(4),
+ "p_CHAN_BOND_SEQ_2_1":0,
+ "p_CHAN_BOND_SEQ_2_2":0,
+ "p_CHAN_BOND_SEQ_2_3":0,
+ "p_CHAN_BOND_SEQ_2_4":0,
+ "p_CHAN_BOND_SEQ_2_ENABLE":ones(4),
+ "p_CHAN_BOND_SEQ_2_USE":"FALSE",
+ "p_FTS_DESKEW_SEQ_ENABLE":ones(4),
+ "p_FTS_LANE_DESKEW_CFG":ones(4),
+ "p_FTS_LANE_DESKEW_EN":"FALSE",
+
+ # RX Margin Analysis Attributes
+ "p_ES_CONTROL":0,
+ "p_ES_ERRDET_EN":"FALSE",
+ "p_ES_EYE_SCAN_EN":"TRUE",
+ "p_ES_HORZ_OFFSET":0,
+ "p_ES_PMA_CFG":0,
+ "p_ES_PRESCALE":0,
+ "p_ES_QUALIFIER":0,
+ "p_ES_QUAL_MASK":0,
+ "p_ES_SDATA_MASK":0,
+ "p_ES_VERT_OFFSET":0,
+
+ # FPGA RX Interface Attributes
+ "p_RX_DATA_WIDTH":20,
+
+ # PMA Attributes
+ "p_OUTREFCLK_SEL_INV":0b11,
+ "p_PMA_RSV":0x00018480,
+ "p_PMA_RSV2":0x2050,
+ "p_PMA_RSV3":0,
+ "p_PMA_RSV4":0,
+ "p_RX_BIAS_CFG":0b100,
+ "p_DMONITOR_CFG":0xA00,
+ "p_RX_CM_SEL":0b11,
+ "p_RX_CM_TRIM":0b010,
+ "p_RX_DEBUG_CFG":0,
+ "p_RX_OS_CFG":0b10000000,
+ "p_TERM_RCAL_CFG":0,
+ "p_TERM_RCAL_OVRD":0,
+ "p_TST_RSV":0,
+ "p_RX_CLK25_DIV":6,
+ "p_TX_CLK25_DIV":6,
+ "p_UCODEER_CLR":0,
+
+ # PCI Express Attributes
+ "p_PCS_PCIE_EN":"FALSE",
+
+ # PCS Attributes
+ "p_PCS_RSVD_ATTR":0x100,
+
+ # RX Buffer Attributes
+ "p_RXBUF_ADDR_MODE":"FAST",
+ "p_RXBUF_EIDLE_HI_CNT":0b1000,
+ "p_RXBUF_EIDLE_LO_CNT":0,
+ "p_RXBUF_EN":"TRUE",
+ "p_RX_BUFFER_CFG":0,
+ "p_RXBUF_RESET_ON_CB_CHANGE":"TRUE",
+ "p_RXBUF_RESET_ON_COMMAALIGN":"FALSE",
+ "p_RXBUF_RESET_ON_EIDLE":"FALSE",
+ "p_RXBUF_RESET_ON_RATE_CHANGE":"TRUE",
+ "p_RXBUFRESET_TIME":1,
+ "p_RXBUF_THRESH_OVFLW":61,
+ "p_RXBUF_THRESH_OVRD":"FALSE",
+ "p_RXBUF_THRESH_UNDFLW":4,
+ "p_RXDLY_CFG":0x1f,
+ "p_RXDLY_LCFG":0x30,
+ "p_RXDLY_TAP_CFG":0,
+ "p_RXPH_CFG":0,
+ "p_RXPHDLY_CFG":0x084820,
+ "p_RXPH_MONITOR_SEL":0,
+ "p_RX_XCLK_SEL":"RXUSR",
+ "p_RX_DDI_SEL":0,
+ "p_RX_DEFER_RESET_BUF_EN":"TRUE",
+
+ #CDR Attributes
+ "p_RXCDR_CFG":rxcdr_cfg,
+ "p_RXCDR_FR_RESET_ON_EIDLE":0,
+ "p_RXCDR_HOLD_DURING_EIDLE":0,
+ "p_RXCDR_PH_RESET_ON_EIDLE":0,
+ "p_RXCDR_LOCK_CFG":0b010101,
+
+ # RX Initialization and Reset Attributes
+ "p_RXCDRFREQRESET_TIME":1,
+ "p_RXCDRPHRESET_TIME":1,
+ "p_RXISCANRESET_TIME":1,
+ "p_RXPCSRESET_TIME":1,
+ "p_RXPMARESET_TIME":3,
+
+ # RX OOB Signaling Attributes
+ "p_RXOOB_CFG":0b0000110,
+
+ # RX Gearbox Attributes
+ "p_RXGEARBOX_EN":"FALSE",
+ "p_GEARBOX_MODE":0,
+
+ # PRBS Detection Attribute
+ "p_RXPRBS_ERR_LOOPBACK":0,
+
+ # Power-Down Attributes
+ "p_PD_TRANS_TIME_FROM_P2":0x03c,
+ "p_PD_TRANS_TIME_NONE_P2":0x3c,
+ "p_PD_TRANS_TIME_TO_P2":0x64,
+
+ # RX OOB Signaling Attributes
+ "p_SAS_MAX_COM":64,
+ "p_SAS_MIN_COM":36,
+ "p_SATA_BURST_SEQ_LEN":0b0101,
+ "p_SATA_BURST_VAL":0b100,
+ "p_SATA_EIDLE_VAL":0b100,
+ "p_SATA_MAX_BURST":8,
+ "p_SATA_MAX_INIT":21,
+ "p_SATA_MAX_WAKE":7,
+ "p_SATA_MIN_BURST":4,
+ "p_SATA_MIN_INIT":12,
+ "p_SATA_MIN_WAKE":4,
+
+ # RX Fabric Clock Output Control Attributes
+ "p_TRANS_TIME_RATE":0x0e,
+
+ # TX Buffer Attributes
+ "p_TXBUF_EN":"TRUE",
+ "p_TXBUF_RESET_ON_RATE_CHANGE":"TRUE",
+ "p_TXDLY_CFG":0x1f,
+ "p_TXDLY_LCFG":0x030,
+ "p_TXDLY_TAP_CFG":0,
+ "p_TXPH_CFG":0x0780,
+ "p_TXPHDLY_CFG":0x084020,
+ "p_TXPH_MONITOR_SEL":0,
+ "p_TX_XCLK_SEL":"TXOUT",
+
+ # FPGA TX Interface Attributes
+ "p_TX_DATA_WIDTH":20,
+
+ # TX Configurable Driver Attributes
+ "p_TX_DEEMPH0":0,
+ "p_TX_DEEMPH1":0,
+ "p_TX_EIDLE_ASSERT_DELAY":0b110,
+ "p_TX_EIDLE_DEASSERT_DELAY":0b100,
+ "p_TX_LOOPBACK_DRIVE_HIZ":"FALSE",
+ "p_TX_MAINCURSOR_SEL":0,
+ "p_TX_DRIVE_MODE":"DIRECT",
+ "p_TX_MARGIN_FULL_0":0b1001110,
+ "p_TX_MARGIN_FULL_1":0b1001001,
+ "p_TX_MARGIN_FULL_2":0b1000101,
+ "p_TX_MARGIN_FULL_3":0b1000010,
+ "p_TX_MARGIN_FULL_4":0b1000000,
+ "p_TX_MARGIN_LOW_0":0b1000110,
+ "p_TX_MARGIN_LOW_1":0b1000100,
+ "p_TX_MARGIN_LOW_2":0b1000010,
+ "p_TX_MARGIN_LOW_3":0b1000000,
+ "p_TX_MARGIN_LOW_4":0b1000000,
+
+ # TX Gearbox Attributes
+ "p_TXGEARBOX_EN":"FALSE",
+
+ # TX Initialization and Reset Attributes
+ "p_TXPCSRESET_TIME":1,
+ "p_TXPMARESET_TIME":1,
+
+ # TX Receiver Detection Attributes
+ "p_TX_RXDETECT_CFG":0x1832,
+ "p_TX_RXDETECT_REF":0b100,
+
+ # CPLL Attributes
+ "p_CPLL_CFG":0xBC07DC,
+ "p_CPLL_FBDIV":4,
+ "p_CPLL_FBDIV_45":5,
+ "p_CPLL_INIT_CFG":0x00001e,
+ "p_CPLL_LOCK_CFG":0x01e8,
+ "p_CPLL_REFCLK_DIV":1,
+ "p_RXOUT_DIV":rxout_div,
+ "p_TXOUT_DIV":txout_div,
+ "p_SATA_CPLL_CFG":"VCO_3000MHZ",
+
+ # RX Initialization and Reset Attributes
+ "p_RXDFELPMRESET_TIME":0b0001111,
+
+ # RX Equalizer Attributes
+ "p_RXLPM_HF_CFG":0b00000011110000,
+ "p_RXLPM_LF_CFG":0b00000011110000,
+ "p_RX_DFE_GAIN_CFG":0x020fea,
+ "p_RX_DFE_H2_CFG":0b000000000000,
+ "p_RX_DFE_H3_CFG":0b000001000000,
+ "p_RX_DFE_H4_CFG":0b00011110000,
+ "p_RX_DFE_H5_CFG":0b00011100000,
+ "p_RX_DFE_KL_CFG":0b0000011111110,
+ "p_RX_DFE_LPM_CFG":0x0954,
+ "p_RX_DFE_LPM_HOLD_DURING_EIDLE":0,
+ "p_RX_DFE_UT_CFG":0b10001111000000000,
+ "p_RX_DFE_VP_CFG":0b00011111100000011,
+
+ # Power-Down Attributes
+ "p_RX_CLKMUX_PD":1,
+ "p_TX_CLKMUX_PD":1,
+
+ # FPGA RX Interface Attribute
+ "p_RX_INT_DATAWIDTH":0,
+
+ # FPGA TX Interface Attribute
+ "p_TX_INT_DATAWIDTH":0,
+
+ # TX Configurable Driver Attributes
+ "p_TX_QPI_STATUS_EN":0,
+
+ # RX Equalizer Attributes
+ "p_RX_DFE_KL_CFG2":0b00110011000100000001100000001100,
+ "p_RX_DFE_XYD_CFG":0b0000000000000,
+
+ # TX Configurable Driver Attributes
+ "p_TX_PREDRIVER_MODE":0,
+ }
+
+ self.specials += \
+ Instance("GTXE2_CHANNEL",
+ # CPLL Ports
+ #o_CPLLFBCLKLOST=,
+ o_CPLLLOCK=self.cplllock,
+ i_CPLLLOCKDETCLK=0,
+ i_CPLLLOCKEN=1,
+ i_CPLLPD=0,
+ #o_CPLLREFCLKLOST=0,
+ i_CPLLREFCLKSEL=0b001,
+ i_CPLLRESET=self.cpllreset,
+ i_GTRSVD=0,
+ i_PCSRSVDIN=0,
+ i_PCSRSVDIN2=0,
+ i_PMARSVDIN=0,
+ i_PMARSVDIN2=0,
+ i_TSTIN=ones(20),
+ #o_TSTOUT=,
+
+ # Channel
+ i_CLKRSVD=0,
+
+ # Channel - Clocking Ports
+ i_GTGREFCLK=0,
+ i_GTNORTHREFCLK0=0,
+ i_GTNORTHREFCLK1=0,
+ i_GTREFCLK0=self.gtrefclk0,
+ i_GTREFCLK1=0,
+ i_GTSOUTHREFCLK0=0,
+ i_GTSOUTHREFCLK1=0,
+
+ # Channel - DRP Ports
+ i_DRPADDR=0,
+ i_DRPCLK=0,
+ i_DRPDI=0,
+ #o_DRPDO=,
+ i_DRPEN=0,
+ #o_DRPRDY=,
+ i_DRPWE=0,
+
+ # Clocking Ports
+ #o_GTREFCLKMONITOR=,
+ i_QPLLCLK=self.qpllclk,
+ i_QPLLREFCLK=self.qpllrefclk,
+ i_RXSYSCLKSEL=0b00,
+ i_TXSYSCLKSEL=0b00,
+
+ # Digital Monitor Ports
+ #o_DMONITOROUT=,
+
+ # FPGA TX Interface Datapath Configuration
+ i_TX8B10BEN=1,
+
+ # Loopback Ports
+ i_LOOPBACK=0,
+
+ # PCI Express Ports
+ #o_PHYSTATUS=,
+ i_RXRATE=0,
+ #o_RXVALID=,
+
+ # Power-Down Ports
+ i_RXPD=0b00,
+ i_TXPD=0b00,
+
+ # RX 8B/10B Decoder Ports
+ i_SETERRSTATUS=0,
+
+ # RX Initialization and Reset Ports
+ i_EYESCANRESET=0,
+ i_RXUSERRDY=rxuserrdy,
+
+ # RX Margin Analysis Ports
+ #o_EYESCANDATAERROR=,
+ i_EYESCANMODE=0,
+ i_EYESCANTRIGGER=0,
+
+ # Receive Ports - CDR Ports
+ i_RXCDRFREQRESET=0,
+ i_RXCDRHOLD=0,
+ o_RXCDRLOCK=rxcdrlock,
+ i_RXCDROVRDEN=0,
+ i_RXCDRRESET=0,
+ i_RXCDRRESETRSV=0,
+
+ # Receive Ports - Clock Correction Ports
+ #o_RXCLKCORCNT=,
+
+ # Receive Ports - FPGA RX Interface Datapath Configuration
+ i_RX8B10BEN=1,
+
+ # Receive Ports - FPGA RX Interface Ports
+ i_RXUSRCLK=self.rxusrclk,
+ i_RXUSRCLK2=self.rxusrclk2,
+
+ # Receive Ports - FPGA RX interface Ports
+ o_RXDATA=self.rxdata,
+
+ # Receive Ports - Pattern Checker Ports
+ #o_RXPRBSERR=,
+ i_RXPRBSSEL=0,
+
+ # Receive Ports - Pattern Checker ports
+ i_RXPRBSCNTRESET=0,
+
+ # Receive Ports - RX Equalizer Ports
+ i_RXDFEXYDEN=0,
+ i_RXDFEXYDHOLD=0,
+ i_RXDFEXYDOVRDEN=0,
+
+ # Receive Ports - RX 8B/10B Decoder Ports
+ #o_RXDISPERR=,
+ #o_RXNOTINTABLE=,
+
+ # Receive Ports - RX AFE
+ i_GTXRXP=pads.rxp,
+ i_GTXRXN=pads.rxn,
+
+ # Receive Ports - RX Buffer Bypass Ports
+ i_RXBUFRESET=0,
+ #o_RXBUFSTATUS=,
+ i_RXDDIEN=0,
+ i_RXDLYBYPASS=1,
+ i_RXDLYEN=0,
+ i_RXDLYOVRDEN=0,
+ i_RXDLYSRESET=0,
+ #o_RXDLYSRESETDONE=0,
+ i_RXPHALIGN=0,
+ #o_RXPHALIGNDONE=,
+ i_RXPHALIGNEN=0,
+ i_RXPHDLYPD=0,
+ i_RXPHDLYRESET=0,
+ #o_RXPHMONITOR=,
+ i_RXPHOVRDEN=0,
+ #o_RXPHSLIPMONITOR=,
+ #o_RXSTATUS=,
+
+ # Receive Ports - RX Byte and Word Alignment Ports
+ o_RXBYTEISALIGNED=self.rxbyteisaligned,
+ #o_RXBYTEREALIGN=,
+ #o_RXCOMMADET=,
+ i_RXCOMMADETEN=1,
+ i_RXMCOMMAALIGNEN=1,
+ i_RXPCOMMAALIGNEN=1,
+
+ # Receive Ports - RX Channel Bonding Ports
+ #o_RXCHANBONDSEQ=,
+ i_RXCHBONDEN=0,
+ i_RXCHBONDLEVEL=0,
+ i_RXCHBONDMASTER=0,
+ #o_RXCHBONDO=,
+ i_RXCHBONDSLAVE=0,
+
+ # Receive Ports - RX Channel Bonding Ports
+ #o_RXCHANISALIGNED=,
+ #o_RXCHANREALIGN=,
+
+ # Receive Ports - RX Equalizer Ports
+ i_RXDFEAGCHOLD=0,
+ i_RXDFEAGCOVRDEN=0,
+ i_RXDFECM1EN=0,
+ i_RXDFELFHOLD=0,
+ i_RXDFELFOVRDEN=1,
+ i_RXDFELPMRESET=0,
+ i_RXDFETAP2HOLD=0,
+ i_RXDFETAP2OVRDEN=0,
+ i_RXDFETAP3HOLD=0,
+ i_RXDFETAP3OVRDEN=0,
+ i_RXDFETAP4HOLD=0,
+ i_RXDFETAP4OVRDEN=0,
+ i_RXDFETAP5HOLD=0,
+ i_RXDFETAP5OVRDEN=0,
+ i_RXDFEUTHOLD=0,
+ i_RXDFEUTOVRDEN=0,
+ i_RXDFEVPHOLD=0,
+ i_RXDFEVPOVRDEN=0,
+ i_RXDFEVSEN=0,
+ i_RXLPMLFKLOVRDEN=0,
+ #o_RXMONITOROUT=,
+ i_RXMONITORSEL=0b00,
+ i_RXOSHOLD=0,
+ i_RXOSOVRDEN=0,
+
+ # Receive Ports - RX Equilizer Ports
+ i_RXLPMHFHOLD=0,
+ i_RXLPMHFOVRDEN=0,
+ i_RXLPMLFHOLD=0,
+
+ # Receive Ports - RX Fabric ClocK Output Control Ports
+ #o_RXRATEDONE=,
+
+ # Receive Ports - RX Fabric Output Control Ports
+ o_RXOUTCLK=self.rxoutclk,
+ #o_RXOUTCLKFABRIC=,
+ #o_RXOUTCLKPCS=,
+ i_RXOUTCLKSEL=0b010,
+
+ # Receive Ports - RX Gearbox Ports
+ #o_RXDATAVALID=,
+ #o_RXHEADER=,
+ #o_RXHEADERVALID=,
+ #o_RXSTARTOFSEQ=,
+
+ # Receive Ports - RX Gearbox Ports
+ i_RXGEARBOXSLIP=0,
+
+ # Receive Ports - RX Initialization and Reset Ports
+ i_GTRXRESET=self.gtrxreset,
+ i_RXOOBRESET=0,
+ i_RXPCSRESET=0,
+ i_RXPMARESET=self.pmarxreset,
+
+ # Receive Ports - RX Margin Analysis ports
+ i_RXLPMEN=0,
+
+ # Receive Ports - RX OOB Signaling ports
+ #o_RXCOMSASDET=,
+ o_RXCOMWAKEDET=rxcomwakedet,
+
+ # Receive Ports - RX OOB Signaling ports
+ o_RXCOMINITDET=rxcominitdet,
+
+ # Receive Ports - RX OOB signalling Ports
+ o_RXELECIDLE=rxelecidle,
+ i_RXELECIDLEMODE=0b00,
+
+ # Receive Ports - RX Polarity Control Ports
+ i_RXPOLARITY=0,
+
+ # Receive Ports - RX gearbox ports
+ i_RXSLIDE=0,
+
+ # Receive Ports - RX8B/10B Decoder Ports
+ #o_RXCHARISCOMMA=,
+ o_RXCHARISK=self.rxcharisk,
+
+ # Receive Ports - Rx Channel Bonding Ports
+ i_RXCHBONDI=0,
+
+ # Receive Ports -RX Initialization and Reset Ports
+ o_RXRESETDONE=rxresetdone,
+
+ # Rx AFE Ports
+ i_RXQPIEN=0,
+ #o_RXQPISENN=,
+ #o_RXQPISENP=,
+
+ # TX Buffer Bypass Ports
+ i_TXPHDLYTSTCLK=0,
+
+ # TX Configurable Driver Ports
+ i_TXPOSTCURSOR=0,
+ i_TXPOSTCURSORINV=0,
+ i_TXPRECURSOR=0,
+ i_TXPRECURSORINV=0,
+ i_TXQPIBIASEN=0,
+ i_TXQPISTRONGPDOWN=0,
+ i_TXQPIWEAKPUP=0,
+
+ # TX Initialization and Reset Ports
+ i_CFGRESET=0,
+ i_GTTXRESET=self.gttxreset,
+ #o_PCSRSVDOUT=,
+ i_TXUSERRDY=txuserrdy,
+
+ # Transceiver Reset Mode Operation
+ i_GTRESETSEL=0,
+ i_RESETOVRD=0,
+
+ # Transmit Ports - 8b10b Encoder Control Ports
+ i_TXCHARDISPMODE=0,
+ i_TXCHARDISPVAL=0,
+
+ # Transmit Ports - FPGA TX Interface Ports
+ i_TXUSRCLK=self.txusrclk,
+ i_TXUSRCLK2=self.txusrclk2,
+
+ # Transmit Ports - PCI Express Ports
+ i_TXELECIDLE=txelecidle,
+ i_TXMARGIN=0,
+ i_TXRATE=txrate,
+ i_TXSWING=0,
+
+ # Transmit Ports - Pattern Generator Ports
+ i_TXPRBSFORCEERR=0,
+
+ # Transmit Ports - TX Buffer Bypass Ports
+ i_TXDLYBYPASS=1,
+ i_TXDLYEN=0,
+ i_TXDLYHOLD=0,
+ i_TXDLYOVRDEN=0,
+ i_TXDLYSRESET=0,
+ #o_TXDLYSRESETDONE=,
+ i_TXDLYUPDOWN=0,
+ i_TXPHALIGN=0,
+ #o_TXPHALIGNDONE=txphaligndone,
+ i_TXPHALIGNEN=0,
+ i_TXPHDLYPD=0,
+ i_TXPHDLYRESET=0,
+ i_TXPHINIT=0,
+ #o_TXPHINITDONE=,
+ i_TXPHOVRDEN=0,
+
+ # Transmit Ports - TX Buffer Ports
+ #o_TXBUFSTATUS=,
+
+ # Transmit Ports - TX Configurable Driver Ports
+ i_TXBUFDIFFCTRL=0b100,
+ i_TXDEEMPH=0,
+ i_TXDIFFCTRL=0b1000,
+ i_TXDIFFPD=0,
+ i_TXINHIBIT=0,
+ i_TXMAINCURSOR=0,
+ i_TXPISOPD=0,
+
+ # Transmit Ports - TX Data Path interface
+ i_TXDATA=self.txdata,
+
+ # Transmit Ports - TX Driver and OOB signaling
+ o_GTXTXP=pads.txp,
+ o_GTXTXN=pads.txn,
+
+ # Transmit Ports - TX Fabric Clock Output Control Ports
+ o_TXOUTCLK=self.txoutclk,
+ #o_TXOUTCLKFABRIC=,
+ #o_TXOUTCLKPCS=,
+ i_TXOUTCLKSEL=0b11, #??
+ #o_TXRATEDONE=,
+ # Transmit Ports - TX Gearbox Ports
+ i_TXCHARISK=self.txcharisk,
+ #o_TXGEARBOXREADY=,
+ i_TXHEADER=0,
+ i_TXSEQUENCE=0,
+ i_TXSTARTSEQ=0,
+
+ # Transmit Ports - TX Initialization and Reset Ports
+ i_TXPCSRESET=0,
+ i_TXPMARESET=0,
+ o_TXRESETDONE=txresetdone,
+
+ # Transmit Ports - TX OOB signalling Ports
+ o_TXCOMFINISH=txcomfinish,
+ i_TXCOMINIT=txcominit,
+ i_TXCOMSAS=0,
+ i_TXCOMWAKE=txcomwake,
+ i_TXPDELECIDLEMODE=0,
+
+ # Transmit Ports - TX Polarity Control Ports
+ i_TXPOLARITY=0,
+
+ # Transmit Ports - TX Receiver Detection Ports
+ i_TXDETECTRX=0,
+
+ # Transmit Ports - TX8b/10b Encoder Ports
+ i_TX8B10BBYPASS=0,
+
+ # Transmit Ports - pattern Generator Ports
+ i_TXPRBSSEL=0,
+
+ # Tx Configurable Driver Ports
+ #o_TXQPISENN=,
+ #o_TXQPISENP=,
+
+ **gtxe2_channel_parameters
+ )
--- /dev/null
+MSCDIR = ../../
+PYTHON = python3
+
+CMD = PYTHONPATH=$(MSCDIR) $(PYTHON)
+
+CC=gcc
+CFLAGS =-Wall -O0
+
+phy_datapath_tb:
+ $(CMD) phy_datapath_tb.py
+
+crc_tb:
+ $(CC) $(CFLAGS) $(INC) -o crc crc.c
+ $(CMD) crc_tb.py
+
+scrambler_tb:
+ $(CC) $(CFLAGS) $(INC) -o scrambler scrambler.c
+ $(CMD) scrambler_tb.py
+
+cont_tb:
+ $(CMD) cont_tb.py
+
+link_tb:
+ $(CMD) link_tb.py
+
+command_tb:
+ $(CMD) command_tb.py
+
+bist_tb:
+ $(CMD) bist_tb.py
+
+clean:
+ rm crc scrambler *.vcd
--- /dev/null
+from litesata.common import *
+from litesata import LiteSATA
+from litesata.frontend.bist import LiteSATABISTGenerator, LiteSATABISTChecker
+
+from litesata.test.hdd import *
+from litesata.test.common import *
+
+class TB(Module):
+ def __init__(self):
+ self.hdd = HDD(
+ link_debug=False, link_random_level=0,
+ transport_debug=False, transport_loopback=False,
+ hdd_debug=True)
+ self.controller = LiteSATA(self.hdd.phy, with_crossbar=True)
+ self.generator = LiteSATABISTGenerator(self.controller.crossbar.get_port())
+ self.checker = LiteSATABISTChecker(self.controller.crossbar.get_port())
+
+ def gen_simulation(self, selfp):
+ hdd = self.hdd
+ hdd.malloc(0, 64)
+ selfp.generator.sector = 0
+ selfp.generator.count = 17
+ selfp.checker.sector = 0
+ selfp.checker.count = 17
+ while True:
+ selfp.generator.start = 1
+ yield
+ selfp.generator.start = 0
+ yield
+ while selfp.generator.done == 0:
+ yield
+ selfp.checker.start = 1
+ yield
+ selfp.checker.start = 0
+ yield
+ while selfp.checker.done == 0:
+ yield
+ print("errors {}".format(selfp.checker.errors))
+ selfp.generator.sector += 1
+ selfp.generator.count = max((selfp.generator.count + 1)%8, 1)
+ selfp.checker.sector += 1
+ selfp.checker.count = max((selfp.checker.count + 1)%8, 1)
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
--- /dev/null
+from litesata.common import *
+from litesata.core import LiteSATACore
+
+from litesata.test.hdd import *
+from litesata.test.common import *
+
+class CommandTXPacket(list):
+ def __init__(self, write=0, read=0, sector=0, count=0, data=[]):
+ self.ongoing = False
+ self.done = False
+ self.write = write
+ self.read = read
+ self.sector = sector
+ self.count = count
+ for d in data:
+ self.append(d)
+
+class CommandStreamer(PacketStreamer):
+ def __init__(self):
+ PacketStreamer.__init__(self, command_tx_description(32), CommandTXPacket)
+
+ def do_simulation(self, selfp):
+ PacketStreamer.do_simulation(self, selfp)
+ selfp.source.write = self.packet.write
+ selfp.source.read = self.packet.read
+ selfp.source.sector = self.packet.sector
+ selfp.source.count = self.packet.count
+
+class CommandRXPacket(list):
+ def __init__(self):
+ self.ongoing = False
+ self.done = False
+ self.write = 0
+ self.read = 0
+ self.success = 0
+ self.failed = 0
+
+class CommandLogger(PacketLogger):
+ def __init__(self):
+ PacketLogger.__init__(self, command_rx_description(32), CommandRXPacket)
+
+ def do_simulation(self, selfp):
+ selfp.sink.ack = 1
+ if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+ self.packet = CommandRXPacket()
+ self.packet.write = selfp.sink.write
+ self.packet.read = selfp.sink.read
+ self.packet.sucess = selfp.sink.success
+ self.packet.failed = selfp.sink.failed
+ self.packet.append(selfp.sink.data)
+ elif selfp.sink.stb:
+ self.packet.append(selfp.sink.data)
+ if selfp.sink.stb == 1 and selfp.sink.eop == 1:
+ self.packet.done = True
+
+class TB(Module):
+ def __init__(self):
+ self.hdd = HDD(
+ link_debug=False, link_random_level=50,
+ transport_debug=False, transport_loopback=False,
+ hdd_debug=True)
+ self.core = LiteSATACore(self.hdd.phy)
+
+ self.streamer = CommandStreamer()
+ self.streamer_randomizer = Randomizer(command_tx_description(32), level=50)
+
+ self.logger = CommandLogger()
+ self.logger_randomizer = Randomizer(command_rx_description(32), level=50)
+
+ self.pipeline = Pipeline(
+ self.streamer,
+ self.streamer_randomizer,
+ self.core,
+ self.logger_randomizer,
+ self.logger
+ )
+
+ def gen_simulation(self, selfp):
+ hdd = self.hdd
+ hdd.malloc(0, 64)
+ write_data = [i for i in range(sectors2dwords(2))]
+ write_len = dwords2sectors(len(write_data))
+ write_packet = CommandTXPacket(write=1, sector=2, count=write_len, data=write_data)
+ yield from self.streamer.send(write_packet)
+ yield from self.logger.receive()
+ read_packet = CommandTXPacket(read=1, sector=2, count=write_len)
+ yield from self.streamer.send(read_packet)
+ yield from self.logger.receive()
+ read_data = self.logger.packet
+
+ # check results
+ s, l, e = check(write_data, read_data)
+ print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
--- /dev/null
+import random, copy
+
+from migen.sim.generic import run_simulation
+
+from litesata.common import *
+
+def seed_to_data(seed, random=True):
+ if random:
+ return (seed * 0x31415979 + 1) & 0xffffffff
+ else:
+ return seed
+
+def check(p1, p2):
+ p1 = copy.deepcopy(p1)
+ p2 = copy.deepcopy(p2)
+ if isinstance(p1, int):
+ return 0, 1, int(p1 != p2)
+ else:
+ if len(p1) >= len(p2):
+ ref, res = p1, p2
+ else:
+ ref, res = p2, p1
+ shift = 0
+ while((ref[0] != res[0]) and (len(res)>1)):
+ res.pop(0)
+ shift += 1
+ length = min(len(ref), len(res))
+ errors = 0
+ for i in range(length):
+ if ref.pop(0) != res.pop(0):
+ errors += 1
+ return shift, length, errors
+
+def randn(max_n):
+ return random.randint(0, max_n-1)
+
+class PacketStreamer(Module):
+ def __init__(self, description, packet_class):
+ self.source = Source(description)
+ ###
+ self.packets = []
+ self.packet = packet_class()
+ self.packet.done = 1
+
+ self.source_data = 0
+
+ def send(self, packet, blocking=True):
+ packet = copy.deepcopy(packet)
+ self.packets.append(packet)
+ if blocking:
+ while packet.done == 0:
+ yield
+
+ def do_simulation(self, selfp):
+ if len(self.packets) and self.packet.done:
+ self.packet = self.packets.pop(0)
+ if not self.packet.ongoing and not self.packet.done:
+ selfp.source.stb = 1
+ if self.source.description.packetized:
+ selfp.source.sop = 1
+ if len(self.packet) > 0:
+ self.source_data = self.packet.pop(0)
+ if hasattr(selfp.source, "data"):
+ selfp.source.data = self.source_data
+ else:
+ selfp.source.d = self.source_data
+ self.packet.ongoing = True
+ elif selfp.source.stb == 1 and selfp.source.ack == 1:
+ if self.source.description.packetized:
+ selfp.source.sop = 0
+ selfp.source.eop = (len(self.packet) == 1)
+ if len(self.packet) > 0:
+ selfp.source.stb = 1
+ self.source_data = self.packet.pop(0)
+ if hasattr(selfp.source, "data"):
+ selfp.source.data = self.source_data
+ else:
+ selfp.source.d = self.source_data
+ else:
+ self.packet.done = 1
+ selfp.source.stb = 0
+
+class PacketLogger(Module):
+ def __init__(self, description, packet_class):
+ self.sink = Sink(description)
+ ###
+ self.packet_class = packet_class
+ self.packet = packet_class()
+
+ def receive(self, length=None):
+ self.packet.done = 0
+ if length is None:
+ while self.packet.done == 0:
+ yield
+ else:
+ while length > len(self.packet):
+ yield
+
+ def do_simulation(self, selfp):
+ selfp.sink.ack = 1
+ if self.sink.description.packetized:
+ if selfp.sink.stb == 1 and selfp.sink.sop == 1:
+ self.packet = self.packet_class()
+ if selfp.sink.stb:
+ if hasattr(selfp.sink, "data"):
+ self.packet.append(selfp.sink.data)
+ else:
+ self.packet.append(selfp.sink.d)
+ if self.sink.description.packetized:
+ if selfp.sink.stb == 1 and selfp.sink.eop == 1:
+ self.packet.done = True
+
+class Randomizer(Module):
+ def __init__(self, description, level=0):
+ self.level = level
+
+ self.sink = Sink(description)
+ self.source = Source(description)
+
+ self.run = Signal()
+
+ self.comb += \
+ If(self.run,
+ Record.connect(self.sink, self.source)
+ ).Else(
+ self.source.stb.eq(0),
+ self.sink.ack.eq(0),
+ )
+
+ def do_simulation(self, selfp):
+ n = randn(100)
+ if n < self.level:
+ selfp.run = 0
+ else:
+ selfp.run = 1
--- /dev/null
+from litesata.common import *
+from litesata.core.link.cont import LiteSATACONTInserter, LiteSATACONTRemover
+
+from litesata.test.common import *
+
+class ContPacket(list):
+ def __init__(self, data=[]):
+ self.ongoing = False
+ self.done = False
+ for d in data:
+ self.append(d)
+
+class ContStreamer(PacketStreamer):
+ def __init__(self):
+ PacketStreamer.__init__(self, phy_description(32), ContPacket)
+
+ def do_simulation(self, selfp):
+ PacketStreamer.do_simulation(self, selfp)
+ selfp.source.charisk = 0
+ # Note: for simplicity we generate charisk by detecting
+ # primitives in data
+ for k, v in primitives.items():
+ try:
+ if self.source_data == v:
+ selfp.source.charisk = 0b0001
+ except:
+ pass
+
+class ContLogger(PacketLogger):
+ def __init__(self):
+ PacketLogger.__init__(self, phy_description(32), ContPacket)
+
+class TB(Module):
+ def __init__(self):
+ self.streamer = ContStreamer()
+ self.streamer_randomizer = Randomizer(phy_description(32), level=50)
+ self.inserter = LiteSATACONTInserter(phy_description(32))
+ self.remover = LiteSATACONTRemover(phy_description(32))
+ self.logger_randomizer = Randomizer(phy_description(32), level=50)
+ self.logger = ContLogger()
+
+ self.pipeline = Pipeline(
+ self.streamer,
+ self.streamer_randomizer,
+ self.inserter,
+ self.remover,
+ self.logger_randomizer,
+ self.logger
+ )
+
+ def gen_simulation(self, selfp):
+ test_packet = ContPacket([
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["ALIGN"],
+ primitives["ALIGN"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ #primitives["SYNC"],
+ 0x00000000,
+ 0x00000001,
+ 0x00000002,
+ 0x00000003,
+ 0x00000004,
+ 0x00000005,
+ 0x00000006,
+ 0x00000007,
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["ALIGN"],
+ primitives["ALIGN"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"],
+ primitives["SYNC"]]*4
+ )
+ streamer_packet = ContPacket(test_packet)
+ yield from self.streamer.send(streamer_packet)
+ yield from self.logger.receive(len(test_packet))
+ #for d in self.logger.packet:
+ # print("%08x" %d)
+
+ # check results
+ s, l, e = check(streamer_packet, self.logger.packet)
+ print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=1024, vcd_name="my.vcd", keep_files=True)
--- /dev/null
+// Adapted from SATA specification
+/****************************************************************************/
+/* */
+/* crc.c */
+/* */
+/* This sample code reads standard in for a sequence of 32 bit values */
+/* formatted in hexadecimal with a leading "0x" (e.g. 0xDEADBEEF). The */
+/* code calculates the Serial ATA CRC for the input data stream. The */
+/* generator polynomial used is: */
+/* 32 26 23 22 16 12 11 10 8 7 5 4 2 */
+/* G(x) = x + x + x + x + x + x + x + x + x + x + x + x + x + x + 1 */
+/* */
+/* This sample code uses a parallel implementation of the CRC calculation */
+/* circuit that is suitable for implementation in hardware. A block */
+/* diagram of the circuit being emulated is shown below. */
+/* */
+/* +---+ +---+ +---+ */
+/* Data_In --------->| | | | | R | */
+/* | + |--------->| * |--------->| e |----+ */
+/* +---->| | | | | g | | */
+/* | +---+ +---+ +---+ | */
+/* | | */
+/* | | */
+/* +--------------------------------------------+ */
+/* */
+/* The CRC value is initialized to 0x52325032 as defined in the Serial ATA */
+/* specification. */
+/* */
+/****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+ int i;
+ unsigned int data_count;
+ unsigned int crc;
+ unsigned int data_in;
+ unsigned char crc_bit[32];
+ unsigned char new_bit[32];
+
+ crc = 0x52325032;
+ data_count = 0;
+
+ while((scanf(" 0x%8x", &data_in) == 1) && (!scanf("exit"))) {
+ data_count++;
+ /* Add the data_in value to the current value of the CRC held in the */
+ /* "register". The addition is performed modulo two (XOR). */
+ crc ^= data_in;
+ /* Expand the value of the CRC held in the register to 32 individual */
+ /* bits for easy manipulation. */
+ for (i = 0; i < 32; ++i) {
+ crc_bit[i] = (crc >> i) & 0x01;
+ }
+ /* The following 32 assignments perform the function of the box */
+ /* labeled "*" in the block diagram above. The new_bit array is a */
+ /* temporary holding place for the new CRC value being calculated. */
+ /* Note that there are lots of shared terms in the assignments below. */
+ new_bit[31] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^
+ crc_bit[23] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[5];
+ new_bit[30] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^
+ crc_bit[22] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[4];
+ new_bit[29] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^
+ crc_bit[22] ^ crc_bit[21] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[3];
+ new_bit[28] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^
+ crc_bit[21] ^ crc_bit[20] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[2];
+ new_bit[27] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^
+ crc_bit[20] ^ crc_bit[19] ^ crc_bit[11] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[1];
+ new_bit[26] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^
+ crc_bit[20] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[10] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
+ crc_bit[0];
+ new_bit[25] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^ crc_bit[18] ^
+ crc_bit[17] ^ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[3] ^ crc_bit[2];
+ new_bit[24] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[17] ^
+ crc_bit[16] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[2] ^ crc_bit[1];
+ new_bit[23] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^
+ crc_bit[16] ^ crc_bit[15] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
+ new_bit[22] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[19] ^
+ crc_bit[18] ^ crc_bit[16] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[9] ^ crc_bit[0];
+ new_bit[21] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[18] ^
+ crc_bit[17] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[5];
+ new_bit[20] = crc_bit[30] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[17] ^
+ crc_bit[16] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[4];
+ new_bit[19] = crc_bit[29] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[20] ^ crc_bit[16] ^
+ crc_bit[15] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3];
+ new_bit[18] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[21] ^ crc_bit[19] ^
+ crc_bit[15] ^ crc_bit[14] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2];
+ new_bit[17] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[20] ^
+ crc_bit[18] ^ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[1];
+ new_bit[16] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[19] ^
+ crc_bit[17] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[8] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[0];
+ new_bit[15] = crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[18] ^ crc_bit[16] ^
+ crc_bit[15] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[4] ^
+ crc_bit[3];
+ new_bit[14] = crc_bit[29] ^ crc_bit[26] ^ crc_bit[23] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[17] ^ crc_bit[15] ^
+ crc_bit[14] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[4] ^ crc_bit[3] ^
+ crc_bit[2];
+ new_bit[13] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[16] ^
+ crc_bit[14] ^ crc_bit[13] ^ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[3] ^
+ crc_bit[2] ^ crc_bit[1];
+ new_bit[12] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[18] ^ crc_bit[17] ^
+ crc_bit[15] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^
+ crc_bit[2] ^ crc_bit[1] ^ crc_bit[0];
+ new_bit[11] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[27] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^
+ crc_bit[17] ^ crc_bit[16] ^ crc_bit[15] ^ crc_bit[14] ^ crc_bit[12] ^ crc_bit[9] ^ crc_bit[4] ^
+ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
+ new_bit[10] = crc_bit[31] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[19] ^ crc_bit[16] ^ crc_bit[14] ^
+ crc_bit[13] ^ crc_bit[9] ^ crc_bit[5] ^ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
+ new_bit[9] = crc_bit[29] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[18] ^ crc_bit[13] ^ crc_bit[12] ^ crc_bit[11] ^
+ crc_bit[9] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^ crc_bit[1];
+ new_bit[8] = crc_bit[31] ^ crc_bit[28] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[17] ^ crc_bit[12] ^ crc_bit[11] ^
+ crc_bit[10] ^ crc_bit[8] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^ crc_bit[0];
+ new_bit[7] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[23] ^ crc_bit[22] ^ crc_bit[21] ^
+ crc_bit[16] ^ crc_bit[15] ^ crc_bit[10] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[5] ^ crc_bit[3] ^
+ crc_bit[2] ^ crc_bit[0];
+ new_bit[6] = crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[22] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[14] ^
+ crc_bit[11] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[2] ^
+ crc_bit[1];
+ new_bit[5] = crc_bit[29] ^ crc_bit[28] ^ crc_bit[24] ^ crc_bit[21] ^ crc_bit[20] ^ crc_bit[19] ^ crc_bit[13] ^
+ crc_bit[10] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[5] ^ crc_bit[4] ^ crc_bit[3] ^ crc_bit[1] ^
+ crc_bit[0];
+ new_bit[4] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[25] ^ crc_bit[24] ^ crc_bit[20] ^ crc_bit[19] ^
+ crc_bit[18] ^ crc_bit[15] ^ crc_bit[12] ^ crc_bit[11] ^ crc_bit[8] ^ crc_bit[6] ^ crc_bit[4] ^
+ crc_bit[3] ^ crc_bit[2] ^ crc_bit[0];
+ new_bit[3] = crc_bit[31] ^ crc_bit[27] ^ crc_bit[25] ^ crc_bit[19] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[15] ^
+ crc_bit[14] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[3] ^ crc_bit[2] ^
+ crc_bit[1];
+ new_bit[2] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[26] ^ crc_bit[24] ^ crc_bit[18] ^ crc_bit[17] ^ crc_bit[16] ^
+ crc_bit[14] ^ crc_bit[13] ^ crc_bit[9] ^ crc_bit[8] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[2] ^
+ crc_bit[1] ^ crc_bit[0];
+ new_bit[1] = crc_bit[28] ^ crc_bit[27] ^ crc_bit[24] ^ crc_bit[17] ^ crc_bit[16] ^ crc_bit[13] ^ crc_bit[12] ^
+ crc_bit[11] ^ crc_bit[9] ^ crc_bit[7] ^ crc_bit[6] ^ crc_bit[1] ^ crc_bit[0];
+ new_bit[0] = crc_bit[31] ^ crc_bit[30] ^ crc_bit[29] ^ crc_bit[28] ^ crc_bit[26] ^ crc_bit[25] ^ crc_bit[24] ^
+ crc_bit[16] ^ crc_bit[12] ^ crc_bit[10] ^ crc_bit[9] ^ crc_bit[6] ^ crc_bit[0];
+
+ /* The new CRC value has been calculated as individual bits in the */
+ /* new_bit array. Re-assembled it into a 32 bit value and "clock" it */
+ /* into the "register". */
+ crc = 0;
+ for (i = 31; i >= 0; --i) {
+ crc = crc << 1;
+ crc |= new_bit[i];
+ }
+ }
+ printf("%08x\n", crc);
+ return 0;
+}
--- /dev/null
+import subprocess
+
+from litesata.common import *
+from litesata.core.link.crc import *
+
+from litesata.test.common import *
+
+class TB(Module):
+ def __init__(self, length, random):
+ self.crc = LiteSATACRC()
+ self.length = length
+ self.random = random
+
+ def get_c_crc(self, datas):
+ stdin = ""
+ for data in datas:
+ stdin += "0x%08x " %data
+ stdin += "exit"
+ with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+ process.stdin.write(stdin.encode("ASCII"))
+ out, err = process.communicate()
+ return int(out.decode("ASCII"), 16)
+
+ def gen_simulation(self, selfp):
+ # init CRC
+ selfp.crc.d = 0
+ selfp.crc.ce = 1
+ selfp.crc.reset = 1
+ yield
+ selfp.crc.reset = 0
+
+ # feed CRC with datas
+ datas = []
+ for i in range(self.length):
+ data = seed_to_data(i, self.random)
+ datas.append(data)
+ selfp.crc.d = data
+ yield
+
+ # log results
+ yield
+ sim_crc = selfp.crc.value
+
+ # stop
+ selfp.crc.ce = 0
+ for i in range(32):
+ yield
+
+ # get C core reference
+ c_crc = self.get_c_crc(datas)
+
+ # check results
+ s, l, e = check(c_crc, sim_crc)
+ print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+ from migen.sim.generic import run_simulation
+ length = 8192
+ run_simulation(TB(length, True), ncycles=length+100, vcd_name="my.vcd")
--- /dev/null
+import subprocess
+import math
+
+from litesata.common import *
+from litesata.test.common import *
+
+def print_with_prefix(s, prefix=""):
+ if not isinstance(s, str):
+ s = s.__repr__()
+ s = s.split("\n")
+ for l in s:
+ print(prefix + l)
+
+# PHY Layer model
+class PHYDword:
+ def __init__(self, dat=0):
+ self.dat = dat
+ self.start = 1
+ self.done = 0
+
+class PHYSource(Module):
+ def __init__(self):
+ self.source = Source(phy_description(32))
+ ###
+ self.dword = PHYDword()
+
+ def send(self, dword):
+ self.dword = dword
+
+ def do_simulation(self, selfp):
+ selfp.source.stb = 1
+ selfp.source.charisk = 0b0000
+ for k, v in primitives.items():
+ if v == self.dword.dat:
+ selfp.source.charisk = 0b0001
+ selfp.source.data = self.dword.dat
+
+class PHYSink(Module):
+ def __init__(self):
+ self.sink = Sink(phy_description(32))
+ ###
+ self.dword = PHYDword()
+
+ def receive(self):
+ self.dword.done = 0
+ while self.dword.done == 0:
+ yield
+
+ def do_simulation(self, selfp):
+ self.dword.done = 0
+ selfp.sink.ack = 1
+ if selfp.sink.stb == 1:
+ self.dword.done = 1
+ self.dword.dat = selfp.sink.data
+
+class PHYLayer(Module):
+ def __init__(self):
+
+ self.rx = PHYSink()
+ self.tx = PHYSource()
+
+ self.source = self.tx.source
+ self.sink = self.rx.sink
+
+ def send(self, dword):
+ packet = PHYDword(dword)
+ self.tx.send(packet)
+
+ def receive(self):
+ yield from self.rx.receive()
+
+ def __repr__(self):
+ receiving = "%08x " %self.rx.dword.dat
+ receiving += decode_primitive(self.rx.dword.dat)
+ receiving += " "*(16-len(receiving))
+
+ sending = "%08x " %self.tx.dword.dat
+ sending += decode_primitive(self.tx.dword.dat)
+ sending += " "*(16-len(sending))
+
+ return receiving + sending
+
+# Link Layer model
+def print_link(s):
+ print_with_prefix(s, "[LNK]: ")
+
+def import_scrambler_datas():
+ with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+ process.stdin.write("0x10000".encode("ASCII"))
+ out, err = process.communicate()
+ return [int(e, 16) for e in out.decode("utf-8").split("\n")[:-1]]
+
+class LinkPacket(list):
+ def __init__(self, init=[]):
+ self.ongoing = False
+ self.done = False
+ self.scrambled_datas = import_scrambler_datas()
+ for dword in init:
+ self.append(dword)
+
+class LinkRXPacket(LinkPacket):
+ def descramble(self):
+ for i in range(len(self)):
+ self[i] = self[i] ^ self.scrambled_datas[i]
+
+ def check_crc(self):
+ stdin = ""
+ for v in self[:-1]:
+ stdin += "0x%08x " %v
+ stdin += "exit"
+ with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+ process.stdin.write(stdin.encode("ASCII"))
+ out, err = process.communicate()
+ crc = int(out.decode("ASCII"), 16)
+ r = (self[-1] == crc)
+ self.pop()
+ return r
+
+ def decode(self):
+ self.descramble()
+ return self.check_crc()
+
+class LinkTXPacket(LinkPacket):
+ def insert_crc(self):
+ stdin = ""
+ for v in self:
+ stdin += "0x%08x " %v
+ stdin += "exit"
+ with subprocess.Popen("./crc", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+ process.stdin.write(stdin.encode("ASCII"))
+ out, err = process.communicate()
+ crc = int(out.decode("ASCII"), 16)
+ self.append(crc)
+
+ def scramble(self):
+ for i in range(len(self)):
+ self[i] = self[i] ^ self.scrambled_datas[i]
+
+ def encode(self):
+ self.insert_crc()
+ self.scramble()
+
+class LinkLayer(Module):
+ def __init__(self, phy, debug=False, random_level=0):
+ self.phy = phy
+ self.debug = debug
+ self.random_level = random_level
+ self.tx_packets = []
+ self.tx_packet = LinkTXPacket()
+ self.rx_packet = LinkRXPacket()
+
+ self.rx_cont = False
+ self.rx_last = 0
+ self.tx_cont = False
+ self.tx_cont_nb = -1
+ self.tx_lasts = [0, 0, 0]
+
+ self.scrambled_datas = import_scrambler_datas()
+
+ self.transport_callback = None
+
+ self.send_state = ""
+ self.send_states = ["RDY", "SOF", "DATA", "EOF", "WTRM"]
+
+ def set_transport_callback(self, callback):
+ self.transport_callback = callback
+
+ def send(self, dword):
+ if self.send_state == "RDY":
+ self.phy.send(primitives["X_RDY"])
+ if dword == primitives["R_RDY"]:
+ self.send_state = "SOF"
+ elif self.send_state == "SOF":
+ self.phy.send(primitives["SOF"])
+ self.send_state = "DATA"
+ elif self.send_state == "DATA":
+ if dword == primitives["HOLD"]:
+ self.phy.send(primitives["HOLDA"])
+ else:
+ self.phy.send(self.tx_packet.pop(0))
+ if len(self.tx_packet) == 0:
+ self.send_state = "EOF"
+ elif self.send_state == "EOF":
+ self.phy.send(primitives["EOF"])
+ self.send_state = "WTRM"
+ elif self.send_state == "WTRM":
+ self.phy.send(primitives["WTRM"])
+ if dword == primitives["R_OK"]:
+ self.tx_packet.done = True
+ elif dword == primitives["R_ERR"]:
+ self.tx_packet.done = True
+ if self.tx_packet.done:
+ self.phy.send(primitives["SYNC"])
+
+ def insert_cont(self):
+ self.tx_lasts.pop(0)
+ self.tx_lasts.append(self.phy.tx.dword.dat)
+ self.tx_cont = True
+ for i in range(3):
+ if not is_primitive(self.tx_lasts[i]):
+ self.tx_cont = False
+ if self.tx_lasts[i] != self.tx_lasts[0]:
+ self.tx_cont = False
+ if self.tx_cont:
+ if self.tx_cont_nb == 0:
+ self.phy.send(primitives["CONT"])
+ else:
+ self.phy.send(self.scrambled_datas[self.tx_cont_nb])
+ self.tx_cont_nb += 1
+ else:
+ self.tx_cont_nb = 0
+
+ def remove_cont(self, dword):
+ if dword == primitives["HOLD"]:
+ if self.rx_cont:
+ self.tx_lasts = [0, 0, 0]
+ if dword == primitives["CONT"]:
+ self.rx_cont = True
+ elif is_primitive(dword):
+ self.rx_last = dword
+ self.rx_cont = False
+ if self.rx_cont:
+ dword = self.rx_last
+ return dword
+
+ def callback(self, dword):
+ if dword == primitives["X_RDY"]:
+ self.phy.send(primitives["R_RDY"])
+ elif dword == primitives["WTRM"]:
+ self.phy.send(primitives["R_OK"])
+ if self.rx_packet.ongoing:
+ self.rx_packet.decode()
+ if self.transport_callback is not None:
+ self.transport_callback(self.rx_packet)
+ self.rx_packet.ongoing = False
+ elif dword == primitives["HOLD"]:
+ self.phy.send(primitives["HOLDA"])
+ elif dword == primitives["EOF"]:
+ pass
+ elif self.rx_packet.ongoing:
+ if dword != primitives["HOLD"]:
+ n = randn(100)
+ if n < self.random_level:
+ self.phy.send(primitives["HOLD"])
+ else:
+ self.phy.send(primitives["R_IP"])
+ if not is_primitive(dword):
+ self.rx_packet.append(dword)
+ elif dword == primitives["SOF"]:
+ self.rx_packet = LinkRXPacket()
+ self.rx_packet.ongoing = True
+
+ def gen_simulation(self, selfp):
+ self.tx_packet.done = True
+ self.phy.send(primitives["SYNC"])
+ while True:
+ yield from self.phy.receive()
+ if self.debug:
+ print_link(self.phy)
+ self.phy.send(primitives["SYNC"])
+ rx_dword = self.phy.rx.dword.dat
+ rx_dword = self.remove_cont(rx_dword)
+ if len(self.tx_packets) != 0:
+ if self.tx_packet.done:
+ self.tx_packet = self.tx_packets.pop(0)
+ self.tx_packet.encode()
+ self.send_state = "RDY"
+ if not self.tx_packet.done:
+ self.send(rx_dword)
+ else:
+ self.callback(rx_dword)
+ self.insert_cont()
+
+# Transport Layer model
+def print_transport(s):
+ print_with_prefix(s, "[TRN]: ")
+
+def get_field_data(field, packet):
+ return (packet[field.dword] >> field.offset) & (2**field.width-1)
+
+class FIS:
+ def __init__(self, packet, description, direction="H2D"):
+ self.packet = packet
+ self.description = description
+ self.direction = direction
+ self.decode()
+
+ def decode(self):
+ for k, v in self.description.items():
+ setattr(self, k, get_field_data(v, self.packet))
+
+ def encode(self):
+ for k, v in self.description.items():
+ self.packet[v.dword] |= (getattr(self, k) << v.offset)
+
+ def __repr__(self):
+ if self.direction == "H2D":
+ r = ">>>>>>>>\n"
+ else:
+ r = "<<<<<<<<\n"
+ for k in sorted(self.description.keys()):
+ r += k + " : 0x%x" %getattr(self,k) + "\n"
+ return r
+
+class FIS_REG_H2D(FIS):
+ def __init__(self, packet=[0]*fis_reg_h2d_cmd_len):
+ FIS.__init__(self, packet, fis_reg_h2d_layout)
+ self.type = fis_types["REG_H2D"]
+ self.direction = "H2D"
+
+ def __repr__(self):
+ r = "FIS_REG_H2D\n"
+ r += FIS.__repr__(self)
+ return r
+
+class FIS_REG_D2H(FIS):
+ def __init__(self, packet=[0]*fis_reg_d2h_cmd_len):
+ FIS.__init__(self, packet, fis_reg_d2h_layout)
+ self.type = fis_types["REG_D2H"]
+ self.direction = "D2H"
+
+ def __repr__(self):
+ r = "FIS_REG_D2H\n"
+ r += FIS.__repr__(self)
+ return r
+
+class FIS_DMA_ACTIVATE_D2H(FIS):
+ def __init__(self, packet=[0]*fis_dma_activate_d2h_cmd_len):
+ FIS.__init__(self, packet, fis_dma_activate_d2h_layout)
+ self.type = fis_types["DMA_ACTIVATE_D2H"]
+ self.direction = "D2H"
+
+ def __repr__(self):
+ r = "FIS_DMA_ACTIVATE_D2H\n"
+ r += FIS.__repr__(self)
+ return r
+
+class FIS_DATA(FIS):
+ def __init__(self, packet=[0], direction="H2D"):
+ FIS.__init__(self, packet, fis_data_layout, direction)
+ self.type = fis_types["DATA"]
+
+ def __repr__(self):
+ r = "FIS_DATA\n"
+ r += FIS.__repr__(self)
+ for data in self.packet[1:]:
+ r += "%08x\n" %data
+ return r
+
+class FIS_UNKNOWN(FIS):
+ def __init__(self, packet=[0], direction="H2D"):
+ FIS.__init__(self, packet, {}, direction)
+
+ def __repr__(self):
+ r = "UNKNOWN\n"
+ if self.direction == "H2D":
+ r += ">>>>>>>>\n"
+ else:
+ r += "<<<<<<<<\n"
+ for dword in self.packet:
+ r += "%08x\n" %dword
+ return r
+
+class TransportLayer(Module):
+ def __init__(self, link, debug=False, loopback=False):
+ self.link = link
+ self.debug = debug
+ self.loopback = loopback
+ self.link.set_transport_callback(self.callback)
+
+ def set_command_callback(self, callback):
+ self.command_callback = callback
+
+ def send(self, fis):
+ fis.encode()
+ packet = LinkTXPacket(fis.packet)
+ self.link.tx_packets.append(packet)
+ if self.debug and not self.loopback:
+ print_transport(fis)
+
+ def callback(self, packet):
+ fis_type = packet[0] & 0xff
+ if fis_type == fis_types["REG_H2D"]:
+ fis = FIS_REG_H2D(packet)
+ elif fis_type == fis_types["REG_D2H"]:
+ fis = FIS_REG_D2H(packet)
+ elif fis_type == fis_types["DMA_ACTIVATE_D2H"]:
+ fis = FIS_DMA_ACTIVATE_D2H(packet)
+ elif fis_type == fis_types["DATA"]:
+ fis = FIS_DATA(packet, direction="H2D")
+ else:
+ fis = FIS_UNKNOWN(packet, direction="H2D")
+ if self.debug:
+ print_transport(fis)
+ if self.loopback:
+ self.send(fis)
+ else:
+ self.command_callback(fis)
+
+# Command Layer model
+class CommandLayer(Module):
+ def __init__(self, transport):
+ self.transport = transport
+ self.transport.set_command_callback(self.callback)
+
+ self.hdd = None
+
+ def set_hdd(self, hdd):
+ self.hdd = hdd
+
+ def callback(self, fis):
+ resp = None
+ if isinstance(fis, FIS_REG_H2D):
+ if fis.command == regs["WRITE_DMA_EXT"]:
+ resp = self.hdd.write_dma_callback(fis)
+ elif fis.command == regs["READ_DMA_EXT"]:
+ resp = self.hdd.read_dma_callback(fis)
+ elif isinstance(fis, FIS_DATA):
+ resp = self.hdd.data_callback(fis)
+
+ if resp is not None:
+ for packet in resp:
+ self.transport.send(packet)
+
+# HDD model
+def print_hdd(s):
+ print_with_prefix(s, "[HDD]: ")
+
+class HDDMemRegion:
+ def __init__(self, base, count, sector_size):
+ self.base = base
+ self.count = count
+ self.data = [0]*(count*sector_size//4)
+
+class HDD(Module):
+ def __init__(self,
+ link_debug=False, link_random_level=0,
+ transport_debug=False, transport_loopback=False,
+ hdd_debug=False,
+ ):
+ ###
+ self.phy = PHYLayer()
+ self.link = LinkLayer(self.phy, link_debug, link_random_level)
+ self.transport = TransportLayer(self.link, transport_debug, transport_loopback)
+ self.command = CommandLayer(self.transport)
+
+ self.command.set_hdd(self)
+
+ self.debug = hdd_debug
+ self.mem = None
+ self.wr_sector = 0
+ self.wr_end_sector = 0
+ self.rd_sector = 0
+ self.rx_end_sector = 0
+
+ def malloc(self, sector, count):
+ if self.debug:
+ s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count)
+ s += " ({} KB)".format(count*logical_sector_size//1024)
+ print_hdd(s)
+ self.mem = HDDMemRegion(sector, count, logical_sector_size)
+
+ def write(self, sector, data):
+ n = math.ceil(dwords2sectors(len(data)))
+ if self.debug:
+ if n == 1:
+ s = "{}".format(sector)
+ else:
+ s = "{s} to {e}".format(s=sector, e=sector+n-1)
+ print_hdd("Writing sector " + s)
+ for i in range(len(data)):
+ offset = sectors2dwords(sector)
+ self.mem.data[offset+i] = data[i]
+
+ def read(self, sector, count):
+ if self.debug:
+ if count == 1:
+ s = "{}".format(sector)
+ else:
+ s = "{s} to {e}".format(s=sector, e=sector+count-1)
+ print_hdd("Reading sector " + s)
+ data = []
+ for i in range(sectors2dwords(count)):
+ data.append(self.mem.data[sectors2dwords(sector)+i])
+ return data
+
+ def write_dma_callback(self, fis):
+ self.wr_sector = fis.lba_lsb + (fis.lba_msb << 32)
+ self.wr_end_sector = self.wr_sector + fis.count
+ return [FIS_DMA_ACTIVATE_D2H()]
+
+ def read_dma_callback(self, fis):
+ self.rd_sector = fis.lba_lsb + (fis.lba_msb << 32)
+ self.rd_end_sector = self.rd_sector + fis.count
+ packets = []
+ while self.rd_sector != self.rd_end_sector:
+ count = min(self.rd_end_sector-self.rd_sector, (fis_max_dwords*4)//logical_sector_size)
+ packet = self.read(self.rd_sector, count)
+ packet.insert(0, 0)
+ packets.append(FIS_DATA(packet, direction="D2H"))
+ self.rd_sector += count
+ packets.append(FIS_REG_D2H())
+ return packets
+
+ def data_callback(self, fis):
+ self.write(self.wr_sector, fis.packet[1:])
+ self.wr_sector += dwords2sectors(len(fis.packet[1:]))
+ if self.wr_sector == self.wr_end_sector:
+ return [FIS_REG_D2H()]
+ else:
+ return [FIS_DMA_ACTIVATE_D2H()]
--- /dev/null
+from litesata.common import *
+from litesata.core.link import LiteSATALink
+
+from litesata.test.common import *
+from litesata.test.hdd import *
+
+class LinkStreamer(PacketStreamer):
+ def __init__(self):
+ PacketStreamer.__init__(self, link_description(32), LinkTXPacket)
+
+class LinkLogger(PacketLogger):
+ def __init__(self):
+ PacketLogger.__init__(self, link_description(32), LinkRXPacket)
+
+class TB(Module):
+ def __init__(self):
+ self.hdd = HDD(
+ link_debug=False, link_random_level=50,
+ transport_debug=False, transport_loopback=True)
+ self.link = InsertReset(LiteSATALink(self.hdd.phy))
+
+ self.streamer = LinkStreamer()
+ self.streamer_randomizer = Randomizer(link_description(32), level=50)
+
+ self.logger_randomizer = Randomizer(link_description(32), level=50)
+ self.logger = LinkLogger()
+
+ self.pipeline = Pipeline(
+ self.streamer,
+ self.streamer_randomizer,
+ self.link,
+ self.logger_randomizer,
+ self.logger
+ )
+
+ def gen_simulation(self, selfp):
+ for i in range(8):
+ streamer_packet = LinkTXPacket([i for i in range(64)])
+ yield from self.streamer.send(streamer_packet)
+ yield from self.logger.receive()
+
+ # check results
+ s, l, e = check(streamer_packet, self.logger.packet)
+ print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
--- /dev/null
+from litesata.common import *
+from litesata.phy.datapath import liteSATAPHYDatapath
+
+from litesata.test.common import *
+
+class DataPacket(list):
+ def __init__(self, data=[]):
+ self.ongoing = False
+ self.done = False
+ for d in data:
+ self.append(d)
+
+class DataStreamer(PacketStreamer):
+ def __init__(self):
+ PacketStreamer.__init__(self, phy_description(32), DataPacket)
+
+ def do_simulation(self, selfp):
+ PacketStreamer.do_simulation(self, selfp)
+ selfp.source.charisk = 0
+ # Note: for simplicity we generate charisk by detecting
+ # primitives in data
+ for k, v in primitives.items():
+ try:
+ if self.source_data == v:
+ selfp.source.charisk = 0b0001
+ except:
+ pass
+
+class DataLogger(PacketLogger):
+ def __init__(self):
+ PacketLogger.__init__(self, phy_description(32), DataPacket)
+
+class TRX(Module):
+ def __init__(self):
+ self.sink = Sink(phy_description(32))
+ self.source = Source(phy_description(32))
+ self.comb += Record.connect(self.sink, self.source)
+
+class CTRL(Module):
+ def __init__(self):
+ self.sink = Sink(phy_description(32))
+ self.source = Source(phy_description(32))
+ self.ready = Signal(reset=1)
+
+class TB(Module):
+ def __init__(self):
+ # use sys_clk for each clock_domain
+ self.cd_sata_rx = ClockDomain()
+ self.cd_sata_tx = ClockDomain()
+ self.comb += [
+ self.cd_sata_rx.clk.eq(ClockSignal()),
+ self.cd_sata_rx.rst.eq(ResetSignal()),
+ self.cd_sata_tx.clk.eq(ClockSignal()),
+ self.cd_sata_tx.rst.eq(ResetSignal()),
+ ]
+
+ self.streamer = DataStreamer()
+ self.streamer_randomizer = Randomizer(phy_description(32), level=10)
+ self.trx = TRX()
+ self.ctrl = CTRL()
+ self.datapath = LiteSATAPHYDatapath(self.trx, self.ctrl)
+ self.logger_randomizer = Randomizer(phy_description(32), level=10)
+ self.logger = DataLogger()
+
+ self.pipeline = Pipeline(
+ self.streamer,
+ self.streamer_randomizer,
+ self.datapath,
+ self.logger_randomizer,
+ self.logger
+ )
+
+ def gen_simulation(self, selfp):
+ streamer_packet = DataPacket([seed_to_data(i, False) for i in range(512)])
+ yield from self.streamer.send(streamer_packet)
+ yield from self.logger.receive(512)
+ for d in self.logger.packet:
+ r = "%08x " %d
+ r +=decode_primitive(d)
+ print(r)
+
+ # check results
+ #s, l, e = check(streamer_packet, self.logger.packet)
+ #print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=4096, vcd_name="my.vcd", keep_files=True)
--- /dev/null
+// Adapted from SATA specification
+/****************************************************************************/
+/* */
+/* scramble.c */
+/* */
+/* This sample code generates the entire sequence of 65535 Dwords produced */
+/* by the scrambler defined in the Serial ATA specification. The */
+/* specification calls for an LFSR to generate a string of bits that will */
+/* be packaged into 32 bit Dwords to be XORed with the data Dwords. The */
+/* generator polynomial specified is: */
+/* 16 15 13 4 */
+/* G(x) = x + x + x + x + 1 */
+/* */
+/* Parallelized versions of the scrambler are initialized to a value */
+/* derived from the initialization value of 0xFFFF defined in the */
+/* specification. This implementation is initialized to 0xF0F6. Other */
+/* parallel implementations will have different initial values. The */
+/* important point is that the first Dword output of any implementation */
+/* must equal 0xC2D2768D. */
+/* This code does not represent an elegant solution for a C implementation, */
+/* but it does demonstrate a method of generating the sequence that can be */
+/* easily implemented in hardware. A block diagram of the circuit emulated */
+/* by this code is shown below. */
+/* */
+/* +-----------------------------------+ */
+/* | | */
+/* | | */
+/* | +---+ +---+ | */
+/* | | R | | * | | */
+/* +---->| e |----------+---->| M |----+----> Output(31 downto 16) */
+/* | g | | | 1 | */
+/* +---+ | +---+ */
+/* | */
+/* | +---+ */
+/* | | * | */
+/* +---->| M |---------> Output(15 downto 0) */
+/* | 2 | */
+/* +---+ */
+/* */
+/* The register shown in the block diagram is a 16 bit register. The two */
+/* boxes, *M1 and *M2, each represent a multiply by a 16 by 16 binary */
+/* matrix. A 16 by 16 matrix times a 16 bit vector yields a 16 bit vector. */
+/* The two vectors are the two halves of the 32 bit scrambler value. The */
+/* upper half of the scrambler value is stored back into the context */
+/* register to be used to generate the next value in the scrambler */
+/* */
+/****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char *argv[])
+{
+ int i, j;
+ unsigned int length;
+ unsigned short context;
+ unsigned long scrambler;
+ unsigned char now[16];
+ unsigned char next[32];
+ context = 0xF0F6;
+
+ scanf("0x%8x", &length);
+
+ for (i = 0; i < length; ++i) {
+ for (j = 0; j < 16; ++j) {
+ now[j] = (context >> j) & 0x01;
+ }
+ next[31] = now[12] ^ now[10] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
+ next[30] = now[15] ^ now[14] ^ now[12] ^ now[11] ^ now[9] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
+ next[29] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
+ next[28] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
+ next[27] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[1] ^ now[0];
+ next[26] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[0];
+ next[25] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[3] ^ now[2];
+ next[24] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
+ next[23] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
+ next[22] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
+ next[21] = now[15] ^ now[13] ^ now[12] ^ now[6] ^ now[5] ^ now[4] ^ now[0];
+ next[20] = now[15] ^ now[11] ^ now[5] ^ now[4];
+ next[19] = now[14] ^ now[10] ^ now[4] ^ now[3];
+ next[18] = now[13] ^ now[9] ^ now[3] ^ now[2];
+ next[17] = now[12] ^ now[8] ^ now[2] ^ now[1];
+ next[16] = now[11] ^ now[7] ^ now[1] ^ now[0];
+
+
+ next[15] = now[15] ^ now[14] ^ now[12] ^ now[10] ^ now[6] ^ now[3] ^ now[0];
+ next[14] = now[15] ^ now[13] ^ now[12] ^ now[11] ^ now[9] ^ now[5] ^ now[3] ^ now[2];
+ next[13] = now[14] ^ now[12] ^ now[11] ^ now[10] ^ now[8] ^ now[4] ^ now[2] ^ now[1];
+ next[12] = now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[7] ^ now[3] ^ now[1] ^ now[0];
+ next[11] = now[15] ^ now[14] ^ now[10] ^ now[9] ^ now[8] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
+ next[10] = now[15] ^ now[13] ^ now[12] ^ now[9] ^ now[8] ^ now[7] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
+ next[9] = now[14] ^ now[12] ^ now[11] ^ now[8] ^ now[7] ^ now[6] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
+ next[8] = now[15] ^ now[14] ^ now[13] ^ now[12] ^ now[11] ^ now[10] ^ now[7] ^ now[6] ^ now[5] ^ now[1] ^ now[0];
+ next[7] = now[15] ^ now[13] ^ now[11] ^ now[10] ^ now[9] ^ now[6] ^ now[5] ^ now[4] ^ now[3] ^ now[0];
+ next[6] = now[15] ^ now[10] ^ now[9] ^ now[8] ^ now[5] ^ now[4] ^ now[2];
+ next[5] = now[14] ^ now[9] ^ now[8] ^ now[7] ^ now[4] ^ now[3] ^ now[1];
+ next[4] = now[13] ^ now[8] ^ now[7] ^ now[6] ^ now[3] ^ now[2] ^ now[0];
+ next[3] = now[15] ^ now[14] ^ now[7] ^ now[6] ^ now[5] ^ now[3] ^ now[2] ^ now[1];
+ next[2] = now[14] ^ now[13] ^ now[6] ^ now[5] ^ now[4] ^ now[2] ^ now[1] ^ now[0];
+ next[1] = now[15] ^ now[14] ^ now[13] ^ now[5] ^ now[4] ^ now[1] ^ now[0];
+ next[0] = now[15] ^ now[13] ^ now[4] ^ now[0];
+
+ scrambler = 0;
+ for (j = 31; j >= 0; --j) {
+ scrambler = scrambler << 1;
+ scrambler |= next[j];
+ }
+ context = scrambler >> 16;
+ printf("%08x\n", (unsigned int) scrambler);
+
+ }
+
+ return 0;
+
+}
\ No newline at end of file
--- /dev/null
+import subprocess
+
+from litesata.common import *
+from litesata.core.link.scrambler import *
+
+from litesata.test.common import *
+
+class TB(Module):
+ def __init__(self, length):
+ self.scrambler = InsertReset(Scrambler())
+ self.length = length
+
+ def get_c_values(self, length):
+ stdin = "0x%08x" %length
+ with subprocess.Popen("./scrambler", stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
+ process.stdin.write(stdin.encode("ASCII"))
+ out, err = process.communicate()
+ return [int(e, 16) for e in out.decode("ASCII").split("\n")[:-1]]
+
+ def gen_simulation(self, selfp):
+ # init CRC
+ selfp.scrambler.ce = 1
+ selfp.scrambler.reset = 1
+ yield
+ selfp.scrambler.reset = 0
+
+ # log results
+ yield
+ sim_values = []
+ for i in range(self.length):
+ sim_values.append(selfp.scrambler.value)
+ yield
+
+ # stop
+ selfp.scrambler.ce = 0
+ for i in range(32):
+ yield
+
+ # get C code reference
+ c_values = self.get_c_values(self.length)
+
+ # check results
+ s, l, e = check(c_values, sim_values)
+ print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
+
+if __name__ == "__main__":
+ from migen.sim.generic import run_simulation
+ length = 8192
+ run_simulation(TB(length), ncycles=length+100, vcd_name="my.vcd")
IOStandard("LVCMOS25")
),
- ("sata_host", 0,
+ ("sata0", 0,
Subsignal("refclk_p", Pins("C8")),
Subsignal("refclk_n", Pins("C7")),
Subsignal("txp", Pins("D2")),
Subsignal("rxp", Pins("E4")),
Subsignal("rxn", Pins("E3")),
),
-
- ("sata_device", 0,
- Subsignal("refclk_p", Pins("G8")), # 125MHz SGMII
- Subsignal("refclk_n", Pins("G7")), # 125MHz SGMII
- Subsignal("txp", Pins("H2")), # SFP
- Subsignal("txn", Pins("H1")), # SFP
- Subsignal("rxp", Pins("G4")), # SFP
- Subsignal("rxn", Pins("G3")), # SFP
- ),
]
def Platform(*args, toolchain="vivado", programmer="xc3sprog", **kwargs):
--- /dev/null
+#!/usr/bin/env python3
+
+import sys, os
+from setuptools import setup
+from setuptools import find_packages
+
+here = os.path.abspath(os.path.dirname(__file__))
+README = open(os.path.join(here, "README")).read()
+
+required_version = (3, 3)
+if sys.version_info < required_version:
+ raise SystemExit("LiteSATA requires python {0} or greater".format(
+ ".".join(map(str, required_version))))
+
+setup(
+ name="litesata",
+ version="unknown",
+ description="Generic open-source SATA1/2/3 controller",
+ long_description=README,
+ author="Florent Kermarrec",
+ author_email="florent@enjoy-digital.fr",
+ url="http://enjoy-digital.fr",
+ download_url="https://github.com/Florent-Kermarrec/litesata",
+ packages=find_packages(here),
+ license="GPL",
+ platforms=["Any"],
+ keywords="HDL ASIC FPGA hardware design",
+ classifiers=[
+ "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
+ "Environment :: Console",
+ "Development Status :: Alpha",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: GNU General Public License (GPL)",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ ],
+)
+++ /dev/null
-import os
-
-from migen.fhdl.std import *
-from migen.bank import csrgen
-from migen.bus import wishbone, csr
-from migen.bus import wishbone2csr
-from migen.genlib.cdc import *
-from migen.genlib.resetsync import AsyncResetSynchronizer
-from migen.bank.description import *
-
-from miscope import MiLa, Term, UART2Wishbone
-
-from misoclib import identifier
-from lib.sata.common import *
-from lib.sata.phy import SATAPHY
-from lib.sata import SATACON
-from lib.sata.bist import SATABIST
-
-class _CRG(Module):
- def __init__(self, platform):
- self.cd_sys = ClockDomain()
- self.sata_reset = Signal()
-
- clk200 = platform.request("clk200")
- clk200_se = Signal()
- self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se)
-
- pll_locked = Signal()
- pll_fb = Signal()
- pll_sys = Signal()
- self.specials += [
- Instance("PLLE2_BASE",
- p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
-
- # VCO @ 1GHz
- p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0,
- p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1,
- i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
-
- # 166MHz
- p_CLKOUT0_DIVIDE=6, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys,
-
- p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, #o_CLKOUT1=,
-
- p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, #o_CLKOUT2=,
-
- p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=,
-
- p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
- ),
- Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
- AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.sata_reset),
- ]
-
-class GenSoC(Module):
- csr_base = 0x00000000
- csr_data_width = 32
- csr_map = {
- "uart2wb": 0,
- "identifier": 2,
- }
- interrupt_map = {}
- cpu_type = None
- def __init__(self, platform, clk_freq):
- # UART <--> Wishbone bridge
- self.uart2wb = UART2Wishbone(platform.request("serial"), clk_freq, baud=921600)
-
- # CSR bridge 0x00000000 (shadow @0x00000000)
- self.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(self.csr_data_width))
- self._wb_masters = [self.uart2wb.wishbone]
- self._wb_slaves = [(lambda a: a[23:25] == 0, self.wishbone2csr.wishbone)]
- self.cpu_csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
-
- # CSR
- self.identifier = identifier.Identifier(0, int(clk_freq), 0)
-
- def add_cpu_memory_region(self, name, origin, length):
- self.cpu_memory_regions.append((name, origin, length))
-
- def add_cpu_csr_region(self, name, origin, busword, obj):
- self.cpu_csr_regions.append((name, origin, busword, obj))
-
- def do_finalize(self):
- # Wishbone
- self.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
- self._wb_slaves, register=True)
-
- # CSR
- self.csrbankarray = csrgen.BankArray(self,
- lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
- data_width=self.csr_data_width)
- self.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
- for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
- self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), csrs)
- for name, memory, mapaddr, mmap in self.csrbankarray.srams:
- self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), memory)
-
-class BISTLeds(Module):
- def __init__(self, platform, sata_phy):
- # 1Hz blinking leds (sata_rx and sata_tx clocks)
- sata_rx_led = platform.request("user_led", 0)
- sata_tx_led = platform.request("user_led", 1)
-
- sata_rx_cnt = Signal(32)
- sata_tx_cnt = Signal(32)
-
- sata_freqs_mhz = {
- "SATA3" : 150.0,
- "SATA2" : 75.0,
- "SATA1" : 37.5,
- }
- sata_freq = int(sata_freqs_mhz[sata_phy.speed]*1000*1000)
-
- self.sync.sata_rx += \
- If(sata_rx_cnt == 0,
- sata_rx_led.eq(~sata_rx_led),
- sata_rx_cnt.eq(sata_freq//2)
- ).Else(
- sata_rx_cnt.eq(sata_rx_cnt-1)
- )
-
- self.sync.sata_tx += \
- If(sata_tx_cnt == 0,
- sata_tx_led.eq(~sata_tx_led),
- sata_tx_cnt.eq(sata_freq//2)
- ).Else(
- sata_tx_cnt.eq(sata_tx_cnt-1)
- )
-
- # ready leds (crg and ctrl)
- self.comb += platform.request("user_led", 2).eq(sata_phy.crg.ready)
- self.comb += platform.request("user_led", 3).eq(sata_phy.ctrl.ready)
-
-class BISTSoC(GenSoC, AutoCSR):
- default_platform = "kc705"
- csr_map = {
- "sata_bist": 10,
- }
- csr_map.update(GenSoC.csr_map)
-
- def __init__(self, platform, export_mila=False):
- clk_freq = 166*1000000
- GenSoC.__init__(self, platform, clk_freq)
- self.crg = _CRG(platform)
-
- # SATA PHY and controller
- self.sata_phy = SATAPHY(platform.request("sata_host"), clk_freq, speed="SATA2")
- self.comb += self.crg.sata_reset.eq(self.sata_phy.ctrl.need_reset)
- self.sata_con = SATACON(self.sata_phy)
-
- # SATA BIST generator and checker
- self.sata_bist = SATABIST(self.sata_con.crossbar.get_ports(3), with_control=True)
-
- # Status Leds
- self.leds = BISTLeds(platform, self.sata_phy)
-
-class BISTSoCDevel(BISTSoC, AutoCSR):
- csr_map = {
- "mila": 11
- }
- csr_map.update(BISTSoC.csr_map)
- def __init__(self, platform, export_mila=False):
- BISTSoC.__init__(self, platform, export_mila)
-
- self.sata_con_link_rx_fsm_state = Signal(4)
- self.sata_con_link_tx_fsm_state = Signal(4)
- self.sata_con_transport_rx_fsm_state = Signal(4)
- self.sata_con_transport_tx_fsm_state = Signal(4)
- self.sata_con_command_rx_fsm_state = Signal(4)
- self.sata_con_command_tx_fsm_state = Signal(4)
-
- debug = (
- self.sata_phy.ctrl.ready,
-
- self.sata_phy.source.stb,
- self.sata_phy.source.data,
- self.sata_phy.source.charisk,
-
- self.sata_phy.sink.stb,
- self.sata_phy.sink.data,
- self.sata_phy.sink.charisk,
-
- self.sata_con.command.sink.stb,
- self.sata_con.command.sink.sop,
- self.sata_con.command.sink.eop,
- self.sata_con.command.sink.ack,
- self.sata_con.command.sink.write,
- self.sata_con.command.sink.read,
- self.sata_con.command.sink.identify,
-
- self.sata_con.command.source.stb,
- self.sata_con.command.source.sop,
- self.sata_con.command.source.eop,
- self.sata_con.command.source.ack,
- self.sata_con.command.source.write,
- self.sata_con.command.source.read,
- self.sata_con.command.source.identify,
- self.sata_con.command.source.success,
- self.sata_con.command.source.failed,
- self.sata_con.command.source.data,
-
- self.sata_con_link_rx_fsm_state,
- self.sata_con_link_tx_fsm_state,
- self.sata_con_transport_rx_fsm_state,
- self.sata_con_transport_tx_fsm_state,
- self.sata_con_command_rx_fsm_state,
- self.sata_con_command_tx_fsm_state,
- )
-
- self.mila = MiLa(depth=2048, dat=Cat(*debug))
- self.mila.add_port(Term)
- if export_mila:
- mila_filename = os.path.join(platform.soc_ext_path, "test", "mila.csv")
- self.mila.export(self, debug, mila_filename)
- def do_finalize(self):
- BISTSoC.do_finalize(self)
- self.comb += [
- self.sata_con_link_rx_fsm_state.eq(self.sata_con.link.rx.fsm.state),
- self.sata_con_link_tx_fsm_state.eq(self.sata_con.link.tx.fsm.state),
- self.sata_con_transport_rx_fsm_state.eq(self.sata_con.transport.rx.fsm.state),
- self.sata_con_transport_tx_fsm_state.eq(self.sata_con.transport.tx.fsm.state),
- self.sata_con_command_rx_fsm_state.eq(self.sata_con.command.rx.fsm.state),
- self.sata_con_command_tx_fsm_state.eq(self.sata_con.command.tx.fsm.state)
- ]
-
-default_subtarget = BISTSoC
-#default_subtarget = BISTSoCDevel
--- /dev/null
+import os
+
+from litesata.common import *
+from migen.bank import csrgen
+from migen.bus import wishbone, csr
+from migen.bus import wishbone2csr
+from migen.genlib.cdc import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+from migen.bank.description import *
+
+from misoclib import identifier
+
+from miscope import MiLa, Term, UART2Wishbone
+
+from litesata.common import *
+from litesata.phy import LiteSATAPHY
+from litesata import LiteSATA
+
+class _CRG(Module):
+ def __init__(self, platform):
+ self.cd_sys = ClockDomain()
+ self.reset = Signal()
+
+ clk200 = platform.request("clk200")
+ clk200_se = Signal()
+ self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se)
+
+ pll_locked = Signal()
+ pll_fb = Signal()
+ pll_sys = Signal()
+ self.specials += [
+ Instance("PLLE2_BASE",
+ p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
+
+ # VCO @ 1GHz
+ p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0,
+ p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1,
+ i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
+
+ # 166MHz
+ p_CLKOUT0_DIVIDE=6, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys,
+
+ p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, #o_CLKOUT1=,
+
+ p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, #o_CLKOUT2=,
+
+ p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=,
+
+ p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
+ ),
+ Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
+ AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.reset),
+ ]
+
+class GenSoC(Module):
+ csr_base = 0x00000000
+ csr_data_width = 32
+ csr_map = {
+ "uart2wb": 0,
+ "identifier": 2,
+ }
+ interrupt_map = {}
+ cpu_type = None
+ def __init__(self, platform, clk_freq):
+ # UART <--> Wishbone bridge
+ self.uart2wb = UART2Wishbone(platform.request("serial"), clk_freq, baud=921600)
+
+ # CSR bridge 0x00000000 (shadow @0x00000000)
+ self.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(self.csr_data_width))
+ self._wb_masters = [self.uart2wb.wishbone]
+ self._wb_slaves = [(lambda a: a[23:25] == 0, self.wishbone2csr.wishbone)]
+ self.cpu_csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
+
+ # CSR
+ self.identifier = identifier.Identifier(0, int(clk_freq), 0)
+
+ def add_cpu_memory_region(self, name, origin, length):
+ self.cpu_memory_regions.append((name, origin, length))
+
+ def add_cpu_csr_region(self, name, origin, busword, obj):
+ self.cpu_csr_regions.append((name, origin, busword, obj))
+
+ def do_finalize(self):
+ # Wishbone
+ self.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
+ self._wb_slaves, register=True)
+
+ # CSR
+ self.csrbankarray = csrgen.BankArray(self,
+ lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
+ data_width=self.csr_data_width)
+ self.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
+ for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
+ self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), csrs)
+ for name, memory, mapaddr, mmap in self.csrbankarray.srams:
+ self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), memory)
+
+class BISTLeds(Module):
+ def __init__(self, platform, sata_phy):
+ # 1Hz blinking leds (sata_rx and sata_tx clocks)
+ sata_rx_led = platform.request("user_led", 0)
+ sata_tx_led = platform.request("user_led", 1)
+
+ sata_rx_cnt = Signal(32)
+ sata_tx_cnt = Signal(32)
+
+ sata_freqs_mhz = {
+ "SATA3" : 150.0,
+ "SATA2" : 75.0,
+ "SATA1" : 37.5,
+ }
+ sata_freq = int(sata_freqs_mhz[sata_phy.speed]*1000*1000)
+
+ self.sync.sata_rx += \
+ If(sata_rx_cnt == 0,
+ sata_rx_led.eq(~sata_rx_led),
+ sata_rx_cnt.eq(sata_freq//2)
+ ).Else(
+ sata_rx_cnt.eq(sata_rx_cnt-1)
+ )
+
+ self.sync.sata_tx += \
+ If(sata_tx_cnt == 0,
+ sata_tx_led.eq(~sata_tx_led),
+ sata_tx_cnt.eq(sata_freq//2)
+ ).Else(
+ sata_tx_cnt.eq(sata_tx_cnt-1)
+ )
+
+ # ready leds (crg and ctrl)
+ self.comb += platform.request("user_led", 2).eq(sata_phy.crg.ready)
+ self.comb += platform.request("user_led", 3).eq(sata_phy.ctrl.ready)
+
+class BISTSoC(GenSoC, AutoCSR):
+ default_platform = "kc705"
+ csr_map = {
+ "sata": 10,
+ }
+ csr_map.update(GenSoC.csr_map)
+
+ def __init__(self, platform, export_mila=False):
+ clk_freq = 166*1000000
+ GenSoC.__init__(self, platform, clk_freq)
+ self.crg = _CRG(platform)
+
+ # SATA PHY/Core/Frontend
+ self.sata_phy = LiteSATAPHY(platform.device, platform.request("sata0"), "SATA2", clk_freq)
+ self.comb += self.crg.reset.eq(self.sata_phy.ctrl.need_reset) # XXX FIXME
+ self.sata = LiteSATA(self.sata_phy, with_crossbar=True, with_bist=True, with_bist_csr=True)
+
+ # Status Leds
+ self.leds = BISTLeds(platform, self.sata_phy)
+
+class BISTSoCDevel(BISTSoC, AutoCSR):
+ csr_map = {
+ "mila": 11
+ }
+ csr_map.update(BISTSoC.csr_map)
+ def __init__(self, platform, export_mila=False):
+ BISTSoC.__init__(self, platform, export_mila)
+
+ self.sata_core_link_rx_fsm_state = Signal(4)
+ self.sata_core_link_tx_fsm_state = Signal(4)
+ self.sata_core_transport_rx_fsm_state = Signal(4)
+ self.sata_core_transport_tx_fsm_state = Signal(4)
+ self.sata_core_command_rx_fsm_state = Signal(4)
+ self.sata_core_command_tx_fsm_state = Signal(4)
+
+ debug = (
+ self.sata_phy.ctrl.ready,
+
+ self.sata_phy.source.stb,
+ self.sata_phy.source.data,
+ self.sata_phy.source.charisk,
+
+ self.sata_phy.sink.stb,
+ self.sata_phy.sink.data,
+ self.sata_phy.sink.charisk,
+
+ self.sata.core.command.sink.stb,
+ self.sata.core.command.sink.sop,
+ self.sata.core.command.sink.eop,
+ self.sata.core.command.sink.ack,
+ self.sata.core.command.sink.write,
+ self.sata.core.command.sink.read,
+ self.sata.core.command.sink.identify,
+
+ self.sata.core.command.source.stb,
+ self.sata.core.command.source.sop,
+ self.sata.core.command.source.eop,
+ self.sata.core.command.source.ack,
+ self.sata.core.command.source.write,
+ self.sata.core.command.source.read,
+ self.sata.core.command.source.identify,
+ self.sata.core.command.source.success,
+ self.sata.core.command.source.failed,
+ self.sata.core.command.source.data,
+
+ self.sata_core_link_rx_fsm_state,
+ self.sata_core_link_tx_fsm_state,
+ self.sata_core_transport_rx_fsm_state,
+ self.sata_core_transport_tx_fsm_state,
+ self.sata_core_command_rx_fsm_state,
+ self.sata_core_command_tx_fsm_state,
+ )
+
+ self.mila = MiLa(depth=2048, dat=Cat(*debug))
+ self.mila.add_port(Term)
+ if export_mila:
+ mila_filename = os.path.join(platform.soc_ext_path, "test", "mila.csv")
+ self.mila.export(self, debug, mila_filename)
+
+ def do_finalize(self):
+ BISTSoC.do_finalize(self)
+ self.comb += [
+ self.sata_core_link_rx_fsm_state.eq(self.sata.core.link.rx.fsm.state),
+ self.sata_core_link_tx_fsm_state.eq(self.sata.core.link.tx.fsm.state),
+ self.sata_core_transport_rx_fsm_state.eq(self.sata.core.transport.rx.fsm.state),
+ self.sata_core_transport_tx_fsm_state.eq(self.sata.core.transport.tx.fsm.state),
+ self.sata_core_command_rx_fsm_state.eq(self.sata.core.command.rx.fsm.state),
+ self.sata_core_command_tx_fsm_state.eq(self.sata.core.command.tx.fsm.state)
+ ]
+
+#default_subtarget = BISTSoC
+default_subtarget = BISTSoCDevel
logical_sector_size = 512
-class SATABISTUnitDriver:
+class LiteSATABISTUnitDriver:
def __init__(self, regs, name):
self.regs = regs
self.name = name
errors = self.errors.read()
return (speed, errors)
-class SATABISTGeneratorDriver(SATABISTUnitDriver):
+class LiteSATABISTGeneratorDriver(LiteSATABISTUnitDriver):
def __init__(self, regs, name):
- SATABISTUnitDriver.__init__(self, regs, name + "_generator")
+ LiteSATABISTUnitDriver.__init__(self, regs, name + "_generator")
-class SATABISTCheckerDriver(SATABISTUnitDriver):
+class LiteSATABISTCheckerDriver(LiteSATABISTUnitDriver):
def __init__(self, regs, name):
- SATABISTUnitDriver.__init__(self, regs, name + "_checker")
+ LiteSATABISTUnitDriver.__init__(self, regs, name + "_checker")
-class SATABISTIdentifyDriver:
+class LiteSATABISTIdentifyDriver:
def __init__(self, regs, name):
self.regs = regs
self.name = name
def decode(self):
self.serial_number = ""
for i, dword in enumerate(self.data[10:20]):
- s = dword.to_bytes(4, byteorder='big').decode("utf-8")
- self.serial_number += s[2:] + s[:2]
-
- def __repr__(self):
- r = "Serial Number: " + self.serial_number
+ try:
+ s = dword.to_bytes(4, byteorder='big').decode("utf-8")
+ self.serial_number += s[2:] + s[:2]
+ except:
+ self.serial_number += " "
+
+ def hdd_info(self):
+ info = "Serial Number: " + self.serial_number
# XXX: enhance decode function
- return r
+ print(info)
KB = 1024
MB = 1024*KB
args = _get_args()
wb.open()
###
- identify = SATABISTIdentifyDriver(wb.regs, "sata_bist")
- generator = SATABISTGeneratorDriver(wb.regs, "sata_bist")
- checker = SATABISTCheckerDriver(wb.regs, "sata_bist")
+ identify = LiteSATABISTIdentifyDriver(wb.regs, "sata_bist")
+ generator = LiteSATABISTGeneratorDriver(wb.regs, "sata_bist")
+ checker = LiteSATABISTCheckerDriver(wb.regs, "sata_bist")
identify.run()
- print(identify)
+ identify.hdd_info()
sector = 0
count = int(args.transfer_size)*MB//logical_sector_size
from miscope.host.drivers import MiLaDriver
mila = MiLaDriver(wb.regs, "mila")
-identify = SATABISTIdentifyDriver(wb.regs, "sata_bist")
-generator = SATABISTGeneratorDriver(wb.regs, "sata_bist")
-checker = SATABISTCheckerDriver(wb.regs, "sata_bist")
+identify = LiteSATABISTIdentifyDriver(wb.regs, "sata_bist")
+generator = LiteSATABISTGeneratorDriver(wb.regs, "sata_bist")
+checker = LiteSATABISTCheckerDriver(wb.regs, "sata_bist")
wb.open()
regs = wb.regs
###
conditions = {}
conditions["wr_cmd"] = {
- "bistsocdevel_sata_con_command_sink_stb" : 1,
- "bistsocdevel_sata_con_command_sink_payload_write" : 1,
+ "bistsocdevel_core_sink_stb" : 1,
+ "bistsocdevel_core_sink_payload_write" : 1,
}
conditions["wr_dma_activate"] = {
- "bistsocdevel_sata_con_command_source_source_stb" : 1,
- "bistsocdevel_sata_con_command_source_source_payload_write" : 1,
+ "bistsocdevel_core_source_source_stb" : 1,
+ "bistsocdevel_core_source_source_payload_write" : 1,
}
conditions["rd_cmd"] = {
- "bistsocdevel_sata_con_command_sink_stb" : 1,
- "bistsocdevel_sata_con_command_sink_payload_read" : 1,
+ "bistsocdevel_core_sink_stb" : 1,
+ "bistsocdevel_core_sink_payload_read" : 1,
}
conditions["rd_data"] = {
- "bistsocdevel_sata_con_command_source_source_stb" : 1,
- "bistsocdevel_sata_con_command_source_source_payload_read" : 1,
+ "bistsocdevel_core_source_source_stb" : 1,
+ "bistsocdevel_core_source_source_payload_read" : 1,
}
conditions["id_cmd"] = {
- "bistsocdevel_sata_con_command_sink_stb" : 1,
- "bistsocdevel_sata_con_command_sink_payload_identify" : 1,
+ "bistsocdevel_core_sink_stb" : 1,
+ "bistsocdevel_core_sink_payload_identify" : 1,
}
conditions["id_pio_setup"] = {
- "bistsocdevel_sata_phy_source_source_payload_data" : primitives["X_RDY"],
+ "bistsocdevel_source_source_payload_data" : primitives["X_RDY"],
}
mila.prog_term(port=0, cond=conditions[sys.argv[1]])
wb.close()
print_link_trace(mila,
- tx_data_name="bistsocdevel_sata_phy_sink_sink_payload_data",
- rx_data_name="bistsocdevel_sata_phy_source_source_payload_data"
+ tx_data_name="bistsocdevel_sink_sink_payload_data",
+ rx_data_name="bistsocdevel_source_source_payload_data"
)