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: 8bbfaa01fcf3
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: 7f767095ec43
Choose a head ref
  • 3 commits
  • 13 files changed
  • 1 contributor

Commits on Sep 20, 2015

  1. Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    59802be View commit details
  2. Copy the full SHA
    320dffb View commit details
  3. Copy the full SHA
    7f76709 View commit details
2 changes: 1 addition & 1 deletion examples/basic/graycounter.py
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ def tb(dut):
for i in range(35):
print("{0:0{1}b} CE={2} bin={3}".format((yield dut.q),
flen(dut.q), (yield dut.ce), (yield dut.q_binary)))
yield dut.ce, prng.getrandbits(1)
yield dut.ce.eq(prng.getrandbits(1))
yield


4 changes: 2 additions & 2 deletions examples/sim/basic2.py
Original file line number Diff line number Diff line change
@@ -18,9 +18,9 @@ def counter_test(dut):
# Only assert CE every second cycle.
# => each counter value is held for two cycles.
if cycle % 2:
yield dut.ce, 0 # This is how you write to a signal.
yield dut.ce.eq(0) # This is how you write to a signal.
else:
yield dut.ce, 1
yield dut.ce.eq(1)
print("Cycle: {} Count: {}".format(cycle, (yield dut.count)))
yield

2 changes: 1 addition & 1 deletion examples/sim/fir.py
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ def fir_tb(dut, frequency, inputs, outputs):
f = 2**(dut.wsize - 1)
for cycle in range(200):
v = 0.1*cos(2*pi*frequency*cycle)
yield dut.i, int(f*v)
yield dut.i.eq(int(f*v))
inputs.append(v)
outputs.append((yield dut.o)/f)
yield
27 changes: 14 additions & 13 deletions examples/sim/memory.py
Original file line number Diff line number Diff line change
@@ -7,19 +7,20 @@ def __init__(self):
# from 0 to 19.
self.specials.mem = Memory(16, 2**12, init=list(range(20)))

def do_simulation(self, selfp):
# Read the memory. Use the cycle counter as address.
value = selfp.mem[selfp.simulator.cycle_counter]
# Print the result. Output is:
# 0
# 1
# 2
# ...

def memory_test(dut):
# write (only first 5 values)
for i in range(5):
yield dut.mem[i].eq(42 + i)
# remember: values are written after the tick, and read before the tick.
# wait one tick for the memory to update.
yield
# read what we have written, plus some initialization data
for i in range(10):
value = yield dut.mem[i]
print(value)
# Raising StopSimulation disables the current (and here, only one)
# simulation function. Simulator stops when all functions are disabled.
if value == 10:
raise StopSimulation


if __name__ == "__main__":
run_simulation(Mem())
dut = Mem()
Simulator(dut, memory_test(dut)).run()
21 changes: 20 additions & 1 deletion migen/fhdl/simplify.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,9 @@


class FullMemoryWE(ModuleTransformer):
def __init__(self):
self.replacments = dict()

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

