soc/interconnect/csr: add initial field support
This commit is contained in:
parent
c120f6d457
commit
8c080e5fb6
|
@ -181,6 +181,10 @@ def get_csr_header(regions, constants, with_access_functions=True, with_shadow_b
|
|||
r += _get_rw_functions_c(name + "_" + csr.name, origin, nr, busword, alignment,
|
||||
isinstance(csr, CSRStatus), with_access_functions)
|
||||
origin += alignment//8*nr
|
||||
if hasattr(csr, "fields"):
|
||||
for field in csr.fields.fields:
|
||||
r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_OFFSET "+str(field.offset)+"\n"
|
||||
r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_SIZE "+str(field.size)+"\n"
|
||||
|
||||
r += "\n/* constants */\n"
|
||||
for name, value in constants:
|
||||
|
|
|
@ -122,6 +122,57 @@ class _CompoundCSR(_CSRBase, Module):
|
|||
raise NotImplementedError
|
||||
|
||||
|
||||
class CSRField(Signal):
|
||||
def __init__(self, name, size=1, offset=None, reset=0, description=None, values=None):
|
||||
assert name == name.lower()
|
||||
self.name = name
|
||||
self.size = size
|
||||
self.offset = offset
|
||||
self.reset_value = reset
|
||||
self.description = description
|
||||
self.values = values
|
||||
Signal.__init__(self, size, name=name, reset=reset)
|
||||
|
||||
|
||||
class CSRFieldCompound:
|
||||
def __init__(self, fields):
|
||||
self.check_names(fields)
|
||||
self.check_ordering_overlap(fields)
|
||||
self.fields = fields
|
||||
for field in fields:
|
||||
setattr(self, field.name, field)
|
||||
|
||||
@staticmethod
|
||||
def check_names(fields):
|
||||
names = []
|
||||
for field in fields:
|
||||
if field.name in names:
|
||||
raise ValueError("CSRField \"{}\" name is already used in CSR".format(field.name))
|
||||
else:
|
||||
names.append(field.name)
|
||||
|
||||
@staticmethod
|
||||
def check_ordering_overlap(fields):
|
||||
offset = 0
|
||||
for field in fields:
|
||||
if field.offset is not None:
|
||||
if field.offset < offset:
|
||||
raise ValueError("CSRField ordering/overlap issue on \"{}\" field".format(field.name))
|
||||
offset = field.offset
|
||||
else:
|
||||
field.offset = offset
|
||||
offset += field.size
|
||||
|
||||
def get_size(self):
|
||||
return self.fields[-1].offset + self.fields[-1].size
|
||||
|
||||
def get_reset(self):
|
||||
reset = 0
|
||||
for field in self.fields:
|
||||
reset |= (field.reset_value << field.offset)
|
||||
return reset
|
||||
|
||||
|
||||
class CSRStatus(_CompoundCSR):
|
||||
"""Status Register.
|
||||
|
||||
|
@ -156,9 +207,15 @@ class CSRStatus(_CompoundCSR):
|
|||
The value of the CSRStatus register.
|
||||
"""
|
||||
|
||||
def __init__(self, size=1, reset=0, name=None):
|
||||
def __init__(self, size=1, reset=0, fields=[], name=None, description=None):
|
||||
if fields != []:
|
||||
self.fields = CSRFieldCompound(fields)
|
||||
size = self.fields.get_size()
|
||||
reset = self.fields.get_reset()
|
||||
_CompoundCSR.__init__(self, size, name)
|
||||
self.status = Signal(self.size, reset=reset)
|
||||
for field in fields:
|
||||
self.comb += self.status[field.offset:field.offset + field.size].eq(getattr(self.fields, field.name))
|
||||
|
||||
def do_finalize(self, busword):
|
||||
nwords = (self.size + busword - 1)//busword
|
||||
|
@ -227,7 +284,11 @@ class CSRStorage(_CompoundCSR):
|
|||
???
|
||||
"""
|
||||
|
||||
def __init__(self, size=1, reset=0, atomic_write=False, write_from_dev=False, alignment_bits=0, name=None):
|
||||
def __init__(self, size=1, reset=0, fields=[], atomic_write=False, write_from_dev=False, alignment_bits=0, name=None, description=None):
|
||||
if fields != []:
|
||||
self.fields = CSRFieldCompound(fields)
|
||||
size = self.fields.get_size()
|
||||
reset = self.fields.get_reset()
|
||||
_CompoundCSR.__init__(self, size, name)
|
||||
self.alignment_bits = alignment_bits
|
||||
self.storage_full = Signal(self.size, reset=reset)
|
||||
|
@ -239,6 +300,8 @@ class CSRStorage(_CompoundCSR):
|
|||
self.we = Signal()
|
||||
self.dat_w = Signal(self.size - self.alignment_bits)
|
||||
self.sync += If(self.we, self.storage_full.eq(self.dat_w << self.alignment_bits))
|
||||
for field in [*fields]:
|
||||
self.comb += getattr(self.fields, field.name).eq(self.storage[field.offset:field.offset + field.size])
|
||||
|
||||
def do_finalize(self, busword):
|
||||
nwords = (self.size + busword - 1)//busword
|
||||
|
|
|
@ -94,3 +94,31 @@ class TestCSR(unittest.TestCase):
|
|||
|
||||
dut = CSRDUT()
|
||||
run_simulation(dut, generator(dut))
|
||||
|
||||
def test_csr_fields(self):
|
||||
def generator(dut):
|
||||
# check reset values
|
||||
self.assertEqual((yield dut._storage.fields.foo), 0xa)
|
||||
self.assertEqual((yield dut._storage.fields.bar), 0x5a)
|
||||
self.assertEqual((yield dut._storage.storage), 0x5a000a)
|
||||
yield
|
||||
yield
|
||||
self.assertEqual((yield dut._status.fields.foo), 0xa)
|
||||
self.assertEqual((yield dut._status.fields.bar), 0x5a)
|
||||
|
||||
class DUT(Module):
|
||||
def __init__(self):
|
||||
self._storage = csr.CSRStorage(fields=[
|
||||
csr.CSRField("foo", size=4, offset=0, reset=0xa, description="foo"),
|
||||
csr.CSRField("bar", size=8, offset=16, reset=0x5a, description="bar")
|
||||
])
|
||||
self._status = csr.CSRStatus(fields=[
|
||||
csr.CSRField("foo", size=4, offset=4, description="foo"),
|
||||
csr.CSRField("bar", size=8, offset=8, description="bar")
|
||||
])
|
||||
self.comb += [
|
||||
self._status.fields.foo.eq(self._storage.fields.foo),
|
||||
self._status.fields.bar.eq(self._storage.fields.bar),
|
||||
]
|
||||
dut = DUT()
|
||||
run_simulation(dut, generator(dut))
|
||||
|
|
Loading…
Reference in New Issue