diff --git a/src/xspice/icm/digital/d_process/cfunc.mod b/src/xspice/icm/digital/d_process/cfunc.mod index 1cf0a2f83..1d6f0374b 100644 --- a/src/xspice/icm/digital/d_process/cfunc.mod +++ b/src/xspice/icm/digital/d_process/cfunc.mod @@ -21,10 +21,10 @@ PROJECT http://isotel.eu/mixedsim Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -AUTHORS +AUTHORS 2017-2018 Uros Platse - + SUMMARY @@ -32,13 +32,13 @@ SUMMARY standard unix stdin/stdout pipe to extend ngspice functionality to the level of embedded systems. - If a process ends with | character then rather than invoking + If a process ends with | character then rather than invoking a process it opens named pipe, process_in which is input to the process and pipe process_out for reading back from process. - + Communication between this code model and a process is in 8-bit binary format. On start-up - + 0x01: version 0x00-0xFF: number of inputs, max 255, 0 means none 0x00-0xFF: number of outputs, max 255, 0 means none @@ -46,7 +46,7 @@ SUMMARY On start: outputs are set to uknown state and high impedance - + On each rising edge of a clock and reset being low double (8-byte): positive value of TIME if reset is low otherwise -TIME @@ -54,7 +54,7 @@ SUMMARY ooutputs are defined by returning process and process must return: - + [output array]: output bytes, each byte packs up to 8 outputs For example project please see: http://isotel.eu/mixedsim @@ -69,13 +69,21 @@ MODIFICATIONS - Tested and polished ready to be published 7 April 2018 Uros Platse - Removed async reset and converted it to synchronous reset only. + Removed async reset and converted it to synchronous reset only. Code cleanup. + 30 September 2023 Brian Taylor + Modify the code for Windows VisualC and Mingw. + In VisualC, #pragma pack(...) compiler directives are needed for + the struct declarations using __attribute__(packed). + Use Microsoft CRT library functions _pipe, _read, _write, _spawn. + For Windows VisualC and Mingw the pipes use binary mode, and + named pipes or fifos are not supported. + REFERENCED FILES - Inputs from and outputs to ARGS structure. + Inputs from and outputs to ARGS structure. ===============================================================================*/ @@ -86,9 +94,11 @@ REFERENCED FILES #include #if !defined(_MSC_VER) #include +#include +#include #endif #include - + #define D_PROCESS_FORMAT_VERSION 0x01 #define DLEN(x) (uint8_t)( ((x)==0) ? 0 : (((x)-1)/8 + 1) ) #define DIN_SIZE_MAX 256 // also represents a theoretical maximum for 8-bit input length specifier @@ -98,7 +108,7 @@ typedef unsigned char uint8_t; typedef struct { int pipe_to_child; int pipe_from_child; - uint8_t N_din, N_dout; // number of inputs/outputs bytes + uint8_t N_din, N_dout; // number of inputs/outputs bytes Digital_State_t dout_old[256]; // max possible storage to track output changes } Process_t; @@ -120,10 +130,10 @@ static void sendheader(Process_t * process, int N_din, int N_dout) uint8_t version, N_din, N_dout; } __attribute__((packed)) header = {D_PROCESS_FORMAT_VERSION, (uint8_t)N_din, (uint8_t)N_dout}; #endif - + if (N_din > 255 || N_dout > 255) { fprintf(stderr, "Error: d_process supports max 255 input and output and 255 output signals\n"); - exit(1); + exit(1); } #if defined(_MSC_VER) || defined(__MINGW64__) @@ -134,7 +144,7 @@ static void sendheader(Process_t * process, int N_din, int N_dout) fprintf(stderr, "Error: d_process when sending header\n"); exit(1); } - + // Wait for echo which must return the same header to ack transfer #if defined(_MSC_VER) || defined(__MINGW64__) if (_read(process->pipe_from_child, &header, sizeof(header)) != sizeof(header)) { @@ -143,17 +153,17 @@ static void sendheader(Process_t * process, int N_din, int N_dout) #endif fprintf(stderr, "Error: d_process didn't respond to the header\n"); exit(1); - } + } if (header.version != D_PROCESS_FORMAT_VERSION) { fprintf(stderr, "Error: d_process returned invalid version: %d\n", header.version); - exit(1); - } - if (header.N_din != N_din || header.N_dout != N_dout) { - fprintf(stderr, "Error: d_process I/O mismatch: in %d vs. returned %d, out %d vs. returned %d\n", - N_din, header.N_din, N_dout, header.N_dout); - exit(1); + exit(1); } - + if (header.N_din != N_din || header.N_dout != N_dout) { + fprintf(stderr, "Error: d_process I/O mismatch: in %d vs. returned %d, out %d vs. returned %d\n", + N_din, header.N_din, N_dout, header.N_dout); + exit(1); + } + process->N_din = (uint8_t)DLEN(N_din); process->N_dout = (uint8_t)DLEN(N_dout); } @@ -174,7 +184,7 @@ static void dprocess_exchangedata(Process_t * process, double time, uint8_t din[ uint8_t din[DIN_SIZE_MAX]; } __attribute__((packed)) packet_t; #endif - + size_t dlen = 0; int wlen = 0; packet_t packet; @@ -218,31 +228,37 @@ static void start(char *system_command, char * c_argv[], Process_t * process) exit(1); } if (system_command[syscmd_len-1] == '|') { - char filename[syscmd_len+5]; - strncpy(filename, system_command, syscmd_len-1); - strcpy(&filename[syscmd_len-1], "_in"); - if ( (process->pipe_to_child = open(filename, O_WRONLY)) < 0) { - perror(filename); + char *filename_in = NULL, *filename_out = NULL; + filename_in = (char *) malloc(syscmd_len + 5); + filename_out = (char *) malloc(syscmd_len + 5); + filename_in[0] = '\0'; + filename_out[0] = '\0'; + strncpy(filename_in, system_command, syscmd_len-1); + strcpy(&filename_in[syscmd_len-1], "_in"); + strncpy(filename_out, system_command, syscmd_len-1); + strcpy(&filename_out[syscmd_len-1], "_out"); + if ((process->pipe_to_child = open(filename_in, O_WRONLY)) == -1) { + perror("open in file"); exit(1); } - strncpy(filename, system_command, syscmd_len-1); - strcpy(&filename[syscmd_len-1], "_out"); - if ( (process->pipe_from_child = open(filename, O_RDONLY)) < 0) { - perror(filename); + if ((process->pipe_from_child = open(filename_out, O_RDONLY)) == -1) { + perror("open out file"); exit(1); } + if (filename_in) free(filename_in); + if (filename_out) free(filename_out); } else { if (pipe(pipe_to_child) || pipe(pipe_from_child) || (pid=fork()) ==-1) { perror("Error: d_process cannot create pipes and fork"); exit(1); - } + } if (pid == 0) { dup2(pipe_to_child[0],0); dup2(pipe_from_child[1],1); close(pipe_to_child[1]); close(pipe_from_child[0]); - + if (execv(system_command, c_argv) == -1) { perror(system_command); exit(1); @@ -259,10 +275,10 @@ static void start(char *system_command, char * c_argv[], Process_t * process) #endif -void cm_d_process(ARGS) +void cm_d_process(ARGS) { int i; /* generic loop counter index */ - + Digital_State_t *reset, /* storage for clock value */ *reset_old; /* previous clock value */ @@ -272,18 +288,18 @@ void cm_d_process(ARGS) Process_t *local_process; /* Structure containing process vars */ - if (INIT) { + if (INIT) { char * c_argv[1024]; int c_argc = 1; cm_event_alloc(0,sizeof(Digital_State_t)); cm_event_alloc(1,sizeof(Digital_State_t)); - + clk = clk_old = (Digital_State_t *) cm_event_get_ptr(0,0); reset = reset_old = (Digital_State_t *) cm_event_get_ptr(1,0); - STATIC_VAR(process) = malloc(sizeof(Process_t)); + STATIC_VAR(process) = malloc(sizeof(Process_t)); local_process = STATIC_VAR(process); - + if (!PARAM_NULL(process_params)) { for (i=0; iN_dout * sizeof(uint8_t)); - din = malloc(local_process->N_din * sizeof(uint8_t)); + dout = (uint8_t *) malloc(local_process->N_dout * sizeof(uint8_t)); + din = (uint8_t *) malloc(local_process->N_din * sizeof(uint8_t)); memset(din, 0, local_process->N_din); for (i=0; i> 3] >> (i & 7)) & 0x01) ? ONE : ZERO; - + if (new_state != local_process->dout_old[i]) { OUTPUT_STATE(out[i]) = new_state; OUTPUT_STRENGTH(out[i]) = STRONG; @@ -370,7 +386,7 @@ void cm_d_process(ARGS) } else { OUTPUT_CHANGED(out[i]) = FALSE; - } + } } free(din); free(dout); @@ -393,19 +409,17 @@ static void w_start(char *system_command, char * c_argv[], Process_t * process) int pipe_to_child[2]; int pipe_from_child[2]; int pid = 0; -#define USE_BINARY_MODE -#ifdef USE_BINARY_MODE int mode = _O_BINARY; -#else - int mode = _O_TEXT; -#endif size_t syscmd_len = strlen(system_command); if (syscmd_len == 0) { fprintf(stderr, "Error: d_process process_file argument is not given"); exit(1); } - + if (system_command[syscmd_len-1] == '|') { + fprintf(stderr, "Error: d_process named pipe/fifo not supported\n"); + exit(1); + } if (_pipe(pipe_to_child, 1024, mode) == -1) { perror("pipe_to_child"); fprintf(stderr, "Failed to open pipe_to_child\n"); diff --git a/src/xspice/icm/digital/d_process/ifspec.ifs b/src/xspice/icm/digital/d_process/ifspec.ifs index d002b97b6..4531f12d4 100644 --- a/src/xspice/icm/digital/d_process/ifspec.ifs +++ b/src/xspice/icm/digital/d_process/ifspec.ifs @@ -2,20 +2,20 @@ ================================================================================ Copyright 2017-2018 Isotel d.o.o. http://www.isotel.eu -AUTHORS +AUTHORS 5 November 2017 Uros Platse - + SUMMARY - This file contains the interface specification file for the + This file contains the interface specification file for the digital d_process (extends to a system process) code model. ===============================================================================*/ - + NAME_TABLE: @@ -32,8 +32,8 @@ Description: "input" "clock" Direction: in in Default_Type: d d Allowed_Types: [d] [d] -Vector: yes no -Vector_Bounds: - - +Vector: yes no +Vector_Bounds: - - Null_Allowed: yes no @@ -45,8 +45,8 @@ Description: "reset" "output" Direction: in out Default_Type: d d Allowed_Types: [d] [d] -Vector: no yes -Vector_Bounds: - [1 -] +Vector: no yes +Vector_Bounds: - [1 -] Null_Allowed: yes yes @@ -58,35 +58,35 @@ Parameter_Name: clk_delay reset_delay Description: "delay from CLK" "delay from reset" Data_Type: real real Default_Value: 1.0e-9 1.0e-9 -Limits: - - -Vector: no no -Vector_Bounds: - - -Null_Allowed: yes yes +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes PARAMETER_TABLE: Parameter_Name: process_file -Description: "file name of the executable process" -Data_Type: string -Default_Value: "process" -Limits: - -Vector: no -Vector_Bounds: - -Null_Allowed: no +Description: "file name of the executable process" +Data_Type: string +Default_Value: "process" +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: no PARAMETER_TABLE: Parameter_Name: process_params -Description: "parameters to be passed to an executable process" -Data_Type: string +Description: "parameters to be passed to an executable process" +Data_Type: string Default_Value: - -Limits: - -Vector: yes -Vector_Bounds: - +Limits: - +Vector: yes +Vector_Bounds: - Null_Allowed: yes @@ -94,50 +94,50 @@ PARAMETER_TABLE: Parameter_Name: reset_state -Description: "default state on RESET & at DC" -Data_Type: int -Default_Value: 0 -Limits: - -Vector: no -Vector_Bounds: - -Null_Allowed: no +Description: "default state on RESET & at DC" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: no PARAMETER_TABLE: Parameter_Name: input_load -Description: "input loading capacitance (F)" -Data_Type: real -Default_Value: 1.0e-12 -Limits: - -Vector: no -Vector_Bounds: - -Null_Allowed: no +Description: "input loading capacitance (F)" +Data_Type: real +Default_Value: 1.0e-12 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: no PARAMETER_TABLE: Parameter_Name: clk_load -Description: "clock loading capacitance (F)" -Data_Type: real -Default_Value: 1.0e-12 -Limits: - -Vector: no -Vector_Bounds: - -Null_Allowed: no +Description: "clock loading capacitance (F)" +Data_Type: real +Default_Value: 1.0e-12 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: no PARAMETER_TABLE: Parameter_Name: reset_load -Description: "reset loading capacitance (F)" -Data_Type: real -Default_Value: 1.0e-12 -Limits: - -Vector: no -Vector_Bounds: - -Null_Allowed: no +Description: "reset loading capacitance (F)" +Data_Type: real +Default_Value: 1.0e-12 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: no STATIC_VAR_TABLE: