[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Simulavr-devel] [PATCH 12/13] Major update of Verilog interface for Sim
From: |
Onno Kortmann |
Subject: |
[Simulavr-devel] [PATCH 12/13] Major update of Verilog interface for SimulAVR |
Date: |
Tue, 3 Mar 2009 23:46:34 +0100 |
- Some parts of the interface are functions, some are tasks now (whatever fits
better).
- New methods to read/write the memory and read the program counter
as well as to start the simulavrxx tracing functionality.
- Fixed a lot of memory leaks.
Signed-off-by: Onno Kortmann <address@hidden>
---
configure.ac | 6 +
src/Makefile.am | 21 +++-
src/avrdevice.h | 2 +-
src/verilog/avr.v | 114 +++++++++++++++
src/vpi.cpp | 393 +++++++++++++++++++++++++++++------------------------
5 files changed, 358 insertions(+), 178 deletions(-)
create mode 100644 src/verilog/avr.v
diff --git a/configure.ac b/configure.ac
index 9b628f8..f48fdfc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,6 +10,12 @@ SWIG_PYTHON
AM_CONDITIONAL([USE_SWIG],[test "x$SWIG" != 'x'])
AM_CONDITIONAL([USE_PYTHON],[test "x$PYTHON" != 'x'])
+AC_CHECK_HEADER([vpi_user.h],
+ [AC_DEFINE(HAVE_VERILOG, [1], Icarus verilog interface)
+ WE_HAVE_VERILOG="yes"],
+ [])
+AM_CONDITIONAL([USE_VERILOG], [test "$WE_HAVE_VERILOG"])
+
dnl AC_CHECK_PROG(CCACHE, ccache, ccache)
diff --git a/src/Makefile.am b/src/Makefile.am
index 63a7c27..03a607e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,7 +14,7 @@ endif
bin_PROGRAMS = simulavr kbdgentables
-lib_LTLIBRARIES = libavrsim_pp.la
+lib_LTLIBRARIES = libavrsim_pp.la libavrvpi_pp.la
libavrsim_pp_la_SOURCES = \
application.cpp \
@@ -64,6 +64,23 @@ libavrsim_pp_la_SOURCES = \
ui.cpp
libavrsim_pp_la_LDFLAGS = -version-info 0:0:0
+if USE_VERILOG
+libavrvpi_pp_la_SOURCES = \
+ $(libavrsim_pp_la_SOURCES) \
+ vpi.cpp
+
+libavrvpi_pp_la_LDFLAGS= \
+ -version-info 0:0:0
+
+libavrvpi_pp_la_LIBADD= \
+ -L $(AVR_LIBIBERTY_INC)/../lib -lbfd $(AVR_LIBIBERTY_LIB) -lz
+
+all-local: avr.vpi
+
+avr.vpi: libavrvpi_pp.la
+ cp .libs/libavrvpi_pp.so avr.vpi
+endif
+
pkginclude_HEADERS = \
application.h \
at4433.h \
@@ -146,7 +163,7 @@ EXTRA_DIST = pysimulavr.i
DISTCLEANFILES:=${DISTCLEANFILES} simulavr.so keytrans.h _pysimulavr.so
pysimulavr.py pysimulavr_wrap.cpp
-Cleanfiles:=${CLEANFILES} simulavr.so keytrans.h simulavr_wrap.cpp
+Cleanfiles:=${CLEANFILES} simulavr.so keytrans.h simulavr_wrap.cpp avr.vpi
diff --git a/src/avrdevice.h b/src/avrdevice.h
index d4ff640..248570f 100644
--- a/src/avrdevice.h
+++ b/src/avrdevice.h
@@ -95,7 +95,7 @@ class AvrDevice: public SimulationMember {
AvrDevice(unsigned int ioSpaceSize, unsigned int IRamSize, unsigned
int ERamSize, unsigned int flashSize);
/*! Steps the AVR core.
- \param untilCoreStepFinished if true, steps a core step and not a
+ \param untilCoreStepFinished iff true, steps a core step and not a
single clock cycle. */
int Step(bool &untilCoreStepFinished, SystemClockOffset *nextStepIn_ns
=0);
void Reset();
diff --git a/src/verilog/avr.v b/src/verilog/avr.v
new file mode 100644
index 0000000..d41a96c
--- /dev/null
+++ b/src/verilog/avr.v
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 Onno Kortmann <address@hidden>
+ *
+ * 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 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.
+ *
+ */
+
+/* SimulavrXX glue code on the verilog side. */
+
+/* FIXME: Some parts are still unfinished!
+ FIXME: Output-pullups are not implemented yet - find a good way to do that!
+ */
+
+module avr_pin(conn);
+ parameter name="UNSPECIFIED";
+ inout conn;
+ wire out;
+
+ integer val;
+
+ wire output_active;
+ assign output_active = (val<=2);
+
+ assign conn = output_active ? out : 1'bz;
+
+ function a2v;
+ input apin;
+ if (apin==0) // low
+ a2v=0;
+ else if (apin==1) // high
+ a2v=1;
+ else if (apin==2) // shorted
+ a2v=1'bx;
+ else if (apin==3) // pull-up
+ a2v=1;
+ else if (apin==4) // tristate
+ a2v=1'bz;
+ else if (apin==5) // pull-down
+ a2v=0;
+ else if (apin==6) // analog
+ a2v=1'bx;
+ else if (apin==7) // analog, shorted
+ a2v=1'bx;
+ endfunction // a2v
+
+ function v2a;
+ input vpin;
+ if (vpin==1'bz)
+ v2a=4; // tristate
+ else if (vpin==1'bx)
+ v2a=2; // approximate as shorted
+ else if (vpin==1)
+ v2a=1; // high
+ else if (vpin==0)
+ v2a=0; // low
+ endfunction // v2a
+
+ assign out=a2v(val);
+
+ always @(posedge core.clk) begin
+ val=$avr_get_pin(core.handle, name);
+ $avr_set_pin(core.handle, name, v2a(conn));
+ end
+
+endmodule // avr_pin
+
+module avr_clock(clk);
+ output clk;
+ reg clk;
+ parameter FREQ=4_000_000;
+ initial begin
+ clk<=0;
+ end
+
+ always @(clk) begin
+ #(1_000_000_000/FREQ/2) clk<=~clk; //125000 -> 4MHz clock
+ end
+endmodule // avr_clock
+
+module AVRCORE(clk);
+ parameter progfile="UNSPECIFIED";
+ parameter name="UNSPECIFIED";
+ input clk;
+
+ integer handle;
+ integer PCw; // word-wise PC as it comes from simulavrxx
+ wire [16:0] PCb; // byte-wise PC as used in output from avr-objdump!
+ assign PCb=2*PCw;
+
+ initial begin
+ $display("Creating an AVR device.");
+ handle=$avr_create(name, progfile);
+ //$avr_reset(handle);
+ end
+
+ always @(posedge clk) begin
+ PCw=$avr_get_pc(handle);
+ $avr_tick(handle);
+ end
+
+endmodule // AVRCORE
+
diff --git a/src/vpi.cpp b/src/vpi.cpp
index a644f13..5884276 100644
--- a/src/vpi.cpp
+++ b/src/vpi.cpp
@@ -23,6 +23,9 @@
#include <vpi_user.h>
#include "avrdevice.h"
#include "avrfactory.h"
+#include "rwmem.h"
+#include "trace.h"
+
static std::vector<AvrDevice*> devices;
@@ -41,57 +44,100 @@ static bool checkHandle(int h) {
return true;
}
+#define VPI_UNPACKS(name) \
+ { \
+ vpiHandle name = vpi_scan(argv); \
+ if (! name) { \
+ vpi_printf("%s: " #name " parameter missing.\n", xx);\
+ vpi_free_object(argv); \
+ return 0; \
+ } \
+ value.format = vpiStringVal; \
+ vpi_get_value(name, &value); \
+ } \
+ std::string name = value.value.str;
+
+#define VPI_UNPACKI(name) \
+ { \
+ vpiHandle name = vpi_scan(argv); \
+ if (! name) { \
+ vpi_printf("%s: " #name " parameter missing.\n", xx);\
+ vpi_free_object(argv); \
+ return 0; \
+ } \
+ value.format = vpiIntVal; \
+ vpi_get_value(name, &value); \
+ } \
+ int name = value.value.integer;
+
+#define VPI_RETURN_INT(val) \
+ value.format = vpiIntVal; \
+ value.value.integer = (val); \
+ vpi_put_value(ch, &value, 0, vpiNoDelay); \
+ return 0;
+
+#define AVR_HCHECK() \
+ if (!checkHandle(handle)) { \
+ vpi_printf("%s: Invalid handle parameter.\n", xx); \
+ return 0; \
+ }
+
+#define VPI_BEGIN() \
+ s_vpi_value value; \
+ vpiHandle ch = vpi_handle(vpiSysTfCall, 0); \
+ vpiHandle argv = vpi_iterate(vpiArgument, ch);
+
+#define VPI_END() \
+ vpi_free_object(argv);
+
+#define VPI_REGISTER_TASK(name) \
+ { \
+ s_vpi_systf_data tf_data; \
+ tf_data.type = vpiSysTask; \
+ tf_data.tfname = "$" #name; \
+ tf_data.calltf = name ## _tf; \
+ tf_data.compiletf = 0; \
+ tf_data.sizetf = 0; \
+ tf_data.user_data = "$" #name; \
+ vpi_register_systf(&tf_data); \
+ }
+
+#define VPI_REGISTER_FUNC(name) \
+ { \
+ s_vpi_systf_data tf_data; \
+ tf_data.type = vpiSysFunc; \
+ tf_data.tfname = "$" #name; \
+ tf_data.calltf = name ## _tf; \
+ tf_data.compiletf = 0; \
+ tf_data.sizetf = 0; \
+ tf_data.user_data = "$" #name; \
+ vpi_register_systf(&tf_data); \
+ }
+
/*!
This function creates a new AVR core and `returns' a handle to it
Usage from Verilog:
- $avr_create(handle, device, progname)
+ $avr_create(device, progname) -> handle
where
handle is an integer handle by which the avr can be accessed in all other
calls here
- devic is the name of the AVR device to create
+ device is the name of the AVR device to create
progname is the path to the flash program elf binary
*/
static PLI_INT32 avr_create_tf(char *xx) {
- s_vpi_value value;
- vpiHandle ch = vpi_handle(vpiSysTfCall, 0);
- vpiHandle argv = vpi_iterate(vpiArgument, ch);
- vpiHandle handle=vpi_scan(argv);
- vpiHandle _device=vpi_scan(argv);
- vpiHandle _progname=vpi_scan(argv);
-
- value.format = vpiStringVal;
- vpi_get_value(_device, &value);
- std::string device=value.value.str;
-
- value.format = vpiStringVal;
- vpi_get_value(_progname, &value);
- std::string progname=value.value.str;
-
- // FIXME: Better error handling than exit(...) here. Exceptions!
- AvrDevice* dev;
- devices.push_back(dev=AvrFactory::instance().makeDevice(device));
+ VPI_BEGIN();
+ VPI_UNPACKS(device);
+ VPI_UNPACKS(progname);
+ VPI_END();
- /*
- if (device=="AT90S4433") {
- devices.push_back(dev=new AvrDevice_at90s4433());
- } else {
- vpi_printf("Invalid AVR device: %s\n", device.c_str());
- vpi_control(vpiFinish, 1);
- return 0;
- }
- if (!dev) {
- vpi_printf("Can't create backend AVR simulavrxx device.");
- vpi_control(vpiFinish, 1);
- return 0;
- }*/
+ AvrDevice* dev=AvrFactory::instance().makeDevice(device);
+ devices.push_back(dev);
dev->Load(progname.c_str());
-
- value.format = vpiIntVal;
- value.value.integer = devices.size()-1;
- vpi_put_value(handle, &value, 0, vpiNoDelay);
+
+ VPI_RETURN_INT(devices.size()-1);
}
/*!
@@ -101,17 +147,12 @@ static PLI_INT32 avr_create_tf(char *xx) {
$avr_reset(handle)
*/
static PLI_INT32 avr_reset_tf(char *xx) {
- s_vpi_value value;
- vpiHandle ch = vpi_handle(vpiSysTfCall, 0);
- vpiHandle argv = vpi_iterate(vpiArgument, ch);
- vpiHandle handle=vpi_scan(argv);
-
- value.format = vpiIntVal;
- vpi_get_value(handle, &value);
- int h = value.value.integer;
- if (!checkHandle(h)) return 0;
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_END();
- devices[h]->Reset();
+ AVR_HCHECK();
+ devices[handle]->Reset();
return 0;
}
@@ -122,20 +163,16 @@ static PLI_INT32 avr_reset_tf(char *xx) {
$avr_destroy(handle)
*/
static PLI_INT32 avr_destroy_tf(char *xx) {
- s_vpi_value value;
- vpiHandle ch = vpi_handle(vpiSysTfCall, 0);
- vpiHandle argv = vpi_iterate(vpiArgument, ch);
- vpiHandle handle=vpi_scan(argv);
-
- value.format = vpiIntVal;
- vpi_get_value(handle, &value);
- int h = value.value.integer;
- if (!checkHandle(h)) return 0;
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_END();
- /* We leak a bit of memory for the pointer in the vector,
+ AVR_HCHECK();
+
+ /* We may leak a bity of memory for the pointer in the vector,
but... what the hell! */
- delete devices[h];
- devices[h]=0;
+ delete devices[handle];
+ devices[handle]=0;
return 0;
}
@@ -146,53 +183,34 @@ static PLI_INT32 avr_destroy_tf(char *xx) {
$avr_tick(handle)
*/
static PLI_INT32 avr_tick_tf(char *xx) {
- s_vpi_value value;
- vpiHandle ch = vpi_handle(vpiSysTfCall, 0);
- vpiHandle argv = vpi_iterate(vpiArgument, ch);
- vpiHandle handle=vpi_scan(argv);
-
- value.format = vpiIntVal;
- vpi_get_value(handle, &value);
- int h = value.value.integer;
- if (!checkHandle(h)) return 0;
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_END();
+
+ AVR_HCHECK();
- /* Lets do a HARDWARE step in the AVR core.
- uC stepping in opcode units does not seem to make any sense from this
- HDL view. But it looks like avrdevice does have no interest in this
- value at all? */
bool no_hw=false;
- devices[h]->Step(no_hw);
+ devices[handle]->Step(no_hw);
return 0;
}
/*!
This function reads an AVR pin value.
Usage from verilog:
- $avr_pin_get(handle, name, value)
+ $avr_pin_get(handle, name) -> value
*/
static PLI_INT32 avr_get_pin_tf(char *xx) {
- s_vpi_value value;
- vpiHandle ch = vpi_handle(vpiSysTfCall, 0);
- vpiHandle argv = vpi_iterate(vpiArgument, ch);
- vpiHandle handle=vpi_scan(argv);
- vpiHandle _name=vpi_scan(argv);
- vpiHandle _value=vpi_scan(argv);
- value.format = vpiIntVal;
- vpi_get_value(handle, &value);
- int h = value.value.integer;
- if (!checkHandle(h)) return 0;
-
- value.format = vpiStringVal;
- vpi_get_value(_name, &value);
- std::string name=value.value.str;
-
- Pin *pin=devices[h]->GetPin(name.c_str());
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_UNPACKS(name);
+ VPI_END();
+
+ AVR_HCHECK();
+
+ Pin *pin=devices[handle]->GetPin(name.c_str());
int ret(pin->outState);
- value.format = vpiIntVal;
- value.value.integer = ret;
- vpi_put_value(_value, &value, 0, vpiNoDelay);
- return 0;
+ VPI_RETURN_INT(ret);
}
/*!
@@ -201,98 +219,123 @@ static PLI_INT32 avr_get_pin_tf(char *xx) {
$avr_pin_set(handle, name, val)
*/
static PLI_INT32 avr_set_pin_tf(char *xx) {
- s_vpi_value value;
- vpiHandle ch = vpi_handle(vpiSysTfCall, 0);
- vpiHandle argv = vpi_iterate(vpiArgument, ch);
- vpiHandle handle=vpi_scan(argv);
- vpiHandle _name=vpi_scan(argv);
- vpiHandle _value=vpi_scan(argv);
- value.format = vpiIntVal;
- vpi_get_value(handle, &value);
- int h = value.value.integer;
- if (!checkHandle(h)) return 0;
-
- value.format = vpiStringVal;
- vpi_get_value(_name, &value);
- std::string name=value.value.str;
-
- Pin *pin=devices[h]->GetPin(name.c_str());
-
- value.format = vpiIntVal;
- vpi_get_value(_value, &value);
- int val=value.value.integer;
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_UNPACKS(name);
+ VPI_UNPACKI(val);
+ VPI_END();
+
+ AVR_HCHECK();
+
+ Pin *pin=devices[handle]->GetPin(name.c_str());
+
/* FIXME: Simply exports AVR pin states to verilog. This
- a breach of abstractions. */
+ may be considered a breach of abstractions.
+ */
pin->SetInState(Pin::T_Pinstate(val));
return 0;
}
-static void register_tasks() {
- {
- s_vpi_systf_data tf_data;
-
- tf_data.type = vpiSysTask;
- tf_data.tfname = "$avr_create";
- tf_data.calltf = avr_create_tf;
- tf_data.compiletf = 0;
- tf_data.sizetf = 0;
- vpi_register_systf(&tf_data);
- }
- {
- s_vpi_systf_data tf_data;
-
- tf_data.type = vpiSysTask;
- tf_data.tfname = "$avr_reset";
- tf_data.calltf = avr_reset_tf;
- tf_data.compiletf = 0;
- tf_data.sizetf = 0;
- vpi_register_systf(&tf_data);
- }
- {
- s_vpi_systf_data tf_data;
-
- tf_data.type = vpiSysTask;
- tf_data.tfname = "$avr_destroy";
- tf_data.calltf = avr_destroy_tf;
- tf_data.compiletf = 0;
- tf_data.sizetf = 0;
- vpi_register_systf(&tf_data);
- }
+/*!
+ This function reads the value of the program counter
+ in the AVR.
+ Usage from verilog:
+ $avr_get_pc(handle) -> pc_value
+*/
+static PLI_INT32 avr_get_pc_tf(char *xx) {
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_END();
- {
- s_vpi_systf_data tf_data;
-
- tf_data.type = vpiSysTask;
- tf_data.tfname = "$avr_tick";
- tf_data.calltf = avr_tick_tf;
- tf_data.compiletf = 0;
- tf_data.sizetf = 0;
- vpi_register_systf(&tf_data);
- }
+ AVR_HCHECK();
- {
- s_vpi_systf_data tf_data;
-
- tf_data.type = vpiSysTask;
- tf_data.tfname = "$avr_get_pin";
- tf_data.calltf = avr_get_pin_tf;
- tf_data.compiletf = 0;
- tf_data.sizetf = 0;
- vpi_register_systf(&tf_data);
- }
+ VPI_RETURN_INT(devices[handle]->PC);
+}
+
+/*!
+ This function reads the value of a RAM-readable
+ location in the AVR (0..31 are the regs, followed by the IO-space etc).
+ Usage from verilog:
+ $avr_get_rw(handle, adr) -> val
+ where
+ adr is the adress to read
+ and val is the returned value at that address
+*/
+static PLI_INT32 avr_get_rw_tf(char *xx) {
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_UNPACKI(address);
+ VPI_END();
+
+ AVR_HCHECK();
+
+ VPI_RETURN_INT(*(devices[handle]->rw[address]));
+}
+
+/*!
+ Counterpart to avr_get_rw_tf. It sets the value of a RAM-readable
+ location in the AVR (0..31 are the regs, followed by the IO-space etc).
+ Usage from verilog:
+ $avr_set_rw(handle, adr, val)
+ where
+ adr is the adress to read
+ and val is the value to set at that address
+*/
+static PLI_INT32 avr_set_rw_tf(char *xx) {
+ VPI_BEGIN();
+ VPI_UNPACKI(handle);
+ VPI_UNPACKI(address);
+ VPI_UNPACKI(val);
+ VPI_END();
+
+ AVR_HCHECK();
+
+ *(devices[handle]->rw[address])=val;
+ return 0;
+}
+
+/*!
+ Enable or disable tracing for all AVR core.
+ TODO: Implement tracing per core?
+
+ Usage from Verilog:
+
+ $avr_trace(tracename)
- {
- s_vpi_systf_data tf_data;
-
- tf_data.type = vpiSysTask;
- tf_data.tfname = "$avr_set_pin";
- tf_data.calltf = avr_set_pin_tf;
- tf_data.compiletf = 0;
- tf_data.sizetf = 0;
- vpi_register_systf(&tf_data);
+ where
+ tracename is the output file name for tracing. If it is the empty string,
+ tracing will be disabled again and the file will be closed.
+*/
+
+static PLI_INT32 avr_trace_tf(char *xx) {
+ VPI_BEGIN();
+ VPI_UNPACKS(tracename);
+ VPI_END();
+
+ if (tracename.length()) {
+ traceOut.open(tracename.c_str());
+ for (size_t i=0; i < devices.size(); i++)
+ devices[i]->trace_on=1;
+ } else {
+ traceOut.close();
+ for (size_t i=0; i < devices.size(); i++)
+ devices[i]->trace_on=0;
}
}
+static void register_tasks() {
+ VPI_REGISTER_FUNC(avr_create);
+ VPI_REGISTER_TASK(avr_reset);
+ VPI_REGISTER_TASK(avr_destroy);
+ VPI_REGISTER_TASK(avr_tick);
+ VPI_REGISTER_FUNC(avr_get_pin);
+ VPI_REGISTER_TASK(avr_set_pin);
+ VPI_REGISTER_FUNC(avr_get_pc);
+ VPI_REGISTER_FUNC(avr_get_rw);
+ VPI_REGISTER_TASK(avr_set_rw);
+ VPI_REGISTER_TASK(avr_trace);
+}
+
/* This is a table of register functions. This table is the external symbol
that the simulator looks for when loading this .vpi module. */
void (*vlog_startup_routines[])() = {
--
1.5.6.5
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Simulavr-devel] [PATCH 12/13] Major update of Verilog interface for SimulAVR,
Onno Kortmann <=