@@ -16,13 +19,15 @@ def transform_fragment(self, i, f):
if global_granularity == orig.width:
newspecials.add(orig) # nothing to do
else:
newmems = []
for i in range(orig.width//global_granularity):
if orig.init is None:
newinit = None
else:
newinit = [(v >> i*global_granularity) & (2**global_granularity - 1) for v in orig.init]
newmem = Memory(global_granularity, orig.depth, newinit, orig.name_override + "_grain" + str(i))
newspecials.add(newmem)
newmems.append(newmem)
for port in orig.ports:
port_granularity = port.we_granularity if port.we_granularity else orig.width
newport = _MemoryPort(
@@ -39,11 +44,15 @@ def transform_fragment(self, i, f):
clock_domain=port.clock)
newmem.ports.append(newport)
newspecials.add(newport)
self.replacments[orig] = newmems

f.specials = newspecials


class MemoryToArray(ModuleTransformer):
def __init__(self):
self.replacements = dict()

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

@@ -53,6 +62,7 @@ def transform_fragment(self, i, f):
continue

storage = Array()
self.replacements[mem] = storage
init = []
if mem.init is not None:
init = mem.init
@@ -90,6 +100,15 @@ def transform_fragment(self, i, f):

# write
if port.we is not None:
sync.append(If(port.we, storage[port.adr].eq(port.dat_w)))
if port.we_granularity:
n = mem.width//port.we_granularity
for i in range(n):
m = i*port.we_granularity
M = (i+1)*port.we_granularity
sync.append(If(port.we[i],
storage[port.adr][m:M].eq(port.dat_w)))
else:
sync.append(If(port.we,
storage[port.adr].eq(port.dat_w)))

f.specials = newspecials
19 changes: 17 additions & 2 deletions migen/fhdl/specials.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from operator import itemgetter

from migen.fhdl.structure import *
from migen.fhdl.structure import _DUID
from migen.fhdl.structure import _DUID, _Value
from migen.fhdl.bitcontainer import bits_for, value_bits_sign
from migen.fhdl.tools import *
from migen.fhdl.tracer import get_obj_var_name
@@ -210,6 +210,18 @@ def emit_verilog(port, ns, add_data_file):
return "" # done by parent Memory object


class _MemoryLocation(_Value):
def __init__(self, memory, index):
_Value.__init__(self)
if isinstance(index, (bool, int)):
index = Constant(index)
if not isinstance(index, _Value):
raise TypeError("Memory index is not a Migen value: {}"
.format(index))
self.memory = memory
self.index = index


class Memory(Special):
def __init__(self, width, depth, init=None, name=None):
Special.__init__(self)
@@ -219,6 +231,10 @@ def __init__(self, width, depth, init=None, name=None):
self.init = init
self.name_override = get_obj_var_name(name, "mem")

def __getitem__(self, index):
# simulation only
return _MemoryLocation(self, index)

def get_port(self, write_capable=False, async_read=False,
has_re=False, we_granularity=0, mode=WRITE_FIRST,
clock_domain="sys"):
@@ -325,7 +341,6 @@ def gn(e):
r += "\t$readmemh(\"" + memory_filename + "\", " + gn(memory) + ");\n"
r += "end\n\n"


return r


1 change: 1 addition & 0 deletions migen/fhdl/structure.py
Original file line number Diff line number Diff line change
@@ -579,6 +579,7 @@ def makedefault(self, key=None):

class _ArrayProxy(_Value):
def __init__(self, choices, key):
_Value.__init__(self)
self.choices = []
for c in choices:
if isinstance(c, (bool, int)):
34 changes: 22 additions & 12 deletions migen/sim.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import operator

from migen.fhdl.structure import *
from migen.fhdl.structure import (_Operator, _Slice, _ArrayProxy,
from migen.fhdl.structure import (_Value, _Statement,
_Operator, _Slice, _ArrayProxy,
_Assign, _Fragment)
from migen.fhdl.bitcontainer import flen
from migen.fhdl.tools import list_targets
from migen.fhdl.simplify import FullMemoryWE, MemoryToArray
from migen.fhdl.simplify import MemoryToArray
from migen.fhdl.specials import _MemoryLocation


__all__ = ["Simulator"]
@@ -61,7 +63,8 @@ def tick(self):


class Evaluator:
def __init__(self):
def __init__(self, replaced_memories):
self.replaced_memories = replaced_memories
self.signal_values = dict()
self.modifications = dict()

@@ -114,6 +117,9 @@ def eval(self, node, postcommit=False):
elif isinstance(node, _ArrayProxy):
return self.eval(node.choices[self.eval(node.key, postcommit)],
postcommit)
elif isinstance(node, _MemoryLocation):
array = self.replaced_memories[node.memory]
return self.eval(array[self.eval(node.index, postcommit)], postcommit)
else:
# TODO: ClockSignal, ResetSignal
raise NotImplementedError
@@ -140,6 +146,9 @@ def assign(self, node, value):
self.assign(node, full_value)
elif isinstance(node, _ArrayProxy):
self.assign(node.choices[self.eval(node.key)], value)
elif isinstance(node, _MemoryLocation):
array = self.replaced_memories[node.memory]
self.assign(array[self.eval(node.index)], value)
else:
# TODO: ClockSignal, ResetSignal
raise NotImplementedError
@@ -182,15 +191,15 @@ 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)
mta = MemoryToArray()
mta.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)
for s in list_targets(self.fragment.comb)]

self.time = TimeManager(clocks)
self.evaluator = Evaluator()
self.evaluator = Evaluator(mta.replacements)

def _commit_and_comb_propagate(self):
# TODO: optimize
@@ -199,11 +208,14 @@ def _commit_and_comb_propagate(self):
self.evaluator.execute(self.fragment.comb)
modified = self.evaluator.commit()

