Commits

Martin Vejnár  committed 3050682

Added support for ddt, cap and inductor can now be modeled.

  • Participants
  • Parent commits 2736edf

Comments (0)

Files changed (7)

     analog V(p,n) <+ v*sin(2.0*3.1415926535897932384626433832795*freq*$abstime);
 endmodule
 
-module main();
+module src #(parameter real v = 5.0) (p,n);
+    electrical p, n;
+    analog V(p,n) <+ v;
+endmodule
+
+module cap #(parameter real C = 1e-4) (p, n);
+    electrical p, n;
+    analog I(p,n) <+ C*ddt(V(p,n));
+endmodule
+
+module inductor #(parameter real L = 1e-2) (p, n);
+    electrical p, n;
+    analog V(p,n) <+ L*ddt(I(p,n));
+endmodule
+
+module main;
     ground n;
-    ac_src #(10.0, 100.0) s1(p, n);
-    res #(100.0) r3(p, n);
+    ac_src #(10.0, 10.0) s1(p, n);
+    res #(1.0) r3(p, m);
+    cap c1(m, n);
 endmodule

File mm_solver.cpp

 #include <ida/ida_dense.h>
 #include <nvector/nvector_serial.h>
 
-namespace {
-
-struct expr_evaluator
-	: vams::default_visitor<expr_evaluator, vams::vpi_value>
+struct mm_solver::expr_evaluator
+	: vams::default_visitor<mm_solver::expr_evaluator, vams::vpi_value>
 {
-	expr_evaluator(merged_module & mm, realtype * s, realtype t)
-		: mm(mm), s(s), t(t)
+	expr_evaluator(mm_solver & solver, merged_module & mm, realtype * s, realtype * ddts, realtype t)
+		: solver(solver), mm(mm), s(s), ddts(ddts), t(t)
 	{
 	}
 
 		return vams::visit_expr(*this, ee->arg.get());
 	}
 
+	vams::vpi_value operator()(vams::vpi_ddt_expr * ee)
+	{
+		return ddts[solver.m_ddt_var_map[ee]];
+	}
+
 	vams::vpi_value operator()(vams::vpi_binary_expr * ee)
 	{
 		// XXX
 	{
 		if (ee->signal_access)
 		{
+			double res;
 			if (ee->signal_access->type == vams::vpi_access_function_call::at_potential)
 			{
-				return s[mm.get_net_index(ee->signal_access->branch->lhs_net)]
-				- s[mm.get_net_index(ee->signal_access->branch->rhs_net)];
+				res = s[mm.get_net_index(ee->signal_access->branch->lhs_net)]
+					- s[mm.get_net_index(ee->signal_access->branch->rhs_net)];
 			}
 			else
 			{
 				std::size_t r = mm.get_branch_index(ee->signal_access->branch);
-				double res = s[r];
-				if (ee->signal_access->reverse_access)
-					res = -res;
-				return res;
+				res = s[r];
 			}
+
+			if (ee->signal_access->reverse_access)
+				res = -res;
+			return res;
 		}
 		else
 		{
 		throw std::runtime_error("Can't handle `" + ee->decl_name + "` in an expression.");
 	}
 
+	mm_solver & solver;
 	merged_module & mm;
 	realtype * s;
+	realtype * ddts;
 	realtype t;
 };
 
-}
+struct mm_solver::stmt_walker
+	: vams::default_visitor<mm_solver::stmt_walker>
+{
+	stmt_walker(mm_solver & solver, merged_module & mm, realtype * r, realtype * s, realtype * ddts, realtype t)
+		: solver(solver), mm(mm), r(r), s(s), ddts(ddts), t(t)
+	{
+	}
+
+	return_type operator()(vams::vpi_contribution_stmt * ee)
+	{
+		expr_evaluator eval(solver, mm, s, ddts, t);
+		vams::vpi_value vpires = vams::visit_expr(eval, ee->rhs.get());
+		BOOST_ASSERT(vpires.value.which() == vams::vpi_value::type_real || vpires.value.which() == vams::vpi_value::type_int);
+
+		double res = 0;
+		if (vpires.value.which() == vams::vpi_value::type_real)
+			res = vpires.get_real();
+		else
+			res = vpires.get_int();
+
+		vams::vpi_function_call_expr * fncall = dynamic_cast<vams::vpi_function_call_expr *>(ee->lhs.get());
+		BOOST_ASSERT(fncall);
+		BOOST_ASSERT(fncall->signal_access);
 
-static int system_fn(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, void *user_data)
+		std::size_t bi = mm.get_branch_index(fncall->signal_access->branch);
+		r[bi] += fncall->signal_access->reverse_access? -res: res;
+	}
+
+	using default_visitor::operator();
+
+	mm_solver & solver;
+	merged_module & mm;
+	realtype * r;
+	realtype * s;
+	realtype * ddts;
+	realtype t;
+};
+
+int mm_solver::system_fn(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, void *user_data)
 {
 	realtype * r = NV_DATA_S(rr);
 	realtype * s = NV_DATA_S(yy);
 	realtype * ddts = NV_DATA_S(yp);
 
-	merged_module & mm = *(merged_module *)user_data;
+	mm_solver & solver = *(mm_solver *)user_data;
+	merged_module & mm = solver.mm;
 
 	// non-ground nets
 	for (std::size_t i = 0; i < mm.nets.size(); ++i)
 	// the ground net
 	r[mm.get_net_index(mm.ground_net)] = s[mm.get_net_index(mm.ground_net)];
 
-	struct stmt_walker
-		: vams::default_visitor<stmt_walker>
-	{
-		stmt_walker(merged_module & mm, realtype * r, realtype * s, realtype t)
-			: mm(mm), r(r), s(s), t(t)
-		{
-		}
-
-		return_type operator()(vams::vpi_contribution_stmt * ee)
-		{
-			expr_evaluator eval(mm, s, t);
-			vams::vpi_value vpires = vams::visit_expr(eval, ee->rhs.get());
-			BOOST_ASSERT(vpires.value.which() == vams::vpi_value::type_real || vpires.value.which() == vams::vpi_value::type_int);
-
-			double res = 0;
-			if (vpires.value.which() == vams::vpi_value::type_real)
-				res = vpires.get_real();
-			else
-				res = vpires.get_int();
-
-			vams::vpi_function_call_expr * fncall = dynamic_cast<vams::vpi_function_call_expr *>(ee->lhs.get());
-			BOOST_ASSERT(fncall);
-			BOOST_ASSERT(fncall->signal_access);
-
-			std::size_t bi = mm.get_branch_index(fncall->signal_access->branch);
-			r[bi] += fncall->signal_access->reverse_access? -res: res;
-		}
-
-		using default_visitor::operator();
-
-		merged_module & mm;
-		realtype * r;
-		realtype * s;
-		realtype t;
-	};
-
 	// branch currents
 	for (std::map<vams::vpi_branch *, std::size_t>::iterator it = mm.branch_indexes.begin(); it != mm.branch_indexes.end(); ++it)
 	{
 		}
 	}
 
-	stmt_walker walker(mm, r, s, tt);
-	for (size_t i = 0; i < mm.stmts.size(); ++i)
-		vams::visit_stmt(walker, mm.stmts[i].get());
+	{
+		stmt_walker walker(solver, mm, r, s, ddts, tt);
+		for (size_t i = 0; i < mm.stmts.size(); ++i)
+			vams::visit_stmt(walker, mm.stmts[i].get());
+	}
+
+	// ddt variables
+	{
+		expr_evaluator eval(solver, mm, s, ddts, tt);
+		for (std::map<vams::vpi_ddt_expr *, std::size_t>::const_iterator it = solver.m_ddt_var_map.begin(); it != solver.m_ddt_var_map.end(); ++it)
+			r[it->second] = s[it->second] - vams::visit_expr(eval, it->first->nested.get()).get_real();
+	}
+
 	return 0;
 }
 
