Add MODIFICATIONS note, cleanup white space.
This commit is contained in:
parent
5c4352d02f
commit
33780055ee
|
|
@ -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);
|
||||
}
|
||||
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; 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");
|
||||
|
|
|
|||
|
|
@ -2,20 +2,20 @@
|
|||
================================================================================
|
||||
Copyright 2017-2018 Isotel d.o.o. http://www.isotel.eu
|
||||
|
||||
AUTHORS
|
||||
AUTHORS
|
||||
|
||||
5 November 2017 Uros Platse <uros@isotel.eu>
|
||||
|
||||
|
||||
|
||||
|
||||
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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue