89 lines
2.2 KiB
Python
89 lines
2.2 KiB
Python
|
import inspect
|
||
|
import ast
|
||
|
|
||
|
from migen.fhdl.structure import *
|
||
|
from migen.pytholite import transel
|
||
|
|
||
|
class FinalizeError(Exception):
|
||
|
pass
|
||
|
|
||
|
class _AbstractLoad:
|
||
|
def __init__(self, target, source):
|
||
|
self.target = target
|
||
|
self.source = source
|
||
|
|
||
|
class _Register:
|
||
|
def __init__(self, name, nbits):
|
||
|
self.storage = Signal(BV(nbits), name=name)
|
||
|
self.source_encoding = {}
|
||
|
self.finalized = False
|
||
|
|
||
|
def load(self, source):
|
||
|
if source not in self.source_encoding:
|
||
|
self.source_encoding[source] = len(self.source_encoding) + 1
|
||
|
return _AbstractLoad(self, source)
|
||
|
|
||
|
def finalize(self):
|
||
|
if self.finalized:
|
||
|
raise FinalizeError
|
||
|
self.sel = Signal(BV(bits_for(len(self.source_encoding) + 1)))
|
||
|
self.finalized = True
|
||
|
|
||
|
def get_fragment(self):
|
||
|
if not self.finalized:
|
||
|
raise FinalizeError
|
||
|
# do nothing when sel == 0
|
||
|
cases = [(v, self.storage.eq(k)) for k, v in self.source_encoding.items()]
|
||
|
sync = [Case(self.sel, *cases)]
|
||
|
return Fragment(sync=sync)
|
||
|
|
||
|
class _AnonymousRegister:
|
||
|
def __init__(self, nbits):
|
||
|
self.nbits = nbits
|
||
|
|
||
|
class _CompileVisitor(ast.NodeVisitor):
|
||
|
def __init__(self, symdict, registers):
|
||
|
self.symdict = symdict
|
||
|
self.registers = registers
|
||
|
|
||
|
def visit_Assign(self, node):
|
||
|
value = self.visit(node.value)
|
||
|
if isinstance(value, _AnonymousRegister):
|
||
|
if isinstance(node.targets[0], ast.Name):
|
||
|
name = node.targets[0].id
|
||
|
else:
|
||
|
raise NotImplementedError
|
||
|
value = _Register(name, value.nbits)
|
||
|
self.registers.append(value)
|
||
|
for target in node.targets:
|
||
|
if isinstance(target, ast.Name):
|
||
|
self.symdict[target.id] = value
|
||
|
else:
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def visit_Call(self, node):
|
||
|
if isinstance(node.func, ast.Name):
|
||
|
callee = self.symdict[node.func.id]
|
||
|
else:
|
||
|
raise NotImplementedError
|
||
|
if callee == transel.Register:
|
||
|
if len(node.args) != 1:
|
||
|
raise TypeError("Register() takes exactly 1 argument")
|
||
|
nbits = ast.literal_eval(node.args[0])
|
||
|
return _AnonymousRegister(nbits)
|
||
|
else:
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def make_pytholite(func):
|
||
|
tree = ast.parse(inspect.getsource(func))
|
||
|
symdict = func.__globals__.copy()
|
||
|
registers = []
|
||
|
|
||
|
cv = _CompileVisitor(symdict, registers)
|
||
|
cv.visit(tree)
|
||
|
|
||
|
print(registers)
|
||
|
print(symdict)
|
||
|
|
||
|
#print(ast.dump(tree))
|