Source code for inverter_testbench

"""
==================
Inverter testbench
==================

This class demonstrates how you can construct testbeches for your model
Entities to gain more versatilyty that can be provided by self tests in the 
mainguard.

Initially written by Marko Kosunen, marko.kosunen@aalto.fi, 2022.

"""

import os
import sys
if not (os.path.abspath('../../thesdk') in sys.path):
    sys.path.append(os.path.abspath('../../thesdk'))

from thesdk import *

from inverter import *
from inverter.controller import controller as inverter_controller
from inverter.signal_source import signal_source
from inverter.signal_plotter import signal_plotter


import numpy as np

[docs] class inverter_testbench(thesdk): @property def _classfile(self): return os.path.dirname(os.path.realpath(__file__)) + "/"+__name__
[docs] def __init__(self,*arg): self.print_log(type='I', msg='Inititalizing %s' %(__name__)) self.proplist = [ 'Rs' ]; # Properties that can be propagated from parent self.Rs = 100e6; # Sampling frequency self.vdd = 1.0 # Suplly voltage self.model='py'; # Can be set externally, but is not propagated self.models=['py','sv','vhdl', 'ghdl', 'eldo','spectre', 'ngspice'] self.configuration='parallel' #self.models=['ngspice'] self.par= False # By default, no parallel processing self.queue= [] # By default, no parallel processing if len(arg)>=1: parent=arg[0] self.copy_propval(parent,self.proplist) self.parent =parent; self.init()
[docs] def init(self): pass #Currently nohing to add
[docs] def parallel(self): ''' Implements a configuration with a signal source, parallel inverters and plotters ''' length=2**8 controller=inverter_controller() controller.Rs=self.Rs #controller.reset() #controller.step_time() controller.start_datafeed() # Here we instantiate the signal source duts=[] plotters=[] #Here we construct the 'testbench' s_source=signal_source() for model in self.models: # Create an inverter d=inverter(self) # this is self is the parent duts.append(d) d.model=model # Enable debug messages #d.DEBUG = True # Run simulations in interactive modes to monitor progress/results #d.interactive_spice=True #d.interactive_rtl=True # Preserve the IO files or simulator files for debugging purposes # d.preserve_iofiles = True # d.preserve_spicefiles = True # Save the entity state after simulation #d.save_state = True #d.save_database = True # Optionally load the state of the most recent simulation #d.load_state = 'latest' # This connects the input to the output of the signal source d.IOS.Members['A']=s_source.IOS.Members['data'] # This connects the clock to the output of the signal source d.IOS.Members['CLK']=s_source.IOS.Members['clk'] d.IOS.Members['control_write']=controller.IOS.Members['control_write'] ## Add plotters p=signal_plotter() plotters.append(p) p.plotmodel=d.model p.plotprefix='parallel' p.plotvdd=self.vdd p.Rs = self.Rs p.IOS.Members['A']=d.IOS.Members['A'] p.IOS.Members['Z']=d.IOS.Members['Z'] p.IOS.Members['A_OUT']=d.IOS.Members['A_OUT'] p.IOS.Members['A_DIG']=d.IOS.Members['A_DIG'] p.IOS.Members['Z_ANA']=d.IOS.Members['Z_ANA'] p.IOS.Members['Z_RISE']=d.IOS.Members['Z_RISE'] # Here we run the instances s_source.run() # Creates the data to the output for d in duts: d.init() d.run() for p in plotters: p.init() p.run()
[docs] def serial(self): """ Configuration for inverter chain according to self.models Plots from intermediate outputs """ # Construct first controller=inverter_controller() s_source=signal_source() duts=[] plotters=[] for k in range(len(self.models)): d=inverter(self) duts.append(d) if k==0: d.IOS.Members['A']=s_source.IOS.Members['data'] else: d.IOS.Members['A']=duts[k-1].IOS.Members['Z'] d.model=self.models[k] d.IOS.Members['control_write']=controller.IOS.Members['control_write'] # Passing the same clock to all inverters (used in spice simulations) d.IOS.Members['CLK']=s_source.IOS.Members['clk'] p=signal_plotter() plotters.append(p) p.plotmodel=d.model p.plotprefix='serial' print(p.plotmodel) p.plotvdd=self.vdd p.Rs = self.Rs p.IOS.Members['A']=d.IOS.Members['A'] p.IOS.Members['Z']=d.IOS.Members['Z'] p.IOS.Members['A_OUT']=d.IOS.Members['A_OUT'] p.IOS.Members['A_DIG']=d.IOS.Members['A_DIG'] p.IOS.Members['Z_ANA']=d.IOS.Members['Z_ANA'] p.IOS.Members['Z_RISE']=d.IOS.Members['Z_RISE'] s_source.run() # Creates the data to the output controller.start_datafeed() for d in duts: d.init() d.run() for p in plotters: p.init() p.run()
[docs] def main(self): """ Chooses the model to construct """ if self.configuration == 'parallel': self.parallel() elif self.configuration == 'serial': self.serial() else: self.print_log(type='E' , msg='Test %s not implemented' %(self.configuration))
[docs] def run(self,*arg): '''Guideline: Define model depencies of executions in `run` method. ''' if self.model=='py': self.main() if self.par: # Return empty dict not to block the execution self.queue.put({})
if __name__=="__main__": from inverter_testbench import * import pdb tb=inverter_testbench() tb.models=['py','icarus','ghdl','ngspice'] #tb.configuration='parallel' tb.configuration='serial' tb.run() #This is here to keep the images visible #For batch execution, you should comment the following line input()