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:
couriersud 2022-07-16 22:48:22 +02:00 committed by GitHub
parent 20d6ea06f4
commit 4ecc148240
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1221 additions and 954 deletions

View File

@ -11,14 +11,11 @@
#include "emu.h"
#include "netlist.h"
#include "netlist/nl_base.h"
#include "netlist/nl_setup.h"
#include "netlist/nl_factory.h"
#include "netlist/nl_parser.h"
#include "netlist/nl_interface.h"
#include "netlist/plib/palloc.h"
#include "netlist/plib/pmempool.h"
#include "netlist/plib/pdynlib.h"
#include "netlist/plib/pstonum.h"

View File

@ -2,24 +2,26 @@
// copyright-holders:Couriersud
/***************************************************************************
fixfreq.h
fixfreq.h
2013-2021 Couriersud
2013-2021 Couriersud
Fixed frequency monochrome monitor emulation
Fixed frequency monochrome monitor emulation
The driver is intended for drivers which provide an analog video signal.
VSYNC and HSYNC levels are used to create the bitmap.
The driver is intended for drivers which provide an analog video signal.
VSYNC and HSYNC levels are used to create the bitmap.
***************************************************************************/
// emu.h must be first to be included
#include "emu.h"
#include "fixfreq.h"
#include "render.h"
#include "ui/uimain.h"
#include <cstdio>
#include <iostream>
// for quick and dirty debugging
#define VERBOSE 0
@ -36,20 +38,24 @@
// --------------------------------------------------------------------------
// device type definition
DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monochrome Monitor")
DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq",
"Fixed-Frequency Monochrome Monitor")
// --------------------------------------------------------------------------
// Port adjuster support
// --------------------------------------------------------------------------
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
PORT_START(# _id) \
configurer.field_alloc(IPT_ADJUSTER, (static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, ("Monitor - " _name)); \
PORT_MINMAX(_min, _max) \
PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
#define PORT_ADJUSTERX(_id, _name, _min, _max) \
PORT_START(#_id) \
configurer.field_alloc( \
IPT_ADJUSTER, \
(static_cast<fixedfreq_device &>(owner).monitor_val(_id)), 0xffff, \
("Monitor - " _name)); \
PORT_MINMAX(_min, _max) \
PORT_CHANGED_MEMBER(DEVICE_SELF, fixedfreq_device, port_changed, _id) \
PORT_CONDITION("ENABLE", 0x01, EQUALS, 0x01)
#define IOPORT_ID(_id) ioport(# _id)
#define IOPORT_ID(_id) ioport(#_id)
enum fixedfreq_tag_id_e
{
@ -67,30 +73,36 @@ enum fixedfreq_tag_id_e
SCANLINE_HEIGHT
};
void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const double newval)
void fixedfreq_monitor_state::update_sync_channel(const time_type &time,
const double newval)
{
const time_type delta_time = time - m_last_sync_time;
const int last_vsync = m_sig_vsync;
const int last_comp = m_sig_composite;
m_vsync_filter += ((double) last_comp - m_vsync_filter) * (1.0 - exp(-delta_time * m_desc.vsync_filter_timeconst()));
m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0 ;
m_vsync_filter += ((double)last_comp - m_vsync_filter)
* (1.0
- exp(-delta_time * m_desc.vsync_filter_timeconst()));
m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0;
m_sig_vsync = (m_vsync_filter > m_desc.m_vsync_threshold) ? 1 : 0;
if (!last_vsync && m_sig_vsync)
{
LOG("VSYNC UP %f %d\n", m_last_x, m_last_y);
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
const int has_fields = (m_desc.m_fieldcount > 1) ? 1 : 0;
// FIXME: add modes: true interlaced, overlayed, false progressive (see popeye video)
// FIXME: add modes: true interlaced, overlayed, false progressive (see
// popeye video)
if (has_fields)
{
const auto avg_line_dur = (time - m_last_field_time) * m_desc.m_fieldcount / (m_last_y + 1);
const auto avg_line_dur = (time - m_last_field_time)
* m_desc.m_fieldcount / (m_last_y + 1);
m_last_field_time = time;
m_sig_field = avg_line_dur * 0.75 > m_last_line_duration;
LOG("%d %f %f %f\n", m_sig_field, m_last_line_duration, avg_line_dur, time);
LOG("%d %f %f %f\n", m_sig_field, m_last_line_duration,
avg_line_dur, time);
}
// notify the controlling device about the vsync and the field.
@ -108,12 +120,13 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
{
if (m_sig_vsync)
LOG("Hsync in vsync\n");
//LOG("HSYNC up %d\n", m_last_x);
// FIXME: pixels > 0 filters some spurious hysnc on line 23/24 in breakout
// The hsync signal transition from high to low is 7 pixels too
// early, goes up again after 6.8 pix and down after 7.2 pix.
// Therefore we need to filter early low to high transitions
// and base hsync on the start of the hsync signal.
// LOG("HSYNC up %d\n", m_last_x);
// FIXME: pixels > 0 filters some spurious hysnc on line
// 23/24 in breakout
// The hsync signal transition from high to low is 7 pixels too
// early, goes up again after 6.8 pix and down after 7.2 pix.
// Therefore we need to filter early low to high transitions
// and base hsync on the start of the hsync signal.
if (!m_sig_vsync && (m_last_x > 0))
{
m_last_y += m_desc.m_fieldcount;
@ -122,13 +135,12 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
m_last_line_duration = time - m_last_hsync_time;
m_last_hsync_time = time;
}
}
else if (last_comp && !m_sig_composite)
{
/* falling composite */
//LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
// LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
}
m_last_sync_val = newval;
m_last_sync_time = time;
@ -136,99 +148,109 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
void fixedfreq_monitor_state::update_bm(const time_type &time)
{
const float pixels = (time - m_line_time) * (double) m_desc.monitor_clock();
const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;
const float pixels = (time - m_line_time) * (double)m_desc.monitor_clock();
const int has_fields = (m_desc.m_fieldcount > 1) ? 1 : 0;
const float fhscale(static_cast<float>(m_desc.m_hscale));
//uint32_t col(0xffff0000); // Mark sync areas
//if (m_last_sync >= m_desc.m_sync_threshold)
// col = m_col;
// uint32_t col(0xffff0000); // Mark sync areas
// if (m_last_sync >= m_desc.m_sync_threshold)
// col = m_col;
if (!m_sig_vsync && !m_sig_composite)
{
//uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields),
m_last_x * fhscale, pixels * fhscale, m_col}); // & mask});
// uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
m_fragments.push_back(
{static_cast<float>(m_last_y + m_sig_field * has_fields),
m_last_x * fhscale, pixels * fhscale, m_col}); // & mask});
}
//m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels, col);
// m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels,
// col);
m_last_x = pixels;
}
void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time, const double data)
void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time,
const double data)
{
update_bm(time);
update_sync_channel(time, data);
//int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
int colv = (int) ((data - 1.5) * m_desc.m_gain * 255.0);
//#int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
int colv = (int)((data - 1.5) * m_desc.m_gain * 255.0);
if (colv > 255)
colv = 255;
if (colv < 0)
//m_col = 0xffff0000;
// m_col = 0xffff0000;
m_col = 0x0000000;
else
m_col = 0xff000000 | (colv<<16) | (colv<<8) | colv;
m_col = 0xff000000 | (colv << 16) | (colv << 8) | colv;
}
void fixedfreq_monitor_state::update_red(const time_type &time, const double data)
void fixedfreq_monitor_state::update_red(const time_type &time,
const double data)
{
update_bm(time);
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
int colv = (int)((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
if (colv > 255)
colv = 255;
if (colv < 0)
colv = 0;
m_col = (m_col & 0xff00ffff) | (colv<<16);
m_col = (m_col & 0xff00ffff) | (colv << 16);
}
void fixedfreq_monitor_state::update_green(const time_type &time, const double data)
void fixedfreq_monitor_state::update_green(const time_type &time,
const double data)
{
update_bm(time);
//update_sync_channel(ctime, data);
// update_sync_channel(ctime, data);
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
int colv = (int)((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
if (colv > 255)
colv = 255;
if (colv < 0)
colv = 0;
m_col = (m_col & 0xffff00ff) | (colv<<8);
m_col = (m_col & 0xffff00ff) | (colv << 8);
}
void fixedfreq_monitor_state::update_blue(const time_type &time, const double data)
void fixedfreq_monitor_state::update_blue(const time_type &time,
const double data)
{
update_bm(time);
//update_sync_channel(ctime, data);
// update_sync_channel(ctime, data);
int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
int colv = (int)((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
if (colv > 255)
colv = 255;
if (colv < 0)
colv = 0;
m_col = (m_col & 0xffffff00) | colv;
}
void fixedfreq_monitor_state::update_sync(const time_type &time, const double data)
void fixedfreq_monitor_state::update_sync(const time_type &time,
const double data)
{
update_bm(time);
update_sync_channel(time, data);
}
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock),
device_video_interface(mconfig, *this, false),
m_enable(*this, "ENABLE"),
m_vector(*this, "VECTOR"),
m_scanline_height(1.0),
m_last_rt(0.0),
m_monitor(),
m_state(m_monitor, *this)
fixedfreq_device::fixedfreq_device(const machine_config &mconfig,
device_type type, const char *tag,
device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, device_video_interface(mconfig, *this, false)
, m_enable(*this, "ENABLE")
, m_vector(*this, "VECTOR")
, m_scanline_height(1.0)
, m_last_rt(0.0)
, m_monitor()
, m_state(m_monitor, *this)
{
}
fixedfreq_device::fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
fixedfreq_device::fixedfreq_device(const machine_config &mconfig,
const char *tag, device_t *owner,
uint32_t clock)
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
{
}
@ -251,10 +273,11 @@ void fixedfreq_device::device_config_complete()
// to specify the window size.
if (!screen().refresh_attoseconds())
screen().set_raw(m_monitor.m_monitor_clock, m_monitor.htotal(), 0,
m_monitor.htotal(), m_monitor.vtotal(), 0,
m_monitor.vtotal());
m_monitor.htotal(), m_monitor.vtotal(), 0,
m_monitor.vtotal());
if (!screen().has_screen_update())
screen().set_screen_update(*this, FUNC(fixedfreq_device::screen_update));
screen().set_screen_update(*this,
FUNC(fixedfreq_device::screen_update));
LOG("config complete\n");
}
@ -288,7 +311,7 @@ void fixedfreq_device::device_reset()
{
m_state.reset();
LOG("Reset\n");
//ioport("YYY")->field(0xffff)->live().value = 20;
// ioport("YYY")->field(0xffff)->live().value = 20;
#if 0
//IOPORT_ID(HVISIBLE)->field(~0)->set_value(m_monitor.m_hvisible);
//IOPORT_ID(HVISIBLE)->update_defvalue(false);
@ -307,36 +330,39 @@ void fixedfreq_device::device_reset()
void fixedfreq_device::device_post_load()
{
//recompute_parameters();
// recompute_parameters();
LOG("post load\n");
}
static uint32_t nom_col(uint32_t col)
{
float r = ((col >> 16) & 0xff);
float g = ((col >> 8) & 0xff);
float b = ((col >> 0) & 0xff);
float g = ((col >> 8) & 0xff);
float b = ((col >> 0) & 0xff);
float m = std::max(r, std::max(g,b));
float m = std::max(r, std::max(g, b));
if (m == 0.0f)
return 0;
return (((uint32_t) m ) << 24) | (((uint32_t) (r/m*255.0f) ) << 16)
| (((uint32_t) (g/m*255.0f) ) << 8) | (((uint32_t) (b/m*255.0f) ) << 0);
return (((uint32_t)m) << 24) | (((uint32_t)(r / m * 255.0f)) << 16)
| (((uint32_t)(g / m * 255.0f)) << 8)
| (((uint32_t)(b / m * 255.0f)) << 0);
}
static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap,
const rectangle &cliprect)
{
// Test pattern Grey scale
const int stripes = 255;
//auto va(screen.visible_area());
// auto va(screen.visible_area());
auto &va(cliprect);
for (int i = 0; i < stripes; i++)
{
int l = va.left() + (i * va.width() / stripes);
int w = (va.left() + (i+1) * va.width() / stripes) - l;
int w = (va.left() + (i + 1) * va.width() / stripes) - l;
int v = (255 * i) / stripes;
bitmap.plot_box(l, va.top()+20, w, va.height()/2-20, rgb_t(0xff, v, v, v));
bitmap.plot_box(l, va.top() + 20, w, va.height() / 2 - 20,
rgb_t(0xff, v, v, v));
}
int l(va.left() + va.width() / 4);
@ -353,14 +379,20 @@ static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rect
bitmap.plot_box(l, t, w, h, rgb_t(0xff, 0xc3, 0xc3, 0xc3)); // 195
}
uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
uint32_t
fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
const rectangle &cliprect)
{
//printf("%f\n", machine().time().as_double());
//printf("%d %lu %f %f\n", m_state.m_sig_vsync, m_state.m_fragments.size(), m_state.m_fragments[0].y, m_state.m_fragments[m_state.m_fragments.size()-1].y);
bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR || (m_vector->read() & 1);
bool debug_timing = (m_enable->read() & 2) == 2;
bool test_pat = (m_enable->read() & 4) == 4;
rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00) : rgb_t(0xff, 0x00, 0x00, 0x00);
// printf("%f\n", machine().time().as_double());
// printf("%d %lu %f %f\n", m_state.m_sig_vsync, m_state.m_fragments.size(),
// m_state.m_fragments[0].y,
// m_state.m_fragments[m_state.m_fragments.size()-1].y);
bool force_vector = screen.screen_type() == SCREEN_TYPE_VECTOR
|| (m_vector->read() & 1);
bool debug_timing = (m_enable->read() & 2) == 2;
bool test_pat = (m_enable->read() & 4) == 4;
rgb_t backcol = debug_timing ? rgb_t(0xff, 0xff, 0x00, 0x00)
: rgb_t(0xff, 0x00, 0x00, 0x00);
if (!force_vector)
{
@ -377,18 +409,22 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
{
screen.set_video_attributes(VIDEO_SELF_RENDER);
const uint32_t flags(PRIMFLAG_ANTIALIAS(1)
| PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1) : 0));
const uint32_t flags(
PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD)
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTOR(1)
: 0));
const rectangle &visarea = screen.visible_area();
float xscale = 1.0f / (float)visarea.width();
float yscale = 1.0f / (float)visarea.height();
float xoffs = (float)visarea.min_x;
float yoffs = (float)visarea.min_y;
float xscale = 1.0f / (float)visarea.width();
float yscale = 1.0f / (float)visarea.height();
float xoffs = (float)visarea.min_x;
float yoffs = (float)visarea.min_y;
screen.container().empty();
screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00),
screen.container().add_rect(
0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff, 0x00, 0x00, 0x00),
PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)
| (screen.screen_type() == SCREEN_TYPE_VECTOR ? PRIMFLAG_VECTORBUF(1) : 0));
| (screen.screen_type() == SCREEN_TYPE_VECTOR
? PRIMFLAG_VECTORBUF(1)
: 0));
float last_y = -1e6;
for (auto &f : m_state.m_fragments)
@ -397,7 +433,7 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
const float y0((f.y - yoffs) * yscale);
const float x1((f.xr - xoffs) * xscale);
rgb_t col = (debug_timing && f.y < last_y) ? backcol : (rgb_t) f.col;
rgb_t col = (debug_timing && f.y < last_y) ? backcol : (rgb_t)f.col;
// FIXME: Debug check for proper vsync timing
#if 0
auto w = m_scanline_height * xscale * 0.5;
@ -407,21 +443,18 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
// (0xff << 24) | (f.col & 0xffffff),
flags);
#elif 1
const float y1((f.y + m_scanline_height - yoffs) * yscale);
screen.container().add_rect(
x0, y0, x1, y1,
nom_col(col),
// (0xaf << 24) | (f.col & 0xffffff),
flags);
const float y1((f.y + m_scanline_height - yoffs) * yscale);
screen.container().add_rect(x0, y0, x1, y1, nom_col(col),
// (0xaf << 24) |
// (f.col & 0xffffff),
flags);
#else
const float y1((f.y + m_scanline_height - yoffs) * yscale);
// Crashes with bgfx
screen.container().add_quad(
x0, y0, x1, y1,
rgb_t(nom_col(f.col)),
// (0xaf << 24) | (f.col & 0xffffff),
m_texture,
flags);
const float y1((f.y + m_scanline_height - yoffs) * yscale);
// Crashes with bgfx
screen.container().add_quad(x0, y0, x1, y1, rgb_t(nom_col(f.col)),
// (0xaf << 24) |
// (f.col & 0xffffff),
m_texture, flags);
#endif
last_y = f.y;
}
@ -432,8 +465,9 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
{
const auto expected_frame_period(m_monitor.clock_period() * m_monitor.vtotal() * m_monitor.htotal());
bool progressive = (m_enable->read() & 8) == 8;
const auto expected_frame_period(m_monitor.clock_period()
* m_monitor.vtotal() * m_monitor.htotal());
bool progressive = (m_enable->read() & 8) == 8;
double mult = 0.5;
@ -448,15 +482,21 @@ void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
mult = 1.0;
}
const auto refresh_limited(std::min(4.0 * expected_frame_period,
std::max((refresh_time + m_last_rt) * mult, 0.25 * expected_frame_period)));
const auto refresh_limited(std::min(
4.0 * expected_frame_period, std::max((refresh_time + m_last_rt) * mult,
0.25 * expected_frame_period)));
m_last_rt = refresh_time;
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(), m_monitor.maxv());
rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(),
m_monitor.maxv());
// reset_origin must be called first.
screen().reset_origin(m_state.m_last_y-(m_monitor.vsync_width() + m_monitor.vbackporch_width()), 0);
screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea, DOUBLE_TO_ATTOSECONDS(refresh_limited));
screen().reset_origin(
m_state.m_last_y
- (m_monitor.vsync_width() + m_monitor.vbackporch_width()),
0);
screen().configure(m_monitor.htotal_scaled(), m_monitor.vtotal(), visarea,
DOUBLE_TO_ATTOSECONDS(refresh_limited));
}
NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_composite_monochrome)
@ -501,6 +541,8 @@ NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_sync)
/***************************************************************************/
// clang-format off
static INPUT_PORTS_START(fixedfreq_base_ports)
PORT_START("ENABLE")
PORT_CONFNAME( 0x01, 0x00, "Display Monitor sliders" )
@ -549,6 +591,9 @@ static INPUT_PORTS_START(fixedfreq_vector_ports)
PORT_ADJUSTERX(SCANLINE_HEIGHT, "Scanline Height", 10, 300)
INPUT_PORTS_END
//
// clang-format on
ioport_constructor fixedfreq_device::device_input_ports() const
{
LOG("input ports\n");
@ -567,30 +612,18 @@ unsigned fixedfreq_device::monitor_val(unsigned param) const
{
switch (param)
{
case HVISIBLE:
return m_monitor.hvisible_width();
case HFRONTPORCH:
return m_monitor.hfrontporch_width();
case HSYNC:
return m_monitor.hsync_width();
case HBACKPORCH:
return m_monitor.hbackporch_width();
case VVISIBLE:
return m_monitor.vvisible_width();
case VFRONTPORCH:
return m_monitor.vfrontporch_width();
case VSYNC:
return m_monitor.vsync_width();
case VBACKPORCH:
return m_monitor.vbackporch_width();
case SYNCTHRESHOLD:
return m_monitor.m_sync_threshold * 1000.0;
case VSYNCTHRESHOLD:
return m_monitor.m_vsync_threshold * 1000.0;
case GAIN:
return m_monitor.m_gain * 100.0;
case SCANLINE_HEIGHT:
return m_scanline_height * 100.0;
case HVISIBLE: return m_monitor.hvisible_width();
case HFRONTPORCH: return m_monitor.hfrontporch_width();
case HSYNC: return m_monitor.hsync_width();
case HBACKPORCH: return m_monitor.hbackporch_width();
case VVISIBLE: return m_monitor.vvisible_width();
case VFRONTPORCH: return m_monitor.vfrontporch_width();
case VSYNC: return m_monitor.vsync_width();
case VBACKPORCH: return m_monitor.vbackporch_width();
case SYNCTHRESHOLD: return m_monitor.m_sync_threshold * 1000.0;
case VSYNCTHRESHOLD: return m_monitor.m_vsync_threshold * 1000.0;
case GAIN: return m_monitor.m_gain * 100.0;
case SCANLINE_HEIGHT: return m_scanline_height * 100.0;
}
return 0;
}
@ -603,28 +636,36 @@ INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
switch (param)
{
case HVISIBLE:
m.set_h_rel(newval, m.hfrontporch_width(), m.hsync_width(), m.hbackporch_width());
m.set_h_rel(newval, m.hfrontporch_width(), m.hsync_width(),
m.hbackporch_width());
break;
case HFRONTPORCH:
m.set_h_rel(m.hvisible_width(), newval, m.hsync_width(), m.hbackporch_width());
m.set_h_rel(m.hvisible_width(), newval, m.hsync_width(),
m.hbackporch_width());
break;
case HSYNC:
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), newval, m.hbackporch_width());
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), newval,
m.hbackporch_width());
break;
case HBACKPORCH:
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(), m.hsync_width(), newval);
m.set_h_rel(m.hvisible_width(), m.hfrontporch_width(),
m.hsync_width(), newval);
break;
case VVISIBLE:
m.set_v_rel(newval, m.vfrontporch_width(), m.vsync_width(), m.vbackporch_width());
m.set_v_rel(newval, m.vfrontporch_width(), m.vsync_width(),
m.vbackporch_width());
break;
case VFRONTPORCH:
m.set_v_rel(m.vvisible_width(), newval, m.vsync_width(), m.vbackporch_width());
m.set_v_rel(m.vvisible_width(), newval, m.vsync_width(),
m.vbackporch_width());
break;
case VSYNC:
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), newval, m.vbackporch_width());
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), newval,
m.vbackporch_width());
break;
case VBACKPORCH:
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(), m.vsync_width(), newval);
m.set_v_rel(m.vvisible_width(), m.vfrontporch_width(),
m.vsync_width(), newval);
break;
case SYNCTHRESHOLD:
m.m_sync_threshold = static_cast<double>(newval) / 1000.0;
@ -632,13 +673,12 @@ INPUT_CHANGED_MEMBER(fixedfreq_device::port_changed)
case VSYNCTHRESHOLD:
m.m_vsync_threshold = static_cast<double>(newval) / 1000.0;
break;
case GAIN:
m.m_gain = static_cast<double>(newval) / 100.0;
break;
case GAIN: m.m_gain = static_cast<double>(newval) / 100.0; break;
case SCANLINE_HEIGHT:
m_scanline_height = static_cast<double>(newval) / 100.0;
break;
}
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(), m.vtotal());
//ioport("YYY")->update_defvalue(true);
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(),
m.vtotal());
// ioport("YYY")->update_defvalue(true);
}

