diff options
Diffstat (limited to 'src/lib')
151 files changed, 4620 insertions, 3524 deletions
diff --git a/src/lib/formats/apd_dsk.cpp b/src/lib/formats/apd_dsk.cpp new file mode 100644 index 00000000000..3c972c25e49 --- /dev/null +++ b/src/lib/formats/apd_dsk.cpp @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + formats/apd_dsk.c + + Archimedes Protected Disk Image format + +*********************************************************************/ + +#include <zlib.h> +#include "formats/apd_dsk.h" + +static const uint8_t APD_HEADER[8] = { 'A', 'P', 'D', 'X', '0', '0', '0', '1' }; +static const uint8_t GZ_HEADER[2] = { 0x1f, 0x8b }; + +apd_format::apd_format() +{ +} + +const char *apd_format::name() const +{ + return "apd"; +} + +const char *apd_format::description() const +{ + return "Archimedes Protected Disk Image"; +} + +const char *apd_format::extensions() const +{ + return "apd"; +} + +int apd_format::identify(io_generic *io, uint32_t form_factor) +{ + uint64_t size = io_generic_size(io); + std::vector<uint8_t> img(size); + io_generic_read(io, &img[0], 0, size); + + int err; + std::vector<uint8_t> gz_ptr(8); + z_stream d_stream; + + if (!memcmp(&img[0], GZ_HEADER, sizeof(GZ_HEADER))) { + d_stream.zalloc = nullptr; + d_stream.zfree = nullptr; + d_stream.opaque = nullptr; + d_stream.next_in = &img[0]; + d_stream.avail_in = size; + d_stream.next_out = &gz_ptr[0]; + d_stream.avail_out = 8; + + err = inflateInit2(&d_stream, MAX_WBITS | 16); + if (err != Z_OK) return 0; + + err = inflate(&d_stream, Z_SYNC_FLUSH); + if (err != Z_OK) return 0; + + err = inflateEnd(&d_stream); + if (err != Z_OK) return 0; + + img = gz_ptr; + } + + if (!memcmp(&img[0], APD_HEADER, sizeof(APD_HEADER))) { + return 100; + } + + return 0; +} + +bool apd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +{ + uint64_t size = io_generic_size(io); + std::vector<uint8_t> img(size); + io_generic_read(io, &img[0], 0, size); + + int err; + std::vector<uint8_t> gz_ptr; + z_stream d_stream; + int inflate_size = (img[size - 1] << 24) | (img[size - 2] << 16) | (img[size - 3] << 8) | img[size - 4]; + uint8_t *in_ptr = &img[0]; + + if (!memcmp(&img[0], GZ_HEADER, sizeof(GZ_HEADER))) { + gz_ptr.resize(inflate_size); + + d_stream.zalloc = nullptr; + d_stream.zfree = nullptr; + d_stream.opaque = nullptr; + d_stream.next_in = in_ptr; + d_stream.avail_in = size; + d_stream.next_out = &gz_ptr[0]; + d_stream.avail_out = inflate_size; + + err = inflateInit2(&d_stream, MAX_WBITS | 16); + if (err != Z_OK) { + LOG_FORMATS("inflateInit2 error: %d\n", err); + return false; + } + err = inflate(&d_stream, Z_FINISH); + if (err != Z_STREAM_END && err != Z_OK) { + LOG_FORMATS("inflate error: %d\n", err); + return false; + } + err = inflateEnd(&d_stream); + if (err != Z_OK) { + LOG_FORMATS("inflateEnd error: %d\n", err); + return false; + } + size = inflate_size; + img = gz_ptr; + } + + int data = 0x7d0; + for (int track = 0; track < 166; track++) { + uint32_t sdlen = little_endianize_int32(*(uint32_t *)(&img[(track * 12) + 8 + 0x0])); + uint32_t ddlen = little_endianize_int32(*(uint32_t *)(&img[(track * 12) + 8 + 0x4])); + uint32_t qdlen = little_endianize_int32(*(uint32_t *)(&img[(track * 12) + 8 + 0x8])); + + if (sdlen > 0) { + generate_track_from_bitstream(track / 2, track % 2, &img[data], sdlen, image); + data += (sdlen + 7) >> 3; + } + if (ddlen > 0) { + generate_track_from_bitstream(track / 2, track % 2, &img[data], ddlen, image); + data += (ddlen + 7) >> 3; + } + if (qdlen > 0) { + generate_track_from_bitstream(track / 2, track % 2, &img[data], qdlen, image); + data += (qdlen + 7) >> 3; + } + } + image->set_variant(floppy_image::DSDD); + + return true; +} + +bool apd_format::supports_save() const +{ + return false; +} + +const floppy_format_type FLOPPY_APD_FORMAT = &floppy_image_format_creator<apd_format>; diff --git a/src/lib/formats/apd_dsk.h b/src/lib/formats/apd_dsk.h new file mode 100644 index 00000000000..3bf40055a7b --- /dev/null +++ b/src/lib/formats/apd_dsk.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/********************************************************************* + + formats/apd_dsk.h + + Archimedes Protected Disk Image format + +*********************************************************************/ + +#ifndef APD_DSK_H_ +#define APD_DSK_H_ + +#include "flopimg.h" + +class apd_format : public floppy_image_format_t { +public: + apd_format(); + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + + virtual int identify(io_generic *io, uint32_t form_factor) override; + virtual bool load(io_generic *io, uint32_t form_factor, floppy_image *image) override; + virtual bool supports_save() const override; +}; + +extern const floppy_format_type FLOPPY_APD_FORMAT; + +#endif diff --git a/src/lib/formats/tzx_cas.cpp b/src/lib/formats/tzx_cas.cpp index 748f0227c65..7f03be7977a 100644 --- a/src/lib/formats/tzx_cas.cpp +++ b/src/lib/formats/tzx_cas.cpp @@ -8,7 +8,6 @@ TODO: Add support for the remaining block types: case 0x15: Direct Recording case 0x18: CSW Recording - case 0x19: Generalized Data Block case 0x21: Group Start case 0x22: Group End case 0x23: Jump To Block @@ -31,7 +30,7 @@ Notes: TZX format specification lists 8064 pulses for a header block and 3220 for a data block -but the documentaiton on worldofspectrum lists +but the documentation on worldofspectrum lists 8063 pulses for a header block and 3223 for a data block see http://www.worldofspectrum.org/faq/reference/48kreference.htm#TapeDataStructure @@ -315,7 +314,6 @@ static int tzx_handle_direct(int16_t **buffer, const uint8_t *bytes, int pause, tzx_output_wave(buffer, samples); size += samples; - } } @@ -342,8 +340,6 @@ static inline int tzx_handle_symbol(int16_t **buffer, const uint8_t *symtable, u uint8_t starttype = cursymb[0]; -// printf("start polarity %01x (max number of symbols is %d)\n", starttype, maxp); - switch (starttype) { case 0x00: @@ -371,7 +367,6 @@ static inline int tzx_handle_symbol(int16_t **buffer, const uint8_t *symtable, u for (int i = 0; i < maxp; i++) { uint16_t pulse_length = cursymb[1 + (i*2)] | (cursymb[2 + (i*2)] << 8); - // printf("pulse_length %04x\n", pulse_length); // shorter lists can be terminated with a pulse_length of 0 if (pulse_length != 0) @@ -380,7 +375,6 @@ static inline int tzx_handle_symbol(int16_t **buffer, const uint8_t *symtable, u tzx_output_wave(buffer, samples); size += samples; toggle_wave_data(); - } else { @@ -390,8 +384,6 @@ static inline int tzx_handle_symbol(int16_t **buffer, const uint8_t *symtable, u } } - //toggle_wave_data(); - return size; } @@ -405,7 +397,6 @@ static inline int stream_get_bit(const uint8_t *bytes, uint8_t &stream_bit, uint if (byte & 0x80) retbit = 1; - stream_bit++; if (stream_bit == 8) @@ -433,34 +424,26 @@ static int tzx_handle_generalized(int16_t **buffer, const uint8_t *bytes, int pa { uint8_t symbol = table2[i + 0]; uint16_t repetitions = table2[i + 1] + (table2[i + 2] << 8); - //printf("symbol %02x repititions %04x\n", symbol, repetitions); // does 1 mean repeat once, or that it only occurs once? + //printf("symbol %02x repetitions %04x\n", symbol, repetitions); // does 1 mean repeat once, or that it only occurs once? for (int j = 0; j < repetitions; j++) { size += tzx_handle_symbol(buffer, symtable, symbol, npp); - // toggle_wave_data(); } - - } // advance to after this data bytes += ((2 * npp + 1)*asp) + totp * 3; } - else - { - printf("no pilot block\n"); - } if (totd > 0) { - printf("data block table %04x (has %0d symbols, max symbol length is %d)\n", totd, asd, npd); + // printf("data block table %04x (has %0d symbols, max symbol length is %d)\n", totd, asd, npd); const uint8_t *symtable = bytes; const uint8_t *table2 = bytes + (2 * npd + 1)*asd; int NB = ceil(compute_log2(asd)); // number of bits needed to represent each symbol - printf("NB is %d\n", NB); uint8_t stream_bit = 0; uint32_t stream_byte = 0; @@ -475,16 +458,8 @@ static int tzx_handle_generalized(int16_t **buffer, const uint8_t *bytes, int pa } size += tzx_handle_symbol(buffer, symtable, symbol, npd); - - //toggle_wave_data(); } } - else - { - printf("no data block\n"); - } - - /* pause */ if (pause > 0) @@ -505,9 +480,7 @@ static int tzx_handle_generalized(int16_t **buffer, const uint8_t *bytes, int pa static void ascii_block_common_log( const char *block_type_string, uint8_t block_type ) { - LOG_FORMATS("%s (type %02x) encountered.\n", block_type_string, block_type); - LOG_FORMATS("This block contains info on the .tzx file you are loading.\n"); - LOG_FORMATS("Please include the following info in your bug reports, if the image has issue in M.E.S.S.\n"); + LOG_FORMATS("%s (type %02x) encountered:\n", block_type_string, block_type); } static const char *const archive_ident[] = @@ -744,20 +717,18 @@ static int tzx_cas_do_work( int16_t **buffer ) { // having this missing is fatal // used crudely by batmanc in spectrum_cass list (which is just a redundant encoding of batmane ?) - printf("Unsupported block type (0x19 - Generalized Data Block) encountered.\n"); - data_size = cur_block[1] + (cur_block[2] << 8) + (cur_block[3] << 16) + (cur_block[4] << 24); pause_time= cur_block[5] + (cur_block[6] << 8); uint32_t totp = cur_block[7] + (cur_block[8] << 8) + (cur_block[9] << 16) + (cur_block[10] << 24); int npp = cur_block[11]; int asp = cur_block[12]; - if (asp == 0) asp = 256; + if (asp == 0 && totp > 0) asp = 256; uint32_t totd = cur_block[13] + (cur_block[14] << 8) + (cur_block[15] << 16) + (cur_block[16] << 24); int npd = cur_block[17]; int asd = cur_block[18]; - if (asd == 0) asd = 256; + if (asd == 0 && totd > 0) asd = 256; size += tzx_handle_generalized(buffer, &cur_block[19], pause_time, data_size, totp, npp, asp, totd, npd, asd); @@ -840,7 +811,7 @@ static int tap_cas_to_wav_size( const uint8_t *casdata, int caslen ) { int data_size = p[0] + (p[1] << 8); int pilot_length = (p[2] == 0x00) ? 8064 : 3220; /* TZX specification */ -// int pilot_length = (p[2] == 0x00) ? 8063 : 3223; /* worldofspectrum */ +// int pilot_length = (p[2] == 0x00) ? 8063 : 3223; /* worldofspectrum */ LOG_FORMATS("tap_cas_to_wav_size: Handling TAP block containing 0x%X bytes", data_size); p += 2; size += tzx_cas_handle_block(nullptr, p, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8); @@ -859,7 +830,7 @@ static int tap_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { int data_size = bytes[0] + (bytes[1] << 8); int pilot_length = (bytes[2] == 0x00) ? 8064 : 3220; /* TZX specification */ -// int pilot_length = (bytes[2] == 0x00) ? 8063 : 3223; /* worldofspectrum */ +// int pilot_length = (bytes[2] == 0x00) ? 8063 : 3223; /* worldofspectrum */ LOG_FORMATS("tap_cas_fill_wave: Handling TAP block containing 0x%X bytes\n", data_size); bytes += 2; size += tzx_cas_handle_block(&p, bytes, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8); @@ -871,34 +842,34 @@ static int tap_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) static const struct CassetteLegacyWaveFiller tzx_legacy_fill_wave = { tzx_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tzx_cas_to_wav_size, /* chunk_sample_calc */ + -1, /* chunk_size */ + 0, /* chunk_samples */ + tzx_cas_to_wav_size, /* chunk_sample_calc */ TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + 0, /* header_samples */ + 0 /* trailer_samples */ }; static const struct CassetteLegacyWaveFiller tap_legacy_fill_wave = { tap_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tap_cas_to_wav_size, /* chunk_sample_calc */ + -1, /* chunk_size */ + 0, /* chunk_samples */ + tap_cas_to_wav_size, /* chunk_sample_calc */ TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + 0, /* header_samples */ + 0 /* trailer_samples */ }; static const struct CassetteLegacyWaveFiller cdt_legacy_fill_wave = { cdt_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tzx_cas_to_wav_size, /* chunk_sample_calc */ + -1, /* chunk_size */ + 0, /* chunk_samples */ + tzx_cas_to_wav_size, /* chunk_sample_calc */ TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + 0, /* header_samples */ + 0 /* trailer_samples */ }; static cassette_image::error tzx_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) @@ -931,7 +902,7 @@ static cassette_image::error cdt_cassette_load( cassette_image *cassette ) return cassette_legacy_construct(cassette, &cdt_legacy_fill_wave); } -static const struct CassetteFormat tzx_cassette_format = +const struct CassetteFormat tzx_cassette_format = { "tzx", tzx_cassette_identify, diff --git a/src/lib/formats/tzx_cas.h b/src/lib/formats/tzx_cas.h index 8610fb0cdd4..2db31245310 100644 --- a/src/lib/formats/tzx_cas.h +++ b/src/lib/formats/tzx_cas.h @@ -12,6 +12,8 @@ #include "cassimg.h" +extern const struct CassetteFormat tzx_cassette_format; + CASSETTE_FORMATLIST_EXTERN(tzx_cassette_formats); CASSETTE_FORMATLIST_EXTERN(cdt_cassette_formats); diff --git a/src/lib/formats/zx81_p.cpp b/src/lib/formats/zx81_p.cpp index 7f359ccaca3..9fa5814385f 100644 --- a/src/lib/formats/zx81_p.cpp +++ b/src/lib/formats/zx81_p.cpp @@ -34,6 +34,7 @@ medium transfer rate is approx. 307 bps (38 bytes/sec) for files that contain #include <assert.h> #include "zx81_p.h" +#include "tzx_cas.h" #define WAVEENTRY_LOW -32768 @@ -197,13 +198,13 @@ static int zx81_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) static const struct CassetteLegacyWaveFiller zx81_legacy_fill_wave = { - zx81_cassette_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ + zx81_cassette_fill_wave, /* fill_wave */ + -1, /* chunk_size */ + 0, /* chunk_samples */ zx81_cassette_calculate_size_in_samples, /* chunk_sample_calc */ - ZX81_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + ZX81_WAV_FREQUENCY, /* sample_frequency */ + 0, /* header_samples */ + 0 /* trailer_samples */ }; static cassette_image::error zx81_p_identify(cassette_image *cassette, struct CassetteOptions *opts) @@ -233,6 +234,11 @@ CASSETTE_FORMATLIST_START(zx81_p_format) CASSETTE_FORMAT(zx81_p_image_format) CASSETTE_FORMATLIST_END +CASSETTE_FORMATLIST_START(zx81_cassette_formats) + CASSETTE_FORMAT(zx81_p_image_format) + CASSETTE_FORMAT(tzx_cassette_format) +CASSETTE_FORMATLIST_END + /* ZX-80 functions */ static int zx80_cassette_calculate_size_in_samples(const uint8_t *bytes, int length) @@ -265,11 +271,11 @@ static int zx80_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) static const struct CassetteLegacyWaveFiller zx80_legacy_fill_wave = { - zx80_cassette_fill_wave, /* fill_wave */ + zx80_cassette_fill_wave, /* fill_wave */ -1, /* chunk_size */ 0, /* chunk_samples */ zx80_cassette_calculate_size_in_samples, /* chunk_sample_calc */ - ZX81_WAV_FREQUENCY, /* sample_frequency */ + ZX81_WAV_FREQUENCY, /* sample_frequency */ 0, /* header_samples */ 0 /* trailer_samples */ }; diff --git a/src/lib/formats/zx81_p.h b/src/lib/formats/zx81_p.h index 16a1b22724d..36da808c989 100644 --- a/src/lib/formats/zx81_p.h +++ b/src/lib/formats/zx81_p.h @@ -14,6 +14,7 @@ #include "cassimg.h" CASSETTE_FORMATLIST_EXTERN(zx81_p_format); +CASSETTE_FORMATLIST_EXTERN(zx81_cassette_formats); CASSETTE_FORMATLIST_EXTERN(zx80_o_format); #endif /* ZX81_P_H */ diff --git a/src/lib/netlist/analog/nld_bjt.cpp b/src/lib/netlist/analog/nld_bjt.cpp index 0acd0887e74..e40fbfa366d 100644 --- a/src/lib/netlist/analog/nld_bjt.cpp +++ b/src/lib/netlist/analog/nld_bjt.cpp @@ -6,13 +6,16 @@ */ #include "solver/nld_solver.h" -#include "analog/nld_bjt.h" +#include "analog/nlid_twoterm.h" #include "nl_setup.h" +#include <cmath> + namespace netlist { namespace analog { + class diode { public: @@ -40,6 +43,240 @@ private: nl_double m_VT_inv; }; +// ----------------------------------------------------------------------------- +// nld_Q - Base classes +// ----------------------------------------------------------------------------- + + /*! Class representing the bjt model paramers. + * + * This is the model representation of the bjt model. Typically, SPICE uses + * the following parameters. A "Y" in the first column indicates that the + * parameter is actually used in netlist. + * + * | NL? | name | parameter | units | default | example | area | + * |:---:|------|-----------------------------------------------------------------------|-------|---------:|----------------:|:----:| + * | Y | IS | transport saturation current | A | 1E-016 | 1E-015 | * | + * | Y | BF | ideal maximum forward beta | - | 100 | 100 | | + * | Y | NF | forward current emission coefficient | - | 1 | 1 | | + * | | VAF | forward Early voltage | V | infinite | 200 | | + * | | IKF | corner for forward beta high current roll-off | A | infinite | 0.01 | * | + * | | ISE | B-E leakage saturation current | A | 0 | 0.0000000000001 | * | + * | | NE | B-E leakage emission coefficient | - | 1.5 | 2 | | + * | Y | BR | ideal maximum reverse beta | - | 1 | 0.1 | | + * | Y | NR | reverse current emission coefficient | - | 1 | 1 | | + * | | VAR | reverse Early voltage | V | infinite | 200 | | + * | | IKR | corner for reverse beta high current roll-off | A | infinite | 0.01 | * | + * | | ISC | leakage saturation current | A | 0 | 8 | | + * | | NC | leakage emission coefficient | - | 2 | 1.5 | | + * | | RB | zero bias base resistance | | 0 | 100 | * | + * | | IRB | current where base resistance falls halfway to its min value | A | infinte | 0.1 | * | + * | | RBM | minimum base resistance at high currents | | RB | 10 | * | + * | | RE | emitter resistance | | 0 | 1 | * | + * | | RC | collector resistance | | 0 | 10 | * | + * | | CJE | B-E zero-bias depletion capacitance | F | 0 | 2pF | * | + * | | VJE | B-E built-in potential | V | 0.75 | 0.6 | | + * | | MJE | B-E junction exponential factor | - | 0.33 | 0.33 | | + * | | TF | ideal forward transit time | sec | 0 | 0.1ns | | + * | | XTF | coefficient for bias dependence of TF | - | 0 | | | + * | | VTF | voltage describing VBC dependence of TF | V | infinite | | | + * | | ITF | high-current parameter for effect on TF | A | 0 | | * | + * | | PTF | excess phase at freq=1.0/(TF*2PI) Hz | deg | 0 | | | + * | | CJC | B-C zero-bias depletion capacitance | F | 0 | 2pF | * | + * | | VJC | B-C built-in potential | V | 0.75 | 0.5 | | + * | | MJC | B-C junction exponential factor | - | 0.33 | 0.5 | | + * | | XCJC | fraction of B-C depletion capacitance connected to internal base node | - | 1 | | | + * | | TR | ideal reverse transit time | sec | 0 | 10ns | | + * | | CJS | zero-bias collector-substrate capacitance | F | 0 | 2pF | * | + * | | VJS | substrate junction built-in potential | V | 0.75 | | | + * | | MJS | substrate junction exponential factor | - | 0 | 0.5 | | + * | | XTB | forward and reverse beta temperature exponent | - | 0 | | | + * | | EG | energy gap for temperature effect on IS | eV | 1.11 | | | + * | | XTI | temperature exponent for effect on IS | - | 3 | | | + * | | KF | flicker-noise coefficient | - | 0 | | | + * | | AF | flicker-noise exponent | - | 1 | | | + * | | FC | coefficient for forward-bias depletion capacitance formula | - | 0.5 | | | + * | | TNOM | Parameter measurement temperature | C | 27 | 50 | | */ + + class bjt_model_t : public param_model_t + { + public: + bjt_model_t(device_t &device, const pstring name, const pstring val) + : param_model_t(device, name, val) + , m_IS(*this, "IS") + , m_BF(*this, "BF") + , m_NF(*this, "NF") + , m_BR(*this, "BR") + , m_NR(*this, "NR") + {} + + value_t m_IS; //!< transport saturation current + value_t m_BF; //!< ideal maximum forward beta + value_t m_NF; //!< forward current emission coefficient + value_t m_BR; //!< ideal maximum reverse beta + value_t m_NR; //!< reverse current emission coefficient + }; + + // Have a common start for transistors + +NETLIB_OBJECT(Q) +{ +public: + enum q_type { + BJT_NPN, + BJT_PNP + }; + + NETLIB_CONSTRUCTOR(Q) + , m_model(*this, "MODEL", "") + , m_qtype(BJT_NPN) + { + } + + NETLIB_IS_DYNAMIC(true) + + //NETLIB_RESETI(); + NETLIB_UPDATEI(); + + inline q_type qtype() const { return m_qtype; } + inline bool is_qtype(q_type atype) const { return m_qtype == atype; } + inline void set_qtype(q_type atype) { m_qtype = atype; } +protected: + + bjt_model_t m_model; +private: + q_type m_qtype; +}; + +NETLIB_OBJECT_DERIVED(QBJT, Q) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(QBJT, Q) + { } + +protected: + +private: +}; + + + + +// ----------------------------------------------------------------------------- +// nld_QBJT_switch +// ----------------------------------------------------------------------------- + + +/* + * + - C + * B ----VVV----+ | + * | | + * Rb Rc + * Rb Rc + * Rb Rc + * | | + * +----+----+ + * | + * E + */ + +NETLIB_OBJECT_DERIVED(QBJT_switch, QBJT) +{ + NETLIB_CONSTRUCTOR_DERIVED(QBJT_switch, QBJT) + , m_RB(*this, "m_RB", true) + , m_RC(*this, "m_RC", true) + , m_BC_dummy(*this, "m_BC", true) + , m_gB(NETLIST_GMIN_DEFAULT) + , m_gC(NETLIST_GMIN_DEFAULT) + , m_V(0.0) + , m_state_on(*this, "m_state_on", 0) + { + register_subalias("B", m_RB.m_P); + register_subalias("E", m_RB.m_N); + register_subalias("C", m_RC.m_P); + //register_term("_E1", m_RC.m_N); + + //register_term("_B1", m_BC_dummy.m_P); + //register_term("_C1", m_BC_dummy.m_N); + + connect(m_RB.m_N, m_RC.m_N); + + connect(m_RB.m_P, m_BC_dummy.m_P); + connect(m_RC.m_P, m_BC_dummy.m_N); + } + + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + NETLIB_UPDATE_TERMINALSI(); + + nld_twoterm m_RB; + nld_twoterm m_RC; + + // FIXME: this is needed so we have all terminals belong to one net list + + nld_twoterm m_BC_dummy; + +protected: + + + nl_double m_gB; // base conductance / switch on + nl_double m_gC; // collector conductance / switch on + nl_double m_V; // internal voltage source + state_var<unsigned> m_state_on; + +private: +}; + +// ----------------------------------------------------------------------------- +// nld_QBJT_EB +// ----------------------------------------------------------------------------- + + +NETLIB_OBJECT_DERIVED(QBJT_EB, QBJT) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(QBJT_EB, QBJT) + , m_gD_BC(*this, "m_D_BC") + , m_gD_BE(*this, "m_D_BE") + , m_D_CB(*this, "m_D_CB", true) + , m_D_EB(*this, "m_D_EB", true) + , m_D_EC(*this, "m_D_EC", true) + , m_alpha_f(0) + , m_alpha_r(0) + { + register_subalias("E", m_D_EB.m_P); // Cathode + register_subalias("B", m_D_EB.m_N); // Anode + + register_subalias("C", m_D_CB.m_P); // Cathode + //register_term("_B1", m_D_CB.m_N); // Anode + + //register_term("_E1", m_D_EC.m_P); + //register_term("_C1", m_D_EC.m_N); + + connect(m_D_EB.m_P, m_D_EC.m_P); + connect(m_D_EB.m_N, m_D_CB.m_N); + connect(m_D_CB.m_P, m_D_EC.m_N); + } + +protected: + + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + NETLIB_UPDATE_TERMINALSI(); + + generic_diode m_gD_BC; + generic_diode m_gD_BE; + +private: + nld_twoterm m_D_CB; // gcc, gce - gcc, gec - gcc, gcc - gce | Ic + nld_twoterm m_D_EB; // gee, gec - gee, gce - gee, gee - gec | Ie + nld_twoterm m_D_EC; // 0, -gec, -gcc, 0 | 0 + + nl_double m_alpha_f; + nl_double m_alpha_r; + +}; // ---------------------------------------------------------------------------------------- @@ -122,8 +359,6 @@ NETLIB_UPDATE_TERMINALS(QBJT_switch) m_RB.set(gb, v, 0.0); m_RC.set(gc, 0.0, 0.0); - //m_RB.update_dev(); - //m_RC.update_dev(); m_state_on = new_state; } } @@ -166,11 +401,11 @@ NETLIB_UPDATE_TERMINALS(QBJT_EB) const nl_double Ic = (sIc - gce * m_gD_BE.Vd() + gcc * m_gD_BC.Vd()) * polarity; m_D_EB.set_mat( gee, gec - gee, -Ie, - gce - gee, gee - gec, Ie); + gce - gee, gee - gec, Ie); m_D_CB.set_mat( gcc, gce - gcc, -Ic, - gec - gcc, gcc - gce, Ic); + gec - gcc, gcc - gce, Ic); m_D_EC.set_mat( 0, -gec, 0, - -gce, 0, 0); + -gce, 0, 0); } @@ -192,5 +427,11 @@ NETLIB_UPDATE_PARAM(QBJT_EB) m_gD_BC.set_param(IS / m_alpha_r, NR, netlist().gmin()); } - } //namespace devices + } //namespace analog + + namespace devices { + NETLIB_DEVICE_IMPL_NS(analog, QBJT_EB) + NETLIB_DEVICE_IMPL_NS(analog, QBJT_switch) + } + } // namespace netlist diff --git a/src/lib/netlist/analog/nld_bjt.h b/src/lib/netlist/analog/nld_bjt.h index a4e163b13bc..5e40bd1ef36 100644 --- a/src/lib/netlist/analog/nld_bjt.h +++ b/src/lib/netlist/analog/nld_bjt.h @@ -8,8 +8,7 @@ #ifndef NLD_BJT_H_ #define NLD_BJT_H_ -#include "nl_base.h" -#include "nld_twoterm.h" +#include "nl_setup.h" // ----------------------------------------------------------------------------- // Macros @@ -23,249 +22,4 @@ NET_REGISTER_DEV(QBJT_EB, name) \ NETDEV_PARAMI(name, MODEL, model) - -namespace netlist -{ - namespace analog - { -// ----------------------------------------------------------------------------- -// nld_Q - Base classes -// ----------------------------------------------------------------------------- - - /* FIXME: Make table pretty */ - - /*! Class representing the bjt model paramers. - * This is the model representation of the bjt model. Typically, SPICE uses - * the following parameters. A "Y" in the first column indicates that the - * parameter is actually used in netlist. - * - * |NL? |name |parameter |units|default| example|area | - * |:--:|:-----|:--------------------------------|:----|------:|-------:|:----:| - * | Y |IS |transport saturation current|A |1E-016|1E-015|* | - * | Y |BF |ideal maximum forward beta|- |100|100| | - * | Y |NF |forward current emission coefficient|- |1|1| | - * | |VAF |forward Early voltage|V |infinite |200| | - * | |IKF |corner for forward beta high current roll-off|A |infinite |0.01|* | - * | |ISE |B-E leakage saturation current|A |0|0.0000000000001|* | - * | |NE |B-E leakage emission coefficient|- |1.5|2| | - * | Y |BR |ideal maximum reverse beta |- |1|0.1| | - * | Y |NR |reverse current emission coefficient|- |1|1| | - * | |VAR |reverse Early voltage|V |infinite |200| | - * | |IKR |corner for reverse beta high current roll-off|A |infinite |0.01|* | - * | |ISC |leakage saturation current|A |0|8| | - * | |NC |leakage emission coefficient|- |2|1.5| | - * | |RB |zero bias base resistance| |0|100|* | - * | |IRB |current where base resistance falls halfway to its min value|A |infinte |0.1|* | - * | |RBM |minimum base resistance at high currents| |RB |10|* | - * | |RE |emitter resistance| |0|1|* | - * | |RC |collector resistance | |0|10|* | - * | |CJE |B-E zero-bias depletion capacitance|F |0|2pF |* | - * | |VJE |B-E built-in potential|V |0.75|0.6| | - * | |MJE |B-E junction exponential factor |- |0.33|0.33| | - * | |TF |ideal forward transit time |sec |0|0.1ns | | - * | |XTF|coefficient for bias dependence of TF |- |0| | | - * | |VTF |voltage describing VBC dependence of TF |V |infinite | | | - * | |ITF |high-current parameter for effect on TF |A |0| |* | - * | |PTF |excess phase at freq=1.0/(TF*2PI) Hz |deg |0| | | - * | |CJC |B-C zero-bias depletion capacitance |F |0|2pF |* | - * | |VJC |B-C built-in potential |V |0.75|0.5| | - * | |MJC |B-C junction exponential factor |- |0.33|0.5| | - * | |XCJC |fraction of B-C depletion capacitance connected to internal base node |- |1| | | - * | |TR |ideal reverse transit time |sec |0|10ns | | - * | |CJS |zero-bias collector-substrate capacitance |F |0|2pF |* | - * | |VJS |substrate junction built-in potential |V |0.75| | | - * | |MJS |substrate junction exponential factor |- |0|0.5| | - * | |XTB |forward and reverse beta temperature exponent |- |0| | | - * | |EG|energy gap for temperature effect on IS |eV |1.11| | | - * | |XTI|temperature exponent for effect on IS |- |3| | | - * | |KF |flicker-noise coefficient |- |0| | | - * | |AF |flicker-noise exponent |- |1| | | - * | |FC |coefficient for forward-bias depletion capacitance formula |- |0.5| | | - * | |TNOM |Parameter measurement temperature |C |27|50| | - */ - - class bjt_model_t : public param_model_t - { - public: - bjt_model_t(device_t &device, const pstring name, const pstring val) - : param_model_t(device, name, val) - , m_IS(*this, "IS") - , m_BF(*this, "BF") - , m_NF(*this, "NF") - , m_BR(*this, "BR") - , m_NR(*this, "NR") - {} - - value_t m_IS; //!< transport saturation current - value_t m_BF; //!< ideal maximum forward beta - value_t m_NF; //!< forward current emission coefficient - value_t m_BR; //!< ideal maximum reverse beta - value_t m_NR; //!< reverse current emission coefficient - }; - - // Have a common start for transistors - -NETLIB_OBJECT(Q) -{ -public: - enum q_type { - BJT_NPN, - BJT_PNP - }; - - NETLIB_CONSTRUCTOR(Q) - , m_model(*this, "MODEL", "") - , m_qtype(BJT_NPN) - { - } - - NETLIB_IS_DYNAMIC() - - //NETLIB_RESETI(); - NETLIB_UPDATEI(); - - inline q_type qtype() const { return m_qtype; } - inline bool is_qtype(q_type atype) const { return m_qtype == atype; } - inline void set_qtype(q_type atype) { m_qtype = atype; } -protected: - - bjt_model_t m_model; -private: - q_type m_qtype; -}; - -NETLIB_OBJECT_DERIVED(QBJT, Q) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(QBJT, Q) - { } - -protected: - -private: -}; - - - - -// ----------------------------------------------------------------------------- -// nld_QBJT_switch -// ----------------------------------------------------------------------------- - - -/* - * + - C - * B ----VVV----+ | - * | | - * Rb Rc - * Rb Rc - * Rb Rc - * | | - * +----+----+ - * | - * E - */ - -NETLIB_OBJECT_DERIVED(QBJT_switch, QBJT) -{ - NETLIB_CONSTRUCTOR_DERIVED(QBJT_switch, QBJT) - , m_RB(*this, "m_RB", true) - , m_RC(*this, "m_RC", true) - , m_BC_dummy(*this, "m_BC", true) - , m_gB(NETLIST_GMIN_DEFAULT) - , m_gC(NETLIST_GMIN_DEFAULT) - , m_V(0.0) - , m_state_on(*this, "m_state_on", 0) - { - register_subalias("B", m_RB.m_P); - register_subalias("E", m_RB.m_N); - register_subalias("C", m_RC.m_P); - //register_term("_E1", m_RC.m_N); - - //register_term("_B1", m_BC_dummy.m_P); - //register_term("_C1", m_BC_dummy.m_N); - - connect(m_RB.m_N, m_RC.m_N); - - connect(m_RB.m_P, m_BC_dummy.m_P); - connect(m_RC.m_P, m_BC_dummy.m_N); - } - - NETLIB_RESETI(); - NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI(); - NETLIB_UPDATE_TERMINALSI(); - - nld_twoterm m_RB; - nld_twoterm m_RC; - - // FIXME: this is needed so we have all terminals belong to one net list - - nld_twoterm m_BC_dummy; - -protected: - - - nl_double m_gB; // base conductance / switch on - nl_double m_gC; // collector conductance / switch on - nl_double m_V; // internal voltage source - state_var<unsigned> m_state_on; - -private: -}; - -// ----------------------------------------------------------------------------- -// nld_QBJT_EB -// ----------------------------------------------------------------------------- - - -NETLIB_OBJECT_DERIVED(QBJT_EB, QBJT) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(QBJT_EB, QBJT) - , m_gD_BC(*this, "m_D_BC") - , m_gD_BE(*this, "m_D_BE") - , m_D_CB(*this, "m_D_CB", true) - , m_D_EB(*this, "m_D_EB", true) - , m_D_EC(*this, "m_D_EC", true) - , m_alpha_f(0) - , m_alpha_r(0) - { - register_subalias("E", m_D_EB.m_P); // Cathode - register_subalias("B", m_D_EB.m_N); // Anode - - register_subalias("C", m_D_CB.m_P); // Cathode - //register_term("_B1", m_D_CB.m_N); // Anode - - //register_term("_E1", m_D_EC.m_P); - //register_term("_C1", m_D_EC.m_N); - - connect(m_D_EB.m_P, m_D_EC.m_P); - connect(m_D_EB.m_N, m_D_CB.m_N); - connect(m_D_CB.m_P, m_D_EC.m_N); - } - -protected: - - NETLIB_RESETI(); - NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI(); - NETLIB_UPDATE_TERMINALSI(); - - generic_diode m_gD_BC; - generic_diode m_gD_BE; - -private: - nld_twoterm m_D_CB; // gcc, gce - gcc, gec - gcc, gcc - gce | Ic - nld_twoterm m_D_EB; // gee, gec - gee, gce - gee, gee - gec | Ie - nld_twoterm m_D_EC; // 0, -gec, -gcc, 0 | 0 - - nl_double m_alpha_f; - nl_double m_alpha_r; - -}; - - } //namespace devices -} // namespace netlist - #endif /* NLD_BJT_H_ */ diff --git a/src/lib/netlist/analog/nld_fourterm.h b/src/lib/netlist/analog/nld_fourterm.h index 0e4bcc03429..bd420b8cfa9 100644 --- a/src/lib/netlist/analog/nld_fourterm.h +++ b/src/lib/netlist/analog/nld_fourterm.h @@ -9,8 +9,7 @@ #define NLD_FOURTERM_H_ -#include "nl_base.h" -#include "nld_twoterm.h" +#include "nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros @@ -28,204 +27,4 @@ #define LVCCS(name) \ NET_REGISTER_DEV(LVCCS, name) -namespace netlist -{ - namespace analog - { -// ---------------------------------------------------------------------------------------- -// nld_VCCS -// ---------------------------------------------------------------------------------------- - -/* - * Voltage controlled current source - * - * IP ---+ +------> OP - * | | - * RI I - * RI => G => I IOut = (V(IP)-V(IN)) * G - * RI I - * | | - * IN ---+ +------< ON - * - * G=1 ==> 1V ==> 1A - * - * RI = 1 / NETLIST_GMIN - * - */ - -NETLIB_OBJECT(VCCS) -{ -public: - NETLIB_CONSTRUCTOR(VCCS) - , m_G(*this, "G", 1.0) - , m_RI(*this, "RI", 1e9) - , m_OP(*this, "OP") - , m_ON(*this, "ON") - , m_IP(*this, "IP") - , m_IN(*this, "IN") - , m_OP1(*this, "_OP1") - , m_ON1(*this, "_ON1") - , m_gfac(1.0) - { - m_IP.m_otherterm = &m_IN; // <= this should be NULL and terminal be filtered out prior to solving... - m_IN.m_otherterm = &m_IP; // <= this should be NULL and terminal be filtered out prior to solving... - - m_OP.m_otherterm = &m_IP; - m_OP1.m_otherterm = &m_IN; - - m_ON.m_otherterm = &m_IP; - m_ON1.m_otherterm = &m_IN; - - connect(m_OP, m_OP1); - connect(m_ON, m_ON1); - m_gfac = NL_FCONST(1.0); - } - - param_double_t m_G; - param_double_t m_RI; - -protected: - NETLIB_RESETI(); - NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI() - { - NETLIB_NAME(VCCS)::reset(); - } - - terminal_t m_OP; - terminal_t m_ON; - - terminal_t m_IP; - terminal_t m_IN; - - terminal_t m_OP1; - terminal_t m_ON1; - - nl_double m_gfac; -}; - -/* Limited Current source*/ - -NETLIB_OBJECT_DERIVED(LVCCS, VCCS) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(LVCCS, VCCS) - , m_cur_limit(*this, "CURLIM", 1000.0) - , m_vi(0.0) - { - } - - NETLIB_IS_DYNAMIC() - - param_double_t m_cur_limit; /* current limit */ - -protected: - NETLIB_UPDATEI(); - NETLIB_RESETI(); - NETLIB_UPDATE_PARAMI(); - NETLIB_UPDATE_TERMINALSI(); - - nl_double m_vi; -}; - -// ---------------------------------------------------------------------------------------- -// nld_CCCS -// ---------------------------------------------------------------------------------------- - -/* - * Current controlled current source - * - * IP ---+ +------> OP - * | | - * RI I - * RI => G => I IOut = (V(IP)-V(IN)) / RI * G - * RI I - * | | - * IN ---+ +------< ON - * - * G=1 ==> 1A ==> 1A - * - * RI = 1 - * - * This needs high levels of accuracy to work with 1 Ohm RI. - * - */ - -NETLIB_OBJECT_DERIVED(CCCS, VCCS) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(CCCS, VCCS) - , m_gfac(1.0) - { - m_gfac = NL_FCONST(1.0) / m_RI(); - } - -protected: - NETLIB_UPDATEI(); - NETLIB_RESETI(); - NETLIB_UPDATE_PARAMI(); - - nl_double m_gfac; -}; - - -// ---------------------------------------------------------------------------------------- -// nld_VCVS -// ---------------------------------------------------------------------------------------- - -/* - * Voltage controlled voltage source - * - * Parameters: - * G Default: 1 - * RO Default: 1 (would be typically 50 for an op-amp - * - * IP ---+ +--+---- OP - * | | | - * RI I RO - * RI => G => I RO V(OP) - V(ON) = (V(IP)-V(IN)) * G - * RI I RO - * | | | - * IN ---+ +--+---- ON - * - * G=1 ==> 1V ==> 1V - * - * RI = 1 / NETLIST_GMIN - * - * Internal GI = G / RO - * - */ - - -NETLIB_OBJECT_DERIVED(VCVS, VCCS) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(VCVS, VCCS) - , m_RO(*this, "RO", 1.0) - , m_OP2(*this, "_OP2") - , m_ON2(*this, "_ON2") - { - m_OP2.m_otherterm = &m_ON2; - m_ON2.m_otherterm = &m_OP2; - - connect(m_OP2, m_OP1); - connect(m_ON2, m_ON1); - } - - param_double_t m_RO; - -protected: - //NETLIB_UPDATEI(); - NETLIB_RESETI(); - //NETLIB_UPDATE_PARAMI(); - - terminal_t m_OP2; - terminal_t m_ON2; - -}; - - } //namespace devices -} // namespace netlist - - #endif /* NLD_FOURTERM_H_ */ diff --git a/src/lib/netlist/analog/nld_opamps.cpp b/src/lib/netlist/analog/nld_opamps.cpp index e777ffb791c..64f6b1b6df9 100644 --- a/src/lib/netlist/analog/nld_opamps.cpp +++ b/src/lib/netlist/analog/nld_opamps.cpp @@ -6,9 +6,14 @@ */ #include "nld_opamps.h" -#include "devices/net_lib.h" +#include "nl_base.h" +#include "nl_errstr.h" +#include "nlid_twoterm.h" +#include "nlid_fourterm.h" +#include <cmath> + namespace netlist { namespace analog @@ -42,6 +47,61 @@ namespace netlist * * */ + /*! Class representing the opamp model parameters. + * The opamp model was designed based on designs from + * http://www.ecircuitcenter.com/Circuits/opmodel1/opmodel1.htm. + * Currently 2 different types are supported: Type 1 and Type 3. Type 1 + * is less complex and should run faster than Type 3. + * + * This is an extension to the traditional SPICE approach which + * assumes that you will be using an manufacturer model. These models may + * have copyrights incompatible with the netlist license. Thus they may not + * be suitable for certain implementations of netlist. + * + * For the typical use cases in low frequency (< 100 KHz) applications at + * which netlist is targeted, this model is certainly suitable. All parameters + * can be determined from a typical opamp datasheet. + * + * |Type|name |parameter |units|default| example| + * |:--:|:-----|:----------------------------------------------|:----|------:|-------:| + * | 3 |TYPE |Model Type, 1 and 3 are supported | | | | + * |1,3 |FPF |frequency of first pole |Hz | |100 | + * | 3 |SLEW |unity gain slew rate |V/s | | 1| + * |1,3 |RI |input resistance |Ohm | |1M | + * |1,3 |RO |output resistance |Ohm | |50 | + * |1,3 |UGF |unity gain frequency (transition frequency) |Hz | |1000 | + * | 3 |VLL |low output swing minus low supply rail |V | |1.5 | + * | 3 |VLH |high supply rail minus high output swing |V | |1.5 | + * | 3 |DAB |Differential Amp Bias - total quiescent current|A | |0.001 | + */ + + class opamp_model_t : public param_model_t + { + public: + opamp_model_t(device_t &device, const pstring name, const pstring val) + : param_model_t(device, name, val) + , m_TYPE(*this, "TYPE") + , m_FPF(*this, "FPF") + , m_SLEW(*this, "SLEW") + , m_RI(*this, "RI") + , m_RO(*this, "RO") + , m_UGF(*this, "UGF") + , m_VLL(*this, "VLL") + , m_VLH(*this, "VLH") + , m_DAB(*this, "DAB") + {} + + value_t m_TYPE; //!< Model Type, 1 and 3 are supported + value_t m_FPF; //!< frequency of first pole + value_t m_SLEW; //!< unity gain slew rate + value_t m_RI; //!< input resistance + value_t m_RO; //!< output resistance + value_t m_UGF; //!< unity gain frequency (transition frequency) + value_t m_VLL; //!< low output swing minus low supply rail + value_t m_VLH; //!< high supply rail minus high output swing + value_t m_DAB; //!< Differential Amp Bias - total quiescent current + }; + NETLIB_OBJECT(opamp) { @@ -99,7 +159,7 @@ namespace netlist connect("EBUF.IP", "RP1.1"); } else - netlist().log().fatal("Unknown opamp type: {1}", m_type); + log().fatal(MF_1_UNKNOWN_OPAMP_TYPE, m_type); } diff --git a/src/lib/netlist/analog/nld_opamps.h b/src/lib/netlist/analog/nld_opamps.h index b407bb2215e..31b883be688 100644 --- a/src/lib/netlist/analog/nld_opamps.h +++ b/src/lib/netlist/analog/nld_opamps.h @@ -10,10 +10,7 @@ #ifndef NLD_OPAMPS_H_ #define NLD_OPAMPS_H_ -#include "nl_base.h" #include "nl_setup.h" -#include "nld_twoterm.h" -#include "nld_fourterm.h" // ---------------------------------------------------------------------------------------- // Macros @@ -23,72 +20,5 @@ NET_REGISTER_DEV(OPAMP, name) \ NETDEV_PARAMI(name, MODEL, model) -// ---------------------------------------------------------------------------------------- -// Devices ... -// ---------------------------------------------------------------------------------------- - -namespace netlist -{ - namespace analog - { - - /*! Class representing the opamp model parameters. - * The opamp model was designed based on designs from - * http://www.ecircuitcenter.com/Circuits/opmodel1/opmodel1.htm. - * Currently 2 different types are supported: Type 1 and Type 3. Type 1 - * is less complex and should run faster than Type 3. - * - * This is an extension to the traditional SPICE approach which - * assumes that you will be using an manufacturer model. These models may - * have copyrights incompatible with the netlist license. Thus they may not - * be suitable for certain implementations of netlist. - * - * For the typical use cases in low frequency (< 100 KHz) applications at - * which netlist is targeted, this model is certainly suitable. All parameters - * can be determined from a typical opamp datasheet. - * - * |Type|name |parameter |units|default| example| - * |:--:|:-----|:----------------------------------------------|:----|------:|-------:| - * | 3 |TYPE |Model Type, 1 and 3 are supported | | | | - * |1,3 |FPF |frequency of first pole |Hz | |100 | - * | 3 |SLEW |unity gain slew rate |V/s | | 1| - * |1,3 |RI |input resistance |Ohm | |1M | - * |1,3 |RO |output resistance |Ohm | |50 | - * |1,3 |UGF |unity gain frequency (transition frequency) |Hz | |1000 | - * | 3 |VLL |low output swing minus low supply rail |V | |1.5 | - * | 3 |VLH |high supply rail minus high output swing |V | |1.5 | - * | 3 |DAB |Differential Amp Bias - total quiescent current|A | |0.001 | - */ - - class opamp_model_t : public param_model_t - { - public: - opamp_model_t(device_t &device, const pstring name, const pstring val) - : param_model_t(device, name, val) - , m_TYPE(*this, "TYPE") - , m_FPF(*this, "FPF") - , m_SLEW(*this, "SLEW") - , m_RI(*this, "RI") - , m_RO(*this, "RO") - , m_UGF(*this, "UGF") - , m_VLL(*this, "VLL") - , m_VLH(*this, "VLH") - , m_DAB(*this, "DAB") - {} - - value_t m_TYPE; //!< Model Type, 1 and 3 are supported - value_t m_FPF; //!< frequency of first pole - value_t m_SLEW; //!< unity gain slew rate - value_t m_RI; //!< input resistance - value_t m_RO; //!< output resistance - value_t m_UGF; //!< unity gain frequency (transition frequency) - value_t m_VLL; //!< low output swing minus low supply rail - value_t m_VLH; //!< high supply rail minus high output swing - value_t m_DAB; //!< Differential Amp Bias - total quiescent current - }; - - - } //namespace analog -} // namespace netlist #endif /* NLD_OPAMPS_H_ */ diff --git a/src/lib/netlist/analog/nld_switches.cpp b/src/lib/netlist/analog/nld_switches.cpp index 92afa752e86..bf92a8cf4f8 100644 --- a/src/lib/netlist/analog/nld_switches.cpp +++ b/src/lib/netlist/analog/nld_switches.cpp @@ -5,8 +5,9 @@ * */ -#include "nld_switches.h" -#include "nl_setup.h" +#include "nlid_twoterm.h" +#include "nl_base.h" +#include "nl_factory.h" #define R_OFF (1.0 / netlist().gmin()) #define R_ON 0.01 diff --git a/src/lib/netlist/analog/nld_switches.h b/src/lib/netlist/analog/nld_switches.h index d91cf775377..06af3fad0ca 100644 --- a/src/lib/netlist/analog/nld_switches.h +++ b/src/lib/netlist/analog/nld_switches.h @@ -10,8 +10,7 @@ #ifndef NLD_SWITCHES_H_ #define NLD_SWITCHES_H_ -#include "nl_base.h" -#include "nld_twoterm.h" +#include "nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros @@ -23,5 +22,4 @@ #define SWITCH2(name) \ NET_REGISTER_DEV(SWITCH2, name) - #endif /* NLD_SWITCHES_H_ */ diff --git a/src/lib/netlist/analog/nld_twoterm.h b/src/lib/netlist/analog/nld_twoterm.h index 06325679dff..3ffbafd3b51 100644 --- a/src/lib/netlist/analog/nld_twoterm.h +++ b/src/lib/netlist/analog/nld_twoterm.h @@ -1,39 +1,10 @@ // license:GPL-2.0+ // copyright-holders:Couriersud -/* - * nld_twoterm.h - * - * Devices with two terminals ... - * - * - * (k) - * +-----T-----+ - * | | | - * | +--+--+ | - * | | | | - * | R | | - * | R | | - * | R I | - * | | I | Device n - * | V+ I | - * | V | | - * | V- | | - * | | | | - * | +--+--+ | - * | | | - * +-----T-----+ - * (l) - * - * This is a resistance in series to a voltage source and paralleled by a - * current source. This is suitable to model voltage sources, current sources, - * resistors, capacitors, inductances and diodes. - * - */ #ifndef NLD_TWOTERM_H_ #define NLD_TWOTERM_H_ -#include "nl_base.h" +#include "nl_setup.h" // ----------------------------------------------------------------------------- // Macros @@ -95,397 +66,4 @@ #define IND_P(ind) (static_cast<double>(ind) * 1e-12) #endif -// ----------------------------------------------------------------------------- -// Implementation -// ----------------------------------------------------------------------------- - -namespace netlist -{ - namespace analog - { -// ----------------------------------------------------------------------------- -// nld_twoterm -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT(twoterm) -{ - NETLIB_CONSTRUCTOR_EX(twoterm, bool terminals_owned = false) - , m_P(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "1") - , m_N(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "2") - { - m_P.m_otherterm = &m_N; - m_N.m_otherterm = &m_P; - } - - terminal_t m_P; - terminal_t m_N; - - //NETLIB_UPDATE_TERMINALSI() { } - //NETLIB_RESETI() { } - NETLIB_UPDATEI(); - -public: - /* inline */ void set(const nl_double G, const nl_double V, const nl_double I) - { - /* GO, GT, I */ - m_P.set( G, G, ( V) * G - I); - m_N.set( G, G, ( -V) * G + I); - } - - /* inline */ nl_double deltaV() const - { - return m_P.net().Q_Analog() - m_N.net().Q_Analog(); - } - - void set_mat(const nl_double a11, const nl_double a12, const nl_double r1, - const nl_double a21, const nl_double a22, const nl_double r2) - { - /* GO, GT, I */ - m_P.set(-a12, a11, r1); - m_N.set(-a21, a22, r2); - } - -private: - template <class C> - static core_device_t &bselect(bool b, C &d1, core_device_t &d2) - { - core_device_t *h = dynamic_cast<core_device_t *>(&d1); - return b ? *h : d2; - } -}; - - -// ----------------------------------------------------------------------------- -// nld_R -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT_DERIVED(R_base, twoterm) -{ - NETLIB_CONSTRUCTOR_DERIVED(R_base, twoterm) - { - } - -public: - inline void set_R(const nl_double R) - { - const nl_double G = NL_FCONST(1.0) / R; - set_mat( G, -G, 0.0, - -G, G, 0.0); - } - -protected: - NETLIB_RESETI(); - NETLIB_UPDATEI(); - -}; - -NETLIB_OBJECT_DERIVED(R, R_base) -{ - NETLIB_CONSTRUCTOR_DERIVED(R, R_base) - , m_R(*this, "R", 1e9) - { - } - - param_double_t m_R; - -protected: - - NETLIB_RESETI(); - //NETLIB_UPDATEI() { } - NETLIB_UPDATE_PARAMI(); - -private: - /* protect set_R ... it's a recipe to desaster when used to bypass the parameter */ - using NETLIB_NAME(R_base)::set_R; -}; - -// ----------------------------------------------------------------------------- -// nld_POT -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT(POT) -{ - NETLIB_CONSTRUCTOR(POT) - , m_R1(*this, "_R1") - , m_R2(*this, "_R2") - , m_R(*this, "R", 10000) - , m_Dial(*this, "DIAL", 0.5) - , m_DialIsLog(*this, "DIALLOG", 0) - { - register_subalias("1", m_R1.m_P); - register_subalias("2", m_R1.m_N); - register_subalias("3", m_R2.m_N); - - connect(m_R2.m_P, m_R1.m_N); - - } - - //NETLIB_UPDATEI(); - NETLIB_RESETI(); - NETLIB_UPDATE_PARAMI(); - -private: - NETLIB_SUB(R_base) m_R1; - NETLIB_SUB(R_base) m_R2; - - param_double_t m_R; - param_double_t m_Dial; - param_logic_t m_DialIsLog; -}; - -NETLIB_OBJECT(POT2) -{ - NETLIB_CONSTRUCTOR(POT2) - , m_R1(*this, "_R1") - , m_R(*this, "R", 10000) - , m_Dial(*this, "DIAL", 0.5) - , m_DialIsLog(*this, "DIALLOG", 0) - , m_Reverse(*this, "REVERSE", 0) - { - register_subalias("1", m_R1.m_P); - register_subalias("2", m_R1.m_N); - - } - - //NETLIB_UPDATEI(); - NETLIB_RESETI(); - NETLIB_UPDATE_PARAMI(); - -private: - NETLIB_SUB(R_base) m_R1; - - param_double_t m_R; - param_double_t m_Dial; - param_logic_t m_DialIsLog; - param_logic_t m_Reverse; -}; - - -// ----------------------------------------------------------------------------- -// nld_C -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT_DERIVED(C, twoterm) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(C, twoterm) - , m_C(*this, "C", 1e-6) - , m_GParallel(0.0) - { - //register_term("1", m_P); - //register_term("2", m_N); - } - - NETLIB_IS_TIMESTEP() - NETLIB_TIMESTEPI(); - - param_double_t m_C; - -protected: - NETLIB_RESETI(); - NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI(); - -private: - nl_double m_GParallel; - -}; - -// ----------------------------------------------------------------------------- -// nld_L -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT_DERIVED(L, twoterm) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(L, twoterm) - , m_L(*this, "L", 1e-6) - , m_GParallel(0.0) - , m_G(0.0) - , m_I(0.0) - { - //register_term("1", m_P); - //register_term("2", m_N); - } - - NETLIB_IS_TIMESTEP() - NETLIB_TIMESTEPI(); - - param_double_t m_L; - -protected: - NETLIB_RESETI(); - NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI(); - -private: - nl_double m_GParallel; - nl_double m_G; - nl_double m_I; -}; - -// ----------------------------------------------------------------------------- -// A generic diode model to be used in other devices (Diode, BJT ...) -// ----------------------------------------------------------------------------- - -class generic_diode -{ -public: - generic_diode(device_t &dev, pstring name); - - void update_diode(const nl_double nVd); - - void set_param(const nl_double Is, const nl_double n, nl_double gmin); - - inline nl_double I() const { return m_Id; } - inline nl_double G() const { return m_G; } - inline nl_double Ieq() const { return (m_Id - m_Vd * m_G); } - inline nl_double Vd() const { return m_Vd; } - - /* owning object must save those ... */ - -private: - state_var<nl_double> m_Vd; - state_var<nl_double> m_Id; - state_var<nl_double> m_G; - - nl_double m_Vt; - nl_double m_Is; - nl_double m_n; - nl_double m_gmin; - - nl_double m_VtInv; - nl_double m_Vcrit; -}; - -/*! Class representing the diode model paramers. - * This is the model representation of the diode model. Typically, SPICE uses - * the following parameters. A "Y" in the first column indicates that the - * parameter is actually used in netlist. - * - * |NL? |name |parameter |units|default| example|area | - * |:--:|:-----|:--------------------------------|:----|------:|-------:|:----:| - * | Y |IS |saturation current |A |1.0e-14| 1.0e-14| * | - * | |RS |ohmic resistanc |Ohm | 0| 10| * | - * | Y |N |emission coefficient |- | 1| 1| | - * | |TT |transit-time |sec | 0| 0.1ns| | - * | |CJO |zero-bias junction capacitance |F | 0| 2pF| * | - * | |VJ |junction potential |V | 1| 0.6| | - * | |M |grading coefficient |- | 0.5| 0.5| | - * | |EG |band-gap energy |eV | 1.11| 1.11 Si| | - * | |XTI |saturation-current temp.exp |- | 3|3.0 pn. 2.0 Schottky| | - * | |KF |flicker noise coefficient |- | 0| | | - * | |AF |flicker noise exponent |- | 1| | | - * | |FC |coefficient for forward-bias depletion capacitance formula|-|0.5|| | - * | |BV |reverse breakdown voltage |V |infinite| 40| | - * | |IBV |current at breakdown voltage |V | 0.001| | | - * | |TNOM |parameter measurement temperature|deg C| 27| 50| | - * - */ - -class diode_model_t : public param_model_t -{ -public: - diode_model_t(device_t &device, const pstring name, const pstring val) - : param_model_t(device, name, val) - , m_IS(*this, "IS") - , m_N(*this, "N") - {} - - value_t m_IS; //!< saturation current. - value_t m_N; //!< emission coefficient. -}; - - -// ----------------------------------------------------------------------------- -// nld_D -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT_DERIVED(D, twoterm) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(D, twoterm) - , m_model(*this, "MODEL", "") - , m_D(*this, "m_D") - { - register_subalias("A", m_P); - register_subalias("K", m_N); - } - - template <class CLASS> - NETLIB_NAME(D)(CLASS &owner, const pstring name, const pstring model) - : NETLIB_NAME(twoterm)(owner, name) - , m_model(*this, "MODEL", model) - , m_D(*this, "m_D") - { - register_subalias("A", m_P); - register_subalias("K", m_N); - } - - - NETLIB_IS_DYNAMIC() - - NETLIB_UPDATE_TERMINALSI(); - - diode_model_t m_model; - -protected: - NETLIB_RESETI(); - NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI(); - - generic_diode m_D; -}; - - -// ----------------------------------------------------------------------------- -// nld_VS - Voltage source -// -// netlist voltage source must have inner resistance -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT_DERIVED(VS, twoterm) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(VS, twoterm) - , m_R(*this, "R", 0.1) - , m_V(*this, "V", 0.0) - { - register_subalias("P", m_P); - register_subalias("N", m_N); - } - -protected: - NETLIB_UPDATEI(); - NETLIB_RESETI(); - - param_double_t m_R; - param_double_t m_V; -}; - -// ----------------------------------------------------------------------------- -// nld_CS - Current source -// ----------------------------------------------------------------------------- - -NETLIB_OBJECT_DERIVED(CS, twoterm) -{ -public: - NETLIB_CONSTRUCTOR_DERIVED(CS, twoterm) - , m_I(*this, "I", 1.0) - { - register_subalias("P", m_P); - register_subalias("N", m_N); - } - - NETLIB_UPDATEI(); - NETLIB_RESETI(); -protected: - - param_double_t m_I; -}; - - - } //namespace devices -} // namespace netlist - #endif /* NLD_TWOTERM_H_ */ diff --git a/src/lib/netlist/analog/nld_fourterm.cpp b/src/lib/netlist/analog/nlid_fourterm.cpp index 3707b2a74c4..493b22fe231 100644 --- a/src/lib/netlist/analog/nld_fourterm.cpp +++ b/src/lib/netlist/analog/nlid_fourterm.cpp @@ -6,13 +6,17 @@ */ #include "solver/nld_solver.h" -#include "nld_fourterm.h" +#include "nlid_fourterm.h" #include "nl_setup.h" +#include <cmath> + namespace netlist { namespace analog { + + // ---------------------------------------------------------------------------------------- // nld_VCCS // ---------------------------------------------------------------------------------------- @@ -119,5 +123,12 @@ NETLIB_RESET(VCVS) m_ON2.set(NL_FCONST(1.0) / m_RO()); } - } //namespace devices + } //namespace analog + + namespace devices { + NETLIB_DEVICE_IMPL_NS(analog, VCVS) + NETLIB_DEVICE_IMPL_NS(analog, VCCS) + NETLIB_DEVICE_IMPL_NS(analog, CCCS) + NETLIB_DEVICE_IMPL_NS(analog, LVCCS) + } } // namespace netlist diff --git a/src/lib/netlist/analog/nlid_fourterm.h b/src/lib/netlist/analog/nlid_fourterm.h new file mode 100644 index 00000000000..cfc8f30d751 --- /dev/null +++ b/src/lib/netlist/analog/nlid_fourterm.h @@ -0,0 +1,211 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nlid_fourterm.h + * + */ + +#ifndef NLID_FOURTERM_H_ +#define NLID_FOURTERM_H_ + +#include "nl_base.h" + +namespace netlist { + namespace analog { + + // ---------------------------------------------------------------------------------------- + // nld_VCCS + // ---------------------------------------------------------------------------------------- + + /* + * Voltage controlled current source + * + * IP ---+ +------> OP + * | | + * RI I + * RI => G => I IOut = (V(IP)-V(IN)) * G + * RI I + * | | + * IN ---+ +------< ON + * + * G=1 ==> 1V ==> 1A + * + * RI = 1 / NETLIST_GMIN + * + */ + + NETLIB_OBJECT(VCCS) + { + public: + NETLIB_CONSTRUCTOR(VCCS) + , m_G(*this, "G", 1.0) + , m_RI(*this, "RI", 1e9) + , m_OP(*this, "OP") + , m_ON(*this, "ON") + , m_IP(*this, "IP") + , m_IN(*this, "IN") + , m_OP1(*this, "_OP1") + , m_ON1(*this, "_ON1") + , m_gfac(1.0) + { + m_IP.m_otherterm = &m_IN; // <= this should be NULL and terminal be filtered out prior to solving... + m_IN.m_otherterm = &m_IP; // <= this should be NULL and terminal be filtered out prior to solving... + + m_OP.m_otherterm = &m_IP; + m_OP1.m_otherterm = &m_IN; + + m_ON.m_otherterm = &m_IP; + m_ON1.m_otherterm = &m_IN; + + connect(m_OP, m_OP1); + connect(m_ON, m_ON1); + m_gfac = NL_FCONST(1.0); + } + + param_double_t m_G; + param_double_t m_RI; + + protected: + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI() + { + NETLIB_NAME(VCCS)::reset(); + } + + terminal_t m_OP; + terminal_t m_ON; + + terminal_t m_IP; + terminal_t m_IN; + + terminal_t m_OP1; + terminal_t m_ON1; + + nl_double m_gfac; + }; + + /* Limited Current source*/ + + NETLIB_OBJECT_DERIVED(LVCCS, VCCS) + { + public: + NETLIB_CONSTRUCTOR_DERIVED(LVCCS, VCCS) + , m_cur_limit(*this, "CURLIM", 1000.0) + , m_vi(0.0) + { + } + + NETLIB_IS_DYNAMIC(true) + + param_double_t m_cur_limit; /* current limit */ + + protected: + NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATE_PARAMI(); + NETLIB_UPDATE_TERMINALSI(); + + nl_double m_vi; + }; + + // ---------------------------------------------------------------------------------------- + // nld_CCCS + // ---------------------------------------------------------------------------------------- + + /* + * Current controlled current source + * + * IP ---+ +------> OP + * | | + * RI I + * RI => G => I IOut = (V(IP)-V(IN)) / RI * G + * RI I + * | | + * IN ---+ +------< ON + * + * G=1 ==> 1A ==> 1A + * + * RI = 1 + * + * This needs high levels of accuracy to work with 1 Ohm RI. + * + */ + + NETLIB_OBJECT_DERIVED(CCCS, VCCS) + { + public: + NETLIB_CONSTRUCTOR_DERIVED(CCCS, VCCS) + , m_gfac(1.0) + { + m_gfac = NL_FCONST(1.0) / m_RI(); + } + + protected: + NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATE_PARAMI(); + + nl_double m_gfac; + }; + + + // ---------------------------------------------------------------------------------------- + // nld_VCVS + // ---------------------------------------------------------------------------------------- + + /* + * Voltage controlled voltage source + * + * Parameters: + * G Default: 1 + * RO Default: 1 (would be typically 50 for an op-amp + * + * IP ---+ +--+---- OP + * | | | + * RI I RO + * RI => G => I RO V(OP) - V(ON) = (V(IP)-V(IN)) * G + * RI I RO + * | | | + * IN ---+ +--+---- ON + * + * G=1 ==> 1V ==> 1V + * + * RI = 1 / NETLIST_GMIN + * + * Internal GI = G / RO + * + */ + + + NETLIB_OBJECT_DERIVED(VCVS, VCCS) + { + public: + NETLIB_CONSTRUCTOR_DERIVED(VCVS, VCCS) + , m_RO(*this, "RO", 1.0) + , m_OP2(*this, "_OP2") + , m_ON2(*this, "_ON2") + { + m_OP2.m_otherterm = &m_ON2; + m_ON2.m_otherterm = &m_OP2; + + connect(m_OP2, m_OP1); + connect(m_ON2, m_ON1); + } + + param_double_t m_RO; + + protected: + //NETLIB_UPDATEI(); + NETLIB_RESETI(); + //NETLIB_UPDATE_PARAMI(); + + terminal_t m_OP2; + terminal_t m_ON2; + + }; + + } +} + +#endif /* NLD_FOURTERM_H_ */ diff --git a/src/lib/netlist/analog/nld_twoterm.cpp b/src/lib/netlist/analog/nlid_twoterm.cpp index a87e0c03f88..a9a4edb604a 100644 --- a/src/lib/netlist/analog/nld_twoterm.cpp +++ b/src/lib/netlist/analog/nlid_twoterm.cpp @@ -5,10 +5,12 @@ * */ -#include <solver/nld_solver.h> -#include <algorithm> +#include "solver/nld_solver.h" -#include "nld_twoterm.h" +#include "nlid_twoterm.h" +#include "nl_factory.h" + +#include <cmath> namespace netlist { @@ -23,7 +25,9 @@ generic_diode::generic_diode(device_t &dev, pstring name) , m_Id(dev, name + ".m_Id", 0.0) , m_G(dev, name + ".m_G", 1e-15) , m_Vt(0.0) + , m_Vmin(0.0) , m_Is(0.0) + , m_logIs(0.0) , m_n(0.0) , m_gmin(1e-15) , m_VtInv(0.0) @@ -36,10 +40,12 @@ void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double g { static const double csqrt2 = std::sqrt(2.0); m_Is = Is; + m_logIs = std::log(Is); m_n = n; m_gmin = gmin; m_Vt = 0.0258 * m_n; + m_Vmin = -5.0 * m_Vt; m_Vcrit = m_Vt * std::log(m_Vt / m_Is / csqrt2); m_VtInv = 1.0 / m_Vt; @@ -47,8 +53,7 @@ void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double g void generic_diode::update_diode(const nl_double nVd) { -#if 1 - if (nVd < NL_FCONST(-5.0) * m_Vt) + if (nVd < m_Vmin) { m_Vd = nVd; m_G = m_gmin; @@ -58,29 +63,20 @@ void generic_diode::update_diode(const nl_double nVd) { m_Vd = nVd; //m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - m_G = m_Is * m_VtInv * eVDVt + m_gmin; + //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv); + const double IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv); + m_Id = IseVDVt - m_Is; + m_G = IseVDVt * m_VtInv + m_gmin; } else { -#if 1 - const nl_double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(-0.99)); + const double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(-0.99)); m_Vd = m_Vd + std::log1p(a) * m_Vt; -#else - m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); -#endif - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - - m_G = m_Is * m_VtInv * eVDVt + m_gmin; + //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv); + const double IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv); + m_Id = IseVDVt - m_Is; + m_G = IseVDVt * m_VtInv + m_gmin; } -#else - m_Vd = m_Vd + 20.0 * m_Vt * std::tanh((nVd - m_Vd) / 20.0 / m_Vt); - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - m_G = m_Is * m_VtInv * eVDVt + m_gmin; -#endif } // ---------------------------------------------------------------------------------------- @@ -300,6 +296,13 @@ NETLIB_UPDATE(VS) NETLIB_NAME(twoterm)::update(); } +NETLIB_TIMESTEP(VS) +{ + this->set(1.0 / m_R(), + m_compiled.evaluate(std::vector<double>({netlist().time().as_double()})), + 0.0); +} + // ---------------------------------------------------------------------------------------- // nld_CS // ---------------------------------------------------------------------------------------- @@ -319,5 +322,24 @@ NETLIB_UPDATE(CS) NETLIB_NAME(twoterm)::update(); } - } //namespace devices +NETLIB_TIMESTEP(CS) +{ + const double I = m_compiled.evaluate(std::vector<double>({netlist().time().as_double()})); + set_mat(0.0, 0.0, -I, + 0.0, 0.0, I); +} + + } //namespace analog + + namespace devices { + NETLIB_DEVICE_IMPL_NS(analog, R) + NETLIB_DEVICE_IMPL_NS(analog, POT) + NETLIB_DEVICE_IMPL_NS(analog, POT2) + NETLIB_DEVICE_IMPL_NS(analog, C) + NETLIB_DEVICE_IMPL_NS(analog, L) + NETLIB_DEVICE_IMPL_NS(analog, D) + NETLIB_DEVICE_IMPL_NS(analog, VS) + NETLIB_DEVICE_IMPL_NS(analog, CS) + } + } // namespace netlist diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h new file mode 100644 index 00000000000..6166c707d2d --- /dev/null +++ b/src/lib/netlist/analog/nlid_twoterm.h @@ -0,0 +1,448 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nld_twoterm.h + * + * Devices with two terminals ... + * + * + * (k) + * +-----T-----+ + * | | | + * | +--+--+ | + * | | | | + * | R | | + * | R | | + * | R I | + * | | I | Device n + * | V+ I | + * | V | | + * | V- | | + * | | | | + * | +--+--+ | + * | | | + * +-----T-----+ + * (l) + * + * This is a resistance in series to a voltage source and paralleled by a + * current source. This is suitable to model voltage sources, current sources, + * resistors, capacitors, inductances and diodes. + * + */ + +#ifndef NLID_TWOTERM_H_ +#define NLID_TWOTERM_H_ + +#include "nl_base.h" +#include "plib/pfunction.h" + +// ----------------------------------------------------------------------------- +// Implementation +// ----------------------------------------------------------------------------- + +namespace netlist +{ + namespace analog + { +// ----------------------------------------------------------------------------- +// nld_twoterm +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT(twoterm) +{ + NETLIB_CONSTRUCTOR_EX(twoterm, bool terminals_owned = false) + , m_P(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "1") + , m_N(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "2") + { + m_P.m_otherterm = &m_N; + m_N.m_otherterm = &m_P; + } + + terminal_t m_P; + terminal_t m_N; + + //NETLIB_UPDATE_TERMINALSI() { } + //NETLIB_RESETI() { } + NETLIB_UPDATEI(); + +public: + /* inline */ void set(const nl_double G, const nl_double V, const nl_double I) + { + /* GO, GT, I */ + m_P.set( G, G, ( V) * G - I); + m_N.set( G, G, ( -V) * G + I); + } + + /* inline */ nl_double deltaV() const + { + return m_P.net().Q_Analog() - m_N.net().Q_Analog(); + } + + void set_mat(const nl_double a11, const nl_double a12, const nl_double r1, + const nl_double a21, const nl_double a22, const nl_double r2) + { + /* GO, GT, I */ + m_P.set(-a12, a11, r1); + m_N.set(-a21, a22, r2); + } + +private: + template <class C> + static core_device_t &bselect(bool b, C &d1, core_device_t &d2) + { + core_device_t *h = dynamic_cast<core_device_t *>(&d1); + return b ? *h : d2; + } +}; + + +// ----------------------------------------------------------------------------- +// nld_R +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT_DERIVED(R_base, twoterm) +{ + NETLIB_CONSTRUCTOR_DERIVED(R_base, twoterm) + { + } + +public: + inline void set_R(const nl_double R) + { + const nl_double G = NL_FCONST(1.0) / R; + set_mat( G, -G, 0.0, + -G, G, 0.0); + } + +protected: + NETLIB_RESETI(); + NETLIB_UPDATEI(); + +}; + +NETLIB_OBJECT_DERIVED(R, R_base) +{ + NETLIB_CONSTRUCTOR_DERIVED(R, R_base) + , m_R(*this, "R", 1e9) + { + } + + param_double_t m_R; + +protected: + + NETLIB_RESETI(); + //NETLIB_UPDATEI() { } + NETLIB_UPDATE_PARAMI(); + +private: + /* protect set_R ... it's a recipe to desaster when used to bypass the parameter */ + using NETLIB_NAME(R_base)::set_R; +}; + +// ----------------------------------------------------------------------------- +// nld_POT +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT(POT) +{ + NETLIB_CONSTRUCTOR(POT) + , m_R1(*this, "_R1") + , m_R2(*this, "_R2") + , m_R(*this, "R", 10000) + , m_Dial(*this, "DIAL", 0.5) + , m_DialIsLog(*this, "DIALLOG", 0) + { + register_subalias("1", m_R1.m_P); + register_subalias("2", m_R1.m_N); + register_subalias("3", m_R2.m_N); + + connect(m_R2.m_P, m_R1.m_N); + + } + + //NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATE_PARAMI(); + +private: + NETLIB_SUB(R_base) m_R1; + NETLIB_SUB(R_base) m_R2; + + param_double_t m_R; + param_double_t m_Dial; + param_logic_t m_DialIsLog; +}; + +NETLIB_OBJECT(POT2) +{ + NETLIB_CONSTRUCTOR(POT2) + , m_R1(*this, "_R1") + , m_R(*this, "R", 10000) + , m_Dial(*this, "DIAL", 0.5) + , m_DialIsLog(*this, "DIALLOG", 0) + , m_Reverse(*this, "REVERSE", 0) + { + register_subalias("1", m_R1.m_P); + register_subalias("2", m_R1.m_N); + + } + + //NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATE_PARAMI(); + +private: + NETLIB_SUB(R_base) m_R1; + + param_double_t m_R; + param_double_t m_Dial; + param_logic_t m_DialIsLog; + param_logic_t m_Reverse; +}; + + +// ----------------------------------------------------------------------------- +// nld_C +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT_DERIVED(C, twoterm) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(C, twoterm) + , m_C(*this, "C", 1e-6) + , m_GParallel(0.0) + { + //register_term("1", m_P); + //register_term("2", m_N); + } + + NETLIB_IS_TIMESTEP(true) + NETLIB_TIMESTEPI(); + + param_double_t m_C; + +protected: + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + +private: + nl_double m_GParallel; + +}; + +// ----------------------------------------------------------------------------- +// nld_L +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT_DERIVED(L, twoterm) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(L, twoterm) + , m_L(*this, "L", 1e-6) + , m_GParallel(0.0) + , m_G(0.0) + , m_I(0.0) + { + //register_term("1", m_P); + //register_term("2", m_N); + } + + NETLIB_IS_TIMESTEP(true) + NETLIB_TIMESTEPI(); + + param_double_t m_L; + +protected: + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + +private: + nl_double m_GParallel; + nl_double m_G; + nl_double m_I; +}; + +// ----------------------------------------------------------------------------- +// A generic diode model to be used in other devices (Diode, BJT ...) +// ----------------------------------------------------------------------------- + +class generic_diode +{ +public: + generic_diode(device_t &dev, pstring name); + + void update_diode(const double nVd); + + void set_param(const double Is, const double n, double gmin); + + double I() const { return m_Id; } + double G() const { return m_G; } + double Ieq() const { return (m_Id - m_Vd * m_G); } + double Vd() const { return m_Vd; } + + /* owning object must save those ... */ + +private: + state_var<double> m_Vd; + state_var<double> m_Id; + state_var<double> m_G; + + double m_Vt; + double m_Vmin; + double m_Is; + double m_logIs; + double m_n; + double m_gmin; + + double m_VtInv; + double m_Vcrit; +}; + +/*! Class representing the diode model paramers. + * This is the model representation of the diode model. Typically, SPICE uses + * the following parameters. A "Y" in the first column indicates that the + * parameter is actually used in netlist. + * + * |NL? |name |parameter |units|default| example|area | + * |:--:|:-----|:--------------------------------|:----|------:|-------:|:----:| + * | Y |IS |saturation current |A |1.0e-14| 1.0e-14| * | + * | |RS |ohmic resistanc |Ohm | 0| 10| * | + * | Y |N |emission coefficient |- | 1| 1| | + * | |TT |transit-time |sec | 0| 0.1ns| | + * | |CJO |zero-bias junction capacitance |F | 0| 2pF| * | + * | |VJ |junction potential |V | 1| 0.6| | + * | |M |grading coefficient |- | 0.5| 0.5| | + * | |EG |band-gap energy |eV | 1.11| 1.11 Si| | + * | |XTI |saturation-current temp.exp |- | 3|3.0 pn. 2.0 Schottky| | + * | |KF |flicker noise coefficient |- | 0| | | + * | |AF |flicker noise exponent |- | 1| | | + * | |FC |coefficient for forward-bias depletion capacitance formula|-|0.5|| | + * | |BV |reverse breakdown voltage |V |infinite| 40| | + * | |IBV |current at breakdown voltage |V | 0.001| | | + * | |TNOM |parameter measurement temperature|deg C| 27| 50| | + * + */ + +class diode_model_t : public param_model_t +{ +public: + diode_model_t(device_t &device, const pstring name, const pstring val) + : param_model_t(device, name, val) + , m_IS(*this, "IS") + , m_N(*this, "N") + {} + + value_t m_IS; //!< saturation current. + value_t m_N; //!< emission coefficient. +}; + + +// ----------------------------------------------------------------------------- +// nld_D +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT_DERIVED(D, twoterm) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(D, twoterm) + , m_model(*this, "MODEL", "") + , m_D(*this, "m_D") + { + register_subalias("A", m_P); + register_subalias("K", m_N); + } + + template <class CLASS> + NETLIB_NAME(D)(CLASS &owner, const pstring name, const pstring model) + : NETLIB_NAME(twoterm)(owner, name) + , m_model(*this, "MODEL", model) + , m_D(*this, "m_D") + { + register_subalias("A", m_P); + register_subalias("K", m_N); + } + + NETLIB_IS_DYNAMIC(true) + NETLIB_UPDATE_TERMINALSI(); + + diode_model_t m_model; + +protected: + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + + generic_diode m_D; +}; + + +// ----------------------------------------------------------------------------- +// nld_VS - Voltage source +// +// netlist voltage source must have inner resistance +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT_DERIVED(VS, twoterm) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(VS, twoterm) + , m_R(*this, "R", 0.1) + , m_V(*this, "V", 0.0) + , m_func(*this,"FUNC", "") + { + register_subalias("P", m_P); + register_subalias("N", m_N); + if (m_func() != "") + m_compiled.compile_postfix(std::vector<pstring>({{"T"}}), m_func()); + } + + NETLIB_IS_TIMESTEP(m_func() != "") + NETLIB_TIMESTEPI(); + +protected: + NETLIB_UPDATEI(); + NETLIB_RESETI(); + + param_double_t m_R; + param_double_t m_V; + param_str_t m_func; + plib::pfunction m_compiled; +}; + +// ----------------------------------------------------------------------------- +// nld_CS - Current source +// ----------------------------------------------------------------------------- + +NETLIB_OBJECT_DERIVED(CS, twoterm) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(CS, twoterm) + , m_I(*this, "I", 1.0) + , m_func(*this,"FUNC", "") + { + register_subalias("P", m_P); + register_subalias("N", m_N); + if (m_func() != "") + m_compiled.compile_postfix(std::vector<pstring>({{"T"}}), m_func()); + } + + NETLIB_IS_TIMESTEP(m_func() != "") + NETLIB_TIMESTEPI(); +protected: + + NETLIB_UPDATEI(); + NETLIB_RESETI(); + + param_double_t m_I; + param_str_t m_func; + plib::pfunction m_compiled; +}; + + + } //namespace devices +} // namespace netlist + +#endif /* NLD_TWOTERM_H_ */ diff --git a/src/lib/netlist/build/doxygen.conf b/src/lib/netlist/build/doxygen.conf index adf69b30e54..9de9b691114 100644 --- a/src/lib/netlist/build/doxygen.conf +++ b/src/lib/netlist/build/doxygen.conf @@ -24,7 +24,7 @@ # for the list of possible encodings. # The default value is: UTF-8. -DOXYFILE_ENCODING = UTF-8 +DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the @@ -32,33 +32,33 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "My Project" +PROJECT_NAME = Netlist documentaton # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doxy +OUTPUT_DIRECTORY = doxy # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -68,7 +68,7 @@ OUTPUT_DIRECTORY = doxy # performance problems for the file system. # The default value is: NO. -CREATE_SUBDIRS = NO +CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII @@ -76,7 +76,7 @@ CREATE_SUBDIRS = NO # U+3044. # The default value is: NO. -ALLOW_UNICODE_NAMES = NO +ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this @@ -91,14 +91,14 @@ ALLOW_UNICODE_NAMES = NO # Ukrainian and Vietnamese. # The default value is: English. -OUTPUT_LANGUAGE = English +OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. -BRIEF_MEMBER_DESC = YES +BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description @@ -107,7 +107,7 @@ BRIEF_MEMBER_DESC = YES # brief descriptions will be completely suppressed. # The default value is: YES. -REPEAT_BRIEF = YES +REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found @@ -118,14 +118,14 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. -ALWAYS_DETAILED_SEC = NO +ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those @@ -133,14 +133,14 @@ ALWAYS_DETAILED_SEC = NO # operators of the base classes will not be shown. # The default value is: NO. -INLINE_INHERITED_MEMB = NO +INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = ../.. +STRIP_FROM_PATH = ../.. # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -161,14 +161,14 @@ STRIP_FROM_PATH = ../.. # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. -SHORT_NAMES = NO +SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief @@ -177,7 +177,7 @@ SHORT_NAMES = NO # description.) # The default value is: NO. -JAVADOC_AUTOBRIEF = YES +JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If @@ -185,7 +185,7 @@ JAVADOC_AUTOBRIEF = YES # requiring an explicit \brief command for a brief description.) # The default value is: NO. -QT_AUTOBRIEF = YES +QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as @@ -203,20 +203,20 @@ MULTILINE_CPP_IS_BRIEF = NO # documentation from any documented member that it re-implements. # The default value is: YES. -INHERIT_DOCS = YES +INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. -SEPARATE_MEMBER_PAGES = NO +SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. -TAB_SIZE = 4 +TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: @@ -228,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -242,7 +242,7 @@ TCL_SUBST = # members will be omitted, etc. # The default value is: NO. -OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored @@ -250,19 +250,19 @@ OPTIMIZE_OUTPUT_FOR_C = NO # qualified scopes will look different, etc. # The default value is: NO. -OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. -OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. -OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given @@ -281,7 +281,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -291,7 +291,7 @@ EXTENSION_MAPPING = # case of backward compatibilities issues. # The default value is: YES. -MARKDOWN_SUPPORT = YES +MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can @@ -299,7 +299,7 @@ MARKDOWN_SUPPORT = YES # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. -AUTOLINK_SUPPORT = YES +AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this @@ -309,13 +309,13 @@ AUTOLINK_SUPPORT = YES # diagrams that involve STL classes more complete and accurate. # The default value is: NO. -BUILTIN_STL_SUPPORT = NO +BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. -CPP_CLI_SUPPORT = NO +CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen @@ -323,7 +323,7 @@ CPP_CLI_SUPPORT = NO # of private inheritance when no explicit protection keyword is present. # The default value is: NO. -SIP_SUPPORT = NO +SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make @@ -333,7 +333,7 @@ SIP_SUPPORT = NO # should set this option to NO. # The default value is: YES. -IDL_PROPERTY_SUPPORT = YES +IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first @@ -341,7 +341,7 @@ IDL_PROPERTY_SUPPORT = YES # all members of a group must be documented explicitly. # The default value is: NO. -DISTRIBUTE_GROUP_DOC = NO +DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option @@ -357,7 +357,7 @@ GROUP_NESTED_COMPOUNDS = NO # \nosubgrouping command. # The default value is: YES. -SUBGROUPING = YES +SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) @@ -378,7 +378,7 @@ INLINE_GROUPED_CLASSES = NO # Man pages) or section (for LaTeX and RTF). # The default value is: NO. -INLINE_SIMPLE_STRUCTS = NO +INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So @@ -389,7 +389,7 @@ INLINE_SIMPLE_STRUCTS = NO # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. -TYPEDEF_HIDES_STRUCT = NO +TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be @@ -402,7 +402,7 @@ TYPEDEF_HIDES_STRUCT = NO # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. -LOOKUP_CACHE_SIZE = 0 +LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options @@ -416,25 +416,25 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = NO +EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. -EXTRACT_PRIVATE = NO +EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. -EXTRACT_PACKAGE = NO +EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, @@ -442,7 +442,7 @@ EXTRACT_STATIC = NO # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are @@ -450,7 +450,7 @@ EXTRACT_LOCAL_CLASSES = YES # included. # The default value is: NO. -EXTRACT_LOCAL_METHODS = NO +EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called @@ -459,7 +459,7 @@ EXTRACT_LOCAL_METHODS = NO # are hidden. # The default value is: NO. -EXTRACT_ANON_NSPACES = NO +EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these @@ -467,7 +467,7 @@ EXTRACT_ANON_NSPACES = NO # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. -HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set @@ -475,28 +475,28 @@ HIDE_UNDOC_MEMBERS = NO # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. -HIDE_UNDOC_CLASSES = NO +HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. -HIDE_FRIEND_COMPOUNDS = NO +HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. -HIDE_IN_BODY_DOCS = NO +HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. -INTERNAL_DOCS = NO +INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also @@ -505,53 +505,53 @@ INTERNAL_DOCS = NO # and Mac users are advised to set this option to NO. # The default value is: system dependent. -CASE_SENSE_NAMES = YES +CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. -HIDE_SCOPE_NAMES = NO +HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. -HIDE_COMPOUND_REFERENCE= NO +HIDE_COMPOUND_REFERENCE = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. -SHOW_INCLUDE_FILES = YES +SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. -SHOW_GROUPED_MEMB_INC = NO +SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. -FORCE_LOCAL_INCLUDES = NO +FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. -INLINE_INFO = YES +INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member @@ -559,7 +559,7 @@ SORT_MEMBER_DOCS = YES # this will also influence the order of the classes in the class list. # The default value is: NO. -SORT_BRIEF_DOCS = NO +SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and @@ -578,7 +578,7 @@ SORT_MEMBERS_CTORS_1ST = NO # appear in their defined order. # The default value is: NO. -SORT_GROUP_NAMES = NO +SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will @@ -588,7 +588,7 @@ SORT_GROUP_NAMES = NO # list. # The default value is: NO. -SORT_BY_SCOPE_NAME = NO +SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between @@ -598,38 +598,38 @@ SORT_BY_SCOPE_NAME = NO # accept a match between prototype and implementation in such cases. # The default value is: NO. -STRICT_PROTO_MATCHING = NO +STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. -GENERATE_TODOLIST = YES +GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. -GENERATE_TESTLIST = YES +GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. -GENERATE_BUGLIST = YES +GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. -GENERATE_DEPRECATEDLIST= YES +GENERATE_DEPRECATEDLIST = YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -640,28 +640,28 @@ ENABLED_SECTIONS = # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. -MAX_INITIALIZER_LINES = 30 +MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. -SHOW_USED_FILES = YES +SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. -SHOW_FILES = YES +SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. -SHOW_NAMESPACES = YES +SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from @@ -671,7 +671,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -684,7 +684,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -694,7 +694,7 @@ LAYOUT_FILE = # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -705,7 +705,7 @@ CITE_BIB_FILES = # messages are off. # The default value is: NO. -QUIET = NO +QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES @@ -714,14 +714,14 @@ QUIET = NO # Tip: Turn warnings on while writing the documentation. # The default value is: YES. -WARNINGS = YES +WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. -WARN_IF_UNDOCUMENTED = YES +WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters @@ -729,7 +729,7 @@ WARN_IF_UNDOCUMENTED = YES # markup commands wrongly. # The default value is: YES. -WARN_IF_DOC_ERROR = YES +WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return @@ -737,13 +737,13 @@ WARN_IF_DOC_ERROR = YES # parameter documentation, but not about the absence of documentation. # The default value is: NO. -WARN_NO_PARAMDOC = NO +WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. -WARN_AS_ERROR = NO +WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -753,13 +753,13 @@ WARN_AS_ERROR = NO # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. -WARN_FORMAT = "$file:$line: $text" +WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -771,7 +771,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ".." "../analog" "../documentation" +INPUT = ".." "../analog" "../documentation" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -780,7 +780,7 @@ INPUT = ".." "../analog" "../documentation" # possible encodings. # The default value is: UTF-8. -INPUT_ENCODING = UTF-8 +INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and @@ -796,13 +796,13 @@ INPUT_ENCODING = UTF-8 # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, # *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. -FILE_PATTERNS = *.h *.cpp +FILE_PATTERNS = *.h *.cpp # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. -RECURSIVE = NO +RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a @@ -811,14 +811,14 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. -EXCLUDE_SYMLINKS = NO +EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude @@ -827,7 +827,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -838,33 +838,33 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. -EXAMPLE_RECURSIVE = NO +EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = "../documentation" +IMAGE_PATH = "../documentation" # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -885,7 +885,7 @@ IMAGE_PATH = "../documentation" # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -898,14 +898,14 @@ INPUT_FILTER = # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. -FILTER_SOURCE_FILES = NO +FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and @@ -913,14 +913,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -933,20 +933,20 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. -INLINE_SOURCES = NO +INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. -STRIP_CODE_COMMENTS = YES +STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. @@ -958,7 +958,7 @@ REFERENCED_BY_RELATION = NO # all documented entities called/used by that function will be listed. # The default value is: NO. -REFERENCES_RELATION = NO +REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and @@ -976,7 +976,7 @@ REFERENCES_LINK_SOURCE = YES # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. -SOURCE_TOOLTIPS = YES +SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in @@ -998,7 +998,7 @@ SOURCE_TOOLTIPS = YES # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. -USE_HTAGS = NO +USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is @@ -1006,7 +1006,7 @@ USE_HTAGS = NO # See also: Section \class. # The default value is: YES. -VERBATIM_HEADERS = YES +VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the @@ -1025,7 +1025,7 @@ CLANG_ASSISTED_PARSING = NO # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. -CLANG_OPTIONS = +CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index @@ -1036,14 +1036,14 @@ CLANG_OPTIONS = # classes, structs, unions or interfaces. # The default value is: YES. -ALPHABETICAL_INDEX = YES +ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -COLS_IN_ALPHA_INDEX = 5 +COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag @@ -1051,7 +1051,7 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output @@ -1060,7 +1060,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = YES +GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1068,14 +1068,14 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = html +HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FILE_EXTENSION = .html +HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a @@ -1095,7 +1095,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1105,7 +1105,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1117,7 +1117,7 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets @@ -1130,7 +1130,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = "../documentation/doc.css" +HTML_EXTRA_STYLESHEET = "../documentation/doc.css" # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1140,7 +1140,7 @@ HTML_EXTRA_STYLESHEET = "../documentation/doc.css" # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to @@ -1151,7 +1151,7 @@ HTML_EXTRA_FILES = # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A @@ -1159,7 +1159,7 @@ HTML_COLORSTYLE_HUE = 220 # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 @@ -1170,7 +1170,7 @@ HTML_COLORSTYLE_SAT = 100 # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_GAMMA = 80 +HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this @@ -1179,7 +1179,7 @@ HTML_COLORSTYLE_GAMMA = 80 # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_TIMESTAMP = NO +HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the @@ -1187,7 +1187,7 @@ HTML_TIMESTAMP = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1214,7 +1214,7 @@ HTML_INDEX_NUM_ENTRIES = 100 # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_DOCSET = NO +GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider @@ -1222,7 +1222,7 @@ GENERATE_DOCSET = NO # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. @@ -1230,7 +1230,7 @@ DOCSET_FEEDNAME = "Doxygen generated docs" # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style @@ -1238,13 +1238,13 @@ DOCSET_BUNDLE_ID = org.doxygen.Project # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_PUBLISHER_NAME = Publisher +DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The @@ -1262,14 +1262,14 @@ DOCSET_PUBLISHER_NAME = Publisher # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_HTMLHELP = NO +GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, @@ -1277,20 +1277,20 @@ CHM_FILE = # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -GENERATE_CHI = NO +GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it @@ -1298,14 +1298,14 @@ CHM_INDEX_ENCODING = # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -BINARY_TOC = NO +BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -TOC_EXPAND = NO +TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that @@ -1314,14 +1314,14 @@ TOC_EXPAND = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_QHP = NO +GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1329,7 +1329,7 @@ QCH_FILE = # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_NAMESPACE = org.doxygen.Project +QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual @@ -1338,7 +1338,7 @@ QHP_NAMESPACE = org.doxygen.Project # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_VIRTUAL_FOLDER = doc +QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom @@ -1346,7 +1346,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1354,21 +1354,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1380,7 +1380,7 @@ QHG_LOCATION = # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_ECLIPSEHELP = NO +GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this @@ -1388,7 +1388,7 @@ GENERATE_ECLIPSEHELP = NO # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. -ECLIPSE_DOC_ID = org.doxygen.Project +ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The @@ -1399,7 +1399,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -DISABLE_INDEX = NO +DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag @@ -1416,7 +1416,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. @@ -1426,21 +1426,21 @@ GENERATE_TREEVIEW = NO # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. -ENUM_VALUES_PER_LINE = 4 +ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. -TREEVIEW_WIDTH = 250 +TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -EXT_LINKS_IN_WINDOW = NO +EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful @@ -1449,7 +1449,7 @@ EXT_LINKS_IN_WINDOW = NO # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. -FORMULA_FONTSIZE = 10 +FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not @@ -1460,7 +1460,7 @@ FORMULA_FONTSIZE = 10 # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -FORMULA_TRANSPARENT = YES +FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering @@ -1471,7 +1471,7 @@ FORMULA_TRANSPARENT = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = YES +USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: @@ -1481,7 +1481,7 @@ USE_MATHJAX = YES # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_FORMAT = HTML-CSS +MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory @@ -1494,14 +1494,14 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1509,7 +1509,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1530,7 +1530,7 @@ MATHJAX_CODEFILE = # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -SEARCHENGINE = YES +SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There @@ -1542,7 +1542,7 @@ SEARCHENGINE = YES # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. -SERVER_BASED_SEARCH = NO +SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file @@ -1558,7 +1558,7 @@ SERVER_BASED_SEARCH = NO # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH = NO +EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. @@ -1569,7 +1569,7 @@ EXTERNAL_SEARCH = NO # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1577,7 +1577,7 @@ SEARCHENGINE_URL = # The default file is: searchdata.xml. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHDATA_FILE = searchdata.xml +SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is @@ -1585,7 +1585,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1595,7 +1595,7 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output @@ -1604,7 +1604,7 @@ EXTRA_SEARCH_MAPPINGS = # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. -GENERATE_LATEX = YES +GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1612,7 +1612,7 @@ GENERATE_LATEX = YES # The default directory is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_OUTPUT = latex +LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. @@ -1623,14 +1623,14 @@ LATEX_OUTPUT = latex # The default file is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. -MAKEINDEX_CMD_NAME = makeindex +MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some @@ -1638,7 +1638,7 @@ MAKEINDEX_CMD_NAME = makeindex # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -COMPACT_LATEX = NO +COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used by the # printer. @@ -1647,7 +1647,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4 +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -1659,7 +1659,7 @@ PAPER_TYPE = a4 # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1675,7 +1675,7 @@ EXTRA_PACKAGES = # to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last @@ -1686,7 +1686,7 @@ LATEX_HEADER = # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined # LaTeX style sheets that are included after the standard style sheets created @@ -1697,7 +1697,7 @@ LATEX_FOOTER = # list). # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1705,7 +1705,7 @@ LATEX_EXTRA_STYLESHEET = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1714,7 +1714,7 @@ LATEX_EXTRA_FILES = # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -PDF_HYPERLINKS = YES +PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate # the PDF file directly from the LaTeX files. Set this option to YES, to get a @@ -1722,7 +1722,7 @@ PDF_HYPERLINKS = YES # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -USE_PDFLATEX = YES +USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running @@ -1731,14 +1731,14 @@ USE_PDFLATEX = YES # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_BATCHMODE = NO +LATEX_BATCHMODE = NO # If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the # index chapters (such as File Index, Compound Index, etc.) in the output. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HIDE_INDICES = NO +LATEX_HIDE_INDICES = NO # If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source # code with syntax highlighting in the LaTeX output. @@ -1748,7 +1748,7 @@ LATEX_HIDE_INDICES = NO # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_SOURCE_CODE = NO +LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See @@ -1756,7 +1756,7 @@ LATEX_SOURCE_CODE = NO # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_BIB_STYLE = plain +LATEX_BIB_STYLE = plain # If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated # page will contain the date and time when the page was generated. Setting this @@ -1764,7 +1764,7 @@ LATEX_BIB_STYLE = plain # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_TIMESTAMP = NO +LATEX_TIMESTAMP = NO #--------------------------------------------------------------------------- # Configuration options related to the RTF output @@ -1775,7 +1775,7 @@ LATEX_TIMESTAMP = NO # readers/editors. # The default value is: NO. -GENERATE_RTF = NO +GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1783,7 +1783,7 @@ GENERATE_RTF = NO # The default directory is: rtf. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_OUTPUT = rtf +RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some @@ -1791,7 +1791,7 @@ RTF_OUTPUT = rtf # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. -COMPACT_RTF = NO +COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will # contain hyperlink fields. The RTF file will contain links (just like the HTML @@ -1803,7 +1803,7 @@ COMPACT_RTF = NO # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_HYPERLINKS = NO +RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's config # file, i.e. a series of assignments. You only have to provide replacements, @@ -1813,14 +1813,14 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = # If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code # with syntax highlighting in the RTF output. @@ -1830,7 +1830,7 @@ RTF_EXTENSIONS_FILE = # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_SOURCE_CODE = NO +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output @@ -1840,7 +1840,7 @@ RTF_SOURCE_CODE = NO # classes and files. # The default value is: NO. -GENERATE_MAN = NO +GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1849,7 +1849,7 @@ GENERATE_MAN = NO # The default directory is: man. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_OUTPUT = man +MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to the generated # man pages. In case the manual section does not start with a number, the number @@ -1858,14 +1858,14 @@ MAN_OUTPUT = man # The default value is: .3. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_EXTENSION = .3 +MAN_EXTENSION = .3 # The MAN_SUBDIR tag determines the name of the directory created within # MAN_OUTPUT in which the man pages are placed. If defaults to man followed by # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_SUBDIR = +MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real @@ -1874,7 +1874,7 @@ MAN_SUBDIR = # The default value is: NO. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_LINKS = NO +MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output @@ -1884,7 +1884,7 @@ MAN_LINKS = NO # captures the structure of the code including all documentation. # The default value is: NO. -GENERATE_XML = NO +GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1892,7 +1892,7 @@ GENERATE_XML = NO # The default directory is: xml. # This tag requires that the tag GENERATE_XML is set to YES. -XML_OUTPUT = xml +XML_OUTPUT = xml # If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to @@ -1901,7 +1901,7 @@ XML_OUTPUT = xml # The default value is: YES. # This tag requires that the tag GENERATE_XML is set to YES. -XML_PROGRAMLISTING = YES +XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output @@ -1911,7 +1911,7 @@ XML_PROGRAMLISTING = YES # that can be used to generate PDF. # The default value is: NO. -GENERATE_DOCBOOK = NO +GENERATE_DOCBOOK = NO # The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in @@ -1919,7 +1919,7 @@ GENERATE_DOCBOOK = NO # The default directory is: docbook. # This tag requires that the tag GENERATE_DOCBOOK is set to YES. -DOCBOOK_OUTPUT = docbook +DOCBOOK_OUTPUT = docbook # If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the # program listings (including syntax highlighting and cross-referencing @@ -1940,7 +1940,7 @@ DOCBOOK_PROGRAMLISTING = NO # still experimental and incomplete at the moment. # The default value is: NO. -GENERATE_AUTOGEN_DEF = NO +GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output @@ -1952,7 +1952,7 @@ GENERATE_AUTOGEN_DEF = NO # Note that this feature is still experimental and incomplete at the moment. # The default value is: NO. -GENERATE_PERLMOD = NO +GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI @@ -1960,7 +1960,7 @@ GENERATE_PERLMOD = NO # The default value is: NO. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_LATEX = NO +PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to @@ -1970,7 +1970,7 @@ PERLMOD_LATEX = NO # The default value is: YES. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_PRETTY = YES +PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file are # prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful @@ -1978,7 +1978,7 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor @@ -1988,7 +1988,7 @@ PERLMOD_MAKEVAR_PREFIX = # C-preprocessor directives found in the sources and include files. # The default value is: YES. -ENABLE_PREPROCESSING = YES +ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names # in the source code. If set to NO, only conditional compilation will be @@ -1997,7 +1997,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2005,21 +2005,21 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -SEARCH_INCLUDES = YES +SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = +INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -2027,7 +2027,7 @@ INCLUDE_PATH = # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -2037,7 +2037,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2046,7 +2046,7 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -2056,7 +2056,7 @@ EXPAND_AS_DEFINED = # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -SKIP_FUNCTION_MACROS = YES +SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references @@ -2075,40 +2075,40 @@ SKIP_FUNCTION_MACROS = YES # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES, all external class will be listed in # the class index. If set to NO, only the inherited external classes will be # listed. # The default value is: NO. -ALLEXTERNALS = NO +ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed # in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. -EXTERNAL_GROUPS = YES +EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. -EXTERNAL_PAGES = YES +EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of 'which perl'). # The default file (with absolute path) is: /usr/bin/perl. -PERL_PATH = /usr/bin/perl +PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool @@ -2121,7 +2121,7 @@ PERL_PATH = /usr/bin/perl # powerful graphs. # The default value is: YES. -CLASS_DIAGRAMS = YES +CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see: @@ -2130,20 +2130,20 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. -HIDE_UNDOC_RELATIONS = YES +HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: @@ -2152,7 +2152,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: YES. -HAVE_DOT = YES +HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2162,7 +2162,7 @@ HAVE_DOT = YES # Minimum value: 0, maximum value: 32, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_NUM_THREADS = 0 +DOT_NUM_THREADS = 0 # When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make @@ -2172,21 +2172,21 @@ DOT_NUM_THREADS = 0 # The default value is: Helvetica. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # dot graphs. # Minimum value: 4, maximum value: 24, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the default font as specified with # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2194,7 +2194,7 @@ DOT_FONTPATH = # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -CLASS_GRAPH = YES +CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation @@ -2203,14 +2203,14 @@ CLASS_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -COLLABORATION_GRAPH = YES +COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for # groups, showing the direct groups dependencies. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GROUP_GRAPHS = YES +GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling @@ -2218,7 +2218,7 @@ GROUP_GRAPHS = YES # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -UML_LOOK = NO +UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside the # class node. If there are many fields or methods and many nodes the graph may @@ -2231,7 +2231,7 @@ UML_LOOK = NO # Minimum value: 0, maximum value: 100, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. -UML_LIMIT_NUM_FIELDS = 10 +UML_LIMIT_NUM_FIELDS = 10 # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their @@ -2239,7 +2239,7 @@ UML_LIMIT_NUM_FIELDS = 10 # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -TEMPLATE_RELATIONS = NO +TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the @@ -2248,7 +2248,7 @@ TEMPLATE_RELATIONS = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDE_GRAPH = YES +INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing @@ -2257,7 +2257,7 @@ INCLUDE_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -INCLUDED_BY_GRAPH = YES +INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH tag is set to YES then doxygen will generate a call # dependency graph for every global function or class method. @@ -2269,7 +2269,7 @@ INCLUDED_BY_GRAPH = YES # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -CALL_GRAPH = NO +CALL_GRAPH = NO # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller # dependency graph for every global function or class method. @@ -2281,14 +2281,14 @@ CALL_GRAPH = NO # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -CALLER_GRAPH = NO +CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical # hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GRAPHICAL_HIERARCHY = YES +GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The @@ -2297,7 +2297,7 @@ GRAPHICAL_HIERARCHY = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -DIRECTORY_GRAPH = YES +DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section @@ -2314,7 +2314,7 @@ DIRECTORY_GRAPH = YES # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. @@ -2326,32 +2326,32 @@ DOT_IMAGE_FORMAT = png # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -INTERACTIVE_SVG = NO +INTERACTIVE_SVG = NO # The DOT_PATH tag can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file. If left blank, it is assumed @@ -2359,12 +2359,12 @@ DIAFILE_DIRS = # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. -PLANTUML_INCLUDE_PATH = +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2376,7 +2376,7 @@ PLANTUML_INCLUDE_PATH = # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_GRAPH_MAX_NODES = 50 +DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # generated by dot. A depth value of 3 means that only nodes reachable from the @@ -2388,7 +2388,7 @@ DOT_GRAPH_MAX_NODES = 50 # Minimum value: 0, maximum value: 1000, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. -MAX_DOT_GRAPH_DEPTH = 0 +MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not seem @@ -2400,7 +2400,7 @@ MAX_DOT_GRAPH_DEPTH = 0 # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_TRANSPARENT = NO +DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This @@ -2409,7 +2409,7 @@ DOT_TRANSPARENT = NO # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_MULTI_TARGETS = NO +DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated @@ -2417,11 +2417,11 @@ DOT_MULTI_TARGETS = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GENERATE_LEGEND = YES +GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_CLEANUP = YES +DOT_CLEANUP = YES diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile index 7ee5a204629..fa983cb1d6c 100644 --- a/src/lib/netlist/build/makefile +++ b/src/lib/netlist/build/makefile @@ -50,6 +50,7 @@ POBJS := \ $(POBJ)/pchrono.o \ $(POBJ)/pdynlib.o \ $(POBJ)/pexception.o \ + $(POBJ)/pfunction.o \ $(POBJ)/pfmtlog.o \ $(POBJ)/poptions.o \ $(POBJ)/pparser.o \ @@ -63,9 +64,9 @@ NLOBJS := \ $(NLOBJ)/nl_setup.o \ $(NLOBJ)/nl_factory.o \ $(NLOBJ)/analog/nld_bjt.o \ - $(NLOBJ)/analog/nld_fourterm.o \ + $(NLOBJ)/analog/nlid_fourterm.o \ $(NLOBJ)/analog/nld_switches.o \ - $(NLOBJ)/analog/nld_twoterm.o \ + $(NLOBJ)/analog/nlid_twoterm.o \ $(NLOBJ)/analog/nld_opamps.o \ $(NLOBJ)/devices/nld_2102A.o \ $(NLOBJ)/devices/nld_2716.o \ @@ -114,7 +115,7 @@ NLOBJS := \ $(NLOBJ)/devices/nld_log.o \ $(NLOBJ)/devices/nlid_proxy.o \ $(NLOBJ)/devices/nld_system.o \ - $(NLOBJ)/devices/nld_truthtable.o \ + $(NLOBJ)/devices/nlid_truthtable.o \ $(NLOBJ)/macro/nlm_base.o \ $(NLOBJ)/macro/nlm_cd4xxx.o \ $(NLOBJ)/macro/nlm_opamp.o \ @@ -169,7 +170,7 @@ maketree: $(sort $(OBJDIRS)) .PHONY: clang mingw doc clang: - $(MAKE) CC=clang++ LD=clang++ CEXTRAFLAGS="-march=native -Weverything -Werror -Wno-padded -Wno-weak-vtables -Wno-missing-variable-declarations -Wconversion -Wno-c++98-compat -Wno-float-equal -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-weak-template-vtables -Wno-exit-time-destructors" + $(MAKE) CC=clang++-5.0 LD=clang++-5.0 CEXTRAFLAGS="-march=native -Weverything -Werror -Wno-padded -Wno-weak-vtables -Wno-missing-variable-declarations -Wconversion -Wno-c++98-compat -Wno-float-equal -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-weak-template-vtables -Wno-exit-time-destructors" # # Mostly done: -Wno-weak-vtables -Wno-cast-align diff --git a/src/lib/netlist/devices/net_lib.cpp b/src/lib/netlist/devices/net_lib.cpp index 502f044ec76..bc1d7051b39 100644 --- a/src/lib/netlist/devices/net_lib.cpp +++ b/src/lib/netlist/devices/net_lib.cpp @@ -9,60 +9,62 @@ ****************************************************************************/ #include "net_lib.h" -#include "nld_system.h" #include "nl_factory.h" #include "solver/nld_solver.h" + #define xstr(s) # s + +#if 0 #define ENTRY1(nic, name, defparam) factory.register_device<nic>( # name, xstr(nic), defparam ); #define ENTRY(nic, name, defparam) ENTRY1(NETLIB_NAME(nic), name, defparam) +#endif #define NETLIB_DEVICE_DECL(chip) extern factory::constructor_ptr_t decl_ ## chip; -#define ENTRYX1(nic, name, defparam, decl) factory.register_device( decl (# name, xstr(nic), defparam) ); +//#define ENTRYX1(nic, name, defparam, decl) factory.register_device( decl (# name, xstr(nic), defparam) ); +#define ENTRYX1(nic, name, defparam, decl) factory.register_device( decl (pstring(# name), pstring(xstr(nic)), pstring(defparam)) ); #define ENTRYX(nic, name, defparam) { NETLIB_DEVICE_DECL(nic) ENTRYX1(NETLIB_NAME(nic), name, defparam, decl_ ## nic) } namespace netlist { - using namespace netlist::analog; - namespace devices { -static void initialize_factory(factory::list_t &factory) + void initialize_factory(factory::list_t &factory) { - ENTRY(R, RES, "R") - ENTRY(POT, POT, "R") - ENTRY(POT2, POT2, "R") - ENTRY(C, CAP, "C") - ENTRY(L, IND, "L") - ENTRY(D, DIODE, "MODEL") - ENTRY(VCVS, VCVS, "") - ENTRY(VCCS, VCCS, "") - ENTRY(CCCS, CCCS, "") - ENTRY(LVCCS, LVCCS, "") - ENTRY(VS, VS, "V") - ENTRY(CS, CS, "I") - ENTRYX(opamp, OPAMP, "MODEL") + ENTRYX(R, RES, "R") + ENTRYX(POT, POT, "R") + ENTRYX(POT2, POT2, "R") + ENTRYX(C, CAP, "C") + ENTRYX(L, IND, "L") + ENTRYX(D, DIODE, "MODEL") + ENTRYX(VS, VS, "V") + ENTRYX(CS, CS, "I") + ENTRYX(VCVS, VCVS, "") + ENTRYX(VCCS, VCCS, "") + ENTRYX(CCCS, CCCS, "") + ENTRYX(LVCCS, LVCCS, "") + ENTRYX(opamp, OPAMP, "MODEL") ENTRYX(dummy_input, DUMMY_INPUT, "") ENTRYX(frontier, FRONTIER_DEV, "+I,+G,+Q") // not intended to be used directly ENTRYX(function, AFUNC, "N,FUNC") // only for macro devices - NO FEEDBACK loops - ENTRY(QBJT_EB, QBJT_EB, "MODEL") - ENTRY(QBJT_switch, QBJT_SW, "MODEL") + ENTRYX(QBJT_EB, QBJT_EB, "MODEL") + ENTRYX(QBJT_switch, QBJT_SW, "MODEL") ENTRYX(logic_input, TTL_INPUT, "IN") ENTRYX(logic_input, LOGIC_INPUT, "IN,FAMILY") ENTRYX(analog_input, ANALOG_INPUT, "IN") ENTRYX(log, LOG, "+I") ENTRYX(logD, LOGD, "+I,+I2") ENTRYX(clock, CLOCK, "FREQ") - ENTRYX(extclock, EXTCLOCK, "FREQ") + ENTRYX(extclock, EXTCLOCK, "FREQ,PATTERN") ENTRYX(mainclock, MAINCLOCK, "FREQ") ENTRYX(gnd, GND, "") ENTRYX(netlistparams, PARAMETER, "") - ENTRY(solver, SOLVER, "FREQ") + ENTRYX(solver, SOLVER, "FREQ") ENTRYX(res_sw, RES_SWITCH, "+IN,+P1,+P2") ENTRYX(switch1, SWITCH, "") ENTRYX(switch2, SWITCH2, "") - ENTRYX(nicRSFF, NETDEV_RSFF, "+S,+R") + ENTRYX(nicRSFF, NETDEV_RSFF, "") ENTRYX(nicDelay, NETDEV_DELAY, "") ENTRYX(2716, EPROM_2716, "+GQ,+EPQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10") ENTRYX(2102A, RAM_2102A, "+CEQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+RWQ,+DI") @@ -158,10 +160,3 @@ static void initialize_factory(factory::list_t &factory) } //namespace devices } // namespace netlist -namespace netlist -{ - void initialize_factory(factory::list_t &factory) - { - devices::initialize_factory(factory); - } -} diff --git a/src/lib/netlist/devices/net_lib.h b/src/lib/netlist/devices/net_lib.h index 9bbd9db744a..9ac05f9bccb 100644 --- a/src/lib/netlist/devices/net_lib.h +++ b/src/lib/netlist/devices/net_lib.h @@ -11,7 +11,28 @@ #ifndef NET_LIB_H #define NET_LIB_H -#include "nl_base.h" +#include "nl_setup.h" + +//#define NL_AUTO_DEVICES 1 + +#ifdef NL_AUTO_DEVICES +#include "nld_devinc.h" + +#include "solver/nld_solver.h" + +#include "macro/nlm_cd4xxx.h" +#include "macro/nlm_ttl74xx.h" +#include "macro/nlm_opamp.h" +#include "macro/nlm_other.h" + +#include "nld_7448.h" + +#else + +#define SOLVER(name, freq) \ + NET_REGISTER_DEV(SOLVER, name) \ + PARAM(name.FREQ, freq) + #include "nld_system.h" #include "nld_2102A.h" @@ -72,12 +93,8 @@ #include "analog/nld_switches.h" #include "analog/nld_twoterm.h" #include "analog/nld_opamps.h" -#include "solver/nld_solver.h" #include "nld_legacy.h" - -namespace netlist { - void initialize_factory(factory::list_t &factory); -} +#endif #endif diff --git a/src/lib/netlist/devices/nld_2102A.cpp b/src/lib/netlist/devices/nld_2102A.cpp index 8dbd5be8fec..803f5b523c9 100644 --- a/src/lib/netlist/devices/nld_2102A.cpp +++ b/src/lib/netlist/devices/nld_2102A.cpp @@ -6,6 +6,7 @@ */ #include "nld_2102A.h" +#include "nl_base.h" #define ADDR2BYTE(a) ((a) >> 3) #define ADDR2BIT(a) ((a) & 0x7) diff --git a/src/lib/netlist/devices/nld_2716.cpp b/src/lib/netlist/devices/nld_2716.cpp index 7ba974b92da..aa491c47d3c 100644 --- a/src/lib/netlist/devices/nld_2716.cpp +++ b/src/lib/netlist/devices/nld_2716.cpp @@ -6,6 +6,7 @@ */ #include "nld_2716.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_4020.cpp b/src/lib/netlist/devices/nld_4020.cpp index a147cf3f58f..14459fb3b62 100644 --- a/src/lib/netlist/devices/nld_4020.cpp +++ b/src/lib/netlist/devices/nld_4020.cpp @@ -5,7 +5,7 @@ * */ -#include <devices/nlid_cmos.h> +#include "devices/nlid_cmos.h" #include "nld_4020.h" namespace netlist diff --git a/src/lib/netlist/devices/nld_4066.cpp b/src/lib/netlist/devices/nld_4066.cpp index f33688b73b7..11dca7b11dd 100644 --- a/src/lib/netlist/devices/nld_4066.cpp +++ b/src/lib/netlist/devices/nld_4066.cpp @@ -5,8 +5,8 @@ * */ -#include <devices/nlid_cmos.h> -#include "analog/nld_twoterm.h" +#include "devices/nlid_cmos.h" +#include "analog/nlid_twoterm.h" #include "nld_4066.h" namespace netlist diff --git a/src/lib/netlist/devices/nld_4316.cpp b/src/lib/netlist/devices/nld_4316.cpp index 8b9cb0d46ad..5c86f885545 100644 --- a/src/lib/netlist/devices/nld_4316.cpp +++ b/src/lib/netlist/devices/nld_4316.cpp @@ -5,8 +5,8 @@ * */ -#include <devices/nlid_cmos.h> -#include "analog/nld_twoterm.h" +#include "devices/nlid_cmos.h" +#include "analog/nlid_twoterm.h" #include "nld_4316.h" namespace netlist { namespace devices { diff --git a/src/lib/netlist/devices/nld_74107.cpp b/src/lib/netlist/devices/nld_74107.cpp index a9006d55a75..3a3c43ac0fa 100644 --- a/src/lib/netlist/devices/nld_74107.cpp +++ b/src/lib/netlist/devices/nld_74107.cpp @@ -6,6 +6,7 @@ */ #include "nld_74107.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74123.cpp b/src/lib/netlist/devices/nld_74123.cpp index bcbfdcb106a..514ea4e9390 100644 --- a/src/lib/netlist/devices/nld_74123.cpp +++ b/src/lib/netlist/devices/nld_74123.cpp @@ -5,10 +5,10 @@ * */ -#include "nld_74123.h" - #include "nlid_system.h" -#include "analog/nld_twoterm.h" +#include "analog/nlid_twoterm.h" + +#include <cmath> namespace netlist { diff --git a/src/lib/netlist/devices/nld_74153.cpp b/src/lib/netlist/devices/nld_74153.cpp index fb97411e350..efa6322e514 100644 --- a/src/lib/netlist/devices/nld_74153.cpp +++ b/src/lib/netlist/devices/nld_74153.cpp @@ -6,6 +6,7 @@ */ #include "nld_74153.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74161.cpp b/src/lib/netlist/devices/nld_74161.cpp index d6e31f36417..4579fa41b7a 100644 --- a/src/lib/netlist/devices/nld_74161.cpp +++ b/src/lib/netlist/devices/nld_74161.cpp @@ -8,6 +8,7 @@ #define MAXCNT 15 #include "nld_74161.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74165.cpp b/src/lib/netlist/devices/nld_74165.cpp index bb263409bf9..c967f95d44c 100644 --- a/src/lib/netlist/devices/nld_74165.cpp +++ b/src/lib/netlist/devices/nld_74165.cpp @@ -6,6 +6,7 @@ */ #include "nld_74165.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74166.cpp b/src/lib/netlist/devices/nld_74166.cpp index 5cb7114ee0f..d56159183b0 100644 --- a/src/lib/netlist/devices/nld_74166.cpp +++ b/src/lib/netlist/devices/nld_74166.cpp @@ -6,6 +6,7 @@ */ #include "nld_74166.h" +#include "nl_base.h" namespace netlist { @@ -82,7 +83,7 @@ namespace netlist netlist_time delay = NLTIME_FROM_NS(26); if (m_CLRQ()) { - bool clear_unset = !m_last_CLRQ(); + bool clear_unset = !m_last_CLRQ; if (clear_unset) { delay = NLTIME_FROM_NS(35); diff --git a/src/lib/netlist/devices/nld_74174.cpp b/src/lib/netlist/devices/nld_74174.cpp index 64698423435..d131b18af23 100644 --- a/src/lib/netlist/devices/nld_74174.cpp +++ b/src/lib/netlist/devices/nld_74174.cpp @@ -6,6 +6,7 @@ */ #include "nld_74174.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74175.cpp b/src/lib/netlist/devices/nld_74175.cpp index 4d8e3608ee8..3055a73f2c9 100644 --- a/src/lib/netlist/devices/nld_74175.cpp +++ b/src/lib/netlist/devices/nld_74175.cpp @@ -6,6 +6,7 @@ */ #include "nld_74175.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74192.cpp b/src/lib/netlist/devices/nld_74192.cpp index 80e1853b7f7..77029cfdf50 100644 --- a/src/lib/netlist/devices/nld_74192.cpp +++ b/src/lib/netlist/devices/nld_74192.cpp @@ -8,6 +8,7 @@ #define MAXCNT 9 #include "nld_74192.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74193.cpp b/src/lib/netlist/devices/nld_74193.cpp index 3d32596dbee..f5370719778 100644 --- a/src/lib/netlist/devices/nld_74193.cpp +++ b/src/lib/netlist/devices/nld_74193.cpp @@ -8,6 +8,7 @@ #define MAXCNT 15 #include "nld_74193.h" +#include "nl_base.h" namespace netlist { @@ -136,8 +137,8 @@ namespace netlist for (std::size_t i=0; i<4; i++) m_Q[i].push((m_cnt >> i) & 1, delay[i]); - m_BORROWQ.push(tBorrow, NLTIME_FROM_NS(20)); //FIXME - m_CARRYQ.push(tCarry, NLTIME_FROM_NS(20)); //FIXME + m_BORROWQ.push(tBorrow, NLTIME_FROM_NS(20)); //FIXME timing + m_CARRYQ.push(tCarry, NLTIME_FROM_NS(20)); //FIXME timing } NETLIB_DEVICE_IMPL(74193) diff --git a/src/lib/netlist/devices/nld_74194.cpp b/src/lib/netlist/devices/nld_74194.cpp index e951e351e93..4fe5092f4d5 100644 --- a/src/lib/netlist/devices/nld_74194.cpp +++ b/src/lib/netlist/devices/nld_74194.cpp @@ -6,6 +6,7 @@ */ #include "nld_74194.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_74194.h b/src/lib/netlist/devices/nld_74194.h index 944d9537754..8d07b685e55 100644 --- a/src/lib/netlist/devices/nld_74194.h +++ b/src/lib/netlist/devices/nld_74194.h @@ -28,17 +28,17 @@ #include "nl_setup.h" -#define TTL_74194(name, cCLK, cS0, cS1, cSRIN, cA, cB, cC, cD, cSLIN, cCLRQ) \ - NET_REGISTER_DEV(TTL_74194, name) \ - NET_CONNECT(name, CLK, cCLK) \ - NET_CONNECT(name, S0, cS0) \ - NET_CONNECT(name, S1, cS1) \ - NET_CONNECT(name, SRIN, cSRIN) \ - NET_CONNECT(name, A, cA) \ - NET_CONNECT(name, B, cB) \ - NET_CONNECT(name, C, cC) \ - NET_CONNECT(name, D, cD) \ - NET_CONNECT(name, SLIN, cSLIN) \ +#define TTL_74194(name, cCLK, cS0, cS1, cSRIN, cA, cB, cC, cD, cSLIN, cCLRQ) \ + NET_REGISTER_DEV(TTL_74194, name) \ + NET_CONNECT(name, CLK, cCLK) \ + NET_CONNECT(name, S0, cS0) \ + NET_CONNECT(name, S1, cS1) \ + NET_CONNECT(name, SRIN, cSRIN) \ + NET_CONNECT(name, A, cA) \ + NET_CONNECT(name, B, cB) \ + NET_CONNECT(name, C, cC) \ + NET_CONNECT(name, D, cD) \ + NET_CONNECT(name, SLIN, cSLIN) \ NET_CONNECT(name, CLRQ, cCLRQ) #define TTL_74194_DIP(name) \ diff --git a/src/lib/netlist/devices/nld_74279.cpp b/src/lib/netlist/devices/nld_74279.cpp index 48c2e7e095b..ff8f12e07ea 100644 --- a/src/lib/netlist/devices/nld_74279.cpp +++ b/src/lib/netlist/devices/nld_74279.cpp @@ -5,8 +5,9 @@ * */ +#include "nlid_truthtable.h" #include "nld_74279.h" -#include "nld_truthtable.h" +#include "nl_base.h" namespace netlist { @@ -56,7 +57,7 @@ namespace netlist nld_74279A::truthtable_t nld_74279A::m_ttbl; nld_74279B::truthtable_t nld_74279B::m_ttbl; - const char *nld_74279A::m_desc[] = { + const pstring nld_74279A::m_desc[] = { "S,R,_Q|Q", "0,X,X|1|22", "1,0,X|0|27", @@ -66,7 +67,7 @@ namespace netlist }; - const char *nld_74279B::m_desc[] = { + const pstring nld_74279B::m_desc[] = { "S1,S2,R,_Q|Q", "0,X,X,X|1|22", "X,0,X,X|1|22", diff --git a/src/lib/netlist/devices/nld_74365.cpp b/src/lib/netlist/devices/nld_74365.cpp index 34eafb0856e..f008b721344 100644 --- a/src/lib/netlist/devices/nld_74365.cpp +++ b/src/lib/netlist/devices/nld_74365.cpp @@ -6,6 +6,7 @@ */ #include "nld_74365.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7448.cpp b/src/lib/netlist/devices/nld_7448.cpp index 8b4d11c374b..a4b358c3da5 100644 --- a/src/lib/netlist/devices/nld_7448.cpp +++ b/src/lib/netlist/devices/nld_7448.cpp @@ -5,8 +5,8 @@ * */ +#include "nlid_truthtable.h" #include "nld_7448.h" -#include "nld_truthtable.h" namespace netlist { @@ -14,7 +14,7 @@ namespace netlist { #if (USE_TRUTHTABLE_7448 && USE_TRUTHTABLE) - NETLIB_TRUTHTABLE(7448, 7, 7, 0); + NETLIB_TRUTHTABLE(7448, 7, 7); #else @@ -80,7 +80,7 @@ namespace netlist #if (USE_TRUTHTABLE_7448 && USE_TRUTHTABLE) nld_7448::truthtable_t nld_7448::m_ttbl; - const char *nld_7448::m_desc[] = { + const pstring nld_7448::m_desc[] = { " LTQ,BIQ,RBIQ, A , B , C , D | a, b, c, d, e, f, g", " 1, 1, 1, 0, 0, 0, 0 | 1, 1, 1, 1, 1, 1, 0|100,100,100,100,100,100,100", diff --git a/src/lib/netlist/devices/nld_7448.h b/src/lib/netlist/devices/nld_7448.h index 199b46343a8..24cdcb8f6f1 100644 --- a/src/lib/netlist/devices/nld_7448.h +++ b/src/lib/netlist/devices/nld_7448.h @@ -24,7 +24,7 @@ #ifndef NLD_7448_H_ #define NLD_7448_H_ -#include "nl_base.h" +#include "nl_setup.h" /* * FIXME: Using truthtable is a lot slower than the explicit device @@ -34,6 +34,8 @@ #define USE_TRUTHTABLE_7448 (0) +#ifndef NL_AUTO_DEVICES + #define TTL_7448(name, cA0, cA1, cA2, cA3, cLTQ, cBIQ, cRBIQ) \ NET_REGISTER_DEV(TTL_7448, name) \ NET_CONNECT(name, A, cA0) \ @@ -47,4 +49,6 @@ #define TTL_7448_DIP(name) \ NET_REGISTER_DEV(TTL_7448_DIP, name) +#endif + #endif /* NLD_7448_H_ */ diff --git a/src/lib/netlist/devices/nld_7450.cpp b/src/lib/netlist/devices/nld_7450.cpp index 007f899a5f9..2ad560b1d07 100644 --- a/src/lib/netlist/devices/nld_7450.cpp +++ b/src/lib/netlist/devices/nld_7450.cpp @@ -6,6 +6,7 @@ */ #include "nld_7450.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7473.cpp b/src/lib/netlist/devices/nld_7473.cpp index fc73b97c201..3c88b0f8167 100644 --- a/src/lib/netlist/devices/nld_7473.cpp +++ b/src/lib/netlist/devices/nld_7473.cpp @@ -6,6 +6,7 @@ */ #include "nld_7473.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7474.cpp b/src/lib/netlist/devices/nld_7474.cpp index f11ccbd2164..627d3a9b48a 100644 --- a/src/lib/netlist/devices/nld_7474.cpp +++ b/src/lib/netlist/devices/nld_7474.cpp @@ -6,6 +6,7 @@ */ #include "nld_7474.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7475.cpp b/src/lib/netlist/devices/nld_7475.cpp index 3c26c1ce439..7bf3f14d7f2 100644 --- a/src/lib/netlist/devices/nld_7475.cpp +++ b/src/lib/netlist/devices/nld_7475.cpp @@ -7,6 +7,7 @@ */ #include "nld_7475.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7483.cpp b/src/lib/netlist/devices/nld_7483.cpp index a11f36c1540..518026e7fe5 100644 --- a/src/lib/netlist/devices/nld_7483.cpp +++ b/src/lib/netlist/devices/nld_7483.cpp @@ -6,6 +6,7 @@ */ #include "nld_7483.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7485.cpp b/src/lib/netlist/devices/nld_7485.cpp index b4237a6426d..4526b9001ea 100644 --- a/src/lib/netlist/devices/nld_7485.cpp +++ b/src/lib/netlist/devices/nld_7485.cpp @@ -6,6 +6,7 @@ */ #include "nld_7485.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7490.cpp b/src/lib/netlist/devices/nld_7490.cpp index e395c64120e..a85ccbcfbcb 100644 --- a/src/lib/netlist/devices/nld_7490.cpp +++ b/src/lib/netlist/devices/nld_7490.cpp @@ -6,6 +6,7 @@ */ #include "nld_7490.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_7493.cpp b/src/lib/netlist/devices/nld_7493.cpp index 557d7fa42b6..df6ab4ad668 100644 --- a/src/lib/netlist/devices/nld_7493.cpp +++ b/src/lib/netlist/devices/nld_7493.cpp @@ -6,7 +6,7 @@ */ #include "nld_7493.h" -#include "nl_setup.h" +#include "nl_base.h" namespace netlist { @@ -29,8 +29,8 @@ namespace netlist logic_input_t m_I; logic_output_t m_Q; - state_var_u8 m_reset; - state_var_u8 m_state; + state_var<netlist_sig_t> m_reset; + state_var<netlist_sig_t> m_state; }; NETLIB_OBJECT(7493) @@ -99,7 +99,7 @@ namespace netlist NETLIB_UPDATE(7493ff) { - constexpr netlist_time out_delay = NLTIME_FROM_NS(18); + static constexpr netlist_time out_delay = NLTIME_FROM_NS(18); if (m_reset) { m_state ^= 1; diff --git a/src/lib/netlist/devices/nld_74ls629.cpp b/src/lib/netlist/devices/nld_74ls629.cpp index 07eee6f5a57..26a5aaf2220 100644 --- a/src/lib/netlist/devices/nld_74ls629.cpp +++ b/src/lib/netlist/devices/nld_74ls629.cpp @@ -40,7 +40,7 @@ #include "nld_74ls629.h" -#include "analog/nld_twoterm.h" +#include "analog/nlid_twoterm.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_82S115.cpp b/src/lib/netlist/devices/nld_82S115.cpp index c01d013aec5..855e22c0f87 100644 --- a/src/lib/netlist/devices/nld_82S115.cpp +++ b/src/lib/netlist/devices/nld_82S115.cpp @@ -6,6 +6,7 @@ */ #include "nld_82S115.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_82S115.h b/src/lib/netlist/devices/nld_82S115.h index 0c900e4dad7..1ceb22dc1b1 100644 --- a/src/lib/netlist/devices/nld_82S115.h +++ b/src/lib/netlist/devices/nld_82S115.h @@ -30,19 +30,19 @@ #include "nl_setup.h" -#define PROM_82S115(name, cCE1Q, cCE2, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7, cA8, cSTROBE) \ - NET_REGISTER_DEV(PROM_82S115, name) \ - NET_CONNECT(name, CE1Q, cCE1Q) \ - NET_CONNECT(name, CE2, cCE2) \ - NET_CONNECT(name, A0, cA0) \ - NET_CONNECT(name, A1, cA1) \ - NET_CONNECT(name, A2, cA2) \ - NET_CONNECT(name, A3, cA3) \ - NET_CONNECT(name, A4, cA4) \ - NET_CONNECT(name, A5, cA5) \ - NET_CONNECT(name, A6, cA6) \ - NET_CONNECT(name, A7, cA7) \ - NET_CONNECT(name, A8, cA8) \ +#define PROM_82S115(name, cCE1Q, cCE2, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7, cA8, cSTROBE) \ + NET_REGISTER_DEV(PROM_82S115, name) \ + NET_CONNECT(name, CE1Q, cCE1Q) \ + NET_CONNECT(name, CE2, cCE2) \ + NET_CONNECT(name, A0, cA0) \ + NET_CONNECT(name, A1, cA1) \ + NET_CONNECT(name, A2, cA2) \ + NET_CONNECT(name, A3, cA3) \ + NET_CONNECT(name, A4, cA4) \ + NET_CONNECT(name, A5, cA5) \ + NET_CONNECT(name, A6, cA6) \ + NET_CONNECT(name, A7, cA7) \ + NET_CONNECT(name, A8, cA8) \ NET_CONNECT(name, STROBE, cSTROBE) #define PROM_82S115_DIP(name) \ diff --git a/src/lib/netlist/devices/nld_82S123.cpp b/src/lib/netlist/devices/nld_82S123.cpp index f9e97174d4a..2152bd738eb 100644 --- a/src/lib/netlist/devices/nld_82S123.cpp +++ b/src/lib/netlist/devices/nld_82S123.cpp @@ -6,6 +6,7 @@ */ #include "nld_82S123.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_82S126.cpp b/src/lib/netlist/devices/nld_82S126.cpp index d3a86ce84ee..221b7425c8d 100644 --- a/src/lib/netlist/devices/nld_82S126.cpp +++ b/src/lib/netlist/devices/nld_82S126.cpp @@ -6,6 +6,7 @@ */ #include "nld_82S126.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_82S16.cpp b/src/lib/netlist/devices/nld_82S16.cpp index fccdc8b1044..a2a199a61d5 100644 --- a/src/lib/netlist/devices/nld_82S16.cpp +++ b/src/lib/netlist/devices/nld_82S16.cpp @@ -6,6 +6,7 @@ */ #include "nld_82S16.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_9310.cpp b/src/lib/netlist/devices/nld_9310.cpp index 4ddb62af519..dd448c4282b 100644 --- a/src/lib/netlist/devices/nld_9310.cpp +++ b/src/lib/netlist/devices/nld_9310.cpp @@ -6,6 +6,7 @@ */ #include "nld_9310.h" +#include "nl_base.h" #define MAXCNT 9 @@ -158,21 +159,22 @@ namespace netlist { if (m_loadq) { - switch (m_cnt()) + if (m_cnt < MAXCNT - 1) { - case MAXCNT - 1: - m_cnt = MAXCNT; - m_RC.push(m_ent, NLTIME_FROM_NS(20)); - m_QA.push(1, NLTIME_FROM_NS(20)); - break; - case MAXCNT: - m_RC.push(0, NLTIME_FROM_NS(20)); - m_cnt = 0; - update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); - break; - default: - m_cnt++; - update_outputs(m_cnt); + m_cnt++; + update_outputs(m_cnt); + } + else if (m_cnt == MAXCNT - 1) + { + m_cnt = MAXCNT; + m_RC.push(m_ent, NLTIME_FROM_NS(20)); + m_QA.push(1, NLTIME_FROM_NS(20)); + } + else // MAXCNT + { + m_RC.push(0, NLTIME_FROM_NS(20)); + m_cnt = 0; + update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); } } else diff --git a/src/lib/netlist/devices/nld_9312.cpp b/src/lib/netlist/devices/nld_9312.cpp index 2ad298f368a..b3fe0545f81 100644 --- a/src/lib/netlist/devices/nld_9312.cpp +++ b/src/lib/netlist/devices/nld_9312.cpp @@ -20,8 +20,8 @@ * | 1 | 1 | 1 | 0 || D7|D7Q| * +---+---+---+---++---+---+ */ +#include "nlid_truthtable.h" #include "nld_9312.h" -#include "nld_truthtable.h" namespace netlist { @@ -130,7 +130,7 @@ namespace netlist * do this right now. */ - const char *nld_9312::m_desc[] = { + const pstring nld_9312::m_desc[] = { " C, B, A, G,D0,D1,D2,D3,D4,D5,D6,D7| Y,YQ", " X, X, X, 1, X, X, X, X, X, X, X, X| 0, 1|33,19", " 0, 0, 0, 0, 0, X, X, X, X, X, X, X| 0, 1|33,28", diff --git a/src/lib/netlist/devices/nld_9312.h b/src/lib/netlist/devices/nld_9312.h index 98cc0d115c8..c85d86d2773 100644 --- a/src/lib/netlist/devices/nld_9312.h +++ b/src/lib/netlist/devices/nld_9312.h @@ -39,19 +39,19 @@ #include "nl_setup.h" -#define TTL_9312(name, cA, cB, cC, cD0, cD1, cD2, cD3, cD4, cD5, cD6, cD7, cSTROBE) \ - NET_REGISTER_DEV(TTL_9312, name) \ - NET_CONNECT(name, A, cA) \ - NET_CONNECT(name, B, cB) \ - NET_CONNECT(name, C, cC) \ - NET_CONNECT(name, D0, cD0) \ - NET_CONNECT(name, D1, cD1) \ - NET_CONNECT(name, D2, cD2) \ - NET_CONNECT(name, D3, cD3) \ - NET_CONNECT(name, D4, cD4) \ - NET_CONNECT(name, D5, cD5) \ - NET_CONNECT(name, D6, cD6) \ - NET_CONNECT(name, D7, cD7) \ +#define TTL_9312(name, cA, cB, cC, cD0, cD1, cD2, cD3, cD4, cD5, cD6, cD7, cSTROBE) \ + NET_REGISTER_DEV(TTL_9312, name) \ + NET_CONNECT(name, A, cA) \ + NET_CONNECT(name, B, cB) \ + NET_CONNECT(name, C, cC) \ + NET_CONNECT(name, D0, cD0) \ + NET_CONNECT(name, D1, cD1) \ + NET_CONNECT(name, D2, cD2) \ + NET_CONNECT(name, D3, cD3) \ + NET_CONNECT(name, D4, cD4) \ + NET_CONNECT(name, D5, cD5) \ + NET_CONNECT(name, D6, cD6) \ + NET_CONNECT(name, D7, cD7) \ NET_CONNECT(name, G, cSTROBE) #define TTL_9312_DIP(name) \ diff --git a/src/lib/netlist/devices/nld_9316.cpp b/src/lib/netlist/devices/nld_9316.cpp index ea7ca9fc45c..e9004417b6d 100644 --- a/src/lib/netlist/devices/nld_9316.cpp +++ b/src/lib/netlist/devices/nld_9316.cpp @@ -6,6 +6,7 @@ */ #include "nld_9316.h" +#include "nl_base.h" #define MAXCNT 15 @@ -161,22 +162,22 @@ namespace netlist { if (m_loadq) { - switch (m_cnt()) + if (m_cnt < MAXCNT - 1) { - case MAXCNT - 1: - m_cnt = MAXCNT; - m_RC.push(m_ent, NLTIME_FROM_NS(27)); - m_QA.push(1, NLTIME_FROM_NS(20)); - break; - case MAXCNT: - m_RC.push(0, NLTIME_FROM_NS(27)); - m_cnt = 0; - update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); - break; - default: - m_cnt++; - update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); - break; + m_cnt++; + update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); + } + else if (m_cnt == MAXCNT - 1) + { + m_cnt = MAXCNT; + m_RC.push(m_ent, NLTIME_FROM_NS(27)); + m_QA.push(1, NLTIME_FROM_NS(20)); + } + else // MAXCNT + { + m_RC.push(0, NLTIME_FROM_NS(27)); + m_cnt = 0; + update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); } } else diff --git a/src/lib/netlist/devices/nld_9322.cpp b/src/lib/netlist/devices/nld_9322.cpp index 881ec9e5355..1f402d4111b 100644 --- a/src/lib/netlist/devices/nld_9322.cpp +++ b/src/lib/netlist/devices/nld_9322.cpp @@ -6,6 +6,7 @@ */ #include "nld_9322.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_am2847.cpp b/src/lib/netlist/devices/nld_am2847.cpp index b4891db5398..be5f75c3774 100644 --- a/src/lib/netlist/devices/nld_am2847.cpp +++ b/src/lib/netlist/devices/nld_am2847.cpp @@ -6,6 +6,7 @@ */ #include "nld_am2847.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_dm9334.cpp b/src/lib/netlist/devices/nld_dm9334.cpp index 091f08f00a8..b8607374620 100644 --- a/src/lib/netlist/devices/nld_dm9334.cpp +++ b/src/lib/netlist/devices/nld_dm9334.cpp @@ -6,6 +6,7 @@ */ #include "nld_dm9334.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_legacy.cpp b/src/lib/netlist/devices/nld_legacy.cpp index 3a063094b72..29cff9576ab 100644 --- a/src/lib/netlist/devices/nld_legacy.cpp +++ b/src/lib/netlist/devices/nld_legacy.cpp @@ -6,7 +6,7 @@ */ #include "nld_legacy.h" -#include "nl_setup.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_log.cpp b/src/lib/netlist/devices/nld_log.cpp index 17661de803d..d69bc6aa81e 100644 --- a/src/lib/netlist/devices/nld_log.cpp +++ b/src/lib/netlist/devices/nld_log.cpp @@ -5,7 +5,6 @@ * */ -#include <memory> #include "nl_base.h" #include "plib/pstream.h" #include "plib/pfmtlog.h" @@ -20,21 +19,22 @@ namespace netlist { NETLIB_CONSTRUCTOR(log) , m_I(*this, "I") + , m_strm(plib::pfmt("{1}.log")(this->name())) + , m_writer(m_strm) { - pstring filename = plib::pfmt("{1}.log")(this->name()); - m_strm = plib::make_unique<plib::pofilestream>(filename); } NETLIB_UPDATEI() { /* use pstring::sprintf, it is a LOT faster */ - m_strm->writeline(plib::pfmt("{1} {2}").e(netlist().time().as_double(),".9").e(static_cast<double>(m_I()))); + m_writer.writeline(plib::pfmt("{1} {2}").e(netlist().time().as_double(),".9").e(static_cast<double>(m_I()))); } NETLIB_RESETI() { } protected: analog_input_t m_I; - std::unique_ptr<plib::pofilestream> m_strm; + plib::pofilestream m_strm; + plib::putf8_writer m_writer; }; NETLIB_OBJECT_DERIVED(logD, log) @@ -46,7 +46,7 @@ namespace netlist NETLIB_UPDATEI() { - m_strm->writeline(plib::pfmt("{1} {2}").e(netlist().time().as_double(),".9").e(static_cast<double>(m_I() - m_I2()))); + m_writer.writeline(plib::pfmt("{1} {2}").e(netlist().time().as_double(),".9").e(static_cast<double>(m_I() - m_I2()))); } NETLIB_RESETI() { } diff --git a/src/lib/netlist/devices/nld_mm5837.cpp b/src/lib/netlist/devices/nld_mm5837.cpp index 7650538997b..d9297166d94 100644 --- a/src/lib/netlist/devices/nld_mm5837.cpp +++ b/src/lib/netlist/devices/nld_mm5837.cpp @@ -6,8 +6,8 @@ */ #include "nld_mm5837.h" -#include <solver/nld_matrix_solver.h> -#include "analog/nld_twoterm.h" +#include "solver/nld_matrix_solver.h" +#include "analog/nlid_twoterm.h" #define R_LOW (1000.0) #define R_HIGH (1000.0) @@ -72,7 +72,7 @@ namespace netlist m_RV.set(NL_FCONST(1.0) / R_LOW, 0.0, 0.0); m_inc = netlist_time::from_double(1.0 / m_FREQ()); if (m_FREQ() < 24000 || m_FREQ() > 56000) - netlist().log().warning("MM5837: Frequency outside of specs.", m_FREQ()); + log().warning(MW_1_FREQUENCY_OUTSIDE_OF_SPECS_1, m_FREQ()); m_shift = 0x1ffff; m_is_timestep = m_RV.m_P.net().solver()->is_timestep(); @@ -82,7 +82,7 @@ namespace netlist { m_inc = netlist_time::from_double(1.0 / m_FREQ()); if (m_FREQ() < 24000 || m_FREQ() > 56000) - netlist().log().warning("MM5837: Frequency outside of specs.", m_FREQ()); + log().warning(MW_1_FREQUENCY_OUTSIDE_OF_SPECS_1, m_FREQ()); } NETLIB_UPDATE(MM5837_dip) diff --git a/src/lib/netlist/devices/nld_ne555.cpp b/src/lib/netlist/devices/nld_ne555.cpp index 3cfd120be30..f9bb5e261c2 100644 --- a/src/lib/netlist/devices/nld_ne555.cpp +++ b/src/lib/netlist/devices/nld_ne555.cpp @@ -6,8 +6,8 @@ */ #include "nld_ne555.h" -#include "analog/nld_twoterm.h" -#include <solver/nld_solver.h> +#include "analog/nlid_twoterm.h" +#include "solver/nld_solver.h" #define R_OFF (1E20) #define R_ON (25) // Datasheet states a maximum discharge of 200mA, R = 5V / 0.2 diff --git a/src/lib/netlist/devices/nld_r2r_dac.cpp b/src/lib/netlist/devices/nld_r2r_dac.cpp index 8a6d811f2d4..f4006eef31d 100644 --- a/src/lib/netlist/devices/nld_r2r_dac.cpp +++ b/src/lib/netlist/devices/nld_r2r_dac.cpp @@ -5,8 +5,9 @@ * */ -#include "nld_r2r_dac.h" -#include "analog/nld_twoterm.h" +#include "nl_base.h" +#include "nl_factory.h" +#include "analog/nlid_twoterm.h" namespace netlist { diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp index f555e41720a..e3585271696 100644 --- a/src/lib/netlist/devices/nld_system.cpp +++ b/src/lib/netlist/devices/nld_system.cpp @@ -5,8 +5,8 @@ * */ -#include <solver/nld_solver.h> -#include <solver/nld_matrix_solver.h> +#include "solver/nld_solver.h" +#include "solver/nld_matrix_solver.h" #include "nlid_system.h" namespace netlist @@ -132,82 +132,13 @@ namespace netlist NETLIB_UPDATE(function) { - //nl_double val = INPANALOG(m_I[0]) * INPANALOG(m_I[1]) * 0.2; - //OUTANALOG(m_Q, val); - nl_double stack[20]; - unsigned ptr = 0; - std::size_t e = m_precompiled.size(); - for (std::size_t i = 0; i<e; i++) + for (std::size_t i=0; i < static_cast<unsigned>(m_N()); i++) { - rpn_inst &rc = m_precompiled[i]; - switch (rc.m_cmd) - { - case ADD: - ptr--; - stack[ptr-1] = stack[ptr] + stack[ptr-1]; - break; - case MULT: - ptr--; - stack[ptr-1] = stack[ptr] * stack[ptr-1]; - break; - case SUB: - ptr--; - stack[ptr-1] = stack[ptr-1] - stack[ptr]; - break; - case DIV: - ptr--; - stack[ptr-1] = stack[ptr-1] / stack[ptr]; - break; - case POW: - ptr--; - stack[ptr-1] = std::pow(stack[ptr-1], stack[ptr]); - break; - case PUSH_INPUT: - stack[ptr++] = (*m_I[static_cast<unsigned>(rc.m_param)])(); - break; - case PUSH_CONST: - stack[ptr++] = rc.m_param; - break; - } + m_vals[i] = (*m_I[i])(); } - m_Q.push(stack[ptr-1]); + m_Q.push(m_precompiled.evaluate(m_vals)); } - void NETLIB_NAME(function)::compile() - { - plib::pstring_vector_t cmds(m_func(), " "); - m_precompiled.clear(); - - for (std::size_t i=0; i < cmds.size(); i++) - { - pstring cmd = cmds[i]; - rpn_inst rc; - if (cmd == "+") - rc.m_cmd = ADD; - else if (cmd == "-") - rc.m_cmd = SUB; - else if (cmd == "*") - rc.m_cmd = MULT; - else if (cmd == "/") - rc.m_cmd = DIV; - else if (cmd == "pow") - rc.m_cmd = POW; - else if (cmd.startsWith("A")) - { - rc.m_cmd = PUSH_INPUT; - rc.m_param = cmd.substr(1).as_long(); - } - else - { - bool err = false; - rc.m_cmd = PUSH_CONST; - rc.m_param = cmd.as_double(&err); - if (err) - netlist().log().fatal("nld_function: unknown/misformatted token <{1}> in <{2}>", cmd, m_func()); - } - m_precompiled.push_back(rc); - } - } NETLIB_DEVICE_IMPL(dummy_input) NETLIB_DEVICE_IMPL(frontier) diff --git a/src/lib/netlist/devices/nld_system.h b/src/lib/netlist/devices/nld_system.h index 738ceb2a171..46781fe2884 100644 --- a/src/lib/netlist/devices/nld_system.h +++ b/src/lib/netlist/devices/nld_system.h @@ -54,9 +54,6 @@ NET_C(cG, name.G) \ NET_C(cOUT, name.Q) -#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \ - setup.register_frontier(# attach, r_in, r_out); - #define RES_SWITCH(name, cIN, cP1, cP2) \ NET_REGISTER_DEV(RES_SWITCH, name) \ NET_C(cIN, name.I) \ @@ -72,4 +69,5 @@ PARAM(name.N, p_N) \ PARAM(name.FUNC, p_F) + #endif /* NLD_SYSTEM_H_ */ diff --git a/src/lib/netlist/devices/nld_tristate.cpp b/src/lib/netlist/devices/nld_tristate.cpp index db21468685e..b724a09bf9c 100644 --- a/src/lib/netlist/devices/nld_tristate.cpp +++ b/src/lib/netlist/devices/nld_tristate.cpp @@ -6,6 +6,7 @@ */ #include "nld_tristate.h" +#include "nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nlid_cmos.h b/src/lib/netlist/devices/nlid_cmos.h index 4770eac2164..2d836ef656d 100644 --- a/src/lib/netlist/devices/nlid_cmos.h +++ b/src/lib/netlist/devices/nlid_cmos.h @@ -8,6 +8,7 @@ #ifndef NLID_CMOS_H_ #define NLID_CMOS_H_ +#include "nl_setup.h" #include "nl_base.h" namespace netlist diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp index 0b08327070c..4b18ca0bbb2 100644 --- a/src/lib/netlist/devices/nlid_proxy.cpp +++ b/src/lib/netlist/devices/nlid_proxy.cpp @@ -5,7 +5,6 @@ * */ -//#include <memory> #include "nlid_proxy.h" #include "solver/nld_solver.h" //#include "plib/pstream.h" @@ -100,7 +99,7 @@ namespace netlist , m_last_state(*this, "m_last_var", -1) , m_is_timestep(false) { - const char *power_syms[3][2] ={ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}; + const pstring power_syms[3][2] ={ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}; //register_sub(m_RV); //register_term("1", m_RV.m_P); //register_term("2", m_RV.m_N); @@ -112,8 +111,10 @@ namespace netlist for (int i = 0; i < 3; i++) { pstring devname = out_proxied->device().name(); - auto tp = netlist().setup().find_terminal(devname + "." + power_syms[i][0], detail::device_object_t::type_t::INPUT, false); - auto tn = netlist().setup().find_terminal(devname + "." + power_syms[i][1], detail::device_object_t::type_t::INPUT, false); + auto tp = netlist().setup().find_terminal(devname + "." + power_syms[i][0], + detail::terminal_type::INPUT, false); + auto tn = netlist().setup().find_terminal(devname + "." + power_syms[i][1], + detail::terminal_type::INPUT, false); if (tp != nullptr && tn != nullptr) { /* alternative logic */ @@ -121,12 +122,12 @@ namespace netlist } } if (!f) - netlist().log().warning("D/A Proxy: Found no valid combination of power terminals on device {1}", out_proxied->device().name()); + log().warning(MW_1_NO_POWER_TERMINALS_ON_DEVICE_1, out_proxied->device().name()); else - netlist().log().warning("D/A Proxy: Found power terminals on device {1}", out_proxied->device().name()); + log().verbose("D/A Proxy: Found power terminals on device {1}", out_proxied->device().name()); #if (0) printf("%s %s\n", out_proxied->name().c_str(), out_proxied->device().name().c_str()); - auto x = netlist().setup().find_terminal(out_proxied->name(), detail::device_object_t::type_t::OUTPUT, false); + auto x = netlist().setup().find_terminal(out_proxied->name(), detail::device_object_t::terminal_type::OUTPUT, false); if (x) printf("==> %s\n", x->name().c_str()); #endif } diff --git a/src/lib/netlist/devices/nlid_proxy.h b/src/lib/netlist/devices/nlid_proxy.h index 77a8d52026c..178faae20fd 100644 --- a/src/lib/netlist/devices/nlid_proxy.h +++ b/src/lib/netlist/devices/nlid_proxy.h @@ -11,12 +11,8 @@ #ifndef NLID_PROXY_H_ #define NLID_PROXY_H_ -#include <vector> - #include "nl_setup.h" -#include "nl_base.h" -#include "nl_factory.h" -#include "analog/nld_twoterm.h" +#include "analog/nlid_twoterm.h" namespace netlist { @@ -127,7 +123,7 @@ namespace netlist analog::NETLIB_SUB(twoterm) m_RV; state_var<int> m_last_state; bool m_is_timestep; - }; +}; } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index 8d2cd8162f8..e9baa4c159d 100644 --- a/src/lib/netlist/devices/nlid_system.h +++ b/src/lib/netlist/devices/nlid_system.h @@ -11,12 +11,10 @@ #ifndef NLID_SYSTEM_H_ #define NLID_SYSTEM_H_ -#include <vector> - -#include "nl_setup.h" #include "nl_base.h" -#include "nl_factory.h" -#include "analog/nld_twoterm.h" +#include "nl_setup.h" +#include "analog/nlid_twoterm.h" +#include "plib/putil.h" namespace netlist { @@ -126,7 +124,7 @@ namespace netlist connect(m_feedback, m_Q); { netlist_time base = netlist_time::from_double(1.0 / (m_freq()*2.0)); - plib::pstring_vector_t pat(m_pattern(),","); + std::vector<pstring> pat(plib::psplit(m_pattern(),",")); m_off = netlist_time::from_double(m_offset()); unsigned long pati[256]; @@ -175,7 +173,7 @@ namespace netlist /* make sure we get the family first */ , m_FAMILY(*this, "FAMILY", "FAMILY(TYPE=TTL)") { - set_logic_family(netlist().family_from_model(m_FAMILY())); + set_logic_family(setup().family_from_model(m_FAMILY())); } NETLIB_UPDATE_AFTER_PARAM_CHANGE() @@ -309,9 +307,15 @@ namespace netlist , m_func(*this, "FUNC", "") , m_Q(*this, "Q") { + std::vector<pstring> inps; for (int i=0; i < m_N(); i++) - m_I.push_back(plib::make_unique<analog_input_t>(*this, plib::pfmt("A{1}")(i))); - compile(); + { + pstring n = plib::pfmt("A{1}")(i); + m_I.push_back(plib::make_unique<analog_input_t>(*this, n)); + inps.push_back(n); + m_vals.push_back(0.0); + } + m_precompiled.compile(inps, m_func()); } protected: @@ -321,32 +325,13 @@ namespace netlist private: - enum rpn_cmd - { - ADD, - MULT, - SUB, - DIV, - POW, - PUSH_CONST, - PUSH_INPUT - }; - - struct rpn_inst - { - rpn_inst() : m_cmd(ADD), m_param(0.0) { } - rpn_cmd m_cmd; - nl_double m_param; - }; - - void compile(); - param_int_t m_N; param_str_t m_func; analog_output_t m_Q; std::vector<std::unique_ptr<analog_input_t>> m_I; - std::vector<rpn_inst> m_precompiled; + std::vector<double> m_vals; + plib::pfunction m_precompiled; }; // ----------------------------------------------------------------------------- diff --git a/src/lib/netlist/devices/nld_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp index 9030f6b8801..824061fdc30 100644 --- a/src/lib/netlist/devices/nld_truthtable.cpp +++ b/src/lib/netlist/devices/nlid_truthtable.cpp @@ -5,9 +5,10 @@ * */ -#include "nld_truthtable.h" +#include "nlid_truthtable.h" #include "plib/plists.h" #include "nl_setup.h" +#include "plib/palloc.h" namespace netlist { @@ -16,11 +17,10 @@ namespace netlist template<unsigned m_NI, unsigned m_NO> class netlist_factory_truthtable_t : public netlist_base_factory_truthtable_t { - P_PREVENT_COPYING(netlist_factory_truthtable_t) public: netlist_factory_truthtable_t(const pstring &name, const pstring &classname, - const pstring &def_param) - : netlist_base_factory_truthtable_t(name, classname, def_param) + const pstring &def_param, const pstring &sourcefile) + : netlist_base_factory_truthtable_t(name, classname, def_param, sourcefile) { } plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override @@ -120,7 +120,7 @@ uint_least64_t truthtable_desc_t::get_ignored_extended(uint_least64_t state) // desc // ---------------------------------------------------------------------------------------- -void truthtable_desc_t::help(unsigned cur, plib::pstring_vector_t list, +void truthtable_desc_t::help(unsigned cur, std::vector<pstring> list, uint_least64_t state, uint_least64_t val, std::vector<uint_least8_t> &timing_index) { pstring elem = list[cur].trim(); @@ -165,7 +165,7 @@ void truthtable_desc_t::help(unsigned cur, plib::pstring_vector_t list, } } -void truthtable_desc_t::setup(const plib::pstring_vector_t &truthtable, uint_least64_t disabled_ignore) +void truthtable_desc_t::setup(const std::vector<pstring> &truthtable, uint_least64_t disabled_ignore) { unsigned line = 0; @@ -185,14 +185,14 @@ void truthtable_desc_t::setup(const plib::pstring_vector_t &truthtable, uint_lea while (!ttline.equals("")) { - plib::pstring_vector_t io(ttline,"|"); + std::vector<pstring> io(plib::psplit(ttline,"|")); // checks nl_assert_always(io.size() == 3, "io.count mismatch"); - plib::pstring_vector_t inout(io[0], ","); + std::vector<pstring> inout(plib::psplit(io[0], ",")); nl_assert_always(inout.size() == m_num_bits, "number of bits not matching"); - plib::pstring_vector_t out(io[1], ","); + std::vector<pstring> out(plib::psplit(io[1], ",")); nl_assert_always(out.size() == m_NO, "output count not matching"); - plib::pstring_vector_t times(io[2], ","); + std::vector<pstring> times(plib::psplit(io[2], ",")); nl_assert_always(times.size() == m_NO, "timing count not matching"); uint_least64_t val = 0; @@ -260,8 +260,8 @@ void truthtable_desc_t::setup(const plib::pstring_vector_t &truthtable, uint_lea } netlist_base_factory_truthtable_t::netlist_base_factory_truthtable_t(const pstring &name, const pstring &classname, - const pstring &def_param) -: factory::element_t(name, classname, def_param), m_family(family_TTL()) + const pstring &def_param, const pstring &sourcefile) +: factory::element_t(name, classname, def_param, sourcefile), m_family(family_TTL()) { } @@ -270,35 +270,36 @@ netlist_base_factory_truthtable_t::~netlist_base_factory_truthtable_t() } -#define ENTRYY(n, m) case (n * 100 + m): \ +#define ENTRYY(n, m, s) case (n * 100 + m): \ { using xtype = netlist_factory_truthtable_t<n, m>; \ - ret = new xtype(desc.name, desc.classname, desc.def_param); } break + ret = plib::palloc<xtype>(desc.name, desc.classname, desc.def_param, s); } break -#define ENTRY(n) ENTRYY(n, 1); ENTRYY(n, 2); ENTRYY(n, 3); ENTRYY(n, 4); ENTRYY(n, 5); ENTRYY(n, 6) +#define ENTRY(n, s) ENTRYY(n, 1, s); ENTRYY(n, 2, s); ENTRYY(n, 3, s); \ + ENTRYY(n, 4, s); ENTRYY(n, 5, s); ENTRYY(n, 6, s) -void tt_factory_create(setup_t &setup, tt_desc &desc) +void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile) { netlist_base_factory_truthtable_t *ret; switch (desc.ni * 100 + desc.no) { - ENTRY(1); - ENTRY(2); - ENTRY(3); - ENTRY(4); - ENTRY(5); - ENTRY(6); - ENTRY(7); - ENTRY(8); - ENTRY(9); - ENTRY(10); + ENTRY(1, sourcefile); + ENTRY(2, sourcefile); + ENTRY(3, sourcefile); + ENTRY(4, sourcefile); + ENTRY(5, sourcefile); + ENTRY(6, sourcefile); + ENTRY(7, sourcefile); + ENTRY(8, sourcefile); + ENTRY(9, sourcefile); + ENTRY(10, sourcefile); default: pstring msg = plib::pfmt("unable to create truthtable<{1},{2}>")(desc.ni)(desc.no); nl_assert_always(false, msg); } ret->m_desc = desc.desc; if (desc.family != "") - ret->m_family = setup.netlist().family_from_model(desc.family); + ret->m_family = setup.family_from_model(desc.family); setup.factory().register_device(std::unique_ptr<netlist_base_factory_truthtable_t>(ret)); } diff --git a/src/lib/netlist/devices/nld_truthtable.h b/src/lib/netlist/devices/nlid_truthtable.h index 990afc45dd7..68c3d680e40 100644 --- a/src/lib/netlist/devices/nld_truthtable.h +++ b/src/lib/netlist/devices/nlid_truthtable.h @@ -7,15 +7,12 @@ * Author: andre */ -#ifndef NLD_TRUTHTABLE_H_ -#define NLD_TRUTHTABLE_H_ - -#include <new> -#include <cstdint> +#ifndef NLID_TRUTHTABLE_H_ +#define NLID_TRUTHTABLE_H_ #include "nl_setup.h" -#include "nl_factory.h" -#include "plib/plists.h" +#include "nl_base.h" +#include "plib/putil.h" #define NETLIB_TRUTHTABLE(cname, nIN, nOUT) \ class NETLIB_NAME(cname) : public nld_truthtable_t<nIN, nOUT> \ @@ -26,7 +23,7 @@ : nld_truthtable_t<nIN, nOUT>(owner, name, family_TTL(), &m_ttbl, m_desc) { } \ private: \ static truthtable_t m_ttbl; \ - static const char *m_desc[]; \ + static const pstring m_desc[]; \ } @@ -112,10 +109,10 @@ namespace netlist { } - void setup(const plib::pstring_vector_t &desc, uint_least64_t disabled_ignore); + void setup(const std::vector<pstring> &desc, uint_least64_t disabled_ignore); private: - void help(unsigned cur, plib::pstring_vector_t list, + void help(unsigned cur, std::vector<pstring> list, uint_least64_t state, uint_least64_t val, std::vector<uint_least8_t> &timing_index); static unsigned count_bits(uint_least64_t v); static uint_least64_t set_bits(uint_least64_t v, uint_least64_t b); @@ -159,14 +156,14 @@ namespace netlist template <class C> nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam, - truthtable_t *ttp, const char *desc[]) + truthtable_t *ttp, const pstring *desc) : device_t(owner, name) , m_fam(*this, fam) , m_ign(*this, "m_ign", 0) , m_active(*this, "m_active", 1) , m_ttp(ttp) { - while (*desc != nullptr && **desc != 0 ) + while (*desc != "" ) { m_desc.push_back(*desc); desc++; @@ -176,7 +173,7 @@ namespace netlist template <class C> nld_truthtable_t(C &owner, const pstring &name, const logic_family_desc_t *fam, - truthtable_t *ttp, const plib::pstring_vector_t &desc) + truthtable_t *ttp, const std::vector<pstring> &desc) : device_t(owner, name) , m_fam(*this, fam) , m_ign(*this, "m_ign", 0) @@ -193,12 +190,12 @@ namespace netlist pstring header = m_desc[0]; - plib::pstring_vector_t io(header,"|"); + std::vector<pstring> io(plib::psplit(header,"|")); // checks nl_assert_always(io.size() == 2, "too many '|'"); - plib::pstring_vector_t inout(io[0], ","); + std::vector<pstring> inout(plib::psplit(io[0], ",")); nl_assert_always(inout.size() == m_num_bits, "bitcount wrong"); - plib::pstring_vector_t out(io[1], ","); + std::vector<pstring> out(plib::psplit(io[1], ",")); nl_assert_always(out.size() == m_NO, "output count wrong"); for (std::size_t i=0; i < m_NI; i++) @@ -363,27 +360,26 @@ namespace netlist state_var_u32 m_ign; state_var_s32 m_active; truthtable_t * m_ttp; - plib::pstring_vector_t m_desc; + std::vector<pstring> m_desc; }; class netlist_base_factory_truthtable_t : public factory::element_t { - P_PREVENT_COPYING(netlist_base_factory_truthtable_t) public: netlist_base_factory_truthtable_t(const pstring &name, const pstring &classname, - const pstring &def_param); + const pstring &def_param, const pstring &sourcefile); virtual ~netlist_base_factory_truthtable_t(); - plib::pstring_vector_t m_desc; + std::vector<pstring> m_desc; const logic_family_desc_t *m_family; }; - void tt_factory_create(setup_t &setup, tt_desc &desc); + void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile); } //namespace devices } // namespace netlist -#endif /* NLD_TRUTHTABLE_H_ */ +#endif /* NLID_TRUTHTABLE_H_ */ diff --git a/src/lib/netlist/documentation/mainpage.dox.h b/src/lib/netlist/documentation/mainpage.dox.h index 75df1a18065..744abe642e6 100644 --- a/src/lib/netlist/documentation/mainpage.dox.h +++ b/src/lib/netlist/documentation/mainpage.dox.h @@ -161,5 +161,4 @@ equation solver. The formal representation of the circuit will stay the same, thus scales. - */ diff --git a/src/lib/netlist/macro/nlm_cd4xxx.cpp b/src/lib/netlist/macro/nlm_cd4xxx.cpp index 469ff13b954..ed805cb52dc 100644 --- a/src/lib/netlist/macro/nlm_cd4xxx.cpp +++ b/src/lib/netlist/macro/nlm_cd4xxx.cpp @@ -2,7 +2,6 @@ // copyright-holders:Couriersud #include "nlm_cd4xxx.h" -#include "devices/nld_truthtable.h" #include "devices/nld_system.h" #include "devices/nld_4020.h" #include "devices/nld_4066.h" diff --git a/src/lib/netlist/macro/nlm_cd4xxx.h b/src/lib/netlist/macro/nlm_cd4xxx.h index de10ff7a64d..446c2d6e435 100644 --- a/src/lib/netlist/macro/nlm_cd4xxx.h +++ b/src/lib/netlist/macro/nlm_cd4xxx.h @@ -22,6 +22,8 @@ * Netlist Macros * ---------------------------------------------------------------------------*/ +#ifndef NL_AUTO_DEVICES + #define CD4001_NOR(name) \ NET_REGISTER_DEV(CD4001_NOR, name) @@ -44,6 +46,7 @@ #define CD4316_DIP(name) \ NET_REGISTER_DEV(CD4016_DIP, name) +#endif /* ---------------------------------------------------------------------------- * External declarations * ---------------------------------------------------------------------------*/ diff --git a/src/lib/netlist/macro/nlm_opamp.cpp b/src/lib/netlist/macro/nlm_opamp.cpp index 146f95b72b4..f363c88a100 100644 --- a/src/lib/netlist/macro/nlm_opamp.cpp +++ b/src/lib/netlist/macro/nlm_opamp.cpp @@ -1,9 +1,7 @@ // license:GPL-2.0+ // copyright-holders:Couriersud #include "nlm_opamp.h" - -#include "analog/nld_opamps.h" -#include "devices/nld_system.h" +#include "devices/net_lib.h" /* * Generic layout with 4 opamps, VCC on pin 4 and GND on pin 11 diff --git a/src/lib/netlist/macro/nlm_opamp.h b/src/lib/netlist/macro/nlm_opamp.h index 6e3c1f615e7..ec717fdb2dc 100644 --- a/src/lib/netlist/macro/nlm_opamp.h +++ b/src/lib/netlist/macro/nlm_opamp.h @@ -11,6 +11,8 @@ * Netlist Macros * ---------------------------------------------------------------------------*/ +#ifndef NL_AUTO_DEVICES + #define MB3614_DIP(name) \ NET_REGISTER_DEV(MB3614_DIP, name) @@ -23,6 +25,8 @@ #define LM3900(name) \ NET_REGISTER_DEV(LM3900, name) +#endif + /* ---------------------------------------------------------------------------- * External declarations * ---------------------------------------------------------------------------*/ diff --git a/src/lib/netlist/macro/nlm_other.cpp b/src/lib/netlist/macro/nlm_other.cpp index 84a3af4dc04..49f4404427a 100644 --- a/src/lib/netlist/macro/nlm_other.cpp +++ b/src/lib/netlist/macro/nlm_other.cpp @@ -2,7 +2,6 @@ // copyright-holders:Couriersud #include "nlm_other.h" -#include "devices/nld_truthtable.h" #include "devices/nld_system.h" /* diff --git a/src/lib/netlist/macro/nlm_other.h b/src/lib/netlist/macro/nlm_other.h index bb73d0105d2..f0e8ca05af0 100644 --- a/src/lib/netlist/macro/nlm_other.h +++ b/src/lib/netlist/macro/nlm_other.h @@ -11,12 +11,15 @@ * Netlist Macros * ---------------------------------------------------------------------------*/ +#ifndef NL_AUTO_DEVICES + #define MC14584B_GATE(name) \ NET_REGISTER_DEV(MC14584B_GATE, name) #define MC14584B_DIP(name) \ NET_REGISTER_DEV(MC14584B_DIP, name) +#endif /* ---------------------------------------------------------------------------- * External declarations diff --git a/src/lib/netlist/macro/nlm_ttl74xx.cpp b/src/lib/netlist/macro/nlm_ttl74xx.cpp index c66314366d2..c8fe9912911 100644 --- a/src/lib/netlist/macro/nlm_ttl74xx.cpp +++ b/src/lib/netlist/macro/nlm_ttl74xx.cpp @@ -2,7 +2,6 @@ // copyright-holders:Couriersud #include "nlm_ttl74xx.h" -#include "devices/nld_truthtable.h" #include "devices/nld_system.h" @@ -377,7 +376,7 @@ static NETLIST_START(TTL_7427_DIP) s2.C, /* C2 |5 10| B3 */ s3.B, s2.Q, /* Y2 |6 9| A3 */ s3.A, GND.I, /* GND |7 8| Y3 */ s3.Q - /* +--------------+ */ + /* +--------------+ */ ) NETLIST_END() @@ -413,11 +412,11 @@ static NETLIST_START(TTL_7430_DIP) s1.A, /* A |1 ++ 14| VCC */ VCC.I, s1.B, /* B |2 13| NC */ NC.I, s1.C, /* C |3 12| H */ s1.H, - s1.D, /* D |4 7420 11| G */ s1.G, + s1.D, /* D |4 7430 11| G */ s1.G, s1.E, /* E |5 10| NC */ NC.I, s1.F, /* F |6 9| NC */ NC.I, GND.I, /* GND |7 8| Y */ s1.Q - /* +--------------+ */ + /* +--------------+ */ ) NETLIST_END() diff --git a/src/lib/netlist/macro/nlm_ttl74xx.h b/src/lib/netlist/macro/nlm_ttl74xx.h index 44b3db63bd3..526fbf395da 100644 --- a/src/lib/netlist/macro/nlm_ttl74xx.h +++ b/src/lib/netlist/macro/nlm_ttl74xx.h @@ -11,6 +11,8 @@ * Netlist Macros * ---------------------------------------------------------------------------*/ +#ifndef NL_AUTO_DEVICES + #define TTL_7400_GATE(name) \ NET_REGISTER_DEV(TTL_7400_GATE, name) @@ -200,6 +202,8 @@ #define TTL_74260_DIP(name) \ NET_REGISTER_DEV(TTL_74260_DIP, name) +#endif + /* ---------------------------------------------------------------------------- * External declarations * ---------------------------------------------------------------------------*/ diff --git a/src/lib/netlist/netlist_types.h b/src/lib/netlist/netlist_types.h new file mode 100644 index 00000000000..c7c4aef4750 --- /dev/null +++ b/src/lib/netlist/netlist_types.h @@ -0,0 +1,54 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/*! + * + * \file netlist_types.h + * + */ + +#ifndef NETLIST_TYPES_H_ +#define NETLIST_TYPES_H_ + +#include <cstdint> +#include <unordered_map> + +#include "nl_config.h" +#include "plib/pchrono.h" +#include "plib/pstring.h" + +namespace netlist +{ + //============================================================ + // Performance tracking + //============================================================ + +#if NL_KEEP_STATISTICS + using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, true>; + using nperfcount_t = plib::chrono::counter<true>; +#else + using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, false>; + using nperfcount_t = plib::chrono::counter<false>; +#endif + + //============================================================ + // Types needed by various includes + //============================================================ + + namespace detail { + + /*! Enum specifying the type of object */ + enum terminal_type { + TERMINAL = 0, /*!< object is an analog terminal */ + INPUT = 1, /*!< object is an input */ + OUTPUT = 2, /*!< object is an output */ + }; + + /*! Type of the model map used. + * This is used to hold all #Models in an unordered map + */ + using model_map_t = std::unordered_map<pstring, pstring>; + + } +} + +#endif /* NETLIST_TYPES_H_ */ diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 80acf9847a3..4374ef2212d 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -6,6 +6,7 @@ */ #include <cstring> +#include <cmath> #include "solver/nld_matrix_solver.h" #include "solver/nld_solver.h" @@ -25,7 +26,7 @@ namespace netlist namespace detail { #if (USE_MEMPOOL) -static plib::mempool pool(65536, 8); +static plib::mempool pool(6553600, 64); void * object_t::operator new (size_t size) { @@ -135,24 +136,6 @@ const logic_family_desc_t *family_CD4XXX() return &obj; } -class logic_family_std_proxy_t : public logic_family_desc_t -{ -public: - logic_family_std_proxy_t() { } - virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, - const pstring &name, logic_output_t *proxied) const override; - virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override; -}; - -plib::owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_std_proxy_t::create_d_a_proxy(netlist_t &anetlist, - const pstring &name, logic_output_t *proxied) const -{ - return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied); -} -plib::owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_std_proxy_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const -{ - return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied); -} // ---------------------------------------------------------------------------------------- // queue_t @@ -199,10 +182,10 @@ void detail::queue_t::on_post_load() netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize); for (std::size_t i = 0; i < m_qsize; i++ ) { - detail::net_t *n = netlist().find_net(m_names[i].m_buf); + detail::net_t *n = netlist().find_net(pstring(m_names[i].m_buf, pstring::UTF8)); //log().debug("Got {1} ==> {2}\n", qtemp[i].m_name, n)); //log().debug("schedule time {1} ({2})\n", n->time().as_double(), netlist_time::from_raw(m_times[i]).as_double())); - this->push(n, netlist_time::from_raw(m_times[i])); + this->push(queue_t::entry_t(netlist_time::from_raw(m_times[i]),n)); } } @@ -234,24 +217,22 @@ detail::device_object_t::device_object_t(core_device_t &dev, const pstring &anam { } -detail::device_object_t::type_t detail::device_object_t::type() const +detail::terminal_type detail::core_terminal_t::type() const { if (dynamic_cast<const terminal_t *>(this) != nullptr) - return type_t::TERMINAL; - else if (dynamic_cast<const param_t *>(this) != nullptr) - return param_t::PARAM; + return terminal_type::TERMINAL; else if (dynamic_cast<const logic_input_t *>(this) != nullptr) - return param_t::INPUT; + return terminal_type::INPUT; else if (dynamic_cast<const logic_output_t *>(this) != nullptr) - return param_t::OUTPUT; + return terminal_type::OUTPUT; else if (dynamic_cast<const analog_input_t *>(this) != nullptr) - return param_t::INPUT; + return terminal_type::INPUT; else if (dynamic_cast<const analog_output_t *>(this) != nullptr) - return param_t::OUTPUT; + return terminal_type::OUTPUT; else { netlist().log().fatal(MF_1_UNKNOWN_TYPE_FOR_OBJECT, name()); - return type_t::TERMINAL; // please compiler + return terminal_type::TERMINAL; // please compiler } } @@ -272,19 +253,16 @@ netlist_t::netlist_t(const pstring &aname) { state().save_item(this, static_cast<plib::state_manager_t::callback_t &>(m_queue), "m_queue"); state().save_item(this, m_time, "m_time"); - m_setup = new setup_t(*this); + m_setup = plib::make_unique<setup_t>(*this); /* FIXME: doesn't really belong here */ NETLIST_NAME(base)(*m_setup); } netlist_t::~netlist_t() { - if (m_setup != nullptr) - delete m_setup; m_nets.clear(); m_devices.clear(); - pfree(m_lib); pstring::resetmem(); } @@ -303,48 +281,18 @@ void netlist_t::register_dev(plib::owned_ptr<core_device_t> dev) void netlist_t::remove_dev(core_device_t *dev) { - m_devices.erase( - std::remove_if( - m_devices.begin(), + m_devices.erase( + std::remove_if( + m_devices.begin(), m_devices.end(), - [&] (plib::owned_ptr<core_device_t> const& p) - { - return p.get() == dev; - }), + [&] (plib::owned_ptr<core_device_t> const& p) + { + return p.get() == dev; + }), m_devices.end() - ); + ); } -const logic_family_desc_t *netlist_t::family_from_model(const pstring &model) -{ - model_map_t map; - setup().model_parse(model, map); - - if (setup().model_value_str(map, "TYPE") == "TTL") - return family_TTL(); - if (setup().model_value_str(map, "TYPE") == "CD4XXX") - return family_CD4XXX(); - - for (auto & e : m_family_cache) - if (e.first == model) - return e.second.get(); - - auto ret = plib::make_unique_base<logic_family_desc_t, logic_family_std_proxy_t>(); - - ret->m_fixed_V = setup().model_value(map, "FV"); - ret->m_low_thresh_PCNT = setup().model_value(map, "IVL"); - ret->m_high_thresh_PCNT = setup().model_value(map, "IVH"); - ret->m_low_VO = setup().model_value(map, "OVL"); - ret->m_high_VO = setup().model_value(map, "OVH"); - ret->m_R_low = setup().model_value(map, "ORL"); - ret->m_R_high = setup().model_value(map, "ORH"); - - auto retp = ret.get(); - - m_family_cache.emplace_back(model, std::move(ret)); - - return retp; -} void netlist_t::start() @@ -372,6 +320,7 @@ void netlist_t::start() /* create devices */ + log().debug("Creating devices ...\n"); for (auto & e : setup().m_device_factory) { if ( !setup().factory().is_class<devices::NETLIB_NAME(solver)>(e.second) @@ -394,9 +343,12 @@ void netlist_t::start() auto p = setup().m_param_values.find(d->name() + ".HINT_NO_DEACTIVATE"); if (p != setup().m_param_values.end()) { - //FIXME: Error checking - auto v = p->second.as_long(); - d->set_hint_deactivate(!v); + //FIXME: turn this into a proper function + bool error; + auto v = p->second.as_double(&error); + if (error || std::abs(v - std::floor(v)) > 1e-6 ) + log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second); + d->set_hint_deactivate(v == 0.0); } } else @@ -404,11 +356,30 @@ void netlist_t::start() } pstring libpath = plib::util::environment("NL_BOOSTLIB", plib::util::buildpath({".", "nlboost.so"})); - m_lib = plib::palloc<plib::dynlib>(libpath); + m_lib = plib::make_unique<plib::dynlib>(libpath); /* resolve inputs */ setup().resolve_inputs(); + /* Make sure devices are fully created - now done in register_dev */ + + log().debug("Setting delegate pointers ...\n"); + for (auto &dev : m_devices) + dev->set_delegate_pointer(); + + log().verbose("looking for two terms connected to rail nets ..."); + for (auto & t : get_device_list<analog::NETLIB_NAME(twoterm)>()) + { + if (t->m_N.net().isRailNet() && t->m_P.net().isRailNet()) + { + log().warning(MW_3_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3, + t->name(), t->m_N.net().name(), t->m_P.net().name()); + t->m_N.net().remove_terminal(t->m_N); + t->m_P.net().remove_terminal(t->m_P); + remove_dev(t); + } + } + log().verbose("initialize solver ...\n"); if (m_solver == nullptr) @@ -420,12 +391,6 @@ void netlist_t::start() else m_solver->post_start(); - /* finally, set the pointers */ - - log().debug("Setting delegate pointers ...\n"); - for (auto &dev : m_devices) - dev->set_delegate_pointer(); - } void netlist_t::stop() @@ -433,7 +398,8 @@ void netlist_t::stop() log().debug("Printing statistics ...\n"); print_stats(); log().debug("Stopping solver device ...\n"); - m_solver->stop(); + if (m_solver != nullptr) + m_solver->stop(); } detail::net_t *netlist_t::find_net(const pstring &name) @@ -474,16 +440,16 @@ void netlist_t::reset() dev->update_param(); // Step all devices once ! + /* + * INFO: The order here affects power up of e.g. breakout. However, such + * variations are explicitly stated in the breakout manual. + */ #if 0 for (std::size_t i = 0; i < m_devices.size(); i++) { m_devices[i]->update_dev(); } #else - /* FIXME: this makes breakout attract mode working again. - * It is however not acceptable that this depends on the startup order. - * Best would be, if reset would call update_dev for devices which need it. - */ std::size_t i = m_devices.size(); while (i>0) m_devices[--i]->update_dev(); @@ -495,7 +461,7 @@ void netlist_t::process_queue(const netlist_time &delta) { netlist_time stop(m_time + delta); - m_queue.push(nullptr, stop); + m_queue.push(detail::queue_t::entry_t(stop, nullptr)); m_stat_mainloop.start(); @@ -522,17 +488,20 @@ void netlist_t::process_queue(const netlist_time &delta) while (m_queue.top().m_exec_time > mc_time) { m_time = mc_time; - mc_time += inc; mc_net.toggle_new_Q(); mc_net.update_devs(); + mc_time += inc; } const detail::queue_t::entry_t e(m_queue.pop()); m_time = e.m_exec_time; - if (e.m_object == nullptr) + if (e.m_object != nullptr) + { + e.m_object->update_devs(); + m_perf_out_processed.inc(); + } + else break; - e.m_object->update_devs(); - m_perf_out_processed.inc(); } mc_net.set_time(mc_time); } @@ -599,6 +568,21 @@ void netlist_t::print_stats() const } } +core_device_t *netlist_t::pget_single_device(const pstring classname, bool (*cc)(core_device_t *)) +{ + core_device_t *ret = nullptr; + for (auto &d : m_devices) + { + if (cc(d.get())) + { + if (ret != nullptr) + this->log().fatal(MF_1_MORE_THAN_ONE_1_DEVICE_FOUND, classname); + else + ret = d.get(); + } + } + return ret; +} // ---------------------------------------------------------------------------------------- @@ -610,7 +594,7 @@ core_device_t::core_device_t(netlist_t &owner, const pstring &name) , logic_family_t() , netlist_ref(owner) , m_hint_deactivate(false) -#if (NL_PMF_TYPE > NL_PMF_TYPE_VIRTUAL) +#if (!NL_USE_PMF_VIRTUAL) , m_static_update() #endif { @@ -623,7 +607,7 @@ core_device_t::core_device_t(core_device_t &owner, const pstring &name) , logic_family_t() , netlist_ref(owner.netlist()) , m_hint_deactivate(false) -#if (NL_PMF_TYPE > NL_PMF_TYPE_VIRTUAL) +#if (!NL_USE_PMF_VIRTUAL) , m_static_update() #endif { @@ -639,17 +623,16 @@ core_device_t::~core_device_t() void core_device_t::set_delegate_pointer() { -#if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF) - void (core_device_t::* pFunc)() = &core_device_t::update; - m_static_update = pFunc; -#elif (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) - void (core_device_t::* pFunc)() = &core_device_t::update; - m_static_update = reinterpret_cast<net_update_delegate>((this->*pFunc)); -#elif (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL) - m_static_update = plib::mfp::get_mfp<net_update_delegate>(&core_device_t::update, this); +#if (!NL_USE_PMF_VIRTUAL) + m_static_update.set_base(&core_device_t::update, this); #endif } +plib::plog_base<NL_DEBUG> &core_device_t::log() +{ + return netlist().log(); +} + // ---------------------------------------------------------------------------------------- // device_t // ---------------------------------------------------------------------------------------- @@ -697,7 +680,7 @@ void device_t::connect(const pstring &t1, const pstring &t2) void device_t::connect_post_start(detail::core_terminal_t &t1, detail::core_terminal_t &t2) { if (!setup().connect(t1, t2)) - netlist().log().fatal(MF_2_ERROR_CONNECTING_1_TO_2, t1.name(), t2.name()); + log().fatal(MF_2_ERROR_CONNECTING_1_TO_2, t1.name(), t2.name()); } @@ -705,9 +688,9 @@ void device_t::connect_post_start(detail::core_terminal_t &t1, detail::core_term // family_setter_t // ----------------------------------------------------------------------------- -detail::family_setter_t::family_setter_t(core_device_t &dev, const char *desc) +detail::family_setter_t::family_setter_t(core_device_t &dev, const pstring desc) { - dev.set_logic_family(dev.netlist().family_from_model(desc)); + dev.set_logic_family(dev.netlist().setup().family_from_model(desc)); } detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_desc_t *desc) @@ -719,13 +702,6 @@ detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_ // net_t // ---------------------------------------------------------------------------------------- -// FIXME: move somewhere central - -struct do_nothing_deleter{ - template<typename T> void operator()(T*){} -}; - - detail::net_t::net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr) : object_t(aname) , netlist_ref(nl) @@ -734,10 +710,9 @@ detail::net_t::net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr) , m_time(*this, "m_time", netlist_time::zero()) , m_active(*this, "m_active", 0) , m_in_queue(*this, "m_in_queue", 2) - , m_railterminal(nullptr) , m_cur_Analog(*this, "m_cur_Analog", 0.0) + , m_railterminal(mr) { - m_railterminal = mr; } detail::net_t::~net_t() @@ -758,7 +733,7 @@ void detail::net_t::inc_active(core_terminal_t &term) NL_NOEXCEPT if (m_time > netlist().time()) { m_in_queue = 1; /* pending */ - netlist().queue().push(this, m_time); + netlist().queue().push(queue_t::entry_t(m_time, this)); } else { @@ -968,16 +943,20 @@ terminal_t::~terminal_t() void terminal_t::schedule_solve() { - // FIXME: Remove this after we found a way to remove *ALL* twoterms connected to railnets only. - if (net().solver() != nullptr) - net().solver()->update_forced(); + // Nets may belong to railnets which do not have a solver attached + // FIXME: Enforce that all terminals get connected? + if (this->has_net()) + if (net().solver() != nullptr) + net().solver()->update_forced(); } void terminal_t::schedule_after(const netlist_time &after) { - // FIXME: Remove this after we found a way to remove *ALL* twoterms connected to railnets only. - if (net().solver() != nullptr) - net().solver()->update_after(after); + // Nets may belong to railnets which do not have a solver attached + // FIXME: Enforce that all terminals get connected? + if (this->has_net()) + if (net().solver() != nullptr) + net().solver()->update_after(after); } // ---------------------------------------------------------------------------------------- @@ -1037,7 +1016,7 @@ analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname) netlist().m_nets.push_back(plib::owned_ptr<analog_net_t>(&m_my_net, false)); this->set_net(&m_my_net); - net().m_cur_Analog = NL_FCONST(0.0); + //net().m_cur_Analog = NL_FCONST(0.0); netlist().setup().register_term(*this); } @@ -1047,7 +1026,7 @@ analog_output_t::~analog_output_t() void analog_output_t::initial(const nl_double val) { - net().m_cur_Analog = val; + net().set_Q_Analog(val); } // ----------------------------------------------------------------------------- @@ -1133,11 +1112,11 @@ param_double_t::param_double_t(device_t &device, const pstring name, const doubl m_param = device.setup().get_initial_param_val(this->name(),val); netlist().save(*this, m_param, "m_param"); } - +#if 0 param_double_t::~param_double_t() { } - +#endif param_int_t::param_int_t(device_t &device, const pstring name, const int val) : param_t(device, name) { @@ -1145,9 +1124,11 @@ param_int_t::param_int_t(device_t &device, const pstring name, const int val) netlist().save(*this, m_param, "m_param"); } +#if 0 param_int_t::~param_int_t() { } +#endif param_logic_t::param_logic_t(device_t &device, const pstring name, const bool val) : param_t(device, name) @@ -1156,9 +1137,11 @@ param_logic_t::param_logic_t(device_t &device, const pstring name, const bool va netlist().save(*this, m_param, "m_param"); } +#if 0 param_logic_t::~param_logic_t() { } +#endif param_ptr_t::param_ptr_t(device_t &device, const pstring name, uint8_t * val) : param_t(device, name) @@ -1167,13 +1150,15 @@ param_ptr_t::param_ptr_t(device_t &device, const pstring name, uint8_t * val) //netlist().save(*this, m_param, "m_param"); } +#if 0 param_ptr_t::~param_ptr_t() { } +#endif void param_model_t::changed() { - netlist().log().fatal("Models can not be changed at runtime"); + netlist().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name()); m_map.clear(); } @@ -1200,8 +1185,6 @@ std::unique_ptr<plib::pistream> param_data_t::stream() return device().netlist().setup().get_data_stream(Value()); } - - namespace devices { // ---------------------------------------------------------------------------------------- diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 171a81292ae..e56a10b9e20 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -9,27 +9,27 @@ #ifndef NLBASE_H_ #define NLBASE_H_ -#include <vector> -#include <unordered_map> -#include <memory> -//#include <cmath> -#include <cstdint> - #include "nl_lists.h" #include "nl_time.h" -#include "plib/palloc.h" +#include "plib/palloc.h" // owned_ptr #include "plib/pdynlib.h" #include "plib/pstate.h" #include "plib/pfmtlog.h" #include "plib/pstream.h" -#include "plib/pexception.h" +#include "plib/ppmf.h" + +#include <unordered_map> + +#ifdef NL_PROHIBIT_BASEH_INCLUDE +#error "nl_base.h included. Please correct." +#endif // ---------------------------------------------------------------------------------------- // Type definitions // ---------------------------------------------------------------------------------------- /*! netlist_sig_t is the type used for logic signals. */ -using netlist_sig_t = std::uint_least32_t; +using netlist_sig_t = std::uint32_t; //============================================================ // MACROS / New Syntax @@ -85,18 +85,26 @@ class NETLIB_NAME(name) : public device_t : device_t(owner, name) /*! Add this to a device definition to mark the device as dynamic. - * If this is added to device definition the device is treated as an analog - * dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI is called on a each step - * of the Newton-Raphson step of solving the linear equations. + * If NETLIB_IS_DYNAMIC(true) is added to the device definition the device + * is treated as an analog dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI + * is called on a each step of the Newton-Raphson step + * of solving the linear equations. + * + * You may also use e.g. NETLIB_IS_DYNAMIC(m_func() != "") to only make the + * device a dynamic device if parameter m_func is set. */ -#define NETLIB_IS_DYNAMIC() \ - public: virtual bool is_dynamic() const override { return true; } +#define NETLIB_IS_DYNAMIC(expr) \ + public: virtual bool is_dynamic() const override { return expr; } /*! Add this to a device definition to mark the device as a time-stepping device. - * + * * You have to implement NETLIB_TIMESTEP in this case as well. Currently, only * the capacitor and inductor devices uses this. * + * You may also use e.g. NETLIB_IS_TIMESTEP(m_func() != "") to only make the + * device a dynamic device if parameter m_func is set. This is used by the + * Voltage Source element. + * * Example: * * NETLIB_TIMESTEP_IS_TIMESTEP() @@ -109,8 +117,8 @@ class NETLIB_NAME(name) : public device_t * } * */ -#define NETLIB_IS_TIMESTEP() \ - public: virtual bool is_timestep() const override { return true; } +#define NETLIB_IS_TIMESTEP(expr) \ + public: virtual bool is_timestep() const override { return expr; } /*! Used to implement the time stepping code. * @@ -220,11 +228,6 @@ namespace netlist class core_device_t; class device_t; - /*! Type of the model map used. - * This is used to hold all #Models in an unordered map - */ - using model_map_t = std::unordered_map<pstring, pstring>; - /*! Logic families descriptors are used to create proxy devices. * The logic family describes the analog capabilities of logic devices, * inputs and outputs. @@ -248,7 +251,7 @@ namespace netlist double R_low() const { return m_R_low; } double R_high() const { return m_R_high; } - double m_fixed_V; //!< For variable voltage families, specify 0. For TTL this would be 5. */ + double m_fixed_V; //!< For variable voltage families, specify 0. For TTL this would be 5. */ double m_low_thresh_PCNT; //!< low input threshhold offset. If the input voltage is below this value times supply voltage, a "0" input is signalled double m_high_thresh_PCNT; //!< high input threshhold offset. If the input voltage is above the value times supply voltage, a "0" input is signalled double m_low_VO; //!< low output voltage offset. This voltage is output if the ouput is "0" @@ -273,12 +276,12 @@ namespace netlist public: logic_family_t() : m_logic_family(nullptr) {} - ~logic_family_t() { } const logic_family_desc_t *logic_family() const { return m_logic_family; } void set_logic_family(const logic_family_desc_t *fam) { m_logic_family = fam; } protected: + ~logic_family_t() { } // prohibit polymorphic destruction const logic_family_desc_t *m_logic_family; }; @@ -313,19 +316,15 @@ namespace netlist //! Move Constructor. state_var(state_var &&rhs) NL_NOEXCEPT = default; //! Assignment operator to assign value of a state var. - state_var &operator=(state_var rhs) { std::swap(rhs.m_value, this->m_value); return *this; } + state_var &operator=(const state_var &rhs) { m_value = rhs; return *this; } //! Assignment operator to assign value of type T. - state_var &operator=(const T rhs) { m_value = rhs; return *this; } + state_var &operator=(const T &rhs) { m_value = rhs; return *this; } //! Return value of state variable. operator T & () { return m_value; } - //! Return value of state variable. - T & operator()() { return m_value; } //! Return const value of state variable. - operator const T & () const { return m_value; } - //! Return const value of state variable. - const T & operator()() const { return m_value; } + constexpr operator const T & () const { return m_value; } T * ptr() { return &m_value; } - const T * ptr() const { return &m_value; } + constexpr T * ptr() const { return &m_value; } private: T m_value; }; @@ -338,13 +337,20 @@ namespace netlist struct state_var<T[N]> { public: - state_var(device_t &dev, const pstring name, const T & value); + //! Constructor. + template <typename O> + state_var(O &owner, //!< owner must have a netlist() method. + const pstring name, //!< identifier/name for this state variable + const T &value //!< Initial value after construction + ); + //! Copy Constructor. state_var(const state_var &rhs) NL_NOEXCEPT = default; + //! Move Constructor. state_var(state_var &&rhs) NL_NOEXCEPT = default; - state_var &operator=(const state_var rhs) { m_value = rhs.m_value; return *this; } - state_var &operator=(const T rhs) { m_value = rhs; return *this; } + state_var &operator=(const state_var &rhs) { m_value = rhs.m_value; return *this; } + state_var &operator=(const T &rhs) { m_value = rhs; return *this; } T & operator[](const std::size_t i) { return m_value[i]; } - const T & operator[](const std::size_t i) const { return m_value[i]; } + constexpr T & operator[](const std::size_t i) const { return m_value[i]; } private: T m_value[N]; }; @@ -376,7 +382,6 @@ namespace netlist */ class detail::object_t { - P_PREVENT_COPYING(object_t) public: /*! Constructor. @@ -384,7 +389,6 @@ namespace netlist * Every class derived from the object_t class must have a name. */ object_t(const pstring &aname /*!< string containing name of the object */); - virtual ~object_t(); /*! return name of the object * @@ -396,6 +400,8 @@ namespace netlist void operator delete (void *ptr, void *) { } void * operator new (size_t size); void operator delete (void * mem); + protected: + ~object_t(); // only childs should be destructible private: pstring m_name; @@ -404,11 +410,13 @@ namespace netlist struct detail::netlist_ref { netlist_ref(netlist_t &nl) : m_netlist(nl) { } - ~netlist_ref() {} netlist_t & netlist() { return m_netlist; } const netlist_t & netlist() const { return m_netlist; } + protected: + ~netlist_ref() {} // prohibit polymorphic destruction + private: netlist_t & m_netlist; @@ -425,16 +433,7 @@ namespace netlist */ class detail::device_object_t : public detail::object_t { - P_PREVENT_COPYING(device_object_t) public: - /*! Enum specifying the type of object */ - enum type_t { - TERMINAL = 0, /*!< object is an analog terminal */ - INPUT = 1, /*!< object is an input */ - OUTPUT = 2, /*!< object is an output */ - PARAM = 3, /*!< object is a parameter */ - }; - /*! Constructor. * * \param dev device owning the object. @@ -446,16 +445,6 @@ namespace netlist */ core_device_t &device() const { return m_device; } - /*! The object type. - * \returns type of the object - */ - type_t type() const; - /*! Checks if object is of specified type. - * \param atype type to check object against. - * \returns true if object is of specified type else false. - */ - bool is_type(const type_t atype) const { return (type() == atype); } - /*! The netlist owning the owner of this object. * \returns reference to netlist object. */ @@ -478,7 +467,6 @@ namespace netlist */ class detail::core_terminal_t : public device_object_t, public plib::linkedlist_t<core_terminal_t>::element_t { - P_PREVENT_COPYING(core_terminal_t) public: using list_t = std::vector<core_terminal_t *>; @@ -495,6 +483,16 @@ namespace netlist core_terminal_t(core_device_t &dev, const pstring &aname, const state_e state); virtual ~core_terminal_t(); + /*! The object type. + * \returns type of the object + */ + terminal_type type() const; + /*! Checks if object is of specified type. + * \param atype type to check object against. + * \returns true if object is of specified type else false. + */ + bool is_type(const terminal_type atype) const { return (type() == atype); } + void set_net(net_t *anet); void clear_net(); bool has_net() const { return (m_net != nullptr); } @@ -540,7 +538,6 @@ namespace netlist class terminal_t : public analog_t { - P_PREVENT_COPYING(terminal_t) public: terminal_t(core_device_t &dev, const pstring &aname); @@ -550,16 +547,12 @@ namespace netlist void set(const nl_double G) { - set_ptr(m_Idr1, 0); - set_ptr(m_go1, G); - set_ptr(m_gt1, G); + set(G,G, 0.0); } void set(const nl_double GO, const nl_double GT) { - set_ptr(m_Idr1, 0); - set_ptr(m_go1, GO); - set_ptr(m_gt1, GT); + set(GO, GT, 0.0); } void set(const nl_double GO, const nl_double GT, const nl_double I) @@ -690,7 +683,6 @@ namespace netlist public detail::object_t, public detail::netlist_ref { - P_PREVENT_COPYING(net_t) public: net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr = nullptr); @@ -698,12 +690,6 @@ namespace netlist void reset(); - void add_terminal(core_terminal_t &terminal); - void remove_terminal(core_terminal_t &terminal); - - bool is_logic() const NL_NOEXCEPT; - bool is_analog() const NL_NOEXCEPT; - void toggle_new_Q() { m_new_Q ^= 1; } void force_queue_execution() { m_new_Q = (m_cur_Q ^ 1); } @@ -724,6 +710,14 @@ namespace netlist void inc_active(core_terminal_t &term) NL_NOEXCEPT; void dec_active(core_terminal_t &term) NL_NOEXCEPT; + /* setup stuff */ + + void add_terminal(core_terminal_t &terminal); + void remove_terminal(core_terminal_t &terminal); + + bool is_logic() const NL_NOEXCEPT; + bool is_analog() const NL_NOEXCEPT; + void rebuild_list(); /* rebuild m_list after a load */ void move_connections(net_t &dest_net); @@ -737,26 +731,25 @@ namespace netlist state_var_s32 m_active; state_var_u8 m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */ + state_var<nl_double> m_cur_Analog; + private: plib::linkedlist_t<core_terminal_t> m_list_active; core_terminal_t * m_railterminal; public: - // FIXME: Have to fix the public at some time - state_var<nl_double> m_cur_Analog; }; class logic_net_t : public detail::net_t { - P_PREVENT_COPYING(logic_net_t) public: logic_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr); virtual ~logic_net_t(); netlist_sig_t Q() const { return m_cur_Q; } - netlist_sig_t new_Q() const { return m_new_Q; } + netlist_sig_t new_Q() const { return m_new_Q; } void initial(const netlist_sig_t val) { m_cur_Q = m_new_Q = val; } void set_Q(const netlist_sig_t newQ, const netlist_time delay) NL_NOEXCEPT @@ -781,7 +774,7 @@ namespace netlist /* internal state support * FIXME: get rid of this and implement export/import in MAME */ - netlist_sig_t &Q_state_ptr() { return m_cur_Q; } + netlist_sig_t *Q_state_ptr() { return m_cur_Q.ptr(); } protected: private: @@ -790,7 +783,6 @@ namespace netlist class analog_net_t : public detail::net_t { - P_PREVENT_COPYING(analog_net_t) public: using list_t = std::vector<analog_net_t *>; @@ -800,7 +792,8 @@ namespace netlist virtual ~analog_net_t(); nl_double Q_Analog() const { return m_cur_Analog; } - nl_double &Q_Analog_state_ptr() { return m_cur_Analog; } + void set_Q_Analog(const nl_double &v) { m_cur_Analog = v; } + nl_double *Q_Analog_state_ptr() { return m_cur_Analog.ptr(); } //FIXME: needed by current solver code devices::matrix_solver_t *solver() const { return m_solver; } @@ -816,7 +809,6 @@ namespace netlist class logic_output_t : public logic_t { - P_PREVENT_COPYING(logic_output_t) public: logic_output_t(core_device_t &dev, const pstring &aname); @@ -835,7 +827,6 @@ namespace netlist class analog_output_t : public analog_t { - P_PREVENT_COPYING(analog_output_t) public: analog_output_t(core_device_t &dev, const pstring &aname); virtual ~analog_output_t(); @@ -854,7 +845,6 @@ namespace netlist class param_t : public detail::device_object_t { - P_PREVENT_COPYING(param_t) public: enum param_type_t { @@ -866,11 +856,12 @@ namespace netlist }; param_t(device_t &device, const pstring &name); - virtual ~param_t(); param_type_t param_type() const; protected: + virtual ~param_t(); /* not intended to be destroyed */ + void update_param(); template<typename C> @@ -889,7 +880,6 @@ namespace netlist { public: param_ptr_t(device_t &device, const pstring name, std::uint8_t* val); - virtual ~param_ptr_t(); std::uint8_t * operator()() const { return m_param; } void setTo(std::uint8_t *param) { set(m_param, param); } private: @@ -900,7 +890,6 @@ namespace netlist { public: param_logic_t(device_t &device, const pstring name, const bool val); - virtual ~param_logic_t(); bool operator()() const { return m_param; } void setTo(const bool ¶m) { set(m_param, param); } private: @@ -911,7 +900,6 @@ namespace netlist { public: param_int_t(device_t &device, const pstring name, const int val); - virtual ~param_int_t(); int operator()() const { return m_param; } void setTo(const int ¶m) { set(m_param, param); } private: @@ -922,7 +910,6 @@ namespace netlist { public: param_double_t(device_t &device, const pstring name, const double val); - virtual ~param_double_t(); double operator()() const { return m_param; } void setTo(const double ¶m) { set(m_param, param); } private: @@ -934,6 +921,7 @@ namespace netlist public: param_str_t(device_t &device, const pstring name, const pstring val); virtual ~param_str_t(); + const pstring operator()() const { return Value(); } void setTo(const pstring ¶m) { @@ -981,8 +969,8 @@ namespace netlist private: /* hide this */ void setTo(const pstring ¶m) = delete; - model_map_t m_map; - }; + detail::model_map_t m_map; +}; class param_data_t : public param_str_t @@ -996,6 +984,28 @@ namespace netlist }; // ----------------------------------------------------------------------------- + // rom parameter + // ----------------------------------------------------------------------------- + + template <typename ST, std::size_t AW, std::size_t DW> + class param_rom_t final: public param_data_t + { + public: + + param_rom_t(device_t &device, const pstring name); + + const ST & operator[] (std::size_t n) { return m_data[n]; } + protected: + virtual void changed() override + { + stream()->read(&m_data[0],1<<AW); + } + + private: + ST m_data[1 << AW]; + }; + + // ----------------------------------------------------------------------------- // core_device_t // ----------------------------------------------------------------------------- @@ -1004,7 +1014,6 @@ namespace netlist public logic_family_t, public detail::netlist_ref { - P_PREVENT_COPYING(core_device_t) public: core_device_t(netlist_t &owner, const pstring &name); core_device_t(core_device_t &owner, const pstring &name); @@ -1052,15 +1061,15 @@ namespace netlist void do_update() NL_NOEXCEPT { - #if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF) - (this->*m_static_update)(); - #elif ((NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) || (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL)) - m_static_update(this); + #if (NL_USE_PMF_VIRTUAL) + update(); #else - update(); + m_static_update.call(this); #endif } + plib::plog_base<NL_DEBUG> &log(); + public: virtual void timestep(ATTR_UNUSED const nl_double st) { } virtual void update_terminals() { } @@ -1072,14 +1081,9 @@ namespace netlist private: bool m_hint_deactivate; - #if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF) - typedef void (core_device_t::*net_update_delegate)(); - #elif ((NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) || (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL)) - using net_update_delegate = MEMBER_ABI void (*)(core_device_t *); - #endif - #if (NL_PMF_TYPE > NL_PMF_TYPE_VIRTUAL) - net_update_delegate m_static_update; + #if (!NL_USE_PMF_VIRTUAL) + plib::pmfp_base<void> m_static_update; #endif }; @@ -1089,7 +1093,6 @@ namespace netlist class device_t : public core_device_t { - P_PREVENT_COPYING(device_t) public: template <class C> @@ -1103,7 +1106,7 @@ namespace netlist template<class C, typename... Args> void register_sub(const pstring &name, std::unique_ptr<C> &dev, const Args&... args) { - dev.reset(new C(*this, name, args...)); + dev.reset(plib::palloc<C>(*this, name, args...)); } void register_subalias(const pstring &name, detail::core_terminal_t &term); @@ -1127,7 +1130,7 @@ namespace netlist struct detail::family_setter_t { family_setter_t() { } - family_setter_t(core_device_t &dev, const char *desc); + family_setter_t(core_device_t &dev, const pstring desc); family_setter_t(core_device_t &dev, const logic_family_desc_t *desc); }; @@ -1171,9 +1174,8 @@ namespace netlist // ----------------------------------------------------------------------------- - class netlist_t : public plib::plog_dispatch_intf + class netlist_t : public plib::plog_dispatch_intf, private plib::nocopyassignmove { - P_PREVENT_COPYING(netlist_t) public: explicit netlist_t(const pstring &aname); @@ -1207,7 +1209,6 @@ namespace netlist void remove_dev(core_device_t *dev); detail::net_t *find_net(const pstring &name); - const logic_family_desc_t *family_from_model(const pstring &model); template<class device_class> std::vector<device_class *> get_device_list() @@ -1222,22 +1223,16 @@ namespace netlist return tmp; } - template<class device_class> - device_class *get_single_device(const char *classname) + template<class C> + static bool check_class(core_device_t *p) { - device_class *ret = nullptr; - for (auto &d : m_devices) - { - device_class *dev = dynamic_cast<device_class *>(d.get()); - if (dev != nullptr) - { - if (ret != nullptr) - this->log().fatal("more than one {1} device found", classname); - else - ret = dev; - } - } - return ret; + return dynamic_cast<C *>(p) != nullptr; + } + + template<class C> + C *get_single_device(const pstring classname) + { + return dynamic_cast<C *>(pget_single_device(classname, check_class<C>)); } /* logging and name */ @@ -1252,24 +1247,34 @@ namespace netlist template<typename O, typename C> void save(O &owner, C &state, const pstring &stname) { - this->state().save_item(static_cast<void *>(&owner), state, owner.name() + pstring(".") + stname); + this->state().save_item(static_cast<void *>(&owner), state, from_utf8(owner.name()) + pstring(".") + stname); } template<typename O, typename C> void save(O &owner, C *state, const pstring &stname, const std::size_t count) { - this->state().save_state_ptr(static_cast<void *>(&owner), owner.name() + pstring(".") + stname, plib::state_manager_t::datatype_f<C>::f(), count, state); + this->state().save_state_ptr(static_cast<void *>(&owner), from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f<C>::f(), count, state); } void rebuild_lists(); /* must be called after post_load ! */ plib::dynlib &lib() { return *m_lib; } + // FIXME: find something better /* sole use is to manage lifetime of net objects */ std::vector<plib::owned_ptr<detail::net_t>> m_nets; + /* sole use is to manage lifetime of family objects */ + std::vector<std::pair<pstring, std::unique_ptr<logic_family_desc_t>>> m_family_cache; protected: void print_stats() const; private: + + /* helper for save above */ + static pstring from_utf8(const char *c) { return pstring(c, pstring::UTF8); } + static pstring from_utf8(const pstring &c) { return c; } + + core_device_t *pget_single_device(const pstring classname, bool (*cc)(core_device_t *)); + /* mostly rw */ netlist_time m_time; detail::queue_t m_queue; @@ -1281,21 +1286,17 @@ namespace netlist devices::NETLIB_NAME(netlistparams) *m_params; pstring m_name; - setup_t * m_setup; + std::unique_ptr<setup_t> m_setup; plib::plog_base<NL_DEBUG> m_log; - plib::dynlib * m_lib; // external lib needs to be loaded as long as netlist exists + std::unique_ptr<plib::dynlib> m_lib; // external lib needs to be loaded as long as netlist exists plib::state_manager_t m_state; // performance nperftime_t m_stat_mainloop; nperfcount_t m_perf_out_processed; - nperfcount_t m_perf_inp_processed; - nperfcount_t m_perf_inp_active; std::vector<plib::owned_ptr<core_device_t>> m_devices; - /* sole use is to manage lifetime of family objects */ - std::vector<std::pair<pstring, std::unique_ptr<logic_family_desc_t>>> m_family_cache; }; // ----------------------------------------------------------------------------- @@ -1313,43 +1314,24 @@ namespace netlist object_array_t(core_device_t &dev, init names) { for (std::size_t i = 0; i<N; i++) - this->emplace(i, dev, names.p[i]); + this->emplace(i, dev, pstring(names.p[i], pstring::UTF8)); } }; // ----------------------------------------------------------------------------- - // rom parameter + // inline implementations // ----------------------------------------------------------------------------- template <typename ST, std::size_t AW, std::size_t DW> - class param_rom_t final: public param_data_t + inline param_rom_t<ST, AW, DW>::param_rom_t(device_t &device, const pstring name) + : param_data_t(device, name) { - public: - - param_rom_t(device_t &device, const pstring name) - : param_data_t(device, name) - { - auto f = stream(); - if (f != nullptr) - f->read(&m_data[0],1<<AW); - else - device.netlist().log().warning("Rom {1} not found", Value()); - } - - const ST & operator[] (std::size_t n) { return m_data[n]; } - - protected: - virtual void changed() override - { - stream()->read(&m_data[0],1<<AW); - } - private: - ST m_data[1 << AW]; - }; - - // ----------------------------------------------------------------------------- - // inline implementations - // ----------------------------------------------------------------------------- + auto f = stream(); + if (f != nullptr) + f->read(&m_data[0],1<<AW); + else + device.netlist().log().warning("Rom {1} not found", Value()); + } inline bool detail::core_terminal_t::is_logic() const NL_NOEXCEPT { @@ -1414,7 +1396,7 @@ namespace netlist m_time = netlist().time() + delay; m_in_queue = (m_active > 0); /* queued ? */ if (m_in_queue) - netlist().queue().push(this, m_time); + netlist().queue().push(queue_t::entry_t(m_time, this)); } } @@ -1426,7 +1408,7 @@ namespace netlist m_time = netlist().time() + delay; m_in_queue = (m_active > 0); /* queued ? */ if (m_in_queue) - netlist().queue().push(this, m_time); + netlist().queue().push(queue_t::entry_t(m_time, this)); } inline const analog_net_t & analog_t::net() const NL_NOEXCEPT @@ -1443,7 +1425,7 @@ namespace netlist inline logic_net_t & logic_t::net() NL_NOEXCEPT { - return *static_cast<logic_net_t *>(&core_terminal_t::net()); + return static_cast<logic_net_t &>(core_terminal_t::net()); } inline const logic_net_t & logic_t::net() const NL_NOEXCEPT @@ -1465,7 +1447,7 @@ namespace netlist { if (newQ != m_my_net.Q_Analog()) { - m_my_net.m_cur_Analog = newQ; + m_my_net.set_Q_Analog(newQ); m_my_net.toggle_new_Q(); m_my_net.push_to_queue(NLTIME_FROM_NS(1)); } @@ -1480,9 +1462,10 @@ namespace netlist } template <typename T, std::size_t N> - state_var<T[N]>::state_var(device_t &dev, const pstring name, const T & value) + template <typename O> + state_var<T[N]>::state_var(O &owner, const pstring name, const T & value) { - dev.netlist().save(dev, m_value, name); + owner.netlist().save(owner, m_value, name); for (std::size_t i=0; i<N; i++) m_value[i] = value; } @@ -1499,5 +1482,14 @@ namespace netlist } +namespace plib +{ + template<typename X> + struct ptype_traits<netlist::state_var<X>> : ptype_traits<X> + { + }; +} + + #endif /* NLBASE_H_ */ diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index 88f240394be..ded567717f9 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -9,68 +9,12 @@ #ifndef NLCONFIG_H_ #define NLCONFIG_H_ -#include <cstdint> - #include "plib/pconfig.h" -#include "plib/pchrono.h" //============================================================ // SETUP //============================================================ -/* - * The following options determine how object::update is called. - * NL_PMF_TYPE_VIRTUAL - * Use stock virtual call - * - * NL_PMF_TYPE_GNUC_PMF - * Use standard pointer to member function syntax - * - * NL_PMF_TYPE_GNUC_PMF_CONV - * Use gnu extension and convert the pmf to a function pointer. - * This is not standard compliant and needs - * -Wno-pmf-conversions to compile. - * - * NL_PMF_TYPE_INTERNAL - * Use the same approach as MAME for deriving the function pointer. - * This is compiler-dependant as well - * - * Benchmarks for ./nltool -c run -f src/mame/drivers/nl_pong.c -t 10 -n pong_fast - * - * NL_PMF_TYPE_INTERNAL: 215% - * NL_PMF_TYPE_GNUC_PMF: 163% - * NL_PMF_TYPE_GNUC_PMF_CONV: 215% - * NL_PMF_TYPE_VIRTUAL: 213% - * - * The whole exercise was done to avoid virtual calls. In prior versions of - * netlist, the INTERNAL and GNUC_PMF_CONV approach provided significant improvement. - * Since than, was removed from functions declared as virtual. - * This may explain that the recent benchmarks show no difference at all. - * - * Disappointing is the GNUC_PMF performance. - */ - -// This will be autodetected -// #define NL_PMF_TYPE 0 - -#define NL_PMF_TYPE_VIRTUAL 0 -#define NL_PMF_TYPE_GNUC_PMF 1 -#define NL_PMF_TYPE_GNUC_PMF_CONV 2 -#define NL_PMF_TYPE_INTERNAL 3 - -#ifndef NL_PMF_TYPE - #if PHAS_PMF_INTERNAL - #define NL_PMF_TYPE NL_PMF_TYPE_INTERNAL - #else - #define NL_PMF_TYPE NL_PMF_TYPE_VIRTUAL - #endif -#endif - -#if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) -#pragma GCC diagnostic ignored "-Wpmf-conversions" -#endif - - //============================================================ // GENERAL @@ -86,8 +30,12 @@ * */ #define USE_MEMPOOL (0) + #define USE_TRUTHTABLE (1) +// How many times do we try to resolve links (connections) +#define NL_MAX_LINK_RESOLVE_LOOPS (100) + //============================================================ // Solver defines //============================================================ @@ -120,20 +68,6 @@ #endif //============================================================ -// Performance tracking -//============================================================ - -namespace netlist -{ -#if NL_KEEP_STATISTICS -using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, true>; -using nperfcount_t = plib::chrono::counter<true>; -#else -using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, false>; -using nperfcount_t = plib::chrono::counter<false>; -#endif -} -//============================================================ // General //============================================================ @@ -156,6 +90,20 @@ using nperfcount_t = plib::chrono::counter<false>; #define NL_FCONST(x) x using nl_double = double; +/* The following option determines how object::update is called. + * If set to 1, a virtual call is used. If it is left undefined, the best + * approach will be automatically selected. + */ + +//#define NL_USE_PMF_VIRTUAL 1 + +#ifndef NL_USE_PMF_VIRTUAL + #if PPMF_TYPE == PPMF_TYPE_PMF + #define NL_USE_PMF_VIRTUAL 1 + #else + #define NL_USE_PMF_VIRTUAL 0 + #endif +#endif //============================================================ // WARNINGS diff --git a/src/lib/netlist/nl_dice_compat.h b/src/lib/netlist/nl_dice_compat.h index 209f18d82af..b0ebdb2e371 100644 --- a/src/lib/netlist/nl_dice_compat.h +++ b/src/lib/netlist/nl_dice_compat.h @@ -27,8 +27,11 @@ sed -e 's/#define \(.*\)"\(.*\)"[ \t]*,[ \t]*\(.*\)/NET_ALIAS(\1,\2.\3)/' src/ma #ifndef NL_CONVERT_CPP #include "devices/net_lib.h" #include "analog/nld_twoterm.h" + +#include <cmath> #endif + /* -------------------------------------------------------------------- * Compatibility macros for DICE netlists ... * -------------------------------------------------------------------- */ diff --git a/src/lib/netlist/nl_errstr.h b/src/lib/netlist/nl_errstr.h index 563e33dd93f..ec52187558f 100644 --- a/src/lib/netlist/nl_errstr.h +++ b/src/lib/netlist/nl_errstr.h @@ -11,18 +11,92 @@ // nl_base.cpp -#define MF_1_DUPLICATE_NAME_DEVICE_LIST "Error adding {1} to device list. Duplicate name." -#define MF_1_UNKNOWN_TYPE_FOR_OBJECT "Unknown type for object {1} " -#define MF_2_NET_1_DUPLICATE_TERMINAL_2 "net {1}: duplicate terminal {2}" -#define MF_2_REMOVE_TERMINAL_1_FROM_NET_2 "Can not remove terminal {1} from net {2}." -#define MF_1_UNKNOWN_PARAM_TYPE "Can not determine param_type for {1}" -#define MF_2_ERROR_CONNECTING_1_TO_2 "Error connecting {1} to {2}" -#define MF_0_NO_SOLVER "No solver found for this netlist although analog elements are present\n" +#define MF_1_DUPLICATE_NAME_DEVICE_LIST "Error adding {1} to device list. Duplicate name." +#define MF_1_UNKNOWN_TYPE_FOR_OBJECT "Unknown type for object {1} " +#define MF_2_NET_1_DUPLICATE_TERMINAL_2 "net {1}: duplicate terminal {2}" +#define MF_2_REMOVE_TERMINAL_1_FROM_NET_2 "Can not remove terminal {1} from net {2}." +#define MF_1_UNKNOWN_PARAM_TYPE "Can not determine param_type for {1}" +#define MF_2_ERROR_CONNECTING_1_TO_2 "Error connecting {1} to {2}" +#define MF_0_NO_SOLVER "No solver found for this netlist although analog elements are present" +#define MF_1_HND_VAL_NOT_SUPPORTED "HINT_NO_DEACTIVATE value not supported: <{1}>" // nl_factory.cpp -#define MF_1_FACTORY_ALREADY_CONTAINS_1 "factory already contains {1}" +#define MF_1_FACTORY_ALREADY_CONTAINS_1 "factory already contains {1}" #define MF_1_CLASS_1_NOT_FOUND "Class <{1}> not found!" +// nld_opamps.cpp -#endif /* NLBASE_H_ */ +#define MF_1_UNKNOWN_OPAMP_TYPE "Unknown opamp type: {1}" + +// nld_matrix_solver.cpp + +#define MF_1_UNHANDLED_ELEMENT_1_FOUND "setup_base:unhandled element <{1}> found" +#define MF_1_FOUND_TERM_WITH_MISSING_OTHERNET "found term with missing othernet {1}" + +#define MW_1_NEWTON_LOOPS_EXCEEDED_ON_NET_1 "NEWTON_LOOPS exceeded on net {1}... reschedule" + +// nld_solver.cpp + +#define MF_1_UNKNOWN_SOLVER_TYPE "Unknown solver type: {1}" +#define MF_1_NETGROUP_SIZE_EXCEEDED_1 "Encountered netgroup with > {1} nets" + +#define MW_1_NO_SPECIFIC_SOLVER "No specific solver found for netlist of size {1}" + +// nl_base.cpp + +#define MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME "Model {1} can not be changed at runtime" +#define MF_1_MORE_THAN_ONE_1_DEVICE_FOUND "more than one {1} device found" + +// nl_parser.cpp + +#define MF_0_UNEXPECTED_NETLIST_END "Unexpected NETLIST_END" +#define MF_0_UNEXPECTED_NETLIST_START "Unexpected NETLIST_START" + +// nl_setup.cpp + +//#define MF_1_CLASS_1_NOT_FOUND "Class {1} not found!" +#define MF_1_UNABLE_TO_PARSE_MODEL_1 "Unable to parse model: {1}" +#define MF_1_MODEL_ALREADY_EXISTS_1 "Model already exists: {1}" +#define MF_1_ADDING_ALIAS_1_TO_ALIAS_LIST "Error adding alias {1} to alias list" +#define MF_1_DIP_PINS_MUST_BE_AN_EQUAL_NUMBER_OF_PINS_1 "You must pass an equal number of pins to DIPPINS {1}" +#define MF_1_UNKNOWN_OBJECT_TYPE_1 "Unknown object type {1}" +#define MF_2_INVALID_NUMBER_CONVERSION_1_2 "Invalid number conversion {1} : {2}" +#define MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST "Error adding parameter {1} to parameter list" +#define MF_2_ADDING_1_2_TO_TERMINAL_LIST "Error adding {1} {2} to terminal list" +#define MF_2_NET_C_NEEDS_AT_LEAST_2_TERMINAL "You must pass at least 2 terminals to NET_C" +#define MF_1_FOUND_NO_OCCURRENCE_OF_1 "Found no occurrence of {1}" +#define MF_2_TERMINAL_1_2_NOT_FOUND "Alias {1} was resolved to be terminal {2}. Terminal {2} was not found." +#define MF_2_OBJECT_1_2_WRONG_TYPE "object {1}({2}) found but wrong type" +#define MF_2_PARAMETER_1_2_NOT_FOUND "parameter {1}({2}) not found!" +#define MF_2_CONNECTING_1_TO_2 "Error connecting {1} to {2}" +#define MF_2_MERGE_RAIL_NETS_1_AND_2 "Trying to merge two rail nets: {1} and {2}" +#define MF_1_OBJECT_INPUT_TYPE_1 "Unable to determine input type of {1}" +#define MF_1_OBJECT_OUTPUT_TYPE_1 "Unable to determine output type of {1}" +#define MF_1_INPUT_1_ALREADY_CONNECTED "Input {1} already connected" +#define MF_0_LINK_TRIES_EXCEEDED "Error connecting -- bailing out" +#define MF_1_MODEL_NOT_FOUND "Model {1} not found" +#define MF_1_MODEL_ERROR_1 "Model error {1}" +#define MF_1_MODEL_ERROR_ON_PAIR_1 "Model error on pair {1}" +#define MF_2_MODEL_PARAMETERS_NOT_UPPERCASE_1_2 "model parameters should be uppercase:{1} {2}" +#define MF_2_ENTITY_1_NOT_FOUND_IN_MODEL_2 "Entity {1} not found in model {2}" +#define MF_1_UNKNOWN_NUMBER_FACTOR_IN_1 "Unknown number factor in: {1}" +#define MF_1_NOT_FOUND_IN_SOURCE_COLLECTION "unable to find {1} in source collection" + +#define MW_3_OVERWRITING_PARAM_1_OLD_2_NEW_3 "Overwriting {1} old <{2}> new <{3}>" +#define MW_1_CONNECTING_1_TO_ITSELF "Connecting {1} to itself. This may be right, though" +#define MW_1_DUMMY_1_WITHOUT_CONNECTIONS "Found dummy terminal {1} without connections" +#define MW_1_TERMINAL_1_WITHOUT_CONNECTIONS "Found terminal {1} without connections" +#define MW_3_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3 "Found device {1} connected only to railterminals {2}/{3}. Will be removed" +#define MW_1_DATA_1_NOT_FOUND "unable to find data named {1} in source collection" + +// nld_mm5837.cpp + +#define MW_1_FREQUENCY_OUTSIDE_OF_SPECS_1 "MM5837: Frequency outside of specs: {1}" + +// nlid_proxy.cpp + +#define MW_1_NO_POWER_TERMINALS_ON_DEVICE_1 "D/A Proxy: Found no valid combination of power terminals on device {1}" + + +#endif /* NL_ERRSTR_H_ */ diff --git a/src/lib/netlist/nl_factory.cpp b/src/lib/netlist/nl_factory.cpp index 50dc2ef9c8d..2ab15375d62 100644 --- a/src/lib/netlist/nl_factory.cpp +++ b/src/lib/netlist/nl_factory.cpp @@ -9,6 +9,7 @@ ****************************************************************************/ #include "nl_factory.h" +#include "nl_base.h" #include "nl_setup.h" #include "plib/putil.h" #include "nl_errstr.h" @@ -16,9 +17,31 @@ namespace netlist { namespace factory { +class NETLIB_NAME(wrapper) : public device_t +{ +public: + NETLIB_NAME(wrapper)(netlist_t &anetlist, const pstring &name) + : device_t(anetlist, name) + { + } +protected: + NETLIB_RESETI(); + NETLIB_UPDATEI(); +}; + + + +element_t::element_t(const pstring &name, const pstring &classname, + const pstring &def_param, const pstring &sourcefile) + : m_name(name), m_classname(classname), m_def_param(def_param), + m_sourcefile(sourcefile) +{ +} + element_t::element_t(const pstring &name, const pstring &classname, const pstring &def_param) - : m_name(name), m_classname(classname), m_def_param(def_param) + : m_name(name), m_classname(classname), m_def_param(def_param), + m_sourcefile("<unknown>") { } diff --git a/src/lib/netlist/nl_factory.h b/src/lib/netlist/nl_factory.h index 9e2185e0729..92f126ea4d5 100644 --- a/src/lib/netlist/nl_factory.h +++ b/src/lib/netlist/nl_factory.h @@ -9,29 +9,42 @@ #ifndef NLFACTORY_H_ #define NLFACTORY_H_ -#include <type_traits> - -#include "nl_config.h" #include "plib/palloc.h" -#include "plib/plists.h" -#include "plib/putil.h" -#include "nl_base.h" - -#define NETLIB_DEVICE_IMPL(chip) factory::constructor_ptr_t decl_ ## chip = factory::constructor_t< NETLIB_NAME(chip) >; -#define NETLIB_DEVICE_IMPL_NS(ns, chip) factory::constructor_ptr_t decl_ ## chip = factory::constructor_t< ns :: NETLIB_NAME(chip) >; - -namespace netlist { namespace factory -{ +#include "plib/ptypes.h" + +#define NETLIB_DEVICE_IMPL(chip) \ + static std::unique_ptr<factory::element_t> NETLIB_NAME(chip ## _c)( \ + const pstring &name, const pstring &classname, const pstring &def_param) \ + { \ + return std::unique_ptr<factory::element_t>(plib::palloc<factory::device_element_t<NETLIB_NAME(chip)>>(name, classname, def_param, pstring(__FILE__))); \ + } \ + factory::constructor_ptr_t decl_ ## chip = NETLIB_NAME(chip ## _c); + +#define NETLIB_DEVICE_IMPL_NS(ns, chip) \ + static std::unique_ptr<factory::element_t> NETLIB_NAME(chip ## _c)( \ + const pstring &name, const pstring &classname, const pstring &def_param) \ + { \ + return std::unique_ptr<factory::element_t>(plib::palloc<factory::device_element_t<ns :: NETLIB_NAME(chip)>>(name, classname, def_param, pstring(__FILE__))); \ + } \ + factory::constructor_ptr_t decl_ ## chip = NETLIB_NAME(chip ## _c); + +namespace netlist { + class netlist_t; + class device_t; + class setup_t; + +namespace factory { // ----------------------------------------------------------------------------- // net_dev class factory // ----------------------------------------------------------------------------- - class element_t + class element_t : plib::nocopyassignmove { - P_PREVENT_COPYING(element_t) public: element_t(const pstring &name, const pstring &classname, const pstring &def_param); + element_t(const pstring &name, const pstring &classname, + const pstring &def_param, const pstring &sourcefile); virtual ~element_t(); virtual plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) = 0; @@ -40,21 +53,25 @@ namespace netlist { namespace factory const pstring &name() const { return m_name; } const pstring &classname() const { return m_classname; } const pstring ¶m_desc() const { return m_def_param; } + const pstring &sourcefile() const { return m_sourcefile; } protected: pstring m_name; /* device name */ pstring m_classname; /* device class name */ pstring m_def_param; /* default parameter */ + pstring m_sourcefile; /* source file */ }; template <class C> class device_element_t : public element_t { - P_PREVENT_COPYING(device_element_t) public: device_element_t(const pstring &name, const pstring &classname, const pstring &def_param) : element_t(name, classname, def_param) { } + device_element_t(const pstring &name, const pstring &classname, + const pstring &def_param, const pstring &sourcefile) + : element_t(name, classname, def_param, sourcefile) { } plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override { @@ -72,7 +89,7 @@ namespace netlist { namespace factory void register_device(const pstring &name, const pstring &classname, const pstring &def_param) { - register_device(std::unique_ptr<element_t>(new device_element_t<device_class>(name, classname, def_param))); + register_device(std::unique_ptr<element_t>(plib::palloc<device_element_t<device_class>>(name, classname, def_param))); } void register_device(std::unique_ptr<element_t> factory); @@ -87,7 +104,7 @@ namespace netlist { namespace factory private: setup_t &m_setup; -}; + }; // ----------------------------------------------------------------------------- // factory_creator_ptr_t @@ -100,42 +117,33 @@ namespace netlist { namespace factory std::unique_ptr<element_t> constructor_t(const pstring &name, const pstring &classname, const pstring &def_param) { - return std::unique_ptr<element_t>(new device_element_t<T>(name, classname, def_param)); + return std::unique_ptr<element_t>(plib::palloc<device_element_t<T>>(name, classname, def_param)); } // ----------------------------------------------------------------------------- // factory_lib_entry_t: factory class to wrap macro based chips/elements // ----------------------------------------------------------------------------- - class NETLIB_NAME(wrapper) : public device_t - { - public: - NETLIB_NAME(wrapper)(netlist_t &anetlist, const pstring &name) - : device_t(anetlist, name) - { - } - protected: - NETLIB_RESETI(); - NETLIB_UPDATEI(); - }; - class library_element_t : public element_t { - P_PREVENT_COPYING(library_element_t) public: library_element_t(setup_t &setup, const pstring &name, const pstring &classname, - const pstring &def_param) - : element_t(name, classname, def_param), m_setup(setup) { } + const pstring &def_param, const pstring &source) + : element_t(name, classname, def_param, source) { } plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override; void macro_actions(netlist_t &anetlist, const pstring &name) override; private: - setup_t &m_setup; }; -} } + } + + namespace devices { + void initialize_factory(factory::list_t &factory); + } +} #endif /* NLFACTORY_H_ */ diff --git a/src/lib/netlist/nl_lists.h b/src/lib/netlist/nl_lists.h index 2b378dadf71..4c6935bd7d4 100644 --- a/src/lib/netlist/nl_lists.h +++ b/src/lib/netlist/nl_lists.h @@ -11,10 +11,14 @@ #define NLLISTS_H_ #include <atomic> +#include <thread> +#include <mutex> #include "nl_config.h" +#include "netlist_types.h" #include "plib/plists.h" #include "plib/pchrono.h" +#include "plib/ptypes.h" // ---------------------------------------------------------------------------------------- // timed queue @@ -23,41 +27,45 @@ namespace netlist { - //FIXME: move to an appropriate place template<bool enabled_ = true> - class pspin_lock + class pspin_mutex { public: - pspin_lock() { } - void acquire() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } } - void release() noexcept { m_lock.clear(std::memory_order_release); } + pspin_mutex() noexcept { } + void lock() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } } + void unlock() noexcept { m_lock.clear(std::memory_order_release); } private: std::atomic_flag m_lock = ATOMIC_FLAG_INIT; }; template<> - class pspin_lock<false> + class pspin_mutex<false> { public: - void acquire() const noexcept { } - void release() const noexcept { } + void lock() const noexcept { } + void unlock() const noexcept { } }; - #if HAS_OPENMP && USE_OPENMP - using tqlock = pspin_lock<true>; - #else - using tqlock = pspin_lock<false>; - #endif - template <class Element, class Time> - class timed_queue + class timed_queue : plib::nocopyassignmove { - P_PREVENT_COPYING(timed_queue) public: struct entry_t { + entry_t() { } + entry_t(const Time &t, const Element &o) : m_exec_time(t), m_object(o) { } + entry_t(const entry_t &e) : m_exec_time(e.m_exec_time), m_object(e.m_object) { } + entry_t(entry_t &&e) : m_exec_time(e.m_exec_time), m_object(e.m_object) { } + + entry_t& operator=(entry_t && other) + { + m_exec_time = other.m_exec_time; + m_object = other.m_object; + return *this; + } + Time m_exec_time; Element m_object; }; @@ -65,37 +73,35 @@ namespace netlist timed_queue(unsigned list_size) : m_list(list_size) { - m_lock.acquire(); clear(); - m_lock.release(); } std::size_t capacity() const { return m_list.size(); } bool empty() const { return (m_end == &m_list[1]); } - void push(Element o, const Time t) noexcept + void push(entry_t &&e) noexcept { /* Lock */ - m_lock.acquire(); + tqlock lck(m_lock); entry_t * i = m_end; - for (; t > (i - 1)->m_exec_time; --i) + while (e.m_exec_time > (i - 1)->m_exec_time) { - *(i) = *(i-1); + *(i) = std::move(*(i-1)); + --i; m_prof_sortmove.inc(); } - *i = { t, o }; + *i = std::move(e); ++m_end; m_prof_call.inc(); - m_lock.release(); } - entry_t pop() noexcept { return *(--m_end); } - const entry_t &top() const noexcept { return *(m_end-1); } + entry_t pop() noexcept { return std::move(*(--m_end)); } + const entry_t &top() const noexcept { return std::move(*(m_end-1)); } void remove(const Element &elem) noexcept { /* Lock */ - m_lock.acquire(); + tqlock lck(m_lock); for (entry_t * i = m_end - 1; i > &m_list[0]; i--) { if (i->m_object == elem) @@ -103,24 +109,23 @@ namespace netlist m_end--; while (i < m_end) { - *i = *(i+1); + *i = std::move(*(i+1)); ++i; } - m_lock.release(); return; } } - m_lock.release(); } void retime(const Element &elem, const Time t) noexcept { remove(elem); - push(elem, t); + push(entry_t(t, elem)); } void clear() { + tqlock lck(m_lock); m_end = &m_list[0]; /* put an empty element with maximum time into the queue. * the insert algo above will run into this element and doesn't @@ -137,8 +142,14 @@ namespace netlist const entry_t & operator[](const std::size_t index) const { return m_list[ 1 + index]; } private: + #if HAS_OPENMP && USE_OPENMP + using tqmutex = pspin_mutex<true>; + #else + using tqmutex = pspin_mutex<false>; + #endif + using tqlock = std::lock_guard<tqmutex>; - tqlock m_lock; + tqmutex m_lock; entry_t * m_end; std::vector<entry_t> m_list; diff --git a/src/lib/netlist/nl_parser.cpp b/src/lib/netlist/nl_parser.cpp index 6dee211ce56..db7ced8fae0 100644 --- a/src/lib/netlist/nl_parser.cpp +++ b/src/lib/netlist/nl_parser.cpp @@ -7,7 +7,7 @@ #include "nl_parser.h" #include "nl_factory.h" -#include "devices/nld_truthtable.h" +#include "nl_errstr.h" namespace netlist { @@ -28,13 +28,7 @@ bool parser_t::parse(const pstring nlname) { set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-"); set_number_chars(".0123456789", "0123456789eE-."); //FIXME: processing of numbers - char ws[5]; - ws[0] = ' '; - ws[1] = 9; - ws[2] = 10; - ws[3] = 13; - ws[4] = 0; - set_whitespace(ws); + set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13)); set_comment("/*", "*/", "//"); m_tok_param_left = register_token("("); m_tok_param_right = register_token(")"); @@ -64,18 +58,16 @@ bool parser_t::parse(const pstring nlname) while (true) { token_t token = get_token(); - if (token.is_type(ENDOFFILE)) { return false; - //error("EOF while searching for <{1}>", nlname); } if (token.is(m_tok_NETLIST_END)) { require_token(m_tok_param_left); if (!in_nl) - error("Unexpected NETLIST_END"); + error (MF_0_UNEXPECTED_NETLIST_END); else { in_nl = false; @@ -85,7 +77,7 @@ bool parser_t::parse(const pstring nlname) else if (token.is(m_tok_NETLIST_START)) { if (in_nl) - error("Unexpected NETLIST_START"); + error (MF_0_UNEXPECTED_NETLIST_START); require_token(m_tok_param_left); token_t name = get_token(); require_token(m_tok_param_right); @@ -99,7 +91,7 @@ bool parser_t::parse(const pstring nlname) } } -void parser_t::parse_netlist(ATTR_UNUSED const pstring &nlname) +void parser_t::parse_netlist(const pstring &nlname) { while (true) { @@ -132,10 +124,10 @@ void parser_t::parse_netlist(ATTR_UNUSED const pstring &nlname) else if (token.is(m_tok_LOCAL_SOURCE)) net_local_source(); else if (token.is(m_tok_TRUTHTABLE_START)) - net_truthtable_start(); + net_truthtable_start(nlname); else if (token.is(m_tok_LOCAL_LIB_ENTRY)) { - m_setup.register_lib_entry(get_identifier()); + m_setup.register_lib_entry(get_identifier(), "parser: " + nlname); require_token(m_tok_param_right); } else if (token.is(m_tok_NETLIST_END)) @@ -148,7 +140,7 @@ void parser_t::parse_netlist(ATTR_UNUSED const pstring &nlname) } } -void parser_t::net_truthtable_start() +void parser_t::net_truthtable_start(const pstring &nlname) { pstring name = get_identifier(); require_token(m_tok_comma); @@ -194,7 +186,7 @@ void parser_t::net_truthtable_start() require_token(token, m_tok_TRUTHTABLE_END); require_token(m_tok_param_left); require_token(m_tok_param_right); - netlist::devices::tt_factory_create(m_setup, desc); + m_setup.tt_factory_create(desc, nlname); return; } } @@ -300,7 +292,7 @@ void parser_t::net_c() void parser_t::dippins() { - plib::pstring_vector_t pins; + std::vector<pstring> pins; pins.push_back(get_identifier()); require_token(m_tok_comma); @@ -357,7 +349,7 @@ void parser_t::netdev_hint() void parser_t::device(const pstring &dev_type) { factory::element_t *f = m_setup.factory().factory_by_name(dev_type); - auto paramlist = plib::pstring_vector_t(f->param_desc(), ","); + auto paramlist = plib::psplit(f->param_desc(), ","); pstring devname = get_identifier(); @@ -404,7 +396,7 @@ void parser_t::device(const pstring &dev_type) nl_double parser_t::eval_param(const token_t tok) { - static const char *macs[6] = {"", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"}; + static pstring macs[6] = {"", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"}; static nl_double facs[6] = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12}; int i; int f=0; @@ -415,7 +407,6 @@ nl_double parser_t::eval_param(const token_t tok) for (i=1; i<6;i++) if (tok.str().equals(macs[i])) f = i; -#if 1 if (f>0) { require_token(m_tok_param_left); @@ -431,22 +422,6 @@ nl_double parser_t::eval_param(const token_t tok) } return ret * facs[f]; -#else - if (f>0) - { - require_token(m_tok_param_left); - val = get_identifier(); - } - else - val = tok.str(); - - ret = val.as_double(&e); - - if (e) - fatal("Error with parameter ...\n"); - if (f>0) - require_token(m_tok_param_right); - return ret * facs[f]; -#endif } + } diff --git a/src/lib/netlist/nl_parser.h b/src/lib/netlist/nl_parser.h index 5c915e69997..4654bcb3f87 100644 --- a/src/lib/netlist/nl_parser.h +++ b/src/lib/netlist/nl_parser.h @@ -15,10 +15,9 @@ namespace netlist { class parser_t : public plib::ptokenizer { - P_PREVENT_COPYING(parser_t) public: - parser_t(plib::pistream &strm, setup_t &setup) - : plib::ptokenizer(strm), m_setup(setup), m_buf(nullptr) {} + parser_t(plib::putf8_reader &strm, setup_t &setup) + : plib::ptokenizer(strm), m_setup(setup) {} bool parse(const pstring nlname = ""); @@ -37,7 +36,7 @@ namespace netlist void net_submodel(); void net_include(); void net_local_source(); - void net_truthtable_start(); + void net_truthtable_start(const pstring &nlname); /* for debugging messages */ netlist_t &netlist() { return m_setup.netlist(); } @@ -70,9 +69,7 @@ namespace netlist token_id_t m_tok_TT_FAMILY; setup_t &m_setup; - - const char *m_buf; - }; +}; } diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp index 84aa7c8d384..0572ec1e693 100644 --- a/src/lib/netlist/nl_setup.cpp +++ b/src/lib/netlist/nl_setup.cpp @@ -5,22 +5,17 @@ * */ -#include <cstdio> - -#include "solver/nld_solver.h" - #include "plib/palloc.h" #include "plib/putil.h" #include "nl_base.h" #include "nl_setup.h" #include "nl_parser.h" #include "nl_factory.h" -#include "devices/net_lib.h" -#include "devices/nld_truthtable.h" #include "devices/nlid_system.h" #include "devices/nlid_proxy.h" #include "analog/nld_twoterm.h" #include "solver/nld_solver.h" +#include "devices/nlid_truthtable.h" // ---------------------------------------------------------------------------------------- // setup_t @@ -34,7 +29,7 @@ setup_t::setup_t(netlist_t &netlist) , m_proxy_cnt(0) , m_frontier_cnt(0) { - initialize_factory(m_factory); + devices::initialize_factory(m_factory); } setup_t::~setup_t() @@ -73,16 +68,16 @@ void setup_t::namespace_pop() m_namespace_stack.pop(); } -void setup_t::register_lib_entry(const pstring &name) +void setup_t::register_lib_entry(const pstring &name, const pstring &sourcefile) { - factory().register_device(plib::make_unique_base<factory::element_t, factory::library_element_t>(*this, name, name, "")); + factory().register_device(plib::make_unique_base<factory::element_t, factory::library_element_t>(*this, name, name, "", sourcefile)); } void setup_t::register_dev(const pstring &classname, const pstring &name) { auto f = factory().factory_by_name(classname); if (f == nullptr) - log().fatal("Class {1} not found!\n", classname); + log().fatal(MF_1_CLASS_1_NOT_FOUND, classname); /* make sure we parse macro library entries */ f->macro_actions(netlist(), name); m_device_factory.push_back(std::pair<pstring, factory::element_t *>(build_fqn(name), f)); @@ -103,17 +98,17 @@ void setup_t::register_model(const pstring &model_in) { auto pos = model_in.find(" "); if (pos == model_in.end()) - log().fatal("Unable to parse model: {1}", model_in); + log().fatal(MF_1_UNABLE_TO_PARSE_MODEL_1, model_in); pstring model = model_in.left(pos).trim().ucase(); pstring def = model_in.substr(pos + 1).trim(); if (!m_models.insert({model, def}).second) - log().fatal("Model already exists: {1}", model_in); + log().fatal(MF_1_MODEL_ALREADY_EXISTS_1, model_in); } void setup_t::register_alias_nofqn(const pstring &alias, const pstring &out) { if (!m_alias.insert({alias, out}).second) - log().fatal("Error adding alias {1} to alias list\n", alias); + log().fatal(MF_1_ADDING_ALIAS_1_TO_ALIAS_LIST, alias); } void setup_t::register_alias(const pstring &alias, const pstring &out) @@ -125,9 +120,10 @@ void setup_t::register_alias(const pstring &alias, const pstring &out) void setup_t::register_dippins_arr(const pstring &terms) { - plib::pstring_vector_t list(terms,", "); + std::vector<pstring> list(plib::psplit(terms,", ")); if (list.size() == 0 || (list.size() % 2) == 1) - log().fatal("You must pass an equal number of pins to DIPPINS {1}" , build_fqn("")); + log().fatal(MF_1_DIP_PINS_MUST_BE_AN_EQUAL_NUMBER_OF_PINS_1, + build_fqn("")); std::size_t n = list.size(); for (std::size_t i = 0; i < n / 2; i++) { @@ -136,22 +132,19 @@ void setup_t::register_dippins_arr(const pstring &terms) } } -pstring setup_t::objtype_as_str(detail::device_object_t &in) const +pstring setup_t::termtype_as_str(detail::core_terminal_t &in) const { switch (in.type()) { - case terminal_t::TERMINAL: - return "TERMINAL"; - case terminal_t::INPUT: - return "INPUT"; - case terminal_t::OUTPUT: - return "OUTPUT"; - case terminal_t::PARAM: - return "PARAM"; + case detail::terminal_type::TERMINAL: + return pstring("TERMINAL"); + case detail::terminal_type::INPUT: + return pstring("INPUT"); + case detail::terminal_type::OUTPUT: + return pstring("OUTPUT"); } - // FIXME: noreturn - log().fatal("Unknown object type {1}\n", static_cast<unsigned>(in.type())); - return "Error"; + log().fatal(MF_1_UNKNOWN_OBJECT_TYPE_1, static_cast<unsigned>(in.type())); + return pstring("Error"); } pstring setup_t::get_initial_param_val(const pstring name, const pstring def) @@ -170,7 +163,7 @@ double setup_t::get_initial_param_val(const pstring name, const double def) { double vald = 0; if (sscanf(i->second.c_str(), "%lf", &vald) != 1) - log().fatal("Invalid number conversion {1} : {2}\n", name, i->second); + log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); return vald; } else @@ -184,7 +177,7 @@ int setup_t::get_initial_param_val(const pstring name, const int def) { double vald = 0; if (sscanf(i->second.c_str(), "%lf", &vald) != 1) - log().fatal("Invalid number conversion {1} : {2}\n", name, i->second); + log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second); return static_cast<int>(vald); } else @@ -194,21 +187,22 @@ int setup_t::get_initial_param_val(const pstring name, const int def) void setup_t::register_param(pstring name, param_t ¶m) { if (!m_params.insert({param.name(), param_ref_t(param.name(), param.device(), param)}).second) - log().fatal("Error adding parameter {1} to parameter list\n", name); + log().fatal(MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST, name); } void setup_t::register_term(detail::core_terminal_t &term) { if (!m_terminals.insert({term.name(), &term}).second) - log().fatal("Error adding {1} {2} to terminal list\n", objtype_as_str(term), term.name()); - log().debug("{1} {2}\n", objtype_as_str(term), term.name()); + log().fatal(MF_2_ADDING_1_2_TO_TERMINAL_LIST, termtype_as_str(term), + term.name()); + log().debug("{1} {2}\n", termtype_as_str(term), term.name()); } void setup_t::register_link_arr(const pstring &terms) { - plib::pstring_vector_t list(terms,", "); + std::vector<pstring> list(plib::psplit(terms,", ")); if (list.size() < 2) - log().fatal("You must pass at least 2 terminals to NET_C"); + log().fatal(MF_2_NET_C_NEEDS_AT_LEAST_2_TERMINAL); for (std::size_t i = 1; i < list.size(); i++) { register_link(list[0], list[i]); @@ -245,7 +239,7 @@ void setup_t::remove_connections(const pstring pin) link++; } if (!found) - log().fatal("remove_connections: found no occurrence of {1}\n", pin); + log().fatal(MF_1_FOUND_NO_OCCURRENCE_OF_1, pin); } @@ -274,7 +268,7 @@ void setup_t::register_frontier(const pstring attach, const double r_IN, const d } } if (!found) - log().fatal("Frontier setup: found no occurrence of {1}\n", attach); + log().fatal(MF_1_FOUND_NO_OCCURRENCE_OF_1, attach); register_link(attach, frontier_name + ".Q"); } @@ -292,11 +286,13 @@ void setup_t::register_param(const pstring ¶m, const pstring &value) if (idx == m_param_values.end()) { if (!m_param_values.insert({fqn, value}).second) - log().fatal("Unexpected error adding parameter {1} to parameter list\n", param); + log().fatal(MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST, + param); } else { - log().warning("Overwriting {1} old <{2}> new <{3}>\n", fqn, idx->second, value); + log().warning(MW_3_OVERWRITING_PARAM_1_OLD_2_NEW_3, fqn, idx->second, + value); m_param_values[fqn] = value; } } @@ -331,32 +327,32 @@ detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, bool detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second); if (term == nullptr && required) - log().fatal("terminal {1}({2}) not found!\n", terminal_in, tname); + log().fatal(MF_2_TERMINAL_1_2_NOT_FOUND, terminal_in, tname); if (term != nullptr) log().debug("Found input {1}\n", tname); return term; } detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, - detail::device_object_t::type_t atype, bool required) + detail::terminal_type atype, bool required) { const pstring &tname = resolve_alias(terminal_in); auto ret = m_terminals.find(tname); /* look for default */ - if (ret == m_terminals.end() && atype == detail::device_object_t::OUTPUT) + if (ret == m_terminals.end() && atype == detail::terminal_type::OUTPUT) { /* look for ".Q" std output */ ret = m_terminals.find(tname + ".Q"); } if (ret == m_terminals.end() && required) - log().fatal("terminal {1}({2}) not found!\n", terminal_in, tname); + log().fatal(MF_2_TERMINAL_1_2_NOT_FOUND, terminal_in, tname); detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second); if (term != nullptr && term->type() != atype) { if (required) - log().fatal("object {1}({2}) found but wrong type\n", terminal_in, tname); + log().fatal(MF_2_OBJECT_1_2_WRONG_TYPE, terminal_in, tname); else term = nullptr; } @@ -373,18 +369,17 @@ param_t *setup_t::find_param(const pstring ¶m_in, bool required) const const pstring &outname = resolve_alias(param_in_fqn); auto ret = m_params.find(outname); if (ret == m_params.end() && required) - log().fatal("parameter {1}({2}) not found!\n", param_in_fqn, outname); + log().fatal(MF_2_PARAMETER_1_2_NOT_FOUND, param_in_fqn, outname); if (ret != m_params.end()) log().debug("Found parameter {1}\n", outname); return (ret == m_params.end() ? nullptr : &ret->second.m_param); } -// FIXME avoid dynamic cast here devices::nld_base_proxy *setup_t::get_d_a_proxy(detail::core_terminal_t &out) { nl_assert(out.is_logic()); - logic_output_t &out_cast = dynamic_cast<logic_output_t &>(out); + logic_output_t &out_cast = static_cast<logic_output_t &>(out); devices::nld_base_proxy *proxy = out_cast.get_proxy(); if (proxy == nullptr) @@ -403,7 +398,8 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(detail::core_terminal_t &out) { p->clear_net(); // de-link from all nets ... if (!connect(new_proxy->proxy_term(), *p)) - log().fatal("Error connecting {1} to {2}\n", new_proxy->proxy_term().name(), (*p).name()); + log().fatal(MF_2_CONNECTING_1_TO_2, + new_proxy->proxy_term().name(), (*p).name()); } out.net().m_core_terms.clear(); // clear the list @@ -437,7 +433,6 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp) auto ret = new_proxy.get(); -#if 1 /* connect all existing terminals to new net */ if (inp.has_net()) @@ -446,18 +441,12 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp) { p->clear_net(); // de-link from all nets ... if (!connect(ret->proxy_term(), *p)) - log().fatal("Error connecting {1} to {2}\n", ret->proxy_term().name(), (*p).name()); + log().fatal(MF_2_CONNECTING_1_TO_2, + ret->proxy_term().name(), (*p).name()); } inp.net().m_core_terms.clear(); // clear the list } ret->out().net().add_terminal(inp); -#else - if (inp.has_net()) - //fatalerror("logic inputs can only belong to one net!\n"); - merge_nets(ret->out().net(), inp.net()); - else - ret->out().net().add_terminal(inp); -#endif netlist().register_dev(std::move(new_proxy)); return ret; } @@ -465,19 +454,20 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp) void setup_t::merge_nets(detail::net_t &thisnet, detail::net_t &othernet) { - netlist().log().debug("merging nets ...\n"); + log().debug("merging nets ...\n"); if (&othernet == &thisnet) { - netlist().log().warning("Connecting {1} to itself. This may be right, though\n", thisnet.name()); + log().warning(MW_1_CONNECTING_1_TO_ITSELF, thisnet.name()); return; // Nothing to do } if (thisnet.isRailNet() && othernet.isRailNet()) - netlist().log().fatal("Trying to merge two rail nets: {1} and {2}\n", thisnet.name(), othernet.name()); + log().fatal(MF_2_MERGE_RAIL_NETS_1_AND_2, + thisnet.name(), othernet.name()); if (othernet.isRailNet()) { - netlist().log().debug("othernet is railnet\n"); + log().debug("othernet is railnet\n"); merge_nets(othernet, thisnet); } else @@ -521,7 +511,8 @@ void setup_t::connect_terminal_input(terminal_t &term, detail::core_terminal_t & } else if (inp.is_logic()) { - netlist().log().verbose("connect terminal {1} (in, {2}) to {3}\n", inp.name(), pstring(inp.is_analog() ? "analog" : inp.is_logic() ? "logic" : "?"), term.name()); + log().verbose("connect terminal {1} (in, {2}) to {3}\n", inp.name(), + inp.is_analog() ? pstring("analog") : inp.is_logic() ? pstring("logic") : pstring("?"), term.name()); auto proxy = get_a_d_proxy(inp); //out.net().register_con(proxy->proxy_term()); @@ -530,7 +521,7 @@ void setup_t::connect_terminal_input(terminal_t &term, detail::core_terminal_t & } else { - log().fatal("Netlist: Severe Error"); + log().fatal(MF_1_OBJECT_INPUT_TYPE_1, inp.name()); } } @@ -554,7 +545,7 @@ void setup_t::connect_terminal_output(terminal_t &in, detail::core_terminal_t &o } else { - log().fatal("Netlist: Severe Error"); + log().fatal(MF_1_OBJECT_OUTPUT_TYPE_1, out.name()); } } @@ -609,7 +600,7 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term { for (auto & t : t1.net().m_core_terms) { - if (t->is_type(detail::core_terminal_t::TERMINAL)) + if (t->is_type(detail::terminal_type::TERMINAL)) ret = connect(t2, *t); if (ret) break; @@ -624,7 +615,7 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term { for (auto & t : t2.net().m_core_terms) { - if (t->is_type(detail::core_terminal_t::TERMINAL)) + if (t->is_type(detail::terminal_type::TERMINAL)) ret = connect(t1, *t); if (ret) break; @@ -643,39 +634,39 @@ bool setup_t::connect(detail::core_terminal_t &t1_in, detail::core_terminal_t &t detail::core_terminal_t &t2 = resolve_proxy(t2_in); bool ret = true; - if (t1.is_type(detail::core_terminal_t::OUTPUT) && t2.is_type(detail::core_terminal_t::INPUT)) + if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::INPUT)) { if (t2.has_net() && t2.net().isRailNet()) - log().fatal("Input {1} already connected\n", t2.name()); + log().fatal(MF_1_INPUT_1_ALREADY_CONNECTED, t2.name()); connect_input_output(t2, t1); } - else if (t1.is_type(detail::core_terminal_t::INPUT) && t2.is_type(detail::core_terminal_t::OUTPUT)) + else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::OUTPUT)) { if (t1.has_net() && t1.net().isRailNet()) - log().fatal("Input {1} already connected\n", t1.name()); + log().fatal(MF_1_INPUT_1_ALREADY_CONNECTED, t1.name()); connect_input_output(t1, t2); } - else if (t1.is_type(detail::core_terminal_t::OUTPUT) && t2.is_type(detail::core_terminal_t::TERMINAL)) + else if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::TERMINAL)) { connect_terminal_output(dynamic_cast<terminal_t &>(t2), t1); } - else if (t1.is_type(detail::core_terminal_t::TERMINAL) && t2.is_type(detail::core_terminal_t::OUTPUT)) + else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::OUTPUT)) { connect_terminal_output(dynamic_cast<terminal_t &>(t1), t2); } - else if (t1.is_type(detail::core_terminal_t::INPUT) && t2.is_type(detail::core_terminal_t::TERMINAL)) + else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::TERMINAL)) { connect_terminal_input(dynamic_cast<terminal_t &>(t2), t1); } - else if (t1.is_type(detail::core_terminal_t::TERMINAL) && t2.is_type(detail::core_terminal_t::INPUT)) + else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::INPUT)) { connect_terminal_input(dynamic_cast<terminal_t &>(t1), t2); } - else if (t1.is_type(detail::core_terminal_t::TERMINAL) && t2.is_type(detail::core_terminal_t::TERMINAL)) + else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::TERMINAL)) { connect_terminals(dynamic_cast<terminal_t &>(t1), dynamic_cast<terminal_t &>(t2)); } - else if (t1.is_type(detail::core_terminal_t::INPUT) && t2.is_type(detail::core_terminal_t::INPUT)) + else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::INPUT)) { ret = connect_input_input(t1, t2); } @@ -693,8 +684,8 @@ void setup_t::resolve_inputs() * We therefore first park connecting inputs and retry * after all other terminals were connected. */ - int tries = 100; - while (m_links.size() > 0 && tries > 0) // FIXME: convert into constant + int tries = NL_MAX_LINK_RESOLVE_LOOPS; + while (m_links.size() > 0 && tries > 0) { for (auto li = m_links.begin(); li != m_links.end(); ) @@ -714,9 +705,9 @@ void setup_t::resolve_inputs() if (tries == 0) { for (auto & link : m_links) - log().warning("Error connecting {1} to {2}\n", link.first, link.second); + log().warning(MF_2_CONNECTING_1_TO_2, link.first, link.second); - log().fatal("Error connecting -- bailing out\n"); + log().fatal(MF_0_LINK_TRIES_EXCEEDED); } log().verbose("deleting empty nets ..."); @@ -743,38 +734,26 @@ void setup_t::resolve_inputs() { detail::core_terminal_t *term = i.second; if (!term->has_net() && dynamic_cast< devices::NETLIB_NAME(dummy_input) *>(&term->device()) != nullptr) - log().warning("Found dummy terminal {1} without connections", term->name()); + log().warning(MW_1_DUMMY_1_WITHOUT_CONNECTIONS, term->name()); else if (!term->has_net()) errstr += plib::pfmt("Found terminal {1} without a net\n")(term->name()); else if (term->net().num_cons() == 0) - log().warning("Found terminal {1} without connections", term->name()); + log().warning(MW_1_TERMINAL_1_WITHOUT_CONNECTIONS, term->name()); } + //FIXME: error string handling if (errstr != "") log().fatal("{1}", errstr); - - log().verbose("looking for two terms connected to rail nets ..."); - for (auto & t : netlist().get_device_list<analog::NETLIB_NAME(twoterm)>()) - { - if (t->m_N.net().isRailNet() && t->m_P.net().isRailNet()) - { - log().warning("Found device {1} connected only to railterminals {2}/{3}. Will be removed", - t->name(), t->m_N.net().name(), t->m_P.net().name()); - t->m_N.net().remove_terminal(t->m_N); - t->m_P.net().remove_terminal(t->m_P); - netlist().remove_dev(t); - } - } } void setup_t::start_devices() { - pstring env = plib::util::environment("NL_LOGS"); + pstring env = plib::util::environment("NL_LOGS", ""); if (env != "") { log().debug("Creating dynamic logs ..."); - plib::pstring_vector_t loglist(env, ":"); + std::vector<pstring> loglist(plib::psplit(env, ":")); for (pstring ll : loglist) { pstring name = "log_" + ll; @@ -800,7 +779,7 @@ const plib::plog_base<NL_DEBUG> &setup_t::log() const // Model // ---------------------------------------------------------------------------------------- -static pstring model_string(model_map_t &map) +static pstring model_string(detail::model_map_t &map) { pstring ret = map["COREMODEL"] + "("; for (auto & i : map) @@ -809,7 +788,7 @@ static pstring model_string(model_map_t &map) return ret + ")"; } -void setup_t::model_parse(const pstring &model_in, model_map_t &map) +void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map) { pstring model = model_in; pstring::iterator pos(nullptr); @@ -823,7 +802,7 @@ void setup_t::model_parse(const pstring &model_in, model_map_t &map) key = model.ucase(); auto i = m_models.find(key); if (i == m_models.end()) - log().fatal("Model {1} not found\n", model); + log().fatal(MF_1_MODEL_NOT_FOUND, model); model = i->second; } pstring xmodel = model.left(pos); @@ -836,40 +815,41 @@ void setup_t::model_parse(const pstring &model_in, model_map_t &map) if (i != m_models.end()) model_parse(xmodel, map); else - log().fatal("Model doesn't exist: <{1}>\n", model_in); + log().fatal(MF_1_MODEL_NOT_FOUND, model_in); } pstring remainder=model.substr(pos+1).trim(); if (!remainder.endsWith(")")) - log().fatal("Model error {1}\n", model); + log().fatal(MF_1_MODEL_ERROR_1, model); // FIMXE: Not optimal remainder = remainder.left(remainder.begin() + (remainder.len() - 1)); - plib::pstring_vector_t pairs(remainder," ", true); + std::vector<pstring> pairs(plib::psplit(remainder," ", true)); for (pstring &pe : pairs) { auto pose = pe.find("="); if (pose == pe.end()) - log().fatal("Model error on pair {1}\n", model); + log().fatal(MF_1_MODEL_ERROR_ON_PAIR_1, model); map[pe.left(pose).ucase()] = pe.substr(pose+1); } } -const pstring setup_t::model_value_str(model_map_t &map, const pstring &entity) +const pstring setup_t::model_value_str(detail::model_map_t &map, const pstring &entity) { pstring ret; if (entity != entity.ucase()) - log().fatal("model parameters should be uppercase:{1} {2}\n", entity, model_string(map)); + log().fatal(MF_2_MODEL_PARAMETERS_NOT_UPPERCASE_1_2, entity, + model_string(map)); if (map.find(entity) == map.end()) - log().fatal("Entity {1} not found in model {2}\n", entity, model_string(map)); + log().fatal(MF_2_ENTITY_1_NOT_FOUND_IN_MODEL_2, entity, model_string(map)); else ret = map[entity]; return ret; } -nl_double setup_t::model_value(model_map_t &map, const pstring &entity) +nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity) { pstring tmp = model_value_str(map, entity); @@ -887,16 +867,67 @@ nl_double setup_t::model_value(model_map_t &map, const pstring &entity) case 'a': factor = 1e-18; break; default: if (*p < '0' || *p > '9') - nl_exception(plib::pfmt("Unknown number factor in: {1}")(entity)); + log().fatal(MF_1_UNKNOWN_NUMBER_FACTOR_IN_1, entity); } if (factor != NL_FCONST(1.0)) tmp = tmp.left(tmp.begin() + (tmp.len() - 1)); return tmp.as_double() * factor; } -void setup_t::tt_factory_create(tt_desc &desc) +class logic_family_std_proxy_t : public logic_family_desc_t +{ +public: + logic_family_std_proxy_t() { } + virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, + const pstring &name, logic_output_t *proxied) const override; + virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override; +}; + +plib::owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_std_proxy_t::create_d_a_proxy(netlist_t &anetlist, + const pstring &name, logic_output_t *proxied) const +{ + return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied); +} +plib::owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_std_proxy_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const +{ + return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied); +} + + +const logic_family_desc_t *setup_t::family_from_model(const pstring &model) { - devices::tt_factory_create(*this, desc); + detail::model_map_t map; + model_parse(model, map); + + if (model_value_str(map, "TYPE") == "TTL") + return family_TTL(); + if (model_value_str(map, "TYPE") == "CD4XXX") + return family_CD4XXX(); + + for (auto & e : netlist().m_family_cache) + if (e.first == model) + return e.second.get(); + + auto ret = plib::make_unique_base<logic_family_desc_t, logic_family_std_proxy_t>(); + + ret->m_fixed_V = model_value(map, "FV"); + ret->m_low_thresh_PCNT = model_value(map, "IVL"); + ret->m_high_thresh_PCNT = model_value(map, "IVH"); + ret->m_low_VO = model_value(map, "OVL"); + ret->m_high_VO = model_value(map, "OVH"); + ret->m_R_low = model_value(map, "ORL"); + ret->m_R_high = model_value(map, "ORH"); + + auto retp = ret.get(); + + netlist().m_family_cache.emplace_back(model, std::move(ret)); + + return retp; +} + +void setup_t::tt_factory_create(tt_desc &desc, const pstring &sourcefile) +{ + devices::tt_factory_create(*this, desc, sourcefile); } @@ -911,7 +942,7 @@ void setup_t::include(const pstring &netlist_name) if (source->parse(netlist_name)) return; } - log().fatal("unable to find {1} in source collection", netlist_name); + log().fatal(MF_1_NOT_FOUND_IN_SOURCE_COLLECTION, netlist_name); } std::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring name) @@ -925,18 +956,21 @@ std::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring name) return strm; } } - //log().fatal("unable to find data named {1} in source collection", name); - log().warning("unable to find data named {1} in source collection", name); + log().warning(MW_1_DATA_1_NOT_FOUND, name); return std::unique_ptr<plib::pistream>(nullptr); } -bool setup_t::parse_stream(plib::pistream &istrm, const pstring &name) +bool setup_t::parse_stream(plib::putf8_reader &istrm, const pstring &name) { plib::pomemstream ostrm; + plib::putf8_writer owrt(ostrm); - plib::pimemstream istrm2(plib::ppreprocessor(&m_defines).process(istrm, ostrm)); - return parser_t(istrm2, *this).parse(name); + plib::ppreprocessor(&m_defines).process(istrm, owrt); + + plib::pimemstream istrm2(ostrm); + plib::putf8_reader reader2(istrm2); + return parser_t(reader2, *this).parse(name); } void setup_t::register_define(pstring defstr) @@ -957,7 +991,11 @@ bool source_t::parse(const pstring &name) if (m_type != SOURCE) return false; else - return m_setup.parse_stream(*stream(name), name); + { + auto rstream = stream(name); + plib::putf8_reader reader(*rstream); + return m_setup.parse_stream(reader, name); + } } std::unique_ptr<plib::pistream> source_string_t::stream(const pstring &name) diff --git a/src/lib/netlist/nl_setup.h b/src/lib/netlist/nl_setup.h index 798ba8f4140..e9fc0861328 100644 --- a/src/lib/netlist/nl_setup.h +++ b/src/lib/netlist/nl_setup.h @@ -8,19 +8,18 @@ #ifndef NLSETUP_H_ #define NLSETUP_H_ -#include <memory> -#include <stack> -#include <unordered_map> -#include <vector> - #include "plib/pstring.h" -#include "plib/pfmtlog.h" -#include "plib/pstream.h" #include "plib/putil.h" +#include "plib/pstream.h" #include "plib/pparser.h" -#include "nl_config.h" -#include "nl_base.h" + #include "nl_factory.h" +#include "nl_config.h" +#include "netlist_types.h" + +#include <stack> +#include <vector> +#include <memory> //============================================================ // MACROS / inline netlist definitions @@ -71,7 +70,7 @@ void NETLIST_NAME(name)(netlist::setup_t &setup) \ #define LOCAL_LIB_ENTRY(name) \ LOCAL_SOURCE(name) \ - setup.register_lib_entry(# name); + setup.register_lib_entry(# name, __FILE__); #define INCLUDE(name) \ setup.include(# name); @@ -81,6 +80,9 @@ void NETLIST_NAME(name)(netlist::setup_t &setup) \ NETLIST_NAME(model)(setup); \ setup.namespace_pop(); +#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \ + setup.register_frontier(# attach, r_in, r_out); + // ----------------------------------------------------------------------------- // truthtable defines // ----------------------------------------------------------------------------- @@ -105,12 +107,29 @@ void NETLIST_NAME(name)(netlist::setup_t &setup) \ desc.family = x; #define TRUTHTABLE_END() \ - netlist::devices::tt_factory_create(setup, desc); \ + setup.tt_factory_create(desc, __FILE__); \ } namespace netlist { + + namespace detail { + class core_terminal_t; + class net_t; + } + + namespace devices { + class nld_base_proxy; + } + + class core_device_t; + class param_t; + class setup_t; + class netlist_t; + class logic_family_desc_t; + class terminal_t; + // ----------------------------------------------------------------------------- // truthtable desc // ----------------------------------------------------------------------------- @@ -122,7 +141,7 @@ namespace netlist unsigned long ni; unsigned long no; pstring def_param; - plib::pstring_vector_t desc; + std::vector<pstring> desc; pstring family; }; @@ -178,9 +197,8 @@ namespace netlist // ---------------------------------------------------------------------------------------- - class setup_t + class setup_t : plib::nocopyassignmove { - P_PREVENT_COPYING(setup_t) public: using link_t = std::pair<pstring, pstring>; @@ -202,7 +220,7 @@ namespace netlist void register_dev(const pstring &classname, const pstring &name); - void register_lib_entry(const pstring &name); + void register_lib_entry(const pstring &name, const pstring &sourcefile); void register_model(const pstring &model_in); void register_alias(const pstring &alias, const pstring &out); @@ -241,7 +259,7 @@ namespace netlist std::unique_ptr<plib::pistream> get_data_stream(const pstring name); - bool parse_stream(plib::pistream &istrm, const pstring &name); + bool parse_stream(plib::putf8_reader &istrm, const pstring &name); /* register a source */ @@ -258,14 +276,14 @@ namespace netlist /* model / family related */ - const pstring model_value_str(model_map_t &map, const pstring &entity); - nl_double model_value(model_map_t &map, const pstring &entity); + const pstring model_value_str(detail::model_map_t &map, const pstring &entity); + double model_value(detail::model_map_t &map, const pstring &entity); - void model_parse(const pstring &model, model_map_t &map); + void model_parse(const pstring &model, detail::model_map_t &map); - /* FIXME: truth table trampoline */ + const logic_family_desc_t *family_from_model(const pstring &model); - void tt_factory_create(tt_desc &desc); + void tt_factory_create(tt_desc &desc, const pstring &sourcefile); /* helper - also used by nltool */ const pstring resolve_alias(const pstring &name) const; @@ -280,7 +298,7 @@ namespace netlist std::unordered_map<pstring, detail::core_terminal_t *> m_terminals; /* needed by proxy */ - detail::core_terminal_t *find_terminal(const pstring &outname_in, detail::device_object_t::type_t atype, bool required = true); + detail::core_terminal_t *find_terminal(const pstring &outname_in, const detail::terminal_type atype, bool required = true); private: @@ -295,7 +313,7 @@ namespace netlist bool connect_input_input(detail::core_terminal_t &t1, detail::core_terminal_t &t2); // helpers - pstring objtype_as_str(detail::device_object_t &in) const; + pstring termtype_as_str(detail::core_terminal_t &in) const; devices::nld_base_proxy *get_d_a_proxy(detail::core_terminal_t &out); devices::nld_base_proxy *get_a_d_proxy(detail::core_terminal_t &inp); @@ -312,7 +330,7 @@ namespace netlist unsigned m_proxy_cnt; unsigned m_frontier_cnt; - }; +}; // ---------------------------------------------------------------------------------------- // base sources @@ -353,7 +371,7 @@ namespace netlist { public: source_mem_t(setup_t &setup, const char *mem) - : source_t(setup), m_str(mem) + : source_t(setup), m_str(mem, pstring::UTF8) { } diff --git a/src/lib/netlist/nl_time.h b/src/lib/netlist/nl_time.h index 4edc9524a43..7706555f995 100644 --- a/src/lib/netlist/nl_time.h +++ b/src/lib/netlist/nl_time.h @@ -10,6 +10,7 @@ #include <cstdint> #include "nl_config.h" +#include "plib/ptypes.h" #include "plib/pstate.h" //============================================================ @@ -45,82 +46,83 @@ namespace netlist constexpr explicit ptime(const internal_type nom, const internal_type den) noexcept : m_time(nom * (resolution / den)) { } - ptime &operator=(const ptime rhs) { m_time = rhs.m_time; return *this; } + ptime &operator=(const ptime rhs) noexcept { m_time = rhs.m_time; return *this; } - ptime &operator+=(const ptime &rhs) { m_time += rhs.m_time; return *this; } - ptime &operator-=(const ptime &rhs) { m_time -= rhs.m_time; return *this; } + ptime &operator+=(const ptime &rhs) noexcept { m_time += rhs.m_time; return *this; } + ptime &operator-=(const ptime &rhs) noexcept { m_time -= rhs.m_time; return *this; } - friend ptime operator-(ptime lhs, const ptime &rhs) + friend constexpr ptime operator-(const ptime &lhs, const ptime &rhs) noexcept { - lhs -= rhs; - return lhs; + return ptime(lhs.m_time - rhs.m_time); } - friend ptime operator+(ptime lhs, const ptime &rhs) + friend constexpr ptime operator+(const ptime &lhs, const ptime &rhs) noexcept { - lhs += rhs; - return lhs; + return ptime(lhs.m_time + rhs.m_time); } - friend ptime operator*(ptime lhs, const mult_type factor) + friend constexpr ptime operator*(const ptime &lhs, const mult_type factor) noexcept { - lhs.m_time *= static_cast<internal_type>(factor); - return lhs; + return ptime(lhs.m_time * static_cast<internal_type>(factor)); } - friend mult_type operator/(const ptime &lhs, const ptime &rhs) + friend constexpr mult_type operator/(const ptime &lhs, const ptime &rhs) noexcept { return static_cast<mult_type>(lhs.m_time / rhs.m_time); } - friend bool operator<(const ptime &lhs, const ptime &rhs) + friend constexpr bool operator<(const ptime &lhs, const ptime &rhs) noexcept { return (lhs.m_time < rhs.m_time); } - friend bool operator>(const ptime &lhs, const ptime &rhs) + friend constexpr bool operator>(const ptime &lhs, const ptime &rhs) noexcept { return (rhs < lhs); } - friend bool operator<=(const ptime &lhs, const ptime &rhs) + friend constexpr bool operator<=(const ptime &lhs, const ptime &rhs) noexcept { return !(lhs > rhs); } - friend bool operator>=(const ptime &lhs, const ptime &rhs) + friend constexpr bool operator>=(const ptime &lhs, const ptime &rhs) noexcept { return !(lhs < rhs); } - friend bool operator==(const ptime &lhs, const ptime &rhs) + friend constexpr bool operator==(const ptime &lhs, const ptime &rhs) noexcept { return lhs.m_time == rhs.m_time; } - friend bool operator!=(const ptime &lhs, const ptime &rhs) + friend constexpr bool operator!=(const ptime &lhs, const ptime &rhs) noexcept { return !(lhs == rhs); } - constexpr internal_type as_raw() const { return m_time; } - constexpr double as_double() const { return static_cast<double>(m_time) - / static_cast<double>(resolution); } + constexpr internal_type as_raw() const noexcept { return m_time; } + constexpr double as_double() const noexcept + { + return static_cast<double>(m_time) + / static_cast<double>(resolution); + } // for save states .... - internal_type *get_internaltype_ptr() { return &m_time; } - - static constexpr ptime from_nsec(const internal_type ns) { return ptime(ns, UINT64_C(1000000000)); } - static constexpr ptime from_usec(const internal_type us) { return ptime(us, UINT64_C(1000000)); } - static constexpr ptime from_msec(const internal_type ms) { return ptime(ms, UINT64_C(1000)); } - static constexpr ptime from_hz(const internal_type hz) { return ptime(1 , hz); } - static constexpr ptime from_raw(const internal_type raw) { return ptime(raw, resolution); } - static constexpr ptime from_double(const double t) { return ptime(static_cast<internal_type>( t * static_cast<double>(resolution)), resolution); } - - static constexpr ptime zero() { return ptime(0, resolution); } - static constexpr ptime quantum() { return ptime(1, resolution); } - static constexpr ptime never() { return ptime(plib::numeric_limits<internal_type>::max(), resolution); } + internal_type *get_internaltype_ptr() noexcept { return &m_time; } + + static constexpr ptime from_nsec(const internal_type ns) noexcept { return ptime(ns, UINT64_C(1000000000)); } + static constexpr ptime from_usec(const internal_type us) noexcept { return ptime(us, UINT64_C(1000000)); } + static constexpr ptime from_msec(const internal_type ms) noexcept { return ptime(ms, UINT64_C(1000)); } + static constexpr ptime from_hz(const internal_type hz) noexcept { return ptime(1 , hz); } + static constexpr ptime from_raw(const internal_type raw) noexcept { return ptime(raw); } + static constexpr ptime from_double(const double t) noexcept { return ptime(static_cast<internal_type>( t * static_cast<double>(resolution)), resolution); } + + static constexpr ptime zero() noexcept { return ptime(0, resolution); } + static constexpr ptime quantum() noexcept { return ptime(1, resolution); } + static constexpr ptime never() noexcept { return ptime(plib::numeric_limits<internal_type>::max(), resolution); } private: + constexpr explicit ptime(const internal_type time) : m_time(time) {} internal_type m_time; }; diff --git a/src/lib/netlist/plib/palloc.cpp b/src/lib/netlist/plib/palloc.cpp index 2f1131601da..ceee5a75904 100644 --- a/src/lib/netlist/plib/palloc.cpp +++ b/src/lib/netlist/plib/palloc.cpp @@ -5,8 +5,6 @@ * */ -#include <cstdio> - #include "pconfig.h" #include "palloc.h" #include "pfmtlog.h" diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index 2d223180b3d..2e4c2809048 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -10,9 +10,6 @@ #include <vector> #include <memory> -#include <utility> - -#include "pconfig.h" #include "pstring.h" namespace plib { @@ -31,7 +28,7 @@ template<typename T> void pfree(T *ptr) { delete ptr; } template<typename T> -inline T* palloc_array(std::size_t num) +inline T* palloc_array(const std::size_t num) { return new T[num](); } diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h index e37cd995ab5..5d64f9c4add 100644 --- a/src/lib/netlist/plib/pchrono.h +++ b/src/lib/netlist/plib/pchrono.h @@ -9,7 +9,6 @@ #define PCHRONO_H_ #include <cstdint> -#include <thread> #include <chrono> #include "pconfig.h" diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h index f2164bbde7f..e3870206cbd 100644 --- a/src/lib/netlist/plib/pconfig.h +++ b/src/lib/netlist/plib/pconfig.h @@ -8,10 +8,6 @@ #ifndef PCONFIG_H_ #define PCONFIG_H_ -#include <cstdint> -#include <thread> -#include <chrono> - /* * Define this for more accurate measurements if you processor supports * RDTSCP. @@ -41,6 +37,9 @@ typedef __int128_t INT128; #endif #if defined(__GNUC__) +#ifdef RESTRICT +#undef RESTRICT +#endif #define RESTRICT __restrict__ #define ATTR_UNUSED __attribute__((__unused__)) #else @@ -52,16 +51,17 @@ typedef __int128_t INT128; // Standard defines //============================================================ -// prevent implicit copying -#define P_PREVENT_COPYING(name) \ - private: \ - name(const name &); \ - name &operator=(const name &); - //============================================================ -// cut down delegate implementation +// Pointer to Member Function //============================================================ +// This will be autodetected +// #define PPMF_TYPE 0 + +#define PPMF_TYPE_PMF 0 +#define PPMF_TYPE_GNUC_PMF_CONV 1 +#define PPMF_TYPE_INTERNAL 2 + #if defined(__GNUC__) /* does not work in versions over 4.7.x of 32bit MINGW */ #if defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))) @@ -86,66 +86,12 @@ typedef __int128_t INT128; #define MEMBER_ABI #endif -namespace plib { -/* - * The following class was derived from the MAME delegate.h code. - * It derives a pointer to a member function. - */ - -#if (PHAS_PMF_INTERNAL) - class mfp - { - public: - // construct from any member function pointer - class generic_class; - using generic_function = void (*)(); - - template<typename MemberFunctionType> - mfp(MemberFunctionType mftp) - : m_function(0), m_this_delta(0) - { - *reinterpret_cast<MemberFunctionType *>(this) = mftp; - } - - // binding helper - template<typename FunctionType, typename ObjectType> - FunctionType update_after_bind(ObjectType *object) - { - return reinterpret_cast<FunctionType>( - convert_to_generic(reinterpret_cast<generic_class *>(object))); - } - template<typename FunctionType, typename MemberFunctionType, typename ObjectType> - static FunctionType get_mfp(MemberFunctionType mftp, ObjectType *object) - { - mfp mfpo(mftp); - return mfpo.update_after_bind<FunctionType>(object); - } - - private: - // extract the generic function and adjust the object pointer - generic_function convert_to_generic(generic_class * object) const - { - // apply the "this" delta to the object first - generic_class * o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); - - // if the low bit of the vtable index is clear, then it is just a raw function pointer - if (!(m_function & 1)) - return reinterpret_cast<generic_function>(m_function); - - // otherwise, it is the byte index into the vtable where the actual function lives - std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(o_p_delta); - return *reinterpret_cast<generic_function *>(vtable_base + m_function - 1); - } - - // actual state - uintptr_t m_function; // first item can be one of two things: - // if even, it's a pointer to the function - // if odd, it's the byte offset into the vtable - int m_this_delta; // delta to apply to the 'this' pointer - }; - +#ifndef PPMF_TYPE + #if PHAS_PMF_INTERNAL + #define PPMF_TYPE PPMF_TYPE_INTERNAL + #else + #define PPMF_TYPE PPMF_TYPE_PMF + #endif #endif -} - #endif /* PCONFIG_H_ */ diff --git a/src/lib/netlist/plib/pdynlib.h b/src/lib/netlist/plib/pdynlib.h index e91b86e3a82..3a0c12a5f2d 100644 --- a/src/lib/netlist/plib/pdynlib.h +++ b/src/lib/netlist/plib/pdynlib.h @@ -7,10 +7,6 @@ #ifndef PDYNLIB_H_ #define PDYNLIB_H_ -#include <cstdarg> -#include <cstddef> - -#include "pconfig.h" #include "pstring.h" namespace plib { diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp index 2eedd6f9d16..282acfe30d5 100644 --- a/src/lib/netlist/plib/pexception.cpp +++ b/src/lib/netlist/plib/pexception.cpp @@ -11,9 +11,9 @@ #include "pfmtlog.h" #if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__) -#define HAS_FEENABLE_EXCEPT (1) +#define HAS_FEENABLE_EXCEPT (1) #else -#define HAS_FEENABLE_EXCEPT (0) +#define HAS_FEENABLE_EXCEPT (0) #endif namespace plib { diff --git a/src/lib/netlist/plib/pexception.h b/src/lib/netlist/plib/pexception.h index a4d3b3c498f..9ef3077a75d 100644 --- a/src/lib/netlist/plib/pexception.h +++ b/src/lib/netlist/plib/pexception.h @@ -10,7 +10,6 @@ #include <exception> -#include "pconfig.h" #include "pstring.h" namespace plib { diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp index 48b0f1544c1..9451e11866d 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -6,11 +6,8 @@ */ #include <cstring> -//FIXME:: pstring should be locale free -#include <cctype> #include <cstdlib> -#include <cstdio> - +#include <cstdarg> #include <algorithm> #include "pfmtlog.h" @@ -22,7 +19,7 @@ plog_dispatch_intf::~plog_dispatch_intf() { } -pfmt::pfmt(const pstring &fmt) +pfmt::pfmt(const pstring fmt) : m_str(m_str_buf), m_allocated(0), m_arg(0) { std::size_t l = fmt.blen() + 1; @@ -34,18 +31,6 @@ pfmt::pfmt(const pstring &fmt) memcpy(m_str, fmt.c_str(), l); } -pfmt::pfmt(const char *fmt) -: m_str(m_str_buf), m_allocated(0), m_arg(0) -{ - std::size_t l = strlen(fmt) + 1; - if (l>sizeof(m_str_buf)) - { - m_allocated = 2 * l; - m_str = palloc_array<char>(2 * l); - } - memcpy(m_str, fmt, l); -} - pfmt::~pfmt() { if (m_allocated > 0) diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index c5369109b81..681607bddc0 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -9,12 +9,19 @@ #include <limits> -#include "pconfig.h" #include "pstring.h" #include "ptypes.h" namespace plib { +P_ENUM(plog_level, + DEBUG, + INFO, + VERBOSE, + WARNING, + ERROR, + FATAL) + template <typename T> struct ptype_traits_base { @@ -157,13 +164,12 @@ protected: class pfmt : public pformat_base<pfmt> { public: - explicit pfmt(const pstring &fmt); - explicit pfmt(const char *fmt); + explicit pfmt(const pstring fmt); virtual ~pfmt(); - operator pstring() const { return m_str; } + operator pstring() const { return pstring(m_str, pstring::UTF8); } - const char *cstr() { return m_str; } + const char *c_str() { return m_str; } protected: @@ -177,54 +183,53 @@ private: unsigned m_arg; }; -P_ENUM(plog_level, - DEBUG, - INFO, - VERBOSE, - WARNING, - ERROR, - FATAL) - class plog_dispatch_intf; template <bool build_enabled = true> -class pfmt_writer_t +class pfmt_writer_t : plib::nocopyassignmove { public: - pfmt_writer_t() : m_enabled(true) { } + explicit pfmt_writer_t() : m_enabled(true) { } virtual ~pfmt_writer_t() { } - void operator ()(const char *fmt) const + /* runtime enable */ + template<bool enabled, typename... Args> + void log(const pstring fmt, Args&&... args) const + { + if (build_enabled && enabled && m_enabled) (*this)(fmt, std::forward<Args>(args)...); + } + + void operator ()(const pstring fmt) const { if (build_enabled && m_enabled) vdowrite(fmt); } template<typename T1> - void operator ()(const char *fmt, const T1 &v1) const + void operator ()(const pstring fmt, const T1 &v1) const { if (build_enabled && m_enabled) vdowrite(pfmt(fmt)(v1)); } template<typename T1, typename T2> - void operator ()(const char *fmt, const T1 &v1, const T2 &v2) const + void operator ()(const pstring fmt, const T1 &v1, const T2 &v2) const { if (build_enabled && m_enabled) vdowrite(pfmt(fmt)(v1)(v2)); } template<typename T1, typename T2, typename T3> - void operator ()(const char *fmt, const T1 &v1, const T2 &v2, const T3 &v3) const + void operator ()(const pstring fmt, const T1 &v1, const T2 &v2, const T3 &v3) const { if (build_enabled && m_enabled) vdowrite(pfmt(fmt)(v1)(v2)(v3)); } template<typename T1, typename T2, typename T3, typename T4> - void operator ()(const char *fmt, const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) const + void operator ()(const pstring fmt, const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) const { if (build_enabled && m_enabled) vdowrite(pfmt(fmt)(v1)(v2)(v3)(v4)); } template<typename T1, typename T2, typename T3, typename T4, typename T5> - void operator ()(const char *fmt, const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) const + void operator ()(const pstring fmt, const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) const { if (build_enabled && m_enabled) vdowrite(pfmt(fmt)(v1)(v2)(v3)(v4)(v5)); } @@ -237,18 +242,18 @@ public: bool is_enabled() const { return m_enabled; } protected: - virtual void vdowrite(const pstring &ls) const {} + virtual void vdowrite(const pstring &ls) const = 0; private: bool m_enabled; }; -template <plog_level::e L, bool build_enabled = true> +template <plog_level::E L, bool build_enabled = true> class plog_channel : public pfmt_writer_t<build_enabled> { public: - explicit plog_channel(plog_dispatch_intf *b) : pfmt_writer_t<build_enabled>(), m_base(b) { } + explicit plog_channel(plog_dispatch_intf *b) : pfmt_writer_t<build_enabled>(), m_base(b) { } virtual ~plog_channel() { } protected: @@ -260,7 +265,7 @@ private: class plog_dispatch_intf { - template<plog_level::e, bool> friend class plog_channel; + template<plog_level::E, bool> friend class plog_channel; public: virtual ~plog_dispatch_intf(); @@ -292,7 +297,7 @@ public: }; -template <plog_level::e L, bool build_enabled> +template <plog_level::E L, bool build_enabled> void plog_channel<L, build_enabled>::vdowrite(const pstring &ls) const { m_base->vlog(L, ls); diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp new file mode 100644 index 00000000000..b457c940021 --- /dev/null +++ b/src/lib/netlist/plib/pfunction.cpp @@ -0,0 +1,212 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * palloc.c + * + */ + +#include <cmath> +#include <stack> +#include "pfunction.h" +#include "pfmtlog.h" +#include "putil.h" +#include "pexception.h" + +namespace plib { + +void pfunction::compile(const std::vector<pstring> &inputs, const pstring expr) +{ + if (expr.startsWith("rpn:")) + compile_postfix(inputs, expr.substr(4)); + else + compile_infix(inputs, expr); +} + +void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstring expr) +{ + std::vector<pstring> cmds(plib::psplit(expr, " ")); + compile_postfix(inputs, cmds, expr); +} + +void pfunction::compile_postfix(const std::vector<pstring> &inputs, + const std::vector<pstring> &cmds, const pstring expr) +{ + m_precompiled.clear(); + int stk = 0; + + for (const pstring &cmd : cmds) + { + rpn_inst rc; + if (cmd == "+") + { rc.m_cmd = ADD; stk -= 1; } + else if (cmd == "-") + { rc.m_cmd = SUB; stk -= 1; } + else if (cmd == "*") + { rc.m_cmd = MULT; stk -= 1; } + else if (cmd == "/") + { rc.m_cmd = DIV; stk -= 1; } + else if (cmd == "pow") + { rc.m_cmd = POW; stk -= 1; } + else if (cmd == "sin") + { rc.m_cmd = SIN; stk -= 0; } + else if (cmd == "cos") + { rc.m_cmd = COS; stk -= 0; } + else + { + for (unsigned i = 0; i < inputs.size(); i++) + { + if (inputs[i] == cmd) + { + rc.m_cmd = PUSH_INPUT; + rc.m_param = i; + stk += 1; + break; + } + } + if (rc.m_cmd != PUSH_INPUT) + { + bool err = false; + rc.m_cmd = PUSH_CONST; + rc.m_param = cmd.as_double(&err); + if (err) + throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); + stk += 1; + } + } + if (stk < 1) + throw plib::pexception(plib::pfmt("nld_function: stack underflow on token <{1}> in <{2}>")(cmd)(expr)); + m_precompiled.push_back(rc); + } + if (stk != 1) + throw plib::pexception(plib::pfmt("nld_function: stack count different to one on <{2}>")(expr)); +} + +static int get_prio(pstring v) +{ + if (v == "(" || v == ")") + return 1; + else if (v.left(v.begin()+1) >= "a" && v.left(v.begin()+1) <= "z") + return 0; + else if (v == "*" || v == "/") + return 20; + else if (v == "+" || v == "-") + return 10; + else if (v == "^") + return 30; + else + return -1; +} + +static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) +{ + if (stk.size() == 0) + throw plib::pexception(plib::pfmt("nld_function: stack underflow during infix parsing of: <{1}>")(expr)); + pstring res = stk.top(); + stk.pop(); + return res; +} + +void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring expr) +{ + // Shunting-yard infix parsing + std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; + std::vector<pstring> sexpr(plib::psplit(expr.replace(" ",""), sep)); + std::stack<pstring> opstk; + std::vector<pstring> postfix; + + //printf("dbg: %s\n", expr.c_str()); + for (unsigned i = 0; i < sexpr.size(); i++) + { + pstring &s = sexpr[i]; + if (s=="(") + opstk.push(s); + else if (s==")") + { + pstring x = pop_check(opstk, expr); + while (x != "(") + { + postfix.push_back(x); + x = pop_check(opstk, expr); + } + if (opstk.size() > 0 && get_prio(opstk.top()) == 0) + postfix.push_back(pop_check(opstk, expr)); + } + else if (s==",") + { + pstring x = pop_check(opstk, expr); + while (x != "(") + { + postfix.push_back(x); + x = pop_check(opstk, expr); + } + opstk.push(x); + } + else { + int p = get_prio(s); + if (p>0) + { + if (opstk.size() == 0) + opstk.push(s); + else + { + if (get_prio(opstk.top()) >= get_prio(s)) + postfix.push_back(pop_check(opstk, expr)); + opstk.push(s); + } + } + else if (p == 0) // Function or variable + { + if (sexpr[i+1] == "(") + opstk.push(s); + else + postfix.push_back(s); + } + else + postfix.push_back(s); + } + } + while (opstk.size() > 0) + { + postfix.push_back(opstk.top()); + opstk.pop(); + } + compile_postfix(inputs, postfix, expr); +} + + +#define ST1 stack[ptr] +#define ST2 stack[ptr-1] + +#define OP(OP, ADJ, EXPR) \ +case OP: \ + ptr-=ADJ; \ + stack[ptr-1] = EXPR; \ + break; + +double pfunction::evaluate(const std::vector<double> &values) +{ + double stack[20]; + unsigned ptr = 0; + for (auto &rc : m_precompiled) + { + switch (rc.m_cmd) + { + OP(ADD, 1, ST2 + ST1) + OP(MULT, 1, ST2 * ST1) + OP(SUB, 1, ST2 - ST1) + OP(DIV, 1, ST2 / ST1) + OP(POW, 1, std::pow(ST2, ST1)) + OP(SIN, 0, std::sin(ST2)); + OP(COS, 0, std::cos(ST2)); + case PUSH_INPUT: + stack[ptr++] = values[static_cast<unsigned>(rc.m_param)]; + break; + case PUSH_CONST: + stack[ptr++] = rc.m_param; + break; + } + } + return stack[ptr-1]; +} + +} diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h new file mode 100644 index 00000000000..da61fe84e17 --- /dev/null +++ b/src/lib/netlist/plib/pfunction.h @@ -0,0 +1,87 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * pfunction.h + * + */ + +#ifndef PFUNCTION_H_ +#define PFUNCTION_H_ + +#include <vector> + +#include "pstring.h" + +namespace plib { + + //============================================================ + // function evaluation + //============================================================ + + /*! Class providing support for evaluating expressions + * + */ + class pfunction + { + enum rpn_cmd + { + ADD, + MULT, + SUB, + DIV, + POW, + SIN, + COS, + PUSH_CONST, + PUSH_INPUT + }; + struct rpn_inst + { + rpn_inst() : m_cmd(ADD), m_param(0.0) { } + rpn_cmd m_cmd; + double m_param; + }; + public: + pfunction() + { + } + + /*! Compile an expression + * + * @param inputs Vector of input variables, e.g. {"A","B"} + * @param expr infix or postfix expression. default is infix, postrix + * to be prefixed with rpn, e.g. "rpn:A B + 1.3 /" + */ + void compile(const std::vector<pstring> &inputs, const pstring expr); + + /*! Compile a rpn expression + * + * @param inputs Vector of input variables, e.g. {"A","B"} + * @param expr Reverse polish notation expression, e.g. "A B + 1.3 /" + */ + void compile_postfix(const std::vector<pstring> &inputs, const pstring expr); + /*! Compile an infix expression + * + * @param inputs Vector of input variables, e.g. {"A","B"} + * @param expr Infix expression, e.g. "(A+B)/1.3" + */ + void compile_infix(const std::vector<pstring> &inputs, const pstring expr); + /*! Evaluate the expression + * + * @param values for input variables, e.g. {1.1, 2.2} + * @return value of expression + */ + double evaluate(const std::vector<double> &values); + + private: + + void compile_postfix(const std::vector<pstring> &inputs, + const std::vector<pstring> &cmds, const pstring expr); + + std::vector<rpn_inst> m_precompiled; //!< precompiled expression + }; + + +} + +#endif /* PEXCEPTION_H_ */ diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h index 37f4e2a1391..c6ba2821790 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -10,10 +10,7 @@ #ifndef PLISTS_H_ #define PLISTS_H_ -#include <algorithm> #include <vector> -#include <type_traits> -#include <cmath> #include "pstring.h" @@ -56,6 +53,7 @@ public: template<typename... Args> void emplace(const std::size_t index, Args&&... args) { + // allocate on buffer new (&m_buf[index]) C(std::forward<Args>(args)...); } diff --git a/src/lib/netlist/plib/poptions.cpp b/src/lib/netlist/plib/poptions.cpp index a14d4ae93e7..775ee6d8810 100644 --- a/src/lib/netlist/plib/poptions.cpp +++ b/src/lib/netlist/plib/poptions.cpp @@ -39,13 +39,13 @@ namespace plib { { } - int option_str::parse(pstring argument) + int option_str::parse(const pstring &argument) { m_val = argument; return 0; } - int option_str_limit::parse(pstring argument) + int option_str_limit::parse(const pstring &argument) { if (plib::container::contains(m_limit, argument)) { @@ -56,20 +56,27 @@ namespace plib { return 1; } - int option_bool::parse(ATTR_UNUSED pstring argument) + int option_bool::parse(const pstring &argument) { m_val = true; return 0; } - int option_double::parse(pstring argument) + int option_double::parse(const pstring &argument) { bool err = false; m_val = argument.as_double(&err); return (err ? 1 : 0); } - int option_vec::parse(pstring argument) + int option_long::parse(const pstring &argument) + { + bool err = false; + m_val = argument.as_long(&err); + return (err ? 1 : 0); + } + + int option_vec::parse(const pstring &argument) { bool err = false; m_val.push_back(argument); @@ -102,18 +109,18 @@ namespace plib { int options::parse(int argc, char *argv[]) { - m_app = argv[0]; + m_app = pstring(argv[0], pstring::UTF8); for (int i=1; i<argc; ) { - pstring arg(argv[i]); + pstring arg(argv[i], pstring::UTF8); option *opt = nullptr; pstring opt_arg; bool has_equal_arg = false; if (arg.startsWith("--")) { - auto v = pstring_vector_t(arg.substr(2),"="); + auto v = psplit(arg.substr(2),"="); opt = getopt_long(v[0]); has_equal_arg = (v.size() > 1); if (has_equal_arg) @@ -148,7 +155,7 @@ namespace plib { else { i++; // FIXME: are there more arguments? - if (opt->parse(argv[i]) != 0) + if (opt->parse(pstring(argv[i], pstring::UTF8)) != 0) return i - 1; } } @@ -166,13 +173,13 @@ namespace plib { pstring options::split_paragraphs(pstring text, unsigned width, unsigned indent, unsigned firstline_indent) { - auto paragraphs = pstring_vector_t(text,"\n"); + auto paragraphs = psplit(text,"\n"); pstring ret(""); for (auto &p : paragraphs) { pstring line = pstring("").rpad(" ", firstline_indent); - for (auto &s : pstring_vector_t(p, " ")) + for (auto &s : psplit(p, " ")) { if (line.len() + s.len() > width) { diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h index aa5ce07cbc8..f859b2f5b3d 100644 --- a/src/lib/netlist/plib/poptions.h +++ b/src/lib/netlist/plib/poptions.h @@ -10,8 +10,6 @@ #ifndef POPTIONS_H_ #define POPTIONS_H_ -#include <cstddef> - #include "pstring.h" #include "plists.h" #include "putil.h" @@ -67,7 +65,7 @@ public: /* no_argument options will be called with "" argument */ - virtual int parse(ATTR_UNUSED pstring argument) = 0; + virtual int parse(const pstring &argument) = 0; pstring short_opt() { return m_short; } pstring long_opt() { return m_long; } @@ -85,7 +83,7 @@ public: : option(parent, ashort, along, help, true), m_val(defval) {} - virtual int parse(pstring argument) override; + virtual int parse(const pstring &argument) override; pstring operator ()() { return m_val; } private: @@ -96,17 +94,19 @@ class option_str_limit : public option { public: option_str_limit(options &parent, pstring ashort, pstring along, pstring defval, pstring limit, pstring help) - : option(parent, ashort, along, help, true), m_val(defval), m_limit(limit, ":") - {} + : option(parent, ashort, along, help, true), m_val(defval) + { + m_limit = plib::psplit(limit, ":"); + } - virtual int parse(pstring argument) override; + virtual int parse(const pstring &argument) override; pstring operator ()() { return m_val; } - const plib::pstring_vector_t &limit() { return m_limit; } + const std::vector<pstring> &limit() { return m_limit; } private: pstring m_val; - plib::pstring_vector_t m_limit; + std::vector<pstring> m_limit; }; class option_bool : public option @@ -116,7 +116,7 @@ public: : option(parent, ashort, along, help, false), m_val(false) {} - virtual int parse(ATTR_UNUSED pstring argument) override; + virtual int parse(const pstring &argument) override; bool operator ()() { return m_val; } private: @@ -130,13 +130,27 @@ public: : option(parent, ashort, along, help, true), m_val(defval) {} - virtual int parse(pstring argument) override; + virtual int parse(const pstring &argument) override; double operator ()() { return m_val; } private: double m_val; }; +class option_long : public option +{ +public: + option_long(options &parent, pstring ashort, pstring along, long defval, pstring help) + : option(parent, ashort, along, help, true), m_val(defval) + {} + + virtual int parse(const pstring &argument) override; + + long operator ()() { return m_val; } +private: + long m_val; +}; + class option_vec : public option { public: @@ -144,7 +158,7 @@ public: : option(parent, ashort, along, help, true) {} - virtual int parse(pstring argument) override; + virtual int parse(const pstring &argument) override; std::vector<pstring> operator ()() { return m_val; } private: diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp index 35629aacdee..6604c07dcb7 100644 --- a/src/lib/netlist/plib/pparser.cpp +++ b/src/lib/netlist/plib/pparser.cpp @@ -8,14 +8,15 @@ #include <cstdarg> #include "pparser.h" -#include "plib/palloc.h" +#include "palloc.h" +#include "putil.h" namespace plib { // ---------------------------------------------------------------------------------------- // A simple tokenizer // ---------------------------------------------------------------------------------------- -ptokenizer::ptokenizer(pistream &strm) +ptokenizer::ptokenizer(plib::putf8_reader &strm) : m_strm(strm), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"') { } @@ -302,7 +303,7 @@ void ppreprocessor::error(const pstring &err) -double ppreprocessor::expr(const pstring_vector_t &sexpr, std::size_t &start, int prio) +double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio) { double val; pstring tok=sexpr[start]; @@ -383,7 +384,7 @@ ppreprocessor::define_t *ppreprocessor::get_define(const pstring &name) pstring ppreprocessor::replace_macros(const pstring &line) { - pstring_vector_t elems(line, m_expr_sep); + std::vector<pstring> elems(psplit(line, m_expr_sep)); pstringbuffer ret = ""; for (auto & elem : elems) { @@ -396,7 +397,7 @@ pstring ppreprocessor::replace_macros(const pstring &line) return ret; } -static pstring catremainder(const pstring_vector_t &elems, std::size_t start, pstring sep) +static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, pstring sep) { pstringbuffer ret = ""; for (auto & elem : elems) @@ -415,13 +416,13 @@ pstring ppreprocessor::process_line(const pstring &line) // FIXME ... revise and extend macro handling if (lt.startsWith("#")) { - pstring_vector_t lti(lt, " ", true); + std::vector<pstring> lti(psplit(lt, " ", true)); if (lti[0].equals("#if")) { m_level++; std::size_t start = 0; lt = replace_macros(lt); - pstring_vector_t t(lt.substr(3).replace(" ",""), m_expr_sep); + std::vector<pstring> t(psplit(lt.substr(3).replace(" ",""), m_expr_sep)); int val = static_cast<int>(expr(t, start, 0)); if (val == 0) m_ifflag |= (1 << m_level); @@ -483,7 +484,7 @@ pstring ppreprocessor::process_line(const pstring &line) } -postream & ppreprocessor::process_i(pistream &istrm, postream &ostrm) +void ppreprocessor::process(putf8_reader &istrm, putf8_writer &ostrm) { pstring line; while (istrm.readline(line)) @@ -491,7 +492,6 @@ postream & ppreprocessor::process_i(pistream &istrm, postream &ostrm) line = process_line(line); ostrm.writeline(line); } - return ostrm; } } diff --git a/src/lib/netlist/plib/pparser.h b/src/lib/netlist/plib/pparser.h index db88299d85c..321dad2f608 100644 --- a/src/lib/netlist/plib/pparser.h +++ b/src/lib/netlist/plib/pparser.h @@ -11,18 +11,16 @@ #include <unordered_map> #include <cstdint> -#include "pconfig.h" #include "pstring.h" #include "plists.h" -#include "putil.h" +//#include "putil.h" #include "pstream.h" namespace plib { -class ptokenizer +class ptokenizer : nocopyassignmove { - P_PREVENT_COPYING(ptokenizer) public: - explicit ptokenizer(pistream &strm); + explicit ptokenizer(plib::putf8_reader &strm); virtual ~ptokenizer(); @@ -126,7 +124,7 @@ private: bool eof() { return m_strm.eof(); } - pistream &m_strm; + putf8_reader &m_strm; int m_lineno; pstring m_cur_line; @@ -148,9 +146,8 @@ private: }; -class ppreprocessor +class ppreprocessor : plib::nocopyassignmove { - P_PREVENT_COPYING(ppreprocessor) public: struct define_t @@ -165,22 +162,12 @@ public: ppreprocessor(std::vector<define_t> *defines = nullptr); virtual ~ppreprocessor() {} - template<class ISTR, class OSTR> - OSTR &process(ISTR &istrm, OSTR &ostrm) - { - return dynamic_cast<OSTR &>(process_i(istrm, ostrm)); - } + void process(putf8_reader &istrm, putf8_writer &ostrm); protected: - - postream &process_i(pistream &istrm, postream &ostrm); - - double expr(const plib::pstring_vector_t &sexpr, std::size_t &start, int prio); - + double expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio); define_t *get_define(const pstring &name); - pstring replace_macros(const pstring &line); - virtual void error(const pstring &err); private: @@ -188,9 +175,9 @@ private: pstring process_line(const pstring &line); std::unordered_map<pstring, define_t> m_defines; - plib::pstring_vector_t m_expr_sep; + std::vector<pstring> m_expr_sep; - std::uint_least32_t m_ifflag; // 31 if levels + std::uint_least64_t m_ifflag; // 31 if levels int m_level; int m_lineno; }; diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h new file mode 100644 index 00000000000..03a2a65baa4 --- /dev/null +++ b/src/lib/netlist/plib/ppmf.h @@ -0,0 +1,198 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * ppmf.h + * + */ + +#ifndef PPMF_H_ +#define PPMF_H_ + +#include "pconfig.h" +#include <utility> +#include <cstdint> + + +/* + * + * NL_PMF_TYPE_GNUC_PMF + * Use standard pointer to member function syntax C++11 + * + * NL_PMF_TYPE_GNUC_PMF_CONV + * Use gnu extension and convert the pmf to a function pointer. + * This is not standard compliant and needs + * -Wno-pmf-conversions to compile. + * + * NL_PMF_TYPE_INTERNAL + * Use the same approach as MAME for deriving the function pointer. + * This is compiler-dependent as well + * + * Benchmarks for ./nltool -c run -f src/mame/machine/nl_pong.cpp -t 10 -n pong_fast + * + * NL_PMF_TYPE_INTERNAL: 215% 215% + * NL_PMF_TYPE_GNUC_PMF: 163% 196% + * NL_PMF_TYPE_GNUC_PMF_CONV: 215% 215% + * NL_PMF_TYPE_VIRTUAL: 213% 209% + * + * The whole exercise was done to avoid virtual calls. In prior versions of + * netlist, the INTERNAL and GNUC_PMF_CONV approach provided significant improvement. + * Since than, "hot" was removed from functions declared as virtual. + * This may explain that the recent benchmarks show no difference at all. + * + */ + +#if (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) +#pragma GCC diagnostic ignored "-Wpmf-conversions" +#endif + +namespace plib { +/* + * The following class was derived from the MAME delegate.h code. + * It derives a pointer to a member function. + */ + +#if (PHAS_PMF_INTERNAL) + class mfp + { + public: + // construct from any member function pointer + class generic_class; + using generic_function = void (*)(); + + template<typename MemberFunctionType> + mfp(MemberFunctionType mftp) + : m_function(0), m_this_delta(0) + { + *reinterpret_cast<MemberFunctionType *>(this) = mftp; + } + + template<typename FunctionType, typename MemberFunctionType, typename ObjectType> + static FunctionType get_mfp(MemberFunctionType mftp, ObjectType *object) + { + mfp mfpo(mftp); + //return mfpo.update_after_bind<FunctionType>(object); + return reinterpret_cast<FunctionType>( + mfpo.convert_to_generic(reinterpret_cast<generic_class *>(object))); + } + + private: + // extract the generic function and adjust the object pointer + generic_function convert_to_generic(generic_class * object) const + { + // apply the "this" delta to the object first + generic_class * o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); + + // if the low bit of the vtable index is clear, then it is just a raw function pointer + if (!(m_function & 1)) + return reinterpret_cast<generic_function>(m_function); + + // otherwise, it is the byte index into the vtable where the actual function lives + std::uint8_t *vtable_base = *reinterpret_cast<std::uint8_t **>(o_p_delta); + return *reinterpret_cast<generic_function *>(vtable_base + m_function - 1); + } + + // actual state + uintptr_t m_function; // first item can be one of two things: + // if even, it's a pointer to the function + // if odd, it's the byte offset into the vtable + int m_this_delta; // delta to apply to the 'this' pointer + }; +#endif + +#if (PPMF_TYPE == PPMF_TYPE_PMF) + template<typename R, typename... Targs> + class pmfp_base + { + public: + class generic_class; +#if defined (__INTEL_COMPILER) && defined (_M_X64) // needed for "Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 14.0.2.176 Build 20140130" at least + using generic_function = int [((sizeof(void *) + 4 * sizeof(int)) + (sizeof(int) - 1)) / sizeof(int)]; +#elif defined(_MSC_VER)// all other cases - for MSVC maximum size is one pointer, plus 3 ints; all other implementations seem to be smaller + using generic_function = int [((sizeof(void *) + 3 * sizeof(int)) + (sizeof(int) - 1)) / sizeof(int)]; +#else + using generic_function = R (generic_class::*)(Targs...); +#endif + pmfp_base() {} + + template<typename MemberFunctionType, typename O> + void set_base(MemberFunctionType mftp, O *object) + { + using function_ptr = R (O::*)(Targs...); + function_ptr t = mftp; + *reinterpret_cast<function_ptr *>(&m_func) = t; + } + template<typename O> + inline R call(O *obj, Targs... args) + { + using function_ptr = R (O::*)(Targs...); + function_ptr t = *reinterpret_cast<function_ptr *>(&m_func); + return (obj->*t)(std::forward<Targs>(args)...); + } + private: + generic_function m_func; + }; + +#elif ((PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) || (PPMF_TYPE == PPMF_TYPE_INTERNAL)) + template<typename R, typename... Targs> + class pmfp_base + { + public: + using generic_function = void (*)(); + + pmfp_base() : m_func(nullptr) {} + + template<typename MemberFunctionType, typename O> + void set_base(MemberFunctionType mftp, O *object) + { + #if (PPMF_TYPE == PPMF_TYPE_INTERNAL) + using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args); + m_func = reinterpret_cast<generic_function>(plib::mfp::get_mfp<function_ptr>(mftp, object)); + #elif (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) + R (O::* pFunc)(Targs...) = mftp; + m_func = reinterpret_cast<generic_function>((object->*pFunc)); + #endif + } + template<typename O> + inline R call(O *obj, Targs... args) const + { + using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args); + return (reinterpret_cast<function_ptr>(m_func))(obj, std::forward<Targs>(args)...); + } + bool is_set() { return m_func != nullptr; } + private: + generic_function m_func; + }; +#endif + + template<typename R, typename... Targs> + class pmfp : public pmfp_base<R, Targs...> + { + public: + class generic_class; + pmfp() : pmfp_base<R, Targs...>(), m_obj(nullptr) {} + + template<typename MemberFunctionType, typename O> + pmfp(MemberFunctionType mftp, O *object) + { + this->set(mftp, object); + } + + template<typename MemberFunctionType, typename O> + void set(MemberFunctionType mftp, O *object) + { + this->set_base(mftp, object); + m_obj = reinterpret_cast<generic_class *>(object); + } + + inline R operator()(Targs... args) + { + return this->call(m_obj, std::forward<Targs>(args)...); + } + private: + generic_class *m_obj; + }; + + +} + +#endif /* PPMF_H_ */ diff --git a/src/lib/netlist/plib/pstate.h b/src/lib/netlist/plib/pstate.h index 7c25bf4d722..4256fa45152 100644 --- a/src/lib/netlist/plib/pstate.h +++ b/src/lib/netlist/plib/pstate.h @@ -8,13 +8,12 @@ #ifndef PSTATE_H_ #define PSTATE_H_ -#include <memory> -#include <type_traits> - -#include "plists.h" #include "pstring.h" #include "ptypes.h" +#include <vector> +#include <memory> + // ---------------------------------------------------------------------------------------- // state saving ... // ---------------------------------------------------------------------------------------- diff --git a/src/lib/netlist/plib/pstream.cpp b/src/lib/netlist/plib/pstream.cpp index b05d86d7bc5..efbf2aa2374 100644 --- a/src/lib/netlist/plib/pstream.cpp +++ b/src/lib/netlist/plib/pstream.cpp @@ -27,28 +27,6 @@ pistream::~pistream() { } -bool pistream::readline(pstring &line) -{ - char c = 0; - m_linebuf.clear(); - if (!this->readbyte(c)) - { - line = ""; - return false; - } - while (true) - { - if (c == 10) - break; - else if (c != 13) /* ignore CR */ - m_linebuf += c; - if (!this->readbyte(c)) - break; - } - line = m_linebuf; - return true; -} - // ----------------------------------------------------------------------------- // postream: output stream // ----------------------------------------------------------------------------- @@ -367,9 +345,43 @@ pstream::pos_type pomemstream::vtell() return m_pos; } -pstream_fmt_writer_t::~pstream_fmt_writer_t() +bool putf8_reader::readline(pstring &line) { + pstring::code_t c = 0; + m_linebuf.clear(); + if (!this->readcode(c)) + { + line = ""; + return false; + } + while (true) + { + if (c == 10) + break; + else if (c != 13) /* ignore CR */ + m_linebuf += pstring(c); + if (!this->readcode(c)) + break; + } + line = m_linebuf; + return true; } +putf8_fmt_writer::putf8_fmt_writer(postream &strm) +: pfmt_writer_t() +, putf8_writer(strm) +{ +} + +putf8_fmt_writer::~putf8_fmt_writer() +{ +} + +void putf8_fmt_writer::vdowrite(const pstring &ls) const +{ + write(ls); +} + + } diff --git a/src/lib/netlist/plib/pstream.h b/src/lib/netlist/plib/pstream.h index 6d02c4d1551..83c514da2e1 100644 --- a/src/lib/netlist/plib/pstream.h +++ b/src/lib/netlist/plib/pstream.h @@ -7,9 +7,6 @@ #ifndef PSTREAM_H_ #define PSTREAM_H_ -#include <cstdarg> -#include <cstddef> - #include "pconfig.h" #include "pstring.h" #include "pfmtlog.h" @@ -20,9 +17,8 @@ namespace plib { // pstream: things common to all streams // ----------------------------------------------------------------------------- -class pstream +class pstream : nocopyassignmove { - P_PREVENT_COPYING(pstream) public: using pos_type = std::size_t; @@ -73,7 +69,6 @@ private: class pistream : public pstream { - P_PREVENT_COPYING(pistream) public: explicit pistream(const unsigned flags) : pstream(flags) {} @@ -81,15 +76,6 @@ public: bool eof() const { return ((flags() & FLAG_EOF) != 0); } - /* this digests linux & dos/windows text files */ - - bool readline(pstring &line); - - bool readbyte(char &b) - { - return (read(&b, 1) == 1); - } - pos_type read(void *buf, const unsigned n) { return vread(buf, n); @@ -99,8 +85,6 @@ protected: /* read up to n bytes from stream */ virtual pos_type vread(void *buf, const pos_type n) = 0; -private: - pstringbuffer m_linebuf; }; // ----------------------------------------------------------------------------- @@ -109,30 +93,11 @@ private: class postream : public pstream { - P_PREVENT_COPYING(postream) public: explicit postream(unsigned flags) : pstream(flags) {} virtual ~postream(); - /* this digests linux & dos/windows text files */ - - void writeline(const pstring &line) - { - write(line); - write(10); - } - - void write(const pstring &text) - { - write(text.c_str(), text.blen()); - } - - void write(const char c) - { - write(&c, 1); - } - void write(const void *buf, const pos_type n) { vwrite(buf, n); @@ -153,7 +118,6 @@ private: class pomemstream : public postream { - P_PREVENT_COPYING(pomemstream) public: pomemstream(); @@ -177,8 +141,6 @@ private: class postringstream : public postream { - P_PREVENT_COPYING(postringstream ) - public: postringstream() : postream(0) { } @@ -205,7 +167,6 @@ private: class pofilestream : public postream { - P_PREVENT_COPYING(pofilestream) public: explicit pofilestream(const pstring &fname); @@ -233,7 +194,6 @@ private: class pstderr : public pofilestream { - P_PREVENT_COPYING(pstderr) public: pstderr(); virtual ~pstderr(); @@ -245,7 +205,6 @@ public: class pstdout : public pofilestream { - P_PREVENT_COPYING(pstdout) public: pstdout(); virtual ~pstdout(); @@ -257,7 +216,6 @@ public: class pifilestream : public pistream { - P_PREVENT_COPYING(pifilestream) public: explicit pifilestream(const pstring &fname); @@ -286,7 +244,6 @@ private: class pstdin : public pifilestream { - P_PREVENT_COPYING(pstdin) public: pstdin(); @@ -299,13 +256,13 @@ public: class pimemstream : public pistream { - P_PREVENT_COPYING(pimemstream) public: pimemstream(const void *mem, const pos_type len); explicit pimemstream(const pomemstream &ostrm); virtual ~pimemstream(); + pos_type size() const { return m_len; } protected: /* read up to n bytes from stream */ virtual pos_type vread(void *buf, const pos_type n) override; @@ -324,7 +281,6 @@ private: class pistringstream : public pimemstream { - P_PREVENT_COPYING(pistringstream) public: pistringstream(const pstring &str) : pimemstream(str.c_str(), str.len()), m_str(str) { } virtual ~pistringstream(); @@ -335,27 +291,86 @@ private: }; // ----------------------------------------------------------------------------- -// pstream_fmt_writer_t: writer on top of ostream +// putf8reader_t: reader on top of istream // ----------------------------------------------------------------------------- -class pstream_fmt_writer_t : public plib::pfmt_writer_t<> +/* this digests linux & dos/windows text files */ + +class putf8_reader : plib::nocopyassignmove { - P_PREVENT_COPYING(pstream_fmt_writer_t) public: + explicit putf8_reader(pistream &strm) : m_strm(strm) {} + virtual ~putf8_reader() {} - explicit pstream_fmt_writer_t(postream &strm) : m_strm(strm) {} - virtual ~pstream_fmt_writer_t(); + bool eof() const { return m_strm.eof(); } + bool readline(pstring &line); -protected: - virtual void vdowrite(const pstring &ls) const override + bool readbyte1(char &b) + { + return (m_strm.read(&b, 1) == 1); + } + + bool readcode(pstring::code_t &c) + { + char b[4]; + if (m_strm.read(&b[0], 1) != 1) + return false; + const unsigned l = pstring::traits::codelen(b); + for (unsigned i = 1; i < l; i++) + if (m_strm.read(&b[i], 1) != 1) + return false; + c = pstring::traits::code(b); + return true; + } + +private: + pistream &m_strm; + pstringbuffer m_linebuf; +}; + +// ----------------------------------------------------------------------------- +// putf8writer_t: writer on top of ostream +// ----------------------------------------------------------------------------- + +class putf8_writer : plib::nocopyassignmove +{ +public: + explicit putf8_writer(postream &strm) : m_strm(strm) {} + virtual ~putf8_writer() {} + + void writeline(const pstring &line) const { - m_strm.write(ls); + write(line); + write(10); + } + + void write(const pstring &text) const + { + m_strm.write(text.c_str(), text.blen()); + } + + void write(const pstring::code_t c) const + { + write(pstring(c)); } private: postream &m_strm; }; +class putf8_fmt_writer : public pfmt_writer_t<>, public putf8_writer +{ +public: + + explicit putf8_fmt_writer(postream &strm); + virtual ~putf8_fmt_writer(); + +protected: + virtual void vdowrite(const pstring &ls) const override; + +private: +}; + } #endif /* PSTREAM_H_ */ diff --git a/src/lib/netlist/plib/pstring.cpp b/src/lib/netlist/plib/pstring.cpp index 2506357c9a5..baeace1edb9 100644 --- a/src/lib/netlist/plib/pstring.cpp +++ b/src/lib/netlist/plib/pstring.cpp @@ -6,17 +6,16 @@ */ #include <cstring> -//FIXME:: pstring should be locale free -#include <cctype> -#include <cstdlib> -#include <cstdio> #include <algorithm> #include <stack> +#include <cstdlib> #include "pstring.h" #include "palloc.h" #include "plists.h" +template <typename F> pstr_t pstring_t<F>::m_zero(0); + template<typename F> pstring_t<F>::~pstring_t() { @@ -97,14 +96,15 @@ const pstring_t<F> pstring_t<F>::substr(const iterator start, const iterator end return ret; } - template<typename F> const pstring_t<F> pstring_t<F>::ucase() const { - pstring_t ret = *this; - ret.pcopy(c_str(), blen()); - for (std::size_t i=0; i<ret.len(); i++) - ret.m_ptr->str()[i] = static_cast<char>(toupper(static_cast<int>(ret.m_ptr->str()[i]))); + pstring_t ret = ""; + for (auto c : *this) + if (c >= 'a' && c <= 'z') + ret += (c - 'a' + 'A'); + else + ret += c; return ret; } @@ -151,7 +151,7 @@ typename pstring_t<F>::iterator pstring_t<F>::find_last_not_of(const pstring_t & } template<typename F> -typename pstring_t<F>::iterator pstring_t<F>::find(const pstring_t &search, iterator start) const +typename pstring_t<F>::iterator pstring_t<F>::find(const pstring_t search, iterator start) const { for (; start != end(); ++start) { @@ -169,6 +169,15 @@ typename pstring_t<F>::iterator pstring_t<F>::find(const pstring_t &search, iter } template<typename F> +typename pstring_t<F>::iterator pstring_t<F>::find(const code_t search, iterator start) const +{ + mem_t buf[traits::MAXCODELEN+1] = { 0 }; + traits::encode(search, buf); + return find(pstring_t(&buf[0], UTF8), start); +} + + +template<typename F> pstring_t<F> pstring_t<F>::replace(const pstring_t &search, const pstring_t &replace) const { pstring_t ret(""); @@ -188,13 +197,13 @@ pstring_t<F> pstring_t<F>::replace(const pstring_t &search, const pstring_t &rep } template<typename F> -const pstring_t<F> pstring_t<F>::ltrim(const pstring_t &ws) const +const pstring_t<F> pstring_t<F>::ltrim(const pstring_t ws) const { return substr(find_first_not_of(ws), end()); } template<typename F> -const pstring_t<F> pstring_t<F>::rtrim(const pstring_t &ws) const +const pstring_t<F> pstring_t<F>::rtrim(const pstring_t ws) const { auto f = find_last_not_of(ws); if (f==end()) @@ -230,7 +239,7 @@ double pstring_t<F>::as_double(bool *error) const if (error != nullptr) *error = false; - ret = strtod(c_str(), &e); + ret = std::strtod(c_str(), &e); if (*e != 0) if (error != nullptr) *error = true; @@ -246,9 +255,9 @@ long pstring_t<F>::as_long(bool *error) const if (error != nullptr) *error = false; if (startsWith("0x")) - ret = strtol(substr(2).c_str(), &e, 16); + ret = std::strtol(substr(2).c_str(), &e, 16); else - ret = strtol(c_str(), &e, 10); + ret = std::strtol(c_str(), &e, 10); if (*e != 0) if (error != nullptr) *error = true; @@ -256,24 +265,6 @@ long pstring_t<F>::as_long(bool *error) const } template<typename F> -typename pstring_t<F>::iterator pstring_t<F>::find(const mem_t *search, iterator start) const -{ - for (; start != end(); ++start) - { - iterator itc(start); - iterator cmp(search); - while (itc != end() && *cmp != 0 && *itc == *cmp) - { - ++itc; - ++cmp; - } - if (*cmp == 0) - return start; - } - return end(); -} - -template<typename F> bool pstring_t<F>::startsWith(const pstring_t &arg) const { if (arg.blen() > blen()) @@ -291,17 +282,6 @@ bool pstring_t<F>::endsWith(const pstring_t &arg) const return (memcmp(c_str()+this->blen()-arg.blen(), arg.c_str(), arg.blen()) == 0); } - -template<typename F> -bool pstring_t<F>::startsWith(const mem_t *arg) const -{ - std::size_t alen = strlen(arg); - if (alen > blen()) - return false; - else - return (memcmp(arg, c_str(), alen) == 0); -} - template<typename F> int pstring_t<F>::pcmp(const mem_t *right) const { @@ -435,8 +415,8 @@ static inline std::size_t countleadbits(std::size_t x) template<typename F> void pstring_t<F>::sfree(pstr_t *s) { - s->m_ref_count--; - if (s->m_ref_count == 0 && s != &m_zero) + bool b = s->dec_and_check(); + if ( b && s != &m_zero) { if (stk != nullptr) { @@ -445,7 +425,6 @@ void pstring_t<F>::sfree(pstr_t *s) } else plib::pfree_array(reinterpret_cast<char *>(s)); - //_mm_free(((char *)s)); } } @@ -492,16 +471,15 @@ void pstring_t<F>::resetmem() template<typename F> void pstring_t<F>::sfree(pstr_t *s) { - s->m_ref_count--; - if (s->m_ref_count == 0 && s != &m_zero) + bool b = s->dec_and_check(); + if ( b && s != &m_zero) { plib::pfree_array(((char *)s)); - //_mm_free(((char *)s)); } } template<typename F> -pstr_t *pstring_t<F>::salloc(int n) +pstr_t *pstring_t<F>::salloc(std::size_t n) { int size = sizeof(pstr_t) + n + 1; pstr_t *p = (pstr_t *) plib::palloc_array<char>(size); diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h index 16bf61b08ee..80a8fc4e78e 100644 --- a/src/lib/netlist/plib/pstring.h +++ b/src/lib/netlist/plib/pstring.h @@ -7,11 +7,8 @@ #ifndef PSTRING_H_ #define PSTRING_H_ -#include <cstdarg> -#include <cstddef> #include <iterator> - -#include "pconfig.h" +#include <exception> // ---------------------------------------------------------------------------------------- // pstring: immutable strings ... @@ -22,27 +19,24 @@ struct pstr_t { - //str_t() : m_ref_count(1), m_len(0) { m_str[0] = 0; } - pstr_t(const std::size_t alen) - { - init(alen); - } + pstr_t(const std::size_t alen) { init(alen); } void init(const std::size_t alen) { - m_ref_count = 1; - m_len = alen; - m_str[0] = 0; + m_ref_count = 1; + m_len = alen; + m_str[0] = 0; } char *str() { return &m_str[0]; } unsigned char *ustr() { return reinterpret_cast<unsigned char *>(&m_str[0]); } std::size_t len() const { return m_len; } - int m_ref_count; + void inc() { m_ref_count++; } + bool dec_and_check() { --m_ref_count; return m_ref_count == 0; } private: + int m_ref_count; std::size_t m_len; char m_str[1]; }; - template <typename F> struct pstring_t { @@ -53,20 +47,38 @@ public: typedef typename F::code_t code_t; typedef std::size_t size_type; + enum enc_t + { + UTF8 + }; + // simple construction/destruction - pstring_t() + pstring_t() : m_ptr(&m_zero) { - init(); + init(nullptr); } ~pstring_t(); - // construction with copy - pstring_t(const mem_t *string) { init(); if (string != nullptr && *string != 0) pcopy(string); } - pstring_t(const pstring_t &string) { init(); pcopy(string); } + // FIXME: Do something with encoding + pstring_t(const mem_t *string, const enc_t enc) : m_ptr(&m_zero) + { + init(string); + } + + template<typename C, std::size_t N> + pstring_t(C (&string)[N]) : m_ptr(&m_zero) { + static_assert(std::is_same<C, const mem_t>::value, "pstring constructor only accepts const mem_t"); + static_assert(N>0,"pstring from array of length 0"); + if (string[N-1] != 0) + throw std::exception(); + init(string); + } + + pstring_t(const pstring_t &string) : m_ptr(&m_zero) { init(string); } pstring_t(pstring_t &&string) : m_ptr(string.m_ptr) { string.m_ptr = nullptr; } + explicit pstring_t(code_t code) : m_ptr(&m_zero) { pstring_t t; t+= code; init(t); } // assignment operators - pstring_t &operator=(const mem_t *string) { pcopy(string); return *this; } pstring_t &operator=(const pstring_t &string) { pcopy(string); return *this; } struct iterator final : public std::iterator<std::forward_iterator_tag, mem_t> @@ -94,41 +106,24 @@ public: // concatenation operators pstring_t& operator+=(const pstring_t &string) { pcat(string); return *this; } - pstring_t& operator+=(const mem_t *string) { pcat(string); return *this; } friend pstring_t operator+(const pstring_t &lhs, const pstring_t &rhs) { return pstring_t(lhs) += rhs; } - friend pstring_t operator+(const pstring_t &lhs, const mem_t *rhs) { return pstring_t(lhs) += rhs; } - friend pstring_t operator+(const mem_t *lhs, const pstring_t &rhs) { return pstring_t(lhs) += rhs; } // comparison operators - bool operator==(const mem_t *string) const { return (pcmp(string) == 0); } bool operator==(const pstring_t &string) const { return (pcmp(string) == 0); } - bool operator!=(const mem_t *string) const { return (pcmp(string) != 0); } bool operator!=(const pstring_t &string) const { return (pcmp(string) != 0); } - bool operator<(const mem_t *string) const { return (pcmp(string) < 0); } bool operator<(const pstring_t &string) const { return (pcmp(string) < 0); } - bool operator<=(const mem_t *string) const { return (pcmp(string) <= 0); } bool operator<=(const pstring_t &string) const { return (pcmp(string) <= 0); } - bool operator>(const mem_t *string) const { return (pcmp(string) > 0); } bool operator>(const pstring_t &string) const { return (pcmp(string) > 0); } - bool operator>=(const mem_t *string) const { return (pcmp(string) >= 0); } bool operator>=(const pstring_t &string) const { return (pcmp(string) >= 0); } bool equals(const pstring_t &string) const { return (pcmp(string) == 0); } - - //int cmp(const pstring_t &string) const { return pcmp(string); } - //int cmp(const mem_t *string) const { return pcmp(string); } - bool startsWith(const pstring_t &arg) const; - bool startsWith(const mem_t *arg) const; - bool endsWith(const pstring_t &arg) const; - bool endsWith(const mem_t *arg) const { return endsWith(pstring_t(arg)); } pstring_t replace(const pstring_t &search, const pstring_t &replace) const; - const pstring_t cat(const pstring_t &s) const { return *this + s; } - const pstring_t cat(const mem_t *s) const { return *this + s; } + const pstring_t cat(const code_t c) const { return *this + c; } size_type blen() const { return m_ptr->len(); } @@ -145,11 +140,9 @@ public: pstring_t& operator+=(const code_t c) { mem_t buf[traits::MAXCODELEN+1] = { 0 }; traits::encode(c, buf); pcat(buf); return *this; } friend pstring_t operator+(const pstring_t &lhs, const code_t rhs) { return pstring_t(lhs) += rhs; } - iterator find(const pstring_t &search, iterator start) const; - iterator find(const pstring_t &search) const { return find(search, begin()); } - iterator find(const mem_t *search, iterator start) const; - iterator find(const mem_t *search) const { return find(search, begin()); } - iterator find(const code_t search, iterator start) const { mem_t buf[traits::MAXCODELEN+1] = { 0 }; traits::encode(search, buf); return find(buf, start); } + iterator find(const pstring_t search, iterator start) const; + iterator find(const pstring_t search) const { return find(search, begin()); } + iterator find(const code_t search, iterator start) const; iterator find(const code_t search) const { return find(search, begin()); } const pstring_t substr(const iterator start, const iterator end) const ; @@ -162,9 +155,9 @@ public: iterator find_first_not_of(const pstring_t &no) const; iterator find_last_not_of(const pstring_t &no) const; - const pstring_t ltrim(const pstring_t &ws = " \t\n\r") const; - const pstring_t rtrim(const pstring_t &ws = " \t\n\r") const; - const pstring_t trim(const pstring_t &ws = " \t\n\r") const { return this->ltrim(ws).rtrim(ws); } + const pstring_t ltrim(const pstring_t ws = pstring_t(" \t\n\r")) const; + const pstring_t rtrim(const pstring_t ws = pstring_t(" \t\n\r")) const; + const pstring_t trim(const pstring_t ws = pstring_t(" \t\n\r")) const { return this->ltrim(ws).rtrim(ws); } const pstring_t rpad(const pstring_t &ws, const size_type cnt) const; @@ -178,10 +171,16 @@ protected: pstr_t *m_ptr; private: - void init() + void init(const mem_t *string) + { + m_ptr->inc(); + if (string != nullptr && *string != 0) + pcopy(string); + } + void init(const pstring_t &string) { - m_ptr = &m_zero; - m_ptr->m_ref_count++; + m_ptr->inc(); + pcopy(string); } int pcmp(const pstring_t &right) const; @@ -191,14 +190,12 @@ private: void pcopy(const mem_t *from, std::size_t size); void pcopy(const mem_t *from); - void pcopy(const pstring_t &from) { sfree(m_ptr); m_ptr = from.m_ptr; - m_ptr->m_ref_count++; + m_ptr->inc(); } - void pcat(const mem_t *s); void pcat(const pstring_t &s); @@ -208,8 +205,6 @@ private: static pstr_t m_zero; }; -template <typename F> pstr_t pstring_t<F>::m_zero(0); - struct pu8_traits { static const unsigned MAXCODELEN = 1; /* in memory units */ @@ -358,7 +353,8 @@ public: // C string conversion helpers const char *c_str() const { return m_ptr; } - operator pstring() const { return pstring(m_ptr); } + // FIXME: encoding should be parameter + operator pstring() const { return pstring(m_ptr, pstring::UTF8); } // concatenation operators pstringbuffer& operator+=(const char c) { char buf[2] = { c, 0 }; pcat(buf); return *this; } diff --git a/src/lib/netlist/plib/ptypes.h b/src/lib/netlist/plib/ptypes.h index 9c477f71944..182333875d0 100644 --- a/src/lib/netlist/plib/ptypes.h +++ b/src/lib/netlist/plib/ptypes.h @@ -9,6 +9,7 @@ #define PTYPES_H_ #include <type_traits> +#include <limits> #include "pconfig.h" #include "pstring.h" @@ -39,10 +40,25 @@ namespace plib #endif //============================================================ + // prevent implicit copying + //============================================================ + + struct nocopyassignmove + { + protected: + nocopyassignmove() = default; + ~nocopyassignmove() = default; + private: + nocopyassignmove(const nocopyassignmove &) = delete; + nocopyassignmove(nocopyassignmove &&) = delete; + nocopyassignmove &operator=(const nocopyassignmove &) = delete; + }; + + //============================================================ // penum - strongly typed enumeration //============================================================ - struct enum_base + struct penum_base { protected: static int from_string_int(const char *str, const char *x); @@ -52,22 +68,22 @@ namespace plib } #define P_ENUM(ename, ...) \ - struct ename : public plib::enum_base { \ - enum e { __VA_ARGS__ }; \ - ename (e v) : m_v(v) { } \ + struct ename : public plib::penum_base { \ + enum E { __VA_ARGS__ }; \ + ename (E v) : m_v(v) { } \ bool set_from_string (const pstring &s) { \ static const char *strings = # __VA_ARGS__; \ int f = from_string_int(strings, s.c_str()); \ - if (f>=0) { m_v = static_cast<e>(f); return true; } else { return false; } \ + if (f>=0) { m_v = static_cast<E>(f); return true; } else { return false; } \ } \ - operator e() const {return m_v;} \ + operator E() const {return m_v;} \ bool operator==(const ename &rhs) const {return m_v == rhs.m_v;} \ - bool operator==(const e &rhs) const {return m_v == rhs;} \ + bool operator==(const E &rhs) const {return m_v == rhs;} \ const pstring name() const { \ static const char *strings = # __VA_ARGS__; \ return nthstr(static_cast<int>(m_v), strings); \ } \ - private: e m_v; }; + private: E m_v; }; #endif /* PTYPES_H_ */ diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp index 39e1b444f33..6a24e8c4012 100644 --- a/src/lib/netlist/plib/putil.cpp +++ b/src/lib/netlist/plib/putil.cpp @@ -36,13 +36,14 @@ namespace plib if (getenv(var.c_str()) == nullptr) return default_val; else - return pstring(getenv(var.c_str())); + return pstring(getenv(var.c_str()), pstring::UTF8); } } - pstring_vector_t::pstring_vector_t(const pstring &str, const pstring &onstr, bool ignore_empty) - : std::vector<pstring>() + std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty) { + std::vector<pstring> ret; + pstring::iterator p = str.begin(); pstring::iterator pn = str.find(onstr, p); @@ -50,7 +51,7 @@ namespace plib { pstring t = str.substr(p, pn); if (!ignore_empty || t.len() != 0) - this->push_back(t); + ret.push_back(t); p = pn + onstr.len(); pn = str.find(onstr, p); } @@ -58,14 +59,15 @@ namespace plib { pstring t = str.substr(p, str.end()); if (!ignore_empty || t.len() != 0) - this->push_back(t); + ret.push_back(t); } + return ret; } - pstring_vector_t::pstring_vector_t(const pstring &str, const pstring_vector_t &onstrl) - : std::vector<pstring>() + std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl) { pstring col = ""; + std::vector<pstring> ret; unsigned i = 0; while (i<str.blen()) @@ -82,10 +84,10 @@ namespace plib if (p != static_cast<std::size_t>(-1)) { if (col != "") - this->push_back(col); + ret.push_back(col); col = ""; - this->push_back(onstrl[p]); + ret.push_back(onstrl[p]); i += onstrl[p].blen(); } else @@ -96,11 +98,13 @@ namespace plib } } if (col != "") - this->push_back(col); + ret.push_back(col); + + return ret; } - int enum_base::from_string_int(const char *str, const char *x) + int penum_base::from_string_int(const char *str, const char *x) { int cnt = 0; const char *cur = str; @@ -127,7 +131,7 @@ namespace plib return cnt; return -1; } - pstring enum_base::nthstr(int n, const char *str) + pstring penum_base::nthstr(int n, const char *str) { char buf[64]; char *bufp = buf; @@ -139,7 +143,7 @@ namespace plib if (*str == ',') { *bufp = 0; - return pstring(buf); + return pstring(buf, pstring::UTF8); } else if (*str != ' ') *bufp++ = *str; @@ -152,6 +156,6 @@ namespace plib str++; } *bufp = 0; - return pstring(buf); + return pstring(buf, pstring::UTF8); } } // namespace plib diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 9e79e958927..4bc8dcd695f 100644..100755 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -8,17 +8,18 @@ #ifndef P_UTIL_H_ #define P_UTIL_H_ -#include <initializer_list> +#include "pstring.h" -#include "plib/pstring.h" -#include "plib/plists.h" +#include <initializer_list> +#include <algorithm> +#include <vector> // <<= needed by windows build namespace plib { namespace util { const pstring buildpath(std::initializer_list<pstring> list ); - const pstring environment(const pstring &var, const pstring &default_val = ""); + const pstring environment(const pstring &var, const pstring &default_val); } namespace container @@ -66,13 +67,8 @@ namespace plib // string list // ---------------------------------------------------------------------------------------- - class pstring_vector_t : public std::vector<pstring> - { - public: - pstring_vector_t() : std::vector<pstring>() { } - pstring_vector_t(const pstring &str, const pstring &onstr, bool ignore_empty = false); - pstring_vector_t(const pstring &str, const pstring_vector_t &onstrl); - }; + std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty = false); + std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl); } diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp index 91f9fc7c1ae..6eec3d0e6dc 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -8,21 +8,12 @@ ****************************************************************************/ -#include <cstdio> -#include <cstdlib> - #include "plib/poptions.h" -#include "plib/pstring.h" -#include "plib/plists.h" -#include "plib/ptypes.h" -#include "plib/pexception.h" #include "nl_setup.h" -#include "nl_factory.h" #include "nl_parser.h" #include "devices/net_lib.h" #include "tools/nl_convert.h" - -#include <cfenv> +#include "solver/nld_solver.h" class tool_options_t : public plib::options { @@ -30,7 +21,7 @@ public: tool_options_t() : plib::options(), opt_grp1(*this, "General options", "The following options apply to all commands."), - opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static", "run|convert|listdevices|static"), + opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header", "run|convert|listdevices|static|header"), opt_file(*this, "f", "file", "-", "file to process (default is stdin)"), opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."), opt_rfolders(*this, "r", "rom", "where to look for files"), @@ -77,8 +68,8 @@ public: static plib::pstdout pout_strm; static plib::pstderr perr_strm; -static plib::pstream_fmt_writer_t pout(pout_strm); -static plib::pstream_fmt_writer_t perr(perr_strm); +static plib::putf8_fmt_writer pout(pout_strm); +static plib::putf8_fmt_writer perr(perr_strm); static NETLIST_START(dummy) /* Standard stuff */ @@ -211,7 +202,7 @@ struct input_t if (e != 3) throw netlist::nl_exception(plib::pfmt("error {1} scanning line {2}\n")(e)(line)); m_time = netlist::netlist_time::from_double(t); - m_param = setup.find_param(buf, true); + m_param = setup.find_param(pstring(buf, pstring::UTF8), true); } void setparam() @@ -244,8 +235,9 @@ static std::vector<input_t> read_input(const netlist::setup_t &setup, pstring fn if (fname != "") { plib::pifilestream f(fname); + plib::putf8_reader r(f); pstring l; - while (f.readline(l)) + while (r.readline(l)) { if (l != "") { @@ -319,12 +311,95 @@ static void static_compile(tool_options_t &opts) opts.opt_logs(), opts.opt_defines(), opts.opt_rfolders()); - nt.solver()->create_solver_code(pout_strm); + plib::putf8_writer w(pout_strm); + std::map<pstring, pstring> mp; + + nt.solver()->create_solver_code(mp); + + for (auto &e : mp) + { + w.write(e.second); + } nt.stop(); } +static void mac_out(const pstring s, const bool cont = true) +{ + static const unsigned RIGHT = 72; + if (cont) + { + unsigned adj = 0; + for (auto x : s) + adj += (x == '\t' ? 3 : 0); + pout("{1}\\\n", s.rpad(" ", RIGHT-1-adj)); + } + else + pout("{1}\n", s); +} + +static void create_header(tool_options_t &opts) +{ + netlist_tool_t nt("netlist"); + + nt.init(); + + nt.log().verbose.set_enabled(false); + nt.log().warning.set_enabled(false); + + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); + nt.setup().include("dummy"); + + pout("// license:GPL-2.0+\n"); + pout("// copyright-holders:Couriersud\n"); + pout("#ifndef NLD_DEVINC_H\n"); + pout("#define NLD_DEVINC_H\n"); + pout("\n"); + pout("#include \"nl_setup.h\"\n"); + pout("#ifndef __PLIB_PREPROCESSOR__\n"); + pout("\n"); + pout("/* ----------------------------------------------------------------------------\n"); + pout(" * Netlist Macros\n"); + pout(" * ---------------------------------------------------------------------------*/\n"); + pout("\n"); + + pstring last_source(""); + + for (auto &e : nt.setup().factory()) + { + if (last_source != e->sourcefile()) + { + last_source = e->sourcefile(); + pout("{1}\n", pstring("// ").rpad("-", 72)); + pout("{1}\n", pstring("// Source: ").cat(e->sourcefile().replace("../",""))); + pout("{1}\n", pstring("// ").rpad("-", 72)); + } + auto v = plib::psplit(e->param_desc(), ","); + pstring vs; + for (auto s : v) + vs += ", p" + s.replace("+","").replace(".","_"); + mac_out("#define " + e->name() + "(name" + vs + ")"); + mac_out("\tNET_REGISTER_DEV(" + e->name() +", name)"); \ + + for (auto s : v) + { + pstring r(s.replace("+","").replace(".","_")); + if (s.startsWith("+")) + mac_out("\tNET_CONNECT(name, " + r + ", p" + r + ")"); + else + mac_out("\tNETDEV_PARAMI(name, " + r + ", p" + r + ")"); + } + mac_out("", false); + } + pout("#endif // __PLIB_PREPROCESSOR__\n"); + pout("#endif\n"); + nt.stop(); + +} + + /*------------------------------------------------- listdevices - list all known devices -------------------------------------------------*/ @@ -390,7 +465,7 @@ static void listdevices(tool_options_t &opts) } out += "," + f->param_desc(); - for (auto p : plib::pstring_vector_t(f->param_desc(),",") ) + for (auto p : plib::psplit(f->param_desc(),",") ) { if (p.startsWith("+")) { @@ -417,7 +492,7 @@ static void listdevices(tool_options_t &opts) -------------------------------------------------*/ #if 0 -static const char *pmf_verbose[] = +static const pstring pmf_verbose[] = { "NL_PMF_TYPE_VIRTUAL", "NL_PMF_TYPE_GNUC_PMF", @@ -455,7 +530,7 @@ int main(int argc, char *argv[]) { pout( "nltool (netlist) 0.1\n" - "Copyright (C) 2016 Couriersud\n" + "Copyright (C) 2017 Couriersud\n" "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n\n" @@ -472,6 +547,8 @@ int main(int argc, char *argv[]) run(opts); else if (cmd == "static") static_compile(opts); + else if (cmd == "header") + create_header(opts); else if (cmd == "convert") { pstring contents; @@ -508,7 +585,7 @@ int main(int argc, char *argv[]) result = c.result(); } /* present result */ - pout_strm.write(result.c_str()); + pout.write(result); } else { diff --git a/src/lib/netlist/prg/nlwav.cpp b/src/lib/netlist/prg/nlwav.cpp index 44adf2b3508..52f59f366f6 100644 --- a/src/lib/netlist/prg/nlwav.cpp +++ b/src/lib/netlist/prg/nlwav.cpp @@ -1,13 +1,12 @@ // license:GPL-2.0+ // copyright-holders:Couriersud -#include <plib/poptions.h> -#include <cstdio> #include <cstring> #include "plib/pstring.h" #include "plib/plists.h" #include "plib/pstream.h" +#include "plib/poptions.h" +#include "plib/ppmf.h" #include "nl_setup.h" -#include <memory> class nlwav_options_t : public plib::options { @@ -17,6 +16,7 @@ public: opt_inp(*this, "i", "input", "-", "input file"), opt_out(*this, "o", "output", "-", "output file"), opt_amp(*this, "a", "amp", 10000.0, "amplification after mean correction"), + opt_rate(*this, "r", "rate", 48000, "sample rate of output file"), opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"), opt_quiet(*this,"q", "quiet", "be quiet - no warnings"), opt_version(*this, "", "version", "display version and exit"), @@ -25,6 +25,7 @@ public: plib::option_str opt_inp; plib::option_str opt_out; plib::option_double opt_amp; + plib::option_long opt_rate; plib::option_bool opt_verb; plib::option_bool opt_quiet; plib::option_bool opt_version; @@ -35,8 +36,8 @@ plib::pstdin pin_strm; plib::pstdout pout_strm; plib::pstderr perr_strm; -plib::pstream_fmt_writer_t pout(pout_strm); -plib::pstream_fmt_writer_t perr(perr_strm); +plib::putf8_fmt_writer pout(pout_strm); +plib::putf8_fmt_writer perr(perr_strm); nlwav_options_t opts; @@ -141,11 +142,114 @@ private: }; -static void convert() +class log_processor { - plib::postream *fo = (opts.opt_out() == "-" ? &pout_strm : new plib::pofilestream(opts.opt_out())); - plib::pistream *fin = (opts.opt_inp() == "-" ? &pin_strm : new plib::pifilestream(opts.opt_inp())); - wav_t *wo = new wav_t(*fo, 48000); +public: + typedef plib::pmfp<void, double, double> callback_type; + log_processor(plib::pistream &is, callback_type cb) : m_is(is), m_cb(cb) { } + + void process() + { + plib::putf8_reader reader(m_is); + pstring line; + + while(reader.readline(line)) + { + double t = 0.0; double v = 0.0; + sscanf(line.c_str(), "%lf %lf", &t, &v); + m_cb(t, v); + } + } + +private: + plib::pistream &m_is; + callback_type m_cb; +}; + +struct aggregator +{ + typedef plib::pmfp<void, double, double> callback_type; + + aggregator(double quantum, callback_type cb) + : m_quantum(quantum) + , m_cb(cb) + , ct(0.0) + , lt(0.0) + , outsam(0.0) + , cursam(0.0) + { } + void process(double time, double val) + { + while (time >= ct) + { + outsam += (ct - lt) * cursam; + outsam = outsam / m_quantum; + m_cb(ct, outsam); + outsam = 0.0; + lt = ct; + ct += m_quantum; + } + outsam += (time-lt)*cursam; + lt = time; + cursam = val; + } + +private: + double m_quantum; + callback_type m_cb; + double ct; + double lt; + double outsam; + double cursam; +}; + +class wavwriter +{ +public: + wavwriter(plib::postream &fo, unsigned sample_rate, double ampa) + : mean(0.0) + , means(0.0) + , maxsam(-1e9) + , minsam(1e9) + , n(0) + , m_fo(fo) + , amp(ampa) + , m_wo(m_fo, sample_rate) + { } + + void process(double time, double outsam) + { + means += outsam; + maxsam = std::max(maxsam, outsam); + minsam = std::min(minsam, outsam); + n++; + //mean = means / (double) n; + mean += 5.0 / static_cast<double>(m_wo.sample_rate()) * (outsam - mean); + + outsam = (outsam - mean) * amp; + outsam = std::max(-32000.0, outsam); + outsam = std::min(32000.0, outsam); + m_wo.write_sample(static_cast<int>(outsam)); + } + + double mean; + double means; + double maxsam; + double minsam; + std::size_t n; + +private: + plib::postream &m_fo; + double amp; + wav_t m_wo; +}; + +static void convert(long sample_rate) +{ + plib::postream *fo = (opts.opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opts.opt_out())); + plib::pistream *fin = (opts.opt_inp() == "-" ? &pin_strm : plib::palloc<plib::pifilestream>(opts.opt_inp())); + plib::putf8_reader reader(*fin); + wav_t *wo = plib::palloc<wav_t>(*fo, static_cast<unsigned>(sample_rate)); double dt = 1.0 / static_cast<double>(wo->sample_rate()); double ct = dt; @@ -162,7 +266,7 @@ static void convert() //short sample = 0; pstring line; - while(fin->readline(line)) + while(reader.readline(line)) { #if 1 double t = 0.0; double v = 0.0; @@ -212,11 +316,11 @@ static void convert() //printf("%f %f\n", t, v); #endif } - delete wo; + plib::pfree(wo); if (opts.opt_inp() != "-") - delete fin; + plib::pfree(fin); if (opts.opt_out() != "-") - delete fo; + plib::pfree(fo); if (!opts.opt_quiet()) { @@ -227,10 +331,39 @@ static void convert() } } -static void usage(plib::pstream_fmt_writer_t &fw) +static void convert1(long sample_rate) +{ + plib::postream *fo = (opts.opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opts.opt_out())); + plib::pistream *fin = (opts.opt_inp() == "-" ? &pin_strm : plib::palloc<plib::pifilestream>(opts.opt_inp())); + + double dt = 1.0 / static_cast<double>(sample_rate); + + wavwriter *wo = plib::palloc<wavwriter>(*fo, static_cast<unsigned>(sample_rate), opts.opt_amp()); + aggregator ag(dt, aggregator::callback_type(&wavwriter::process, wo)); + log_processor lp(*fin, log_processor::callback_type(&aggregator::process, &ag)); + + lp.process(); + + if (!opts.opt_quiet()) + { + perr("Mean (low freq filter): {}\n", wo->mean); + perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->n)); + perr("Amp + {}\n", 32000.0 / (wo->maxsam - wo->mean)); + perr("Amp - {}\n", -32000.0 / (wo->minsam - wo->mean)); + } + + plib::pfree(wo); + if (opts.opt_inp() != "-") + plib::pfree(fin); + if (opts.opt_out() != "-") + plib::pfree(fo); + +} + +static void usage(plib::putf8_fmt_writer &fw) { fw("{}\n", opts.help("Convert netlist log files into wav files.\n", - "nltool [options]").c_str()); + "nltool [options]")); } @@ -255,7 +388,7 @@ int main(int argc, char *argv[]) { pout( "nlwav (netlist) 0.1\n" - "Copyright (C) 2016 Couriersud\n" + "Copyright (C) 2017 Couriersud\n" "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n\n" @@ -263,7 +396,10 @@ int main(int argc, char *argv[]) return 0; } - convert(); + if ((1)) + convert1(opts.opt_rate()); + else + convert(opts.opt_rate()); return 0; } diff --git a/src/lib/netlist/solver/mat_cr.h b/src/lib/netlist/solver/mat_cr.h index 340c662752f..c39af1b2f5f 100644 --- a/src/lib/netlist/solver/mat_cr.h +++ b/src/lib/netlist/solver/mat_cr.h @@ -12,38 +12,79 @@ #include <algorithm> #include "plib/pconfig.h" +#include "plib/palloc.h" -template<int storage_N> +template<std::size_t N, typename C = uint16_t, typename T = double> struct mat_cr_t { - unsigned nz_num; - unsigned ia[storage_N + 1]; - unsigned ja[storage_N * storage_N]; - unsigned diag[storage_N]; /* n */ + typedef C index_type; + typedef T value_type; - template<typename T> - void mult_vec(const T * RESTRICT A, const T * RESTRICT x, T * RESTRICT res) + C diag[N]; // diagonal index pointer n + C ia[N+1]; // row index pointer n + 1 + C ja[N*N]; // column index array nz_num, initially (n * n) + T A[N*N]; // Matrix elements nz_num, initially (n * n) + + std::size_t size; + std::size_t nz_num; + + mat_cr_t(const std::size_t n) + : size(n) + , nz_num(0) + { +#if 0 +#if 0 + ia = plib::palloc_array<C>(n + 1); + ja = plib::palloc_array<C>(n * n); + diag = plib::palloc_array<C>(n); +#else + diag = plib::palloc_array<C>(n + (n + 1) + n * n); + ia = diag + n; + ja = ia + (n+1); + A = plib::palloc_array<T>(n * n); +#endif +#endif + } + + ~mat_cr_t() + { +#if 0 + plib::pfree_array(diag); +#if 0 + plib::pfree_array(ia); + plib::pfree_array(ja); +#endif + plib::pfree_array(A); +#endif + } + + void set_scalar(const T scalar) + { + for (std::size_t i=0, e=nz_num; i<e; i++) + A[i] = scalar; + } + + void mult_vec(const T * RESTRICT x, T * RESTRICT res) { /* * res = A * x */ - unsigned i = 0; - unsigned k = 0; - const unsigned oe = nz_num; + std::size_t i = 0; + std::size_t k = 0; + const std::size_t oe = nz_num; while (k < oe) { T tmp = 0.0; - const unsigned e = ia[i+1]; + const std::size_t e = ia[i+1]; for (; k < e; k++) tmp += A[k] * x[ja[k]]; res[i++] = tmp; } } - template<typename T> - void incomplete_LU_factorization(const T * RESTRICT A, T * RESTRICT LU) + void incomplete_LU_factorization(T * RESTRICT LU) { /* * incomplete LU Factorization according to http://de.wikipedia.org/wiki/ILU-Zerlegung @@ -52,28 +93,28 @@ struct mat_cr_t * */ - const unsigned lnz = nz_num; + const std::size_t lnz = nz_num; - for (unsigned k = 0; k < lnz; k++) + for (std::size_t k = 0; k < lnz; k++) LU[k] = A[k]; - for (unsigned i = 1; ia[i] < lnz; i++) // row i + for (std::size_t i = 1; ia[i] < lnz; i++) // row i { - const unsigned iai1 = ia[i + 1]; - const unsigned pke = diag[i]; - for (unsigned pk = ia[i]; pk < pke; pk++) // all columns left of diag in row i + const std::size_t iai1 = ia[i + 1]; + const std::size_t pke = diag[i]; + for (std::size_t pk = ia[i]; pk < pke; pk++) // all columns left of diag in row i { // pk == (i, k) - const unsigned k = ja[pk]; - const unsigned iak1 = ia[k + 1]; + const std::size_t k = ja[pk]; + const std::size_t iak1 = ia[k + 1]; const T LUpk = LU[pk] = LU[pk] / LU[diag[k]]; - unsigned pt = ia[k]; + std::size_t pt = ia[k]; - for (unsigned pj = pk + 1; pj < iai1; pj++) // pj = (i, j) + for (std::size_t pj = pk + 1; pj < iai1; pj++) // pj = (i, j) { // we can assume that within a row ja increases continuously */ - const unsigned ej = ja[pj]; + const std::size_t ej = ja[pj]; while (ja[pt] < ej && pt < iak1) pt++; if (pt < iak1 && ja[pt] == ej) @@ -83,7 +124,6 @@ struct mat_cr_t } } - template<typename T> void solveLUx (const T * RESTRICT LU, T * RESTRICT r) { /* @@ -96,7 +136,7 @@ struct mat_cr_t * * ==> LUx = r * - * ==> Ux = L?????r = w + * ==> Ux = L⁻¹ r = w * * ==> r = Lw * @@ -108,32 +148,28 @@ struct mat_cr_t * */ - unsigned i; - - for (i = 1; ia[i] < nz_num; i++ ) + for (std::size_t i = 1; ia[i] < nz_num; ++i ) { T tmp = 0.0; - const unsigned j1 = ia[i]; - const unsigned j2 = diag[i]; + const std::size_t j1 = ia[i]; + const std::size_t j2 = diag[i]; - for (unsigned j = j1; j < j2; j++ ) + for (std::size_t j = j1; j < j2; ++j ) tmp += LU[j] * r[ja[j]]; r[i] -= tmp; } // i now is equal to n; - for (; 0 < i; i-- ) + for (std::size_t i = size; i-- > 0; ) { - const unsigned im1 = i - 1; T tmp = 0.0; - const unsigned j1 = diag[im1] + 1; - const unsigned j2 = ia[im1+1]; - for (unsigned j = j1; j < j2; j++ ) + const std::size_t di = diag[i]; + const std::size_t j2 = ia[i+1]; + for (std::size_t j = di + 1; j < j2; j++ ) tmp += LU[j] * r[ja[j]]; - r[im1] = (r[im1] - tmp) / LU[diag[im1]]; + r[i] = (r[i] - tmp) / LU[di]; } } - }; #endif /* MAT_CR_H_ */ diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp index a27301a754d..f314aea2314 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.cpp +++ b/src/lib/netlist/solver/nld_matrix_solver.cpp @@ -8,6 +8,8 @@ #include "nld_matrix_solver.h" #include "plib/putil.h" +#include <cmath> // <<= needed by windows build + namespace netlist { namespace devices @@ -64,7 +66,7 @@ void terms_for_net_t::set_pointers() for (unsigned i = 0; i < count(); i++) { m_terms[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]); - m_connected_net_V[i] = m_terms[i]->m_otherterm->net().m_cur_Analog.ptr(); + m_connected_net_V[i] = m_terms[i]->m_otherterm->net().Q_Analog_state_ptr(); } } @@ -91,15 +93,11 @@ matrix_solver_t::matrix_solver_t(netlist_t &anetlist, const pstring &name, matrix_solver_t::~matrix_solver_t() { - for (unsigned k = 0; k < m_terms.size(); k++) - { - plib::pfree(m_terms[k]); - } - } void matrix_solver_t::setup_base(analog_net_t::list_t &nets) { + log().debug("New solver setup\n"); m_nets.clear(); @@ -108,7 +106,7 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets) for (auto & net : nets) { m_nets.push_back(net); - m_terms.push_back(plib::palloc<terms_for_net_t>()); + m_terms.push_back(plib::make_unique<terms_for_net_t>()); m_rails_temp.push_back(plib::palloc<terms_for_net_t>()); } @@ -125,7 +123,7 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets) log().debug("{1} {2} {3}\n", p->name(), net->name(), net->isRailNet()); switch (p->type()) { - case terminal_t::TERMINAL: + case detail::terminal_type::TERMINAL: if (p->device().is_timestep()) if (!plib::container::contains(m_step_devices, &p->device())) m_step_devices.push_back(&p->device()); @@ -138,7 +136,7 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets) } log().debug("Added terminal {1}\n", p->name()); break; - case terminal_t::INPUT: + case detail::terminal_type::INPUT: { proxied_analog_output_t *net_proxy_output = nullptr; for (auto & input : m_inps) @@ -157,14 +155,14 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets) net_proxy_output->m_proxied_net = static_cast<analog_net_t *>(&p->net()); } net_proxy_output->net().add_terminal(*p); - // FIXME: repeated + // FIXME: repeated calling - kind of brute force net_proxy_output->net().rebuild_list(); log().debug("Added input\n"); } break; - case terminal_t::OUTPUT: - case terminal_t::PARAM: - log().fatal("unhandled element found\n"); + case detail::terminal_type::OUTPUT: + log().fatal(MF_1_UNHANDLED_ELEMENT_1_FOUND, + p->name()); break; } } @@ -210,7 +208,7 @@ void matrix_solver_t::setup_matrix() * literature but I have found no articles about Gauss Seidel. * * For Gaussian Elimination however increasing order is better suited. - * FIXME: 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. * */ @@ -240,7 +238,7 @@ void matrix_solver_t::setup_matrix() /* create a list of non zero elements. */ for (unsigned k = 0; k < iN; k++) { - terms_for_net_t * t = m_terms[k]; + terms_for_net_t * t = m_terms[k].get(); /* pretty brutal */ int *other = t->connected_net_idx(); @@ -262,7 +260,7 @@ void matrix_solver_t::setup_matrix() */ for (unsigned k = 0; k < iN; k++) { - terms_for_net_t * t = m_terms[k]; + terms_for_net_t * t = m_terms[k].get(); /* pretty brutal */ int *other = t->connected_net_idx(); @@ -292,9 +290,9 @@ void matrix_solver_t::setup_matrix() * This should reduce cache misses ... */ - bool **touched = new bool*[iN]; + bool **touched = plib::palloc_array<bool *>(iN); for (unsigned k=0; k<iN; k++) - touched[k] = new bool[iN]; + touched[k] = plib::palloc_array<bool>(iN); for (unsigned k = 0; k < iN; k++) { @@ -352,8 +350,8 @@ void matrix_solver_t::setup_matrix() } for (unsigned k=0; k<iN; k++) - delete [] touched[k]; - delete [] touched; + plib::pfree_array(touched[k]); + plib::pfree_array(touched); } void matrix_solver_t::update_inputs() @@ -378,6 +376,7 @@ void matrix_solver_t::reset() void matrix_solver_t::update() NL_NOEXCEPT { const netlist_time new_timestep = solve(); + update_inputs(); if (m_params.m_dynamic_ts && has_timestep_devices() && new_timestep > netlist_time::zero()) { @@ -389,6 +388,7 @@ void matrix_solver_t::update() NL_NOEXCEPT void matrix_solver_t::update_forced() { ATTR_UNUSED const netlist_time new_timestep = solve(); + update_inputs(); if (m_params.m_dynamic_ts && has_timestep_devices()) { @@ -423,7 +423,7 @@ void matrix_solver_t::solve_base() // reschedule .... if (this_resched > 1 && !m_Q_sync.net().is_queued()) { - log().warning("NEWTON_LOOPS exceeded on net {1}... reschedule", this->name()); + log().warning(MW_1_NEWTON_LOOPS_EXCEEDED_ON_NET_1, this->name()); m_Q_sync.net().toggle_new_Q(); m_Q_sync.net().reschedule_in_queue(m_params.m_nr_recalc_delay); } @@ -449,7 +449,6 @@ const netlist_time matrix_solver_t::solve() step(delta); solve_base(); const netlist_time next_time_step = compute_next_timestep(delta.as_double()); - update_inputs(); return next_time_step; } @@ -479,7 +478,7 @@ void matrix_solver_t::add_term(std::size_t k, terminal_t *term) else // if (ot<0) { m_rails_temp[k]->add(term, ot, true); - log().fatal("found term with missing othernet {1}\n", term->name()); + log().fatal(MF_1_FOUND_TERM_WITH_MISSING_OTHERNET, term->name()); } } } @@ -490,14 +489,10 @@ netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts) if (m_params.m_dynamic_ts) { - /* - * FIXME: We should extend the logic to use either all nets or - * only output nets. - */ for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++) { analog_net_t *n = m_nets[k]; - terms_for_net_t *t = m_terms[k]; + terms_for_net_t *t = m_terms[k].get(); const nl_double DD_n = (n->Q_Analog() - t->m_last_V); const nl_double hn = cur_ts; @@ -546,12 +541,12 @@ void matrix_solver_t::log_stats() log().verbose(" {1:6.3} average newton raphson loops", static_cast<double>(this->m_stat_newton_raphson) / static_cast<double>(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<double>(this->m_stat_calculations()) / this->netlist().time().as_double(), - this->m_iterative_fail(), - 100.0 * static_cast<double>(this->m_iterative_fail()) - / static_cast<double>(this->m_stat_calculations()), - static_cast<double>(this->m_iterative_total()) / static_cast<double>(this->m_stat_calculations())); + this->m_stat_calculations, + static_cast<double>(this->m_stat_calculations) / this->netlist().time().as_double(), + this->m_iterative_fail, + 100.0 * static_cast<double>(this->m_iterative_fail) + / static_cast<double>(this->m_stat_calculations), + static_cast<double>(this->m_iterative_total) / static_cast<double>(this->m_stat_calculations)); } } diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h index 522b157eafb..82910e9c4d1 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.h +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -8,11 +8,9 @@ #ifndef NLD_MATRIX_SOLVER_H_ #define NLD_MATRIX_SOLVER_H_ -#include <type_traits> - -//#include "solver/nld_solver.h" #include "nl_base.h" -#include "plib/pstream.h" +#include "nl_errstr.h" +#include "plib/putil.h" namespace netlist { @@ -36,10 +34,8 @@ namespace netlist }; -class terms_for_net_t +class terms_for_net_t : plib::nocopyassignmove { - P_PREVENT_COPYING(terms_for_net_t) - public: terms_for_net_t(); @@ -47,14 +43,14 @@ public: void add(terminal_t *term, int net_other, bool sorted); - inline std::size_t count() { return m_terms.size(); } + inline std::size_t count() const { return m_terms.size(); } inline terminal_t **terms() { return m_terms.data(); } inline int *connected_net_idx() { return m_connected_net_idx.data(); } inline nl_double *gt() { return m_gt.data(); } inline nl_double *go() { return m_go.data(); } inline nl_double *Idr() { return m_Idr.data(); } - inline nl_double **connected_net_V() { return m_connected_net_V.data(); } + inline nl_double * const *connected_net_V() const { return m_connected_net_V.data(); } void set_pointers(); @@ -110,11 +106,18 @@ public: virtual ~matrix_solver_t(); - void setup(analog_net_t::list_t &nets) { vsetup(nets); } + void setup(analog_net_t::list_t &nets) + { + vsetup(nets); + } void solve_base(); + /* after every call to solve, update inputs must be called. + * this can be done as well as a batch to ease parallel processing. + */ const netlist_time solve(); + void update_inputs(); inline bool has_dynamic_devices() const { return m_dynamic_devices.size() > 0; } inline bool has_timestep_devices() const { return m_step_devices.size() > 0; } @@ -133,13 +136,11 @@ public: public: int get_net_idx(detail::net_t *net); - plib::plog_base<NL_DEBUG> &log() { return netlist().log(); } - virtual void log_stats(); - virtual void create_solver_code(plib::postream &strm) + virtual std::pair<pstring, pstring> create_solver_code() { - strm.writeline(plib::pfmt("/* {1} doesn't support static compile */")); + return std::pair<pstring, pstring>("", plib::pfmt("/* {1} doesn't support static compile */")); } protected: @@ -163,7 +164,7 @@ protected: template <typename T> void build_LE_RHS(); - std::vector<terms_for_net_t *> m_terms; + std::vector<std::unique_ptr<terms_for_net_t>> m_terms; std::vector<analog_net_t *> m_nets; std::vector<std::unique_ptr<proxied_analog_output_t>> m_inps; @@ -191,31 +192,30 @@ private: void step(const netlist_time &delta); - void update_inputs(); - const eSortType m_sort; }; template <typename T> T matrix_solver_t::delta(const T * RESTRICT V) { - /* FIXME: Ideally we should also include currents (RHS) here. This would + /* NOTE: Ideally we should also include currents (RHS) here. This would * need a reevaluation of the right hand side after voltages have been updated * and thus belong into a different calculation. This applies to all solvers. */ - std::size_t iN = this->m_terms.size(); + const std::size_t iN = this->m_terms.size(); T cerr = 0; - for (unsigned i = 0; i < iN; i++) - cerr = std::max(cerr, std::abs(V[i] - static_cast<T>(this->m_nets[i]->m_cur_Analog))); + for (std::size_t i = 0; i < iN; i++) + cerr = std::max(cerr, std::abs(V[i] - static_cast<T>(this->m_nets[i]->Q_Analog()))); return cerr; } template <typename T> void matrix_solver_t::store(const T * RESTRICT V) { - for (std::size_t i = 0, iN=m_terms.size(); i < iN; i++) - this->m_nets[i]->m_cur_Analog = V[i]; + const std::size_t iN = this->m_terms.size(); + for (std::size_t i = 0; i < iN; i++) + this->m_nets[i]->set_Q_Analog(V[i]); } template <typename T> @@ -225,26 +225,28 @@ void matrix_solver_t::build_LE_A() T &child = static_cast<T &>(*this); - const unsigned iN = child.N(); - for (unsigned k = 0; k < iN; k++) + const std::size_t iN = child.N(); + for (std::size_t k = 0; k < iN; k++) { - for (unsigned i=0; i < iN; i++) + terms_for_net_t *terms = m_terms[k].get(); + + for (std::size_t i=0; i < iN; i++) child.A(k,i) = 0.0; - const std::size_t terms_count = m_terms[k]->count(); - const std::size_t railstart = m_terms[k]->m_railstart; - const nl_double * RESTRICT gt = m_terms[k]->gt(); + const std::size_t terms_count = terms->count(); + const std::size_t railstart = terms->m_railstart; + const nl_double * const RESTRICT gt = terms->gt(); { nl_double akk = 0.0; - for (unsigned i = 0; i < terms_count; i++) + for (std::size_t i = 0; i < terms_count; i++) akk += gt[i]; child.A(k,k) = akk; } - const nl_double * RESTRICT go = m_terms[k]->go(); - const int * RESTRICT net_other = m_terms[k]->connected_net_idx(); + const nl_double * const RESTRICT go = terms->go(); + int * RESTRICT net_other = terms->connected_net_idx(); for (std::size_t i = 0; i < railstart; i++) child.A(k,net_other[i]) -= go[i]; @@ -257,15 +259,15 @@ void matrix_solver_t::build_LE_RHS() static_assert(std::is_base_of<matrix_solver_t, T>::value, "T must derive from matrix_solver_t"); T &child = static_cast<T &>(*this); - const unsigned iN = child.N(); - for (unsigned k = 0; k < iN; k++) + const std::size_t iN = child.N(); + for (std::size_t k = 0; k < iN; k++) { nl_double rhsk_a = 0.0; nl_double rhsk_b = 0.0; const std::size_t terms_count = m_terms[k]->count(); - const nl_double * RESTRICT go = m_terms[k]->go(); - const nl_double * RESTRICT Idr = m_terms[k]->Idr(); + const nl_double * const RESTRICT go = m_terms[k]->go(); + const nl_double * const RESTRICT Idr = m_terms[k]->Idr(); const nl_double * const * RESTRICT other_cur_analog = m_terms[k]->connected_net_V(); for (std::size_t i = 0; i < terms_count; i++) diff --git a/src/lib/netlist/solver/nld_ms_direct.h b/src/lib/netlist/solver/nld_ms_direct.h index 5b4a33ce66e..b929fb6ed22 100644 --- a/src/lib/netlist/solver/nld_ms_direct.h +++ b/src/lib/netlist/solver/nld_ms_direct.h @@ -19,7 +19,7 @@ * going forward in case we implement cuda solvers in the future. */ #define NL_USE_DYNAMIC_ALLOCATION (0) -#define TEST_PARALLEL (0) +#define TEST_PARALLEL (0 ) #if TEST_PARALLEL #include <thread> @@ -36,16 +36,17 @@ namespace netlist #if TEST_PARALLEL #define MAXTHR 10 -static const int num_thr = 1; +static const int num_thr = 3; struct thr_intf { + virtual ~thr_intf() = default; virtual void do_work(const int id, void *param) = 0; }; struct ti_t { - volatile std::atomic<int> lo; + /*volatile */std::atomic<int> lo; thr_intf *intf; void *params; // int block[29]; /* make it 256 bytes */ @@ -113,7 +114,7 @@ static void thr_dispose() } #endif -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> #if TEST_PARALLEL class matrix_solver_direct_t: public matrix_solver_t, public thr_intf #else @@ -123,8 +124,8 @@ class matrix_solver_direct_t: public matrix_solver_t friend class matrix_solver_t; public: - matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const unsigned size); - matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, const eSortType sort, const solver_parameters_t *params, const unsigned size); + matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size); + matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, const eSortType sort, const solver_parameters_t *params, const std::size_t size); virtual ~matrix_solver_direct_t(); @@ -135,7 +136,7 @@ protected: virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; unsigned solve_non_dynamic(const bool newton_raphson); - inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; } void LE_solve(); @@ -156,13 +157,14 @@ protected: inline nl_ext_double &RHS(const T1 &r) { return m_A[r * m_pitch + N()]; } #else template <typename T1, typename T2> - inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; } + nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; } template <typename T1> - inline nl_ext_double &RHS(const T1 &r) { return m_A[r][N()]; } + nl_ext_double &RHS(const T1 &r) { return m_A[r][N()]; } #endif nl_double m_last_RHS[storage_N]; // right hand side - contains currents private: + //static const std::size_t m_pitch = (((storage_N + 1) + 0) / 1) * 1; static const std::size_t m_pitch = (((storage_N + 1) + 7) / 8) * 8; //static const std::size_t m_pitch = (((storage_N + 1) + 15) / 16) * 16; //static const std::size_t m_pitch = (((storage_N + 1) + 31) / 32) * 32; @@ -173,7 +175,7 @@ private: #endif //nl_ext_double m_RHSx[storage_N]; - const unsigned m_dim; + const std::size_t m_dim; }; @@ -181,44 +183,41 @@ private: // matrix_solver_direct // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_direct_t<m_N, storage_N>::~matrix_solver_direct_t() { #if (NL_USE_DYNAMIC_ALLOCATION) - pfree_array(m_A); + plib::pfree_array(m_A); #endif #if TEST_PARALLEL thr_dispose(); #endif } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { - if (m_dim < nets.size()) - log().fatal("Dimension {1} less than {2}", m_dim, nets.size()); - matrix_solver_t::setup_base(nets); /* add RHS element */ - for (unsigned k = 0; k < N(); k++) + for (std::size_t k = 0; k < N(); k++) { - terms_for_net_t * t = m_terms[k]; + terms_for_net_t * t = m_terms[k].get(); - if (!plib::container::contains(t->m_nzrd, N())) - t->m_nzrd.push_back(N()); + if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(N()))) + t->m_nzrd.push_back(static_cast<unsigned>(N())); } netlist().save(*this, m_last_RHS, "m_last_RHS"); - for (unsigned k = 0; k < N(); k++) + for (std::size_t k = 0; k < N(); k++) netlist().save(*this, RHS(k), plib::pfmt("RHS.{1}")(k)); } #if TEST_PARALLEL -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_direct_t<m_N, storage_N>::do_work(const int id, void *param) { const int i = x_i[id]; @@ -242,58 +241,13 @@ void matrix_solver_direct_t<m_N, storage_N>::do_work(const int id, void *param) } #endif -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_direct_t<m_N, storage_N>::LE_solve() { - const unsigned kN = N(); - - for (unsigned i = 0; i < kN; i++) { - // FIXME: use a parameter to enable pivoting? m_pivot - if (!TEST_PARALLEL && m_params.m_pivot) - { - /* Find the row with the largest first value */ - unsigned maxrow = i; - for (unsigned j = i + 1; j < kN; j++) - { - //if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i])) - if (A(j,i) * A(j,i) > A(maxrow,i) * A(maxrow,i)) - maxrow = j; - } - - if (maxrow != i) - { - /* Swap the maxrow and ith row */ - for (unsigned k = 0; k < kN + 1; k++) { - std::swap(A(i,k), A(maxrow,k)); - } - //std::swap(RHS(i), RHS(maxrow)); - } - /* FIXME: Singular matrix? */ - const nl_double f = 1.0 / A(i,i); - - /* Eliminate column i from row j */ - - for (unsigned j = i + 1; j < kN; j++) - { - const nl_double f1 = - A(j,i) * f; - if (f1 != NL_FCONST(0.0)) - { - const nl_double * RESTRICT pi = &A(i,i+1); - nl_double * RESTRICT pj = &A(j,i+1); -#if 1 - vec_add_mult_scalar(kN-i,pi,f1,pj); -#else - vec_add_mult_scalar(kN-i-1,pj,f1,pi); - //for (unsigned k = i+1; k < kN; k++) - // pj[k] = pj[k] + pi[k] * f1; - //for (unsigned k = i+1; k < kN; k++) - //A(j,k) += A(i,k) * f1; - RHS(j) += RHS(i) * f1; -#endif - } - } - } - else + const std::size_t kN = N(); + if (!(!TEST_PARALLEL && m_params.m_pivot)) + { + for (std::size_t i = 0; i < kN; i++) { #if TEST_PARALLEL const unsigned eb = m_terms[i]->m_nzbd.size(); @@ -326,29 +280,76 @@ void matrix_solver_direct_t<m_N, storage_N>::LE_solve() const auto &nzrd = m_terms[i]->m_nzrd; const auto &nzbd = m_terms[i]->m_nzbd; - for (auto & j : nzbd) + for (std::size_t j : nzbd) { const nl_double f1 = -f * A(j,i); - for (auto & k : nzrd) + for (std::size_t k : nzrd) A(j,k) += A(i,k) * f1; //RHS(j) += RHS(i) * f1; + } #endif + } + } + else + { + for (std::size_t i = 0; i < kN; i++) + { + /* Find the row with the largest first value */ + std::size_t maxrow = i; + for (std::size_t j = i + 1; j < kN; j++) + { + //if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i])) + if (A(j,i) * A(j,i) > A(maxrow,i) * A(maxrow,i)) + maxrow = j; + } + + if (maxrow != i) + { + /* Swap the maxrow and ith row */ + for (std::size_t k = 0; k < kN + 1; k++) { + std::swap(A(i,k), A(maxrow,k)); + } + //std::swap(RHS(i), RHS(maxrow)); + } + /* FIXME: Singular matrix? */ + const nl_double f = 1.0 / A(i,i); + + /* Eliminate column i from row j */ + + for (std::size_t j = i + 1; j < kN; j++) + { + const nl_double f1 = - A(j,i) * f; + if (f1 != NL_FCONST(0.0)) + { + const nl_double * RESTRICT pi = &A(i,i+1); + nl_double * RESTRICT pj = &A(j,i+1); +#if 1 + vec_add_mult_scalar_p(kN-i,pi,f1,pj); +#else + vec_add_mult_scalar_p(kN-i-1,pj,f1,pi); + //for (unsigned k = i+1; k < kN; k++) + // pj[k] = pj[k] + pi[k] * f1; + //for (unsigned k = i+1; k < kN; k++) + //A(j,k) += A(i,k) * f1; + RHS(j) += RHS(i) * f1; +#endif + } } } } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> template <typename T> void matrix_solver_direct_t<m_N, storage_N>::LE_back_subst( T * RESTRICT x) { - const unsigned kN = N(); + const std::size_t kN = N(); /* back substitution */ if (m_params.m_pivot) { - for (unsigned j = kN; j-- > 0; ) + for (std::size_t j = kN; j-- > 0; ) { T tmp = 0; for (std::size_t k = j+1; k < kN; k++) @@ -358,14 +359,14 @@ void matrix_solver_direct_t<m_N, storage_N>::LE_back_subst( } else { - for (unsigned j = kN; j-- > 0; ) + for (std::size_t j = kN; j-- > 0; ) { T tmp = 0; const auto *p = m_terms[j]->m_nzrd.data(); const auto e = m_terms[j]->m_nzrd.size() - 1; /* exclude RHS element */ - for (unsigned k = 0; k < e; k++) + for (std::size_t k = 0; k < e; k++) { const auto pk = p[k]; tmp += A(j,pk) * x[pk]; @@ -376,7 +377,7 @@ void matrix_solver_direct_t<m_N, storage_N>::LE_back_subst( } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_direct_t<m_N, storage_N>::solve_non_dynamic(const bool newton_raphson) { nl_double new_V[storage_N]; // = { 0.0 }; @@ -399,27 +400,27 @@ unsigned matrix_solver_direct_t<m_N, storage_N>::solve_non_dynamic(const bool ne } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> inline unsigned matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { build_LE_A<matrix_solver_direct_t>(); build_LE_RHS<matrix_solver_direct_t>(); - for (unsigned i=0, iN=N(); i < iN; i++) + for (std::size_t i=0, iN=N(); i < iN; i++) m_last_RHS[i] = RHS(i); this->m_stat_calculations++; return this->solve_non_dynamic(newton_raphson); } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, - const solver_parameters_t *params, const unsigned size) + const solver_parameters_t *params, const std::size_t size) : matrix_solver_t(anetlist, name, ASCENDING, params) , m_dim(size) { #if (NL_USE_DYNAMIC_ALLOCATION) - m_A = palloc_array(nl_ext_double, N() * m_pitch); + m_A = plib::palloc_array<nl_ext_double>(N() * m_pitch); #endif for (unsigned k = 0; k < N(); k++) { @@ -430,14 +431,14 @@ matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(netlist_t &anetli #endif } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, - const eSortType sort, const solver_parameters_t *params, const unsigned size) + const eSortType sort, const solver_parameters_t *params, const std::size_t size) : matrix_solver_t(anetlist, name, sort, params) , m_dim(size) { #if (NL_USE_DYNAMIC_ALLOCATION) - m_A = palloc_array(nl_ext_double, N() * m_pitch); + m_A = plib::palloc_array<nl_ext_double>(N() * m_pitch); #endif for (unsigned k = 0; k < N(); k++) { diff --git a/src/lib/netlist/solver/nld_ms_direct_lu.h b/src/lib/netlist/solver/nld_ms_direct_lu.h index f71982f8eb4..c379cf8d055 100644 --- a/src/lib/netlist/solver/nld_ms_direct_lu.h +++ b/src/lib/netlist/solver/nld_ms_direct_lu.h @@ -4,7 +4,7 @@ * nld_ms_direct.h * */ - +#if 0 #ifndef NLD_MS_DIRECT_H_ #define NLD_MS_DIRECT_H_ @@ -345,10 +345,10 @@ void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) if(0) for (unsigned k = 0; k < N(); k++) { - netlist().log("{1:3}: ", k); + log("{1:3}: ", k); for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++) - netlist().log(" {1:3}", m_terms[k]->m_nzrd[j]); - netlist().log("\n"); + log(" {1:3}", m_terms[k]->m_nzrd[j]); + log("\n"); } /* @@ -634,3 +634,4 @@ matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(const eSolverType } // namespace netlist #endif /* NLD_MS_DIRECT_H_ */ +#endif diff --git a/src/lib/netlist/solver/nld_ms_gcr.h b/src/lib/netlist/solver/nld_ms_gcr.h index 80a68604a56..eda9b14aa74 100644 --- a/src/lib/netlist/solver/nld_ms_gcr.h +++ b/src/lib/netlist/solver/nld_ms_gcr.h @@ -5,8 +5,6 @@ * * Gaussian elimination using compressed row format. * - * Fow w==1 we will do the classic Gauss-Seidel approach - * */ #ifndef NLD_MS_GCR_H_ @@ -21,24 +19,20 @@ #include "solver/vector_base.h" #include "plib/pstream.h" -#define NL_USE_SSE 0 -#if NL_USE_SSE -#include <mmintrin.h> -#endif - namespace netlist { namespace devices { -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_GCR_t: public matrix_solver_t { public: matrix_solver_GCR_t(netlist_t &anetlist, const pstring &name, - const solver_parameters_t *params, const unsigned size) + const solver_parameters_t *params, const std::size_t size) : matrix_solver_t(anetlist, name, matrix_solver_t::ASCENDING, params) , m_dim(size) + , mat(size) , m_proc(nullptr) { } @@ -47,55 +41,50 @@ public: { } - inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; } virtual void vsetup(analog_net_t::list_t &nets) override; virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; - virtual void create_solver_code(plib::postream &strm) override; + virtual std::pair<pstring, pstring> create_solver_code() override; private: - void csc_private(plib::postream &strm); + //typedef typename mat_cr_t<storage_N>::type mattype; + typedef typename mat_cr_t<storage_N>::index_type mattype; - using extsolver = void (*)(double * RESTRICT m_A, double * RESTRICT RHS); + void csc_private(plib::putf8_fmt_writer &strm); - pstring static_compile_name() - { - plib::postringstream t; - csc_private(t); - std::hash<pstring> h; + using extsolver = void (*)(double * RESTRICT m_A, double * RESTRICT RHS, double * RESTRICT V); - return plib::pfmt("nl_gcr_{1:x}_{2}")(h( t.str() ))(mat.nz_num); - } + pstring static_compile_name(); - unsigned m_dim; + const std::size_t m_dim; std::vector<unsigned> m_term_cr[storage_N]; mat_cr_t<storage_N> mat; - nl_double m_A[storage_N * storage_N]; extsolver m_proc; }; // ---------------------------------------------------------------------------------------- -// matrix_solver - GMRES +// matrix_solver - GCR // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_GCR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { setup_base(nets); - unsigned nz = 0; - const unsigned iN = this->N(); + mattype nz = 0; + const std::size_t iN = this->N(); /* build the final matrix */ bool touched[storage_N][storage_N] = { { false } }; - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { - for (auto & j : this->m_terms[k]->m_nz) + for (auto &j : this->m_terms[k]->m_nz) touched[k][j] = true; } @@ -103,42 +92,31 @@ void matrix_solver_GCR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) unsigned ops = 0; - const bool static_compile = false; - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { ops++; // 1/A(k,k) - if (static_compile) printf("const double fd%d = 1.0 / A(%d,%d); \n", k, k, k); - for (unsigned row = k + 1; row < iN; row++) + for (std::size_t row = k + 1; row < iN; row++) { if (touched[row][k]) { ops++; fc++; - if (static_compile) printf(" const double f%d = -fd%d * A(%d,%d); \n", fc, k, row, k); - for (unsigned col = k + 1; col < iN; col++) + for (std::size_t col = k + 1; col < iN; col++) if (touched[k][col]) { - if (touched[row][col]) - { - if (static_compile) printf(" A(%d,%d) += f%d * A(%d,%d); \n", row, col, fc, k, col); - } else - { - if (static_compile) printf(" A(%d,%d) = f%d * A(%d,%d); \n", row, col, fc, k, col); - } touched[row][col] = true; ops += 2; } - if (static_compile) printf(" RHS(%d) += f%d * RHS(%d); \n", row, fc, k); } } } - for (unsigned k=0; k<iN; k++) + for (mattype k=0; k<iN; k++) { mat.ia[k] = nz; - for (unsigned j=0; j<iN; j++) + for (mattype j=0; j<iN; j++) { if (touched[k][j]) { @@ -151,10 +129,10 @@ void matrix_solver_GCR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) m_term_cr[k].clear(); /* build pointers into the compressed row format matrix for each terminal */ - for (unsigned j=0; j< this->m_terms[k]->m_railstart;j++) + for (std::size_t j=0; j< this->m_terms[k]->m_railstart;j++) { int other = this->m_terms[k]->connected_net_idx()[j]; - for (unsigned i = mat.ia[k]; i < nz; i++) + for (auto i = mat.ia[k]; i < nz; i++) if (other == static_cast<int>(mat.ja[i])) { m_term_cr[k].push_back(i); @@ -179,82 +157,173 @@ void matrix_solver_GCR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) if (m_proc != nullptr) this->log().verbose("External static solver {1} found ...", symname); else - this->log().verbose("External static solver {1} not found ...", symname); + this->log().warning("External static solver {1} not found ...", symname); } } +#if 0 +template <std::size_t m_N, std::size_t storage_N> +void matrix_solver_GCR_t<m_N, storage_N>::csc_private(plib::putf8_fmt_writer &strm) +{ + const std::size_t iN = N(); + for (std::size_t i = 0; i < iN - 1; i++) + { + const auto &nzbd = this->m_terms[i]->m_nzbd; + + if (nzbd.size() > 0) + { + std::size_t pi = mat.diag[i]; + + //const nl_double f = 1.0 / m_A[pi++]; + strm("const double f{1} = 1.0 / m_A[{2}];\n", i, pi); + pi++; + const std::size_t piie = mat.ia[i+1]; + + //for (auto & j : nzbd) + for (std::size_t j : nzbd) + { + // proceed to column i + std::size_t pj = mat.ia[j]; + + while (mat.ja[pj] < i) + pj++; + + //const nl_double f1 = - m_A[pj++] * f; + strm("\tconst double f{1}_{2} = -f{3} * m_A[{4}];\n", i, j, i, pj); + pj++; -template <unsigned m_N, unsigned storage_N> -void matrix_solver_GCR_t<m_N, storage_N>::csc_private(plib::postream &strm) + // subtract row i from j */ + for (std::size_t pii = pi; pii<piie; ) + { + while (mat.ja[pj] < mat.ja[pii]) + pj++; + //m_A[pj++] += m_A[pii++] * f1; + strm("\tm_A[{1}] += m_A[{2}] * f{3}_{4};\n", pj, pii, i, j); + pj++; pii++; + } + //RHS[j] += f1 * RHS[i]; + strm("\tRHS[{1}] += f{2}_{3} * RHS[{4}];\n", j, i, j, i); + } + } + } + + //new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]]; + strm("\tV[{1}] = RHS[{2}] / m_A[{3}];\n", iN - 1, iN - 1, mat.diag[iN - 1]); + for (std::size_t j = iN - 1; j-- > 0;) + { + strm("\tdouble tmp{1} = 0.0;\n", j); + const std::size_t e = mat.ia[j+1]; + for (std::size_t pk = mat.diag[j] + 1; pk < e; pk++) + { + strm("\ttmp{1} += m_A[{2}] * V[{3}];\n", j, pk, mat.ja[pk]); + } + strm("\tV[{1}] = (RHS[{1}] - tmp{1}) / m_A[{4}];\n", j, j, j, mat.diag[j]); + } +} +#else +template <std::size_t m_N, std::size_t storage_N> +void matrix_solver_GCR_t<m_N, storage_N>::csc_private(plib::putf8_fmt_writer &strm) { - const unsigned iN = N(); - for (unsigned i = 0; i < iN - 1; i++) + const std::size_t iN = N(); + + for (std::size_t i = 0; i < mat.nz_num; i++) + strm("double m_A{1} = m_A[{2}];\n", i, i); + + for (std::size_t i = 0; i < iN - 1; i++) { const auto &nzbd = this->m_terms[i]->m_nzbd; if (nzbd.size() > 0) { - unsigned pi = mat.diag[i]; + std::size_t pi = mat.diag[i]; //const nl_double f = 1.0 / m_A[pi++]; - strm.writeline(plib::pfmt("const double f{1} = 1.0 / m_A[{2}];")(i)(pi)); + strm("const double f{1} = 1.0 / m_A{2};\n", i, pi); pi++; - const unsigned piie = mat.ia[i+1]; + const std::size_t piie = mat.ia[i+1]; - for (auto & j : nzbd) + //for (auto & j : nzbd) + for (std::size_t j : nzbd) { // proceed to column i - unsigned pj = mat.ia[j]; + std::size_t pj = mat.ia[j]; while (mat.ja[pj] < i) pj++; //const nl_double f1 = - m_A[pj++] * f; - strm.writeline(plib::pfmt("\tconst double f{1}_{2} = -f{3} * m_A[{4}];")(i)(j)(i)(pj)); + strm("\tconst double f{1}_{2} = -f{3} * m_A{4};\n", i, j, i, pj); pj++; // subtract row i from j */ - for (unsigned pii = pi; pii<piie; ) + for (std::size_t pii = pi; pii<piie; ) { while (mat.ja[pj] < mat.ja[pii]) pj++; //m_A[pj++] += m_A[pii++] * f1; - strm.writeline(plib::pfmt("\tm_A[{1}] += m_A[{2}] * f{3}_{4};")(pj)(pii)(i)(j)); + strm("\tm_A{1} += m_A{2} * f{3}_{4};\n", pj, pii, i, j); pj++; pii++; } //RHS[j] += f1 * RHS[i]; - strm.writeline(plib::pfmt("\tRHS[{1}] += f{2}_{3} * RHS[{4}];")(j)(i)(j)(i)); + strm("\tRHS[{1}] += f{2}_{3} * RHS[{4}];\n", j, i, j, i); } } } + + //new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]]; + strm("\tV[{1}] = RHS[{2}] / m_A{3};\n", iN - 1, iN - 1, mat.diag[iN - 1]); + for (std::size_t j = iN - 1; j-- > 0;) + { + strm("\tdouble tmp{1} = 0.0;\n", j); + const std::size_t e = mat.ia[j+1]; + for (std::size_t pk = mat.diag[j] + 1; pk < e; pk++) + { + strm("\ttmp{1} += m_A{2} * V[{3}];\n", j, pk, mat.ja[pk]); + } + strm("\tV[{1}] = (RHS[{1}] - tmp{1}) / m_A{4};\n", j, j, j, mat.diag[j]); + } +} +#endif + +template <std::size_t m_N, std::size_t storage_N> +pstring matrix_solver_GCR_t<m_N, storage_N>::static_compile_name() +{ + plib::postringstream t; + plib::putf8_fmt_writer w(t); + csc_private(w); + std::hash<pstring> h; + + return plib::pfmt("nl_gcr_{1:x}_{2}")(h( t.str() ))(mat.nz_num); } -template <unsigned m_N, unsigned storage_N> -void matrix_solver_GCR_t<m_N, storage_N>::create_solver_code(plib::postream &strm) +template <std::size_t m_N, std::size_t storage_N> +std::pair<pstring, pstring> matrix_solver_GCR_t<m_N, storage_N>::create_solver_code() { - //const unsigned iN = N(); + plib::postringstream t; + plib::putf8_fmt_writer strm(t); + pstring name = static_compile_name(); - strm.writeline(plib::pfmt("extern \"C\" void {1}(double * _restrict m_A, double * _restrict RHS)")(static_compile_name())); - strm.writeline("{"); + strm.writeline(plib::pfmt("extern \"C\" void {1}(double * __restrict m_A, double * __restrict RHS, double * __restrict V)\n")(name)); + strm.writeline("{\n"); csc_private(strm); - strm.writeline("}"); + strm.writeline("}\n"); + return std::pair<pstring, pstring>(name, t.str()); } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_GCR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { - const unsigned iN = this->N(); + const std::size_t iN = this->N(); nl_double RHS[storage_N]; nl_double new_V[storage_N]; - for (unsigned i=0, e=mat.nz_num; i<e; i++) - m_A[i] = 0.0; + mat.set_scalar(0.0); - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { - terms_for_net_t *t = this->m_terms[k]; + terms_for_net_t *t = this->m_terms[k].get(); nl_double gtot_t = 0.0; nl_double RHS_t = 0.0; @@ -264,126 +333,109 @@ unsigned matrix_solver_GCR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt const nl_double * const RESTRICT go = t->go(); const nl_double * const RESTRICT Idr = t->Idr(); const nl_double * const * RESTRICT other_cur_analog = t->connected_net_V(); + const unsigned * const RESTRICT tcr = m_term_cr[k].data(); -#if (0 ||NL_USE_SSE) - __m128d mg = _mm_set_pd(0.0, 0.0); - __m128d mr = _mm_set_pd(0.0, 0.0); - unsigned i = 0; - for (; i < term_count - 1; i+=2) - { - mg = _mm_add_pd(mg, _mm_loadu_pd(>[i])); - mr = _mm_add_pd(mr, _mm_loadu_pd(&Idr[i])); - } - gtot_t = _mm_cvtsd_f64(mg) + _mm_cvtsd_f64(_mm_unpackhi_pd(mg,mg)); - RHS_t = _mm_cvtsd_f64(mr) + _mm_cvtsd_f64(_mm_unpackhi_pd(mr,mr)); - for (; i < term_count; i++) - { - gtot_t += gt[i]; - RHS_t += Idr[i]; - } -#else - for (unsigned i = 0; i < term_count; i++) +#if 0 + for (std::size_t i = 0; i < term_count; i++) { gtot_t += gt[i]; RHS_t += Idr[i]; } -#endif + for (std::size_t i = railstart; i < term_count; i++) RHS_t += go[i] * *other_cur_analog[i]; RHS[k] = RHS_t; // add diagonal element - m_A[mat.diag[k]] = gtot_t; + mat.A[mat.diag[k]] = gtot_t; - for (unsigned i = 0; i < railstart; i++) + for (std::size_t i = 0; i < railstart; i++) + mat.A[tcr[i]] -= go[i]; + } +#else + for (std::size_t i = 0; i < railstart; i++) { - const unsigned pi = m_term_cr[k][i]; - m_A[pi] -= go[i]; + mat.A[tcr[i]] -= go[i]; + gtot_t = gtot_t + gt[i]; + RHS_t = RHS_t + Idr[i]; } + + for (std::size_t i = railstart; i < term_count; i++) + { + RHS_t += (Idr[i] + go[i] * *other_cur_analog[i]); + gtot_t += gt[i]; + } + + RHS[k] = RHS_t; + mat.A[mat.diag[k]] += gtot_t; } - mat.ia[iN] = mat.nz_num; +#endif + mat.ia[iN] = static_cast<mattype>(mat.nz_num); /* now solve it */ if (m_proc != nullptr) { //static_solver(m_A, RHS); - m_proc(m_A, RHS); + m_proc(mat.A, RHS, new_V); } else { - for (unsigned i = 0; i < iN - 1; i++) + for (std::size_t i = 0; i < iN - 1; i++) { const auto &nzbd = this->m_terms[i]->m_nzbd; if (nzbd.size() > 0) { - unsigned pi = mat.diag[i]; - const nl_double f = 1.0 / m_A[pi++]; - const unsigned piie = mat.ia[i+1]; + std::size_t pi = mat.diag[i]; + const nl_double f = 1.0 / mat.A[pi++]; + const std::size_t piie = mat.ia[i+1]; - for (auto & j : nzbd) + for (std::size_t j : nzbd) // for (std::size_t j = i + 1; j < iN; j++) { // proceed to column i //__builtin_prefetch(&m_A[mat.diag[j+1]], 1); - unsigned pj = mat.ia[j]; + std::size_t pj = mat.ia[j]; while (mat.ja[pj] < i) pj++; - const nl_double f1 = - m_A[pj++] * f; + const nl_double f1 = - mat.A[pj++] * f; // subtract row i from j */ - for (unsigned pii = pi; pii<piie; ) + for (std::size_t pii = pi; pii<piie; ) { while (mat.ja[pj] < mat.ja[pii]) pj++; - m_A[pj++] += m_A[pii++] * f1; + mat.A[pj++] += mat.A[pii++] * f1; } RHS[j] += f1 * RHS[i]; } } } - } - - /* backward substitution - * - */ + /* backward substitution + * + */ - /* row n-1 */ - new_V[iN - 1] = RHS[iN - 1] / m_A[mat.diag[iN - 1]]; + /* row n-1 */ + new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]]; - for (unsigned j = iN - 1; j-- > 0;) - { - //__builtin_prefetch(&new_V[j-1], 1); - //if (j>0)__builtin_prefetch(&m_A[mat.diag[j-1]], 0); -#if (NL_USE_SSE) - __m128d tmp = _mm_set_pd1(0.0); - const unsigned e = mat.ia[j+1]; - unsigned pk = mat.diag[j] + 1; - for (; pk < e - 1; pk+=2) - { - //tmp += m_A[pk] * new_V[mat.ja[pk]]; - tmp = _mm_add_pd(tmp, _mm_mul_pd(_mm_set_pd(m_A[pk], m_A[pk+1]), - _mm_set_pd(new_V[mat.ja[pk]], new_V[mat.ja[pk+1]]))); - } - double tmpx = _mm_cvtsd_f64(tmp) + _mm_cvtsd_f64(_mm_unpackhi_pd(tmp,tmp)); - for (; pk < e; pk++) - { - tmpx += m_A[pk] * new_V[mat.ja[pk]]; - } - new_V[j] = (RHS[j] - tmpx) / m_A[mat.diag[j]]; -#else - double tmp = 0; - const unsigned e = mat.ia[j+1]; - for (unsigned pk = mat.diag[j] + 1; pk < e; pk++) + for (std::size_t j = iN - 1; j-- > 0;) { - tmp += m_A[pk] * new_V[mat.ja[pk]]; + //__builtin_prefetch(&new_V[j-1], 1); + //if (j>0)__builtin_prefetch(&m_A[mat.diag[j-1]], 0); + double tmp = 0; + auto jdiag = mat.diag[j]; + const std::size_t e = mat.ia[j+1]; + for (std::size_t pk = jdiag + 1; pk < e; pk++) + { + tmp += mat.A[pk] * new_V[mat.ja[pk]]; + } + new_V[j] = (RHS[j] - tmp) / mat.A[jdiag]; } - new_V[j] = (RHS[j] - tmp) / m_A[mat.diag[j]]; -#endif } + this->m_stat_calculations++; if (newton_raphson) diff --git a/src/lib/netlist/solver/nld_ms_gmres.h b/src/lib/netlist/solver/nld_ms_gmres.h index 0c5a5e6228f..a97de6a2446 100644 --- a/src/lib/netlist/solver/nld_ms_gmres.h +++ b/src/lib/netlist/solver/nld_ms_gmres.h @@ -23,16 +23,17 @@ namespace netlist { namespace devices { -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_GMRES_t: public matrix_solver_direct_t<m_N, storage_N> { public: - matrix_solver_GMRES_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const unsigned size) + matrix_solver_GMRES_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size) : matrix_solver_direct_t<m_N, storage_N>(anetlist, name, matrix_solver_t::ASCENDING, params, size) , m_use_iLU_preconditioning(true) , m_use_more_precise_stop_condition(false) , m_accuracy_mult(1.0) + , mat(size) { } @@ -45,7 +46,10 @@ public: private: - unsigned solve_ilu_gmres(nl_double * RESTRICT x, const nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy); + //typedef typename mat_cr_t<storage_N>::type mattype; + typedef typename mat_cr_t<storage_N>::index_type mattype; + + unsigned solve_ilu_gmres(nl_double (& RESTRICT x)[storage_N], const nl_double * RESTRICT rhs, const unsigned restart_max, const std::size_t mr, nl_double accuracy); std::vector<unsigned> m_term_cr[storage_N]; @@ -55,7 +59,6 @@ private: mat_cr_t<storage_N> mat; - nl_double m_A[storage_N * storage_N]; nl_double m_LU[storage_N * storage_N]; nl_double m_c[storage_N + 1]; /* mr + 1 */ @@ -71,22 +74,22 @@ private: // matrix_solver - GMRES // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_GMRES_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { matrix_solver_direct_t<m_N, storage_N>::vsetup(nets); - unsigned nz = 0; - const unsigned iN = this->N(); + mattype nz = 0; + const std::size_t iN = this->N(); - for (unsigned k=0; k<iN; k++) + for (std::size_t k=0; k<iN; k++) { - terms_for_net_t * RESTRICT row = this->m_terms[k]; + terms_for_net_t * RESTRICT row = this->m_terms[k].get(); mat.ia[k] = nz; - for (unsigned j=0; j<row->m_nz.size(); j++) + for (std::size_t j=0; j<row->m_nz.size(); j++) { - mat.ja[nz] = row->m_nz[j]; + mat.ja[nz] = static_cast<mattype>(row->m_nz[j]); if (row->m_nz[j] == k) mat.diag[k] = nz; nz++; @@ -110,10 +113,10 @@ void matrix_solver_GMRES_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) mat.nz_num = nz; } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_GMRES_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { - const unsigned iN = this->N(); + const std::size_t iN = this->N(); /* ideally, we could get an estimate for the spectral radius of * Inv(D - L) * U @@ -127,10 +130,9 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::vsolve_non_dynamic(const bool ne nl_double RHS[storage_N]; nl_double new_V[storage_N]; - for (unsigned i=0, e=mat.nz_num; i<e; i++) - m_A[i] = 0.0; + mat.set_scalar(0.0); - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { nl_double gtot_t = 0.0; nl_double RHS_t = 0.0; @@ -142,7 +144,7 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::vsolve_non_dynamic(const bool ne const nl_double * const RESTRICT Idr = this->m_terms[k]->Idr(); const nl_double * const * RESTRICT other_cur_analog = this->m_terms[k]->connected_net_V(); - new_V[k] = this->m_nets[k]->m_cur_Analog; + new_V[k] = this->m_nets[k]->Q_Analog(); for (std::size_t i = 0; i < term_count; i++) { @@ -156,24 +158,24 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::vsolve_non_dynamic(const bool ne RHS[k] = RHS_t; // add diagonal element - m_A[mat.diag[k]] = gtot_t; + mat.A[mat.diag[k]] = gtot_t; for (std::size_t i = 0; i < railstart; i++) { - const unsigned pi = m_term_cr[k][i]; - m_A[pi] -= go[i]; + const std::size_t pi = m_term_cr[k][i]; + mat.A[pi] -= go[i]; } } - mat.ia[iN] = mat.nz_num; + mat.ia[iN] = static_cast<mattype>(mat.nz_num); const nl_double accuracy = this->m_params.m_accuracy; - unsigned mr = iN; + std::size_t mr = iN; if (iN > 3 ) mr = static_cast<unsigned>(std::sqrt(iN) * 2.0); unsigned iter = std::max(1u, this->m_params.m_gs_loops); - unsigned gsl = solve_ilu_gmres(new_V, RHS, iter, mr, accuracy); - unsigned failed = mr * iter; + unsigned gsl = solve_ilu_gmres(new_V, RHS, iter, static_cast<unsigned>(mr), accuracy); + unsigned failed = static_cast<unsigned>(mr) * iter; this->m_iterative_total += gsl; this->m_stat_calculations++; @@ -200,7 +202,7 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::vsolve_non_dynamic(const bool ne } template <typename T> -inline void givens_mult( const T & c, const T & s, T & g0, T & g1 ) +inline static void givens_mult( const T c, const T s, T & g0, T & g1 ) { const T tg0 = c * g0 - s * g1; const T tg1 = s * g0 + c * g1; @@ -209,8 +211,8 @@ inline void givens_mult( const T & c, const T & s, T & g0, T & g1 ) g1 = tg1; } -template <unsigned m_N, unsigned storage_N> -unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RESTRICT x, const nl_double * RESTRICT rhs, const unsigned restart_max, const unsigned mr, nl_double accuracy) +template <std::size_t m_N, std::size_t storage_N> +unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double (& RESTRICT x)[storage_N], const nl_double * RESTRICT rhs, const unsigned restart_max, const std::size_t mr, nl_double accuracy) { /*------------------------------------------------------------------------- * The code below was inspired by code published by John Burkardt under @@ -237,10 +239,10 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RES unsigned itr_used = 0; double rho_delta = 0.0; - const unsigned n = this->N(); + const std::size_t n = this->N(); if (m_use_iLU_preconditioning) - mat.incomplete_LU_factorization(m_A, m_LU); + mat.incomplete_LU_factorization(m_LU); if (m_use_more_precise_stop_condition) { @@ -258,7 +260,8 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RES nl_double t[storage_N]; nl_double Ax[storage_N]; vec_set(n, accuracy, t); - mat.mult_vec(m_A, t, Ax); + mat.mult_vec(t, Ax); + mat.solveLUx(m_LU, Ax); const nl_double rho_to_accuracy = std::sqrt(vecmult2(n, Ax)) / accuracy; @@ -270,14 +273,13 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RES for (unsigned itr = 0; itr < restart_max; itr++) { - unsigned last_k = mr; - nl_double mu; + std::size_t last_k = mr; nl_double rho; nl_double Ax[storage_N]; nl_double residual[storage_N]; - mat.mult_vec(m_A, x, Ax); + mat.mult_vec(x, Ax); vec_sub(n, rhs, Ax, residual); @@ -288,24 +290,27 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RES rho = std::sqrt(vecmult2(n, residual)); - vec_mult_scalar(n, residual, NL_FCONST(1.0) / rho, m_v[0]); + if (rho < rho_delta) + return itr_used + 1; vec_set(mr+1, NL_FCONST(0.0), m_g); m_g[0] = rho; - for (unsigned i = 0; i < mr; i++) + for (std::size_t i = 0; i < mr; i++) vec_set(mr + 1, NL_FCONST(0.0), m_ht[i]); - for (unsigned k = 0; k < mr; k++) + vec_mult_scalar(n, residual, NL_FCONST(1.0) / rho, m_v[0]); + + for (std::size_t k = 0; k < mr; k++) { - const unsigned k1 = k + 1; + const std::size_t k1 = k + 1; - mat.mult_vec(m_A, m_v[k], m_v[k1]); + mat.mult_vec(m_v[k], m_v[k1]); if (m_use_iLU_preconditioning) mat.solveLUx(m_LU, m_v[k1]); - for (unsigned j = 0; j <= k; j++) + for (std::size_t j = 0; j <= k; j++) { m_ht[j][k] = vecmult(n, m_v[k1], m_v[j]); vec_add_mult_scalar(n, m_v[j], -m_ht[j][k], m_v[k1]); @@ -315,13 +320,13 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RES if (m_ht[k1][k] != 0.0) vec_scale(n, m_v[k1], NL_FCONST(1.0) / m_ht[k1][k]); - for (unsigned j = 0; j < k; j++) + for (std::size_t j = 0; j < k; j++) givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]); - mu = std::hypot(m_ht[k][k], m_ht[k1][k]); + const nl_double mu = 1.0 / std::hypot(m_ht[k][k], m_ht[k1][k]); - m_c[k] = m_ht[k][k] / mu; - m_s[k] = -m_ht[k1][k] / mu; + m_c[k] = m_ht[k][k] * mu; + m_s[k] = -m_ht[k1][k] * mu; m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[k1][k]; m_ht[k1][k] = 0.0; @@ -344,17 +349,17 @@ unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double * RES /* Solve the system H * y = g */ /* x += m_v[j] * m_y[j] */ - for (unsigned i = last_k + 1; i-- > 0;) + for (std::size_t i = last_k + 1; i-- > 0;) { double tmp = m_g[i]; - for (unsigned j = i + 1; j <= last_k; j++) + for (std::size_t j = i + 1; j <= last_k; j++) { tmp -= m_ht[i][j] * m_y[j]; } m_y[i] = tmp / m_ht[i][i]; } - for (unsigned i = 0; i <= last_k; i++) + for (std::size_t i = 0; i <= last_k; i++) vec_add_mult_scalar(n, m_v[i], m_y[i], x); #if 1 diff --git a/src/lib/netlist/solver/nld_ms_sm.h b/src/lib/netlist/solver/nld_ms_sm.h index 2f3597f3a89..b87f5bcc835 100644 --- a/src/lib/netlist/solver/nld_ms_sm.h +++ b/src/lib/netlist/solver/nld_ms_sm.h @@ -47,7 +47,7 @@ namespace netlist //#define nl_ext_double long double // slightly slower #define nl_ext_double nl_double -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_sm_t: public matrix_solver_t { friend class matrix_solver_t; @@ -55,7 +55,7 @@ class matrix_solver_sm_t: public matrix_solver_t public: matrix_solver_sm_t(netlist_t &anetlist, const pstring &name, - const solver_parameters_t *params, const unsigned size); + const solver_parameters_t *params, const std::size_t size); virtual ~matrix_solver_sm_t(); @@ -66,7 +66,7 @@ protected: virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; unsigned solve_non_dynamic(const bool newton_raphson); - inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; } void LE_invert(); @@ -103,7 +103,7 @@ private: //nl_ext_double m_RHSx[storage_N]; - const unsigned m_dim; + const std::size_t m_dim; }; @@ -111,20 +111,17 @@ private: // matrix_solver_direct // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_sm_t<m_N, storage_N>::~matrix_solver_sm_t() { #if (NL_USE_DYNAMIC_ALLOCATION) - pfree_array(m_A); + plib::pfree_array(m_A); #endif } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_sm_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { - if (m_dim < nets.size()) - log().fatal("Dimension {1} less than {2}", m_dim, nets.size()); - matrix_solver_t::setup_base(nets); netlist().save(*this, m_last_RHS, "m_last_RHS"); @@ -135,14 +132,14 @@ void matrix_solver_sm_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_sm_t<m_N, storage_N>::LE_invert() { - const unsigned kN = N(); + const std::size_t kN = N(); - for (unsigned i = 0; i < kN; i++) + for (std::size_t i = 0; i < kN; i++) { - for (unsigned j = 0; j < kN; j++) + for (std::size_t j = 0; j < kN; j++) { W(i,j) = lA(i,j) = A(i,j); Ainv(i,j) = 0.0; @@ -150,7 +147,7 @@ void matrix_solver_sm_t<m_N, storage_N>::LE_invert() Ainv(i,i) = 1.0; } /* down */ - for (unsigned i = 0; i < kN; i++) + for (std::size_t i = 0; i < kN; i++) { /* FIXME: Singular matrix? */ const nl_double f = 1.0 / W(i,i); @@ -169,28 +166,28 @@ void matrix_solver_sm_t<m_N, storage_N>::LE_invert() { for (std::size_t k = 0; k < e; k++) W(j,p[k]) += W(i,p[k]) * f1; - for (unsigned k = 0; k <= i; k ++) + for (std::size_t k = 0; k <= i; k ++) Ainv(j,k) += Ainv(i,k) * f1; } } } /* up */ - for (unsigned i = kN; i-- > 0; ) + for (std::size_t i = kN; i-- > 0; ) { /* FIXME: Singular matrix? */ const nl_double f = 1.0 / W(i,i); - for (unsigned j = i; j-- > 0; ) + for (std::size_t j = i; j-- > 0; ) { const nl_double f1 = - W(j,i) * f; if (f1 != 0.0) { - for (unsigned k = i; k < kN; k++) + for (std::size_t k = i; k < kN; k++) W(j,k) += W(i,k) * f1; - for (unsigned k = 0; k < kN; k++) + for (std::size_t k = 0; k < kN; k++) Ainv(j,k) += Ainv(i,k) * f1; } } - for (unsigned k = 0; k < kN; k++) + for (std::size_t k = 0; k < kN; k++) { Ainv(i,k) *= f; lAinv(i,k) = Ainv(i,k); @@ -198,27 +195,27 @@ void matrix_solver_sm_t<m_N, storage_N>::LE_invert() } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> template <typename T> void matrix_solver_sm_t<m_N, storage_N>::LE_compute_x( T * RESTRICT x) { - const unsigned kN = N(); + const std::size_t kN = N(); - for (unsigned i=0; i<kN; i++) + for (std::size_t i=0; i<kN; i++) x[i] = 0.0; - for (unsigned k=0; k<kN; k++) + for (std::size_t k=0; k<kN; k++) { const nl_double f = RHS(k); - for (unsigned i=0; i<kN; i++) + for (std::size_t i=0; i<kN; i++) x[i] += Ainv(i,k) * f; } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_sm_t<m_N, storage_N>::solve_non_dynamic(const bool newton_raphson) { static const bool incremental = true; @@ -308,29 +305,26 @@ unsigned matrix_solver_sm_t<m_N, storage_N>::solve_non_dynamic(const bool newton } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> inline unsigned matrix_solver_sm_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { build_LE_A<matrix_solver_sm_t>(); build_LE_RHS<matrix_solver_sm_t>(); - for (unsigned i=0, iN=N(); i < iN; i++) + for (std::size_t i=0, iN=N(); i < iN; i++) m_last_RHS[i] = RHS(i); this->m_stat_calculations++; return this->solve_non_dynamic(newton_raphson); } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_sm_t<m_N, storage_N>::matrix_solver_sm_t(netlist_t &anetlist, const pstring &name, - const solver_parameters_t *params, const unsigned size) + const solver_parameters_t *params, const std::size_t size) : matrix_solver_t(anetlist, name, NOSORT, params) , m_dim(size) { -#if (NL_USE_DYNAMIC_ALLOCATION) - m_A = palloc_array(nl_ext_double, N() * m_pitch); -#endif - for (unsigned k = 0; k < N(); k++) + for (std::size_t k = 0; k < N(); k++) { m_last_RHS[k] = 0.0; } diff --git a/src/lib/netlist/solver/nld_ms_sor.h b/src/lib/netlist/solver/nld_ms_sor.h index 15f56ee264b..dc3a5d1821c 100644 --- a/src/lib/netlist/solver/nld_ms_sor.h +++ b/src/lib/netlist/solver/nld_ms_sor.h @@ -21,12 +21,12 @@ namespace netlist { namespace devices { -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_SOR_t: public matrix_solver_direct_t<m_N, storage_N> { public: - matrix_solver_SOR_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const unsigned size) + matrix_solver_SOR_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size) : matrix_solver_direct_t<m_N, storage_N>(anetlist, name, matrix_solver_t::ASCENDING, params, size) , m_lp_fact(*this, "m_lp_fact", 0) { @@ -46,16 +46,16 @@ private: // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_SOR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { matrix_solver_direct_t<m_N, storage_N>::vsetup(nets); } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { - const unsigned iN = this->N(); + const std::size_t iN = this->N(); bool resched = false; unsigned resched_cnt = 0; @@ -74,7 +74,7 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt nl_double RHS[storage_N]; nl_double new_V[storage_N]; - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { nl_double gtot_t = 0.0; nl_double gabs_t = 0.0; @@ -86,7 +86,7 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt const nl_double * const RESTRICT Idr = this->m_terms[k]->Idr(); const nl_double * const *other_cur_analog = this->m_terms[k]->connected_net_V(); - new_V[k] = this->m_nets[k]->m_cur_Analog; + new_V[k] = this->m_nets[k]->Q_Analog(); for (std::size_t i = 0; i < term_count; i++) { @@ -125,17 +125,10 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt const nl_double accuracy = this->m_params.m_accuracy; - /* uncommenting the line below will force dynamic updates every X iterations - * althought the system has not converged yet. This is a proof of concept, - * - */ - const bool interleaved_dynamic_updates = false; - //const bool interleaved_dynamic_updates = newton_raphson; - do { resched = false; nl_double err = 0; - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { const int * RESTRICT net_other = this->m_terms[k]->connected_net_idx(); const std::size_t railstart = this->m_terms[k]->m_railstart; @@ -156,29 +149,20 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt resched_cnt++; //} while (resched && (resched_cnt < this->m_params.m_gs_loops)); - } while (resched && ((!interleaved_dynamic_updates && resched_cnt < this->m_params.m_gs_loops) || (interleaved_dynamic_updates && resched_cnt < 5 ))); + } while (resched && ((resched_cnt < this->m_params.m_gs_loops))); this->m_iterative_total += resched_cnt; + this->m_stat_calculations++; - if (resched && !interleaved_dynamic_updates) + if (resched) { // Fallback to direct solver ... this->m_iterative_fail++; return matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(newton_raphson); } - this->m_stat_calculations++; - - if (interleaved_dynamic_updates) - { - for (unsigned k = 0; k < iN; k++) - this->m_nets[k]->m_cur_Analog += 1.0 * (new_V[k] - this->m_nets[k]->m_cur_Analog); - } - else - { - for (unsigned k = 0; k < iN; k++) - this->m_nets[k]->m_cur_Analog = new_V[k]; - } + for (std::size_t k = 0; k < iN; k++) + this->m_nets[k]->set_Q_Analog(new_V[k]); return resched_cnt; } diff --git a/src/lib/netlist/solver/nld_ms_sor_mat.h b/src/lib/netlist/solver/nld_ms_sor_mat.h index 43b6eeeafb5..265ef821957 100644 --- a/src/lib/netlist/solver/nld_ms_sor_mat.h +++ b/src/lib/netlist/solver/nld_ms_sor_mat.h @@ -22,14 +22,14 @@ namespace netlist { namespace devices { -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_SOR_mat_t: public matrix_solver_direct_t<m_N, storage_N> { friend class matrix_solver_t; public: - matrix_solver_SOR_mat_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const unsigned size) + matrix_solver_SOR_mat_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, std::size_t size) : matrix_solver_direct_t<m_N, storage_N>(anetlist, name, matrix_solver_t::DESCENDING, params, size) , m_Vdelta(*this, "m_Vdelta", 0.0) , m_omega(*this, "m_omega", params->m_gs_sor) @@ -58,7 +58,7 @@ private: // matrix_solver - Gauss - Seidel // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_SOR_mat_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { matrix_solver_direct_t<m_N, storage_N>::vsetup(nets); @@ -113,7 +113,7 @@ nl_double matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve() } #endif -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { /* The matrix based code looks a lot nicer but actually is 30% slower than @@ -123,7 +123,7 @@ unsigned matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve_non_dynamic(const bool nl_double new_v[storage_N] = { 0.0 }; - const unsigned iN = this->N(); + const std::size_t iN = this->N(); matrix_solver_t::build_LE_A<matrix_solver_SOR_mat_t>(); matrix_solver_t::build_LE_RHS<matrix_solver_SOR_mat_t>(); @@ -169,14 +169,14 @@ unsigned matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve_non_dynamic(const bool } #endif - for (unsigned k = 0; k < iN; k++) - new_v[k] = this->m_nets[k]->m_cur_Analog; + for (std::size_t k = 0; k < iN; k++) + new_v[k] = this->m_nets[k]->Q_Analog(); do { resched = false; nl_double cerr = 0.0; - for (unsigned k = 0; k < iN; k++) + for (std::size_t k = 0; k < iN; k++) { nl_double Idrive = 0; @@ -199,10 +199,12 @@ unsigned matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve_non_dynamic(const bool } while (resched && (resched_cnt < this->m_params.m_gs_loops)); this->m_stat_calculations++; + this->m_iterative_total += resched_cnt; this->m_gs_total += resched_cnt; if (resched) { + this->m_iterative_fail++; //this->netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS"); this->m_gs_fail++; diff --git a/src/lib/netlist/solver/nld_ms_w.h b/src/lib/netlist/solver/nld_ms_w.h index e644ce40085..c2e016e4dec 100644 --- a/src/lib/netlist/solver/nld_ms_w.h +++ b/src/lib/netlist/solver/nld_ms_w.h @@ -54,13 +54,13 @@ namespace netlist //#define nl_ext_double long double // slightly slower #define nl_ext_double nl_double -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_w_t: public matrix_solver_t { friend class matrix_solver_t; public: - matrix_solver_w_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const unsigned size); + matrix_solver_w_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size); virtual ~matrix_solver_w_t(); @@ -71,7 +71,7 @@ protected: virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; unsigned solve_non_dynamic(const bool newton_raphson); - inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; } void LE_invert(); @@ -115,7 +115,7 @@ private: //nl_ext_double m_RHSx[storage_N]; - const unsigned m_dim; + const std::size_t m_dim; }; @@ -123,17 +123,14 @@ private: // matrix_solver_direct // ---------------------------------------------------------------------------------------- -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_w_t<m_N, storage_N>::~matrix_solver_w_t() { } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_w_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) { - if (m_dim < nets.size()) - log().fatal("Dimension {1} less than {2}", m_dim, nets.size()); - matrix_solver_t::setup_base(nets); netlist().save(*this, m_last_RHS, "m_last_RHS"); @@ -144,14 +141,14 @@ void matrix_solver_w_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> void matrix_solver_w_t<m_N, storage_N>::LE_invert() { - const unsigned kN = N(); + const std::size_t kN = N(); - for (unsigned i = 0; i < kN; i++) + for (std::size_t i = 0; i < kN; i++) { - for (unsigned j = 0; j < kN; j++) + for (std::size_t j = 0; j < kN; j++) { W(i,j) = lA(i,j) = A(i,j); Ainv(i,j) = 0.0; @@ -159,7 +156,7 @@ void matrix_solver_w_t<m_N, storage_N>::LE_invert() Ainv(i,i) = 1.0; } /* down */ - for (unsigned i = 0; i < kN; i++) + for (std::size_t i = 0; i < kN; i++) { /* FIXME: Singular matrix? */ const nl_double f = 1.0 / W(i,i); @@ -170,63 +167,63 @@ void matrix_solver_w_t<m_N, storage_N>::LE_invert() const auto * RESTRICT const pb = m_terms[i]->m_nzbd.data(); const size_t eb = m_terms[i]->m_nzbd.size(); - for (unsigned jb = 0; jb < eb; jb++) + for (std::size_t jb = 0; jb < eb; jb++) { const auto j = pb[jb]; const nl_double f1 = - W(j,i) * f; if (f1 != 0.0) { - for (unsigned k = 0; k < e; k++) + for (std::size_t k = 0; k < e; k++) W(j,p[k]) += W(i,p[k]) * f1; - for (unsigned k = 0; k <= i; k ++) + for (std::size_t k = 0; k <= i; k ++) Ainv(j,k) += Ainv(i,k) * f1; } } } /* up */ - for (unsigned i = kN; i-- > 0; ) + for (std::size_t i = kN; i-- > 0; ) { /* FIXME: Singular matrix? */ const nl_double f = 1.0 / W(i,i); - for (unsigned j = i; j-- > 0; ) + for (std::size_t j = i; j-- > 0; ) { const nl_double f1 = - W(j,i) * f; if (f1 != 0.0) { - for (unsigned k = i; k < kN; k++) + for (std::size_t k = i; k < kN; k++) W(j,k) += W(i,k) * f1; - for (unsigned k = 0; k < kN; k++) + for (std::size_t k = 0; k < kN; k++) Ainv(j,k) += Ainv(i,k) * f1; } } - for (unsigned k = 0; k < kN; k++) + for (std::size_t k = 0; k < kN; k++) { Ainv(i,k) *= f; } } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> template <typename T> void matrix_solver_w_t<m_N, storage_N>::LE_compute_x( T * RESTRICT x) { - const unsigned kN = N(); + const std::size_t kN = N(); - for (unsigned i=0; i<kN; i++) + for (std::size_t i=0; i<kN; i++) x[i] = 0.0; - for (unsigned k=0; k<kN; k++) + for (std::size_t k=0; k<kN; k++) { const nl_double f = RHS(k); - for (unsigned i=0; i<kN; i++) + for (std::size_t i=0; i<kN; i++) x[i] += Ainv(i,k) * f; } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_raphson) { const auto iN = N(); @@ -372,27 +369,27 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_ } } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> inline unsigned matrix_solver_w_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) { build_LE_A<matrix_solver_w_t>(); build_LE_RHS<matrix_solver_w_t>(); - for (unsigned i=0, iN=N(); i < iN; i++) + for (std::size_t i=0, iN=N(); i < iN; i++) m_last_RHS[i] = RHS(i); this->m_stat_calculations++; return this->solve_non_dynamic(newton_raphson); } -template <unsigned m_N, unsigned storage_N> +template <std::size_t m_N, std::size_t storage_N> matrix_solver_w_t<m_N, storage_N>::matrix_solver_w_t(netlist_t &anetlist, const pstring &name, - const solver_parameters_t *params, const unsigned size) + const solver_parameters_t *params, const std::size_t size) : matrix_solver_t(anetlist, name, NOSORT, params) ,m_cnt(0) , m_dim(size) { - for (unsigned k = 0; k < N(); k++) + for (std::size_t k = 0; k < N(); k++) { m_last_RHS[k] = 0.0; } diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp index 52cccfd8419..d2ecf3c5bd2 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -10,34 +10,37 @@ */ #if 0 -#pragma GCC optimize "-ffast-math" -#pragma GCC optimize "-fstrict-aliasing" -#pragma GCC optimize "-ftree-vectorizer-verbose=2" -#pragma GCC optimize "-fopt-info-vec" -#pragma GCC optimize "-fopt-info-vec-missed" -//#pragma GCC optimize "-ftree-parallelize-loops=4" -#pragma GCC optimize "-funroll-loops" -#pragma GCC optimize "-funswitch-loops" -#pragma GCC optimize "-fvariable-expansion-in-unroller" -#pragma GCC optimize "-funsafe-loop-optimizations" -#pragma GCC optimize "-fvect-cost-model" -#pragma GCC optimize "-fvariable-expansion-in-unroller" -#pragma GCC optimize "-ftree-loop-if-convert-stores" -#pragma GCC optimize "-ftree-loop-distribution" -#pragma GCC optimize "-ftree-loop-im" -#pragma GCC optimize "-ftree-loop-ivcanon" -#pragma GCC optimize "-fivopts" +#pragma GCC optimize "fast-math" +#pragma GCC optimize "strict-aliasing" +#pragma GCC optimize "tree-vectorize" +#pragma GCC optimize "tree-vectorizer-verbose=7" +#pragma GCC optimize "opt-info-vec" +#pragma GCC optimize "opt-info-vec-missed" +//#pragma GCC optimize "tree-parallelize-loops=4" +#pragma GCC optimize "unroll-loops" +#pragma GCC optimize "unswitch-loops" +#pragma GCC optimize "variable-expansion-in-unroller" +#pragma GCC optimize "unsafe-loop-optimizations" +#pragma GCC optimize "vect-cost-model" +#pragma GCC optimize "variable-expansion-in-unroller" +#pragma GCC optimize "tree-loop-if-convert-stores" +#pragma GCC optimize "tree-loop-distribution" +#pragma GCC optimize "tree-loop-im" +#pragma GCC optimize "tree-loop-ivcanon" +#pragma GCC optimize "ivopts" #endif -#include <iostream> #include <algorithm> +#include <cmath> // <<= needed by windows build + #include "nl_lists.h" #if HAS_OPENMP #include "omp.h" #endif -#include "plib/putil.h" +#include "nl_factory.h" + #include "nld_solver.h" #include "nld_matrix_solver.h" @@ -107,6 +110,10 @@ NETLIB_UPDATE(solver) ATTR_UNUSED const netlist_time ts = m_mat_solvers[i]->solve(); } } + + for (auto & solver : m_mat_solvers) + if (solver->has_timestep_devices() || force_solve) + solver->update_inputs(); } else for (int i = 0; i < t_cnt; i++) @@ -114,12 +121,16 @@ NETLIB_UPDATE(solver) { // Ignore return value ATTR_UNUSED const netlist_time ts = m_mat_solvers[i]->solve(); + solver->update_inputs(); } #else for (auto & solver : m_mat_solvers) if (solver->has_timestep_devices() || force_solve) + { // Ignore return value ATTR_UNUSED const netlist_time ts = solver->solve(); + solver->update_inputs(); + } #endif /* step circuit */ @@ -131,65 +142,65 @@ NETLIB_UPDATE(solver) } template <class C> -std::unique_ptr<matrix_solver_t> create_it(netlist_t &nl, pstring name, solver_parameters_t ¶ms, unsigned size) +std::unique_ptr<matrix_solver_t> create_it(netlist_t &nl, pstring name, solver_parameters_t ¶ms, std::size_t size) { typedef C solver; return plib::make_unique<solver>(nl, name, ¶ms, size); } -template <int m_N, int storage_N> -std::unique_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(unsigned size, const bool use_specific) +template <std::size_t m_N, std::size_t storage_N> +std::unique_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername) { - pstring solvername = plib::pfmt("Solver_{1}")(m_mat_solvers.size()); - if (use_specific && m_N == 1) - return plib::make_unique<matrix_solver_direct1_t>(netlist(), solvername, &m_params); - else if (use_specific && m_N == 2) - return plib::make_unique<matrix_solver_direct2_t>(netlist(), solvername, &m_params); - else + if (pstring("SOR_MAT").equals(m_method())) { - if (pstring("SOR_MAT").equals(m_method())) - { - return create_it<matrix_solver_SOR_mat_t<m_N, storage_N>>(netlist(), solvername, m_params, size); - //typedef matrix_solver_SOR_mat_t<m_N,storage_N> solver_sor_mat; - //return plib::make_unique<solver_sor_mat>(netlist(), solvername, &m_params, size); - } - else if (pstring("MAT_CR").equals(m_method())) + return create_it<matrix_solver_SOR_mat_t<m_N, storage_N>>(netlist(), solvername, m_params, size); + //typedef matrix_solver_SOR_mat_t<m_N,storage_N> solver_sor_mat; + //return plib::make_unique<solver_sor_mat>(netlist(), solvername, &m_params, size); + } + else if (pstring("MAT_CR").equals(m_method())) + { + if (size > 0) // GCR always outperforms MAT solver { typedef matrix_solver_GCR_t<m_N,storage_N> solver_mat; return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); } - else if (pstring("MAT").equals(m_method())) + else { typedef matrix_solver_direct_t<m_N,storage_N> solver_mat; return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); } - else if (pstring("SM").equals(m_method())) - { - /* Sherman-Morrison Formula */ - typedef matrix_solver_sm_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); - } - else if (pstring("W").equals(m_method())) - { - /* Woodbury Formula */ - typedef matrix_solver_w_t<m_N,storage_N> solver_mat; - return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); - } - else if (pstring("SOR").equals(m_method())) - { - typedef matrix_solver_SOR_t<m_N,storage_N> solver_GS; - return plib::make_unique<solver_GS>(netlist(), solvername, &m_params, size); - } - else if (pstring("GMRES").equals(m_method())) - { - typedef matrix_solver_GMRES_t<m_N,storage_N> solver_GMRES; - return plib::make_unique<solver_GMRES>(netlist(), solvername, &m_params, size); - } - else - { - netlist().log().fatal("Unknown solver type: {1}\n", m_method()); - return nullptr; - } + } + else if (pstring("MAT").equals(m_method())) + { + typedef matrix_solver_direct_t<m_N,storage_N> solver_mat; + return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); + } + else if (pstring("SM").equals(m_method())) + { + /* Sherman-Morrison Formula */ + typedef matrix_solver_sm_t<m_N,storage_N> solver_mat; + return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); + } + else if (pstring("W").equals(m_method())) + { + /* Woodbury Formula */ + typedef matrix_solver_w_t<m_N,storage_N> solver_mat; + return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); + } + else if (pstring("SOR").equals(m_method())) + { + typedef matrix_solver_SOR_t<m_N,storage_N> solver_GS; + return plib::make_unique<solver_GS>(netlist(), solvername, &m_params, size); + } + else if (pstring("GMRES").equals(m_method())) + { + typedef matrix_solver_GMRES_t<m_N,storage_N> solver_GMRES; + return plib::make_unique<solver_GMRES>(netlist(), solvername, &m_params, size); + } + else + { + log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method()); + return nullptr; } } @@ -214,7 +225,7 @@ struct net_splitter groups.back().push_back(n); for (auto &p : n->m_core_terms) { - if (p->is_type(terminal_t::TERMINAL)) + if (p->is_type(detail::terminal_type::TERMINAL)) { terminal_t *pt = static_cast<terminal_t *>(p); analog_net_t *other_net = &pt->m_otherterm->net(); @@ -275,13 +286,13 @@ void NETLIB_NAME(solver)::post_start() //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::) // Override log statistics - pstring p = plib::util::environment("NL_STATS"); + pstring p = plib::util::environment("NL_STATS", ""); if (p != "") m_params.m_log_stats = p.as_long(); else m_params.m_log_stats = m_log_stats(); - netlist().log().verbose("Scanning net groups ..."); + log().verbose("Scanning net groups ..."); // determine net groups net_splitter splitter; @@ -289,86 +300,103 @@ void NETLIB_NAME(solver)::post_start() splitter.run(netlist()); // setup the solvers - netlist().log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), netlist().m_nets.size()); + log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), netlist().m_nets.size()); for (auto & grp : splitter.groups) { std::unique_ptr<matrix_solver_t> ms; - unsigned net_count = static_cast<unsigned>(grp.size()); + std::size_t net_count = grp.size(); + pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size()); switch (net_count) { #if 1 case 1: - ms = create_solver<1,1>(1, use_specific); + if (use_specific) + ms = plib::make_unique<matrix_solver_direct1_t>(netlist(), sname, &m_params); + else + ms = create_solver<1,1>(1, sname); break; case 2: - ms = create_solver<2,2>(2, use_specific); + if (use_specific) + ms = plib::make_unique<matrix_solver_direct2_t>(netlist(), sname, &m_params); + else + ms = create_solver<2,2>(2, sname); break; case 3: - ms = create_solver<3,3>(3, use_specific); + ms = create_solver<3,3>(3, sname); break; case 4: - ms = create_solver<4,4>(4, use_specific); + ms = create_solver<4,4>(4, sname); break; case 5: - ms = create_solver<5,5>(5, use_specific); + ms = create_solver<5,5>(5, sname); break; case 6: - ms = create_solver<6,6>(6, use_specific); + ms = create_solver<6,6>(6, sname); break; case 7: - ms = create_solver<7,7>(7, use_specific); + ms = create_solver<7,7>(7, sname); break; case 8: - ms = create_solver<8,8>(8, use_specific); + ms = create_solver<8,8>(8, sname); + break; + case 9: + ms = create_solver<9,9>(9, sname); break; case 10: - ms = create_solver<10,10>(10, use_specific); + ms = create_solver<10,10>(10, sname); break; case 11: - ms = create_solver<11,11>(11, use_specific); + ms = create_solver<11,11>(11, sname); break; case 12: - ms = create_solver<12,12>(12, use_specific); + ms = create_solver<12,12>(12, sname); break; case 15: - ms = create_solver<15,15>(15, use_specific); + ms = create_solver<15,15>(15, sname); break; case 31: - ms = create_solver<31,31>(31, use_specific); + ms = create_solver<31,31>(31, sname); + break; + case 35: + ms = create_solver<31,31>(31, sname); break; case 49: - ms = create_solver<49,49>(49, use_specific); + ms = create_solver<49,49>(49, sname); break; #if 0 case 87: - ms = create_solver<87,87>(87, use_specific); + ms = create_solver<87,87>(87, sname); break; #endif #endif default: - netlist().log().warning("No specific solver found for netlist of size {1}", net_count); - if (net_count <= 16) + log().warning(MW_1_NO_SPECIFIC_SOLVER, net_count); + if (net_count <= 8) + { + ms = create_solver<0, 8>(net_count, sname); + } + else if (net_count <= 16) { - ms = create_solver<0,16>(net_count, use_specific); + ms = create_solver<0,16>(net_count, sname); } else if (net_count <= 32) { - ms = create_solver<0,32>(net_count, use_specific); + ms = create_solver<0,32>(net_count, sname); } else if (net_count <= 64) { - ms = create_solver<0,64>(net_count, use_specific); + ms = create_solver<0,64>(net_count, sname); } else if (net_count <= 128) { - ms = create_solver<0,128>(net_count, use_specific); + ms = create_solver<0,128>(net_count, sname); } else { - netlist().log().fatal("Encountered netgroup with > 128 nets"); + log().fatal(MF_1_NETGROUP_SIZE_EXCEEDED_1, 128); ms = nullptr; /* tease compilers */ } @@ -379,16 +407,16 @@ void NETLIB_NAME(solver)::post_start() ms->set_delegate_pointer(); ms->setup(grp); - netlist().log().verbose("Solver {1}", ms->name()); - netlist().log().verbose(" ==> {2} nets", grp.size()); - netlist().log().verbose(" has {1} elements", ms->has_dynamic_devices() ? "dynamic" : "no dynamic"); - netlist().log().verbose(" has {1} elements", ms->has_timestep_devices() ? "timestep" : "no timestep"); + log().verbose("Solver {1}", ms->name()); + log().verbose(" ==> {2} nets", grp.size()); + log().verbose(" has {1} elements", ms->has_dynamic_devices() ? "dynamic" : "no dynamic"); + log().verbose(" has {1} elements", ms->has_timestep_devices() ? "timestep" : "no timestep"); for (auto &n : grp) { - netlist().log().verbose("Net {1}", n->name()); + log().verbose("Net {1}", n->name()); for (const auto &pcore : n->m_core_terms) { - netlist().log().verbose(" {1}", pcore->name()); + log().verbose(" {1}", pcore->name()); } } @@ -396,12 +424,16 @@ void NETLIB_NAME(solver)::post_start() } } -void NETLIB_NAME(solver)::create_solver_code(plib::postream &strm) +void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp) { for (auto & s : m_mat_solvers) - s->create_solver_code(strm); + { + auto r = s->create_solver_code(); + mp[r.first] = r.second; // automatically overwrites identical names + } } + NETLIB_DEVICE_IMPL(solver) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h index e3ba6419f8b..4f6eb2a21d9 100644 --- a/src/lib/netlist/solver/nld_solver.h +++ b/src/lib/netlist/solver/nld_solver.h @@ -8,7 +8,8 @@ #ifndef NLD_SOLVER_H_ #define NLD_SOLVER_H_ -#include "nl_setup.h" +#include <map> + #include "nl_base.h" #include "plib/pstream.h" #include "solver/nld_matrix_solver.h" @@ -17,14 +18,6 @@ #define ATTR_ALIGNED(N) ATTR_ALIGN // ---------------------------------------------------------------------------------------- -// Macros -// ---------------------------------------------------------------------------------------- - -#define SOLVER(name, freq) \ - NET_REGISTER_DEV(SOLVER, name) \ - PARAM(name.FREQ, freq) - -// ---------------------------------------------------------------------------------------- // solver // ---------------------------------------------------------------------------------------- @@ -59,7 +52,7 @@ NETLIB_OBJECT(solver) /* automatic time step */ , m_dynamic_ts(*this, "DYNAMIC_TS", 0) - , m_dynamic_lte(*this, "DYNAMIC_LTE", 5e-5) // diff/timestep + , m_dynamic_lte(*this, "DYNAMIC_LTE", 1e-5) // diff/timestep , m_dynamic_min_ts(*this, "DYNAMIC_MIN_TIMESTEP", 1e-6) // nl_double timestep resolution , m_log_stats(*this, "LOG_STATS", 1) // nl_double timestep resolution @@ -76,7 +69,7 @@ NETLIB_OBJECT(solver) inline nl_double gmin() { return m_gmin(); } - void create_solver_code(plib::postream &strm); + void create_solver_code(std::map<pstring, pstring> &mp); NETLIB_UPDATEI(); NETLIB_RESETI(); @@ -107,8 +100,8 @@ private: solver_parameters_t m_params; - template <int m_N, int storage_N> - std::unique_ptr<matrix_solver_t> create_solver(unsigned size, bool use_specific); + template <std::size_t m_N, std::size_t storage_N> + std::unique_ptr<matrix_solver_t> create_solver(std::size_t size, const pstring &solvername); }; } //namespace devices diff --git a/src/lib/netlist/solver/vector_base.h b/src/lib/netlist/solver/vector_base.h index 3f0c53c8ade..b294eb0ee48 100644..100755 --- a/src/lib/netlist/solver/vector_base.h +++ b/src/lib/netlist/solver/vector_base.h @@ -36,14 +36,14 @@ private: #endif template<typename T> -inline void vec_set (const std::size_t & n, const T &scalar, T * RESTRICT result) +inline static void vec_set (const std::size_t n, const T scalar, T * RESTRICT result) { for ( std::size_t i = 0; i < n; i++ ) result[i] = scalar; } template<typename T> -inline T vecmult (const std::size_t & n, const T * RESTRICT a1, const T * RESTRICT a2 ) +inline static T vecmult (const std::size_t n, const T * RESTRICT a1, const T * RESTRICT a2 ) { T value = 0.0; for ( std::size_t i = 0; i < n; i++ ) @@ -52,7 +52,7 @@ inline T vecmult (const std::size_t & n, const T * RESTRICT a1, const T * RESTRI } template<typename T> -inline T vecmult2 (const std::size_t & n, const T *a1) +inline static T vecmult2 (const std::size_t n, const T *a1) { T value = 0.0; for ( std::size_t i = 0; i < n; i++ ) @@ -63,43 +63,56 @@ inline T vecmult2 (const std::size_t & n, const T *a1) return value; } -template<typename T> -inline void vec_mult_scalar (const std::size_t & n, const T * RESTRICT v, const T & scalar, T * RESTRICT result) +template<typename T, std::size_t N> +inline static void vec_mult_scalar (const std::size_t n, const T (& RESTRICT v)[N], const T & scalar, T (& RESTRICT result)[N]) { - for ( std::size_t i = 0; i < n; i++ ) - { - result[i] = scalar * v[i]; - } + if (n != N) + for ( std::size_t i = 0; i < n; i++ ) + result[i] = scalar * v[i]; + else + for ( std::size_t i = 0; i < N; i++ ) + result[i] = scalar * v[i]; +} + +template<typename T, std::size_t N> +inline static void vec_add_mult_scalar (const std::size_t n, const T (& RESTRICT v)[N], const T scalar, T (& RESTRICT result)[N]) +{ + if (n != N) + for ( std::size_t i = 0; i < n; i++ ) + result[i] = result[i] + scalar * v[i]; + else + for ( std::size_t i = 0; i < N; i++ ) + result[i] = result[i] + scalar * v[i]; } template<typename T> -inline void vec_add_mult_scalar (const std::size_t & n, const T * RESTRICT v, const T scalar, T * RESTRICT result) +inline static void vec_add_mult_scalar_p(const std::size_t & n, const T * RESTRICT v, const T scalar, T * RESTRICT result) { for ( std::size_t i = 0; i < n; i++ ) result[i] += scalar * v[i]; } -inline void vec_add_ip(const std::size_t & n, const double * RESTRICT v, double * RESTRICT result) +inline static void vec_add_ip(const std::size_t n, const double * RESTRICT v, double * RESTRICT result) { for ( std::size_t i = 0; i < n; i++ ) result[i] += v[i]; } template<typename T> -inline void vec_sub(const std::size_t & n, const T * RESTRICT v1, const T * RESTRICT v2, T * RESTRICT result) +inline void vec_sub(const std::size_t n, const T * RESTRICT v1, const T * RESTRICT v2, T * RESTRICT result) { for ( std::size_t i = 0; i < n; i++ ) result[i] = v1[i] - v2[i]; } template<typename T> -inline void vec_scale (const std::size_t & n, T * RESTRICT v, const T scalar) +inline void vec_scale (const std::size_t n, T * RESTRICT v, const T scalar) { for ( std::size_t i = 0; i < n; i++ ) v[i] = scalar * v[i]; } -inline double vec_maxabs(const std::size_t & n, const double * RESTRICT v) +inline double vec_maxabs(const std::size_t n, const double * RESTRICT v) { double ret = 0.0; for ( std::size_t i = 0; i < n; i++ ) diff --git a/src/lib/netlist/tools/nl_convert.cpp b/src/lib/netlist/tools/nl_convert.cpp index 9523febf06a..5b0bfd267c3 100644 --- a/src/lib/netlist/tools/nl_convert.cpp +++ b/src/lib/netlist/tools/nl_convert.cpp @@ -6,7 +6,6 @@ */ #include <algorithm> -#include <cstdio> #include <cmath> #include <unordered_map> #include "nl_convert.h" @@ -18,7 +17,7 @@ * define a model param on core device */ /* Format: external name,netlist device,model */ -static const char *s_lib_map = +static const pstring s_lib_map = "SN74LS00D, TTL_7400_DIP, 74LSXX\n" "SN74LS04D, TTL_7404_DIP, 74LSXX\n" "SN74ALS08D, TTL_7408_DIP, 74ALSXX\n" @@ -44,11 +43,12 @@ using lib_map_t = std::unordered_map<pstring, lib_map_entry>; static lib_map_t read_lib_map(const pstring lm) { plib::pistringstream istrm(lm); + plib::putf8_reader reader(istrm); lib_map_t m; pstring line; - while (istrm.readline(line)) + while (reader.readline(line)) { - plib::pstring_vector_t split(line, ","); + std::vector<pstring> split(plib::psplit(line, ",")); m[split[0].trim()] = { split[1].trim(), split[2].trim() }; } return m; @@ -185,21 +185,21 @@ const pstring nl_convert_base_t::get_nl_val(const double val) { { int i = 0; - while (m_units[i].m_unit != "-" ) + while (pstring(m_units[i].m_unit, pstring::UTF8) != "-" ) { if (m_units[i].m_mult <= std::abs(val)) break; i++; } - return plib::pfmt(m_units[i].m_func.c_str())(val / m_units[i].m_mult); + return plib::pfmt(pstring(m_units[i].m_func, pstring::UTF8))(val / m_units[i].m_mult); } } double nl_convert_base_t::get_sp_unit(const pstring &unit) { int i = 0; - while (m_units[i].m_unit != "-") + while (pstring(m_units[i].m_unit, pstring::UTF8) != "-") { - if (m_units[i].m_unit == unit) + if (pstring(m_units[i].m_unit, pstring::UTF8) == unit) return m_units[i].m_mult; i++; } @@ -242,7 +242,7 @@ nl_convert_base_t::unit_t nl_convert_base_t::m_units[] = { void nl_convert_spice_t::convert(const pstring &contents) { - plib::pstring_vector_t spnl(contents, "\n"); + std::vector<pstring> spnl(plib::psplit(contents, "\n")); // Add gnd net @@ -274,7 +274,7 @@ void nl_convert_spice_t::process_line(const pstring &line) { if (line != "") { - plib::pstring_vector_t tt(line, " ", true); + std::vector<pstring> tt(plib::psplit(line, " ", true)); double val = 0.0; switch (tt[0].code_at(0)) { @@ -313,7 +313,7 @@ void nl_convert_spice_t::process_line(const pstring &line) model = tt[5]; else model = tt[4]; - plib::pstring_vector_t m(model,"{"); + std::vector<pstring> m(plib::psplit(model,"{")); if (m.size() == 2) { if (m[1].len() != 4) @@ -401,19 +401,13 @@ void nl_convert_spice_t::process_line(const pstring &line) Eagle converter -------------------------------------------------*/ -nl_convert_eagle_t::tokenizer::tokenizer(nl_convert_eagle_t &convert, plib::pistream &strm) +nl_convert_eagle_t::tokenizer::tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &strm) : plib::ptokenizer(strm) , m_convert(convert) { set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-"); set_number_chars(".0123456789", "0123456789eE-."); //FIXME: processing of numbers - char ws[5]; - ws[0] = ' '; - ws[1] = 9; - ws[2] = 10; - ws[3] = 13; - ws[4] = 0; - set_whitespace(ws); + set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13)); /* FIXME: gnetlist doesn't print comments */ set_comment("/*", "*/", "//"); set_string_char('\''); @@ -435,7 +429,8 @@ void nl_convert_eagle_t::tokenizer::verror(const pstring &msg, int line_num, con void nl_convert_eagle_t::convert(const pstring &contents) { plib::pistringstream istrm(contents); - tokenizer tok(*this, istrm); + plib::putf8_reader reader(istrm); + tokenizer tok(*this, reader); out("NETLIST_START(dummy)\n"); add_term("GND", "GND"); @@ -543,19 +538,13 @@ void nl_convert_eagle_t::convert(const pstring &contents) RINF converter -------------------------------------------------*/ -nl_convert_rinf_t::tokenizer::tokenizer(nl_convert_rinf_t &convert, plib::pistream &strm) +nl_convert_rinf_t::tokenizer::tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &strm) : plib::ptokenizer(strm) , m_convert(convert) { set_identifier_chars(".abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-"); set_number_chars("0123456789", "0123456789eE-."); //FIXME: processing of numbers - char ws[5]; - ws[0] = ' '; - ws[1] = 9; - ws[2] = 10; - ws[3] = 13; - ws[4] = 0; - set_whitespace(ws); + set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13)); /* FIXME: gnetlist doesn't print comments */ set_comment("","","//"); // FIXME:needs to be confirmed set_string_char('"'); @@ -589,7 +578,8 @@ void nl_convert_rinf_t::tokenizer::verror(const pstring &msg, int line_num, cons void nl_convert_rinf_t::convert(const pstring &contents) { plib::pistringstream istrm(contents); - tokenizer tok(*this, istrm); + plib::putf8_reader reader(istrm); + tokenizer tok(*this, reader); auto lm = read_lib_map(s_lib_map); out("NETLIST_START(dummy)\n"); diff --git a/src/lib/netlist/tools/nl_convert.h b/src/lib/netlist/tools/nl_convert.h index 3536488c766..d0d12c377e0 100644 --- a/src/lib/netlist/tools/nl_convert.h +++ b/src/lib/netlist/tools/nl_convert.h @@ -49,7 +49,7 @@ protected: double get_sp_val(const pstring &sin); - plib::pstream_fmt_writer_t out; + plib::putf8_fmt_writer out; private: struct net_t @@ -59,14 +59,14 @@ private: : m_name(aname), m_no_export(false) {} const pstring &name() { return m_name;} - plib::pstring_vector_t &terminals() { return m_terminals; } + std::vector<pstring> &terminals() { return m_terminals; } void set_no_export() { m_no_export = true; } bool is_no_export() { return m_no_export; } private: pstring m_name; bool m_no_export; - plib::pstring_vector_t m_terminals; + std::vector<pstring> m_terminals; }; struct dev_t @@ -101,8 +101,8 @@ private: }; struct unit_t { - pstring m_unit; - pstring m_func; + const char *m_unit; + const char *m_func; double m_mult; }; @@ -166,7 +166,7 @@ public: class tokenizer : public plib::ptokenizer { public: - tokenizer(nl_convert_eagle_t &convert, plib::pistream &strm); + tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &strm); token_id_t m_tok_ADD; token_id_t m_tok_VALUE; @@ -202,7 +202,7 @@ public: class tokenizer : public plib::ptokenizer { public: - tokenizer(nl_convert_rinf_t &convert, plib::pistream &strm); + tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &strm); token_id_t m_tok_HEA; token_id_t m_tok_APP; diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp index 0db64344861..dc7c334b1bf 100644 --- a/src/lib/util/chd.cpp +++ b/src/lib/util/chd.cpp @@ -885,7 +885,7 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) // get a pointer to the map entry uint64_t blockoffs; uint32_t blocklen; - uint32_t blockcrc; + util::crc32_t blockcrc; uint8_t *rawmap; uint8_t *dest = reinterpret_cast<uint8_t *>(buffer); switch (m_version) @@ -2147,12 +2147,12 @@ void chd_file::decompress_v5_map() // read the reader uint8_t rawbuf[16]; file_read(m_mapoffset, rawbuf, sizeof(rawbuf)); - uint32_t mapbytes = be_read(&rawbuf[0], 4); - uint64_t firstoffs = be_read(&rawbuf[4], 6); - uint16_t mapcrc = be_read(&rawbuf[10], 2); - uint8_t lengthbits = rawbuf[12]; - uint8_t selfbits = rawbuf[13]; - uint8_t parentbits = rawbuf[14]; + uint32_t const mapbytes = be_read(&rawbuf[0], 4); + uint64_t const firstoffs = be_read(&rawbuf[4], 6); + util::crc16_t const mapcrc = be_read(&rawbuf[10], 2); + uint8_t const lengthbits = rawbuf[12]; + uint8_t const selfbits = rawbuf[13]; + uint8_t const parentbits = rawbuf[14]; // now read the map std::vector<uint8_t> compressed(mapbytes); diff --git a/src/lib/util/hashing.h b/src/lib/util/hashing.h index 906bad047b4..5e9c9134c97 100644 --- a/src/lib/util/hashing.h +++ b/src/lib/util/hashing.h @@ -15,10 +15,12 @@ #include "osdcore.h" #include "corestr.h" -#include <string> #include "md5.h" #include "sha1.h" +#include <functional> +#include <string> + namespace util { //************************************************************************** @@ -132,13 +134,23 @@ protected: // final digest struct crc32_t { - bool operator==(const crc32_t &rhs) const { return m_raw == rhs.m_raw; } - bool operator!=(const crc32_t &rhs) const { return m_raw != rhs.m_raw; } + crc32_t() { } + constexpr crc32_t(const crc32_t &rhs) = default; + constexpr crc32_t(const uint32_t crc) : m_raw(crc) { } + + constexpr bool operator==(const crc32_t &rhs) const { return m_raw == rhs.m_raw; } + constexpr bool operator!=(const crc32_t &rhs) const { return m_raw != rhs.m_raw; } + + crc32_t &operator=(const crc32_t &rhs) = default; crc32_t &operator=(const uint32_t crc) { m_raw = crc; return *this; } - operator uint32_t() const { return m_raw; } + + constexpr operator uint32_t() const { return m_raw; } + bool from_string(const char *string, int length = -1); std::string as_string() const; + uint32_t m_raw; + static const crc32_t null; }; @@ -178,13 +190,23 @@ protected: // final digest struct crc16_t { - bool operator==(const crc16_t &rhs) const { return m_raw == rhs.m_raw; } - bool operator!=(const crc16_t &rhs) const { return m_raw != rhs.m_raw; } + crc16_t() { } + constexpr crc16_t(const crc16_t &rhs) = default; + constexpr crc16_t(const uint16_t crc) : m_raw(crc) { } + + constexpr bool operator==(const crc16_t &rhs) const { return m_raw == rhs.m_raw; } + constexpr bool operator!=(const crc16_t &rhs) const { return m_raw != rhs.m_raw; } + + crc16_t &operator=(const crc16_t &rhs) = default; crc16_t &operator=(const uint16_t crc) { m_raw = crc; return *this; } - operator uint16_t() const { return m_raw; } + + constexpr operator uint16_t() const { return m_raw; } + bool from_string(const char *string, int length = -1); std::string as_string() const; + uint16_t m_raw; + static const crc16_t null; }; @@ -220,4 +242,22 @@ protected: } // namespace util +namespace std { + +template <> struct hash<::util::crc32_t> +{ + typedef ::util::crc32_t argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const & s) const { return std::hash<std::uint32_t>()(s); } +}; + +template <> struct hash<::util::crc16_t> +{ + typedef ::util::crc16_t argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const & s) const { return std::hash<std::uint16_t>()(s); } +}; + +} // namespace std + #endif // __HASHING_H__ diff --git a/src/lib/util/path_to_regex.cpp b/src/lib/util/path_to_regex.cpp index 927ababbb8a..89a21a5e7f6 100644 --- a/src/lib/util/path_to_regex.cpp +++ b/src/lib/util/path_to_regex.cpp @@ -1,7 +1,7 @@ // license:MIT // copyright-holders:Alfred Bratterud -// NOTE: Author allowed MAME project to distribute this file under MIT -// license. Other projects need to do it under Apache 2 license +// NOTE: Author allowed MAME project to distribute this file under MIT +// license. Other projects need to do it under Apache 2 license // // This file is a part of the IncludeOS unikernel - www.includeos.org // diff --git a/src/lib/util/path_to_regex.hpp b/src/lib/util/path_to_regex.hpp index 7608d77bb5d..a6b11a22031 100644 --- a/src/lib/util/path_to_regex.hpp +++ b/src/lib/util/path_to_regex.hpp @@ -1,7 +1,7 @@ // license:MIT // copyright-holders:Alfred Bratterud -// NOTE: Author allowed MAME project to distribute this file under MIT -// license. Other projects need to do it under Apache 2 license +// NOTE: Author allowed MAME project to distribute this file under MIT +// license. Other projects need to do it under Apache 2 license // // This file is a part of the IncludeOS unikernel - www.includeos.org // diff --git a/src/lib/util/server_ws.hpp b/src/lib/util/server_ws.hpp index 170dc31ae63..b9d4721e96b 100644 --- a/src/lib/util/server_ws.hpp +++ b/src/lib/util/server_ws.hpp @@ -64,7 +64,7 @@ namespace webpp { } }; - + class Connection { friend class SocketServerBase<socket_type>; friend class SocketServer<socket_type>; @@ -142,7 +142,7 @@ namespace webpp { catch (...) {} } }; - + class Message : public std::istream { friend class SocketServerBase<socket_type>; diff --git a/src/lib/util/sha1.hpp b/src/lib/util/sha1.hpp index 7befbd326f0..a293bebb7cc 100644 --- a/src/lib/util/sha1.hpp +++ b/src/lib/util/sha1.hpp @@ -36,76 +36,76 @@ namespace { // local // Rotate an integer value to left. inline unsigned int rol(unsigned int value, unsigned int steps) { - return ((value << steps) | (value >> (32 - steps))); + return ((value << steps) | (value >> (32 - steps))); } // Sets the first 16 integers in the buffert to zero. // Used for clearing the W buffert. inline void clearWBuffert(unsigned int * buffert) { - for (int pos = 16; --pos >= 0;) - { - buffert[pos] = 0; - } + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } } inline void innerHash(unsigned int * result, unsigned int * w) { - unsigned int a = result[0]; - unsigned int b = result[1]; - unsigned int c = result[2]; - unsigned int d = result[3]; - unsigned int e = result[4]; - - int round = 0; - - #define sha1macro(func,val) \ - { \ - const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ - e = d; \ - d = c; \ - c = rol(b, 30); \ - b = a; \ - a = t; \ - } - - while (round < 16) - { - sha1macro((b & c) | (~b & d), 0x5a827999) - ++round; - } - while (round < 20) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro((b & c) | (~b & d), 0x5a827999) - ++round; - } - while (round < 40) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro(b ^ c ^ d, 0x6ed9eba1) - ++round; - } - while (round < 60) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) - ++round; - } - while (round < 80) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro(b ^ c ^ d, 0xca62c1d6) - ++round; - } - - #undef sha1macro - - result[0] += a; - result[1] += b; - result[2] += c; - result[3] += d; - result[4] += e; + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; } } // namespace @@ -118,62 +118,62 @@ inline void innerHash(unsigned int * result, unsigned int * w) * the sha1 result in. */ inline void calc(void const * src, size_t bytelength, unsigned char * hash) { - // Init the result array. - unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, - 0x10325476, 0xc3d2e1f0 }; - - // Cast the void src pointer to be the byte array we can work with. - unsigned char const * sarray = static_cast<unsigned char const *>(src); - - // The reusable round buffer - unsigned int w[80]; - - // Loop through all complete 64byte blocks. - - size_t endCurrentBlock; - size_t currentBlock = 0; - - if (bytelength >= 64) { - size_t const endOfFullBlocks = bytelength - 64; - - while (currentBlock <= endOfFullBlocks) { - endCurrentBlock = currentBlock + 64; - - // Init the round buffer with the 64 byte block data. - for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) - { - // This line will swap endian on big endian and keep endian on - // little endian. - w[roundPos++] = static_cast<unsigned int>(sarray[currentBlock + 3]) - | (static_cast<unsigned int>(sarray[currentBlock + 2]) << 8) - | (static_cast<unsigned int>(sarray[currentBlock + 1]) << 16) - | (static_cast<unsigned int>(sarray[currentBlock]) << 24); - } - innerHash(result, w); - } - } - - // Handle the last and not full 64 byte block if existing. - endCurrentBlock = bytelength - currentBlock; - clearWBuffert(w); - size_t lastBlockBytes = 0; - for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) { - w[lastBlockBytes >> 2] |= static_cast<unsigned int>(sarray[lastBlockBytes + currentBlock]) << ((3 - (lastBlockBytes & 3)) << 3); - } - - w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); - if (endCurrentBlock >= 56) { - innerHash(result, w); - clearWBuffert(w); - } - w[15] = bytelength << 3; - innerHash(result, w); - - // Store hash in result pointer, and make sure we get in in the correct - // order on both endian models. - for (int hashByte = 20; --hashByte >= 0;) { - hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; - } + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + unsigned char const * sarray = static_cast<unsigned char const *>(src); + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + + size_t endCurrentBlock; + size_t currentBlock = 0; + + if (bytelength >= 64) { + size_t const endOfFullBlocks = bytelength - 64; + + while (currentBlock <= endOfFullBlocks) { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on + // little endian. + w[roundPos++] = static_cast<unsigned int>(sarray[currentBlock + 3]) + | (static_cast<unsigned int>(sarray[currentBlock + 2]) << 8) + | (static_cast<unsigned int>(sarray[currentBlock + 1]) << 16) + | (static_cast<unsigned int>(sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + size_t lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) { + w[lastBlockBytes >> 2] |= static_cast<unsigned int>(sarray[lastBlockBytes + currentBlock]) << ((3 - (lastBlockBytes & 3)) << 3); + } + + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct + // order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } } } // namespace sha1 diff --git a/src/lib/util/unicode.cpp b/src/lib/util/unicode.cpp index 5849abb8d73..b48cef44c79 100644 --- a/src/lib/util/unicode.cpp +++ b/src/lib/util/unicode.cpp @@ -15,7 +15,7 @@ #define UTF8PROC_DLLEXPORT #endif -#include "utf8proc/utf8proc.h" +#include <utf8proc.h> #include <codecvt> #include <locale> @@ -389,7 +389,7 @@ std::string utf8_from_wstring(const std::wstring &string) //------------------------------------------------- // internal_normalize_unicode - uses utf8proc to -// normalize unicode +// normalize unicode //------------------------------------------------- static std::string internal_normalize_unicode(const char *s, size_t length, unicode_normalization_form normalization_form, bool null_terminated) @@ -437,7 +437,7 @@ static std::string internal_normalize_unicode(const char *s, size_t length, unic //------------------------------------------------- // normalize_unicode - uses utf8proc to normalize -// unicode +// unicode //------------------------------------------------- std::string normalize_unicode(const std::string &s, unicode_normalization_form normalization_form) @@ -448,7 +448,7 @@ std::string normalize_unicode(const std::string &s, unicode_normalization_form n //------------------------------------------------- // normalize_unicode - uses utf8proc to normalize -// unicode +// unicode //------------------------------------------------- std::string normalize_unicode(const char *s, unicode_normalization_form normalization_form) @@ -459,7 +459,7 @@ std::string normalize_unicode(const char *s, unicode_normalization_form normaliz //------------------------------------------------- // normalize_unicode - uses utf8proc to normalize -// unicode +// unicode //------------------------------------------------- std::string normalize_unicode(const char *s, size_t length, unicode_normalization_form normalization_form) |