#!/usr/bin/python -O """ # GAL/PAL chip emulator testsuite # # Copyright (C) 2008 Michael Buesch # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ import galemu import sys import re from operator import itemgetter class TestEx(Exception): "Test failure exception" class Sim: "A simulation file entry" def __init__(self, name): # name is a name string for this entry self.name = name # inputs is a list of tuples of input pin states self.inputs = None # outputs is a list of tuples of expected output pin states self.outputs = None # Expected error message, if any self.expectfail = "" def parseInputOutputData(sim, str): old_str = str result = [] str = str.upper().replace("INPUT", "").replace("OUTPUT", "").strip() pin_re = re.compile(r"\s*(\d+)\s*=\s*(\d+)\s*") while len(str): m = pin_re.match(str) if not m: raise TestEx("Simfile error: Invalid pin definitions %s" % old_str) str = str[len(m.group(0)):].strip() try: pin = int(m.group(1)) except ValueError, e: raise TestEx("Simfile error: Invalid pin number: %s" % e.message) if m.group(2) == "0": value = False elif m.group(2) == "1": value = True else: raise TestEx("Simfile error: Invalid pin value: %s" % m.group(2)) result.append( (pin, value) ) # Sort it by pin number result = sorted(result, key=itemgetter(0)) return result def parseExpectfail(sim, text): text = text[10:].strip() if text[0] != '\"' or text[-1] != '\"': raise TestEx("Simfile error: EXPECTFILE message not quoted: %s" % text) return text[1:-1] def parseSimData(simData): simList = [] sim = None lines = simData.splitlines() start_re = re.compile(r"(\w+)\s*{") for line in lines: line = line.strip() if line.startswith("#"): continue # comment if not sim: m = start_re.match(line) if not m: continue name = m.group(1) sim = Sim(name) continue if line.upper().startswith("INPUT"): sim.inputs = parseInputOutputData(sim, line) if line.upper().startswith("OUTPUT"): sim.outputs = parseInputOutputData(sim, line) if line.upper().startswith("EXPECTFAIL"): sim.expectfail = parseExpectfail(sim, line) if line.startswith("}"): if not sim.inputs and not sim.outputs: raise TestEx("Simfile error: Neither inputs nor outputs for test %s" %\ sim.name) simList.append(sim) sim = None return simList def evaluateInputs(emu, testcase): inputs = [] for i in testcase.inputs: inputs.append(i[1]) # Get the pin values # The input list is sorted by pin name emu.setInput(inputs) def validateOutputs(emu, testcase): gal = emu.getGal() out = emu.getOutput() expectedOutput = dict(testcase.outputs) # { pin:value, ... } # Validate the output values for i in range(0, len(out)): outpin = gal.getOlmcList()[i].getOutputPin().getPin() try: expected = expectedOutput[outpin] except KeyError: continue # This pin is not tested if expected == out[i]: continue raise TestEx( ("Emulator error in test %s: "+\ "Output pin %d expected %d, but was %d") %\ (testcase.name, outpin, expectedOutput[outpin], out[i])) def evaluateTestcase(emu, testcase): try: if testcase.inputs: evaluateInputs(emu, testcase) if testcase.outputs: validateOutputs(emu, testcase) except galemu.LogicEx, e: # Check if this failure was expected if testcase.expectfail: if e.message != testcase.expectfail: raise # Nope, that's another error else: raise # Nope, raise the exception again else: if testcase.expectfail: raise TestEx( ("Test %s succeed, but it was expected to "+\ "fail with the exception message: %s") %\ (testcase.name, testcase.expectfail)) def runTest(jed, sim): try: array = galemu.FuseArray() array.readJedecData(jed) gal = galemu.selectGalClassObject(array.getGalType()) (array) emu = galemu.Emulator(gal) testcases = parseSimData(sim) for testcase in testcases: evaluateTestcase(emu, testcase) except galemu.LogicEx, e: raise TestEx("Logics exception: %s" % e.message) except galemu.GalemuEx, e: raise TestEx("Galemu exception: %s" % e.message) def main(argv): total = 0 failed = 0 count = 1 while True: jedFilename = "testsuite/%03d.jed" % count simFilename = "testsuite/%03d.sim" % count try: jed = file(jedFilename, "r").read() sim = file(simFilename, "r").read() except IOError, e: break total += 1 try: runTest(jed, sim) except TestEx, e: failed += 1 print "Test %03d FAILED: %s" % (count, e.message) else: print "Test %03d OK" % count count += 1 print "=" * 70 print "%d OK, %d failed" % (total - failed, failed) return failed if __name__ == "__main__": sys.exit(main(sys.argv))