soc/interconnect/csr: add initial field support
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 13 Sep 2019 18:01:31 +0000 (20:01 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 13 Sep 2019 18:01:31 +0000 (20:01 +0200)
litex/soc/integration/cpu_interface.py
litex/soc/interconnect/csr.py
test/test_csr.py

index 3ac6066efdf0283fc0cdc3845e42136efeb1040e..0134fc9fe737274fd0ba5d9c17035bdd2f4f24d1 100644 (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,
                     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:
index 4165dbd24e63b1d975a1e5b4b8b26e27e2272b26..03464e4861337fee9ff35a3d342d62c54794fbe0 100644 (file)
@@ -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
index a5958650d7ea97ccde7757fc32b9ade9bdb92cdc..38a4fe1e368154ee204e8bda823b358fd96d18de 100644 (file)
@@ -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))