mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
modify addressing (in sectors) and improve hdd model debug
This commit is contained in:
parent
6a783ad291
commit
f226de5ba0
5 changed files with 99 additions and 94 deletions
|
@ -23,15 +23,12 @@ class SATACommandTX(Module):
|
|||
|
||||
###
|
||||
|
||||
sector_bits = log2_int(sector_size)
|
||||
dwords_bits = 2
|
||||
|
||||
self.comb += [
|
||||
transport.sink.pm_port.eq(0),
|
||||
transport.sink.features.eq(0),
|
||||
transport.sink.lba.eq(sink.address[sector_bits-dwords_bits:]),
|
||||
transport.sink.lba.eq(sink.sector),
|
||||
transport.sink.device.eq(0xe0),
|
||||
transport.sink.count.eq(sink.length[sector_bits-dwords_bits:]),
|
||||
transport.sink.count.eq(sink.count),
|
||||
transport.sink.icc.eq(0),
|
||||
transport.sink.control.eq(0),
|
||||
]
|
||||
|
@ -61,11 +58,10 @@ class SATACommandTX(Module):
|
|||
transport.sink.type.eq(fis_types["REG_H2D"]),
|
||||
transport.sink.c.eq(1),
|
||||
transport.sink.command.eq(regs["WRITE_DMA_EXT"]),
|
||||
If(transport.sink.ack,
|
||||
If(sink.stb & transport.sink.ack,
|
||||
NextState("WAIT_DMA_ACTIVATE")
|
||||
)
|
||||
)
|
||||
# XXX: split when length > 2048 dwords
|
||||
fsm.act("WAIT_DMA_ACTIVATE",
|
||||
If(from_rx.dma_activate,
|
||||
NextState("SEND_DATA")
|
||||
|
@ -116,7 +112,7 @@ class SATACommandTX(Module):
|
|||
]
|
||||
|
||||
class SATACommandRX(Module):
|
||||
def __init__(self, transport, sector_size):
|
||||
def __init__(self, transport, sector_size, max_count):
|
||||
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)
|
||||
|
@ -167,7 +163,7 @@ class SATACommandRX(Module):
|
|||
source.eop.eq(1),
|
||||
source.write.eq(1),
|
||||
source.success.eq(1),
|
||||
If(source.ack,
|
||||
If(source.stb & source.ack,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
@ -207,7 +203,7 @@ class SATACommandRX(Module):
|
|||
source.read.eq(~identify),
|
||||
source.identify.eq(identify),
|
||||
source.success.eq(1),
|
||||
If(source.ack,
|
||||
If(source.stb & source.ack,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
@ -217,9 +213,11 @@ class SATACommandRX(Module):
|
|||
]
|
||||
|
||||
class SATACommand(Module):
|
||||
def __init__(self, transport, sector_size=512):
|
||||
def __init__(self, transport, sector_size=512, max_count=16):
|
||||
if max_count*sector_size > 8192:
|
||||
raise ValueError("sector_size x max_count must be <= 2048")
|
||||
self.submodules.tx = SATACommandTX(transport, sector_size)
|
||||
self.submodules.rx = SATACommandRX(transport, sector_size)
|
||||
self.submodules.rx = SATACommandRX(transport, sector_size, max_count)
|
||||
self.comb += [
|
||||
self.rx.to_tx.connect(self.tx.from_rx),
|
||||
self.tx.to_rx.connect(self.rx.from_tx)
|
||||
|
|
|
@ -148,8 +148,8 @@ def command_tx_description(dw):
|
|||
("write", 1),
|
||||
("read", 1),
|
||||
("identify", 1),
|
||||
("address", 32),
|
||||
("length", 32),
|
||||
("sector", 48),
|
||||
("count", 4),
|
||||
("data", dw)
|
||||
]
|
||||
return EndpointDescription(layout, packetized=True)
|
||||
|
|
|
@ -13,14 +13,14 @@ from lib.sata.test.hdd import *
|
|||
from lib.sata.test.common import *
|
||||
|
||||
class CommandTXPacket(list):
|
||||
def __init__(self, write=0, read=0, identify=0, address=0, length=0, data=[]):
|
||||
def __init__(self, write=0, read=0, identify=0, sector=0, count=0, data=[]):
|
||||
self.ongoing = False
|
||||
self.done = False
|
||||
self.write = write
|
||||
self.read = read
|
||||
self.identify = identify
|
||||
self.address = address
|
||||
self.length = length
|
||||
self.sector = sector
|
||||
self.count = count
|
||||
for d in data:
|
||||
self.append(d)
|
||||
|
||||
|
@ -47,8 +47,8 @@ class CommandStreamer(Module):
|
|||
selfp.source.write = self.packet.write
|
||||
selfp.source.read = self.packet.read
|
||||
selfp.source.identify = self.packet.identify
|
||||
selfp.source.address = self.packet.address
|
||||
selfp.source.length = self.packet.length
|
||||
selfp.source.sector = self.packet.sector
|
||||
selfp.source.count = self.packet.count
|
||||
|
||||
if not self.packet.ongoing and not self.packet.done:
|
||||
selfp.source.stb = 1
|
||||
|
@ -105,10 +105,8 @@ class CommandLogger(Module):
|
|||
class TB(Module):
|
||||
def __init__(self):
|
||||
self.submodules.hdd = HDD(
|
||||
phy_debug=False,
|
||||
link_random_level=50, link_debug=False,
|
||||
link_debug=False, link_random_level=50,
|
||||
transport_debug=False, transport_loopback=False,
|
||||
command_debug=False,
|
||||
hdd_debug=True)
|
||||
self.submodules.link = SATALink(self.hdd.phy)
|
||||
self.submodules.transport = SATATransport(self.link)
|
||||
|
@ -128,12 +126,14 @@ class TB(Module):
|
|||
]
|
||||
|
||||
def gen_simulation(self, selfp):
|
||||
self.hdd.allocate_mem(0x00000000, 64*1024*1024)
|
||||
write_data = [i for i in range(512//4)]
|
||||
write_packet = CommandTXPacket(write=1, address=0, length=len(write_data), data=write_data)
|
||||
hdd = self.hdd
|
||||
hdd.malloc(0, 64)
|
||||
write_data = [i for i in range(hdd.sectors2dwords(2))]
|
||||
write_len = hdd.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, address=0, length=len(write_data))
|
||||
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
|
||||
|
@ -144,4 +144,4 @@ class TB(Module):
|
|||
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)
|
||||
run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
|
||||
|
|
|
@ -6,6 +6,13 @@ from migen.fhdl.std import *
|
|||
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):
|
||||
|
@ -49,8 +56,7 @@ class PHYSink(Module):
|
|||
self.dword.dat = selfp.sink.data
|
||||
|
||||
class PHYLayer(Module):
|
||||
def __init__(self, debug=False):
|
||||
self.debug = debug
|
||||
def __init__(self):
|
||||
|
||||
self.submodules.rx = PHYSink()
|
||||
self.submodules.tx = PHYSource()
|
||||
|
@ -63,8 +69,6 @@ class PHYLayer(Module):
|
|||
self.tx.send(packet)
|
||||
|
||||
def receive(self):
|
||||
if self.debug:
|
||||
print(self)
|
||||
yield from self.rx.receive()
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -79,6 +83,9 @@ class PHYLayer(Module):
|
|||
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"))
|
||||
|
@ -249,6 +256,8 @@ class LinkLayer(Module):
|
|||
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)
|
||||
|
@ -264,6 +273,9 @@ class LinkLayer(Module):
|
|||
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)
|
||||
|
||||
|
@ -365,7 +377,7 @@ class TransportLayer(Module):
|
|||
packet = LinkTXPacket(fis.packet)
|
||||
self.link.tx_packets.append(packet)
|
||||
if self.debug and not self.loopback:
|
||||
print(fis)
|
||||
print_transport(fis)
|
||||
|
||||
def callback(self, packet):
|
||||
fis_type = packet[0] & 0xff
|
||||
|
@ -380,7 +392,7 @@ class TransportLayer(Module):
|
|||
else:
|
||||
fis = FIS_UNKNOWN(packet, direction="H2D")
|
||||
if self.debug:
|
||||
print(fis)
|
||||
print_transport(fis)
|
||||
if self.loopback:
|
||||
self.send(fis)
|
||||
else:
|
||||
|
@ -388,9 +400,8 @@ class TransportLayer(Module):
|
|||
|
||||
# Command Layer model
|
||||
class CommandLayer(Module):
|
||||
def __init__(self, transport, debug=False):
|
||||
def __init__(self, transport):
|
||||
self.transport = transport
|
||||
self.debug = debug
|
||||
self.transport.set_command_callback(self.callback)
|
||||
|
||||
self.hdd = None
|
||||
|
@ -399,103 +410,100 @@ class CommandLayer(Module):
|
|||
self.hdd = hdd
|
||||
|
||||
def callback(self, fis):
|
||||
# XXX manage maximum of 2048 DWORDS per DMA
|
||||
resp = None
|
||||
if isinstance(fis, FIS_REG_H2D):
|
||||
if fis.command == regs["WRITE_DMA_EXT"]:
|
||||
resp = self.hdd.write_dma_cmd(fis)
|
||||
resp = self.hdd.write_dma_callback(fis)
|
||||
elif fis.command == regs["READ_DMA_EXT"]:
|
||||
resp = self.hdd.read_dma_cmd(fis)
|
||||
resp = self.hdd.read_dma_callback(fis)
|
||||
elif fis.command == regs["IDENTIFY_DEVICE_DMA"]:
|
||||
resp = self.hdd.identify_device_dma_cmd(fis)
|
||||
resp = self.hdd.identify_device_dma_callback(fis)
|
||||
elif isinstance(fis, FIS_DATA):
|
||||
resp = self.hdd.data_cmd(fis)
|
||||
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, length):
|
||||
def __init__(self, base, count, sector_size):
|
||||
self.base = base
|
||||
self.length = length
|
||||
self.data = [0]*(length//4)
|
||||
self.count = count
|
||||
self.data = [0]*(count*sector_size//4)
|
||||
|
||||
class HDD(Module):
|
||||
def __init__(self,
|
||||
phy_debug=False,
|
||||
link_debug=False, link_random_level=0,
|
||||
transport_debug=False, transport_loopback=False,
|
||||
command_debug=False,
|
||||
hdd_debug=False, hdd_sector_size=512,
|
||||
):
|
||||
###
|
||||
self.submodules.phy = PHYLayer(phy_debug)
|
||||
self.submodules.phy = PHYLayer()
|
||||
self.submodules.link = LinkLayer(self.phy, link_debug, link_random_level)
|
||||
self.submodules.transport = TransportLayer(self.link, transport_debug, transport_loopback)
|
||||
self.submodules.command = CommandLayer(self.transport, command_debug)
|
||||
self.submodules.command = CommandLayer(self.transport)
|
||||
|
||||
self.command.set_hdd(self)
|
||||
|
||||
self.hdd_debug = hdd_debug
|
||||
self.hdd_sector_size = hdd_sector_size
|
||||
self.debug = hdd_debug
|
||||
self.sector_size = hdd_sector_size
|
||||
self.mem = None
|
||||
self.wr_address = 0
|
||||
self.wr_length = 0
|
||||
self.wr_cnt = 0
|
||||
self.rd_address = 0
|
||||
self.rd_length = 0
|
||||
self.wr_sector = 0
|
||||
self.wr_end_sector = 0
|
||||
|
||||
def allocate_mem(self, base, length):
|
||||
if self.hdd_debug:
|
||||
print("[HDD] : Allocating {n} bytes at 0x{a}".format(n=length, a=base))
|
||||
self.mem = HDDMemRegion(base, length)
|
||||
def dwords2sectors(self, n):
|
||||
return math.ceil(n*4/self.sector_size)
|
||||
|
||||
def write_mem(self, adr, data):
|
||||
if self.hdd_debug:
|
||||
print("[HDD] : Writing {n} bytes at 0x{a}".format(n=len(data)*4, a=adr))
|
||||
current_adr = (adr-self.mem.base)//4
|
||||
def sectors2dwords(self, n):
|
||||
return n*self.sector_size//4
|
||||
|
||||
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*self.sector_size//1024)
|
||||
print_hdd(s)
|
||||
self.mem = HDDMemRegion(sector, count, self.sector_size)
|
||||
|
||||
def write(self, sector, data):
|
||||
n = math.ceil(self.dwords2sectors(len(data)))
|
||||
if self.debug:
|
||||
print_hdd("Writing sector {s} to {e}".format(s=sector, e=sector+n-1))
|
||||
for i in range(len(data)):
|
||||
self.mem.data[current_adr+i] = data[i]
|
||||
offset = self.sectors2dwords(sector)
|
||||
self.mem.data[offset+i] = data[i]
|
||||
|
||||
def read_mem(self, adr, length=1):
|
||||
if self.hdd_debug:
|
||||
print("[HDD] : Reading {n} bytes at 0x{a}".format(n=length, a=adr))
|
||||
current_adr = (adr-self.mem.base)//4
|
||||
def read(self, sector, count):
|
||||
if self.debug:
|
||||
print_hdd("Reading sector {s} to {e}".format(s=sector, e=sector+count-1))
|
||||
data = []
|
||||
for i in range(length//4):
|
||||
data.append(self.mem.data[current_adr+i])
|
||||
for i in range(self.sectors2dwords(count)):
|
||||
data.append(self.mem.data[self.sectors2dwords(sector)+i])
|
||||
return data
|
||||
|
||||
def write_dma_cmd(self, fis):
|
||||
self.wr_address = fis.lba_lsb
|
||||
self.wr_length = fis.count*self.hdd_sector_size
|
||||
self.wr_cnt = 0
|
||||
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_cmd(self, fis):
|
||||
self.rd_address = fis.lba_lsb
|
||||
self.rd_length = fis.count*self.hdd_sector_size
|
||||
self.rd_cnt = 0
|
||||
n = math.ceil(self.rd_length/(2048*4))
|
||||
packets = [FIS_REG_D2H()]
|
||||
for i in range(n):
|
||||
length = min(self.rd_length-self.rd_cnt, 2048)
|
||||
packet = self.read_mem(self.rd_address, length)
|
||||
packet.insert(0, 0)
|
||||
packets.insert(0, FIS_DATA(packet, direction="D2H"))
|
||||
return packets
|
||||
def read_dma_callback(self, fis):
|
||||
sector = fis.lba_lsb + (fis.lba_msb << 32)
|
||||
packet = self.read(sector, fis.count)
|
||||
packet.insert(0, 0)
|
||||
return [FIS_DATA(packet, direction="D2H"), FIS_REG_D2H()]
|
||||
|
||||
def identify_dma_cmd(self, fis):
|
||||
def identify_dma_callback(self, fis):
|
||||
packet = [i for i in range(256)]
|
||||
packet.insert(0, 0)
|
||||
return [FIS_DATA(packet, direction="D2H"), FIS_REG_D2H()]
|
||||
|
||||
def data_cmd(self, fis):
|
||||
self.write_mem(self.wr_address, fis.packet[1:])
|
||||
self.wr_cnt += len(fis.packet[1:])*4
|
||||
if self.wr_length == self.wr_cnt:
|
||||
def data_callback(self, fis):
|
||||
self.write(self.wr_sector, fis.packet[1:])
|
||||
self.wr_sector += self.dwords2sectors(len(fis.packet[1:]))
|
||||
if self.wr_sector == self.wr_end_sector:
|
||||
return [FIS_REG_D2H()]
|
||||
else:
|
||||
return [FIS_DMA_ACTIVATE_D2H()]
|
||||
|
|
|
@ -54,7 +54,7 @@ class SATATransportTX(Module):
|
|||
sink.ack.eq(1)
|
||||
)
|
||||
).Else(
|
||||
sink.ack.eq(sink.stb)
|
||||
sink.ack.eq(1)
|
||||
)
|
||||
)
|
||||
fsm.act("SEND_REG_H2D_CMD",
|
||||
|
@ -161,7 +161,6 @@ class SATATransportRX(Module):
|
|||
).Elif(test_type("DATA"),
|
||||
NextState("RECEIVE_DATA_CMD"),
|
||||
).Else(
|
||||
# XXX: Better to ack?
|
||||
link.source.ack.eq(1)
|
||||
)
|
||||
).Else(
|
||||
|
@ -180,7 +179,7 @@ class SATATransportRX(Module):
|
|||
source.sop.eq(1),
|
||||
source.eop.eq(1),
|
||||
_decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
|
||||
If(source.ack,
|
||||
If(source.stb & source.ack,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
@ -196,7 +195,7 @@ class SATATransportRX(Module):
|
|||
source.sop.eq(1),
|
||||
source.eop.eq(1),
|
||||
_decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
|
||||
If(source.ack,
|
||||
If(source.stb & source.ack,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue