Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jfng committed Aug 23, 2023
1 parent 378ba08 commit a44fb7a
Show file tree
Hide file tree
Showing 8 changed files with 767 additions and 697 deletions.
1 change: 0 additions & 1 deletion amaranth_soc/csr/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .bus import *
from .event import *
from .reg import *
from . import field
65 changes: 39 additions & 26 deletions amaranth_soc/csr/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@


class Element:
class Access(enum.Enum):
"""Register access mode.
Coarse access mode for the entire register. Individual fields can have more restrictive
access mode, e.g. R/O fields can be a part of an R/W register.
"""
R = "r"
W = "w"
RW = "rw"

def readable(self):
return self == self.R or self == self.RW

def writable(self):
return self == self.W or self == self.RW

"""Peripheral-side CSR interface.
A low-level interface to a single atomically readable and writable register in a peripheral.
Expand All @@ -20,6 +36,8 @@ class Element:
----------
width : int
Width of the register.
access : :class:`Access`
Register access mode.
Attributes
----------
Expand All @@ -34,39 +52,23 @@ class Element:
Write strobe. Registers should update their value or perform the write side effect when
this strobe is asserted.
"""
def __init__(self, width):
def __init__(self, width, access):
if not isinstance(width, int) or width < 0:
raise ValueError("Width must be a non-negative integer, not {!r}"
.format(width))
if not isinstance(access, Element.Access) and access not in ("r", "w", "rw"):
raise ValueError("Access mode must be one of \"r\", \"w\", or \"rw\", not {!r}"
.format(access))
self.width = width
self.access = Element.Access(access)

self.r_data = Signal(unsigned(width))
self.r_stb = Signal()
self.w_data = Signal(unsigned(width))
self.w_stb = Signal()

@property
def readable(self):
"""Read access mode.
Returns
-------
:class:`bool`
If `True`, `r_data` and `r_stb` are assumed to be driven by the register and the CSR
bus, respectively.
"""
return False

@property
def writable(self):
"""Write access mode.
Returns
-------
:class:`bool`
If `True`, `w_data` and `w_stb` are assumed to be driven by the CSR bus.
"""
return False
def __repr__(self):
return "Element({}, {})".format(self.width, self.access)


class Interface(Record):
Expand Down Expand Up @@ -426,11 +428,23 @@ def add(self, element, *, name, addr=None, alignment=None, extend=False):
return self._map.add_resource(element, name=name, size=size, addr=addr,
alignment=alignment, extend=extend)

def add_cluster(self, cluster, *, addr=None, extend=False):
from amaranth_soc.csr.reg import Cluster # to avoid a circular import
if not isinstance(cluster, Cluster):
raise TypeError("Cluster must be an instance of csr.Cluster, not {!r}"
.format(cluster))
if cluster.memory_map.data_width != self._map.data_width:
raise ValueError("Cluster has data width {}, which is not the same as multiplexer "
"data width {}"
.format(cluster.memory_map.data_width, self._map.data_width))
return self._map.add_window(cluster.memory_map, addr=addr, extend=extend)

def elaborate(self, platform):
m = Module()

for elem, _, (elem_start, elem_end) in self._map.resources():
elem_range = range(elem_start, elem_end)
for elem_info in self._map.all_resources():
elem = elem_info.resource
elem_range = range(elem_info.start, elem_info.end)
if elem.access.readable():
self._r_shadow.add(elem_range)
if elem.access.writable():
Expand All @@ -452,7 +466,6 @@ def elaborate(self, platform):
r_chunk_data_fanin = 0

m.d.sync += r_chunk.r_en.eq(0)
m.d.sync += elem.w_stb.eq(0)

with m.Switch(self.bus.addr):
for elem_range in r_chunk.elements():
Expand Down
4 changes: 2 additions & 2 deletions amaranth_soc/csr/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from amaranth import *

from . import Multiplexer, field
from .reg import FieldMap, RegisterInterface, Register
from .reg import FieldMap, Register
from .. import event


