bfm: create basic HDD model

This commit is contained in:
Florent Kermarrec 2014-12-14 11:44:12 +01:00
parent 1e68b1a907
commit b6d5e23264
2 changed files with 62 additions and 39 deletions

View File

@ -5,6 +5,7 @@ from migen.fhdl.std import *
from lib.sata.common import * from lib.sata.common import *
from lib.sata.test.common import * from lib.sata.test.common import *
# PHY Layer model
class PHYDword: class PHYDword:
def __init__(self, dat=0): def __init__(self, dat=0):
self.dat = dat self.dat = dat
@ -76,6 +77,7 @@ class PHYLayer(Module):
return receiving + sending return receiving + sending
# Link Layer model
def import_scrambler_datas(): def import_scrambler_datas():
with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process: with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
process.stdin.write("0x10000".encode("ASCII")) process.stdin.write("0x10000".encode("ASCII"))
@ -259,6 +261,7 @@ class LinkLayer(Module):
self.callback(rx_dword) self.callback(rx_dword)
self.insert_cont() self.insert_cont()
# Transport Layer model
def get_field_data(field, packet): def get_field_data(field, packet):
return (packet[field.dword] >> field.offset) & (2**field.width-1) return (packet[field.dword] >> field.offset) & (2**field.width-1)
@ -371,66 +374,87 @@ class TransportLayer(Module):
else: else:
self.command_callback(fis) self.command_callback(fis)
# Command Layer model
class CommandLayer(Module): class CommandLayer(Module):
def __init__(self, transport, debug=False): def __init__(self, transport, debug=False):
self.transport = transport self.transport = transport
self.debug = debug self.debug = debug
self.transport.set_command_callback(self.callback) self.transport.set_command_callback(self.callback)
self.dma_enable = 0 self.hdd = None
self.dma_address = 0
def allocate_dma(self, base, length): def set_hdd(self, hdd):
self.dma_base = base self.hdd = hdd
self.dma_buffer = [0]*(length//4)
def enable_dma(self):
self.dma_enable = 1
def disable_dma(self):
self.dma_enable = 0
def dma_write(self, adr, data):
current_adr = (adr-self.dma_base)//4
for i in range(len(data)):
self.dma_buffer[current_adr+i] = data[i]
def dma_read(self, adr, length=1):
current_adr = (adr-self.dma_base)//4
data = []
for i in range(length//4):
data.append(self.dma_buffer[current_adr+i])
return data
def callback(self, fis): def callback(self, fis):
# XXX maximum of 2048 DWORDS per DMA # XXX manage maximum of 2048 DWORDS per DMA
if isinstance(fis, FIS_REG_H2D): if isinstance(fis, FIS_REG_H2D):
if fis.command == regs["WRITE_DMA_EXT"]: if fis.command == regs["WRITE_DMA_EXT"]:
self.dma_address = fis.lba_lsb self.transport.send(self.hdd.write_dma_cmd(fis))
dma_activate = FIS_DMA_ACTIVATE_D2H()
self.transport.send(dma_activate)
elif fis.command == regs["READ_DMA_EXT"]: elif fis.command == regs["READ_DMA_EXT"]:
self.dma_address = fis.lba_lsb self.transport.send(self.hdd.read_dma_cmd(fis))
data = FIS_DATA(self.dma_read(fis.lba_lsb, fis.count*4))
self.transport.send(data)
elif fis.command == regs["IDENTIFY_DEVICE_DMA"]: elif fis.command == regs["IDENTIFY_DEVICE_DMA"]:
self.dma_address = fis.lba_lsb self.transport.send(self.hdd.identify_device_dma_cmd(fis))
data = FIS_DATA(self.dma_read(fis.lba_lsb, fis.count*4))
self.transport.send(data)
elif isinstance(fis, FIS_DATA): elif isinstance(fis, FIS_DATA):
if self.dma_enable: self.hdd.data_cmd(fis)
self.dma_write(self.dma_address, fis.packet[1:])
self.dma_address += len(fis.packet[1:]) # HDD model
class HDDMemRegion:
def __init__(self, base, length):
self.base = base
self.length = length
self.data = [0]*(length//4)
class HDD(Module):
def __init__(self, command, debug=False):
self.command = command
command.set_hdd(self)
self.mem = None
self.wr_address = 0
def write_dma_cmd(self, fis):
self.wr_address = fis.lba_lsb
return FIS_DMA_ACTIVATE_D2H()
def read_dma_cmd(self, fis):
return FIS_DATA(self.read_mem(fis.lba_lsb, fis.count*4))
def identify_dma_cmd(self, fis):
return FIS_DATA([i for i in range(256)])
def data_cmd(self, fis):
self.write_mem(self.wr_address, fis.packet[1:])
def allocate_mem(self, base, length):
# XXX add support for multiple memory regions
self.mem = HDDMemRegion(base, length)
def write_mem(self, adr, data):
# XXX test if adr allocate in one memory region
current_adr = (adr-self.mem.base)//4
for i in range(len(data)):
self.mem.data[current_adr+i] = data[i]
def read_mem(self, adr, length=1):
# XXX test if adr allocate in one memory region
current_adr = (adr-self.mem.base)//4
data = []
for i in range(length//4):
data.append(self.mem.data[current_adr+i])
return data
class BFM(Module): class BFM(Module):
def __init__(self, def __init__(self,
phy_debug=False, phy_debug=False,
link_debug=False, link_random_level=0, link_debug=False, link_random_level=0,
transport_debug=False, transport_loopback=False, transport_debug=False, transport_loopback=False,
command_debug=False command_debug=False,
hdd_debug=False
): ):
### ###
self.submodules.phy = PHYLayer(phy_debug) self.submodules.phy = PHYLayer(phy_debug)
self.submodules.link = LinkLayer(self.phy, link_debug, link_random_level) self.submodules.link = LinkLayer(self.phy, link_debug, link_random_level)
self.submodules.transport = TransportLayer(self.link, transport_debug, transport_loopback) self.submodules.transport = TransportLayer(self.link, transport_debug, transport_loopback)
self.submodules.command = CommandLayer(self.transport, command_debug) self.submodules.command = CommandLayer(self.transport, command_debug)
self.submodules.hdd = HDD(self.command, hdd_debug)

View File

@ -21,8 +21,7 @@ class TB(Module):
self.submodules.command = SATACommand(self.transport) self.submodules.command = SATACommand(self.transport)
def gen_simulation(self, selfp): def gen_simulation(self, selfp):
self.bfm.command.allocate_dma(0x00000000, 64*1024*1024) self.bfm.hdd.allocate_mem(0x00000000, 64*1024*1024)
self.bfm.command.enable_dma()
selfp.command.source.ack = 1 selfp.command.source.ack = 1
for i in range(100): for i in range(100):
yield yield