soc/interconnect/csr: add initial field support

This commit is contained in:
Florent Kermarrec 2019-09-13 20:01:31 +02:00
parent c120f6d457
commit 8c080e5fb6
3 changed files with 97 additions and 2 deletions

View File

@ -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, r += _get_rw_functions_c(name + "_" + csr.name, origin, nr, busword, alignment,
isinstance(csr, CSRStatus), with_access_functions) isinstance(csr, CSRStatus), with_access_functions)
origin += alignment//8*nr 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" r += "\n/* constants */\n"
for name, value in constants: for name, value in constants:

View File

@ -122,6 +122,57 @@ class _CompoundCSR(_CSRBase, Module):
raise NotImplementedError 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): class CSRStatus(_CompoundCSR):
"""Status Register. """Status Register.
@ -156,9 +207,15 @@ class CSRStatus(_CompoundCSR):
The value of the CSRStatus register. 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) _CompoundCSR.__init__(self, size, name)
self.status = Signal(self.size, reset=reset) 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): def do_finalize(self, busword):
nwords = (self.size + busword - 1)//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) _CompoundCSR.__init__(self, size, name)
self.alignment_bits = alignment_bits self.alignment_bits = alignment_bits
self.storage_full = Signal(self.size, reset=reset) self.storage_full = Signal(self.size, reset=reset)
@ -239,6 +300,8 @@ class CSRStorage(_CompoundCSR):
self.we = Signal() self.we = Signal()
self.dat_w = Signal(self.size - self.alignment_bits) self.dat_w = Signal(self.size - self.alignment_bits)
self.sync += If(self.we, self.storage_full.eq(self.dat_w << 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): def do_finalize(self, busword):
nwords = (self.size + busword - 1)//busword nwords = (self.size + busword - 1)//busword

View File

@ -94,3 +94,31 @@ class TestCSR(unittest.TestCase):
dut = CSRDUT() dut = CSRDUT()
run_simulation(dut, generator(dut)) 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))