+struct ddt_locator
+	: vams::default_visitor<ddt_locator>
+{
+	ddt_locator(std::size_t next_var, std::vector<vams::vpi_ddt_expr *> & ddt_vars, std::map<vams::vpi_ddt_expr *, std::size_t> & ddt_var_map)
+		: m_next_var(next_var), m_ddt_var_map(ddt_var_map), m_ddt_vars(ddt_vars)
+	{
+	}
+
+	void operator()(vams::vpi_ddt_expr * ee)
+	{
+		m_ddt_var_map[ee] = m_next_var;
+		m_ddt_vars.push_back(ee);
+		++m_next_var;
+		vams::visit_expr(*this, ee->nested.get());
+	}
+
+	using default_visitor::operator();
+
+	std::size_t m_next_var;
+	std::map<vams::vpi_ddt_expr *, std::size_t> & m_ddt_var_map;
+	std::vector<vams::vpi_ddt_expr *> & m_ddt_vars;
+};
+
 mm_solver::mm_solver(merged_module & mm)
 	: mm(mm)
 {
 
 	N = mm.nets.size() + mm.branch_indexes.size();
 
+	{
+		ddt_locator visitor(N, m_ddt_vars, m_ddt_var_map);
+		for (std::size_t i = 0; i < mm.stmts.size(); ++i)
+			vams::visit_stmt(visitor, mm.stmts[i].get());
+	}
+
+	N += m_ddt_vars.size();
+
 	ida_mem = IDACreate();
 
 	y = N_VNew_Serial(N);
 	std::fill(NV_DATA_S(ddty), NV_DATA_S(ddty) + N, 0.0);
 
 	int res = IDAInit(ida_mem, &system_fn, 0, y, ddty);
-	IDASetUserData(ida_mem, &mm);
+	IDASetUserData(ida_mem, this);
 	IDASStolerances(ida_mem, 1e-6, 1e-6);
 	res = IDADense(ida_mem, N);
 
 	{
 		N_Vector id = N_VNew_Serial(N);
-		std::fill(NV_DATA_S(id), NV_DATA_S(id) + N, 0.0);
+		std::fill(NV_DATA_S(id), NV_DATA_S(id) + N - m_ddt_var_map.size(), 0.0);
+		std::fill(NV_DATA_S(id) + N - m_ddt_var_map.size(), NV_DATA_S(id) + N, 1.0);
 		IDASetId(ida_mem, id);
 		N_VDestroy_Serial(id);
 	}
 std::vector<double> mm_solver::get_iter(double t)
 {
 	std::vector<double> r(NV_DATA_S(y), NV_DATA_S(y) + N);
+	r.insert(r.end(), NV_DATA_S(ddty) + N - m_ddt_var_map.size(), NV_DATA_S(ddty) + N);
 
 	double tt;
 	IDASolve(ida_mem, t, &tt, y, ddty, IDA_NORMAL);

File mm_solver.hpp

 	N_Vector y;
 	N_Vector ddty;
 	int N;
+	std::map<vams::vpi_ddt_expr *, std::size_t> m_ddt_var_map;
+	std::vector<vams::vpi_ddt_expr *> m_ddt_vars;
+
+	struct expr_evaluator;
+	struct stmt_walker;
+	static int system_fn(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, void *user_data);
 };
 
 #endif // MM_SOLVER_HPP

File vams_ast.hpp

 	}
 };
 
