📄 sci_alu_sequential_vpi.c
字号:
/**********************************************************************
* $scientific_alu example -- PLI application using VPI routines
*
* C model of a Scientific Arithmetic Logic Unit.
* Sequential logic version (output values are evaluated on the
* positive edge of the input clock, but are not stored).
*
* For the book, "The Verilog PLI Handbook" by Stuart Sutherland
* Book copyright 1999, Kluwer Academic Publishers, Norwell, MA, USA
* Contact: www.wkap.il
* Example copyright 1998, Sutherland HDL Inc, Portland, Oregon, USA
* Contact: www.sutherland.com or (503) 692-0898
*********************************************************************/
#include <math.h>
#include <ERRNO.h>
void PLIbook_ScientificALU_C_model(
double *result, /* output from ALU */
int *excep, /* output; set if result is out of range */
int *err, /* output; set if input is out of range */
double a, /* input */
double b, /* input */
int opcode) /* input */
{
switch (opcode) {
case 0x0: *result = pow (a, b); break;
case 0x1: *result = sqrt (a); break;
case 0x2: *result = exp (a); break;
case 0x3: *result = ldexp (a, (int)b); break;
case 0x4: *result = fabs (a); break;
case 0x5: *result = fmod (a, b); break;
case 0x6: *result = ceil (a); break;
case 0x7: *result = floor (a); break;
case 0x8: *result = log (a); break;
case 0x9: *result = log10 (a); break;
case 0xA: *result = sin (a); break;
case 0xB: *result = cos (a); break;
case 0xC: *result = tan (a); break;
case 0xD: *result = asin (a); break;
case 0xE: *result = acos (a); break;
case 0xF: *result = atan (a); break;
}
*err = (errno == EDOM); /* arg to math func. out of range */
*excep = (errno == ERANGE); /* result of math func. out of range */
errno = 0; /* clear the error flag */
if (*err) *result = 0.0; /* set result to 0 if error occurred */
return;
}
/*********************************************************************/
#include <stdlib.h> /* ANSI C standard library */
#include <stdio.h> /* ANSI C standard input/output library */
#include "vpi_user.h" /* IEEE 1364 PLI VPI routine library */
#include "veriuser.h" /* IEEE 1364 PLI TF routine library
(using TF routines for simulation control) */
/* prototypes of routines in this PLI application */
int PLIbook_ScientificALU_calltf(), PLIbook_ScientificALU_compiletf();
int PLIbook_ScientificALU_interface();
/**********************************************************************
* VPI Registration Data
*********************************************************************/
void PLIbook_ScientificALU_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$scientific_alu";
tf_data.calltf = PLIbook_ScientificALU_calltf;
tf_data.compiletf = PLIbook_ScientificALU_compiletf;
tf_data.sizetf = NULL;
tf_data.user_data = NULL;
vpi_register_systf(&tf_data);
}
/**********************************************************************
* Definition for a structure to hold the data to be passed from
* calltf routine to the ALU interface.
*********************************************************************/
typedef struct PLIbook_ScientificALU_data {
vpiHandle clock_h, a_h, b_h, opcode_h, result_h, excep_h, err_h;
} PLIbook_ALU_data_s, *PLIbook_ALU_data_p;
/**********************************************************************
* Value change simulation callback routine: Serves as an interface
* between Verilog simulation and the C model. Called whenever the
* C model inputs change value, passes the values to the C model, and
* puts the C model outputs into simulation.
*
* NOTE: The handles for the arguments to $scientific_alu were obtained
* in the calltf routine and saved in application-allocated memory. A
* pointer to this memory is passed to this callback via the user_data
* field.
*********************************************************************/
int PLIbook_ScientificALU_interface(p_cb_data cb_data)
{
double a, b, result;
int opcode, excep, err;
s_vpi_value value_s;
PLIbook_ALU_data_p ALUdata;
/* Retrieve pointer to ALU data structure from callback user_data. */
/* The structure contains the handles for the $scientific_alu args */
ALUdata = (PLIbook_ALU_data_p)cb_data->user_data;
/* Read current values of C model inputs from Verilog simulation */
value_s.format = vpiRealVal;
vpi_get_value(ALUdata->a_h, &value_s);
a = value_s.value.real;
vpi_get_value(ALUdata->b_h, &value_s);
b = value_s.value.real;
value_s.format = vpiIntVal;
vpi_get_value(ALUdata->opcode_h, &value_s);
opcode = value_s.value.integer;
/****** Call the C model ******/
PLIbook_ScientificALU_C_model(&result, &excep, &err, a, b, opcode);
/* Write the C model outputs onto the Verilog signals */
value_s.format = vpiRealVal;
value_s.value.real = result;
vpi_put_value(ALUdata->result_h, &value_s, NULL, vpiNoDelay);
value_s.format = vpiIntVal;
value_s.value.integer = excep;
vpi_put_value(ALUdata->excep_h, &value_s, NULL, vpiNoDelay);
value_s.value.integer = err;
vpi_put_value(ALUdata->err_h, &value_s, NULL, vpiNoDelay);
return(0);
}
/**********************************************************************
* calltf routine: Registers a callback to the C model interface
* whenever any input to the C model changes value
*********************************************************************/
int PLIbook_ScientificALU_calltf(char *user_data)
{
vpiHandle instance_h, arg_itr;
s_vpi_value value_s;
s_vpi_time time_s;
s_cb_data cb_data_s;
PLIbook_ALU_data_p ALUdata;
/* allocate storage to hold $scientific_alu argument handles */
ALUdata = (PLIbook_ALU_data_p)malloc(sizeof(PLIbook_ALU_data_s));
/* obtain a handle to the system task instance */
instance_h = vpi_handle(vpiSysTfCall, NULL);
/* obtain handles to system task arguments */
/* compiletf has already verified arguments are correct */
arg_itr = vpi_iterate(vpiArgument, instance_h);
ALUdata->clock_h = vpi_scan(arg_itr); /* 1st arg is clock input */
ALUdata->a_h = vpi_scan(arg_itr); /* 2nd arg is a input */
ALUdata->b_h = vpi_scan(arg_itr); /* 3rd arg is b input */
ALUdata->opcode_h = vpi_scan(arg_itr); /* 4th arg is opcode input */
ALUdata->result_h = vpi_scan(arg_itr); /* 5th arg is result output */
ALUdata->excep_h = vpi_scan(arg_itr); /* 6th arg is excep output */
ALUdata->err_h = vpi_scan(arg_itr); /* 7th arg is error output */
vpi_free_object(arg_itr); /* free iterator--did not scan to null */
/* setup value change callback options */
time_s.type = vpiSuppressTime;
cb_data_s.reason = cbValueChange;
cb_data_s.cb_rtn = PLIbook_ScientificALU_interface;
cb_data_s.time = &time_s;
cb_data_s.value = &value_s;
/* add value change callbacks to clock input to the C model, */
/* pass pointer to storage for handles as user_data value */
value_s.format = vpiSuppressVal;
cb_data_s.user_data = (char *)ALUdata;
cb_data_s.obj = ALUdata->clock_h;
vpi_register_cb(&cb_data_s);
return(0);
}
/**********************************************************************
* compiletf routine: Verifies that $scientific_alu() is used correctly
* Note: For simplicity, only limited data types are allowed for
* task arguments. Could add checks to allow other data types.
*********************************************************************/
int PLIbook_ScientificALU_compiletf(char *user_data)
{
vpiHandle systf_h, arg_itr, arg_h;
int err = 0;
systf_h = vpi_handle(vpiSysTfCall, NULL);
arg_itr = vpi_iterate(vpiArgument, systf_h);
if (arg_itr == NULL) {
vpi_printf("ERROR: $scientific_alu requires 7 arguments\n");
tf_dofinish();
return(0);
}
arg_h = vpi_scan(arg_itr); /* 1st arg is clock input */
if (vpi_get(vpiType, arg_h) != vpiNet) {
vpi_printf("$scientific_alu arg 1 (clock) must be a net\n");
err = 1;
}
else if (vpi_get(vpiSize, arg_h) != 1) {
vpi_printf("$scientific_alu arg 1 (clock) must be scalar\n");
err = 1;
}
arg_h = vpi_scan(arg_itr); /* 2nd arg is a input */
if (vpi_get(vpiType, arg_h) != vpiRealVar) {
vpi_printf("$scientific_alu arg 2 (a) must be a real variable\n");
err = 1;
}
arg_h = vpi_scan(arg_itr); /* 3rd arg is b input */
if (vpi_get(vpiType, arg_h) != vpiRealVar) {
vpi_printf("$scientific_alu arg 3 (b) must be a real variable\n");
err = 1;
}
arg_h = vpi_scan(arg_itr); /* 4th arg is opcode input */
if (vpi_get(vpiType, arg_h) != vpiNet) {
vpi_printf("$scientific_alu arg 4 (opcode) must be a net\n");
err = 1;
}
else if (vpi_get(vpiSize, arg_h) != 4) {
vpi_printf("$scientific_alu arg 4 (opcode) must be 4-bit vector\n");
err = 1;
}
arg_h = vpi_scan(arg_itr); /* 5th arg is result output */
if (vpi_get(vpiType, arg_h) != vpiRealVar) {
vpi_printf("$scientific_alu arg 5 (result) must be a real var.\n");
err = 1;
}
arg_h = vpi_scan(arg_itr); /* 6th arg is exception output */
if (vpi_get(vpiType, arg_h) != vpiReg) {
vpi_printf("$scientific_alu arg 6 (exception) must be a reg\n");
err = 1;
}
else if (vpi_get(vpiSize, arg_h) != 1) {
vpi_printf("$scientific_alu arg 6 (exception) must be scalar\n");
err = 1;
}
arg_h = vpi_scan(arg_itr); /* 7th arg is error output */
if (vpi_get(vpiType, arg_h) != vpiReg) {
vpi_printf("$scientific_alu arg 7 (error) must be a reg\n");
err = 1;
}
else if (vpi_get(vpiSize, arg_h) != 1) {
vpi_printf("$scientific_alu arg 7 (error) must be scalar\n");
err = 1;
}
if (vpi_scan(arg_itr) != NULL) { /* should not be any more args */
vpi_printf("ERROR: $scientific_alu requires only 7 arguments\n");
vpi_free_object(arg_itr);
err = 1;
}
if (err) {
tf_dofinish();
return(0);
}
}
/*********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -