GHDL support added.

Output signal is calculated by parsing VCD file
parent 07f49352
# This is a manual translation, from perl to python, of :
# http://cpansearch.perl.org/src/GSULLIVAN/Verilog-VCD-0.03/lib/Verilog/VCD.pm
import re
global timescale
global endtime
def croak(*args):
"""Function similar to Perl's Carp::croak, to simplify porting this code"""
a = "".join(args);
raise Exception(a)
def list_sigs(file) :
"""Parse input VCD file into data structure,
then return just a list of the signal names."""
vcd = parse_vcd(file, only_sigs=1)
sigs = []
for k,v in vcd:
nets = v['nets']
sigs.extend( n['hier']+n['name'] for n in nets )
return sigs
def parse_vcd(file, only_sigs=0, use_stdout=0, siglist=[], opt_timescale=''):
"""Parse input VCD file into data structure.
Also, print t-v pairs to STDOUT, if requested."""
usigs = {}
for i in siglist:
usigs[i] = 1
if len(usigs):
all_sigs = 0
else :
all_sigs = 1
data = {}
mult = 0
num_sigs = 0
hier = []
time = 0
re_time = re.compile(r"^#(\d+)")
re_1b_val = re.compile(r"^([01zx])(.+)")
re_Nb_val = re.compile(r"^[br](\S+)\s+(.+)")
fh = open(file, 'r')
while True:
line = fh.readline()
if line == '' : # EOF
break
# chomp
# s/ ^ \s+ //x
line = line.strip()
if "$enddefinitions" in line:
num_sigs = len(data)
if (num_sigs == 0) :
if (all_sigs) :
croak("Error: No signals were found in the VCD file file.",
'Check the VCD file for proper var syntax.')
else :
croak("Error: No matching signals were found in the VCD file file.",
' Use list_sigs to view all signals in the VCD file.')
if ((num_sigs>1) and use_stdout) :
croak("Error: There are too many signals (num_sigs) for output ",
'to STDOUT. Use list_sigs to select a single signal.')
if only_sigs:
break
elif "$timescale" in line:
statement = line
if not "$end" in line:
while fh :
line = fh.readline()
statement += line
if "$end" in line:
break
mult = calc_mult(statement, opt_timescale)
elif "$scope" in line:
# assumes all on one line
# $scope module dff end
hier.append( line.split()[2] ) # just keep scope name
elif "$upscope" in line:
hier.pop()
elif "$var" in line:
# assumes all on one line:
# $var reg 1 *@ data $end
# $var wire 4 ) addr [3:0] $end
ls = line.split()
type = ls[1]
size = ls[2]
code = ls[3]
name = "".join(ls[4:-1])
path = '.'.join(hier)
full_name = path + name
if (full_name in usigs) or all_sigs :
if code not in data :
data[code] = {}
if 'nets' not in data[code]:
data[code]['nets'] = []
var_struct = {
'type' : type,
'name' : name,
'size' : size,
'hier' : path,
}
if var_struct not in data[code]['nets']:
data[code]['nets'].append( var_struct )
elif line.startswith('#'):
re_time_match = re_time.match(line)
time = mult * int(re_time_match.group(1))
endtime = time
elif line.startswith(('0', '1', 'x', 'z', 'b', 'r')):
re_1b_val_match = re_1b_val.match(line)
re_Nb_val_match = re_Nb_val.match(line)
if re_Nb_val_match :
value = re_Nb_val_match.group(1)
code = re_Nb_val_match.group(2)
elif re_1b_val_match :
value = re_1b_val_match.group(1)
code = re_1b_val_match.group(2)
if (code in data) :
if (use_stdout) :
print(time, value)
else :
if 'tv' not in data[code]:
data[code]['tv'] = []
data[code]['tv'].append( (time, value) )
fh.close()
return data
def calc_mult (statement, opt_timescale=''):
"""
Calculate a new multiplier for time values.
Input statement is complete timescale, for example:
timescale 10ns end
Input new_units is one of s|ms|us|ns|ps|fs.
Return numeric multiplier.
Also sets the package timescale variable.
"""
fields = statement.split()
fields.pop() # delete end from array
fields.pop(0) # delete timescale from array
tscale = ''.join(fields)
new_units = ''
if (opt_timescale != ''):
new_units = opt_timescale.lower()
new_units = re.sub(r"\s", '', new_units)
timescale = "1"+new_units
else :
timescale = tscale
return 1
mult = 0
units = 0
ts_match = re.compile(r"(\d+)([a-z]+)")
if ts_match.match(tscale):
mult = ts_match.group(1)
units = ts_match.group(2).lower()
else :
croak("Error: Unsupported timescale found in VCD file: tscale. ",
'Refer to the Verilog LRM.')
mults = {
'fs' : 1e-15,
'ps' : 1e-12,
'ns' : 1e-09,
'us' : 1e-06,
'ms' : 1e-03,
's' : 1e-00,
}
mults_keys = keys(mults)
mults_keys.sort(key=lambda x : mults[x])
usage = '|'.join(mults_keys)
scale = 0
if units in mults :
scale = mults[units]
else :
croak("Error: Unsupported timescale units found in VCD file: "+units+". ",
"Supported values are: "+usage)
new_scale = 0
if new_units in mults :
new_scale = mults[new_units]
else :
croak("Error: Illegal user-supplied timescale: "+new_units+". ",
"Legal values are: "+usage)
return ((mult * scale) / new_scale)
def get_timescale() :
return timescale
def get_endtime() :
return endtime
# =head1 NAME
#
# Verilog_VCD - Parse a Verilog VCD text file
#
# =head1 VERSION
#
# This document refers to Verilog::VCD version 0.03.
#
# =head1 SYNOPSIS
#
# from Verilog_VCD import parse_vcd
# vcd = parse_vcd('/path/to/some.vcd')
#
# =head1 DESCRIPTION
#
# Verilog is a Hardware Description Language (HDL) used to model digital logic.
# While simulating logic circuits, the values of signals can be written out to
# a Value Change Dump (VCD) file. This module can be used to parse a VCD file
# so that further analysis can be performed on the simulation data. The entire
# VCD file can be stored in a python data structure and manipulated using
# standard hash and array operations.
#
# =head2 Input File Syntax
#
# The syntax of the VCD text file is described in the documentation of
# the IEEE standard for Verilog. Only the four-state VCD format is supported.
# The extended VCD format (with strength information) is not supported.
# Since the input file is assumed to be legal VCD syntax, only minimal
# validation is performed.
#
# =head1 SUBROUTINES
#
#
# =head2 parse_vcd(file, $opt_ref)
#
# Parse a VCD file and return a reference to a data structure which
# includes hierarchical signal definitions and time-value data for all
# the specified signals. A file name is required. By default, all
# signals in the VCD file are included, and times are in units
# specified by the C<$timescale> VCD keyword.
#
# vcd = parse_vcd('/path/to/some.vcd')
#
# It returns a reference to a nested data structure. The top of the
# structure is a Hash-of-Hashes. The keys to the top hash are the VCD
# identifier codes for each signal. The following is an example
# representation of a very simple VCD file. It shows one signal named
# C<chip.cpu.alu.clk>, whose VCD code is C<+>. The time-value pairs
# are stored as an Array-of-Tuples, referenced by the C<tv> key. The
# time is always the first number in the pair, and the times are stored in
# increasing order in the array.
#
# {
# '+' : {
# 'tv' : [
# (
# 0,
# '1'
# ),
# (
# 12,
# '0'
# ),
# ],
# 'nets' : [
# {
# 'hier' : 'chip.cpu.alu.',
# 'name' : 'clk',
# 'type' : 'reg',
# 'size' : '1'
# }
# ]
# }
# }
#
# Since each code could have multiple hierarchical signal names, the names are
# stored as an Array-of-Hashes, referenced by the C<nets> key. The example above
# only shows one signal name for the code.
#
#
# =head3 OPTIONS
#
# Options to C<parse_vcd> should be passed as a hash reference.
#
# =over 4
#
# =item timescale
#
# It is possible to scale all times in the VCD file to a desired timescale.
# To specify a certain timescale, such as nanoseconds:
#
# vcd = parse_vcd(file, opt_timescale='ns'})
#
# Valid timescales are:
#
# s ms us ns ps fs
#
# =item siglist
#
# If only a subset of the signals included in the VCD file are needed,
# they can be specified by a signal list passed as an array reference.
# The signals should be full hierarchical paths separated by the dot
# character. For example:
#
# signals = [
# 'top.chip.clk',
# 'top.chip.cpu.alu.status',
# 'top.chip.cpu.alu.sum[15:0]',
# ]
# vcd = parse_vcd(file, siglist=signals)
#
# Limiting the number of signals can substantially reduce memory usage of the
# returned data structure because only the time-value data for the selected
# signals is loaded into the data structure.
#
# =item use_stdout
#
# It is possible to print time-value pairs directly to STDOUT for a
# single signal using the C<use_stdout> option. If the VCD file has
# more than one signal, the C<siglist> option must also be used, and there
# must only be one signal specified. For example:
#
# vcd = parse_vcd(file,
# use_stdout=1,
# siglist=['top.clk']
# )
#
# The time-value pairs are output as space-separated tokens, one per line.
# For example:
#
# 0 x
# 15 0
# 277 1
# 500 0
#
# Times are listed in the first column.
# Times units can be controlled by the C<timescale> option.
#
# =item only_sigs
#
# Parse a VCD file and return a reference to a data structure which
# includes only the hierarchical signal definitions. Parsing stops once
# all signals have been found. Therefore, no time-value data are
# included in the returned data structure. This is useful for
# analyzing signals and hierarchies.
#
# vcd = parse_vcd(file, only_sigs=1)
#
# =back
#
#
# =head2 list_sigs(file)
#
# Parse a VCD file and return a list of all signals in the VCD file.
# Parsing stops once all signals have been found. This is
# helpful for deciding how to limit what signals are parsed.
#
# Here is an example:
#
# signals = list_sigs('input.vcd')
#
# The signals are full hierarchical paths separated by the dot character
#
# top.chip.cpu.alu.status
# top.chip.cpu.alu.sum[15:0]
#
# =head2 get_timescale( )
#
# This returns a string corresponding to the timescale as specified
# by the C<$timescale> VCD keyword. It returns the timescale for
# the last VCD file parsed. If called before a file is parsed, it
# returns an undefined value. If the C<parse_vcd> C<timescale> option
# was used to specify a timescale, the specified value will be returned
# instead of what is in the VCD file.
#
# vcd = parse_vcd(file); # Parse a file first
# ts = get_timescale(); # Then query the timescale
#
# =head2 get_endtime( )
#
# This returns the last time found in the VCD file, scaled
# appropriately. It returns the last time for the last VCD file parsed.
# If called before a file is parsed, it returns an undefined value.
#
# vcd = parse_vcd(file); # Parse a file first
# et = get_endtime(); # Then query the endtime
#
# =head1 EXPORT
#
# Nothing is exported by default. Functions may be exported individually, or
# all functions may be exported at once, using the special tag C<:all>.
#
# =head1 DIAGNOSTICS
#
# Error conditions cause the program to raise an Exception.
#
# =head1 LIMITATIONS
#
# Only the following VCD keywords are parsed:
#
# $end $scope
# $enddefinitions $upscope
# $timescale $var
#
# The extended VCD format (with strength information) is not supported.
#
# The default mode of C<parse_vcd> is to load the entire VCD file into the
# data structure. This could be a problem for huge VCD files. The best solution
# to any memory problem is to plan ahead and keep VCD files as small as possible.
# When simulating, dump fewer signals and scopes, and use shorter dumping
# time ranges. Another technique is to parse only a small list of signals
# using the C<siglist> option; this method only loads the desired signals into
# the data structure. Finally, the C<use_stdout> option will parse the input VCD
# file line-by-line, instead of loading it into the data structure, and directly
# prints time-value data to STDOUT. The drawback is that this only applies to
# one signal.
#
# =head1 BUGS
#
# There are no known bugs in this module.
#
# =head1 SEE ALSO
#
# Refer to the following Verilog documentation:
#
# IEEE Standard for Verilog (c) Hardware Description Language
# IEEE Std 1364-2005
# Section 18.2, "Format of four-state VCD file"
#
# =head1 AUTHOR
#
# Originally written in Perl by Gene Sullivan (gsullivan@cpan.org)
# Translated into Python by Sameer Gauria (sgauria+python@gmail.com)
#
# =head1 COPYRIGHT AND LICENSE
#
# Copyright (c) 2012 Gene Sullivan, Sameer Gauria. All rights reserved.
#
# This module is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself. See L<perlartistic|perlartistic>.
#
# =cut
......@@ -407,13 +407,13 @@ class Filter():
warnings.simplefilter('error')
try:
self.b, self.a = self.calculate_filter_coefficients()
except ValueError, exVE:
except ValueError as exVE:
warningMessage = '%s' % exVE
except ZeroDivisionError, exZDE:
except ZeroDivisionError as exZDE:
warningMessage = '%s' % exZDE
except RuntimeWarning, exRW:
except RuntimeWarning as exRW:
warningMessage = '%s' % exRW
except signal.BadCoefficients, exBC:
except signal.BadCoefficients as exBC:
warningMessage = '%s' % exBC
if warningMessage != '':
......@@ -487,12 +487,12 @@ class Filter():
labelFilterStructure = QLabel('Structure:')
self.comboFilterStructure = QComboBox()
self.comboFilterStructure.addItem("Direct Form I Transposed")
self.comboFilterStructure.addItem("Direct Form II Transposed")
self.comboFilterStructure.addItem("Direct Form I")
self.comboFilterStructure.addItem("Direct_Form_I_Transposed")
self.comboFilterStructure.addItem("Direct_Form_II_Transposed")
self.comboFilterStructure.addItem("Direct_Form_I")
self.comboFilterStructure.addItem("Parallel")
self.comboFilterStructure.addItem("Cascade")
self.comboFilterStructure.addItem("Direct Form II")
self.comboFilterStructure.addItem("Direct_Form_II")
self.comboFilterStructure.setEditable(True)
self.comboFilterStructure.lineEdit().setReadOnly(True)
self.comboFilterStructure.lineEdit().setAlignment(Qt.AlignRight)
......@@ -514,7 +514,7 @@ class Filter():
self.comboFilterOverflow.setItemData(ii, Qt.AlignRight, Qt.TextAlignmentRole)
#self.connect(self.comboFilterStructure, SIGNAL('currentIndexChanged(int)'), self.on_parameter_change)
# TODO: the connected method is still provisional, it forces to DF I Transposed
self.connect(self.comboFilterStructure, SIGNAL('currentIndexChanged(int)'), self.on_overflow_change)
self.connect(self.comboFilterOverflow, SIGNAL('currentIndexChanged(int)'), self.on_overflow_change)
labelResponseType = QLabel('Filtering Method:')
......@@ -1010,10 +1010,11 @@ class Filter():
return vboxMain
def on_structure_change(self):
# TODO: provisional, check the structure change and force to DF1 Trans
activeStructure = str(self.comboFilterStructure.currentText())
if activeStructure == 'Direct Form I Transposed':
if activeStructure == 'Direct_Form_I_Transposed':
self.on_parameter_change()
else:
QMessageBox.information(self, 'Filter Structure',
......@@ -1021,6 +1022,7 @@ class Filter():
% activeStructure,
QMessageBox.Ok)
self.comboFilterStructure.setCurrentIndex(0)
def on_overflow_change(self):
# TODO: provisional, check the structure change and force to DF1 Trans
......
......@@ -45,11 +45,6 @@ import sys, os, random
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#import matplotlib
#from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
#from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
#from matplotlib.figure import Figure
class LibreFDATool(
QMainWindow,
......@@ -62,6 +57,9 @@ class LibreFDATool(
stimulusUpdatedSignal = pyqtSignal()
filterUpdatedSignal = pyqtSignal()
simulatorUpdatedSignal = pyqtSignal()
simulatorBeginSignal = pyqtSignal()
simulatorEndSignal = pyqtSignal()
def __init__(self):
QMainWindow.__init__(self)
......@@ -75,6 +73,8 @@ class LibreFDATool(
self.stimulusUpdatedSignal.connect(self.on_stimulus_updated)
self.filterUpdatedSignal.connect(self.on_filter_updated)
self.simulatorUpdatedSignal.connect(self.on_simulator_updated)
self.simulatorBeginSignal.connect(self.on_simulator_begin)
self.simulatorEndSignal.connect(self.on_simulator_end)
self.runSimulator()
......@@ -245,8 +245,9 @@ class LibreFDATool(
scalingX = 1
scalingC = 1
self.execute_simulation(self.b, self.a,
self.x, str(self.textFilterName.text()), 'vhdl',
self.execute_simulation(self.b, self.a, self.x,
str(self.textFilterName.text()), str(self.comboSimulatorLanguage.currentText()),
str(self.comboSimulatorEngine.currentText()), str(self.comboFilterStructure.currentText()),
busX, busY, busC,
scalingX, scalingC)
......@@ -275,6 +276,16 @@ class LibreFDATool(
#QMessageBox.information(self, 'Simulator Updated',
# 'This is only a message', QMessageBox.Ok)
self.status_text.setText('Simulator configuration has been updated')
def on_simulator_begin(self):
#QMessageBox.information(self, 'Simulator Begin',
# 'This is only a message', QMessageBox.Ok)
self.status_text.setText('Simulation started...')
def on_simulator_end(self):
#QMessageBox.information(self, 'Simulator End',
# 'This is only a message', QMessageBox.Ok)
self.status_text.setText('Simulation ended!!')
def main():
app = QApplication(sys.argv)
......
......@@ -111,11 +111,11 @@ def analyze_pole_zero(figure, b, a, p, q, grid):
p2 = np.roots(a2)
z2 = np.roots(b2)
except ValueError, exVE:
except ValueError as exVE:
warningMessage = '%s' % exVE
except ZeroDivisionError, exZDE:
except ZeroDivisionError as exZDE:
warningMessage = '%s' % exZDE
except RuntimeWarning, exRW:
except RuntimeWarning as exRW:
warningMessage = '%s' % exRW
if warningMessage != '':
......@@ -192,11 +192,11 @@ def analyze_frequency_response(figure, b, a, p, q, grid):
wd,hd = signal.freqz(b2,a2)
hd_dB = 20 * log10 (abs(hd))
except ValueError, exVE:
except ValueError as exVE:
warningMessage = '%s' % exVE
except ZeroDivisionError, exZDE:
except ZeroDivisionError as exZDE:
warningMessage = '%s' % exZDE
except RuntimeWarning, exRW:
except RuntimeWarning as exRW:
warningMessage = '%s' % exRW
......
......@@ -24,6 +24,8 @@ from scipy import signal
from bitstring import BitArray
from Verilog_VCD import *
from snippets import *
......@@ -33,12 +35,21 @@ class Simcore:
'''
def simfilter(self, b, a, x,
structure, model,
structure, language,
engine, name,
busX, busY, busC,
scalingX, scalingC):
self.name = name
self.structure = structure
self.model = model
self.language = language
self.engine = engine
#TODO: debugging prints
print('structure', structure)
print('language', language)
print('engine', engine)
print('name', name)
self.busX = busX
self.busY = busY
......@@ -73,7 +84,7 @@ class Simcore:
self._generateDUT()
self._generateTB(x)
return self._simulation()
return self._simulation(x)
#***********************************************#
......@@ -83,7 +94,6 @@ class Simcore:
def _generateDUT(self):
# All the products has an extra integer (the 2^1 factor)
# A fixed point number is comprised by integer (P) and fractional bits (Q)
# When you calculate the C product of A and B, then => PC = PA + PB; QC = QA + QB;
......@@ -112,11 +122,10 @@ class Simcore:
hdl = snippets()
if self.model == 'vhdl':
if self.language == 'VHDL':
structure = self.structure
name = self.structure
realization='direct_form_1_transposed'
name = self.name
# Code generation for a Transposed Direct Form FIR
hdlFile = open('{!s}.vhd'.format(name),'w')
......@@ -127,62 +136,27 @@ class Simcore:
hdlFile.write(hdl.entity(name, busX, busY))
hdlFile.write('\n')
hdlFile.write(hdl.architectureHeader(name, realization))
hdlFile.write(hdl.architectureHeader(name, structure))
hdlFile.write('\n')
# *** DECLARE INTERNAL SIGNALS ***
if realization == 'direct_form_1_transposed':
hdlFile.write("-- Z^-1 delay blocks\n")
# Z blocks in the b coefficients side
for ii in range(self.M-1):
hdlFile.write('signal zb{!s}, zb{!s}_next: signed({!s} downto 0);\n'.format(ii, ii, busX + busC -1 -1))
hdlFile.write("\n")
# Z blocks in the a coefficients side
for ii in range(self.N-1):
if ii != 0:
hdlFile.write('signal za{!s}, za{!s}_next: signed({!s} downto 0);\n'.format(ii, ii, busX + busC -1 -1))
else:
hdlFile.write('signal za{!s}, za{!s}_next: signed({!s} downto 0);\n'.format(ii, ii, busX -1))
hdlFile.write("\n")
hdlFile.write(hdl.signalZ(self.M, self.N, busX, busY, busC, structure))
hdlFile.write('\n')
hdlFile.write("-- Filter constants\n")
for ii in range(self.M):
hdlFile.write('signal b{!s}: signed({!s} downto 0); \n'.format(ii, busC -1))
hdlFile.write("\n")
for ii in range(self.N):
if ii != 0:
hdlFile.write('signal a{!s}: signed({!s} downto 0); \n'.format(ii, busC -1))
hdlFile.write("\n")
hdlFile.write("-- Filter Adders\n")
for ii in range(self.M-1):
hdlFile.write('signal sb{!s}: signed({!s} downto 0);\n'.format(ii, busX + busC -1 -1))
hdlFile.write("\n")
for ii in range(self.N-1):
if ii != 0:
hdlFile.write('signal sa{!s}: signed({!s} downto 0);\n'.format(ii, busX + busC -1 -1))
else:
hdlFile.write('signal sa{!s}: signed({!s} downto 0);\n'.format(ii, busX -1))
hdlFile.write("\n")
hdlFile.write(hdl.signalC(self.M, self.N, busC, structure))
hdlFile.write('\n')
hdlFile.write("-- Filter Products\n")
for ii in range(self.M):
hdlFile.write('signal pb{!s}: signed({!s} downto 0);\n'.format(ii, busX + busC -1 -1))
hdlFile.write("\n")
for ii in range(self.N):
if ii != 0:
hdlFile.write('signal pa{!s}: signed({!s} downto 0);\n'.format(ii, busX + busC -1 -1))
hdlFile.write("\n")
hdlFile.write(hdl.signalAdders(self.M, self.N, busX, busY, busC, structure))
hdlFile.write('\n')
hdlFile.write(hdl.signalProducts(self.M, self.N, busX, busY, busC, structure))
hdlFile.write('\n')
# Intermediate signal for df1: assume that the width is the same that in x!
# NOTE: we have set v as equal to X, but this may lead to overflow troubles!!!!!!
hdlFile.write('signal v: signed({!s} downto 0);\n\n'.format(busX -1))
hdlFile.write(hdl.signalFeedback(self.M, self.N, busX, busY, busC, structure))
hdlFile.write('\n')
hdlFile.write("-- Begin Architecture\n")
hdlFile.write("begin\n\n")
......@@ -193,81 +167,34 @@ class Simcore:
hdlFile.write('-- Arithmetics\n')
hdlFile.write("\n")
# Coefficients
for ii in range(self.M):
hdlFile.write('b{!s} <= \"{!s}\"; -- {!s}\n'.format(ii, self.icoefB[ii], self.coefB[ii]))
hdlFile.write(hdl.assignCoeff(M, N, self.icoefB, self.coefB,
self.icoefA, self.coefA, structure))
hdlFile.write("\n")
for ii in range(self.N):
if ii != 0:
hdlFile.write('a{!s} <= \"{!s}\"; -- {!s}\n'.format(ii, self.icoefA[ii], self.coefA[ii]))
hdlFile.write("\n")
# Products
for ii in range(self.M):
hdlFile.write('pb{!s} <= v * b{!s};\n'.format(ii, ii))
hdlFile.write("\n")
for ii in range(self.N):
if ii != 0:
hdlFile.write('pa{!s} <= v * a{!s};\n'.format(ii, ii))
hdlFile.write("\n")
hdlFile.write(hdl.arithProduct(M, N,
busX, busY, busC,
structure))
hdlFile.write("\n")
# Sums
for ii in range(self.M-1):
hdlFile.write('sb{!s} <= pb{!s} + zb{!s};\n'.format(ii, ii, ii))
hdlFile.write("\n\n")
for ii in range(self.N-1):
if ii == 0:
hdlFile.write('sa{!s} <= sig_in + za{!s};\n'.format(ii, ii))
else:
hdlFile.write('sa{!s} <= pa{!s} + za{!s};\n'.format(ii, ii, ii))
hdlFile.write("\n\n")
hdlFile.write(hdl.arithAdders(M, N, structure))
hdlFile.write("\n")
hdlFile.write('-- Signal link, trunk, overflow, fixed point...\n')
for ii in range(self.M):
if ii == 0:
# Why always is a Zero as MSB in si? --> this is because the input is always a positive number?????
if self.M == 1:
hdlFile.write(hdl.convertFixedPoint('pb{!s}'.format(ii), self.busC[0] + self.busX[0] -1, self.busC[1] + self.busX[1], 'sig_out', self.busY[0], self.busY[1]))
else:
hdlFile.write(hdl.convertFixedPoint('sb{!s}'.format(ii), self.busC[0] + self.busX[0] -1, self.busC[1] + self.busX[1], 'sig_out', self.busY[0], self.busY[1]))
elif ii == (self.M-1):
hdlFile.write('zb{!s}_next <= pb{!s};\n'.format(ii-1, ii))
else:
hdlFile.write('zb{!s}_next <= sb{!s};\n'.format(ii-1, ii))
hdlFile.write(hdl.connectBlocks(M, N,
self.busX, self.busY, self.busC,
structure))
hdlFile.write('\n')
for ii in range(self.N):
if ii == 0:
# Why always is a Zero as MSB in si? --> this is because the input is always a positive number?????
if self.N == 1:
hdlFile.write('v <= sig_in;\n')
else:
hdlFile.write('v <= sa0;\n')
elif ii == 1:
if ii != (self.N-1):
hdlFile.write(hdl.convertFixedPoint('sa{!s}'.format(ii), self.busC[0] + self.busX[0] -1, self.busC[1] + self.busX[1], 'za{!s}_next'.format(ii-1), self.busX[0], self.busX[1]))
else:
hdlFile.write(hdl.convertFixedPoint('pa{!s}'.format(ii), self.busC[0] + self.busX[0] -1, self.busC[1] + self.busX[1], 'za{!s}_next'.format(ii-1), self.busX[0], self.busX[1]))
elif ii == (self.N-1):
hdlFile.write('za{!s}_next <= pa{!s};\n'.format(ii-1, ii))
else:
hdlFile.write('za{!s}_next <= sa{!s};\n'.format(ii-1, ii))
hdlFile.write("\n\n")
hdlFile.write('end {!s};\n'.format(realization))
hdlFile.write('end {!s};\n'.format(structure))
hdlFile.close()
elif self.model == 'verilog':
elif self.language == 'Verilog':
structure = self.structure
realization='direct_form_transposed'
# Verilog Code generation for a Transposed Direct Form FIR
hdlFile = open('{!s}.v'.format(structure),'w')
......@@ -323,7 +250,7 @@ class Simcore:
hdlFile.write("\n")
hdlFile.write("always @(posedge clk) begin: {!s}\n".format(realization))
hdlFile.write("always @(posedge clk) begin: {!s}\n".format(structure))
hdlFile.write(" if (rst == 1'b1) begin\n")
for ii in range(self.M-1):
hdlFile.write(' z[{!s}] <= 0;\n'.format(ii))
......@@ -365,7 +292,7 @@ class Simcore:
else:
print("Error: simulation mode not recognized\n");
print("Error: simulation language not recognized\n");
return 0
......@@ -373,76 +300,36 @@ class Simcore:
def _generateTB(self, x):
#if self.language == 'vhdl':
# TBD: the process of input signal and output value parse
# must be aligned and configurable
# This Verilog file is common for verilog and vhdl DUTs in IVerilog
# If we want to add support for more simulators, then would be necessary VHDL
# Code generation for the testbench - myhdl link
hdl = snippets()
busX = self.busX[0] + self.busX[1]
busY = self.busY[0] + self.busY[1]
busC = self.busC[0] + self.busC[1]
structure = self.structure
tbFile = open('tb_{!s}.v'.format(structure),'w')
tbFile.write("module tb_{!s};\n".format(structure))
tbFile.write("\n")
tbFile.write("reg clk;\n")
tbFile.write("reg rst;\n")
tbFile.write("reg [{!s}:0] sig_in;\n".format(busX-1))
tbFile.write("wire [{!s}:0] sig_out;\n".format(busY-1))
tbFile.write("\n")
tbFile.write("{!s} dut(\n".format(structure))
tbFile.write(" clk,\n")
tbFile.write(" rst,\n")
tbFile.write(" sig_in,\n")
tbFile.write(" sig_out\n")
tbFile.write(");\n")
tbFile.write("\n")
clockPosWidth = 25
clockNegWidth = 25
tbFile.write("always begin\n")
tbFile.write(" clk <= 1;\n")
tbFile.write(" #{!s};\n".format(clockNegWidth))
tbFile.write(" clk <= 0;\n")
tbFile.write(" $display(\"%d, %b, %b\", $time, sig_in, sig_out);\n")
tbFile.write(" #{!s};\n".format(clockPosWidth))
tbFile.write("end\n")
tbFile.write("\n")
tbFile.write("\n")
tbFile.write("\n")
tbFile.write("\n")
tbFile.write("initial begin\n")
tbFile.write(" $dumpfile(\"{!s}.vcd\");\n".format(structure))
tbFile.write(" $dumpvars;\n")
tbFile.write("end\n")
tbFile.write("\n")
tbFile.write("initial begin\n")
tbFile.write(' sig_in <= {!s}\'b{!s}; // signal is initially zero\n'.format(busX, 0))
tbFile.write(" rst <= 1'b1; #100;\n")
tbFile.write(" rst <= 1'b0; #150;\n")
xb = self._quantizer(x, self.busX, staircase='midtread')
for ii in range(len(x)):
tbFile.write(' #50; sig_in <= {!s}\'b{!s}; // {!s}\n'.format(busX, xb[ii], x[ii]))
tbFile.write(" $finish;\n")
tbFile.write("end\n")
tbFile.write("\n")
busX = self.busX[0] + self.busX[1]
busY = self.busY[0] + self.busY[1]
name = self.name
xb = self._quantizer(x, self.busX, staircase='midtread')
if self.engine == 'Icarus Verilog':
tbFile.write("\n")
tbFile.write("endmodule\n\n")
tbFile = open('tb_{!s}.v'.format(name),'w')
tbFile.write(hdl.verilogTestBench(name, xb, x, busX, busY))
tbFile.close()
elif self.engine == 'GHDL':
tbFile = open('tb_{!s}.vhd'.format(name),'w')
tbFile.write(hdl.vhdlTestBench(name, xb, x, busX, busY))
tbFile.close()
def _quantizer(self, signal, bus, xm=1, staircase= 'midtread'):
......@@ -457,18 +344,18 @@ class Simcore:
B = bus[1] + bus[0] - 1
# Generate an
if staircase == 'midtread':
delta = 1/2
delta = 0.5
elif staircase == 'midriser':
delta = 0
else:
print("Staircase model for quantizer unknown: using default")
delta = 1/2
delta = 0.5
# Convert the normalized signal to a integer value
signalInt = np.floor(signalNorm*(2**(bus[1])) + delta)
signalScaled = signalNorm*(2**(bus[1])) + delta
signalInt = np.floor(signalScaled)
# Trunk if the integers cannot be represented using the bus width
# Then assign the correspondent binary code
......@@ -479,77 +366,136 @@ class Simcore:
elif signalInt[ii] < (-1 * 2**B):
signalInt[ii] = -1 * 2**B
xBinary.append(np.binary_repr(int(signalInt[ii]), width=B+1))
return xBinary
def _simulation(self, simulator='iverilog'):
def _simulation(self, stimulus):
structure = self.structure
name = self.name
totalSamples = len(stimulus)
timeStep = 50
if self.model == 'verilog':
if self.language == 'Verilog':
dutExtension = 'v'
elif self.model == 'vhdl':
elif self.language == 'VHDL':
dutExtension = 'vhd'
else:
print('Unknown model: assuming verilog')
dutExtension = 'v'
print('TESTPOINT_1')
print('Cosimulation...')
print('TEST iverilog -o {!s} {!s}.{!s} tb_{!s}.v'.format(structure, structure, dutExtension, structure))
# Check if verilog/vhdl filter description is available TBD: make it a variable!!!!!!!!!!!!!!!!
if not os.path.isfile('{!s}.vhd'.format(structure)):
if not os.path.isfile('{!s}.{!s}'.format(name, dutExtension)):
print('File not found: Run generation first')
return None
# Clean design
if os.path.isfile('{!s}'.format(structure)):
if os.path.isfile('{!s}'.format(name)):
print('Existing compiled design: erase!! ')
cmd = 'rm {!s}'.format(structure)
cmd = 'rm {!s}'.format(name)
os.system(cmd)
if self.engine == 'Icarus Verilog':
# Running Icarus verilog
# ****** TBD: Set the dut file extension according with the HDL language
cmd = 'iverilog -g2012 -o {!s} {!s}.{!s} tb_{!s}.v'.format(name, name, dutExtension, name)
os.system(cmd)
# Running Icarus verilog
# ****** TBD: Set the dut file extension according with the HDL language
cmd = 'iverilog -g2012 -o {!s} {!s}.{!s} tb_{!s}.v'.format(structure, structure, dutExtension, structure)
os.system(cmd)
cmd = 'vvp {!s}'.format(structure)
cmd = 'vvp {!s}'.format(name)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
elif self.engine == 'GHDL':
#Running GHDL
stopTime = (5 + totalSamples)*timeStep
# Analyze the UUT
cmd = 'ghdl -a {!s}.vhd'.format(name)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
# Analyze the TestBench
cmd = 'ghdl -a tb_{!s}.vhd'.format(name)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
# Build an executable file
cmd = 'ghdl -e tb_{!s}'.format(name)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print('GHDL executed')
# Run the executable
cmd = 'ghdl -r tb_{!s} --vcd={!s}.vcd --stop-time={!s}ns'.format(name, name, stopTime)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print('GHDL runned')
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
reportFile = open('{!s}_report.txt'.format(structure),'wb')
reportFile.write(out)
reportFile.close()
#print("program output: {!s}".format(out))
print('TESTPOINT_4')
parsedOutput = []
with open('{!s}_report.txt'.format(structure),'r') as csvfile:
csvString = csv.reader(csvfile, delimiter=',', quotechar='|', skipinitialspace=True)
ii = 0
for row in csvString:
# Only the lines with three fields qualifies
if len(row) == 3:
# Only the values beyond a time are considered valids samples
# Note that init and reset values must be neglected
if int(row[0]) > 250:
a = BitArray(bin=row[2])
#print(a.int)
parsedOutput.append(a.int/float(2**(self.busY[1]) ))
ii = ii + 1
# The fixed point format for Y is calculated in an automatic fashion!!!
connect_sample_out = np.zeros(len(parsedOutput))
for ii in range(len(parsedOutput)):
connect_sample_out[ii] = parsedOutput[ii]
# *****************************************************************************
#vcdDebug = parse_vcd('{!s}.vcd'.format(name),
# only_sigs=1
# )
#print(vcdDebug)
if self.engine == 'Icarus Verilog':
topName = 'tb_{!s}'.format(name)
timeScale = 1
elif self.engine == 'GHDL':
topName = 'uut'
timeScale = 1000000
print('Parsing VCD')
vcd = parse_vcd('{!s}.vcd'.format(name),
#use_stdout=1,
siglist=['{!s}sig_out[{!s}:0]'.format(
topName, self.busY[0] + self.busY[1] - 1)]
)
for key in sorted(vcd):
vcdKey = key
print('Parsed VCD')
print(vcd[vcdKey]['tv'])
vcdParsedOutput = []
#vcdBinaryOutput = []
outCurrentTime = 0
vcdCurrentValue = vcd[vcdKey]['tv'][0][1]
binOffset = self.busY[0] + self.busY[1] - len(vcdCurrentValue)
for jj in range(binOffset):
vcdCurrentValue = '0' + vcdCurrentValue
for ii in range(len(vcd[vcdKey]['tv'])):
vcdNextTime = vcd[vcdKey]['tv'][ii][0]
vcdNextTime = vcdNextTime/timeScale
vcdNextValue = vcd[vcdKey]['tv'][ii][1]
while vcdNextTime > outCurrentTime:
a = BitArray(bin=vcdCurrentValue)
#vcdBinaryOutput.append(vcdCurrentValue)
vcdParsedOutput.append(a.int/float(2**(self.busY[1])))
vcdCurrentValue = vcdNextValue
binOffset = self.busY[0] + self.busY[1] - len(vcdCurrentValue)
for jj in range(binOffset):
vcdCurrentValue = '0' + vcdCurrentValue
outCurrentTime += timeStep
print('Signal reconstructed')
# remove the output samples from filter initialization
for ii in range(5):
vcdParsedOutput.pop(0)
#vcdBinaryOutput.pop(0)
connect_sample_out = np.zeros(len(vcdParsedOutput))
for ii in range(len(vcdParsedOutput)):
connect_sample_out[ii] = vcdParsedOutput[ii]
return connect_sample_out
......
......@@ -43,6 +43,8 @@ class Simulator(Simcore):
# Declare signals that will be sended to other classes
simulatorUpdatedSignal = pyqtSignal()
simulatorBeginSignal = pyqtSignal()
simulatorEndSignal = pyqtSignal()
......@@ -73,7 +75,7 @@ class Simulator(Simcore):
elif selectedPlot == 'Power Spectrum':
scopePower(self.figSimulator, simulatorWaves, grid)
else:
scopeDual(self.figSimulator, simulatorWaves, grid)
scopeTime(self.figSimulator, simulatorWaves, grid)
# Change pushbutton state
self.pbUpdateFilter.setDisabled(True)
......@@ -84,6 +86,7 @@ class Simulator(Simcore):
def execute_simulation(self, b, a, x,
name, language,
engine, structure,
busX, busY, busC,
scalingX, scalingC):
""" Redraws the figure
......@@ -94,16 +97,19 @@ class Simulator(Simcore):
warningMessage = ''
warnings.simplefilter('error')
try:
self.simulatorBeginSignal.emit()
self.yfloat = signal.lfilter(b, a, x)
self.yhdl = self.simfilter(b, a, x,
'testfilt', 'vhdl',
structure, language,
engine, name,
busX, busY, busC,
scalingX, scalingC)
except ValueError, exVE:
self.simulatorEndSignal.emit()
except ValueError as exVE:
warningMessage = '%s' % exVE
except ZeroDivisionError, exZDE:
except ZeroDivisionError as exZDE:
warningMessage = '%s' % exZDE
except RuntimeWarning, exRW:
except RuntimeWarning as exRW:
warningMessage = '%s' % exRW
if warningMessage != '':
......@@ -156,14 +162,14 @@ class Simulator(Simcore):
labelSimulatorLanguage = QLabel('HDL Language:')
self.comboSimulatorLanguage = QComboBox()
self.comboSimulatorLanguage.addItem("Verilog")
self.comboSimulatorLanguage.addItem("VHDL")
self.comboSimulatorLanguage.addItem("Verilog")
self.comboSimulatorLanguage.setEditable(True)
self.comboSimulatorLanguage.lineEdit().setReadOnly(True)
self.comboSimulatorLanguage.lineEdit().setAlignment(Qt.AlignRight)
for ii in range(self.comboSimulatorLanguage.count()):
self.comboSimulatorLanguage.setItemData(ii, Qt.AlignRight, Qt.TextAlignmentRole)
self.connect(self.comboSimulatorLanguage, SIGNAL('currentIndexChanged(int)'), self.on_simulator_modified)
self.connect(self.comboSimulatorLanguage, SIGNAL('currentIndexChanged(int)'), self.on_language_modified)
labelSimulatorScope = QLabel('Output Scope:')
self.comboSimulatorScope = QComboBox()
......@@ -240,7 +246,7 @@ class Simulator(Simcore):
hboxWorkFolder.addWidget(labelWorkFolder)
hboxWorkFolder.addWidget(self.textWorkFolder)
hboxWorkFolder.addWidget(self.pbWorkFolder)
hboxWorkFolder.setStretch(0,4)
hboxWorkFolder.setStretch(0,5)
hboxWorkFolder.setStretch(1,4)
hboxWorkFolder.setStretch(2,1)
......@@ -280,4 +286,15 @@ class Simulator(Simcore):
self.simulatorUpdatedSignal.emit()
def on_language_modified(self):
# TODO: provisional, check the structure change and force to DF1 Trans
activeLanguage = str(self.comboSimulatorLanguage.currentText())
if activeLanguage == 'VHDL':
self.on_simulator_modified()
else:
QMessageBox.information(self, 'Simulation Language',
'Sorry, but %s is not supported yet!'
% activeLanguage,
QMessageBox.Ok)
self.comboSimulatorLanguage.setCurrentIndex(0)
......@@ -16,14 +16,6 @@
import sys
import os
import subprocess
import csv
import numpy as np
from scipy import signal
from bitstring import BitArray
class snippets:
......@@ -63,17 +55,17 @@ class snippets:
return entityString % entityDict
def architectureHeader(self, name, realization):
def architectureHeader(self, name, structure):
#TBD: include the appropriated realization diagram
archHeadDict = {
'Name': name,
'Realization': realization
'Structure': structure
}
archHeadString = (
'architecture %(Realization)s of %(Name)s is\n\n'
'architecture %(Structure)s of %(Name)s is\n\n'
'-- Architecture depends on selected realization\n'
'-- TODO: this header should each different realization\n'
'--\n'
......@@ -213,9 +205,9 @@ class snippets:
' if (rst = \'%(boolRst)s\') then\n'
)
for ii in range(M-1):
seqString += ' zb%(ii)u <= 0;\n' % {'ii': ii}
seqString += ' zb%(ii)u <= (others => \'0\');\n' % {'ii': ii}
for ii in range(N-1):
seqString += ' za%(ii)u <= 0;\n' % {'ii': ii}
seqString += ' za%(ii)u <= (others => \'0\');\n' % {'ii': ii}
seqString += ' else\n'
for ii in range(M-1):
seqString += ' zb%(ii)u <= zb%(ii)u_next;\n' % {'ii': ii}
......@@ -230,4 +222,390 @@ class snippets:
return seqString % seqDict
def signalZ(self, M, N, busX, busY, busC, structure):
signalZString = '-- Z^-1 delay blocks\n'
if structure == 'Direct_Form_I_Transposed':
# Z blocks in the b coefficients side
for ii in range(M-1):
signalZString += 'signal zb%(ii)u, zb%(ii)u_next: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1 -1}
signalZString += '\n'
# Z blocks in the a coefficients side
for ii in range(N-1):
if ii != 0:
bus = busX + busC -1 -1
else:
bus = busX -1
signalZString += 'signal za%(ii)u, za%(ii)u_next: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': bus}
signalZString += '\n'
return signalZString
def signalC(self, M, N, busC, structure):
signalCString = '-- Filter constants\n'
if structure == 'Direct_Form_I_Transposed':
# Z blocks in the b coefficients side
for ii in range(M):
signalCString += 'signal b%(ii)u: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busC - 1}
signalCString += '\n'
# Z blocks in the a coefficients side
for ii in range(N):
if ii != 0:
signalCString += 'signal a%(ii)u: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busC - 1}
signalCString += '\n'
return signalCString
def signalProducts(self, M, N, busX, busY, busC, structure):
signalProductString = '-- Filter Products\n'
if structure == 'Direct_Form_I_Transposed':
# Products from B coeff
for ii in range(M):
signalProductString += 'signal pb%(ii)u: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1 -1}
signalProductString += '\n'
# Products from A coeff
for ii in range(N):
if ii != 0:
signalProductString += 'signal pa%(ii)u: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1 -1}
signalProductString += '\n'
# Temporal Products from B coeff
for ii in range(M):
signalProductString += 'signal pb%(ii)u_temp: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1}
signalProductString += '\n'
# Temporal Products from A coeff
for ii in range(N):
if ii != 0:
signalProductString += 'signal pa%(ii)u_temp: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1}
signalProductString += '\n'
return signalProductString
def signalAdders(self, M, N, busX, busY, busC, structure):
signalAddString = '-- Filter Adders\n'
if structure == 'Direct_Form_I_Transposed':
# Adders in the b coefficients side
for ii in range(M-1):
signalAddString += 'signal sb%(ii)u: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1 -1}
signalAddString += '\n'
# Adders in the a coefficients side
for ii in range(N-1):
if ii != 0:
bus = busX + busC -1 -1
else:
bus = busX -1
signalAddString += 'signal sa%(ii)u: signed(%(bus)u downto 0);\n' % {'ii': ii, 'bus': bus}
signalAddString += '\n'
return signalAddString
def signalFeedback(self, M, N, busX, busY, busC, structure):
signalFeedbackString = ''
if structure == 'Direct_Form_I_Transposed':
signalFeedbackString += '-- Feedback loop accumulator\n'
signalFeedbackString += 'signal v: signed(%(bus)u downto 0);\n' % {'bus': busX -1}
return signalFeedbackString
def assignCoeff(self, M, N, bCoeffBin, bCoeffFloat,
aCoeffBin, aCoeffFloat, structure):
assignCoeffString = '-- Assign Coefficient\n'
if structure == 'Direct_Form_I_Transposed':
# Z blocks in the b coefficients side
for ii in range(M):
assignCoeffString += 'b%(ii)u <= \"%(BCoeffBin)s\"; -- %(BCoeffFloat)f\n' % {'ii': ii, 'BCoeffBin': bCoeffBin[ii], 'BCoeffFloat': bCoeffFloat[ii]}
assignCoeffString += '\n'
# Z blocks in the a coefficients side
for ii in range(N):
if ii != 0:
assignCoeffString += 'a%(ii)u <= \"%(ACoeffBin)s\"; -- %(ACoeffFloat)f\n' % {'ii': ii, 'ACoeffBin': aCoeffBin[ii], 'ACoeffFloat': aCoeffFloat[ii]}
assignCoeffString += '\n'
return assignCoeffString
def arithProduct(self, M, N, busX, busY, busC, structure):
arithProductString = '-- Product Arithmetics\n'
if structure == 'Direct_Form_I_Transposed':
# Execute products from B side
for ii in range(M):
arithProductString += 'pb%(ii)u_temp <= v * b%(ii)u;\n' % {'ii': ii}
arithProductString += 'pb%(ii)u <= pb%(ii)u_temp(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1 -1}
arithProductString += '\n'
# Execute products from A side
for ii in range(N):
if ii != 0:
arithProductString += 'pa%(ii)u_temp <= v * a%(ii)u;\n' % {'ii': ii}
arithProductString += 'pa%(ii)u <= pa%(ii)u_temp(%(bus)u downto 0);\n' % {'ii': ii, 'bus': busX + busC -1 -1}
arithProductString += '\n'
return arithProductString
def arithAdders(self, M, N, structure):
arithAddersString = '-- Adder Arithmetics\n'
if structure == 'Direct_Form_I_Transposed':
# Z blocks in the b coefficients side
for ii in range(M-1):
arithAddersString += 'sb%(ii)u <= pb%(ii)u + zb%(ii)u;\n' % {'ii': ii}
arithAddersString += '\n'
# Z blocks in the a coefficients side
for ii in range(N-1):
if ii == 0:
arithAddersString += 'sa%(ii)u <= sig_in + za%(ii)u;\n' % {'ii': ii}
else:
arithAddersString += 'sa%(ii)u <= pa%(ii)u + za%(ii)u;\n' % {'ii': ii}
arithAddersString += '\n'
return arithAddersString
def connectBlocks(self, M, N, busX, busY, busC, structure):
connectBlocksString = '-- Structure Blocks Connection\n'
if structure == 'Direct_Form_I_Transposed':
# Z blocks in the b coefficients side
for ii in range(M):
if ii == 0:
if M == 1:
outputStage = 'pb0'
else:
outputStage = 'sb0'
connectBlocksString += self.convertFixedPoint(outputStage, busC[0] + busX[0] -1, busC[1] + busX[1],
'sig_out', busY[0], busY[1])
else:
if ii == (M-1):
sourceTypeB = 'p'
else:
sourceTypeB = 's'
bConnectDict = {
'SrcType': sourceTypeB,
'Src': ii,
'Dst': ii - 1
}
connectBlocksString += 'zb%(Dst)u_next <= %(SrcType)sb%(Src)u;\n' % bConnectDict
connectBlocksString += '\n'
for ii in range(N):
if ii == 0:
if N == 1:
connectBlocksString += 'v <= sig_in;\n'
else:
connectBlocksString += 'v <= sa0;\n'
elif ii == 1:
if ii == (N-1):
firstStageA = 'pa1'
else:
firstStageA = 'sa1'
connectBlocksString += self.convertFixedPoint(firstStageA, busC[0] + busX[0] -1, busC[1] + busX[1],
'za0_next', busX[0], busX[1])
else:
if ii == (N-1):
sourceTypeA = 'p'
else:
sourceTypeA = 's'
aConnectDict = {
'SrcType': sourceTypeA,
'Src': ii,
'Dst': ii - 1
}
connectBlocksString += 'za%(Dst)u_next <= %(SrcType)sa%(Src)u;\n' % aConnectDict
connectBlocksString += '\n'
return connectBlocksString
def verilogTestBench(self, name, stimulusBin, stimulusFloat, busX, busY):
# Write Verilog Dictionary
testBenchDict = {
'Name': name,
'BusX': busX,
'BusY': busY,
'MSBX': busX - 1,
'MSBY': busY - 1,
'ClkPosWidth': 25,
'ClkNegWidth': 25,
}
testBenchString = (
'module tb_%(Name)s;\n'
'\n'
'reg clk;\n'
'reg rst;\n'
'reg [%(MSBX)u:0] sig_in;\n'
'wire [%(MSBY)u:0] sig_out;\n'
'\n'
'%(Name)s dut(\n'
' clk,\n'
' rst,\n'
' sig_in,\n'
' sig_out\n'
');\n'
'\n'
'always begin\n'
' clk <= 1;\n'
' #%(ClkPosWidth)u;\n'
' clk <= 0;\n'
' #%(ClkNegWidth)u;\n'
'end\n'
'\n'
'\n'
'initial begin\n'
' $dumpfile(\"%(Name)s.vcd\");\n'
' $dumpvars;\n'
'end\n'
'\n'
'initial begin\n'
' sig_in <= %(BusX)u\'b0; // signal is initially zero\n'
' rst <= 1\'b1; #100;\n'
' rst <= 1\'b0; #150;\n'
) % testBenchDict
for ii in range(len(stimulusBin)):
stimulusDict = {
'BusX': busX,
'CoeffBin': stimulusBin[ii],
'CoeffFloat': stimulusFloat[ii]
}
tempString = ' #50; sig_in <= %(BusX)u\'b%(CoeffBin)s; // %(CoeffFloat)f\n'
testBenchString += tempString % stimulusDict
testBenchString += (
' $finish;\n'
'end\n'
'\n'
'\n'
'endmodule\n'
)
return testBenchString
def vhdlTestBench(self, name, stimulusBin, stimulusFloat, busX, busY):
# Write Verilog Dictionary
testBenchDict = {
'Name': name,
'BusX': busX,
'BusY': busY,
'MSBX': busX - 1,
'MSBY': busY - 1,
'ClkPosWidth': 25,
'ClkNegWidth': 25,
}
testBenchString = (
'LIBRARY ieee;\n'
'USE ieee.std_logic_1164.ALL;\n'
'USE ieee.numeric_std.all;\n'
'\n'
'ENTITY tb_%(Name)s IS\n'
'END tb_%(Name)s;\n'
'\n'
'ARCHITECTURE behavior OF tb_%(Name)s IS\n'
' -- Component Declaration for the Unit Under Test (UUT)\n'
' COMPONENT %(Name)s\n'
' PORT(\n'
' clk: IN std_logic;\n'
' rst: IN std_logic;\n'
' sig_in: IN signed(%(MSBX)u downto 0);\n'
' sig_out: OUT signed(%(MSBY)u downto 0)\n'
' );\n'
' END COMPONENT;\n'
'\n'
' -- Signal Declaration\n'
' signal clk : std_logic := \'0\';\n'
' signal rst : std_logic := \'1\';\n'
' signal sig_in : signed(%(MSBX)u downto 0);\n'
' signal sig_out : signed(%(MSBY)u downto 0);\n'
'\n'
'BEGIN\n'
' -- Instantiate the Unit Under Test (UUT)\n'
' uut: %(Name)s PORT MAP (\n'
' clk => clk,\n'
' rst => rst,\n'
' sig_in => sig_in,\n'
' sig_out => sig_out\n'
' );\n'
'\n'
' clk_process : process\n'
' begin\n'
' clk <= \'1\';\n'
' wait for %(ClkPosWidth)u ns;\n'
' clk <= \'0\';\n'
' wait for %(ClkNegWidth)u ns;\n'
' end process;'
'\n'
' stimulus_process : process\n'
' begin\n'
' sig_in <= (others => \'0\');\n'
' rst <= \'1\'; wait for 100 ns;\n'
' rst <= \'0\'; wait for 125 ns;\n'
) % testBenchDict
for ii in range(len(stimulusBin)):
stimulusDict = {
'BusX': busX,
'CoeffBin': stimulusBin[ii],
'CoeffFloat': stimulusFloat[ii]
}
tempString = ' wait for 50 ns; sig_in <= "%(CoeffBin)s"; -- %(CoeffFloat)f\n'
testBenchString += tempString % stimulusDict
testBenchString += (
#' wait;\n'
#' -- Terminate Simulation\n'
#' assert false report "Simulation completed" severity failure;\n'
' end process;\n'
'\n'
'END;\n'
)
return testBenchString
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment