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/migen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9420aabc0d8b
Choose a base ref
...
head repository: m-labs/migen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8bbfaa01fcf3
Choose a head ref
  • 5 commits
  • 5 files changed
  • 1 contributor

Commits on Sep 19, 2015

  1. Copy the full SHA
    dcf4f7f View commit details
  2. Copy the full SHA
    944a0b0 View commit details
  3. Copy the full SHA
    262fd50 View commit details
  4. Copy the full SHA
    1861ae9 View commit details
  5. sim: memory support

    sbourdeauducq committed Sep 19, 2015
    Copy the full SHA
    8bbfaa0 View commit details
Showing with 100 additions and 41 deletions.
  1. +60 −7 migen/fhdl/simplify.py
  2. +1 −4 migen/fhdl/specials.py
  3. +1 −0 migen/genlib/fifo.py
  4. +6 −3 migen/sim.py
  5. +32 −27 migen/test/test_fifo.py
67 changes: 60 additions & 7 deletions migen/fhdl/simplify.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from migen.fhdl.structure import *
from migen.fhdl.specials import _MemoryPort
from migen.fhdl.specials import Memory, _MemoryPort, WRITE_FIRST, NO_CHANGE
from migen.fhdl.decorators import ModuleTransformer
from migen.util.misc import gcd_multiple

