def visit_UnaryOp(self, node): """Visit Unary operations.""" if isinstance(node.op, ast.Not): return HDLExpression(self.visit(node.operand)).bool_neg() elif isinstance(node.op, ast.Invert): return ~HDLExpression(self.visit(node.operand)) else: raise TypeError("operator {} not supported".format( node.op.__class__.__name__))
def test_concat(): """Test concatenation.""" sig = HDLSignal("comb", "my_signal", size=4) concat = HDLConcatenation(sig, HDLExpression(0x0C, size=8)) assert len(concat) == 12 concat.append(HDLExpression(0x1, size=1)) # failures with pytest.raises(TypeError): _ = HDLConcatenation(sig, "not_allowed")
def visit_Compare(self, node): """Visit Compare.""" self.generic_visit(node) if isinstance(node.left, ast.Name): # NOTE: Don't know why this is necessary anymore left_sig = self._signal_lookup(node.left.id) if left_sig is None: if self._signal_lookup(node.left.id) is not None: # rename node.left.id = "reg_" + str(node.left.id) else: raise NameError('in "{}": signal "{}" not available in' " current scope".format( self._get_current_block(), node.left.id)) if len(node.comparators) > 1: raise RuntimeError("only single comparison is allowed") (comp, ) = node.comparators if isinstance(comp, ast.Name): comp_sig = self._signal_lookup(comp.id) if comp_sig is None: if self._signal_lookup("reg_" + str(comp.id)) is not None: # is state register, rename comp.id = "reg_" + str(comp.id) else: raise NameError('in "{}": signal "{}" not available in' " current scope".format( self._get_current_block(), comp.id)) return HDLExpression(node)
def get_multiplexer(target, select, *options): """Generate multiplexer pattern.""" if len(options) < 2: raise RuntimeError("must have 2 or more options") for idx, opt in enumerate(options): if not isinstance(opt, (HDLSignal, HDLSignalSlice, HDLModulePort)): raise RuntimeError( "options must be signals or ports, got: {}".format(type(opt)) ) if isinstance(opt, HDLModulePort): opt = opt.signal.name # None is placeholder for last expression if idx < len(options) - 1: _ifexp = HDLIfExp(HDLExpression(select == idx), opt, None) if idx == 0: ifexp = _ifexp root_ifexp = _ifexp else: # update last expression if idx == len(options) - 1: ifexp.else_value = opt else: ifexp.else_value = _ifexp ifexp = _ifexp return HDLAssignment(target, root_ifexp)
def test_hdl_module(): """Test modules.""" mod = HDLModule("my_module") mod = HDLModule("my_module", [HDLModulePort("in", "myport", 8)]) mod = HDLModule("my_module", params=[HDLModuleParameter("myparam", "integer", 0)]) expr = ast.parse("myparam-1", mode="eval") vec = HDLVectorDescriptor(left_size=HDLExpression(expr), right_size=0) mod = HDLModule( "my_module", ports=[HDLModulePort("in", "myport", vec)], params=HDLModuleParameter("myparam", "integer", 0), ) print(mod.dumps(evaluate=True)) _ = mod.get_parameter_scope() _ = mod.get_full_scope() _ = mod.get_param_names() _ = mod.get_port_names() # failures with pytest.raises(TypeError): mod = HDLModule("my_module", 0) with pytest.raises(TypeError): mod = HDLModule("my_module", [0]) with pytest.raises(TypeError): mod = HDLModule("my_module", params=[0]) with pytest.raises(TypeError): mod = HDLModule("my_module", params=0)
def test_seq(): """Test sequential block.""" some_signal = HDLSignal("reg", "signal", size=1) sens_1 = HDLSensitivityDescriptor(sens_type="rise", sig=some_signal) sens_list = HDLSensitivityList() sens_list.add(sens_1) ass_sig = HDLSignal("reg", "counter", size=2) ass_expr = HDLExpression(ass_sig) + 1 assign = HDLAssignment(ass_sig, ass_expr) seq = HDLSequentialBlock(sens_list) seq.add(assign) print(seq.dumps())
def visit_If(self, node): """Visit If statement.""" self.visit(node.test) ifelse = HDLIfElse(HDLExpression(ast.Expression(body=node.test))) self.current_scope.add([ifelse]) last_scope = self.current_scope # ordered visit, two scopes, so separe self.current_scope = ifelse.if_scope for _node in node.body: self.visit(_node) self.current_scope = ifelse.else_scope for _node in node.orelse: self.visit(_node) self.current_scope = last_scope return node
def test_ifelse(): """Test if-else.""" # create an if-else block gen = VerilogCodeGenerator() sig = HDLSignal(sig_type="comb", sig_name="test", size=1) test_sig = HDLSignal(sig_type="reg", sig_name="counter", size=2) assign_rhs = HDLExpression(test_sig) + 1 assignment = HDLAssignment(signal=test_sig, value=assign_rhs) ifelse = HDLIfElse(condition=sig) ifelse.add_to_if_scope(assignment) # make else assignment = HDLAssignment(signal=test_sig, value=0) ifelse.add_to_else_scope(assignment) print(gen.dump_element(ifelse))
def visit_Name(self, node): """Visit Name.""" signal = self._signal_lookup(node.id) if signal is not None: if isinstance(signal, HDLSignalSlice): signal_name = signal.signal.name elif isinstance(signal, (HDLSignal, HDLModulePort)): signal_name = signal.name elif isinstance(signal, int): signal_name = signal else: raise RuntimeError("unknown error") else: signal_name = node.id if self._verify_signal_name: if signal is None: raise NameError("unknown name: {}".format(node.id)) node.id = signal_name return HDLExpression(signal_name)
def test_always(): """Test always block.""" gen = VerilogCodeGenerator() sig = HDLSignal(sig_type="reg", sig_name="clk", size=1) sens = HDLSensitivityDescriptor(sens_type="rise", sig=sig) sens_list = HDLSensitivityList() sens_list.add(sens) test_sig = HDLSignal(sig_type="reg", sig_name="counter", size=2) rst_assign = HDLAssignment(signal=test_sig, value=0) norm_expr = HDLExpression(test_sig) + 1 norm_assign = HDLAssignment(signal=test_sig, value=norm_expr) rst = HDLSignal(sig_type="reg", sig_name="rst", size=1) ifelse = HDLIfElse(condition=rst) ifelse.add_to_if_scope(rst_assign) ifelse.add_to_else_scope(norm_assign) seq = HDLSequentialBlock(sensitivity_list=sens_list) seq.add(ifelse) print(gen.dump_element(seq))
def visit_SlaveRegisterField(self, node): """Visit register field.""" src_reg, src_field = node.source if src_reg not in self._registers: raise ValueError("unknown register: {}".format(src_reg)) ssize = self.slice_size(self.bitfield_pos_to_slice(node.position)) if node.default is not None: if isinstance(node.default, int): param_size = HDLIntegerConstant.minimum_value_size( node.default ) defval = node.default else: if node.default.strip() in self._parameters: param_size = 0 defval = HDLExpression(node.default.strip(), size=ssize) else: raise RuntimeError( "unknown identifier: {}".format(node.default.strip()) ) if ssize < param_size: raise RuntimeError("value does not fit in field") else: defval = 0 reg_field = HDLRegisterField( src_field, self.bitfield_pos_to_slice(node.position), node.access, default_value=defval, ) for prop in node.properties: reg_field.add_properties(**{prop.name: prop.value}) self._registers[src_reg].add_fields(reg_field)
def test_hdl_expression(): """Test expressions.""" expr_1 = "PARAM-2" expr_2 = "PARAM_X+1" expr_3 = "a and ~b" hdl_expr_1 = HDLExpression(ast.parse(expr_1, mode="eval")) hdl_expr_2 = HDLExpression(ast.parse(expr_2, mode="eval")) hdl_expr_3 = HDLExpression(expr_3) print(hdl_expr_3.dumps()) sum = hdl_expr_1 + hdl_expr_2 neg = ~sum bool_neg = sum.bool_neg() bool_and = hdl_expr_1.bool_and(hdl_expr_2) bool_or = hdl_expr_1.bool_or(hdl_expr_2) print(sum.dumps()) print(neg.dumps()) print(bool_neg.dumps()) print(bool_and.dumps()) print(bool_or.dumps()) _ = hdl_expr_1 & 0x1 _ = 0x1 | hdl_expr_1 _ = 0x1 & hdl_expr_1 _ = 0x1 ^ hdl_expr_1 _ = hdl_expr_1 ^ 0x1 my_signal = HDLSignal("reg", "signal_a", size=2) _ = HDLExpression(HDLIntegerConstant(1)) _ = HDLExpression(1) _ = HDLExpression(my_signal) _ = HDLExpression(HDLSignalSlice(my_signal, 1)) _ = HDLExpression(my_signal[1:0]) # test reduction expr_a = HDLExpression("value_a") expr_b = HDLExpression("value_b") full_expr = expr_a << 0 | expr_b << 16 | HDLExpression(0) case_1 = ast.BinOp(left=ast.Constant(value=0), op=ast.BitOr(), right=ast.Name(id="VAR")) case_2 = ast.BinOp(left=ast.Constant(value=1), op=ast.Mult(), right=ast.Name(id="VAR")) case_3 = ast.BinOp(left=ast.Constant(value=0), op=ast.Mult(), right=ast.Name(id="VAR")) hdl_expr = HDLExpression(ast.Expression(body=case_1)) hdl_expr_2 = HDLExpression(ast.Expression(body=case_2)) hdl_expr_3 = HDLExpression(ast.Expression(body=case_3)) print(hdl_expr.dumps()) print(hdl_expr_2.dumps()) reduced_1 = HDLExpression._reduce_binop(case_1) hdl_expr = HDLExpression(ast.Expression(body=reduced_1)) print(hdl_expr.dumps()) reduced_2 = HDLExpression._reduce_binop(case_2) hdl_expr_2 = HDLExpression(ast.Expression(body=reduced_2)) print(hdl_expr_2.dumps()) reduced_3 = HDLExpression._reduce_binop(case_3) hdl_expr_3 = HDLExpression(ast.Expression(body=reduced_3)) print(hdl_expr_3.dumps()) print(full_expr.dumps()) full_expr.reduce_expr() print(full_expr.dumps())
def _parse_file(self): """Parse file.""" meta_model = metamodel_from_file( pkg_resources.resource_filename( "hdltools", "verilog/module_grammar.tx" ) ) module_decl = meta_model.model_from_file(self.mod_file) # create module object hdl_mod = HDLModule(module_decl.mod_decl.mod_name) # create and add parameters if module_decl.mod_decl.param_decl is not None: params = module_decl.mod_decl.param_decl.params[:] for param in params: # use ast to parse if param.def_val.expr is not None: param_str = param.def_val.expr.replace("$", "_") param_tree = ast.parse(param_str, mode="eval") # dependency check param_deps = self._find_dependencies(param_tree) for dep in param_deps: if dep not in self.hdl_model.get_param_names(): raise KeyError( "unknown identifier:" " {}".format(dep) ) # evaluate parameters immediately (not necessary) scope = hdl_mod.get_full_scope() param_val = HDLExpression(param_tree).evaluate(**scope) else: param_val = param.def_val.bitstr hdl_param = HDLModuleParameter( param_name=param.par_name, param_type=param.par_type, param_default=param_val, ) hdl_mod.add_parameters(hdl_param) self.hdl_model = hdl_mod # create and add ports ports = module_decl.mod_decl.ports[:] for port in ports: # ugly, but not my fault direction = self._class_to_port_dir[port.__class__.__name__] name = port.decl.port_name if port.decl.srange is not None: size = ( port.decl.srange.left_size, port.decl.srange.right_size, ) # use ast to parse, avoiding complicated grammar left_str = port.decl.srange.left_size.replace("$", "_") right_str = port.decl.srange.right_size.replace("$", "_") left_tree = ast.parse(left_str, mode="eval") right_tree = ast.parse(right_str, mode="eval") left_deps = self._find_dependencies(left_tree) right_deps = self._find_dependencies(right_tree) # search dependencies in parameters for dep in left_deps: if dep not in self.hdl_model.get_param_names(): raise KeyError("unknown identifier: {}".format(dep)) for dep in right_deps: if dep not in self.hdl_model.get_param_names(): raise KeyError("unknown identifier: {}".format(dep)) size = (HDLExpression(left_tree), HDLExpression(right_tree)) else: size = (0, 0) try: hdl_port = HDLModulePort( direction=direction, name=name, size=size ) except TypeError: pass self.hdl_model.add_ports(hdl_port)
def __pos__(self): """Access internal signal as an expression.""" return HDLExpression(self.signal)
def visit_BinOp(self, node): """Visit Binary operations.""" self.generic_visit(node) return HDLExpression(ast.Expression(body=node))
def visit_Assign(self, node): """Visit Assignments.""" self.generic_visit(node) assignments = [] # check assignees (targets) assignees = [] for target in node.targets: if isinstance(target, ast.Attribute): # attributes are not allowed, except for self access if target.value.id == "self": # bypass attribute access directly, # later on we can execute the block itself in python # if necessary target.id = target.attr else: raise PatternNotAllowedError( "Attribute access is not allowed in HDL blocks.") if self._signal_lookup(target.id) is None: if self._signal_lookup("reg_" + target.id) is None: raise NameError('in "{}": signal "{}" not available in' " current scope".format( self._get_current_block(), target.id)) else: target.id = "reg_" + target.id assignees.append(target.id) # check value assigned if isinstance(node.value, ast.Name): if self._signal_lookup(node.value.id) is None: raise NameError('in "{}": signal "{}" not available in' " current scope".format( self._get_current_block(), node.value.id)) for assignee in assignees: assignments.append( HDLAssignment( self._signal_lookup(assignee), self._signal_lookup(node.value.id), )) elif isinstance(node.value, ast.Constant): for assignee in assignees: assignments.append( HDLAssignment( self._signal_lookup(assignee), HDLExpression(node.value.value), )) elif isinstance(node.value, (ast.List, ast.Tuple)): items = [self.visit(item) for item in node.value.elts] for assignee in assignees: assignments.append( HDLAssignment( self._signal_lookup(assignee), HDLConcatenation(*items[::-1]), )) elif isinstance(node.value, ast.Call): for assignee in assignees: args = [self._signal_lookup(arg.id) for arg in node.value.args] kwargs = { kw.arg: self._signal_lookup(kw.value.id) for kw in node.value.keywords } if node.value.func.id in self._symbols: fn = self._symbols[node.value.func.id] # generate ret = fn(*args, **kwargs) else: # dont do anything for now, lazy fn = node.value.func.id ret = (HDLLazyValue( fn, fnargs=args, fnkwargs=kwargs, ), ) assignments.append( HDLAssignment(self._signal_lookup(assignee), ret)) else: try: expr = self.visit(node.value) for assignee in assignees: assignments.append( HDLAssignment(self._signal_lookup(assignee), expr)) except TypeError: # raise TypeError('type {} not supported'.format( # node.value.__class__.__name__)) raise # find out where to insert statement if len(assignments) > 0: self.current_scope.add(*assignments)
def visit_Constant(self, node): """Visit Constant.""" if isinstance(node.value, int): return HDLExpression(node.value) return node