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,
|
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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue