|
|
|
@ -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 <uros@isotel.eu> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 <uros@isotel.eu> |
|
|
|
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 <stdlib.h> |
|
|
|
#if !defined(_MSC_VER) |
|
|
|
#include <unistd.h> |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/stat.h> |
|
|
|
#endif |
|
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
|
|
|
#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); |
|
|
|
} |
|
|
|
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", |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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; i<PARAM_SIZE(process_params); i++) { |
|
|
|
c_argv[c_argc++] = PARAM(process_params[i]); |
|
|
|
@ -291,25 +307,25 @@ void cm_d_process(ARGS) |
|
|
|
} |
|
|
|
c_argv[0] = PARAM(process_file); |
|
|
|
c_argv[c_argc] = NULL; |
|
|
|
|
|
|
|
|
|
|
|
#if defined(_MSC_VER) || defined(__MINGW64__) |
|
|
|
w_start(c_argv[0], c_argv, local_process); |
|
|
|
#else |
|
|
|
start(c_argv[0], c_argv, local_process); |
|
|
|
#endif |
|
|
|
sendheader(local_process, PORT_SIZE(in), PORT_SIZE(out)); |
|
|
|
|
|
|
|
|
|
|
|
for (i=0; i<PORT_SIZE(in); i++) { |
|
|
|
LOAD(in[i]) = PARAM(input_load); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
LOAD(clk) = PARAM(clk_load); |
|
|
|
|
|
|
|
|
|
|
|
if ( !PORT_NULL(reset) ) { |
|
|
|
LOAD(reset) = PARAM(reset_load); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
local_process = STATIC_VAR(process); |
|
|
|
|
|
|
|
clk = (Digital_State_t *) cm_event_get_ptr(0,0); |
|
|
|
@ -340,8 +356,8 @@ void cm_d_process(ARGS) |
|
|
|
if (*clk != *clk_old && ONE == *clk) { |
|
|
|
uint8_t *dout, *din; |
|
|
|
uint8_t b; |
|
|
|
dout = malloc(local_process->N_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<PORT_SIZE(in); i++) { |
|
|
|
@ -358,10 +374,10 @@ void cm_d_process(ARGS) |
|
|
|
} |
|
|
|
|
|
|
|
dprocess_exchangedata(local_process, (ONE != *reset) ? TIME : -TIME, din, dout); |
|
|
|
|
|
|
|
|
|
|
|
for (i=0; i<PORT_SIZE(out); i++) { |
|
|
|
Digital_State_t new_state = ((dout[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"); |
|
|
|
|