def LibraryDeclarations(self, f : FileWriter) -> FileWriter: VhdlTitle("Libraries", f) for l in sorted(self.libraries): f.WriteLn("library {};".format(l.replace("work", self.dutLibrary))) f.IncIndent() for u in self.libraries[l]: f.WriteLn("use {}.{}.{};".format(u.library.replace("work", self.dutLibrary), u.element, u.object)) f.DecIndent().WriteLn() return f
def CopyrightNotice(f: FileWriter) -> FileWriter: f.WriteLn("-" * 60) f.WriteLn( "-- Copyright (c) {} by Paul Scherrer Institute, Switzerland".format( dt.now().year)) f.WriteLn("-- All rights reserved.") f.WriteLn("-" * 60) f.WriteLn() return f
def VhdlTitle(title: str, f: FileWriter, level: int = 1) -> FileWriter: if level is 1: f.WriteLn("-" * 60) f.WriteLn("-- " + title) f.WriteLn("-" * 60) elif level is 2: f.WriteLn("-- *** " + title + " ***") else: raise Exception("Illegel VHDL Title level") return f
def _GenericConstants(self, f: FileWriter) -> FileWriter: gConst = DutInfo.FilterForTag(self.dutInfo.generics, Tags.CONSTANT) gExp = DutInfo.FilterForTag(self.dutInfo.generics, Tags.EXPORT, "true") VhdlTitle("Fixed Generics", f, 2) for g in gConst: f.WriteLn("constant {} : {} := {};".format( g.name, g.type, DutInfo.GetTag(g, Tags.CONSTANT))) f.WriteLn() VhdlTitle("Not Assigned Generics (default values)", f, 2) for g in self.dutInfo.generics: if (g.default is not None) and (g not in gConst) and (g not in gExp): f.WriteLn("constant {} : {} := {};".format( g.name, g.type, g.default)) if self.tbInfo.isMultiCaseTb: f.WriteLn() VhdlTitle("Exported Generics", f, 2) f.WriteLn("constant Generics_c : Generics_t := (").IncIndent() for g in gExp: f.WriteLn("{} => {},".format(g.name, g.name)) if len(gExp) is 0: f.WriteLn("Dummy => true,") f.RemoveFromLastLine(1, keepNewline=True, append=");") f.DecIndent() return f
def _TbControlSignals(self, f: FileWriter) -> FileWriter: VhdlTitle("TB Control", f, 2) f.WriteLn("signal TbRunning : boolean := True;") f.WriteLn("signal NextCase : integer := -1;") f.WriteLn( "signal ProcessDone : std_logic_vector(0 to {}) := (others => '0');" .format(len(self.tbInfo.tbProcesses) - 1)) f.WriteLn( "constant AllProcessesDone_c : std_logic_vector(0 to {}) := (others => '1');" .format(len(self.tbInfo.tbProcesses) - 1)) for i, p in enumerate(self.tbInfo.tbProcesses): f.WriteLn("constant TbProcNr_{}_c : integer := {};".format(p, i)) return f
def _Clocks(self, f: FileWriter) -> FileWriter: VhdlTitle("Clocks !DO NOT EDIT!", f) for clk in DutInfo.FilterForTag(self.dutInfo.ports, Tags.TYPE, "clk"): if not DutInfo.HasTag(clk, Tags.FREQ): raise Exception("Clock {} has not FREQ tag!".format(clk.name)) f.WriteLn("p_clock_{} : process".format(clk.name)).IncIndent() f.WriteLn("constant Frequency_c : real := real({});".format( DutInfo.GetTag(clk, Tags.FREQ))).DecIndent() f.WriteLn("begin").IncIndent() f.WriteLn("while TbRunning loop").IncIndent() f.WriteLn("wait for 0.5*(1 sec)/Frequency_c;") f.WriteLn("{name} <= not {name};".format(name=clk.name)) f.DecIndent().WriteLn("end loop;") f.WriteLn("wait;").DecIndent() f.WriteLn("end process;") f.WriteLn() return f
def _Processes(self, f: FileWriter) -> FileWriter: if self.tbInfo.isMultiCaseTb: VhdlTitle("Processes !DO NOT EDIT!", f) else: VhdlTitle("Processes", f) #Generate processes for p in self.tbInfo.tbProcesses: VhdlTitle(p, f, 2) f.WriteLn("p_{} : process".format(p)) f.WriteLn("begin").IncIndent() if self.tbInfo.isMultiCaseTb: for i, c in enumerate(self.tbInfo.testCases): f.WriteLn("-- {}".format(c)) f.WriteLn("wait until NextCase = {};".format(i)) f.WriteLn("ProcessDone(TbProcNr_{}_c) <= '0';".format(p)) args = ", ".join( port.name for port in self.tbInfo.GetPortsForProcess(p)) f.WriteLn( "work.{tb}_case_{case}.{proc}({args}, Generics_c);". format(tb=self.tbInfo.tbName, case=c, proc=p, args=args)) f.WriteLn("wait for 1 ps;") f.WriteLn("ProcessDone(TbProcNr_{}_c) <= '1';".format(p))
def _DutInstantiation(self, f: FileWriter) -> FileWriter: VhdlTitle("DUT Instantiation", f) f.WriteLn("i_dut : entity {}.{}".format( self.dutInfo.dutLibrary, self.dutInfo.name)).IncIndent() generics = self.dutInfo.generics eg = (DutInfo.FilterForTag(generics, Tags.EXPORT, "true") + DutInfo.FilterForTag(generics, Tags.CONSTANT)) if len(eg) > 0: f.WriteLn("generic map (").IncIndent() for g in eg: f.WriteLn("{} => {},".format(g.name, g.name)) f.RemoveFromLastLine(1) f.DecIndent().WriteLn(")") f.WriteLn("port map (").IncIndent() for p in self.dutInfo.ports: f.WriteLn("{} => {},".format(p.name, p.name)) f.RemoveFromLastLine(1) f.DecIndent().WriteLn(");").DecIndent() return f
def _TbControl(self, f: FileWriter) -> FileWriter: VhdlTitle("Testbench Control !DO NOT EDIT!", f) f.WriteLn("p_tb_control : process") f.WriteLn("begin").IncIndent() rsts = DutInfo.FilterForTag(self.dutInfo.ports, Tags.TYPE, "rst") if len(rsts) > 0: rstLogic = " and ".join([ r.name + " = " + self.dutInfo.GetPortValue(r, False) for r in rsts ]) f.WriteLn("wait until {};".format(rstLogic)) if self.tbInfo.isMultiCaseTb: for i, c in enumerate(self.tbInfo.testCases): f.WriteLn("-- {}".format(c)) f.WriteLn("NextCase <= {};".format(i)) f.WriteLn("wait until ProcessDone = AllProcessesDone_c;") else: f.WriteLn("wait until ProcessDone = AllProcessesDone_c;") #end of TB f.WriteLn("TbRunning <= false;") f.WriteLn("wait;") f.DecIndent().WriteLn("end process;") return f
def _EntityDeclaration(self, f: FileWriter) -> FileWriter: VhdlTitle("Entity Declaration", f) f.WriteLn("entity {} is".format(self.tbInfo.tbName)) f.IncIndent() eg = DutInfo.FilterForTag(self.dutInfo.generics, Tags.EXPORT, "true") if len(eg) > 0: f.WriteLn("generic (") f.IncIndent() for g in eg: line = "{} : {}".format(g.name, g.type) if g.default is not None: line += " := {};".format(g.default) else: line += ";" f.WriteLn(line) f.RemoveFromLastLine(1) f.DecIndent().WriteLn(");") f.DecIndent() f.WriteLn("end entity;").WriteLn() return f
def _Resets(self, f: FileWriter) -> FileWriter: VhdlTitle("Resets", f) for rst in DutInfo.FilterForTag(self.dutInfo.ports, Tags.TYPE, "rst"): if not DutInfo.HasTag(rst, Tags.CLK): raise Exception("Reset {} has not CLK tag!".format(rst.name)) clkName = DutInfo.GetTag(rst, Tags.CLK) f.WriteLn("p_rst_{} : process".format(rst.name)) f.WriteLn("begin").IncIndent() f.WriteLn("wait for 1 us;") f.WriteLn( "-- Wait for two clk edges to ensure reset is active for at least one edge" ) f.WriteLn("wait until rising_edge({});".format(clkName)) f.WriteLn("wait until rising_edge({});".format(clkName)) f.WriteLn("{} <= {};".format(rst.name, self.dutInfo.GetPortValue(rst, False))) f.WriteLn("wait;").DecIndent() f.WriteLn("end process;") f.WriteLn() return f
def _DutSignals(self, f: FileWriter) -> FileWriter: VhdlTitle("DUT Signals", f, 2) sigs = self.dutInfo.ports for sig in sigs: try: if DutInfo.HastTagValue(sig, Tags.TYPE, "rst"): default = " := " + self.dutInfo.GetPortValue(sig, True) elif DutInfo.HastTagValue(sig, Tags.TYPE, "clk"): default = " := " + self.dutInfo.GetPortValue( sig, True ) #clocks start active so they are rising edge aligned else: default = " := " + self.dutInfo.GetPortValue(sig, False) except UnknownVhdlType: default = "" f.WriteLn("signal {} : {}{};".format(sig.name, str(sig.type), default)) return f
def Generate(self, tbPath: str, extension: str, overwrite: bool = False): if self.dutInfo is None: raise Exception("No VHDL File parsed yet, call ReadHdl() first!") if not os.path.exists(tbPath): os.mkdir(tbPath) with FileWriter(tbPath + "/" + self.tbInfo.tbName + extension, overwrite=overwrite) as f: #Library Declarations self._Header(f).WriteLn() self.dutInfo.LibraryDeclarations(f) self.tbInfo.UserPkgDelcaration(f) if self.tbInfo.isMultiCaseTb: self.tbInfo.TbPkgDeclaration(f) self.tbInfo.TbCaseDeclaration(f) #Entity Declaration self._EntityDeclaration(f) #Architecture Declaration VhdlTitle("Architecture", f) f.WriteLn("architecture sim of {} is".format( self.tbInfo.tbName)).IncIndent() self._GenericConstants(f).WriteLn() self._TbControlSignals(f).WriteLn() self._DutSignals(f).WriteLn() f.DecIndent() f.WriteLn("begin").IncIndent() self._DutInstantiation(f).WriteLn() self._TbControl(f).WriteLn() self._Clocks(f).WriteLn() self._Resets(f).WriteLn() self._Processes(f).WriteLn() f.DecIndent().WriteLn("end;") #Generate multi-case testbench if required if self.tbInfo.isMultiCaseTb: WriteTbPkg(tbPath, self.dutInfo, self.tbInfo, extension, overwrite) #write case packages for case in self.tbInfo.testCases: WriteCasePkg(tbPath, self.dutInfo, self.tbInfo, case, extension, overwrite)
def WriteTbPkg(path: str, dutInfo: DutInfo, tbInfo: TbInfo, extension: str = ".vhd", overwrite: bool = False): pkgName = tbInfo.tbName + "_pkg" with FileWriter(path + "/" + pkgName + extension, overwrite=overwrite) as f: CopyrightNotice(f) #Library Declarations dutInfo.LibraryDeclarations(f) tbInfo.UserPkgDelcaration(f) VhdlTitle("Package Header", f) f.WriteLn("package {} is".format(pkgName)).IncIndent() f.WriteLn() VhdlTitle("Generics Record", f, 2) f.WriteLn("type Generics_t is record").IncIndent() generics = DutInfo.FilterForTag(dutInfo.generics, Tags.EXPORT, "true") for g in generics: f.WriteLn("{} : {};".format(g.name, str(g.type))) if len(generics) is 0: f.WriteLn( "Dummy : boolean; -- required since empty records are not allowed" ) f.DecIndent().WriteLn("end record;") f.WriteLn() VhdlTitle("Not exported Generics", f) for g in set(dutInfo.generics) - set( DutInfo.FilterForTag(dutInfo.generics, Tags.EXPORT, "true")): if DutInfo.HasTag(g, Tags.CONSTANT): value = DutInfo.GetTag(g, Tags.CONSTANT) else: value = g.default f.WriteLn("constant {} : {} := {};".format(g.name, str(g.type), value)) f.WriteLn() f.DecIndent().WriteLn("end package;") f.WriteLn() VhdlTitle("Package Body", f) f.WriteLn("package body {} is".format(pkgName)).IncIndent() f.DecIndent().WriteLn("end;")
return "in" if DutInfo.HastTagValue(port, Tags.TYPE, "clk"): return "in" return "inout" else: return "in" def WriteCasePkg(path: str, dutInfo: DutInfo, tbInfo: TbInfo, case: str, extension: str, overwrite: bool = False): caseName = tbInfo.tbName + "_case_" + case with FileWriter(path + "/" + caseName + extension, overwrite=overwrite) as f: CopyrightNotice(f) #Library Declarations dutInfo.LibraryDeclarations(f) tbInfo.TbPkgDeclaration(f) tbInfo.UserPkgDelcaration(f) VhdlTitle("Package Header", f) f.WriteLn("package {} is".format(caseName)).IncIndent() f.WriteLn() for p in tbInfo.tbProcesses: f.WriteLn("procedure {} (".format(p)).IncIndent() for s in tbInfo.GetPortsForProcess(p): procDir = PortDirectionForProcedure(p, s) f.WriteLn("signal {} : {} {};".format(s.name, procDir, s.type.name)) f.WriteLn("constant Generics_c : Generics_t);")
def TbCaseDeclaration(self, f: FileWriter) -> FileWriter: f.WriteLn("library work;".format()).IncIndent() for c in self.testCases: f.WriteLn("use work.{}_case_{}.all;".format(self.tbName, c)) f.DecIndent().WriteLn() return f
def TbPkgDeclaration(self, f: FileWriter) -> FileWriter: f.WriteLn("library work;".format()).IncIndent() f.WriteLn("use work.{}_pkg.all;".format(self.tbName)) f.DecIndent().WriteLn()
def UserPkgDelcaration(self, f: FileWriter) -> FileWriter: for lib, pkgs in self.tbUserPackages.items(): f.WriteLn("library {};".format(lib)).IncIndent() for pkg in pkgs: f.WriteLn("use {}.{}.all;".format(lib, pkg)) f.DecIndent().WriteLn()
def _Header(self, f: FileWriter) -> FileWriter: CopyrightNotice(f) VhdlTitle("Testbench generated by TbGen.py", f) f.WriteLn("-- see Library/Python/TbGenerator") return f