def _eval_nested_lists(self, x):
def _evalexec_nested_lists(self, x):
if isinstance(x, list):
return [self._eval_nested_lists(e) for e in x]
elif isinstance(x, Signal):
return [self._evalexec_nested_lists(e) for e in x]
elif isinstance(x, _Value):
return self.evaluator.eval(x)
elif isinstance(x, _Statement):
self.evaluator.execute([x])
return None
else:
raise ValueError

@@ -216,10 +228,8 @@ def _process_generators(self, cd):
request = generator.send(reply)
if request is None:
break # next cycle
elif isinstance(request, tuple):
self.evaluator.assign(*request)
else:
reply = self._eval_nested_lists(request)
reply = self._evalexec_nested_lists(request)
except StopIteration:
exhausted.append(generator)
break
10 changes: 5 additions & 5 deletions migen/test/test_coding.py
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ def test_run_sequence(self):
def gen():
for _ in range(256):
if seq:
yield self.tb.dut.i, seq.pop(0)
yield self.tb.dut.i.eq(seq.pop(0))
if (yield self.tb.dut.n):
self.assertNotIn((yield self.tb.dut.i), [1<<i for i in range(8)])
else:
@@ -45,7 +45,7 @@ def test_run_sequence(self):
def gen():
for _ in range(256):
if seq:
yield self.tb.dut.i, seq.pop(0)
yield self.tb.dut.i.eq(seq.pop(0))
i = yield self.tb.dut.i
if (yield self.tb.dut.n):
self.assertEqual(i, 0)
@@ -74,8 +74,8 @@ def gen():
for _ in range(256):
if seq:
i = seq.pop()
yield self.tb.dut.i, i//2
yield self.tb.dut.n, i%2
yield self.tb.dut.i.eq(i//2)
yield self.tb.dut.n.eq(i%2)
i = yield self.tb.dut.i
o = yield self.tb.dut.o
if (yield self.tb.dut.n):
@@ -100,7 +100,7 @@ def test_run_sequence(self):
def gen():
for _ in range(5):
if seq:
yield self.tb.dut.i, seq.pop(0)
yield self.tb.dut.i.eq(seq.pop(0))
i = yield self.tb.dut.i
if (yield self.tb.dut.n):
self.assertEqual(i, 0)
8 changes: 4 additions & 4 deletions migen/test/test_divider.py
Original file line number Diff line number Diff line change
@@ -14,11 +14,11 @@ def test_division(self):
def gen():
for dividend in range(16):
for divisor in range(1, 16):
yield self.tb.dut.dividend_i, dividend
yield self.tb.dut.divisor_i, divisor
yield self.tb.dut.start_i, 1
yield self.tb.dut.dividend_i.eq(dividend)
yield self.tb.dut.divisor_i.eq(divisor)
yield self.tb.dut.start_i.eq(1)
yield
yield self.tb.dut.start_i, 0
yield self.tb.dut.start_i.eq(0)
while not (yield self.tb.dut.ready_o):
yield
self.assertEqual((yield self.tb.dut.quotient_o), dividend//divisor)
11 changes: 6 additions & 5 deletions migen/test/test_fifo.py
Original file line number Diff line number Diff line change
@@ -28,8 +28,8 @@ def test_run_sequence(self):
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
yield self.tb.dut.we.eq(cycle % 2 == 0)
yield self.tb.dut.re.eq(cycle % 3 == 0)
# the output if valid must be correct
if (yield self.tb.dut.readable) and (yield self.tb.dut.re):
try:
@@ -45,9 +45,10 @@ def test_replace(self):
seq = [x for x in range(20) if x % 5]
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
yield self.tb.dut.we.eq(cycle % 2 == 0)
yield self.tb.dut.re.eq(cycle % 7 == 0)
yield self.tb.dut.replace.eq(
(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)
4 changes: 2 additions & 2 deletions migen/test/test_signed.py
Original file line number Diff line number Diff line change
@@ -29,8 +29,8 @@ def __init__(self):
def test_comparisons(self):
def gen():
for i in range(-4, 4):
yield self.tb.a, i
yield self.tb.b, i
yield self.tb.a.eq(i)
yield self.tb.b.eq(i)
a = yield self.tb.a
b = yield self.tb.b
for asign, bsign, f, r, op in self.tb.vals:
2 changes: 1 addition & 1 deletion migen/test/test_sort.py
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ def test_sort(self):
def gen():
for repeat in range(20):
for i in self.tb.dut.i:
yield i, randrange(1<<flen(i))
yield i.eq(randrange(1<<flen(i)))
yield
self.assertEqual(sorted((yield self.tb.dut.i)),
(yield self.tb.dut.o))