From fcb61e5c3e020fb480314b3689da03956dff3f55 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 11 Oct 2023 15:03:57 -0700 Subject: [PATCH] Add examples/xspice/d_process. --- examples/xspice/d_process/README | 55 +++++++++ examples/xspice/d_process/clean.sh | 7 ++ examples/xspice/d_process/compile.bat.txt | 4 + examples/xspice/d_process/compile.sh | 5 + examples/xspice/d_process/d_process.h | 53 +++++++++ examples/xspice/d_process/graycode.c | 131 +++++++++++++++++++++ examples/xspice/d_process/nggtk.tcl | 10 ++ examples/xspice/d_process/prog-pipes.cir | 40 +++++++ examples/xspice/d_process/prog1-4.cir | 46 ++++++++ examples/xspice/d_process/prog1in4out.c | 136 +++++++++++++++++++++ examples/xspice/d_process/prog4in1out.c | 137 ++++++++++++++++++++++ 11 files changed, 624 insertions(+) create mode 100644 examples/xspice/d_process/README create mode 100755 examples/xspice/d_process/clean.sh create mode 100644 examples/xspice/d_process/compile.bat.txt create mode 100755 examples/xspice/d_process/compile.sh create mode 100644 examples/xspice/d_process/d_process.h create mode 100644 examples/xspice/d_process/graycode.c create mode 100644 examples/xspice/d_process/nggtk.tcl create mode 100644 examples/xspice/d_process/prog-pipes.cir create mode 100644 examples/xspice/d_process/prog1-4.cir create mode 100644 examples/xspice/d_process/prog1in4out.c create mode 100644 examples/xspice/d_process/prog4in1out.c diff --git a/examples/xspice/d_process/README b/examples/xspice/d_process/README new file mode 100644 index 000000000..1be54064a --- /dev/null +++ b/examples/xspice/d_process/README @@ -0,0 +1,55 @@ +The d_process Xspice model was created by Uros Platise. + +A complete, non-trivial example is located at: + https://www.isotel.eu/mixedsim/embedded/motorforce/index.html + +This directory contains a simple test of the d_process model. + +Compile the programs that are called from within d_process: + + ./compile.sh (on Linux or Cygwin on Windows) + +In a Windows Powershell using VisualC, copy compile.bat.txt to compile.bat, +then use it. In a Mingw Msys shell, you can use the VisualC compiled programs, +or use compile.sh. In both these environments the programs need to be compiled +this way to use binary mode pipes. + +Run the test case (comment out the gtkwave lines or use plot if you like): + + ngspice prog1-4.cir + +To clean up: + + ./clean.sh + +NOTE that the prog-pipes.cir test needs fifos created on Linux or Cygwin +on Windows. This is not available on Windows VisualC or Mingw builds. + + mkfifo graycode_in + mkfifo graycode_out + +before ngspice prog-pipes.cir, and in another shell: + + ./graycode --pipe + +needs to be started. + +NOTE on debugging. On Linux or Cygwin on Windows, gdb can be attached to +the running d_process programs, or in --pipe mode with fifos, the graycode +example can be run when invoked from gdb. + +From a Windows Powershell, WinDbg can be attached to a running d_process +program. + +Each program prints (to stderr) its process id when started. This makes +it easier to know the process when attaching a debugger. + +All the programs (graycode.c, prog1in4out.c, prog4in1out.c) contain a call +to sleep to give you time to attach a debugger. This is enabled by: + + export GO_TO_SLEEP=1 (on Linux, Cygwin) + $env:go_to_sleep = '1' (on Windows Powershell) + +Don't forget to remove the environment variables after use, or the +prog1-4.cir will sleep (for up to 1 minute) each time you rerun it. + diff --git a/examples/xspice/d_process/clean.sh b/examples/xspice/d_process/clean.sh new file mode 100755 index 000000000..45c7e3558 --- /dev/null +++ b/examples/xspice/d_process/clean.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -v +rm -fv *.vcd *.exe *.obj +rm -fv prog1in4out +rm -fv prog4in1out +rm -fv graycode +rm -fv graycode_in graycode_out diff --git a/examples/xspice/d_process/compile.bat.txt b/examples/xspice/d_process/compile.bat.txt new file mode 100644 index 000000000..ef8470602 --- /dev/null +++ b/examples/xspice/d_process/compile.bat.txt @@ -0,0 +1,4 @@ +# Add /Zi for debug info +cl /Fe: prog1in4out.exe prog1in4out.c +cl /Fe: prog4in1out.exe prog4in1out.c +cl /Fe: graycode.exe graycode.c diff --git a/examples/xspice/d_process/compile.sh b/examples/xspice/d_process/compile.sh new file mode 100755 index 000000000..50d1dcd2d --- /dev/null +++ b/examples/xspice/d_process/compile.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -v +gcc -Wall -Wpedantic -g -o prog1in4out prog1in4out.c +gcc -Wall -Wpedantic -g -o prog4in1out prog4in1out.c +gcc -Wall -Wpedantic -g -o graycode graycode.c diff --git a/examples/xspice/d_process/d_process.h b/examples/xspice/d_process/d_process.h new file mode 100644 index 000000000..face10ab1 --- /dev/null +++ b/examples/xspice/d_process/d_process.h @@ -0,0 +1,53 @@ +/** + * \file + * \brief NgSpice D_PROCESS Interface + * \author Uros Platise + */ + +#ifndef __NGSPICE_D_PROCESS__ +#define __NGSPICE_D_PROCESS__ + +#include +#if !defined(_MSC_VER) +#include +#endif +#include + +#define D_PROCESS_FORMAT_VERSION 0x01 +#define D_PROCESS_DLEN(x) (uint8_t)( ((x)==0) ? 0 : (((x)-1)/8 + 1) ) + +static inline int d_process_init(int pipein, int pipeout, uint8_t N_din, uint8_t N_dout) { +#if defined(_MSC_VER) || defined(__MINGW64__) +#pragma pack(push, 1) + struct header_s { + uint8_t version, N_din, N_dout; + } header; +#pragma pack(pop) +#else + struct header_s { + uint8_t version, N_din, N_dout; + } __attribute__((packed))header; +#endif + +#if defined(_MSC_VER) || defined(__MINGW64__) + if (_read(pipein, &header, sizeof(header)) != sizeof(header)) { +#else + if (read(pipein, &header, sizeof(header)) != sizeof(header)) { +#endif + fprintf(stderr, "Error: Incompatible ngspice d_process header size, requiring version %d\n", header.version); + return 0; + } + if (header.version != D_PROCESS_FORMAT_VERSION || header.N_din != N_din || header.N_dout != N_dout) { + fprintf(stderr, "Error: Incompatible ngspice d_process requiring version %d, number of inputs %d expected %d, and outputs %d expected %d.\n", + header.version, header.N_din, N_din, header.N_dout, N_dout); + return 0; + } +#if defined(_MSC_VER) || defined(__MINGW64__) + _write(pipeout, &header, sizeof(header)); // acknowledge connection by returning back the same header +#else + write(pipeout, &header, sizeof(header)); // acknowledge connection by returning back the same header +#endif + return 1; +} + +#endif diff --git a/examples/xspice/d_process/graycode.c b/examples/xspice/d_process/graycode.c new file mode 100644 index 000000000..19216e088 --- /dev/null +++ b/examples/xspice/d_process/graycode.c @@ -0,0 +1,131 @@ +/* + The organization of this file is modelled after the motorforce example + developed by Uros Platise. +*/ +#include +#include +#include +#if !defined(_MSC_VER) && !defined(__MINGW64__) +#include +#endif +#if defined(_MSC_VER) +#include +#include +#include +#endif +#include "d_process.h" + +#define DIGITAL_IN 0 +#define DIGITAL_OUT 4 + +static int compute(uint8_t *dataout, int outsz, double time); + +static int known_bp(int iargc) +{ + return iargc; +} + +int main(int argc, char *argv[]) { + int i; + int outlen = D_PROCESS_DLEN(DIGITAL_OUT); + +#if defined(_MSC_VER) || defined(__MINGW64__) +#pragma pack(push, 1) + struct in_s { + double time; + } in; + + struct out_s { + uint8_t dout[D_PROCESS_DLEN(DIGITAL_OUT)]; + } out; +#pragma pack(pop) +#else + struct in_s { + double time; + } __attribute__((packed)) in; + + struct out_s { + uint8_t dout[D_PROCESS_DLEN(DIGITAL_OUT)]; + } __attribute__((packed)) out; +#endif + + int pipein = 0; // default stdin to recv from ngspice + int pipeout= 1; // default stdout to send to ngspice +#if defined(_MSC_VER) || defined(__MINGW64__) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + +#if defined(_MSC_VER) || defined(__MINGW64__) + fprintf(stderr, "%s pid %d\n", argv[0], _getpid()); +#else + fprintf(stderr, "%s pid %d\n", argv[0], getpid()); +#endif + +#if !defined(_MSC_VER) && !defined(__MINGW64__) + if (getenv("GO_TO_SLEEP")) { + sleep(40); + } +#endif +#if defined(__MINGW64__) + if (getenv("GO_TO_SLEEP")) { + sleep(40); + } +#endif +#if defined(_MSC_VER) + if (getenv("GO_TO_SLEEP")) { + Sleep(60000); + } +#endif + + (void)known_bp(argc); + + for (i=0; i> 1)) & 0x0F; + return 1; +} + diff --git a/examples/xspice/d_process/nggtk.tcl b/examples/xspice/d_process/nggtk.tcl new file mode 100644 index 000000000..a8669f6f8 --- /dev/null +++ b/examples/xspice/d_process/nggtk.tcl @@ -0,0 +1,10 @@ +# tcl script for gtkwave: show vcd file data created by ngspice +set nfacs [ gtkwave::getNumFacs ] + +for {set i 0} {$i < $nfacs } {incr i} { + set facname [ gtkwave::getFacName $i ] + set num_added [ gtkwave::addSignalsFromList $facname ] +} + +gtkwave::/Edit/UnHighlight_All +gtkwave::/Time/Zoom/Zoom_Full diff --git a/examples/xspice/d_process/prog-pipes.cir b/examples/xspice/d_process/prog-pipes.cir new file mode 100644 index 000000000..2ca3caa62 --- /dev/null +++ b/examples/xspice/d_process/prog-pipes.cir @@ -0,0 +1,40 @@ +prog-pipes.cir + +*** analysis type *** +.tran .01us 10us +v1 1 0 DC 1.0 +v2 2 0 DC 0.0 + +.model d_osc1 d_osc (cntl_array=[-1.0 0.0 1.0 2.0] ++ freq_array=[1.0e6 1.0e6 4.0e6 4.0e6] ++ rise_delay=1.0e-6 fall_delay=2.0e-6) + +a1 1 clk1 d_osc1 +a2 2 clk2 d_osc1 + +ap0_4 null clk1 null [q1 q2 q3 q4] proc0 +.model proc0 d_process (process_file="graycode|" process_params=["--pipe"]) + +ap1_4 [clk2] clk1 null [o1 o2 o3 o4] proc1 +.model proc1 d_process (process_file="prog1in4out" process_params=["opt1", "qwerty"]) + +ap4_1 [o1 o2 o3 o4] clk1 null [zeros] proc2 +.model proc2 d_process (process_file="prog4in1out" process_params=["abc", "99"]) + +ap4_1a [q1 q2 q3 q4] clk1 null [qzeros] proc3 +.model proc3 d_process (process_file="prog4in1out") + +.control +run +edisplay +eprvcd clk1 clk2 o1 o2 o3 o4 q1 q2 q3 q4 zeros qzeros > prog1-4.vcd +shell gtkwave prog1-4.vcd --script nggtk.tcl & +* quit +.endc +.end + + + + + + diff --git a/examples/xspice/d_process/prog1-4.cir b/examples/xspice/d_process/prog1-4.cir new file mode 100644 index 000000000..032a71ba8 --- /dev/null +++ b/examples/xspice/d_process/prog1-4.cir @@ -0,0 +1,46 @@ +prog1-4.cir + +*** analysis type *** +.tran .01us 10us +v1 1 0 DC 1.0 +v2 2 0 DC 0.0 + +.model d_osc1 d_osc (cntl_array=[-1.0 0.0 1.0 2.0] ++ freq_array=[1.0e6 1.0e6 4.0e6 4.0e6] ++ rise_delay=1.0e-6 fall_delay=2.0e-6) + +a1 1 clk1 d_osc1 +a2 2 clk2 d_osc1 + +ap0_4 null clk1 null [q1 q2 q3 q4] proc0 +.model proc0 d_process (process_file="graycode" process_params=["none"]) + +ap1_4 [clk2] clk1 null [o1 o2 o3 o4] proc1 +.model proc1 d_process (process_file="prog1in4out" process_params=["opt1", "qwerty"]) + +ap4_1 [o1 o2 o3 o4] clk1 null [zeros] proc2 +.model proc2 d_process (process_file="prog4in1out" process_params=["abc", "99"]) + +ap4_1a [q1 q2 q3 q4] clk1 null [qzeros] proc3 +.model proc3 d_process (process_file="prog4in1out") + +an1 [o1 ~o2 o3] reseto dand1 +.model dand1 d_and(inertial_delay=true rise_delay=1ns fall_delay=50ns) + +ap1_4a [clk2] clk1 reseto [b1 b2 b3 b4] proc4 +.model proc4 d_process (process_file="prog1in4out") + +.control +run +edisplay +eprvcd clk1 clk2 o1 o2 o3 o4 q1 q2 q3 q4 b1 b2 b3 b4 zeros qzeros reseto > prog1-4.vcd +shell gtkwave prog1-4.vcd --script nggtk.tcl & +quit +.endc +.end + + + + + + diff --git a/examples/xspice/d_process/prog1in4out.c b/examples/xspice/d_process/prog1in4out.c new file mode 100644 index 000000000..da8964114 --- /dev/null +++ b/examples/xspice/d_process/prog1in4out.c @@ -0,0 +1,136 @@ +/* + The organization of this file is modelled after the motorforce example + developed by Uros Platise. +*/ +#include +#include +#include +#if !defined(_MSC_VER) && !defined(__MINGW64__) +#include +#endif +#if defined(_MSC_VER) +#include +#include +#include +#endif +#include "d_process.h" + +#define DIGITAL_IN 1 +#define DIGITAL_OUT 4 + +static int compute( + uint8_t *datain, int insz, uint8_t *dataout, int outsz, double time +); + +static int known_bp(int iargc) +{ + return iargc; +} + +int main(int argc, char *argv[]) { + int i; + int inlen = D_PROCESS_DLEN(DIGITAL_IN); + int outlen = D_PROCESS_DLEN(DIGITAL_OUT); + +#if defined(_MSC_VER) || defined(__MINGW64__) +#pragma pack(push, 1) + struct in_s { + double time; + uint8_t din[D_PROCESS_DLEN(DIGITAL_IN)]; + } in; + + struct out_s { + uint8_t dout[D_PROCESS_DLEN(DIGITAL_OUT)]; + } out; +#pragma pack(pop) +#else + struct in_s { + double time; + uint8_t din[D_PROCESS_DLEN(DIGITAL_IN)]; + } __attribute__((packed)) in; + + struct out_s { + uint8_t dout[D_PROCESS_DLEN(DIGITAL_OUT)]; + } __attribute__((packed)) out; +#endif + + int pipein = 0; // default stdin to recv from ngspice + int pipeout= 1; // default stdout to send to ngspice +#if defined(_MSC_VER) || defined(__MINGW64__) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + +#if defined(_MSC_VER) || defined(__MINGW64__) + fprintf(stderr, "%s pid %d\n", argv[0], _getpid()); +#else + fprintf(stderr, "%s pid %d\n", argv[0], getpid()); +#endif + +#if !defined(_MSC_VER) && !defined(__MINGW64__) + if (getenv("GO_TO_SLEEP")) { + sleep(40); + } +#endif +#if defined(__MINGW64__) + if (getenv("GO_TO_SLEEP")) { + sleep(40); + } +#endif +#if defined(_MSC_VER) + if (getenv("GO_TO_SLEEP")) { + Sleep(60000); + } +#endif + + (void)known_bp(argc); + + for (i=0; i +#include +#include +#if !defined(_MSC_VER) && !defined(__MINGW64__) +#include +#endif +#if defined(_MSC_VER) +#include +#include +#include +#endif +#include "d_process.h" + +#define DIGITAL_IN 4 +#define DIGITAL_OUT 1 + +static int compute( + uint8_t *datain, int insz, uint8_t *dataout, int outsz, double time +); + +static int known_bp(int iargc) +{ + return iargc; +} + +int main(int argc, char *argv[]) { + int i; + int inlen = D_PROCESS_DLEN(DIGITAL_IN); + int outlen = D_PROCESS_DLEN(DIGITAL_OUT); + +#if defined(_MSC_VER) || defined(__MINGW64__) +#pragma pack(push, 1) + struct in_s { + double time; + uint8_t din[D_PROCESS_DLEN(DIGITAL_IN)]; + } in; + + struct out_s { + uint8_t dout[D_PROCESS_DLEN(DIGITAL_OUT)]; + } out; +#pragma pack(pop) +#else + struct in_s { + double time; + uint8_t din[D_PROCESS_DLEN(DIGITAL_IN)]; + } __attribute__((packed)) in; + + struct out_s { + uint8_t dout[D_PROCESS_DLEN(DIGITAL_OUT)]; + } __attribute__((packed)) out; +#endif + + int pipein = 0; // default stdin to recv from ngspice + int pipeout= 1; // default stdout to send to ngspice +#if defined(_MSC_VER) || defined(__MINGW64__) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + +#if defined(_MSC_VER) || defined(__MINGW64__) + fprintf(stderr, "%s pid %d\n", argv[0], _getpid()); +#else + fprintf(stderr, "%s pid %d\n", argv[0], getpid()); +#endif + +#if !defined(_MSC_VER) && !defined(__MINGW64__) + if (getenv("GO_TO_SLEEP")) { + sleep(40); + } +#endif +#if defined(__MINGW64__) + if (getenv("GO_TO_SLEEP")) { + sleep(40); + } +#endif +#if defined(_MSC_VER) + if (getenv("GO_TO_SLEEP")) { + Sleep(60000); + } +#endif + + (void)known_bp(argc); + + for (i=0; i