Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Writing a VCD to toggle-count generator in Python

130 views
Skip to first unread message

Paddy3118

unread,
Mar 25, 2008, 4:46:41 PM3/25/08
to

Andy Botterill

unread,
Mar 25, 2008, 5:16:39 PM3/25/08
to
Paddy3118 wrote:

Do you differentiate between a glitch and data that is present for a
clock cycle? Andy

> http://paddy3118.blogspot.com/2008/03/writing-vcd-to-toggle-count-generator.html
>
> - Paddy.

Paddy3118

unread,
Mar 26, 2008, 12:40:24 AM3/26/08
to
On Mar 25, 9:16 pm, Andy Botterill <a...@plymouth2.demon.co.uk> wrote:
> Paddy3118 wrote:
>
> Do you differentiate between a glitch and data that is present for a
> clock cycle? Andy
>
> >http://paddy3118.blogspot.com/2008/03/writing-vcd-to-toggle-count-gen...
>
> > - Paddy.

In my application that is not required, so has not been added. I am
under a time constraint so was careful to do the minimum, get that
working, and only add features when neccessary.
I have already thought about adding a glitch rejecter as a separate
stage that would change base VCD to glitch-removed VCD so you could
run it as a separate process as the front end of a pipe feeding the
toggle generating code. That way I might make better use of our multi-
core compute cluster and keep the code complexity of the individual
programs down (they could also share a lot of the parsing code
directly via module import).

- Paddy.

mark....@microemissive.com

unread,
May 6, 2008, 4:40:17 AM5/6/08
to
Hi Paddy,

I recently trialled your VCD toggle count code and came across a
problem with it. I use ModelSim so the VCD output may be a little
different to what your simulator produces. Anyway the problem
occurred on $var lines, the example I have has the following syntax:

$var reg 1 " clk $end
$var reg 8 # data [7:0] $end

The first line is parsed okay but the second one caused problems. I
changed the vcd_var function to take into account the extra bus
information. I have included the changes below, you may be able to
think of a better way as my Python knowledge is fairly limited.


def vcd_var(tokeniser, keyword):
var_options = tuple(takewhile(lambda x: x != "$end", tokeniser))
if len(var_options) == 4 :
var_type, size, identifier_code, reference = var_options;
else :
var_type, size, identifier_code, reference, bus_size =
var_options;
reference = vcd.scope + [('var', reference)]
vcd.idcode2references[identifier_code].append( (var_type, size,
reference))
vcd.reference2idcode[tuple(reference)] = identifier_code
vcd.id2stats[identifier_code] = IdStats(size)


One other problem I noticed with your code is when reporting which
signals in a bus where toggling it reversed the bit order.

I have also expanded your code to get a transition count of all the
signals in a simulation as I wanted to use this figure to generate a
guesstimate of the power required. If you would like this code let me
know and I will email it to you.

You also mentioned you made some updates to the code, have you posted
these onto the web anywhere?

Cheers,
Mark

ps. If you see a similar email to this one, its because I thought the
original post did not work.

Paddy3118

unread,
May 7, 2008, 2:17:07 PM5/7/08
to

Mark,
I'll try re-visiting this code this weekend. If you have any more
updates I'll take a look and maybe post the whole thing on Google code
as a project.

I had started to work on a parallel version to make use of multiple
cores (which I must get for home), and compute farms (LSF and
GridEngine). I haven't got the parallel one working yet though.

Anyone else interested?


- Paddy.

mark....@microemissive.com

unread,
May 8, 2008, 5:47:48 AM5/8/08
to
Hi Paddy,

Here is the code with my changes inserted.

Cheers,
Mark

#######################################################

#!python
'''
Extract toggle count from vcd file

Refer to IEEE standard 1364 2001
(http://inst.eecs.berkeley.edu/~cs150/ProtectedDocs/verilog-ieee.pdf)

Author Donald 'Paddy' McCarthy (C) 24 March 2008
'''

from __future__ import with_statement
from itertools import dropwhile, takewhile, izip
from collections import defaultdict
from pprint import pprint as pp

