From 4e9268c1ecec2d32d40642413f91a1c12cc16352 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 7 Apr 2024 22:25:18 +0100 Subject: [PATCH] WIP UCIS implementation --- Makefile.am | 1 + configure.ac | 15 ++ src/cov/cov-api.h | 2 + src/cov/cov-export.c | 161 +++++++++++++++- src/nvc.c | 30 ++- src/ucis/Makemodule.am | 10 + src/ucis/ucis-api.h | 416 +++++++++++++++++++++++++++++++++++++++++ src/ucis/ucis-impl.c | 301 +++++++++++++++++++++++++++++ src/ucis/ucis-util.c | 39 ++++ src/ucis/ucis-util.h | 29 +++ src/ucis/ucis-xml.c | 50 +++++ test/Makemodule.am | 9 +- test/ucdbdump.c | 114 +++++++++++ 13 files changed, 1167 insertions(+), 10 deletions(-) create mode 100644 src/ucis/Makemodule.am create mode 100644 src/ucis/ucis-api.h create mode 100644 src/ucis/ucis-impl.c create mode 100644 src/ucis/ucis-util.c create mode 100644 src/ucis/ucis-util.h create mode 100644 src/ucis/ucis-xml.c create mode 100644 test/ucdbdump.c diff --git a/Makefile.am b/Makefile.am index f892a460..30cea6d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,6 +48,7 @@ include src/cov/Makemodule.am include src/psl/Makemodule.am include src/rt/Makemodule.am include src/jit/Makemodule.am +include src/ucis/Makemodule.am include src/vhpi/Makemodule.am include src/vlog/Makemodule.am include test/Makemodule.am diff --git a/configure.ac b/configure.ac index 5cb91ea1..a2ee25d1 100644 --- a/configure.ac +++ b/configure.ac @@ -426,6 +426,21 @@ AC_ARG_ENABLE([vital], AM_CONDITIONAL([ENABLE_VITAL], [test x$enable_vital = xyes]) +# System UCIS library (e.g. from ModelSim) +AC_ARG_WITH([system-ucis], + [AS_HELP_STRING([--with-system-ucis=PATH], + [Path to third-party UCIS library])], + [system_ucis="$withval"], + [system_ucis=no]) + +if test x$system_ucis != xno; then + AC_CHECK_HEADERS([ucis.h]) + AC_CHECK_LIB([ucis], [ucis_Open], [], + [AC_MSG_ERROR([UCIS library not found])]) +fi + +AM_CONDITIONAL([SYSTEM_UCIS], [test x$system_ucis != xno]) + AC_ARG_ENABLE([werror], [AS_HELP_STRING([--enable-werror], [Treat warnings as errors])], [EXTRA_CFLAGS="$EXTRA_CFLAGS -Werror"]) diff --git a/src/cov/cov-api.h b/src/cov/cov-api.h index 01c16a9e..027d77bc 100644 --- a/src/cov/cov-api.h +++ b/src/cov/cov-api.h @@ -227,6 +227,8 @@ void cover_load_exclude_file(const char *path, cover_data_t *data); void cover_report(const char *path, cover_data_t *data, int item_limit); void cover_export_cobertura(cover_data_t *data, FILE *f, const char *relative); +void cover_export_ucdb(cover_data_t *data, const char *path); +void cover_export_ucis(cover_data_t *data, const char *path); // // Interface to code generator diff --git a/src/cov/cov-export.c b/src/cov/cov-export.c index 360c68ba..ba6eb9cf 100644 --- a/src/cov/cov-export.c +++ b/src/cov/cov-export.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2023 Nick Gasson +// Copyright (C) 2023-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 @@ -21,6 +21,8 @@ #include "hash.h" #include "ident.h" #include "option.h" +#include "ucis/ucis-api.h" +#include "ucis/ucis-util.h" #include #include @@ -261,3 +263,160 @@ void cover_export_cobertura(cover_data_t *data, FILE *f, const char *relative) free(report.relative); hash_free(report.class_map); } + +//////////////////////////////////////////////////////////////////////////////// +// Unified Coverage Interoperability Standard (UCIS) + +typedef struct { + ucisT db; + shash_t *files; +} ucis_export_t; + +static ucisFileHandleT ucis_get_file(ucis_export_t *u, const loc_t *loc) +{ + const char *f = loc_file_str(loc); + + ucisFileHandleT h = shash_get(u->files, f); + if (h != NULL) + return h; + + h = ucis_CreateFileHandle(u->db, f, "./"); + shash_put(u->files, f, h); + return h; +} + +static void ucis_get_source_info(ucis_export_t *u, const loc_t *loc, + ucisSourceInfoT *info) +{ + info->filehandle = ucis_get_file(u, loc); + info->line = loc->first_line; + info->token = 0; +} + +static void ucis_export_scope(ucis_export_t *u, ucisScopeT parent, + cover_scope_t *s) +{ + printf("%s %d\n", istr(s->name), s->type); + + ucisScopeT scope = parent; + + if (s->type == CSCOPE_INSTANCE) { + ucisSourceInfoT srcinfo; + ucis_get_source_info(u, &(s->loc), &srcinfo); + + ucisScopeT du = ucis_CreateScope(u->db, parent, istr(s->block_name), + &srcinfo, 1, UCIS_VHDL, UCIS_DU_MODULE, + UCIS_ENABLED_STMT | UCIS_ENABLED_BRANCH | + UCIS_ENABLED_COND | UCIS_ENABLED_EXPR | + UCIS_ENABLED_FSM | UCIS_ENABLED_TOGGLE | + UCIS_SCOPE_UNDER_DU); + + scope = ucis_CreateInstance(u->db, NULL, istr(s->hier), &srcinfo, 1, + UCIS_VHDL, UCIS_INSTANCE, du, 0); + } + + ucisScopeT branch = NULL; + + for (int i = 0; i < s->items.count; i++) { + cover_item_t *t = &(s->items.items[i]); + switch (t->kind) { + case COV_ITEM_STMT: + { + ucisSourceInfoT srcinfo; + ucis_get_source_info(u, &(t->loc), &srcinfo); + + ucisCoverDataT coverdata = { + .type = UCIS_STMTBIN, + .flags = UCIS_IS_32BIT, + .data = { .int32 = t->data } + }; + + const int index = ucis_CreateNextCover(u->db,parent, NULL, + &coverdata, &srcinfo); + ucis_SetIntProperty(u->db, parent, index, UCIS_INT_STMT_INDEX, 1); + } + break; + case COV_ITEM_BRANCH: + { + ucisSourceInfoT srcinfo; + ucis_get_source_info(u, &(t->loc), &srcinfo); + + if (branch == NULL) { + char name[64]; + checked_sprintf(name, sizeof(name), "branch#%d#%d#", + t->loc.first_line, 1); + + branch = ucis_CreateScope(u->db, scope, name, &srcinfo, 1, + UCIS_VHDL, UCIS_BRANCH, 0); + } + + ucisCoverDataT coverdata = { + .type = UCIS_BRANCHBIN, + .flags = UCIS_IS_32BIT, + .data = { .int32 = t->data } + }; + ucis_CreateNextCover(u->db, branch, NULL, &coverdata, &srcinfo); + } + break; + default: + break; + } + } + + for (int i = 0; i < s->children.count; i++) + ucis_export_scope(u, scope, s->children.items[i]); +} + +static ucisT ucis_convert_from_interal(cover_data_t *data) +{ + ucis_init(); + + ucis_export_t u = { + .db = ucis_Open(NULL), + .files = shash_new(64), + }; + + LOCAL_TEXT_BUF date = tb_new(); + tb_strftime(date, "L%Y%m%d%H%M%S", time(NULL)); + + ucisTestDataT testdata = { + .teststatus = UCIS_TESTSTATUS_OK, + .simtime = 0.0, + .timeunit = "fs", + .runcwd = "./", + .cputime = 0.0, + .seed = "0", + .cmd = PACKAGE, + .args = "", + .compulsory = 0, + .date = tb_get(date), + .username = "", + .cost = 0.0, + .toolcategory = UCIS_SIM_TOOL + }; + + ucisHistoryNodeT testnode = + ucis_CreateHistoryNode(u.db, NULL, "TestLogicalName", "", + UCIS_HISTORYNODE_TEST); + + ucis_SetTestData(u.db, testnode, &testdata); + + ucis_export_scope(&u, NULL, data->root_scope); + + shash_free(u.files); + return u.db; +} + +void cover_export_ucdb(cover_data_t *data, const char *path) +{ + ucisT db = ucis_convert_from_interal(data); + ucis_Write(db, path, NULL, 0, -1); + ucis_Close(db); +} + +void cover_export_ucis(cover_data_t *data, const char *path) +{ + ucisT db = ucis_convert_from_interal(data); + ucis_WriteToInterchangeFormat(db, path, NULL, 0, -1); + ucis_Close(db); +} diff --git a/src/nvc.c b/src/nvc.c index 8255df10..52ed58ac 100644 --- a/src/nvc.c +++ b/src/nvc.c @@ -1577,7 +1577,7 @@ static int cover_export_cmd(int argc, char **argv, cmd_state_t *state) const int next_cmd = scan_cmd(2, argc, argv); - enum { UNSET, COBERTURA } format = UNSET; + enum { UNSET, COBERTURA, UCIS, UCDB } format = UNSET; const char *output = NULL, *relative = NULL; int c, index; const char *spec = ":o"; @@ -1586,8 +1586,13 @@ static int cover_export_cmd(int argc, char **argv, cmd_state_t *state) case 'f': if (strcasecmp(optarg, "cobertura") == 0) format = COBERTURA; + else if (strcasecmp(optarg, "ucis") == 0) + format = UCIS; + else if (strcasecmp(optarg, "ucdb") == 0) + format = UCIS; else - fatal("unknown format '%s', valid formats are: cobertura", optarg); + fatal("unknown format '%s', valid formats are: cobertura, ucis", + optarg); break; case 'o': output = optarg; @@ -1610,6 +1615,7 @@ static int cover_export_cmd(int argc, char **argv, cmd_state_t *state) diag_t *d = diag_new(DIAG_FATAL, NULL); diag_printf(d, "the $bold$--format$$ option is required"); diag_hint(d, NULL, "pass $bold$--format=cobertura$$ for Cobertura XML"); + diag_hint(d, NULL, "pass $bold$--format=ucis$$ for UCIS XML"); diag_emit(d); return EXIT_FAILURE; } @@ -1624,14 +1630,22 @@ static int cover_export_cmd(int argc, char **argv, cmd_state_t *state) cover_data_t *cover = cover_read_items(f, rpt_mask); fbuf_close(f, NULL); - FILE *file = stdout; - if (output != NULL && (file = fopen(output, "w")) == NULL) - fatal_errno("cannot create %s", output); + if (format == COBERTURA) { + FILE *file = stdout; + if (output != NULL && (file = fopen(output, "w")) == NULL) + fatal_errno("cannot create %s", output); - cover_export_cobertura(cover, file, relative); + cover_export_cobertura(cover, file, relative); - if (file != stdout) - fclose(file); + if (file != stdout) + fclose(file); + } + else if (output == NULL) + fatal("the $bold$--output$$ option is required for this file type"); + else if (format == UCIS) + cover_export_ucis(cover, output); + else + cover_export_ucdb(cover, output); argc -= next_cmd - 1; argv += next_cmd - 1; diff --git a/src/ucis/Makemodule.am b/src/ucis/Makemodule.am new file mode 100644 index 00000000..32d5c2d0 --- /dev/null +++ b/src/ucis/Makemodule.am @@ -0,0 +1,10 @@ +lib_libnvc_a_SOURCES += \ + src/ucis/ucis-util.h \ + src/ucis/ucis-util.c \ + src/ucis/ucis-api.h + +if !SYSTEM_UCIS +lib_libnvc_a_SOURCES += \ + src/ucis/ucis-impl.c \ + src/ucis/ucis-xml.c +endif diff --git a/src/ucis/ucis-api.h b/src/ucis/ucis-api.h new file mode 100644 index 00000000..f96f44fe --- /dev/null +++ b/src/ucis/ucis-api.h @@ -0,0 +1,416 @@ +// +// 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 . +// + +#ifndef _UCIS_API_H +#define _UCIS_API_H + +#if HAVE_UCIS_H +#include // System-supplied UCIS library +#else + +#include "prim.h" + +// +// The text of the UCIS standard can be downloaded here: +// +// https://www.accellera.org/downloads/standards/ucis +// +// The standard contains a header file which unfortunately cannot be +// distributed due to its proprietary Accellera license. The +// declarations below are taken from the standard text but do not +// contain the explanatory comments found in the standard header. +// + +typedef uint64_t ucisObjTypeT; +typedef ucisObjTypeT ucisScopeTypeT; +typedef ucisObjTypeT ucisCoverTypeT; +typedef uint64_t ucisCoverMaskTypeT; +typedef uint64_t ucisScopeMaskTypeT; + +typedef struct _ucis *ucisT; +typedef struct _ucisScope *ucisScopeT; +typedef void *ucisObjT; +typedef struct _ucisFileHandle *ucisFileHandleT; +typedef void *ucisIteratorT; +typedef struct _ucisHistoryNode *ucisHistoryNodeT; + +//////////////////////////////////////////////////////////////////////////////// +// Source information + +typedef struct { + ucisFileHandleT filehandle; + int line; + int token; +} ucisSourceInfoT; + +const char *ucis_GetFileName(ucisT db, ucisFileHandleT filehandle); +ucisFileHandleT ucis_CreateFileHandle(ucisT db, const char* filename, + const char* fileworkdir); + +//////////////////////////////////////////////////////////////////////////////// +// Error handling + +typedef enum { + UCIS_MSG_INFO, + UCIS_MSG_WARNING, + UCIS_MSG_ERROR +} ucisMsgSeverityT; + +typedef struct ucisErr_s { + int msgno; + ucisMsgSeverityT severity; + const char* msgstr; +} ucisErrorT; + +typedef void (*ucis_ErrorHandler)(void* userdata, ucisErrorT* errdata); + +void ucis_RegisterErrorHandler(ucis_ErrorHandler errHandle, void *userdata); + +//////////////////////////////////////////////////////////////////////////////// +// Database creation + +ucisT ucis_Open(const char *name); +int ucis_Close(ucisT db); +int ucis_Write(ucisT db, const char* file, ucisScopeT scope, int recurse, + int covertype); +int ucis_WriteToInterchangeFormat(ucisT db, const char* file, ucisScopeT scope, + int recurse, int covertype); + +//////////////////////////////////////////////////////////////////////////////// +// Integer properties + +typedef enum { + UCIS_INT_IS_MODIFIED, + UCIS_INT_MODIFIED_SINCE_SIM, + UCIS_INT_NUM_TESTS, + UCIS_INT_SCOPE_WEIGHT, + UCIS_INT_SCOPE_GOAL, + UCIS_INT_SCOPE_SOURCE_TYPE, + UCIS_INT_NUM_CROSSED_CVPS, + UCIS_INT_SCOPE_IS_UNDER_DU, + UCIS_INT_SCOPE_IS_UNDER_COVERINSTANCE, + UCIS_INT_SCOPE_NUM_COVERITEMS, + UCIS_INT_SCOPE_NUM_EXPR_TERMS, + UCIS_INT_TOGGLE_TYPE, + UCIS_INT_TOGGLE_DIR, + UCIS_INT_TOGGLE_COVERED, + UCIS_INT_BRANCH_HAS_ELSE, + UCIS_INT_BRANCH_ISCASE, + UCIS_INT_COVER_GOAL, + UCIS_INT_COVER_LIMIT, + UCIS_INT_COVER_WEIGHT, + UCIS_INT_TEST_STATUS, + UCIS_INT_TEST_COMPULSORY, + UCIS_INT_STMT_INDEX, + UCIS_INT_BRANCH_COUNT, + UCIS_INT_FSM_STATEVAL, + UCIS_INT_CVG_ATLEAST, + UCIS_INT_CVG_AUTOBINMAX, + UCIS_INT_CVG_DETECTOVERLAP, + UCIS_INT_CVG_NUMPRINTMISSING, + UCIS_INT_CVG_STROBE, + UCIS_INT_CVG_PERINSTANCE, + UCIS_INT_CVG_GETINSTCOV, + UCIS_INT_CVG_MERGEINSTANCES, + UCIS_INT_TOGGLE_METRIC +} ucisIntPropertyEnumT; + +int ucis_GetIntProperty(ucisT db, ucisObjT obj, int coverindex, + ucisIntPropertyEnumT property); +int ucis_SetIntProperty(ucisT db, ucisObjT obj, int coverindex, + ucisIntPropertyEnumT property, int value); + +//////////////////////////////////////////////////////////////////////////////// +// String properties + +typedef enum { + UCIS_STR_FILE_NAME, + UCIS_STR_SCOPE_NAME, + UCIS_STR_SCOPE_HIER_NAME, + UCIS_STR_INSTANCE_DU_NAME, + UCIS_STR_UNIQUE_ID, + UCIS_STR_VER_STANDARD, + UCIS_STR_VER_STANDARD_VERSION, + UCIS_STR_VER_VENDOR_ID, + UCIS_STR_VER_VENDOR_TOOL, + UCIS_STR_VER_VENDOR_VERSION, + UCIS_STR_GENERIC, + UCIS_STR_ITH_CROSSED_CVP_NAME, + UCIS_STR_HIST_CMDLINE, + UCIS_STR_HIST_RUNCWD, + UCIS_STR_COMMENT, + UCIS_STR_TEST_TIMEUNIT, + UCIS_STR_TEST_DATE, + UCIS_STR_TEST_SIMARGS, + UCIS_STR_TEST_USERNAME, + UCIS_STR_TEST_NAME, + UCIS_STR_TEST_SEED, + UCIS_STR_TEST_HOSTNAME, + UCIS_STR_TEST_HOSTOS, + UCIS_STR_EXPR_TERMS, + UCIS_STR_TOGGLE_CANON_NAME, + UCIS_STR_UNIQUE_ID_ALIAS, + UCIS_STR_DESIGN_VERSION_ID, + UCIS_STR_DU_SIGNATURE, + UCIS_STR_HIST_TOOLCATEGORY, + UCIS_STR_HIST_LOG_NAME, + UCIS_STR_HIST_PHYS_NAME, +} ucisStringPropertyEnumT; + +const char *ucis_GetStringProperty(ucisT db, ucisObjT obj, int coverindex, + ucisStringPropertyEnumT property); +int ucis_SetStringProperty(ucisT db, ucisObjT obj, int coverindex, + ucisStringPropertyEnumT property, const char *value); + +//////////////////////////////////////////////////////////////////////////////// +// History nodes + +typedef int ucisHistoryNodeKindT; + +#define UCIS_HISTORYNODE_NONE -1 +#define UCIS_HISTORYNODE_ALL 0 +#define UCIS_HISTORYNODE_TEST 1 +#define UCIS_HISTORYNODE_MERGE 2 + +#define UCIS_SIM_TOOL "UCIS:Simulator" +#define UCIS_FORMAL_TOOL "UCIS:Formal" +#define UCIS_ANALOG_TOOL "UCIS:Analog" +#define UCIS_EMULATOR_TOOL "UCIS:Emulator" +#define UCIS_MERGE_TOOL "UCIS:Merge" + +typedef enum { + UCIS_TESTSTATUS_OK, + UCIS_TESTSTATUS_WARNING, + UCIS_TESTSTATUS_ERROR, + UCIS_TESTSTATUS_FATAL, + UCIS_TESTSTATUS_MISSING, + UCIS_TESTSTATUS_MERGE_ERROR +} ucisTestStatusT; + +typedef struct { + ucisTestStatusT teststatus; + double simtime; + const char* timeunit; + const char* runcwd; + double cputime; + const char* seed; + const char* cmd; + const char* args; + int compulsory; + const char* date; + const char* username; + double cost; + const char* toolcategory; +} ucisTestDataT; + +int ucis_SetTestData(ucisT db, ucisHistoryNodeT testhistorynode, + ucisTestDataT *testdata); +ucisHistoryNodeT ucis_CreateHistoryNode(ucisT db, ucisHistoryNodeT parent, + char *logicalname, char *physicalname, + ucisHistoryNodeKindT kind); + +//////////////////////////////////////////////////////////////////////////////// +// Scopes + +#define UCIS_TOGGLE INT64_C(0x0000000000000001) +#define UCIS_BRANCH INT64_C(0x0000000000000002) +#define UCIS_EXPR INT64_C(0x0000000000000004) +#define UCIS_COND INT64_C(0x0000000000000008) +#define UCIS_INSTANCE INT64_C(0x0000000000000010) +#define UCIS_PROCESS INT64_C(0x0000000000000020) +#define UCIS_BLOCK INT64_C(0x0000000000000040) +#define UCIS_FUNCTION INT64_C(0x0000000000000080) +#define UCIS_FORKJOIN INT64_C(0x0000000000000100) +#define UCIS_GENERATE INT64_C(0x0000000000000200) +#define UCIS_GENERIC INT64_C(0x0000000000000400) +#define UCIS_CLASS INT64_C(0x0000000000000800) +#define UCIS_COVERGROUP INT64_C(0x0000000000001000) +#define UCIS_COVERINSTANCE INT64_C(0x0000000000002000) +#define UCIS_COVERPOINT INT64_C(0x0000000000004000) +#define UCIS_CROSS INT64_C(0x0000000000008000) +#define UCIS_COVER INT64_C(0x0000000000010000) +#define UCIS_ASSERT INT64_C(0x0000000000020000) +#define UCIS_PROGRAM INT64_C(0x0000000000040000) +#define UCIS_PACKAGE INT64_C(0x0000000000080000) +#define UCIS_TASK INT64_C(0x0000000000100000) +#define UCIS_INTERFACE INT64_C(0x0000000000200000) +#define UCIS_FSM INT64_C(0x0000000000400000) +#define UCIS_TESTPLAN INT64_C(0x0000000000800000) +#define UCIS_DU_MODULE INT64_C(0x0000000001000000) +#define UCIS_DU_ARCH INT64_C(0x0000000002000000) +#define UCIS_DU_PACKAGE INT64_C(0x0000000004000000) +#define UCIS_DU_PROGRAM INT64_C(0x0000000008000000) +#define UCIS_DU_INTERFACE INT64_C(0x0000000010000000) +#define UCIS_FSM_STATES INT64_C(0x0000000020000000) +#define UCIS_FSM_TRANS INT64_C(0x0000000040000000) +#define UCIS_COVBLOCK INT64_C(0x0000000080000000) +#define UCIS_CVGBINSCOPE INT64_C(0x0000000100000000) +#define UCIS_ILLEGALBINSCOPE INT64_C(0x0000000200000000) +#define UCIS_IGNOREBINSCOPE INT64_C(0x0000000400000000) +#define UCIS_BBLOCKSCOPE INT64_C(0x0000000800000000) +#define UCIS_GROUP INT64_C(0x0000001000000000) +#define UCIS_TRANSITION INT64_C(0x0000002000000000) +#define UCIS_RESERVEDSCOPE INT64_C(0xFF00000000000000) +#define UCIS_SCOPE_ERROR INT64_C(0x0000000000000000) + +typedef unsigned int ucisFlagsT; + +#define UCIS_SCOPEMASK_GENERAL 0x0000FFFF; +#define UCIS_SCOPEMASK_TYPED 0x07FF0000; +#define UCIS_SCOPEMASK_MARK 0x08000000; +#define UCIS_SCOPEMASK_USER 0xF0000000; + +#define UCIS_INST_ONCE 0x00000001 +#define UCIS_ENABLED_STMT 0x00000002 +#define UCIS_ENABLED_BRANCH 0x00000004 +#define UCIS_ENABLED_COND 0x00000008 +#define UCIS_ENABLED_EXPR 0x00000010 +#define UCIS_ENABLED_FSM 0x00000020 +#define UCIS_ENABLED_TOGGLE 0x00000040 +#define UCIS_SCOPE_UNDER_DU 0x00000100 +#define UCIS_SCOPE_EXCLUDED 0x00000200 +#define UCIS_SCOPE_PRAGMA_EXCLUDED 0x00000400 +#define UCIS_SCOPE_PRAGMA_CLEARED 0x00000800 +#define UCIS_SCOPE_SPECIALIZED 0x00001000 +#define UCIS_IS_TOP_NODE 0x00010000 +#define UCIS_IS_IMMEDIATE_ASSERT 0x00010000 +#define UCIS_SCOPE_CVG_AUTO 0x00010000 +#define UCIS_SCOPE_CVG_SCALAR 0x00020000 +#define UCIS_SCOPE_CVG_VECTOR 0x00040000 +#define UCIS_SCOPE_CVG_TRANSITION 0x00080000 +#define UCIS_SCOPE_IFF_EXISTS 0x00100000 +#define UCIS_SCOPE_SAMPLE_TRUE 0x00200000 +#define UCIS_ENABLED_BLOCK 0x00800000 +#define UCIS_SCOPE_BLOCK_ISBRANCH 0x01000000 +#define UCIS_SCOPEFLAG_MARK 0x08000000 +#define UCIS_SCOPE_INTERNAL 0xF0000000 + +typedef enum { + UCIS_VHDL, + UCIS_VLOG, + UCIS_SV, + UCIS_SYSTEMC, + UCIS_PSL_VHDL, + UCIS_PSL_VLOG, + UCIS_PSL_SV, + UCIS_PSL_SYSTEMC, + UCIS_E, + UCIS_VERA, + UCIS_NONE, + UCIS_OTHER, + UCIS_SOURCE_ERROR +} ucisSourceT; + +ucisScopeT ucis_CreateScope(ucisT db, ucisScopeT parent, const char *name, + ucisSourceInfoT *srcinfo, int weight, + ucisSourceT source, ucisScopeTypeT type, + ucisFlagsT flags); +ucisScopeT ucis_CreateInstance(ucisT db, ucisScopeT parent, const char *name, + ucisSourceInfoT *fileinfo, int weight, + ucisSourceT source, ucisScopeTypeT type, + ucisScopeT du_scope, ucisFlagsT flags); + +//////////////////////////////////////////////////////////////////////////////// +// Cover items + +#define UCIS_CVGBIN INT64_C(0x0000000000000001) +#define UCIS_COVERBIN INT64_C(0x0000000000000002) +#define UCIS_ASSERTBIN INT64_C(0x0000000000000004) +#define UCIS_SCBIN INT64_C(0x0000000000000008) +#define UCIS_ZINBIN INT64_C(0x0000000000000010) +#define UCIS_STMTBIN INT64_C(0x0000000000000020) +#define UCIS_BRANCHBIN INT64_C(0x0000000000000040) +#define UCIS_EXPRBIN INT64_C(0x0000000000000080) +#define UCIS_CONDBIN INT64_C(0x0000000000000100) +#define UCIS_TOGGLEBIN INT64_C(0x0000000000000200) +#define UCIS_PASSBIN INT64_C(0x0000000000000400) +#define UCIS_FSMBIN INT64_C(0x0000000000000800) +#define UCIS_USERBIN INT64_C(0x0000000000001000) +#define UCIS_GENERICBIN UCIS_USERBIN +#define UCIS_COUNT INT64_C(0x0000000000002000) +#define UCIS_FAILBIN INT64_C(0x0000000000004000) +#define UCIS_VACUOUSBIN INT64_C(0x0000000000008000) +#define UCIS_DISABLEDBIN INT64_C(0x0000000000010000) +#define UCIS_ATTEMPTBIN INT64_C(0x0000000000020000) +#define UCIS_ACTIVEBIN INT64_C(0x0000000000040000) +#define UCIS_IGNOREBIN INT64_C(0x0000000000080000) +#define UCIS_ILLEGALBIN INT64_C(0x0000000000100000) +#define UCIS_DEFAULTBIN INT64_C(0x0000000000200000) +#define UCIS_PEAKACTIVEBIN INT64_C(0x0000000000400000) +#define UCIS_BLOCKBIN INT64_C(0x0000000001000000) +#define UCIS_USERBITS INT64_C(0x00000000FE000000) +#define UCIS_RESERVEDBIN INT64_C(0xFF00000000000000) + +#define UCIS_COVERITEMMASK_GENERAL 0x0000FFFF +#define UCIS_COVERITEMMASK_TYPED 0x07FF0000 +#define UCIS_COVERITEMMASK_MARK 0x08000000 +#define UCIS_COVERITEMMASK_USER 0xF0000000 + +#define UCIS_IS_32BIT 0x00000001 +#define UCIS_IS_64BIT 0x00000002 +#define UCIS_IS_VECTOR 0x00000004 +#define UCIS_HAS_GOAL 0x00000008 +#define UCIS_HAS_WEIGHT 0x00000010 +#define UCIS_EXCLUDE_PRAGMA 0x00000020 +#define UCIS_EXCLUDE_FILE 0x00000040 +#define UCIS_EXCLUDE_INST 0x00000080 +#define UCIS_EXCLUDE_AUTO 0x00000100 +#define UCIS_ENABLED 0x00000200 +#define UCIS_HAS_LIMIT 0x00000400 +#define UCIS_HAS_COUNT 0x00000800 +#define UCIS_IS_COVERED 0x00001000 +#define UCIS_UOR_SAFE_COVERITEM 0x00002000 +#define UCIS_CLEAR_PRAGMA 0x00004000 +#define UCIS_HAS_ACTION 0x00010000 +#define UCIS_IS_TLW_ENABLED 0x00020000 +#define UCIS_LOG_ON 0x00040000 +#define UCIS_IS_EOS_NOTE 0x00080000 +#define UCIS_IS_FSM_RESET 0x00010000 +#define UCIS_IS_FSM_TRAN 0x00020000 +#define UCIS_IS_BR_ELSE 0x00010000 +#define UCIS_BIN_IFF_EXISTS 0x00010000 +#define UCIS_BIN_SAMPLE_TRUE 0x00020000 +#define UCIS_IS_CROSSAUTO 0x00040000 +#define UCIS_COVERFLAG_MARK 0x08000000 +#define UCIS_USERFLAGS 0xF0000000 +#define UCIS_FLAG_MASK 0xFFFFFFFF + +#define UCIS_EXCLUDED (UCIS_EXCLUDE_FILE | UCIS_EXCLUDE_PRAGMA | \ + UCIS_EXCLUDE_INST | UCIS_EXCLUDE_AUTO) + +typedef union { + uint64_t int64; + uint32_t int32; + unsigned char* bytevector; +} ucisCoverDataValueT; + +typedef struct { + ucisCoverTypeT type; + ucisFlagsT flags; + ucisCoverDataValueT data; + int goal; + int weight; + int limit; + int bitlen; +} ucisCoverDataT; + +int ucis_CreateNextCover(ucisT db, ucisScopeT parent, const char *name, + ucisCoverDataT *data, ucisSourceInfoT *sourceinfo); + +#endif // !HAVE_UCIS_H + +#endif // _UCIS_API_H diff --git a/src/ucis/ucis-impl.c b/src/ucis/ucis-impl.c new file mode 100644 index 00000000..57488e07 --- /dev/null +++ b/src/ucis/ucis-impl.c @@ -0,0 +1,301 @@ +// +// 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 "util.h" +#include "array.h" +#include "fbuf.h" +#include "hash.h" +#include "ucis/ucis-api.h" + +#include +#include +#include + +#define MISSING fatal_trace("not implemented"); +#define EMBED_COVER_ITEMS 4 +#define FILE_MAGIC 0x75636973 +#define FORMAT_VERSION 1 + +#define MARKER_HISTORY_NODE 1 +#define MARKER_END_OF_FILE 2 + +struct _ucisFileHandle { + char *filename; +}; + +typedef struct { + ucisCoverDataT data; + ucisSourceInfoT sourceinfo; + unsigned stmt_index; +} ucisCoverItemT; + +struct _ucisScope { + unsigned numitems; + unsigned maxitems; + union { + ucisCoverItemT embed[EMBED_COVER_ITEMS]; + ucisCoverItemT *extended; + }; +}; + +struct _ucisHistoryNode { + ucisHistoryNodeT next; + ucisHistoryNodeKindT kind; + ucisTestDataT testdata; +}; + +struct _ucis { + ucisHistoryNodeT history_nodes; + shash_t *files; + shash_t *strings; +}; + +static ucis_ErrorHandler error_handler = NULL; +static void *handler_userdata = NULL; + +static char *ucis_copy_string(ucisT db, const char *str) +{ + if (str == NULL) + return NULL; + + char *exist = shash_get(db->strings, str); + if (exist != NULL) + return exist; + + char *copy = xstrdup(str); + shash_put(db->files, str, copy); + return copy; +} + +static void ucis_error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + if (error_handler != NULL) { + char *buf LOCAL = xvasprintf(fmt, ap); + ucisErrorT error = { + .msgstr = buf, + .severity = UCIS_MSG_ERROR, + }; + (*error_handler)(handler_userdata, &error); + } + + va_end(ap); +} + +static ucisCoverItemT *ucis_get_cover_item(ucisScopeT scope, int index) +{ + if (index < 0 || index >= scope->numitems) { + ucis_error("invalid cover item index %d", index); + return NULL; + } + else if (scope->maxitems == EMBED_COVER_ITEMS) + return &(scope->embed[index]); + else + return &(scope->extended[index]); +} + +void ucis_RegisterErrorHandler(ucis_ErrorHandler errHandle, void *userdata) +{ + handler_userdata = userdata; + error_handler = errHandle; +} + +ucisT ucis_Open(const char *name) +{ + ucisT db = xcalloc(sizeof(struct _ucis)); + db->files = shash_new(16); + db->strings = shash_new(128); + + return db; +} + +int ucis_Close(ucisT db) +{ + shash_free(db->files); + shash_free(db->strings); + free(db); + return 0; +} + +int ucis_Write(ucisT db, const char* file, ucisScopeT scope, int recurse, + int covertype) +{ + fbuf_t *f = fbuf_open(file, FBUF_OUT, FBUF_CS_NONE); + if (f == NULL) { + ucis_error("failed to create %s", file); + return 1; + } + + write_u32(FILE_MAGIC, f); + fbuf_put_uint(f, FORMAT_VERSION); + + for (ucisHistoryNodeT h = db->history_nodes; h != NULL; h = h->next) { + write_u8(MARKER_HISTORY_NODE, f); + } + + write_u8(MARKER_END_OF_FILE, f); + + uint32_t checksum; + fbuf_close(f, &checksum); + + return 0; +} + +int ucis_GetIntProperty(ucisT db, ucisObjT obj, int coverindex, + ucisIntPropertyEnumT property) +{ + MISSING; +} + +int ucis_SetIntProperty(ucisT db, ucisObjT obj, int coverindex, + ucisIntPropertyEnumT property, int value) +{ + switch (property) { + case UCIS_INT_STMT_INDEX: + { + ucisCoverItemT *item = ucis_get_cover_item(obj, coverindex); + if (item == NULL) + return 1; + + assert(item->data.type == UCIS_STMTBIN); + item->stmt_index = value; + return 0; + } + default: + fatal_trace("unhandled ucisIntPropertyEnumT %d", property); + } +} + +ucisScopeT ucis_CreateScope(ucisT db, ucisScopeT parent, const char *name, + ucisSourceInfoT *srcinfo, int weight, + ucisSourceT source, ucisScopeTypeT type, + ucisFlagsT flags) +{ + ucisScopeT scope = xcalloc(sizeof(struct _ucisScope)); + scope->maxitems = EMBED_COVER_ITEMS; + + return scope; +} + +ucisScopeT ucis_CreateInstance(ucisT db, ucisScopeT parent, const char *name, + ucisSourceInfoT *fileinfo, int weight, + ucisSourceT source, ucisScopeTypeT type, + ucisScopeT du_scope, ucisFlagsT flags) +{ + ucisScopeT scope = xcalloc(sizeof(struct _ucisScope)); + scope->maxitems = EMBED_COVER_ITEMS; + + return scope; +} + +int ucis_SetTestData(ucisT db, ucisHistoryNodeT testhistorynode, + ucisTestDataT *testdata) +{ + ucisTestDataT copy = { + .teststatus = testdata->teststatus, + .simtime = testdata->simtime, + .timeunit = ucis_copy_string(db, testdata->timeunit), + .runcwd = ucis_copy_string(db, testdata->runcwd), + .cputime = 0.0, + .seed = ucis_copy_string(db, testdata->seed), + .cmd = PACKAGE, + .args = ucis_copy_string(db, testdata->args), + .compulsory = 0, + .date = ucis_copy_string(db, testdata->date), + .username = ucis_copy_string(db, testdata->username), + .cost = 0.0, + .toolcategory = UCIS_SIM_TOOL + }; + + testhistorynode->testdata = copy; + return 0; +} + +ucisHistoryNodeT ucis_CreateHistoryNode(ucisT db, ucisHistoryNodeT parent, + char *logicalname, char *physicalname, + ucisHistoryNodeKindT kind) +{ + ucisHistoryNodeT h = xcalloc(sizeof(struct _ucisHistoryNode)); + h->kind = kind; + + ucisHistoryNodeT *p = &(db->history_nodes); + for (; *p; p = &((*p)->next)); + *p = h; + + return h; +} + +const char *ucis_GetFileName(ucisT db, ucisFileHandleT filehandle) +{ + return filehandle->filename; +} + +ucisFileHandleT ucis_CreateFileHandle(ucisT db, const char* filename, + const char* fileworkdir) +{ + ucisFileHandleT exist = shash_get(db->files, filename); + if (exist != NULL) + return exist; + + ucisFileHandleT new = xcalloc(sizeof(struct _ucisFileHandle)); + new->filename = ucis_copy_string(db, filename); + + shash_put(db->files, filename, new); + return new; +} + +int ucis_CreateNextCover(ucisT db, ucisScopeT parent, const char *name, + ucisCoverDataT *data, ucisSourceInfoT *sourceinfo) +{ + if (parent->numitems == parent->maxitems) { + parent->maxitems *= 2; + + if (parent->maxitems == EMBED_COVER_ITEMS*2) { + ucisCoverItemT *list = + xmalloc_array(parent->maxitems, sizeof(ucisCoverItemT)); + for (int i = 0; i < EMBED_COVER_ITEMS; i++) + list[i] = parent->embed[i]; + + parent->extended = list; + } + else + parent->extended = xrealloc_array(parent->extended, parent->maxitems, + sizeof(ucisCoverItemT)); + } + + const int index = parent->numitems++; + ucisCoverItemT *item = ucis_get_cover_item(parent, index); + + item->data = *data; + item->sourceinfo = *sourceinfo; + + return index; +} + +const char *ucis_GetStringProperty(ucisT db, ucisObjT obj, int coverindex, + ucisStringPropertyEnumT property) +{ + MISSING; +} + +int ucis_SetStringProperty(ucisT db, ucisObjT obj, int coverindex, + ucisStringPropertyEnumT property, const char *value) +{ + MISSING; +} diff --git a/src/ucis/ucis-util.c b/src/ucis/ucis-util.c new file mode 100644 index 00000000..c8024536 --- /dev/null +++ b/src/ucis/ucis-util.c @@ -0,0 +1,39 @@ +// +// 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 "util.h" +#include "diag.h" +#include "ucis/ucis-api.h" + +#include + +static void ucis_error_handler(void *data, ucisErrorT *errorInfo) +{ + static const diag_level_t map[] = { DIAG_NOTE, DIAG_WARN, DIAG_ERROR }; + + diag_t *d = diag_new(map[errorInfo->severity], NULL); + diag_printf(d, "UCIS error: %s", errorInfo->msgstr); + diag_emit(d); + + if (errorInfo->severity == UCIS_MSG_ERROR) + fatal_exit(1); +} + +void ucis_init(void) +{ + ucis_RegisterErrorHandler(ucis_error_handler, NULL); +} diff --git a/src/ucis/ucis-util.h b/src/ucis/ucis-util.h new file mode 100644 index 00000000..2a16593d --- /dev/null +++ b/src/ucis/ucis-util.h @@ -0,0 +1,29 @@ +// +// 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 . +// + +#ifndef _UCIS_UTIL_H +#define _UCIS_UTIL_H + +#include "prim.h" +#include "ucis/ucis-api.h" + +#include +#include + +void ucis_init(void); + +#endif // _UCIS_UTIL_H diff --git a/src/ucis/ucis-xml.c b/src/ucis/ucis-xml.c new file mode 100644 index 00000000..3a8888c0 --- /dev/null +++ b/src/ucis/ucis-xml.c @@ -0,0 +1,50 @@ +// +// 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 "util.h" +#include "ucis/ucis-api.h" +#include "ucis/ucis-util.h" + +#include + +static void ucis_write_xml(ucisT db, FILE *f, time_t date) +{ + LOCAL_TEXT_BUF tb = tb_new(); + tb_strftime(tb, "L%FT%TZ", date); + + fprintf(f, "\n"); + fprintf(f, "\n", tb_get(tb)); + + fprintf(f, "\n"); +} + +int ucis_WriteToInterchangeFormat(ucisT db, const char* file, ucisScopeT scope, + int recurse, int covertype) +{ + FILE *f = fopen(file, "w"); + if (f == NULL) { + // ucis_error() + return -1; + } + + ucis_write_xml(db, f, time(NULL)); + + fclose(f); + return 0; +} diff --git a/test/Makemodule.am b/test/Makemodule.am index 59310941..7ee73591 100644 --- a/test/Makemodule.am +++ b/test/Makemodule.am @@ -4,7 +4,12 @@ TESTS = \ check_PROGRAMS += $(TESTS) bin/fstdump -EXTRA_PROGRAMS += bin/lockbench bin/jitperf bin/workqbench bin/mtstress +EXTRA_PROGRAMS += \ + bin/lockbench \ + bin/jitperf \ + bin/workqbench \ + bin/mtstress \ + bin/ucdbdump EXTRA_DIST += test/cobertura.dtd @@ -126,6 +131,8 @@ bin_mtstress_LDADD = \ $(check_LIBS) \ $(libzstd_LIBS) +bin_ucdbdump_SOURCES = test/ucdbdump.c + TESTS_ENVIRONMENT = \ BUILD_DIR=$(top_builddir) \ NVC_LIBPATH=$(abs_top_builddir)/lib \ diff --git a/test/ucdbdump.c b/test/ucdbdump.c new file mode 100644 index 00000000..f30e40e2 --- /dev/null +++ b/test/ucdbdump.c @@ -0,0 +1,114 @@ +// +// 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 "util.h" +#include "option.h" +#include "ucis/ucis-util.h" + +#include +#include +#include +#include +#include +#include + +static void print_coverage_count(ucisCoverDataT* coverdata) +{ + if (coverdata->flags & UCIS_IS_32BIT) + printf("%d", coverdata->data.int32); + else if (coverdata->flags & UCIS_IS_64BIT) + printf("%"PRIi64, coverdata->data.int64); + else if (coverdata->flags & UCIS_IS_VECTOR) { + const int bytelen = coverdata->bitlen/8 + (coverdata->bitlen%8)?1:0; + for (int i = 0; i < bytelen; i++) { + if (i) printf(" "); + printf("%02x",coverdata->data.bytevector[i]); + } + } +} + +static ucisCBReturnT callback(void* userdata, ucisCBDataT* cbdata) +{ + ucisScopeT **underneathp = userdata; + + switch (cbdata->reason) { + case UCIS_REASON_DU: + assert(*underneathp == NULL); + *underneathp = cbdata->obj; + break; + case UCIS_REASON_SCOPE: + break; + case UCIS_REASON_ENDSCOPE: + if (cbdata->obj == *underneathp) + *underneathp = NULL; + break; + case UCIS_REASON_CVBIN: + { + ucisT db = cbdata->db; + ucisScopeT scope = (ucisScopeT)cbdata->obj; + char* name; + ucisCoverDataT coverdata; + ucisSourceInfoT sourceinfo; + ucis_GetCoverData(db, scope, cbdata->coverindex, &name, + &coverdata, &sourceinfo); + + const char sep = ucis_GetPathSeparator(db); + const char *hier = + ucis_GetStringProperty(db, scope, -1, UCIS_STR_SCOPE_HIER_NAME); + + if (*underneathp != NULL && hier[0] == sep) { + // Handle UCIS_INST_ONCE optimisation + const char *du_name = ucis_GetStringProperty(db, *underneathp, -1, + UCIS_STR_SCOPE_NAME); + printf("%s%s", du_name, strchr(hier + 1, sep)); + } + else + printf("%s", hier); + + if (name != NULL && name[0] != '\0') + printf("%c%s: ", sep, name); + else + printf(" [%s:%d]: ", ucis_GetFileName(db,&sourceinfo.filehandle), + sourceinfo.line); + + print_coverage_count(&coverdata); + printf("\n"); + } + break; + default: + break; + } + + return UCIS_SCAN_CONTINUE; +} + +int main(int argc, char **argv) +{ + if (argc != 2) + err(1, "usage: ucdbdump FILE"); + + ucisT db = ucis_Open(argv[1]); + if (db == NULL) + return 1; + + ucisScopeT *underneath = NULL; + ucis_CallBack(db, NULL, callback, &underneath); + assert(underneath == NULL); + + ucis_Close(argv[1]); + return 0; +} -- 2.39.2