def __init__(self, machine, sim_data): # Machine is the simulation's machine. # SimData cannot be empty. self.machine = machine if sim_data.strip() == '': die('empty sim data') self.data = sim_data.splitlines() self.step = e.settings.step
def _jsonInsertExternal(img, pat, data): # Looks for the corresponding metaobject and sets the submachine data to it if pat in img['objects']: img['extobjects'][pat] = {} img['extobjects'][pat]['objects'] = img['metaobjects'][pat] img['extobjects'][pat]['data'] = data del img['metaobjects'][pat] else: log.error('pattern = %s' % pat) die('trying to set sub-machine data to non-metaobject')
def _checkCycleLine(self, line): # Some sanity checks on split line (that time and clk are integers). try: time = int(line[0]) except: die('first col (time) in sim output not an int decimal') try: clk = int(line[1], 2) except: die('second col (clk) in sim output not a binary decimal') log.info('emulator pass, time=%s, clk=%s' % (time, clk)) return time, clk
def _findDataProgFiles(self, files): if files[0].endswith('.d'): data_file = files[0] elif files[1].endswith('.d'): data_file = files[1] else: die('cannot find data (.d) file') if files[0].endswith('.p'): program_file = files[0] elif files[1].endswith('.p'): program_file = files[1] else: die('cannot find program (.p) file') return data_file, program_file
def __init__(self): ap = ArgParser(description='Online Machine Simulation Tool') addarg = ap.add_argument outf = sys.stdout.fileno() errf = sys.stderr.fileno() addarg('machine', type=str, metavar='MACHINE', help='Machine name M to run') addarg('step', type=int, metavar='STEP', help='Step number to retrieve') addarg('files', metavar='FILES', nargs='+', help='Program files to compile and run') addarg('-m', '--max-steps', default=500, type=int, metavar='N', help='Maximum number of steps [%(default)s]') addarg('-x', '--range', default=10, type=int, metavar='N', help='Range of steps to cache [%(default)s]') addarg('-f', '--format', default='js', type=str, metavar='FMT', choices=['js', 'json'], help='Output format (%(choices)s) [%(default)s]') addarg('-c', '--compress', default=False, type=bool, metavar='C', help='Compress output [%(default)s]') addarg('-d', '--mach-dir', default='machines/', type=str, metavar='D', help='Directory with machine files [%(default)s]') addarg('-t', '--text', default=outf, type=int, metavar='FD', help='Text output file descriptor [stdout]') addarg('-e', '--error', default=errf, type=int, metavar='FD', help='Error output file descriptor [stderr]') addarg('-w', '--warn', default=errf, type=int, metavar='FD', help='Warning output file descriptor [stderr]') addarg('-r', '--result', default=7, type=int, metavar='FD', help='Result output file descriptor [%(default)s]') addarg('-l', '--sim-log', default=devnull, type=str, metavar='F', help='Dump simulation log to file [%(default)s]') args = ap.parse_args() # do some sanity checks if args.range > args.max_steps: die('bad range > max_steps') if args.step < 0: die('step should be >= 0') self.machineName = args.machine self.step = args.step self.machineFile = path.join(args.mach_dir, args.machine, 'main.machine') self.text = fdopen(args.text, 'w') self.error = fdopen(args.error, 'w') self.warn = fdopen(args.warn, 'w') self.files = args.files self.simLogFile = args.sim_log self.format = args.format self.maxSteps = args.max_steps self.range = args.range try: self.result = fdopen(args.result, 'w') except OSError: self.result = self.text
def export(machine): f = e.settings.format out = e.settings.result if f.startswith('js'): res = json.dumps(jsonExport(machine), indent=2) if e.settings.compress == True: res = _compressJSON(res) tmpJS = 'var machine = %s;' if f == 'js': out.write(tmpJS % res) elif f == 'json': out.write(res) else: die('unknown format')
def run(self): # This is the main flowchart-like logic to deal with possible # cases of missing machine file and/or simulator # binary. Described in docs/simulation.dia. simcode = self.machine['simcode'] simulator = self.machine['simulator'] if not simcode: log.info('sim machine is empty, checking simulator') if not simulator: die('no simulator nor machine provided') else: log.info('simulator not empty, checking') if simulator == 'veriwell': die('no machine for verilog sim') elif simulator == 'vhdl': die('no machine for vhdl sim') else: self._runStandaloneSim() else: log.info('sim machine not empty, checking simulator') if not simulator: log.info('simulator empty, checking extension') if simcode.endswith('.v'): log.info('machine ends in .v, using veriwell') self._runVeriwellSim() elif simcode.endswith('.vh'): # put other simulators here log.info('machine ends in .vh, using vhdl') # run vhdl simulation else: die('cannot determine simulator from extension') else: log.info('simulator not empty, checking') if simulator == 'veriwell': log.info('machine not empty, simulator is veriwell') self._runVeriwellSim() elif simulator == 'vhdl': # put other simulators here log.info('machine not empty, simulator is vhdl') else: die('unknown simulator given')
def _checkSplitSimOutput(self): # Check sanity of the simulator output and splits it accordingly. sInd = '=== start ===' eInd = '=== end ===' if sInd not in self.data: die('start-ind not found in sim output') if eInd not in self.data: die('end-ind not found in sim output') if self.data.index(eInd) < self.data.index(sInd): die('end-ind found before start-ind in sim output') self.data = self.data.split(sInd)[1].split(eInd)[0].strip()
def advance(self, step=0): # Moves through the simulation data, parsing every line. Works # according to the emulator state machine: # START: Get 0 -> S0 # S0: Get 0 -> S0 # S0: Get 1 -> S1 # S1: Get 1 -> S1 # S1: Get 0 -> S0, step++, machine.load_values() # END when counter == wanted_steps or premature_finish # Returns True for success # Returns False for premature finish splitLine = lambda row: self.data[row].strip().split(':') if len(self.data) == 0: die('empty sim data') if step < 0: die('bad step number %s' % step) if step == 0: tmpLine = splitLine(0) if tmpLine[0] == 'mw': die('step 0 is a memwrite operation') self._checkCycleLine(tmpLine) _machineLoadMem(self.machine) _machineLoadValues(self.machine, tmpLine[2].split(',')) _machineUnmarkAll(self.machine) else: i = 0 row = 0 state = 0 _machineLoadMem(self.machine) while i < step: if row == len(self.data) - 1: return False _machineUnmarkAll(self.machine) tmpLine = splitLine(row) if tmpLine[0] == 'mw': _machineMemWrite(self.machine, tmpLine[1].split(',')) else: time, clk = self._checkCycleLine(tmpLine) if state == 0 and clk == 1: state = 1 elif state == 1 and clk == 0: state = 0; i += 1 pLine = splitLine(row-1) # previous line log.info('applying line at time=%s, clk=%s' % (pLine[0], pLine[1])) _machineLoadValues(self.machine, pLine[2].split(',')) row += 1 return True
def run(self): # Runs assembler according to flowchart in docs/assembler.dia files = e.settings.files assembler = self.machine['assembler'] if len(files) == 1: log.info('single file provided') if self.machine['single_mem']: log.info('machine is single memory') if not assembler: log.info('no assembler, using input directly') tmp = mktempf('_tmp') shutil.copyfile(files[0], tmp) e.settings.program_prog = tmp self.machine['debug_info'] = False else: log.info('have assembler, trying to assemble') returncode = self._tryAssembling(files[0], canDie=False) log.info('assembler returned errorcode %s' % returncode) if returncode != 0: log.info('assembler failed, using input directly') tmp = mktempf(suffix='_tmp') shutil.copyfile(files[0], tmp) e.settings.program_prog = tmp self.machine['debug_info'] = False else: log.info('assembler succeeded') else: log.info('machine is dual memory') if not assembler: die('machine does not have an assembler') else: log.info('machine has an assembler') self._tryAssembling(files[0]) elif len(files) == 2: log.info('two files provided') if self.machine['single_mem']: log.info('machine is single mem, merging files (data first)') dataFile, progFile = self._findDataProgFiles(files) with open(dataFile, 'r') as f: data = f.read() with open(progFile, 'r') as f: data += f.read() name = mktempf('_name') with open(name, 'w') as f: f.write(data) e.settings.program_prog = name self.machine['debug_info'] = False else: log.info('machine is dual mem') dataFile, progFile = self._findDataProgFiles(files) tmp = mktempf('_tmp') shutil.copyfile(progFile, tmp) e.settings.programProg = tmp tmp = mktempf('_tmp') shutil.copyfile(dataFile, tmp) e.settings.program_data = tmp self.machine['debug_info'] = False else: die('more than 2 files given')