def dip_gen_module_uc(self): # create dip_generator module # this is the assume based version # slower than dip_gen_module() due to the assume portslist = [] portslist.append(vast.Ioport(vast.Input('clk'))) portslist.append(vast.Ioport(vast.Input('iv', width=self.inp_width))) portslist.append(vast.Ioport(vast.Input('k1', width=self.key_width))) portslist.append(vast.Ioport(vast.Input('k2', width=self.key_width))) portslist = vast.Portlist(portslist) inst_list = [] inst_list.append(vast.Wire('ov1', width=self.out_width)) inst_list.append(vast.Wire('ov2', width=self.out_width)) inst_list.extend([self.obf1, self.obf2]) # add always* block blocks = [] blocks.append(vast.Identifier('assume (k1 != k2);')) blocks.append(vast.Identifier('assert (ov1 == ov2);')) statement = vast.Block(blocks) # sens = vast.Sens(None, type='all') sens = vast.Sens(vast.Identifier('clk'), type='posedge') inst_list.append(vast.Always(vast.SensList([sens]), statement)) self.dip_gen = vast.ModuleDef("dip_generator", None, portslist, inst_list)
def visit_Scope(self, node): scope = [] for a in node.args: if isinstance(a, module.GenerateIf): if a.true_scope is None: raise TypeError("GenerateIf statement without scope name" "can not be used as an scope index.") scope.append(vast.IdentifierScopeLabel(a.true_scope)) elif isinstance(a, module.GenerateIfElse): if a.false_scope is None: raise TypeError( "GenerateIfElse statement without scope name" "can not be used as an scope index.") scope.append(vast.IdentifierScopeLabel(a.false_scope)) elif isinstance(a, module.GenerateFor): raise TypeError("Scope index must not be GenerateFor. " "Use slice, like 'obj[index]'") elif isinstance(a, vtypes.ScopeIndex): scope.append(self.visit(a)) elif isinstance(a, str): scope.append(vast.IdentifierScopeLabel(a)) else: _id = self.visit(a) if not isinstance(_id, vast.Identifier): raise TypeError( "Cannot convert into IdentifierScopeLabel from %s." % str(type(_id))) scope.append(vast.IdentifierScopeLabel(_id.name)) if len(scope) == 1: return vast.Identifier(scope[0].name) return vast.Identifier(scope[-1].name, vast.IdentifierScope(tuple(scope[:-1])))
def dip_chk_module(self): # create dip_checker module portslist = [] portslist.append(vast.Ioport(vast.Input('clk'))) portslist.append(vast.Ioport(vast.Input('iv', width=self.inp_width))) portslist.append(vast.Ioport(vast.Input('k1', width=self.key_width))) portslist.append(vast.Ioport(vast.Input('k2', width=self.key_width))) portslist = vast.Portlist(portslist) inst_list = [] inst_list.append(vast.Wire('ov0', width=self.out_width)) inst_list.append(vast.Wire('ov1', width=self.out_width)) inst_list.append(vast.Wire('ov2', width=self.out_width)) inst_list.extend([self.org0, self.obf1, self.obf2]) # add always block sens = vast.Sens(vast.Identifier('clk'), type='posedge') senslist = vast.SensList([sens]) blocks = [] blocks.append(vast.Identifier('assume (ov0 == ov1);')) blocks.append(vast.Identifier('assume (ov0 == ov2);')) statement = vast.Block(blocks) inst_list.append(vast.Always(senslist, statement)) self.dip_chk = vast.ModuleDef("dip_checker", None, portslist, inst_list)
def ce_module_ext_sby(self): self.ce.items.append( vast.Identifier('(* anyconst *) wire [{}:0] k1;'.format( self.key_size_msb))) self.ce.items.append( vast.Identifier('(* anyconst *) wire [{}:0] k2;'.format( self.key_size_msb))) self.ce.items.append(vast.Identifier('reg [10:0] cycle = 0;'))
def main(): a = vast.Identifier('a') b = vast.Identifier('b') c = vast.Plus(a, b) ids = {'a': 'x', 'b': 'y'} d = replaceIdentifiers(c, ids) print(d)
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 ce_module_ext_formal(self): self.ce.portlist.ports.append( vast.Ioport(vast.Input('k1', width=self.key_width))) self.ce.portlist.ports.append( vast.Ioport(vast.Input('k2', width=self.key_width))) self.ce.items.append( vast.Identifier('assume property (@(clk) $stable(k1));')) self.ce.items.append( vast.Identifier('assume property (@(clk) $stable(k2));')) self.ce.items.append(vast.Identifier('reg [10:0] cycle;'))
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 uc_module_ext_formal(self, ): # create additional blocks for jaspergold self.uc.portlist.ports.append(vast.Ioport(vast.Input('clk'))) self.uc.portlist.ports.append( vast.Ioport(vast.Input('k1', width=self.key_width))) self.uc.portlist.ports.append( vast.Ioport(vast.Input('k2', width=self.key_width))) self.uc.items.append(vast.Identifier('reg [10:0] cycle;')) self.uc.items.append( vast.Identifier('assume property (@(clk) $stable(k1));')) self.uc.items.append( vast.Identifier('assume property (@(clk) $stable(k2));'))
def lower_action(fsm_reg: vast.Reg, done_stage: vast.IntConst, action: Action): body = [lower_update(upd) for upd in action.updates] # Statement to update the FSM register to next state. st_upd = vast.NonblockingSubstitution( vast.Lvalue(vast.Identifier(fsm_reg.name)), lower_next(done_stage, action.next_state), ) return vast.Block(body + [st_upd])
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 __init__(self, orcl_cir, obf_cir, enable_async, key_constraints): self.dip_gen = None self.dis_gen = None self.dip_chk = None self.uc = None self.ce = None self.umc = None self.state_size_msb = 0 self.main = None self.enable_async = enable_async self.key_constraints = key_constraints self.orcl_cir = orcl_cir # create common components module if obf_cir: self.key_size_msb = obf_cir.n_keys - 1 self.input_size_msb = orcl_cir.n_inputs - 2 self.output_size_msb = orcl_cir.n_outputs - 1 self.key_width = vast.Width(vast.IntConst(self.key_size_msb), vast.IntConst('0')) self.inp_width = vast.Width(vast.IntConst(str(self.input_size_msb)), vast.IntConst('0')) self.out_width = vast.Width(vast.IntConst(str(self.output_size_msb)), vast.IntConst('0')) # create instances for org0 and obf1 and obf2 ports = create_ports('iv', 'ov0', orcl_cir) inst = vast.Instance(orcl_cir.name, "org0", ports, "") self.org0 = vast.InstanceList(orcl_cir.name, "", [inst]) ports = create_ports('iv', 'ov1', orcl_cir) key_ports = [vast.PortArg("", vast.Identifier('k1'))] inst = vast.Instance(orcl_cir.name + '_obf', "obf1", ports + key_ports, "") self.obf1 = vast.InstanceList(orcl_cir.name + '_obf', "", [inst]) ports = create_ports('iv', 'ov2', orcl_cir) key_ports = [vast.PortArg("", vast.Identifier('k2'))] inst = vast.Instance(orcl_cir.name + '_obf', "obf2", ports + key_ports, "") self.obf2 = vast.InstanceList(orcl_cir.name + '_obf', "", [inst])
def lower_expr(expr: SynthExpr): if isinstance(expr, RegRef): return vast.Identifier(expr.name) elif isinstance(expr, Num): return vast.IntConst(expr.val) elif isinstance(expr, Binop): return BINOP_MAP[expr.op]( lower_expr(expr.left), lower_expr(expr.right), ) else: raise ValueError("Malformed AST, expected expr: %s" % expr.pretty())
def uc_module_ext_sby(self): # create additional blocks for symbiyosys if not self.enable_async: self.uc.portlist.ports.append(vast.Ioport(vast.Input('clk = 0'))) else: self.uc.items.append(vast.Identifier('reg clk = 0;')) self.uc.items.append(vast.Identifier('reg [10:0] cycle = 0;')) self.uc.items.append( vast.Identifier('(* anyconst *) wire [{}:0] k1;'.format( self.key_size_msb))) self.uc.items.append( vast.Identifier('(* anyconst *) wire [{}:0] k2;'.format( self.key_size_msb))) if self.enable_async: self.uc.items.append(vast.Identifier('(* gclk *) reg gbl_clk;')) self.uc.items.append(vast.Identifier('always @(posedge gbl_clk)')) self.uc.items.append(vast.Identifier('clk = !clk;')) self.uc.items.append(vast.Identifier('always @(posedge gbl_clk)')) self.uc.items.append(vast.Identifier('if (!$rose(clk))')) self.uc.items.append(vast.Identifier('assume($stable(iv));'))
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 create_ports(prefix1, prefix2, circuit): ports = [vast.PortArg("", vast.Identifier('clk'))] input_index = 0 output_index = 0 for p in circuit.port_defs: if ('clk' not in p) and ('keyinput' not in p) and ('CK' not in p): if p in circuit.input_wires: next_index = input_index + circuit.input_wires[p] - 1 ports.append( vast.PortArg( "", vast.Identifier('{}[{}:{}]'.format( prefix1, input_index, next_index)))) input_index += circuit.input_wires[p] if p in circuit.output_wires: next_index = output_index + circuit.output_wires[p] - 1 ports.append( vast.PortArg( "", vast.Identifier('{}[{}:{}]'.format( prefix2, output_index, next_index)))) output_index += circuit.output_wires[p] return ports
def dip_gen_module(self): # creates dip_generator module # a more complicated version of dip_gen_module_uc # uses if in place of assume, it is faster but couldn't be used for uc termination portslist = [] portslist.append(vast.Ioport(vast.Input('clk'))) portslist.append(vast.Ioport(vast.Input('iv', width=self.inp_width))) portslist.append(vast.Ioport(vast.Input('k1', width=self.key_width))) portslist.append(vast.Ioport(vast.Input('k2', width=self.key_width))) portslist = vast.Portlist(portslist) inst_list = [] inst_list.append(vast.Wire('ov1', width=self.out_width)) inst_list.append(vast.Wire('ov2', width=self.out_width)) inst_list.extend([self.obf1, self.obf2]) # add always* block blocks = [] # blocks.append(vast.IfStatement(vast.Identifier('k1 != k2'), # vast.IfStatement(vast.Identifier('ov1 != ov2'), # vast.Identifier('assert (ov1 == ov2);'), None), # None)) # TODO: changed for latch locking blocks.append(vast.Identifier('assume (k1 != k2);')) blocks.append(vast.Identifier('assert (ov1 == ov2);')) statement = vast.Block(blocks) # TODO: posedge in case of latch # sens = vast.Sens(None, type='all') sens = vast.Sens(vast.Identifier('clk'), type='posedge') inst_list.append(vast.Always(vast.SensList([sens]), statement)) self.dip_gen = vast.ModuleDef("dip_generator", None, portslist, inst_list)
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.Identifier('led'), vast.IntConst('8')), ) ast = vast.ModuleDef("top", params, ports, items) codegen = ASTCodeGenerator() rslt = codegen.visit(ast) print(rslt) assert (expected == rslt)
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 fk_module_ext_sby(self): if self.enable_async: self.ce.items.append(vast.Identifier('reg clk = 0;')) self.ce.items.append(vast.Identifier('(* gclk *) reg gbl_clk;')) self.ce.items.append(vast.Identifier('always @(posedge gbl_clk)')) self.ce.items.append(vast.Identifier('clk =! clk;')) else: self.ce.portlist.ports.append(vast.Ioport(vast.Input('clk'))) self.ce.items.append(vast.Identifier('reg [10:0] cycle = 0;')) self.ce.items.append( vast.Identifier('(* anyconst *) wire [' + str(self.key_size_msb) + ':0] k1;')) self.ce.items.append( vast.Identifier('(* anyconst *) wire [' + str(self.key_size_msb) + ':0] k2;'))
def expose_internal_scheduling_signals(self, num_rules_per_module=None, scheduling_order=None, add_force_fire=False): # if schedule isn't provided, assume rules first then modules if scheduling_order is None: scheduling_order = [ 'RL_' + x for x in self.get_rules_in_scheduling_order() ] + ['MODULE_' + x for x, y in self.get_submodules()] instance_to_module = {x: y for x, y in self.get_submodules()} can_fires = [] will_fires = [] # compute total number of bits total_num_bits = 0 for name in scheduling_order: if name.startswith('RL_'): total_num_bits += 1 elif name.startswith('MODULE_'): instance_name = name[len('MODULE_'):] module_name = instance_to_module[instance_name] if num_rules_per_module is None: continue if module_name not in num_rules_per_module: continue num_submodule_rules = num_rules_per_module[module_name] if num_submodule_rules == 0: continue total_num_bits += num_submodule_rules # now add the signals curr_bit_index = 0 for name in scheduling_order: if name.startswith('RL_'): self.add_decls('BLOCK_FIRE_' + name, ast.Wire) if add_force_fire: self.add_decls('FORCE_FIRE_' + name, ast.Wire) # definition of BLOCK_FIRE and FORCE_FILE assign = self.get_assign('WILL_FIRE_' + name) if add_force_fire: new_rhs = ast.Or( ast.Identifier('FORCE_FIRE_' + name), ast.And(ast.Unot(ast.Identifier('BLOCK_FIRE_' + name)), assign.right.var)) else: new_rhs = ast.And( ast.Unot(ast.Identifier('BLOCK_FIRE_' + name)), assign.right.var) assign.right.var = new_rhs # definition of BLOCK_FIRE_* and FORCE_FIRE_* signals from top-level BLOCK_FIRE and FORCE_FIRE if total_num_bits == 1: self.add_assign('BLOCK_FIRE_' + name, ast.Identifier('BLOCK_FIRE')) if add_force_fire: self.add_assign('FORCE_FIRE_' + name, ast.Identifier('FORCE_FIRE')) else: self.add_assign( 'BLOCK_FIRE_' + name, ast.Partselect(ast.Identifier('BLOCK_FIRE'), ast.IntConst(curr_bit_index), ast.IntConst(curr_bit_index))) if add_force_fire: self.add_assign( 'FORCE_FIRE_' + name, ast.Partselect(ast.Identifier('FORCE_FIRE'), ast.IntConst(curr_bit_index), ast.IntConst(curr_bit_index))) curr_bit_index += 1 can_fires.append(ast.Identifier('CAN_FIRE_' + name)) will_fires.append(ast.Identifier('WILL_FIRE_' + name)) elif name.startswith('MODULE_'): instance_name = name[len('MODULE_'):] module_name = instance_to_module[instance_name] if num_rules_per_module is None: continue if module_name not in num_rules_per_module: continue num_submodule_rules = num_rules_per_module[module_name] if num_submodule_rules == 0: continue instance = self.get_instance(instance_name) for signal_type in [ 'CAN_FIRE', 'WILL_FIRE', 'BLOCK_FIRE', 'FORCE_FIRE' ]: if signal_type == 'FORCE_FIRE' and not add_force_fire: continue # declarations of all FIRE signals for the submodule self.add_decls(signal_type + '_' + name, ast.Wire, width=num_submodule_rules) # connection of all FIRE signals to the submodule # this assumes the submodule has ports named CAN_FIRE, WILL_FIRE, BLOCK_FIRE, and if add_force_fire is true, FORCE_FIRE instance.portlist += (ast.PortArg( signal_type, ast.Identifier(signal_type + '_' + name)), ) # assignments of BLOCK_FIRE_* and FORCE_FIRE_* signals from top-level BLOCK_FIRE and FORCE_FIRE lsb = curr_bit_index msb = curr_bit_index + num_submodule_rules - 1 curr_bit_index += num_submodule_rules if total_num_bits == 1: self.add_assign('BLOCK_FIRE_' + name, ast.Identifier('BLOCK_FIRE')) if add_force_fire: self.add_assign('FORCE_FIRE_' + name, ast.Identifier('FORCE_FIRE')) else: self.add_assign( 'BLOCK_FIRE_' + name, ast.Partselect(ast.Identifier('BLOCK_FIRE'), ast.IntConst(msb), ast.IntConst(lsb))) if add_force_fire: self.add_assign( 'FORCE_FIRE_' + name, ast.Partselect(ast.Identifier('FORCE_FIRE'), ast.IntConst(msb), ast.IntConst(lsb))) can_fires.append(ast.Identifier('CAN_FIRE_' + name)) will_fires.append(ast.Identifier('WILL_FIRE_' + name)) elif name.startswith('METH_'): raise ValueError( '"METH_" scheduling signals are not supported yet') else: raise ValueError('unexpected entry "%s" in scheduling_order' % name) if total_num_bits != 0: # new ports self.add_ports(['CAN_FIRE', 'WILL_FIRE', 'BLOCK_FIRE']) if add_force_fire: self.add_ports(['FORCE_FIRE']) self.add_decls('CAN_FIRE', ast.Output, width=total_num_bits) self.add_decls('WILL_FIRE', ast.Output, width=total_num_bits) self.add_decls('BLOCK_FIRE', ast.Input, width=total_num_bits) if add_force_fire: self.add_decls('FORCE_FIRE', ast.Input, width=total_num_bits) self.add_decls('CAN_FIRE', ast.Wire, width=total_num_bits) self.add_decls('WILL_FIRE', ast.Wire, width=total_num_bits) # connect CAN_FIRE and WILL_FIRE can_fires.reverse() will_fires.reverse() self.add_assign('CAN_FIRE', ast.Concat(can_fires)) self.add_assign('WILL_FIRE', ast.Concat(will_fires)) return total_num_bits
def getIdentifiers(node): v = IdentifierVisitor() v.visit(node) ids = v.getIdentifiers() return ids class IdentifierVisitor(NodeVisitor): def __init__(self): self.identifiers = [] def getIdentifiers(self): return tuple(self.identifiers) def reset(self): self.identifiers = [] def visit_Identifier(self, node): self.identifiers.append(node.name) if __name__ == '__main__': import pyverilog.vparser.ast as vast a = vast.Identifier('a') b = vast.Identifier('b') c = vast.Plus(a, b) ids = getIdentifiers(c) print(ids)
def visit_Instance(self, node): return vast.Identifier(node.instname)
def visit_Task(self, node): name = node.name return vast.Identifier(name)
def visit_Function(self, node): name = node.name return vast.Identifier(name)
def visit_AnyType(self, node): name = node.name return vast.Identifier(name)
def visit_Integer(self, node): name = node.name return vast.Identifier(name)
def visit_Identifier(self, node): if node.name in self.ids: return vast.Identifier(self.ids[node.name]) return node
def visit_Output(self, node): name = node.name return vast.Identifier(name)
def visit_TaskCall(self, node): name = vast.Identifier(node.name) args = tuple([self.visit(a) for a in node.args]) return vast.TaskCall(name, args)