Add VPI examples

This commit is contained in:
Nikolay Puzanov 2022-07-12 18:47:44 +03:00
parent d298a14bff
commit 2c8c60429c
10 changed files with 257 additions and 0 deletions

View File

@ -0,0 +1,2 @@
*.o
*.vpi

View File

@ -0,0 +1,16 @@
`ifndef UTEST_VERILOG_DEFINES
`define UTEST_VERILOG_DEFINES
// Log level string prefixes for use with $display function.
// Example usage: $display("%sError message", `LOG_ERR);
`define LOG_INFO "INFO#"
`define LOG_WARN "WARN#"
`define LOG_ERR "FAIL#"
// Dirty hacked redefine of $display function. Must be used with two parentheses.
// Example usage: `log_info(("Information message"));
`define log_quiet(msg) begin $display({$sformatf msg}); end
`define log_info(msg) begin $display({`LOG_INFO, $sformatf msg}); end
`define log_warn(msg) begin $display({`LOG_WARN, $sformatf msg}); end
`define log_error(msg) begin $display({`LOG_ERR, $sformatf msg}); end
`endif

View File

@ -0,0 +1,67 @@
#include <math.h>
#include <stdlib.h>
#include <vpi_user.h>
/* --------------------------- VPI INTERFACE -------------------------------- */
#define MAX_ARGS 8
static int calltf(char *user_data)
{
vpiHandle systfref, arg_iter;
vpiHandle arg_hndl[MAX_ARGS];
struct t_vpi_value argval;
int arg_cnt = 0;
for (int i = 0; i < MAX_ARGS; i++)
arg_hndl[i] = NULL;
systfref = vpi_handle(vpiSysTfCall, NULL);
arg_iter = vpi_iterate(vpiArgument, systfref);
/* ---- Get agruments ---- */
if (arg_iter != NULL)
while (arg_cnt < MAX_ARGS &&
NULL != (arg_hndl[arg_cnt] = vpi_scan(arg_iter)))
arg_cnt++;
// function $log2
if (arg_cnt != 1)
vpi_printf("ERROR: $log2() wrong argument count\n");
else {
double arg, ret;
// get argument
argval.format = vpiRealVal;
vpi_get_value(arg_hndl[0], &argval);
arg = argval.value.real;
ret = log2(arg);
// put return value
argval.format = vpiRealVal;
argval.value.real = ret;
vpi_put_value(systfref, &argval, NULL, vpiNoDelay);
}
for (int i = 0; i < MAX_ARGS; i++)
if (arg_hndl[i]) vpi_free_object(arg_hndl[i]);
return 0;
}
static void register_interface(void)
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiRealFunc;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.calltf = calltf;
tf_data.tfname = "$log2";
vpi_register_systf(&tf_data);
}
typedef void (*stfunc)(void);
stfunc vlog_startup_routines[] = {register_interface, 0};

View File

@ -0,0 +1,22 @@
`timescale 1ps/1ps
`include "utest.vh"
module vpi_log2 #(parameter ARGUMENT = 1.0,
parameter SIGMA = 1e-6);
real dut, gold;
initial begin
gold = $ln(ARGUMENT) / $ln(2);
dut = $log2(ARGUMENT);
`log_info(("Gold: %0f", gold));
`log_info((" DUT: %0f", dut));
if ($abs(gold - dut) > SIGMA)
`log_error(("FAIL"));
$finish;
end
endmodule // vpi_log2

View File

@ -0,0 +1,25 @@
;; -*- scheme -*-
;; Uses one common VPI module compiled in the testbench base directory
(let ((top "vpi_log2"))
;; compile VPI module in the base directory
(if (utest/iverilog-compile-vpi "vpi_log2.c"
#:output-dir (utest/base-path)
#:name top #:libs "m")
(map
(lambda (arg)
(utest/tb
((format "log2_~a" arg))
(utest/run-simulation-iverilog
"vpi_log2.sv"
top
#:parameters `((ARGUMENT ,arg))
#:vpimods top
;; VPI modules search path
#:vpipaths (utest/base-path))))
(iota 20))
#f))

View File

@ -0,0 +1,16 @@
`ifndef UTEST_VERILOG_DEFINES
`define UTEST_VERILOG_DEFINES
// Log level string prefixes for use with $display function.
// Example usage: $display("%sError message", `LOG_ERR);
`define LOG_INFO "INFO#"
`define LOG_WARN "WARN#"
`define LOG_ERR "FAIL#"
// Dirty hacked redefine of $display function. Must be used with two parentheses.
// Example usage: `log_info(("Information message"));
`define log_quiet(msg) begin $display({$sformatf msg}); end
`define log_info(msg) begin $display({`LOG_INFO, $sformatf msg}); end
`define log_warn(msg) begin $display({`LOG_WARN, $sformatf msg}); end
`define log_error(msg) begin $display({`LOG_ERR, $sformatf msg}); end
`endif

View File

@ -0,0 +1,67 @@
#include <math.h>
#include <stdlib.h>
#include <vpi_user.h>
/* --------------------------- VPI INTERFACE -------------------------------- */
#define MAX_ARGS 8
static int calltf(char *user_data)
{
vpiHandle systfref, arg_iter;
vpiHandle arg_hndl[MAX_ARGS];
struct t_vpi_value argval;
int arg_cnt = 0;
for (int i = 0; i < MAX_ARGS; i++)
arg_hndl[i] = NULL;
systfref = vpi_handle(vpiSysTfCall, NULL);
arg_iter = vpi_iterate(vpiArgument, systfref);
/* ---- Get agruments ---- */
if (arg_iter != NULL)
while (arg_cnt < MAX_ARGS &&
NULL != (arg_hndl[arg_cnt] = vpi_scan(arg_iter)))
arg_cnt++;
// function $log2
if (arg_cnt != 1)
vpi_printf("ERROR: $log2() wrong argument count\n");
else {
double arg, ret;
// get argument
argval.format = vpiRealVal;
vpi_get_value(arg_hndl[0], &argval);
arg = argval.value.real;
ret = log2(arg);
// put return value
argval.format = vpiRealVal;
argval.value.real = ret;
vpi_put_value(systfref, &argval, NULL, vpiNoDelay);
}
for (int i = 0; i < MAX_ARGS; i++)
if (arg_hndl[i]) vpi_free_object(arg_hndl[i]);
return 0;
}
static void register_interface(void)
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysFunc;
tf_data.sysfunctype = vpiRealFunc;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.calltf = calltf;
tf_data.tfname = "$log2";
vpi_register_systf(&tf_data);
}
typedef void (*stfunc)(void);
stfunc vlog_startup_routines[] = {register_interface, 0};

View File

@ -0,0 +1,22 @@
`timescale 1ps/1ps
`include "utest.vh"
module vpi_log2 #(parameter ARGUMENT = 1.0,
parameter SIGMA = 1e-6);
real dut, gold;
initial begin
gold = $ln(ARGUMENT) / $ln(2);
dut = $log2(ARGUMENT);
`log_info(("Gold: %0f", gold));
`log_info((" DUT: %0f", dut));
if ($abs(gold - dut) > SIGMA)
`log_error(("FAIL"));
$finish;
end
endmodule // vpi_log2

View File

@ -0,0 +1,19 @@
;; -*- scheme -*-
;; Compile VPI module for each test
(let ((top "vpi_log2"))
(map
(lambda (arg)
(utest/tb
((format "log2_~a" arg))
(if (utest/iverilog-compile-vpi "vpi_log2.c" #:name top #:libs "m")
(utest/run-simulation-iverilog
"vpi_log2.sv"
top
#:parameters `((ARGUMENT ,arg))
#:vpimods top)
#f)))
(iota 20)))

1
examples/simple-counter/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/work