sim: support arrays, and cat+slice in assignment target

This commit is contained in:
Sebastien Bourdeauducq 2015-09-19 14:56:26 +08:00
parent 563231fdfb
commit 9420aabc0d
1 changed files with 43 additions and 19 deletions

View File

@ -1,7 +1,8 @@
import operator
from migen.fhdl.structure import *
from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment
from migen.fhdl.structure import (_Operator, _Slice, _ArrayProxy,
_Assign, _Fragment)
from migen.fhdl.bitcontainer import flen
from migen.fhdl.tools import list_targets
@ -72,16 +73,21 @@ class Evaluator:
self.modifications.clear()
return r
def eval(self, node):
def eval(self, node, postcommit=False):
if isinstance(node, Constant):
return node.value
elif isinstance(node, Signal):
if postcommit:
try:
return self.modifications[node]
except KeyError:
pass
try:
return self.signal_values[node]
except KeyError:
return node.reset.value
elif isinstance(node, _Operator):
operands = [self.eval(o) for o in node.operands]
operands = [self.eval(o, postcommit) for o in node.operands]
if node.op == "-":
if len(operands) == 1:
return -operands[0]
@ -92,7 +98,7 @@ class Evaluator:
else:
return str2op[node.op](*operands)
elif isinstance(node, _Slice):
v = self.eval(node.value)
v = self.eval(node.value, postcommit)
idx = range(node.start, node.stop)
return sum(((v >> i) & 1) << j for j, i in enumerate(idx))
elif isinstance(node, Cat):
@ -101,29 +107,46 @@ class Evaluator:
for element in node.l:
nbits = flen(element)
# make value always positive
r |= (self.eval(element) & (2**nbits-1)) << shift
r |= (self.eval(element, postcommit) & (2**nbits-1)) << shift
shift += nbits
return r
elif isinstance(node, _ArrayProxy):
return self.eval(node.choices[self.eval(node.key, postcommit)],
postcommit)
else:
# TODO: Array, ClockSignal, ResetSignal, Memory
# TODO: ClockSignal, ResetSignal, Memory
raise NotImplementedError
def assign(self, signal, value):
assert not signal.variable
value = value & (2**signal.nbits - 1)
if signal.signed and (value & 2**(signal.nbits - 1)):
value -= 2**signal.nbits
self.modifications[signal] = value
def assign(self, node, value):
if isinstance(node, Signal):
assert not node.variable
value = value & (2**node.nbits - 1)
if node.signed and (value & 2**(node.nbits - 1)):
value -= 2**node.nbits
self.modifications[node] = value
elif isinstance(node, Cat):
for element in node.l:
nbits = flen(element)
self.assign(element, value & (2**nbits-1))
value >>= nbits
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))
# set them to the new value
value &= 2**(node.stop - node.start)-1
full_value |= value << node.start
self.assign(node, full_value)
elif isinstance(node, _ArrayProxy):
self.assign(node.choices[self.eval(node.key)], value)
else:
# TODO: ClockSignal, ResetSignal, Memory
raise NotImplementedError
def execute(self, statements):
for s in statements:
if isinstance(s, _Assign):
value = self.eval(s.r)
if isinstance(s.l, Signal):
self.assign(s.l, value)
else:
# TODO: Cat, Slice, Array, ClockSignal, ResetSignal, Memory
raise NotImplementedError
self.assign(s.l, self.eval(s.r))
elif isinstance(s, If):
if self.eval(s.cond):
self.execute(s.t)
@ -158,7 +181,8 @@ class Simulator:
else:
self.generators[k] = [v]
# TODO: insert_resets
# 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)]