+struct vpi_ddt_expr
+	: vpi_expr
+{
+	boost::shared_ptr<vpi_expr> nested;
+};
+
 struct vpi_function_call_expr
 	: vpi_expr, boost::noncopyable
 {
 	{
 		return visitor(ee);
 	}
+	else if (vams::vpi_ddt_expr * ee = dynamic_cast<vams::vpi_ddt_expr *>(expr))
+	{
+		return visitor(ee);
+	}
 	else if (vams::vpi_port_probe_expr * ee = dynamic_cast<vams::vpi_port_probe_expr *>(expr))
 	{
 		return visitor(ee);
 			visit_expr(static_cast<Derived &>(*this), ee->arguments[i].get());
 	}
 
+	return_type operator()(vams::vpi_ddt_expr * ee)
+	{
+		return visit_expr(static_cast<Derived &>(*this), ee->nested.get());
+	}
+
 	return_type operator()(vams::vpi_port_probe_expr * ee)
 	{
 	}

File vams_instantiate.cpp

 		return instantiate_expr(net_map, branch_map, param_map, ee->nested.get());
 	}
 
+	return_type operator()(vams::vpi_ddt_expr * ee)
+	{
+		boost::shared_ptr<vams::vpi_ddt_expr> rr(new vams::vpi_ddt_expr());
+		rr->nested = instantiate_expr(net_map, branch_map, param_map, ee->nested.get());
+		return rr;
+	}
+
 	return_type operator()(vams::vpi_function_call_expr * ee)
 	{
 		boost::shared_ptr<vams::vpi_function_call_expr> rr(new vams::vpi_function_call_expr());

File vams_parser.y

 	return r;
 }
 
+primary ::= "ddt" "(" expr(e) ")". {
+	boost::shared_ptr<vams::vpi_ddt_expr> r(new vams::vpi_ddt_expr());
+	r->nested = e;
+	return r;
+}
+
 primary ::= function_call.
 
 function_call :: {boost::shared_ptr<vams::vpi_expr>}

File vams_sema.cpp

 		resolve_decls(m, ee->nested.get(), create_implicit_nets);
 	}
 
+	void operator()(vams::vpi_ddt_expr * ee)
+	{
+		resolve_decls(m, ee->nested.get(), create_implicit_nets);
+	}
+
 	void operator()(vams::vpi_cond_expr * ee)
 	{
 		resolve_decls(m, ee->cond.get(), create_implicit_nets);
 
 	std::set<vams::vpi_module *> top_level_modules = get_top_level_modules(r);
 	if (top_level_modules.size() != 1)
-		throw std::runtime_error("There must be exactly one top-level module!");
-	r.top_module = *top_level_modules.begin();
-
+	{
+		r.top_module = 0;
+		for (std::set<vams::vpi_module *>::const_iterator it = top_level_modules.begin(); it != top_level_modules.end(); ++it)
+		{
+			if ((*it)->name == "main")
+			{
+				r.top_module = *it;
+				break;
+			}
+		}
 
+		if (!r.top_module)
+			throw std::runtime_error("There must be exactly one top-level module!");
+	}
+	else
+	{
+		r.top_module = *top_level_modules.begin();
+	}
 }