Commits

Martin Vejnár committed 83792a7

Added basic support for module parameters. No type checking.

Comments (0)

Files changed (7)

-module res(p,n);
+module res #(parameter real r = 1.0) (p,n);
     electrical p, n;
-    analog V(p,n) <+ 100.0*I(p,n);
+    analog V(p,n) <+ r*I(p,n);
 endmodule
 
-module src(p,n);
+module src #(parameter real v = 5.0) (p,n);
     electrical p, n;
-    analog V(p,n) <+ 5;
+    analog V(p,n) <+ v;
 endmodule
 
 module main();
     ground n;
-    src s1(p, n);
-    res r1(p, m);
-    res r2(m, n);
+    src #(10.0) s1(p, n);
+    res #(200.0) r1(p, n);
+    res #(90.0) r3(p, m);
+    res #(10.0)  r2(m, n);
 endmodule

merged_module.cpp

 static void bmm_impl(std::string const & name_prefix,
 	std::map<vams::vpi_net *, vams::vpi_net *> & net_map,
 	std::map<vams::vpi_branch *, vams::vpi_branch *> & branch_map,
+	std::map<vams::vpi_parameter *, vams::vpi_value> & mod_param_assignment,
 	merged_module & mm, vams::vpi_module * m)
 {
 	for (std::map<std::string, boost::shared_ptr<vams::vpi_net> >::iterator it = m->nets.begin(); it != m->nets.end(); ++it)
 
 	for (size_t i = 0; i < m->analog_stmts.size(); ++i)
 	{
-		mm.stmts.push_back(instantiate_stmt(net_map, branch_map, m->analog_stmts[i].get()));
+		mm.stmts.push_back(instantiate_stmt(net_map, branch_map, mod_param_assignment, m->analog_stmts[i].get()));
 	}
 
 	for (size_t i = 0; i < m->module_instances.size(); ++i)
 			n = net_map[boost::get<vams::vpi_net *>(dynamic_cast<vams::vpi_decl_ref_expr *>(m->module_instances[i].args[j].get())->item)];
 		}
 
+		std::map<vams::vpi_parameter *, vams::vpi_value> inst_param_assignment;
+		for (size_t j = 0; j < m->module_instances[i].module_param_args.size(); ++j)
+		{
+			vams::vpi_expr * e = m->module_instances[i].module_param_args[j].get();
+			inst_param_assignment[&instm->module_parameters[j]] = e->get_const_value();
+		}
+
+		for (size_t j = m->module_instances[i].module_param_args.size(); j < instm->module_parameters.size(); ++j)
+		{
+			inst_param_assignment[&instm->module_parameters[j]] = instm->module_parameters[j].default_value_expr->get_const_value();
+		}
+
 		std::map<vams::vpi_branch *, vams::vpi_branch *> inst_branch_map;
 
 		bmm_impl(
 			name_prefix + "." + m->module_instances[i].name,
 			inst_net_map,
 			inst_branch_map,
+			inst_param_assignment,
 			mm,
 			instm);
 	}
 	mm.ground_net = gnd.get();
 
 	std::map<vams::vpi_branch *, vams::vpi_branch *> branch_map;
-	bmm_impl("", net_map, branch_map, mm, r.top_module);
+	std::map<vams::vpi_parameter *, vams::vpi_value> mod_param_assignment;
+	bmm_impl("", net_map, branch_map, mod_param_assignment, mm, r.top_module);
 
 	mm.calc_indexes();
 }
 {
 	virtual ~vpi_expr() {}
 
-	virtual bool is_const_expr() const { return false; }
+	virtual bool is_const_expr(bool allow_module_params = false) const { return false; }
 	virtual vpi_value get_const_value() const { throw std::runtime_error(""); }
 };
 
 {
 	vpi_value value;
 
-	virtual bool is_const_expr() const { return true; }
+	virtual bool is_const_expr(bool allow_module_params = false) const { return true; }
 	virtual vpi_value get_const_value() const { return value; }
 };
 
 	int op;
 	boost::shared_ptr<vpi_expr> arg;
 
