Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b0bd7bfaca2a
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c49211c76ab1
Choose a head ref
  • 3 commits
  • 6 files changed
  • 1 contributor

Commits on Dec 21, 2018

  1. Copy the full SHA
    8d58cbf View commit details
  2. Copy the full SHA
    a061bfa View commit details
  3. hdl.mem: add tests for all error conditions.

    whitequark committed Dec 21, 2018
    Copy the full SHA
    c49211c View commit details
Showing with 140 additions and 22 deletions.
  1. +0 −1 examples/mem.py
  2. +3 −5 nmigen/back/rtlil.py
  3. +0 −2 nmigen/back/verilog.py
  4. +27 −13 nmigen/hdl/mem.py
  5. +1 −1 nmigen/test/test_hdl_cd.py
  6. +109 −0 nmigen/test/test_hdl_mem.py
1 change: 0 additions & 1 deletion examples/mem.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@ def get_fragment(self, platform):
m.d.comb += [
rdport.addr.eq(self.adr),
self.dat_r.eq(rdport.data),
rdport.en.eq(1),
wrport.addr.eq(self.adr),
wrport.data.eq(self.dat_w),
wrport.en.eq(self.we),
8 changes: 3 additions & 5 deletions nmigen/back/rtlil.py
Original file line number Diff line number Diff line change
@@ -645,11 +645,9 @@ def convert_fragment(builder, fragment, name, top):

sub_ports = OrderedDict()
for port, value in sub_port_map.items():
if isinstance(value, ast.Signal):
sigspec = compiler_state.resolve_curr(value, prefix=sub_name)
else:
sigspec = rhs_compiler(value)
sub_ports[port] = sigspec
for signal in value._rhs_signals():
compiler_state.resolve_curr(signal, prefix=sub_name)
sub_ports[port] = rhs_compiler(value)

module.cell(sub_type, name=sub_name, ports=sub_ports, params=sub_params)

2 changes: 0 additions & 2 deletions nmigen/back/verilog.py
Original file line number Diff line number Diff line change
@@ -27,11 +27,9 @@ def convert(*args, **kwargs):
proc_arst
proc_dff
proc_clean
design -save orig
memory_collect
write_verilog
# Make sure there are no undriven wires in generated RTLIL.
design -load orig
proc
select -assert-none w:* i:* %a %d o:* %a %ci* %d c:* %co* %a %d n:$* %d
""".format(il_text))
40 changes: 27 additions & 13 deletions nmigen/hdl/mem.py
Original file line number Diff line number Diff line change
@@ -28,39 +28,53 @@ def __init__(self, width, depth, init=None, name=None):
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)
if self.init is not None and len(self.init) > self.depth:
raise ValueError("Memory initialization value count exceed memory depth ({} > {})"
.format(len(self.init), self.depth))

def read_port(self, domain="sync", synchronous=True, transparent=True):
if not synchronous and not transparent:
raise ValueError("Read port cannot be simultaneously asynchronous and non-transparent")
return ReadPort(self, domain, synchronous, 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}'"
if not isinstance(granularity, int) or granularity < 0:
raise TypeError("Write port granularity must be a non-negative integer, not '{!r}'"
.format(granularity))
if granularity > self.width:
raise ValueError("Write port granularity must not be greater than memory width "
"({} > {})"
.format(granularity, self.width))
if self.width // granularity * granularity != self.width:
raise ValueError("Write port granularity must divide memory width evenly")
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
def __init__(self, memory, domain, synchronous, transparent):
self.memory = memory
self.domain = domain
self.synchronous = synchronous
self.transparent = transparent

self.addr = Signal(max=memory.depth)
self.data = Signal(memory.width)
self.en = Signal()
if synchronous and not transparent:
self.en = Signal()
else:
self.en = Const(1)

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_ENABLE=self.synchronous,
p_CLK_POLARITY=1,
p_TRANSPARENT=self.transparent,
i_CLK=ClockSignal(self.domain),
i_CLK=ClockSignal(self.domain) if self.synchronous else Const(0),
i_EN=self.en,
i_ADDR=self.addr,
o_DATA=self.data,
2 changes: 1 addition & 1 deletion nmigen/test/test_hdl_cd.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
from .tools import *


class ClockDomainCase(FHDLTestCase):
class ClockDomainTestCase(FHDLTestCase):
def test_name(self):
sync = ClockDomain()
self.assertEqual(sync.name, "sync")
109 changes: 109 additions & 0 deletions nmigen/test/test_hdl_mem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from ..hdl.ast import *
from ..hdl.mem import *
from .tools import *


class MemoryTestCase(FHDLTestCase):
def test_name(self):
m1 = Memory(width=8, depth=4)
self.assertEqual(m1.name, "m1")
m2 = [Memory(width=8, depth=4)][0]
self.assertEqual(m2.name, "$memory")
m3 = Memory(width=8, depth=4, name="foo")
self.assertEqual(m3.name, "foo")

def test_geometry(self):
m = Memory(width=8, depth=4)
self.assertEqual(m.width, 8)
self.assertEqual(m.depth, 4)

def test_geometry_wrong(self):
with self.assertRaises(TypeError,
msg="Memory width must be a non-negative integer, not '-1'"):
m = Memory(width=-1, depth=4)
with self.assertRaises(TypeError,
msg="Memory depth must be a non-negative integer, not '-1'"):
m = Memory(width=8, depth=-1)

def test_init(self):
m = Memory(width=8, depth=4, init=range(4))
self.assertEqual(m.init, [0, 1, 2, 3])

def test_init_wrong(self):
with self.assertRaises(ValueError,
msg="Memory initialization value count exceed memory depth (8 > 4)"):
m = Memory(width=8, depth=4, init=range(8))

def test_read_port_transparent(self):
mem = Memory(width=8, depth=4)
rdport = mem.read_port()
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.synchronous, True)
self.assertEqual(rdport.transparent, True)
self.assertEqual(len(rdport.addr), 2)
self.assertEqual(len(rdport.data), 8)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Const)
self.assertEqual(rdport.en.value, 1)

def test_read_port_non_transparent(self):
mem = Memory(width=8, depth=4)
rdport = mem.read_port(transparent=False)
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.synchronous, True)
self.assertEqual(rdport.transparent, False)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal)

def test_read_port_asynchronous(self):
mem = Memory(width=8, depth=4)
rdport = mem.read_port(synchronous=False)
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.synchronous, False)
self.assertEqual(rdport.transparent, True)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Const)
self.assertEqual(rdport.en.value, 1)

def test_read_port_wrong(self):
mem = Memory(width=8, depth=4)
with self.assertRaises(ValueError,
msg="Read port cannot be simultaneously asynchronous and non-transparent"):
mem.read_port(synchronous=False, transparent=False)

def test_write_port(self):
mem = Memory(width=8, depth=4)
wrport = mem.write_port()
self.assertEqual(wrport.memory, mem)
self.assertEqual(wrport.domain, "sync")
self.assertEqual(wrport.priority, 0)
self.assertEqual(wrport.granularity, 8)
self.assertEqual(len(wrport.addr), 2)
self.assertEqual(len(wrport.data), 8)
self.assertEqual(len(wrport.en), 1)

def test_write_port_granularity(self):
mem = Memory(width=8, depth=4)
wrport = mem.write_port(granularity=2)
self.assertEqual(wrport.memory, mem)
self.assertEqual(wrport.domain, "sync")
self.assertEqual(wrport.priority, 0)
self.assertEqual(wrport.granularity, 2)
self.assertEqual(len(wrport.addr), 2)
self.assertEqual(len(wrport.data), 8)
self.assertEqual(len(wrport.en), 4)

def test_write_port_granularity_wrong(self):
mem = Memory(width=8, depth=4)
with self.assertRaises(TypeError,
msg="Write port granularity must be a non-negative integer, not '-1'"):
mem.write_port(granularity=-1)
with self.assertRaises(ValueError,
msg="Write port granularity must not be greater than memory width (10 > 8)"):
mem.write_port(granularity=10)
with self.assertRaises(ValueError,
msg="Write port granularity must divide memory width evenly"):
mem.write_port(granularity=3)