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: a67b4baa0c7e
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: 2c1553fea2f0
Choose a head ref
  • 2 commits
  • 1 file changed
  • 1 contributor

Commits on Sep 21, 2015

  1. Copy the full SHA
    99af825 View commit details
  2. Copy the full SHA
    2c1553f View commit details
Showing with 66 additions and 27 deletions.
  1. +66 −27 migen/sim/core.py
93 changes: 66 additions & 27 deletions migen/sim/core.py
Original file line number Diff line number Diff line change
@@ -5,37 +5,52 @@
_Operator, _Slice, _ArrayProxy,
_Assign, _Fragment)
from migen.fhdl.bitcontainer import flen
from migen.fhdl.tools import list_signals, list_targets
from migen.fhdl.tools import list_signals, list_targets, insert_resets
from migen.fhdl.simplify import MemoryToArray
from migen.fhdl.specials import _MemoryLocation
from migen.sim.vcd import VCDWriter, DummyVCDWriter


class ClockState:
def __init__(self, period, times_before_tick):
self.period = period
self.times_before_tick = times_before_tick
def __init__(self, high, half_period, time_before_trans):
self.high = high
self.half_period = half_period
self.time_before_trans = time_before_trans


class TimeManager:
def __init__(self, description):
self.clocks = dict()

for k, v in description.items():
if not isinstance(v, tuple):
v = v, 0
self.clocks[k] = ClockState(v[0], v[0] - v[1])
for k, period_phase in description.items():
if isinstance(period_phase, tuple):
period, phase = period_phase
else:
period = period_phase
phase = 0
half_period = period//2
if phase >= half_period:
phase -= half_period
high = True
else:
high = False
self.clocks[k] = ClockState(high, half_period, half_period - phase)

def tick(self):
r = set()
dt = min(cs.times_before_tick for cs in self.clocks.values())
rising = set()
falling = set()
dt = min(cs.time_before_trans for cs in self.clocks.values())
for k, cs in self.clocks.items():
if cs.times_before_tick == dt:
r.add(k)
cs.times_before_tick -= dt
if not cs.times_before_tick:
cs.times_before_tick += cs.period
return dt, r
if cs.time_before_trans == dt:
cs.high = not cs.high
if cs.high:
rising.add(k)
else:
falling.add(k)
cs.time_before_trans -= dt
if not cs.time_before_trans:
cs.time_before_trans += cs.half_period
return dt, rising, falling


str2op = {
@@ -61,7 +76,8 @@ def tick(self):


class Evaluator:
def __init__(self, replaced_memories):
def __init__(self, clock_domains, replaced_memories):
self.clock_domains = clock_domains
self.replaced_memories = replaced_memories
self.signal_values = dict()
self.modifications = dict()
@@ -118,8 +134,19 @@ def eval(self, node, postcommit=False):
elif isinstance(node, _MemoryLocation):
array = self.replaced_memories[node.memory]
return self.eval(array[self.eval(node.index, postcommit)], postcommit)
elif isinstance(node, ClockSignal):
return self.eval(self.clock_domains[node.cd].clk, postcommit)
elif isinstance(node, ResetSignal):
rst = self.clock_domains[node.cd].rst
if rst is None:
if node.allow_reset_less:
return 0
else:
raise ValueError("Attempted to get reset signal of resetless"
" domain '{}'".format(node.cd))
else:
return self.eval(rst, postcommit)
else:
# TODO: ClockSignal, ResetSignal
raise NotImplementedError

def assign(self, node, value):
@@ -148,7 +175,6 @@ def assign(self, node, value):
array = self.replaced_memories[node.memory]
self.assign(array[self.eval(node.index)], value)
else:
# TODO: ClockSignal, ResetSignal
raise NotImplementedError

def execute(self, statements):
@@ -188,23 +214,33 @@ def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=
else:
self.generators[k] = [v]

self.time = TimeManager(clocks)
for clock in clocks.keys():
if clock not in self.fragment.clock_domains:
cd = ClockDomain(name=clock, reset_less=True)
cd.clk.reset = C(self.time.clocks[clock].high)
self.fragment.clock_domains.append(cd)

mta = MemoryToArray()
mta.transform_fragment(None, self.fragment)
# TODO: insert_resets on sync
insert_resets(self.fragment)
# 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.evaluator = Evaluator(self.fragment.clock_domains,
mta.replacements)

if vcd_name is None:
self.vcd = DummyVCDWriter()
else:
signals = sorted(list_signals(self.fragment),
key=lambda x: x.duid)
signals = list_signals(self.fragment)
for cd in self.fragment.clock_domains:
signals.add(cd.clk)
if cd.rst is not None:
signals.add(cd.rst)
signals = sorted(signals, key=lambda x: x.duid)
self.vcd = VCDWriter(vcd_name, signals)

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

def __enter__(self):
return self

@@ -263,13 +299,16 @@ def run(self):
self._commit_and_comb_propagate()

while True:
dt, cds = self.time.tick()
dt, rising, falling = self.time.tick()
self.vcd.delay(dt)
for cd in cds:
for cd in rising:
self.evaluator.assign(self.fragment.clock_domains[cd].clk, 1)
if cd in self.fragment.sync:
self.evaluator.execute(self.fragment.sync[cd])
if cd in self.generators:
self._process_generators(cd)
for cd in falling:
self.evaluator.assign(self.fragment.clock_domains[cd].clk, 0)
self._commit_and_comb_propagate()

if not self._continue_simulation():