-	virtual bool is_const_expr() const { return arg->is_const_expr(); }
+	virtual bool is_const_expr(bool allow_module_params = false) const { return arg->is_const_expr(allow_module_params); }
 	virtual vpi_value get_const_value() const
 	{
 		return arg->get_const_value();
 	boost::shared_ptr<vpi_expr> lhs;
 	boost::shared_ptr<vpi_expr> rhs;
 
-	virtual bool is_const_expr() const
+	virtual bool is_const_expr(bool allow_module_params = false) const
 	{
-		return lhs->is_const_expr() && rhs->is_const_expr();
+		return lhs->is_const_expr(allow_module_params) && rhs->is_const_expr(allow_module_params);
 	}
 
 	virtual vpi_value get_const_value() const
 	boost::shared_ptr<vpi_expr> lhs;
 	boost::shared_ptr<vpi_expr> rhs;
 
-	virtual bool is_const_expr() const
+	virtual bool is_const_expr(bool allow_module_params = false) const
 	{
-		return cond->is_const_expr() && lhs->is_const_expr() && rhs->is_const_expr();
+		return cond->is_const_expr(allow_module_params) && lhs->is_const_expr(allow_module_params) && rhs->is_const_expr(allow_module_params);
 	}
 
 	virtual vpi_value get_const_value() const
 {
 	boost::shared_ptr<vpi_expr> nested;
 
-	virtual bool is_const_expr() const
+	virtual bool is_const_expr(bool allow_module_params = false) const
 	{
-		return nested->is_const_expr();
+		return nested->is_const_expr(allow_module_params);
 	}
 
 	virtual vpi_value get_const_value() const
 	}
 };
 
-enum scope_item_kind { si_none, si_net, si_branch };
-typedef boost::variant<boost::none_t, vpi_net *, vpi_branch *> scope_item_t;
+enum variable_type { vt_integer, vt_real, vt_time, vt_realtime, vt_string };
+
+struct vpi_parameter
+{
+	std::string name;
+	variable_type type;
+	boost::shared_ptr<vpi_expr> default_value_expr;
+};
+
+enum scope_item_kind { si_none, si_net, si_branch, si_parameter };
+typedef boost::variant<boost::none_t, vpi_net *, vpi_branch *, vpi_parameter *> scope_item_t;
 
 struct vpi_decl_ref_expr
 	: vpi_expr
 {
 	std::string decl_name;
 	scope_item_t item;
+
+	bool is_const_expr(bool allow_module_params = false) const
+	{
+		if (!allow_module_params)
+			return false;
+		return item.which() == si_parameter;
+	}
 };
 
 struct vpi_module;
 	std::string module_ref;
 	vpi_module * module;
 	std::string name;
+	std::vector<boost::shared_ptr<vpi_expr> > module_param_args;
 	std::vector<boost::shared_ptr<vpi_expr> > args;
 
 	vpi_module_instance()
 	std::map<std::string, boost::shared_ptr<vpi_branch> > named_branches;
 	std::map<std::pair<vpi_net *, vpi_net *>, boost::shared_ptr<vpi_branch> > unnamed_branches;
 
+	std::vector<vpi_parameter> module_parameters;
+
 	std::map<std::string, scope_item_t> scope;
 
 	scope_item_t lookup(std::string const & name) const

vams_instantiate.cpp

 
 	expr_instantiator(
 		std::map<vams::vpi_net *, vams::vpi_net *> const & net_map,
-		std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map)
-		: net_map(net_map), branch_map(branch_map)
+		std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map,
+		std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map)
+		: net_map(net_map), branch_map(branch_map), param_map(param_map)
 	{
 	}
 
 	{
 		boost::shared_ptr<vams::vpi_unary_expr> rr(new vams::vpi_unary_expr());
 		rr->op = ee->op;
-		rr->arg = instantiate_expr(net_map, branch_map, ee->arg.get());
+		rr->arg = instantiate_expr(net_map, branch_map, param_map, ee->arg.get());
 		return rr;
 	}
 
 	{
 		boost::shared_ptr<vams::vpi_binary_expr> rr(new vams::vpi_binary_expr());
 		rr->op = ee->op;
-		rr->lhs = instantiate_expr(net_map, branch_map, ee->lhs.get());
-		rr->rhs = instantiate_expr(net_map, branch_map, ee->rhs.get());
+		rr->lhs = instantiate_expr(net_map, branch_map, param_map, ee->lhs.get());
+		rr->rhs = instantiate_expr(net_map, branch_map, param_map, ee->rhs.get());
 		return rr;
 	}
 
 	return_type operator()(vams::vpi_cond_expr * ee)
 	{
 		boost::shared_ptr<vams::vpi_cond_expr> rr(new vams::vpi_cond_expr());
-		rr->cond = instantiate_expr(net_map, branch_map, ee->cond.get());
-		rr->lhs = instantiate_expr(net_map, branch_map, ee->lhs.get());
-		rr->rhs = instantiate_expr(net_map, branch_map, ee->rhs.get());
+		rr->cond = instantiate_expr(net_map, branch_map, param_map, ee->cond.get());
+		rr->lhs = instantiate_expr(net_map, branch_map, param_map, ee->lhs.get());
+		rr->rhs = instantiate_expr(net_map, branch_map, param_map, ee->rhs.get());
 		return rr;
 	}
 
 	return_type operator()(vams::vpi_paren_expr * ee)
 	{
-		return instantiate_expr(net_map, branch_map, ee->nested.get());
+		return instantiate_expr(net_map, branch_map, param_map, ee->nested.get());
 	}
 
 	return_type operator()(vams::vpi_function_call_expr * ee)
 		boost::shared_ptr<vams::vpi_function_call_expr> rr(new vams::vpi_function_call_expr());
 		rr->function_name = ee->function_name;
 		for (size_t i = 0; i < ee->arguments.size(); ++i)
