From 174cc937948e762c170d95536ccb9cb6eba2278a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 28 Jan 2024 11:27:17 +0000 Subject: [PATCH] New approach to translating Verilog modules --- lib/nvc/verilog-body.vhd | 2 +- src/common.c | 48 +++++++++- src/common.h | 12 ++- src/dump.c | 26 +++-- src/elab.c | 158 +++++++++++++++++++++++-------- src/jit/jit-irgen.c | 3 + src/lower.c | 19 ++-- src/lower.h | 6 +- src/rt/model.c | 78 +++++---------- src/vcode.c | 82 +++++++++++++++- src/vcode.h | 3 + src/vlog/Makemodule.am | 3 +- src/vlog/vlog-dump.c | 35 ++++--- src/vlog/vlog-lower.c | 199 +++++++++++++++------------------------ src/vlog/vlog-node.c | 15 ++- src/vlog/vlog-node.h | 1 - src/vlog/vlog-phase.h | 5 +- src/vlog/vlog-trans.c | 135 ++++++++++++++++++++++++++ test/dump/vlog1.v | 1 + test/regress/vlog1.vhd | 2 +- test/test_dump.c | 4 +- 21 files changed, 551 insertions(+), 286 deletions(-) create mode 100644 src/vlog/vlog-trans.c diff --git a/lib/nvc/verilog-body.vhd b/lib/nvc/verilog-body.vhd index 5e8ae5f5..026de730 100644 --- a/lib/nvc/verilog-body.vhd +++ b/lib/nvc/verilog-body.vhd @@ -52,7 +52,7 @@ package body verilog is when '1' => return '1'; when '0' => return '0'; when 'Z' => return 'Z'; - when others => return 'U'; + when 'X' => return 'U'; end case; end function; diff --git a/src/common.c b/src/common.c index ba3ae56a..c67fa3c7 100644 --- a/src/common.c +++ b/src/common.c @@ -1070,6 +1070,7 @@ void intern_strings(void) id_cache[W_NEVER_WAITS] = ident_new("NEVER_WAITS"); id_cache[W_NVC_VERILOG] = ident_new("NVC.VERILOG"); id_cache[W_NVC_PSL_SUPPORT] = ident_new("NVC.PSL_SUPPORT"); + id_cache[W_SHAPE] = ident_new("shape"); id_cache[W_IEEE_LOGIC_VECTOR] = ident_new("IEEE.STD_LOGIC_1164.STD_LOGIC_VECTOR"); @@ -1305,6 +1306,37 @@ type_t ieee_type(ieee_type_t which) return cache[which]; } +static tree_t cached_verilog(void) +{ + static tree_t verilog_cache[STD_19 + 1] = {}; + return cached_unit(NULL, verilog_cache, W_NVC, W_NVC_VERILOG); +} + +type_t verilog_type(verilog_type_t which) +{ + static type_t cache[VERILOG_INT64 + 1] = {}; + assert(which < ARRAY_LEN(cache)); + + if (cache[which] == NULL) { + const char *names[] = { + "T_LOGIC", + "T_PACKED_LOGIC", + "T_INT64", + }; + + tree_t d = search_decls(cached_verilog(), ident_new(names[which]), 0); + if (d == NULL) + fatal_trace("cannot find NVC.VERILOG type %s", names[which]); + + // STD.STANDARD cannot depend on NVC.VERILOG + assert(!opt_get_int(OPT_BOOTSTRAP)); + + return (cache[which] = tree_type(d)); + } + else + return cache[which]; +} + type_t reflection_type(reflect_type_t which) { static type_t cache[REFLECT_SUBTYPE_MIRROR + 1] = {}; @@ -1410,6 +1442,20 @@ tree_t std_func(ident_t mangled) return NULL; } +tree_t verilog_func(ident_t mangled) +{ + tree_t pack = cached_verilog(); + + const int ndecls = tree_decls(pack); + for (int i = 0; i < ndecls; i++) { + tree_t d = tree_decl(pack, i); + if (is_subprogram(d) && tree_ident2(d) == mangled) + return d; + } + + fatal_trace("missing Verilog helper function %s", istr(mangled)); +} + tree_t name_to_ref(tree_t name) { tree_kind_t kind; @@ -2270,7 +2316,7 @@ void print_syntax(const char *fmt, ...) last_was_newline = true; } } - else if (*p == '#') { + else if (*p == '#' && *(p + 1) != '#') { tb_printf(tb, "$bold$$cyan$"); last_was_newline = false; highlighting = true; diff --git a/src/common.h b/src/common.h index 9446d82a..a11ae410 100644 --- a/src/common.h +++ b/src/common.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2013-2023 Nick Gasson +// Copyright (C) 2013-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 @@ -171,6 +171,15 @@ typedef enum { type_t ieee_type(ieee_type_t which); +typedef enum { + VERILOG_LOGIC, + VERILOG_PACKED_LOGIC, + VERILOG_INT64, +} verilog_type_t; + +type_t verilog_type(verilog_type_t which); +tree_t verilog_func(ident_t mangled); + typedef enum { REFLECT_VALUE_MIRROR, REFLECT_SUBTYPE_MIRROR, @@ -232,6 +241,7 @@ typedef enum { W_VITAL, W_NEVER_WAITS, W_NVC_VERILOG, + W_SHAPE, NUM_WELL_KNOWN } well_known_t; diff --git a/src/dump.c b/src/dump.c index 9ff903ca..fddb08df 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1064,6 +1064,17 @@ static void dump_instance(tree_t t, int indent) static void dump_stmt(tree_t t, int indent) { + switch (tree_kind(t)) { + case T_PSL: + dump_psl(t, indent); + return; + case T_VERILOG: + vlog_dump(tree_vlog(t), indent); + return; + default: + break; + } + tab(indent); if (tree_has_ident(t)) { @@ -1367,21 +1378,6 @@ static void dump_stmt(tree_t t, int indent) dump_stmt(tree_stmt(t, 0), 0); return; - case T_PSL: - dump_psl(t, 0); - break; - - case T_VERILOG: - print_syntax("#block #is\n"); - dump_generic_map(t, indent + 2, ";\n"); - dump_port_map(t, indent + 2, ";\n"); - tab(indent); - print_syntax("#begin\n"); - vlog_dump(tree_vlog(t), indent + 2); - tab(indent); - print_syntax("#end #block"); - break; - case T_DUMMY_DRIVER: print_syntax("-- dummy driver for "); dump_expr(tree_target(t)); diff --git a/src/elab.c b/src/elab.c index 607c1c9e..c37fde40 100644 --- a/src/elab.c +++ b/src/elab.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2023 Nick Gasson +// Copyright (C) 2011-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 @@ -64,6 +64,7 @@ typedef struct _elab_ctx { cover_data_t *cover; void *context; driver_set_t *drivers; + hash_t *shapes; } elab_ctx_t; typedef struct { @@ -1109,6 +1110,7 @@ static void elab_inherit_context(elab_ctx_t *ctx, const elab_ctx_t *parent) ctx->out = ctx->out ?: parent->out; ctx->cover = parent->cover; ctx->inst = ctx->inst ?: parent->inst; + ctx->shapes = parent->shapes; } static driver_set_t *elab_driver_set(const elab_ctx_t *ctx) @@ -1121,9 +1123,9 @@ static driver_set_t *elab_driver_set(const elab_ctx_t *ctx) return NULL; } -static void elab_lower(tree_t b, elab_ctx_t *ctx) +static void elab_lower(tree_t b, vcode_unit_t shape, elab_ctx_t *ctx) { - ctx->lowered = lower_instance(ctx->registry, ctx->parent->lowered, + ctx->lowered = lower_instance(ctx->registry, ctx->parent->lowered, shape, elab_driver_set(ctx), ctx->cover, b); if (error_count() > 0) @@ -1138,7 +1140,7 @@ static void elab_lower(tree_t b, elab_ctx_t *ctx) diag_remove_hint_fn(elab_hint_fn); } -static void elab_mixed_port_map(tree_t wrap, tree_t inst, vlog_node_t mod) +static void elab_mixed_port_map(tree_t block, tree_t inst, vlog_node_t mod) { tree_t comp = tree_ref(inst); assert(tree_kind(comp) == T_COMPONENT); @@ -1151,6 +1153,14 @@ static void elab_mixed_port_map(tree_t wrap, tree_t inst, vlog_node_t mod) type_t std_logic = ieee_type(IEEE_STD_LOGIC); +#define T_LOGIC "19NVC.VERILOG.T_LOGIC" + ident_t to_vhdl_name = ident_new("NVC.VERILOG.TO_VHDL(" T_LOGIC ")U"); + ident_t to_verilog_name = ident_new("NVC.VERILOG.TO_VERILOG(U)" T_LOGIC); + + tree_t to_vhdl = verilog_func(to_vhdl_name); + tree_t to_verilog = verilog_func(to_verilog_name); + + bool have_named = false; for (int i = 0; i < ndecls; i++) { vlog_node_t mport = vlog_decl(mod, i); if (vlog_kind(mport) != V_PORT_DECL) @@ -1159,12 +1169,13 @@ static void elab_mixed_port_map(tree_t wrap, tree_t inst, vlog_node_t mod) ident_t name = vlog_ident2(mport); int cpos = 0; - tree_t cport = NULL; + tree_t cport = NULL, bport = NULL; for (; cpos < nports; cpos++) { tree_t pj = tree_port(comp, cpos); if (tree_ident(pj) == name) { cport = pj; mask_set(&have, cpos); + bport = tree_port(block, cpos); // XXX: need two levels of block break; } } @@ -1198,7 +1209,39 @@ static void elab_mixed_port_map(tree_t wrap, tree_t inst, vlog_node_t mod) return; } - tree_add_param(wrap, map); + tree_t value = tree_value(map); + const tree_kind_t value_kind = tree_kind(value); + if (value_kind == T_TYPE_CONV || value_kind == T_CONV_FUNC) { + error_at(tree_loc(map), "type conversions are not supported in port " + "maps when instantiating a Verilog module"); + return; + } + + if (vlog_subkind(mport) == V_PORT_INPUT) { + tree_t conv = tree_new(T_CONV_FUNC); + tree_set_loc(conv, tree_loc(map)); + tree_set_ref(conv, to_verilog); + tree_set_ident(conv, tree_ident(to_verilog)); + tree_set_type(conv, type_result(tree_type(to_verilog))); + tree_set_value(conv, value); + + if (have_named) + add_param(block, conv, P_NAMED, make_ref(bport)); + else + add_param(block, conv, P_POS, NULL); + } + else { + tree_t conv = tree_new(T_CONV_FUNC); + tree_set_loc(conv, tree_loc(map)); + tree_set_ref(conv, to_vhdl); + tree_set_ident(conv, tree_ident(to_vhdl)); + tree_set_type(conv, type_result(tree_type(to_vhdl))); + tree_set_value(conv, make_ref(bport)); + + add_param(block, value, P_NAMED, conv); + have_named = true; + } + cpos++; } @@ -1215,29 +1258,34 @@ static void elab_mixed_port_map(tree_t wrap, tree_t inst, vlog_node_t mod) mask_free(&have); } -static void elab_verilog_module(tree_t wrap, tree_t inst, const elab_ctx_t *ctx) +static void elab_verilog_module(tree_t wrap, tree_t inst, elab_ctx_t *ctx) { vlog_node_t mod = tree_vlog(wrap); - vlog_node_t root = vlog_new(V_ROOT); - vlog_set_loc(root, tree_loc(wrap)); - vlog_set_ident(root, tree_ident(wrap)); - - const int ndecls = vlog_decls(mod); - for (int i = 0; i < ndecls; i++) - vlog_add_decl(root, vlog_decl(mod, i)); + vcode_unit_t shape = hash_get(ctx->shapes, mod); + if (shape == NULL) { + shape = vlog_lower(ctx->registry, wrap); + hash_put(ctx->shapes, mod, shape); + } - if (inst != NULL) - elab_mixed_port_map(wrap, inst, mod); + vlog_trans(mod, ctx->out); const int nstmts = vlog_stmts(mod); - for (int i = 0; i < nstmts; i++) - vlog_add_stmt(root, vlog_stmt(mod, i)); + for (int i = 0; i < nstmts; i++) { + vlog_node_t s = vlog_stmt(mod, i); - tree_set_vlog(wrap, root); - tree_add_stmt(ctx->out, wrap); + tree_t w = tree_new(T_VERILOG); + tree_set_ident(w, vlog_ident(s)); + tree_set_loc(w, vlog_loc(s)); + tree_set_vlog(w, s); - vlog_lower(ctx->registry, wrap, ctx->parent ? ctx->parent->lowered : NULL); + tree_add_stmt(ctx->out, w); + } + + if (inst != NULL) + elab_mixed_port_map(ctx->out, inst, mod); + + elab_lower(ctx->out, shape, ctx); } static void elab_instance(tree_t t, const elab_ctx_t *ctx) @@ -1287,11 +1335,6 @@ static void elab_instance(tree_t t, const elab_ctx_t *ctx) tree_kind_str(tree_kind(ref))); } - if (arch != NULL && tree_kind(arch) == T_VERILOG) { - elab_verilog_module(arch, t, &new_ctx); - return; - } - tree_t b = tree_new(T_BLOCK); tree_set_ident(b, tree_ident(t)); tree_set_loc(b, tree_loc(t)); @@ -1307,11 +1350,17 @@ static void elab_instance(tree_t t, const elab_ctx_t *ctx) elab_ports(ref, ref, t, &new_ctx); if (error_count() == 0) - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_pop_scope(&new_ctx); return; } + else if (tree_kind(arch) == T_VERILOG) { + elab_push_scope(arch, &new_ctx); + elab_verilog_module(arch, t, &new_ctx); + elab_pop_scope(&new_ctx); + return; + } new_ctx.inst_name = hpathf(new_ctx.inst_name, '@', "%s(%s)", simple_name(istr(tree_ident2(arch))), @@ -1343,7 +1392,7 @@ static void elab_instance(tree_t t, const elab_ctx_t *ctx) if (error_count() == 0) { new_ctx.drivers = find_drivers(arch_copy); - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_stmts(entity, &new_ctx); elab_stmts(arch_copy, &new_ctx); } @@ -1531,7 +1580,7 @@ static void elab_for_generate(tree_t t, const elab_ctx_t *ctx) elab_decls(copy, &new_ctx); if (error_count() == 0) { - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_stmts(copy, &new_ctx); } @@ -1585,7 +1634,7 @@ static void elab_if_generate(tree_t t, const elab_ctx_t *ctx) new_ctx.drivers = find_drivers(cond); if (error_count() == 0) { - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_stmts(cond, &new_ctx); } @@ -1628,7 +1677,7 @@ static void elab_case_generate(tree_t t, const elab_ctx_t *ctx) new_ctx.drivers = find_drivers(chosen); if (error_count() == 0) { - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_stmts(chosen, &new_ctx); } @@ -1716,7 +1765,7 @@ static void elab_block(tree_t t, const elab_ctx_t *ctx) elab_decls(t, &new_ctx); if (error_count() == base_errors) { - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_stmts(t, &new_ctx); } @@ -1830,7 +1879,7 @@ static void elab_top_level(tree_t arch, ident_t ename, const elab_ctx_t *ctx) elab_decls(arch_copy, &new_ctx); if (error_count() == 0) { - elab_lower(b, &new_ctx); + elab_lower(b, NULL, &new_ctx); elab_stmts(entity, &new_ctx); elab_stmts(arch_copy, &new_ctx); } @@ -1838,6 +1887,38 @@ static void elab_top_level(tree_t arch, ident_t ename, const elab_ctx_t *ctx) elab_pop_scope(&new_ctx); } +static void elab_verilog_top_level(vlog_node_t mod, const elab_ctx_t *ctx) +{ + tree_t wrap = tree_new(T_VERILOG); + tree_set_loc(wrap, vlog_loc(mod)); + tree_set_ident(wrap, vlog_ident(mod)); + tree_set_vlog(wrap, mod); + + ident_t base = ident_rfrom(vlog_ident(mod), '.'); + + const char *name = simple_name(istr(base)); + ident_t ninst = hpathf(ctx->inst_name, ':', ":%s(verilog)", name); + ident_t npath = hpathf(ctx->path_name, ':', ":%s", name); + + tree_t b = tree_new(T_BLOCK); + tree_set_ident(b, base); + tree_set_loc(b, vlog_loc(mod)); + + tree_add_stmt(ctx->out, b); + + elab_ctx_t new_ctx = { + .out = b, + .path_name = npath, + .inst_name = ninst, + .dotted = vlog_ident(mod), + }; + elab_inherit_context(&new_ctx, ctx); + + elab_push_scope(wrap, &new_ctx); + elab_verilog_module(wrap, NULL, &new_ctx); + elab_pop_scope(&new_ctx); +} + void elab_set_generic(const char *name, const char *value) { ident_t id = ident_new(name); @@ -1885,6 +1966,7 @@ tree_t elab(object_t *top, jit_t *jit, unit_registry_t *ur, cover_data_t *cover) .library = lib_work(), .jit = jit, .registry = ur, + .shapes = hash_new(16), }; if (vhdl != NULL) { @@ -1908,14 +1990,10 @@ tree_t elab(object_t *top, jit_t *jit, unit_registry_t *ur, cover_data_t *cover) fatal("%s is not a suitable top-level unit", istr(tree_ident(vhdl))); } } - else { - tree_t wrap = tree_new(T_VERILOG); - tree_set_loc(wrap, vlog_loc(vlog)); - tree_set_ident(wrap, vlog_ident(vlog)); - tree_set_vlog(wrap, vlog); + else + elab_verilog_top_level(vlog, &ctx); - elab_verilog_module(wrap, NULL, &ctx); - } + hash_free(ctx.shapes); if (error_count() > 0) return NULL; diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index 439ca35f..ddce2289 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -1266,7 +1266,9 @@ static void irgen_op_return(jit_irgen_t *g, int op) if (g->used_tlab && !vcode_unit_has_escaping_tlab(g->func->unit)) macro_trim(g); + break; + case VCODE_UNIT_SHAPE: break; } @@ -3911,6 +3913,7 @@ static void irgen_locals(jit_irgen_t *g) case VCODE_UNIT_PROCEDURE: case VCODE_UNIT_PACKAGE: case VCODE_UNIT_PROTECTED: + case VCODE_UNIT_SHAPE: on_stack = false; break; default: diff --git a/src/lower.c b/src/lower.c index 90add050..c217012e 100644 --- a/src/lower.c +++ b/src/lower.c @@ -9797,7 +9797,7 @@ static void lower_decl(lower_unit_t *lu, tree_t decl) } } -void lower_finished(lower_unit_t *lu) +void lower_finished(lower_unit_t *lu, vcode_unit_t shape) { assert(!lu->finished); @@ -9807,6 +9807,9 @@ void lower_finished(lower_unit_t *lu) if (opt_get_verbose(OPT_DUMP_VCODE, istr(lu->name))) vcode_dump(); + if (shape != NULL) + vcode_check_shape(lu->vunit, shape); + lu->finished = true; } @@ -11211,7 +11214,7 @@ void lower_process(lower_unit_t *parent, tree_t proc, driver_set_t *ds) cover_pop_scope(lu->cover); - lower_finished(lu); + lower_finished(lu, NULL); unit_registry_finalise(parent->registry, lu); } @@ -12542,7 +12545,7 @@ vcode_unit_t lower_case_generate_thunk(lower_unit_t *parent, tree_t t) if (!vcode_block_finished()) emit_return(emit_const(vint, -1)); - lower_finished(lu); + lower_finished(lu, NULL); lower_unit_free(lu); return thunk; @@ -12589,7 +12592,7 @@ vcode_unit_t lower_thunk(lower_unit_t *parent, tree_t t) else emit_return(result_reg); - lower_finished(lu); + lower_finished(lu, NULL); lower_unit_free(lu); if (vcode_unit_has_undefined(thunk)) { @@ -12602,8 +12605,8 @@ vcode_unit_t lower_thunk(lower_unit_t *parent, tree_t t) } lower_unit_t *lower_instance(unit_registry_t *ur, lower_unit_t *parent, - driver_set_t *ds, cover_data_t *cover, - tree_t block) + vcode_unit_t shape, driver_set_t *ds, + cover_data_t *cover, tree_t block) { assert(tree_kind(block) == T_BLOCK); @@ -12635,7 +12638,7 @@ lower_unit_t *lower_instance(unit_registry_t *ur, lower_unit_t *parent, emit_return(VCODE_INVALID_REG); - lower_finished(lu); + lower_finished(lu, shape); return lu; } @@ -12817,7 +12820,7 @@ void unit_registry_finalise(unit_registry_t *ur, lower_unit_t *lu) assert(pointer_tag(hash_get(ur->map, lu->name)) == UNIT_GENERATED); if (!lu->finished) - lower_finished(lu); + lower_finished(lu, NULL); if (lu->deferred > 0) return; diff --git a/src/lower.h b/src/lower.h index b1b37f5a..8ffdd3f6 100644 --- a/src/lower.h +++ b/src/lower.h @@ -43,7 +43,7 @@ lower_unit_t *lower_unit_new(unit_registry_t *ur, lower_unit_t *parent, vcode_unit_t vunit, cover_data_t *cover, tree_t container); void lower_unit_free(lower_unit_t *lu); -void lower_finished(lower_unit_t *lu); +void lower_finished(lower_unit_t *lu, vcode_unit_t shape); vcode_unit_t get_vcode(lower_unit_t *lu); @@ -51,8 +51,8 @@ vcode_reg_t lower_lvalue(lower_unit_t *lu, tree_t expr); vcode_reg_t lower_rvalue(lower_unit_t *lu, tree_t expr); lower_unit_t *lower_instance(unit_registry_t *ur, lower_unit_t *parent, - driver_set_t *ds, cover_data_t *cover, - tree_t block); + vcode_unit_t shape, driver_set_t *ds, + cover_data_t *cover, tree_t block); void lower_process(lower_unit_t *parent, tree_t proc, driver_set_t *ds); vcode_unit_t lower_thunk(lower_unit_t *parent, tree_t fcall); vcode_unit_t lower_case_generate_thunk(lower_unit_t *parent, tree_t t); diff --git a/src/rt/model.c b/src/rt/model.c index ec8633b7..03e69857 100644 --- a/src/rt/model.c +++ b/src/rt/model.c @@ -414,52 +414,6 @@ static void global_event(rt_model_t *m, rt_event_t kind) } } -static rt_scope_t *scope_for_verilog(rt_model_t *m, vlog_node_t scope, - ident_t prefix) -{ - rt_scope_t *s = xcalloc(sizeof(rt_scope_t)); - s->where = NULL; - s->name = ident_prefix(prefix, vlog_ident(scope), '.'); - s->kind = SCOPE_INSTANCE; - s->privdata = mptr_new(m->mspace, "block privdata"); - - hash_put(m->scopes, scope, s); - - const int nstmts = vlog_stmts(scope); - for (int i = 0; i < nstmts; i++) { - vlog_node_t v = vlog_stmt(scope, i); - switch (vlog_kind(v)) { - case V_ALWAYS: - case V_INITIAL: - case V_ASSIGN: - { - ident_t name = vlog_ident(v); - ident_t sym = ident_prefix(s->name, name, '.'); - - rt_proc_t *p = xcalloc(sizeof(rt_proc_t)); - p->where = NULL; - p->name = ident_prefix(NULL, ident_downcase(name), ':'); - p->handle = jit_lazy_compile(m->jit, sym); - p->scope = s; - p->privdata = mptr_new(m->mspace, "process privdata"); - - p->wakeable.kind = W_PROC; - p->wakeable.pending = false; - p->wakeable.postponed = false; - p->wakeable.delayed = false; - - list_add(&s->procs, p); - } - break; - - default: - break; - } - } - - return s; -} - static rt_scope_t *scope_for_block(rt_model_t *m, tree_t block, ident_t prefix) { rt_scope_t *s = xcalloc(sizeof(rt_scope_t)); @@ -489,9 +443,27 @@ static rt_scope_t *scope_for_block(rt_model_t *m, tree_t block, ident_t prefix) case T_VERILOG: { - rt_scope_t *c = scope_for_verilog(m, tree_vlog(t), s->name); - c->parent = s; - list_add(&s->children, c); + vlog_node_t mod = tree_vlog(tree_ref(hier)); + assert(vlog_kind(mod) == V_MODULE); + + ident_t name = tree_ident(t); + ident_t suffix = well_known(W_SHAPE); + ident_t shape = ident_prefix(vlog_ident(mod), suffix, '.'); + ident_t sym = ident_prefix(shape, name, '.'); + + rt_proc_t *p = xcalloc(sizeof(rt_proc_t)); + p->where = t; + p->name = ident_prefix(path, ident_downcase(name), ':'); + p->handle = jit_lazy_compile(m->jit, sym); + p->scope = s; + p->privdata = mptr_new(m->mspace, "process privdata"); + + p->wakeable.kind = W_PROC; + p->wakeable.pending = false; + p->wakeable.postponed = false; + p->wakeable.delayed = false; + + list_add(&s->procs, p); } break; @@ -573,13 +545,7 @@ rt_model_t *model_new(tree_t top, jit_t *jit) m->threads[thread_id()] = xcalloc(sizeof(model_thread_t)); - rt_scope_t *s = NULL; - tree_t s0 = tree_stmt(top, 0); - if (tree_kind(s0) == T_VERILOG) - s = scope_for_verilog(m, tree_vlog(s0), lib_name(lib_work())); - else - s = scope_for_block(m, s0, lib_name(lib_work())); - + rt_scope_t *s = scope_for_block(m, tree_stmt(top, 0), lib_name(lib_work())); list_add(&m->root->children, s); __trace_on = opt_get_int(OPT_RT_TRACE); diff --git a/src/vcode.c b/src/vcode.c index c63d2642..03d7fa17 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -1182,6 +1182,7 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) case VCODE_UNIT_PACKAGE: printf("package"); break; case VCODE_UNIT_PROTECTED: printf("protected"); break; case VCODE_UNIT_PROPERTY: printf("property"); break; + case VCODE_UNIT_SHAPE: printf("shape"); break; } color_printf("$$\n"); if (vu->context != NULL) @@ -3068,7 +3069,8 @@ vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context) vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context) { - assert(context->kind == VCODE_UNIT_INSTANCE); + assert(context->kind == VCODE_UNIT_INSTANCE + || context->kind == VCODE_UNIT_SHAPE); vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit)); vu->kind = VCODE_UNIT_PROCESS; @@ -3111,6 +3113,29 @@ vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context) return vu; } +vcode_unit_t emit_shape(ident_t name, object_t *obj, vcode_unit_t context) +{ + assert(context == NULL || context->kind == VCODE_UNIT_SHAPE); + + vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit)); + vu->kind = VCODE_UNIT_SHAPE; + vu->name = name; + vu->context = context; + vu->depth = vcode_unit_calc_depth(vu); + vu->result = VCODE_INVALID_TYPE; + + object_locus(obj, &vu->module, &vu->offset); + + if (context != NULL) + vcode_add_child(context, vu); + + vcode_select_unit(vu); + vcode_select_block(emit_block()); + emit_debug_info(&(obj->loc)); + + return vu; +} + vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context) { vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit)); @@ -5957,6 +5982,61 @@ void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx) } } +#ifdef DEBUG +static void shape_mismatch(vcode_unit_t vu, vcode_unit_t shape, + const char *fmt, ...) +{ + vcode_select_unit(vu); + vcode_dump(); + + vcode_select_unit(shape); + vcode_dump(); + + va_list ap; + va_start(ap, fmt); + + diag_t *d = diag_new(DIAG_FATAL, NULL); + diag_printf(d, "instance %s does not match shape %s", istr(vu->name), + istr(shape->name)); + diag_stacktrace(d, true); + diag_vhint(d, NULL, fmt, ap); + diag_emit(d); + + va_end(ap); + + fatal_exit(1); +} +#endif + +void vcode_check_shape(vcode_unit_t vu, vcode_unit_t shape) +{ +#ifdef DEBUG + assert(shape->kind == VCODE_UNIT_SHAPE); + assert(vu->kind == VCODE_UNIT_INSTANCE); + + if (shape->vars.count <= vu->vars.count) { + for (int i = 0; i < shape->vars.count; i++) { + var_t *v = var_array_nth_ptr(&(vu->vars), i); + var_t *s = var_array_nth_ptr(&(shape->vars), i); + + if (v->name != s->name) + shape_mismatch(vu, shape, "var %d name %s != %s", i, istr(v->name), + istr(s->name)); + else if (v->flags != s->flags) + shape_mismatch(vu, shape, "var %d flags %x != %x", i, v->flags, + s->flags); + // XXX: not possible to compare types at the moment + } + } + else + shape_mismatch(vu, shape, "shape vars %d > unit vars %d", + shape->vars.count, vu->vars.count); + + if (shape->context != NULL) + vcode_check_shape(vu->context, shape->context); +#endif +} + #if VCODE_CHECK_UNIONS #define OP_USE_COUNT_U0(x) \ (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x)) diff --git a/src/vcode.h b/src/vcode.h index c92d40cf..24c1faeb 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -208,6 +208,7 @@ typedef enum { VCODE_UNIT_PACKAGE, VCODE_UNIT_PROTECTED, VCODE_UNIT_PROPERTY, + VCODE_UNIT_SHAPE, } vunit_kind_t; typedef enum { @@ -312,6 +313,7 @@ vcode_unit_t vcode_active_unit(void); vcode_unit_t vcode_unit_context(vcode_unit_t vu); void vcode_unit_object(vcode_unit_t vu, ident_t *module, ptrdiff_t *offset); void vcode_set_result(vcode_type_t type); +void vcode_check_shape(vcode_unit_t vu, vcode_unit_t shape); void vcode_state_save(vcode_state_t *state); void vcode_state_restore(const vcode_state_t *state); @@ -361,6 +363,7 @@ vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context); vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context); vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context); vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context); +vcode_unit_t emit_shape(ident_t name, object_t *obj, vcode_unit_t context); vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context); vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context); vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context); diff --git a/src/vlog/Makemodule.am b/src/vlog/Makemodule.am index a9a412e3..41c0a347 100644 --- a/src/vlog/Makemodule.am +++ b/src/vlog/Makemodule.am @@ -5,7 +5,8 @@ lib_libnvc_a_SOURCES += \ src/vlog/vlog-dump.c \ src/vlog/vlog-lower.c \ src/vlog/vlog-number.h \ - src/vlog/vlog-number.c + src/vlog/vlog-number.c \ + src/vlog/vlog-trans.c if ENABLE_VERILOG lib_libnvc_a_SOURCES += \ diff --git a/src/vlog/vlog-dump.c b/src/vlog/vlog-dump.c index 6d7a150f..be7af4ed 100644 --- a/src/vlog/vlog-dump.c +++ b/src/vlog/vlog-dump.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2022-2023 Nick Gasson +// Copyright (C) 2022-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 @@ -56,17 +56,6 @@ static void vlog_dump_module(vlog_node_t v, int indent) print_syntax("#endmodule // %s\n\n", istr(vlog_ident2(v))); } -static void vlog_dump_root(vlog_node_t v, int indent) -{ - const int ndecls = vlog_decls(v); - for (int i = 0; i < ndecls; i++) - vlog_dump(vlog_decl(v, i), indent); - - const int nstmts = vlog_stmts(v); - for (int i = 0; i < nstmts; i++) - vlog_dump(vlog_stmt(v, i), indent); -} - static void vlog_dump_port_decl(vlog_node_t v, int indent) { tab(indent); @@ -158,24 +147,24 @@ static void vlog_dump_seq_block(vlog_node_t v, int indent) static void vlog_dump_timing(vlog_node_t v, int indent) { - print_syntax("@("); - vlog_dump(vlog_value(v), 0); - print_syntax(")\n"); + vlog_dump(vlog_value(v), indent); if (vlog_stmts(v) > 0) - vlog_dump(vlog_stmt(v, 0), indent + 2); + vlog_dump(vlog_stmt(v, 0), 0); else print_syntax(";\n"); } static void vlog_dump_event(vlog_node_t v) { + print_syntax("@("); switch (vlog_subkind(v)) { case V_EVENT_POSEDGE: print_syntax("#posedge "); break; case V_EVENT_NEGEDGE: print_syntax("#negedge "); break; } vlog_dump(vlog_value(v), 0); + print_syntax(") "); } static void vlog_dump_nbassign(vlog_node_t v, int indent) @@ -285,15 +274,20 @@ static void vlog_dump_binary(vlog_node_t v) vlog_dump(vlog_right(v), 0); } +static void vlog_dump_delay_control(vlog_node_t v, int indent) +{ + tab(indent); + print_syntax("##"); + vlog_dump(vlog_value(v), 0); + print_syntax(" "); +} + void vlog_dump(vlog_node_t v, int indent) { switch (vlog_kind(v)) { case V_MODULE: vlog_dump_module(v, indent); break; - case V_ROOT: - vlog_dump_root(v, indent); - break; case V_REF: print_syntax("%s", istr(vlog_ident(v))); break; @@ -345,6 +339,9 @@ void vlog_dump(vlog_node_t v, int indent) case V_BINARY: vlog_dump_binary(v); break; + case V_DELAY_CONTROL: + vlog_dump_delay_control(v, indent); + break; default: print_syntax("\n"); fflush(stdout); diff --git a/src/vlog/vlog-lower.c b/src/vlog/vlog-lower.c index ac53e30a..115030db 100644 --- a/src/vlog/vlog-lower.c +++ b/src/vlog/vlog-lower.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 @@ -57,6 +57,7 @@ static inline vcode_type_t vlog_packed_logic_type(void) return vtype_uarray(1, vlogic, vlogic); } +#if 0 static vcode_reg_t vlog_debug_locus(vlog_node_t v) { ident_t unit; @@ -65,6 +66,7 @@ static vcode_reg_t vlog_debug_locus(vlog_node_t v) return emit_debug_locus(unit, offset); } +#endif static vcode_reg_t vlog_helper_package(void) { @@ -165,7 +167,7 @@ static vcode_reg_t vlog_lower_to_bool(lower_unit_t *lu, vcode_reg_t reg) case VCODE_TYPE_INT: { vcode_type_t vlogic = vlog_logic_type(); - vcode_reg_t one_reg = emit_const(vlogic, 1); + vcode_reg_t one_reg = emit_const(vlogic, LOGIC_1); assert(vtype_eq(vcode_reg_type(reg), vlogic)); return emit_cmp(VCODE_CMP_EQ, reg, one_reg); } @@ -176,122 +178,39 @@ static vcode_reg_t vlog_lower_to_bool(lower_unit_t *lu, vcode_reg_t reg) } } -static void vlog_lower_signal_decl(lower_unit_t *lu, vlog_node_t decl) +static vcode_reg_t vlog_lower_integer(lower_unit_t *lu, vlog_node_t expr) { - vcode_type_t vlogic = vlog_logic_type(); - vcode_type_t vsignal = vtype_signal(vlogic); - vcode_type_t voffset = vtype_offset(); - - const int nranges = vlog_ranges(decl); - - vcode_dim_t *dims = NULL; - if (nranges > 0) { - dims = xmalloc_array(nranges, sizeof(vcode_dim_t)); - vsignal = vtype_uarray(nranges, vsignal, vsignal); + if (vlog_kind(expr) == V_NUMBER) { + number_t n = vlog_number(expr); + if (number_is_defined(n)) { + vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX); + return emit_const(vint64, number_integer(n)); + } } - vcode_var_t var = emit_var(vsignal, vlogic, vlog_ident(decl), VAR_SIGNAL); - lower_put_vcode_obj(decl, var, lu); + return vlog_lower_to_integer(lu, vlog_lower_rvalue(lu, expr)); +} - vcode_reg_t size = emit_const(voffset, 1); - vcode_reg_t count = emit_const(voffset, 1); - vcode_reg_t init = emit_const(vlogic, 0); - vcode_reg_t flags = emit_const(voffset, 0); - vcode_reg_t locus = vlog_debug_locus(decl); +static vcode_reg_t vlog_lower_decl_bounds(lower_unit_t *lu, vlog_node_t decl, + vcode_reg_t data) +{ + const int nranges = vlog_ranges(decl); + vcode_dim_t *dims LOCAL = xmalloc_array(nranges, sizeof(vcode_dim_t)); for (int i = 0; i < nranges; i++) { vlog_node_t r = vlog_range(decl, i); - vcode_reg_t left_reg = vlog_lower_rvalue(lu, vlog_left(r)); - vcode_reg_t right_reg = vlog_lower_rvalue(lu, vlog_right(r)); - - vcode_reg_t ileft_reg = vlog_lower_to_integer(lu, left_reg); - vcode_reg_t iright_reg = vlog_lower_to_integer(lu, right_reg); - vcode_reg_t dir_reg = emit_cmp(VCODE_CMP_GT, ileft_reg, iright_reg); - vcode_reg_t length_reg = - emit_range_length(ileft_reg, iright_reg, dir_reg); + vcode_reg_t left_reg = vlog_lower_integer(lu, vlog_left(r)); + vcode_reg_t right_reg = vlog_lower_integer(lu, vlog_right(r)); - count = emit_mul(count, length_reg); + vcode_reg_t dir_reg = emit_cmp(VCODE_CMP_GT, left_reg, right_reg); + dims[i].left = left_reg; + dims[i].right = right_reg; dims[i].dir = dir_reg; - dims[i].left = ileft_reg; - dims[i].right = iright_reg; - } - - vcode_reg_t nets_reg = emit_init_signal(vlogic, count, size, init, flags, - locus, VCODE_INVALID_REG); - - if (nranges > 0) { - vcode_reg_t wrap_reg = emit_wrap(nets_reg, dims, nranges); - emit_store(wrap_reg, var); - } - else - emit_store(nets_reg, var); -} - -static void vlog_lower_decls(lower_unit_t *lu, vlog_node_t scope) -{ - const int ndecls = vlog_decls(scope); - for (int i = 0; i < ndecls; i++) { - vlog_node_t d = vlog_decl(scope, i); - switch (vlog_kind(d)) { - case V_PORT_DECL: - case V_VAR_DECL: - case V_NET_DECL: - vlog_lower_signal_decl(lu, d); - break; - default: - CANNOT_HANDLE(d); - } - } -} - -static void vlog_lower_port_map(lower_unit_t *lu, vlog_node_t root, tree_t wrap) -{ - const int nparams = tree_params(wrap); - - ident_t to_vhdl_name = ident_new("NVC.VERILOG.TO_VHDL(" T_LOGIC ")U"); - ident_t to_verilog_name = ident_new("NVC.VERILOG.TO_VERILOG(U)" T_LOGIC); - - vcode_reg_t context_reg = vlog_helper_package(); - - vcode_type_t vt_verilog = vlog_logic_type(); - vcode_type_t vt_vhdl = vtype_int(0, 8); - - vcode_reg_t to_vhdl = - emit_closure(to_vhdl_name, context_reg, vt_verilog, vt_vhdl); - vcode_reg_t to_verilog = - emit_closure(to_verilog_name, context_reg, vt_vhdl, vt_verilog); - - for (int i = 0, pos = 0; i < nparams; i++) { - tree_t map = tree_param(wrap, i); - assert(tree_subkind(map) == P_POS); - - vlog_node_t port = NULL; - while (vlog_kind((port = vlog_decl(root, pos++))) != V_PORT_DECL) - ; - - int hops; - vcode_var_t var = lower_search_vcode_obj(port, lu, &hops); - assert(var != VCODE_INVALID_VAR); - assert(hops == 0); - - vcode_reg_t vhdl_reg = lower_lvalue(lu, tree_value(map)); - vcode_reg_t vlog_reg = emit_load(var); - - vcode_reg_t count_reg = emit_const(vtype_offset(), 1); + }; - if (vlog_subkind(port) == V_PORT_INPUT) { - vcode_reg_t conv_reg = emit_port_conversion(to_verilog); - emit_convert_out(conv_reg, vlog_reg, count_reg); - emit_convert_in(conv_reg, vhdl_reg, count_reg); - } - else { - vcode_reg_t conv_reg = emit_port_conversion(to_vhdl); - emit_convert_out(conv_reg, vhdl_reg, count_reg); - emit_convert_in(conv_reg, vlog_reg, count_reg); - } - } + return emit_wrap(data, dims, nranges); } static vcode_reg_t vlog_lower_lvalue(lower_unit_t *lu, vlog_node_t v) @@ -307,10 +226,17 @@ static vcode_reg_t vlog_lower_lvalue(lower_unit_t *lu, vlog_node_t v) vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops); assert(var != VCODE_INVALID_VAR); + vcode_reg_t nets_reg; if (hops == 0) - return emit_load(var); + nets_reg = emit_load(var); else - return emit_load_indirect(emit_var_upref(hops, var)); + nets_reg = emit_load_indirect(emit_var_upref(hops, var)); + + if (vcode_reg_kind(nets_reg) != VCODE_TYPE_UARRAY + && vlog_ranges(decl) > 0) + return vlog_lower_decl_bounds(lu, decl, nets_reg); + else + return nets_reg; } default: CANNOT_HANDLE(v); @@ -389,8 +315,13 @@ static vcode_reg_t vlog_lower_rvalue(lower_unit_t *lu, vlog_node_t v) }; return emit_wrap(data_reg, dims, 1); } - else - return emit_load_indirect(emit_resolved(nets_reg)); + else { + vcode_reg_t resolved_reg = emit_resolved(nets_reg); + if (vlog_ranges(decl) > 0) + return vlog_lower_decl_bounds(lu, decl, resolved_reg); + else + return emit_load_indirect(resolved_reg); + } } case V_EVENT: { @@ -406,7 +337,10 @@ static vcode_reg_t vlog_lower_rvalue(lower_unit_t *lu, vlog_node_t v) vcode_type_t vlogic = vlog_logic_type(); - vcode_reg_t const_reg = emit_const(vlogic, ekind == V_EVENT_POSEDGE); + const vlog_logic_t level = + ekind == V_EVENT_POSEDGE ? LOGIC_1 : LOGIC_0; + + vcode_reg_t const_reg = emit_const(vlogic, level); vcode_reg_t value_reg = vlog_lower_rvalue(lu, value); vcode_reg_t cmp_reg = emit_cmp(VCODE_CMP_EQ, value_reg, const_reg); @@ -835,32 +769,47 @@ static void vlog_lower_concurrent(unit_registry_t *ur, lower_unit_t *parent, } } -void vlog_lower(unit_registry_t *ur, tree_t wrap, lower_unit_t *parent) +vcode_unit_t vlog_lower(unit_registry_t *ur, tree_t wrap) { assert(tree_kind(wrap) == T_VERILOG); - vlog_node_t root = tree_vlog(wrap); - assert(vlog_kind(root) == V_ROOT); - - vcode_unit_t context = parent ? get_vcode(parent) : NULL; + vlog_node_t mod = tree_vlog(wrap); + assert(vlog_kind(mod) == V_MODULE); - ident_t prefix = parent ? vcode_unit_name(context) : lib_name(lib_work()); - ident_t label = tree_ident(wrap); - ident_t name = ident_prefix(prefix, label, '.'); + ident_t name = ident_prefix(vlog_ident(mod), well_known(W_SHAPE), '.'); - vcode_unit_t vu = emit_instance(name, tree_to_object(wrap), context); + vcode_unit_t vu = emit_shape(name, tree_to_object(wrap), NULL); - lower_unit_t *lu = lower_unit_new(ur, parent, vu, NULL, NULL); + lower_unit_t *lu = lower_unit_new(ur, NULL, vu, NULL, NULL); unit_registry_put(ur, lu); - vlog_lower_decls(lu, root); - vlog_lower_port_map(lu, root, wrap); + vcode_type_t vlogic = vlog_logic_type(); + vcode_type_t vsignal = vtype_signal(vlogic); + + const int ndecls = vlog_decls(mod); + for (int i = 0; i < ndecls; i++) { + vlog_node_t d = vlog_decl(mod, i); + switch (vlog_kind(d)) { + case V_PORT_DECL: + case V_VAR_DECL: + case V_NET_DECL: + { + vcode_var_t var = + emit_var(vsignal, vsignal, vlog_ident(d), VAR_SIGNAL); + lower_put_vcode_obj(d, var, lu); + } + break; + default: + CANNOT_HANDLE(d); + } + } emit_return(VCODE_INVALID_REG); - lower_finished(lu); + lower_finished(lu, NULL); - vlog_lower_concurrent(ur, lu, root); + vlog_lower_concurrent(ur, lu, mod); unit_registry_finalise(ur, lu); + return vu; } diff --git a/src/vlog/vlog-node.c b/src/vlog/vlog-node.c index 334443a9..e2ea6cf5 100644 --- a/src/vlog/vlog-node.c +++ b/src/vlog/vlog-node.c @@ -68,9 +68,6 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { // V_ASSIGN (I_TARGET | I_VALUE | I_IDENT), - // V_ROOT - (I_IDENT | I_STMTS | I_DECLS), - // V_DIMENSION (I_SUBKIND | I_LEFT | I_RIGHT), @@ -97,12 +94,12 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { }; static const char *kind_text_map[V_LAST_NODE_KIND] = { - "V_MODULE", "V_PORT_DECL", "V_REF", "V_ALWAYS", - "V_TIMING", "V_NBASSIGN", "V_EVENT", "V_INITIAL", - "V_SEQ_BLOCK", "V_SYSTASK", "V_STRING", "V_NUMBER", - "V_NET_DECL", "V_ASSIGN", "V_ROOT", "V_DIMENSION", - "V_IF", "V_COND", "V_VAR_DECL", "V_DELAY_CONTROL", - "V_BINARY", "V_BASSIGN", "V_UNARY", + "V_MODULE", "V_PORT_DECL", "V_REF", "V_ALWAYS", + "V_TIMING", "V_NBASSIGN", "V_EVENT", "V_INITIAL", + "V_SEQ_BLOCK", "V_SYSTASK", "V_STRING", "V_NUMBER", + "V_NET_DECL", "V_ASSIGN", "V_DIMENSION", "V_IF", + "V_COND", "V_VAR_DECL", "V_DELAY_CONTROL", "V_BINARY", + "V_BASSIGN", "V_UNARY", }; static const change_allowed_t change_allowed[] = { diff --git a/src/vlog/vlog-node.h b/src/vlog/vlog-node.h index 77bda27b..f1556c8f 100644 --- a/src/vlog/vlog-node.h +++ b/src/vlog/vlog-node.h @@ -58,7 +58,6 @@ typedef enum { V_NUMBER, V_NET_DECL, V_ASSIGN, - V_ROOT, V_DIMENSION, V_IF, V_COND, diff --git a/src/vlog/vlog-phase.h b/src/vlog/vlog-phase.h index 3dd75133..ce57567d 100644 --- a/src/vlog/vlog-phase.h +++ b/src/vlog/vlog-phase.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2022 Nick Gasson +// Copyright (C) 2022-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 @@ -24,6 +24,7 @@ void vlog_preprocess(text_buf_t *tb); vlog_node_t vlog_parse(void); void vlog_check(vlog_node_t v); void vlog_dump(vlog_node_t v, int indent); -void vlog_lower(unit_registry_t *ur, tree_t wrap, lower_unit_t *parent); +void vlog_trans(vlog_node_t mod, tree_t out); +vcode_unit_t vlog_lower(unit_registry_t *ur, tree_t wrap); #endif // _VLOG_PHASE_H diff --git a/src/vlog/vlog-trans.c b/src/vlog/vlog-trans.c new file mode 100644 index 00000000..d8a7728a --- /dev/null +++ b/src/vlog/vlog-trans.c @@ -0,0 +1,135 @@ +// +// 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 "common.h" +#include "tree.h" +#include "type.h" +#include "vlog/vlog-node.h" +#include "vlog/vlog-number.h" +#include "vlog/vlog-phase.h" + +#define CANNOT_HANDLE(v) do { \ + fatal_at(vlog_loc(v), "cannot handle %s in %s" , \ + vlog_kind_str(vlog_kind(v)), __FUNCTION__); \ + } while (0) + +static tree_t trans_expr(vlog_node_t expr) +{ + switch (vlog_kind(expr)) { + case V_NUMBER: + { + number_t n = vlog_number(expr); + type_t std_int = std_type(NULL, STD_INTEGER); + + tree_t lit = tree_new(T_LITERAL); + tree_set_subkind(lit, L_INT); + tree_set_ival(lit, number_integer(n)); + tree_set_type(lit, std_int); + + return lit; + } + default: + CANNOT_HANDLE(expr); + } +} + +static type_t trans_type(vlog_node_t decl) +{ + const int nranges = vlog_ranges(decl); + if (nranges > 0) { + type_t packed = verilog_type(VERILOG_PACKED_LOGIC); + + tree_t c = tree_new(T_CONSTRAINT); + tree_set_subkind(c, C_INDEX); + tree_set_loc(c, vlog_loc(decl)); + + for (int i = 0; i < nranges; i++) { + type_t index_type = index_type_of(packed, i); + vlog_node_t vr = vlog_range(decl, i); + + tree_t left = trans_expr(vlog_left(vr)); + tree_t right = trans_expr(vlog_right(vr)); + + const range_kind_t dir = + assume_int(left) < assume_int(right) ? RANGE_TO : RANGE_DOWNTO; + + tree_t r = tree_new(T_RANGE); + tree_set_subkind(r, dir); + tree_set_left(r, left); + tree_set_right(r, right); + tree_set_loc(r, vlog_loc(decl)); + tree_set_type(r, index_type); + + tree_add_range(c, r); + } + + type_t sub = type_new(T_SUBTYPE); + type_set_base(sub, packed); + type_add_constraint(sub, c); + + return sub; + } + else + return verilog_type(VERILOG_LOGIC); +} + +static void trans_port_decl(vlog_node_t decl, tree_t out) +{ + static const port_mode_t map[] = { + [V_PORT_INPUT] = PORT_IN, + [V_PORT_OUTPUT] = PORT_OUT, + [V_PORT_OUTPUT_REG] = PORT_OUT, + [V_PORT_INOUT] = PORT_INOUT, + }; + + tree_t t = tree_new(T_PORT_DECL); + tree_set_ident(t, vlog_ident(decl)); + tree_set_subkind(t, map[vlog_subkind(decl)]); + tree_set_class(t, C_SIGNAL); + tree_set_type(t, trans_type(decl)); + + tree_add_port(out, t); +} + +static void trans_var_decl(vlog_node_t decl, tree_t out) +{ + tree_t t = tree_new(T_SIGNAL_DECL); + tree_set_ident(t, vlog_ident(decl)); + tree_set_type(t, trans_type(decl)); + + tree_add_decl(out, t); +} + +void vlog_trans(vlog_node_t mod, tree_t out) +{ + const int ndecls = vlog_decls(mod); + for (int i = 0; i < ndecls; i++) { + vlog_node_t d = vlog_decl(mod, i); + switch (vlog_kind(d)) { + case V_PORT_DECL: + trans_port_decl(d, out); + break; + case V_VAR_DECL: + case V_NET_DECL: + trans_var_decl(d, out); + break; + default: + CANNOT_HANDLE(d); + } + } +} diff --git a/test/dump/vlog1.v b/test/dump/vlog1.v index 236758a4..ac15a0f8 100644 --- a/test/dump/vlog1.v +++ b/test/dump/vlog1.v @@ -13,6 +13,7 @@ module mod2; r <= 1 | r; $finish; r = 1; + #1 r <= 0; end assign bus = 3; endmodule // mod2 diff --git a/test/regress/vlog1.vhd b/test/regress/vlog1.vhd index 7d10b352..a37a11c3 100644 --- a/test/regress/vlog1.vhd +++ b/test/regress/vlog1.vhd @@ -33,7 +33,7 @@ begin clk <= '0'; d <= '0'; wait for 1 ns; - assert q = 'U'; -- XXX + assert q = '1'; wait; end process; diff --git a/test/test_dump.c b/test/test_dump.c index 327a0004..2b51e145 100644 --- a/test/test_dump.c +++ b/test/test_dump.c @@ -463,8 +463,7 @@ START_TEST(test_vlog1) " input clk;\n" " input rstb;\n" " output reg q;\n" - " always @(posedge clk)\n" - " q <= d;\n" + " always @(posedge clk) q <= d;\n" "endmodule // dff\n\n"); tb_rewind(tb); @@ -482,6 +481,7 @@ START_TEST(test_vlog1) " r <= 5'b1 | r;\n" " $finish;\n" " r = 5'b1;\n" + " #5'b1 r <= 5'b0;\n" " end\n" " assign bus = 5'b11;\n" "endmodule // mod2\n\n"); -- 2.39.2