Skip to content

Commit

Permalink
Merge e3684e4 into 7d64f7e
Browse files Browse the repository at this point in the history
  • Loading branch information
THofstee committed Oct 4, 2018
2 parents 7d64f7e + e3684e4 commit 7934601
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 25 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ git+git://github.com/phanrahan/magma.git#egg=magma
git+git://github.com/phanrahan/mantle.git#egg=mantle
git+git://github.com/phanrahan/loam.git#egg=loam
coreir
veriloggen
55 changes: 42 additions & 13 deletions silica/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from silica.coroutine import Coroutine
from silica.cfg import ControlFlowGraph, BasicBlock, HeadBlock
from silica.cfg.control_flow_graph import render_paths_between_yields, build_state_info, render_fsm, get_constant
from silica.ast_utils import get_ast
from silica.ast_utils import *
from silica.liveness import liveness_analysis
from silica.transformations import specialize_constants, replace_symbols, \
constant_fold, desugar_for_loops, specialize_evals, inline_yield_from_functions
Expand All @@ -24,6 +24,7 @@
from silica.analysis import CollectInitialWidthsAndTypes
from silica.transformations.promote_widths import PromoteWidths

import veriloggen as vg

def specialize_list_comps(tree, globals, locals):
locals.update(silica.operators)
Expand All @@ -34,7 +35,7 @@ def visit_ListComp(self, node):
return ast.parse(f"[{result}]").body[0].value