Expand Down Expand Up @@ -38,7 +38,7 @@ def __init__(self, width):
"src": field.RW1S(width),
}))

class _EventPending(RegisterInterface):
class _EventPending(Register):
def __init__(self, width):
super().__init__(FieldMap({
"src": field.RW1C(width),
Expand Down
120 changes: 84 additions & 36 deletions amaranth_soc/csr/field.py
Original file line number Diff line number Diff line change
@@ -1,57 +1,105 @@
from .reg import GenericField
from amaranth import *

from .reg import Field


__all__ = ["R", "W", "RW", "RW1C", "RW1S"]


# Capabilities
class R(Field):
def __init__(self, shape):
super().__init__(shape, access="r")

def elaborate(self, platform):
m = Module()
m.d.comb += self.port.r_data.eq(self.data)
return m


class W(Field):
def __init__(self, shape):
super().__init__(shape, access="w")

def elaborate(self, platform):
m = Module()
m.d.comb += self.data.eq(self.port.w_data)
return m


class RW(Field):
def __init__(self, shape, *, reset=0):
super().__init__(shape, access="rw")
self._storage = Signal(shape, reset=reset)
self._reset = reset

@property
def reset(self):
return self._reset

def elaborate(self, platform):
m = Module()

with m.If(self.port.w_stb):
m.d.sync += self._storage.eq(self.port.w_data)

class _IntrRead:
@staticmethod
def intr_read(storage):
return storage
m.d.comb += [
self.port.r_data.eq(self._storage),
self.data.eq(self._storage),
]

return m

class _IntrWrite:
@staticmethod
def intr_write(storage, w_data):
return w_data

class RW1C(Field):
def __init__(self, shape, *, reset=0):
super().__init__(shape, access="rw")
self.set = Signal(shape)
self._storage = Signal(shape, reset=reset)
self._reset = reset

class _IntrSet:
@staticmethod
def intr_write(storage, w_data):
return storage | w_data
@property
def reset(self):
return self._reset

def elaborate(self, platform):
m = Module()

class _IntrClear:
@staticmethod
def intr_write(storage, w_data):
return storage & ~w_data
for i, storage_bit in enumerate(self._storage):
with m.If(self.port.w_stb & self.port.w_data[i]):
m.d.sync += storage_bit.eq(0)
with m.If(self.set[i]):
m.d.sync += storage_bit.eq(1)

m.d.comb += [
self.port.r_data.eq(self._storage),
self.data.eq(self._storage),
]

class _UserWrite:
@staticmethod
def user_write(storage, w_data):
return w_data
return m


class _UserSet:
@staticmethod
def user_write(storage, w_data):
return storage | w_data
class RW1S(Field):
def __init__(self, shape, *, reset=0):
super().__init__(shape, access="rw")
self.clear = Signal(shape)
self._storage = Signal(shape, reset=reset)

@property
def reset(self):
return self._reset

class _UserClear:
@staticmethod
def user_write(storage, w_data):
return storage & ~w_data
def elaborate(self, platform):
m = Module()

for i, storage_bit in enumerate(self._storage):
with m.If(self.clear[i]):
m.d.sync += storage_bit.eq(0)
with m.If(self.port.w_stb & self.port.w_data[i]):
m.d.sync += storage_bit.eq(1)

# Field types
m.d.comb += [
self.port.r_data.eq(self._storage),
self.data.eq(self._storage),
]

class R (_IntrRead, _UserWrite, GenericField): intr_write = None
class W ( _IntrWrite, GenericField): intr_read = None; user_write = None
class RW (_IntrRead, _IntrWrite, GenericField): user_write = None
class RW1C(_IntrRead, _IntrClear, _UserSet, GenericField): pass
class RW1S(_IntrRead, _IntrSet, _UserClear, GenericField): pass
return m
Loading

0 comments on commit a44fb7a

Please sign in to comment.