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

@ -13,13 +13,15 @@
***************************************************************************/
// 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,7 +38,8 @@
// --------------------------------------------------------------------------
// 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
@ -44,7 +47,10 @@ DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monoch
#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)); \
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)
@ -67,14 +73,17 @@ 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_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;
@ -84,13 +93,16 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
LOG("VSYNC UP %f %d\n", m_last_x, m_last_y);
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.
@ -109,7 +121,8 @@ 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
// 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
@ -122,7 +135,6 @@ void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const d
m_last_line_duration = time - m_last_hsync_time;
m_last_hsync_time = time;
}
}
else if (last_comp && !m_sig_composite)
@ -147,19 +159,22 @@ void fixedfreq_monitor_state::update_bm(const time_type &time)
if (!m_sig_vsync && !m_sig_composite)
{
// uint32_t mask = m_sig_field ? 0xffffffff : 0xffff0000;
m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields),
m_fragments.push_back(
{static_cast<float>(m_last_y + m_sig_field * has_fields),
m_last_x * fhscale, pixels * fhscale, m_col}); // & mask});
}
//m_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 - 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;
@ -170,7 +185,8 @@ void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time,
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);
@ -182,7 +198,8 @@ void fixedfreq_monitor_state::update_red(const time_type &time, const double dat
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);
@ -195,7 +212,8 @@ void fixedfreq_monitor_state::update_green(const time_type &time, const double d
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);
@ -206,28 +224,32 @@ void fixedfreq_monitor_state::update_blue(const time_type &time, const double da
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::fixedfreq_device(const machine_config &mconfig,
const char *tag, device_t *owner,
uint32_t clock)
: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
{
}
@ -254,7 +276,8 @@ void fixedfreq_device::device_config_complete()
m_monitor.htotal(), m_monitor.vtotal(), 0,
m_monitor.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");
}
@ -321,10 +344,12 @@ static uint32_t nom_col(uint32_t col)
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);
| (((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;
@ -336,7 +361,8 @@ static void draw_testpat(screen_device &screen, bitmap_rgb32 &bitmap, const rect
int l = va.left() + (i * va.width() / stripes);
int 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);
// 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);
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;
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)
@ -408,20 +444,17 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
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),
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);
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,7 +465,8 @@ uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bi
void fixedfreq_device::vsync_end_cb(double refresh_time, uint32_t field)
{
const auto expected_frame_period(m_monitor.clock_period() * m_monitor.vtotal() * m_monitor.htotal());
const auto expected_frame_period(m_monitor.clock_period()
* m_monitor.vtotal() * m_monitor.htotal());
bool progressive = (m_enable->read() & 8) == 8;
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());
machine().ui().popup_time(5, "Screen Dim %d x %d\n", m.htotal(),
m.vtotal());
// ioport("YYY")->update_defvalue(true);
}

View File

@ -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,7 +94,8 @@ 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
@ -91,6 +109,7 @@ struct fixedfreq_monitor_desc
double m_gain;
int m_hscale;
double m_vsync_threshold;
private:
int m_hvisible;
int m_hfrontporch;
@ -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
@ -169,12 +190,14 @@ 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);
// 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,7 +215,8 @@ 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);
@ -224,44 +248,68 @@ struct fixedfreq_monitor_state
// ======================> 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,
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)
{
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)
fixedfreq_device &
set_vert_params(int visible, int frontporch, int sync, int backporch)
{
m_monitor.set_v_rel(
visible,
frontporch - visible,
sync - frontporch,
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;
@ -315,10 +365,8 @@ private:
/* adjustable by drivers */
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,13 +21,15 @@
/// 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"
#include "solver/nld_solver.h"
#define BODY_CONNECTED_TO_SOURCE (1)
namespace netlist::analog
@ -119,7 +121,8 @@ 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
@ -137,10 +140,14 @@ namespace netlist::analog
param_model_t::value_t m_LAMBDA; //!< Channel-length modulation [1/V]
param_model_t::value_t m_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_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")
@ -189,18 +195,20 @@ namespace netlist::analog
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();
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,10 +261,13 @@ 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();
}
@ -254,8 +277,8 @@ namespace netlist::analog
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 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());
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());
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;
@ -355,18 +380,23 @@ namespace netlist::analog
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 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;
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,
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;
@ -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,17 +461,24 @@ 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
@ -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;
@ -473,7 +518,8 @@ namespace netlist::analog
}
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
@ -486,11 +532,16 @@ namespace netlist::analog
// 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());
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;
}
@ -514,8 +565,8 @@ namespace netlist::analog
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 IeqDS = (is_forward) ?
Ids - gm * Vgs - gmb * Vbs - gds * Vds
const nl_fptype IeqDS = (is_forward)
? Ids - gm * Vgs - gmb * Vbs - gds * Vds
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
// IG = 0
@ -553,9 +604,12 @@ 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!
@ -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
{
@ -139,8 +149,8 @@ namespace netlist::detail
// 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)...);
}
@ -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)
{

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)
{
// 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,7 +56,8 @@ namespace netlist
return bool(plib::dynamic_downcast<C *>(p));
}
core_device_t *get_single_device(const pstring &classname,
core_device_t *
get_single_device(const pstring &classname,
bool (*cc)(core_device_t *)) const noexcept(false);
/// \brief Get single device filtered by class and name
@ -115,8 +117,8 @@ namespace netlist
plib::state_manager_t &run_state_manager() noexcept { return m_state; }
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);
@ -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
@ -212,8 +214,8 @@ namespace netlist
// 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();
@ -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];
}

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
@ -206,14 +206,14 @@ namespace netlist
/// \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>;
@ -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>
@ -28,18 +28,15 @@
#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__);
// 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, ...) \
@ -51,14 +48,12 @@
#define NET_C(term1, ...) \
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));
#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);
@ -69,7 +64,7 @@
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));
@ -78,8 +73,7 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
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) \
@ -87,10 +81,10 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
#define LOCAL_LIB_ENTRY(...) PCALLVARARG(LOCAL_LIB_ENTRY_, LOCAL, __VA_ARGS__)
#define 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); \
@ -104,40 +98,23 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
// 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); \
#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, pdef_params, PSOURCELOC()); \
setup.truth_table_create(desc, params, PSOURCELOC()); \
} \
static void NETLIST_NAME(cname ## _impl)([[maybe_unused]] netlist::nlparse_t &setup, netlist::tt_desc &desc) \
static void NETLIST_NAME(cname##_impl)( \
[[maybe_unused]] netlist::nlparse_t & setup, netlist::tt_desc & desc)
#endif
#define TT_HEAD(x) desc.desc.emplace_back(x);
#define TT_HEAD(x) \
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) \
@ -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);
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,9 +211,11 @@ 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>
@ -243,7 +226,8 @@ namespace netlist
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,7 +240,8 @@ 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)
@ -303,5 +288,4 @@ namespace netlist
} // 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,6 +181,9 @@ namespace netlist
// Types needed by various includes
//============================================================
namespace detail
{
/// \brief Time step type.
///
/// May be either FORWARD or RESTORE
@ -194,15 +194,6 @@ namespace netlist
RESTORE //!< restore state before last forward
};
/// \brief Delegate type for device notification.
///
using nl_delegate = plib::pmfp<void()>;
using nl_delegate_ts = plib::pmfp<void(time_step_type, nl_fptype)>;
using nl_delegate_dyn = plib::pmfp<void()>;
namespace detail
{
/// \brief Enum specifying the type of object
///
enum class terminal_type
@ -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
@ -374,8 +344,8 @@ namespace plib
/// \return absolute value of argument
///
template <typename T>
constexpr
std::enable_if_t<plib::is_integral<T>::value && plib::is_signed<T>::value, 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;
@ -388,8 +358,8 @@ namespace plib
/// \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>
constexpr std::enable_if_t<
plib::is_integral<T>::value && plib::is_unsigned<T>::value, T>
abs(T v) noexcept
{
return v;
@ -413,9 +383,7 @@ namespace plib
static_assert(plib::is_integral<M>::value, "gcd: M must be an integer");
static_assert(plib::is_integral<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
@ -430,13 +398,13 @@ namespace plib
/// \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
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>
@ -446,7 +414,8 @@ namespace plib
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,10 +7,13 @@
// 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
@ -27,7 +30,8 @@ namespace netlist::solver
{
}
void terms_for_net_t::add_terminal(terminal_t *term, int net_other, bool sorted)
void
terms_for_net_t::add_terminal(terminal_t *term, int net_other, bool sorted)
{
if (sorted)
for (std::size_t i = 0; i < m_connected_net_idx.size(); i++)
@ -35,7 +39,8 @@ namespace netlist::solver
if (m_connected_net_idx[i] > net_other)
{
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,11 +52,13 @@ namespace netlist::solver
// matrix_solver
// ----------------------------------------------------------------------------------------
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver,
const pstring &name,
const net_list_t &nets,
const 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})
: device_t(
device_data_t{main_solver.state(), main_solver.name() + "." + name})
, m_params(*params)
, m_gonn(m_arena)
, m_gtn(m_arena)
@ -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;
@ -108,7 +116,8 @@ 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);
@ -116,19 +125,24 @@ namespace netlist::solver
{
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());
@ -145,31 +159,44 @@ namespace netlist::solver
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);
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));
m_inputs.emplace_back(
std::move(net_proxy_output_u));
}
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());
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)
@ -238,20 +266,23 @@ namespace netlist::solver
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++)
{
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]);
}
}
}
break;
case matrix_sort_type_e::NOSORT:
break;
case matrix_sort_type_e::NOSORT: break;
}
// rebuild
for (auto &term : m_terms)
@ -260,7 +291,8 @@ namespace netlist::solver
for (std::size_t i = 0; i < term.count(); i++)
// 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
@ -292,7 +326,8 @@ namespace netlist::solver
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
@ -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)
@ -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());
}
}
@ -420,14 +461,16 @@ namespace netlist::solver
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();
}
}
}
@ -451,7 +494,8 @@ namespace netlist::solver
// 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)
@ -465,7 +509,8 @@ namespace netlist::solver
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();
@ -485,15 +530,18 @@ namespace netlist::solver
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++)
{
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());)
@ -533,7 +586,9 @@ namespace netlist::solver
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();
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)
{
{
//
@ -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;
}
}
@ -657,31 +724,39 @@ namespace netlist::solver
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",
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>(),
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));
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"
@ -42,6 +42,8 @@ namespace netlist::solver
CXX_STATIC
};
// clang-format off
PENUM(matrix_sort_type_e,
NOSORT,
ASCENDING,
@ -67,6 +69,8 @@ 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>>;
@ -76,8 +80,14 @@ namespace netlist::solver
// 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 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); }
@ -87,17 +97,32 @@ namespace netlist::solver
// 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 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 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; }
@ -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_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,7 +191,8 @@ 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)
{
@ -181,7 +229,6 @@ namespace netlist::solver
nl_fptype m_max_time_step;
};
class terms_for_net_t
{
public:
@ -201,17 +248,28 @@ 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;
@ -221,15 +279,18 @@ namespace netlist::solver
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; }
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
@ -245,8 +306,14 @@ namespace netlist::solver
netlist_time solve(netlist_time_ext now, const char *source);
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
@ -311,7 +385,9 @@ namespace netlist::solver
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;
@ -339,7 +415,6 @@ 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);
@ -349,10 +424,11 @@ namespace netlist::solver
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);
@ -374,7 +450,9 @@ namespace netlist::solver
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"