From 63befc0f073e599f32fd4a7a8f0a5f2c7c65c527 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 18 May 2024 16:43:05 +0100 Subject: [PATCH] Add support for packages in VHPI. Issue #891 --- .github/workflows/build-test.yml | 2 +- src/vhpi/vhpi-model.c | 188 +++++++++++++++++++++++++------ test/regress/testlist.txt | 1 + test/regress/vhpi15.vhd | 18 +++ test/vhpi/Makemodule.am | 3 +- test/vhpi/vhpi15.c | 111 ++++++++++++++++++ test/vhpi/vhpi_test.c | 9 ++ test/vhpi/vhpi_test.h | 3 + 8 files changed, 300 insertions(+), 35 deletions(-) create mode 100644 test/regress/vhpi15.vhd create mode 100644 test/vhpi/vhpi15.c diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 83e50bfa..3e323c65 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -450,7 +450,7 @@ jobs: python3 -mvirtualenv venv . venv/bin/activate pip install nox - nox -k "dev_test and nvc and vhdl" + nox -k "dev_test_sim and nvc and vhdl" msi-installer: name: Windows installer diff --git a/src/vhpi/vhpi-model.c b/src/vhpi/vhpi-model.c index ddcf4c86..21e90453 100644 --- a/src/vhpi/vhpi-model.c +++ b/src/vhpi/vhpi-model.c @@ -399,6 +399,10 @@ typedef struct { vhpiObjectListT ports; } c_entityDecl; +typedef struct { + c_designUnit designUnit; +} c_packDecl; + typedef struct { c_abstractRegion region; c_designUnit *DesignUnit; @@ -410,6 +414,12 @@ typedef struct { DEF_CLASS(rootInst, vhpiRootInstK, designInstUnit.region.object); +typedef struct { + c_designInstUnit designInstUnit; +} c_packInst; + +DEF_CLASS(packInst, vhpiPackInstK, designInstUnit.region.object); + typedef struct { vhpiBooleanT IsSeqStmt; vhpiStringT LabelName; @@ -480,6 +490,7 @@ typedef struct { typedef struct _vhpi_context { c_tool *tool; c_rootInst *root; + vhpiObjectListT packages; shash_t *strtab; rt_model_t *model; hash_t *objcache; @@ -503,6 +514,7 @@ static c_typeDecl *vhpi_get_type(c_vhpiObject *obj); static vhpiClassKindT vhpi_get_prefix_kind(c_vhpiObject *obj); static void vhpi_build_stmts(tree_t container, c_abstractRegion *region); static const char *handle_pp(vhpiHandleT handle); +static void vhpi_find_packages(vhpi_context_t *c); static vhpi_context_t *global_context = NULL; // TODO: thread local @@ -635,6 +647,7 @@ static c_abstractRegion *is_abstractRegion(c_vhpiObject *obj) case vhpiBlockStmtK: case vhpiCompInstStmtK: case vhpiForGenerateK: + case vhpiPackInstK: return container_of(obj, c_abstractRegion, object); default: return NULL; @@ -840,6 +853,7 @@ static c_designInstUnit *cast_designInstUnit(c_vhpiObject *obj) switch (obj->kind) { case vhpiRootInstK: case vhpiCompInstStmtK: + case vhpiPackInstK: return container_of(obj, c_designInstUnit, region.object); default: vhpi_error(vhpiError, &(obj->loc), "class kind %s is not an instance of " @@ -942,9 +956,19 @@ static void init_abstractRegion(c_abstractRegion *r, tree_t t) r->LineNo = loc->first_line; r->LineOffset = loc->line_delta; - r->Name = r->CaseName = new_string(istr(tree_ident(t))); - char *full LOCAL = xasprintf(":%s", r->Name); - r->FullName = r->FullCaseName = new_string(full); + if (is_design_unit(t)) { + ident_t qual = tree_ident(t); + ident_t suffix = ident_rfrom(qual, '.'); + + r->Name = r->CaseName = new_string(istr(suffix)); + char *full LOCAL = xasprintf("@%s", istr(qual)); + r->FullName = r->FullCaseName = new_string(full); + } + else { + r->Name = r->CaseName = new_string(istr(tree_ident(t))); + char *full LOCAL = xasprintf(":%s", r->Name); + r->FullName = r->FullCaseName = new_string(full); + } r->tree = t; r->handle = JIT_HANDLE_INVALID; @@ -1283,6 +1307,11 @@ static void init_entityDecl(c_entityDecl *e, tree_t t) init_designUnit(&(e->designUnit), t); } +static void init_packDecl(c_packDecl *p, tree_t t) +{ + init_designUnit(&(p->designUnit), t); +} + static void expand_lazy_region(c_abstractRegion *r) { if (r->lazyfn == NULL) @@ -1296,6 +1325,20 @@ static bool init_iterator(c_iterator *it, vhpiOneToManyT type, c_vhpiObject *obj { it->filter = vhpiUndefined; + if (obj == NULL) { + switch (type) { + case vhpiPackInsts: + { + vhpi_context_t *c = vhpi_context(); + vhpi_find_packages(c); + it->list = &(c->packages); + return true; + } + default: + return false; + } + } + c_abstractRegion *region = is_abstractRegion(obj); if (region != NULL) { expand_lazy_region(region); @@ -1727,16 +1770,30 @@ static void *vhpi_get_value_ptr(c_vhpiObject *obj) if (decl->decl.ImmRegion == NULL) return NULL; + else if (decl->decl.ImmRegion->handle == JIT_HANDLE_INVALID) { + c_packInst *pi = is_packInst(&(decl->decl.ImmRegion->object)); + if (pi != NULL) { + decl->decl.ImmRegion->handle = + jit_lazy_compile(j, tree_ident(decl->decl.ImmRegion->tree)); + + if (jit_link(j, decl->decl.ImmRegion->handle) == NULL) { + vhpi_error(vhpiError, &(obj->loc), "failed to initialise package"); + return NULL; + } + } + else { + rt_scope_t *scope = + vhpi_get_scope_abstractRegion(decl->decl.ImmRegion); - rt_scope_t *scope = vhpi_get_scope_abstractRegion(decl->decl.ImmRegion); - if (*mptr_get(scope->privdata) == NULL) { - vhpi_error(vhpiError, &(obj->loc), "%s has not been elaborated", - decl->decl.FullName); - return NULL; - } + if (*mptr_get(scope->privdata) == NULL) { + vhpi_error(vhpiError, &(obj->loc), "%s has not been elaborated", + decl->decl.FullName); + return NULL; + } - if (decl->decl.ImmRegion->handle == JIT_HANDLE_INVALID) - decl->decl.ImmRegion->handle = jit_lazy_compile(j, scope->name); + decl->decl.ImmRegion->handle = jit_lazy_compile(j, scope->name); + } + } return jit_get_frame_var(j, decl->decl.ImmRegion->handle, decl->name); } @@ -2053,7 +2110,13 @@ vhpiHandleT vhpi_handle(vhpiOneToOneT type, vhpiHandleT referenceHandle) } case vhpiPrimaryUnit: - return handle_for(&(cast_secondaryUnit(obj)->PrimaryUnit->object)); + { + c_secondaryUnit *su = cast_secondaryUnit(obj); + if (su == NULL) + return NULL; + + return handle_for(&(su->PrimaryUnit->object)); + } case vhpiPrefix: { @@ -2103,20 +2166,30 @@ vhpiHandleT vhpi_handle_by_name(const char *name, vhpiHandleT scope) char *copy LOCAL = xstrdup(name), *saveptr; char *elem = strtok_r(copy, ":.", &saveptr); - c_abstractRegion *region; + c_abstractRegion *region = NULL; if (scope == NULL) { vhpi_context_t *c = vhpi_context(); if (strcasecmp(elem, (char *)c->root->designInstUnit.region.Name) == 0) region = &(c->root->designInstUnit.region); - else if (name[0] != ':') { - vhpi_error(vhpiError, NULL, "relative names with a NULL scope " - "argument are not supported"); - return NULL; - } else { - vhpi_error(vhpiError, NULL, "no design unit instance named %s", elem); - return NULL; + vhpi_find_packages(c); + + for (int i = 0; i < c->packages.count; i++) { + c_packInst *pi = is_packInst(c->packages.items[i]); + assert(pi != NULL); + + if (strcasecmp(elem, (char *)pi->designInstUnit.region.Name) == 0) { + region = &(pi->designInstUnit.region); + break; + } + } + + if (region == NULL) { + vhpi_error(vhpiError, NULL, "no design unit instance named %s", + elem); + return NULL; + } } elem = strtok_r(NULL, ":.", &saveptr); @@ -2129,10 +2202,10 @@ vhpiHandleT vhpi_handle_by_name(const char *name, vhpiHandleT scope) region = cast_abstractRegion(obj); if (region == NULL) return NULL; - - expand_lazy_region(region); } + expand_lazy_region(region); + if (elem == NULL) return handle_for(&(region->object)); @@ -2192,20 +2265,20 @@ vhpiHandleT vhpi_handle_by_index(vhpiOneToManyT itRel, VHPI_TRACE("itRel=%s parent=%s index=%d", vhpi_one_to_many_str(itRel), handle_pp(parent), index); - c_vhpiObject *obj = from_handle(parent); - if (obj == NULL) + c_vhpiObject *obj = NULL; + if (parent != NULL && (obj = from_handle(parent)) == NULL) return NULL; c_iterator it = {}; if (!init_iterator(&it, itRel, obj)) { - vhpi_error(vhpiError, &(obj->loc), - "relation %s not supported in vhpi_handle_by_index", - vhpi_one_to_many_str(itRel)); + vhpi_error(vhpiError, obj ? &(obj->loc) : NULL, + "relation %s not supported for parent %s", + vhpi_one_to_many_str(itRel), handle_pp(parent)); return NULL; } if (it.single ? index : index > it.list->count) { - vhpi_error(vhpiError, &(obj->loc), "invalid %s index %d", + vhpi_error(vhpiError, obj ? &(obj->loc) : NULL, "invalid %s index %d", vhpi_one_to_many_str(itRel), index); return NULL; } @@ -2219,15 +2292,15 @@ vhpiHandleT vhpi_iterator(vhpiOneToManyT type, vhpiHandleT handle) VHPI_TRACE("type=%s handle=%s", vhpi_one_to_many_str(type), handle_pp(handle)); - c_vhpiObject *obj = from_handle(handle); - if (obj == NULL) + c_vhpiObject *obj = NULL; + if (handle != NULL && (obj = from_handle(handle)) == NULL) return NULL; c_iterator *it = new_object(sizeof(c_iterator), vhpiIteratorK); if (!init_iterator(it, type, obj)) { - vhpi_error(vhpiError, &(obj->loc), - "relation %s not supported in vhpi_iterator", - vhpi_one_to_many_str(type)); + vhpi_error(vhpiError, obj ? &(obj->loc) : NULL, + "relation %s not supported for handle %p", + vhpi_one_to_many_str(type), handle_pp(handle)); return NULL; } @@ -3884,6 +3957,14 @@ static c_designUnit *build_designUnit(tree_t t) return &(secondary->designUnit); } + case T_PACKAGE: + { + c_packDecl *pack = new_object(sizeof(c_packDecl), vhpiPackDeclK); + init_packDecl(pack, t); + + return &(pack->designUnit); + } + default: fatal_trace("unsupported tree kind %s in build_designUnit", tree_kind_str(tree_kind(t))); @@ -4201,6 +4282,47 @@ static void vhpi_lazy_block(c_abstractRegion *r) vhpi_build_stmts(r->tree, r); } +static void vhpi_lazy_package(c_abstractRegion *r) +{ + vhpi_build_generics(r->tree, r); + vhpi_build_decls(r->tree, r); +} + +static void vhpi_build_deps_cb(ident_t name, void *ctx) +{ + hset_t *visited = ctx; + + if (hset_contains(visited, name)) + return; + + hset_insert(visited, name); + + tree_t unit = lib_get_qualified(name); + if (unit == NULL) + return; + else if (tree_kind(unit) == T_PACKAGE) { + c_designUnit *du = cached_designUnit(unit); + + c_packInst *pi = new_object(sizeof(c_packInst), vhpiPackInstK); + init_designInstUnit(&(pi->designInstUnit), unit, du); + pi->designInstUnit.region.lazyfn = vhpi_lazy_package; + + APUSH(vhpi_context()->packages, &(pi->designInstUnit.region.object)); + } + + tree_walk_deps(unit, vhpi_build_deps_cb, visited); +} + +static void vhpi_find_packages(vhpi_context_t *c) +{ + if (c->packages.count > 0) + return; + + hset_t *visited = hset_new(64); + tree_walk_deps(c->top, vhpi_build_deps_cb, visited); + hset_free(visited); +} + static void vhpi_build_design_model(vhpi_context_t *c) { const uint64_t start_us = get_timestamp_us(); diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 6c5d9106..755e81f6 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -981,3 +981,4 @@ implicit6 normal bounds44 fail,gold,2008 issue887 normal issue890 normal,2008 +vhpi15 normal,vhpi diff --git a/test/regress/vhpi15.vhd b/test/regress/vhpi15.vhd new file mode 100644 index 00000000..53824874 --- /dev/null +++ b/test/regress/vhpi15.vhd @@ -0,0 +1,18 @@ +package pack1 is + constant c1 : integer := 42; + constant c2 : string := "hello"; +end package; + +------------------------------------------------------------------------------- + +entity vhpi15 is +end entity; + +use work.pack1.all; + +architecture test of vhpi15 is + signal s1 : integer := c1; + signal s2 : string(1 to 5) := c2; +begin + +end architecture; diff --git a/test/vhpi/Makemodule.am b/test/vhpi/Makemodule.am index b0e51d0e..fcd66da9 100644 --- a/test/vhpi/Makemodule.am +++ b/test/vhpi/Makemodule.am @@ -19,7 +19,8 @@ lib_vhpi_test_so_SOURCES = \ test/vhpi/issue762.c \ test/vhpi/vhpi12.c \ test/vhpi/vhpi13.c \ - test/vhpi/vhpi14.c + test/vhpi/vhpi14.c \ + test/vhpi/vhpi15.c lib_vhpi_test_so_CFLAGS = $(PIC_FLAG) -I$(top_srcdir)/src/vhpi $(AM_CFLAGS) lib_vhpi_test_so_LDFLAGS = -shared $(VHPI_LDFLAGS) $(AM_LDFLAGS) diff --git a/test/vhpi/vhpi15.c b/test/vhpi/vhpi15.c new file mode 100644 index 00000000..2352b567 --- /dev/null +++ b/test/vhpi/vhpi15.c @@ -0,0 +1,111 @@ +// +// Copyright (C) 2024 Nick Gasson +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 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, see . +// + +#include "vhpi_test.h" + +#include +#include + +static void start_of_sim(const vhpiCbDataT *cb_data) +{ + vhpiHandleT root = vhpi_handle(vhpiRootInst, NULL); + check_error(); + fail_if(root == NULL); + vhpi_printf("root handle %p", root); + + vhpiHandleT bad1 = vhpi_handle_by_name(":bad", NULL); + fail_unless(bad1 == NULL); + + vhpiHandleT root2 = vhpi_handle_by_name(":vhpi15", NULL); + fail_unless(root2 == root); + vhpi_release_handle(root2); + + vhpiHandleT pack1 = vhpi_handle_by_name(":pack1", NULL); + check_handle(pack1); + vhpi_printf("pack1 handle %p", pack1); + + vhpiHandleT du = vhpi_handle(vhpiDesignUnit, pack1); + check_handle(du); + fail_unless(vhpi_get(vhpiKindP, du) == vhpiPackDeclK); + + vhpiHandleT su = vhpi_handle(vhpiPrimaryUnit, du); + fail_unless(su == NULL); + + vhpiHandleT c1 = vhpi_handle_by_name("c1", pack1); + check_handle(c1); + vhpi_printf("c1 full name is %s", vhpi_get_str(vhpiFullNameP, c1)); + fail_unless(vhpi_get(vhpiKindP, c1) == vhpiConstDeclK); + + vhpiValueT c1_value = { + .format = vhpiIntVal, + }; + vhpi_get_value(c1, &c1_value); + check_error(); + vhpi_printf("c1 value is %d", c1_value.value.intg); + fail_unless(c1_value.value.intg == 42); + + vhpiHandleT c2 = vhpi_handle_by_name("c2", pack1); + check_handle(c2); + vhpi_printf("c2 full name is %s", vhpi_get_str(vhpiFullNameP, c2)); + fail_unless(vhpi_get(vhpiKindP, c2) == vhpiConstDeclK); + + vhpiCharT c2_str[6]; + vhpiValueT c2_value = { + .format = vhpiStrVal, + .bufSize = sizeof(c2_str), + .value.str = c2_str + }; + vhpi_get_value(c2, &c2_value); + check_error(); + vhpi_printf("c2 value is %s", c2_str); + fail_unless(strcmp((char *)c2_str, "hello") == 0); + + vhpiHandleT it = vhpi_iterator(vhpiPackInsts, NULL); + fail_if(it == NULL); + + bool found = false; + int i = 0; + for (vhpiHandleT h = vhpi_scan(it); h != NULL; h = vhpi_scan(it), i++) { + vhpi_printf("found package %s", vhpi_get_str(vhpiNameP, h)); + + found |= vhpi_compare_handles(h, pack1); + + vhpiHandleT h2 = vhpi_handle_by_index(vhpiPackInsts, NULL, i); + fail_unless(vhpi_compare_handles(h, h2)); + vhpi_release_handle(h); + vhpi_release_handle(h2); + } + vhpi_release_handle(it); + fail_unless(found); + fail_unless(i == 2); + + vhpi_release_handle(root); + vhpi_release_handle(pack1); + vhpi_release_handle(c1); + vhpi_release_handle(c2); + vhpi_release_handle(du); +} + +void vhpi15_startup(void) +{ + vhpiCbDataT cb_data1 = { + .reason = vhpiCbStartOfSimulation, + .cb_rtn = start_of_sim, + }; + vhpi_register_cb(&cb_data1, 0); + check_error(); +} diff --git a/test/vhpi/vhpi_test.c b/test/vhpi/vhpi_test.c index a490f343..1313f1d4 100644 --- a/test/vhpi/vhpi_test.c +++ b/test/vhpi/vhpi_test.c @@ -43,6 +43,7 @@ static const vhpi_test_t tests[] = { { "vhpi12", vhpi12_startup }, { "vhpi13", vhpi13_startup }, { "vhpi14", vhpi14_startup }, + { "vhpi15", vhpi15_startup }, { NULL, NULL }, }; @@ -54,6 +55,14 @@ void __check_error(const char *file, int lineno) file, lineno, info.message); } +void __check_handle(vhpiHandleT h, const char *file, int lineno) +{ + __check_error(file, lineno); + + if (h == NULL) + vhpi_assert(vhpiFailure, "%s:%d: unexpected NULL handle", file, lineno); +} + static void shared_startup(void) { const char *test_name = getenv("TEST_NAME"); diff --git a/test/vhpi/vhpi_test.h b/test/vhpi/vhpi_test.h index e9e2157d..3b26eef7 100644 --- a/test/vhpi/vhpi_test.h +++ b/test/vhpi/vhpi_test.h @@ -26,8 +26,10 @@ #define fail_unless(x) fail_if(!(x)) #define check_error() __check_error(__FILE__, __LINE__) +#define check_handle(h) __check_handle(h, __FILE__, __LINE__) void __check_error(const char *file, int lineno); +void __check_handle(vhpiHandleT h, const char *file, int lineno); void vhpi1_startup(void); void vhpi2_startup(void); @@ -42,6 +44,7 @@ void vhpi11_startup(void); void vhpi12_startup(void); void vhpi13_startup(void); void vhpi14_startup(void); +void vhpi15_startup(void); void issue744_startup(void); void issue762_startup(void); -- 2.39.2