1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00
myhdl/cosimulation/icarus/myhdl.c.20030518
2003-11-24 10:37:13 +00:00

461 lines
12 KiB
Plaintext

#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "vpi_user.h"
#include <string.h>
#define MAXLINE 4096
#define MAXWIDTH 10
#define MAXARGS 64
// #define DEBUG 1
/* Sized variables */
#ifndef PLI_TYPES
#define PLI_TYPES
typedef int PLI_INT32;
typedef unsigned int PLI_UINT32;
typedef short PLI_INT16;
typedef unsigned short PLI_UINT16;
typedef char PLI_BYTE8;
typedef unsigned char PLI_UBYTE8;
#endif
/* 64 bit type for time calculations */
typedef unsigned long long myhdl_time64_t;
static int rpipe;
static int wpipe;
static vpiHandle from_myhdl_systf_handle = NULL;
static vpiHandle to_myhdl_systf_handle = NULL;
static char changeFlag[MAXARGS];
static char bufcp[MAXLINE];
static myhdl_time64_t myhdl_time;
static myhdl_time64_t verilog_time;
static myhdl_time64_t pli_time;
static myhdl_time64_t delay;
static int delta;
/* prototypes */
static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data);
static PLI_INT32 to_myhdl_calltf(PLI_BYTE8 *user_data);
static PLI_INT32 readonly_callback(p_cb_data cb_data);
static PLI_INT32 delay_callback(p_cb_data cb_data);
static PLI_INT32 delta_callback(p_cb_data cb_data);
static PLI_INT32 change_callback(p_cb_data cb_data);
static int init_pipes();
static myhdl_time64_t timestruct_to_time(const struct t_vpi_time*ts);
/* from Icarus */
static myhdl_time64_t timestruct_to_time(const struct t_vpi_time*ts)
{
myhdl_time64_t ti = ts->high;
ti <<= 32;
ti += ts->low & 0xffffffff;
return ti;
}
static int init_pipes()
{
char *w;
char *r;
static int init_pipes_flag = 0;
if (init_pipes_flag) {
return(0);
}
if ((w = getenv("MYHDL_TO_PIPE")) == NULL) {
vpi_printf("ERROR: no write pipe to myhdl\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
if ((r = getenv("MYHDL_FROM_PIPE")) == NULL) {
vpi_printf("ERROR: no read pipe from myhdl\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
wpipe = atoi(w);
rpipe = atoi(r);
init_pipes_flag = 1;
return (0);
}
static PLI_INT32 from_myhdl_calltf(PLI_BYTE8 *user_data)
{
vpiHandle reg_iter, reg_handle;
s_vpi_time verilog_time_s;
char buf[MAXLINE];
char s[MAXWIDTH];
int n;
static int from_myhdl_flag = 0;
if (from_myhdl_flag) {
vpi_printf("ERROR: $from_myhdl called more than once\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
from_myhdl_flag = 1;
init_pipes();
verilog_time_s.type = vpiSimTime;
vpi_get_time(NULL, &verilog_time_s);
verilog_time = timestruct_to_time(&verilog_time_s);
if (verilog_time != 0) {
vpi_printf("ERROR: $from_myhdl should be called at time 0\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
sprintf(buf, "FROM 0 ");
pli_time = 0;
delta = 0;
from_myhdl_systf_handle = vpi_handle(vpiSysTfCall, NULL);
reg_iter = vpi_iterate(vpiArgument, from_myhdl_systf_handle);
while ((reg_handle = vpi_scan(reg_iter)) != NULL) {
if (vpi_get(vpiType, reg_handle) != vpiReg) {
vpi_printf("ERROR: $from_myhdl argument %s should be a reg\n",
vpi_get_str(vpiName, reg_handle));
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
strcat(buf, vpi_get_str(vpiName, reg_handle));
strcat(buf, " ");
sprintf(s, "%d ", vpi_get(vpiSize, reg_handle));
strcat(buf, s);
}
n = write(wpipe, buf, strlen(buf));
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
vpi_printf("Info: MyHDL simulator down\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
assert(n > 0);
buf[n] = '\0';
return(0);
}
static PLI_INT32 to_myhdl_calltf(PLI_BYTE8 *user_data)
{
vpiHandle net_iter, net_handle;
char buf[MAXLINE];
char s[MAXWIDTH];
int n;
int i;
int *id;
s_cb_data cb_data_s;
s_vpi_time verilog_time_s;
s_vpi_time time_s;
s_vpi_value value_s;
static int to_myhdl_flag = 0;
if (to_myhdl_flag) {
vpi_printf("ERROR: $to_myhdl called more than once\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
to_myhdl_flag = 1;
init_pipes();
verilog_time_s.type = vpiSimTime;
vpi_get_time(NULL, &verilog_time_s);
verilog_time = timestruct_to_time(&verilog_time_s);
if (verilog_time != 0) {
vpi_printf("ERROR: $to_myhdl should be called at time 0\n");
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
sprintf(buf, "TO 0 ");
pli_time = 0;
delta = 0;
time_s.type = vpiSuppressTime;
cb_data_s.reason = cbValueChange;
cb_data_s.cb_rtn = change_callback;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
// value_s.format = vpiHexStrVal;
i = 0;
to_myhdl_systf_handle = vpi_handle(vpiSysTfCall, NULL);
net_iter = vpi_iterate(vpiArgument, to_myhdl_systf_handle);
while ((net_handle = vpi_scan(net_iter)) != NULL) {
if (i == MAXARGS) {
vpi_printf("ERROR: $to_myhdl max #args (%d) exceeded\n", MAXARGS);
vpi_control(vpiFinish, 1); /* abort simulation */
}
strcat(buf, vpi_get_str(vpiName, net_handle));
strcat(buf, " ");
sprintf(s, "%d ", vpi_get(vpiSize, net_handle));
strcat(buf, s);
changeFlag[i] = 0;
id = malloc(sizeof(int));
*id = i;
cb_data_s.user_data = (PLI_BYTE8 *)id;
cb_data_s.obj = net_handle;
vpi_register_cb(&cb_data_s);
i++;
}
n = write(wpipe, buf, strlen(buf));
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
buf[n] = '\0';
assert(n > 0);
// register read-only callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 0;
cb_data_s.reason = cbReadOnlySynch;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = readonly_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
// pre-register delta cycle callback //
delta = 0;
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 1;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delta_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
return(0);
}
static PLI_INT32 readonly_callback(p_cb_data cb_data)
{
vpiHandle systf_handle;
vpiHandle net_iter, net_handle;
vpiHandle reg_iter, reg_handle;
s_cb_data cb_data_s;
s_vpi_time verilog_time_s;
s_vpi_value value_s;
s_vpi_time time_s;
char buf[MAXLINE];
int n;
int i;
char *myhdl_time_string;
myhdl_time64_t delay;
static int start_flag = 1;
if (start_flag) {
start_flag = 0;
n = write(wpipe, "START", 5);
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
vpi_control(vpiFinish, 1); /* abort simulation */
}
assert(n > 0);
}
buf[0] = '\0';
verilog_time_s.type = vpiSimTime;
vpi_get_time(NULL, &verilog_time_s);
verilog_time = timestruct_to_time(&verilog_time_s);
/* if (verilog_time != (pli_time * 1000 + delta)) { */
/* vpi_printf("%u %u\n", verilog_time_s.high, verilog_time_s.low ); */
/* vpi_printf("%llu %llu %d", verilog_time, pli_time, delta); */
/* } */
/* Icarus 0.7 fails on this assertion beyond 32 bits due to a bug */
// assert(verilog_time == pli_time * 1000 + delta);
assert( (verilog_time & 0xFFFFFFFF) == ( (pli_time * 1000 + delta) & 0xFFFFFFFF ) );
sprintf(buf, "%llu ", pli_time);
net_iter = vpi_iterate(vpiArgument, to_myhdl_systf_handle);
value_s.format = vpiHexStrVal;
i = 0;
while ((net_handle = vpi_scan(net_iter)) != NULL) {
if (changeFlag[i]) {
strcat(buf, vpi_get_str(vpiName, net_handle));
strcat(buf, " ");
vpi_get_value(net_handle, &value_s);
strcat(buf, value_s.value.str);
strcat(buf, " ");
changeFlag[i] = 0;
}
i++;
}
n = write(wpipe, buf, strlen(buf));
if ((n = read(rpipe, buf, MAXLINE)) == 0) {
vpi_control(vpiFinish, 1); /* abort simulation */
return(0);
}
assert(n > 0);
buf[n] = '\0';
/* save copy for later callback */
strcpy(bufcp, buf);
myhdl_time_string = strtok(buf, " ");
myhdl_time = (myhdl_time64_t) strtoull(myhdl_time_string, (char **) NULL, 10);
delay = (myhdl_time - pli_time) * 1000;
assert(delay >= 0);
assert(delay <= 0xFFFFFFFF);
if (delay > 0) { // schedule cbAfterDelay callback
assert(delay > delta);
delay -= delta;
/* Icarus runs RO callbacks when time has already advanced */
/* Therefore, compensate for the prescheduled delta callback */
delay -= 1;
delta = 0;
pli_time = myhdl_time;
// register cbAfterDelay callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = (PLI_UINT32) delay;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delay_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
} else {
delta++;
assert(delta < 1000);
}
return(0);
}
static PLI_INT32 delay_callback(p_cb_data cb_data)
{
s_vpi_time time_s;
s_cb_data cb_data_s;
// register readonly callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 0;
cb_data_s.reason = cbReadOnlySynch;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = readonly_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
// register delta callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 1;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delta_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
return(0);
}
static PLI_INT32 delta_callback(p_cb_data cb_data)
{
s_cb_data cb_data_s;
s_vpi_time time_s;
vpiHandle systf_handle;
vpiHandle reg_iter, reg_handle;
s_vpi_value value_s;
if (delta == 0) {
return(0);
}
/* skip time value */
strtok(bufcp, " ");
reg_iter = vpi_iterate(vpiArgument, from_myhdl_systf_handle);
value_s.format = vpiHexStrVal;
while ((value_s.value.str = strtok(NULL, " ")) != NULL) {
reg_handle = vpi_scan(reg_iter);
vpi_put_value(reg_handle, &value_s, NULL, vpiNoDelay);
}
if (reg_iter != NULL) {
vpi_free_object(reg_iter);
}
// register readonly callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 0;
cb_data_s.reason = cbReadOnlySynch;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = readonly_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
// register delta callback //
time_s.type = vpiSimTime;
time_s.high = 0;
time_s.low = 1;
cb_data_s.reason = cbAfterDelay;
cb_data_s.user_data = NULL;
cb_data_s.cb_rtn = delta_callback;
cb_data_s.obj = NULL;
cb_data_s.time = &time_s;
cb_data_s.value = NULL;
vpi_register_cb(&cb_data_s);
return(0);
}
static PLI_INT32 change_callback(p_cb_data cb_data)
{
s_cb_data cb_data_s;
s_vpi_time time_s;
s_vpi_time verilog_time;
vpiHandle systf_handle;
int *id;
id = (int *)cb_data->user_data;
changeFlag[*id] = 1;
}
void myhdl_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$to_myhdl";
tf_data.calltf = (void *) to_myhdl_calltf;
tf_data.compiletf = NULL;
tf_data.sizetf = NULL;
tf_data.user_data = "$to_myhdl";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$from_myhdl";
tf_data.calltf = (void *) from_myhdl_calltf;
tf_data.compiletf = NULL;
tf_data.sizetf = NULL;
tf_data.user_data = "$from_myhdl";
vpi_register_systf(&tf_data);
}