def visit_Call(self, node):
if isinstance(node.func, ast.Name) and node.func.id == "list":
if is_name(node.func) and node.func.id == "list":
result = eval(astor.to_source(node), globals, locals)
result = ", ".join(repr(x) for x in result)
return ast.parse(f"[{result}]").body[0].value
Expand Down Expand Up @@ -145,15 +146,15 @@ def compile(coroutine, file_name=None, mux_strategy="one-hot", output='verilog',
for node in cfg.paths[0][:-1]:
if isinstance(node, HeadBlock):
for statement in node:
if isinstance(statement.value, ast.Call) and isinstance(statement.value.func, ast.Name) and statement.value.func.id == "coroutine_create":
if is_call(statement.value) and is_name(statement.value.func) and statement.value.func.id == "coroutine_create":
sub_coroutine = eval(astor.to_source(statement.value.args[0]), func_globals, func_locals)
raise NotImplementedError()
verilog_source += verilog_compile(sub_coroutine(), func_globals, func_locals)
statement.value.func = ast.Name(sub_coroutine._name, ast.Load())
statement.value.args = []
sub_coroutines.append((statement, sub_coroutine))
else:
if isinstance(statement.value, ast.Name) and statement.value.id in initial_values:
if is_name(statement.value) and statement.value.id in initial_values:
initial_values[statement.targets[0].id] = initial_values[statement.value.id]
else:
initial_values[statement.targets[0].id] = get_constant(statement.value)
Expand All @@ -168,17 +169,29 @@ def compile(coroutine, file_name=None, mux_strategy="one-hot", output='verilog',
num_states = len(states)
if has_ce:
raise NotImplementedError("add ce to module decl")

# declare module and ports
module = vg.Module(module_name)
for o in outputs:
module.Output(o, width_table.get(o, 1))
if coroutine._inputs:
for i,t in coroutine._inputs.items():
if isinstance(t, m.BitKind):
module.Input(i)
else:
module.Input(i, t.N)
module.Input("CLK")
verilog_source += f"""
module {module_name} ({io_string}, input CLK);
"""



# declare wires
for var in cfg.replacer.id_counter:
width = width_table[var]
for i in range(cfg.replacer.id_counter[var] + 1):
if f"{var}_{i}" not in registers:
width_str = get_width_str(width)
module.Wire(f"{var}_{i}", width)
verilog_source += f" wire {width_str} {var}_{i};\n"

for (name, index), value in cfg.replacer.array_stores.items():
Expand All @@ -194,29 +207,38 @@ def compile(coroutine, file_name=None, mux_strategy="one-hot", output='verilog',
var = name + f"_{value}_i{count}"
width_table[var] = width

init_strings = []
# declare regs
for register in registers:
width = width_table[register]
if isinstance(width, MemoryType):
module.Reg(register, width.width, width.height)
width_str = get_width_str(width.width)
verilog_source += f" reg {width_str} {register} [0:{width.height - 1}];\n"
else:
module.Reg(register, width)
width_str = get_width_str(width)
verilog_source += f" reg {width_str} {register};\n"

init_strings = []
init = module.Initial()
for key, value in initial_values.items():
if value is not None:
init.add(
verilog.get_by_name(module, key)(value)
)
init_strings.append(f"{key} = {value};")


if cfg.curr_yield_id > 1:
module.Reg("yield_state", (cfg.curr_yield_id - 1).bit_length(), initval=0)
verilog_source += f" reg [{(cfg.curr_yield_id - 1).bit_length() - 1}:0] yield_state;\n"
init_strings.append(f"yield_state = 0;")

# TODO: need to do this
if initial_basic_block:
for statement in states[0].statements:
verilog.process_statement(statement)
# temp_var_promoter.visit(statement)
init_strings.append(astor.to_source(statement).rstrip().replace(" = ", " = ") + ";")
init_strings.append(astor.to_source(statement).rstrip() + ";")

init_string = '\n '.join(init_strings)
verilog_source += f"""
Expand All @@ -225,20 +247,27 @@ def compile(coroutine, file_name=None, mux_strategy="one-hot", output='verilog',
end
"""


raddrs = {}
waddrs = {}
wdatas = {}
wens = {}
# render_paths_between_yields(cfg.paths)
if initial_basic_block:
states = states[1:]
always_source, temp_var_source = verilog.compile_states(states, cfg.curr_yield_id == 1, width_table, strategy)
always_source, temp_var_source = verilog.compile_states(module, states, cfg.curr_yield_id == 1, width_table, strategy)
verilog_source += temp_var_source + always_source
verilog_source += "\n end\nendmodule"
verilog_source = verilog_source.replace("True", "1")
verilog_source = verilog_source.replace("False", "0")
# cfg.render()

print(module.to_verilog())
print(verilog_source)

# with open(file_name, "w") as f:
# f.write(verilog_source)
# return m.DefineFromVerilog(verilog_source, type_map={"CLK": m.In(m.Clock)})[-1]

with open(file_name, "w") as f:
f.write(verilog_source)
return m.DefineFromVerilog(verilog_source, type_map={"CLK": m.In(m.Clock)})[-1]
f.write(module.to_verilog())
return m.DefineFromVerilog(module.to_verilog(), type_map={"CLK": m.In(m.Clock)})[-1]
116 changes: 104 additions & 12 deletions silica/verilog.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import astor
import ast
from .width import get_width

import veriloggen as vg
from functools import *
from .ast_utils import *

def get_width_str(width):
return f"[{width-1}:0] " if width is not None else ""
Expand Down Expand Up @@ -99,8 +101,68 @@ def compile_state_by_path(state, index, _tab, one_state, width_table):
verilog_source += f"\n{_tab}end"
return verilog_source, temp_var_source

def get_by_name(module, name):
return module.get_ports().get(name, module.get_vars().get(name))

# TODO: these translate functions should be merged
# TODO: the only reason translate takes in a module is to do the name lookup. should figure out how to not need to pass in module.
def translate_slice(module, slice, target):
if is_index(slice):
return vg.Pointer(target, translate_value(module, slice.value))
elif is_slice(slice):
return vg.Slice(target, translate_value(module, slice.lower), translate_value(module, slice.upper))

raise NotImplementedError(slice)

# TODO: should reorder the switch into more sensible ordering
# TODO: should split this up into a few translate functions that translate certain classes of inputs
def translate_value(module, value):
if isinstance(value, bool):
return vg.Int(1 if value else 0)
elif is_add(value):
return vg.Add
elif is_assign(value):
return vg.Subst(translate_value(module, value.targets[0]), translate_value(module, value.value), 1)
elif is_bin_op(value):
return translate_value(module, value.op)(translate_value(module, value.left), translate_value(module, value.right))
elif is_bit_and(value):
return vg.And
elif is_bit_xor(value):
return vg.Xor
elif is_compare(value):
assert(len(value.ops) == len(value.comparators) == 1)
return translate_value(module, value.ops[0])(translate_value(module, value.left), translate_value(module, value.comparators[0]))
elif is_eq(value):
return vg.Eq
elif is_if_exp(value):
return vg.Cond(
translate_value(module, value.test),
translate_value(module, value.body),
translate_value(module, value.orelse)
)
elif is_invert(value):
return vg.Unot
elif is_lt(value):
return vg.LessThan
elif is_name(value):
return get_by_name(module, value.id)
elif is_name_constant(value):
# TODO: distinguish between int, bool, etc.
return translate_value(module, value.value)
elif is_not_eq(value):
return vg.NotEq
elif is_num(value):
return vg.Int(value.n)
elif is_sub(value):
return vg.Sub
elif is_subscript(value):
return translate_slice(module, value.slice, translate_value(module, value.value))
elif is_unary_op(value):
return translate_value(module, value.op)(translate_value(module, value.operand))

def compile_statements(states, _tab, one_state, width_table, statements):
raise NotImplementedError(value)

def compile_statements(module, seq, states, _tab, one_state, width_table, statements):
offset = ""
verilog_source = ""
# temp_var_promoter = TempVarPromoter(width_table)
Expand All @@ -122,34 +184,50 @@ def compile_statements(states, _tab, one_state, width_table, statements):
# if these_conds:
# conds.append(" & ".join(these_conds))
if not one_state:
conds = [f"(yield_state == {yield_id})" for yield_id in yields]
conds = [module.get_vars()["yield_state"] == yield_id for yield_id in yields]
conds_old = [f"(yield_state == {yield_id})" for yield_id in yields] # TODO: remove
process_statement(statement)
if conds:
cond = " | ".join(conds)
verilog_source += f"\n{_tab}if ({cond}) begin"
cond = reduce(vg.Lor, conds)
seq.If(cond)(
vg.Subst(translate_value(module, statement.targets[0]), translate_value(module, statement.value), 1)
)
# TODO: remove
cond_old = " | ".join(conds_old)
verilog_source += f"\n{_tab}if ({cond_old}) begin"
verilog_source += f"\n{_tab + offset}" + astor.to_source(statement).rstrip() + ";"
verilog_source += f"\n{_tab}end"
else:
verilog_source += f"\n{_tab}" + astor.to_source(statement).rstrip() + ";"
seq(
vg.Subst(translate_value(module, statement.targets[0]), translate_value(module, statement.value), 1)
)
else:
process_statement(statement)
verilog_source += f"\n{_tab}" + astor.to_source(statement).rstrip() + ";"
seq(
vg.Subst(translate_value(module, statement.targets[0]), translate_value(module, statement.value), 1)
)
temp_var_source = ""
return verilog_source, temp_var_source


def compile_states(states, one_state, width_table, strategy="by_statement"):
def compile_states(module, states, one_state, width_table, strategy="by_statement"):
seq = vg.TmpSeq(module, module.get_ports()["CLK"])
always_source = """\
always @(posedge CLK) begin\
"""
tab = " "
temp_var_source = ""
if strategy == "by_path":
raise NotImplementedError("by_path is not implemented.")
# TODO: do this
for i, state in enumerate(states):
always_inside, temp_vars = compile_state_by_path(state, i, tab * 3, one_state, width_table)
always_source += always_inside
temp_var_source += temp_vars
elif strategy == "by_statement":
# TODO: do this
statements = []
for state in states:
index = len(statements)
Expand All @@ -158,38 +236,51 @@ def compile_states(states, one_state, width_table, strategy="by_statement"):
index = statements.index(statement)
else:
statements.insert(index, statement)
always_inside, temp_vars = compile_statements(states, tab * 3, one_state, width_table, statements)
always_inside, temp_vars = compile_statements(module, seq, states, tab * 3, one_state, width_table, statements)
always_source += always_inside
temp_var_source += temp_vars
_tab = tab * 3
if not one_state:
for i, state in enumerate(states):
offset = tab
cond = ""
conds = []
if state.conds:
cond += " & ".join(astor.to_source(process_statement(cond)).rstrip() for cond in state.conds)
if not one_state:
if cond:
cond += " & "
cond += f"(yield_state == {state.start_yield_id})"
conds = [translate_value(module, process_statement(cond)) for cond in state.conds]
if cond:
cond += " & "
cond += f"(yield_state == {state.start_yield_id})"
cond_new = reduce(vg.Land, conds, get_by_name(module, 'yield_state') == state.start_yield_id)
if i == 0:
if_stmt = seq.If(cond_new)
if_str = "if"
else:
if_stmt = seq.Elif(cond_new)
if_str = "else if"
stmts = []
stmts.append(get_by_name(module, 'yield_state')(state.end_yield_id))
always_source += f"\n{_tab}{if_str} ({cond}) begin"
always_source += f"\n{_tab + offset}yield_state = {state.end_yield_id};"
for output, var in state.path[-1].output_map.items():
stmts.append(get_by_name(module, output)(get_by_name(module, var)))
always_source += f"\n{_tab + offset}{output} = {var};"
for stmt in state.path[-1].array_stores_to_process:
always_source += f"\n{tab + offset}" + astor.to_source(process_statement(stmt)).rstrip() + ";"

stmts.append(translate_value(module, process_statement(stmt)))
always_source += f"\n{_tab}end"
if_stmt(stmts)

else:
for output, var in states[0].path[-1].output_map.items():
seq(
get_by_name(module, output)(get_by_name(module, var))
)
always_source += f"\n{_tab}{output} = {var};"
else:
raise NotImplementedError(strategy)

# rewrite (a if cond else b) to cond ? a : b
new_always_source = ""
for line in always_source.split("\n"):
if "if" in line and "else" in line and not "else if" in line:
Expand All @@ -199,4 +290,5 @@ def compile_states(states, one_state, width_table, strategy="by_statement"):
new_always_source += f"{assign} ={cond}? {true}:{false}" + "\n"
else:
new_always_source += line + "\n"

return new_always_source, temp_var_source

0 comments on commit 7934601

Please sign in to comment.