89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
from migen.fhdl.structure import *
|
|
|
|
class RegisterRaw:
|
|
def __init__(self, name, size=1):
|
|
self.name = name
|
|
self.size = size
|
|
self.re = Signal()
|
|
self.r = Signal(BV(self.size))
|
|
self.w = Signal(BV(self.size))
|
|
|
|
(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3)
|
|
|
|
class Field:
|
|
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0):
|
|
self.name = name
|
|
self.size = size
|
|
self.access_bus = access_bus
|
|
self.access_dev = access_dev
|
|
self.storage = Signal(BV(self.size), reset=reset)
|
|
if self.access_bus == READ_ONLY and self.access_dev == WRITE_ONLY:
|
|
self.w = Signal(BV(self.size))
|
|
else:
|
|
if self.access_dev == READ_ONLY or self.access_dev == READ_WRITE:
|
|
self.r = Signal(BV(self.size))
|
|
if self.access_dev == WRITE_ONLY or self.access_dev == READ_WRITE:
|
|
self.w = Signal(BV(self.size))
|
|
self.we = Signal()
|
|
|
|
class RegisterFields:
|
|
def __init__(self, name, fields, re=None):
|
|
self.name = name
|
|
self.fields = fields
|
|
if re is None:
|
|
self.re = Signal()
|
|
else:
|
|
self.re = re
|
|
|
|
class RegisterField(RegisterFields):
|
|
def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0):
|
|
self.field = Field(name, size, access_bus, access_dev, reset)
|
|
super().__init__(name, [self.field])
|
|
|
|
class FieldAlias:
|
|
def __init__(self, f, start, end):
|
|
self.size = end - start
|
|
self.access_bus = f.access_bus
|
|
self.access_dev = f.access_dev
|
|
self.storage = f.storage[start:end]
|
|
# device access is through the original field
|
|
|
|
def expand_description(description, busword):
|
|
d = []
|
|
for reg in description:
|
|
if isinstance(reg, RegisterRaw):
|
|
if reg.size > busword:
|
|
raise ValueError("Raw register larger than a bus word")
|
|
d.append(reg)
|
|
elif isinstance(reg, RegisterFields):
|
|
f = []
|
|
size = 0
|
|
for field in reg.fields:
|
|
size += field.size
|
|
if size > busword:
|
|
# add padding
|
|
totalsize = sum([field.size for field in reg.fields])
|
|
padding = busword - (totalsize % busword)
|
|
if padding == busword:
|
|
padding = 0
|
|
size += padding
|
|
|
|
top = field.size
|
|
while size > busword:
|
|
slice1 = busword - size + top
|
|
slice2 = min(size - busword, busword)
|
|
if slice1:
|
|
f.append(FieldAlias(field, top - slice1, top))
|
|
top -= slice1
|
|
d.append(RegisterFields(reg.name, f))
|
|
f = [FieldAlias(field, top - slice2, top)]
|
|
top -= slice2
|
|
size -= busword
|
|
else:
|
|
f.append(field)
|
|
if f:
|
|
d.append(RegisterFields(reg.name, f, reg.re))
|
|
else:
|
|
raise TypeError
|
|
return d
|