[myhdl-list] Re: VCD viewer ?
Brought to you by:
jandecaluwe
From: Jan D. <ja...@ja...> - 2005-04-21 20:25:24
|
Jean Demartini wrote: > Jean DEMARTINI a écrit : > >> Hi all, >> >> For many reasons I've to use MyHDL on a Windows platform (XP SP2). >> Python and MyHDL works perfectly. But has anyone knowledge of a >> working free VCD viewer onto Windows. Despite many effort, I've not >> succeded to use GTKwave and Wavevcd from ISS (beta downloadable at >> www.iss-us.com) does not recognize the VCD format generated by MyHDL >> (its is a drawback of the ISS viewer as the VCD format generated by >> MyDHL is quite correct) . >> >> Jean >> >> > > ISS has just release a new version of its free Wave VCD viewer > (http://www.iss-us.com/wavevcd/). This viewer functions quite properly > but is only conformant with IEEE VCD std. To generate such VCD files, it > is necessary to modifie: > _Signal.py > _traceSignals.py > > Enclosed are a modified version of these files. Testing is in progress > and these files are given as it. In _traceSignal.py, I had expected a type check to differentiate between the various types - instead this is done by checking the bit width. Doesn't this mean that a reg of width 32 or 64 would be declared as an int or a float ?? Jan > > vcd-test.py is a modified version of the examle given in the tutorial > and tb_fsm.vcd is the generated VCD file. > > Warning: enum type has not been modified. Then states are denoted by > integers ans no more by strings. > > Hope this helps. > JDem > > > ------------------------------------------------------------------------ > > # This file is part of the myhdl library, a Python package for using > # Python as a Hardware Description Language. > # > # Copyright (C) 2003 Jan Decaluwe > # > # The myhdl library is free software; you can redistribute it and/or > # modify it under the terms of the GNU Lesser General Public License as > # published by the Free Software Foundation; either version 2.1 of the > # License, or (at your option) any later version. > # > # This library 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 > # Lesser General Public License for more details. > # > # You should have received a copy of the GNU Lesser General Public > # License along with this library; if not, write to the Free Software > # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > # > ######################## > # > # modified by Jean DEMARTINI to generate true std. IEEE VCD files > # modified or inserted instruction are shown by a comment like # XXXXX ---- JDM > # > # these modifcations are only partly tested. Their effects on Verilog generation > # has not been tested. > > """ myhdl traceSignals module. > > """ > > __author__ = "Jan Decaluwe <ja...@ja...>" > __revision__ = "$Revision: 1.20 $" > __date__ = "$Date: 2004/09/23 20:38:07 $" > > import sys > from inspect import currentframe, getouterframes > import time > import os > path = os.path > import shutil > from sets import Set > > from myhdl import _simulator, Signal, __version__ > from myhdl._util import _isGenFunc > from myhdl._isGenSeq import _isGenSeq > from myhdl._extractHierarchy import _findInstanceName, _HierExtr > from myhdl import TraceSignalsError > > _tracing = 0 > _profileFunc = None > > class _error: > pass > _error.TopLevelName = "result of traceSignals call should be assigned to a top level name" > _error.ArgType = "traceSignals first argument should be a classic function" > _error.MultipleTraces = "Cannot trace multiple instances simultaneously" > > def traceSignals(dut, *args, **kwargs): > global _tracing > if _tracing: > return dut(*args, **kwargs) # skip > else: > # clean start > sys.setprofile(None) > from myhdl._toVerilog import _convert > if _convert._converting: > raise TraceSignalsError("Cannot use traceSignals while converting to Verilog") > if not callable(dut): > raise TraceSignalsError(_error.ArgType, "got %s" % type(dut)) > if _simulator._tracing: > raise TraceSignalsError(_error.MultipleTraces) > > _tracing = 1 > try: > outer = getouterframes(currentframe())[1] > name = _findInstanceName(outer) > if name is None: > raise TraceSignalsError(_error.TopLevelName) > h = _HierExtr(name, dut, *args, **kwargs) > vcdpath = name + ".vcd" > if path.exists(vcdpath): > backup = vcdpath + '.' + str(path.getmtime(vcdpath)) > shutil.copyfile(vcdpath, backup) > os.remove(vcdpath) > vcdfile = open(vcdpath, 'w') > _simulator._tracing = 1 > _simulator._tf = vcdfile > _writeVcdHeader(vcdfile) > _writeVcdSigs(vcdfile, h.hierarchy) > finally: > _tracing = 0 > > return h.top > > > _codechars = "" > for i in range(33, 127): > _codechars += chr(i) > _mod = len(_codechars) > > def _genNameCode(): > n = 0 > while 1: > yield _namecode(n) > n += 1 > > def _namecode(n): > q, r = divmod(n, _mod) > code = _codechars[r] > while q > 0: > q, r = divmod(q, _mod) > code = _codechars[r] + code > return code > > def _writeVcdHeader(f): > print >> f, "$date" > print >> f, " %s" % time.asctime() > print >> f, "$end" > print >> f, "$version" > print >> f, " MyHDL %s" % __version__ > print >> f, "$end" > print >> f, "$timescale" > print >> f, " 1ns" > print >> f, "$end" > print >> f > > def _writeVcdSigs(f, hierarchy): > curlevel = 0 > namegen = _genNameCode() > siglist = [] > for level, name, sigdict in hierarchy: > delta = curlevel - level > curlevel = level > assert(delta >= -1) > if delta >= 0: > for i in range(delta + 1): > print >> f, "$upscope $end" > print >> f, "$scope module %s $end" % name > for n, s in sigdict.items(): > if not s._tracing: > s._tracing = 1 > s._code = namegen.next() > siglist.append(s) > w = s._nrbits > if w: > if w == 1: > print >> f, "$var reg 1 %s %s $end" % (s._code, n) # single bit ------------- JDM > elif w == 32: > print >> f, "$var integer %s %s %s $end" % (w, s._code, n) # integer ------------- JDM > elif w == 64: > print >> f, "$var real %s %s %s $end" % (w, s._code, n) # float ------------- JDM > else: > print >> f, "$var reg %s %s %s[%s:0] $end" % (w, s._code, n, w-1) # register ------------- JDM > else: > raise ValueError("Unexpected type, got %s" % w) # error ------------- JDM > for i in range(curlevel): > print >> f, "$upscope $end" > print >> f > print >> f, "$enddefinitions $end" > print >> f, "$dumpvars" > for s in siglist: > s._printVcd() # initial value > print >> f, "$end" > > > > > > > > > > > > > > > > ------------------------------------------------------------------------ > > # This file is part of the myhdl library, a Python package for using > # Python as a Hardware Description Language. > # > # Copyright (C) 2003 Jan Decaluwe > # > # The myhdl library is free software; you can redistribute it and/or > # modify it under the terms of the GNU Lesser General Public License as > # published by the Free Software Foundation; either version 2.1 of the > # License, or (at your option) any later version. > # > # This library 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 > # Lesser General Public License for more details. > > # You should have received a copy of the GNU Lesser General Public > # License along with this library; if not, write to the Free Software > # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > # > ######################## > # > # modified by Jean DEMARTINI to generate true std. IEEE VCD files > # modified or inserted instruction are shown by a comment like # XXXXX ---- JDM > # > # these modifcations are only partly tested. Their effects on Verilog generation > # has not been tested. > > """ Module that provides the Signal class and related objects. > > This module provides the following objects: > > Signal -- class to model hardware signals > posedge -- callable to model a rising edge on a signal in a yield statement > negedge -- callable to model a falling edge on a signal in a yield statement > > """ > __author__ = "Jan Decaluwe <ja...@ja...>" > __revision__ = "$Revision: 1.25 $" > __date__ = "$Date: 2004/12/27 12:31:47 $" > > from inspect import currentframe, getouterframes > from copy import deepcopy as copy > > from myhdl import _simulator as sim > from myhdl._simulator import _siglist, _futureEvents, now > from myhdl._Waiter import _WaiterList > from myhdl._intbv import intbv > from myhdl._bin import bin > > _schedule = _futureEvents.append > > > def posedge(sig): > """ Return a posedge trigger object """ > return sig.posedge > > def negedge(sig): > """ Return a negedge trigger object """ > return sig.negedge > > class Signal(object): > > """ Signal class. > > Properties: > val -- current value (read-only) > next -- next value (read-write) > > """ > > __slots__ = ('_next', '_val', '_min', '_max', '_type', > '_eventWaiters', '_posedgeWaiters', '_negedgeWaiters', > '_code', '_tracing', '_nrbits', '_checkVal', '_setNextVal', > '_printVcd', '_driven' ,'_read', '_name' > ) > > def __new__(cls, val=None, delay=None): > """ Return a new Signal (default or delay 0) or DelayedSignal """ > if delay is not None: > if delay < 0: > raise TypeError("Signal: delay should be >= 0") > return object.__new__(DelayedSignal) > else: > return object.__new__(cls) > > def __init__(self, val=None): > """ Construct a signal. > > val -- initial value > > """ > self._next = self._val = val > self._min = self._max = None > self._name = self._read = self._driven = None > self._nrbits = 0 > self._printVcd = self._printVcdStr > if isinstance(val, bool): > self._type = bool > self._setNextVal = self._setNextBool > self._printVcd = self._printVcdBit > self._nrbits = 1 > elif isinstance(val, (int, long)): > self._type = (int, long) > self._setNextVal = self._setNextInt > self._nrbits = 32 # ------------- JDM > self._printVcd = self._printVcdInt # ------------- JDM > elif isinstance(val, float): # ------------- JDM > self._type = float # ------------- JDM > self._setNextVal = self._setNextReal # ------------- JDM > self._nrbits = 64 # ------------- JDM > self._printVcd = self._printVcdReal # ------------- JDM > elif isinstance(val, intbv): > self._type = intbv > self._min = val._min > self._max = val._max > self._nrbits = val._nrbits > self._setNextVal = self._setNextIntbv > if self._nrbits: > self._printVcd = self._printVcdVec > else: > self._printVcd = self._printVcdHex > elif val is None: > self._type = None > self._setNextVal = self._setNext > else: > self._type = type(val) > self._setNextVal = self._setNextType > if hasattr(val, '_nrbits'): > self._nrbits = val._nrbits > self._eventWaiters = _WaiterList() > self._posedgeWaiters = _WaiterList() > self._negedgeWaiters = _WaiterList() > self._code = "" > self._tracing = 0 > > def _update(self): > val, next = self._val, self._next > if val != next: > waiters = self._eventWaiters[:] > del self._eventWaiters[:] > if not val and next: > waiters.extend(self._posedgeWaiters[:]) > del self._posedgeWaiters[:] > elif not next and val: > waiters.extend(self._negedgeWaiters[:]) > del self._negedgeWaiters[:] > self._val = next > if self._tracing: > self._printVcd() > return waiters > else: > return [] > > # support for the 'val' attribute > def _get_val(self): > return self._val > val = property(_get_val, None, None, "'val' access methods") > > # support for the 'next' attribute > def _get_next(self): > if self._next is self._val: > self._next = copy(self._val) > _siglist.append(self) > return self._next > def _set_next(self, val): > if isinstance(val, Signal): > val = val._val > self._setNextVal(val) > _siglist.append(self) > next = property(_get_next, _set_next, None, "'next' access methods") > > # support for the 'posedge' attribute > def _get_posedge(self): > return self._posedgeWaiters > posedge = property(_get_posedge, None, None, "'posedge' access methods") > > # support for the 'negedge' attribute > def _get_negedge(self): > return self._negedgeWaiters > negedge = property(_get_negedge, None, None, "'negedge' access methods") > > # support for the 'min' and 'max' attribute > def _get_max(self): > return self._max > max = property(_get_max, None) > def _get_min(self): > return self._min > min = property(_get_min, None) > > # set next methods > def _setNextBool(self, val): > if not val in (0, 1): > raise ValueError("Expected value 0 or 1, got %s" % val) > self._next = val > > def _setNextInt(self, val): > if not isinstance(val, (int, long, intbv)): > raise TypeError("Expected int or intbv, got %s" % type(val)) > self._next = val > > def _setNextReal(self, val): > if not isinstance(val, float): > raise TypeError("Expected float, got %s" % type(val)) > self._next = val > > def _setNextIntbv(self, val): > if isinstance(val, intbv): > val = val._val > elif not isinstance(val, (int, long)): > raise TypeError("Expected int or intbv, got %s" % type(val)) > if self._next is self._val: > self._next = copy(self._val) > self._next._val = val > self._next._checkBounds() > > def _setNextType(self, val): > if not isinstance(val, self._type): > raise TypeError("Expected %s, got %s" % (self._type, type(val))) > self._next = val > > def _setNext(self, val): > self._next = val > > # vcd print methods > def _printVcdReal(self): > print >> sim._tf, "R%.16g%s" % (self._val, self._code) # --------------- JDM > > def _printVcdInt(self): > print >> sim._tf, "B%s%s" % (bin(self._val,32), self._code) # --------------- JDM > > def _printVcdStr(self): > print >> sim._tf, "s%s %s" % (str(self._val), self._code) > > def _printVcdHex(self): > print >> sim._tf, "s%s %s" % (hex(self._val), self._code) > > def _printVcdBit(self): > print >> sim._tf, "%d%s" % (self._val, self._code) > > def _printVcdVec(self): > print >> sim._tf, "b%s %s" % (bin(self._val, self._nrbits), self._code) > > ### operators for which delegation to current value is appropriate ### > > # hashing (?) > def __hash__(self): > return hash(self._val) > > > def __nonzero__(self): > if self._val: > return 1 > else: > return 0 > > # length > def __len__(self): > return len(self._val) > > # indexing and slicing methods > > def __getitem__(self, key): > return self._val[key] > > # integer-like methods > > def __add__(self, other): > if isinstance(other, Signal): > return self._val + other._val > else: > return self._val + other > def __radd__(self, other): > return other + self._val > > def __sub__(self, other): > if isinstance(other, Signal): > return self._val - other._val > else: > return self._val - other > def __rsub__(self, other): > return other - self._val > > def __mul__(self, other): > if isinstance(other, Signal): > return self._val * other._val > else: > return self._val * other > def __rmul__(self, other): > return other * self._val > > def __div__(self, other): > if isinstance(other, Signal): > return self._val / other._val > else: > return self._val / other > def __rdiv__(self, other): > return other / self._val > > def __truediv__(self, other): > if isinstance(other, Signal): > return operator.truediv(self._val, other._val) > else: > return operator.truediv(self._val, other) > def __rtruediv__(self, other): > return operator.truediv(other, self._val) > > def __floordiv__(self, other): > if isinstance(other, Signal): > return self._val // other._val > else: > return self._val // other > def __rfloordiv__(self, other): > return other // self._val > > def __mod__(self, other): > if isinstance(other, Signal): > return self._val % other._val > else: > return self._val % other > def __rmod__(self, other): > return other % self._val > > # XXX divmod > > def __pow__(self, other): > if isinstance(other, Signal): > return self._val ** other._val > else: > return self._val ** other > def __rpow__(self, other): > return other ** self._val > > def __lshift__(self, other): > if isinstance(other, Signal): > return self._val << other._val > else: > return self._val << other > def __rlshift__(self, other): > return other << self._val > > def __rshift__(self, other): > if isinstance(other, Signal): > return self._val >> other._val > else: > return self._val >> other > def __rrshift__(self, other): > return other >> self._val > > def __and__(self, other): > if isinstance(other, Signal): > return self._val & other._val > else: > return self._val & other > def __rand__(self, other): > return other & self._val > > def __or__(self, other): > if isinstance(other, Signal): > return self._val | other._val > else: > return self._val | other > def __ror__(self, other): > return other | self._val > > def __xor__(self, other): > if isinstance(other, Signal): > return self._val ^ other._val > else: > return self._val ^ other > def __rxor__(self, other): > return other ^ self._val > > def __neg__(self): > return -self._val > > def __pos__(self): > return +self._val > > def __abs__(self): > return abs(self._val) > > def __invert__(self): > return ~self._val > > # conversions > > def __int__(self): > return int(self._val) > > def __long__(self): > return long(self._val) > > def __float__(self): > return float(self._val) > > def __oct__(self): > return oct(self._val) > > def __hex__(self): > return hex(self._val) > > > # comparison > def __cmp__(self, other): > return cmp(self._val, other) > > # representation > def __str__(self): > return str(self._val) > > def __repr__(self): > return "Signal(" + repr(self._val) + ")" > > # augmented assignment not supported > def _augm(self): > raise TypeError, "Signal object doesn't support augmented assignment" > > __iadd__ = __isub__ = __idiv__ = __imul__ = __ipow__ = __imod__ = _augm > __ior__ = __iand__ = __ixor__ = __irshift__ = __ilshift__ = _augm > > # index and slice assignment not supported > def __setitem__(self, key, val): > raise TypeError, "Signal object doesn't support item/slice assignment" > > > class DelayedSignal(Signal): > > __slots__ = ('_nextZ', '_delay', '_timeStamp', > ) > > def __init__(self, val=None, delay=1): > """ Construct a new DelayedSignal. > > Automatically invoked through the Signal new method. > val -- initial value > delay -- non-zero delay value > """ > Signal.__init__(self, val) > self._nextZ = val > self._delay = delay > self._timeStamp = 0 > > def _update(self): > if self._next != self._nextZ: > self._timeStamp = sim._time > self._nextZ = self._next > t = sim._time + self._delay > _schedule((t, _SignalWrap(self, self._next, self._timeStamp))) > return [] > > def _apply(self, next, timeStamp): > val = self._val > if timeStamp == self._timeStamp and val != next: > waiters = self._eventWaiters[:] > del self._eventWaiters[:] > if not val and next: > waiters.extend(self._posedgeWaiters[:]) > del self._posedgeWaiters[:] > elif not next and val: > waiters.extend(self._negedgeWaiters[:]) > del self._negedgeWaiters[:] > self._val = copy(next) > if self._tracing: > self._printVcd() > return waiters > else: > return [] > > # support for the 'delay' attribute > def _get_delay(self): > return self._delay > def _set_delay(self, delay): > self._delay = delay > delay = property(_get_delay, _set_delay, None, "'delay' access methods") > > > class _SignalWrap(object): > def __init__(self, sig, next, timeStamp): > self.sig = sig > self.next = next > self.timeStamp = timeStamp > def apply(self): > return self.sig._apply(self.next, self.timeStamp) > > > > > ------------------------------------------------------------------------ > > # essai VCD from example found in tutorial > # slightly modified to generated a std. IEEE VCD file > # > # by: Jean DEMARTINI > # > from myhdl import * > > ACTIVE_LOW = 0 > FRAME_SIZE = 8 > #t_State = enum('SEARCH','CONFIRM','SYNC') > SEARCH = 0 > CONFIRM = 1 > SYNC = 2 > > def FrameCtrl(SOF,state,syncFlag,clk,reset_n): > index = Signal(0) > > def FSM(): > while 1: > yield posedge(clk),negedge(reset_n) > > if reset_n == ACTIVE_LOW: > SOF.next = 0 > index.next = 0 > state.next = SEARCH #t_State.SEARCH > else: > index.next = (index+1)%FRAME_SIZE > SOF.next = 0 > > if state == SEARCH: #t_State.SEARCH: > index.next = 1 > if syncFlag: > state.next = CONFIRM #t_State.CONFIRM > elif state == CONFIRM: #t_State.CONFIRM: > if index == 0: > if syncFlag: > state.next = SYNC #t_State.SYNC > else: > state.next = SEARCH #t_State.SEARCH > elif state == SYNC: #t_State.SYNC: > if index == 0: > if not syncFlag: > state.next = SEARCH #t_State.SEARCH > SOF.next = (index == FRAME_SIZE-1) > else: > raise ValueError("Undefined state") > return FSM() > > def testbench(): > SOF = Signal(bool(0)) > syncFlag = Signal(bool(0)) > clk = Signal(bool(0)) > reset_n = Signal(bool(1)) > state = Signal(SEARCH) #Signal(t_State.SEARCH) > > frameCtrl = FrameCtrl(SOF,state,syncFlag,clk,reset_n) > > def clkgen(): > while 1: > yield delay(10) > clk.next = not clk > > def stimulus(): > for i in range(3): > yield posedge(clk) > for n in (12,8,8,4): > syncFlag.next = 1 > yield posedge(clk) > syncFlag.next = 0 > for i in range(n-1): > yield posedge(clk) > raise StopSimulation > > return frameCtrl,clkgen(),stimulus() > > tb_fsm = traceSignals(testbench) > > sim = Simulation(tb_fsm) > sim.run() > > > > > ------------------------------------------------------------------------ > > $date > Wed Apr 20 10:01:48 2005 > $end > $version > MyHDL 0.4.1 > $end > $timescale > 1ns > $end > > $scope module tb_fsm $end > $var reg 1 ! reset_n $end > $var integer 32 " state $end > $var reg 1 # clk $end > $var reg 1 $ syncFlag $end > $var reg 1 % SOF $end > $scope module frameCtrl $end > $var integer 32 & index $end > $var reg 1 # clk $end > $var reg 1 % SOF $end > $var integer 32 " state $end > $var reg 1 ! reset_n $end > $var reg 1 $ syncFlag $end > $upscope $end > $upscope $end > > $enddefinitions $end > $dumpvars > 1! > B00000000000000000000000000000000" > 0# > 0$ > 0% > B00000000000000000000000000000000& > $end > #10 > 1# > B00000000000000000000000000000001& > #20 > 0# > #30 > 1# > #40 > 0# > #50 > 1# > 1$ > #60 > 0# > #70 > 1# > 0$ > B00000000000000000000000000000001" > #80 > 0# > #90 > 1# > B00000000000000000000000000000010& > #100 > 0# > #110 > 1# > B00000000000000000000000000000011& > #120 > 0# > #130 > 1# > B00000000000000000000000000000100& > #140 > 0# > #150 > 1# > B00000000000000000000000000000101& > #160 > 0# > #170 > 1# > B00000000000000000000000000000110& > #180 > 0# > #190 > 1# > B00000000000000000000000000000111& > #200 > 0# > #210 > 1# > B00000000000000000000000000000000& > #220 > 0# > #230 > 1# > B00000000000000000000000000000001& > B00000000000000000000000000000000" > #240 > 0# > #250 > 1# > #260 > 0# > #270 > 1# > #280 > 0# > #290 > 1# > 1$ > #300 > 0# > #310 > 1# > 0$ > B00000000000000000000000000000001" > #320 > 0# > #330 > 1# > B00000000000000000000000000000010& > #340 > 0# > #350 > 1# > B00000000000000000000000000000011& > #360 > 0# > #370 > 1# > B00000000000000000000000000000100& > #380 > 0# > #390 > 1# > B00000000000000000000000000000101& > #400 > 0# > #410 > 1# > B00000000000000000000000000000110& > #420 > 0# > #430 > 1# > B00000000000000000000000000000111& > #440 > 0# > #450 > 1# > B00000000000000000000000000000000& > 1$ > #460 > 0# > #470 > 1# > 0$ > B00000000000000000000000000000001& > B00000000000000000000000000000010" > #480 > 0# > #490 > 1# > B00000000000000000000000000000010& > #500 > 0# > #510 > 1# > B00000000000000000000000000000011& > #520 > 0# > #530 > 1# > B00000000000000000000000000000100& > #540 > 0# > #550 > 1# > B00000000000000000000000000000101& > #560 > 0# > #570 > 1# > B00000000000000000000000000000110& > #580 > 0# > #590 > 1# > B00000000000000000000000000000111& > #600 > 0# > #610 > 1# > B00000000000000000000000000000000& > 1% > 1$ > #620 > 0# > #630 > 1# > 0$ > B00000000000000000000000000000001& > 0% > #640 > 0# > #650 > 1# > B00000000000000000000000000000010& > #660 > 0# > #670 > 1# > B00000000000000000000000000000011& > #680 > 0# > #690 > 1# -- Jan Decaluwe - Resources bvba - http://jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium Using Python as a hardware description language: http://jandecaluwe.com/Tools/MyHDL/Overview.html |