View File

@ -2,12 +2,12 @@
// copyright-holders:Couriersud
/***************************************************************************
fixfreq.h
fixfreq.h
Fixed frequency monochrome monitor emulation
Fixed frequency monochrome monitor emulation
The driver is intended for drivers which provide an analog video signal.
VSYNC and HSYNC levels are used to create the bitmap.
The driver is intended for drivers which provide an analog video signal.
VSYNC and HSYNC levels are used to create the bitmap.
***************************************************************************/
@ -21,41 +21,58 @@ struct fixedfreq_monitor_desc
{
fixedfreq_monitor_desc()
// default to NTSC "704x480@30i"
: m_monitor_clock(13500000),
m_fieldcount(2),
m_sync_threshold(0.3),
m_gain(1.0 / 3.7),
m_hscale(1),
m_vsync_threshold(0.600), // trigger at 91% of vsync length 1-exp(-0.6)
m_hvisible(704),
m_hfrontporch(728),
m_hsync(791),
m_hbackporch(858),
m_vvisible(480),
m_vfrontporch(486),
m_vsync(492),
m_vbackporch(525)
{}
: m_monitor_clock(13500000)
, m_fieldcount(2)
, m_sync_threshold(0.3)
, m_gain(1.0 / 3.7)
, m_hscale(1)
, m_vsync_threshold(0.600)
, // trigger at 91% of vsync length 1-exp(-0.6)
m_hvisible(704)
, m_hfrontporch(728)
, m_hsync(791)
, m_hbackporch(858)
, m_vvisible(480)
, m_vfrontporch(486)
, m_vsync(492)
, m_vbackporch(525)
{
}
uint32_t monitor_clock() const noexcept { return m_monitor_clock; }
double clock_period() const noexcept { return 1.0 / (double) m_monitor_clock; }
double clock_period() const noexcept
{
return 1.0 / (double)m_monitor_clock;
}
int minh() const noexcept { return (m_hbackporch - m_hsync) * m_hscale; }
int maxh() const noexcept { return (m_hbackporch - m_hsync + m_hvisible) * m_hscale - 1; }
int maxh() const noexcept
{
return (m_hbackporch - m_hsync + m_hvisible) * m_hscale - 1;
}
int minv() const noexcept { return m_vbackporch - m_vsync; }
int maxv() const noexcept { return m_vbackporch - m_vsync + m_vvisible - 1; }
int maxv() const noexcept
{
return m_vbackporch - m_vsync + m_vvisible - 1;
}
int htotal_scaled() const noexcept { return m_hbackporch * m_hscale; }
int vbackporch_width() const noexcept { return m_vbackporch - m_vsync; }
int vsync_width() const noexcept { return m_vsync - m_vfrontporch; }
int vfrontporch_width() const noexcept { return m_vfrontporch - m_vvisible; }
int vfrontporch_width() const noexcept
{
return m_vfrontporch - m_vvisible;
}
int vvisible_width() const noexcept { return m_vvisible; }
int vtotal() const noexcept { return m_vbackporch; }
int hbackporch_width() const noexcept { return m_hbackporch - m_hsync; }
int hsync_width() const noexcept { return m_hsync - m_hfrontporch; }
int hfrontporch_width() const noexcept { return m_hfrontporch - m_hvisible; }
int hfrontporch_width() const noexcept
{
return m_hfrontporch - m_hvisible;
}
int hvisible_width() const noexcept { return m_hvisible; }
int htotal() const noexcept { return m_hbackporch; }
@ -77,20 +94,22 @@ struct fixedfreq_monitor_desc
double vsync_filter_timeconst() const noexcept
{
return (double) (m_monitor_clock) / ((double) m_hbackporch * vsync_width());
return (double)(m_monitor_clock)
/ ((double)m_hbackporch * vsync_width());
}
double hsync_filter_timeconst() const noexcept
{
return (double) m_monitor_clock / (double) hsync_width();
return (double)m_monitor_clock / (double)hsync_width();
}
uint32_t m_monitor_clock;
int m_fieldcount;
double m_sync_threshold;
double m_gain;
int m_hscale;
double m_vsync_threshold;
int m_fieldcount;
double m_sync_threshold;
double m_gain;
int m_hscale;
double m_vsync_threshold;
private:
int m_hvisible;
int m_hfrontporch;
@ -110,9 +129,9 @@ struct fixedfreq_monitor_intf
struct fixedfreq_monitor_line
{
float y;
float x;
float xr;
float y;
float x;
float xr;
uint32_t col;
};
@ -120,24 +139,26 @@ struct fixedfreq_monitor_state
{
using time_type = double;
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc, fixedfreq_monitor_intf &intf)
: m_desc(desc),
m_intf(intf),
m_last_sync_val(0),
m_col(0),
m_last_x(0),
m_last_y(0),
m_last_sync_time(time_type(0)),
m_line_time(time_type(0)),
m_last_hsync_time(time_type(0)),
m_last_vsync_time(time_type(0)),
m_last_line_duration(time_type(0)),
m_last_field_time(time_type(0)),
m_vsync_filter(0),
m_sig_vsync(0),
m_sig_composite(0),
m_sig_field(0)
{}
fixedfreq_monitor_state(fixedfreq_monitor_desc &desc,
fixedfreq_monitor_intf &intf)
: m_desc(desc)
, m_intf(intf)
, m_last_sync_val(0)
, m_col(0)
, m_last_x(0)
, m_last_y(0)
, m_last_sync_time(time_type(0))
, m_line_time(time_type(0))
, m_last_hsync_time(time_type(0))
, m_last_vsync_time(time_type(0))
, m_last_line_duration(time_type(0))
, m_last_field_time(time_type(0))
, m_vsync_filter(0)
, m_sig_vsync(0)
, m_sig_composite(0)
, m_sig_field(0)
{
}
/***
* \brief To be called after monitor parameters are set
@ -148,7 +169,7 @@ struct fixedfreq_monitor_state
// Only copies constructor init
m_last_sync_val = 0.0;
m_col = rgb_t(0,0,0);
m_col = rgb_t(0, 0, 0);
m_last_x = 0;
m_last_y = 0;
m_last_sync_time = time_type(0);
@ -168,13 +189,15 @@ struct fixedfreq_monitor_state
/* sync separator */
//m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
//printf("trigger %f with len %f\n", m_vsync_threshold, 1e6 / m_vsync_filter_timeconst);
// Minimum frame period to be passed to video system ?
// m_vsync_threshold = (exp(- 3.0/(3.0+3.0))) - exp(-1.0);
// printf("trigger %f with len %f\n", m_vsync_threshold, 1e6 /
// m_vsync_filter_timeconst);
// Minimum frame period to be passed to video system ?
m_fragments.clear();
//m_intf.vsync_end_cb(m_desc.clock_period() * m_desc.vtotal() * m_desc.htotal(), 0);
// m_intf.vsync_end_cb(m_desc.clock_period() * m_desc.vtotal() *
// m_desc.htotal(), 0);
}
void reset()
@ -192,19 +215,20 @@ struct fixedfreq_monitor_state
void update_sync_channel(const time_type &time, const double newval);
void update_bm(const time_type &time);
void update_composite_monochrome(const time_type &time, const double newval);
void
update_composite_monochrome(const time_type &time, const double newval);
void update_red(const time_type &time, const double data);
void update_green(const time_type &time, const double data);
void update_blue(const time_type &time, const double data);
void update_sync(const time_type &time, const double data);
const fixedfreq_monitor_desc &m_desc;
fixedfreq_monitor_intf &m_intf;
fixedfreq_monitor_intf &m_intf;
double m_last_sync_val;
uint32_t m_col;
float m_last_x;
int m_last_y;
double m_last_sync_val;
uint32_t m_col;
float m_last_x;
int m_last_y;
time_type m_last_sync_time;
time_type m_line_time;
time_type m_last_hsync_time;
@ -216,52 +240,76 @@ struct fixedfreq_monitor_state
/* sync separator */
double m_vsync_filter;
int m_sig_vsync;
int m_sig_composite;
int m_sig_field;
int m_sig_vsync;
int m_sig_composite;
int m_sig_field;
std::vector<fixedfreq_monitor_line> m_fragments;
};
// ======================> fixedfreq_device
class fixedfreq_device : public device_t, public device_video_interface,
public fixedfreq_monitor_intf
class fixedfreq_device
: public device_t
, public device_video_interface
, public fixedfreq_monitor_intf
{
public:
using time_type = fixedfreq_monitor_state::time_type;
// construction/destruction
fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
fixedfreq_device(const machine_config &mconfig, const char *tag,
device_t *owner, uint32_t clock = 0);
// inline configuration helpers
fixedfreq_device &set_monitor_clock(uint32_t clock) { m_monitor.m_monitor_clock = clock; return *this;}
fixedfreq_device &set_fieldcount(int count) { m_monitor.m_fieldcount = count; return *this; }
fixedfreq_device &set_threshold(double threshold) { m_monitor.m_sync_threshold = threshold; return *this; }
fixedfreq_device &set_vsync_threshold(double threshold) { m_monitor.m_vsync_threshold = threshold; return *this; }
fixedfreq_device &set_gain(double gain) { m_monitor.m_gain = gain; return *this; }
fixedfreq_device &set_horz_params(int visible, int frontporch, int sync, int backporch)
fixedfreq_device &set_monitor_clock(uint32_t clock)
{
m_monitor.set_h_rel(
visible,
frontporch - visible,
sync - frontporch,
backporch - sync);
m_monitor.m_monitor_clock = clock;
return *this;
}
fixedfreq_device &set_vert_params(int visible, int frontporch, int sync, int backporch)
fixedfreq_device &set_fieldcount(int count)
{
m_monitor.set_v_rel(
visible,
frontporch - visible,
sync - frontporch,
backporch - sync);
m_monitor.m_fieldcount = count;
return *this;
}
fixedfreq_device &set_threshold(double threshold)
{
m_monitor.m_sync_threshold = threshold;
return *this;
}
fixedfreq_device &set_vsync_threshold(double threshold)
{
m_monitor.m_vsync_threshold = threshold;
return *this;
}
fixedfreq_device &set_gain(double gain)
{
m_monitor.m_gain = gain;
return *this;
}
fixedfreq_device &
set_horz_params(int visible, int frontporch, int sync, int backporch)
{
m_monitor.set_h_rel(visible, frontporch - visible, sync - frontporch,
backporch - sync);
return *this;
}
fixedfreq_device &
set_vert_params(int visible, int frontporch, int sync, int backporch)
{
m_monitor.set_v_rel(visible, frontporch - visible, sync - frontporch,
backporch - sync);
return *this;
}
fixedfreq_device &set_horz_scale(int hscale)
{
m_monitor.m_hscale = hscale;
return *this;
}
fixedfreq_device &set_horz_scale(int hscale) { m_monitor.m_hscale = hscale; return *this;}
// pre-defined configurations
fixedfreq_device &set_mode_ntsc720() //ModeLine "720x480@30i" 13.5 720 736 799 858 480 486 492 525 interlace -hsync -vsync
fixedfreq_device &set_mode_ntsc720() // ModeLine "720x480@30i" 13.5 720 736
// 799 858 480 486 492 525 interlace
// -hsync -vsync
{
set_monitor_clock(13500000);
set_horz_params(720, 736, 799, 858);
@ -270,7 +318,8 @@ public:
set_threshold(0.3);
return *this;
}
fixedfreq_device &set_mode_ntsc704() //ModeLine "704x480@30i" 13.5 704 728 791 858 480 486 492 525
fixedfreq_device &set_mode_ntsc704() // ModeLine "704x480@30i" 13.5 704 728
// 791 858 480 486 492 525
{
set_monitor_clock(13500000);
set_horz_params(704, 728, 791, 858);
@ -280,7 +329,8 @@ public:
return *this;
}
virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
const rectangle &cliprect);
NETDEV_ANALOG_CALLBACK_MEMBER(update_composite_monochrome);
NETDEV_ANALOG_CALLBACK_MEMBER(update_red);
@ -293,8 +343,8 @@ public:
unsigned monitor_val(unsigned param) const;
protected:
fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
fixedfreq_device(const machine_config &mconfig, device_type type,
const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_config_complete() override;
@ -309,16 +359,14 @@ protected:
private:
required_ioport m_enable;
required_ioport m_vector;
float m_scanline_height;
double m_last_rt;
float m_scanline_height;
double m_last_rt;
/* adjustable by drivers */
fixedfreq_monitor_desc m_monitor;
fixedfreq_monitor_desc m_monitor;
fixedfreq_monitor_state m_state;
};
// device type definition
DECLARE_DEVICE_TYPE(FIXFREQ, fixedfreq_device)

View File

@ -353,8 +353,6 @@ namespace netlist::analog
nld_two_terminal m_P0_P1; // 0, -gec, -gcc, 0 | 0
};
#define USE_THREE (1)
// -----------------------------------------------------------------------------
// nld_QBJT_EB
// -----------------------------------------------------------------------------

View File