@@ -25,18 +25,71 @@ def transform_fragment(self, i, f):
newspecials.add(newmem)
for port in orig.ports:
port_granularity = port.we_granularity if port.we_granularity else orig.width
newport = _MemoryPort(adr=port.adr,
newport = _MemoryPort(
adr=port.adr,

dat_r=port.dat_r[i*global_granularity:(i+1)*global_granularity] if port.dat_r is not None else None,
we=port.we[i*global_granularity//port_granularity] if port.we is not None else None,
dat_w=port.dat_w[i*global_granularity:(i+1)*global_granularity] if port.dat_w is not None else None,

async_read=port.async_read,
re=port.re,
we_granularity=0,
mode=port.mode,
clock_domain=port.clock)
async_read=port.async_read,
re=port.re,
we_granularity=0,
mode=port.mode,
clock_domain=port.clock)
newmem.ports.append(newport)
newspecials.add(newport)

f.specials = newspecials


class MemoryToArray(ModuleTransformer):
def transform_fragment(self, i, f):
newspecials = set()

for mem in f.specials:
if not isinstance(mem, Memory):
newspecials.add(mem)
continue

storage = Array()
init = []
if mem.init is not None:
init = mem.init
for d in init:
mem_storage = Signal(mem.width, reset=d)
storage.append(mem_storage)
for _ in range(mem.depth-len(init)):
mem_storage = Signal(mem.width)
storage.append(mem_storage)

for port in mem.ports:
if port.we_granularity:
raise NotImplementedError
try:
sync = f.sync[port.clock.cd]
except KeyError:
sync = f.sync[port.clock.cd] = []

# read
if port.async_read:
f.comb.append(port.dat_r.eq(storage[port.adr]))
else:
if port.mode == WRITE_FIRST and port.we is not None:
adr_reg = Signal.like(port.adr)
rd_stmt = adr_reg.eq(port.adr)
f.comb.append(port.dat_r.eq(storage[adr_reg]))
elif port.mode == NO_CHANGE and port.we is not None:
rd_stmt = If(~port.we, port.dat_r.eq(storage[port.adr]))
else: # READ_FIRST or port.we is None, simplest case
rd_stmt = port.dat_r.eq(storage[port.adr])
if port.re is None:
sync.append(rd_stmt)
else:
sync.append(If(port.re, rd_stmt))

# write
if port.we is not None:
sync.append(If(port.we, storage[port.adr].eq(port.dat_w)))

f.specials = newspecials
5 changes: 1 addition & 4 deletions migen/fhdl/specials.py
Original file line number Diff line number Diff line change
@@ -193,10 +193,7 @@ def __init__(self, adr, dat_r, we=None, dat_w=None,
self.re = re
self.we_granularity = we_granularity
self.mode = mode
if isinstance(clock_domain, str):
self.clock = ClockSignal(clock_domain)
else:
self.clock = clock_domain
self.clock = ClockSignal(clock_domain)

def iter_expressions(self):
for attr, target_context in [
1 change: 1 addition & 0 deletions migen/genlib/fifo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.fhdl.specials import Memory
from migen.fhdl.bitcontainer import flen
from migen.genlib.cdc import NoRetiming, MultiReg, GrayCounter
from migen.genlib.record import layout_len, Record

9 changes: 6 additions & 3 deletions migen/sim.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
_Assign, _Fragment)
from migen.fhdl.bitcontainer import flen
from migen.fhdl.tools import list_targets
from migen.fhdl.simplify import FullMemoryWE, MemoryToArray


__all__ = ["Simulator"]
@@ -114,7 +115,7 @@ def eval(self, node, postcommit=False):
return self.eval(node.choices[self.eval(node.key, postcommit)],
postcommit)
else:
# TODO: ClockSignal, ResetSignal, Memory
# TODO: ClockSignal, ResetSignal
raise NotImplementedError

def assign(self, node, value):
@@ -129,7 +130,7 @@ def assign(self, node, value):
nbits = flen(element)
self.assign(element, value & (2**nbits-1))
value >>= nbits
elif isinstance(node, Slice):
elif isinstance(node, _Slice):
full_value = self.eval(node, True)
# clear bits assigned to by the slice
full_value &= ~((2**node.stop-1) - (2**node.start-1))
@@ -140,7 +141,7 @@ def assign(self, node, value):
elif isinstance(node, _ArrayProxy):
self.assign(node.choices[self.eval(node.key)], value)
else:
# TODO: ClockSignal, ResetSignal, Memory
# TODO: ClockSignal, ResetSignal
raise NotImplementedError

def execute(self, statements):
@@ -181,6 +182,8 @@ def __init__(self, fragment_or_module, generators, clocks={"sys": 100}):
else:
self.generators[k] = [v]

FullMemoryWE().transform_fragment(None, self.fragment)
MemoryToArray().transform_fragment(None, self.fragment)
# TODO: insert_resets on sync
# comb signals return to their reset value if nothing assigns them
self.fragment.comb[0:0] = [s.eq(s.reset)
59 changes: 32 additions & 27 deletions migen/test/test_fifo.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import unittest
from itertools import count

from migen import *
from migen.genlib.fifo import SyncFIFO

from migen.test.support import SimCase, SimBench
from migen.test.support import SimCase


class SyncFIFOCase(SimCase, unittest.TestCase):
class TestBench(SimBench):
class TestBench(Module):
def __init__(self):
self.submodules.dut = SyncFIFO([("a", 32), ("b", 32)], 2)

@@ -24,31 +25,35 @@ def test_sizes(self):

def test_run_sequence(self):
seq = list(range(20))
def cb(tb, tbp):
# fire re and we at "random"
tbp.dut.we = tbp.simulator.cycle_counter % 2 == 0
tbp.dut.re = tbp.simulator.cycle_counter % 3 == 0
# the output if valid must be correct
if tbp.dut.readable and tbp.dut.re:
try:
i = seq.pop(0)
except IndexError:
raise StopSimulation
self.assertEqual(tbp.dut.dout.a, i)
self.assertEqual(tbp.dut.dout.b, i*2)
self.run_with(cb)
def gen():
for cycle in count():
# fire re and we at "random"
yield self.tb.dut.we, cycle % 2 == 0
yield self.tb.dut.re, cycle % 3 == 0
# the output if valid must be correct
if (yield self.tb.dut.readable) and (yield self.tb.dut.re):
try:
i = seq.pop(0)
except IndexError:
break
self.assertEqual((yield self.tb.dut.dout.a), i)
self.assertEqual((yield self.tb.dut.dout.b), i*2)
yield
self.run_with(gen())

def test_replace(self):
seq = [x for x in range(20) if x % 5]
def cb(tb, tbp):
tbp.dut.we = tbp.simulator.cycle_counter % 2 == 0
tbp.dut.re = tbp.simulator.cycle_counter % 3 == 0
tbp.dut.replace = tbp.dut.din.a % 5 == 1
if tbp.dut.readable and tbp.dut.re:
try:
i = seq.pop(0)
except IndexError:
raise StopSimulation
self.assertEqual(tbp.dut.dout.a, i)
self.assertEqual(tbp.dut.dout.b, i*2)
self.run_with(cb)
def gen():
for cycle in count():
yield self.tb.dut.we, cycle % 2 == 0
yield self.tb.dut.re, cycle % 7 == 0
yield self.tb.dut.replace, (yield self.tb.dut.din.a) % 5 == 1
if (yield self.tb.dut.readable) and (yield self.tb.dut.re):
try:
i = seq.pop(0)
except IndexError:
break
self.assertEqual((yield self.tb.dut.dout.a), i)
self.assertEqual((yield self.tb.dut.dout.b), i*2)
yield
self.run_with(gen())