mirror of
https://github.com/holub/mame
synced 2025-04-28 19:14:55 +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 "emu.h"
|
||||||
#include "netlist.h"
|
#include "netlist.h"
|
||||||
|
|
||||||
#include "netlist/nl_base.h"
|
|
||||||
#include "netlist/nl_setup.h"
|
#include "netlist/nl_setup.h"
|
||||||
#include "netlist/nl_factory.h"
|
#include "netlist/nl_factory.h"
|
||||||
#include "netlist/nl_parser.h"
|
#include "netlist/nl_parser.h"
|
||||||
#include "netlist/nl_interface.h"
|
#include "netlist/nl_interface.h"
|
||||||
|
|
||||||
#include "netlist/plib/palloc.h"
|
|
||||||
#include "netlist/plib/pmempool.h"
|
|
||||||
#include "netlist/plib/pdynlib.h"
|
#include "netlist/plib/pdynlib.h"
|
||||||
#include "netlist/plib/pstonum.h"
|
#include "netlist/plib/pstonum.h"
|
||||||
|
|
||||||
|
@ -13,13 +13,15 @@
|
|||||||
|
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
// emu.h must be first to be included
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
|
|
||||||
#include "fixfreq.h"
|
#include "fixfreq.h"
|
||||||
|
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "ui/uimain.h"
|
#include "ui/uimain.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <iostream>
|
||||||
|
|
||||||
// for quick and dirty debugging
|
// for quick and dirty debugging
|
||||||
#define VERBOSE 0
|
#define VERBOSE 0
|
||||||
@ -36,7 +38,8 @@
|
|||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
// device type definition
|
// 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
|
// Port adjuster support
|
||||||
@ -44,7 +47,10 @@ DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monoch
|
|||||||
|
|
||||||
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
|
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
|
||||||
PORT_START(#_id) \
|
PORT_START(#_id) \
|
||||||
configurer.field_alloc(IPT_ADJUSTER, (static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, ("Monitor - " _name)); \
|
configurer.field_alloc( \
|
||||||
|
IPT_ADJUSTER, \
|
||||||
|
(static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, \
|
||||||
|
("Monitor - " _name)); \
|
||||||
PORT_MINMAX(_min, _max) \
|
PORT_MINMAX(_min, _max) \
|
||||||
PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
|
PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
|
||||||
PORT_CONDITION("ENABLE", 0x01, EQUALS, 0x01)
|
PORT_CONDITION("ENABLE", 0x01, EQUALS, 0x01)
|
||||||
@ -67,14 +73,17 @@ enum fixedfreq_tag_id_e
|
|||||||
SCANLINE_HEIGHT
|
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 time_type delta_time = time - m_last_sync_time;
|
||||||
|
|
||||||
const int last_vsync = m_sig_vsync;
|
const int last_vsync = m_sig_vsync;
|
||||||
const int last_comp = m_sig_composite;
|
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_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_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0;
|
||||||
|
|
||||||
m_sig_vsync = (m_vsync_filter > m_desc.m_vsync_threshold) ? 1 : 0;
|
m_sig_vsync = (m_vsync_filter > m_desc.m_vsync_threshold) ? 1 : 0;
|
||||||
@ -84,13 +93,16 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
|
|||||||
LOG("VSYNC UP %f %d\n", m_last_x, m_last_y);
|
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)
|
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_last_field_time = time;
|
||||||
m_sig_field = avg_line_dur * 0.75 > m_last_line_duration;
|
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.
|
// notify the controlling device about the vsync and the field.
|
||||||
@ -109,7 +121,8 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
|
|||||||
if (m_sig_vsync)
|
if (m_sig_vsync)
|
||||||
LOG("Hsync in vsync\n");
|
LOG("Hsync in vsync\n");
|
||||||
// LOG("HSYNC up %d\n", m_last_x);
|
// LOG("HSYNC up %d\n", m_last_x);
|
||||||
// FIXME: pixels > 0 filters some spurious hysnc on line 23/24 in breakout
|
// 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
|
// 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.
|
// early, goes up again after 6.8 pix and down after 7.2 pix.
|
||||||
// Therefore we need to filter early low to high transitions
|
// Therefore we need to filter early low to high transitions
|
||||||
@ -122,7 +135,6 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
|
|||||||
|
|
||||||
m_last_line_duration = time - m_last_hsync_time;
|
m_last_line_duration = time - m_last_hsync_time;
|
||||||
m_last_hsync_time = time;
|
m_last_hsync_time = time;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (last_comp && !m_sig_composite)
|
else if (last_comp && !m_sig_composite)
|
||||||
@ -147,19 +159,22 @@ void fixedfreq_monitor_state::update_bm(const time_type &time)
|
|||||||
if (!m_sig_vsync && !m_sig_composite)
|
if (!m_sig_vsync && !m_sig_composite)
|
||||||
{
|
{
|
||||||
// uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
|
// uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
|
||||||
m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields),
|
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_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;
|
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_bm(time);
|
||||||
update_sync_channel(time, data);
|
update_sync_channel(time, 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);
|
||||||
int colv = (int)((data - 1.5) * m_desc.m_gain * 255.0);
|
int colv = (int)((data - 1.5) * m_desc.m_gain * 255.0);
|
||||||
if (colv > 255)
|
if (colv > 255)
|
||||||
colv = 255;
|
colv = 255;
|
||||||
@ -170,7 +185,8 @@ void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time,
|
|||||||
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);
|
update_bm(time);
|
||||||
|
|
||||||
@ -182,7 +198,8 @@ void fixedfreq_monitor_state::update_red(const time_type &time, const double dat
|
|||||||
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_bm(time);
|
||||||
// update_sync_channel(ctime, data);
|
// update_sync_channel(ctime, data);
|
||||||
@ -195,7 +212,8 @@ void fixedfreq_monitor_state::update_green(const time_type &time, const double d
|
|||||||
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_bm(time);
|
||||||
// update_sync_channel(ctime, data);
|
// update_sync_channel(ctime, data);
|
||||||
@ -206,28 +224,32 @@ void fixedfreq_monitor_state::update_blue(const time_type &time, const double da
|
|||||||
if (colv < 0)
|
if (colv < 0)
|
||||||
colv = 0;
|
colv = 0;
|
||||||
m_col = (m_col & 0xffffff00) | colv;
|
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_bm(time);
|
||||||
update_sync_channel(time, data);
|
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)
|
fixedfreq_device::fixedfreq_device(const machine_config &mconfig,
|
||||||
: device_t(mconfig, type, tag, owner, clock),
|
device_type type, const char *tag,
|
||||||
device_video_interface(mconfig, *this, false),
|
device_t *owner, uint32_t clock)
|
||||||
m_enable(*this, "ENABLE"),
|
: device_t(mconfig, type, tag, owner, clock)
|
||||||
m_vector(*this, "VECTOR"),
|
, device_video_interface(mconfig, *this, false)
|
||||||
m_scanline_height(1.0),
|
, m_enable(*this, "ENABLE")
|
||||||
m_last_rt(0.0),
|
, m_vector(*this, "VECTOR")
|
||||||
m_monitor(),
|
, m_scanline_height(1.0)
|
||||||
m_state(m_monitor, *this)
|
, 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::fixedfreq_device(const machine_config &mconfig,
|
||||||
|
const char *tag, device_t *owner,
|
||||||
|
uint32_t clock)
|
||||||
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
|
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -254,7 +276,8 @@ void fixedfreq_device::device_config_complete()
|
|||||||
m_monitor.htotal(), m_monitor.vtotal(), 0,
|
m_monitor.htotal(), m_monitor.vtotal(), 0,
|
||||||
m_monitor.vtotal());
|
m_monitor.vtotal());
|
||||||
if (!screen().has_screen_update())
|
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");
|
LOG("config complete\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,10 +344,12 @@ static uint32_t nom_col(uint32_t col)
|
|||||||
if (m == 0.0f)
|
if (m == 0.0f)
|
||||||
return 0;
|
return 0;
|
||||||
return (((uint32_t)m) << 24) | (((uint32_t)(r / m * 255.0f)) << 16)
|
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);
|
| (((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
|
// Test pattern Grey scale
|
||||||
const int stripes = 255;
|
const int stripes = 255;
|
||||||
@ -336,7 +361,8 @@ static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rect
|
|||||||
int l = va.left() + (i * va.width() / stripes);
|
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;
|
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);
|
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
|
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("%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);
|
// printf("%d %lu %f %f\n", m_state.m_sig_vsync, m_state.m_fragments.size(),
|
||||||
bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR || (m_vector->read() & 1);
|
// 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 debug_timing = (m_enable->read() & 2) == 2;
|
||||||
bool test_pat = (m_enable->read() & 4) == 4;
|
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);
|
rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00)
|
||||||
|
: rgb_t(0xff, 0x00, 0x00, 0x00);
|
||||||
|
|
||||||
if (!force_vector)
|
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);
|
screen.set_video_attributes(VIDEO_SELF_RENDER);
|
||||||
|
|
||||||
const uint32_t flags(PRIMFLAG_ANTIALIAS(1)
|
const uint32_t flags(
|
||||||
| PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
|
PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
|
||||||
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1) : 0));
|
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1)
|
||||||
|
: 0));
|
||||||
const rectangle &visarea = screen.visible_area();
|
const rectangle &visarea = screen.visible_area();
|
||||||
float xscale = 1.0f / (float)visarea.width();
|
float xscale = 1.0f / (float)visarea.width();
|
||||||
float yscale = 1.0f / (float)visarea.height();
|
float yscale = 1.0f / (float)visarea.height();
|
||||||
float xoffs = (float)visarea.min_x;
|
float xoffs = (float)visarea.min_x;
|
||||||
float yoffs = (float)visarea.min_y;
|
float yoffs = (float)visarea.min_y;
|
||||||
screen.container().empty();
|
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)
|
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;
|
float last_y = -1e6;
|
||||||
for (auto &f : m_state.m_fragments)
|
for (auto &f : m_state.m_fragments)
|
||||||
@ -408,20 +444,17 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
|
|||||||
flags);
|
flags);
|
||||||
#elif 1
|
#elif 1
|
||||||
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
||||||
screen.container().add_rect(
|
screen.container().add_rect(x0, y0, x1, y1, nom_col(col),
|
||||||
x0, y0, x1, y1,
|
// (0xaf << 24) |
|
||||||
nom_col(col),
|
// (f.col & 0xffffff),
|
||||||
// (0xaf << 24) | (f.col & 0xffffff),
|
|
||||||
flags);
|
flags);
|
||||||
#else
|
#else
|
||||||
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
const float y1((f.y + m_scanline_height - yoffs) * yscale);
|
||||||
// Crashes with bgfx
|
// Crashes with bgfx
|
||||||
screen.container().add_quad(
|
screen.container().add_quad(x0, y0, x1, y1, rgb_t(nom_col(f.col)),
|
||||||
x0, y0, x1, y1,
|
// (0xaf << 24) |
|
||||||
rgb_t(nom_col(f.col)),
|
// (f.col & 0xffffff),
|
||||||
// (0xaf << 24) | (f.col & 0xffffff),
|
m_texture, flags);
|
||||||
m_texture,
|
|
||||||
flags);
|
|
||||||
#endif
|
#endif
|
||||||
last_y = f.y;
|
last_y = f.y;
|
||||||
}
|
}
|
||||||
@ -432,7 +465,8 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
|
|||||||
|
|
||||||
void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
|
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());
|
const auto expected_frame_period(m_monitor.clock_period()
|
||||||
|
* m_monitor.vtotal() * m_monitor.htotal());
|
||||||
bool progressive = (m_enable->read() & 8) == 8;
|
bool progressive = (m_enable->read() & 8) == 8;
|
||||||
|
|
||||||
double mult = 0.5;
|
double mult = 0.5;
|
||||||
@ -448,15 +482,21 @@ void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
|
|||||||
mult = 1.0;
|
mult = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto refresh_limited(std::min(4.0 * expected_frame_period,
|
const auto refresh_limited(std::min(
|
||||||
std::max((refresh_time + m_last_rt) * mult, 0.25 * expected_frame_period)));
|
4.0 * expected_frame_period, std::max((refresh_time + m_last_rt) * mult,
|
||||||
|
0.25 * expected_frame_period)));
|
||||||
|
|
||||||
m_last_rt = refresh_time;
|
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.
|
// reset_origin must be called first.
|
||||||
screen().reset_origin(m_state.m_last_y-(m_monitor.vsync_width() + m_monitor.vbackporch_width()), 0);
|
screen().reset_origin(
|
||||||
screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea, DOUBLE_TO_ATTOSECONDS(refresh_limited));
|
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)
|
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)
|
static INPUT_PORTS_START(fixedfreq_base_ports)
|
||||||
PORT_START("ENABLE")
|
PORT_START("ENABLE")
|
||||||
PORT_CONFNAME( 0x01, 0x00, "Display Monitor sliders" )
|
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)
|
PORT_ADJUSTERX(SCANLINE_HEIGHT, "Scanline Height", 10, 300)
|
||||||
INPUT_PORTS_END
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
//
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
ioport_constructor fixedfreq_device::device_input_ports() const
|
ioport_constructor fixedfreq_device::device_input_ports() const
|
||||||
{
|
{
|
||||||
LOG("input ports\n");
|
LOG("input ports\n");
|
||||||
@ -567,30 +612,18 @@ unsigned fixedfreq_device::monitor_val(unsigned param) const
|
|||||||
{
|
{
|
||||||
switch (param)
|
switch (param)
|
||||||
{
|
{
|
||||||
case HVISIBLE:
|
case HVISIBLE: return m_monitor.hvisible_width();
|
||||||
return m_monitor.hvisible_width();
|
case HFRONTPORCH: return m_monitor.hfrontporch_width();
|
||||||
case HFRONTPORCH:
|
case HSYNC: return m_monitor.hsync_width();
|
||||||
return m_monitor.hfrontporch_width();
|
case HBACKPORCH: return m_monitor.hbackporch_width();
|
||||||
case HSYNC:
|
case VVISIBLE: return m_monitor.vvisible_width();
|
||||||
return m_monitor.hsync_width();
|
case VFRONTPORCH: return m_monitor.vfrontporch_width();
|
||||||
case HBACKPORCH:
|
case VSYNC: return m_monitor.vsync_width();
|
||||||
return m_monitor.hbackporch_width();
|
case VBACKPORCH: return m_monitor.vbackporch_width();
|
||||||
case VVISIBLE:
|
case SYNCTHRESHOLD: return m_monitor.m_sync_threshold * 1000.0;
|
||||||
return m_monitor.vvisible_width();
|
case VSYNCTHRESHOLD: return m_monitor.m_vsync_threshold * 1000.0;
|
||||||
case VFRONTPORCH:
|
case GAIN: return m_monitor.m_gain * 100.0;
|
||||||
return m_monitor.vfrontporch_width();
|
case SCANLINE_HEIGHT: return m_scanline_height * 100.0;
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -603,28 +636,36 @@ INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
|
|||||||
switch (param)
|
switch (param)
|
||||||
{
|
{
|
||||||
case HVISIBLE:
|
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;
|
break;
|
||||||
case HFRONTPORCH:
|
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;
|
break;
|
||||||
case HSYNC:
|
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;
|
break;
|
||||||
case HBACKPORCH:
|
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;
|
break;
|
||||||
case VVISIBLE:
|
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;
|
break;
|
||||||
case VFRONTPORCH:
|
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;
|
break;
|
||||||
case VSYNC:
|
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;
|
break;
|
||||||
case VBACKPORCH:
|
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;
|
break;
|
||||||
case SYNCTHRESHOLD:
|
case SYNCTHRESHOLD:
|
||||||
m.m_sync_threshold = static_cast<double>(newval) / 1000.0;
|
m.m_sync_threshold = static_cast<double>(newval) / 1000.0;
|
||||||
@ -632,13 +673,12 @@ INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
|
|||||||
case VSYNCTHRESHOLD:
|
case VSYNCTHRESHOLD:
|
||||||
m.m_vsync_threshold = static_cast<double>(newval) / 1000.0;
|
m.m_vsync_threshold = static_cast<double>(newval) / 1000.0;
|
||||||
break;
|
break;
|
||||||
case GAIN:
|
case GAIN: m.m_gain = static_cast<double>(newval) / 100.0; break;
|
||||||
m.m_gain = static_cast<double>(newval) / 100.0;
|
|
||||||
break;
|
|
||||||
case SCANLINE_HEIGHT:
|
case SCANLINE_HEIGHT:
|
||||||
m_scanline_height = static_cast<double>(newval) / 100.0;
|
m_scanline_height = static_cast<double>(newval) / 100.0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(), m.vtotal());
|
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(),
|
||||||
|
m.vtotal());
|
||||||
// ioport("YYY")->update_defvalue(true);
|
// ioport("YYY")->update_defvalue(true);
|
||||||
}
|
}
|
||||||
|
@ -21,41 +21,58 @@ struct fixedfreq_monitor_desc
|
|||||||
{
|
{
|
||||||
fixedfreq_monitor_desc()
|
fixedfreq_monitor_desc()
|
||||||
// default to NTSC "704x480@30i"
|
// default to NTSC "704x480@30i"
|
||||||
: m_monitor_clock(13500000),
|
: m_monitor_clock(13500000)
|
||||||
m_fieldcount(2),
|
, m_fieldcount(2)
|
||||||
m_sync_threshold(0.3),
|
, m_sync_threshold(0.3)
|
||||||
m_gain(1.0 / 3.7),
|
, m_gain(1.0 / 3.7)
|
||||||
m_hscale(1),
|
, m_hscale(1)
|
||||||
m_vsync_threshold(0.600), // trigger at 91% of vsync length 1-exp(-0.6)
|
, m_vsync_threshold(0.600)
|
||||||
m_hvisible(704),
|
, // trigger at 91% of vsync length 1-exp(-0.6)
|
||||||
m_hfrontporch(728),
|
m_hvisible(704)
|
||||||
m_hsync(791),
|
, m_hfrontporch(728)
|
||||||
m_hbackporch(858),
|
, m_hsync(791)
|
||||||
m_vvisible(480),
|
, m_hbackporch(858)
|
||||||
m_vfrontporch(486),
|
, m_vvisible(480)
|
||||||
m_vsync(492),
|
, m_vfrontporch(486)
|
||||||
m_vbackporch(525)
|
, m_vsync(492)
|
||||||
{}
|
, m_vbackporch(525)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t monitor_clock() const noexcept { return m_monitor_clock; }
|
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 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 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 htotal_scaled() const noexcept { return m_hbackporch * m_hscale; }
|
||||||
|
|
||||||
int vbackporch_width() const noexcept { return m_vbackporch - m_vsync; }
|
int vbackporch_width() const noexcept { return m_vbackporch - m_vsync; }
|
||||||
int vsync_width() const noexcept { return m_vsync - m_vfrontporch; }
|
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 vvisible_width() const noexcept { return m_vvisible; }
|
||||||
int vtotal() const noexcept { return m_vbackporch; }
|
int vtotal() const noexcept { return m_vbackporch; }
|
||||||
|
|
||||||
int hbackporch_width() const noexcept { return m_hbackporch - m_hsync; }
|
int hbackporch_width() const noexcept { return m_hbackporch - m_hsync; }
|
||||||
int hsync_width() const noexcept { return m_hsync - m_hfrontporch; }
|
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 hvisible_width() const noexcept { return m_hvisible; }
|
||||||
int htotal() const noexcept { return m_hbackporch; }
|
int htotal() const noexcept { return m_hbackporch; }
|
||||||
|
|
||||||
@ -77,7 +94,8 @@ struct fixedfreq_monitor_desc
|
|||||||
|
|
||||||
double vsync_filter_timeconst() const noexcept
|
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
|
double hsync_filter_timeconst() const noexcept
|
||||||
@ -91,6 +109,7 @@ struct fixedfreq_monitor_desc
|
|||||||
double m_gain;
|
double m_gain;
|
||||||
int m_hscale;
|
int m_hscale;
|
||||||
double m_vsync_threshold;
|
double m_vsync_threshold;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_hvisible;
|
int m_hvisible;
|
||||||
int m_hfrontporch;
|
int m_hfrontporch;
|
||||||
@ -120,24 +139,26 @@ struct fixedfreq_monitor_state
|
|||||||
{
|
{
|
||||||
using time_type = double;
|
using time_type = double;
|
||||||
|
|
||||||
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc, fixedfreq_monitor_intf &intf)
|
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc,
|
||||||
: m_desc(desc),
|
fixedfreq_monitor_intf &intf)
|
||||||
m_intf(intf),
|
: m_desc(desc)
|
||||||
m_last_sync_val(0),
|
, m_intf(intf)
|
||||||
m_col(0),
|
, m_last_sync_val(0)
|
||||||
m_last_x(0),
|
, m_col(0)
|
||||||
m_last_y(0),
|
, m_last_x(0)
|
||||||
m_last_sync_time(time_type(0)),
|
, m_last_y(0)
|
||||||
m_line_time(time_type(0)),
|
, m_last_sync_time(time_type(0))
|
||||||
m_last_hsync_time(time_type(0)),
|
, m_line_time(time_type(0))
|
||||||
m_last_vsync_time(time_type(0)),
|
, m_last_hsync_time(time_type(0))
|
||||||
m_last_line_duration(time_type(0)),
|
, m_last_vsync_time(time_type(0))
|
||||||
m_last_field_time(time_type(0)),
|
, m_last_line_duration(time_type(0))
|
||||||
m_vsync_filter(0),
|
, m_last_field_time(time_type(0))
|
||||||
m_sig_vsync(0),
|
, m_vsync_filter(0)
|
||||||
m_sig_composite(0),
|
, m_sig_vsync(0)
|
||||||
m_sig_field(0)
|
, m_sig_composite(0)
|
||||||
{}
|
, m_sig_field(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* \brief To be called after monitor parameters are set
|
* \brief To be called after monitor parameters are set
|
||||||
@ -169,12 +190,14 @@ struct fixedfreq_monitor_state
|
|||||||
/* sync separator */
|
/* sync separator */
|
||||||
|
|
||||||
// m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
|
// 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);
|
// printf("trigger %f with len %f\n", m_vsync_threshold, 1e6 /
|
||||||
|
// m_vsync_filter_timeconst);
|
||||||
// Minimum frame period to be passed to video system ?
|
// Minimum frame period to be passed to video system ?
|
||||||
|
|
||||||
m_fragments.clear();
|
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()
|
void reset()
|
||||||
@ -192,7 +215,8 @@ struct fixedfreq_monitor_state
|
|||||||
|
|
||||||
void update_sync_channel(const time_type &time, const double newval);
|
void update_sync_channel(const time_type &time, const double newval);
|
||||||
void update_bm(const time_type &time);
|
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_red(const time_type &time, const double data);
|
||||||
void update_green(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_blue(const time_type &time, const double data);
|
||||||
@ -224,44 +248,68 @@ struct fixedfreq_monitor_state
|
|||||||
|
|
||||||
// ======================> fixedfreq_device
|
// ======================> fixedfreq_device
|
||||||
|
|
||||||
class fixedfreq_device : public device_t, public device_video_interface,
|
class fixedfreq_device
|
||||||
public fixedfreq_monitor_intf
|
: public device_t
|
||||||
|
, public device_video_interface
|
||||||
|
, public fixedfreq_monitor_intf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using time_type = fixedfreq_monitor_state::time_type;
|
using time_type = fixedfreq_monitor_state::time_type;
|
||||||
|
|
||||||
// construction/destruction
|
// 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
|
// inline configuration helpers
|
||||||
fixedfreq_device &set_monitor_clock(uint32_t clock) { m_monitor.m_monitor_clock = clock; return *this;}
|
fixedfreq_device &set_monitor_clock(uint32_t clock)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
m_monitor.set_h_rel(
|
m_monitor.m_monitor_clock = clock;
|
||||||
visible,
|
return *this;
|
||||||
frontporch - visible,
|
}
|
||||||
sync - frontporch,
|
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)
|
||||||
|
{
|
||||||
|
m_monitor.set_h_rel(visible, frontporch - visible, sync - frontporch,
|
||||||
backporch - sync);
|
backporch - sync);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
fixedfreq_device &set_vert_params(int visible, int frontporch, int sync, int backporch)
|
fixedfreq_device &
|
||||||
|
set_vert_params(int visible, int frontporch, int sync, int backporch)
|
||||||
{
|
{
|
||||||
m_monitor.set_v_rel(
|
m_monitor.set_v_rel(visible, frontporch - visible, sync - frontporch,
|
||||||
visible,
|
|
||||||
frontporch - visible,
|
|
||||||
sync - frontporch,
|
|
||||||
backporch - sync);
|
backporch - sync);
|
||||||
return *this;
|
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
|
// 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_monitor_clock(13500000);
|
||||||
set_horz_params(720, 736, 799, 858);
|
set_horz_params(720, 736, 799, 858);
|
||||||
@ -270,7 +318,8 @@ public:
|
|||||||
set_threshold(0.3);
|
set_threshold(0.3);
|
||||||
return *this;
|
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_monitor_clock(13500000);
|
||||||
set_horz_params(704, 728, 791, 858);
|
set_horz_params(704, 728, 791, 858);
|
||||||
@ -280,7 +329,8 @@ public:
|
|||||||
return *this;
|
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_composite_monochrome);
|
||||||
NETDEV_ANALOG_CALLBACK_MEMBER(update_red);
|
NETDEV_ANALOG_CALLBACK_MEMBER(update_red);
|
||||||
@ -293,8 +343,8 @@ public:
|
|||||||
unsigned monitor_val(unsigned param) const;
|
unsigned monitor_val(unsigned param) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
fixedfreq_device(const machine_config &mconfig, device_type type,
|
||||||
fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
virtual void device_config_complete() override;
|
virtual void device_config_complete() override;
|
||||||
@ -315,10 +365,8 @@ private:
|
|||||||
/* adjustable by drivers */
|
/* adjustable by drivers */
|
||||||
fixedfreq_monitor_desc m_monitor;
|
fixedfreq_monitor_desc m_monitor;
|
||||||
fixedfreq_monitor_state m_state;
|
fixedfreq_monitor_state m_state;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// device type definition
|
// device type definition
|
||||||
DECLARE_DEVICE_TYPE(FIXFREQ, fixedfreq_device)
|
DECLARE_DEVICE_TYPE(FIXFREQ, fixedfreq_device)
|
||||||
|
|
||||||
|
@ -353,8 +353,6 @@ namespace netlist::analog
|
|||||||
nld_two_terminal m_P0_P1; // 0, -gec, -gcc, 0 | 0
|
nld_two_terminal m_P0_P1; // 0, -gec, -gcc, 0 | 0
|
||||||
};
|
};
|
||||||
|
|
||||||
#define USE_THREE (1)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// nld_QBJT_EB
|
// nld_QBJT_EB
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -21,13 +21,15 @@
|
|||||||
/// http://jaco.ec.t.kanazawa-u.ac.jp/edu/mix/pdf/3.pdf
|
/// http://jaco.ec.t.kanazawa-u.ac.jp/edu/mix/pdf/3.pdf
|
||||||
///
|
///
|
||||||
/// Farid N. Naim, Circuit Simulation (Wiley-IEEE Press, 2010).
|
/// 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 "../nl_setup.h"
|
||||||
#include "nlid_twoterm.h"
|
#include "nlid_twoterm.h"
|
||||||
|
|
||||||
|
#include "solver/nld_solver.h"
|
||||||
|
|
||||||
#define BODY_CONNECTED_TO_SOURCE (1)
|
#define BODY_CONNECTED_TO_SOURCE (1)
|
||||||
|
|
||||||
namespace netlist::analog
|
namespace netlist::analog
|
||||||
@ -119,7 +121,8 @@ namespace netlist::analog
|
|||||||
, m_CGDO(model, "CGDO")
|
, m_CGDO(model, "CGDO")
|
||||||
, m_CGBO(model, "CGBO")
|
, m_CGBO(model, "CGBO")
|
||||||
, m_CAPMOD(model, "CAPMOD")
|
, m_CAPMOD(model, "CAPMOD")
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
param_model_t::value_t m_VTO; //!< Threshold voltage [V]
|
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_N; //!< Bulk diode emission coefficient
|
||||||
@ -137,10 +140,14 @@ namespace netlist::analog
|
|||||||
param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/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_RD; //!< Drain ohmic resistance
|
||||||
param_model_t::value_t m_RS; //!< Source 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_CGSO; //!< Gate-source overlap capacitance per
|
||||||
param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per meter channel width
|
//!< meter channel width
|
||||||
param_model_t::value_t m_CGBO; //!< Gate-bulk overlap capacitance per meter channel width
|
param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per
|
||||||
param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no model 2=Meyer)
|
//!< 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
|
class nld_MOSFET : public base_device_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
public: \
|
|
||||||
nld_MOSFET(constructor_param_t data)
|
nld_MOSFET(constructor_param_t data)
|
||||||
: base_device_t(data)
|
: base_device_t(data)
|
||||||
, m_model(*this, "MODEL", "NMOS")
|
, m_model(*this, "MODEL", "NMOS")
|
||||||
@ -189,18 +195,20 @@ namespace netlist::analog
|
|||||||
connect(m_SG.N(), m_DG.N());
|
connect(m_SG.N(), m_DG.N());
|
||||||
connect(m_DG.P(), m_SD.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;
|
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);
|
//# 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 :
|
// From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
|
||||||
//
|
//
|
||||||
// VTO, KP, LAMBDA, PHI and GAMMA. These parameters are computed
|
// VTO, KP, LAMBDA, PHI and GAMMA. These parameters are
|
||||||
// if the process parameters(NSUB, TOX,...) are given, but
|
// computed if the process parameters(NSUB, TOX,...) are given,
|
||||||
// user-specified values always override.
|
// but user-specified values always override.
|
||||||
//
|
//
|
||||||
// But couldn't find a formula for lambda anywhere
|
// But couldn't find a formula for lambda anywhere
|
||||||
//
|
//
|
||||||
@ -209,20 +217,28 @@ namespace netlist::analog
|
|||||||
|
|
||||||
// calculate effective channel length
|
// calculate effective channel length
|
||||||
m_Leff = m_model_acc.m_L - 2 * m_model_acc.m_LD;
|
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
|
// calculate DC transconductance coefficient
|
||||||
if (m_model_acc.m_KP > nlconst::zero())
|
if (m_model_acc.m_KP > nlconst::zero())
|
||||||
m_beta = m_model_acc.m_KP * m_model_acc.m_W / m_Leff;
|
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())
|
else if (Cox > nlconst::zero()
|
||||||
m_beta = m_model_acc.m_UO * nlconst::magic(1e-4) * Cox * m_model_acc.m_W / m_Leff;
|
&& 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
|
else
|
||||||
m_beta = nlconst::magic(2e-5) * m_model_acc.m_W / m_Leff;
|
m_beta = nlconst::magic(2e-5) * m_model_acc.m_W / m_Leff;
|
||||||
|
|
||||||
// FIXME::UT can disappear
|
// FIXME::UT can disappear
|
||||||
const nl_fptype Vt = constants::T0() * constants::k_b() / constants::Q_e();
|
const nl_fptype Vt = constants::T0() * constants::k_b()
|
||||||
|
/ constants::Q_e();
|
||||||
|
|
||||||
// calculate surface potential if not given
|
// calculate surface potential if not given
|
||||||
|
|
||||||
@ -230,8 +246,12 @@ namespace netlist::analog
|
|||||||
m_phi = m_model_acc.m_PHI;
|
m_phi = m_model_acc.m_PHI;
|
||||||
else if (m_model_acc.m_NSUB > nlconst::zero())
|
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");
|
nl_assert_always(m_model_acc.m_NSUB * nlconst::magic(1e6)
|
||||||
m_phi = nlconst::two() * Vt * plib::log (m_model_acc.m_NSUB * nlconst::magic(1e6) / constants::NiSi());
|
>= 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
|
else
|
||||||
m_phi = nlconst::magic(0.6);
|
m_phi = nlconst::magic(0.6);
|
||||||
@ -241,10 +261,13 @@ namespace netlist::analog
|
|||||||
m_gamma = m_model_acc.m_GAMMA;
|
m_gamma = m_model_acc.m_GAMMA;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Cox > nlconst::zero() && m_model_acc.m_NSUB > nlconst::zero())
|
if (Cox > nlconst::zero()
|
||||||
m_gamma = plib::sqrt (nlconst::two()
|
&& m_model_acc.m_NSUB > nlconst::zero())
|
||||||
* constants::Q_e() * constants::eps_Si() * constants::eps_0()
|
m_gamma = plib::sqrt(
|
||||||
* m_model_acc.m_NSUB * nlconst::magic(1e6)) / Cox;
|
nlconst::two() * constants::Q_e()
|
||||||
|
* constants::eps_Si() * constants::eps_0()
|
||||||
|
* m_model_acc.m_NSUB * nlconst::magic(1e6))
|
||||||
|
/ Cox;
|
||||||
else
|
else
|
||||||
m_gamma = nlconst::zero();
|
m_gamma = nlconst::zero();
|
||||||
}
|
}
|
||||||
@ -254,8 +277,8 @@ namespace netlist::analog
|
|||||||
if (m_vto == nlconst::zero())
|
if (m_vto == nlconst::zero())
|
||||||
log().warning(MW_MOSFET_THRESHOLD_VOLTAGE(m_model.name()));
|
log().warning(MW_MOSFET_THRESHOLD_VOLTAGE(m_model.name()));
|
||||||
|
|
||||||
// FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
|
// FIXME: VTO if missing may be calculated from TPG, NSS and
|
||||||
// specify VTO so skip this here.
|
// temperature. Usually models specify VTO so skip this here.
|
||||||
|
|
||||||
m_CoxWL = Cox * m_model_acc.m_W * m_Leff;
|
m_CoxWL = Cox * m_model_acc.m_W * m_Leff;
|
||||||
|
|
||||||
@ -269,13 +292,14 @@ namespace netlist::analog
|
|||||||
{
|
{
|
||||||
if (m_capacitor_model != 0)
|
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 Ugd = -m_DG.deltaV() * m_polarity; // Gate - Drain
|
||||||
//#const nl_nl_fptype Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
|
//#const nl_nl_fptype Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
|
||||||
const nl_fptype Ugd = m_Vgd; // Gate - Drain
|
const nl_fptype Ugd = m_Vgd; // Gate - Drain
|
||||||
const nl_fptype Ugs = m_Vgs; // Gate - Source
|
const nl_fptype Ugs = m_Vgs; // Gate - Source
|
||||||
const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0 if connected
|
const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0
|
||||||
|
// if connected
|
||||||
const nl_fptype Ugb = Ugs - Ubs;
|
const nl_fptype Ugb = Ugs - Ubs;
|
||||||
|
|
||||||
m_cap_gb.time_step(m_Cgb, Ugb, step);
|
m_cap_gb.time_step(m_Cgb, Ugb, step);
|
||||||
@ -292,20 +316,22 @@ namespace netlist::analog
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
NETLIB_RESETI()
|
NETLIB_RESETI()
|
||||||
{
|
{
|
||||||
// Bulk diodes
|
// Bulk diodes
|
||||||
|
|
||||||
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(), constants::T0());
|
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(),
|
||||||
|
constants::T0());
|
||||||
#if (!BODY_CONNECTED_TO_SOURCE)
|
#if (!BODY_CONNECTED_TO_SOURCE)
|
||||||
m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(), constants::T0());
|
m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(),
|
||||||
|
constants::T0());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
NETLIB_HANDLERI(terminal_handler)
|
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());
|
auto *solv(m_SG.solver());
|
||||||
if (solv != nullptr)
|
if (solv != nullptr)
|
||||||
solv->solve_now();
|
solv->solve_now();
|
||||||
@ -316,7 +342,6 @@ namespace netlist::analog
|
|||||||
NETLIB_UPDATE_TERMINALSI();
|
NETLIB_UPDATE_TERMINALSI();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
param_model_t m_model;
|
param_model_t m_model;
|
||||||
|
|
||||||
NETLIB_NAME(two_terminal) m_DG;
|
NETLIB_NAME(two_terminal) m_DG;
|
||||||
@ -355,18 +380,23 @@ namespace netlist::analog
|
|||||||
fet_model_t m_model_acc;
|
fet_model_t m_model_acc;
|
||||||
|
|
||||||
void set_cap(generic_capacitor<capacitor_e::VARIABLE_CAPACITY> &cap,
|
void set_cap(generic_capacitor<capacitor_e::VARIABLE_CAPACITY> &cap,
|
||||||
nl_fptype capval, nl_fptype V,
|
nl_fptype capval, nl_fptype V, nl_fptype &g11,
|
||||||
nl_fptype &g11, nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
|
nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
|
||||||
nl_fptype &I1, nl_fptype &I2) const
|
nl_fptype &I1, nl_fptype &I2) const
|
||||||
{
|
{
|
||||||
const nl_fptype I = cap.Ieq(capval, V) * m_polarity;
|
const nl_fptype I = cap.Ieq(capval, V) * m_polarity;
|
||||||
const nl_fptype G = cap.G(capval);
|
const nl_fptype G = cap.G(capval);
|
||||||
g11 += G; g12 -= G; g21 -= G; g22 += G;
|
g11 += G;
|
||||||
I1 -= I; I2 += I;
|
g12 -= G;
|
||||||
|
g21 -= G;
|
||||||
|
g22 += G;
|
||||||
|
I1 -= I;
|
||||||
|
I2 += I;
|
||||||
// printf("Cap: %g\n", capval);
|
// printf("Cap: %g\n", capval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
|
void
|
||||||
|
calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
|
||||||
nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
|
nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
|
||||||
{
|
{
|
||||||
nl_fptype Vctrl = Vgs - Vth * m_polarity;
|
nl_fptype Vctrl = Vgs - Vth * m_polarity;
|
||||||
@ -388,7 +418,8 @@ namespace netlist::analog
|
|||||||
else if (Vctrl <= 0)
|
else if (Vctrl <= 0)
|
||||||
{
|
{
|
||||||
Cgb = -Vctrl * m_CoxWL / m_phi;
|
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();
|
Cgd = nlconst::zero();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -405,11 +436,15 @@ namespace netlist::analog
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// linear
|
// linear
|
||||||
const auto Sqr1(plib::narrow_cast<nl_fptype>(plib::pow(Vdsat - Vds, 2)));
|
const auto Sqr1(plib::narrow_cast<nl_fptype>(
|
||||||
const auto Sqr2(plib::narrow_cast<nl_fptype>(plib::pow(nlconst::two() * Vdsat - Vds, 2)));
|
plib::pow(Vdsat - Vds, 2)));
|
||||||
|
const auto Sqr2(plib::narrow_cast<nl_fptype>(
|
||||||
|
plib::pow(nlconst::two() * Vdsat - Vds, 2)));
|
||||||
Cgb = 0;
|
Cgb = 0;
|
||||||
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2) * nlconst::two_thirds();
|
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2)
|
||||||
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2) * nlconst::two_thirds();
|
* nlconst::two_thirds();
|
||||||
|
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2)
|
||||||
|
* nlconst::two_thirds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,17 +461,24 @@ namespace netlist::analog
|
|||||||
|
|
||||||
// limit step sizes
|
// 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);
|
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);
|
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_Vgs = Vgs;
|
||||||
m_Vgd = Vgd;
|
m_Vgd = Vgd;
|
||||||
|
|
||||||
const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if connected
|
const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if
|
||||||
//const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain = Source - Drain
|
// connected
|
||||||
|
// const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain
|
||||||
|
// = Source - Drain
|
||||||
const nl_fptype Vds = Vgs - Vgd;
|
const nl_fptype Vds = Vgs - Vgd;
|
||||||
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
|
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
|
||||||
|
|
||||||
@ -451,8 +493,11 @@ namespace netlist::analog
|
|||||||
|
|
||||||
// calculate Vth
|
// calculate Vth
|
||||||
const nl_fptype Vbulk = is_forward ? Vbs : Vbd;
|
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 phi_m_Vbulk = (m_phi > Vbulk)
|
||||||
const nl_fptype Vth = m_vto * m_polarity + m_gamma * (phi_m_Vbulk - plib::sqrt(m_phi));
|
? 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;
|
const nl_fptype Vctrl = (is_forward ? Vgs : Vgd) - Vth;
|
||||||
|
|
||||||
@ -473,7 +518,8 @@ namespace netlist::analog
|
|||||||
}
|
}
|
||||||
else
|
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)
|
if (Vctrl <= absVds)
|
||||||
{
|
{
|
||||||
// saturation region
|
// saturation region
|
||||||
@ -486,11 +532,16 @@ namespace netlist::analog
|
|||||||
// linear region
|
// linear region
|
||||||
Ids = beta * absVds * (Vctrl - absVds / nlconst::two());
|
Ids = beta * absVds * (Vctrl - absVds / nlconst::two());
|
||||||
gm = beta * absVds;
|
gm = beta * absVds;
|
||||||
gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / nlconst::two());
|
gds = beta * (Vctrl - absVds)
|
||||||
|
+ m_lambda * m_beta * absVds
|
||||||
|
* (Vctrl - absVds / nlconst::two());
|
||||||
}
|
}
|
||||||
|
|
||||||
// back gate transconductance
|
// 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;
|
gmb = gm * bgtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,8 +565,8 @@ namespace netlist::analog
|
|||||||
const nl_fptype gate_source = is_forward ? (gm + gmb) : nlconst::zero();
|
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) ?
|
const nl_fptype IeqDS = (is_forward)
|
||||||
Ids - gm * Vgs - gmb * Vbs - gds * Vds
|
? Ids - gm * Vgs - gmb * Vbs - gds * Vds
|
||||||
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
|
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
|
||||||
|
|
||||||
// IG = 0
|
// IG = 0
|
||||||
@ -553,9 +604,12 @@ namespace netlist::analog
|
|||||||
else
|
else
|
||||||
calculate_caps(Vgd, Vgs, Vth, m_Cgd, m_Cgs, m_Cgb);
|
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_gb, m_Cgb + m_model_acc.m_CGBO * m_Leff, Vgb, gGG,
|
||||||
set_cap(m_cap_gs, m_Cgs + m_model_acc.m_CGSO * m_model_acc.m_W, Vgs, gGG, gGS, gSG, gSS, IG, IS);
|
gGB, gBG, gBB, IG, IB);
|
||||||
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_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!
|
// Source connected to body, Diode S-B shorted!
|
||||||
@ -600,13 +654,11 @@ namespace netlist::analog
|
|||||||
/// |
|
/// |
|
||||||
}
|
}
|
||||||
|
|
||||||
NETLIB_UPDATE_PARAM(MOSFET)
|
NETLIB_UPDATE_PARAM(MOSFET) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace netlist::analog
|
} // namespace netlist::analog
|
||||||
|
|
||||||
namespace netlist::devices {
|
namespace netlist::devices
|
||||||
|
{
|
||||||
NETLIB_DEVICE_IMPL_NS(analog, MOSFET, "MOSFET", "MODEL")
|
NETLIB_DEVICE_IMPL_NS(analog, MOSFET, "MOSFET", "MODEL")
|
||||||
} // namespace netlist::devices
|
} // namespace netlist::devices
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ namespace netlist::analog
|
|||||||
|
|
||||||
NETLIB_TIMESTEP(L)
|
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_I = m_I;
|
||||||
m_last_G = m_G;
|
m_last_G = m_G;
|
||||||
|
@ -312,7 +312,7 @@ namespace netlist::analog
|
|||||||
NETLIB_IS_TIMESTEP(true)
|
NETLIB_IS_TIMESTEP(true)
|
||||||
NETLIB_TIMESTEPI()
|
NETLIB_TIMESTEPI()
|
||||||
{
|
{
|
||||||
if (ts_type == time_step_type::FORWARD)
|
if (ts_type == detail::time_step_type::FORWARD)
|
||||||
{
|
{
|
||||||
// G, Ieq
|
// G, Ieq
|
||||||
const auto res(m_cap.time_step(m_C(), deltaV(), step));
|
const auto res(m_cap.time_step(m_C(), deltaV(), step));
|
||||||
@ -584,7 +584,7 @@ namespace netlist::analog
|
|||||||
|
|
||||||
NETLIB_TIMESTEPI()
|
NETLIB_TIMESTEPI()
|
||||||
{
|
{
|
||||||
if (ts_type == time_step_type::FORWARD)
|
if (ts_type == detail::time_step_type::FORWARD)
|
||||||
{
|
{
|
||||||
m_t += step;
|
m_t += step;
|
||||||
m_funcparam[0] = m_t;
|
m_funcparam[0] = m_t;
|
||||||
@ -637,7 +637,7 @@ namespace netlist::analog
|
|||||||
NETLIB_IS_TIMESTEP(!m_func().empty())
|
NETLIB_IS_TIMESTEP(!m_func().empty())
|
||||||
NETLIB_TIMESTEPI()
|
NETLIB_TIMESTEPI()
|
||||||
{
|
{
|
||||||
if (ts_type == time_step_type::FORWARD)
|
if (ts_type == detail::time_step_type::FORWARD)
|
||||||
{
|
{
|
||||||
m_t += step;
|
m_t += step;
|
||||||
m_funcparam[0] = m_t;
|
m_funcparam[0] = m_t;
|
||||||
|
@ -25,13 +25,14 @@ BreakStringLiterals: false
|
|||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
# AfterComma does not work <= 13
|
# AfterComma does not work <= 13
|
||||||
#BreakInheritanceList: AfterComma
|
#BreakInheritanceList: AfterComma
|
||||||
#BreakInheritanceList: BeforeComma
|
BreakInheritanceList: BeforeComma
|
||||||
#BreakInheritanceList: false
|
#BreakInheritanceList: false
|
||||||
SpaceBeforeInheritanceColon: true
|
SpaceBeforeInheritanceColon: true
|
||||||
|
|
||||||
#AlignAfterOpenBracket: DontAlign
|
#AlignAfterOpenBracket: DontAlign
|
||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: Align
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
|
ReferenceAlignment: Right
|
||||||
SpacesInAngles: false
|
SpacesInAngles: false
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
AlignConsecutiveDeclarations: true
|
AlignConsecutiveDeclarations: true
|
||||||
@ -90,16 +91,17 @@ StatementMacros:
|
|||||||
TypenameMacros:
|
TypenameMacros:
|
||||||
- "NETLIST_NAME"
|
- "NETLIST_NAME"
|
||||||
- "NETLIB_NAME"
|
- "NETLIB_NAME"
|
||||||
|
- "PENUM"
|
||||||
|
|
||||||
WhitespaceSensitiveMacros:
|
WhitespaceSensitiveMacros:
|
||||||
- "ALIAS"
|
- "ALIAS"
|
||||||
- "NET_C"
|
|
||||||
- "DIPPINS"
|
- "DIPPINS"
|
||||||
|
- "NET_C"
|
||||||
|
- "PENUM"
|
||||||
|
|
||||||
IndentPPDirectives: BeforeHash
|
IndentPPDirectives: BeforeHash
|
||||||
MacroBlockBegin: "^static NETLIST_START\\(.+\\)|static TRUTHTABLE_START\\(.*\\)$"
|
MacroBlockBegin: "^static NETLIST_START\\(.+\\)|static TRUTHTABLE_START\\(.*\\)$"
|
||||||
MacroBlockEnd: "^NETLIST_END\\(\\)|TRUTHTABLE_END\\(\\)$"
|
MacroBlockEnd: "^NETLIST_END\\(\\)|TRUTHTABLE_END\\(\\)$"
|
||||||
# ReferenceAlignment: Middle
|
|
||||||
|
|
||||||
# Avoid formatting
|
# Avoid formatting
|
||||||
# -- clang-tidy
|
# -- clang-tidy
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"Schmitt",
|
"Schmitt",
|
||||||
"Schottky",
|
"Schottky",
|
||||||
"Zener",
|
"Zener",
|
||||||
|
"Thevenin",
|
||||||
// Company names
|
// Company names
|
||||||
"Fairchild",
|
"Fairchild",
|
||||||
"Signetics",
|
"Signetics",
|
||||||
@ -69,6 +70,7 @@
|
|||||||
// FIXME: Remove everything below here again
|
// FIXME: Remove everything below here again
|
||||||
// Excluded for now ... Still over 1000 in the log
|
// Excluded for now ... Still over 1000 in the log
|
||||||
"plib", // namespace
|
"plib", // namespace
|
||||||
|
"isnull",
|
||||||
"pstring",
|
"pstring",
|
||||||
"passert",
|
"passert",
|
||||||
"putf",
|
"putf",
|
||||||
@ -79,6 +81,8 @@
|
|||||||
"idrn",
|
"idrn",
|
||||||
"preprocessor",
|
"preprocessor",
|
||||||
"ppreprocessor",
|
"ppreprocessor",
|
||||||
|
"psource",
|
||||||
|
"psemaphore",
|
||||||
"modacc",
|
"modacc",
|
||||||
"Ainv",
|
"Ainv",
|
||||||
"anetlist",
|
"anetlist",
|
||||||
|
@ -114,7 +114,7 @@ TIDY_DB = $(OBJ)/compile_commands.json
|
|||||||
#LTO decreases performance :-(
|
#LTO decreases performance :-(
|
||||||
#LTO = -flto=4 -fuse-linker-plugin -Wodr
|
#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)
|
CFLAGS = $(LTO) $(CCOREFLAGS) $(CEXTRAFLAGS)
|
||||||
LDFLAGS = $(LTO) -g -O3 -std=c++17 $(LDEXTRAFLAGS)
|
LDFLAGS = $(LTO) -g -O3 -std=c++17 $(LDEXTRAFLAGS)
|
||||||
|
@ -17,9 +17,19 @@
|
|||||||
#include "../plib/pexception.h"
|
#include "../plib/pexception.h"
|
||||||
#include "../plib/plists.h"
|
#include "../plib/plists.h"
|
||||||
#include "../plib/pmempool.h"
|
#include "../plib/pmempool.h"
|
||||||
|
#include "../plib/ppmf.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#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
|
namespace netlist::detail
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -139,8 +149,8 @@ namespace netlist::detail
|
|||||||
|
|
||||||
// to ease template design
|
// to ease template design
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
device_arena::unique_ptr<T> make_pool_object(Args &&...args) noexcept(
|
device_arena::unique_ptr<T>
|
||||||
false)
|
make_pool_object(Args &&...args) noexcept(false)
|
||||||
{
|
{
|
||||||
return state().make_pool_object<T>(std::forward<Args>(args)...);
|
return state().make_pool_object<T>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@ -271,12 +281,12 @@ namespace netlist::detail
|
|||||||
|
|
||||||
void reset() noexcept
|
void reset() noexcept
|
||||||
{
|
{
|
||||||
set_state(
|
set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT
|
||||||
is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE);
|
: STATE_INP_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void set_copied_input(
|
constexpr void
|
||||||
[[maybe_unused]] netlist_sig_t val) noexcept
|
set_copied_input([[maybe_unused]] netlist_sig_t val) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (config::use_copy_instead_of_reference::value)
|
if constexpr (config::use_copy_instead_of_reference::value)
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ namespace netlist
|
|||||||
friend class factory::device_element_t;
|
friend class factory::device_element_t;
|
||||||
friend class factory::library_element_t;
|
friend class factory::library_element_t;
|
||||||
|
|
||||||
template <typename CX>
|
template <typename DEVICE>
|
||||||
friend struct sub_device_wrapper;
|
friend struct sub_device_wrapper;
|
||||||
|
|
||||||
friend class solver::matrix_solver_t;
|
friend class solver::matrix_solver_t;
|
||||||
@ -103,7 +103,7 @@ namespace netlist
|
|||||||
log_type &log();
|
log_type &log();
|
||||||
|
|
||||||
public:
|
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
|
[[maybe_unused]] nl_fptype st) noexcept
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -73,40 +73,42 @@ namespace netlist
|
|||||||
// FIXME: Rename
|
// FIXME: Rename
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
template <typename CX>
|
template <typename DEVICE>
|
||||||
struct sub_device_wrapper
|
struct sub_device_wrapper
|
||||||
{
|
{
|
||||||
using constructor_data_t = typename CX::constructor_data_t;
|
using constructor_data_t = typename DEVICE::constructor_data_t;
|
||||||
using constructor_param_t = typename CX::constructor_param_t;
|
using constructor_param_t = typename DEVICE::constructor_param_t;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
sub_device_wrapper(base_device_t &owner, const pstring &name,
|
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)...);
|
// 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},
|
constructor_data_t{owner.state(), owner.name() + "." + name},
|
||||||
std::forward<Args>(args)...);
|
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));
|
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
|
||||||
}
|
}
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
sub_device_wrapper(device_t &owner, const pstring &name, Args &&...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)...);
|
// 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},
|
constructor_data_t{owner.state(), owner.name() + "." + name},
|
||||||
std::forward<Args>(args)...);
|
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));
|
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
|
||||||
}
|
}
|
||||||
CX & operator()() { return *m_dev; }
|
DEVICE & operator()() { return *m_dev; }
|
||||||
const CX &operator()() const { return *m_dev; }
|
const DEVICE &operator()() const { return *m_dev; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
device_arena::unique_ptr<CX> m_dev;
|
device_arena::unique_ptr<DEVICE> m_dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace netlist
|
} // namespace netlist
|
||||||
|
@ -107,7 +107,7 @@ public: \
|
|||||||
|
|
||||||
#define NETLIB_TIMESTEPI() \
|
#define NETLIB_TIMESTEPI() \
|
||||||
public: \
|
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
|
nl_fptype step) noexcept override
|
||||||
|
|
||||||
/// \brief Used to implement the body of the time stepping code.
|
/// \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
|
/// \param cname Name of object as given to \ref NETLIB_OBJECT
|
||||||
///
|
///
|
||||||
#define NETLIB_TIMESTEP(cname) \
|
#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
|
nl_fptype step) noexcept
|
||||||
|
|
||||||
//#define NETLIB_DELEGATE(name) nl_delegate(&this_type :: name, this)
|
//#define NETLIB_DELEGATE(name) nl_delegate(&this_type :: name, this)
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "../nltypes.h"
|
#include "../nltypes.h"
|
||||||
|
|
||||||
|
#include "../plib/palloc.h"
|
||||||
|
#include "../plib/pmempool.h"
|
||||||
#include "../plib/pstring.h"
|
#include "../plib/pstring.h"
|
||||||
|
|
||||||
namespace netlist
|
namespace netlist
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
#include "../plib/plists.h"
|
#include "../plib/plists.h"
|
||||||
|
#include "../plib/pmempool.h"
|
||||||
#include "../plib/pstate.h"
|
#include "../plib/pstate.h"
|
||||||
#include "../plib/pstring.h"
|
#include "../plib/pstring.h"
|
||||||
|
|
||||||
@ -31,8 +32,8 @@ namespace netlist
|
|||||||
public:
|
public:
|
||||||
using nets_collection_type = std::vector<
|
using nets_collection_type = std::vector<
|
||||||
device_arena::owned_ptr<detail::net_t>>;
|
device_arena::owned_ptr<detail::net_t>>;
|
||||||
using family_collection_type = std::unordered_map<pstring,
|
using family_collection_type = std::unordered_map<
|
||||||
host_arena::unique_ptr<logic_family_desc_t>>;
|
pstring, host_arena::unique_ptr<logic_family_desc_t>>;
|
||||||
|
|
||||||
// need to preserve order of device creation ...
|
// need to preserve order of device creation ...
|
||||||
using devices_collection_type = std::vector<
|
using devices_collection_type = std::vector<
|
||||||
@ -55,7 +56,8 @@ namespace netlist
|
|||||||
return bool(plib::dynamic_downcast<C *>(p));
|
return bool(plib::dynamic_downcast<C *>(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
core_device_t *get_single_device(const pstring &classname,
|
core_device_t *
|
||||||
|
get_single_device(const pstring &classname,
|
||||||
bool (*cc)(core_device_t *)) const noexcept(false);
|
bool (*cc)(core_device_t *)) const noexcept(false);
|
||||||
|
|
||||||
/// \brief Get single device filtered by class and name
|
/// \brief Get single device filtered by class and name
|
||||||
@ -115,8 +117,8 @@ namespace netlist
|
|||||||
plib::state_manager_t &run_state_manager() noexcept { return m_state; }
|
plib::state_manager_t &run_state_manager() noexcept { return m_state; }
|
||||||
|
|
||||||
template <typename O, typename C>
|
template <typename O, typename C>
|
||||||
void save(O &owner, C &state, const pstring &module,
|
void
|
||||||
const pstring &stname)
|
save(O &owner, C &state, const pstring &module, const pstring &stname)
|
||||||
{
|
{
|
||||||
this->run_state_manager().save_item(plib::void_ptr_cast(&owner),
|
this->run_state_manager().save_item(plib::void_ptr_cast(&owner),
|
||||||
state, module + "." + stname);
|
state, module + "." + stname);
|
||||||
@ -187,11 +189,11 @@ namespace netlist
|
|||||||
/// \param dev Device to be registered
|
/// \param dev Device to be registered
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void register_device(const pstring &name,
|
void
|
||||||
device_arena::unique_ptr<T> && dev)
|
register_device(const pstring &name, device_arena::unique_ptr<T> &&dev)
|
||||||
{
|
{
|
||||||
register_device(name, device_arena::owned_ptr<T>(dev.release(),
|
register_device(name, device_arena::owned_ptr<T>(
|
||||||
true, dev.get_deleter()));
|
dev.release(), true, dev.get_deleter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Remove device
|
/// \brief Remove device
|
||||||
@ -212,8 +214,8 @@ namespace netlist
|
|||||||
// FIXME: make a post load member and include code there
|
// FIXME: make a post load member and include code there
|
||||||
void rebuild_lists(); // must be called after post_load !
|
void rebuild_lists(); // must be called after post_load !
|
||||||
|
|
||||||
static void compile_defines(
|
static void
|
||||||
std::vector<std::pair<pstring, pstring>> &defs);
|
compile_defines(std::vector<std::pair<pstring, pstring>> &defs);
|
||||||
static pstring version();
|
static pstring version();
|
||||||
static pstring version_patchlevel();
|
static pstring version_patchlevel();
|
||||||
|
|
||||||
@ -256,8 +258,8 @@ namespace netlist
|
|||||||
///
|
///
|
||||||
void free_setup_resources();
|
void free_setup_resources();
|
||||||
#if !(NL_USE_INPLACE_CORE_TERMS)
|
#if !(NL_USE_INPLACE_CORE_TERMS)
|
||||||
std::vector<detail::core_terminal_t *> &core_terms(
|
std::vector<detail::core_terminal_t *> &
|
||||||
const detail::net_t &net)
|
core_terms(const detail::net_t &net)
|
||||||
{
|
{
|
||||||
return m_core_terms[&net];
|
return m_core_terms[&net];
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,12 @@
|
|||||||
#ifndef NL_CORE_OBJECT_ARRAY_H_
|
#ifndef NL_CORE_OBJECT_ARRAY_H_
|
||||||
#define NL_CORE_OBJECT_ARRAY_H_
|
#define NL_CORE_OBJECT_ARRAY_H_
|
||||||
|
|
||||||
|
#include "base_objects.h"
|
||||||
|
#include "logic.h"
|
||||||
|
|
||||||
#include "../nltypes.h"
|
#include "../nltypes.h"
|
||||||
|
|
||||||
|
#include "../plib/pfmtlog.h"
|
||||||
#include "../plib/plists.h"
|
#include "../plib/plists.h"
|
||||||
#include "../plib/pstring.h"
|
#include "../plib/pstring.h"
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "../nltypes.h"
|
#include "../nltypes.h"
|
||||||
|
|
||||||
|
#include "../plib/pfmtlog.h"
|
||||||
#include "../plib/pstring.h"
|
#include "../plib/pstring.h"
|
||||||
|
|
||||||
namespace netlist
|
namespace netlist
|
||||||
|
@ -78,7 +78,7 @@ namespace netlist::devices {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newstate_setreset(set, reset);
|
set_reset(set, reset);
|
||||||
m_CLK.inactivate();
|
m_CLK.inactivate();
|
||||||
m_D.inactivate();
|
m_D.inactivate();
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ namespace netlist::devices {
|
|||||||
|
|
||||||
NETLIB_HANDLERI(clk)
|
NETLIB_HANDLERI(clk)
|
||||||
{
|
{
|
||||||
newstate_clk(m_nextD);
|
set_output(m_nextD);
|
||||||
m_CLK.inactivate();
|
m_CLK.inactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,14 +101,14 @@ namespace netlist::devices {
|
|||||||
|
|
||||||
nld_power_pins m_power_pins;
|
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_Q.push(stateQ, delay);
|
||||||
m_QQ.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
|
// Q: 150 ns, QQ: 200 ns
|
||||||
static constexpr const std::array<netlist_time, 2> delay = { NLTIME_FROM_NS(150), NLTIME_FROM_NS(200) };
|
static constexpr const std::array<netlist_time, 2> delay = { NLTIME_FROM_NS(150), NLTIME_FROM_NS(200) };
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
namespace netlist
|
namespace netlist
|
||||||
{
|
{
|
||||||
// nothing in here. This should not change.
|
// nothing in here. This should not change.
|
||||||
|
|
||||||
} // namespace netlist
|
} // namespace netlist
|
||||||
|
|
||||||
#endif // NLBASE_H_
|
#endif // NLBASE_H_
|
||||||
|
@ -134,7 +134,7 @@ namespace netlist
|
|||||||
/// brief default minimum alignment of mempool_arena
|
/// brief default minimum alignment of mempool_arena
|
||||||
///
|
///
|
||||||
/// 256 is the best compromise between logic applications like MAME
|
/// 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.
|
/// sound.
|
||||||
///
|
///
|
||||||
/// Best performance for pong is achieved with a value of 16, but this
|
/// Best performance for pong is achieved with a value of 16, but this
|
||||||
@ -206,14 +206,14 @@ namespace netlist
|
|||||||
/// \brief Support float type for matrix calculations.
|
/// \brief Support float type for matrix calculations.
|
||||||
///
|
///
|
||||||
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
||||||
using use_float_matrix = std::integral_constant<bool,
|
using use_float_matrix = std::integral_constant<
|
||||||
NL_USE_ACADEMIC_SOLVERS>;
|
bool, NL_USE_ACADEMIC_SOLVERS>;
|
||||||
|
|
||||||
/// \brief Support long double type for matrix calculations.
|
/// \brief Support long double type for matrix calculations.
|
||||||
///
|
///
|
||||||
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
||||||
using use_long_double_matrix = std::integral_constant<bool,
|
using use_long_double_matrix = std::integral_constant<
|
||||||
NL_USE_ACADEMIC_SOLVERS>;
|
bool, NL_USE_ACADEMIC_SOLVERS>;
|
||||||
|
|
||||||
using use_float128_matrix = std::integral_constant<bool,
|
using use_float128_matrix = std::integral_constant<bool,
|
||||||
NL_USE_FLOAT128>;
|
NL_USE_FLOAT128>;
|
||||||
@ -416,16 +416,4 @@ namespace netlist
|
|||||||
#endif
|
#endif
|
||||||
} // namespace netlist
|
} // 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_
|
#endif // NLCONFIG_H_
|
||||||
|
@ -8,13 +8,53 @@
|
|||||||
#ifndef NL_ERRSTR_H_
|
#ifndef NL_ERRSTR_H_
|
||||||
#define NL_ERRSTR_H_
|
#define NL_ERRSTR_H_
|
||||||
|
|
||||||
|
#include "plib/pexception.h"
|
||||||
#include "plib/pfmtlog.h"
|
#include "plib/pfmtlog.h"
|
||||||
|
|
||||||
namespace netlist
|
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_NO_DEACTIVATE[]
|
||||||
static constexpr const char sHINT_NC[] = ".HINT_NC"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
= ".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
|
// nl_base.cpp
|
||||||
|
|
||||||
@ -187,9 +227,19 @@ namespace netlist
|
|||||||
|
|
||||||
PERRMSGV(MF_FILE_OPEN_ERROR, 1, "Error opening file: {1}")
|
PERRMSGV(MF_FILE_OPEN_ERROR, 1, "Error opening file: {1}")
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
} // namespace netlist
|
} // 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_
|
#endif // NL_ERRSTR_H_
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
#ifndef NLSETUP_H_
|
#ifndef NLSETUP_H_
|
||||||
#define NLSETUP_H_
|
#define NLSETUP_H_
|
||||||
|
|
||||||
|
#include "nl_config.h"
|
||||||
|
#include "nltypes.h"
|
||||||
|
|
||||||
#include "plib/ppreprocessor.h"
|
#include "plib/ppreprocessor.h"
|
||||||
#include "plib/psource.h"
|
#include "plib/psource.h"
|
||||||
#include "plib/pstream.h"
|
#include "plib/pstream.h"
|
||||||
#include "plib/pstring.h"
|
#include "plib/pstring.h"
|
||||||
|
|
||||||
#include "nl_config.h"
|
|
||||||
#include "nltypes.h"
|
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@ -28,18 +28,15 @@
|
|||||||
|
|
||||||
#define NET_STR(x) #x
|
#define NET_STR(x) #x
|
||||||
|
|
||||||
#define NET_MODEL(model) \
|
#define NET_MODEL(model) setup.register_model(model);
|
||||||
setup.register_model(model);
|
|
||||||
|
|
||||||
#define ALIAS(alias, name) \
|
#define ALIAS(alias, name) setup.register_alias(#alias, #name);
|
||||||
setup.register_alias(# alias, # name);
|
|
||||||
|
|
||||||
#define DIPPINS(pin1, ...) \
|
#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
|
// to be used to reference new library truth table devices
|
||||||
#define NET_REGISTER_DEV(type, name) \
|
#define NET_REGISTER_DEV(type, name) setup.register_dev(#type, #name);
|
||||||
setup.register_dev(# type, # name);
|
|
||||||
|
|
||||||
// name is first element so that __VA_ARGS__ always has one element
|
// name is first element so that __VA_ARGS__ always has one element
|
||||||
#define NET_REGISTER_DEVEXT(type, ...) \
|
#define NET_REGISTER_DEVEXT(type, ...) \
|
||||||
@ -51,14 +48,12 @@
|
|||||||
#define NET_C(term1, ...) \
|
#define NET_C(term1, ...) \
|
||||||
setup.register_connection_arr(#term1 ", " #__VA_ARGS__);
|
setup.register_connection_arr(#term1 ", " #__VA_ARGS__);
|
||||||
|
|
||||||
#define PARAM(name, val) \
|
#define PARAM(name, val) setup.register_param(NET_STR(name), NET_STR(val));
|
||||||
setup.register_param(NET_STR(name), NET_STR(val));
|
|
||||||
|
|
||||||
#define DEFPARAM(name, 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) \
|
#define HINT(name, val) setup.register_hint(#name, ".HINT_" #val);
|
||||||
setup.register_hint(# name , ".HINT_" # val);
|
|
||||||
|
|
||||||
#define NETDEV_PARAMI(name, param, val) \
|
#define NETDEV_PARAMI(name, param, val) \
|
||||||
setup.register_param(#name "." #param, val);
|
setup.register_param(#name "." #param, val);
|
||||||
@ -69,7 +64,7 @@
|
|||||||
void NETLIST_NAME(name)(netlist::nlparse_t & setup);
|
void NETLIST_NAME(name)(netlist::nlparse_t & setup);
|
||||||
|
|
||||||
#define NETLIST_START(name) \
|
#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) \
|
#define LOCAL_SOURCE(name) \
|
||||||
setup.register_source_proc(#name, &NETLIST_NAME(name));
|
setup.register_source_proc(#name, &NETLIST_NAME(name));
|
||||||
@ -78,8 +73,7 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
|
|||||||
setup.register_source_proc(#name, &NETLIST_NAME(name));
|
setup.register_source_proc(#name, &NETLIST_NAME(name));
|
||||||
|
|
||||||
#define LOCAL_LIB_ENTRY_2(type, name) \
|
#define LOCAL_LIB_ENTRY_2(type, name) \
|
||||||
type ## _SOURCE(name) \
|
type##_SOURCE(name) setup.register_lib_entry(#name, "", PSOURCELOC());
|
||||||
setup.register_lib_entry(# name, "", PSOURCELOC());
|
|
||||||
|
|
||||||
#define LOCAL_LIB_ENTRY_3(type, name, param_spec) \
|
#define LOCAL_LIB_ENTRY_3(type, name, param_spec) \
|
||||||
type##_SOURCE(name) \
|
type##_SOURCE(name) \
|
||||||
@ -87,10 +81,10 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
|
|||||||
|
|
||||||
#define LOCAL_LIB_ENTRY(...) PCALLVARARG(LOCAL_LIB_ENTRY_, LOCAL, __VA_ARGS__)
|
#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) \
|
#define INCLUDE(name) setup.include(#name);
|
||||||
setup.include(# name);
|
|
||||||
|
|
||||||
#define SUBMODEL(model, name) \
|
#define SUBMODEL(model, name) \
|
||||||
setup.namespace_push(#name); \
|
setup.namespace_push(#name); \
|
||||||
@ -104,40 +98,23 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
|
|||||||
// truth table defines
|
// truth table defines
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if 0
|
#define TRUTH_TABLE(cname, in, out, params) \
|
||||||
#define TRUTHTABLE_START(cname, in, out, pdef_params) \
|
void NETLIST_NAME(cname##_impl)(netlist::nlparse_t & setup, \
|
||||||
void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc); \
|
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) \
|
static void NETLIST_NAME(cname)(netlist::nlparse_t & setup) \
|
||||||
{ \
|
{ \
|
||||||
netlist::tt_desc desc{#cname, in, out, "", {}}; \
|
netlist::tt_desc desc{#cname, in, out, "", {}}; \
|
||||||
NETLIST_NAME(cname##_impl)(setup, desc); \
|
NETLIST_NAME(cname##_impl)(setup, desc); \
|
||||||
setup.truth_table_create(desc, pdef_params, PSOURCELOC()); \
|
setup.truth_table_create(desc, params, PSOURCELOC()); \
|
||||||
} \
|
} \
|
||||||
static void NETLIST_NAME(cname ## _impl)([[maybe_unused]] netlist::nlparse_t &setup, netlist::tt_desc &desc) \
|
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) \
|
#define TT_LINE(x) desc.desc.emplace_back(x);
|
||||||
desc.desc.emplace_back(x);
|
|
||||||
|
|
||||||
#define TT_LINE(x) \
|
#define TT_FAMILY(x) desc.family = x;
|
||||||
desc.desc.emplace_back(x);
|
|
||||||
|
|
||||||
#define TT_FAMILY(x) \
|
|
||||||
desc.family = x;
|
|
||||||
|
|
||||||
#define TRUTHTABLE_ENTRY(name) \
|
#define TRUTHTABLE_ENTRY(name) \
|
||||||
LOCAL_SOURCE(name) \
|
LOCAL_SOURCE(name) \
|
||||||
@ -193,25 +170,29 @@ namespace netlist
|
|||||||
/// \param type the alias type see \ref alias_type
|
/// \param type the alias type see \ref alias_type
|
||||||
/// \param alias the alias to be qualified
|
/// \param alias the alias to be qualified
|
||||||
/// \param points_to the pin aliased
|
/// \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
|
/// \brief Register an aliases where alias and references are fully qualified names
|
||||||
/// \param type the alias type see \ref alias_type
|
/// \param type the alias type see \ref alias_type
|
||||||
/// \param alias the alias to be qualified
|
/// \param alias the alias to be qualified
|
||||||
/// \param points_to the pin aliased
|
/// \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);
|
void register_dip_alias_arr(const pstring &terms);
|
||||||
|
|
||||||
// last argument only needed by nltool
|
// last argument only needed by nltool
|
||||||
void register_dev(const pstring &classname, const pstring &name,
|
void register_dev(const pstring &classname, const pstring &name,
|
||||||
const std::vector<pstring> ¶ms_and_connections,
|
const std::vector<pstring> ¶ms_and_connections,
|
||||||
factory::element_t **factory_element = nullptr);
|
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,
|
||||||
|
std::initializer_list<const char *> more_parameters);
|
||||||
void register_dev(const pstring &classname, const pstring &name)
|
void register_dev(const pstring &classname, const pstring &name)
|
||||||
{
|
{
|
||||||
register_dev(classname, name, std::vector<pstring>());
|
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(const pstring &sin, const pstring &sout);
|
||||||
void register_connection_arr(const pstring &terms);
|
void register_connection_arr(const pstring &terms);
|
||||||
@ -230,9 +211,11 @@ namespace netlist
|
|||||||
register_param_fp(param, plib::narrow_cast<nl_fptype>(value));
|
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
|
// register a source
|
||||||
template <typename S, typename... Args>
|
template <typename S, typename... Args>
|
||||||
@ -243,7 +226,8 @@ namespace netlist
|
|||||||
|
|
||||||
void register_source_proc(const pstring &name, nlsetup_func func);
|
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
|
// include other files
|
||||||
|
|
||||||
@ -256,7 +240,8 @@ namespace netlist
|
|||||||
|
|
||||||
// FIXME: used by source_t - need a different approach at some time
|
// 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_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>
|
template <typename S, typename... Args>
|
||||||
void add_include(Args &&...args)
|
void add_include(Args &&...args)
|
||||||
@ -303,5 +288,4 @@ namespace netlist
|
|||||||
|
|
||||||
} // namespace netlist
|
} // namespace netlist
|
||||||
|
|
||||||
|
|
||||||
#endif // NLSETUP_H_
|
#endif // NLSETUP_H_
|
||||||
|
@ -14,9 +14,6 @@
|
|||||||
|
|
||||||
#include "nl_config.h"
|
#include "nl_config.h"
|
||||||
|
|
||||||
#include "plib/pmempool.h"
|
|
||||||
#include "plib/ppmf.h"
|
|
||||||
#include "plib/pstring.h"
|
|
||||||
#include "plib/ptime.h"
|
#include "plib/ptime.h"
|
||||||
#include "plib/ptypes.h"
|
#include "plib/ptypes.h"
|
||||||
|
|
||||||
@ -170,12 +167,12 @@ namespace netlist
|
|||||||
///
|
///
|
||||||
/// \note This is not the right location yet.
|
/// \note This is not the right location yet.
|
||||||
///
|
///
|
||||||
|
|
||||||
using device_arena = std::conditional_t<
|
using device_arena = std::conditional_t<
|
||||||
config::use_mempool::value,
|
config::use_mempool::value,
|
||||||
plib::mempool_arena<plib::aligned_arena<>,
|
plib::mempool_arena<plib::aligned_arena<>,
|
||||||
config::mempool_align::value>,
|
config::mempool_align::value>,
|
||||||
plib::aligned_arena<>>;
|
plib::aligned_arena<>>;
|
||||||
|
|
||||||
using host_arena = plib::aligned_arena<>;
|
using host_arena = plib::aligned_arena<>;
|
||||||
|
|
||||||
using log_type = plib::plog_base<NL_DEBUG>;
|
using log_type = plib::plog_base<NL_DEBUG>;
|
||||||
@ -184,6 +181,9 @@ namespace netlist
|
|||||||
// Types needed by various includes
|
// Types needed by various includes
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
/// \brief Time step type.
|
/// \brief Time step type.
|
||||||
///
|
///
|
||||||
/// May be either FORWARD or RESTORE
|
/// May be either FORWARD or RESTORE
|
||||||
@ -194,15 +194,6 @@ namespace netlist
|
|||||||
RESTORE //!< restore state before last forward
|
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 Enum specifying the type of object
|
/// \brief Enum specifying the type of object
|
||||||
///
|
///
|
||||||
enum class terminal_type
|
enum class terminal_type
|
||||||
@ -317,37 +308,6 @@ namespace netlist
|
|||||||
using desc_const_t = std::integral_constant<const T, V>;
|
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
|
} // namespace netlist
|
||||||
|
|
||||||
#endif // NLTYPES_H_
|
#endif // NLTYPES_H_
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
#include "pconfig.h"
|
#include "pconfig.h"
|
||||||
|
#include "pgsl.h"
|
||||||
#include "ptypes.h"
|
#include "ptypes.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -271,8 +272,7 @@ namespace plib
|
|||||||
/// FIXME: limited implementation
|
/// FIXME: limited implementation
|
||||||
///
|
///
|
||||||
template <typename T1, typename T2>
|
template <typename T1, typename T2>
|
||||||
static inline
|
static inline auto pow(T1 v, T2 p) noexcept -> decltype(std::pow(v, p))
|
||||||
auto pow(T1 v, T2 p) noexcept -> decltype(std::pow(v, p))
|
|
||||||
{
|
{
|
||||||
return std::pow(v, p);
|
return std::pow(v, p);
|
||||||
}
|
}
|
||||||
@ -283,60 +283,30 @@ namespace plib
|
|||||||
return constants<FLOAT128>::one() / v;
|
return constants<FLOAT128>::one() / v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLOAT128 abs(FLOAT128 v) noexcept
|
static FLOAT128 abs(FLOAT128 v) noexcept { return fabsq(v); }
|
||||||
{
|
|
||||||
return fabsq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 sqrt(FLOAT128 v) noexcept
|
static FLOAT128 sqrt(FLOAT128 v) noexcept { return sqrtq(v); }
|
||||||
{
|
|
||||||
return sqrtq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 hypot(FLOAT128 v1, FLOAT128 v2) noexcept
|
static FLOAT128 hypot(FLOAT128 v1, FLOAT128 v2) noexcept
|
||||||
{
|
{
|
||||||
return hypotq(v1, v2);
|
return hypotq(v1, v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLOAT128 exp(FLOAT128 v) noexcept
|
static FLOAT128 exp(FLOAT128 v) noexcept { return expq(v); }
|
||||||
{
|
|
||||||
return expq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 log(FLOAT128 v) noexcept
|
static FLOAT128 log(FLOAT128 v) noexcept { return logq(v); }
|
||||||
{
|
|
||||||
return logq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 tanh(FLOAT128 v) noexcept
|
static FLOAT128 tanh(FLOAT128 v) noexcept { return tanhq(v); }
|
||||||
{
|
|
||||||
return tanhq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 floor(FLOAT128 v) noexcept
|
static FLOAT128 floor(FLOAT128 v) noexcept { return floorq(v); }
|
||||||
{
|
|
||||||
return floorq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 log1p(FLOAT128 v) noexcept
|
static FLOAT128 log1p(FLOAT128 v) noexcept { return log1pq(v); }
|
||||||
{
|
|
||||||
return log1pq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 sin(FLOAT128 v) noexcept
|
static FLOAT128 sin(FLOAT128 v) noexcept { return sinq(v); }
|
||||||
{
|
|
||||||
return sinq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 cos(FLOAT128 v) noexcept
|
static FLOAT128 cos(FLOAT128 v) noexcept { return cosq(v); }
|
||||||
{
|
|
||||||
return cosq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FLOAT128 trunc(FLOAT128 v) noexcept
|
static FLOAT128 trunc(FLOAT128 v) noexcept { return truncq(v); }
|
||||||
{
|
|
||||||
return truncq(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static FLOAT128 pow(FLOAT128 v, T p) noexcept
|
static FLOAT128 pow(FLOAT128 v, T p) noexcept
|
||||||
@ -374,8 +344,8 @@ namespace plib
|
|||||||
/// \return absolute value of argument
|
/// \return absolute value of argument
|
||||||
///
|
///
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr
|
constexpr std::enable_if_t<
|
||||||
std::enable_if_t<plib::is_integral<T>::value && plib::is_signed<T>::value, T>
|
plib::is_integral<T>::value && plib::is_signed<T>::value, T>
|
||||||
abs(T v) noexcept
|
abs(T v) noexcept
|
||||||
{
|
{
|
||||||
return v < 0 ? -v : v;
|
return v < 0 ? -v : v;
|
||||||
@ -388,8 +358,8 @@ namespace plib
|
|||||||
/// \return argument since it has no sign
|
/// \return argument since it has no sign
|
||||||
///
|
///
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr
|
constexpr std::enable_if_t<
|
||||||
std::enable_if_t<plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
|
plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
|
||||||
abs(T v) noexcept
|
abs(T v) noexcept
|
||||||
{
|
{
|
||||||
return v;
|
return v;
|
||||||
@ -413,9 +383,7 @@ namespace plib
|
|||||||
static_assert(plib::is_integral<M>::value, "gcd: M must be an integer");
|
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");
|
static_assert(plib::is_integral<N>::value, "gcd: N must be an integer");
|
||||||
|
|
||||||
return m == 0 ? plib::abs(n)
|
return m == 0 ? plib::abs(n) : n == 0 ? plib::abs(m) : gcd(n, m % n);
|
||||||
: n == 0 ? plib::abs(m)
|
|
||||||
: gcd(n, m % n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief return least common multiple
|
/// \brief return least common multiple
|
||||||
@ -430,13 +398,13 @@ namespace plib
|
|||||||
/// \return least common multiple of m and n
|
/// \return least common multiple of m and n
|
||||||
///
|
///
|
||||||
template <typename M, typename N>
|
template <typename M, typename N>
|
||||||
constexpr typename std::common_type<M, N>::type
|
constexpr typename std::common_type<M, N>::type lcm(M m, N n) noexcept
|
||||||
lcm(M m, N n) noexcept
|
|
||||||
{
|
{
|
||||||
static_assert(plib::is_integral<M>::value, "lcm: M must be an integer");
|
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");
|
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>
|
template <class T>
|
||||||
@ -446,7 +414,8 @@ namespace plib
|
|||||||
return (v < low) ? low : (high < v) ? high : v;
|
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
|
} // namespace plib
|
||||||
|
|
||||||
|
@ -7,10 +7,13 @@
|
|||||||
// Specific technical terms
|
// Specific technical terms
|
||||||
// spell-checker: words vsolver
|
// spell-checker: words vsolver
|
||||||
|
|
||||||
#include "nld_solver.h"
|
|
||||||
#include "core/setup.h"
|
|
||||||
#include "nl_setup.h"
|
|
||||||
#include "nld_matrix_solver.h"
|
#include "nld_matrix_solver.h"
|
||||||
|
|
||||||
|
#include "nl_setup.h"
|
||||||
|
#include "nld_solver.h"
|
||||||
|
|
||||||
|
#include "core/setup.h"
|
||||||
|
|
||||||
#include "plib/putil.h"
|
#include "plib/putil.h"
|
||||||
|
|
||||||
namespace netlist::solver
|
namespace netlist::solver
|
||||||
@ -27,7 +30,8 @@ namespace netlist::solver
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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++)
|
||||||
@ -35,7 +39,8 @@ namespace netlist::solver
|
|||||||
if (m_connected_net_idx[i] > net_other)
|
if (m_connected_net_idx[i] > net_other)
|
||||||
{
|
{
|
||||||
plib::container::insert_at(m_terms, i, term);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,11 +52,13 @@ namespace netlist::solver
|
|||||||
// matrix_solver
|
// matrix_solver
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
|
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver,
|
||||||
|
const pstring &name,
|
||||||
const net_list_t &nets,
|
const net_list_t &nets,
|
||||||
const solver::solver_parameters_t *params)
|
const solver::solver_parameters_t *params)
|
||||||
//: device_t(static_cast<device_t &>(main_solver), name)
|
//: device_t(static_cast<device_t &>(main_solver), name)
|
||||||
: device_t(device_data_t{main_solver.state(), main_solver.name() + "." + name})
|
: device_t(
|
||||||
|
device_data_t{main_solver.state(), main_solver.name() + "." + name})
|
||||||
, m_params(*params)
|
, m_params(*params)
|
||||||
, m_gonn(m_arena)
|
, m_gonn(m_arena)
|
||||||
, m_gtn(m_arena)
|
, m_gtn(m_arena)
|
||||||
@ -87,7 +94,8 @@ namespace netlist::solver
|
|||||||
m_main_solver.reschedule(this, ts);
|
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");
|
log().debug("New solver setup\n");
|
||||||
std::vector<core_device_t *> step_devices;
|
std::vector<core_device_t *> step_devices;
|
||||||
@ -108,7 +116,8 @@ namespace netlist::solver
|
|||||||
analog_net_t &net = *nets[k];
|
analog_net_t &net = *nets[k];
|
||||||
|
|
||||||
// FIXME: add size() to list
|
// 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);
|
net.set_solver(this);
|
||||||
|
|
||||||
@ -116,19 +125,24 @@ namespace netlist::solver
|
|||||||
{
|
{
|
||||||
nl_assert_always(&p->net() == &net, "Net integrity violated");
|
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())
|
switch (p->type())
|
||||||
{
|
{
|
||||||
case detail::terminal_type::TERMINAL:
|
case detail::terminal_type::TERMINAL:
|
||||||
if (p->device().is_time_step())
|
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());
|
step_devices.push_back(&p->device());
|
||||||
if (p->device().is_dynamic())
|
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());
|
dynamic_devices.push_back(&p->device());
|
||||||
{
|
{
|
||||||
auto pterm = plib::dynamic_downcast<terminal_t *>(p);
|
auto pterm = plib::dynamic_downcast<terminal_t *>(
|
||||||
nl_assert_always(bool(pterm), "cast to terminal_t * failed");
|
p);
|
||||||
|
nl_assert_always(bool(pterm),
|
||||||
|
"cast to terminal_t * failed");
|
||||||
add_term(k, *pterm);
|
add_term(k, *pterm);
|
||||||
}
|
}
|
||||||
log().debug("Added terminal {1}\n", p->name());
|
log().debug("Added terminal {1}\n", p->name());
|
||||||
@ -145,31 +159,44 @@ namespace netlist::solver
|
|||||||
|
|
||||||
if (net_proxy_output == nullptr)
|
if (net_proxy_output == nullptr)
|
||||||
{
|
{
|
||||||
pstring new_name(this->name() + "." + pstring(plib::pfmt("m{1}")(m_inputs.size())));
|
pstring new_name(
|
||||||
auto proxied_net = plib::dynamic_downcast<analog_net_t *>(p->net());
|
this->name() + "."
|
||||||
nl_assert_always(proxied_net, "Net is not an analog net");
|
+ pstring(plib::pfmt("m{1}")(m_inputs.size())));
|
||||||
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, new_name, *proxied_net);
|
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();
|
net_proxy_output = net_proxy_output_u.get();
|
||||||
m_inputs.emplace_back(std::move(net_proxy_output_u));
|
m_inputs.emplace_back(
|
||||||
|
std::move(net_proxy_output_u));
|
||||||
}
|
}
|
||||||
net.remove_terminal(*p);
|
net.remove_terminal(*p);
|
||||||
net_proxy_output->net().add_terminal(*p);
|
net_proxy_output->net().add_terminal(*p);
|
||||||
// FIXME: repeated calling - kind of brute force
|
// FIXME: repeated calling - kind of brute force
|
||||||
net_proxy_output->net().rebuild_list();
|
net_proxy_output->net().rebuild_list();
|
||||||
log().debug("Added input {1}", net_proxy_output->name());
|
log().debug("Added input {1}",
|
||||||
|
net_proxy_output->name());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case detail::terminal_type::OUTPUT:
|
case detail::terminal_type::OUTPUT:
|
||||||
log().fatal(MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
|
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();
|
net.rebuild_list();
|
||||||
}
|
}
|
||||||
for (auto &d : step_devices)
|
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)
|
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
|
/// \brief Sort terminals
|
||||||
@ -192,7 +219,8 @@ namespace netlist::solver
|
|||||||
/// literature but I have found no articles about Gauss Seidel.
|
/// literature but I have found no articles about Gauss Seidel.
|
||||||
///
|
///
|
||||||
/// For Gaussian Elimination however increasing order is better suited.
|
/// 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.
|
/// FIXME: This entry needs an update.
|
||||||
///
|
///
|
||||||
void matrix_solver_t::sort_terms(matrix_sort_type_e sort)
|
void matrix_solver_t::sort_terms(matrix_sort_type_e sort)
|
||||||
@ -238,20 +266,23 @@ namespace netlist::solver
|
|||||||
case matrix_sort_type_e::ASCENDING:
|
case matrix_sort_type_e::ASCENDING:
|
||||||
case matrix_sort_type_e::DESCENDING:
|
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 k = 0; k < iN - 1; k++)
|
||||||
for (std::size_t i = k + 1; i < iN; i++)
|
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;
|
break;
|
||||||
case matrix_sort_type_e::NOSORT:
|
case matrix_sort_type_e::NOSORT: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
// rebuild
|
// rebuild
|
||||||
for (auto &term : m_terms)
|
for (auto &term : m_terms)
|
||||||
@ -260,7 +291,8 @@ namespace netlist::solver
|
|||||||
for (std::size_t i = 0; i < term.count(); i++)
|
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)
|
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());
|
m_terms[k].set_rail_start(m_terms[k].count());
|
||||||
for (std::size_t i = 0; i < m_rails_temp[k].count(); i++)
|
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
|
// free all - no longer needed
|
||||||
@ -292,7 +326,8 @@ namespace netlist::solver
|
|||||||
t.m_nz.clear();
|
t.m_nz.clear();
|
||||||
|
|
||||||
for (std::size_t i = 0; i < t.rail_start(); i++)
|
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(static_cast<unsigned>(other[i]));
|
||||||
|
|
||||||
t.m_nz.push_back(k); // add diagonal
|
t.m_nz.push_back(k); // add diagonal
|
||||||
@ -326,7 +361,9 @@ namespace netlist::solver
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t i = 0; i < t.rail_start(); i++)
|
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]));
|
t.m_nzrd.push_back(static_cast<unsigned>(other[i]));
|
||||||
|
|
||||||
// and sort
|
// 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
|
// Dumps non zero elements right of diagonal -> to much output, disabled
|
||||||
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
|
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
|
||||||
@ -387,9 +425,12 @@ namespace netlist::solver
|
|||||||
{
|
{
|
||||||
pstring num = plib::pfmt("{1}")(k);
|
pstring num = plib::pfmt("{1}")(k);
|
||||||
|
|
||||||
state().save(*this, m_gonn[k],"GO" + num, this->name(), m_terms[k].count());
|
state().save(*this, m_gonn[k], "GO" + num, this->name(),
|
||||||
state().save(*this, m_gtn[k],"GT" + num, this->name(), m_terms[k].count());
|
m_terms[k].count());
|
||||||
state().save(*this, m_Idrn[k],"IDR" + 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,14 +461,16 @@ namespace netlist::solver
|
|||||||
m_connected_net_Vn.set(k, j, nullptr);
|
m_connected_net_Vn.set(k, j, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (std::size_t k = 0; k < iN; k++)
|
for (std::size_t k = 0; k < iN; k++)
|
||||||
{
|
{
|
||||||
auto count = m_terms[k].count();
|
auto count = m_terms[k].count();
|
||||||
for (std::size_t i = 0; i < count; i++)
|
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_terms[k].terms()[i]->set_ptrs(&m_gtn[k][i], &m_gonn[k][i],
|
||||||
m_connected_net_Vn[k][i] = get_connected_net(m_terms[k].terms()[i])->Q_Analog_state_ptr();
|
&m_Idrn[k][i]);
|
||||||
|
m_connected_net_Vn[k][i] = get_connected_net(
|
||||||
|
m_terms[k].terms()[i])
|
||||||
|
->Q_Analog_state_ptr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +494,8 @@ namespace netlist::solver
|
|||||||
// 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>());
|
const auto dd(delta.as_fp<fptype>());
|
||||||
for (auto &d : m_step_funcs)
|
for (auto &d : m_step_funcs)
|
||||||
@ -465,7 +509,8 @@ namespace netlist::solver
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
update_dynamic();
|
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->m_stat_calculations++;
|
||||||
this->upstream_solve_non_dynamic();
|
this->upstream_solve_non_dynamic();
|
||||||
this_resched = this->check_err();
|
this_resched = this->check_err();
|
||||||
@ -485,15 +530,18 @@ namespace netlist::solver
|
|||||||
bool resched(false);
|
bool resched(false);
|
||||||
|
|
||||||
restore();
|
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();
|
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();
|
resched = solve_nr_base();
|
||||||
// update time step calculation
|
// 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());
|
delta -= netlist_time::from_fp(m_params.m_min_ts_ts());
|
||||||
}
|
}
|
||||||
// try remaining time using compute_next_time step
|
// try remaining time using compute_next_time step
|
||||||
@ -502,19 +550,23 @@ namespace netlist::solver
|
|||||||
if (next_time_step > delta)
|
if (next_time_step > delta)
|
||||||
next_time_step = delta;
|
next_time_step = delta;
|
||||||
backup();
|
backup();
|
||||||
step(time_step_type::FORWARD, next_time_step);
|
step(detail::time_step_type::FORWARD, next_time_step);
|
||||||
delta -= next_time_step;
|
delta -= next_time_step;
|
||||||
resched = solve_nr_base();
|
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)
|
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)
|
if (resched)
|
||||||
{
|
{
|
||||||
// reschedule ....
|
// 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());
|
return netlist_time::from_fp(m_params.m_nr_recalc_delay());
|
||||||
}
|
}
|
||||||
if (m_params.m_dynamic_ts)
|
if (m_params.m_dynamic_ts)
|
||||||
@ -523,7 +575,8 @@ namespace netlist::solver
|
|||||||
return netlist_time::from_fp(m_params.m_max_time_step);
|
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());
|
auto delta = static_cast<netlist_time>(now - m_last_step());
|
||||||
PFDEBUG(printf("solve %.10f\n", delta.as_double());)
|
PFDEBUG(printf("solve %.10f\n", delta.as_double());)
|
||||||
@ -533,7 +586,9 @@ namespace netlist::solver
|
|||||||
if (delta < netlist_time::quantum())
|
if (delta < netlist_time::quantum())
|
||||||
{
|
{
|
||||||
// printf("solve return %s at %f\n", source, now.as_double());
|
// 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();
|
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
|
backup(); // save voltages for backup and time step calculation
|
||||||
@ -543,7 +598,7 @@ namespace netlist::solver
|
|||||||
++m_stat_vsolver_calls;
|
++m_stat_vsolver_calls;
|
||||||
if (dynamic_device_count() != 0)
|
if (dynamic_device_count() != 0)
|
||||||
{
|
{
|
||||||
step(time_step_type::FORWARD, delta);
|
step(detail::time_step_type::FORWARD, delta);
|
||||||
const auto resched = solve_nr_base();
|
const auto resched = solve_nr_base();
|
||||||
|
|
||||||
if (resched)
|
if (resched)
|
||||||
@ -551,7 +606,7 @@ namespace netlist::solver
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
step(time_step_type::FORWARD, delta);
|
step(detail::time_step_type::FORWARD, delta);
|
||||||
this->m_stat_calculations++;
|
this->m_stat_calculations++;
|
||||||
this->upstream_solve_non_dynamic();
|
this->upstream_solve_non_dynamic();
|
||||||
this->store();
|
this->store();
|
||||||
@ -560,14 +615,15 @@ namespace netlist::solver
|
|||||||
if (m_params.m_dynamic_ts)
|
if (m_params.m_dynamic_ts)
|
||||||
{
|
{
|
||||||
if (time_step_device_count() > 0)
|
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)
|
if (time_step_device_count() > 0)
|
||||||
return netlist_time::from_fp(m_params.m_max_time_step);
|
return netlist_time::from_fp(m_params.m_max_time_step);
|
||||||
|
|
||||||
return netlist_time::zero();
|
return netlist_time::zero();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
|
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
|
||||||
@ -578,11 +634,14 @@ namespace netlist::solver
|
|||||||
return -1;
|
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 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);
|
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]));
|
auto col = get_net_idx(get_connected_net(term.terms()[i]));
|
||||||
if (col != -1)
|
if (col != -1)
|
||||||
{
|
{
|
||||||
if (col==row) col = diag;
|
if (col == row)
|
||||||
else if (col==diag) col = row;
|
col = diag;
|
||||||
|
else if (col == diag)
|
||||||
|
col = row;
|
||||||
|
|
||||||
if (col > diag && col < colmin)
|
if (col > diag && col < colmin)
|
||||||
colmin = col;
|
colmin = col;
|
||||||
@ -610,7 +671,9 @@ namespace netlist::solver
|
|||||||
return {colmax, colmin};
|
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)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@ -629,10 +692,14 @@ namespace netlist::solver
|
|||||||
auto colu = static_cast<std::size_t>(col);
|
auto colu = static_cast<std::size_t>(col);
|
||||||
if (!touched[colu])
|
if (!touched[colu])
|
||||||
{
|
{
|
||||||
if (colu==row) colu = static_cast<unsigned>(diag);
|
if (colu == row)
|
||||||
else if (colu==diag) colu = static_cast<unsigned>(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;
|
touched[colu] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -657,31 +724,39 @@ namespace netlist::solver
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
log().fatal(MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
|
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()
|
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("==============================================");
|
||||||
log().verbose("Solver {1}", this->name());
|
log().verbose("Solver {1}", this->name());
|
||||||
log().verbose(" ==> {1} nets", this->m_terms.size());
|
log().verbose(" ==> {1} nets", this->m_terms.size());
|
||||||
log().verbose(" has {1} dynamic elements", this->dynamic_device_count());
|
log().verbose(" has {1} dynamic elements",
|
||||||
log().verbose(" has {1} time step elements", this->time_step_device_count());
|
this->dynamic_device_count());
|
||||||
log().verbose(" {1:6.3} average newton raphson loops",
|
log().verbose(" has {1} time step elements",
|
||||||
static_cast<fptype>(this->m_stat_newton_raphson) / static_cast<fptype>(this->m_stat_vsolver_calls));
|
this->time_step_device_count());
|
||||||
log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
|
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,
|
this->m_stat_calculations,
|
||||||
static_cast<fptype>(this->m_stat_calculations) / this->exec().time().as_fp<fptype>(),
|
static_cast<fptype>(this->m_stat_calculations)
|
||||||
|
/ this->exec().time().as_fp<fptype>(),
|
||||||
this->m_iterative_fail,
|
this->m_iterative_fail,
|
||||||
nlconst::hundred() * static_cast<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_stat_calculations),
|
||||||
static_cast<fptype>(this->m_iterative_total) / static_cast<fptype>(this->m_stat_calculations));
|
static_cast<fptype>(this->m_iterative_total)
|
||||||
|
/ static_cast<fptype>(this->m_stat_calculations));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace netlist::solver
|
} // namespace netlist::solver
|
||||||
|
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
/// \file nld_matrix_solver.h
|
/// \file nld_matrix_solver.h
|
||||||
///
|
///
|
||||||
|
|
||||||
|
#include "nl_errstr.h"
|
||||||
|
#include "nltypes.h"
|
||||||
|
|
||||||
#include "../core/analog.h"
|
#include "../core/analog.h"
|
||||||
#include "../core/device.h"
|
#include "../core/device.h"
|
||||||
#include "../core/device_macros.h"
|
#include "../core/device_macros.h"
|
||||||
#include "../core/param.h"
|
#include "../core/param.h"
|
||||||
|
|
||||||
#include "nl_errstr.h"
|
|
||||||
#include "nltypes.h"
|
|
||||||
#include "plib/palloc.h"
|
#include "plib/palloc.h"
|
||||||
#include "plib/penum.h"
|
#include "plib/penum.h"
|
||||||
#include "plib/pmatrix2d.h"
|
#include "plib/pmatrix2d.h"
|
||||||
@ -42,6 +42,8 @@ namespace netlist::solver
|
|||||||
CXX_STATIC
|
CXX_STATIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
PENUM(matrix_sort_type_e,
|
PENUM(matrix_sort_type_e,
|
||||||
NOSORT,
|
NOSORT,
|
||||||
ASCENDING,
|
ASCENDING,
|
||||||
@ -67,6 +69,8 @@ namespace netlist::solver
|
|||||||
, FLOATQ128
|
, FLOATQ128
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
using arena_type = plib::mempool_arena<plib::aligned_arena<>, 1024>;
|
using arena_type = plib::mempool_arena<plib::aligned_arena<>, 1024>;
|
||||||
using static_compile_container = std::vector<std::pair<pstring, pstring>>;
|
using static_compile_container = std::vector<std::pair<pstring, pstring>>;
|
||||||
|
|
||||||
@ -76,8 +80,14 @@ namespace netlist::solver
|
|||||||
|
|
||||||
// iteration parameters
|
// iteration parameters
|
||||||
static constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
|
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_type_e m_method()
|
||||||
static constexpr matrix_fp_type_e m_fp_type() { return matrix_fp_type_e::DOUBLE; }
|
{
|
||||||
|
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_reltol() { return nlconst::magic(1e-3); }
|
||||||
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
|
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
|
||||||
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
|
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
|
||||||
@ -87,17 +97,32 @@ namespace netlist::solver
|
|||||||
// general parameters
|
// general parameters
|
||||||
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
|
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
|
||||||
static constexpr bool m_pivot() { return false; }
|
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 nl_fptype m_nr_recalc_delay()
|
||||||
|
{
|
||||||
|
return netlist_time::quantum().as_fp<nl_fptype>();
|
||||||
|
}
|
||||||
static constexpr int m_parallel() { return 0; }
|
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
|
// automatic time step
|
||||||
static constexpr bool m_dynamic_ts() { return false; }
|
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_lte()
|
||||||
static constexpr nl_fptype m_dynamic_min_ts() { return nlconst::magic(1e-6); }
|
{
|
||||||
|
return nlconst::magic(1e-5);
|
||||||
|
}
|
||||||
|
static constexpr nl_fptype m_dynamic_min_ts()
|
||||||
|
{
|
||||||
|
return nlconst::magic(1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
// matrix sorting
|
// 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
|
// special
|
||||||
static constexpr bool m_use_gabs() { return true; }
|
static constexpr bool m_use_gabs() { return true; }
|
||||||
@ -112,30 +137,52 @@ namespace netlist::solver
|
|||||||
struct solver_parameters_t
|
struct solver_parameters_t
|
||||||
{
|
{
|
||||||
template <typename D>
|
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())
|
: m_freq(parent, prefix + "FREQ", defaults.m_freq())
|
||||||
|
|
||||||
// iteration parameters
|
// iteration parameters
|
||||||
, m_gs_sor(parent, prefix + "SOR_FACTOR", defaults.m_gs_sor())
|
, m_gs_sor(parent, prefix + "SOR_FACTOR", defaults.m_gs_sor())
|
||||||
, m_method(parent, prefix + "METHOD", defaults.m_method())
|
, m_method(parent, prefix + "METHOD", defaults.m_method())
|
||||||
, m_fp_type(parent, prefix + "FPTYPE", defaults.m_fp_type())
|
, m_fp_type(parent, prefix + "FPTYPE", defaults.m_fp_type())
|
||||||
, m_reltol(parent, prefix + "RELTOL", defaults.m_reltol()) //!< SPICE RELTOL parameter
|
, m_reltol(parent, prefix + "RELTOL",
|
||||||
, m_vntol(parent, prefix + "VNTOL", defaults.m_vntol()) //!< SPICE VNTOL parameter
|
defaults.m_reltol()) //!< SPICE RELTOL parameter
|
||||||
, m_accuracy(parent, prefix + "ACCURACY", defaults.m_accuracy()) //!< Iterative solver accuracy
|
, m_vntol(parent, prefix + "VNTOL", defaults.m_vntol()) //!< SPICE VNTOL
|
||||||
, m_nr_loops(parent, prefix + "NR_LOOPS", defaults.m_nr_loops()) //!< Maximum number of Newton-Raphson loops
|
//!< parameter
|
||||||
, m_gs_loops(parent, prefix + "GS_LOOPS", defaults.m_gs_loops()) //!< Maximum number of Gauss-Seidel loops
|
, 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
|
// general parameters
|
||||||
, m_gmin(parent, prefix + "GMIN", defaults.m_gmin())
|
, m_gmin(parent, prefix + "GMIN", defaults.m_gmin())
|
||||||
, m_pivot(parent, prefix + "PIVOT", defaults.m_pivot()) //!< use pivoting on supported solvers
|
, m_pivot(parent, prefix + "PIVOT", defaults.m_pivot()) //!< use
|
||||||
, m_nr_recalc_delay(parent, prefix + "NR_RECALC_DELAY", defaults.m_nr_recalc_delay()) //!< Delay to next solve attempt if nr loops exceeded
|
//!< 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_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
|
// automatic time step
|
||||||
, m_dynamic_ts(parent, prefix + "DYNAMIC_TS", defaults.m_dynamic_ts()) //!< Use dynamic time stepping
|
, m_dynamic_ts(parent, prefix + "DYNAMIC_TS",
|
||||||
, m_dynamic_lte(parent, prefix + "DYNAMIC_LTE", defaults.m_dynamic_lte()) //!< dynamic time stepping slope
|
defaults.m_dynamic_ts()) //!< Use dynamic time stepping
|
||||||
, m_dynamic_min_ts(parent, prefix + "DYNAMIC_MIN_TIMESTEP", defaults.m_dynamic_min_ts()) //!< smallest time step allowed
|
, 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
|
// matrix sorting
|
||||||
, m_sort_type(parent, prefix + "SORT_TYPE", defaults.m_sort_type())
|
, m_sort_type(parent, prefix + "SORT_TYPE", defaults.m_sort_type())
|
||||||
@ -144,7 +191,8 @@ namespace netlist::solver
|
|||||||
, m_use_gabs(parent, prefix + "USE_GABS", defaults.m_use_gabs())
|
, m_use_gabs(parent, prefix + "USE_GABS", defaults.m_use_gabs())
|
||||||
, m_min_time_step(m_dynamic_min_ts())
|
, 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)
|
if (m_dynamic_ts)
|
||||||
{
|
{
|
||||||
@ -181,7 +229,6 @@ namespace netlist::solver
|
|||||||
nl_fptype m_max_time_step;
|
nl_fptype m_max_time_step;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class terms_for_net_t
|
class terms_for_net_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -201,17 +248,28 @@ namespace netlist::solver
|
|||||||
|
|
||||||
void setV(nl_fptype v) noexcept { m_net->set_Q_Analog(v); }
|
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; }
|
void set_rail_start(std::size_t val) noexcept { m_rail_start = val; }
|
||||||
|
|
||||||
PALIGNAS_VECTOROPT()
|
PALIGNAS_VECTOROPT()
|
||||||
|
|
||||||
plib::arena_vector<arena_type, unsigned> m_nz; //!< all non zero for multiplication
|
plib::arena_vector<arena_type, unsigned> m_nz; //!< all non zero for
|
||||||
plib::arena_vector<arena_type, unsigned> m_nzrd; //!< non zero right of the diagonal for elimination, may include RHS element
|
//!< multiplication
|
||||||
plib::arena_vector<arena_type, unsigned> m_nzbd; //!< non zero below of the diagonal for elimination
|
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;
|
plib::arena_vector<arena_type, int> m_connected_net_idx;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
plib::arena_vector<arena_type, terminal_t *> m_terms;
|
plib::arena_vector<arena_type, terminal_t *> m_terms;
|
||||||
analog_net_t *m_net;
|
analog_net_t *m_net;
|
||||||
@ -221,15 +279,18 @@ namespace netlist::solver
|
|||||||
class proxied_analog_output_t : public analog_output_t
|
class proxied_analog_output_t : public analog_output_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
proxied_analog_output_t(core_device_t &dev, const pstring &aname,
|
||||||
proxied_analog_output_t(core_device_t &dev, const pstring &aname, analog_net_t *pnet)
|
analog_net_t *pnet)
|
||||||
: analog_output_t(dev, aname)
|
: analog_output_t(dev, aname)
|
||||||
, m_proxied_net(pnet)
|
, 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:
|
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
|
class matrix_solver_t : public device_t
|
||||||
@ -245,8 +306,14 @@ namespace netlist::solver
|
|||||||
netlist_time solve(netlist_time_ext now, const char *source);
|
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 dynamic_device_count() const noexcept
|
||||||
std::size_t time_step_device_count() const noexcept { return m_step_funcs.size(); }
|
{
|
||||||
|
return m_dynamic_funcs.size();
|
||||||
|
}
|
||||||
|
std::size_t time_step_device_count() const noexcept
|
||||||
|
{
|
||||||
|
return m_step_funcs.size();
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief reschedule solver execution
|
/// \brief reschedule solver execution
|
||||||
///
|
///
|
||||||
@ -264,23 +331,28 @@ namespace netlist::solver
|
|||||||
// this should only occur outside of execution and thus
|
// this should only occur outside of execution and thus
|
||||||
// using time should be safe.
|
// 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();
|
update_inputs();
|
||||||
|
|
||||||
if (time_step_device_count() > 0)
|
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>
|
template <typename F>
|
||||||
void change_state(F 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)
|
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();
|
update_inputs();
|
||||||
}
|
}
|
||||||
f();
|
f();
|
||||||
@ -297,9 +369,11 @@ namespace netlist::solver
|
|||||||
|
|
||||||
virtual void log_stats();
|
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
|
// return number of floating point operations for solve
|
||||||
@ -311,7 +385,9 @@ namespace netlist::solver
|
|||||||
const solver_parameters_t *params);
|
const solver_parameters_t *params);
|
||||||
|
|
||||||
virtual void upstream_solve_non_dynamic() = 0;
|
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 bool check_err() const = 0;
|
||||||
virtual void store() = 0;
|
virtual void store() = 0;
|
||||||
virtual void backup() = 0;
|
virtual void backup() = 0;
|
||||||
@ -339,7 +415,6 @@ namespace netlist::solver
|
|||||||
std::vector<terms_for_net_t> m_terms; // setup only
|
std::vector<terms_for_net_t> m_terms; // setup only
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// base setup - called from constructor
|
// base setup - called from constructor
|
||||||
void setup_base(setup_t &setup, const net_list_t &nets) noexcept(false);
|
void setup_base(setup_t &setup, const net_list_t &nets) noexcept(false);
|
||||||
|
|
||||||
@ -349,10 +424,11 @@ namespace netlist::solver
|
|||||||
void sort_terms(matrix_sort_type_e sort);
|
void sort_terms(matrix_sort_type_e sort);
|
||||||
|
|
||||||
void update_dynamic() noexcept;
|
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;
|
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);
|
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);
|
void add_term(std::size_t net_idx, terminal_t *term) noexcept(false);
|
||||||
@ -374,7 +450,9 @@ namespace netlist::solver
|
|||||||
state_var<netlist_time_ext> m_last_step;
|
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_ts> m_step_funcs;
|
||||||
plib::arena_vector<arena_type, nl_delegate_dyn> m_dynamic_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;
|
std::size_t m_ops;
|
||||||
|
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
// copyright-holders:Couriersud
|
// 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/pconfig.h"
|
||||||
#include "plib/ppmf.h"
|
#include "plib/ppmf.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user