def getFIFOInstOfNewTemplate(self, e_name: str, e_width: int, e_depth: int, pipeline_level: int): e_inst_list = self.e_name_to_ast_node[e_name] # use our FIFO template e_inst_list.module = 'fifo_almost_full' param_width = ast.ParamArg('DATA_WIDTH', ast.Rvalue(ast.IntConst(str(e_width)))) param_depth = ast.ParamArg('DEPTH', ast.Rvalue(ast.IntConst(str(e_depth)))) addr_bitwidth = int(math.log2(e_width) + 1) param_addr_width = ast.ParamArg( 'ADDR_WIDTH', ast.Rvalue(ast.IntConst(str(addr_bitwidth)))) # pipeline_level equals the required grace period param_grace_period = ast.ParamArg( 'GRACE_PERIOD', ast.Rvalue(ast.IntConst(str(pipeline_level)))) params = [ param_width, param_depth, param_addr_width, param_grace_period ] e_inst_list.parameterlist = params for c in e_inst_list.instances: # should only has 1 instance c.module = e_inst_list.module c.parameterlist = params return self.codegen.visit(e_inst_list)
def test(): datawid = vast.Parameter( 'DATAWID', vast.Rvalue(vast.IntConst('32')) ) params = vast.Paramlist( [datawid] ) clk = vast.Ioport( vast.Input('CLK') ) rst = vast.Ioport( vast.Input('RST') ) width = vast.Width( vast.IntConst('7'), vast.IntConst('0') ) led = vast.Ioport( vast.Output('led', width=width) ) ports = vast.Portlist( [clk, rst, led] ) width = vast.Width( vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('1')), vast.IntConst('0') ) count = vast.Reg('count', width=width) assign = vast.Assign( vast.Lvalue(vast.Identifier('led')), vast.Rvalue( vast.Partselect( vast.Identifier('count'), # count vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('1')), # [DATAWID-1: vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('8'))))) # :DATAWID-8] sens = vast.Sens(vast.Identifier('CLK'), type='posedge') senslist = vast.SensList([ sens ]) assign_count_true = vast.NonblockingSubstitution( vast.Lvalue(vast.Identifier('count')), vast.Rvalue(vast.IntConst('0'))) if0_true = vast.Block([ assign_count_true ]) # (count + 1) * 2 count_plus_1 = vast.Plus(vast.Identifier('count'), vast.IntConst('1')) cp1_times_2 = vast.Times(count_plus_1, vast.IntConst('2')) cp1t2_plus_1 = vast.Plus(cp1_times_2, vast.IntConst('1')) assign_count_false = vast.NonblockingSubstitution( vast.Lvalue(vast.Identifier('count')), vast.Rvalue(cp1t2_plus_1)) if0_false = vast.Block([ assign_count_false ]) if0 = vast.IfStatement(vast.Identifier('RST'), if0_true, if0_false) statement = vast.Block([ if0 ]) always = vast.Always(senslist, statement) items = [] items.append(count) items.append(assign) items.append(always) ast = vast.ModuleDef("top", params, ports, items) codegen = ASTCodeGenerator() rslt = codegen.visit(ast) print(rslt) assert(expected == rslt)
def gen_lat(path): clk = vast.Ioport(vast.Input('en')) q = vast.Ioport(vast.Output('Q')) d = vast.Ioport(vast.Input('D')) r = vast.Ioport(vast.Input('rst')) ports = vast.Portlist([clk, q, d, r]) q_reg = vast.Identifier('reg Q = 0;') sens = [] sens.append(vast.Sens(vast.Identifier('en'), type='level')) sens.append(vast.Sens(vast.Identifier('rst'), type='level')) sens.append(vast.Sens(vast.Identifier('D'), type='level')) senslist = vast.SensList(sens) assign_q = vast.NonblockingSubstitution(vast.Lvalue(vast.Identifier('Q')), vast.Rvalue(vast.Identifier('D'))) blocks = [] blocks.append( vast.IfStatement( vast.Identifier('rst'), vast.Identifier('Q <= 0;'), vast.IfStatement(vast.Identifier('en'), assign_q, None), None)) statement = vast.Block(blocks) always = vast.Always(senslist, statement) items = [] items.append(q_reg) items.append(always) ast = vast.ModuleDef("lat", None, ports, items) write_verilog(ast, 'lat.v', path)
def visit_Localparam(self, node): name = node.name value = self.bind_visitor.visit(node.value) value = vast.Rvalue(value) width = self.make_width(node) signed = node.signed return vast.Localparam(name, value, width, signed)
def visit_Assign(self, node): if not isinstance(node.statement, vtypes.Subst): raise TypeError("Assign expects Subst object.") left = self.bind_visitor.visit(node.statement.left) right = self.bind_visitor.visit(node.statement.right) lvalue = vast.Lvalue(left) rvalue = vast.Rvalue(right) return vast.Assign(lvalue, rvalue)
def _convert_hls_fifo_to_relay_station(node, e: Edge) -> None: node.module = 'relay_station' # pipeline the FIFO width = ast.ParamArg('DATA_WIDTH', ast.Rvalue(ast.IntConst(str(e.width)))) depth = ast.ParamArg( 'DEPTH', ast.Rvalue(ast.IntConst(str(e.depth + e.added_depth_for_rebalance)))) addr_width = ast.ParamArg('ADDR_WIDTH', ast.Rvalue(ast.IntConst(str(e.addr_width)))) level = ast.ParamArg('LEVEL', ast.Rvalue(ast.IntConst(str(e.pipeline_level)))) params = [width, depth, addr_width, level] node.parameterlist = params for c in node.instances: c.module = 'relay_station' c.parameterlist = params
def lower_next(done_stage: vast.IntConst, ns: NextState): """ done_stage is the index of the final stage which just holds the all the values in the register. """ # The computation is finished; transition to the done stage. if isinstance(ns, Done): return vast.Rvalue(done_stage) elif isinstance(ns, DirectNext): return vast.Rvalue(vast.IntConst(ns.state)) elif isinstance(ns, CondNext): return vast.Cond( vast.Rvalue(vast.Identifier(ns.cond.name)), vast.IntConst(ns.on_true), vast.IntConst(ns.on_false), ) else: raise ValueError("Malformed AST, expected next: %s" % ns.pretty())
def visit_Subst(self, node): left = self.visit(node.left) right = self.visit(node.right) ldelay = vast.DelayStatement(self.visit( node.ldelay)) if node.ldelay else None rdelay = vast.DelayStatement(self.visit( node.rdelay)) if node.rdelay else None lvalue = vast.Lvalue(left) rvalue = vast.Rvalue(right) return vast.BlockingSubstitution(lvalue, rvalue, ldelay, rdelay)
def visit_Localparam(self, node): name = node.name value = self.bind_visitor.visit(node.value) value = vast.Rvalue(value) width = (None if node.width is None else self.make_width_msb_lsb(node.width_msb, node.width_lsb) if node.width_msb is not None and node.width_lsb is not None else self.make_width(node.width)) signed = node.signed return vast.Localparam(name, value, width, signed)
def add_assign(self, lhs, rhs): '''Adds a new assignment''' assign = ast.Assign(ast.Lvalue(ast.Identifier(lhs)), ast.Rvalue(rhs)) # find index to insert at insert_index = 0 for i in range(len(self.module.items)): if isinstance(self.module.items[i], ast.Assign): insert_index = i + 1 # insert the new assign node self.module.items = self.module.items[:insert_index] + ( assign, ) + self.module.items[insert_index:]
def _convert_hls_fifo_to_autobridge_fifo_template(node, e: Edge) -> None: # TODO: remove the extra grace period from the FIFO template node.module = 'fifo_almost_full' # pipeline the FIFO width = ast.ParamArg('DATA_WIDTH', ast.Rvalue(ast.IntConst(str(e.width)))) depth = ast.ParamArg( 'DEPTH', ast.Rvalue(ast.IntConst(str(e.depth + e.added_depth_for_rebalance)))) addr_width = ast.ParamArg('ADDR_WIDTH', ast.Rvalue(ast.IntConst(str(e.addr_width)))) grace_period = ast.ParamArg('GRACE_PERIOD', ast.Rvalue(ast.IntConst(str("0")))) params = [width, depth, addr_width, grace_period] node.parameterlist = params for c in node.instances: c.module = 'fifo_almost_full' c.parameterlist = params
def test(): params = vast.Paramlist( [] ) clk = vast.Ioport( vast.Input('CLK') ) rst = vast.Ioport( vast.Input('RST') ) width = vast.Width( vast.IntConst('7'), vast.IntConst('0') ) led = vast.Ioport( vast.Output('led', width=width) ) ports = vast.Portlist( (clk, rst, led) ) items = [ vast.Assign( vast.Lvalue(vast.Identifier('led')), vast.Rvalue(vast.IntConst('8'))) ] ast = vast.ModuleDef("top", params, ports, items) codegen = ASTCodeGenerator() rslt = codegen.visit(ast) print(rslt) assert(expected == rslt)
def addRelayStation(formator, node, edges_dict): # only considers fifo/rs instances if (not formator.isFIFOInstanceList(node)): return edge_name = formator.getFIFONameFromInstanceList(node) e = edges_dict[edge_name] if (e.mark): node.module = 'relay_station' width = ast.ParamArg('DATA_WIDTH', ast.Rvalue(ast.IntConst(str(e.width)))) depth = ast.ParamArg('DEPTH', ast.Rvalue(ast.IntConst(str(e.depth)))) addr_width = ast.ParamArg('ADDR_WIDTH', ast.Rvalue(ast.IntConst(str(e.addr_width)))) level = ast.ParamArg('LEVEL', ast.Rvalue(ast.IntConst(str(e.latency)))) params = [width, depth, addr_width, level] node.parameterlist = params for c in node.instances: c.module = 'relay_station' c.parameterlist = params # print(f'[codegen] update rs to {edge_name} -> {node.module}') # replace the ad-hoc fifos by hls # add the depth used for balancing reconvergent paths else: node.module = 'fifo' new_depth = int(e.depth + e.additional_depth) new_addr_width = int(math.log2(new_depth) + 1) width = ast.ParamArg('DATA_WIDTH', ast.Rvalue(ast.IntConst(str(e.width)))) depth = ast.ParamArg('DEPTH', ast.Rvalue(ast.IntConst(str(new_depth)))) addr_width = ast.ParamArg( 'ADDR_WIDTH', ast.Rvalue(ast.IntConst(str(new_addr_width)))) params = [width, depth, addr_width] node.parameterlist = params for c in node.instances: c.module = 'fifo' c.parameterlist = params
def gen_dff(path): clk = vast.Ioport(vast.Input('clk')) q = vast.Ioport(vast.Output('Q')) d = vast.Ioport(vast.Input('D')) ports = vast.Portlist([clk, q, d]) q_reg = vast.Identifier('reg Q = 0;') sens = vast.Sens(vast.Identifier('clk'), type='posedge') senslist = vast.SensList([sens]) assign_q = vast.NonblockingSubstitution(vast.Lvalue(vast.Identifier('Q')), vast.Rvalue(vast.Identifier('D'))) statement = vast.Block([assign_q]) always = vast.Always(senslist, statement) items = [] items.append(q_reg) items.append(always) ast = vast.ModuleDef("dff", None, ports, items) write_verilog(ast, 'dff.v', path)
def lower_fsm(fsm: FSM): assert fsm.start_state == 0, "Starting state is not 0" zero = vast.IntConst(0) all_registers = [ Register("a", 8), Register("b", 8), Register("tmp", 8), Register("_cond", 1), ] register_defs = [ vast.Reg( reg.name, vast.Width(vast.IntConst(reg.width - 1), zero) if reg.width - 1 != 0 else None) for reg in all_registers ] ports = vast.Portlist([ vast.Ioport(vast.Input('clk')), # XXX(rachit): AST can't represent `output reg done` # so assign to a local register and use a wire. vast.Ioport(vast.Output('done')), ]) done_state = max(fsm.actions.keys()) + 1 done_reg = vast.Reg('done_out') hook_up_done = vast.Assign( vast.Lvalue(vast.Identifier('done')), vast.Rvalue(vast.Identifier('done_out')), ) # Register to store the FSM state. fsm_reg_size = int(math.ceil(math.log2(done_state))) + 1 fsm_reg = vast.Reg(name="fsm_reg", width=vast.Width(vast.IntConst(fsm_reg_size - 1), zero)) # Define all the registers. reg_decl = register_defs + [fsm_reg] # Define the initial process inits = vast.Initial( vast.Block([ vast.BlockingSubstitution( vast.Lvalue(vast.Identifier(reg.name)), vast.Rvalue(vast.IntConst(0)), ) for reg in reg_decl ])) # Default case, assigns to the done register. done = vast.IntConst(done_state) default_case = vast.Case(cond=None, statement=vast.Block([ vast.NonblockingSubstitution( vast.Lvalue(vast.Identifier(reg.name)), vast.Rvalue(vast.Identifier(reg.name)), ) for reg in reg_decl ] + [ vast.NonblockingSubstitution( vast.Lvalue(vast.Identifier('done_out')), vast.Rvalue(vast.IntConst(1))) ])) # Generate Case conditions for each transition. cases = [ vast.Case([vast.IntConst(cond_val)], lower_action(fsm_reg, done, action)) for (cond_val, action) in fsm.actions.items() ] case_statement = vast.CaseStatement(comp=vast.Identifier(fsm_reg.name), caselist=cases + [default_case]) always_ff = vast.Always( vast.SensList([vast.Sens(vast.Identifier('clk'), 'posedge')]), vast.Block([case_statement])) return vast.ModuleDef(name="main", paramlist=vast.Paramlist([]), portlist=ports, items=reg_decl + [done_reg, hook_up_done, inits, always_ff])
def lower_update(upd: Update): reg = upd.register.name return vast.NonblockingSubstitution(vast.Lvalue(vast.Identifier(reg)), vast.Rvalue(lower_expr(upd.expr)))