diff --git a/pymlac/test_CPU.py b/pymlac/test_CPU.py new file mode 100644 index 0000000..1886d1c --- /dev/null +++ b/pymlac/test_CPU.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Test pymlac CPU opcodes DIRECTLY. + +Usage: test_CPU.py [] + +where is a file of test instructions and + is one or more of + -h prints this help and stops +""" + +# We implement a small interpreter to test the CPU. The test code is read in +# from a file: +# +# # LAW +# setreg ac 012345; setreg l 1; setreg pc 0100; setmem 0100 [LAW 0]; RUN; checkcycles 1; checkreg pc 0101; checkreg ac 0 +# setreg ac 012345; setreg l 0; setmem 0100 [LAW 0]; RUN 0100 +# checkcycles 1; checkreg pc 0101; checkreg ac 0 +# +# The instructions are delimited by ';' characters. A line beginning with a +# TAB character is a continuation of the previous line. +# Lines with '#' in column 1 are comments. +# +# The test instructions are: +# setreg +# where is one of AC, L or PC, value is any value +# (all registers are set to 0 initially) +# +# setmem +# where is an address and value is any value OR +# [] where the value is the assembled opcode +# +# run [] +# execute one instruction, if optional is used PC := addr before +# +# checkcycles +# check number of executed cycles is +# +# checkreg +# check register (AC, L or PC) has value +# +# checkmem +# check that memory at has +# +# allreg +# sets all registers to +# a "allreg 0" is assumed before each test +# +# allmem +# sets all of memory to +# a "allmem 0" is assumed before each test +# +# In addition, all of memory is checked for changed values after execution +# except where an explicit "checkmem " has been performed. +# Additionally, registers that aren't explicitly checked are tested to make +# sure they didn't change. +# +# If a test line finds no error, just print the fully assembled test line. +# If any errors are found, print line followed by all errors. + + +import MainCPU +import Memory + + +def setreg(name, value): + """Set register to a value. + + Remember value to check later. + """ + + global RegValues + + RegValues[name] = value + exec "MainCPU.%s = %07o" % (name, value) + +def setmem(addr, value): + """Set memory location to a value.""" + + global MemValues + + MemValues[addr] = value + Memory.memory[addr] = value + + +def allmem(value): + """Set all of memory to a value. + + Remember value to check later. + """ + + global MemAllValue + + MemAllValue = value + for mem in range(Memory.MAXMEM): + Memory.memory[mem] = value + +def allreg(value): + """Set all registers to a value.""" + + global RegAllValue + + RegAllValue = value + MainCPU.AC = value + MainCPU.L = value & 1 + MainCPU.PC = value + +def execute(test): + """Execute test string in 'test'.""" + + global RegValues, MemValues + global RegAllValue, MemAllValue + + # set globals + RegValues = {} + MemValues = {} + RegAllValue = {} + MemAllValue = {} + + # clear memory and registers to 0 first + memset(0) + regset(0) + + # interpret the test instructions + instructions = test.split(';') + for op in instructions: + print op + + + + +def main(filename): + """Execute CPU tests from 'filename'.""" + + # get all tests from file + with open(filename, 'rb') as fd: + lines = fd.readlines() + + # read lines, join continued, get complete tests + tests = [] + test = '' + for line in lines: + line = line[:-1] # strip newline + + if line[0] == '#': # a comment + continue + + if line[0] == '\t': # continuation + if test: + test += '; ' + test += line[1:] + else: # beginning of new test + if test: + tests.append(test) + test = line + + # flush last test + if test: + tests.append(test) + + # now do each test + for test in tests: + execute(test) + + +################################################################################ + +if __name__ == '__main__': + main('CPU.test')