vcdfile = r"dump.vcd"

class VCD(object):
def __init__(self):
self.scope = []
self.idcode2references = defaultdict(list)
self.reference2idcode = dict()
self.enddefinitions = False
self.id2stats = dict() # Maps id to its accumulated
statistics

def textstats(self):
total, updown, uponly, downonly = 0,0,0,0
total_transistions = 0
out = []
for ref in sorted(self.reference2idcode.keys()):
id = self.reference2idcode[ref]
stats = self.id2stats[id]
if stats.size == 1 :
total +=1
total_transistions = total_transistions +
stats.transistions
if stats.zero2one and stats.one2zero:
updown +=1
covered = 'PASS'
elif stats.zero2one:
uponly +=1
covered = 'FAIL0'
elif stats.one2zero:
downonly +=1
covered = 'FAIL1'
else:
covered = 'FAIL10'
out.append( " %-50s %s" % ( '"'+".".join(x[1] for x
in ref)+'":', (covered, stats.zero2one, stats.one2zero)) )
else:
total += stats.size
for count, (one2zero, zero2one, transistions) in
enumerate(izip(stats.one2zero, stats.zero2one, stats.transistions)) :
total_transistions = total_transistions +
transistions
if zero2one and one2zero:
updown +=1
covered = 'PASS'
elif zero2one:
uponly +=1
covered = 'FAIL0'
elif stats.one2zero:
downonly +=1
covered = 'FAIL1'
else:
covered = 'FAIL10'
name = ".".join( x[1] for x in (ref+
(('BIT:','<'+str(count)+'>'),)) )
out.append( " %-50s %s" % ( '"'+name+'":',
(covered, zero2one, one2zero)) )
header = "# TOGGLE REPORT: %g %%, %i / %i covered. %i up-only,
%i down-only." % (
updown/1.0/total*100, updown, total, uponly, downonly )
body = "toggle={\n" + "\n".join(out) + '\n }'
trans = []
trans.append( " \"transistion_count
\": (%d)" % ( total_transistions) )
trans_count = "total_transistions={\n" + "\n".join(trans) +
'\n }'
return header, body, trans_count

def scaler_value_change(self, value, id):
if value in '01' :
stats = self.id2stats[id]
if not stats.value:
stats.value = value
elif stats.value != value:
stats.value = value
stats.transistions = stats.transistions + 1;
if value == '0':
stats.one2zero +=1
else:
stats.zero2one +=1

def vector_value_change(self, format, number, id):
if format == 'b':
stats = self.id2stats[id]
extend = stats.size - len(number)
if extend:
number = ('0' if number[0] == '1' else
number[0])*extend + number
newdigit, newone2zero, newzero2one, newtransistions = [],
[],[],[]
for digit, olddigit, one2zero, zero2one, transistions in
izip(number,

stats.value,

stats.one2zero,

stats.zero2one,

stats.transistions) :
if digit in '01' and olddigit and olddigit != digit:
transistions = transistions + 1;
if digit == '0':
one2zero +=1
else:
zero2one +=1
elif digit not in '01':
digit = olddigit
newdigit.append(digit)
newone2zero.append(one2zero)
newzero2one.append(zero2one)
newtransistions.append(transistions)
stats.value, stats.one2zero, stats.zero2one,
stats.transistions = newdigit, newone2zero, newzero2one,
newtransistions


class IdStats(object):
def __init__(self, size):
size = int(size)
self.size = size
if size == 1 :
self.value = ''
self.zero2one = 0
self.one2zero = 0
self.transistions = 0
else :
# stats for each bit
self.value = ['' for x in range(size)]
self.zero2one = [0 for x in range(size)]
self.one2zero = [0 for x in range(size)]
self.transistions = [0 for x in range(size)]
def __repr__(self):
return "<IdStats: " + repr((self.size, self.value,
self.zero2one, self.one2zero, self.transistions)) + ">"


vcd = VCD()

def parse_error(tokeniser, keyword):
raise "Don't understand keyword: " + keyword

def drop_declaration(tokeniser, keyword):
dropwhile(lambda x: x != "$end", tokeniser).next()

def save_declaration(tokeniser, keyword):
vcd.__setattr__(keyword.lstrip('$'),
" ".join( takewhile(lambda x: x != "$end",
tokeniser)) )
vcd_date = save_declaration
vcd_timescale = save_declaration
vcd_version = save_declaration

def vcd_enddefinitions(tokeniser, keyword):
vcd.enddefinitions = True
drop_declaration(tokeniser, keyword)
def vcd_scope(tokeniser, keyword):
vcd.scope.append( tuple(takewhile(lambda x: x != "$end",
tokeniser)))
def vcd_upscope(tokeniser, keyword):
vcd.scope.pop()
tokeniser.next()
def vcd_var(tokeniser, keyword):
# var_type, size, identifier_code, reference =


tuple(takewhile(lambda x: x != "$end", tokeniser))
var_options = tuple(takewhile(lambda x: x != "$end", tokeniser))
if len(var_options) == 4 :
var_type, size, identifier_code, reference = var_options;
else :
var_type, size, identifier_code, reference, bus_size =
var_options;
reference = vcd.scope + [('var', reference)]
vcd.idcode2references[identifier_code].append( (var_type, size,
reference))
vcd.reference2idcode[tuple(reference)] = identifier_code
vcd.id2stats[identifier_code] = IdStats(size)

def vcd_dumpall(tokeniser, keyword): pass
def vcd_dumpoff(tokeniser, keyword): pass
def vcd_dumpon(tokeniser, keyword): pass
def vcd_dumpvars(tokeniser, keyword): pass
def vcd_end(tokeniser, keyword):
if not vcd.enddefinitions:
parse_error(tokeniser, keyword)


keyword2handler = {
# declaration_keyword ::=
"$comment": drop_declaration,
"$date": vcd_date,
"$enddefinitions": vcd_enddefinitions,
"$scope": vcd_scope,
"$timescale": vcd_timescale,
"$upscope": vcd_upscope,
"$var": vcd_var,
"$version": vcd_version,
# simulation_keyword ::=
"$dumpall": vcd_dumpall,
"$dumpoff": vcd_dumpoff,
"$dumpon": vcd_dumpon,
"$dumpvars": vcd_dumpvars,
"$end": vcd_end,
}
keyword2handler = defaultdict(parse_error, keyword2handler)

def vcd_toggle_count(vcdfile):
fp = open(vcdfile)
tokeniser = (word for line in fp for word in line.split() if word)
for count,token in enumerate(tokeniser):
if not vcd.enddefinitions:
# definition section
if token != '$var':
print token
keyword2handler[token](tokeniser, token)
else:
if count % 10000 == 0:
print count, "\r",
c, rest = token[0], token[1:]
if c == '$':
# skip $dump* tokens and $end tokens in sim section
continue
elif c == '#':
vcd.now = rest
elif c in '01xXzZ':
vcd.scaler_value_change(value=c, id=rest)
elif c in 'bBrR':
vcd.vector_value_change(format=c.lower(), number=rest,
id=tokeniser.next())
else:
raise "Don't understand: %s After %i words" % (token,
count)
print count
fp.close()

vcd_toggle_count(vcdfile)
header, body, transistion_count = vcd.textstats()
print '\n'+header+'\n\n'+body+'\n\n'+transistion_count+'\n'

Message has been deleted
Message has been deleted

artemis...@gmail.com

unread,
Sep 21, 2018, 10:00:16 AM9/21/18
to
Hi Paddy,

Thanks for sharing your script and your experience. when I ran the python file, the following result is appeared for all the wires which shows that the script is not work well for my vcd files because there are lots of zero2one and one2zero for each wire, but the covered value is equal to FAIL10 for all of them. Could you please tell me what is the exact problem?

"TOP.chip_top.Rocket.ioNetwork.ClientTileLinkNetworkPort.io_network_grant_bits_payload_manager_xact_id": ('FAIL10', 0, 0)

Sincerely,
Artemis
0 new messages