From d14f60f28a8db08f98b03fd7350dac0399787423 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 22 Jun 2011 18:13:40 -0700 Subject: [PATCH 1/2] Elaborate and emit vhdl elsif sections. The IfStatement contains a list of elsif sections that need to be elaborated/emitted in the middle of the true and false clauses. --- vhdlpp/expression.h | 1 + vhdlpp/expression_elaborate.cc | 13 +++++++++++++ vhdlpp/sequential.h | 4 ++++ vhdlpp/sequential_elaborate.cc | 19 +++++++++++++++++++ vhdlpp/sequential_emit.cc | 31 ++++++++++++++++++++++++++++--- 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 40d352507..cd60165e8 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -279,6 +279,7 @@ class ExpInteger : public Expression { ExpInteger(int64_t val); ~ExpInteger(); + int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int emit(ostream&out, Entity*ent, Architecture*arc); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 654702934..279fd5264 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -175,6 +175,19 @@ int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*lty return errors; } +int ExpInteger::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +{ + int errors = 0; + + if (ltype == 0) { + ltype = probe_type(ent, arc); + } + + assert(ltype != 0); + + return errors; +} + int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) { int errors = 0; diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 45c9b1ab6..5799a5ea4 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -46,6 +46,10 @@ class IfSequential : public SequentialStmt { Elsif(Expression*cond, std::list*tr); ~Elsif(); + int elaborate(Entity*entity, Architecture*arc); + int condition_emit(ostream&out, Entity*entity, Architecture*arc); + int statement_emit(ostream&out, Entity*entity, Architecture*arc); + void dump(ostream&out, int indent) const; private: diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 4229bc91d..e6f72180c 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -36,6 +36,11 @@ int IfSequential::elaborate(Entity*ent, Architecture*arc) errors += (*cur)->elaborate(ent, arc); } + for (list::iterator cur = elsif_.begin() + ; cur != elsif_.end() ; ++cur) { + errors += (*cur)->elaborate(ent, arc); + } + for (list::iterator cur = else_.begin() ; cur != else_.end() ; ++cur) { errors += (*cur)->elaborate(ent, arc); @@ -44,6 +49,20 @@ int IfSequential::elaborate(Entity*ent, Architecture*arc) return errors; } +int IfSequential::Elsif::elaborate(Entity*ent, Architecture*arc) +{ + int errors = 0; + + errors += cond_->elaborate_expr(ent, arc, 0); + + for (list::iterator cur = if_.begin() + ; cur != if_.end() ; ++cur) { + errors += (*cur)->elaborate(ent, arc); + } + + return errors; +} + int SignalSeqAssignment::elaborate(Entity*ent, Architecture*arc) { int errors = 0; diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index e2f792124..ede823246 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -22,7 +22,7 @@ # include # include -int SequentialStmt::emit(ostream&out, Entity*ent, Architecture*arc) +int SequentialStmt::emit(ostream&out, Entity*, Architecture*) { out << " // " << get_fileline() << ": internal error: " << "I don't know how to emit this sequential statement! " @@ -39,14 +39,22 @@ int IfSequential::emit(ostream&out, Entity*ent, Architecture*arc) for (list::iterator cur = if_.begin() ; cur != if_.end() ; ++cur) - (*cur)->emit(out, ent, arc); + errors += (*cur)->emit(out, ent, arc); + + for (list::iterator cur = elsif_.begin() + ; cur != elsif_.end() ; ++cur) { + out << "end else if ("; + errors += (*cur)->condition_emit(out, ent, arc); + out << ") begin" << endl; + errors += (*cur)->statement_emit(out, ent, arc); + } if (else_.size() > 0) { out << "end else begin" << endl; for (list::iterator cur = else_.begin() ; cur != else_.end() ; ++cur) - (*cur)->emit(out, ent, arc); + errors += (*cur)->emit(out, ent, arc); } @@ -54,6 +62,23 @@ int IfSequential::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } +int IfSequential::Elsif::condition_emit(ostream&out, Entity*ent, Architecture*arc) +{ + return cond_->emit(out, ent, arc); +} + +int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + + for (list::iterator cur = if_.begin() + ; cur != if_.end() ; ++cur) + errors += (*cur)->emit(out, ent, arc); + + return errors; +} + + int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; From 91ffc68e9558795317f076dc1cba0302a75147a6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 24 Jun 2011 18:42:43 -0700 Subject: [PATCH 2/2] Add $ivlh_attribute_event for VHDL support The $ivlh_attribute_event system function helps the Verilog runtime support 'event expressions in VHDL. The vhdlpp generates a call to $ivlh_attribute_event, which in turn uses callbacks to handle the support. This is also the start of the vhdl_sys vpi module. This module should by included whenever VHDL code is parsed. --- vhdlpp/expression_emit.cc | 9 +++ vpi/Makefile.in | 16 ++++- vpi/vhdl_sys.sft | 1 + vpi/vhdl_table.cc | 133 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 vpi/vhdl_sys.sft create mode 100644 vpi/vhdl_table.cc diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 0712af26d..148c26e54 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -68,6 +68,14 @@ int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc) int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; + + if (name_ == "event") { + out << "$ivlh_attribute_event("; + errors += base_->emit(out, ent, arc); + out << ")"; + return errors; + } + out << "$ivl_attribute("; errors += base_->emit(out, ent, arc); out << ", \"" << name_ << "\")"; @@ -166,6 +174,7 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*ent, Architecture*arc, default: return 1; } + return 1; } int ExpCharacter::emit(ostream&out, Entity*ent, Architecture*arc) diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 717aeeebf..ce094e30e 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -76,7 +76,9 @@ V = va_math.o V2009 = v2009_table.o v2009_enum.o -all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi $(ALL32) +VHDL_SYS = vhdl_table.o + +all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi $(ALL32) check: all @@ -148,6 +150,9 @@ v2009.vpi: $(V2009) ../vvp/libvpi.a va_math.vpi: $V ../vvp/libvpi.a $(CC) @shared@ -o $@ $V -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) +vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a + $(CXX) @shared@ -o $@ $(VHDL_SYS) -L ../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_FLAGS) + stamp-vpi_config-h: $(srcdir)/vpi_config.h.in ../config.status @rm -f $@ cd ..; ./config.status --header=vpi/vpi_config.h @@ -158,6 +163,7 @@ install: all installdirs \ $(vpidir)/va_math.vpi $(vpidir)/va_math.sft \ $(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \ $(vpidir)/v2009.vpi $(vpidir)/v2009.sft \ + $(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft $(vpidir)/system.vpi: ./system.vpi $(INSTALL_PROGRAM) ./system.vpi "$(DESTDIR)$(vpidir)/system.vpi" @@ -183,6 +189,12 @@ $(vpidir)/v2009.vpi: ./v2009.vpi $(vpidir)/v2009.sft: v2009.sft $(INSTALL_DATA) $< "$(DESTDIR)$@" +$(vpidir)/vhdl_sys.vpi: ./vhdl_sys.vpi + $(INSTALL_PROGRAM) ./vhdl_sys.vpi "$(DESTDIR)$(vpidir)/vhdl_sys.vpi" + +$(vpidir)/vhdl_sys.sft: vhdl_sys.sft + $(INSTALL_DATA) $< "$(DESTDIR)$@" + installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)" "$(DESTDIR)$(vpidir)" @@ -195,6 +207,8 @@ uninstall: rm -f "$(DESTDIR)$(vpidir)/v2005_math.sft" rm -f "$(DESTDIR)$(vpidir)/v2009.vpi" rm -f "$(DESTDIR)$(vpidir)/v2009.sft" + rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi" + rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.sft" -include $(patsubst %.o, dep/%.d, $O) -include $(patsubst %.o, dep/%.d, $(OPP)) diff --git a/vpi/vhdl_sys.sft b/vpi/vhdl_sys.sft new file mode 100644 index 000000000..7e9c7aaac --- /dev/null +++ b/vpi/vhdl_sys.sft @@ -0,0 +1 @@ +$ivlh_attribute_event vpiSysFuncSized 1 unsigned diff --git a/vpi/vhdl_table.cc b/vpi/vhdl_table.cc new file mode 100644 index 000000000..75d48df35 --- /dev/null +++ b/vpi/vhdl_table.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 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 "vpi_config.h" +# include "vpi_user.h" +# include + +/* + * The $ivlh_attribute_event implements the VHDL 'event + * attribute. It does this by monitoring value-change events on the + * operand, and noting the time. If the $ivlh_attribute_event is + * called at the same simulation time as a value-change, then the + * function returns logic true. Otherwise it returns false. + */ +struct monitor_data { + struct t_vpi_time last_event; +}; + +static PLI_INT32 monitor_events(struct t_cb_data*cb) +{ + struct monitor_data*mon = reinterpret_cast (cb->user_data); + + assert(cb->time); + assert(cb->time->type == vpiSimTime); + mon->last_event = *(cb->time); + + return 0; +} + +static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle arg; + + // Check that there is at least 1 argument... + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo, sys)); + vpi_printf("Call to %s missing its argument\n", vpi_get_str(vpiName,sys)); + vpi_control(vpiFinish, 1); + return 0; + } + + arg = vpi_scan(argv); + assert(arg); + + struct monitor_data*monitor_handle = new struct monitor_data; + + struct t_cb_data cb; + struct t_vpi_time tb; + tb.type = vpiSimTime; + cb.reason = cbValueChange; + cb.cb_rtn = monitor_events; + cb.obj = arg; + cb.time = &tb; + cb.value = 0; + cb.user_data = reinterpret_cast(monitor_handle); + vpi_register_cb(&cb); + vpi_put_userdata(sys, monitor_handle); + + // check that there is no more then 1 argument + arg = vpi_scan(argv); + if (arg != 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), vpi_get(vpiLineNo, sys)); + vpi_printf("Too many arguments for call to %s.\n", vpi_get_str(vpiName,sys)); + vpi_control(vpiFinish, 1); + } + + return 0; +} + +static PLI_INT32 ivlh_attribute_event_calltf(ICARUS_VPI_CONST PLI_BYTE8*) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + + struct t_vpi_value rval; + rval.format = vpiScalarVal; + + struct monitor_data*mon = reinterpret_cast(vpi_get_userdata(sys)); + + if (mon->last_event.type == 0) { + rval.value.scalar = vpi0; + + } else { + struct t_vpi_time tnow; + tnow.type = vpiSimTime; + vpi_get_time(0,&tnow); + + rval.value.scalar = vpi1; + if (mon->last_event.high != tnow.high) + rval.value.scalar = vpi0; + if (mon->last_event.low != tnow.low) + rval.value.scalar = vpi0; + } + + vpi_put_value(sys, &rval, 0, vpiNoDelay); + + return 0; +} + +static void vhdl_register(void) +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysFunc; + tf_data.tfname = "$ivlh_attribute_event"; + tf_data.calltf = ivlh_attribute_event_calltf; + tf_data.compiletf = ivlh_attribute_event_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$ivlh_attribute_event"; + vpi_register_systf(&tf_data); +} + +void (*vlog_startup_routines[])() = { + vhdl_register, + 0 +};