-			rr->arguments.push_back(instantiate_expr(net_map, branch_map, ee->arguments[i].get()));
+			rr->arguments.push_back(instantiate_expr(net_map, branch_map, param_map, ee->arguments[i].get()));
 		if (ee->signal_access)
 		{
 			rr->signal_access.reset(new vams::vpi_access_function_call());
 
 	return_type operator()(vams::vpi_decl_ref_expr * ee)
 	{
+		if (ee->item.which() == vams::si_parameter)
+		{
+			boost::shared_ptr<vams::vpi_constant> rr(new vams::vpi_constant());
+			rr->value = param_map.find(boost::get<vams::vpi_parameter *>(ee->item))->second;
+			return rr;
+		}
+
 		boost::shared_ptr<vams::vpi_decl_ref_expr> rr(new vams::vpi_decl_ref_expr());
 		rr->decl_name = ee->decl_name;
 		if (ee->item.which() == vams::si_net)
 
 	std::map<vams::vpi_net *, vams::vpi_net *> const & net_map;
 	std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map;
+	std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map;
 };
 
 boost::shared_ptr<vams::vpi_expr> instantiate_expr(
 	std::map<vams::vpi_net *, vams::vpi_net *> const & net_map,
 	std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map,
+	std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map,
 	vams::vpi_expr * expr)
 {
-	expr_instantiator visitor(net_map, branch_map);
+	expr_instantiator visitor(net_map, branch_map, param_map);
 	return vams::visit_expr(visitor, expr);
 }
 
 
 	stmt_instantiator(
 		std::map<vams::vpi_net *, vams::vpi_net *> const & net_map,
-		std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map)
-		: net_map(net_map), branch_map(branch_map)
+		std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map,
+		std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map)
+		: net_map(net_map), branch_map(branch_map), param_map(param_map)
 	{
 	}
 
 	{
 		boost::shared_ptr<vams::vpi_analog_stmt> rr(new vams::vpi_analog_stmt());
 		rr->initial = ss->initial;
-		rr->nested = instantiate_stmt(net_map, branch_map, ss->nested.get());
+		rr->nested = instantiate_stmt(net_map, branch_map, param_map, ss->nested.get());
 		return rr;
 	}
 
 		boost::shared_ptr<vams::vpi_compound_stmt> rr(new vams::vpi_compound_stmt());
 		for (size_t i = 0; i < ss->stmts.size(); ++i)
 		{
-			rr->stmts.push_back(instantiate_stmt(net_map, branch_map, ss->stmts[i].get()));
+			rr->stmts.push_back(instantiate_stmt(net_map, branch_map, param_map, ss->stmts[i].get()));
 		}
 		return rr;
 	}
 	return_type operator()(vams::vpi_contribution_stmt * ss)
 	{
 		boost::shared_ptr<vams::vpi_contribution_stmt> rr(new vams::vpi_contribution_stmt());
-		rr->lhs = instantiate_expr(net_map, branch_map, ss->lhs.get());
-		rr->rhs = instantiate_expr(net_map, branch_map, ss->rhs.get());
+		rr->lhs = instantiate_expr(net_map, branch_map, param_map, ss->lhs.get());
+		rr->rhs = instantiate_expr(net_map, branch_map, param_map, ss->rhs.get());
 		return rr;
 	}
 
 	std::map<vams::vpi_net *, vams::vpi_net *> const & net_map;
 	std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map;
+	std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map;
 };
 
 boost::shared_ptr<vams::vpi_stmt> instantiate_stmt(
 	std::map<vams::vpi_net *, vams::vpi_net *> const & net_map,
 	std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map,
+	std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map,
 	vams::vpi_stmt * stmt)
 {
-	stmt_instantiator visitor(net_map, branch_map);
+	stmt_instantiator visitor(net_map, branch_map, param_map);
 	return vams::visit_stmt(visitor, stmt);
 }

