Skip to content

Commit

Permalink
Revert semantic changes
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardt committed Dec 3, 2019
1 parent fd3dbfa commit 42f1b3c
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 54 deletions.
77 changes: 43 additions & 34 deletions magma/syntax/verilog.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,13 @@ def process_comb_func(defn_env, fn, circ_name, registers={}, init_fn=None):
width_table = {}
type_table = {}
if registers:
tree = RewriteSelfAttributes(registers).visit(tree)
for name, info in registers.items():
width = 1 if isinstance(info[3], m._BitKind) else len(info[3])
width_table[name] = width
width_table["self_" + name + "_I"] = width
type_table["self_" + name + "_I"] = to_type_str(info[2])
width_table["self_" + name + "_O"] = width
type_table["self_" + name + "_O"] = to_type_str(info[2])
for arg in tree.args.args:
if arg.arg == "self":
continue
Expand Down Expand Up @@ -139,14 +143,15 @@ def process_comb_func(defn_env, fn, circ_name, registers={}, init_fn=None):
if registers:
IO += m.ClockInterface(has_async_reset=True)

names = collect_names(tree, ctx=ast.Store) | set(name for name in registers)
names = collect_names(tree, ctx=ast.Store) | \
set(f"self_{name}_I" for name in registers) | \
set(f"self_{name}_O" for name in registers)

for io_port in inputs.keys() | outputs.keys():
if io_port in names:
names.remove(io_port)

CollectInitialWidthsAndTypes(width_table, type_table, defn_env,
registers).visit(tree)
CollectInitialWidthsAndTypes(width_table, type_table, defn_env).visit(tree)
PromoteWidths(width_table, type_table).visit(tree)
tree = ProcessNames(inputs, outputs, names).visit(tree)
tree = ProcessReturns(outputs).visit(tree)
Expand All @@ -162,36 +167,6 @@ def process_comb_func(defn_env, fn, circ_name, registers={}, init_fn=None):
fn_ln = kratos.pyast.get_fn(fn), kratos.pyast.get_ln(fn) + lineno_offset - 2

print(astor.to_source(tree))
if registers:
tree.decorator_list = [
ast.Call(func=ast.Name(id='always', ctx=ast.Load()),
args=[ast.Tuple(elts=[ast.Name(id='posedge',
ctx=ast.Load()),
ast.Str(s='CLK')],
ctx=ast.Load()),
ast.Tuple(elts=[ast.Name(id='posedge',
ctx=ast.Load()),
ast.Str(s='ASYNCRESET')],
ctx=ast.Load())],
keywords=[])]
defn_env["always"] = kratos.always
defn_env["posedge"] = kratos.posedge
reg_inits = []
for reg, info in registers.items():
eval_value = info[3]
try:
init = int(eval_value)
except Exception:
raise NotImplementedError(eval_value)
reg_inits.append(ast.parse(
f"self.{reg} = {init}"
).body[0])
tree.body = [ast.If(
ast.Attribute(ast.Name("self", ast.Load()), "ASYNCRESET",
ast.Load()),
reg_inits,
tree.body
)]
func = ast_utils.compile_function_to_file(tree, fn.__name__, defn_env)

class Module(kratos.Generator):
Expand All @@ -207,6 +182,40 @@ def __init__(self):
self.CLK = self.clock("CLK")
self.ASYNCRESET = self.reset("ASYNCRESET")

reg_updates = "\n ".join(
f"self.self_{name}_O = self.self_{name}_I"
for name in registers
)
reg_inits = []
for reg, info in registers.items():
eval_value = info[3]
try:
init = int(eval_value)
except Exception as e:
raise NotImplementedError(eval_value)
reg_inits.append(
f"self.self_{reg}_O = {init}"
)
reg_inits = "\n ".join(reg_inits)
code = f"""
from kratos import always, posedge
@always((posedge, "CLK"), (posedge, "ASYNCRESET"))
def seq_code_block(self):
if self.ASYNCRESET:
{reg_inits}
else:
{reg_updates}
"""
lineno_offset = ast_utils.get_ast(init_fn).body[0].lineno
init_fn_ln = kratos.pyast.get_fn(init_fn), \
kratos.pyast.get_ln(init_fn) + lineno_offset - 2
seq_code_block = ast_utils.compile_function_to_file(
ast.parse(code), "seq_code_block", defn_env)
# TODO: What lines should this block map to? This is implict
# in sequential, for now we can just map it to __init__
seq_block = self.add_code(seq_code_block, fn_ln=init_fn_ln)

block = self.add_code(func, fn_ln=fn_ln)
# set locals, which is the inputs and outputs
for key in inputs:
Expand Down
14 changes: 3 additions & 11 deletions magma/syntax/verilog_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import sys
import re
import ast
import magma as m


# The code in this file is adapted from the Silica compiler, shout out to Teguh
Expand Down Expand Up @@ -35,7 +34,7 @@ def f(node):
is_generator(x)


def get_width(node, width_table, defn_env={}, registers={}):
def get_width(node, width_table, defn_env={}):
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and \
node.func.id in {"bits", "uint", "BitVector"}:
if isinstance(node.args[1], ast.Call) and \
Expand Down Expand Up @@ -149,11 +148,6 @@ def get_width(node, width_table, defn_env={}, registers={}):
elif isinstance(node, ast.Num):
return max(node.n.bit_length(), 1)
elif isinstance(node, ast.Attribute):
if isinstance(node.value, ast.Name) and node.value.id == "self" and \
node.attr in registers:
width = registers[node.attr][3]
return 1 if isinstance(width, m._BitKind) else len(width)

type_ = width_table[node.value.id]._outputs[node.attr]
if isinstance(type_, m.BitKind):
return None
Expand All @@ -163,11 +157,10 @@ def get_width(node, width_table, defn_env={}, registers={}):


class CollectInitialWidthsAndTypes(ast.NodeVisitor):
def __init__(self, width_table, type_table, defn_env, registers):
def __init__(self, width_table, type_table, defn_env):
self.width_table = width_table
self.type_table = type_table
self.defn_env = defn_env
self.registers = registers

def visit_Assign(self, node):
if len(node.targets) == 1:
Expand All @@ -180,8 +173,7 @@ def visit_Assign(self, node):
pass
elif node.targets[0].id not in self.width_table:
self.width_table[node.targets[0].id] = \
get_width(node.value, self.width_table, self.defn_env,
self.registers)
get_width(node.value, self.width_table, self.defn_env)
if isinstance(node.value, ast.Call) and \
isinstance(node.value.func, ast.Name) and \
node.value.func.id in {"bits", "uint", "bit"}:
Expand Down
22 changes: 15 additions & 7 deletions tests/test_syntax/gold/TestBasicToVerilog.v
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@ module TestBasic (
output logic [1:0] O
);

logic [1:0] x;
logic [1:0] y;
logic [1:0] _O;
logic [1:0] self_x_I;
logic [1:0] self_x_O;
logic [1:0] self_y_I;
logic [1:0] self_y_O;

always_ff @(posedge CLK, posedge ASYNCRESET) begin
if (ASYNCRESET) begin
x <= 2'h0;
y <= 2'h0;
self_x_O <= 2'h0;
self_y_O <= 2'h0;
end
else begin
y <= x;
x <= I;
O <= y;
self_x_O <= self_x_I;
self_y_O <= self_y_I;
end
end
always_comb begin
_O = self_y_O;
self_y_I = self_x_O;
self_x_I = I;
O = _O;
end
endmodule // TestBasic


6 changes: 4 additions & 2 deletions tests/test_syntax/test_to_verilog.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,11 @@ def __init__(self):
self.y: m.Bits[2] = m.bits(0, 2)

def __call__(self, I: m.Bits[2]) -> m.Bits[2]:
# Issue: can't overload temporary name with output name
_O = self.y
self.y = self.x
self.x = I
return self.y
return _O

m.compile('build/TestBasicToVerilog', TestBasic, output="verilog")
assert check_files_equal(__file__, f"build/TestBasicToVerilog.v",
Expand All @@ -121,11 +123,11 @@ def __call__(self, I: m.Bits[2]) -> m.Bits[2]:
for i in range(len(stream)):
tester.circuit.I = stream[i]
tester.print(f"%d\n", tester.circuit.O)
tester.step(2)
if i > 1:
tester.circuit.O.expect(stream[i - 2])
else:
tester.circuit.O.expect(0)
tester.step(2)
directory = f"{os.path.abspath(os.path.dirname(__file__))}/build/"
tester.compile_and_run(target,
directory=directory,
Expand Down

0 comments on commit 42f1b3c

Please sign in to comment.