mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
Netlist can now be included as sub-circuits. That's the same approach SPICE uses.
The implementation also supports nesting. Opamp emulation now is as easy as /* Opamp wired as impedance changer */ SUBMODEL(op, opamp) NET_C(op.GND, GND) NET_C(op.PLUS, clk) NET_C(op.MINUS, op.OUT) The missing bit now is a central submodel repository. I'll start a discussion soon on the list. nl_examples/opamp.c is an example of a impedance changer stage followed by a 1:2 amplifier stage. System size (= number of voltage levels to be calculated) is between 20 - 30. Using a simple, yet better opamp model than usually implemented in the old discrete core, I get ./nltool -f nl_examples/opamp.c -t 30 startup time ==> 0.002 runnning ... 30.000000 seconds emulation took 0.438599 real time ==> 6839.96% Which leaves quite some buffer to emulate even complex mixing and filtering stages in real-time :-)
This commit is contained in:
parent
c99b5bf4aa
commit
686d540bad
@ -6,6 +6,45 @@
|
||||
|
||||
#include "netlist/devices/net_lib.h"
|
||||
|
||||
NETLIST_START(main)
|
||||
|
||||
/* Standard stuff */
|
||||
|
||||
CLOCK(clk, 1000) // 1000 Hz
|
||||
SOLVER(Solver, 48000)
|
||||
//PARAM(Solver.ACCURACY, 1e-3)
|
||||
//PARAM(Solver.CONVERG, 1.0)
|
||||
//PARAM(Solver.RESCHED_LOOPS, 30)
|
||||
|
||||
/* Opamp wired as impedance changer */
|
||||
SUBMODEL(op, opamp)
|
||||
|
||||
NET_C(op.GND, GND)
|
||||
NET_C(op.PLUS, clk)
|
||||
NET_C(op.MINUS, op.OUT)
|
||||
|
||||
SUBMODEL(op1, opamp)
|
||||
/* Wired as inverting amplifier connected to output of first opamp */
|
||||
|
||||
RES(R1, 100000)
|
||||
RES(R2, 200000)
|
||||
|
||||
NET_C(op1.GND, GND)
|
||||
NET_C(op1.PLUS, GND)
|
||||
NET_C(op1.MINUS, R2.2)
|
||||
NET_C(op1.MINUS, R1.2)
|
||||
|
||||
NET_C(op.OUT, R1.1)
|
||||
NET_C(op1.OUT, R2.1)
|
||||
|
||||
RES(RL, 1000)
|
||||
NET_C(RL.2, GND)
|
||||
NET_C(RL.1, op1.OUT)
|
||||
|
||||
//LOG(logX, op1.OUT)
|
||||
//LOG(logY, clk)
|
||||
NETLIST_END()
|
||||
|
||||
NETLIST_START(opamp)
|
||||
|
||||
/* Opamp model from
|
||||
@ -14,19 +53,15 @@ NETLIST_START(opamp)
|
||||
*
|
||||
* Bandwidth 10Mhz
|
||||
*
|
||||
* This one is connected as a impedance changer
|
||||
*/
|
||||
|
||||
/* Standard stuff */
|
||||
/* Terminal definitions for calling netlists */
|
||||
|
||||
CLOCK(clk, 1000) // 1000 Hz
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-6)
|
||||
ALIAS(PLUS, G1.IP) // Positive input
|
||||
ALIAS(MINUS, G1.IN) // Negative input
|
||||
ALIAS(OUT, EBUF.OP) // Opamp output ...
|
||||
|
||||
/* Wiring up the opamp */
|
||||
|
||||
NET_C(PLUS, clk)
|
||||
NET_C(MINUS, OUT)
|
||||
ALIAS(GND, EBUF.ON) // GND terminal
|
||||
|
||||
/* The opamp model */
|
||||
|
||||
@ -38,11 +73,7 @@ NETLIST_START(opamp)
|
||||
PARAM(EBUF.RO, 50)
|
||||
PARAM(EBUF.G, 1)
|
||||
|
||||
ALIAS(PLUS, G1.IP) // Positive input
|
||||
ALIAS(MINUS, G1.IN) // Negative input
|
||||
ALIAS(OUT, EBUF.OP) // Opamp output ...
|
||||
|
||||
NET_C(EBUF.ON, GND)
|
||||
// NET_C(EBUF.ON, GND)
|
||||
|
||||
NET_C(G1.ON, GND)
|
||||
NET_C(RP1.2, GND)
|
||||
@ -53,10 +84,4 @@ NETLIST_START(opamp)
|
||||
NET_C(CP1.1, RP1.1)
|
||||
NET_C(EBUF.IP, RP1.1)
|
||||
|
||||
RES(RL, 1000)
|
||||
NET_C(RL.2, GND)
|
||||
NET_C(RL.1, OUT)
|
||||
|
||||
//LOG(logX, OUT)
|
||||
//LOG(logY, clk)
|
||||
NETLIST_END()
|
||||
|
@ -118,7 +118,7 @@ void netlist_matrix_solver_t::schedule()
|
||||
}
|
||||
else
|
||||
{
|
||||
//m_owner->netlist().warning("Matrix solver reschedule .. Consider increasing RESCHED_LOOPS");
|
||||
m_owner->netlist().warning("Matrix solver reschedule .. Consider increasing RESCHED_LOOPS");
|
||||
if (m_owner != NULL)
|
||||
this->m_owner->schedule();
|
||||
}
|
||||
@ -167,6 +167,7 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve()
|
||||
else
|
||||
{
|
||||
resched_cnt = solve_non_dynamic();
|
||||
//printf("resched_cnt %d %d\n", resched_cnt, m_resched_loops);
|
||||
}
|
||||
return (resched_cnt >= m_resched_loops);
|
||||
}
|
||||
@ -750,7 +751,7 @@ NETLIB_UPDATE(solver)
|
||||
|
||||
if (global_resched)
|
||||
{
|
||||
//netlist().warning("Gobal reschedule .. Consider increasing RESCHED_LOOPS");
|
||||
netlist().warning("Gobal reschedule .. Consider increasing RESCHED_LOOPS");
|
||||
schedule();
|
||||
}
|
||||
else
|
||||
|
@ -120,6 +120,9 @@ public:
|
||||
ATTR_COLD virtual void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner)
|
||||
{
|
||||
netlist_matrix_solver_t::setup(nets, owner);
|
||||
m_fallback.m_accuracy = m_accuracy;
|
||||
m_fallback.m_convergence_factor = m_convergence_factor;
|
||||
m_fallback.m_resched_loops = m_resched_loops;
|
||||
m_fallback.setup(nets, owner);
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_HOT inline void remove_at(const int pos)
|
||||
{
|
||||
assert((pos>=0) && (pos<m_count));
|
||||
m_count--;
|
||||
for (int i = pos; i < m_count; i++)
|
||||
{
|
||||
m_list[i] = m_list[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_HOT inline bool contains(const _ListClass &elem) const
|
||||
{
|
||||
for (_ListClass *i = m_list; i < m_list + m_count; i++)
|
||||
@ -224,5 +234,62 @@ private:
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// netlist_stack_t: a simple stack
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <class _StackClass, int _NumElem = 128>
|
||||
class netlist_stack_t
|
||||
{
|
||||
public:
|
||||
|
||||
ATTR_COLD netlist_stack_t(int numElements = _NumElem)
|
||||
: m_list(numElements)
|
||||
{
|
||||
}
|
||||
|
||||
ATTR_COLD netlist_stack_t(const netlist_stack_t &rhs)
|
||||
: m_list(rhs.m_list)
|
||||
{
|
||||
}
|
||||
|
||||
ATTR_COLD netlist_stack_t &operator=(const netlist_stack_t &rhs)
|
||||
{
|
||||
m_list = rhs.m_list;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ATTR_COLD ~netlist_stack_t()
|
||||
{
|
||||
}
|
||||
|
||||
ATTR_HOT inline void push(const _StackClass &elem)
|
||||
{
|
||||
m_list.add(elem);
|
||||
}
|
||||
|
||||
ATTR_HOT inline _StackClass peek() const
|
||||
{
|
||||
return m_list[m_list.count() - 1];
|
||||
}
|
||||
|
||||
ATTR_HOT inline _StackClass pop()
|
||||
{
|
||||
_StackClass ret = peek();
|
||||
m_list.remove_at(m_list.count() - 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ATTR_HOT inline int count() const { return m_list.count(); }
|
||||
ATTR_HOT inline bool empty() const { return (m_list.count() == 0); }
|
||||
ATTR_HOT inline void reset() { m_list.reset(); }
|
||||
ATTR_HOT inline int capacity() const { return m_list.capacity(); }
|
||||
|
||||
private:
|
||||
netlist_list_t<_StackClass, _NumElem> m_list;
|
||||
};
|
||||
|
||||
|
||||
#endif /* NLLISTS_H_ */
|
||||
|
@ -214,8 +214,10 @@ ATTR_COLD void netlist_parser::verror(pstring msg, int line_num, pstring line)
|
||||
}
|
||||
|
||||
|
||||
void netlist_parser::parse(const char *buf)
|
||||
void netlist_parser::parse(const char *buf, const pstring nlname)
|
||||
{
|
||||
m_buf = buf;
|
||||
|
||||
reset(buf);
|
||||
set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-");
|
||||
set_number_chars("01234567890eE-."); //FIXME: processing of numbers
|
||||
@ -234,19 +236,20 @@ void netlist_parser::parse(const char *buf)
|
||||
m_tok_ALIAS = register_token("ALIAS");
|
||||
m_tok_NET_C = register_token("NET_C");
|
||||
m_tok_PARAM = register_token("PARAM");
|
||||
m_tok_NET_MODEL = register_token("PARAM");
|
||||
m_tok_NET_MODEL = register_token("NET_MODEL");
|
||||
m_tok_INCLUDE = register_token("INCLUDE");
|
||||
m_tok_SUBMODEL = register_token("SUBMODEL");
|
||||
m_tok_NETLIST_START = register_token("NETLIST_START");
|
||||
m_tok_NETLIST_END = register_token("NETLIST_END");
|
||||
|
||||
bool in_nl = false;
|
||||
pstring nlname = "";
|
||||
|
||||
while (true)
|
||||
while (true)
|
||||
{
|
||||
token_t token = get_token();
|
||||
|
||||
if (token.is_type(ENDOFFILE))
|
||||
return;
|
||||
error("EOF while searching for <%s>", nlname.cstr());
|
||||
|
||||
if (token.is(m_tok_NETLIST_END))
|
||||
{
|
||||
@ -297,6 +300,10 @@ void netlist_parser::parse_netlist(const pstring &nlname)
|
||||
netdev_param();
|
||||
else if (token.is(m_tok_NET_MODEL))
|
||||
net_model();
|
||||
else if (token.is(m_tok_SUBMODEL))
|
||||
net_submodel();
|
||||
else if (token.is(m_tok_INCLUDE))
|
||||
net_include();
|
||||
else if (token.is(m_tok_NETLIST_END))
|
||||
{
|
||||
netdev_netlist_end();
|
||||
@ -329,6 +336,30 @@ void netlist_parser::net_model()
|
||||
require_token(m_tok_param_right);
|
||||
}
|
||||
|
||||
void netlist_parser::net_submodel()
|
||||
{
|
||||
// don't do much
|
||||
pstring name = get_identifier();
|
||||
require_token(m_tok_comma);
|
||||
pstring model = get_identifier();
|
||||
require_token(m_tok_param_right);
|
||||
|
||||
m_setup.namespace_push(name);
|
||||
netlist_parser subparser(m_setup);
|
||||
subparser.parse(m_buf, model);
|
||||
m_setup.namespace_pop();
|
||||
}
|
||||
|
||||
void netlist_parser::net_include()
|
||||
{
|
||||
// don't do much
|
||||
pstring name = get_identifier();
|
||||
require_token(m_tok_param_right);
|
||||
|
||||
netlist_parser subparser(m_setup);
|
||||
subparser.parse(m_buf, name);
|
||||
}
|
||||
|
||||
void netlist_parser::net_alias()
|
||||
{
|
||||
pstring alias = get_identifier();
|
||||
|
@ -144,7 +144,7 @@ public:
|
||||
netlist_parser(netlist_setup_t &setup)
|
||||
: ptokenizer(), m_setup(setup) {}
|
||||
|
||||
void parse(const char *buf);
|
||||
void parse(const char *buf, const pstring nlname = "");
|
||||
|
||||
void parse_netlist(const pstring &nlname);
|
||||
void net_alias();
|
||||
@ -154,6 +154,8 @@ public:
|
||||
void netdev_netlist_start();
|
||||
void netdev_netlist_end();
|
||||
void net_model();
|
||||
void net_submodel();
|
||||
void net_include();
|
||||
|
||||
protected:
|
||||
virtual void verror(pstring msg, int line_num, pstring line);
|
||||
@ -170,8 +172,12 @@ private:
|
||||
token_id_t m_tok_NET_MODEL;
|
||||
token_id_t m_tok_NETLIST_START;
|
||||
token_id_t m_tok_NETLIST_END;
|
||||
token_id_t m_tok_SUBMODEL;
|
||||
token_id_t m_tok_INCLUDE;
|
||||
|
||||
netlist_setup_t &m_setup;
|
||||
|
||||
const char *m_buf;
|
||||
};
|
||||
|
||||
|
||||
|
@ -58,9 +58,26 @@ netlist_setup_t::~netlist_setup_t()
|
||||
|
||||
ATTR_COLD pstring netlist_setup_t::build_fqn(const pstring &obj_name) const
|
||||
{
|
||||
return netlist().name() + "." + obj_name;
|
||||
if (m_stack.empty())
|
||||
return netlist().name() + "." + obj_name;
|
||||
else
|
||||
return m_stack.peek() + "." + obj_name;
|
||||
}
|
||||
|
||||
void netlist_setup_t::namespace_push(const pstring &aname)
|
||||
{
|
||||
if (m_stack.empty())
|
||||
m_stack.push(netlist().name() + "." + aname);
|
||||
else
|
||||
m_stack.push(m_stack.peek() + "." + aname);
|
||||
}
|
||||
|
||||
void netlist_setup_t::namespace_pop()
|
||||
{
|
||||
m_stack.pop();
|
||||
}
|
||||
|
||||
|
||||
netlist_device_t *netlist_setup_t::register_dev(netlist_device_t *dev, const pstring &name)
|
||||
{
|
||||
pstring fqn = build_fqn(name);
|
||||
|
@ -55,9 +55,14 @@ ATTR_COLD void NETLIST_NAME(_name)(netlist_setup_t &netlist)
|
||||
|
||||
#define NETLIST_END() }
|
||||
|
||||
#define NETLIST_INCLUDE(_name) \
|
||||
#define INCLUDE(_name) \
|
||||
NETLIST_NAME(_name)(netlist);
|
||||
|
||||
#define SUBMODEL(_name, _model) \
|
||||
netlist.namespace_push(# _name); \
|
||||
NETLIST_NAME(_model)(netlist); \
|
||||
netlist.namespace_pop();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// FIXME: Clean this up
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -135,6 +140,11 @@ public:
|
||||
void start_devices();
|
||||
void resolve_inputs();
|
||||
|
||||
/* handle namespace */
|
||||
|
||||
void namespace_push(const pstring &aname);
|
||||
void namespace_pop();
|
||||
|
||||
/* not ideal, but needed for save_state */
|
||||
tagmap_terminal_t m_terminals;
|
||||
|
||||
@ -157,6 +167,9 @@ private:
|
||||
|
||||
int m_proxy_cnt;
|
||||
|
||||
netlist_stack_t<pstring> m_stack;
|
||||
|
||||
|
||||
void connect_terminals(netlist_core_terminal_t &in, netlist_core_terminal_t &out);
|
||||
void connect_input_output(netlist_input_t &in, netlist_output_t &out);
|
||||
void connect_terminal_output(netlist_terminal_t &in, netlist_output_t &out);
|
||||
|
@ -732,7 +732,7 @@ NETLIST_END()
|
||||
|
||||
static NETLIST_START(pong_fast)
|
||||
|
||||
NETLIST_INCLUDE(pong_schematics)
|
||||
INCLUDE(pong_schematics)
|
||||
|
||||
//NETDEV_ANALOG_CALLBACK(sound_cb, sound, pong_state, sound_cb, "")
|
||||
//NETDEV_ANALOG_CALLBACK(video_cb, videomix, fixedfreq_device, update_vid, "fixfreq")
|
||||
|
Loading…
Reference in New Issue
Block a user