vams_instantiate.hpp

 boost::shared_ptr<vams::vpi_expr> instantiate_expr(
 	std::map<vams::vpi_net *, vams::vpi_net *> const & net_map,
 	std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map,
+	std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map,
 	vams::vpi_expr * expr);
 
 boost::shared_ptr<vams::vpi_stmt> instantiate_stmt(
 	std::map<vams::vpi_net *, vams::vpi_net *> const & net_map,
 	std::map<vams::vpi_branch *, vams::vpi_branch *> const & branch_map,
+	std::map<vams::vpi_parameter *, vams::vpi_value> const & param_map,
 	vams::vpi_stmt * stmt);
 
 #endif // INSTANTIATE_HPP
 module_declaration ::= open_module_declaration "endmodule".
 
 open_module_declaration :: {boost::shared_ptr<vams::vpi_module>}
-open_module_declaration(r) ::= module_keyword IDENT(name) list_of_ports(ports) ";". {
+open_module_declaration(r) ::= module_keyword IDENT(name) opt_module_parameter_port_list(mod_params) list_of_ports(ports) ";". {
 	// TODO: exception safety?
 	r.reset(new vams::vpi_module());
 	r->name = name;
 	r->ports.swap(ports);
+	r->module_parameters.swap(mod_params);
 }
 
 open_module_declaration(r) ::= open_module_declaration(r) analog_construct(a). {
 	r.args.swap(args);
 }
 
+module_instantiation(r) ::= IDENT(module_ref) "#" "(" expr_list(mod_args) ")" IDENT(name) "(" expr_list(args) ")" ";". {
+	r.module_ref = module_ref;
+	r.name = name;
+	r.args.swap(args);
+	r.module_param_args.swap(mod_args);
+}
+
 expr_list :: {std::vector<boost::shared_ptr<vams::vpi_expr> >}
 expr_list(r) ::= . {}
 expr_list(r) ::= expr(e). { r.push_back(e); }
 	r->stmts.push_back(s);
 }
 
+opt_module_parameter_port_list :: {std::vector<vams::vpi_parameter>}
+opt_module_parameter_port_list(r) ::= . {}
+opt_module_parameter_port_list(r) ::= "#" "(" ")". {}
+opt_module_parameter_port_list ::= open_module_parameter_port_list ")".
+
+open_module_parameter_port_list :: {std::vector<vams::vpi_parameter>}
+open_module_parameter_port_list(r) ::= "#" "(" parameter_declaration(param). { r.push_back(param); }
+open_module_parameter_port_list(r) ::= open_module_parameter_port_list(r) "," parameter_declaration(param). { r.push_back(param); }
+
+parameter_declaration :: {vams::vpi_parameter}
+parameter_declaration(r) ::= "parameter" parameter_type(type) IDENT(name) "=" expr(e). {
+	r.name = name;
+	r.type = type;
+	r.default_value_expr.swap(e);
+}
+
+parameter_type :: {vams::variable_type}
+parameter_type ::= "integer". { return vams::vt_integer; }
+parameter_type ::= "real". { return vams::vt_real; }
+parameter_type ::= "realtime". { return vams::vt_realtime; }
+parameter_type ::= "time". { return vams::vt_time; }
+parameter_type ::= "string". { return vams::vt_string; }
+
 list_of_ports :: {std::vector<vams::vpi_port>}
+list_of_ports(r) ::= . {}
 list_of_ports(r) ::= "(" ")". {}
 list_of_ports ::= open_list_of_ports ")".
 
 					throw std::runtime_error("The name " + it->first + " is already declared.");
 				item = it->second.get();
 			}
+
+			for (size_t i = 0; i < m.module_parameters.size(); ++i)
+			{
+				vams::vpi_parameter & param = m.module_parameters[i];
+				vams::scope_item_t & item = m.scope[param.name];
+				if (item.which() != vams::si_none)
+					throw std::runtime_error("The name " + param.name + " is already declared.");
+				item = &param;
+			}
 		}
 
 		// Resolve nets in branches
 				throw std::runtime_error("Can't instantiate a module that isn't defined: " + it->second->module_instances[j].module_ref);
 			it->second->module_instances[j].module = ref_it->second.get();
 
+			if (it->second->module_instances[j].module->module_parameters.size() < it->second->module_instances[j].module_param_args.size())
+				throw std::runtime_error("Too many module parameter arguments");
+
+			for (std::size_t k = 0; k < it->second->module_instances[j].module_param_args.size(); ++k)
+			{
+				if (!it->second->module_instances[j].module_param_args[k]->is_const_expr(true))
+					throw std::runtime_error("Module parameter arguments must be constant expressions.");
+			}
+
 			for (std::size_t k = 0; k < it->second->module_instances[j].args.size(); ++k)
 			{
 				resolve_decls(m, it->second->module_instances[j].args[k].get());