hdl.mem: implement memories.

This commit is contained in:
whitequark 2018-12-21 01:53:32 +00:00
parent 6672ab2e3f
commit 6d9a6b5d84
4 changed files with 104 additions and 6 deletions

View file

@ -54,9 +54,14 @@ Compatibility summary
- () `Tristate` ?
- (+) `TSTriple``.lib.io.TSTriple`, `bits_sign=`→`shape=`
- () `Instance` ?
- () `READ_FIRST`/`WRITE_FIRST`/`NO_CHANGE` ?
- () `_MemoryPort` ?
- () `Memory` ?
- () `Memory` id
- () `.get_port` **obs**`.read_port()` + `.write_port()`
- () `_MemoryPort` **obs**
<br>Note: nMigen separates read and write ports.
- () `READ_FIRST`/`WRITE_FIRST` **obs**
<br>Note: `READ_FIRST` corresponds to `mem.read_port(transparent=False)`, and `WRITE_FIRST` to `mem.read_port(transparent=True)`.
- (-) `NO_CHANGE` **brk**
<br>Note: in designs using `NO_CHANGE`, repalce it with an asynchronous read port and logic implementing required semantics explicitly.
- () `structure``.hdl.ast`
- (+) `DUID` id
- (+) `_Value``Value`

View file

@ -2,6 +2,7 @@ from .hdl.ast import Value, Const, C, Mux, Cat, Repl, Array, Signal, ClockSignal
from .hdl.dsl import Module
from .hdl.cd import ClockDomain
from .hdl.ir import Fragment, Instance
from .hdl.mem import Memory
from .hdl.xfrm import ResetInserter, CEInserter
from .lib.cdc import MultiReg

View file

@ -236,7 +236,7 @@ class Const(Value):
shape = shape, self.value < 0
self.nbits, self.signed = shape
if not isinstance(self.nbits, int) or self.nbits < 0:
raise TypeError("Width must be a non-negative integer")
raise TypeError("Width must be a non-negative integer, not '{!r}'", self.nbits)
self.value = self.normalize(self.value, shape)
def shape(self):
@ -1067,7 +1067,7 @@ class ValueSet(_MappedKeySet):
class SignalKey:
def __init__(self, signal):
if type(signal) is not Signal:
raise TypeError("Object '{!r}' is not an nMigen signal")
raise TypeError("Object '{!r}' is not an nMigen signal".format(signal))
self.signal = signal
def __hash__(self):
@ -1080,7 +1080,7 @@ class SignalKey:
def __lt__(self, other):
if type(other) is not SignalKey:
raise TypeError("Object '{!r}' cannot be compared to a SignalKey")
raise TypeError("Object '{!r}' cannot be compared to a SignalKey".format(signal))
return self.signal.duid < other.signal.duid
def __repr__(self):

92
nmigen/hdl/mem.py Normal file
View file

@ -0,0 +1,92 @@
import traceback
from .. import tracer
from .ast import *
from .ir import Instance
class Memory:
def __init__(self, width, depth, init=None, name=None):
if not isinstance(width, int) or width < 0:
raise TypeError("Memory width must be a non-negative integer, not '{!r}'"
.format(width))
if not isinstance(depth, int) or depth < 0:
raise TypeError("Memory depth must be a non-negative integer, not '{!r}'"
.format(depth))
tb = traceback.extract_stack(limit=2)
self.src_loc = (tb[0].filename, tb[0].lineno)
if name is None:
try:
name = tracer.get_var_name(depth=2)
except tracer.NameNotFound:
name = "$memory"
self.name = name
self.width = width
self.depth = depth
self.init = None if init is None else list(init)
def read_port(self, domain="sync", asynchronous=False, transparent=True):
return ReadPort(self, domain, asynchronous, transparent)
def write_port(self, domain="sync", priority=0, granularity=None):
if granularity is None:
granularity = self.width
if not isinstance(granularity, int) or granularity < 0 or granularity > self.width:
raise TypeError("Write port granularity must be a non-negative integer not greater "
"than memory width, not '{!r}'"
.format(granularity))
return WritePort(self, domain, priority, granularity)
class ReadPort:
def __init__(self, memory, domain, asynchronous, transparent):
self.memory = memory
self.domain = domain
self.asynchronous = asynchronous
self.transparent = transparent
self.addr = Signal(max=memory.depth)
self.data = Signal(memory.width)
self.en = Signal()
def get_fragment(self, platform):
return Instance("$memrd",
p_MEMID=self.memory,
p_ABITS=self.addr.nbits,
p_WIDTH=self.data.nbits,
p_CLK_ENABLE=not self.asynchronous,
p_CLK_POLARITY=1,
p_TRANSPARENT=self.transparent,
i_CLK=ClockSignal(self.domain),
i_EN=self.en,
i_ADDR=self.addr,
o_DATA=self.data,
)
class WritePort:
def __init__(self, memory, domain, priority, granularity):
self.memory = memory
self.domain = domain
self.priority = priority
self.granularity = granularity
self.addr = Signal(max=memory.depth)
self.data = Signal(memory.width)
self.en = Signal(memory.width // granularity)
def get_fragment(self, platform):
return Instance("$memwr",
p_MEMID=self.memory,
p_ABITS=self.addr.nbits,
p_WIDTH=self.data.nbits,
p_CLK_ENABLE=1,
p_CLK_POLARITY=1,
p_PRIORITY=self.priority,
i_CLK=ClockSignal(self.domain),
i_EN=Cat(Repl(en_bit, self.granularity) for en_bit in self.en),
i_ADDR=self.addr,
i_DATA=self.data,
)