Extract system function return types from VPI modules, not SFT files.
This commit is contained in:
parent
df38460d26
commit
9f93989944
|
|
@ -117,7 +117,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
|||
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
|
||||
pform_disciplines.o pform_dump.o pform_package.o pform_pclass.o \
|
||||
pform_class_type.o pform_string_type.o pform_struct_type.o pform_types.o \
|
||||
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
|
||||
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o vpi_modules.o target.o \
|
||||
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PFunction.o \
|
||||
PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o \
|
||||
PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT)
|
||||
|
|
|
|||
|
|
@ -290,9 +290,16 @@ struct sfunc_return_type {
|
|||
bool override_flag;
|
||||
};
|
||||
|
||||
extern void add_sys_func(const struct sfunc_return_type&ret_type);
|
||||
extern const struct sfunc_return_type* lookup_sys_func(const char*name);
|
||||
extern int load_sys_func_table(const char*path);
|
||||
extern void cleanup_sys_func_table();
|
||||
/*
|
||||
* This temporarily loads a VPI module, to determine the return values
|
||||
* of system functions provided by that module, and adds the return values
|
||||
* to the system function table.
|
||||
*/
|
||||
extern bool load_vpi_module(const char*path);
|
||||
|
||||
/*
|
||||
* In system Verilog it is allowed with a warning to call a function
|
||||
|
|
|
|||
105
driver/main.c
105
driver/main.c
|
|
@ -40,7 +40,7 @@ const char NOTICE[] =
|
|||
const char HELP[] =
|
||||
"Usage: iverilog [-EiSuvV] [-B base] [-c cmdfile|-f cmdfile]\n"
|
||||
" [-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g<feature>]\n"
|
||||
" [-D macro[=defn]] [-I includedir]\n"
|
||||
" [-D macro[=defn]] [-I includedir] [-L moduledir]\n"
|
||||
" [-M [mode=]depfile] [-m module]\n"
|
||||
" [-N file] [-o filename] [-p flag=value]\n"
|
||||
" [-s topmodule] [-t target] [-T min|typ|max]\n"
|
||||
|
|
@ -169,6 +169,9 @@ char*compiled_defines_path = 0;
|
|||
|
||||
static char iconfig_common_path[4096] = "";
|
||||
|
||||
static const char**vpi_path_list = 0;
|
||||
static unsigned vpi_path_list_size = 0;
|
||||
|
||||
int synth_flag = 0;
|
||||
int verbose_flag = 0;
|
||||
|
||||
|
|
@ -673,14 +676,19 @@ void process_timescale(const char*ts_string)
|
|||
/*
|
||||
* This function is called while processing a file name in a command
|
||||
* file, or a file name on the command line. Look to see if there is a
|
||||
* .sft suffix, and if so pass that as a sys_func file. Otherwise, it
|
||||
* is a Verilog source file to be written into the file list.
|
||||
* .sft or .vpi suffix, and if so pass that as a sys_func or module
|
||||
* file. Otherwise, it is a Verilog source file to be written into the
|
||||
* file list.
|
||||
*/
|
||||
void process_file_name(const char*name, int lib_flag)
|
||||
{
|
||||
if (strlen(name) > 4 && strcasecmp(".sft", name+strlen(name)-4) == 0) {
|
||||
fprintf(stderr, "SFT files are deprecated. Please pass the VPI module instead.\n");
|
||||
fprintf(iconfig_file,"sys_func:%s\n", name);
|
||||
|
||||
} else if (strlen(name) > 4 && strcasecmp(".vpi", name+strlen(name)-4) == 0) {
|
||||
fprintf(iconfig_file,"module:%s\n", name);
|
||||
|
||||
} else {
|
||||
fprintf(source_file, "%s\n", name);
|
||||
source_count += 1;
|
||||
|
|
@ -857,24 +865,54 @@ static int process_depfile(const char*name)
|
|||
}
|
||||
|
||||
/*
|
||||
* If it exists add the SFT file for the given module.
|
||||
* If it exists add the VPI file for the given module.
|
||||
*/
|
||||
static void add_sft_file(const char *module)
|
||||
static void add_vpi_file(const char *name)
|
||||
{
|
||||
char *file;
|
||||
char path[4096];
|
||||
|
||||
file = (char *) malloc(strlen(base)+1+strlen(module)+4+1);
|
||||
// If the module name has at least one directory character
|
||||
// in it, assume it includes the path, otherwise look in
|
||||
// the base directory.
|
||||
if (strchr(module, sep))
|
||||
sprintf(file, "%s.sft", module);
|
||||
else
|
||||
sprintf(file, "%s%c%s.sft", base, sep, module);
|
||||
|
||||
if (access(file, R_OK) == 0)
|
||||
fprintf(iconfig_file, "sys_func:%s\n", file);
|
||||
free(file);
|
||||
int found = 0;
|
||||
if (strchr(name, sep)) {
|
||||
/* If the name has at least one directory character in it
|
||||
then assume it is a complete name, maybe including any
|
||||
possible .vpi or .vpl suffix. */
|
||||
found = access(name, R_OK) == 0;
|
||||
if (!found) {
|
||||
snprintf(path, sizeof(path), "%s.vpi", name);
|
||||
found = access(path, R_OK) == 0;
|
||||
if (!found) {
|
||||
snprintf(path, sizeof(path), "%s.vpl", name);
|
||||
found = access(path, R_OK) == 0;
|
||||
}
|
||||
if (!found)
|
||||
fprintf(stderr, "Unable to find VPI module '%s'\n", name);
|
||||
} else {
|
||||
strncpy(path, name, sizeof(path) - 1);
|
||||
}
|
||||
} else {
|
||||
for (unsigned idx = 0; idx < vpi_path_list_size; idx += 1) {
|
||||
snprintf(path, sizeof(path), "%s%c%s.vpi",
|
||||
vpi_path_list[idx], sep, name);
|
||||
found = access(path, R_OK) == 0;
|
||||
if (found) break;
|
||||
snprintf(path, sizeof(path), "%s%c%s.vpl",
|
||||
vpi_path_list[idx], sep, name);
|
||||
found = access(path, R_OK) == 0;
|
||||
if (found) break;
|
||||
}
|
||||
if (!found) {
|
||||
snprintf(path, sizeof(path), "%s%c%s.vpi", base, sep, name);
|
||||
found = access(path, R_OK) == 0;
|
||||
}
|
||||
if (!found) {
|
||||
snprintf(path, sizeof(path), "%s%c%s.vpl", base, sep, name);
|
||||
found = access(path, R_OK) == 0;
|
||||
}
|
||||
if (!found)
|
||||
fprintf(stderr, "Unable to find VPI module '%s' on the search path.\n", name);
|
||||
}
|
||||
if (found)
|
||||
fprintf(iconfig_file, "module:%s\n", path);
|
||||
}
|
||||
|
||||
static void find_ivl_root_failed(const char *reason)
|
||||
|
|
@ -1039,7 +1077,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iM:m:N:o:P:p:Ss:T:t:uvVW:y:Y:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:iL:M:m:N:o:P:p:Ss:T:t:uvVW:y:Y:")) != EOF) {
|
||||
|
||||
switch (opt) {
|
||||
case 'B':
|
||||
|
|
@ -1098,6 +1136,13 @@ int main(int argc, char **argv)
|
|||
ignore_missing_modules = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
vpi_path_list_size += 1;
|
||||
vpi_path_list = (const char**)realloc(vpi_path_list,
|
||||
vpi_path_list_size*sizeof(char*));
|
||||
vpi_path_list[vpi_path_list_size-1] = optarg;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
process_file_name(optarg, 1);
|
||||
break;
|
||||
|
|
@ -1108,8 +1153,7 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
|
||||
case 'm':
|
||||
fprintf(iconfig_file, "module:%s\n", optarg);
|
||||
add_sft_file(optarg);
|
||||
add_vpi_file(optarg);
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
|
@ -1198,12 +1242,10 @@ int main(int argc, char **argv)
|
|||
/* Write values to the iconfig file. */
|
||||
fprintf(iconfig_file, "basedir:%s\n", base);
|
||||
|
||||
/* Tell the core where to find the system.sft. This file
|
||||
describes the system functions so that elaboration knows
|
||||
how to handle them. */
|
||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "sys_func:%s%cvhdl_textio.sft\n", base, sep);
|
||||
/* Tell the core where to find the system VPI modules. */
|
||||
fprintf(iconfig_file, "module:%s%csystem.vpi\n", base, sep);
|
||||
fprintf(iconfig_file, "module:%s%cvhdl_sys.vpi\n", base, sep);
|
||||
fprintf(iconfig_file, "module:%s%cvhdl_textio.vpi\n", base, sep);
|
||||
|
||||
/* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams,
|
||||
* then include the v2005_math library. */
|
||||
|
|
@ -1212,23 +1254,20 @@ int main(int argc, char **argv)
|
|||
strcmp(generation, "2012") == 0 ||
|
||||
strcmp(gen_icarus, "icarus-misc") == 0 ||
|
||||
strcmp(gen_verilog_ams, "verilog-ams") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cv2005_math.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:v2005_math\n");
|
||||
fprintf(iconfig_file, "module:%s%cv2005_math.vpi\n", base, sep);
|
||||
}
|
||||
/* If verilog-ams or icarus_misc is enabled, then include the
|
||||
* va_math module as well. */
|
||||
if (strcmp(gen_verilog_ams,"verilog-ams") == 0 ||
|
||||
strcmp(gen_icarus, "icarus-misc") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cva_math.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:va_math\n");
|
||||
fprintf(iconfig_file, "module:%s%cva_math.vpi\n", base, sep);
|
||||
}
|
||||
/* If verilog-2009 (SystemVerilog) is enabled, then include the
|
||||
v2009 module. */
|
||||
if (strcmp(generation, "2005-sv") == 0 ||
|
||||
strcmp(generation, "2009") == 0 ||
|
||||
strcmp(generation, "2012") == 0) {
|
||||
fprintf(iconfig_file, "sys_func:%s%cv2009.sft\n", base, sep);
|
||||
fprintf(iconfig_file, "module:v2009\n");
|
||||
fprintf(iconfig_file, "module:%s%cv2009.vpi\n", base, sep);
|
||||
}
|
||||
|
||||
if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm);
|
||||
|
|
|
|||
6
main.cc
6
main.cc
|
|
@ -136,6 +136,7 @@ void add_vpi_module(const char*name)
|
|||
vpi_module_list = tmp;
|
||||
}
|
||||
flags["VPI_MODULE_LIST"] = vpi_module_list;
|
||||
load_vpi_module(name);
|
||||
}
|
||||
|
||||
map<perm_string,unsigned> missing_modules;
|
||||
|
|
@ -900,11 +901,6 @@ int main(int argc, char*argv[])
|
|||
}
|
||||
library_suff.push_back(strdup(".v"));
|
||||
|
||||
// Start the module list with the base system module.
|
||||
add_vpi_module("system");
|
||||
add_vpi_module("vhdl_sys");
|
||||
add_vpi_module("vhdl_textio");
|
||||
|
||||
flags["-o"] = strdup("a.out");
|
||||
min_typ_max_flag = TYP;
|
||||
min_typ_max_warn = 10;
|
||||
|
|
|
|||
18
sys_funcs.cc
18
sys_funcs.cc
|
|
@ -104,6 +104,24 @@ const struct sfunc_return_type* lookup_sys_func(const char*name)
|
|||
return sfunc_table + idx;
|
||||
}
|
||||
|
||||
void add_sys_func(const struct sfunc_return_type&ret_type)
|
||||
{
|
||||
struct sfunc_return_type*def = find_in_sys_func_list(ret_type.name);
|
||||
if (def) {
|
||||
/* Keep the original definition, but flag that it
|
||||
overrides a later definition. */
|
||||
def->override_flag = true;
|
||||
return;
|
||||
}
|
||||
struct sfunc_return_type_cell*cell = new struct sfunc_return_type_cell;
|
||||
cell->name = lex_strings.add(ret_type.name);
|
||||
cell->type = ret_type.type;
|
||||
cell->wid = ret_type.wid;
|
||||
cell->signed_flag = ret_type.signed_flag;
|
||||
cell->override_flag = ret_type.override_flag;
|
||||
append_to_list(cell);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function loads a system functions descriptor file with the
|
||||
* format:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Martin Whitaker (icarus@martin-whitaker.me.uk)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "compiler.h"
|
||||
#include "vpi_user.h"
|
||||
#include "sv_vpi_user.h"
|
||||
#include "vvp/ivl_dlfcn.h"
|
||||
|
||||
/* The only VPI routines that can be legally called when the functions in
|
||||
the vlog_startup_routines[] array are executed are vpi_register_systf()
|
||||
and vpi_register_cb(), so we can simply provide stubs for the rest. We
|
||||
aren't going to execute any callbacks, so we can just provide a stub for
|
||||
vpi_register_cb() too.
|
||||
|
||||
Note that the Icarus system module illegally calls vpi_get_vlog_info()
|
||||
during startup, so take care to fill in the data structure for that.
|
||||
*/
|
||||
|
||||
// callback related
|
||||
|
||||
vpiHandle vpi_register_cb(p_cb_data) { return 0; }
|
||||
PLI_INT32 vpi_remove_cb(vpiHandle) { return 0; }
|
||||
|
||||
void vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { }
|
||||
|
||||
// for obtaining handles
|
||||
|
||||
vpiHandle vpi_handle_by_name(const char*, vpiHandle) { return 0; }
|
||||
vpiHandle vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; }
|
||||
|
||||
// for traversing relationships
|
||||
|
||||
vpiHandle vpi_handle(PLI_INT32, vpiHandle) { return 0; }
|
||||
vpiHandle vpi_iterate(PLI_INT32, vpiHandle) { return 0; }
|
||||
vpiHandle vpi_scan(vpiHandle) { return 0; }
|
||||
|
||||
// for processing properties
|
||||
|
||||
PLI_INT32 vpi_get(int, vpiHandle) { return 0; }
|
||||
char* vpi_get_str(PLI_INT32, vpiHandle) { return 0; }
|
||||
|
||||
// delay processing
|
||||
|
||||
void vpi_get_delays(vpiHandle, p_vpi_delay) { }
|
||||
void vpi_put_delays(vpiHandle, p_vpi_delay) { }
|
||||
|
||||
// value processing
|
||||
|
||||
void vpi_get_value(vpiHandle, p_vpi_value) { }
|
||||
vpiHandle vpi_put_value(vpiHandle, p_vpi_value, p_vpi_time, PLI_INT32) { return 0; }
|
||||
|
||||
// time processing
|
||||
|
||||
void vpi_get_time(vpiHandle, s_vpi_time*) { }
|
||||
|
||||
// data processing
|
||||
|
||||
void* vpi_get_userdata(vpiHandle) { return 0; }
|
||||
PLI_INT32 vpi_put_userdata(vpiHandle, void*) { return 0; }
|
||||
|
||||
// I/O routines
|
||||
|
||||
PLI_UINT32 vpi_mcd_open(char *) { return 0; }
|
||||
PLI_UINT32 vpi_mcd_close(PLI_UINT32) { return 0; }
|
||||
PLI_INT32 vpi_mcd_flush(PLI_UINT32) { return 0; }
|
||||
char* vpi_mcd_name(PLI_UINT32) { return 0; }
|
||||
PLI_INT32 vpi_mcd_printf(PLI_UINT32, const char*, ...) { return 0; }
|
||||
PLI_INT32 vpi_mcd_vprintf(PLI_UINT32, const char*, va_list) { return 0; }
|
||||
|
||||
PLI_INT32 vpi_flush(void) { return 0; }
|
||||
PLI_INT32 vpi_printf(const char*, ...) { return 0; }
|
||||
PLI_INT32 vpi_vprintf(const char*, va_list) { return 0; }
|
||||
|
||||
// utility routines
|
||||
|
||||
PLI_INT32 vpi_chk_error(p_vpi_error_info) { return 0; }
|
||||
PLI_INT32 vpi_compare_objects(vpiHandle, vpiHandle) { return 0; }
|
||||
PLI_INT32 vpi_free_object(vpiHandle) { return 0; }
|
||||
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info)
|
||||
{
|
||||
info->argc = 0;
|
||||
info->argv = 0;
|
||||
info->product = 0;
|
||||
info->version = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// control routines
|
||||
|
||||
void vpi_control(PLI_INT32, ...) { }
|
||||
void vpi_sim_control(PLI_INT32, ...) { }
|
||||
|
||||
// proposed standard extensions
|
||||
|
||||
PLI_INT32 vpi_fopen(const char*, const char*) { return 0; }
|
||||
FILE* vpi_get_file(PLI_INT32) { return 0; }
|
||||
|
||||
// Icarus extensions
|
||||
|
||||
s_vpi_vecval vpip_calc_clog2(vpiHandle)
|
||||
{
|
||||
s_vpi_vecval val = { 0, 0 };
|
||||
return val;
|
||||
}
|
||||
void vpip_count_drivers(vpiHandle, unsigned, unsigned [4]) { }
|
||||
void vpip_format_strength(char*, s_vpi_value*, unsigned) { }
|
||||
void vpip_make_systf_system_defined(vpiHandle) { }
|
||||
void vpip_mcd_rawwrite(PLI_UINT32, const char*, size_t) { }
|
||||
void vpip_set_return_value(int) { }
|
||||
|
||||
|
||||
/* When a module registers a system function, extract and save the return
|
||||
type for use during elaboration. */
|
||||
vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss)
|
||||
{
|
||||
if (ss->type != vpiSysFunc)
|
||||
return 0;
|
||||
|
||||
struct sfunc_return_type ret_type;
|
||||
ret_type.name = ss->tfname;
|
||||
switch (ss->sysfunctype) {
|
||||
case vpiIntFunc:
|
||||
ret_type.type = IVL_VT_LOGIC;
|
||||
ret_type.wid = 32;
|
||||
ret_type.signed_flag = true;
|
||||
break;
|
||||
case vpiRealFunc:
|
||||
ret_type.type = IVL_VT_REAL;
|
||||
ret_type.wid = 1;
|
||||
ret_type.signed_flag = true;
|
||||
break;
|
||||
case vpiTimeFunc:
|
||||
ret_type.type = IVL_VT_LOGIC;
|
||||
ret_type.wid = 64;
|
||||
ret_type.signed_flag = false;
|
||||
break;
|
||||
case vpiSizedFunc:
|
||||
ret_type.type = IVL_VT_LOGIC;
|
||||
ret_type.wid = ss->sizetf ? ss->sizetf(ss->user_data) : 32;
|
||||
ret_type.signed_flag = false;
|
||||
break;
|
||||
case vpiSizedSignedFunc:
|
||||
ret_type.type = IVL_VT_LOGIC;
|
||||
ret_type.wid = ss->sizetf ? ss->sizetf(ss->user_data) : 32;
|
||||
ret_type.signed_flag = true;
|
||||
break;
|
||||
case vpiStringFunc:
|
||||
ret_type.type = IVL_VT_STRING;
|
||||
ret_type.wid = 0;
|
||||
ret_type.signed_flag = false;
|
||||
break;
|
||||
case vpiOtherFunc:
|
||||
ret_type.type = IVL_VT_NO_TYPE;
|
||||
ret_type.wid = 0;
|
||||
ret_type.signed_flag = false;
|
||||
break;
|
||||
default:
|
||||
cerr << "warning: " << ss->tfname << " has an unknown return type. "
|
||||
"Assuming 32 bit unsigned." << endl;
|
||||
ret_type.type = IVL_VT_LOGIC;
|
||||
ret_type.wid = 32;
|
||||
ret_type.signed_flag = false;
|
||||
break;
|
||||
}
|
||||
ret_type.override_flag = false;
|
||||
add_sys_func(ret_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void (*vlog_startup_routines_t)(void);
|
||||
|
||||
bool load_vpi_module(const char*path)
|
||||
{
|
||||
ivl_dll_t dll = ivl_dlopen(path, false);
|
||||
if (dll == 0) {
|
||||
cerr << "error: Failed to open '" << path << "' because:" << endl;
|
||||
cerr << " : " << dlerror() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
void*table = ivl_dlsym(dll, "vlog_startup_routines");
|
||||
#else
|
||||
void*table = ivl_dlsym(dll, LU "vlog_startup_routines" TU);
|
||||
#endif
|
||||
if (table == 0) {
|
||||
cerr << "warning: '" << path << "' has no vlog_startup_routines" << endl;
|
||||
ivl_dlclose(dll);
|
||||
return true;
|
||||
}
|
||||
|
||||
vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
|
||||
for (unsigned idx = 0; routines[idx]; idx += 1) {
|
||||
(routines[idx])();
|
||||
}
|
||||
|
||||
ivl_dlclose(dll);
|
||||
return true;
|
||||
}
|
||||
Loading…
Reference in New Issue