@ -21,14 +21,16 @@
/// http://jaco.ec.t.kanazawa-u.ac.jp/edu/mix/pdf/3.pdf
///
/// Farid N. Naim, Circuit Simulation (Wiley-IEEE Press, 2010).
/// Stefan Jahn, Michael Margraf, Vincent Habchi and Raimund Jacob, "Qucs Technical Papers" (2007)
/// Stefan Jahn, Michael Margraf, Vincent Habchi and Raimund Jacob, "Qucs
/// Technical Papers" (2007)
///
#include "solver/nld_solver.h"
#include "../nl_setup.h"
#include "nlid_twoterm.h"
#define BODY_CONNECTED_TO_SOURCE (1)
#include "solver/nld_solver.h"
#define BODY_CONNECTED_TO_SOURCE (1)
namespace netlist::analog
{
@ -99,11 +101,11 @@ namespace netlist::analog
{
public:
fet_model_t(param_model_t &model)
: m_VTO(model, "VTO")
, m_N(model, "N")
, m_ISS(model, "IS") // Haven't seen a model using ISS / ISD
, m_ISD(model, "IS")
, m_LD(model, "LD")
: m_VTO(model, "VTO")
, m_N(model, "N")
, m_ISS(model, "IS") // Haven't seen a model using ISS / ISD
, m_ISD(model, "IS")
, m_LD(model, "LD")
, m_L(model, "L")
, m_W(model, "W")
, m_TOX(model, "TOX")
@ -119,28 +121,33 @@ namespace netlist::analog
, m_CGDO(model, "CGDO")
, m_CGBO(model, "CGBO")
, m_CAPMOD(model, "CAPMOD")
{}
{
}
param_model_t::value_t m_VTO; //!< Threshold voltage [V]
param_model_t::value_t m_N; //!< Bulk diode emission coefficient
param_model_t::value_t m_ISS; //!< Body diode saturation current
param_model_t::value_t m_ISD; //!< Body diode saturation current
param_model_t::value_t m_LD; //!< Lateral diffusion [m]
param_model_t::value_t m_L; //!< Length scaling
param_model_t::value_t m_W; //!< Width scaling
param_model_t::value_t m_TOX; //!< Oxide thickness
param_model_t::value_t m_KP; //!< Transconductance parameter [A/V²]
param_model_t::value_t m_UO; //!< Surface mobility [cm²/V/s]
param_model_t::value_t m_PHI; //!< Surface inversion potential [V]
param_model_t::value_t m_NSUB; //!< Substrate doping [1/cm³]
param_model_t::value_t m_GAMMA; //!< Bulk threshold parameter [V^½]
param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/V]
param_model_t::value_t m_RD; //!< Drain ohmic resistance
param_model_t::value_t m_RS; //!< Source ohmic resistance
param_model_t::value_t m_CGSO; //!< Gate-source overlap capacitance per meter channel width
param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per meter channel width
param_model_t::value_t m_CGBO; //!< Gate-bulk overlap capacitance per meter channel width
param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no model 2=Meyer)
param_model_t::value_t m_VTO; //!< Threshold voltage [V]
param_model_t::value_t m_N; //!< Bulk diode emission coefficient
param_model_t::value_t m_ISS; //!< Body diode saturation current
param_model_t::value_t m_ISD; //!< Body diode saturation current
param_model_t::value_t m_LD; //!< Lateral diffusion [m]
param_model_t::value_t m_L; //!< Length scaling
param_model_t::value_t m_W; //!< Width scaling
param_model_t::value_t m_TOX; //!< Oxide thickness
param_model_t::value_t m_KP; //!< Transconductance parameter [A/V²]
param_model_t::value_t m_UO; //!< Surface mobility [cm²/V/s]
param_model_t::value_t m_PHI; //!< Surface inversion potential [V]
param_model_t::value_t m_NSUB; //!< Substrate doping [1/cm³]
param_model_t::value_t m_GAMMA; //!< Bulk threshold parameter [V^½]
param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/V]
param_model_t::value_t m_RD; //!< Drain ohmic resistance
param_model_t::value_t m_RS; //!< Source ohmic resistance
param_model_t::value_t m_CGSO; //!< Gate-source overlap capacitance per
//!< meter channel width
param_model_t::value_t m_CGDO; //!< Gate-drain overlap capacitance per
//!< meter channel width
param_model_t::value_t m_CGBO; //!< Gate-bulk overlap capacitance per
//!< meter channel width
param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no
//!< model 2=Meyer)
};
// -----------------------------------------------------------------------------
@ -150,7 +157,6 @@ namespace netlist::analog
class nld_MOSFET : public base_device_t
{
public:
public: \
nld_MOSFET(constructor_param_t data)
: base_device_t(data)
, m_model(*this, "MODEL", "NMOS")
@ -171,7 +177,7 @@ namespace netlist::analog
, m_lambda(nlconst::zero())
, m_Leff(nlconst::zero())
, m_CoxWL(nlconst::zero())
//S, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
// S, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
, m_Cgb(nlconst::zero())
, m_Cgs(nlconst::zero())
, m_Cgd(nlconst::zero())
@ -179,28 +185,30 @@ namespace netlist::analog
, m_Vgs(*this, "m_Vgs", nlconst::zero())
, m_Vgd(*this, "m_Vgd", nlconst::zero())
, m_model_acc(m_model)
{
register_sub_alias("S", m_SG.P()); // Source
register_sub_alias("G", m_SG.N()); // Gate
{
register_sub_alias("S", m_SG.P()); // Source
register_sub_alias("G", m_SG.N()); // Gate
register_sub_alias("D", m_DG.P()); // Drain
register_sub_alias("D", m_DG.P()); // Drain
connect(m_SG.P(), m_SD.P());
connect(m_SG.N(), m_DG.N());
connect(m_DG.P(), m_SD.N());
m_polarity = (m_model.type() == "NMOS_DEFAULT" ? nlconst::one() : -nlconst::one());
m_polarity = (m_model.type() == "NMOS_DEFAULT" ? nlconst::one()
: -nlconst::one());
m_capacitor_model = m_model_acc.m_CAPMOD;
//# printf("capmod %d %g %g\n", m_capacitor_model, (nl_fptype)m_model_acc.m_VTO, m_polarity);
nl_assert_always(m_capacitor_model == 0 || m_capacitor_model == 2, "Error: CAPMODEL invalid value");
nl_assert_always(m_capacitor_model == 0 || m_capacitor_model == 2,
"Error: CAPMODEL invalid value");
//
// From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
//
// VTO, KP, LAMBDA, PHI and GAMMA. These parameters are computed
// if the process parameters(NSUB, TOX,...) are given, but
// user-specified values always override.
// VTO, KP, LAMBDA, PHI and GAMMA. These parameters are
// computed if the process parameters(NSUB, TOX,...) are given,
// but user-specified values always override.
//
// But couldn't find a formula for lambda anywhere
//
@ -209,20 +217,28 @@ namespace netlist::analog
// calculate effective channel length
m_Leff = m_model_acc.m_L - 2 * m_model_acc.m_LD;
nl_assert_always(m_Leff > nlconst::zero(), "Effective Lateral diffusion would be negative for model");
nl_assert_always(
m_Leff > nlconst::zero(),
"Effective Lateral diffusion would be negative for model");
nl_fptype Cox = (m_model_acc.m_TOX > nlconst::zero()) ? (constants::eps_SiO2() * constants::eps_0() / m_model_acc.m_TOX) : nlconst::zero();
nl_fptype Cox = (m_model_acc.m_TOX > nlconst::zero())
? (constants::eps_SiO2() * constants::eps_0()
/ m_model_acc.m_TOX)
: nlconst::zero();
// calculate DC transconductance coefficient
if (m_model_acc.m_KP > nlconst::zero())
m_beta = m_model_acc.m_KP * m_model_acc.m_W / m_Leff;
else if (Cox > nlconst::zero() && m_model_acc.m_UO > nlconst::zero())
m_beta = m_model_acc.m_UO * nlconst::magic(1e-4) * Cox * m_model_acc.m_W / m_Leff;
else if (Cox > nlconst::zero()
&& m_model_acc.m_UO > nlconst::zero())
m_beta = m_model_acc.m_UO * nlconst::magic(1e-4) * Cox
* m_model_acc.m_W / m_Leff;
else
m_beta = nlconst::magic(2e-5) * m_model_acc.m_W / m_Leff;
//FIXME::UT can disappear
const nl_fptype Vt = constants::T0() * constants::k_b() / constants::Q_e();
// FIXME::UT can disappear
const nl_fptype Vt = constants::T0() * constants::k_b()
/ constants::Q_e();
// calculate surface potential if not given
@ -230,8 +246,12 @@ namespace netlist::analog
m_phi = m_model_acc.m_PHI;
else if (m_model_acc.m_NSUB > nlconst::zero())
{
nl_assert_always(m_model_acc.m_NSUB * nlconst::magic(1e6) >= constants::NiSi(), "Error calculating phi for model");
m_phi = nlconst::two() * Vt * plib::log (m_model_acc.m_NSUB * nlconst::magic(1e6) / constants::NiSi());
nl_assert_always(m_model_acc.m_NSUB * nlconst::magic(1e6)
>= constants::NiSi(),
"Error calculating phi for model");
m_phi = nlconst::two() * Vt
* plib::log(m_model_acc.m_NSUB * nlconst::magic(1e6)
/ constants::NiSi());
}
else
m_phi = nlconst::magic(0.6);
@ -241,21 +261,24 @@ namespace netlist::analog
m_gamma = m_model_acc.m_GAMMA;
else
{
if (Cox > nlconst::zero() && m_model_acc.m_NSUB > nlconst::zero())
m_gamma = plib::sqrt (nlconst::two()
* constants::Q_e() * constants::eps_Si() * constants::eps_0()
* m_model_acc.m_NSUB * nlconst::magic(1e6)) / Cox;
if (Cox > nlconst::zero()
&& m_model_acc.m_NSUB > nlconst::zero())
m_gamma = plib::sqrt(
nlconst::two() * constants::Q_e()
* constants::eps_Si() * constants::eps_0()
* m_model_acc.m_NSUB * nlconst::magic(1e6))
/ Cox;
else
m_gamma = nlconst::zero();
}
m_vto = m_model_acc.m_VTO;
// FIXME zero conversion
if(m_vto == nlconst::zero())
if (m_vto == nlconst::zero())
log().warning(MW_MOSFET_THRESHOLD_VOLTAGE(m_model.name()));
// FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
// specify VTO so skip this here.
// FIXME: VTO if missing may be calculated from TPG, NSS and
// temperature. Usually models specify VTO so skip this here.
m_CoxWL = Cox * m_model_acc.m_W * m_Leff;
@ -269,13 +292,14 @@ namespace netlist::analog
{
if (m_capacitor_model != 0)
{
if (ts_type == time_step_type::FORWARD)
if (ts_type == detail::time_step_type::FORWARD)
{
//#const nl_nl_fptype Ugd = -m_DG.deltaV() * m_polarity; // Gate - Drain
//#const nl_nl_fptype Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
const nl_fptype Ugd = m_Vgd; // Gate - Drain
const nl_fptype Ugs = m_Vgs; // Gate - Source
const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0 if connected
const nl_fptype Ugd = m_Vgd; // Gate - Drain
const nl_fptype Ugs = m_Vgs; // Gate - Source
const nl_fptype Ubs = nlconst::zero(); // Bulk - Source == 0
// if connected
const nl_fptype Ugb = Ugs - Ubs;
m_cap_gb.time_step(m_Cgb, Ugb, step);
@ -292,20 +316,22 @@ namespace netlist::analog
}
protected:
NETLIB_RESETI()
{
// Bulk diodes
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(), constants::T0());
#if (!BODY_CONNECTED_TO_SOURCE)
m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(), constants::T0());
#endif
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(),
constants::T0());
#if (!BODY_CONNECTED_TO_SOURCE)
m_D_BS.set_param(m_model_acc.m_ISS, m_model_acc.m_N, exec().gmin(),
constants::T0());
#endif
}
NETLIB_HANDLERI(terminal_handler)
{
// only called if connected to a rail net ==> notify the solver to recalculate
// only called if connected to a rail net ==> notify the solver to
// recalculate
auto *solv(m_SG.solver());
if (solv != nullptr)
solv->solve_now();
@ -316,7 +342,6 @@ namespace netlist::analog
NETLIB_UPDATE_TERMINALSI();
private:
param_model_t m_model;
NETLIB_NAME(two_terminal) m_DG;
@ -349,25 +374,30 @@ namespace netlist::analog
nl_fptype m_Cgs;
nl_fptype m_Cgd;
int m_capacitor_model;
int m_capacitor_model;
state_var<nl_fptype> m_Vgs;
state_var<nl_fptype> m_Vgd;
fet_model_t m_model_acc;
fet_model_t m_model_acc;
void set_cap(generic_capacitor<capacitor_e::VARIABLE_CAPACITY> &cap,
nl_fptype capval, nl_fptype V,
nl_fptype &g11, nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
nl_fptype &I1, nl_fptype &I2) const
nl_fptype capval, nl_fptype V, nl_fptype &g11,
nl_fptype &g12, nl_fptype &g21, nl_fptype &g22,
nl_fptype &I1, nl_fptype &I2) const
{
const nl_fptype I = cap.Ieq(capval, V) * m_polarity;
const nl_fptype G = cap.G(capval);
g11 += G; g12 -= G; g21 -= G; g22 += G;
I1 -= I; I2 += I;
//printf("Cap: %g\n", capval);
g11 += G;
g12 -= G;
g21 -= G;
g22 += G;
I1 -= I;
I2 += I;
// printf("Cap: %g\n", capval);
}
void calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
void
calculate_caps(nl_fptype Vgs, nl_fptype Vgd, nl_fptype Vth,
nl_fptype &Cgs, nl_fptype &Cgd, nl_fptype &Cgb) const
{
nl_fptype Vctrl = Vgs - Vth * m_polarity;
// Cut off - now further differentiated into 3 different formulas
@ -388,7 +418,8 @@ namespace netlist::analog
else if (Vctrl <= 0)
{
Cgb = -Vctrl * m_CoxWL / m_phi;
Cgs = Vctrl * m_CoxWL * nlconst::fraction(4.0, 3.0) / m_phi + nlconst::two_thirds() * m_CoxWL;
Cgs = Vctrl * m_CoxWL * nlconst::fraction(4.0, 3.0) / m_phi
+ nlconst::two_thirds() * m_CoxWL;
Cgd = nlconst::zero();
}
else
@ -405,11 +436,15 @@ namespace netlist::analog
else
{
// linear
const auto Sqr1(plib::narrow_cast<nl_fptype>(plib::pow(Vdsat - Vds, 2)));
const auto Sqr2(plib::narrow_cast<nl_fptype>(plib::pow(nlconst::two() * Vdsat - Vds, 2)));
const auto Sqr1(plib::narrow_cast<nl_fptype>(
plib::pow(Vdsat - Vds, 2)));
const auto Sqr2(plib::narrow_cast<nl_fptype>(
plib::pow(nlconst::two() * Vdsat - Vds, 2)));
Cgb = 0;
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2) * nlconst::two_thirds();
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2) * nlconst::two_thirds();
Cgs = m_CoxWL * (nlconst::one() - Sqr1 / Sqr2)
* nlconst::two_thirds();
Cgd = m_CoxWL * (nlconst::one() - Vdsat * Vdsat / Sqr2)
* nlconst::two_thirds();
}
}
}
@ -426,19 +461,26 @@ namespace netlist::analog
// limit step sizes
const nl_fptype k = nlconst::magic(3.5); // see "Circuit Simulation", page 185
const nl_fptype k = nlconst::magic(3.5); // see "Circuit Simulation",
// page 185
nl_fptype d = (Vgs - m_Vgs);
Vgs = m_Vgs + plib::reciprocal(k) * plib::signum(d) * plib::log1p(k * plib::abs(d));
Vgs = m_Vgs
+ plib::reciprocal(k) * plib::signum(d)
* plib::log1p(k * plib::abs(d));
d = (Vgd - m_Vgd);
Vgd = m_Vgd + plib::reciprocal(k) * plib::signum(d) * plib::log1p(k * plib::abs(d));
Vgd = m_Vgd
+ plib::reciprocal(k) * plib::signum(d)
* plib::log1p(k * plib::abs(d));
m_Vgs = Vgs;
m_Vgd = Vgd;
const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if connected
//const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain = Source - Drain
const nl_fptype Vbs = nlconst::zero(); // Bulk - Source == 0 if
// connected
// const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain
// = Source - Drain
const nl_fptype Vds = Vgs - Vgd;
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
#if (!BODY_CONNECTED_TO_SOURCE)
m_D_BS.update_diode(Vbs);
@ -451,8 +493,11 @@ namespace netlist::analog
// calculate Vth
const nl_fptype Vbulk = is_forward ? Vbs : Vbd;
const nl_fptype phi_m_Vbulk = (m_phi > Vbulk) ? plib::sqrt(m_phi - Vbulk) : nlconst::zero();
const nl_fptype Vth = m_vto * m_polarity + m_gamma * (phi_m_Vbulk - plib::sqrt(m_phi));
const nl_fptype phi_m_Vbulk = (m_phi > Vbulk)
? plib::sqrt(m_phi - Vbulk)
: nlconst::zero();
const nl_fptype Vth = m_vto * m_polarity
+ m_gamma * (phi_m_Vbulk - plib::sqrt(m_phi));
const nl_fptype Vctrl = (is_forward ? Vgs : Vgd) - Vth;
@ -467,30 +512,36 @@ namespace netlist::analog
{
// cutoff region
Ids = nlconst::zero();
gm = nlconst::zero();
gm = nlconst::zero();
gds = nlconst::zero();
gmb = nlconst::zero();
}
else
{
const nl_fptype beta = m_beta * (nlconst::one() + m_lambda * absVds);
const nl_fptype beta = m_beta
* (nlconst::one() + m_lambda * absVds);
if (Vctrl <= absVds)
{
// saturation region
Ids = beta * Vctrl * Vctrl / nlconst::two();
gm = beta * Vctrl;
gm = beta * Vctrl;
gds = m_lambda * m_beta * Vctrl * Vctrl / nlconst::two();
}
else
{
// linear region
Ids = beta * absVds * (Vctrl - absVds / nlconst::two());
gm = beta * absVds;
gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / nlconst::two());
gm = beta * absVds;
gds = beta * (Vctrl - absVds)
+ m_lambda * m_beta * absVds
* (Vctrl - absVds / nlconst::two());
}
// back gate transconductance
const nl_fptype bgtc = (phi_m_Vbulk != nlconst::zero()) ? (m_gamma / phi_m_Vbulk / nlconst::two()) : nlconst::zero();
const nl_fptype bgtc = (phi_m_Vbulk != nlconst::zero())
? (m_gamma / phi_m_Vbulk
/ nlconst::two())
: nlconst::zero();
gmb = gm * bgtc;
}
@ -512,11 +563,11 @@ namespace netlist::analog
#endif
// exchange controlling nodes if necessary
const nl_fptype gate_source = is_forward ? (gm + gmb) : nlconst::zero();
const nl_fptype gate_drain = is_forward ? nlconst::zero() : (gm + gmb);
const nl_fptype gate_drain = is_forward ? nlconst::zero() : (gm + gmb);
const nl_fptype IeqDS = (is_forward) ?
Ids - gm * Vgs - gmb * Vbs - gds * Vds
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
const nl_fptype IeqDS = (is_forward)
? Ids - gm * Vgs - gmb * Vbs - gds * Vds
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
// IG = 0
nl_fptype IG = nlconst::zero();
@ -529,20 +580,20 @@ namespace netlist::analog
nl_fptype gGS = nlconst::zero();
nl_fptype gGB = nlconst::zero();
nl_fptype gDG = gm;
nl_fptype gDD = gds + gbd - gate_drain;
nl_fptype gDG = gm;
nl_fptype gDD = gds + gbd - gate_drain;
const nl_fptype gDS = -gds - gate_source;
const nl_fptype gDB = gmb - gbd;
const nl_fptype gDB = gmb - gbd;
nl_fptype gSG = -gm;
nl_fptype gSG = -gm;
const nl_fptype gSD = -gds + gate_drain;
nl_fptype gSS = gbs + gds + gate_source;
nl_fptype gSS = gbs + gds + gate_source;
const nl_fptype gSB = -gbs - gmb;
nl_fptype gBG = nlconst::zero();
nl_fptype gBG = nlconst::zero();
const nl_fptype gBD = -gbd;
const nl_fptype gBS = -gbs;
nl_fptype gBB = gbs + gbd;
nl_fptype gBB = gbs + gbd;
if (m_capacitor_model != 0)
{
@ -553,23 +604,26 @@ namespace netlist::analog
else
calculate_caps(Vgd, Vgs, Vth, m_Cgd, m_Cgs, m_Cgb);
set_cap(m_cap_gb, m_Cgb + m_model_acc.m_CGBO * m_Leff, Vgb, gGG, gGB, gBG, gBB, IG, IB);
set_cap(m_cap_gs, m_Cgs + m_model_acc.m_CGSO * m_model_acc.m_W, Vgs, gGG, gGS, gSG, gSS, IG, IS);
set_cap(m_cap_gd, m_Cgd + m_model_acc.m_CGDO * m_model_acc.m_W, Vgd, gGG, gGD, gDG, gDD, IG, ID);
set_cap(m_cap_gb, m_Cgb + m_model_acc.m_CGBO * m_Leff, Vgb, gGG,
gGB, gBG, gBB, IG, IB);
set_cap(m_cap_gs, m_Cgs + m_model_acc.m_CGSO * m_model_acc.m_W, Vgs,
gGG, gGS, gSG, gSS, IG, IS);
set_cap(m_cap_gd, m_Cgd + m_model_acc.m_CGDO * m_model_acc.m_W, Vgd,
gGG, gGD, gDG, gDD, IG, ID);
}
// Source connected to body, Diode S-B shorted!
const nl_fptype gSSBB = gSS + gBB + gBS + gSB;
const auto zero(nlconst::zero());
const auto zero(nlconst::zero());
// S G
m_SG.set_mat( gSSBB, gSG + gBG, +(IS + IB), // S
gGS + gGB, gGG, IG ); // G
m_SG.set_mat(gSSBB, gSG + gBG, +(IS + IB), // S
gGS + gGB, gGG, IG); // G
// D G
m_DG.set_mat( gDD, gDG, +ID, // D
gGD, zero, zero ); // G
m_DG.set_mat(gDD, gDG, +ID, // D
gGD, zero, zero); // G
// S D
m_SD.set_mat( zero, gSD + gBD, zero, // S
gDS + gDB, zero, zero ); // D
m_SD.set_mat(zero, gSD + gBD, zero, // S
gDS + gDB, zero, zero); // D
/// |
/// | D S G I
@ -600,13 +654,11 @@ namespace netlist::analog
/// |
}
NETLIB_UPDATE_PARAM(MOSFET)
{
}
NETLIB_UPDATE_PARAM(MOSFET) {}
} // namespace netlist::analog
namespace netlist::devices {
namespace netlist::devices
{
NETLIB_DEVICE_IMPL_NS(analog, MOSFET, "MOSFET", "MODEL")
} // namespace netlist::devices

View File

@ -125,7 +125,7 @@ namespace netlist::analog
NETLIB_TIMESTEP(L)
{
if (ts_type == time_step_type::FORWARD)
if (ts_type == detail::time_step_type::FORWARD)
{
m_last_I = m_I;
m_last_G = m_G;

View File

@ -312,7 +312,7 @@ namespace netlist::analog
NETLIB_IS_TIMESTEP(true)
NETLIB_TIMESTEPI()
{
if (ts_type == time_step_type::FORWARD)
if (ts_type == detail::time_step_type::FORWARD)
{
// G, Ieq
const auto res(m_cap.time_step(m_C(), deltaV(), step));
@ -584,7 +584,7 @@ namespace netlist::analog
NETLIB_TIMESTEPI()
{
if (ts_type == time_step_type::FORWARD)
if (ts_type == detail::time_step_type::FORWARD)
{
m_t += step;
m_funcparam[0] = m_t;
@ -637,7 +637,7 @@ namespace netlist::analog
NETLIB_IS_TIMESTEP(!m_func().empty())
NETLIB_TIMESTEPI()
{
if (ts_type == time_step_type::FORWARD)
if (ts_type == detail::time_step_type::FORWARD)
{
m_t += step;
m_funcparam[0] = m_t;

View File

@ -25,13 +25,14 @@ BreakStringLiterals: false
AlwaysBreakTemplateDeclarations: Yes
# AfterComma does not work <= 13
#BreakInheritanceList: AfterComma
#BreakInheritanceList: BeforeComma
BreakInheritanceList: BeforeComma
#BreakInheritanceList: false
SpaceBeforeInheritanceColon: true
#AlignAfterOpenBracket: DontAlign
AlignAfterOpenBracket: Align
PointerAlignment: Right
ReferenceAlignment: Right
SpacesInAngles: false
SpaceBeforeAssignmentOperators: true
AlignConsecutiveDeclarations: true
@ -90,16 +91,17 @@ StatementMacros:
TypenameMacros:
- "NETLIST_NAME"
- "NETLIB_NAME"
- "PENUM"
WhitespaceSensitiveMacros:
- "ALIAS"
- "NET_C"
- "DIPPINS"
- "NET_C"
- "PENUM"
IndentPPDirectives: BeforeHash
MacroBlockBegin: "^static NETLIST_START\\(.+\\)|static TRUTHTABLE_START\\(.*\\)$"
MacroBlockEnd: "^NETLIST_END\\(\\)|TRUTHTABLE_END\\(\\)$"
# ReferenceAlignment: Middle
# Avoid formatting
# -- clang-tidy

View File

@ -19,6 +19,7 @@
"Schmitt",
"Schottky",
"Zener",
"Thevenin",
// Company names
"Fairchild",
"Signetics",
@ -69,6 +70,7 @@
// FIXME: Remove everything below here again
// Excluded for now ... Still over 1000 in the log
"plib", // namespace
"isnull",
"pstring",
"passert",
"putf",
@ -79,6 +81,8 @@
"idrn",
"preprocessor",
"ppreprocessor",
"psource",
"psemaphore",
"modacc",
"Ainv",
"anetlist",

View File

@ -114,7 +114,7 @@ TIDY_DB = $(OBJ)/compile_commands.json
#LTO decreases performance :-(
#LTO = -flto=4 -fuse-linker-plugin -Wodr
CCOREFLAGS = -g -O3 -std=c++17 -I$(SRC) -I$(SRC)/.. -I$(SRC)/../..
CCOREFLAGS = -g -O3 -std=c++17 -I$(SRC)
CFLAGS = $(LTO) $(CCOREFLAGS) $(CEXTRAFLAGS)
LDFLAGS = $(LTO) -g -O3 -std=c++17 $(LDEXTRAFLAGS)

View File

@ -17,9 +17,19 @@
#include "../plib/pexception.h"
#include "../plib/plists.h"
#include "../plib/pmempool.h"
#include "../plib/ppmf.h"
#include <unordered_map>
namespace netlist
{
/// \brief Delegate type for device notification.
///
using nl_delegate = plib::pmfp<void()>;
using nl_delegate_ts = plib::pmfp<void(detail::time_step_type, nl_fptype)>;
using nl_delegate_dyn = plib::pmfp<void()>;
} // namespace netlist
namespace netlist::detail
{
@ -131,16 +141,16 @@ namespace netlist::detail
PCOPYASSIGNMOVE(netlist_object_t, delete)
netlist_state_t & state() noexcept;
netlist_state_t &state() noexcept;
const netlist_state_t &state() const noexcept;
constexpr netlist_t & exec() noexcept { return m_netlist; }
constexpr netlist_t &exec() noexcept { return m_netlist; }
constexpr const netlist_t &exec() const noexcept { return m_netlist; }
// to ease template design
template <typename T, typename... Args>
device_arena::unique_ptr<T> make_pool_object(Args &&...args) noexcept(
false)
device_arena::unique_ptr<T>
make_pool_object(Args &&...args) noexcept(false)
{
return state().make_pool_object<T>(std::forward<Args>(args)...);
}
@ -174,13 +184,13 @@ namespace netlist::detail
/// \brief returns reference to owning device.
/// \returns reference to owning device.
core_device_t & device() noexcept { return *m_device; }
core_device_t &device() noexcept { return *m_device; }
const core_device_t &device() const noexcept { return *m_device; }
/// \brief The netlist owning the owner of this object.
/// \returns reference to netlist object.
netlist_state_t & state() noexcept;
netlist_state_t &state() noexcept;
const netlist_state_t &state() const noexcept;
private:
@ -218,7 +228,7 @@ namespace netlist::detail
static constexpr netlist_sig_t OUT_TRISTATE() { return INP_MASK; }
static_assert(INP_BITS * 2 <= sizeof(netlist_sig_t) * 8,
"netlist_sig_t size not sufficient");
"netlist_sig_t size not sufficient");
enum state_e
{
@ -231,7 +241,7 @@ namespace netlist::detail
};
core_terminal_t(core_device_t &dev, const pstring &aname, state_e state,
nl_delegate delegate);
nl_delegate delegate);
virtual ~core_terminal_t() noexcept = default;
PCOPYASSIGNMOVE(core_terminal_t, delete)
@ -271,12 +281,12 @@ namespace netlist::detail
void reset() noexcept
{
set_state(
is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE);
set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT
: STATE_INP_ACTIVE);
}
constexpr void set_copied_input(
[[maybe_unused]] netlist_sig_t val) noexcept
constexpr void
set_copied_input([[maybe_unused]] netlist_sig_t val) noexcept
{
if constexpr (config::use_copy_instead_of_reference::value)
{
@ -298,7 +308,7 @@ namespace netlist::detail
private:
nl_delegate m_delegate;
net_t * m_net;
net_t *m_net;
state_var<state_e> m_state;
};

View File

@ -33,7 +33,7 @@ namespace netlist
friend class factory::device_element_t;
friend class factory::library_element_t;
template <typename CX>
template <typename DEVICE>
friend struct sub_device_wrapper;
friend class solver::matrix_solver_t;
@ -103,7 +103,7 @@ namespace netlist
log_type &log();
public:
virtual void time_step([[maybe_unused]] time_step_type ts_type,
virtual void time_step([[maybe_unused]] detail::time_step_type ts_type,
[[maybe_unused]] nl_fptype st) noexcept
{
}

View File

@ -73,40 +73,42 @@ namespace netlist
// FIXME: Rename
// -------------------------------------------------------------------------
template <typename CX>
template <typename DEVICE>
struct sub_device_wrapper
{
using constructor_data_t = typename CX::constructor_data_t;
using constructor_param_t = typename CX::constructor_param_t;
using constructor_data_t = typename DEVICE::constructor_data_t;
using constructor_param_t = typename DEVICE::constructor_param_t;
template <typename... Args>
sub_device_wrapper(base_device_t &owner, const pstring &name,
Args &&...args)
Args &&...args)
{
// m_dev = owner.state().make_pool_object<CX>(owner, name,
// m_dev = owner.state().make_pool_object<DEVICE>(owner, name,
// std::forward<Args>(args)...);
m_dev = owner.state().make_pool_object<CX>(
m_dev = owner.state().make_pool_object<DEVICE>(
constructor_data_t{owner.state(), owner.name() + "." + name},
std::forward<Args>(args)...);
owner.state().register_device(m_dev->name(),
owner.state().register_device(
m_dev->name(),
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
}
template <typename... Args>
sub_device_wrapper(device_t &owner, const pstring &name, Args &&...args)
{
// m_dev = owner.state().make_pool_object<CX>(owner, name,
// m_dev = owner.state().make_pool_object<DEVICE>(owner, name,
// std::forward<Args>(args)...);
m_dev = owner.state().make_pool_object<CX>(
m_dev = owner.state().make_pool_object<DEVICE>(
constructor_data_t{owner.state(), owner.name() + "." + name},
std::forward<Args>(args)...);
owner.state().register_device(m_dev->name(),
owner.state().register_device(
m_dev->name(),
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
}
CX & operator()() { return *m_dev; }
const CX &operator()() const { return *m_dev; }
DEVICE & operator()() { return *m_dev; }
const DEVICE &operator()() const { return *m_dev; }
private:
device_arena::unique_ptr<CX> m_dev;
device_arena::unique_ptr<DEVICE> m_dev;
};
} // namespace netlist

View File

@ -107,7 +107,7 @@ public: \
#define NETLIB_TIMESTEPI() \
public: \
virtual void time_step(time_step_type ts_type, \
virtual void time_step(detail::time_step_type ts_type, \
nl_fptype step) noexcept override
/// \brief Used to implement the body of the time stepping code.
@ -119,7 +119,7 @@ public: \
/// \param cname Name of object as given to \ref NETLIB_OBJECT
///
#define NETLIB_TIMESTEP(cname) \
void NETLIB_NAME(cname)::time_step(time_step_type ts_type, \
void NETLIB_NAME(cname)::time_step(detail::time_step_type ts_type, \
nl_fptype step) noexcept
//#define NETLIB_DELEGATE(name) nl_delegate(&this_type :: name, this)

View File

@ -10,6 +10,8 @@
#include "../nltypes.h"
#include "../plib/palloc.h"
#include "../plib/pmempool.h"
#include "../plib/pstring.h"
namespace netlist

View File

@ -12,6 +12,7 @@
#include "queue.h"
#include "../plib/plists.h"
#include "../plib/pmempool.h"
#include "../plib/pstate.h"
#include "../plib/pstring.h"
@ -31,8 +32,8 @@ namespace netlist
public:
using nets_collection_type = std::vector<
device_arena::owned_ptr<detail::net_t>>;
using family_collection_type = std::unordered_map<pstring,
host_arena::unique_ptr<logic_family_desc_t>>;
using family_collection_type = std::unordered_map<
pstring, host_arena::unique_ptr<logic_family_desc_t>>;
// need to preserve order of device creation ...
using devices_collection_type = std::vector<
@ -55,8 +56,9 @@ namespace netlist
return bool(plib::dynamic_downcast<C *>(p));
}
core_device_t *get_single_device(const pstring &classname,
bool (*cc)(core_device_t *)) const noexcept(false);
core_device_t *
get_single_device(const pstring &classname,
bool (*cc)(core_device_t *)) const noexcept(false);
/// \brief Get single device filtered by class and name
///
@ -91,7 +93,7 @@ namespace netlist
// logging
log_type & log() noexcept { return m_log; }
log_type &log() noexcept { return m_log; }
const log_type &log() const noexcept { return m_log; }
plib::dynamic_library_base &static_solver_lib() const noexcept
@ -108,23 +110,23 @@ namespace netlist
void set_static_solver_lib(
std::unique_ptr<plib::dynamic_library_base> &&lib);
netlist_t & exec() noexcept { return *m_netlist; }
netlist_t &exec() noexcept { return *m_netlist; }
const netlist_t &exec() const noexcept { return *m_netlist; }
// state handling
plib::state_manager_t &run_state_manager() noexcept { return m_state; }
template <typename O, typename C>
void save(O &owner, C &state, const pstring &module,
const pstring &stname)
void
save(O &owner, C &state, const pstring &module, const pstring &stname)
{
this->run_state_manager().save_item(plib::void_ptr_cast(&owner),
state, module + "." + stname);
state, module + "." + stname);
}
template <typename O, typename C>
void save(O &owner, C *state, const pstring &module,
const pstring &stname, const std::size_t count)
const pstring &stname, const std::size_t count)
{
this->run_state_manager().save_state_ptr(
plib::void_ptr_cast(&owner), module + "." + stname,
@ -165,8 +167,8 @@ namespace netlist
/// \param dev Device to be registered
template <typename T>
void register_device(const pstring &name,
device_arena::owned_ptr<T> && dev) noexcept(false)
void register_device(const pstring &name,
device_arena::owned_ptr<T> &&dev) noexcept(false)
{
for (auto &d : m_devices)
if (d.first == name)
@ -187,11 +189,11 @@ namespace netlist
/// \param dev Device to be registered
template <typename T>
void register_device(const pstring &name,
device_arena::unique_ptr<T> && dev)
void
register_device(const pstring &name, device_arena::unique_ptr<T> &&dev)
{
register_device(name, device_arena::owned_ptr<T>(dev.release(),
true, dev.get_deleter()));
register_device(name, device_arena::owned_ptr<T>(
dev.release(), true, dev.get_deleter()));
}
/// \brief Remove device
@ -203,24 +205,24 @@ namespace netlist
void remove_device(core_device_t *dev);
setup_t & setup() noexcept { return *m_setup; }
setup_t &setup() noexcept { return *m_setup; }
const setup_t &setup() const noexcept { return *m_setup; }
nlparse_t & parser() noexcept;
nlparse_t &parser() noexcept;
const nlparse_t &parser() const noexcept;
// FIXME: make a post load member and include code there
void rebuild_lists(); // must be called after post_load !
static void compile_defines(
std::vector<std::pair<pstring, pstring>> &defs);
static void
compile_defines(std::vector<std::pair<pstring, pstring>> &defs);
static pstring version();
static pstring version_patchlevel();
nets_collection_type & nets() noexcept { return m_nets; }
nets_collection_type &nets() noexcept { return m_nets; }
const nets_collection_type &nets() const noexcept { return m_nets; }
devices_collection_type & devices() noexcept { return m_devices; }
devices_collection_type &devices() noexcept { return m_devices; }
const devices_collection_type &devices() const noexcept
{
return m_devices;
@ -234,13 +236,13 @@ namespace netlist
return plib::make_unique<T>(m_pool, std::forward<Args>(args)...);
}
// memory pool - still needed in some places
device_arena & pool() noexcept { return m_pool; }
device_arena &pool() noexcept { return m_pool; }
const device_arena &pool() const noexcept { return m_pool; }
struct stats_info
{
const detail::queue_t & m_queue; // performance
const plib::pperftime_t<true> & m_stat_mainloop;
const detail::queue_t &m_queue; // performance
const plib::pperftime_t<true> &m_stat_mainloop;
const plib::pperfcount_t<true> &m_perf_out_processed;
};
@ -256,8 +258,8 @@ namespace netlist
///
void free_setup_resources();
#if !(NL_USE_INPLACE_CORE_TERMS)
std::vector<detail::core_terminal_t *> &core_terms(
const detail::net_t &net)
std::vector<detail::core_terminal_t *> &
core_terms(const detail::net_t &net)
{
return m_core_terms[&net];
}
@ -281,7 +283,7 @@ namespace netlist
#if !(NL_USE_INPLACE_CORE_TERMS)
// all terms for a net
std::unordered_map<const detail::net_t *,
std::vector<detail::core_terminal_t *>>
std::vector<detail::core_terminal_t *>>
m_core_terms;
#endif
// dummy version

View File

@ -8,8 +8,12 @@
#ifndef NL_CORE_OBJECT_ARRAY_H_
#define NL_CORE_OBJECT_ARRAY_H_
#include "base_objects.h"
#include "logic.h"
#include "../nltypes.h"
#include "../plib/pfmtlog.h"
#include "../plib/plists.h"
#include "../plib/pstring.h"

View File

@ -10,6 +10,7 @@
#include "../nltypes.h"
#include "../plib/pfmtlog.h"
#include "../plib/pstring.h"
namespace netlist

View File

@ -78,7 +78,7 @@ namespace netlist::devices {
}
else
{
newstate_setreset(set, reset);
set_reset(set, reset);
m_CLK.inactivate();
m_D.inactivate();
}
@ -86,7 +86,7 @@ namespace netlist::devices {
NETLIB_HANDLERI(clk)
{
newstate_clk(m_nextD);
set_output(m_nextD);
m_CLK.inactivate();
}
@ -101,14 +101,14 @@ namespace netlist::devices {
nld_power_pins m_power_pins;
void newstate_clk(const netlist_sig_t stateQ)
void set_output(const netlist_sig_t stateQ)
{
static constexpr auto delay = NLTIME_FROM_NS(150);
static constexpr const auto delay = NLTIME_FROM_NS(150);
m_Q.push(stateQ, delay);
m_QQ.push(!stateQ, delay);
}
void newstate_setreset(const netlist_sig_t stateQ, const netlist_sig_t stateQQ)
void set_reset(const netlist_sig_t stateQ, const netlist_sig_t stateQQ)
{
// Q: 150 ns, QQ: 200 ns
static constexpr const std::array<netlist_time, 2> delay = { NLTIME_FROM_NS(150), NLTIME_FROM_NS(200) };

View File

@ -17,6 +17,7 @@
namespace netlist
{
// nothing in here. This should not change.
} // namespace netlist
#endif // NLBASE_H_

View File

@ -134,7 +134,7 @@ namespace netlist
/// brief default minimum alignment of mempool_arena
///
/// 256 is the best compromise between logic applications like MAME
/// TTL games (e.g. pong) and analog applications like e.g. kidnikik
/// TTL games (e.g. pong) and analog applications like e.g. kidniki
/// sound.
///
/// Best performance for pong is achieved with a value of 16, but this
@ -178,7 +178,7 @@ namespace netlist
/// | 63 | 1,000,000,000,000 | 9,223,372 | 107| 0.3 |
///
using INTERNAL_RES = std::integral_constant<long long int,
10'000'000'000LL>; // NOLINT
10'000'000'000LL>; // NOLINT
/// \brief Recommended clock to be used
///
@ -187,7 +187,7 @@ namespace netlist
/// contains code illustrating how to deal with remainders if \ref
/// INTERNAL_RES is bigger than NETLIST_CLOCK.
using DEFAULT_CLOCK = std::integral_constant<int,
1'000'000'000>; // NOLINT
1'000'000'000>; // NOLINT
/// \brief Default logic family
///
@ -196,27 +196,27 @@ namespace netlist
/// \brief Maximum queue size
///
using max_queue_size = std::integral_constant<std::size_t,
1024>; // NOLINT
1024>; // NOLINT
/// \brief Maximum queue size for solvers
///
using max_solver_queue_size = std::integral_constant<std::size_t,
512>; // NOLINT
512>; // NOLINT
/// \brief Support float type for matrix calculations.
///
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
using use_float_matrix = std::integral_constant<bool,
NL_USE_ACADEMIC_SOLVERS>;
using use_float_matrix = std::integral_constant<
bool, NL_USE_ACADEMIC_SOLVERS>;
/// \brief Support long double type for matrix calculations.
///
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
using use_long_double_matrix = std::integral_constant<bool,
NL_USE_ACADEMIC_SOLVERS>;
using use_long_double_matrix = std::integral_constant<
bool, NL_USE_ACADEMIC_SOLVERS>;
using use_float128_matrix = std::integral_constant<bool,
NL_USE_FLOAT128>;
NL_USE_FLOAT128>;
/// \brief Floating point types used
///
@ -242,7 +242,7 @@ namespace netlist
/// the default approach. It is ~20% slower.
///
using use_copy_instead_of_reference = std::integral_constant<bool,
false>;
false>;
/// \brief Avoid unnecessary queue pushes
///
@ -416,16 +416,4 @@ namespace netlist
#endif
} // namespace netlist
//============================================================
// Asserts
//============================================================
#define nl_assert(x) \
do \
{ \
if (NL_DEBUG) \
passert_always(x); \
} while (0)
#define nl_assert_always(x, msg) passert_always_msg(x, msg)
#endif // NLCONFIG_H_

View File

@ -8,13 +8,53 @@
#ifndef NL_ERRSTR_H_
#define NL_ERRSTR_H_
#include "plib/pexception.h"
#include "plib/pfmtlog.h"
namespace netlist
{
static constexpr const char sHINT_NO_DEACTIVATE[] = ".HINT_NO_DEACTIVATE"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
static constexpr const char sHINT_NC[] = ".HINT_NC"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
static constexpr const char sHINT_NO_DEACTIVATE[]
= ".HINT_NO_DEACTIVATE"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
static constexpr const char sHINT_NC[]
= ".HINT_NC"; // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
// -------------------------------------------------------------------------
// Exceptions
// -------------------------------------------------------------------------
/// \brief Generic netlist exception.
/// The exception is used in all events which are considered fatal.
class nl_exception : public plib::pexception
{
public:
/// \brief Constructor.
/// Allows a descriptive text to be passed to the exception
explicit nl_exception(const pstring &text //!< text to be passed
)
: plib::pexception(text)
{
}
/// \brief Constructor.
/// Allows to use \ref plib::pfmt logic to be used in exception
template <typename... Args>
explicit nl_exception(const pstring &fmt, //!< format to be used
Args &&...args //!< arguments to be passed
)
: plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...))
{
}
};
// -------------------------------------------------------------------------
// Error messages
// -------------------------------------------------------------------------
// clang-format off
// nl_base.cpp
@ -187,9 +227,19 @@ namespace netlist
PERRMSGV(MF_FILE_OPEN_ERROR, 1, "Error opening file: {1}")
// clang-format on
} // namespace netlist
// -------------------------------------------------------------------------
// Asserts
// -------------------------------------------------------------------------
#define nl_assert(x) \
do \
{ \
if (NL_DEBUG) \
passert_always(x); \
} while (0)
#define nl_assert_always(x, msg) passert_always_msg(x, msg)
#endif // NL_ERRSTR_H_

View File

@ -8,14 +8,14 @@
#ifndef NLSETUP_H_
#define NLSETUP_H_
#include "nl_config.h"
#include "nltypes.h"
#include "plib/ppreprocessor.h"
#include "plib/psource.h"
#include "plib/pstream.h"
#include "plib/pstring.h"
#include "nl_config.h"
#include "nltypes.h"
#include <initializer_list>
#include <memory>
#include <stack>
@ -26,118 +26,95 @@
// MACROS - netlist definitions
//============================================================
#define NET_STR(x) # x
#define NET_STR(x) #x
#define NET_MODEL(model) \
setup.register_model(model);
#define NET_MODEL(model) setup.register_model(model);
#define ALIAS(alias, name) \
setup.register_alias(# alias, # name);
#define ALIAS(alias, name) setup.register_alias(#alias, #name);
#define DIPPINS(pin1, ...) \
setup.register_dip_alias_arr( # pin1 ", " # __VA_ARGS__);
setup.register_dip_alias_arr(#pin1 ", " #__VA_ARGS__);
// to be used to reference new library truth table devices
#define NET_REGISTER_DEV(type, name) \
setup.register_dev(# type, # name);
#define NET_REGISTER_DEV(type, name) setup.register_dev(#type, #name);
// name is first element so that __VA_ARGS__ always has one element
#define NET_REGISTER_DEVEXT(type, ...) \
setup.register_dev(# type, { PSTRINGIFY_VA(__VA_ARGS__) });
#define NET_REGISTER_DEVEXT(type, ...) \
setup.register_dev(#type, {PSTRINGIFY_VA(__VA_ARGS__)});
#define NET_CONNECT(name, input, output) \
setup.register_link(# name "." # input, # output);
setup.register_link(#name "." #input, #output);
#define NET_C(term1, ...) \
setup.register_connection_arr( # term1 ", " # __VA_ARGS__);
setup.register_connection_arr(#term1 ", " #__VA_ARGS__);
#define PARAM(name, val) \
setup.register_param(NET_STR(name), NET_STR(val));
#define PARAM(name, val) setup.register_param(NET_STR(name), NET_STR(val));
#define DEFPARAM(name, val) \
setup.register_default_param(NET_STR(name), NET_STR(val));
setup.register_default_param(NET_STR(name), NET_STR(val));
#define HINT(name, val) \
setup.register_hint(# name , ".HINT_" # val);
#define HINT(name, val) setup.register_hint(#name, ".HINT_" #val);
#define NETDEV_PARAMI(name, param, val) \
setup.register_param(# name "." # param, val);
setup.register_param(#name "." #param, val);
#define NETLIST_NAME(name) netlist ## _ ## name
#define NETLIST_NAME(name) netlist##_##name
#define NETLIST_EXTERNAL(name) \
void NETLIST_NAME(name)(netlist::nlparse_t &setup);
void NETLIST_NAME(name)(netlist::nlparse_t & setup);
#define NETLIST_START(name) \
void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t & setup)
#define LOCAL_SOURCE(name) \
setup.register_source_proc(# name, &NETLIST_NAME(name));
setup.register_source_proc(#name, &NETLIST_NAME(name));
#define EXTERNAL_SOURCE(name) \
setup.register_source_proc(# name, &NETLIST_NAME(name));
setup.register_source_proc(#name, &NETLIST_NAME(name));
#define LOCAL_LIB_ENTRY_2(type, name) \
type ## _SOURCE(name) \
setup.register_lib_entry(# name, "", PSOURCELOC());
type##_SOURCE(name) setup.register_lib_entry(#name, "", PSOURCELOC());
#define LOCAL_LIB_ENTRY_3(type, name, param_spec) \
type ## _SOURCE(name) \
setup.register_lib_entry(# name, param_spec, PSOURCELOC());
type##_SOURCE(name) \
setup.register_lib_entry(#name, param_spec, PSOURCELOC());
#define LOCAL_LIB_ENTRY(...) PCALLVARARG(LOCAL_LIB_ENTRY_, LOCAL, __VA_ARGS__)
#define EXTERNAL_LIB_ENTRY(...) PCALLVARARG(LOCAL_LIB_ENTRY_, EXTERNAL, __VA_ARGS__)
#define EXTERNAL_LIB_ENTRY(...) \
PCALLVARARG(LOCAL_LIB_ENTRY_, EXTERNAL, __VA_ARGS__)
#define INCLUDE(name) \
setup.include(# name);
#define INCLUDE(name) setup.include(#name);
#define SUBMODEL(model, name) \
setup.namespace_push(# name); \
setup.include(# model); \
setup.namespace_pop();
setup.namespace_push(#name); \
setup.include(#model); \
setup.namespace_pop();
#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \
setup.register_frontier(# attach, PSTRINGIFY_VA(r_in), PSTRINGIFY_VA(r_out));
setup.register_frontier(#attach, PSTRINGIFY_VA(r_in), PSTRINGIFY_VA(r_out));
// -----------------------------------------------------------------------------
// truth table defines
// -----------------------------------------------------------------------------
#if 0
#define TRUTHTABLE_START(cname, in, out, pdef_params) \
void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc); \
static NETLIST_START(cname)
{ \
netlist::tt_desc xdesc{ #cname, in, out, "" }; \
auto sloc = PSOURCELOC(); \
const pstring def_params = pdef_params; \
NETLIST_NAME(cname ## _impl)(xdesc); \
setup.truth_table_create(xdesc, def_params, std::move(sloc)); \
} \
static void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc) \
{
#else
#define TRUTH_TABLE(cname, in, out, pdef_params) \
void NETLIST_NAME(cname ## _impl)(netlist::nlparse_t &setup, netlist::tt_desc &desc); \
static void NETLIST_NAME(cname)(netlist::nlparse_t &setup) \
{ \
netlist::tt_desc desc{ #cname, in, out, "", {} }; \
NETLIST_NAME(cname ## _impl)(setup, desc); \
setup.truth_table_create(desc, pdef_params, PSOURCELOC()); \
} \
static void NETLIST_NAME(cname ## _impl)([[maybe_unused]] netlist::nlparse_t &setup, netlist::tt_desc &desc) \
#define TRUTH_TABLE(cname, in, out, params) \
void NETLIST_NAME(cname##_impl)(netlist::nlparse_t & setup, \
netlist::tt_desc & desc); \
static void NETLIST_NAME(cname)(netlist::nlparse_t & setup) \
{ \
netlist::tt_desc desc{#cname, in, out, "", {}}; \
NETLIST_NAME(cname##_impl)(setup, desc); \
setup.truth_table_create(desc, params, PSOURCELOC()); \
} \
static void NETLIST_NAME(cname##_impl)( \
[[maybe_unused]] netlist::nlparse_t & setup, netlist::tt_desc & desc)
#endif
#define TT_HEAD(x) desc.desc.emplace_back(x);
#define TT_HEAD(x) \
desc.desc.emplace_back(x);
#define TT_LINE(x) desc.desc.emplace_back(x);
#define TT_LINE(x) \
desc.desc.emplace_back(x);
#define TT_FAMILY(x) \
desc.family = x;
#define TT_FAMILY(x) desc.family = x;
#define TRUTHTABLE_ENTRY(name) \
LOCAL_SOURCE(name) \
@ -152,10 +129,10 @@ namespace netlist
struct tt_desc
{
pstring name;
unsigned long ni;
unsigned long no;
pstring family;
pstring name;
unsigned long ni;
unsigned long no;
pstring family;
std::vector<pstring> desc;
};
@ -193,25 +170,29 @@ namespace netlist
/// \param type the alias type see \ref alias_type
/// \param alias the alias to be qualified
/// \param points_to the pin aliased
void register_alias(detail::alias_type type, const pstring &alias, const pstring &points_to);
void register_alias(detail::alias_type type, const pstring &alias,
const pstring &points_to);
/// \brief Register an aliases where alias and references are fully qualified names
/// \param type the alias type see \ref alias_type
/// \param alias the alias to be qualified
/// \param points_to the pin aliased
void register_fqn_alias(detail::alias_type type, const pstring &alias, const pstring &points_to);
void register_fqn_alias(detail::alias_type type, const pstring &alias,
const pstring &points_to);
void register_dip_alias_arr(const pstring &terms);
// last argument only needed by nltool
void register_dev(const pstring &classname, const pstring &name,
const std::vector<pstring> &params_and_connections,
factory::element_t **factory_element = nullptr);
void register_dev(const pstring &classname, std::initializer_list<const char *> more_parameters);
const std::vector<pstring> &params_and_connections,
factory::element_t **factory_element = nullptr);
void register_dev(const pstring &classname,
std::initializer_list<const char *> more_parameters);
void register_dev(const pstring &classname, const pstring &name)
{
register_dev(classname, name, std::vector<pstring>());
}
void register_hint(const pstring &object_name, const pstring &hint_name);
void
register_hint(const pstring &object_name, const pstring &hint_name);
void register_connection(const pstring &sin, const pstring &sout);
void register_connection_arr(const pstring &terms);
@ -230,20 +211,23 @@ namespace netlist
register_param_fp(param, plib::narrow_cast<nl_fptype>(value));
}
void register_lib_entry(const pstring &name, const pstring &def_params, plib::source_location &&loc);
void register_lib_entry(const pstring &name, const pstring &def_params,
plib::source_location &&loc);
void register_frontier(const pstring &attach, const pstring &r_IN, const pstring &r_OUT);
void register_frontier(const pstring &attach, const pstring &r_IN,
const pstring &r_OUT);
// register a source
template <typename S, typename... Args>
void register_source(Args&&... args)
void register_source(Args &&...args)
{
m_sources.add_source<S>(std::forward<Args>(args)...);
}
void register_source_proc(const pstring &name, nlsetup_func func);
void truth_table_create(tt_desc &desc, const pstring &def_params, plib::source_location &&loc);
void truth_table_create(tt_desc &desc, const pstring &def_params,
plib::source_location &&loc);
// include other files
@ -256,17 +240,18 @@ namespace netlist
// FIXME: used by source_t - need a different approach at some time
bool parse_stream(plib::istream_uptr &&in_stream, const pstring &name);
bool parse_tokens(const plib::detail::token_store_t &tokens, const pstring &name);
bool parse_tokens(const plib::detail::token_store_t &tokens,
const pstring &name);
template <typename S, typename... Args>
void add_include(Args&&... args)
void add_include(Args &&...args)
{
m_includes.add_source<S>(std::forward<Args>(args)...);
}
void add_define(const pstring &def, const pstring &val)
{
m_defines.insert({ def, plib::ppreprocessor::define_t(def, val)});
m_defines.insert({def, plib::ppreprocessor::define_t(def, val)});
}
void add_define(const pstring &define);
@ -274,10 +259,10 @@ namespace netlist
// register a list of logs
void register_dynamic_log_devices(const std::vector<pstring> &log_list);
factory::list_t &factory() noexcept;
factory::list_t &factory() noexcept;
const factory::list_t &factory() const noexcept;
log_type &log() noexcept { return m_log; }
log_type &log() noexcept { return m_log; }
const log_type &log() const noexcept { return m_log; }
plib::istream_uptr get_data_stream(const pstring &name);
@ -285,23 +270,22 @@ namespace netlist
private:
pstring namespace_prefix() const;
pstring build_fqn(const pstring &obj_name) const;
void register_param_fp(const pstring &param, nl_fptype value);
bool device_exists(const pstring &name) const;
void register_param_fp(const pstring &param, nl_fptype value);
bool device_exists(const pstring &name) const;
// FIXME: stale? - remove later
void remove_connections(const pstring &pin);
plib::ppreprocessor::defines_map_type m_defines;
plib::psource_collection_t m_includes;
std::stack<pstring> m_namespace_stack;
plib::psource_collection_t m_sources;
detail::abstract_t & m_abstract;
plib::ppreprocessor::defines_map_type m_defines;
plib::psource_collection_t m_includes;
std::stack<pstring> m_namespace_stack;
plib::psource_collection_t m_sources;
detail::abstract_t &m_abstract;
log_type &m_log;
unsigned m_frontier_cnt;
unsigned m_frontier_cnt;
};
} // namespace netlist
#endif // NLSETUP_H_

View File

@ -14,9 +14,6 @@
#include "nl_config.h"
#include "plib/pmempool.h"
#include "plib/ppmf.h"
#include "plib/pstring.h"
#include "plib/ptime.h"
#include "plib/ptypes.h"
@ -170,12 +167,12 @@ namespace netlist
///
/// \note This is not the right location yet.
///
using device_arena = std::conditional_t<
config::use_mempool::value,
plib::mempool_arena<plib::aligned_arena<>,
config::mempool_align::value>,
plib::aligned_arena<>>;
using host_arena = plib::aligned_arena<>;
using log_type = plib::plog_base<NL_DEBUG>;
@ -184,25 +181,19 @@ namespace netlist
// Types needed by various includes
//============================================================
/// \brief Time step type.
///
/// May be either FORWARD or RESTORE
///
enum class time_step_type
{
FORWARD, //!< forward time
RESTORE //!< restore state before last forward
};
/// \brief Delegate type for device notification.
///
using nl_delegate = plib::pmfp<void()>;
using nl_delegate_ts = plib::pmfp<void(time_step_type, nl_fptype)>;
using nl_delegate_dyn = plib::pmfp<void()>;
namespace detail
{
/// \brief Time step type.
///
/// May be either FORWARD or RESTORE
///
enum class time_step_type
{
FORWARD, //!< forward time
RESTORE //!< restore state before last forward
};
/// \brief Enum specifying the type of object
///
enum class terminal_type
@ -220,10 +211,10 @@ namespace netlist
///
enum class alias_type
{
UNKNOWN, //!< Used as a placeholder during code changes
INTERNAL, //!< the alias references a internal pin
FUNCTIONAL, //!< Used for aliases e.g. in BJTs : ALIAS("B",
//!< somesub.p())
UNKNOWN, //!< Used as a placeholder during code changes
INTERNAL, //!< the alias references a internal pin
FUNCTIONAL, //!< Used for aliases e.g. in BJTs : ALIAS("B",
//!< somesub.p())
PACKAGE_PIN, //!< the alias references a package pin, e.g. ALIAS(13,
//!< B.CLK)
READABILITY, //!< the alias is used to improved readability, e.g.
@ -317,37 +308,6 @@ namespace netlist
using desc_const_t = std::integral_constant<const T, V>;
};
//============================================================
// Exceptions
//============================================================
/// \brief Generic netlist exception.
/// The exception is used in all events which are considered fatal.
class nl_exception : public plib::pexception
{
public:
/// \brief Constructor.
/// Allows a descriptive text to be passed to the exception
explicit nl_exception(const pstring &text //!< text to be passed
)
: plib::pexception(text)
{
}
/// \brief Constructor.
/// Allows to use \ref plib::pfmt logic to be used in exception
template <typename... Args>
explicit nl_exception(const pstring &fmt, //!< format to be used
Args &&...args //!< arguments to be passed
)
: plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...))
{
}
};
} // namespace netlist
#endif // NLTYPES_H_

View File

@ -9,6 +9,7 @@
///
#include "pconfig.h"
#include "pgsl.h"
#include "ptypes.h"
#include <algorithm>
@ -271,8 +272,7 @@ namespace plib
/// FIXME: limited implementation
///
template <typename T1, typename T2>
static inline
auto pow(T1 v, T2 p) noexcept -> decltype(std::pow(v, p))
static inline auto pow(T1 v, T2 p) noexcept -> decltype(std::pow(v, p))
{
return std::pow(v, p);
}
@ -283,60 +283,30 @@ namespace plib
return constants<FLOAT128>::one() / v;
}
static FLOAT128 abs(FLOAT128 v) noexcept
{
return fabsq(v);
}
static FLOAT128 abs(FLOAT128 v) noexcept { return fabsq(v); }
static FLOAT128 sqrt(FLOAT128 v) noexcept
{
return sqrtq(v);
}
static FLOAT128 sqrt(FLOAT128 v) noexcept { return sqrtq(v); }
static FLOAT128 hypot(FLOAT128 v1, FLOAT128 v2) noexcept
{
return hypotq(v1, v2);
}
static FLOAT128 exp(FLOAT128 v) noexcept
{
return expq(v);
}
static FLOAT128 exp(FLOAT128 v) noexcept { return expq(v); }
static FLOAT128 log(FLOAT128 v) noexcept
{
return logq(v);
}
static FLOAT128 log(FLOAT128 v) noexcept { return logq(v); }
static FLOAT128 tanh(FLOAT128 v) noexcept
{
return tanhq(v);
}
static FLOAT128 tanh(FLOAT128 v) noexcept { return tanhq(v); }
static FLOAT128 floor(FLOAT128 v) noexcept
{
return floorq(v);
}
static FLOAT128 floor(FLOAT128 v) noexcept { return floorq(v); }
static FLOAT128 log1p(FLOAT128 v) noexcept
{
return log1pq(v);
}
static FLOAT128 log1p(FLOAT128 v) noexcept { return log1pq(v); }
static FLOAT128 sin(FLOAT128 v) noexcept
{
return sinq(v);
}
static FLOAT128 sin(FLOAT128 v) noexcept { return sinq(v); }
static FLOAT128 cos(FLOAT128 v) noexcept
{
return cosq(v);
}
static FLOAT128 cos(FLOAT128 v) noexcept { return cosq(v); }
static FLOAT128 trunc(FLOAT128 v) noexcept
{
return truncq(v);
}
static FLOAT128 trunc(FLOAT128 v) noexcept { return truncq(v); }
template <typename T>
static FLOAT128 pow(FLOAT128 v, T p) noexcept
@ -346,8 +316,8 @@ namespace plib
static FLOAT128 pow(FLOAT128 v, int p) noexcept
{
if (p==2)
return v*v;
if (p == 2)
return v * v;
else
return powq(v, static_cast<FLOAT128>(p));
}
@ -364,7 +334,7 @@ namespace plib
constexpr bool is_pow2(T v) noexcept
{
static_assert(is_integral<T>::value, "is_pow2 needs integer arguments");
return !(v & (v-1));
return !(v & (v - 1));
}
/// \brief return absolute value of signed argument
@ -373,9 +343,9 @@ namespace plib
/// \param v argument
/// \return absolute value of argument
///
template<typename T>
constexpr
std::enable_if_t<plib::is_integral<T>::value && plib::is_signed<T>::value, T>
template <typename T>
constexpr std::enable_if_t<
plib::is_integral<T>::value && plib::is_signed<T>::value, T>
abs(T v) noexcept
{
return v < 0 ? -v : v;
@ -387,9 +357,9 @@ namespace plib
/// \param v argument
/// \return argument since it has no sign
///
template<typename T>
constexpr
std::enable_if_t<plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
template <typename T>
constexpr std::enable_if_t<
plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
abs(T v) noexcept
{
return v;
@ -406,16 +376,14 @@ namespace plib
/// \param n first argument
/// \return greatest common denominator of m and n
///
template<typename M, typename N>
template <typename M, typename N>
constexpr typename std::common_type<M, N>::type
gcd(M m, N n) noexcept //NOLINT(misc-no-recursion)
gcd(M m, N n) noexcept // NOLINT(misc-no-recursion)
{
static_assert(plib::is_integral<M>::value, "gcd: M must be an integer");
static_assert(plib::is_integral<N>::value, "gcd: N must be an integer");
return m == 0 ? plib::abs(n)
: n == 0 ? plib::abs(m)
: gcd(n, m % n);
return m == 0 ? plib::abs(n) : n == 0 ? plib::abs(m) : gcd(n, m % n);
}
/// \brief return least common multiple
@ -429,24 +397,25 @@ namespace plib
/// \param n first argument
/// \return least common multiple of m and n
///
template<typename M, typename N>
constexpr typename std::common_type<M, N>::type
lcm(M m, N n) noexcept
template <typename M, typename N>
constexpr typename std::common_type<M, N>::type lcm(M m, N n) noexcept
{
static_assert(plib::is_integral<M>::value, "lcm: M must be an integer");
static_assert(plib::is_integral<N>::value, "lcm: N must be an integer");
return (m != 0 && n != 0) ? (plib::abs(m) / gcd(m, n)) * plib::abs(n) : 0;
return (m != 0 && n != 0) ? (plib::abs(m) / gcd(m, n)) * plib::abs(n)
: 0;
}
template<class T>
constexpr const T& clamp( const T& v, const T& low, const T& high)
template <class T>
constexpr const T &clamp(const T &v, const T &low, const T &high)
{
gsl_Expects(high >= low);
return (v < low) ? low : (high < v) ? high : v;
}
static_assert(noexcept(constants<double>::one()), "Not evaluated as constexpr");
static_assert(noexcept(constants<double>::one()),
"Not evaluated as constexpr");
} // namespace plib

View File

@ -7,35 +7,40 @@
// Specific technical terms
// spell-checker: words vsolver
#include "nld_solver.h"
#include "core/setup.h"
#include "nl_setup.h"
#include "nld_matrix_solver.h"
#include "nl_setup.h"
#include "nld_solver.h"
#include "core/setup.h"
#include "plib/putil.h"
namespace netlist::solver
{
terms_for_net_t::terms_for_net_t(arena_type &arena, analog_net_t * net)
: m_nz(arena)
, m_nzrd(arena)
, m_nzbd(arena)
, m_connected_net_idx(arena)
, m_terms(arena)
, m_net(net)
, m_rail_start(0)
terms_for_net_t::terms_for_net_t(arena_type &arena, analog_net_t *net)
: m_nz(arena)
, m_nzrd(arena)
, m_nzbd(arena)
, m_connected_net_idx(arena)
, m_terms(arena)
, m_net(net)
, m_rail_start(0)
{
}
void terms_for_net_t::add_terminal(terminal_t *term, int net_other, bool sorted)
void
terms_for_net_t::add_terminal(terminal_t *term, int net_other, bool sorted)
{
if (sorted)
for (std::size_t i=0; i < m_connected_net_idx.size(); i++)
for (std::size_t i = 0; i < m_connected_net_idx.size(); i++)
{
if (m_connected_net_idx[i] > net_other)
{
plib::container::insert_at(m_terms, i, term);
plib::container::insert_at(m_connected_net_idx, i, net_other);
plib::container::insert_at(m_connected_net_idx, i,
net_other);
return;
}
}
@ -47,34 +52,36 @@ namespace netlist::solver
// matrix_solver
// ----------------------------------------------------------------------------------------
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
const net_list_t &nets,
const solver::solver_parameters_t *params)
//: device_t(static_cast<device_t &>(main_solver), name)
: device_t(device_data_t{main_solver.state(), main_solver.name() + "." + name})
, m_params(*params)
, m_gonn(m_arena)
, m_gtn(m_arena)
, m_Idrn(m_arena)
, m_connected_net_Vn(m_arena)
, m_iterative_fail(*this, "m_iterative_fail", 0)
, m_iterative_total(*this, "m_iterative_total", 0)
, m_main_solver(main_solver)
, m_stat_calculations(*this, "m_stat_calculations", 0)
, m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
, m_stat_newton_raphson_fail(*this, "m_stat_newton_raphson_fail", 0)
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
, m_last_step(*this, "m_last_step", netlist_time_ext::zero())
, m_step_funcs(m_arena)
, m_dynamic_funcs(m_arena)
, m_inputs(m_arena)
, m_ops(0)
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver,
const pstring &name,
const net_list_t &nets,
const solver::solver_parameters_t *params)
//: device_t(static_cast<device_t &>(main_solver), name)
: device_t(
device_data_t{main_solver.state(), main_solver.name() + "." + name})
, m_params(*params)
, m_gonn(m_arena)
, m_gtn(m_arena)
, m_Idrn(m_arena)
, m_connected_net_Vn(m_arena)
, m_iterative_fail(*this, "m_iterative_fail", 0)
, m_iterative_total(*this, "m_iterative_total", 0)
, m_main_solver(main_solver)
, m_stat_calculations(*this, "m_stat_calculations", 0)
, m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
, m_stat_newton_raphson_fail(*this, "m_stat_newton_raphson_fail", 0)
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
, m_last_step(*this, "m_last_step", netlist_time_ext::zero())
, m_step_funcs(m_arena)
, m_dynamic_funcs(m_arena)
, m_inputs(m_arena)
, m_ops(0)
{
setup_base(this->state().setup(), nets);
// now setup the matrix
setup_matrix();
//printf("Freq: %f\n", m_params.m_freq());
// printf("Freq: %f\n", m_params.m_freq());
}
analog_net_t *matrix_solver_t::get_connected_net(terminal_t *term)
@ -87,7 +94,8 @@ namespace netlist::solver
m_main_solver.reschedule(this, ts);
}
void matrix_solver_t::setup_base([[maybe_unused]] setup_t &setup, const net_list_t &nets)
void matrix_solver_t::setup_base([[maybe_unused]] setup_t &setup,
const net_list_t &nets)
{
log().debug("New solver setup\n");
std::vector<core_device_t *> step_devices;
@ -95,7 +103,7 @@ namespace netlist::solver
m_terms.clear();
for (const auto & net : nets)
for (const auto &net : nets)
{
m_terms.emplace_back(m_arena, net);
m_rails_temp.emplace_back(m_arena);
@ -108,68 +116,87 @@ namespace netlist::solver
analog_net_t &net = *nets[k];
// FIXME: add size() to list
// log().debug("adding net with {1} populated connections\n", net.core_terms().size());
// log().debug("adding net with {1} populated connections\n",
// net.core_terms().size());
net.set_solver(this);
for (detail::core_terminal_t * p : net.core_terms_copy())
for (detail::core_terminal_t *p : net.core_terms_copy())
{
nl_assert_always(&p->net() == &net, "Net integrity violated");
log().debug("{1} {2} {3}\n", p->name(), net.name(), net.is_rail_net());
log().debug("{1} {2} {3}\n", p->name(), net.name(),
net.is_rail_net());
switch (p->type())
{
case detail::terminal_type::TERMINAL:
if (p->device().is_time_step())
if (!plib::container::contains(step_devices, &p->device()))
if (!plib::container::contains(step_devices,
&p->device()))
step_devices.push_back(&p->device());
if (p->device().is_dynamic())
if (!plib::container::contains(dynamic_devices, &p->device()))
if (!plib::container::contains(dynamic_devices,
&p->device()))
dynamic_devices.push_back(&p->device());
{
auto pterm = plib::dynamic_downcast<terminal_t *>(p);
nl_assert_always(bool(pterm), "cast to terminal_t * failed");
auto pterm = plib::dynamic_downcast<terminal_t *>(
p);
nl_assert_always(bool(pterm),
"cast to terminal_t * failed");
add_term(k, *pterm);
}
log().debug("Added terminal {1}\n", p->name());
break;
case detail::terminal_type::INPUT:
{
proxied_analog_output_t *net_proxy_output = nullptr;
for (auto & input : m_inputs)
if (input->proxied_net() == &p->net())
{
net_proxy_output = input.get();
break;
}
if (net_proxy_output == nullptr)
{
proxied_analog_output_t *net_proxy_output = nullptr;
for (auto &input : m_inputs)
if (input->proxied_net() == &p->net())
{
pstring new_name(this->name() + "." + pstring(plib::pfmt("m{1}")(m_inputs.size())));
auto proxied_net = plib::dynamic_downcast<analog_net_t *>(p->net());
nl_assert_always(proxied_net, "Net is not an analog net");
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, new_name, *proxied_net);
net_proxy_output = net_proxy_output_u.get();
m_inputs.emplace_back(std::move(net_proxy_output_u));
net_proxy_output = input.get();
break;
}
net.remove_terminal(*p);
net_proxy_output->net().add_terminal(*p);
// FIXME: repeated calling - kind of brute force
net_proxy_output->net().rebuild_list();
log().debug("Added input {1}", net_proxy_output->name());
if (net_proxy_output == nullptr)
{
pstring new_name(
this->name() + "."
+ pstring(plib::pfmt("m{1}")(m_inputs.size())));
auto proxied_net = plib::dynamic_downcast<
analog_net_t *>(p->net());
nl_assert_always(proxied_net,
"Net is not an analog net");
auto net_proxy_output_u
= state()
.make_pool_object<
proxied_analog_output_t>(
*this, new_name, *proxied_net);
net_proxy_output = net_proxy_output_u.get();
m_inputs.emplace_back(
std::move(net_proxy_output_u));
}
break;
net.remove_terminal(*p);
net_proxy_output->net().add_terminal(*p);
// FIXME: repeated calling - kind of brute force
net_proxy_output->net().rebuild_list();
log().debug("Added input {1}",
net_proxy_output->name());
}
break;
case detail::terminal_type::OUTPUT:
log().fatal(MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
throw nl_exception(MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
throw nl_exception(
MF_UNHANDLED_ELEMENT_1_FOUND(p->name()));
}
}
net.rebuild_list();
}
for (auto &d : step_devices)
m_step_funcs.emplace_back(nl_delegate_ts(&core_device_t::time_step, d));
m_step_funcs.emplace_back(
nl_delegate_ts(&core_device_t::time_step, d));
for (auto &d : dynamic_devices)
m_dynamic_funcs.emplace_back(nl_delegate_dyn(&core_device_t::update_terminals, d));
m_dynamic_funcs.emplace_back(
nl_delegate_dyn(&core_device_t::update_terminals, d));
}
/// \brief Sort terminals
@ -192,7 +219,8 @@ namespace netlist::solver
/// literature but I have found no articles about Gauss Seidel.
///
/// For Gaussian Elimination however increasing order is better suited.
/// NOTE: Even better would be to sort on elements right of the matrix diagonal.
/// NOTE: Even better would be to sort on elements right of the matrix
/// diagonal.
/// FIXME: This entry needs an update.
///
void matrix_solver_t::sort_terms(matrix_sort_type_e sort)
@ -202,65 +230,69 @@ namespace netlist::solver
switch (sort)
{
case matrix_sort_type_e::PREFER_BAND_MATRIX:
{
for (std::size_t k = 0; k < iN - 1; k++)
{
for (std::size_t k = 0; k < iN - 1; k++)
auto pk = get_weight_around_diagonal(k, k);
for (std::size_t i = k + 1; i < iN; i++)
{
auto pk = get_weight_around_diagonal(k,k);
for (std::size_t i = k+1; i < iN; i++)
auto pi = get_weight_around_diagonal(i, k);
if (pi < pk)
{
auto pi = get_weight_around_diagonal(i,k);
if (pi < pk)
{
std::swap(m_terms[i], m_terms[k]);
pk = get_weight_around_diagonal(k,k);
}
std::swap(m_terms[i], m_terms[k]);
pk = get_weight_around_diagonal(k, k);
}
}
}
break;
}
break;
case matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT:
{
for (std::size_t k = 0; k < iN - 1; k++)
{
for (std::size_t k = 0; k < iN - 1; k++)
auto pk = get_left_right_of_diagonal(k, k);
for (std::size_t i = k + 1; i < iN; i++)
{
auto pk = get_left_right_of_diagonal(k,k);
for (std::size_t i = k+1; i < iN; i++)
auto pi = get_left_right_of_diagonal(i, k);
if (pi.first <= pk.first && pi.second >= pk.second)
{
auto pi = get_left_right_of_diagonal(i,k);
if (pi.first <= pk.first && pi.second >= pk.second)
{
std::swap(m_terms[i], m_terms[k]);
pk = get_left_right_of_diagonal(k,k);
}
std::swap(m_terms[i], m_terms[k]);
pk = get_left_right_of_diagonal(k, k);
}
}
}
break;
}
break;
case matrix_sort_type_e::ASCENDING:
case matrix_sort_type_e::DESCENDING:
{
int sort_order = (sort == matrix_sort_type_e::DESCENDING ? 1 : -1);
{
int sort_order = (sort == matrix_sort_type_e::DESCENDING ? 1
: -1);
for (std::size_t k = 0; k < iN - 1; k++)
for (std::size_t i = k+1; i < iN; i++)
for (std::size_t k = 0; k < iN - 1; k++)
for (std::size_t i = k + 1; i < iN; i++)
{
if ((static_cast<int>(m_terms[k].rail_start())
- static_cast<int>(m_terms[i].rail_start()))
* sort_order
< 0)
{
if ((static_cast<int>(m_terms[k].rail_start()) - static_cast<int>(m_terms[i].rail_start())) * sort_order < 0)
{
std::swap(m_terms[i], m_terms[k]);
}
std::swap(m_terms[i], m_terms[k]);
}
}
break;
case matrix_sort_type_e::NOSORT:
break;
}
}
break;
case matrix_sort_type_e::NOSORT: break;
}
// rebuild
for (auto &term : m_terms)
{
//int *other = term.m_connected_net_idx.data();
// int *other = term.m_connected_net_idx.data();
for (std::size_t i = 0; i < term.count(); i++)
//FIXME: this is weird
// FIXME: this is weird
if (term.m_connected_net_idx[i] != -1)
term.m_connected_net_idx[i] = get_net_idx(get_connected_net(term.terms()[i]));
term.m_connected_net_idx[i] = get_net_idx(
get_connected_net(term.terms()[i]));
}
}
@ -272,7 +304,9 @@ namespace netlist::solver
{
m_terms[k].set_rail_start(m_terms[k].count());
for (std::size_t i = 0; i < m_rails_temp[k].count(); i++)
this->m_terms[k].add_terminal(m_rails_temp[k].terms()[i], m_rails_temp[k].m_connected_net_idx.data()[i], false);
this->m_terms[k].add_terminal(
m_rails_temp[k].terms()[i],
m_rails_temp[k].m_connected_net_idx.data()[i], false);
}
// free all - no longer needed
@ -285,17 +319,18 @@ namespace netlist::solver
// create a list of non zero elements.
for (unsigned k = 0; k < iN; k++)
{
terms_for_net_t & t = m_terms[k];
terms_for_net_t &t = m_terms[k];
// pretty brutal
int *other = t.m_connected_net_idx.data();
t.m_nz.clear();
for (std::size_t i = 0; i < t.rail_start(); i++)
if (!plib::container::contains(t.m_nz, static_cast<unsigned>(other[i])))
if (!plib::container::contains(t.m_nz,
static_cast<unsigned>(other[i])))
t.m_nz.push_back(static_cast<unsigned>(other[i]));
t.m_nz.push_back(k); // add diagonal
t.m_nz.push_back(k); // add diagonal
// and sort
std::sort(t.m_nz.begin(), t.m_nz.end());
@ -307,16 +342,16 @@ namespace netlist::solver
for (std::size_t k = 0; k < iN; k++)
{
terms_for_net_t & t = m_terms[k];
terms_for_net_t &t = m_terms[k];
// pretty brutal
int *other = t.m_connected_net_idx.data();
if (k==0)
if (k == 0)
t.m_nzrd.clear();
else
{
t.m_nzrd = m_terms[k-1].m_nzrd;
for (auto j = t.m_nzrd.begin(); j != t.m_nzrd.end(); )
t.m_nzrd = m_terms[k - 1].m_nzrd;
for (auto j = t.m_nzrd.begin(); j != t.m_nzrd.end();)
{
if (*j < k + 1)
j = t.m_nzrd.erase(j);
@ -326,7 +361,9 @@ namespace netlist::solver
}
for (std::size_t i = 0; i < t.rail_start(); i++)
if (!plib::container::contains(t.m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
if (!plib::container::contains(t.m_nzrd,
static_cast<unsigned>(other[i]))
&& other[i] >= static_cast<int>(k + 1))
t.m_nzrd.push_back(static_cast<unsigned>(other[i]));
// and sort
@ -366,7 +403,8 @@ namespace netlist::solver
}
}
}
log().verbose("Number of multiplications/additions for {1}: {2}", name(), m_ops);
log().verbose("Number of multiplications/additions for {1}: {2}",
name(), m_ops);
// Dumps non zero elements right of diagonal -> to much output, disabled
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
@ -374,7 +412,7 @@ namespace netlist::solver
for (std::size_t k = 0; k < iN; k++)
{
pstring line = plib::pfmt("{1:3}")(k);
for (const auto & nzrd : m_terms[k].m_nzrd)
for (const auto &nzrd : m_terms[k].m_nzrd)
line += plib::pfmt(" {1:3}")(nzrd);
log().verbose("{1}", line);
}
@ -387,9 +425,12 @@ namespace netlist::solver
{
pstring num = plib::pfmt("{1}")(k);
state().save(*this, m_gonn[k],"GO" + num, this->name(), m_terms[k].count());
state().save(*this, m_gtn[k],"GT" + num, this->name(), m_terms[k].count());
state().save(*this, m_Idrn[k],"IDR" + num, this->name(), m_terms[k].count());
state().save(*this, m_gonn[k], "GO" + num, this->name(),
m_terms[k].count());
state().save(*this, m_gtn[k], "GT" + num, this->name(),
m_terms[k].count());
state().save(*this, m_Idrn[k], "IDR" + num, this->name(),
m_terms[k].count());
}
}
@ -414,20 +455,22 @@ namespace netlist::solver
for (std::size_t k = 0; k < iN; k++)
for (std::size_t j = 0; j < m_terms[k].count(); j++)
{
m_gtn.set(k,j, nlconst::zero());
m_gonn.set(k,j, nlconst::zero());
m_Idrn.set(k,j, nlconst::zero());
m_gtn.set(k, j, nlconst::zero());
m_gonn.set(k, j, nlconst::zero());
m_Idrn.set(k, j, nlconst::zero());
m_connected_net_Vn.set(k, j, nullptr);
}
for (std::size_t k = 0; k < iN; k++)
{
auto count = m_terms[k].count();
for (std::size_t i = 0; i < count; i++)
{
m_terms[k].terms()[i]->set_ptrs(&m_gtn[k][i], &m_gonn[k][i], &m_Idrn[k][i]);
m_connected_net_Vn[k][i] = get_connected_net(m_terms[k].terms()[i])->Q_Analog_state_ptr();
m_terms[k].terms()[i]->set_ptrs(&m_gtn[k][i], &m_gonn[k][i],
&m_Idrn[k][i]);
m_connected_net_Vn[k][i] = get_connected_net(
m_terms[k].terms()[i])
->Q_Analog_state_ptr();
}
}
}
@ -448,10 +491,11 @@ namespace netlist::solver
void matrix_solver_t::reset()
{
//m_last_step = netlist_time_ext::zero();
// m_last_step = netlist_time_ext::zero();
}
void matrix_solver_t::step(time_step_type ts_type, netlist_time delta) noexcept
void matrix_solver_t::step(detail::time_step_type ts_type,
netlist_time delta) noexcept
{
const auto dd(delta.as_fp<fptype>());
for (auto &d : m_step_funcs)
@ -460,12 +504,13 @@ namespace netlist::solver
bool matrix_solver_t::solve_nr_base()
{
bool this_resched(false);
bool this_resched(false);
std::size_t newton_loops = 0;
do
{
update_dynamic();
// Gauss-Seidel will revert to Gaussian elimination if steps exceeded.
// Gauss-Seidel will revert to Gaussian elimination if steps
// exceeded.
this->m_stat_calculations++;
this->upstream_solve_non_dynamic();
this_resched = this->check_err();
@ -482,18 +527,21 @@ namespace netlist::solver
netlist_time matrix_solver_t::newton_loops_exceeded(netlist_time delta)
{
netlist_time next_time_step;
bool resched(false);
bool resched(false);
restore();
step(time_step_type::RESTORE, delta);
step(detail::time_step_type::RESTORE, delta);
for (std::size_t i=0; i< 10; i++)
for (std::size_t i = 0; i < 10; i++)
{
backup();
step(time_step_type::FORWARD, netlist_time::from_fp(m_params.m_min_ts_ts()));
step(detail::time_step_type::FORWARD,
netlist_time::from_fp(m_params.m_min_ts_ts()));
resched = solve_nr_base();
// update time step calculation
next_time_step = compute_next_time_step(m_params.m_min_ts_ts(), m_params.m_min_ts_ts(), m_params.m_max_time_step);
next_time_step = compute_next_time_step(m_params.m_min_ts_ts(),
m_params.m_min_ts_ts(),
m_params.m_max_time_step);
delta -= netlist_time::from_fp(m_params.m_min_ts_ts());
}
// try remaining time using compute_next_time step
@ -502,19 +550,23 @@ namespace netlist::solver
if (next_time_step > delta)
next_time_step = delta;
backup();
step(time_step_type::FORWARD, next_time_step);
step(detail::time_step_type::FORWARD, next_time_step);
delta -= next_time_step;
resched = solve_nr_base();
next_time_step = compute_next_time_step(next_time_step.as_fp<nl_fptype>(), m_params.m_min_ts_ts(), m_params.m_max_time_step);
next_time_step = compute_next_time_step(
next_time_step.as_fp<nl_fptype>(), m_params.m_min_ts_ts(),
m_params.m_max_time_step);
}
if (m_stat_newton_raphson % 100 == 0)
log().warning(MW_NEWTON_LOOPS_EXCEEDED_INVOCATION_3(100, this->name(), exec().time().as_double() * 1e6));
log().warning(MW_NEWTON_LOOPS_EXCEEDED_INVOCATION_3(
100, this->name(), exec().time().as_double() * 1e6));
if (resched)
{
// reschedule ....
log().warning(MW_NEWTON_LOOPS_EXCEEDED_ON_NET_2(this->name(), exec().time().as_double() * 1e6));
log().warning(MW_NEWTON_LOOPS_EXCEEDED_ON_NET_2(
this->name(), exec().time().as_double() * 1e6));
return netlist_time::from_fp(m_params.m_nr_recalc_delay());
}
if (m_params.m_dynamic_ts)
@ -523,7 +575,8 @@ namespace netlist::solver
return netlist_time::from_fp(m_params.m_max_time_step);
}
netlist_time matrix_solver_t::solve(netlist_time_ext now, [[maybe_unused]] const char *source)
netlist_time matrix_solver_t::solve(netlist_time_ext now,
[[maybe_unused]] const char *source)
{
auto delta = static_cast<netlist_time>(now - m_last_step());
PFDEBUG(printf("solve %.10f\n", delta.as_double());)
@ -532,8 +585,10 @@ namespace netlist::solver
// FIXME: Make this a parameter!
if (delta < netlist_time::quantum())
{
//printf("solve return %s at %f\n", source, now.as_double());
return time_step_device_count() > 0 ? netlist_time::from_fp(m_params.m_min_time_step) : netlist_time::zero();
// printf("solve return %s at %f\n", source, now.as_double());
return time_step_device_count() > 0
? netlist_time::from_fp(m_params.m_min_time_step)
: netlist_time::zero();
}
backup(); // save voltages for backup and time step calculation
@ -543,7 +598,7 @@ namespace netlist::solver
++m_stat_vsolver_calls;
if (dynamic_device_count() != 0)
{
step(time_step_type::FORWARD, delta);
step(detail::time_step_type::FORWARD, delta);
const auto resched = solve_nr_base();
if (resched)
@ -551,7 +606,7 @@ namespace netlist::solver
}
else
{
step(time_step_type::FORWARD, delta);
step(detail::time_step_type::FORWARD, delta);
this->m_stat_calculations++;
this->upstream_solve_non_dynamic();
this->store();
@ -560,14 +615,15 @@ namespace netlist::solver
if (m_params.m_dynamic_ts)
{
if (time_step_device_count() > 0)
return compute_next_time_step(delta.as_fp<nl_fptype>(), m_params.m_min_time_step, m_params.m_max_time_step);
return compute_next_time_step(delta.as_fp<nl_fptype>(),
m_params.m_min_time_step,
m_params.m_max_time_step);
}
if (time_step_device_count() > 0)
return netlist_time::from_fp(m_params.m_max_time_step);
return netlist_time::zero();
}
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
@ -578,11 +634,14 @@ namespace netlist::solver
return -1;
}
std::pair<int, int> matrix_solver_t::get_left_right_of_diagonal(std::size_t irow, std::size_t idiag)
std::pair<int, int>
matrix_solver_t::get_left_right_of_diagonal(std::size_t irow,
std::size_t idiag)
{
//
// return the maximum column left of the diagonal (-1 if no cols found)
// return the minimum column right of the diagonal (999999 if no cols found)
// return the minimum column right of the diagonal (999999 if no cols
// found)
//
const auto row = static_cast<int>(irow);
@ -598,8 +657,10 @@ namespace netlist::solver
auto col = get_net_idx(get_connected_net(term.terms()[i]));
if (col != -1)
{
if (col==row) col = diag;
else if (col==diag) col = row;
if (col == row)
col = diag;
else if (col == diag)
col = row;
if (col > diag && col < colmin)
colmin = col;
@ -610,7 +671,9 @@ namespace netlist::solver
return {colmax, colmin};
}
matrix_solver_t::fptype matrix_solver_t::get_weight_around_diagonal(std::size_t row, std::size_t diag)
matrix_solver_t::fptype
matrix_solver_t::get_weight_around_diagonal(std::size_t row,
std::size_t diag)
{
{
//
@ -620,7 +683,7 @@ namespace netlist::solver
std::vector<bool> touched(1024, false); // FIXME!
fptype weight = nlconst::zero();
auto &term = m_terms[row];
auto &term = m_terms[row];
for (std::size_t i = 0; i < term.count(); i++)
{
auto col = get_net_idx(get_connected_net(term.terms()[i]));
@ -629,10 +692,14 @@ namespace netlist::solver
auto colu = static_cast<std::size_t>(col);
if (!touched[colu])
{
if (colu==row) colu = static_cast<unsigned>(diag);
else if (colu==diag) colu = static_cast<unsigned>(row);
if (colu == row)
colu = static_cast<unsigned>(diag);
else if (colu == diag)
colu = static_cast<unsigned>(row);
weight = weight + plib::abs(static_cast<fptype>(colu) - static_cast<fptype>(diag));
weight = weight
+ plib::abs(static_cast<fptype>(colu)
- static_cast<fptype>(diag));
touched[colu] = true;
}
}
@ -650,38 +717,46 @@ namespace netlist::solver
else
{
int ot = get_net_idx(get_connected_net(term));
if (ot>=0)
if (ot >= 0)
{
m_terms[net_idx].add_terminal(term, ot, true);
}
else
{
log().fatal(MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
throw nl_exception(MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
throw nl_exception(
MF_FOUND_TERM_WITH_MISSING_OTHERNET(term->name()));
}
}
}
void matrix_solver_t::log_stats()
{
if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && log().verbose.is_enabled())
if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls
&& log().verbose.is_enabled())
{
log().verbose("==============================================");
log().verbose("Solver {1}", this->name());
log().verbose(" ==> {1} nets", this->m_terms.size());
log().verbose(" has {1} dynamic elements", this->dynamic_device_count());
log().verbose(" has {1} time step elements", this->time_step_device_count());
log().verbose(" {1:6.3} average newton raphson loops",
static_cast<fptype>(this->m_stat_newton_raphson) / static_cast<fptype>(this->m_stat_vsolver_calls));
log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
this->m_stat_calculations,
static_cast<fptype>(this->m_stat_calculations) / this->exec().time().as_fp<fptype>(),
this->m_iterative_fail,
nlconst::hundred() * static_cast<fptype>(this->m_iterative_fail)
/ static_cast<fptype>(this->m_stat_calculations),
static_cast<fptype>(this->m_iterative_total) / static_cast<fptype>(this->m_stat_calculations));
log().verbose(" has {1} dynamic elements",
this->dynamic_device_count());
log().verbose(" has {1} time step elements",
this->time_step_device_count());
log().verbose(
" {1:6.3} average newton raphson loops",
static_cast<fptype>(this->m_stat_newton_raphson)
/ static_cast<fptype>(this->m_stat_vsolver_calls));
log().verbose(
" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
this->m_stat_calculations,
static_cast<fptype>(this->m_stat_calculations)
/ this->exec().time().as_fp<fptype>(),
this->m_iterative_fail,
nlconst::hundred() * static_cast<fptype>(this->m_iterative_fail)
/ static_cast<fptype>(this->m_stat_calculations),
static_cast<fptype>(this->m_iterative_total)
/ static_cast<fptype>(this->m_stat_calculations));
}
}
} // namespace netlist::solver

View File

@ -11,14 +11,14 @@
/// \file nld_matrix_solver.h
///
#include "nl_errstr.h"
#include "nltypes.h"
#include "../core/analog.h"
#include "../core/device.h"
#include "../core/device_macros.h"
#include "../core/param.h"
#include "nl_errstr.h"
#include "nltypes.h"
#include "plib/palloc.h"
#include "plib/penum.h"
#include "plib/pmatrix2d.h"
@ -29,7 +29,7 @@
#include <numeric>
//FIXME: remove again
// FIXME: remove again
#define PFDEBUG(x)
@ -42,6 +42,8 @@ namespace netlist::solver
CXX_STATIC
};
// clang-format off
PENUM(matrix_sort_type_e,
NOSORT,
ASCENDING,
@ -67,40 +69,63 @@ namespace netlist::solver
, FLOATQ128
)
// clang-format on
using arena_type = plib::mempool_arena<plib::aligned_arena<>, 1024>;
using static_compile_container = std::vector<std::pair<pstring, pstring>>;
struct solver_parameter_defaults
{
static constexpr nl_fptype m_freq() { return nlconst::magic(48000.0); }
static constexpr nl_fptype m_freq() { return nlconst::magic(48000.0); }
// iteration parameters
static constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
static constexpr matrix_type_e m_method() { return matrix_type_e::MAT_CR; }
static constexpr matrix_fp_type_e m_fp_type() { return matrix_fp_type_e::DOUBLE; }
static constexpr nl_fptype m_reltol() { return nlconst::magic(1e-3); }
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
static constexpr std::size_t m_nr_loops() { return 250; }
static constexpr std::size_t m_gs_loops() { return 50; }
static constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
static constexpr matrix_type_e m_method()
{
return matrix_type_e::MAT_CR;
}
static constexpr matrix_fp_type_e m_fp_type()
{
return matrix_fp_type_e::DOUBLE;
}
static constexpr nl_fptype m_reltol() { return nlconst::magic(1e-3); }
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
static constexpr std::size_t m_nr_loops() { return 250; }
static constexpr std::size_t m_gs_loops() { return 50; }
// general parameters
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
static constexpr bool m_pivot() { return false; }
static constexpr nl_fptype m_nr_recalc_delay(){ return netlist_time::quantum().as_fp<nl_fptype>(); }
static constexpr int m_parallel() { return 0; }
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
static constexpr bool m_pivot() { return false; }
static constexpr nl_fptype m_nr_recalc_delay()
{
return netlist_time::quantum().as_fp<nl_fptype>();
}
static constexpr int m_parallel() { return 0; }
static constexpr nl_fptype m_min_ts_ts() { return nlconst::magic(1e-9); }
static constexpr nl_fptype m_min_ts_ts()
{
return nlconst::magic(1e-9);
}
// automatic time step
static constexpr bool m_dynamic_ts() { return false; }
static constexpr nl_fptype m_dynamic_lte() { return nlconst::magic(1e-5); }
static constexpr nl_fptype m_dynamic_min_ts() { return nlconst::magic(1e-6); }
static constexpr bool m_dynamic_ts() { return false; }
static constexpr nl_fptype m_dynamic_lte()
{
return nlconst::magic(1e-5);
}
static constexpr nl_fptype m_dynamic_min_ts()
{
return nlconst::magic(1e-6);
}
// matrix sorting
static constexpr matrix_sort_type_e m_sort_type() { return matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT; }
static constexpr matrix_sort_type_e m_sort_type()
{
return matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT;
}
// special
static constexpr bool m_use_gabs() { return true; }
static constexpr bool m_use_gabs() { return true; }
static solver_parameter_defaults &get_instance()
{
@ -112,30 +137,52 @@ namespace netlist::solver
struct solver_parameters_t
{
template <typename D>
solver_parameters_t(device_t &parent, const pstring &prefix, D &defaults)
solver_parameters_t(device_t &parent, const pstring &prefix,
D &defaults)
: m_freq(parent, prefix + "FREQ", defaults.m_freq())
// iteration parameters
, m_gs_sor(parent, prefix + "SOR_FACTOR", defaults.m_gs_sor())
, m_method(parent, prefix + "METHOD", defaults.m_method())
, m_fp_type(parent, prefix + "FPTYPE", defaults.m_fp_type())
, m_reltol(parent, prefix + "RELTOL", defaults.m_reltol()) //!< SPICE RELTOL parameter
, m_vntol(parent, prefix + "VNTOL", defaults.m_vntol()) //!< SPICE VNTOL parameter
, m_accuracy(parent, prefix + "ACCURACY", defaults.m_accuracy()) //!< Iterative solver accuracy
, m_nr_loops(parent, prefix + "NR_LOOPS", defaults.m_nr_loops()) //!< Maximum number of Newton-Raphson loops
, m_gs_loops(parent, prefix + "GS_LOOPS", defaults.m_gs_loops()) //!< Maximum number of Gauss-Seidel loops
, m_gs_sor(parent, prefix + "SOR_FACTOR", defaults.m_gs_sor())
, m_method(parent, prefix + "METHOD", defaults.m_method())
, m_fp_type(parent, prefix + "FPTYPE", defaults.m_fp_type())
, m_reltol(parent, prefix + "RELTOL",
defaults.m_reltol()) //!< SPICE RELTOL parameter
, m_vntol(parent, prefix + "VNTOL", defaults.m_vntol()) //!< SPICE VNTOL
//!< parameter
, m_accuracy(parent, prefix + "ACCURACY",
defaults.m_accuracy()) //!< Iterative solver accuracy
, m_nr_loops(parent, prefix + "NR_LOOPS",
defaults.m_nr_loops()) //!< Maximum number of
//!< Newton-Raphson loops
, m_gs_loops(parent, prefix + "GS_LOOPS",
defaults.m_gs_loops()) //!< Maximum number of Gauss-Seidel
//!< loops
// general parameters
, m_gmin(parent, prefix + "GMIN", defaults.m_gmin())
, m_pivot(parent, prefix + "PIVOT", defaults.m_pivot()) //!< use pivoting on supported solvers
, m_nr_recalc_delay(parent, prefix + "NR_RECALC_DELAY", defaults.m_nr_recalc_delay()) //!< Delay to next solve attempt if nr loops exceeded
, m_pivot(parent, prefix + "PIVOT", defaults.m_pivot()) //!< use
//!< pivoting on
//!< supported
//!< solvers
, m_nr_recalc_delay(parent, prefix + "NR_RECALC_DELAY",
defaults.m_nr_recalc_delay()) //!< Delay to next
//!< solve attempt if
//!< nr loops exceeded
, m_parallel(parent, prefix + "PARALLEL", defaults.m_parallel())
, m_min_ts_ts(parent, prefix + "MIN_TS_TS", defaults.m_min_ts_ts()) //!< The minimum time step for solvers with time stepping devices.
, m_min_ts_ts(parent, prefix + "MIN_TS_TS",
defaults.m_min_ts_ts()) //!< The minimum time step for
//!< solvers with time stepping
//!< devices.
// automatic time step
, m_dynamic_ts(parent, prefix + "DYNAMIC_TS", defaults.m_dynamic_ts()) //!< Use dynamic time stepping
, m_dynamic_lte(parent, prefix + "DYNAMIC_LTE", defaults.m_dynamic_lte()) //!< dynamic time stepping slope
, m_dynamic_min_ts(parent, prefix + "DYNAMIC_MIN_TIMESTEP", defaults.m_dynamic_min_ts()) //!< smallest time step allowed
, m_dynamic_ts(parent, prefix + "DYNAMIC_TS",
defaults.m_dynamic_ts()) //!< Use dynamic time stepping
, m_dynamic_lte(parent, prefix + "DYNAMIC_LTE",
defaults.m_dynamic_lte()) //!< dynamic time stepping
//!< slope
, m_dynamic_min_ts(parent, prefix + "DYNAMIC_MIN_TIMESTEP",
defaults.m_dynamic_min_ts()) //!< smallest time step
//!< allowed
// matrix sorting
, m_sort_type(parent, prefix + "SORT_TYPE", defaults.m_sort_type())
@ -144,11 +191,12 @@ namespace netlist::solver
, m_use_gabs(parent, prefix + "USE_GABS", defaults.m_use_gabs())
, m_min_time_step(m_dynamic_min_ts())
{
m_max_time_step = netlist_time::from_fp(plib::reciprocal(m_freq())).as_fp<decltype(m_max_time_step)>();
m_max_time_step = netlist_time::from_fp(plib::reciprocal(m_freq()))
.as_fp<decltype(m_max_time_step)>();
if (m_dynamic_ts)
{
m_max_time_step *= 1;//NL_FCONST(1000.0);
m_max_time_step *= 1; // NL_FCONST(1000.0);
}
else
{
@ -156,23 +204,23 @@ namespace netlist::solver
}
}
param_fp_t m_freq;
param_fp_t m_gs_sor;
param_enum_t<matrix_type_e> m_method;
param_enum_t<matrix_fp_type_e> m_fp_type;
param_fp_t m_reltol;
param_fp_t m_vntol;
param_fp_t m_accuracy;
param_num_t<std::size_t> m_nr_loops;
param_num_t<std::size_t> m_gs_loops;
param_fp_t m_gmin;
param_logic_t m_pivot;
param_fp_t m_nr_recalc_delay;
param_int_t m_parallel;
param_fp_t m_min_ts_ts;
param_logic_t m_dynamic_ts;
param_fp_t m_dynamic_lte;
param_fp_t m_dynamic_min_ts;
param_fp_t m_freq;
param_fp_t m_gs_sor;
param_enum_t<matrix_type_e> m_method;
param_enum_t<matrix_fp_type_e> m_fp_type;
param_fp_t m_reltol;
param_fp_t m_vntol;
param_fp_t m_accuracy;
param_num_t<std::size_t> m_nr_loops;
param_num_t<std::size_t> m_gs_loops;
param_fp_t m_gmin;
param_logic_t m_pivot;
param_fp_t m_nr_recalc_delay;
param_int_t m_parallel;
param_fp_t m_min_ts_ts;
param_logic_t m_dynamic_ts;
param_fp_t m_dynamic_lte;
param_fp_t m_dynamic_min_ts;
param_enum_t<matrix_sort_type_e> m_sort_type;
param_logic_t m_use_gabs;
@ -181,11 +229,10 @@ namespace netlist::solver
nl_fptype m_max_time_step;
};
class terms_for_net_t
{
public:
terms_for_net_t(arena_type &arena, analog_net_t * net = nullptr);
terms_for_net_t(arena_type &arena, analog_net_t *net = nullptr);
void clear();
@ -201,35 +248,49 @@ namespace netlist::solver
void setV(nl_fptype v) noexcept { m_net->set_Q_Analog(v); }
bool is_net(const analog_net_t * net) const noexcept { return net == m_net; }
bool is_net(const analog_net_t *net) const noexcept
{
return net == m_net;
}
void set_rail_start(std::size_t val) noexcept { m_rail_start = val; }
PALIGNAS_VECTOROPT()
plib::arena_vector<arena_type, unsigned> m_nz; //!< all non zero for multiplication
plib::arena_vector<arena_type, unsigned> m_nzrd; //!< non zero right of the diagonal for elimination, may include RHS element
plib::arena_vector<arena_type, unsigned> m_nzbd; //!< non zero below of the diagonal for elimination
plib::arena_vector<arena_type, unsigned> m_nz; //!< all non zero for
//!< multiplication
plib::arena_vector<arena_type, unsigned> m_nzrd; //!< non zero right of
//!< the diagonal for
//!< elimination, may
//!< include RHS
//!< element
plib::arena_vector<arena_type, unsigned> m_nzbd; //!< non zero below of
//!< the diagonal for
//!< elimination
plib::arena_vector<arena_type, int> m_connected_net_idx;
private:
plib::arena_vector<arena_type, terminal_t *> m_terms;
analog_net_t * m_net;
std::size_t m_rail_start;
analog_net_t *m_net;
std::size_t m_rail_start;
};
class proxied_analog_output_t : public analog_output_t
{
public:
proxied_analog_output_t(core_device_t &dev, const pstring &aname, analog_net_t *pnet)
proxied_analog_output_t(core_device_t &dev, const pstring &aname,
analog_net_t *pnet)
: analog_output_t(dev, aname)
, m_proxied_net(pnet)
{ }
{
}
analog_net_t *proxied_net() const { return m_proxied_net; }
analog_net_t *proxied_net() const { return m_proxied_net;}
private:
analog_net_t *m_proxied_net; // only for proxy nets in analog input logic
analog_net_t *m_proxied_net; // only for proxy nets in analog input
// logic
};
class matrix_solver_t : public device_t
@ -237,16 +298,22 @@ namespace netlist::solver
public:
using list_t = std::vector<matrix_solver_t *>;
using fptype = nl_fptype;
using net_list_t = std::vector<analog_net_t *>;
using net_list_t = std::vector<analog_net_t *>;
// after every call to solve, update inputs must be called.
// this can be done as well as a batch to ease parallel processing.
netlist_time solve(netlist_time_ext now, const char *source);
void update_inputs();
void update_inputs();
std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); }
std::size_t time_step_device_count() const noexcept { return m_step_funcs.size(); }
std::size_t dynamic_device_count() const noexcept
{
return m_dynamic_funcs.size();
}
std::size_t time_step_device_count() const noexcept
{
return m_step_funcs.size();
}
/// \brief reschedule solver execution
///
@ -264,23 +331,28 @@ namespace netlist::solver
// this should only occur outside of execution and thus
// using time should be safe.
[[maybe_unused]] const netlist_time new_time_step = solve(exec().time(), "solve_now");
[[maybe_unused]] const netlist_time new_time_step = solve(
exec().time(), "solve_now");
update_inputs();
if (time_step_device_count() > 0)
{
this->reschedule(netlist_time::from_fp(m_params.m_dynamic_ts ? m_params.m_min_time_step : m_params.m_max_time_step));
this->reschedule(netlist_time::from_fp(
m_params.m_dynamic_ts ? m_params.m_min_time_step
: m_params.m_max_time_step));
}
}
template <typename F>
void change_state(F f)
{
// We only need to update the net first if this is a time stepping net
// We only need to update the net first if this is a time stepping
// net
if (time_step_device_count() > 0)
{
[[maybe_unused]] const netlist_time new_time_step = solve(exec().time(), "change_state");
[[maybe_unused]] const netlist_time new_time_step = solve(
exec().time(), "change_state");
update_inputs();
}
f();
@ -297,9 +369,11 @@ namespace netlist::solver
virtual void log_stats();
virtual std::pair<pstring, pstring> create_solver_code([[maybe_unused]] solver::static_compile_target target)
virtual std::pair<pstring, pstring> create_solver_code(
[[maybe_unused]] solver::static_compile_target target)
{
return { "", plib::pfmt("// solver doesn't support static compile\n\n") };
return {"",
plib::pfmt("// solver doesn't support static compile\n\n")};
}
// return number of floating point operations for solve
@ -307,11 +381,13 @@ namespace netlist::solver
protected:
matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
const net_list_t &nets,
const solver_parameters_t *params);
const net_list_t &nets,
const solver_parameters_t *params);
virtual void upstream_solve_non_dynamic() = 0;
virtual netlist_time compute_next_time_step(fptype cur_ts, fptype min_ts, fptype max_ts) = 0;
virtual netlist_time
compute_next_time_step(fptype cur_ts, fptype min_ts, fptype max_ts)
= 0;
virtual bool check_err() const = 0;
virtual void store() = 0;
virtual void backup() = 0;
@ -326,7 +402,7 @@ namespace netlist::solver
}
const solver_parameters_t &m_params;
arena_type m_arena;
arena_type m_arena;
plib::pmatrix2d_vrl<arena_type, fptype> m_gonn;
plib::pmatrix2d_vrl<arena_type, fptype> m_gtn;
@ -339,20 +415,20 @@ namespace netlist::solver
std::vector<terms_for_net_t> m_terms; // setup only
private:
// base setup - called from constructor
void setup_base(setup_t &setup, const net_list_t &nets) noexcept(false);
bool solve_nr_base();
bool solve_nr_base();
netlist_time newton_loops_exceeded(netlist_time delta);
void sort_terms(matrix_sort_type_e sort);
void update_dynamic() noexcept;
void step(time_step_type ts_type, netlist_time delta) noexcept;
void step(detail::time_step_type ts_type, netlist_time delta) noexcept;
int get_net_idx(const analog_net_t *net) const noexcept;
std::pair<int, int> get_left_right_of_diagonal(std::size_t irow, std::size_t idiag);
std::pair<int, int>
get_left_right_of_diagonal(std::size_t irow, std::size_t idiag);
fptype get_weight_around_diagonal(std::size_t row, std::size_t diag);
void add_term(std::size_t net_idx, terminal_t *term) noexcept(false);
@ -371,10 +447,12 @@ namespace netlist::solver
state_var<std::size_t> m_stat_newton_raphson_fail;
state_var<std::size_t> m_stat_vsolver_calls;
state_var<netlist_time_ext> m_last_step;
plib::arena_vector<arena_type, nl_delegate_ts> m_step_funcs;
state_var<netlist_time_ext> m_last_step;
plib::arena_vector<arena_type, nl_delegate_ts> m_step_funcs;
plib::arena_vector<arena_type, nl_delegate_dyn> m_dynamic_funcs;
plib::arena_vector<arena_type, device_arena::unique_ptr<proxied_analog_output_t>> m_inputs;
plib::arena_vector<arena_type,
device_arena::unique_ptr<proxied_analog_output_t>>
m_inputs;
std::size_t m_ops;

View File

@ -2,12 +2,12 @@
// copyright-holders:Couriersud
///
/// \file test_pmfp.cpp
/// \file test_precommit.cpp
///
/// tests for `plib::pmfp`
/// tests to check for experimental code before commit
///
#include "netlist/nl_config.h"
#include "nl_config.h"
#include "plib/pconfig.h"
#include "plib/ppmf.h"