From de215f1f8dc152e1a9ea7b66977b648a49905165 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 20 Nov 2010 15:09:32 -0800 Subject: [PATCH] Describe enum type to code generators This gets the enumeration type through to the ivl_target API so that code generators can do something with it. Generate stub output with tgt-stub, and generate the proper vvp run time to make simple enumerations work from end to end. --- compiler.h | 7 +++++- design_dump.cc | 5 ++++ dup_expr.cc | 6 +++++ elab_expr.cc | 10 ++++---- elab_scope.cc | 8 ++++--- emit.cc | 9 ++++++++ ivl_target.h | 20 ++++++++++++++++ main.cc | 3 +++ net_expr.cc | 15 ++++++++++++ net_nex_input.cc | 5 ++++ netenum.cc | 53 +++++++++++++++++++++++++++++++++++++++---- netenum.h | 17 ++++++++++---- netlist.h | 23 +++++++++++++++++++ t-dll-api.cc | 40 ++++++++++++++++++++++++++++++++ t-dll-expr.cc | 11 +++++++++ t-dll.cc | 12 ++++++++++ t-dll.h | 8 +++++++ target.cc | 13 +++++++++++ target.h | 4 ++++ tgt-stub/Makefile.in | 2 +- tgt-stub/enumerate.c | 42 ++++++++++++++++++++++++++++++++++ tgt-stub/expression.c | 9 ++++++++ tgt-stub/priv.h | 2 ++ tgt-stub/stub.c | 3 +++ tgt-vvp/Makefile.in | 2 +- tgt-vvp/draw_enum.c | 49 +++++++++++++++++++++++++++++++++++++++ tgt-vvp/draw_vpi.c | 6 ++++- tgt-vvp/vvp_priv.h | 5 ++++ tgt-vvp/vvp_scope.c | 13 +++++++---- 29 files changed, 377 insertions(+), 25 deletions(-) create mode 100644 tgt-stub/enumerate.c create mode 100644 tgt-vvp/draw_enum.c diff --git a/compiler.h b/compiler.h index 4a2b84bd5..3f3ced279 100644 --- a/compiler.h +++ b/compiler.h @@ -200,7 +200,12 @@ extern map library_file_map; * much sense to use a StringHeapLex to hold them. */ extern StringHeapLex lex_strings; -extern StringHeap misc_strings; + +/* + * The ivl_target.h API in a variety of places keeps strings of + * bits. Manage these as perm_string in a StringHeap. + */ +extern StringHeapLex bits_strings; /* * The filename_strings are perm_strings for file names. They are put diff --git a/design_dump.cc b/design_dump.cc index 4fa205ffe..c15428db4 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1452,6 +1452,11 @@ void NetEEvent::dump(ostream&o) const o << "name() << ">"; } +void NetENetenum::dump(ostream&o) const +{ + o << ""; +} + void NetEScope::dump(ostream&o) const { o << ""; diff --git a/dup_expr.cc b/dup_expr.cc index 3c3c2340c..ca65810e8 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -79,6 +79,12 @@ NetEEvent* NetEEvent::dup_expr() const return 0; } +NetENetenum* NetENetenum::dup_expr() const +{ + assert(0); + return 0; +} + NetEScope* NetEScope::dup_expr() const { assert(0); diff --git a/elab_expr.cc b/elab_expr.cc index b8020cab7..ff9055960 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2262,11 +2262,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, sys_expr = new NetESFunc("$ivl_method$name", IVL_VT_STRING,0, 1); sys_expr->parm(0, expr); } else if (method_name == "next") { - sys_expr = new NetESFunc("$ivl_method$next", netenum, 1); - sys_expr->parm(0, expr); + sys_expr = new NetESFunc("$ivl_method$next", netenum, 2); + sys_expr->parm(0, new NetENetenum(netenum)); + sys_expr->parm(1, expr); } else if (method_name == "prev") { - sys_expr = new NetESFunc("$ivl_method$prev", netenum, 1); - sys_expr->parm(0, expr); + sys_expr = new NetESFunc("$ivl_method$prev", netenum, 2); + sys_expr->parm(0, new NetENetenum(netenum)); + sys_expr->parm(1, expr); } else { cerr << get_fileline() << ": error: " << "Unknown method name `" << method_name << "'" diff --git a/elab_scope.cc b/elab_scope.cc index c7a47b844..7c5f93194 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -222,14 +222,16 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, rc_flag = eval_as_long(lsb, lsb_ex); assert(rc_flag); - netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag, msb, lsb); + netenum_t*use_enum = new netenum_t(enum_type->base_type, enum_type->signed_flag, + msb, lsb, enum_type->names->size()); scope->add_enumeration_set(use_enum); verinum cur_value (0); verinum one_value (1); + size_t name_idx = 0; for (list::const_iterator cur = enum_type->names->begin() - ; cur != enum_type->names->end() ; ++ cur) { + ; cur != enum_type->names->end() ; ++ cur, name_idx += 1) { if (cur->parm) { @@ -262,7 +264,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, verinum tmp_val (cur_value, use_enum->base_width()); tmp_val.has_sign(enum_type->signed_flag); - rc_flag = use_enum->insert_name(cur->name, tmp_val); + rc_flag = use_enum->insert_name(name_idx, cur->name, tmp_val); rc_flag &= scope->add_enumeration_name(use_enum, cur->name); if (! rc_flag) { cerr << "<>:0: error: Duplicate enumeration name " << cur->name << endl; diff --git a/emit.cc b/emit.cc index e78c6daf0..1f0ea7f23 100644 --- a/emit.cc +++ b/emit.cc @@ -385,6 +385,10 @@ void NetScope::emit_scope(struct target_t*tgt) const for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) tgt->event(cur); + for (list::const_iterator cur = enum_sets_.begin() + ; cur != enum_sets_.end() ; ++cur) + tgt->enumeration(this, *cur); + for (map::const_iterator cur = children_.begin() ; cur != children_.end() ; cur ++) cur->second->emit_scope(tgt); @@ -547,6 +551,11 @@ void NetEEvent::expr_scan(struct expr_scan_t*tgt) const tgt->expr_event(this); } +void NetENetenum::expr_scan(struct expr_scan_t*tgt) const +{ + tgt->expr_netenum(this); +} + void NetEScope::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_scope(this); diff --git a/ivl_target.h b/ivl_target.h index e4b002883..c19a5339f 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -159,6 +159,7 @@ typedef struct ivl_branch_s *ivl_branch_t; typedef struct ivl_delaypath_s*ivl_delaypath_t; typedef struct ivl_design_s *ivl_design_t; typedef struct ivl_discipline_s*ivl_discipline_t; +typedef struct netenum_t *ivl_enumtype_t; typedef struct ivl_event_s *ivl_event_t; typedef struct ivl_expr_s *ivl_expr_t; typedef struct ivl_island_s *ivl_island_t; @@ -212,6 +213,7 @@ typedef enum ivl_expr_type_e { IVL_EX_BINARY = 2, IVL_EX_CONCAT = 3, IVL_EX_DELAY = 20, + IVL_EX_ENUMTYPE = 21, IVL_EX_EVENT = 17, IVL_EX_MEMORY = 4, IVL_EX_NUMBER = 5, @@ -618,6 +620,16 @@ extern ivl_nature_t ivl_discipline_flow(ivl_discipline_t net); extern const char* ivl_nature_name(ivl_nature_t net); +/* ENUMERATIONS + * + * Enumerations are a collections of symbolic names and vector + * values. The enumeration has a base type, and a list of names and + * values. + */ +extern unsigned ivl_enum_names(ivl_enumtype_t net); +extern const char*ivl_enum_name(ivl_enumtype_t net, unsigned idx); +extern const char*ivl_enum_bits(ivl_enumtype_t net, unsigned idx); + /* EVENTS * * Events are a unification of named events and implicit events @@ -774,6 +786,8 @@ extern ivl_scope_t ivl_expr_def(ivl_expr_t net); extern uint64_t ivl_expr_delay_val(ivl_expr_t net); /* IVL_EX_REALNUM */ extern double ivl_expr_dvalue(ivl_expr_t net); + /* IVL_EX_ENUMTYPE */ +extern ivl_enumtype_t ivl_expr_enumtype(ivl_expr_t net); /* IVL_EX_SIGNAL, IVL_EX_SFUNC, IVL_EX_VARIABLE */ extern const char* ivl_expr_name(ivl_expr_t net); /* IVL_EX_BACCESS */ @@ -1550,6 +1564,10 @@ extern unsigned ivl_parameter_lineno(ivl_parameter_t net); * ivl_scope_def_lineno * Returns the file and line where this scope is defined. * + * ivl_scope_enumerate + * ivl_scope_enumerates + * Scopes have 0 or more enumeration types in them. + * * ivl_scope_event * ivl_scope_events * Scopes have 0 or more event objects in them. @@ -1637,6 +1655,8 @@ extern ivl_statement_t ivl_scope_def(ivl_scope_t net); extern const char* ivl_scope_def_file(ivl_scope_t net); extern unsigned ivl_scope_def_lineno(ivl_scope_t net); +extern unsigned ivl_scope_enumerates(ivl_scope_t net); +extern ivl_enumtype_t ivl_scope_enumerate(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_events(ivl_scope_t net); extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx); extern const char* ivl_scope_file(ivl_scope_t net); diff --git a/main.cc b/main.cc index dc69e57e7..08ea09651 100644 --- a/main.cc +++ b/main.cc @@ -176,6 +176,8 @@ StringHeapLex lex_strings; StringHeapLex filename_strings; +StringHeapLex bits_strings; + /* * In library searches, Windows file names are never case sensitive. */ @@ -748,6 +750,7 @@ static void EOC_cleanup(void) flags.clear(); lex_strings.cleanup(); + bits_strings.cleanup(); filename_strings.cleanup(); } diff --git a/net_expr.cc b/net_expr.cc index e27e23ab5..ddeedb82a 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -506,6 +506,21 @@ const NetScope* NetECRealParam::scope() const } +NetENetenum::NetENetenum(netenum_t*s) +: netenum_(s) +{ +} + +NetENetenum::~NetENetenum() +{ +} + +netenum_t* NetENetenum::netenum() const +{ + return netenum_; +} + + NetEParam::NetEParam() : des_(0), scope_(0) { diff --git a/net_nex_input.cc b/net_nex_input.cc index 5c7d7a27a..0ca9edc4d 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -100,6 +100,11 @@ NexusSet* NetEEvent::nex_input(bool rem_out) return new NexusSet; } +NexusSet* NetENetenum::nex_input(bool rem_out) +{ + return new NexusSet; +} + NexusSet* NetEScope::nex_input(bool rem_out) { return new NexusSet; diff --git a/netenum.cc b/netenum.cc index 3ea9458f1..873c2b22c 100644 --- a/netenum.cc +++ b/netenum.cc @@ -18,10 +18,13 @@ */ # include "netenum.h" +# include "compiler.h" # include -netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, long msb, long lsb) -: base_type_(btype), signed_flag_(signed_flag), msb_(msb), lsb_(lsb) +netenum_t::netenum_t(ivl_variable_type_t btype, bool signed_flag, + long msb, long lsb, size_t name_count) +: base_type_(btype), signed_flag_(signed_flag), msb_(msb), lsb_(lsb), + names_(name_count), bits_(name_count) { } @@ -29,15 +32,19 @@ netenum_t::~netenum_t() { } -bool netenum_t::insert_name(perm_string name, const verinum&val) +bool netenum_t::insert_name(size_t name_idx, perm_string name, const verinum&val) { std::pair::iterator, bool> res; assert(val.has_len() && val.len() == (msb_-lsb_+1)); + // Insert a map of the name to the value. This also gets a + // flag that returns true if the name is unique, or false + // otherwise. res = names_map_.insert( make_pair(name,val) ); - // Only add the name to the list if it is not there already. - if (res.second) names_.push_back(name); + + assert(name_idx < names_.size() && names_[name_idx] == 0); + names_[name_idx] = name; return res.second; } @@ -61,3 +68,39 @@ netenum_t::iterator netenum_t::last_name() const { return names_map_.find(names_.back()); } + +perm_string netenum_t::name_at(size_t idx) const +{ + assert(idx < names_.size()); + return names_[idx]; +} + +perm_string netenum_t::bits_at(size_t idx) +{ + assert(idx < names_.size()); + + if (bits_[idx] == 0) { + netenum_t::iterator cur = names_map_.find(names_[idx]); + + vectorstr (cur->second.len() + 1); + for (unsigned bit = 0 ; bit < cur->second.len() ; bit += 1) { + switch (cur->second.get(bit)) { + case verinum::V0: + str[bit] = '0'; + break; + case verinum::V1: + str[bit] = '1'; + break; + case verinum::Vx: + str[bit] = 'x'; + break; + case verinum::Vz: + str[bit] = 'z'; + break; + } + } + bits_[idx] = bits_strings.make(&str[0]); + } + + return bits_[idx]; +} diff --git a/netenum.h b/netenum.h index ffc190d10..d89a45595 100644 --- a/netenum.h +++ b/netenum.h @@ -22,14 +22,16 @@ # include "ivl_target.h" # include "verinum.h" # include "StringHeap.h" -# include +# include # include +class NetScope; + class netenum_t { public: explicit netenum_t(ivl_variable_type_t base_type, bool signed_flag, - long msb, long lsb); + long msb, long lsb, size_t name_count); ~netenum_t(); ivl_variable_type_t base_type() const; @@ -38,7 +40,10 @@ class netenum_t { // The size() is the number of enumeration literals. size_t size() const; - bool insert_name(perm_string name, const verinum&val); + // Insert the name (and value) at the specific place in the + // enumeration. This must be done exactly once for each + // enumeration value. + bool insert_name(size_t idx, perm_string name, const verinum&val); typedef std::map::const_iterator iterator; iterator find_name(perm_string name) const; @@ -48,13 +53,17 @@ class netenum_t { iterator first_name() const; iterator last_name() const; + perm_string name_at(size_t idx) const; + perm_string bits_at(size_t idx); + private: ivl_variable_type_t base_type_; bool signed_flag_; long msb_, lsb_; std::map names_map_; - std::list names_; + std::vector names_; + std::vector bits_; }; inline ivl_variable_type_t netenum_t::base_type() const diff --git a/netlist.h b/netlist.h index 6304b75fa..039697c9b 100644 --- a/netlist.h +++ b/netlist.h @@ -3715,6 +3715,29 @@ class NetEEvent : public NetExpr { NetEvent*event_; }; +/* + * This class is a special (and magical) expression node type that + * represents enumeration types. These can only be found as parameters + * to NetSTask objects. + */ +class NetENetenum : public NetExpr { + + public: + NetENetenum(netenum_t*); + ~NetENetenum(); + + netenum_t* netenum() const; + + virtual void expr_scan(struct expr_scan_t*) const; + virtual NetENetenum* dup_expr() const; + virtual NexusSet* nex_input(bool rem_out = true); + + virtual void dump(ostream&os) const; + + private: + netenum_t*netenum_; +}; + /* * This class is a special (and magical) expression node type that * represents scope names. These can only be found as parameters to diff --git a/t-dll-api.cc b/t-dll-api.cc index 81d5bf669..4e35ed9a3 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -21,6 +21,7 @@ # include "StringHeap.h" # include "t-dll.h" # include "discipline.h" +# include "netenum.h" # include "ivl_alloc.h" # include # include @@ -210,6 +211,26 @@ extern "C" unsigned ivl_const_width(ivl_net_const_t net) return net->width_; } +extern "C" unsigned ivl_enum_names(ivl_enumtype_t net) +{ + assert(net); + return net->size(); +} + +extern "C" const char* ivl_enum_name(ivl_enumtype_t net, unsigned idx) +{ + assert(net); + assert(idx < net->size()); + return net->name_at(idx); +} + +extern "C" const char* ivl_enum_bits(ivl_enumtype_t net, unsigned idx) +{ + assert(net); + assert(idx < net->size()); + return net->bits_at(idx); +} + extern "C" const char* ivl_event_name(ivl_event_t net) { static char*name_buffer = 0; @@ -323,6 +344,12 @@ extern "C" double ivl_expr_dvalue(ivl_expr_t net) return net->u_.real_.value; } +extern "C" ivl_enumtype_t ivl_expr_enumtype(ivl_expr_t net) +{ + assert(net->type_ == IVL_EX_ENUMTYPE); + return net->u_.enumtype_.type; +} + extern "C" const char* ivl_expr_name(ivl_expr_t net) { switch (net->type_) { @@ -1671,6 +1698,19 @@ extern "C" unsigned ivl_scope_def_lineno(ivl_scope_t net) return net->def_lineno; } +extern "C" unsigned ivl_scope_enumerates(ivl_scope_t net) +{ + assert(net); + return net->enumerations_.size(); +} + +extern "C" ivl_enumtype_t ivl_scope_enumerate(ivl_scope_t net, unsigned idx) +{ + assert(net); + assert(idx < net->enumerations_.size()); + return net->enumerations_[idx]; +} + extern "C" unsigned ivl_scope_events(ivl_scope_t net) { assert(net); diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 542738022..f53aa4c95 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -340,6 +340,17 @@ void dll_target::expr_scope(const NetEScope*net) expr_->u_.scope_.scope = lookup_scope_(net->scope()); } +void dll_target::expr_netenum(const NetENetenum*net) +{ + assert(expr_ == 0); + + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + + expr_->type_ = IVL_EX_ENUMTYPE; + expr_->value_= IVL_VT_VOID; + expr_->u_.enumtype_.type = net->netenum(); +} + void dll_target::expr_select(const NetESelect*net) { assert(expr_ == 0); diff --git a/t-dll.cc b/t-dll.cc index 2eff9604e..033b7a846 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -396,6 +396,11 @@ void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net) } +static void scope_add_enumeration(ivl_scope_t scope, ivl_enumtype_t net) +{ + scope->enumerations_.push_back(net); +} + void scope_add_event(ivl_scope_t scope, ivl_event_t net) { if (scope->nevent_ == 0) { @@ -786,6 +791,13 @@ bool dll_target::bufz(const NetBUFZ*net) return true; } +bool dll_target::enumeration(const NetScope*in_scope, netenum_t*net) +{ + ivl_scope_t scop = find_scope(des_, in_scope); + scope_add_enumeration(scop, net); + return true; +} + void dll_target::event(const NetEvent*net) { struct ivl_event_s *obj = new struct ivl_event_s; diff --git a/t-dll.h b/t-dll.h index 53bc7ec89..de0995c16 100644 --- a/t-dll.h +++ b/t-dll.h @@ -58,6 +58,7 @@ struct dll_target : public target_t, public expr_scan_t { bool bufz(const NetBUFZ*); bool branch(const NetBranch*); + bool enumeration(const NetScope*, netenum_t*); void event(const NetEvent*); void logic(const NetLogic*); bool tran(const NetTran*); @@ -139,6 +140,7 @@ struct dll_target : public target_t, public expr_scan_t { void expr_rparam(const NetECRealParam*); void expr_event(const NetEEvent*); void expr_scope(const NetEScope*); + void expr_netenum(const NetENetenum*); void expr_select(const NetESelect*); void expr_sfunc(const NetESFunc*); void expr_ternary(const NetETernary*); @@ -251,6 +253,10 @@ struct ivl_expr_s { ivl_scope_t scope; } scope_; + struct { + ivl_enumtype_t type; + } enumtype_; + struct { ivl_signal_t sig; ivl_expr_t word; @@ -599,6 +605,8 @@ struct ivl_scope_s { unsigned def_lineno; ivl_scope_type_t type_; + std::vector enumerations_; + unsigned nsigs_; ivl_signal_t*sigs_; diff --git a/target.cc b/target.cc index a3581c878..26469dfbb 100644 --- a/target.cc +++ b/target.cc @@ -45,6 +45,13 @@ void target_t::event(const NetEvent*ev) << "): Unhandled event <" << ev->name() << ">." << endl; } +bool target_t::enumeration(const NetScope*, netenum_t*obj) +{ + cerr << "<>:0" << ": error: target (" << typeid(*this).name() + << "): Unhandled enumeration <" << obj << ">." << endl; + return false; +} + bool target_t::signal_paths(const NetNet*) { return true; @@ -460,6 +467,12 @@ void expr_scan_t::expr_event(const NetEEvent*) "unhandled expr_event." << endl; } +void expr_scan_t::expr_netenum(const NetENetenum*) +{ + cerr << "expr_scan_t (" << typeid(*this).name() << "): " + "unhandled expr_netenum." << endl; +} + void expr_scan_t::expr_scope(const NetEScope*) { cerr << "expr_scan_t (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index 1f97f3dd4..87d338c24 100644 --- a/target.h +++ b/target.h @@ -59,6 +59,9 @@ struct target_t { /* Output an event object. Called for each named event in the scope. */ virtual void event(const NetEvent*); + /* Output an enumeration typespec. */ + virtual bool enumeration(const NetScope*, netenum_t*); + /* Output a signal (called for each signal) */ virtual void signal(const NetNet*) =0; virtual bool signal_paths(const NetNet*); @@ -156,6 +159,7 @@ struct expr_scan_t { virtual void expr_ufunc(const NetEUFunc*); virtual void expr_unary(const NetEUnary*); virtual void expr_binary(const NetEBinary*); + virtual void expr_netenum(const NetENetenum*); }; diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index 6b4a03fcd..a1fa69549 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -45,7 +45,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = stub.o expression.o statement.o switches.o +O = stub.o enumerate.o expression.o statement.o switches.o all: dep stub.tgt diff --git a/tgt-stub/enumerate.c b/tgt-stub/enumerate.c new file mode 100644 index 000000000..1c18229a7 --- /dev/null +++ b/tgt-stub/enumerate.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "config.h" +# include "priv.h" +# include + +void show_enumerate(ivl_enumtype_t net) +{ + unsigned idx; + fprintf(out, " enumeration %p {\n", net); + + for (idx = 0 ; idx < ivl_enum_names(net) ; idx += 1) { + fprintf(out, " %s = <", ivl_enum_name(net, idx)); + + const char*bits = ivl_enum_bits(net, idx); + size_t bits_len = strlen(bits); + size_t bit; + for (bit = bits_len ; bit > 0 ; bit -= 1) + fputc(bits[bit-1], out); + + fprintf(out, ">\n"); + } + + fprintf(out, " }\n"); +} diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 018f5035a..9b33cdc1e 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -137,6 +137,11 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind) } } +static void show_enumtype_expression(ivl_expr_t net, unsigned ind) +{ + fprintf(out, "%*s\n", ind, "", ivl_expr_enumtype(net)); +} + static void show_function_call(ivl_expr_t net, unsigned ind) { ivl_scope_t def = ivl_expr_def(net); @@ -282,6 +287,10 @@ void show_expression(ivl_expr_t net, unsigned ind) break; + case IVL_EX_ENUMTYPE: + show_enumtype_expression(net, ind); + break; + case IVL_EX_MEMORY: show_memory_expression(net, ind); break; diff --git a/tgt-stub/priv.h b/tgt-stub/priv.h index 1a5ca6298..7ebaed030 100644 --- a/tgt-stub/priv.h +++ b/tgt-stub/priv.h @@ -49,6 +49,8 @@ extern ivl_discipline_t discipline_of_nexus(ivl_nexus_t nex); */ extern void test_expr_is_delay(ivl_expr_t expr); +extern void show_enumerate(ivl_enumtype_t net); + /* * Show the details of the expression. */ diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 5de27490d..a940e97db 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1590,6 +1590,9 @@ static int show_scope(ivl_scope_t net, void*x) for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) show_parameter(ivl_scope_param(net, idx)); + for (idx = 0 ; idx < ivl_scope_enumerates(net) ; idx += 1) + show_enumerate(ivl_scope_enumerate(net, idx)); + for (idx = 0 ; idx < ivl_scope_sigs(net) ; idx += 1) show_signal(ivl_scope_sig(net, idx)); diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index e8fed19a3..69697d32f 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -48,7 +48,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -O = vvp.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \ +O = vvp.o draw_enum.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \ eval_bool.o eval_expr.o eval_real.o modpath.o vector.o vvp_process.o \ vvp_scope.o diff --git a/tgt-vvp/draw_enum.c b/tgt-vvp/draw_enum.c new file mode 100644 index 000000000..9703ed616 --- /dev/null +++ b/tgt-vvp/draw_enum.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vvp_priv.h" +# include "ivl_alloc.h" +# include +# include + +void draw_enumeration_in_scope(ivl_enumtype_t enumtype) +{ + unsigned idx; + + fprintf(vvp_out, "enum%p .enum\n", enumtype); + + for (idx = 0 ; idx < ivl_enum_names(enumtype) ; idx += 1) { + const char*comma = idx+1 < ivl_enum_names(enumtype)? "," : ""; + + fprintf(vvp_out, " \"%s\"", ivl_enum_name(enumtype, idx)); + + long val = 0; + long mask = 1; + const char*bits = ivl_enum_bits(enumtype, idx); + const char*bit; + for (bit = bits, mask = 1 ; bit[0] != 0 ; bit += 1, mask <<= 1) { + if (*bit == '1') + val |= mask; + } + + fprintf(vvp_out, " %ld%s\n", val, comma); + } + + fprintf(vvp_out, " ;\n"); +} diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 7351e9779..af6932f9d 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -287,7 +287,7 @@ static void draw_vpi_taskfunc_args(const char*call_string, assert((unsigned)(dp - buffer) <= sizeof buffer); } args[idx].text = strdup(buffer); - continue; + continue; } case IVL_EX_STRING: @@ -308,6 +308,10 @@ static void draw_vpi_taskfunc_args(const char*call_string, } break; + case IVL_EX_ENUMTYPE: + snprintf(buffer, sizeof buffer, "enum%p", ivl_expr_enumtype(expr)); + args[idx].text = strdup(buffer); + continue; case IVL_EX_EVENT: snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr)); args[idx].text = strdup(buffer); diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 99ae9f79a..72e9fbabb 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -23,6 +23,11 @@ # include "ivl_target.h" # include +#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */ +#define snprintf _snprintf +#endif + + /* * The target_design entry opens the output file that receives the * compiled design, and sets the vvp_out to the descriptor. diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 106d42d4f..cb5ad12c5 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -25,11 +25,6 @@ # include # include -#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */ -#define snprintf _snprintf -#endif - - /* * Escape non-symbol characters in ids, and quotes in strings. */ @@ -2026,6 +2021,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) } } + /* Scan the scope for enumeration types, and write out + enumeration typespecs. */ + + for (idx = 0 ; idx < ivl_scope_enumerates(net) ; idx += 1) { + ivl_enumtype_t enumtype = ivl_scope_enumerate(net, idx); + draw_enumeration_in_scope(enumtype); + } + /* Scan the scope for logic devices. For each device, draw out a functor that connects pin 0 to the output, and the remaining pins to inputs. */