mirror of
https://github.com/holub/mame
synced 2025-04-25 17:56:43 +03:00
netlist: include file work (#10096)
- move code to more appropriate locations - apply clang-format to modified files - fixed some cspell errors - Applied emu.h rule.
This commit is contained in:
parent
20d6ea06f4
commit
4ecc148240
@ -11,14 +11,11 @@
|
||||
#include "emu.h"
|
||||
#include "netlist.h"
|
||||
|
||||
#include "netlist/nl_base.h"
|
||||
#include "netlist/nl_setup.h"
|
||||
#include "netlist/nl_factory.h"
|
||||
#include "netlist/nl_parser.h"
|
||||
#include "netlist/nl_interface.h"
|
||||
|
||||
#include "netlist/plib/palloc.h"
|
||||
#include "netlist/plib/pmempool.h"
|
||||
#include "netlist/plib/pdynlib.h"
|
||||
#include "netlist/plib/pstonum.h"
|
||||
|
||||
|
@ -2,24 +2,26 @@
|
||||
// copyright-holders:Couriersud
|
||||
/***************************************************************************
|
||||
|
||||
fixfreq.h
|
||||
fixfreq.h
|
||||
|
||||
2013-2021 Couriersud
|
||||
2013-2021 Couriersud
|
||||
|
||||
Fixed frequency monochrome monitor emulation
|
||||
Fixed frequency monochrome monitor emulation
|
||||
|
||||
The driver is intended for drivers which provide an analog video signal.
|
||||
VSYNC and HSYNC levels are used to create the bitmap.
|
||||
The driver is intended for drivers which provide an analog video signal.
|
||||
VSYNC and HSYNC levels are used to create the bitmap.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
// emu.h must be first to be included
|
||||
#include "emu.h"
|
||||
|
||||
#include "fixfreq.h"
|
||||
|
||||
#include "render.h"
|
||||
#include "ui/uimain.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
// for quick and dirty debugging
|
||||
#define VERBOSE 0
|
||||
@ -36,20 +38,24 @@
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monochrome Monitor")
|
||||
DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq",
|
||||
"Fixed-Frequency Monochrome Monitor")
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Port adjuster support
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
|
||||
PORT_START(# _id) \
|
||||
configurer.field_alloc(IPT_ADJUSTER, (static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, ("Monitor - " _name)); \
|
||||
PORT_MINMAX(_min, _max) \
|
||||
PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
|
||||
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
|
||||
PORT_START(#_id) \
|
||||
configurer.field_alloc( \
|
||||
IPT_ADJUSTER, \
|
||||
(static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, \
|
||||
("Monitor - " _name)); \
|
||||
PORT_MINMAX(_min, _max) \
|
||||
PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
|
||||
PORT_CONDITION("ENABLE", 0x01, EQUALS, 0x01)
|
||||
|
||||
#define IOPORT_ID(_id) ioport(# _id)
|
||||
#define IOPORT_ID(_id) ioport(#_id)
|
||||
|
||||
enum fixedfreq_tag_id_e
|
||||
{
|
||||
@ -67,30 +73,36 @@ enum fixedfreq_tag_id_e
|
||||
SCANLINE_HEIGHT
|
||||
};
|
||||
|
||||
void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const double newval)
|
||||
void fixedfreq_monitor_state::update_sync_channel(const time_type &time,
|
||||
const double newval)
|
||||
{
|
||||
const time_type delta_time = time - m_last_sync_time;
|
||||
|
||||
const int last_vsync = m_sig_vsync;
|
||||
const int last_comp = m_sig_composite;
|
||||
|
||||
m_vsync_filter += ((double) last_comp - m_vsync_filter) * (1.0 - exp(-delta_time * m_desc.vsync_filter_timeconst()));
|
||||
m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0 ;
|
||||
m_vsync_filter += ((double)last_comp - m_vsync_filter)
|
||||
* (1.0
|
||||
- exp(-delta_time * m_desc.vsync_filter_timeconst()));
|
||||
m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0;
|
||||
|
||||
m_sig_vsync = (m_vsync_filter > m_desc.m_vsync_threshold) ? 1 : 0;
|
||||
|
||||
if (!last_vsync && m_sig_vsync)
|
||||
{
|
||||
LOG("VSYNC UP %f %d\n", m_last_x, m_last_y);
|
||||
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
|
||||
const int has_fields = (m_desc.m_fieldcount > 1) ? 1 : 0;
|
||||
|
||||
// FIXME: add modes: true interlaced, overlayed, false progressive (see popeye video)
|
||||
// FIXME: add modes: true interlaced, overlayed, false progressive (see
|
||||
// popeye video)
|
||||
if (has_fields)
|
||||
{
|
||||
const auto avg_line_dur = (time - m_last_field_time) * m_desc.m_fieldcount / (m_last_y + 1);
|
||||
const auto avg_line_dur = (time - m_last_field_time)
|
||||
* m_desc.m_fieldcount / (m_last_y + 1);
|
||||
m_last_field_time = time;
|
||||
m_sig_field = avg_line_dur * 0.75 > m_last_line_duration;
|
||||
LOG("%d %f %f %f\n", m_sig_field, m_last_line_duration, avg_line_dur, time);
|
||||
LOG("%d %f %f %f\n", m_sig_field, m_last_line_duration,
|
||||
avg_line_dur, time);
|
||||
}
|
||||
|
||||
// notify the controlling device about the vsync and the field.
|
||||
@ -108,12 +120,13 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
|
||||
{
|
||||
if (m_sig_vsync)
|
||||
LOG("Hsync in vsync\n");
|
||||
//LOG("HSYNC up %d\n", m_last_x);
|
||||
// FIXME: pixels > 0 filters some spurious hysnc on line 23/24 in breakout
|
||||
// The hsync signal transition from high to low is 7 pixels too
|
||||
// early, goes up again after 6.8 pix and down after 7.2 pix.
|
||||
// Therefore we need to filter early low to high transitions
|
||||
// and base hsync on the start of the hsync signal.
|
||||
// LOG("HSYNC up %d\n", m_last_x);
|
||||
// FIXME: pixels > 0 filters some spurious hysnc on line
|
||||
// 23/24 in breakout
|
||||
// The hsync signal transition from high to low is 7 pixels too
|
||||
// early, goes up again after 6.8 pix and down after 7.2 pix.
|
||||
// Therefore we need to filter early low to high transitions
|
||||
// and base hsync on the start of the hsync signal.
|
||||
if (!m_sig_vsync && (m_last_x > 0))
|
||||
{
|
||||
m_last_y += m_desc.m_fieldcount;
|
||||
@ -122,13 +135,12 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
|
||||
|
||||
m_last_line_duration = time - m_last_hsync_time;
|
||||
m_last_hsync_time = time;
|
||||
|
||||
}
|
||||
}
|
||||
else if (last_comp && !m_sig_composite)
|
||||
{
|
||||
/* falling composite */
|
||||
//LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
|
||||
// LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
|
||||
}
|
||||
m_last_sync_val = newval;
|
||||
m_last_sync_time = time;
|
||||
@ -136,99 +148,109 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
|
||||
|
||||
void fixedfreq_monitor_state::update_bm(const time_type &time)
|
||||
{
|
||||
const float pixels = (time - m_line_time) * (double) m_desc.monitor_clock();
|
||||
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
|
||||
const float pixels = (time - m_line_time) * (double)m_desc.monitor_clock();
|
||||
const int has_fields = (m_desc.m_fieldcount > 1) ? 1 : 0;
|
||||
const float fhscale(static_cast<float>(m_desc.m_hscale));
|
||||
|
||||
//uint32_t col(0xffff0000); // Mark sync areas
|
||||
//if (m_last_sync >= m_desc.m_sync_threshold)
|
||||
// col = m_col;
|
||||
// uint32_t col(0xffff0000); // Mark sync areas
|
||||
// if (m_last_sync >= m_desc.m_sync_threshold)
|
||||
// col = m_col;
|
||||
|
||||
if (!m_sig_vsync && !m_sig_composite)
|
||||
{
|
||||
//uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
|
||||
m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields),
|
||||
m_last_x * fhscale, pixels * fhscale, m_col}); // & mask});
|
||||
// uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
|
||||
m_fragments.push_back(
|
||||
{static_cast<float>(m_last_y + m_sig_field * has_fields),
|
||||
m_last_x * fhscale, pixels * fhscale, m_col}); // & mask});
|
||||
}
|
||||
//m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels, col);
|
||||
// m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels,
|
||||
// col);
|
||||
m_last_x = pixels;
|
||||
}
|
||||
|
||||
void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time, const double data)
|
||||
void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time,
|
||||
const double data)
|
||||
{
|
||||
update_bm(time);
|
||||
update_sync_channel(time, data);
|
||||
|
||||
//int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
int colv = (int) ((data - 1.5) * m_desc.m_gain * 255.0);
|
||||
//#int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
int colv = (int)((data - 1.5) * m_desc.m_gain * 255.0);
|
||||
if (colv > 255)
|
||||
colv = 255;
|
||||
if (colv < 0)
|
||||
//m_col = 0xffff0000;
|
||||
// m_col = 0xffff0000;
|
||||
m_col = 0x0000000;
|
||||
else
|
||||
m_col = 0xff000000 | (colv<<16) | (colv<<8) | colv;
|
||||
m_col = 0xff000000 | (colv << 16) | (colv << 8) | colv;
|
||||
}
|
||||
|
||||
void fixedfreq_monitor_state::update_red(const time_type &time, const double data)
|
||||
void fixedfreq_monitor_state::update_red(const time_type &time,
|
||||
const double data)
|
||||
{
|
||||
update_bm(time);
|
||||
|
||||
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
int colv = (int)((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
if (colv > 255)
|
||||
colv = 255;
|
||||
if (colv < 0)
|
||||
colv = 0;
|
||||
m_col = (m_col & 0xff00ffff) | (colv<<16);
|
||||
m_col = (m_col & 0xff00ffff) | (colv << 16);
|
||||
}
|
||||
|
||||
void fixedfreq_monitor_state::update_green(const time_type &time, const double data)
|
||||
void fixedfreq_monitor_state::update_green(const time_type &time,
|
||||
const double data)
|
||||
{
|
||||
update_bm(time);
|
||||
//update_sync_channel(ctime, data);
|
||||
// update_sync_channel(ctime, data);
|
||||
|
||||
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
int colv = (int)((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
if (colv > 255)
|
||||
colv = 255;
|
||||
if (colv < 0)
|
||||
colv = 0;
|
||||
m_col = (m_col & 0xffff00ff) | (colv<<8);
|
||||
m_col = (m_col & 0xffff00ff) | (colv << 8);
|
||||
}
|
||||
|
||||
void fixedfreq_monitor_state::update_blue(const time_type &time, const double data)
|
||||
void fixedfreq_monitor_state::update_blue(const time_type &time,
|
||||
const double data)
|
||||
{
|
||||
update_bm(time);
|
||||
//update_sync_channel(ctime, data);
|
||||
// update_sync_channel(ctime, data);
|
||||
|
||||
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
int colv = (int)((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
|
||||
if (colv > 255)
|
||||
colv = 255;
|
||||
if (colv < 0)
|
||||
colv = 0;
|
||||
m_col = (m_col & 0xffffff00) | colv;
|
||||
|
||||
}
|
||||
|
||||
void fixedfreq_monitor_state::update_sync(const time_type &time, const double data)
|
||||
void fixedfreq_monitor_state::update_sync(const time_type &time,
|
||||
const double data)
|
||||
{
|
||||
update_bm(time);
|
||||
update_sync_channel(time, data);
|
||||
}
|
||||
|
||||
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock),
|
||||
device_video_interface(mconfig, *this, false),
|
||||
m_enable(*this, "ENABLE"),
|
||||
m_vector(*this, "VECTOR"),
|
||||
m_scanline_height(1.0),
|
||||
m_last_rt(0.0),
|
||||
m_monitor(),
|
||||
m_state(m_monitor, *this)
|
||||
fixedfreq_device::fixedfreq_device(const machine_config &mconfig,
|
||||
device_type type, const char *tag,
|
||||
device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_video_interface(mconfig, *this, false)
|
||||
, m_enable(*this, "ENABLE")
|
||||
, m_vector(*this, "VECTOR")
|
||||
, m_scanline_height(1.0)
|
||||
, m_last_rt(0.0)
|
||||
, m_monitor()
|
||||
, m_state(m_monitor, *this)
|
||||
{
|
||||
}
|
||||
|
||||
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
|
||||
fixedfreq_device::fixedfreq_device(const machine_config &mconfig,
|
||||
const char *tag, device_t *owner,
|
||||
uint32_t clock)
|
||||
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
@ -251,10 +273,11 @@ void fixedfreq_device::device_config_complete()
|
||||
// to specify the window size.
|
||||
if (!screen().refresh_attoseconds())
|
||||
screen().set_raw(m_monitor.m_monitor_clock, m_monitor.htotal(), 0,
|
||||
m_monitor.htotal(), m_monitor.vtotal(), 0,
|
||||
m_monitor.vtotal());
|
||||
m_monitor.htotal(), m_monitor.vtotal(), 0,
|
||||
m_monitor.vtotal());
|
||||
if (!screen().has_screen_update())
|
||||
screen().set_screen_update(*this, FUNC(fixedfreq_device::screen_update));
|
||||
screen().set_screen_update(*this,
|
||||
FUNC(fixedfreq_device::screen_update));
|
||||
LOG("config complete\n");
|
||||
}
|
||||
|
||||
@ -288,7 +311,7 @@ void fixedfreq_device::device_reset()
|
||||
{
|
||||
m_state.reset();
|
||||
LOG("Reset\n");
|
||||
//ioport("YYY")->field(0xffff)->live().value = 20;
|
||||
// ioport("YYY")->field(0xffff)->live().value = 20;
|
||||
#if 0
|
||||
//IOPORT_ID(HVISIBLE)->field(~0)->set_value(m_monitor.m_hvisible);
|
||||
//IOPORT_ID(HVISIBLE)->update_defvalue(false);
|
||||
@ -307,36 +330,39 @@ void fixedfreq_device::device_reset()
|
||||
|
||||
void fixedfreq_device::device_post_load()
|
||||
{
|
||||
//recompute_parameters();
|
||||
// recompute_parameters();
|
||||
LOG("post load\n");
|
||||
}
|
||||
|
||||
static uint32_t nom_col(uint32_t col)
|
||||
{
|
||||
float r = ((col >> 16) & 0xff);
|
||||
float g = ((col >> 8) & 0xff);
|
||||
float b = ((col >> 0) & 0xff);
|
||||
float g = ((col >> 8) & 0xff);
|
||||
float b = ((col >> 0) & 0xff);
|
||||
|
||||
float m = std::max(r, std::max(g,b));
|
||||
float m = std::max(r, std::max(g, b));
|
||||
if (m == 0.0f)
|
||||
return 0;
|
||||
return (((uint32_t) m ) << 24) | (((uint32_t) (r/m*255.0f) ) << 16)
|
||||
| (((uint32_t) (g/m*255.0f) ) << 8) | (((uint32_t) (b/m*255.0f) ) << 0);
|
||||
return (((uint32_t)m) << 24) | (((uint32_t)(r / m * 255.0f)) << 16)
|
||||
| (((uint32_t)(g / m * 255.0f)) << 8)
|
||||
| (((uint32_t)(b / m * 255.0f)) << 0);
|
||||
}
|
||||
|
||||
static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap,
|
||||
const rectangle &cliprect)
|
||||
{
|
||||
// Test pattern Grey scale
|
||||
const int stripes = 255;
|
||||
//auto va(screen.visible_area());
|
||||
// auto va(screen.visible_area());
|
||||
auto &va(cliprect);
|
||||
|
||||
for (int i = 0; i < stripes; i++)
|
||||
{
|
||||
int l = va.left() + (i * va.width() / stripes);
|
||||
int w = (va.left() + (i+1) * va.width() / stripes) - l;
|
||||
int w = (va.left() + (i + 1) * va.width() / stripes) - l;
|
||||
int v = (255 * i) / stripes;
|
||||
bitmap.plot_box(l, va.top()+20, w, va.height()/2-20, rgb_t(0xff, v, v, v));
|
||||
bitmap.plot_box(l, va.top() + 20, w, va.height() / 2 - 20,
|
||||
rgb_t(0xff, v, v, v));
|
||||
}
|
||||
|
||||
int l(va.left() + va.width() / 4);
|
||||
@ -353,14 +379,20 @@ static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rect
|
||||
bitmap.plot_box(l, t, w, h, rgb_t(0xff, 0xc3, 0xc3, 0xc3)); // 195
|
||||
}
|
||||
|
||||
uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
uint32_t
|
||||
fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
|
||||
const rectangle &cliprect)
|
||||
{
|
||||
//printf("%f\n", machine().time().as_double());
|
||||
//printf("%d %lu %f %f\n", m_state.m_sig_vsync, m_state.m_fragments.size(), m_state.m_fragments[0].y, m_state.m_fragments[m_state.m_fragments.size()-1].y);
|
||||
bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR || (m_vector->read() & 1);
|
||||
bool debug_timing = (m_enable->read() & 2) == 2;
|
||||
bool test_pat = (m_enable->read() & 4) == 4;
|
||||
rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00) : rgb_t(0xff, 0x00, 0x00, 0x00);
|
||||
// printf("%f\n", machine().time().as_double());
|
||||
// printf("%d %lu %f %f\n", m_state.m_sig_vsync, m_state.m_fragments.size(),
|
||||
// m_state.m_fragments[0].y,
|
||||
// m_state.m_fragments[m_state.m_fragments.size()-1].y);
|
||||
bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR
|
||||
|| (m_vector->read() & 1);
|
||||
bool debug_timing = (m_enable->read() & 2) == 2;
|
||||
bool test_pat = (m_enable->read() & 4) == 4;
|
||||
rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00)
|
||||
: rgb_t(0xff, 0x00, 0x00, 0x00);
|
||||
|
||||
if (!force_vector)
|
||||
{
|
||||
@ -377,18 +409,22 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
|
||||
{
|
||||
screen.set_video_attributes(VIDEO_SELF_RENDER);
|
||||
|
||||
const uint32_t flags(PRIMFLAG_ANTIALIAS(1)
|
||||
| PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
|
||||
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1) : 0));
|
||||
const uint32_t flags(
|
||||
PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
|
||||
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1)
|
||||
: 0));
|
||||
const rectangle &visarea = screen.visible_area();
|
||||
float xscale = 1.0f / (float)visarea.width();
|
||||
float yscale = 1.0f / (float)visarea.height();
|
||||
float xoffs = (float)visarea.min_x;
|
||||
float yoffs = (float)visarea.min_y;
|
||||
float xscale = 1.0f / (float)visarea.width();
|
||||
float yscale = 1.0f / (float)visarea.height();
|
||||
float xoffs = (float)visarea.min_x;
|
||||
float yoffs = (float)visarea.min_y;
|
||||
screen.container().empty();
|
||||
screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00),
|
||||
screen.container().add_rect(
|
||||
0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff, 0x00, 0x00, 0x00),
|
||||
PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)
|
||||
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTORBUF(1) : 0));
|
||||
| (screen.screen_type() == SCREEN_TYPE_VECTOR
|
||||
? PRIMFLAG_VECTORBUF(1)
|
||||
: 0));
|
||||
|
||||
float last_y = -1e6;
|
||||
for (auto &f : m_state.m_fragments)
|
||||
@ -397,7 +433,7 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
|
||||
const float y0((f.y - yoffs) * yscale);
|
||||
const float x1((f.xr - xoffs) * xscale);
|
||||
|
||||
rgb_t col = (debug_timing && f.y < last_y) ? backcol : (rgb_t) f.col;
|
||||
rgb_t col = (debug_timing && f.y < last_y) ? backcol : (rgb_t)f.col;
|
||||
// FIXME: Debug check for proper vsync timing
|
||||
#if 0
|
||||
auto w = m_scanline_height * xscale * 0.5;
|
||||
@ -407,21 +443,18 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
|
||||
// (0xff << 24) | (f.col & 0xffffff),
|
||||
flags);
|
||||
#elif 1
|
||||
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
||||
screen.container().add_rect(
|
||||
x0, y0, x1, y1,
|
||||
nom_col(col),
|
||||
// (0xaf << 24) | (f.col & 0xffffff),
|
||||
flags);
|
||||
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
||||
screen.container().add_rect(x0, y0, x1, y1, nom_col(col),
|
||||
// (0xaf << 24) |
|
||||
// (f.col & 0xffffff),
|
||||
flags);
|
||||
#else
|
||||
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
||||
// Crashes with bgfx
|
||||
screen.container().add_quad(
|
||||
x0, y0, x1, y1,
|
||||
rgb_t(nom_col(f.col)),
|
||||
// (0xaf << 24) | (f.col & 0xffffff),
|
||||
m_texture,
|
||||
flags);
|
||||
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
||||
// Crashes with bgfx
|
||||
screen.container().add_quad(x0, y0, x1, y1, rgb_t(nom_col(f.col)),
|
||||
// (0xaf << 24) |
|
||||
// (f.col & 0xffffff),
|
||||
m_texture, flags);
|
||||
#endif
|
||||
last_y = f.y;
|
||||
}
|
||||
@ -432,8 +465,9 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
|
||||
|
||||
void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
|
||||
{
|
||||
const auto expected_frame_period(m_monitor.clock_period() * m_monitor.vtotal() * m_monitor.htotal());
|
||||
bool progressive = (m_enable->read() & 8) == 8;
|
||||
const auto expected_frame_period(m_monitor.clock_period()
|
||||
* m_monitor.vtotal() * m_monitor.htotal());
|
||||
bool progressive = (m_enable->read() & 8) == 8;
|
||||
|
||||
double mult = 0.5;
|
||||
|
||||
@ -448,15 +482,21 @@ void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
|
||||
mult = 1.0;
|
||||
}
|
||||
|
||||
const auto refresh_limited(std::min(4.0 * expected_frame_period,
|
||||
std::max((refresh_time + m_last_rt) * mult, 0.25 * expected_frame_period)));
|
||||
const auto refresh_limited(std::min(
|
||||
4.0 * expected_frame_period, std::max((refresh_time + m_last_rt) * mult,
|
||||
0.25 * expected_frame_period)));
|
||||
|
||||
m_last_rt = refresh_time;
|
||||
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(), m_monitor.maxv());
|
||||
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(),
|
||||
m_monitor.maxv());
|
||||
|
||||
// reset_origin must be called first.
|
||||
screen().reset_origin(m_state.m_last_y-(m_monitor.vsync_width() + m_monitor.vbackporch_width()), 0);
|
||||
screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea, DOUBLE_TO_ATTOSECONDS(refresh_limited));
|
||||
screen().reset_origin(
|
||||
m_state.m_last_y
|
||||
- (m_monitor.vsync_width() + m_monitor.vbackporch_width()),
|
||||
0);
|
||||
screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea,
|
||||
DOUBLE_TO_ATTOSECONDS(refresh_limited));
|
||||
}
|
||||
|
||||
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_composite_monochrome)
|
||||
@ -501,6 +541,8 @@ NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_sync)
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
// clang-format off
|
||||
|
||||
static INPUT_PORTS_START(fixedfreq_base_ports)
|
||||
PORT_START("ENABLE")
|
||||
PORT_CONFNAME( 0x01, 0x00, "Display Monitor sliders" )
|
||||
@ -549,6 +591,9 @@ static INPUT_PORTS_START(fixedfreq_vector_ports)
|
||||
PORT_ADJUSTERX(SCANLINE_HEIGHT, "Scanline Height", 10, 300)
|
||||
INPUT_PORTS_END
|
||||
|
||||
//
|
||||
// clang-format on
|
||||
|
||||
ioport_constructor fixedfreq_device::device_input_ports() const
|
||||
{
|
||||
LOG("input ports\n");
|
||||
@ -567,30 +612,18 @@ unsigned fixedfreq_device::monitor_val(unsigned param) const
|
||||
{
|
||||
switch (param)
|
||||
{
|
||||
case HVISIBLE:
|
||||
return m_monitor.hvisible_width();
|
||||
case HFRONTPORCH:
|
||||
return m_monitor.hfrontporch_width();
|
||||
case HSYNC:
|
||||
return m_monitor.hsync_width();
|
||||
case HBACKPORCH:
|
||||
return m_monitor.hbackporch_width();
|
||||
case VVISIBLE:
|
||||
return m_monitor.vvisible_width();
|
||||
case VFRONTPORCH:
|
||||
return m_monitor.vfrontporch_width();
|
||||
case VSYNC:
|
||||
return m_monitor.vsync_width();
|
||||
case VBACKPORCH:
|
||||
return m_monitor.vbackporch_width();
|
||||
case SYNCTHRESHOLD:
|
||||
return m_monitor.m_sync_threshold * 1000.0;
|
||||
case VSYNCTHRESHOLD:
|
||||
return m_monitor.m_vsync_threshold * 1000.0;
|
||||
case GAIN:
|
||||
return m_monitor.m_gain * 100.0;
|
||||
case SCANLINE_HEIGHT:
|
||||
return m_scanline_height * 100.0;
|
||||
case HVISIBLE: return m_monitor.hvisible_width();
|
||||
case HFRONTPORCH: return m_monitor.hfrontporch_width();
|
||||
case HSYNC: return m_monitor.hsync_width();
|
||||
case HBACKPORCH: return m_monitor.hbackporch_width();
|
||||
case VVISIBLE: return m_monitor.vvisible_width();
|
||||
case VFRONTPORCH: return m_monitor.vfrontporch_width();
|
||||
case VSYNC: return m_monitor.vsync_width();
|
||||
case VBACKPORCH: return m_monitor.vbackporch_width();
|
||||
case SYNCTHRESHOLD: return m_monitor.m_sync_threshold * 1000.0;
|
||||
case VSYNCTHRESHOLD: return m_monitor.m_vsync_threshold * 1000.0;
|
||||
case GAIN: return m_monitor.m_gain * 100.0;
|
||||
case SCANLINE_HEIGHT: return m_scanline_height * 100.0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -603,28 +636,36 @@ INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
|
||||
switch (param)
|
||||
{
|
||||
case HVISIBLE:
|
||||
m.set_h_rel(newval, m.hfrontporch_width(), m.hsync_width(), m.hbackporch_width());
|
||||
m.set_h_rel(newval, m.hfrontporch_width(), m.hsync_width(),
|
||||
m.hbackporch_width());
|
||||
break;
|
||||
case HFRONTPORCH:
|
||||
m.set_h_rel(m.hvisible_width(), newval, m.hsync_width(), m.hbackporch_width());
|
||||
m.set_h_rel(m.hvisible_width(), newval, m.hsync_width(),
|
||||
m.hbackporch_width());
|
||||
break;
|
||||
case HSYNC:
|
||||
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), newval, m.hbackporch_width());
|
||||
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), newval,
|
||||
m.hbackporch_width());
|
||||
break;
|
||||
case HBACKPORCH:
|
||||
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), m.hsync_width(), newval);
|
||||
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(),
|
||||
m.hsync_width(), newval);
|
||||
break;
|
||||
case VVISIBLE:
|
||||
m.set_v_rel(newval, m.vfrontporch_width(), m.vsync_width(), m.vbackporch_width());
|
||||
m.set_v_rel(newval, m.vfrontporch_width(), m.vsync_width(),
|
||||
m.vbackporch_width());
|
||||
break;
|
||||
case VFRONTPORCH:
|
||||
m.set_v_rel(m.vvisible_width(), newval, m.vsync_width(), m.vbackporch_width());
|
||||
m.set_v_rel(m.vvisible_width(), newval, m.vsync_width(),
|
||||
m.vbackporch_width());
|
||||
break;
|
||||
case VSYNC:
|
||||
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), newval, m.vbackporch_width());
|
||||
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), newval,
|
||||
m.vbackporch_width());
|
||||
break;
|
||||
case VBACKPORCH:
|
||||
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), m.vsync_width(), newval);
|
||||
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(),
|
||||
m.vsync_width(), newval);
|
||||
break;
|
||||
case SYNCTHRESHOLD:
|
||||
m.m_sync_threshold = static_cast<double>(newval) / 1000.0;
|
||||
@ -632,13 +673,12 @@ INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
|
||||
case VSYNCTHRESHOLD:
|
||||
m.m_vsync_threshold = static_cast<double>(newval) / 1000.0;
|
||||
break;
|
||||
case GAIN:
|
||||
m.m_gain = static_cast<double>(newval) / 100.0;
|
||||
break;
|
||||
case GAIN: m.m_gain = static_cast<double>(newval) / 100.0; break;
|
||||
case SCANLINE_HEIGHT:
|
||||
m_scanline_height = static_cast<double>(newval) / 100.0;
|
||||
break;
|
||||
}
|
||||
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(), m.vtotal());
|
||||
//ioport("YYY")->update_defvalue(true);
|
||||
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(),
|
||||
m.vtotal());
|
||||
// ioport("YYY")->update_defvalue(true);
|
||||
}
|
||||
|
@ -2,12 +2,12 @@
|
||||
// copyright-holders:Couriersud
|
||||
/***************************************************************************
|
||||
|
||||
fixfreq.h
|
||||
fixfreq.h
|
||||
|
||||
Fixed frequency monochrome monitor emulation
|
||||
Fixed frequency monochrome monitor emulation
|
||||
|
||||
The driver is intended for drivers which provide an analog video signal.
|
||||
VSYNC and HSYNC levels are used to create the bitmap.
|
||||
The driver is intended for drivers which provide an analog video signal.
|
||||
VSYNC and HSYNC levels are used to create the bitmap.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
@ -21,41 +21,58 @@ struct fixedfreq_monitor_desc
|
||||
{
|
||||
fixedfreq_monitor_desc()
|
||||
// default to NTSC "704x480@30i"
|
||||
: m_monitor_clock(13500000),
|
||||
m_fieldcount(2),
|
||||
m_sync_threshold(0.3),
|
||||
m_gain(1.0 / 3.7),
|
||||
m_hscale(1),
|
||||
m_vsync_threshold(0.600), // trigger at 91% of vsync length 1-exp(-0.6)
|
||||
m_hvisible(704),
|
||||
m_hfrontporch(728),
|
||||
m_hsync(791),
|
||||
m_hbackporch(858),
|
||||
m_vvisible(480),
|
||||
m_vfrontporch(486),
|
||||
m_vsync(492),
|
||||
m_vbackporch(525)
|
||||
{}
|
||||
: m_monitor_clock(13500000)
|
||||
, m_fieldcount(2)
|
||||
, m_sync_threshold(0.3)
|
||||
, m_gain(1.0 / 3.7)
|
||||
, m_hscale(1)
|
||||
, m_vsync_threshold(0.600)
|
||||
, // trigger at 91% of vsync length 1-exp(-0.6)
|
||||
m_hvisible(704)
|
||||
, m_hfrontporch(728)
|
||||
, m_hsync(791)
|
||||
, m_hbackporch(858)
|
||||
, m_vvisible(480)
|
||||
, m_vfrontporch(486)
|
||||
, m_vsync(492)
|
||||
, m_vbackporch(525)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t monitor_clock() const noexcept { return m_monitor_clock; }
|
||||
double clock_period() const noexcept { return 1.0 / (double) m_monitor_clock; }
|
||||
double clock_period() const noexcept
|
||||
{
|
||||
return 1.0 / (double)m_monitor_clock;
|
||||
}
|
||||
|
||||
int minh() const noexcept { return (m_hbackporch - m_hsync) * m_hscale; }
|
||||
int maxh() const noexcept { return (m_hbackporch - m_hsync + m_hvisible) * m_hscale - 1; }
|
||||
int maxh() const noexcept
|
||||
{
|
||||
return (m_hbackporch - m_hsync + m_hvisible) * m_hscale - 1;
|
||||
}
|
||||
int minv() const noexcept { return m_vbackporch - m_vsync; }
|
||||
int maxv() const noexcept { return m_vbackporch - m_vsync + m_vvisible - 1; }
|
||||
int maxv() const noexcept
|
||||
{
|
||||
return m_vbackporch - m_vsync + m_vvisible - 1;
|
||||
}
|
||||
|
||||
int htotal_scaled() const noexcept { return m_hbackporch * m_hscale; }
|
||||
|
||||
int vbackporch_width() const noexcept { return m_vbackporch - m_vsync; }
|
||||
int vsync_width() const noexcept { return m_vsync - m_vfrontporch; }
|
||||
int vfrontporch_width() const noexcept { return m_vfrontporch - m_vvisible; }
|
||||
int vfrontporch_width() const noexcept
|
||||
{
|
||||
return m_vfrontporch - m_vvisible;
|
||||
}
|
||||
int vvisible_width() const noexcept { return m_vvisible; }
|
||||
int vtotal() const noexcept { return m_vbackporch; }
|
||||
|
||||
int hbackporch_width() const noexcept { return m_hbackporch - m_hsync; }
|
||||
int hsync_width() const noexcept { return m_hsync - m_hfrontporch; }
|
||||
int hfrontporch_width() const noexcept { return m_hfrontporch - m_hvisible; }
|
||||
int hfrontporch_width() const noexcept
|
||||
{
|
||||
return m_hfrontporch - m_hvisible;
|
||||
}
|
||||
int hvisible_width() const noexcept { return m_hvisible; }
|
||||
int htotal() const noexcept { return m_hbackporch; }
|
||||
|
||||
@ -77,20 +94,22 @@ struct fixedfreq_monitor_desc
|
||||
|
||||
double vsync_filter_timeconst() const noexcept
|
||||
{
|
||||
return (double) (m_monitor_clock) / ((double) m_hbackporch * vsync_width());
|
||||
return (double)(m_monitor_clock)
|
||||
/ ((double)m_hbackporch * vsync_width());
|
||||
}
|
||||
|
||||
double hsync_filter_timeconst() const noexcept
|
||||
{
|
||||
return (double) m_monitor_clock / (double) hsync_width();
|
||||
return (double)m_monitor_clock / (double)hsync_width();
|
||||
}
|
||||
|
||||
uint32_t m_monitor_clock;
|
||||
int m_fieldcount;
|
||||
double m_sync_threshold;
|
||||
double m_gain;
|
||||
int m_hscale;
|
||||
double m_vsync_threshold;
|
||||
int m_fieldcount;
|
||||
double m_sync_threshold;
|
||||
double m_gain;
|
||||
int m_hscale;
|
||||
double m_vsync_threshold;
|
||||
|
||||
private:
|
||||
int m_hvisible;
|
||||
int m_hfrontporch;
|
||||
@ -110,9 +129,9 @@ struct fixedfreq_monitor_intf
|
||||
|
||||
struct fixedfreq_monitor_line
|
||||
{
|
||||
float y;
|
||||
float x;
|
||||
float xr;
|
||||
float y;
|
||||
float x;
|
||||
float xr;
|
||||
uint32_t col;
|
||||
};
|
||||
|
||||
@ -120,24 +139,26 @@ struct fixedfreq_monitor_state
|
||||
{
|
||||
using time_type = double;
|
||||
|
||||
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc, fixedfreq_monitor_intf &intf)
|
||||
: m_desc(desc),
|
||||
m_intf(intf),
|
||||
m_last_sync_val(0),
|
||||
m_col(0),
|
||||
m_last_x(0),
|
||||
m_last_y(0),
|
||||
m_last_sync_time(time_type(0)),
|
||||
m_line_time(time_type(0)),
|
||||
m_last_hsync_time(time_type(0)),
|
||||
m_last_vsync_time(time_type(0)),
|
||||
m_last_line_duration(time_type(0)),
|
||||
m_last_field_time(time_type(0)),
|
||||
m_vsync_filter(0),
|
||||
m_sig_vsync(0),
|
||||
m_sig_composite(0),
|
||||
m_sig_field(0)
|
||||
{}
|
||||
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc,
|
||||
fixedfreq_monitor_intf &intf)
|
||||
: m_desc(desc)
|
||||
, m_intf(intf)
|
||||
, m_last_sync_val(0)
|
||||
, m_col(0)
|
||||
, m_last_x(0)
|
||||
, m_last_y(0)
|
||||
, m_last_sync_time(time_type(0))
|
||||
, m_line_time(time_type(0))
|
||||
, m_last_hsync_time(time_type(0))
|
||||
, m_last_vsync_time(time_type(0))
|
||||
, m_last_line_duration(time_type(0))
|
||||
, m_last_field_time(time_type(0))
|
||||
, m_vsync_filter(0)
|
||||
, m_sig_vsync(0)
|
||||
, m_sig_composite(0)
|
||||
, m_sig_field(0)
|
||||
{
|
||||
}
|
||||
|
||||
/***
|
||||
* \brief To be called after monitor parameters are set
|
||||
@ -148,7 +169,7 @@ struct fixedfreq_monitor_state
|
||||
// Only copies constructor init
|
||||
|
||||
m_last_sync_val = 0.0;
|
||||
m_col = rgb_t(0,0,0);
|
||||
m_col = rgb_t(0, 0, 0);
|
||||
m_last_x = 0;
|
||||
m_last_y = 0;
|
||||
m_last_sync_time = time_type(0);
|
||||
@ -168,13 +189,15 @@ struct fixedfreq_monitor_state
|
||||
|
||||
/* sync separator */
|
||||
|
||||
//m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
|
||||
//printf("trigger %f with len %f\n", m_vsync_threshold, 1e6 / m_vsync_filter_timeconst);
|
||||
// Minimum frame period to be passed to video system ?
|
||||
// m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
|
||||
// printf("trigger %f with len %f\n", m_vsync_threshold, 1e6 /
|
||||
// m_vsync_filter_timeconst);
|
||||
// Minimum frame period to be passed to video system ?
|
||||
|
||||
m_fragments.clear();
|
||||
|
||||
//m_intf.vsync_end_cb(m_desc.clock_period() * m_desc.vtotal() * m_desc.htotal(), 0);
|
||||
// m_intf.vsync_end_cb(m_desc.clock_period() * m_desc.vtotal() *
|
||||
// m_desc.htotal(), 0);
|
||||
}
|
||||
|
||||
void reset()
|
||||
@ -192,19 +215,20 @@ struct fixedfreq_monitor_state
|
||||
|
||||
void update_sync_channel(const time_type &time, const double newval);
|
||||
void update_bm(const time_type &time);
|
||||
void update_composite_monochrome(const time_type &time, const double newval);
|
||||
void
|
||||
update_composite_monochrome(const time_type &time, const double newval);
|
||||
void update_red(const time_type &time, const double data);
|
||||
void update_green(const time_type &time, const double data);
|
||||
void update_blue(const time_type &time, const double data);
|
||||
void update_sync(const time_type &time, const double data);
|
||||
|
||||
const fixedfreq_monitor_desc &m_desc;
|
||||
fixedfreq_monitor_intf &m_intf;
|
||||
fixedfreq_monitor_intf &m_intf;
|
||||
|
||||
double m_last_sync_val;
|
||||
uint32_t m_col;
|
||||
float m_last_x;
|
||||
int m_last_y;
|
||||
double m_last_sync_val;
|
||||
uint32_t m_col;
|
||||
float m_last_x;
|
||||
int m_last_y;
|
||||
time_type m_last_sync_time;
|
||||
time_type m_line_time;
|
||||
time_type m_last_hsync_time;
|
||||
@ -216,52 +240,76 @@ struct fixedfreq_monitor_state
|
||||
/* sync separator */
|
||||
double m_vsync_filter;
|
||||
|
||||
int m_sig_vsync;
|
||||
int m_sig_composite;
|
||||
int m_sig_field;
|
||||
int m_sig_vsync;
|
||||
int m_sig_composite;
|
||||
int m_sig_field;
|
||||
std::vector<fixedfreq_monitor_line> m_fragments;
|
||||
};
|
||||
|
||||
// ======================> fixedfreq_device
|
||||
|
||||
class fixedfreq_device : public device_t, public device_video_interface,
|
||||
public fixedfreq_monitor_intf
|
||||
class fixedfreq_device
|
||||
: public device_t
|
||||
, public device_video_interface
|
||||
, public fixedfreq_monitor_intf
|
||||
{
|
||||
public:
|
||||
|
||||
using time_type = fixedfreq_monitor_state::time_type;
|
||||
|
||||
// construction/destruction
|
||||
fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
fixedfreq_device(const machine_config &mconfig, const char *tag,
|
||||
device_t *owner, uint32_t clock = 0);
|
||||
|
||||
// inline configuration helpers
|
||||
fixedfreq_device &set_monitor_clock(uint32_t clock) { m_monitor.m_monitor_clock = clock; return *this;}
|
||||
fixedfreq_device &set_fieldcount(int count) { m_monitor.m_fieldcount = count; return *this; }
|
||||
fixedfreq_device &set_threshold(double threshold) { m_monitor.m_sync_threshold = threshold; return *this; }
|
||||
fixedfreq_device &set_vsync_threshold(double threshold) { m_monitor.m_vsync_threshold = threshold; return *this; }
|
||||
fixedfreq_device &set_gain(double gain) { m_monitor.m_gain = gain; return *this; }
|
||||
fixedfreq_device &set_horz_params(int visible, int frontporch, int sync, int backporch)
|
||||
fixedfreq_device &set_monitor_clock(uint32_t clock)
|
||||
{
|
||||
m_monitor.set_h_rel(
|
||||
visible,
|
||||
frontporch - visible,
|
||||
sync - frontporch,
|
||||
backporch - sync);
|
||||
m_monitor.m_monitor_clock = clock;
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_vert_params(int visible, int frontporch, int sync, int backporch)
|
||||
fixedfreq_device &set_fieldcount(int count)
|
||||
{
|
||||
m_monitor.set_v_rel(
|
||||
visible,
|
||||
frontporch - visible,
|
||||
sync - frontporch,
|
||||
backporch - sync);
|
||||
m_monitor.m_fieldcount = count;
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_threshold(double threshold)
|
||||
{
|
||||
m_monitor.m_sync_threshold = threshold;
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_vsync_threshold(double threshold)
|
||||
{
|
||||
m_monitor.m_vsync_threshold = threshold;
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_gain(double gain)
|
||||
{
|
||||
m_monitor.m_gain = gain;
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &
|
||||
set_horz_params(int visible, int frontporch, int sync, int backporch)
|
||||
{
|
||||
m_monitor.set_h_rel(visible, frontporch - visible, sync - frontporch,
|
||||
backporch - sync);
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &
|
||||
set_vert_params(int visible, int frontporch, int sync, int backporch)
|
||||
{
|
||||
m_monitor.set_v_rel(visible, frontporch - visible, sync - frontporch,
|
||||
backporch - sync);
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_horz_scale(int hscale)
|
||||
{
|
||||
m_monitor.m_hscale = hscale;
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_horz_scale(int hscale) { m_monitor.m_hscale = hscale; return *this;}
|
||||
|
||||
// pre-defined configurations
|
||||
fixedfreq_device &set_mode_ntsc720() //ModeLine "720x480@30i" 13.5 720 736 799 858 480 486 492 525 interlace -hsync -vsync
|
||||
fixedfreq_device &set_mode_ntsc720() // ModeLine "720x480@30i" 13.5 720 736
|
||||
// 799 858 480 486 492 525 interlace
|
||||
// -hsync -vsync
|
||||
{
|
||||
set_monitor_clock(13500000);
|
||||
set_horz_params(720, 736, 799, 858);
|
||||
@ -270,7 +318,8 @@ public:
|
||||
set_threshold(0.3);
|
||||
return *this;
|
||||
}
|
||||
fixedfreq_device &set_mode_ntsc704() //ModeLine "704x480@30i" 13.5 704 728 791 858 480 486 492 525
|
||||
fixedfreq_device &set_mode_ntsc704() // ModeLine "704x480@30i" 13.5 704 728
|
||||
// 791 858 480 486 492 525
|
||||
{
|
||||
set_monitor_clock(13500000);
|
||||
set_horz_params(704, 728, 791, 858);
|
||||
@ -280,7 +329,8 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
|
||||
const rectangle &cliprect);
|
||||
|
||||
NETDEV_ANALOG_CALLBACK_MEMBER(update_composite_monochrome);
|
||||
NETDEV_ANALOG_CALLBACK_MEMBER(update_red);
|
||||
@ -293,8 +343,8 @@ public:
|
||||
unsigned monitor_val(unsigned param) const;
|
||||
|
||||
protected:
|
||||
|
||||
fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
fixedfreq_device(const machine_config &mconfig, device_type type,
|
||||
const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_config_complete() override;
|
||||
@ -309,16 +359,14 @@ protected:
|
||||
private:
|
||||
required_ioport m_enable;
|
||||
required_ioport m_vector;
|
||||
float m_scanline_height;
|
||||
double m_last_rt;
|
||||
float m_scanline_height;
|
||||
double m_last_rt;
|
||||
|
||||
/* adjustable by drivers */
|
||||
fixedfreq_monitor_desc m_monitor;
|
||||
fixedfreq_monitor_desc m_monitor;
|
||||
fixedfreq_monitor_state m_state;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(FIXFREQ, fixedfreq_device)
|
||||
|
||||
|
@ -353,8 +353,6 @@ namespace netlist::analog
|
||||
nld_two_terminal m_P0_P1; // 0, -gec, -gcc, 0 | 0
|
||||
};
|
||||
|
||||
#define USE_THREE (1)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// nld_QBJT_EB
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -21,14 +21,16 @@
|
||||
/// http://jaco.ec.t.kanazawa-u.ac.jp/edu/mix/pdf/3.pdf
|
||||
///
|
||||
/// Farid N. Naim, Circuit Simulation (Wiley-IEEE Press, 2010).
|
||||
/// Stefan Jahn, Michael Margraf, Vincent Habchi and Raimund Jacob, "Qucs Technical Papers" (2007)
|
||||
/// Stefan Jahn, Michael Margraf, Vincent Habchi and Raimund Jacob, "Qucs
|
||||
/// Technical Papers" (2007)
|
||||
///
|
||||
|
||||
#include "solver/nld_solver.h"
|
||||
#include "../nl_setup.h"
|
||||
#include "nlid_twoterm.h"
|
||||
|
||||
#define BODY_CONNECTED_TO_SOURCE (1)
|
||||
#include "solver/nld_solver.h"
|
||||
|
||||
#define BODY_CONNECTED_TO_SOURCE (1)
|
||||
|
||||
namespace netlist::analog
|
||||
{
|
||||
@ -99,11 +101,11 @@ namespace netlist::analog
|
||||
{
|
||||
public:
|
||||
fet_model_t(param_model_t &model)
|
||||
: m_VTO(model, "VTO")
|
||||
, m_N(model, "N")
|
||||
, m_ISS(model, "IS") // Haven't seen a model using ISS / ISD
|
||||
, m_ISD(model, "IS")
|
||||
, m_LD(model, "LD")
|
||||
: m_VTO(model, "VTO")
|
||||
, m_N(model, "N")
|
||||
, m_ISS(model, "IS") // Haven't seen a model using ISS / ISD
|
||||
, m_ISD(model, "IS")
|
||||
, m_LD(model, "LD")
|
||||
, m_L(model, "L")
|
||||
, m_W(model, "W")
|
||||
, m_TOX(model, "TOX")
|
||||
@ -119,28 +121,33 @@ namespace netlist::analog
|
||||
, m_CGDO(model, "CGDO")
|
||||
, m_CGBO(model, "CGBO")
|
||||
, m_CAPMOD(model, "CAPMOD")
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
param_model_t::value_t m_VTO; //!< Threshold voltage [V]
|
||||
param_model_t::value_t m_N; //!< Bulk diode emission coefficient
|
||||
param_model_t::value_t m_ISS; //!< Body diode saturation current
|
||||
param_model_t::value_t m_ISD; //!< Body diode saturation current
|
||||
param_model_t::value_t m_LD; //!< Lateral diffusion [m]
|
||||
param_model_t::value_t m_L; //!< Length scaling
|
||||
param_model_t::value_t m_W; //!< Width scaling
|
||||
param_model_t::value_t m_TOX; //!< Oxide thickness
|
||||
param_model_t::value_t m_KP; //!< Transconductance parameter [A/V²]
|
||||
param_model_t::value_t m_UO; //!< Surface mobility [cm²/V/s]
|
||||
param_model_t::value_t m_PHI; //!< Surface inversion potential [V]
|
||||
param_model_t::value_t m_NSUB; //!< Substrate doping [1/cm³]
|
||||
param_model_t::value_t m_GAMMA; //!< Bulk threshold parameter [V^½]
|
||||
param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/V]
|
||||
param_model_t::value_t m_RD; //!< Drain ohmic resistance
|
||||
param_model_t::value_t m_RS; //!< Source ohmic resistance
|
||||
param_model_t::value_t m_CGSO; //!< Gate-source overlap capacitance per meter channel width
|
||||
param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per meter channel width
|
||||
param_model_t::value_t m_CGBO; //!< Gate-bulk overlap capacitance per meter channel width
|
||||
param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no model 2=Meyer)
|
||||
param_model_t::value_t m_VTO; //!< Threshold voltage [V]
|
||||
param_model_t::value_t m_N; //!< Bulk diode emission coefficient
|
||||
param_model_t::value_t m_ISS; //!< Body diode saturation current
|
||||
param_model_t::value_t m_ISD; //!< Body diode saturation current
|
||||
param_model_t::value_t m_LD; //!< Lateral diffusion [m]
|
||||
param_model_t::value_t m_L; //!< Length scaling
|
||||
param_model_t::value_t m_W; //!< Width scaling
|
||||
param_model_t::value_t m_TOX; //!< Oxide thickness
|
||||
param_model_t::value_t m_KP; //!< Transconductance parameter [A/V²]
|
||||
param_model_t::value_t m_UO; //!< Surface mobility [cm²/V/s]
|
||||
param_model_t::value_t m_PHI; //!< Surface inversion potential [V]
|
||||
param_model_t::value_t m_NSUB; //!< Substrate doping [1/cm³]
|
||||
param_model_t::value_t m_GAMMA; //!< Bulk threshold parameter [V^½]
|
||||
param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/V]
|
||||
param_model_t::value_t m_RD; //!< Drain ohmic resistance
|
||||
param_model_t::value_t m_RS; //!< Source ohmic resistance
|
||||
param_model_t::value_t m_CGSO; //!< Gate-source overlap capacitance per
|
||||
//!< meter channel width
|
||||
param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per
|
||||
//!< meter channel width
|
||||
param_model_t::value_t m_CGBO; //!< Gate-bulk overlap capacitance per
|
||||
//!< meter channel width
|
||||
param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no
|
||||
//!< model 2=Meyer)
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -150,7 +157,6 @@ namespace netlist::analog
|
||||
class nld_MOSFET : public base_device_t
|
||||
{
|
||||
public:
|
||||
public: \
|
||||
nld_MOSFET(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_model(*this, "MODEL", "NMOS")
|
||||
@ -171,7 +177,7 @@ namespace netlist::analog
|
||||
, m_lambda(nlconst::zero())
|
||||
, m_Leff(nlconst::zero())
|
||||
, m_CoxWL(nlconst::zero())
|
||||
//S, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
|
||||
// S, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
|
||||
, m_Cgb(nlconst::zero())
|
||||
, m_Cgs(nlconst::zero())
|
||||
, m_Cgd(nlconst::zero())
|
||||
@ -179,28 +185,30 @@ namespace netlist::analog
|
||||
, m_Vgs(*this, "m_Vgs", nlconst::zero())
|
||||
, m_Vgd(*this, "m_Vgd", nlconst::zero())
|
||||
, m_model_acc(m_model)
|
||||
{
|
||||
register_sub_alias("S", m_SG.P()); // Source
|
||||
register_sub_alias("G", m_SG.N()); // Gate
|
||||
{
|
||||
register_sub_alias("S", m_SG.P()); // Source
|
||||
register_sub_alias("G", m_SG.N()); // Gate
|
||||
|
||||
register_sub_alias("D", m_DG.P()); // Drain
|
||||
register_sub_alias("D", m_DG.P()); // Drain
|
||||
|
||||
connect(m_SG.P(), m_SD.P());
|
||||
connect(m_SG.N(), m_DG.N());
|
||||
connect(m_DG.P(), m_SD.N());
|
||||
|
||||
m_polarity = (m_model.type() == "NMOS_DEFAULT" ? nlconst::one() : -nlconst::one());
|
||||
m_polarity = (m_model.type() == "NMOS_DEFAULT" ? nlconst::one()
|
||||
: -nlconst::one());
|
||||
|
||||
m_capacitor_model = m_model_acc.m_CAPMOD;
|
||||
//# printf("capmod %d %g %g\n", m_capacitor_model, (nl_fptype)m_model_acc.m_VTO, m_polarity);
|
||||
nl_assert_always(m_capacitor_model == 0 || m_capacitor_model == 2, "Error: CAPMODEL invalid value");
|
||||
nl_assert_always(m_capacitor_model == 0 || m_capacitor_model == 2,
|
||||
"Error: CAPMODEL invalid value");
|
||||
|
||||
//
|
||||
// From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
|
||||
//
|
||||
// VTO, KP, LAMBDA, PHI and GAMMA. These parameters are computed
|
||||
// if the process parameters(NSUB, TOX,...) are given, but
|
||||
// user-specified values always override.
|
||||
// VTO, KP, LAMBDA, PHI and GAMMA. These parameters are
|
||||
// computed if the process parameters(NSUB, TOX,...) are given,
|
||||
// but user-specified values always override.
|
||||
//
|
||||
// But couldn't find a formula for lambda anywhere
|
||||
//
|
||||
@ -209,20 +217,28 @@ namespace netlist::analog
|
||||
|
||||
// calculate effective channel length
|
||||
m_Leff = m_model_acc.m_L - 2 * m_model_acc.m_LD;
|
||||
nl_assert_always(m_Leff > nlconst::zero(), "Effective Lateral diffusion would be negative for model");
|
||||
nl_assert_always(
|
||||
m_Leff > nlconst::zero(),
|
||||
"Effective Lateral diffusion would be negative for model");
|
||||
|
||||
nl_fptype Cox = (m_model_acc.m_TOX > nlconst::zero()) ? (constants::eps_SiO2() * constants::eps_0() / m_model_acc.m_TOX) : nlconst::zero();
|
||||
nl_fptype Cox = (m_model_acc.m_TOX > nlconst::zero())
|
||||
? (constants::eps_SiO2() * constants::eps_0()
|
||||
/ m_model_acc.m_TOX)
|
||||
: nlconst::zero();
|
||||
|
||||
// calculate DC transconductance coefficient
|
||||
if (m_model_acc.m_KP > nlconst::zero())
|
||||
m_beta = m_model_acc.m_KP * m_model_acc.m_W / m_Leff;
|
||||
else if (Cox > nlconst::zero() && m_model_acc.m_UO > nlconst::zero())
|
||||
m_beta = m_model_acc.m_UO * nlconst::magic(1e-4) * Cox * m_model_acc.m_W / m_Leff;
|
||||
else if (Cox > nlconst::zero()
|
||||
&& m_model_acc.m_UO > nlconst::zero())
|
||||
m_beta = m_model_acc.m_UO * nlconst::magic(1e-4) * Cox
|
||||
* m_model_acc.m_W / m_Leff;
|
||||
else
|
||||
m_beta = nlconst::magic(2e-5) * m_model_acc.m_W / m_Leff;
|
||||
|
||||
//FIXME::UT can disappear
|
||||
const nl_fptype Vt = constants::T0() * constants::k_b() / constants::Q_e();
|
||||
// FIXME::UT can disappear
|
||||
const nl_fptype Vt = constants::T0() * constants::k_b()
|
||||
/ constants::Q_e();
|
||||
|
||||
// calculate surface potential if not given
|
||||
|
||||
@ -230,8 +246,12 @@ namespace netlist::analog
|
||||
m_phi = m_model_acc.m_PHI;
|
||||
else if (m_model_acc.m_NSUB > nlconst::zero())
|
||||
{
|
||||
nl_assert_always(m_model_acc.m_NSUB * nlconst::magic(1e6) >= constants::NiSi(), "Error calculating phi for model");
|
||||
m_phi = nlconst::two() * Vt * plib::log (m_model_acc.m_NSUB * nlconst::magic(1e6) / constants::NiSi());
|
||||
nl_assert_always(m_model_acc.m_NSUB * nlconst::magic(1e6)
|
||||
>= constants::NiSi(),
|
||||
"Error calculating phi for model");
|
||||
m_phi = nlconst::two() * Vt
|
||||
* plib::log(m_model_acc.m_NSUB * nlconst::magic(1e6)
|
||||
/ constants::NiSi());
|
||||
}
|
||||
else
|
||||
m_phi = nlconst::magic(0.6);
|
||||
@ -241,21 +261,24 @@ namespace netlist::analog
|
||||
m_gamma = m_model_acc.m_GAMMA;
|
||||
else
|
||||
{
|
||||
if (Cox > nlconst::zero() && m_model_acc.m_NSUB > nlconst::zero())
|
||||
m_gamma = plib::sqrt (nlconst::two()
|
||||
* constants::Q_e() * constants::eps_Si() * constants::eps_0()
|
||||
* m_model_acc.m_NSUB * nlconst::magic(1e6)) / Cox;
|
||||
if (Cox > nlconst::zero()
|
||||
&& m_model_acc.m_NSUB > nlconst::zero())
|
||||
m_gamma = plib::sqrt(
|
||||
nlconst::two() * constants::Q_e()
|
||||
* constants::eps_Si() * constants::eps_0()
|
||||
* m_model_acc.m_NSUB * nlconst::magic(1e6))
|
||||
/ Cox;
|
||||
else
|
||||
m_gamma = nlconst::zero();
|
||||
}
|
||||
|
||||
m_vto = m_model_acc.m_VTO;
|
||||
// FIXME zero conversion
|
||||
if(m_vto == nlconst::zero())
|
||||
if (m_vto == nlconst::zero())
|
||||
log().warning(MW_MOSFET_THRESHOLD_VOLTAGE(m_model.name()));
|
||||
|
||||
// FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
|
||||
// specify VTO so skip this here.
|
||||
// FIXME: VTO if missing may be calculated from TPG, NSS and
|
||||
// temperature. Usually models specify VTO so skip this here.
|
||||
|
||||
m_CoxWL = Cox * m_model_acc.m_W * m_Leff;
|
||||
|
||||
@ -269,13 +292,14 @@ namespace netlist::analog
|
||||
{
|
||||
if (m_capacitor_model != 0)
|
||||
{
|
||||
if (ts_type == time_step_type::FORWARD)
|
||||
if (ts_type == detail::time_step_type::FORWARD)
|
||||
{
|
||||
//#const nl_nl_fptype Ugd = -m_DG.deltaV() * m_polarity; // Gate - Drain
|
||||
//#const nl_nl_fptype Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
|
||||
const nl_fptype Ugd = m_Vgd; // Gate - Drain
|
||||
const nl_fptype Ugs = m_Vgs; // Gate - Source
|
||||
const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0 if connected
|
||||
const nl_fptype Ugd = m_Vgd; // Gate - Drain
|
||||
const nl_fptype Ugs = m_Vgs; // Gate - Source
|
||||
const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0
|
||||
// if connected
|
||||
const nl_fptype Ugb = Ugs - Ubs;
|
||||
|
||||
m_cap_gb.time_step(m_Cgb, Ugb, step);
|
||||
@ -292,20 +316,22 @@ namespace netlist::analog
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
// Bulk diodes
|
||||
|
||||
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(), constants::T0());
|
||||
#if (!BODY_CONNECTED_TO_SOURCE)
|
||||
m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(), constants::T0());
|
||||
#endif
|
||||
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(),
|
||||
constants::T0());
|
||||
#if (!BODY_CONNECTED_TO_SOURCE)
|
||||
m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(),
|
||||
constants::T0());
|
||||
#endif
|
||||
}
|
||||
|
||||
NETLIB_HANDLERI(terminal_handler)
|
||||
{
|
||||
// only called if connected to a rail net ==> notify the solver to recalculate
|
||||
// only called if connected to a rail net ==> notify the solver to
|
||||
// recalculate
|
||||
auto *solv(m_SG.solver());
|
||||
if (solv != nullptr)
|
||||
solv->solve_now();
|
||||
@ -316,7 +342,6 @@ namespace netlist::analog
|
||||
NETLIB_UPDATE_TERMINALSI();
|
||||
|
||||
private:
|
||||
|
||||
param_model_t m_model;
|
||||
|
||||
NETLIB_NAME(two_terminal) m_DG;
|
||||
@ -349,25 +374,30 @@ namespace netlist::analog
|
||||
nl_fptype m_Cgs;
|
||||
nl_fptype m_Cgd;
|
||||
|
||||
int m_capacitor_model;
|
||||
int m_capacitor_model;
|
||||
state_var<nl_fptype> m_Vgs;
|
||||
state_var<nl_fptype> m_Vgd;
|
||||
fet_model_t m_model_acc;
|
||||
fet_model_t m_model_acc;
|
||||
|
||||
void set_cap(generic_capacitor<capacitor_e::VARIABLE_CAPACITY> &cap,
|
||||
nl_fptype capval, nl_fptype V,
|
||||
nl_fptype &g11, nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
|
||||
nl_fptype &I1, nl_fptype &I2) const
|
||||
nl_fptype capval, nl_fptype V, nl_fptype &g11,
|
||||
nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
|
||||
nl_fptype &I1, nl_fptype &I2) const
|
||||
{
|
||||
const nl_fptype I = cap.Ieq(capval, V) * m_polarity;
|
||||
const nl_fptype G = cap.G(capval);
|
||||
g11 += G; g12 -= G; g21 -= G; g22 += G;
|
||||
I1 -= I; I2 += I;
|
||||
//printf("Cap: %g\n", capval);
|
||||
g11 += G;
|
||||
g12 -= G;
|
||||
g21 -= G;
|
||||
g22 += G;
|
||||
I1 -= I;
|
||||
I2 += I;
|
||||
// printf("Cap: %g\n", capval);
|
||||
}
|
||||
|
||||
void calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
|
||||
nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
|
||||
void
|
||||
calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
|
||||
nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
|
||||
{
|
||||
nl_fptype Vctrl = Vgs - Vth * m_polarity;
|
||||
// Cut off - now further differentiated into 3 different formulas
|
||||
@ -388,7 +418,8 @@ namespace netlist::analog
|
||||
else if (Vctrl <= 0)
|
||||
{
|
||||
Cgb = -Vctrl * m_CoxWL / m_phi;
|
||||
Cgs = Vctrl * m_CoxWL * nlconst::fraction(4.0, 3.0) / m_phi + nlconst::two_thirds() * m_CoxWL;
|
||||
Cgs = Vctrl * m_CoxWL * nlconst::fraction(4.0, 3.0) / m_phi
|
||||
+ nlconst::two_thirds() * m_CoxWL;
|
||||
Cgd = nlconst::zero();
|
||||
}
|
||||
else
|
||||
@ -405,11 +436,15 @@ namespace netlist::analog
|
||||
else
|
||||
{
|
||||
// linear
|
||||
const auto Sqr1(plib::narrow_cast<nl_fptype>(plib::pow(Vdsat - Vds, 2)));
|
||||
const auto Sqr2(plib::narrow_cast<nl_fptype>(plib::pow(nlconst::two() * Vdsat - Vds, 2)));
|
||||
const auto Sqr1(plib::narrow_cast<nl_fptype>(
|
||||
plib::pow(Vdsat - Vds, 2)));
|
||||
const auto Sqr2(plib::narrow_cast<nl_fptype>(
|
||||
plib::pow(nlconst::two() * Vdsat - Vds, 2)));
|
||||
Cgb = 0;
|
||||
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2) * nlconst::two_thirds();
|
||||
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2) * nlconst::two_thirds();
|
||||
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2)
|
||||
* nlconst::two_thirds();
|
||||
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2)
|
||||
* nlconst::two_thirds();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -426,19 +461,26 @@ namespace netlist::analog
|
||||
|
||||
// limit step sizes
|
||||
|
||||
const nl_fptype k = nlconst::magic(3.5); // see "Circuit Simulation", page 185
|
||||
const nl_fptype k = nlconst::magic(3.5); // see "Circuit Simulation",
|
||||
// page 185
|
||||
nl_fptype d = (Vgs - m_Vgs);
|
||||
Vgs = m_Vgs + plib::reciprocal(k) * plib::signum(d) * plib::log1p(k * plib::abs(d));
|
||||
Vgs = m_Vgs
|
||||
+ plib::reciprocal(k) * plib::signum(d)
|
||||
* plib::log1p(k * plib::abs(d));
|
||||
d = (Vgd - m_Vgd);
|
||||
Vgd = m_Vgd + plib::reciprocal(k) * plib::signum(d) * plib::log1p(k * plib::abs(d));
|
||||
Vgd = m_Vgd
|
||||
+ plib::reciprocal(k) * plib::signum(d)
|
||||
* plib::log1p(k * plib::abs(d));
|
||||
|
||||
m_Vgs = Vgs;
|
||||
m_Vgd = Vgd;
|
||||
|
||||
const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if connected
|
||||
//const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain = Source - Drain
|
||||
const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if
|
||||
// connected
|
||||
// const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain
|
||||
// = Source - Drain
|
||||
const nl_fptype Vds = Vgs - Vgd;
|
||||
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
|
||||
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
|
||||
|
||||
#if (!BODY_CONNECTED_TO_SOURCE)
|
||||
m_D_BS.update_diode(Vbs);
|
||||
@ -451,8 +493,11 @@ namespace netlist::analog
|
||||
|
||||
// calculate Vth
|
||||
const nl_fptype Vbulk = is_forward ? Vbs : Vbd;
|
||||
const nl_fptype phi_m_Vbulk = (m_phi > Vbulk) ? plib::sqrt(m_phi - Vbulk) : nlconst::zero();
|
||||
const nl_fptype Vth = m_vto * m_polarity + m_gamma * (phi_m_Vbulk - plib::sqrt(m_phi));
|
||||
const nl_fptype phi_m_Vbulk = (m_phi > Vbulk)
|
||||
? plib::sqrt(m_phi - Vbulk)
|
||||
: nlconst::zero();
|
||||
const nl_fptype Vth = m_vto * m_polarity
|
||||
+ m_gamma * (phi_m_Vbulk - plib::sqrt(m_phi));
|
||||
|
||||
const nl_fptype Vctrl = (is_forward ? Vgs : Vgd) - Vth;
|
||||
|
||||
@ -467,30 +512,36 @@ namespace netlist::analog
|
||||
{
|
||||
// cutoff region
|
||||
Ids = nlconst::zero();
|
||||
gm = nlconst::zero();
|
||||
gm = nlconst::zero();
|
||||
gds = nlconst::zero();
|
||||
gmb = nlconst::zero();
|
||||
}
|
||||
else
|
||||
{
|
||||
const nl_fptype beta = m_beta * (nlconst::one() + m_lambda * absVds);
|
||||
const nl_fptype beta = m_beta
|
||||
* (nlconst::one() + m_lambda * absVds);
|
||||
if (Vctrl <= absVds)
|
||||
{
|
||||
// saturation region
|
||||
Ids = beta * Vctrl * Vctrl / nlconst::two();
|
||||
gm = beta * Vctrl;
|
||||
gm = beta * Vctrl;
|
||||
gds = m_lambda * m_beta * Vctrl * Vctrl / nlconst::two();
|
||||
}
|
||||
else
|
||||
{
|
||||
// linear region
|
||||
Ids = beta * absVds * (Vctrl - absVds / nlconst::two());
|
||||
gm = beta * absVds;
|
||||
gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / nlconst::two());
|
||||
gm = beta * absVds;
|
||||
gds = beta * (Vctrl - absVds)
|
||||
+ m_lambda * m_beta * absVds
|
||||
* (Vctrl - absVds / nlconst::two());
|
||||
}
|
||||
|
||||
// back gate transconductance
|
||||
const nl_fptype bgtc = (phi_m_Vbulk != nlconst::zero()) ? (m_gamma / phi_m_Vbulk / nlconst::two()) : nlconst::zero();
|
||||
const nl_fptype bgtc = (phi_m_Vbulk != nlconst::zero())
|
||||
? (m_gamma / phi_m_Vbulk
|
||||
/ nlconst::two())
|
||||
: nlconst::zero();
|
||||
gmb = gm * bgtc;
|
||||
}
|
||||
|
||||
@ -512,11 +563,11 @@ namespace netlist::analog
|
||||
#endif
|
||||
// exchange controlling nodes if necessary
|
||||
const nl_fptype gate_source = is_forward ? (gm + gmb) : nlconst::zero();
|
||||
const nl_fptype gate_drain = is_forward ? nlconst::zero() : (gm + gmb);
|
||||
const nl_fptype gate_drain = is_forward ? nlconst::zero() : (gm + gmb);
|
||||
|
||||
const nl_fptype IeqDS = (is_forward) ?
|
||||
Ids - gm * Vgs - gmb * Vbs - gds * Vds
|
||||
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
|
||||
const nl_fptype IeqDS = (is_forward)
|
||||
? Ids - gm * Vgs - gmb * Vbs - gds * Vds
|
||||
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
|
||||
|
||||
// IG = 0
|
||||
nl_fptype IG = nlconst::zero();
|
||||
@ -529,20 +580,20 @@ namespace netlist::analog
|
||||
nl_fptype gGS = nlconst::zero();
|
||||
nl_fptype gGB = nlconst::zero();
|
||||
|
||||
nl_fptype gDG = gm;
|
||||
nl_fptype gDD = gds + gbd - gate_drain;
|
||||
nl_fptype gDG = gm;
|
||||
nl_fptype gDD = gds + gbd - gate_drain;
|
||||
const nl_fptype gDS = -gds - gate_source;
|
||||
const nl_fptype gDB = gmb - gbd;
|
||||
const nl_fptype gDB = gmb - gbd;
|
||||
|
||||
nl_fptype gSG = -gm;
|
||||
nl_fptype gSG = -gm;
|
||||
const nl_fptype gSD = -gds + gate_drain;
|
||||
nl_fptype gSS = gbs + gds + gate_source;
|
||||
nl_fptype gSS = gbs + gds + gate_source;
|
||||
const nl_fptype gSB = -gbs - gmb;
|
||||
|
||||
nl_fptype gBG = nlconst::zero();
|
||||
nl_fptype gBG = nlconst::zero();
|
||||
const nl_fptype gBD = -gbd;
|
||||
const nl_fptype gBS = -gbs;
|
||||
nl_fptype gBB = gbs + gbd;
|
||||
nl_fptype gBB = gbs + gbd;
|
||||
|
||||
if (m_capacitor_model != 0)
|
||||
{
|
||||
@ -553,23 +604,26 @@ namespace netlist::analog
|
||||
else
|
||||
calculate_caps(Vgd, Vgs, Vth, m_Cgd, m_Cgs, m_Cgb);
|
||||
|
||||
set_cap(m_cap_gb, m_Cgb + m_model_acc.m_CGBO * m_Leff, Vgb, gGG, gGB, gBG, gBB, IG, IB);
|
||||
set_cap(m_cap_gs, m_Cgs + m_model_acc.m_CGSO * m_model_acc.m_W, Vgs, gGG, gGS, gSG, gSS, IG, IS);
|
||||
set_cap(m_cap_gd, m_Cgd + m_model_acc.m_CGDO * m_model_acc.m_W, Vgd, gGG, gGD, gDG, gDD, IG, ID);
|
||||
set_cap(m_cap_gb, m_Cgb + m_model_acc.m_CGBO * m_Leff, Vgb, gGG,
|
||||
gGB, gBG, gBB, IG, IB);
|
||||
set_cap(m_cap_gs, m_Cgs + m_model_acc.m_CGSO * m_model_acc.m_W, Vgs,
|
||||
gGG, gGS, gSG, gSS, IG, IS);
|
||||
set_cap(m_cap_gd, m_Cgd + m_model_acc.m_CGDO * m_model_acc.m_W, Vgd,
|
||||
gGG, gGD, gDG, gDD, IG, ID);
|
||||
}
|
||||
|
||||
// Source connected to body, Diode S-B shorted!
|
||||
const nl_fptype gSSBB = gSS + gBB + gBS + gSB;
|
||||
const auto zero(nlconst::zero());
|
||||
const auto zero(nlconst::zero());
|
||||
// S G
|
||||
m_SG.set_mat( gSSBB, gSG + gBG, +(IS + IB), // S
|
||||
gGS + gGB, gGG, IG ); // G
|
||||
m_SG.set_mat(gSSBB, gSG + gBG, +(IS + IB), // S
|
||||
gGS + gGB, gGG, IG); // G
|
||||
// D G
|
||||
m_DG.set_mat( gDD, gDG, +ID, // D
|
||||
gGD, zero, zero ); // G
|
||||
m_DG.set_mat(gDD, gDG, +ID, // D
|
||||
gGD, zero, zero); // G
|
||||
// S D
|
||||
m_SD.set_mat( zero, gSD + gBD, zero, // S
|
||||
gDS + gDB, zero, zero ); // D
|
||||
m_SD.set_mat(zero, gSD + gBD, zero, // S
|
||||
gDS + gDB, zero, zero); // D
|
||||
|
||||
/// |
|
||||
/// | D S G I
|
||||
@ -600,13 +654,11 @@ namespace netlist::analog
|
||||
/// |
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(MOSFET)
|
||||
{
|
||||
}
|
||||
NETLIB_UPDATE_PARAM(MOSFET) {}
|
||||
|
||||
} // namespace netlist::analog
|
||||
|
||||
namespace netlist::devices {
|
||||
namespace netlist::devices
|
||||
{
|
||||
NETLIB_DEVICE_IMPL_NS(analog, MOSFET, "MOSFET", "MODEL")
|
||||
} // namespace netlist::devices
|
||||
|
||||
|
@ -125,7 +125,7 @@ namespace netlist::analog
|
||||
|
||||
NETLIB_TIMESTEP(L)
|
||||
{
|
||||
if (ts_type == time_step_type::FORWARD)
|
||||
if (ts_type == detail::time_step_type::FORWARD)
|
||||
{
|
||||
m_last_I = m_I;
|
||||
m_last_G = m_G;
|
||||
|
@ -312,7 +312,7 @@ namespace netlist::analog
|
||||
NETLIB_IS_TIMESTEP(true)
|
||||
NETLIB_TIMESTEPI()
|
||||
{
|
||||
if (ts_type == time_step_type::FORWARD)
|
||||
if (ts_type == detail::time_step_type::FORWARD)
|
||||
{
|
||||
// G, Ieq
|
||||
const auto res(m_cap.time_step(m_C(), deltaV(), step));
|
||||
@ -584,7 +584,7 @@ namespace netlist::analog
|
||||
|
||||
NETLIB_TIMESTEPI()
|
||||
{
|
||||
if (ts_type == time_step_type::FORWARD)
|
||||
if (ts_type == detail::time_step_type::FORWARD)
|
||||
{
|
||||
m_t += step;
|
||||
m_funcparam[0] = m_t;
|
||||
@ -637,7 +637,7 @@ namespace netlist::analog
|
||||
NETLIB_IS_TIMESTEP(!m_func().empty())
|
||||
NETLIB_TIMESTEPI()
|
||||
{
|
||||
if (ts_type == time_step_type::FORWARD)
|
||||
if (ts_type == detail::time_step_type::FORWARD)
|
||||
{
|
||||
m_t += step;
|
||||
m_funcparam[0] = m_t;
|
||||
|
@ -25,13 +25,14 @@ BreakStringLiterals: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
# AfterComma does not work <= 13
|
||||
#BreakInheritanceList: AfterComma
|
||||
#BreakInheritanceList: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
#BreakInheritanceList: false
|
||||
SpaceBeforeInheritanceColon: true
|
||||
|
||||
#AlignAfterOpenBracket: DontAlign
|
||||
AlignAfterOpenBracket: Align
|
||||
PointerAlignment: Right
|
||||
ReferenceAlignment: Right
|
||||
SpacesInAngles: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
@ -90,16 +91,17 @@ StatementMacros:
|
||||
TypenameMacros:
|
||||
- "NETLIST_NAME"
|
||||
- "NETLIB_NAME"
|
||||
- "PENUM"
|
||||
|
||||
WhitespaceSensitiveMacros:
|
||||
- "ALIAS"
|
||||
- "NET_C"
|
||||
- "DIPPINS"
|
||||
- "NET_C"
|
||||
- "PENUM"
|
||||
|
||||
IndentPPDirectives: BeforeHash
|
||||
MacroBlockBegin: "^static NETLIST_START\\(.+\\)|static TRUTHTABLE_START\\(.*\\)$"
|
||||
MacroBlockEnd: "^NETLIST_END\\(\\)|TRUTHTABLE_END\\(\\)$"
|
||||
# ReferenceAlignment: Middle
|
||||
|
||||
# Avoid formatting
|
||||
# -- clang-tidy
|
||||
|
@ -19,6 +19,7 @@
|
||||
"Schmitt",
|
||||
"Schottky",
|
||||
"Zener",
|
||||
"Thevenin",
|
||||
// Company names
|
||||
"Fairchild",
|
||||
"Signetics",
|
||||
@ -69,6 +70,7 @@
|
||||
// FIXME: Remove everything below here again
|
||||
// Excluded for now ... Still over 1000 in the log
|
||||
"plib", // namespace
|
||||
"isnull",
|
||||
"pstring",
|
||||
"passert",
|
||||
"putf",
|
||||
@ -79,6 +81,8 @@
|
||||
"idrn",
|
||||
"preprocessor",
|
||||
"ppreprocessor",
|
||||
"psource",
|
||||
"psemaphore",
|
||||
"modacc",
|
||||
"Ainv",
|
||||
"anetlist",
|
||||
|
@ -114,7 +114,7 @@ TIDY_DB = $(OBJ)/compile_commands.json
|
||||
#LTO decreases performance :-(
|
||||
#LTO = -flto=4 -fuse-linker-plugin -Wodr
|
||||
|
||||
CCOREFLAGS = -g -O3 -std=c++17 -I$(SRC) -I$(SRC)/.. -I$(SRC)/../..
|
||||
CCOREFLAGS = -g -O3 -std=c++17 -I$(SRC)
|
||||
|
||||
CFLAGS = $(LTO) $(CCOREFLAGS) $(CEXTRAFLAGS)
|
||||
LDFLAGS = $(LTO) -g -O3 -std=c++17 $(LDEXTRAFLAGS)
|
||||
|
@ -17,9 +17,19 @@
|
||||
#include "../plib/pexception.h"
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pmempool.h"
|
||||
#include "../plib/ppmf.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
/// \brief Delegate type for device notification.
|
||||
///
|
||||
using nl_delegate = plib::pmfp<void()>;
|
||||
using nl_delegate_ts = plib::pmfp<void(detail::time_step_type, nl_fptype)>;
|
||||
using nl_delegate_dyn = plib::pmfp<void()>;
|
||||
} // namespace netlist
|
||||
|
||||
namespace netlist::detail
|
||||
{
|
||||
|
||||
@ -131,16 +141,16 @@ namespace netlist::detail
|
||||
|
||||
PCOPYASSIGNMOVE(netlist_object_t, delete)
|
||||
|
||||
netlist_state_t & state() noexcept;
|
||||
netlist_state_t &state() noexcept;
|
||||
const netlist_state_t &state() const noexcept;
|
||||
|
||||
constexpr netlist_t & exec() noexcept { return m_netlist; }
|
||||
constexpr netlist_t &exec() noexcept { return m_netlist; }
|
||||
constexpr const netlist_t &exec() const noexcept { return m_netlist; }
|
||||
|
||||
// to ease template design
|
||||
template <typename T, typename... Args>
|
||||
device_arena::unique_ptr<T> make_pool_object(Args &&...args) noexcept(
|
||||
false)
|
||||
device_arena::unique_ptr<T>
|
||||
make_pool_object(Args &&...args) noexcept(false)
|
||||
{
|
||||
return state().make_pool_object<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
@ -174,13 +184,13 @@ namespace netlist::detail
|
||||
/// \brief returns reference to owning device.
|
||||
/// \returns reference to owning device.
|
||||
|
||||
core_device_t & device() noexcept { return *m_device; }
|
||||
core_device_t &device() noexcept { return *m_device; }
|
||||
const core_device_t &device() const noexcept { return *m_device; }
|
||||
|
||||
/// \brief The netlist owning the owner of this object.
|
||||
/// \returns reference to netlist object.
|
||||
|
||||
netlist_state_t & state() noexcept;
|
||||
netlist_state_t &state() noexcept;
|
||||
const netlist_state_t &state() const noexcept;
|
||||
|
||||
private:
|
||||
@ -218,7 +228,7 @@ namespace netlist::detail
|
||||
static constexpr netlist_sig_t OUT_TRISTATE() { return INP_MASK; }
|
||||
|
||||
static_assert(INP_BITS * 2 <= sizeof(netlist_sig_t) * 8,
|
||||
"netlist_sig_t size not sufficient");
|
||||
"netlist_sig_t size not sufficient");
|
||||
|
||||
enum state_e
|
||||
{
|
||||
@ -231,7 +241,7 @@ namespace netlist::detail
|
||||
};
|
||||
|
||||
core_terminal_t(core_device_t &dev, const pstring &aname, state_e state,
|
||||
nl_delegate delegate);
|
||||
nl_delegate delegate);
|
||||
virtual ~core_terminal_t() noexcept = default;
|
||||
|
||||
PCOPYASSIGNMOVE(core_terminal_t, delete)
|
||||
@ -271,12 +281,12 @@ namespace netlist::detail
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
set_state(
|
||||
is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE);
|
||||
set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT
|
||||
: STATE_INP_ACTIVE);
|
||||
}
|
||||
|
||||
constexpr void set_copied_input(
|
||||
[[maybe_unused]] netlist_sig_t val) noexcept
|
||||
constexpr void
|
||||
set_copied_input([[maybe_unused]] netlist_sig_t val) noexcept
|
||||
{
|
||||
if constexpr (config::use_copy_instead_of_reference::value)
|
||||
{
|
||||
@ -298,7 +308,7 @@ namespace netlist::detail
|
||||
|
||||
private:
|
||||
nl_delegate m_delegate;
|
||||
net_t * m_net;
|
||||
net_t *m_net;
|
||||
state_var<state_e> m_state;
|
||||
};
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace netlist
|
||||
friend class factory::device_element_t;
|
||||
friend class factory::library_element_t;
|
||||
|
||||
template <typename CX>
|
||||
template <typename DEVICE>
|
||||
friend struct sub_device_wrapper;
|
||||
|
||||
friend class solver::matrix_solver_t;
|
||||
@ -103,7 +103,7 @@ namespace netlist
|
||||
log_type &log();
|
||||
|
||||
public:
|
||||
virtual void time_step([[maybe_unused]] time_step_type ts_type,
|
||||
virtual void time_step([[maybe_unused]] detail::time_step_type ts_type,
|
||||
[[maybe_unused]] nl_fptype st) noexcept
|
||||
{
|
||||
}
|
||||
|
@ -73,40 +73,42 @@ namespace netlist
|
||||
// FIXME: Rename
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <typename CX>
|
||||
template <typename DEVICE>
|
||||
struct sub_device_wrapper
|
||||
{
|
||||
using constructor_data_t = typename CX::constructor_data_t;
|
||||
using constructor_param_t = typename CX::constructor_param_t;
|
||||
using constructor_data_t = typename DEVICE::constructor_data_t;
|
||||
using constructor_param_t = typename DEVICE::constructor_param_t;
|
||||
|
||||
template <typename... Args>
|
||||
sub_device_wrapper(base_device_t &owner, const pstring &name,
|
||||
Args &&...args)
|
||||
Args &&...args)
|
||||
{
|
||||
// m_dev = owner.state().make_pool_object<CX>(owner, name,
|
||||
// m_dev = owner.state().make_pool_object<DEVICE>(owner, name,
|
||||
// std::forward<Args>(args)...);
|
||||
m_dev = owner.state().make_pool_object<CX>(
|
||||
m_dev = owner.state().make_pool_object<DEVICE>(
|
||||
constructor_data_t{owner.state(), owner.name() + "." + name},
|
||||
std::forward<Args>(args)...);
|
||||
owner.state().register_device(m_dev->name(),
|
||||
owner.state().register_device(
|
||||
m_dev->name(),
|
||||
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
|
||||
}
|
||||
template <typename... Args>
|
||||
sub_device_wrapper(device_t &owner, const pstring &name, Args &&...args)
|
||||
{
|
||||
// m_dev = owner.state().make_pool_object<CX>(owner, name,
|
||||
// m_dev = owner.state().make_pool_object<DEVICE>(owner, name,
|
||||
// std::forward<Args>(args)...);
|
||||
m_dev = owner.state().make_pool_object<CX>(
|
||||
m_dev = owner.state().make_pool_object<DEVICE>(
|
||||
constructor_data_t{owner.state(), owner.name() + "." + name},
|
||||
std::forward<Args>(args)...);
|
||||
owner.state().register_device(m_dev->name(),
|
||||
owner.state().register_device(
|
||||
m_dev->name(),
|
||||
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
|
||||
}
|
||||
CX & operator()() { return *m_dev; }
|
||||
const CX &operator()() const { return *m_dev; }
|
||||
DEVICE & operator()() { return *m_dev; }
|
||||
const DEVICE &operator()() const { return *m_dev; }
|
||||
|
||||
private:
|
||||
device_arena::unique_ptr<CX> m_dev;
|
||||
device_arena::unique_ptr<DEVICE> m_dev;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
@ -107,7 +107,7 @@ public: \
|
||||
|
||||
#define NETLIB_TIMESTEPI() \
|
||||
public: \
|
||||
virtual void time_step(time_step_type ts_type, \
|
||||
virtual void time_step(detail::time_step_type ts_type, \
|
||||
nl_fptype step) noexcept override
|
||||
|
||||
/// \brief Used to implement the body of the time stepping code.
|
||||
@ -119,7 +119,7 @@ public: \
|
||||
/// \param cname Name of object as given to \ref NETLIB_OBJECT
|
||||
///
|
||||
#define NETLIB_TIMESTEP(cname) \
|
||||
void NETLIB_NAME(cname)::time_step(time_step_type ts_type, \
|
||||
void NETLIB_NAME(cname)::time_step(detail::time_step_type ts_type, \
|
||||
nl_fptype step) noexcept
|
||||
|
||||
//#define NETLIB_DELEGATE(name) nl_delegate(&this_type :: name, this)
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "../plib/palloc.h"
|
||||
#include "../plib/pmempool.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "queue.h"
|
||||
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pmempool.h"
|
||||
#include "../plib/pstate.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
@ -31,8 +32,8 @@ namespace netlist
|
||||
public:
|
||||
using nets_collection_type = std::vector<
|
||||
device_arena::owned_ptr<detail::net_t>>;
|
||||
using family_collection_type = std::unordered_map<pstring,
|
||||
host_arena::unique_ptr<logic_family_desc_t>>;
|
||||
using family_collection_type = std::unordered_map<
|
||||
pstring, host_arena::unique_ptr<logic_family_desc_t>>;
|
||||
|
||||
// need to preserve order of device creation ...
|
||||
using devices_collection_type = std::vector<
|
||||
@ -55,8 +56,9 @@ namespace netlist
|
||||
return bool(plib::dynamic_downcast<C *>(p));
|
||||
}
|
||||
|
||||
core_device_t *get_single_device(const pstring &classname,
|
||||
bool (*cc)(core_device_t *)) const noexcept(false);
|
||||
core_device_t *
|
||||
get_single_device(const pstring &classname,
|
||||
bool (*cc)(core_device_t *)) const noexcept(false);
|
||||
|
||||
/// \brief Get single device filtered by class and name
|
||||
///
|
||||
@ -91,7 +93,7 @@ namespace netlist
|
||||
|
||||
// logging
|
||||
|
||||
log_type & log() noexcept { return m_log; }
|
||||
log_type &log() noexcept { return m_log; }
|
||||
const log_type &log() const noexcept { return m_log; }
|
||||
|
||||
plib::dynamic_library_base &static_solver_lib() const noexcept
|
||||
@ -108,23 +110,23 @@ namespace netlist
|
||||
void set_static_solver_lib(
|
||||
std::unique_ptr<plib::dynamic_library_base> &&lib);
|
||||
|
||||
netlist_t & exec() noexcept { return *m_netlist; }
|
||||
netlist_t &exec() noexcept { return *m_netlist; }
|
||||
const netlist_t &exec() const noexcept { return *m_netlist; }
|
||||
|
||||
// state handling
|
||||
plib::state_manager_t &run_state_manager() noexcept { return m_state; }
|
||||
|
||||
template <typename O, typename C>
|
||||
void save(O &owner, C &state, const pstring &module,
|
||||
const pstring &stname)
|
||||
void
|
||||
save(O &owner, C &state, const pstring &module, const pstring &stname)
|
||||
{
|
||||
this->run_state_manager().save_item(plib::void_ptr_cast(&owner),
|
||||
state, module + "." + stname);
|
||||
state, module + "." + stname);
|
||||
}
|
||||
|
||||
template <typename O, typename C>
|
||||
void save(O &owner, C *state, const pstring &module,
|
||||
const pstring &stname, const std::size_t count)
|
||||
const pstring &stname, const std::size_t count)
|
||||
{
|
||||
this->run_state_manager().save_state_ptr(
|
||||
plib::void_ptr_cast(&owner), module + "." + stname,
|
||||
@ -165,8 +167,8 @@ namespace netlist
|
||||
/// \param dev Device to be registered
|
||||
|
||||
template <typename T>
|
||||
void register_device(const pstring &name,
|
||||
device_arena::owned_ptr<T> && dev) noexcept(false)
|
||||
void register_device(const pstring &name,
|
||||
device_arena::owned_ptr<T> &&dev) noexcept(false)
|
||||
{
|
||||
for (auto &d : m_devices)
|
||||
if (d.first == name)
|
||||
@ -187,11 +189,11 @@ namespace netlist
|
||||
/// \param dev Device to be registered
|
||||
|
||||
template <typename T>
|
||||
void register_device(const pstring &name,
|
||||
device_arena::unique_ptr<T> && dev)
|
||||
void
|
||||
register_device(const pstring &name, device_arena::unique_ptr<T> &&dev)
|
||||
{
|
||||
register_device(name, device_arena::owned_ptr<T>(dev.release(),
|
||||
true, dev.get_deleter()));
|
||||
register_device(name, device_arena::owned_ptr<T>(
|
||||
dev.release(), true, dev.get_deleter()));
|
||||
}
|
||||
|
||||
/// \brief Remove device
|
||||
@ -203,24 +205,24 @@ namespace netlist
|
||||
|
||||
void remove_device(core_device_t *dev);
|
||||
|
||||
setup_t & setup() noexcept { return *m_setup; }
|
||||
setup_t &setup() noexcept { return *m_setup; }
|
||||
const setup_t &setup() const noexcept { return *m_setup; }
|
||||
|
||||
nlparse_t & parser() noexcept;
|
||||
nlparse_t &parser() noexcept;
|
||||
const nlparse_t &parser() const noexcept;
|
||||
|
||||
// FIXME: make a post load member and include code there
|
||||
void rebuild_lists(); // must be called after post_load !
|
||||
|
||||
static void compile_defines(
|
||||
std::vector<std::pair<pstring, pstring>> &defs);
|
||||
static void
|
||||
compile_defines(std::vector<std::pair<pstring, pstring>> &defs);
|
||||
static pstring version();
|
||||
static pstring version_patchlevel();
|
||||
|
||||
nets_collection_type & nets() noexcept { return m_nets; }
|
||||
nets_collection_type &nets() noexcept { return m_nets; }
|
||||
const nets_collection_type &nets() const noexcept { return m_nets; }
|
||||
|
||||
devices_collection_type & devices() noexcept { return m_devices; }
|
||||
devices_collection_type &devices() noexcept { return m_devices; }
|
||||
const devices_collection_type &devices() const noexcept
|
||||
{
|
||||
return m_devices;
|
||||
@ -234,13 +236,13 @@ namespace netlist
|
||||
return plib::make_unique<T>(m_pool, std::forward<Args>(args)...);
|
||||
}
|
||||
// memory pool - still needed in some places
|
||||
device_arena & pool() noexcept { return m_pool; }
|
||||
device_arena &pool() noexcept { return m_pool; }
|
||||
const device_arena &pool() const noexcept { return m_pool; }
|
||||
|
||||
struct stats_info
|
||||
{
|
||||
const detail::queue_t & m_queue; // performance
|
||||
const plib::pperftime_t<true> & m_stat_mainloop;
|
||||
const detail::queue_t &m_queue; // performance
|
||||
const plib::pperftime_t<true> &m_stat_mainloop;
|
||||
const plib::pperfcount_t<true> &m_perf_out_processed;
|
||||
};
|
||||
|
||||
@ -256,8 +258,8 @@ namespace netlist
|
||||
///
|
||||
void free_setup_resources();
|
||||
#if !(NL_USE_INPLACE_CORE_TERMS)
|
||||
std::vector<detail::core_terminal_t *> &core_terms(
|
||||
const detail::net_t &net)
|
||||
std::vector<detail::core_terminal_t *> &
|
||||
core_terms(const detail::net_t &net)
|
||||
{
|
||||
return m_core_terms[&net];
|
||||
}
|
||||
@ -281,7 +283,7 @@ namespace netlist
|
||||
#if !(NL_USE_INPLACE_CORE_TERMS)
|
||||
// all terms for a net
|
||||
std::unordered_map<const detail::net_t *,
|
||||
std::vector<detail::core_terminal_t *>>
|
||||
std::vector<detail::core_terminal_t *>>
|
||||
m_core_terms;
|
||||
#endif
|
||||
// dummy version
|
||||
|
@ -8,8 +8,12 @@
|
||||
#ifndef NL_CORE_OBJECT_ARRAY_H_
|
||||
#define NL_CORE_OBJECT_ARRAY_H_
|
||||
|
||||
#include "base_objects.h"
|
||||
#include "logic.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "../plib/pfmtlog.h"
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "../plib/pfmtlog.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
|
@ -78,7 +78,7 @@ namespace netlist::devices {
|
||||
}
|
||||
else
|
||||
{
|
||||
newstate_setreset(set, reset);
|
||||
set_reset(set, reset);
|
||||
m_CLK.inactivate();
|
||||
m_D.inactivate();
|
||||
}
|
||||
@ -86,7 +86,7 @@ namespace netlist::devices {
|
||||
|
||||
NETLIB_HANDLERI(clk)
|
||||
{
|
||||
newstate_clk(m_nextD);
|
||||
set_output(m_nextD);
|
||||
m_CLK.inactivate();
|
||||
}
|
||||
|
||||
@ -101,14 +101,14 @@ namespace netlist::devices {
|
||||
|
||||
nld_power_pins m_power_pins;
|
||||
|
||||
void newstate_clk(const netlist_sig_t stateQ)
|
||||
void set_output(const netlist_sig_t stateQ)
|
||||
{
|
||||
static constexpr auto delay = NLTIME_FROM_NS(150);
|
||||
static constexpr const auto delay = NLTIME_FROM_NS(150);
|
||||
m_Q.push(stateQ, delay);
|
||||
m_QQ.push(!stateQ, delay);
|
||||
}
|
||||
|
||||
void newstate_setreset(const netlist_sig_t stateQ, const netlist_sig_t stateQQ)
|
||||
void set_reset(const netlist_sig_t stateQ, const netlist_sig_t stateQQ)
|
||||
{
|
||||
// Q: 150 ns, QQ: 200 ns
|
||||
static constexpr const std::array<netlist_time, 2> delay = { NLTIME_FROM_NS(150), NLTIME_FROM_NS(200) };
|
||||
|
@ -17,6 +17,7 @@
|
||||
namespace netlist
|
||||
{
|
||||
// nothing in here. This should not change.
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
#endif // NLBASE_H_
|
||||
|
@ -134,7 +134,7 @@ namespace netlist
|
||||
/// brief default minimum alignment of mempool_arena
|
||||
///
|
||||
/// 256 is the best compromise between logic applications like MAME
|
||||
/// TTL games (e.g. pong) and analog applications like e.g. kidnikik
|
||||
/// TTL games (e.g. pong) and analog applications like e.g. kidniki
|
||||
/// sound.
|
||||
///
|
||||
/// Best performance for pong is achieved with a value of 16, but this
|
||||
@ -178,7 +178,7 @@ namespace netlist
|
||||
/// | 63 | 1,000,000,000,000 | 9,223,372 | 107| 0.3 |
|
||||
///
|
||||
using INTERNAL_RES = std::integral_constant<long long int,
|
||||
10'000'000'000LL>; // NOLINT
|
||||
10'000'000'000LL>; // NOLINT
|
||||
|
||||
/// \brief Recommended clock to be used
|
||||
///
|
||||
@ -187,7 +187,7 @@ namespace netlist
|
||||
/// contains code illustrating how to deal with remainders if \ref
|
||||
/// INTERNAL_RES is bigger than NETLIST_CLOCK.
|
||||
using DEFAULT_CLOCK = std::integral_constant<int,
|
||||
1'000'000'000>; // NOLINT
|
||||
1'000'000'000>; // NOLINT
|
||||
|
||||
/// \brief Default logic family
|
||||
///
|
||||
@ -196,27 +196,27 @@ namespace netlist
|
||||
/// \brief Maximum queue size
|
||||
///
|
||||
using max_queue_size = std::integral_constant<std::size_t,
|
||||
1024>; // NOLINT
|
||||
1024>; // NOLINT
|
||||
|
||||
/// \brief Maximum queue size for solvers
|
||||
///
|
||||
using max_solver_queue_size = std::integral_constant<std::size_t,
|
||||
512>; // NOLINT
|
||||
512>; // NOLINT
|
||||
|
||||
/// \brief Support float type for matrix calculations.
|
||||
///
|
||||
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
||||
using use_float_matrix = std::integral_constant<bool,
|
||||
NL_USE_ACADEMIC_SOLVERS>;
|
||||
using use_float_matrix = std::integral_constant<
|
||||
bool, NL_USE_ACADEMIC_SOLVERS>;
|
||||
|
||||
/// \brief Support long double type for matrix calculations.
|
||||
///
|
||||
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
||||
using use_long_double_matrix = std::integral_constant<bool,
|
||||
NL_USE_ACADEMIC_SOLVERS>;
|
||||
using use_long_double_matrix = std::integral_constant<
|
||||
bool, NL_USE_ACADEMIC_SOLVERS>;
|
||||
|
||||
using use_float128_matrix = std::integral_constant<bool,
|
||||
NL_USE_FLOAT128>;
|
||||
NL_USE_FLOAT128>;
|
||||
|
||||
/// \brief Floating point types used
|
||||
///
|
||||
@ -242,7 +242,7 @@ namespace netlist
|
||||
/// the default approach. It is ~20% slower.
|
||||
///
|
||||
using use_copy_instead_of_reference = std::integral_constant<bool,
|
||||
false>;
|
||||
false>;
|
||||
|
||||
/// \brief Avoid unnecessary queue pushes
|
||||
///
|
||||
@ -416,16 +416,4 @@ namespace netlist
|
||||
#endif
|
||||
} // namespace netlist
|
||||
|
||||
//============================================================
|
||||
// Asserts
|
||||
//============================================================
|
||||
|
||||
#define nl_assert(x) \
|
||||
do \
|
||||
{ \
|
||||
if (NL_DEBUG) \
|
||||
passert_always(x); \
|
||||
} while (0)
|
||||
#define nl_assert_always(x, msg) passert_always_msg(x, msg)
|
||||
|
||||
#endif // NLCONFIG_H_
|
||||
|
@ -8,13 +8,53 @@
|
||||
#ifndef NL_ERRSTR_H_
|
||||
#define NL_ERRSTR_H_
|
||||
|
||||
#include "plib/pexception.h"
|
||||
#include "plib/pfmtlog.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
|
||||
static constexpr const char sHINT_NO_DEACTIVATE[] = ".HINT_NO_DEACTIVATE"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
static constexpr const char sHINT_NC[] = ".HINT_NC"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
static constexpr const char sHINT_NO_DEACTIVATE[]
|
||||
= ".HINT_NO_DEACTIVATE"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
static constexpr const char sHINT_NC[]
|
||||
= ".HINT_NC"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Exceptions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// \brief Generic netlist exception.
|
||||
/// The exception is used in all events which are considered fatal.
|
||||
|
||||
class nl_exception : public plib::pexception
|
||||
{
|
||||
public:
|
||||
/// \brief Constructor.
|
||||
/// Allows a descriptive text to be passed to the exception
|
||||
|
||||
explicit nl_exception(const pstring &text //!< text to be passed
|
||||
)
|
||||
: plib::pexception(text)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief Constructor.
|
||||
/// Allows to use \ref plib::pfmt logic to be used in exception
|
||||
|
||||
template <typename... Args>
|
||||
explicit nl_exception(const pstring &fmt, //!< format to be used
|
||||
Args &&...args //!< arguments to be passed
|
||||
)
|
||||
: plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Error messages
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// clang-format off
|
||||
|
||||
// nl_base.cpp
|
||||
|
||||
@ -187,9 +227,19 @@ namespace netlist
|
||||
|
||||
PERRMSGV(MF_FILE_OPEN_ERROR, 1, "Error opening file: {1}")
|
||||
|
||||
|
||||
|
||||
// clang-format on
|
||||
} // namespace netlist
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Asserts
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
#define nl_assert(x) \
|
||||
do \
|
||||
{ \
|
||||
if (NL_DEBUG) \
|
||||
passert_always(x); \
|
||||
} while (0)
|
||||
#define nl_assert_always(x, msg) passert_always_msg(x, msg)
|
||||
|
||||
#endif // NL_ERRSTR_H_
|
||||
|
@ -8,14 +8,14 @@
|
||||
#ifndef NLSETUP_H_
|
||||
#define NLSETUP_H_
|
||||
|
||||
#include "nl_config.h"
|
||||
#include "nltypes.h"
|
||||
|
||||
#include "plib/ppreprocessor.h"
|
||||
#include "plib/psource.h"
|
||||
#include "plib/pstream.h"
|
||||
#include "plib/pstring.h"
|
||||
|
||||
#include "nl_config.h"
|
||||
#include "nltypes.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
@ -26,118 +26,95 @@
|
||||
// MACROS - netlist definitions
|
||||
//============================================================
|
||||
|
||||
#define NET_STR(x) # x
|
||||
#define NET_STR(x) #x
|
||||
|
||||
#define NET_MODEL(model) \
|
||||
setup.register_model(model);
|
||||
#define NET_MODEL(model) setup.register_model(model);
|
||||
|
||||
#define ALIAS(alias, name) \
|
||||
setup.register_alias(# alias, # name);
|
||||
#define ALIAS(alias, name) setup.register_alias(#alias, #name);
|
||||
|
||||
#define DIPPINS(pin1, ...) \
|
||||
setup.register_dip_alias_arr( # pin1 ", " # __VA_ARGS__);
|
||||
setup.register_dip_alias_arr(#pin1 ", " #__VA_ARGS__);
|
||||
|
||||
// to be used to reference new library truth table devices
|
||||
#define NET_REGISTER_DEV(type, name) \
|
||||
setup.register_dev(# type, # name);
|
||||
#define NET_REGISTER_DEV(type, name) setup.register_dev(#type, #name);
|
||||
|
||||
// name is first element so that __VA_ARGS__ always has one element
|
||||
#define NET_REGISTER_DEVEXT(type, ...) \
|
||||
setup.register_dev(# type, { PSTRINGIFY_VA(__VA_ARGS__) });
|
||||
#define NET_REGISTER_DEVEXT(type, ...) \
|
||||
setup.register_dev(#type, {PSTRINGIFY_VA(__VA_ARGS__)});
|
||||
|
||||
#define NET_CONNECT(name, input, output) \
|
||||
setup.register_link(# name "." # input, # output);
|
||||
setup.register_link(#name "." #input, #output);
|
||||
|
||||
#define NET_C(term1, ...) \
|
||||
setup.register_connection_arr( # term1 ", " # __VA_ARGS__);
|
||||
setup.register_connection_arr(#term1 ", " #__VA_ARGS__);
|
||||
|
||||
#define PARAM(name, val) \
|
||||
setup.register_param(NET_STR(name), NET_STR(val));
|
||||
#define PARAM(name, val) setup.register_param(NET_STR(name), NET_STR(val));
|
||||
|
||||
#define DEFPARAM(name, val) \
|
||||
setup.register_default_param(NET_STR(name), NET_STR(val));
|
||||
setup.register_default_param(NET_STR(name), NET_STR(val));
|
||||
|
||||
#define HINT(name, val) \
|
||||
setup.register_hint(# name , ".HINT_" # val);
|
||||
#define HINT(name, val) setup.register_hint(#name, ".HINT_" #val);
|
||||
|
||||
#define NETDEV_PARAMI(name, param, val) \
|
||||
setup.register_param(# name "." # param, val);
|
||||
setup.register_param(#name "." #param, val);
|
||||
|
||||
#define NETLIST_NAME(name) netlist ## _ ## name
|
||||
#define NETLIST_NAME(name) netlist##_##name
|
||||
|
||||
#define NETLIST_EXTERNAL(name) \
|
||||
void NETLIST_NAME(name)(netlist::nlparse_t &setup);
|
||||
void NETLIST_NAME(name)(netlist::nlparse_t & setup);
|
||||
|
||||
#define NETLIST_START(name) \
|
||||
void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
|
||||
void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t & setup)
|
||||
|
||||
#define LOCAL_SOURCE(name) \
|
||||
setup.register_source_proc(# name, &NETLIST_NAME(name));
|
||||
setup.register_source_proc(#name, &NETLIST_NAME(name));
|
||||
|
||||
#define EXTERNAL_SOURCE(name) \
|
||||
setup.register_source_proc(# name, &NETLIST_NAME(name));
|
||||
setup.register_source_proc(#name, &NETLIST_NAME(name));
|
||||
|
||||
#define LOCAL_LIB_ENTRY_2(type, name) \
|
||||
type ## _SOURCE(name) \
|
||||
setup.register_lib_entry(# name, "", PSOURCELOC());
|
||||
type##_SOURCE(name) setup.register_lib_entry(#name, "", PSOURCELOC());
|
||||
|
||||
#define LOCAL_LIB_ENTRY_3(type, name, param_spec) \
|
||||
type ## _SOURCE(name) \
|
||||
setup.register_lib_entry(# name, param_spec, PSOURCELOC());
|
||||
type##_SOURCE(name) \
|
||||
setup.register_lib_entry(#name, param_spec, PSOURCELOC());
|
||||
|
||||
#define LOCAL_LIB_ENTRY(...) PCALLVARARG(LOCAL_LIB_ENTRY_, LOCAL, __VA_ARGS__)
|
||||
|
||||
#define EXTERNAL_LIB_ENTRY(...) PCALLVARARG(LOCAL_LIB_ENTRY_, EXTERNAL, __VA_ARGS__)
|
||||
#define EXTERNAL_LIB_ENTRY(...) \
|
||||
PCALLVARARG(LOCAL_LIB_ENTRY_, EXTERNAL, __VA_ARGS__)
|
||||
|
||||
#define INCLUDE(name) \
|
||||
setup.include(# name);
|
||||
#define INCLUDE(name) setup.include(#name);
|
||||
|
||||
#define SUBMODEL(model, name) \
|
||||
setup.namespace_push(# name); \
|
||||
setup.include(# model); \
|
||||
setup.namespace_pop();
|
||||
setup.namespace_push(#name); \
|
||||
setup.include(#model); \
|
||||
setup.namespace_pop();
|
||||
|
||||
#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \
|
||||
setup.register_frontier(# attach, PSTRINGIFY_VA(r_in), PSTRINGIFY_VA(r_out));
|
||||
setup.register_frontier(#attach, PSTRINGIFY_VA(r_in), PSTRINGIFY_VA(r_out));
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// truth table defines
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
#define TRUTHTABLE_START(cname, in, out, pdef_params) \
|
||||
void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc); \
|
||||
static NETLIST_START(cname)
|
||||
{ \
|
||||
netlist::tt_desc xdesc{ #cname, in, out, "" }; \
|
||||
auto sloc = PSOURCELOC(); \
|
||||
const pstring def_params = pdef_params; \
|
||||
NETLIST_NAME(cname ## _impl)(xdesc); \
|
||||
setup.truth_table_create(xdesc, def_params, std::move(sloc)); \
|
||||
} \
|
||||
static void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc) \
|
||||
{
|
||||
#else
|
||||
#define TRUTH_TABLE(cname, in, out, pdef_params) \
|
||||
void NETLIST_NAME(cname ## _impl)(netlist::nlparse_t &setup, netlist::tt_desc &desc); \
|
||||
static void NETLIST_NAME(cname)(netlist::nlparse_t &setup) \
|
||||
{ \
|
||||
netlist::tt_desc desc{ #cname, in, out, "", {} }; \
|
||||
NETLIST_NAME(cname ## _impl)(setup, desc); \
|
||||
setup.truth_table_create(desc, pdef_params, PSOURCELOC()); \
|
||||
} \
|
||||
static void NETLIST_NAME(cname ## _impl)([[maybe_unused]] netlist::nlparse_t &setup, netlist::tt_desc &desc) \
|
||||
#define TRUTH_TABLE(cname, in, out, params) \
|
||||
void NETLIST_NAME(cname##_impl)(netlist::nlparse_t & setup, \
|
||||
netlist::tt_desc & desc); \
|
||||
static void NETLIST_NAME(cname)(netlist::nlparse_t & setup) \
|
||||
{ \
|
||||
netlist::tt_desc desc{#cname, in, out, "", {}}; \
|
||||
NETLIST_NAME(cname##_impl)(setup, desc); \
|
||||
setup.truth_table_create(desc, params, PSOURCELOC()); \
|
||||
} \
|
||||
static void NETLIST_NAME(cname##_impl)( \
|
||||
[[maybe_unused]] netlist::nlparse_t & setup, netlist::tt_desc & desc)
|
||||
|
||||
#endif
|
||||
#define TT_HEAD(x) desc.desc.emplace_back(x);
|
||||
|
||||
#define TT_HEAD(x) \
|
||||
desc.desc.emplace_back(x);
|
||||
#define TT_LINE(x) desc.desc.emplace_back(x);
|
||||
|
||||
#define TT_LINE(x) \
|
||||
desc.desc.emplace_back(x);
|
||||
|
||||
#define TT_FAMILY(x) \
|
||||
desc.family = x;
|
||||
#define TT_FAMILY(x) desc.family = x;
|
||||
|
||||
#define TRUTHTABLE_ENTRY(name) \
|
||||
LOCAL_SOURCE(name) \
|
||||
@ -152,10 +129,10 @@ namespace netlist
|
||||
|
||||
struct tt_desc
|
||||
{
|
||||
pstring name;
|
||||
unsigned long ni;
|
||||
unsigned long no;
|
||||
pstring family;
|
||||
pstring name;
|
||||
unsigned long ni;
|
||||
unsigned long no;
|
||||
pstring family;
|
||||
std::vector<pstring> desc;
|
||||
};
|
||||
|
||||
@ -193,25 +170,29 @@ namespace netlist
|
||||
/// \param type the alias type see \ref alias_type
|
||||
/// \param alias the alias to be qualified
|
||||
/// \param points_to the pin aliased
|
||||
void register_alias(detail::alias_type type, const pstring &alias, const pstring &points_to);
|
||||
void register_alias(detail::alias_type type, const pstring &alias,
|
||||
const pstring &points_to);
|
||||
/// \brief Register an aliases where alias and references are fully qualified names
|
||||
/// \param type the alias type see \ref alias_type
|
||||
/// \param alias the alias to be qualified
|
||||
/// \param points_to the pin aliased
|
||||
void register_fqn_alias(detail::alias_type type, const pstring &alias, const pstring &points_to);
|
||||
void register_fqn_alias(detail::alias_type type, const pstring &alias,
|
||||
const pstring &points_to);
|
||||
void register_dip_alias_arr(const pstring &terms);
|
||||
|
||||
// last argument only needed by nltool
|
||||
void register_dev(const pstring &classname, const pstring &name,
|
||||
const std::vector<pstring> ¶ms_and_connections,
|
||||
factory::element_t **factory_element = nullptr);
|
||||
void register_dev(const pstring &classname, std::initializer_list<const char *> more_parameters);
|
||||
const std::vector<pstring> ¶ms_and_connections,
|
||||
factory::element_t **factory_element = nullptr);
|
||||
void register_dev(const pstring &classname,
|
||||
std::initializer_list<const char *> more_parameters);
|
||||
void register_dev(const pstring &classname, const pstring &name)
|
||||
{
|
||||
register_dev(classname, name, std::vector<pstring>());
|
||||
}
|
||||
|
||||
void register_hint(const pstring &object_name, const pstring &hint_name);
|
||||
void
|
||||
register_hint(const pstring &object_name, const pstring &hint_name);
|
||||
|
||||
void register_connection(const pstring &sin, const pstring &sout);
|
||||
void register_connection_arr(const pstring &terms);
|
||||
@ -230,20 +211,23 @@ namespace netlist
|
||||
register_param_fp(param, plib::narrow_cast<nl_fptype>(value));
|
||||
}
|
||||
|
||||
void register_lib_entry(const pstring &name, const pstring &def_params, plib::source_location &&loc);
|
||||
void register_lib_entry(const pstring &name, const pstring &def_params,
|
||||
plib::source_location &&loc);
|
||||
|
||||
void register_frontier(const pstring &attach, const pstring &r_IN, const pstring &r_OUT);
|
||||
void register_frontier(const pstring &attach, const pstring &r_IN,
|
||||
const pstring &r_OUT);
|
||||
|
||||
// register a source
|
||||
template <typename S, typename... Args>
|
||||
void register_source(Args&&... args)
|
||||
void register_source(Args &&...args)
|
||||
{
|
||||
m_sources.add_source<S>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void register_source_proc(const pstring &name, nlsetup_func func);
|
||||
|
||||
void truth_table_create(tt_desc &desc, const pstring &def_params, plib::source_location &&loc);
|
||||
void truth_table_create(tt_desc &desc, const pstring &def_params,
|
||||
plib::source_location &&loc);
|
||||
|
||||
// include other files
|
||||
|
||||
@ -256,17 +240,18 @@ namespace netlist
|
||||
|
||||
// FIXME: used by source_t - need a different approach at some time
|
||||
bool parse_stream(plib::istream_uptr &&in_stream, const pstring &name);
|
||||
bool parse_tokens(const plib::detail::token_store_t &tokens, const pstring &name);
|
||||
bool parse_tokens(const plib::detail::token_store_t &tokens,
|
||||
const pstring &name);
|
||||
|
||||
template <typename S, typename... Args>
|
||||
void add_include(Args&&... args)
|
||||
void add_include(Args &&...args)
|
||||
{
|
||||
m_includes.add_source<S>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void add_define(const pstring &def, const pstring &val)
|
||||
{
|
||||
m_defines.insert({ def, plib::ppreprocessor::define_t(def, val)});
|
||||
m_defines.insert({def, plib::ppreprocessor::define_t(def, val)});
|
||||
}
|
||||
|
||||
void add_define(const pstring &define);
|
||||
@ -274,10 +259,10 @@ namespace netlist
|
||||
// register a list of logs
|
||||
void register_dynamic_log_devices(const std::vector<pstring> &log_list);
|
||||
|
||||
factory::list_t &factory() noexcept;
|
||||
factory::list_t &factory() noexcept;
|
||||
const factory::list_t &factory() const noexcept;
|
||||
|
||||
log_type &log() noexcept { return m_log; }
|
||||
log_type &log() noexcept { return m_log; }
|
||||
const log_type &log() const noexcept { return m_log; }
|
||||
|
||||
plib::istream_uptr get_data_stream(const pstring &name);
|
||||
@ -285,23 +270,22 @@ namespace netlist
|
||||
private:
|
||||
pstring namespace_prefix() const;
|
||||
pstring build_fqn(const pstring &obj_name) const;
|
||||
void register_param_fp(const pstring ¶m, nl_fptype value);
|
||||
bool device_exists(const pstring &name) const;
|
||||
void register_param_fp(const pstring ¶m, nl_fptype value);
|
||||
bool device_exists(const pstring &name) const;
|
||||
|
||||
// FIXME: stale? - remove later
|
||||
void remove_connections(const pstring &pin);
|
||||
|
||||
plib::ppreprocessor::defines_map_type m_defines;
|
||||
plib::psource_collection_t m_includes;
|
||||
std::stack<pstring> m_namespace_stack;
|
||||
plib::psource_collection_t m_sources;
|
||||
detail::abstract_t & m_abstract;
|
||||
plib::ppreprocessor::defines_map_type m_defines;
|
||||
plib::psource_collection_t m_includes;
|
||||
std::stack<pstring> m_namespace_stack;
|
||||
plib::psource_collection_t m_sources;
|
||||
detail::abstract_t &m_abstract;
|
||||
|
||||
log_type &m_log;
|
||||
unsigned m_frontier_cnt;
|
||||
unsigned m_frontier_cnt;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NLSETUP_H_
|
||||
|
@ -14,9 +14,6 @@
|
||||
|
||||
#include "nl_config.h"
|
||||
|
||||
#include "plib/pmempool.h"
|
||||
#include "plib/ppmf.h"
|
||||
#include "plib/pstring.h"
|
||||
#include "plib/ptime.h"
|
||||
#include "plib/ptypes.h"
|
||||
|
||||
@ -170,12 +167,12 @@ namespace netlist
|
||||
///
|
||||
/// \note This is not the right location yet.
|
||||
///
|
||||
|
||||
using device_arena = std::conditional_t<
|
||||
config::use_mempool::value,
|
||||
plib::mempool_arena<plib::aligned_arena<>,
|
||||
config::mempool_align::value>,
|
||||
plib::aligned_arena<>>;
|
||||
|
||||
using host_arena = plib::aligned_arena<>;
|
||||
|
||||
using log_type = plib::plog_base<NL_DEBUG>;
|
||||
@ -184,25 +181,19 @@ namespace netlist
|
||||
// Types needed by various includes
|
||||
//============================================================
|
||||
|
||||
/// \brief Time step type.
|
||||
///
|
||||
/// May be either FORWARD or RESTORE
|
||||
///
|
||||
enum class time_step_type
|
||||
{
|
||||
FORWARD, //!< forward time
|
||||
RESTORE //!< restore state before last forward
|
||||
};
|
||||
|
||||
/// \brief Delegate type for device notification.
|
||||
///
|
||||
using nl_delegate = plib::pmfp<void()>;
|
||||
using nl_delegate_ts = plib::pmfp<void(time_step_type, nl_fptype)>;
|
||||
using nl_delegate_dyn = plib::pmfp<void()>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// \brief Time step type.
|
||||
///
|
||||
/// May be either FORWARD or RESTORE
|
||||
///
|
||||
enum class time_step_type
|
||||
{
|
||||
FORWARD, //!< forward time
|
||||
RESTORE //!< restore state before last forward
|
||||
};
|
||||
|
||||
/// \brief Enum specifying the type of object
|
||||
///
|
||||
enum class terminal_type
|
||||
@ -220,10 +211,10 @@ namespace netlist
|
||||
///
|
||||
enum class alias_type
|
||||
{
|
||||
UNKNOWN, //!< Used as a placeholder during code changes
|
||||
INTERNAL, //!< the alias references a internal pin
|
||||
FUNCTIONAL, //!< Used for aliases e.g. in BJTs : ALIAS("B",
|
||||
//!< somesub.p())
|
||||
UNKNOWN, //!< Used as a placeholder during code changes
|
||||
INTERNAL, //!< the alias references a internal pin
|
||||
FUNCTIONAL, //!< Used for aliases e.g. in BJTs : ALIAS("B",
|
||||
//!< somesub.p())
|
||||
PACKAGE_PIN, //!< the alias references a package pin, e.g. ALIAS(13,
|
||||
//!< B.CLK)
|
||||
READABILITY, //!< the alias is used to improved readability, e.g.
|
||||
@ -317,37 +308,6 @@ namespace netlist
|
||||
using desc_const_t = std::integral_constant<const T, V>;
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// Exceptions
|
||||
//============================================================
|
||||
|
||||
/// \brief Generic netlist exception.
|
||||
/// The exception is used in all events which are considered fatal.
|
||||
|
||||
class nl_exception : public plib::pexception
|
||||
{
|
||||
public:
|
||||
/// \brief Constructor.
|
||||
/// Allows a descriptive text to be passed to the exception
|
||||
|
||||
explicit nl_exception(const pstring &text //!< text to be passed
|
||||
)
|
||||
: plib::pexception(text)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief Constructor.
|
||||
/// Allows to use \ref plib::pfmt logic to be used in exception
|
||||
|
||||
template <typename... Args>
|
||||
explicit nl_exception(const pstring &fmt, //!< format to be used
|
||||
Args &&...args //!< arguments to be passed
|
||||
)
|
||||
: plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
#endif // NLTYPES_H_
|
||||
|
@ -9,6 +9,7 @@
|
||||
///
|
||||
|
||||
#include "pconfig.h"
|
||||
#include "pgsl.h"
|
||||
#include "ptypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -271,8 +272,7 @@ namespace plib
|
||||
/// FIXME: limited implementation
|
||||
///
|
||||
template <typename T1, typename T2>
|
||||
static inline
|
||||
auto pow(T1 v, T2 p) noexcept -> decltype(std::pow(v, p))
|
||||
static inline auto pow(T1 v, T2 p) noexcept -> decltype(std::pow(v, p))
|
||||
{
|
||||
return std::pow(v, p);
|
||||
}
|
||||
@ -283,60 +283,30 @@ namespace plib
|
||||
return constants<FLOAT128>::one() / v;
|
||||
}
|
||||
|
||||
static FLOAT128 abs(FLOAT128 v) noexcept
|
||||
{
|
||||
return fabsq(v);
|
||||
}
|
||||
static FLOAT128 abs(FLOAT128 v) noexcept { return fabsq(v); }
|
||||
|
||||
static FLOAT128 sqrt(FLOAT128 v) noexcept
|
||||
{
|
||||
return sqrtq(v);
|
||||
}
|
||||
static FLOAT128 sqrt(FLOAT128 v) noexcept { return sqrtq(v); }
|
||||
|
||||
static FLOAT128 hypot(FLOAT128 v1, FLOAT128 v2) noexcept
|
||||
{
|
||||
return hypotq(v1, v2);
|
||||
}
|
||||
|
||||
static FLOAT128 exp(FLOAT128 v) noexcept
|
||||
{
|
||||
return expq(v);
|
||||
}
|
||||
static FLOAT128 exp(FLOAT128 v) noexcept { return expq(v); }
|
||||
|
||||
static FLOAT128 log(FLOAT128 v) noexcept
|
||||
{
|
||||
return logq(v);
|
||||
}
|
||||
static FLOAT128 log(FLOAT128 v) noexcept { return logq(v); }
|
||||
|
||||
static FLOAT128 tanh(FLOAT128 v) noexcept
|
||||
{
|
||||
return tanhq(v);
|
||||
}
|
||||
static FLOAT128 tanh(FLOAT128 v) noexcept { return tanhq(v); }
|
||||
|
||||
static FLOAT128 floor(FLOAT128 v) noexcept
|
||||
{
|
||||
return floorq(v);
|
||||
}
|
||||
static FLOAT128 floor(FLOAT128 v) noexcept { return floorq(v); }
|
||||
|
||||
static FLOAT128 log1p(FLOAT128 v) noexcept
|
||||
{
|
||||
return log1pq(v);
|
||||
}
|
||||
static FLOAT128 log1p(FLOAT128 v) noexcept { return log1pq(v); }
|
||||
|
||||
static FLOAT128 sin(FLOAT128 v) noexcept
|
||||
{
|
||||
return sinq(v);
|
||||
}
|
||||
static FLOAT128 sin(FLOAT128 v) noexcept { return sinq(v); }
|
||||
|
||||
static FLOAT128 cos(FLOAT128 v) noexcept
|
||||
{
|
||||
return cosq(v);
|
||||
}
|
||||
static FLOAT128 cos(FLOAT128 v) noexcept { return cosq(v); }
|
||||
|
||||
static FLOAT128 trunc(FLOAT128 v) noexcept
|
||||
{
|
||||
return truncq(v);
|
||||
}
|
||||
static FLOAT128 trunc(FLOAT128 v) noexcept { return truncq(v); }
|
||||
|
||||
template <typename T>
|
||||
static FLOAT128 pow(FLOAT128 v, T p) noexcept
|
||||
@ -346,8 +316,8 @@ namespace plib
|
||||
|
||||
static FLOAT128 pow(FLOAT128 v, int p) noexcept
|
||||
{
|
||||
if (p==2)
|
||||
return v*v;
|
||||
if (p == 2)
|
||||
return v * v;
|
||||
else
|
||||
return powq(v, static_cast<FLOAT128>(p));
|
||||
}
|
||||
@ -364,7 +334,7 @@ namespace plib
|
||||
constexpr bool is_pow2(T v) noexcept
|
||||
{
|
||||
static_assert(is_integral<T>::value, "is_pow2 needs integer arguments");
|
||||
return !(v & (v-1));
|
||||
return !(v & (v - 1));
|
||||
}
|
||||
|
||||
/// \brief return absolute value of signed argument
|
||||
@ -373,9 +343,9 @@ namespace plib
|
||||
/// \param v argument
|
||||
/// \return absolute value of argument
|
||||
///
|
||||
template<typename T>
|
||||
constexpr
|
||||
std::enable_if_t<plib::is_integral<T>::value && plib::is_signed<T>::value, T>
|
||||
template <typename T>
|
||||
constexpr std::enable_if_t<
|
||||
plib::is_integral<T>::value && plib::is_signed<T>::value, T>
|
||||
abs(T v) noexcept
|
||||
{
|
||||
return v < 0 ? -v : v;
|
||||
@ -387,9 +357,9 @@ namespace plib
|
||||
/// \param v argument
|
||||
/// \return argument since it has no sign
|
||||
///
|
||||
template<typename T>
|
||||
constexpr
|
||||
std::enable_if_t<plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
|
||||
template <typename T>
|
||||
constexpr std::enable_if_t<
|
||||
plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
|
||||
abs(T v) noexcept
|
||||
{
|
||||
return v;
|
||||
@ -406,16 +376,14 @@ namespace plib
|
||||
/// \param n first argument
|
||||
/// \return greatest common denominator of m and n
|
||||
///
|
||||
template<typename M, typename N>
|
||||
template <typename M, typename N>
|
||||
constexpr typename std::common_type<M, N>::type
|
||||
gcd(M m, N n) noexcept //NOLINT(misc-no-recursion)
|
||||
gcd(M m, N n) noexcept // NOLINT(misc-no-recursion)
|
||||
{
|
||||
static_assert(plib::is_integral<M>::value, "gcd: M must be an integer");
|
||||
static_assert(plib::is_integral<N>::value, "gcd: N must be an integer");
|
||||
|
||||
return m == 0 ? plib::abs(n)
|
||||
: n == 0 ? plib::abs(m)
|
||||
: gcd(n, m % n);
|
||||
return m == 0 ? plib::abs(n) : n == 0 ? plib::abs(m) : gcd(n, m % n);
|
||||
}
|
||||
|
||||
/// \brief return least common multiple
|
||||
@ -429,24 +397,25 @@ namespace plib
|
||||
/// \param n first argument
|
||||
/// \return least common multiple of m and n
|
||||
///
|
||||
template<typename M, typename N>
|
||||
constexpr typename std::common_type<M, N>::type
|
||||
lcm(M m, N n) noexcept
|
||||
template <typename M, typename N>
|
||||
constexpr typename std::common_type<M, N>::type lcm(M m, N n) noexcept
|
||||
{
|
||||
static_assert(plib::is_integral<M>::value, "lcm: M must be an integer");
|
||||
static_assert(plib::is_integral<N>::value, "lcm: N must be an integer");
|
||||
|
||||
return (m != 0 && n != 0) ? (plib::abs(m) / gcd(m, n)) * plib::abs(n) : 0;
|
||||
return (m != 0 && n != 0) ? (plib::abs(m) / gcd(m, n)) * plib::abs(n)
|
||||
: 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr const T& clamp( const T& v, const T& low, const T& high)
|
||||
template <class T>
|
||||
constexpr const T &clamp(const T &v, const T &low, const T &high)
|
||||
{
|
||||
gsl_Expects(high >= low);
|
||||
return (v < low) ? low : (high < v) ? high : v;
|
||||
}
|
||||
|
||||
static_assert(noexcept(constants<double>::one()), "Not evaluated as constexpr");
|
||||
static_assert(noexcept(constants<double>::one()),
|
||||
"Not evaluated as constexpr");
|
||||
|
||||
} // namespace plib
|
||||
|
||||
|
@ -7,35 +7,40 @@
|
||||
// Specific technical terms
|
||||
// spell-checker: words vsolver
|
||||
|
||||
#include "nld_solver.h"
|
||||
#include "core/setup.h"
|
||||
#include "nl_setup.h"
|
||||
#include "nld_matrix_solver.h"
|
||||
|
||||
#include "nl_setup.h"
|
||||
#include "nld_solver.h"
|
||||
|
||||
#include "core/setup.h"
|
||||
|
||||
#include "plib/putil.h"
|
||||
|
||||
namespace netlist::solver
|
||||
{
|
||||
|
||||
terms_for_net_t::terms_for_net_t(arena_type &arena, analog_net_t * net)
|
||||
: m_nz(arena)
|
||||
, m_nzrd(arena)
|
||||
, m_nzbd(arena)
|
||||
, m_connected_net_idx(arena)
|
||||
, m_terms(arena)
|
||||
, m_net(net)
|
||||
, m_rail_start(0)
|
||||
terms_for_net_t::terms_for_net_t(arena_type &arena, analog_net_t *net)
|
||||
: m_nz(arena)
|
||||
, m_nzrd(arena)
|
||||
, m_nzbd(arena)
|
||||
, m_connected_net_idx(arena)
|
||||
, m_terms(arena)
|
||||
, m_net(net)
|
||||
, m_rail_start(0)
|
||||
{
|
||||
}
|
||||
|
||||
void terms_for_net_t::add_terminal(terminal_t *term, int net_other, bool sorted)
|
||||
void
|
||||
terms_for_net_t::add_terminal(terminal_t *term, int net_other, bool sorted)
|
||||
{
|
||||
if (sorted)
|
||||
for (std::size_t i=0; i < m_connected_net_idx.size(); i++)
|
||||
for (std::size_t i = 0; i < m_connected_net_idx.size(); i++)
|
||||
{
|
||||
if (m_connected_net_idx[i] > net_other)
|
||||
{
|
||||
plib::container::insert_at(m_terms, i, term);
|
||||
plib::container::insert_at(m_connected_net_idx, i, net_other);
|
||||
plib::container::insert_at(m_connected_net_idx, i,
|
||||
net_other);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -47,34 +52,36 @@ namespace netlist::solver
|
||||
// matrix_solver
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
|
||||
const net_list_t &nets,
|
||||
const solver::solver_parameters_t *params)
|
||||
//: device_t(static_cast<device_t &>(main_solver), name)
|
||||
: device_t(device_data_t{main_solver.state(), main_solver.name() + "." + name})
|
||||
, m_params(*params)
|
||||
, m_gonn(m_arena)
|
||||
, m_gtn(m_arena)
|
||||
, m_Idrn(m_arena)
|
||||
, m_connected_net_Vn(m_arena)
|
||||
, m_iterative_fail(*this, "m_iterative_fail", 0)
|
||||
, m_iterative_total(*this, "m_iterative_total", 0)
|
||||
, m_main_solver(main_solver)
|
||||
, m_stat_calculations(*this, "m_stat_calculations", 0)
|
||||
, m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
|
||||
, m_stat_newton_raphson_fail(*this, "m_stat_newton_raphson_fail", 0)
|
||||
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
|
||||
, m_last_step(*this, "m_last_step", netlist_time_ext::zero())
|
||||
, m_step_funcs(m_arena)
|
||||
, m_dynamic_funcs(m_arena)
|
||||
, m_inputs(m_arena)
|
||||
, m_ops(0)
|
||||
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver,
|
||||
const pstring &name,
|
||||
const net_list_t &nets,
|
||||
const solver::solver_parameters_t *params)
|
||||
//: device_t(static_cast<device_t &>(main_solver), name)
|
||||
: device_t(
|
||||
device_data_t{main_solver.state(), main_solver.name() + "." + name})
|
||||
, m_params(*params)
|
||||
, m_gonn(m_arena)
|
||||
, m_gtn(m_arena)
|
||||
, m_Idrn(m_arena)
|
||||
, m_connected_net_Vn(m_arena)
|
||||
, m_iterative_fail(*this, "m_iterative_fail", 0)
|
||||
, m_iterative_total(*this, "m_iterative_total", 0)
|
||||
, m_main_solver(main_solver)
|
||||
, m_stat_calculations(*this, "m_stat_calculations", 0)
|
||||
, m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
|
||||
, m_stat_newton_raphson_fail(*this, "m_stat_newton_raphson_fail", 0)
|
||||
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
|
||||
, m_last_step(*this, "m_last_step", netlist_time_ext::zero())
|
||||
, m_step_funcs(m_arena)
|
||||
, m_dynamic_funcs(m_arena)
|
||||
, m_inputs(m_arena)
|
||||
, m_ops(0)
|
||||
{
|
||||
setup_base(this->state().setup(), nets);
|
||||
|
||||
// now setup the matrix
|
||||
setup_matrix();
|
||||
//printf("Freq: %f\n", m_params.m_freq());
|
||||
// printf("Freq: %f\n", m_params.m_freq());
|
||||
}
|
||||
|
||||
analog_net_t *matrix_solver_t::get_connected_net(terminal_t *term)
|
||||
@ -87,7 +94,8 @@ namespace netlist::solver
|
||||
m_main_solver.reschedule(this, ts);
|
||||
}
|
||||
|
||||
void matrix_solver_t::setup_base([[maybe_unused]] setup_t &setup, const net_list_t &nets)
|
||||
void matrix_solver_t::setup_base([[maybe_unused]] setup_t &setup,
|
||||
const net_list_t &nets)
|
||||
{
|
||||
log().debug("New solver setup\n");
|
||||
std::vector<core_device_t *> step_devices;
|
||||
@ -95,7 +103,7 @@ namespace netlist::solver
|
||||
|
||||
m_terms.clear();
|
||||
|
||||
for (const auto & net : nets)
|
||||
for (const auto &net : nets)
|
||||
{
|
||||
m_terms.emplace_back(m_arena, net);
|
||||
m_rails_temp.emplace_back(m_arena);
|
||||
@ -108,68 +116,87 @@ namespace netlist::solver
|
||||
analog_net_t &net = *nets[k];
|
||||
|
||||
// FIXME: add size() to list
|
||||
// log().debug("adding net with {1} populated connections\n", net.core_terms().size());
|
||||
// log().debug("adding net with {1} populated connections\n",
|
||||
// net.core_terms().size());
|
||||
|
||||
net.set_solver(this);
|
||||
|
||||
for (detail::core_terminal_t * p : net.core_terms_copy())
|
||||
for (detail::core_terminal_t *p : net.core_terms_copy())
|
||||
{
|
||||
nl_assert_always(&p->net() == &net, "Net integrity violated");
|
||||
|
||||
log().debug("{1} {2} {3}\n", p->name(), net.name(), net.is_rail_net());
|
||||
log().debug("{1} {2} {3}\n", p->name(), net.name(),
|
||||
net.is_rail_net());
|
||||
switch (p->type())
|
||||
{
|
||||
case detail::terminal_type::TERMINAL:
|
||||
if (p->device().is_time_step())
|
||||
if (!plib::container::contains(step_devices, &p->device()))
|
||||
if (!plib::container::contains(step_devices,
|
||||
&p->device()))
|
||||
step_devices.push_back(&p->device());
|
||||
if (p->device().is_dynamic())
|
||||
if (!plib::container::contains(dynamic_devices, &p->device()))
|
||||
if (!plib::container::contains(dynamic_devices,
|
||||
&p->device()))
|
||||
dynamic_devices.push_back(&p->device());
|
||||
{
|
||||
auto pterm = plib::dynamic_downcast<terminal_t *>(p);
|
||||
nl_assert_always(bool(pterm), "cast to terminal_t * failed");
|
||||
auto pterm = plib::dynamic_downcast<terminal_t *>(
|
||||
p);
|
||||
nl_assert_always(bool(pterm),
|
||||
"cast to terminal_t * failed");
|
||||
add_term(k, *pterm);
|
||||
}
|
||||
log().debug("Added terminal {1}\n", p->name());
|
||||
break;
|
||||
case detail::terminal_type::INPUT:
|
||||
{
|
||||
proxied_analog_output_t *net_proxy_output = nullptr;
|
||||
for (auto & input : m_inputs)
|
||||
if (input->proxied_net() == &p->net())
|
||||
{
|
||||
net_proxy_output = input.get();
|
||||
break;
|
||||
}
|
||||
|
||||
if (net_proxy_output == nullptr)
|
||||
{
|
||||
proxied_analog_output_t *net_proxy_output = nullptr;
|
||||
for (auto &input : m_inputs)
|
||||
if (input->proxied_net() == &p->net())
|
||||
{
|
||||
pstring new_name(this->name() + "." + pstring(plib::pfmt("m{1}")(m_inputs.size())));
|
||||
auto proxied_net = plib::dynamic_downcast<analog_net_t *>(p->net());
|
||||
nl_assert_always(proxied_net, "Net is not an analog net");
|
||||
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, new_name, *proxied_net);
|
||||
net_proxy_output = net_proxy_output_u.get();
|
||||
m_inputs.emplace_back(std::move(net_proxy_output_u));
|
||||
net_proxy_output = input.get();
|
||||
break;
|
||||
}
|
||||
net.remove_terminal(*p);
|
||||
net_proxy_output->net().add_terminal(*p);
|
||||
// FIXME: repeated calling - kind of brute force
|
||||
net_proxy_output->net().rebuild_list();
|
||||
log().debug("Added input {1}", net_proxy_output->name());
|
||||
|
||||
if (net_proxy_output == nullptr)
|
||||
{
|
||||
pstring new_name(
|
||||
this->name() + "."
|
||||
+ pstring(plib::pfmt("m{1}")(m_inputs.size())));
|
||||
auto proxied_net = plib::dynamic_downcast<
|
||||
analog_net_t *>(p->net());
|
||||
nl_assert_always(proxied_net,
|
||||
"Net is not an analog net");
|
||||
auto net_proxy_output_u
|
||||
= state()
|
||||
.make_pool_object<
|
||||
proxied_analog_output_t>(
|
||||
*this, new_name, *proxied_net);
|
||||
net_proxy_output = net_proxy_output_u.get();
|
||||
m_inputs.emplace_back(
|
||||
std::move(net_proxy_output_u));
|
||||
}
|
||||
break;
|
||||
net.remove_terminal(*p);
|
||||
net_proxy_output->net().add_terminal(*p);
|
||||
// FIXME: repeated calling - kind of brute force
|
||||
net_proxy_output->net().rebuild_list();
|
||||
log().debug("Added input {1}",
|
||||
net_proxy_output->name());
|
||||
}
|
||||
break;
|
||||
case detail::terminal_type::OUTPUT:
|
||||
log().fatal(MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
|
||||
throw nl_exception(MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
|
||||
throw nl_exception(
|
||||
MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
|
||||
}
|
||||
}
|
||||
net.rebuild_list();
|
||||
}
|
||||
for (auto &d : step_devices)
|
||||
m_step_funcs.emplace_back(nl_delegate_ts(&core_device_t::time_step, d));
|
||||
m_step_funcs.emplace_back(
|
||||
nl_delegate_ts(&core_device_t::time_step, d));
|
||||
for (auto &d : dynamic_devices)
|
||||
m_dynamic_funcs.emplace_back(nl_delegate_dyn(&core_device_t::update_terminals, d));
|
||||
m_dynamic_funcs.emplace_back(
|
||||
nl_delegate_dyn(&core_device_t::update_terminals, d));
|
||||
}
|
||||
|
||||
/// \brief Sort terminals
|
||||
@ -192,7 +219,8 @@ namespace netlist::solver
|
||||
/// literature but I have found no articles about Gauss Seidel.
|
||||
///
|
||||
/// For Gaussian Elimination however increasing order is better suited.
|
||||
/// NOTE: Even better would be to sort on elements right of the matrix diagonal.
|
||||
/// NOTE: Even better would be to sort on elements right of the matrix
|
||||
/// diagonal.
|
||||
/// FIXME: This entry needs an update.
|
||||
///
|
||||
void matrix_solver_t::sort_terms(matrix_sort_type_e sort)
|
||||
@ -202,65 +230,69 @@ namespace netlist::solver
|
||||
switch (sort)
|
||||
{
|
||||
case matrix_sort_type_e::PREFER_BAND_MATRIX:
|
||||
{
|
||||
for (std::size_t k = 0; k < iN - 1; k++)
|
||||
{
|
||||
for (std::size_t k = 0; k < iN - 1; k++)
|
||||
auto pk = get_weight_around_diagonal(k, k);
|
||||
for (std::size_t i = k + 1; i < iN; i++)
|
||||
{
|
||||
auto pk = get_weight_around_diagonal(k,k);
|
||||
for (std::size_t i = k+1; i < iN; i++)
|
||||
auto pi = get_weight_around_diagonal(i, k);
|
||||
if (pi < pk)
|
||||
{
|
||||
auto pi = get_weight_around_diagonal(i,k);
|
||||
if (pi < pk)
|
||||
{
|
||||
std::swap(m_terms[i], m_terms[k]);
|
||||
pk = get_weight_around_diagonal(k,k);
|
||||
}
|
||||
std::swap(m_terms[i], m_terms[k]);
|
||||
pk = get_weight_around_diagonal(k, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT:
|
||||
{
|
||||
for (std::size_t k = 0; k < iN - 1; k++)
|
||||
{
|
||||
for (std::size_t k = 0; k < iN - 1; k++)
|
||||
auto pk = get_left_right_of_diagonal(k, k);
|
||||
for (std::size_t i = k + 1; i < iN; i++)
|
||||
{
|
||||
auto pk = get_left_right_of_diagonal(k,k);
|
||||
for (std::size_t i = k+1; i < iN; i++)
|
||||
auto pi = get_left_right_of_diagonal(i, k);
|
||||
if (pi.first <= pk.first && pi.second >= pk.second)
|
||||
{
|
||||
auto pi = get_left_right_of_diagonal(i,k);
|
||||
if (pi.first <= pk.first && pi.second >= pk.second)
|
||||
{
|
||||
std::swap(m_terms[i], m_terms[k]);
|
||||
pk = get_left_right_of_diagonal(k,k);
|
||||
}
|
||||
std::swap(m_terms[i], m_terms[k]);
|
||||
pk = get_left_right_of_diagonal(k, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case matrix_sort_type_e::ASCENDING:
|
||||
case matrix_sort_type_e::DESCENDING:
|
||||
{
|
||||
int sort_order = (sort == matrix_sort_type_e::DESCENDING ? 1 : -1);
|
||||
{
|
||||
int sort_order = (sort == matrix_sort_type_e::DESCENDING ? 1
|
||||
: -1);
|
||||
|
||||
for (std::size_t k = 0; k < iN - 1; k++)
|
||||
for (std::size_t i = k+1; i < iN; i++)
|
||||
for (std::size_t k = 0; k < iN - 1; k++)
|
||||
for (std::size_t i = k + 1; i < iN; i++)
|
||||
{
|
||||
if ((static_cast<int>(m_terms[k].rail_start())
|
||||
- static_cast<int>(m_terms[i].rail_start()))
|
||||
* sort_order
|
||||
< 0)
|
||||
{
|
||||
if ((static_cast<int>(m_terms[k].rail_start()) - static_cast<int>(m_terms[i].rail_start())) * sort_order < 0)
|
||||
{
|
||||
std::swap(m_terms[i], m_terms[k]);
|
||||
}
|
||||
std::swap(m_terms[i], m_terms[k]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case matrix_sort_type_e::NOSORT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case matrix_sort_type_e::NOSORT: break;
|
||||
}
|
||||
// rebuild
|
||||
for (auto &term : m_terms)
|
||||
{
|
||||
//int *other = term.m_connected_net_idx.data();
|
||||
// int *other = term.m_connected_net_idx.data();
|
||||
for (std::size_t i = 0; i < term.count(); i++)
|
||||
//FIXME: this is weird
|
||||
// FIXME: this is weird
|
||||
if (term.m_connected_net_idx[i] != -1)
|
||||
term.m_connected_net_idx[i] = get_net_idx(get_connected_net(term.terms()[i]));
|
||||
term.m_connected_net_idx[i] = get_net_idx(
|
||||
get_connected_net(term.terms()[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,7 +304,9 @@ namespace netlist::solver
|
||||
{
|
||||
m_terms[k].set_rail_start(m_terms[k].count());
|
||||
for (std::size_t i = 0; i < m_rails_temp[k].count(); i++)
|
||||
this->m_terms[k].add_terminal(m_rails_temp[k].terms()[i], m_rails_temp[k].m_connected_net_idx.data()[i], false);
|
||||
this->m_terms[k].add_terminal(
|
||||
m_rails_temp[k].terms()[i],
|
||||
m_rails_temp[k].m_connected_net_idx.data()[i], false);
|
||||
}
|
||||
|
||||
// free all - no longer needed
|
||||
@ -285,17 +319,18 @@ namespace netlist::solver
|
||||
// create a list of non zero elements.
|
||||
for (unsigned k = 0; k < iN; k++)
|
||||
{
|
||||
terms_for_net_t & t = m_terms[k];
|
||||
terms_for_net_t &t = m_terms[k];
|
||||
// pretty brutal
|
||||
int *other = t.m_connected_net_idx.data();
|
||||
|
||||
t.m_nz.clear();
|
||||
|
||||
for (std::size_t i = 0; i < t.rail_start(); i++)
|
||||
if (!plib::container::contains(t.m_nz, static_cast<unsigned>(other[i])))
|
||||
if (!plib::container::contains(t.m_nz,
|
||||
static_cast<unsigned>(other[i])))
|
||||
t.m_nz.push_back(static_cast<unsigned>(other[i]));
|
||||
|
||||
t.m_nz.push_back(k); // add diagonal
|
||||
t.m_nz.push_back(k); // add diagonal
|
||||
|
||||
// and sort
|
||||
std::sort(t.m_nz.begin(), t.m_nz.end());
|
||||
@ -307,16 +342,16 @@ namespace netlist::solver
|
||||
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
{
|
||||
terms_for_net_t & t = m_terms[k];
|
||||
terms_for_net_t &t = m_terms[k];
|
||||
// pretty brutal
|
||||
int *other = t.m_connected_net_idx.data();
|
||||
|
||||
if (k==0)
|
||||
if (k == 0)
|
||||
t.m_nzrd.clear();
|
||||
else
|
||||
{
|
||||
t.m_nzrd = m_terms[k-1].m_nzrd;
|
||||
for (auto j = t.m_nzrd.begin(); j != t.m_nzrd.end(); )
|
||||
t.m_nzrd = m_terms[k - 1].m_nzrd;
|
||||
for (auto j = t.m_nzrd.begin(); j != t.m_nzrd.end();)
|
||||
{
|
||||
if (*j < k + 1)
|
||||
j = t.m_nzrd.erase(j);
|
||||
@ -326,7 +361,9 @@ namespace netlist::solver
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < t.rail_start(); i++)
|
||||
if (!plib::container::contains(t.m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
|
||||
if (!plib::container::contains(t.m_nzrd,
|
||||
static_cast<unsigned>(other[i]))
|
||||
&& other[i] >= static_cast<int>(k + 1))
|
||||
t.m_nzrd.push_back(static_cast<unsigned>(other[i]));
|
||||
|
||||
// and sort
|
||||
@ -366,7 +403,8 @@ namespace netlist::solver
|
||||
}
|
||||
}
|
||||
}
|
||||
log().verbose("Number of multiplications/additions for {1}: {2}", name(), m_ops);
|
||||
log().verbose("Number of multiplications/additions for {1}: {2}",
|
||||
name(), m_ops);
|
||||
|
||||
// Dumps non zero elements right of diagonal -> to much output, disabled
|
||||
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
|
||||
@ -374,7 +412,7 @@ namespace netlist::solver
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
{
|
||||
pstring line = plib::pfmt("{1:3}")(k);
|
||||
for (const auto & nzrd : m_terms[k].m_nzrd)
|
||||
for (const auto &nzrd : m_terms[k].m_nzrd)
|
||||
line += plib::pfmt(" {1:3}")(nzrd);
|
||||
log().verbose("{1}", line);
|
||||
}
|
||||
@ -387,9 +425,12 @@ namespace netlist::solver
|
||||
{
|
||||
pstring num = plib::pfmt("{1}")(k);
|
||||
|
||||
state().save(*this, m_gonn[k],"GO" + num, this->name(), m_terms[k].count());
|
||||
state().save(*this, m_gtn[k],"GT" + num, this->name(), m_terms[k].count());
|
||||
state().save(*this, m_Idrn[k],"IDR" + num, this->name(), m_terms[k].count());
|
||||
state().save(*this, m_gonn[k], "GO" + num, this->name(),
|
||||
m_terms[k].count());
|
||||
state().save(*this, m_gtn[k], "GT" + num, this->name(),
|
||||
m_terms[k].count());
|
||||
state().save(*this, m_Idrn[k], "IDR" + num, this->name(),
|
||||
m_terms[k].count());
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,20 +455,22 @@ namespace netlist::solver
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
for (std::size_t j = 0; j < m_terms[k].count(); j++)
|
||||
{
|
||||
m_gtn.set(k,j, nlconst::zero());
|
||||
m_gonn.set(k,j, nlconst::zero());
|
||||
m_Idrn.set(k,j, nlconst::zero());
|
||||
m_gtn.set(k, j, nlconst::zero());
|
||||
m_gonn.set(k, j, nlconst::zero());
|
||||
m_Idrn.set(k, j, nlconst::zero());
|
||||
m_connected_net_Vn.set(k, j, nullptr);
|
||||
}
|
||||
|
||||
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
{
|
||||
auto count = m_terms[k].count();
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
{
|
||||
m_terms[k].terms()[i]->set_ptrs(&m_gtn[k][i], &m_gonn[k][i], &m_Idrn[k][i]);
|
||||
m_connected_net_Vn[k][i] = get_connected_net(m_terms[k].terms()[i])->Q_Analog_state_ptr();
|
||||
m_terms[k].terms()[i]->set_ptrs(&m_gtn[k][i], &m_gonn[k][i],
|
||||
&m_Idrn[k][i]);
|
||||
m_connected_net_Vn[k][i] = get_connected_net(
|
||||
m_terms[k].terms()[i])
|
||||
->Q_Analog_state_ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -448,10 +491,11 @@ namespace netlist::solver
|
||||
|
||||
void matrix_solver_t::reset()
|
||||
{
|
||||
//m_last_step = netlist_time_ext::zero();
|
||||
// m_last_step = netlist_time_ext::zero();
|
||||
}
|
||||
|
||||
void matrix_solver_t::step(time_step_type ts_type, netlist_time delta) noexcept
|
||||
void matrix_solver_t::step(detail::time_step_type ts_type,
|
||||
netlist_time delta) noexcept
|
||||
{
|
||||
const auto dd(delta.as_fp<fptype>());
|
||||
for (auto &d : m_step_funcs)
|
||||
@ -460,12 +504,13 @@ namespace netlist::solver
|
||||
|
||||
bool matrix_solver_t::solve_nr_base()
|
||||
{
|
||||
bool this_resched(false);
|
||||
bool this_resched(false);
|
||||
std::size_t newton_loops = 0;
|
||||
do
|
||||
{
|
||||
update_dynamic();
|
||||
// Gauss-Seidel will revert to Gaussian elimination if steps exceeded.
|
||||
// Gauss-Seidel will revert to Gaussian elimination if steps
|
||||
// exceeded.
|
||||
this->m_stat_calculations++;
|
||||
this->upstream_solve_non_dynamic();
|
||||
this_resched = this->check_err();
|
||||
@ -482,18 +527,21 @@ namespace netlist::solver
|
||||
netlist_time matrix_solver_t::newton_loops_exceeded(netlist_time delta)
|
||||
{
|
||||
netlist_time next_time_step;
|
||||
bool resched(false);
|
||||
bool resched(false);
|
||||
|
||||
restore();
|
||||
step(time_step_type::RESTORE, delta);
|
||||
step(detail::time_step_type::RESTORE, delta);
|
||||
|
||||
for (std::size_t i=0; i< 10; i++)
|
||||
for (std::size_t i = 0; i < 10; i++)
|
||||
{
|
||||
backup();
|
||||
step(time_step_type::FORWARD, netlist_time::from_fp(m_params.m_min_ts_ts()));
|
||||
step(detail::time_step_type::FORWARD,
|
||||
netlist_time::from_fp(m_params.m_min_ts_ts()));
|
||||
resched = solve_nr_base();
|
||||
// update time step calculation
|
||||
next_time_step = compute_next_time_step(m_params.m_min_ts_ts(), m_params.m_min_ts_ts(), m_params.m_max_time_step);
|
||||
next_time_step = compute_next_time_step(m_params.m_min_ts_ts(),
|
||||
m_params.m_min_ts_ts(),
|
||||
m_params.m_max_time_step);
|
||||
delta -= netlist_time::from_fp(m_params.m_min_ts_ts());
|
||||
}
|
||||
// try remaining time using compute_next_time step
|
||||
@ -502,19 +550,23 @@ namespace netlist::solver
|
||||
if (next_time_step > delta)
|
||||
next_time_step = delta;
|
||||
backup();
|
||||
step(time_step_type::FORWARD, next_time_step);
|
||||
step(detail::time_step_type::FORWARD, next_time_step);
|
||||
delta -= next_time_step;
|
||||
resched = solve_nr_base();
|
||||
next_time_step = compute_next_time_step(next_time_step.as_fp<nl_fptype>(), m_params.m_min_ts_ts(), m_params.m_max_time_step);
|
||||
next_time_step = compute_next_time_step(
|
||||
next_time_step.as_fp<nl_fptype>(), m_params.m_min_ts_ts(),
|
||||
m_params.m_max_time_step);
|
||||
}
|
||||
|
||||
if (m_stat_newton_raphson % 100 == 0)
|
||||
log().warning(MW_NEWTON_LOOPS_EXCEEDED_INVOCATION_3(100, this->name(), exec().time().as_double() * 1e6));
|
||||
log().warning(MW_NEWTON_LOOPS_EXCEEDED_INVOCATION_3(
|
||||
100, this->name(), exec().time().as_double() * 1e6));
|
||||
|
||||
if (resched)
|
||||
{
|
||||
// reschedule ....
|
||||
log().warning(MW_NEWTON_LOOPS_EXCEEDED_ON_NET_2(this->name(), exec().time().as_double() * 1e6));
|
||||
log().warning(MW_NEWTON_LOOPS_EXCEEDED_ON_NET_2(
|
||||
this->name(), exec().time().as_double() * 1e6));
|
||||
return netlist_time::from_fp(m_params.m_nr_recalc_delay());
|
||||
}
|
||||
if (m_params.m_dynamic_ts)
|
||||
@ -523,7 +575,8 @@ namespace netlist::solver
|
||||
return netlist_time::from_fp(m_params.m_max_time_step);
|
||||
}
|
||||
|
||||
netlist_time matrix_solver_t::solve(netlist_time_ext now, [[maybe_unused]] const char *source)
|
||||
netlist_time matrix_solver_t::solve(netlist_time_ext now,
|
||||
[[maybe_unused]] const char *source)
|
||||
{
|
||||
auto delta = static_cast<netlist_time>(now - m_last_step());
|
||||
PFDEBUG(printf("solve %.10f\n", delta.as_double());)
|
||||
@ -532,8 +585,10 @@ namespace netlist::solver
|
||||
// FIXME: Make this a parameter!
|
||||
if (delta < netlist_time::quantum())
|
||||
{
|
||||
//printf("solve return %s at %f\n", source, now.as_double());
|
||||
return time_step_device_count() > 0 ? netlist_time::from_fp(m_params.m_min_time_step) : netlist_time::zero();
|
||||
// printf("solve return %s at %f\n", source, now.as_double());
|
||||
return time_step_device_count() > 0
|
||||
? netlist_time::from_fp(m_params.m_min_time_step)
|
||||
: netlist_time::zero();
|
||||
}
|
||||
|
||||
backup(); // save voltages for backup and time step calculation
|
||||
@ -543,7 +598,7 @@ namespace netlist::solver
|
||||
++m_stat_vsolver_calls;
|
||||
if (dynamic_device_count() != 0)
|
||||
{
|
||||
step(time_step_type::FORWARD, delta);
|
||||
step(detail::time_step_type::FORWARD, delta);
|
||||
const auto resched = solve_nr_base();
|
||||
|
||||
if (resched)
|
||||
@ -551,7 +606,7 @@ namespace netlist::solver
|
||||
}
|
||||
else
|
||||
{
|
||||
step(time_step_type::FORWARD, delta);
|
||||
step(detail::time_step_type::FORWARD, delta);
|
||||
this->m_stat_calculations++;
|
||||
this->upstream_solve_non_dynamic();
|
||||
this->store();
|
||||
@ -560,14 +615,15 @@ namespace netlist::solver
|
||||
if (m_params.m_dynamic_ts)
|
||||
{
|
||||
if (time_step_device_count() > 0)
|
||||
return compute_next_time_step(delta.as_fp<nl_fptype>(), m_params.m_min_time_step, m_params.m_max_time_step);
|
||||
return compute_next_time_step(delta.as_fp<nl_fptype>(),
|
||||
m_params.m_min_time_step,
|
||||
m_params.m_max_time_step);
|
||||
}
|
||||
|
||||
if (time_step_device_count() > 0)
|
||||
return netlist_time::from_fp(m_params.m_max_time_step);
|
||||
|
||||
return netlist_time::zero();
|
||||
|
||||
}
|
||||
|
||||
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
|
||||
@ -578,11 +634,14 @@ namespace netlist::solver
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::pair<int, int> matrix_solver_t::get_left_right_of_diagonal(std::size_t irow, std::size_t idiag)
|
||||
std::pair<int, int>
|
||||
matrix_solver_t::get_left_right_of_diagonal(std::size_t irow,
|
||||
std::size_t idiag)
|
||||
{
|
||||
//
|
||||
// return the maximum column left of the diagonal (-1 if no cols found)
|
||||
// return the minimum column right of the diagonal (999999 if no cols found)
|
||||
// return the minimum column right of the diagonal (999999 if no cols
|
||||
// found)
|
||||
//
|
||||
|
||||
const auto row = static_cast<int>(irow);
|
||||
@ -598,8 +657,10 @@ namespace netlist::solver
|
||||
auto col = get_net_idx(get_connected_net(term.terms()[i]));
|
||||
if (col != -1)
|
||||
{
|
||||
if (col==row) col = diag;
|
||||
else if (col==diag) col = row;
|
||||
if (col == row)
|
||||
col = diag;
|
||||
else if (col == diag)
|
||||
col = row;
|
||||
|
||||
if (col > diag && col < colmin)
|
||||
colmin = col;
|
||||
@ -610,7 +671,9 @@ namespace netlist::solver
|
||||
return {colmax, colmin};
|
||||
}
|
||||
|
||||
matrix_solver_t::fptype matrix_solver_t::get_weight_around_diagonal(std::size_t row, std::size_t diag)
|
||||
matrix_solver_t::fptype
|
||||
matrix_solver_t::get_weight_around_diagonal(std::size_t row,
|
||||
std::size_t diag)
|
||||
{
|
||||
{
|
||||
//
|
||||
@ -620,7 +683,7 @@ namespace netlist::solver
|
||||
std::vector<bool> touched(1024, false); // FIXME!
|
||||
|
||||
fptype weight = nlconst::zero();
|
||||
auto &term = m_terms[row];
|
||||
auto &term = m_terms[row];
|
||||
for (std::size_t i = 0; i < term.count(); i++)
|
||||
{
|
||||
auto col = get_net_idx(get_connected_net(term.terms()[i]));
|
||||
@ -629,10 +692,14 @@ namespace netlist::solver
|
||||
auto colu = static_cast<std::size_t>(col);
|
||||
if (!touched[colu])
|
||||
{
|
||||
if (colu==row) colu = static_cast<unsigned>(diag);
|
||||
else if (colu==diag) colu = static_cast<unsigned>(row);
|
||||
if (colu == row)
|
||||
colu = static_cast<unsigned>(diag);
|
||||
else if (colu == diag)
|
||||
colu = static_cast<unsigned>(row);
|
||||
|
||||
weight = weight + plib::abs(static_cast<fptype>(colu) - static_cast<fptype>(diag));
|
||||
weight = weight
|
||||
+ plib::abs(static_cast<fptype>(colu)
|
||||
- static_cast<fptype>(diag));
|
||||
touched[colu] = true;
|
||||
}
|
||||
}
|
||||
@ -650,38 +717,46 @@ namespace netlist::solver
|
||||
else
|
||||
{
|
||||
int ot = get_net_idx(get_connected_net(term));
|
||||
if (ot>=0)
|
||||
if (ot >= 0)
|
||||
{
|
||||
m_terms[net_idx].add_terminal(term, ot, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
log().fatal(MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
|
||||
throw nl_exception(MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
|
||||
throw nl_exception(
|
||||
MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void matrix_solver_t::log_stats()
|
||||
{
|
||||
if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && log().verbose.is_enabled())
|
||||
if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls
|
||||
&& log().verbose.is_enabled())
|
||||
{
|
||||
log().verbose("==============================================");
|
||||
log().verbose("Solver {1}", this->name());
|
||||
log().verbose(" ==> {1} nets", this->m_terms.size());
|
||||
log().verbose(" has {1} dynamic elements", this->dynamic_device_count());
|
||||
log().verbose(" has {1} time step elements", this->time_step_device_count());
|
||||
log().verbose(" {1:6.3} average newton raphson loops",
|
||||
static_cast<fptype>(this->m_stat_newton_raphson) / static_cast<fptype>(this->m_stat_vsolver_calls));
|
||||
log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
|
||||
this->m_stat_calculations,
|
||||
static_cast<fptype>(this->m_stat_calculations) / this->exec().time().as_fp<fptype>(),
|
||||
this->m_iterative_fail,
|
||||
nlconst::hundred() * static_cast<fptype>(this->m_iterative_fail)
|
||||
/ static_cast<fptype>(this->m_stat_calculations),
|
||||
static_cast<fptype>(this->m_iterative_total) / static_cast<fptype>(this->m_stat_calculations));
|
||||
log().verbose(" has {1} dynamic elements",
|
||||
this->dynamic_device_count());
|
||||
log().verbose(" has {1} time step elements",
|
||||
this->time_step_device_count());
|
||||
log().verbose(
|
||||
" {1:6.3} average newton raphson loops",
|
||||
static_cast<fptype>(this->m_stat_newton_raphson)
|
||||
/ static_cast<fptype>(this->m_stat_vsolver_calls));
|
||||
log().verbose(
|
||||
" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
|
||||
this->m_stat_calculations,
|
||||
static_cast<fptype>(this->m_stat_calculations)
|
||||
/ this->exec().time().as_fp<fptype>(),
|
||||
this->m_iterative_fail,
|
||||
nlconst::hundred() * static_cast<fptype>(this->m_iterative_fail)
|
||||
/ static_cast<fptype>(this->m_stat_calculations),
|
||||
static_cast<fptype>(this->m_iterative_total)
|
||||
/ static_cast<fptype>(this->m_stat_calculations));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netlist::solver
|
||||
|
||||
|
@ -11,14 +11,14 @@
|
||||
/// \file nld_matrix_solver.h
|
||||
///
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nltypes.h"
|
||||
|
||||
#include "../core/analog.h"
|
||||
#include "../core/device.h"
|
||||
#include "../core/device_macros.h"
|
||||
#include "../core/param.h"
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nltypes.h"
|
||||
#include "plib/palloc.h"
|
||||
#include "plib/penum.h"
|
||||
#include "plib/pmatrix2d.h"
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
#include <numeric>
|
||||
|
||||
//FIXME: remove again
|
||||
// FIXME: remove again
|
||||
|
||||
#define PFDEBUG(x)
|
||||
|
||||
@ -42,6 +42,8 @@ namespace netlist::solver
|
||||
CXX_STATIC
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
|
||||
PENUM(matrix_sort_type_e,
|
||||
NOSORT,
|
||||
ASCENDING,
|
||||
@ -67,40 +69,63 @@ namespace netlist::solver
|
||||
, FLOATQ128
|
||||
)
|
||||
|
||||
// clang-format on
|
||||
|
||||
using arena_type = plib::mempool_arena<plib::aligned_arena<>, 1024>;
|
||||
using static_compile_container = std::vector<std::pair<pstring, pstring>>;
|
||||
|
||||
struct solver_parameter_defaults
|
||||
{
|
||||
static constexpr nl_fptype m_freq() { return nlconst::magic(48000.0); }
|
||||
static constexpr nl_fptype m_freq() { return nlconst::magic(48000.0); }
|
||||
|
||||
// iteration parameters
|
||||
static constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
|
||||
static constexpr matrix_type_e m_method() { return matrix_type_e::MAT_CR; }
|
||||
static constexpr matrix_fp_type_e m_fp_type() { return matrix_fp_type_e::DOUBLE; }
|
||||
static constexpr nl_fptype m_reltol() { return nlconst::magic(1e-3); }
|
||||
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
|
||||
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
|
||||
static constexpr std::size_t m_nr_loops() { return 250; }
|
||||
static constexpr std::size_t m_gs_loops() { return 50; }
|
||||
static constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
|
||||
static constexpr matrix_type_e m_method()
|
||||
{
|
||||
return matrix_type_e::MAT_CR;
|
||||
}
|
||||
static constexpr matrix_fp_type_e m_fp_type()
|
||||
{
|
||||
return matrix_fp_type_e::DOUBLE;
|
||||
}
|
||||
static constexpr nl_fptype m_reltol() { return nlconst::magic(1e-3); }
|
||||
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
|
||||
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
|
||||
static constexpr std::size_t m_nr_loops() { return 250; }
|
||||
static constexpr std::size_t m_gs_loops() { return 50; }
|
||||
|
||||
// general parameters
|
||||
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
|
||||
static constexpr bool m_pivot() { return false; }
|
||||
static constexpr nl_fptype m_nr_recalc_delay(){ return netlist_time::quantum().as_fp<nl_fptype>(); }
|
||||
static constexpr int m_parallel() { return 0; }
|
||||
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
|
||||
static constexpr bool m_pivot() { return false; }
|
||||
static constexpr nl_fptype m_nr_recalc_delay()
|
||||
{
|
||||
return netlist_time::quantum().as_fp<nl_fptype>();
|
||||
}
|
||||
static constexpr int m_parallel() { return 0; }
|
||||
|
||||
static constexpr nl_fptype m_min_ts_ts() { return nlconst::magic(1e-9); }
|
||||
static constexpr nl_fptype m_min_ts_ts()
|
||||
{
|
||||
return nlconst::magic(1e-9);
|
||||
}
|
||||
// automatic time step
|
||||
static constexpr bool m_dynamic_ts() { return false; }
|
||||
static constexpr nl_fptype m_dynamic_lte() { return nlconst::magic(1e-5); }
|
||||
static constexpr nl_fptype m_dynamic_min_ts() { return nlconst::magic(1e-6); }
|
||||
static constexpr bool m_dynamic_ts() { return false; }
|
||||
static constexpr nl_fptype m_dynamic_lte()
|
||||
{
|
||||
return nlconst::magic(1e-5);
|
||||
}
|
||||
static constexpr nl_fptype m_dynamic_min_ts()
|
||||
{
|
||||
return nlconst::magic(1e-6);
|
||||
}
|
||||
|
||||
// matrix sorting
|
||||
static constexpr matrix_sort_type_e m_sort_type() { return matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT; }
|
||||
static constexpr matrix_sort_type_e m_sort_type()
|
||||
{
|
||||
return matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT;
|
||||
}
|
||||
|
||||
// special
|
||||
static constexpr bool m_use_gabs() { return true; }
|
||||
static constexpr bool m_use_gabs() { return true; }
|
||||
|
||||
static solver_parameter_defaults &get_instance()
|
||||
{
|
||||
@ -112,30 +137,52 @@ namespace netlist::solver
|
||||
struct solver_parameters_t
|
||||
{
|
||||
template <typename D>
|
||||
solver_parameters_t(device_t &parent, const pstring &prefix, D &defaults)
|
||||
solver_parameters_t(device_t &parent, const pstring &prefix,
|
||||
D &defaults)
|
||||
: m_freq(parent, prefix + "FREQ", defaults.m_freq())
|
||||
|
||||
// iteration parameters
|
||||
, m_gs_sor(parent, prefix + "SOR_FACTOR", defaults.m_gs_sor())
|
||||
, m_method(parent, prefix + "METHOD", defaults.m_method())
|
||||
, m_fp_type(parent, prefix + "FPTYPE", defaults.m_fp_type())
|
||||
, m_reltol(parent, prefix + "RELTOL", defaults.m_reltol()) //!< SPICE RELTOL parameter
|
||||
, m_vntol(parent, prefix + "VNTOL", defaults.m_vntol()) //!< SPICE VNTOL parameter
|
||||
, m_accuracy(parent, prefix + "ACCURACY", defaults.m_accuracy()) //!< Iterative solver accuracy
|
||||
, m_nr_loops(parent, prefix + "NR_LOOPS", defaults.m_nr_loops()) //!< Maximum number of Newton-Raphson loops
|
||||
, m_gs_loops(parent, prefix + "GS_LOOPS", defaults.m_gs_loops()) //!< Maximum number of Gauss-Seidel loops
|
||||
, m_gs_sor(parent, prefix + "SOR_FACTOR", defaults.m_gs_sor())
|
||||
, m_method(parent, prefix + "METHOD", defaults.m_method())
|
||||
, m_fp_type(parent, prefix + "FPTYPE", defaults.m_fp_type())
|
||||
, m_reltol(parent, prefix + "RELTOL",
|
||||
defaults.m_reltol()) //!< SPICE RELTOL parameter
|
||||
, m_vntol(parent, prefix + "VNTOL", defaults.m_vntol()) //!< SPICE VNTOL
|
||||
//!< parameter
|
||||
, m_accuracy(parent, prefix + "ACCURACY",
|
||||
defaults.m_accuracy()) //!< Iterative solver accuracy
|
||||
, m_nr_loops(parent, prefix + "NR_LOOPS",
|
||||
defaults.m_nr_loops()) //!< Maximum number of
|
||||
//!< Newton-Raphson loops
|
||||
, m_gs_loops(parent, prefix + "GS_LOOPS",
|
||||
defaults.m_gs_loops()) //!< Maximum number of Gauss-Seidel
|
||||
//!< loops
|
||||
|
||||
// general parameters
|
||||
, m_gmin(parent, prefix + "GMIN", defaults.m_gmin())
|
||||
, m_pivot(parent, prefix + "PIVOT", defaults.m_pivot()) //!< use pivoting on supported solvers
|
||||
, m_nr_recalc_delay(parent, prefix + "NR_RECALC_DELAY", defaults.m_nr_recalc_delay()) //!< Delay to next solve attempt if nr loops exceeded
|
||||
, m_pivot(parent, prefix + "PIVOT", defaults.m_pivot()) //!< use
|
||||
//!< pivoting on
|
||||
//!< supported
|
||||
//!< solvers
|
||||
, m_nr_recalc_delay(parent, prefix + "NR_RECALC_DELAY",
|
||||
defaults.m_nr_recalc_delay()) //!< Delay to next
|
||||
//!< solve attempt if
|
||||
//!< nr loops exceeded
|
||||
, m_parallel(parent, prefix + "PARALLEL", defaults.m_parallel())
|
||||
, m_min_ts_ts(parent, prefix + "MIN_TS_TS", defaults.m_min_ts_ts()) //!< The minimum time step for solvers with time stepping devices.
|
||||
, m_min_ts_ts(parent, prefix + "MIN_TS_TS",
|
||||
defaults.m_min_ts_ts()) //!< The minimum time step for
|
||||
//!< solvers with time stepping
|
||||
//!< devices.
|
||||
|
||||
// automatic time step
|
||||
, m_dynamic_ts(parent, prefix + "DYNAMIC_TS", defaults.m_dynamic_ts()) //!< Use dynamic time stepping
|
||||
, m_dynamic_lte(parent, prefix + "DYNAMIC_LTE", defaults.m_dynamic_lte()) //!< dynamic time stepping slope
|
||||
, m_dynamic_min_ts(parent, prefix + "DYNAMIC_MIN_TIMESTEP", defaults.m_dynamic_min_ts()) //!< smallest time step allowed
|
||||
, m_dynamic_ts(parent, prefix + "DYNAMIC_TS",
|
||||
defaults.m_dynamic_ts()) //!< Use dynamic time stepping
|
||||
, m_dynamic_lte(parent, prefix + "DYNAMIC_LTE",
|
||||
defaults.m_dynamic_lte()) //!< dynamic time stepping
|
||||
//!< slope
|
||||
, m_dynamic_min_ts(parent, prefix + "DYNAMIC_MIN_TIMESTEP",
|
||||
defaults.m_dynamic_min_ts()) //!< smallest time step
|
||||
//!< allowed
|
||||
|
||||
// matrix sorting
|
||||
, m_sort_type(parent, prefix + "SORT_TYPE", defaults.m_sort_type())
|
||||
@ -144,11 +191,12 @@ namespace netlist::solver
|
||||
, m_use_gabs(parent, prefix + "USE_GABS", defaults.m_use_gabs())
|
||||
, m_min_time_step(m_dynamic_min_ts())
|
||||
{
|
||||
m_max_time_step = netlist_time::from_fp(plib::reciprocal(m_freq())).as_fp<decltype(m_max_time_step)>();
|
||||
m_max_time_step = netlist_time::from_fp(plib::reciprocal(m_freq()))
|
||||
.as_fp<decltype(m_max_time_step)>();
|
||||
|
||||
if (m_dynamic_ts)
|
||||
{
|
||||
m_max_time_step *= 1;//NL_FCONST(1000.0);
|
||||
m_max_time_step *= 1; // NL_FCONST(1000.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -156,23 +204,23 @@ namespace netlist::solver
|
||||
}
|
||||
}
|
||||
|
||||
param_fp_t m_freq;
|
||||
param_fp_t m_gs_sor;
|
||||
param_enum_t<matrix_type_e> m_method;
|
||||
param_enum_t<matrix_fp_type_e> m_fp_type;
|
||||
param_fp_t m_reltol;
|
||||
param_fp_t m_vntol;
|
||||
param_fp_t m_accuracy;
|
||||
param_num_t<std::size_t> m_nr_loops;
|
||||
param_num_t<std::size_t> m_gs_loops;
|
||||
param_fp_t m_gmin;
|
||||
param_logic_t m_pivot;
|
||||
param_fp_t m_nr_recalc_delay;
|
||||
param_int_t m_parallel;
|
||||
param_fp_t m_min_ts_ts;
|
||||
param_logic_t m_dynamic_ts;
|
||||
param_fp_t m_dynamic_lte;
|
||||
param_fp_t m_dynamic_min_ts;
|
||||
param_fp_t m_freq;
|
||||
param_fp_t m_gs_sor;
|
||||
param_enum_t<matrix_type_e> m_method;
|
||||
param_enum_t<matrix_fp_type_e> m_fp_type;
|
||||
param_fp_t m_reltol;
|
||||
param_fp_t m_vntol;
|
||||
param_fp_t m_accuracy;
|
||||
param_num_t<std::size_t> m_nr_loops;
|
||||
param_num_t<std::size_t> m_gs_loops;
|
||||
param_fp_t m_gmin;
|
||||
param_logic_t m_pivot;
|
||||
param_fp_t m_nr_recalc_delay;
|
||||
param_int_t m_parallel;
|
||||
param_fp_t m_min_ts_ts;
|
||||
param_logic_t m_dynamic_ts;
|
||||
param_fp_t m_dynamic_lte;
|
||||
param_fp_t m_dynamic_min_ts;
|
||||
param_enum_t<matrix_sort_type_e> m_sort_type;
|
||||
|
||||
param_logic_t m_use_gabs;
|
||||
@ -181,11 +229,10 @@ namespace netlist::solver
|
||||
nl_fptype m_max_time_step;
|
||||
};
|
||||
|
||||
|
||||
class terms_for_net_t
|
||||
{
|
||||
public:
|
||||
terms_for_net_t(arena_type &arena, analog_net_t * net = nullptr);
|
||||
terms_for_net_t(arena_type &arena, analog_net_t *net = nullptr);
|
||||
|
||||
void clear();
|
||||
|
||||
@ -201,35 +248,49 @@ namespace netlist::solver
|
||||
|
||||
void setV(nl_fptype v) noexcept { m_net->set_Q_Analog(v); }
|
||||
|
||||
bool is_net(const analog_net_t * net) const noexcept { return net == m_net; }
|
||||
bool is_net(const analog_net_t *net) const noexcept
|
||||
{
|
||||
return net == m_net;
|
||||
}
|
||||
|
||||
void set_rail_start(std::size_t val) noexcept { m_rail_start = val; }
|
||||
|
||||
PALIGNAS_VECTOROPT()
|
||||
|
||||
plib::arena_vector<arena_type, unsigned> m_nz; //!< all non zero for multiplication
|
||||
plib::arena_vector<arena_type, unsigned> m_nzrd; //!< non zero right of the diagonal for elimination, may include RHS element
|
||||
plib::arena_vector<arena_type, unsigned> m_nzbd; //!< non zero below of the diagonal for elimination
|
||||
plib::arena_vector<arena_type, unsigned> m_nz; //!< all non zero for
|
||||
//!< multiplication
|
||||
plib::arena_vector<arena_type, unsigned> m_nzrd; //!< non zero right of
|
||||
//!< the diagonal for
|
||||
//!< elimination, may
|
||||
//!< include RHS
|
||||
//!< element
|
||||
plib::arena_vector<arena_type, unsigned> m_nzbd; //!< non zero below of
|
||||
//!< the diagonal for
|
||||
//!< elimination
|
||||
|
||||
plib::arena_vector<arena_type, int> m_connected_net_idx;
|
||||
|
||||
private:
|
||||
plib::arena_vector<arena_type, terminal_t *> m_terms;
|
||||
analog_net_t * m_net;
|
||||
std::size_t m_rail_start;
|
||||
analog_net_t *m_net;
|
||||
std::size_t m_rail_start;
|
||||
};
|
||||
|
||||
class proxied_analog_output_t : public analog_output_t
|
||||
{
|
||||
public:
|
||||
|
||||
proxied_analog_output_t(core_device_t &dev, const pstring &aname, analog_net_t *pnet)
|
||||
proxied_analog_output_t(core_device_t &dev, const pstring &aname,
|
||||
analog_net_t *pnet)
|
||||
: analog_output_t(dev, aname)
|
||||
, m_proxied_net(pnet)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
analog_net_t *proxied_net() const { return m_proxied_net; }
|
||||
|
||||
analog_net_t *proxied_net() const { return m_proxied_net;}
|
||||
private:
|
||||
analog_net_t *m_proxied_net; // only for proxy nets in analog input logic
|
||||
analog_net_t *m_proxied_net; // only for proxy nets in analog input
|
||||
// logic
|
||||
};
|
||||
|
||||
class matrix_solver_t : public device_t
|
||||
@ -237,16 +298,22 @@ namespace netlist::solver
|
||||
public:
|
||||
using list_t = std::vector<matrix_solver_t *>;
|
||||
using fptype = nl_fptype;
|
||||
using net_list_t = std::vector<analog_net_t *>;
|
||||
using net_list_t = std::vector<analog_net_t *>;
|
||||
|
||||
// after every call to solve, update inputs must be called.
|
||||
// this can be done as well as a batch to ease parallel processing.
|
||||
|
||||
netlist_time solve(netlist_time_ext now, const char *source);
|
||||
void update_inputs();
|
||||
void update_inputs();
|
||||
|
||||
std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); }
|
||||
std::size_t time_step_device_count() const noexcept { return m_step_funcs.size(); }
|
||||
std::size_t dynamic_device_count() const noexcept
|
||||
{
|
||||
return m_dynamic_funcs.size();
|
||||
}
|
||||
std::size_t time_step_device_count() const noexcept
|
||||
{
|
||||
return m_step_funcs.size();
|
||||
}
|
||||
|
||||
/// \brief reschedule solver execution
|
||||
///
|
||||
@ -264,23 +331,28 @@ namespace netlist::solver
|
||||
// this should only occur outside of execution and thus
|
||||
// using time should be safe.
|
||||
|
||||
[[maybe_unused]] const netlist_time new_time_step = solve(exec().time(), "solve_now");
|
||||
[[maybe_unused]] const netlist_time new_time_step = solve(
|
||||
exec().time(), "solve_now");
|
||||
|
||||
update_inputs();
|
||||
|
||||
if (time_step_device_count() > 0)
|
||||
{
|
||||
this->reschedule(netlist_time::from_fp(m_params.m_dynamic_ts ? m_params.m_min_time_step : m_params.m_max_time_step));
|
||||
this->reschedule(netlist_time::from_fp(
|
||||
m_params.m_dynamic_ts ? m_params.m_min_time_step
|
||||
: m_params.m_max_time_step));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void change_state(F f)
|
||||
{
|
||||
// We only need to update the net first if this is a time stepping net
|
||||
// We only need to update the net first if this is a time stepping
|
||||
// net
|
||||
if (time_step_device_count() > 0)
|
||||
{
|
||||
[[maybe_unused]] const netlist_time new_time_step = solve(exec().time(), "change_state");
|
||||
[[maybe_unused]] const netlist_time new_time_step = solve(
|
||||
exec().time(), "change_state");
|
||||
update_inputs();
|
||||
}
|
||||
f();
|
||||
@ -297,9 +369,11 @@ namespace netlist::solver
|
||||
|
||||
virtual void log_stats();
|
||||
|
||||
virtual std::pair<pstring, pstring> create_solver_code([[maybe_unused]] solver::static_compile_target target)
|
||||
virtual std::pair<pstring, pstring> create_solver_code(
|
||||
[[maybe_unused]] solver::static_compile_target target)
|
||||
{
|
||||
return { "", plib::pfmt("// solver doesn't support static compile\n\n") };
|
||||
return {"",
|
||||
plib::pfmt("// solver doesn't support static compile\n\n")};
|
||||
}
|
||||
|
||||
// return number of floating point operations for solve
|
||||
@ -307,11 +381,13 @@ namespace netlist::solver
|
||||
|
||||
protected:
|
||||
matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
|
||||
const net_list_t &nets,
|
||||
const solver_parameters_t *params);
|
||||
const net_list_t &nets,
|
||||
const solver_parameters_t *params);
|
||||
|
||||
virtual void upstream_solve_non_dynamic() = 0;
|
||||
virtual netlist_time compute_next_time_step(fptype cur_ts, fptype min_ts, fptype max_ts) = 0;
|
||||
virtual netlist_time
|
||||
compute_next_time_step(fptype cur_ts, fptype min_ts, fptype max_ts)
|
||||
= 0;
|
||||
virtual bool check_err() const = 0;
|
||||
virtual void store() = 0;
|
||||
virtual void backup() = 0;
|
||||
@ -326,7 +402,7 @@ namespace netlist::solver
|
||||
}
|
||||
|
||||
const solver_parameters_t &m_params;
|
||||
arena_type m_arena;
|
||||
arena_type m_arena;
|
||||
|
||||
plib::pmatrix2d_vrl<arena_type, fptype> m_gonn;
|
||||
plib::pmatrix2d_vrl<arena_type, fptype> m_gtn;
|
||||
@ -339,20 +415,20 @@ namespace netlist::solver
|
||||
std::vector<terms_for_net_t> m_terms; // setup only
|
||||
|
||||
private:
|
||||
|
||||
// base setup - called from constructor
|
||||
void setup_base(setup_t &setup, const net_list_t &nets) noexcept(false);
|
||||
|
||||
bool solve_nr_base();
|
||||
bool solve_nr_base();
|
||||
netlist_time newton_loops_exceeded(netlist_time delta);
|
||||
|
||||
void sort_terms(matrix_sort_type_e sort);
|
||||
|
||||
void update_dynamic() noexcept;
|
||||
void step(time_step_type ts_type, netlist_time delta) noexcept;
|
||||
void step(detail::time_step_type ts_type, netlist_time delta) noexcept;
|
||||
|
||||
int get_net_idx(const analog_net_t *net) const noexcept;
|
||||
std::pair<int, int> get_left_right_of_diagonal(std::size_t irow, std::size_t idiag);
|
||||
std::pair<int, int>
|
||||
get_left_right_of_diagonal(std::size_t irow, std::size_t idiag);
|
||||
fptype get_weight_around_diagonal(std::size_t row, std::size_t diag);
|
||||
|
||||
void add_term(std::size_t net_idx, terminal_t *term) noexcept(false);
|
||||
@ -371,10 +447,12 @@ namespace netlist::solver
|
||||
state_var<std::size_t> m_stat_newton_raphson_fail;
|
||||
state_var<std::size_t> m_stat_vsolver_calls;
|
||||
|
||||
state_var<netlist_time_ext> m_last_step;
|
||||
plib::arena_vector<arena_type, nl_delegate_ts> m_step_funcs;
|
||||
state_var<netlist_time_ext> m_last_step;
|
||||
plib::arena_vector<arena_type, nl_delegate_ts> m_step_funcs;
|
||||
plib::arena_vector<arena_type, nl_delegate_dyn> m_dynamic_funcs;
|
||||
plib::arena_vector<arena_type, device_arena::unique_ptr<proxied_analog_output_t>> m_inputs;
|
||||
plib::arena_vector<arena_type,
|
||||
device_arena::unique_ptr<proxied_analog_output_t>>
|
||||
m_inputs;
|
||||
|
||||
std::size_t m_ops;
|
||||
|
||||
|
@ -2,12 +2,12 @@
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
///
|
||||
/// \file test_pmfp.cpp
|
||||
/// \file test_precommit.cpp
|
||||
///
|
||||
/// tests for `plib::pmfp`
|
||||
/// tests to check for experimental code before commit
|
||||
///
|
||||
|
||||
#include "netlist/nl_config.h"
|
||||
#include "nl_config.h"
|
||||
|
||||
#include "plib/pconfig.h"
|
||||
#include "plib/ppmf.h"
|
||||
|
Loading…
Reference in New Issue
Block a user