pavone@214: #!/usr/bin/env python pavone@214: pavone@214: def split_fields(line): pavone@214: parts = [] pavone@214: while line: pavone@214: field,_,line = line.partition('\t') pavone@214: parts.append(field.strip()) pavone@214: while line.startswith('\t'): pavone@214: line = line[1:] pavone@214: return parts pavone@214: pavone@214: class Program(object): pavone@214: def __init__(self, instruction): pavone@214: self.avail_dregs = {0,1,2,3,4,5,6,7} pavone@214: self.avail_aregs = {0,1,2,3,4,5,6,7} pavone@214: instruction.consume_regs(self) pavone@214: self.inst = instruction pavone@214: pavone@224: def dirname(self): pavone@224: return self.inst.name + '_' + self.inst.size pavone@214: def name(self): pavone@214: return str(self.inst).replace('.', '_').replace('#', '_').replace(',', '_').replace(' ', '_').replace('(', '[').replace(')', ']') pavone@214: pavone@214: def write_rom_test(self, outfile): pavone@214: outfile.write('\tdc.l $0, start\n') pavone@227: needdivzero = self.inst.name.startswith('div') pavone@325: needchk = self.inst.name.startswith('chk') pavone@214: for i in xrange(0x8, 0x100, 0x4): pavone@227: if needdivzero and i == 0x14: pavone@227: outfile.write('\tdc.l div_zero_handler\n') pavone@325: elif needchk and i == 0x18: pavone@325: outfile.write('\tdc.l chk_handler\n') pavone@227: else: pavone@227: outfile.write('\tdc.l empty_handler\n') pavone@227: outfile.write('\tdc.b "SEGA"\nempty_handler:\n\trte\n') pavone@227: if needdivzero: pavone@227: outfile.write('div_zero_handler:\n') pavone@227: div_zero_count = self.get_dreg() pavone@227: outfile.write('\taddq #1, ' + str(div_zero_count) + '\n') pavone@227: outfile.write('\trte\n') pavone@325: if needchk: pavone@325: outfile.write('chk_handler:\n') pavone@325: chk_count = self.get_dreg() pavone@325: outfile.write('\taddq #1, ' + str(chk_count) + '\n') pavone@325: outfile.write('\trte\n') pavone@227: outfile.write('start:\n\tmove #0, CCR\n') pavone@227: if needdivzero: pavone@227: outfile.write('\tmoveq #0, ' + str(div_zero_count) + '\n') pavone@214: already = {} pavone@214: self.inst.write_init(outfile, already) pavone@214: if 'label' in already: pavone@214: outfile.write('lbl_' + str(already['label']) + ':\n') pavone@214: outfile.write('\t'+str(self.inst)+'\n') pavone@214: outfile.write('\t'+self.inst.save_result(self.get_dreg(), True) + '\n') pavone@214: save_ccr = self.get_dreg() pavone@214: outfile.write('\tmove SR, ' + str(save_ccr) + '\n') pavone@214: outfile.write('\tmove #$1F, CCR\n') pavone@214: self.inst.invalidate_dest(already) pavone@214: self.inst.write_init(outfile, already) pavone@214: if 'label' in already: pavone@214: outfile.write('lbl_' + str(already['label']) + ':\n') pavone@214: outfile.write('\t'+str(self.inst)+'\n') pavone@214: outfile.write('\t'+self.inst.save_result(self.get_dreg(), False) + '\n') pavone@214: outfile.write('\treset\n') pavone@214: pavone@214: def consume_dreg(self, num): pavone@214: self.avail_dregs.discard(num) pavone@214: pavone@214: def consume_areg(self, num): pavone@214: self.avail_aregs.discard(num) pavone@214: pavone@214: def get_dreg(self): pavone@214: return Register('d', self.avail_dregs.pop()) pavone@214: pavone@439: class Dummy(object): pavone@439: def __str__(self): pavone@439: return '' pavone@439: def write_init(self, outfile, size, already): pavone@439: pass pavone@439: def consume_regs(self, program): pavone@439: pass pavone@439: pavone@439: dummy_op = Dummy() pavone@439: pavone@214: class Register(object): pavone@214: def __init__(self, kind, num): pavone@214: self.kind = kind pavone@214: self.num = num pavone@214: pavone@214: def __str__(self): pavone@214: if self.kind == 'd' or self.kind == 'a': pavone@214: return self.kind + str(self.num) pavone@214: return self.kind pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: if not str(self) in already: pavone@214: minv,maxv = get_size_range(size) pavone@214: val = randint(minv,maxv) pavone@214: already[str(self)] = val pavone@214: outfile.write('\tmove.'+size+' #'+str(val)+', ' + str(self) + '\n') pavone@214: pavone@214: def consume_regs(self, program): pavone@214: if self.kind == 'd': pavone@214: program.consume_dreg(self.num) pavone@214: elif self.kind == 'a': pavone@214: program.consume_areg(self.num) pavone@214: pavone@214: def valid_ram_address(address, size='b'): pavone@214: return address >= 0xE00000 and address <= 0xFFFFFFFC and (address & 0xE00000) == 0xE00000 and (size == 'b' or not address & 1) pavone@214: pavone@214: def random_ram_address(mina=0xE00000, maxa=0xFFFFFFFC): pavone@214: return randint(mina, maxa) | 0xE00000 pavone@214: pavone@214: class Indexed(object): pavone@214: def __init__(self, base, index, index_size, disp): pavone@214: self.base = base pavone@214: self.index = index pavone@214: self.index_size = index_size pavone@214: self.disp = disp pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: if self.base.kind == 'pc': pavone@214: if str(self.index) in already: pavone@214: index = already[str(self.index)] pavone@214: if self.index_size == 'w': pavone@214: index = index & 0xFFFF pavone@214: #sign extend index pavone@214: if index & 0x8000: pavone@214: index -= 65536 pavone@214: if index > -1024: pavone@214: index = already[str(self.index)] = randint(-32768, -1024) pavone@214: outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n') pavone@214: else: pavone@214: index = already[str(self.index)] = randint(-32768, -1024) pavone@214: outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n') pavone@214: num = already.get('label', 0)+1 pavone@214: already['label'] = num pavone@214: address = 'lbl_' + str(num) + ' + 2 + ' + str(self.disp) + ' + ' + str(index) pavone@214: else: pavone@217: if self.base == self.index: pavone@217: if str(self.base) in already: pavone@217: if not valid_ram_address(already[str(self.base)]*2): pavone@217: del already[str(self.base)] pavone@217: self.write_init(outfile, size, already) pavone@217: return pavone@217: else: pavone@217: base = index = already[str(self.base)] pavone@214: else: pavone@217: base = index = already[str(self.base)] = random_ram_address()/2 pavone@217: outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n') pavone@214: else: pavone@217: if str(self.base) in already: pavone@217: if not valid_ram_address(already[str(self.base)]): pavone@217: del already[str(self.base)] pavone@217: self.write_init(outfile, size, already) pavone@217: return pavone@217: else: pavone@217: base = already[str(self.base)] pavone@217: else: pavone@217: base = already[str(self.base)] = random_ram_address() pavone@217: outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n') pavone@217: if str(self.index) in already: pavone@217: index = already[str(self.index)] pavone@217: if self.index_size == 'w': pavone@217: index = index & 0xFFFF pavone@217: #sign extend index pavone@217: if index & 0x8000: pavone@217: index -= 65536 pavone@217: if not valid_ram_address(base + index): pavone@217: index = already[str(self.index)] = randint(-64, 63) pavone@217: outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n') pavone@217: else: pavone@214: index = already[str(self.index)] = randint(-64, 63) pavone@214: outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n') pavone@214: address = base + index + self.disp pavone@214: if (address & 0xFFFFFF) < 0xE00000: pavone@214: if (address & 0xFFFFFF) < 128: pavone@214: self.disp -= (address & 0xFFFFFF) pavone@214: else: pavone@214: self.disp += 0xE00000-(address & 0xFFFFFF) pavone@608: if self.disp > 127: pavone@608: self.disp = 127 pavone@608: elif self.disp < -128: pavone@608: self.disp = -128 pavone@214: address = base + index + self.disp pavone@214: elif (address & 0xFFFFFF) > 0xFFFFFC: pavone@214: self.disp -= (address & 0xFFFFFF) - 0xFFFFFC pavone@608: if self.disp > 127: pavone@608: self.disp = 127 pavone@608: elif self.disp < -128: pavone@608: self.disp = -128 pavone@214: address = base + index + self.disp pavone@214: if size != 'b' and address & 1: pavone@214: self.disp = self.disp ^ 1 pavone@214: address = base + index + self.disp pavone@214: minv,maxv = get_size_range(size) pavone@214: outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') pavone@214: pavone@214: def __str__(self): pavone@214: return '(' + str(self.disp) + ', ' + str(self.base) + ', ' + str(self.index) + '.' + self.index_size + ')' pavone@214: pavone@214: def consume_regs(self, program): pavone@214: self.base.consume_regs(program) pavone@214: self.index.consume_regs(program) pavone@214: pavone@214: class Displacement(object): pavone@214: def __init__(self, base, disp): pavone@214: self.base = base pavone@214: self.disp = disp pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: if self.base.kind == 'pc': pavone@214: num = already.get('label', 0)+1 pavone@214: already['label'] = num pavone@214: address = 'lbl_' + str(num) + ' + 2 + ' + str(self.disp) pavone@214: else: pavone@214: if str(self.base) in already: pavone@214: if not valid_ram_address(already[str(self.base)]): pavone@214: del already[str(self.base)] pavone@214: self.write_init(outfile, size, already) pavone@214: return pavone@214: else: pavone@214: base = already[str(self.base)] pavone@214: else: pavone@214: base = already[str(self.base)] = random_ram_address() pavone@214: outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n') pavone@214: address = base + self.disp pavone@214: if (address & 0xFFFFFF) < 0xE00000: pavone@214: if (address & 0xFFFFFF) < 0x10000: pavone@214: self.disp -= (address & 0xFFFFFF) pavone@214: else: pavone@214: self.disp += 0xE00000-(address & 0xFFFFFF) pavone@214: address = base + self.disp pavone@214: elif (address & 0xFFFFFF) > 0xFFFFFC: pavone@214: self.disp -= (address & 0xFFFFFF) - 0xFFFFFC pavone@214: address = base + self.disp pavone@214: if size != 'b' and address & 1: pavone@214: self.disp = self.disp ^ 1 pavone@214: address = base + self.disp pavone@214: minv,maxv = get_size_range(size) pavone@214: outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') pavone@214: pavone@214: def __str__(self): pavone@214: return '(' + str(self.disp) + ', ' + str(self.base) + ')' pavone@214: pavone@214: def consume_regs(self, program): pavone@214: self.base.consume_regs(program) pavone@214: pavone@214: class Indirect(object): pavone@214: def __init__(self, reg): pavone@214: self.reg = reg pavone@214: pavone@214: def __str__(self): pavone@214: return '(' + str(self.reg) + ')' pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: if str(self.reg) in already: pavone@214: if not valid_ram_address(already[str(self.reg)], size): pavone@214: del already[str(self.reg)] pavone@214: self.write_init(outfile, size, already) pavone@214: return pavone@214: else: pavone@214: address = already[str(self.reg)] pavone@214: else: pavone@214: address = random_ram_address() pavone@214: if size != 'b': pavone@214: address = address & 0xFFFFFFFE pavone@214: outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n') pavone@214: already[str(self.reg)] = address pavone@214: minv,maxv = get_size_range(size) pavone@214: outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') pavone@214: pavone@214: def consume_regs(self, program): pavone@214: self.reg.consume_regs(program) pavone@214: pavone@214: class Increment(object): pavone@214: def __init__(self, reg): pavone@214: self.reg = reg pavone@214: pavone@214: def __str__(self): pavone@214: return '(' + str(self.reg) + ')+' pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: if str(self.reg) in already: pavone@214: if not valid_ram_address(already[str(self.reg)], size): pavone@214: del already[str(self.reg)] pavone@214: self.write_init(outfile, size, already) pavone@214: return pavone@214: else: pavone@214: address = already[str(self.reg)] pavone@214: else: pavone@214: address = random_ram_address() pavone@214: if size != 'b': pavone@214: address = address & 0xFFFFFFFE pavone@214: outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n') pavone@214: already[str(self.reg)] = address pavone@214: minv,maxv = get_size_range(size) pavone@214: outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') pavone@214: pavone@214: def consume_regs(self, program): pavone@214: self.reg.consume_regs(program) pavone@214: pavone@214: class Decrement(object): pavone@214: def __init__(self, reg): pavone@214: self.reg = reg pavone@214: pavone@214: def __str__(self): pavone@214: return '-(' + str(self.reg) + ')' pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: if str(self.reg) in already: pavone@214: if not valid_ram_address(already[str(self.reg)]- 4 if size == 'l' else 2 if size == 'w' else 1, size): pavone@214: del already[str(self.reg)] pavone@214: self.write_init(outfile, size, already) pavone@214: return pavone@214: else: pavone@214: address = already[str(self.reg)] pavone@214: else: pavone@214: address = random_ram_address(mina=0xE00004) pavone@214: if size != 'b': pavone@214: address = address & 0xFFFFFFFE pavone@214: outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n') pavone@214: already[str(self.reg)] = address pavone@214: minv,maxv = get_size_range(size) pavone@214: outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') pavone@214: pavone@214: def consume_regs(self, program): pavone@214: self.reg.consume_regs(program) pavone@214: pavone@214: class Absolute(object): pavone@214: def __init__(self, address, size): pavone@214: self.address = address pavone@214: self.size = size pavone@214: pavone@214: def __str__(self): pavone@214: return '(' + str(self.address) + ').' + self.size pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: minv,maxv = get_size_range(size) pavone@214: outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', '+str(self)+'\n') pavone@214: pavone@214: def consume_regs(self, program): pavone@214: pass pavone@214: pavone@214: class Immediate(object): pavone@214: def __init__(self, value): pavone@214: self.value = value pavone@214: pavone@214: def __str__(self): pavone@214: return '#' + str(self.value) pavone@214: pavone@214: def write_init(self, outfile, size, already): pavone@214: pass pavone@214: pavone@214: def consume_regs(self, program): pavone@214: pass pavone@214: pavone@214: all_dregs = [Register('d', i) for i in range(0, 8)] pavone@214: all_aregs = [Register('a', i) for i in range(0, 8)] pavone@214: all_indirect = [Indirect(reg) for reg in all_aregs] pavone@214: all_predec = [Decrement(reg) for reg in all_aregs] pavone@214: all_postinc = [Increment(reg) for reg in all_aregs] pavone@214: from random import randint pavone@214: def all_indexed(): pavone@214: return [Indexed(base, index, index_size, randint(-128, 127)) for base in all_aregs for index in all_dregs + all_aregs for index_size in ('w','l')] pavone@214: pavone@214: def all_disp(): pavone@214: return [Displacement(base, randint(-32768, 32767)) for base in all_aregs] pavone@214: pavone@214: def rand_pc_disp(): pavone@214: return [Displacement(Register('pc', 0), randint(-32768, -1024)) for x in xrange(0, 8)] pavone@214: pavone@214: def all_pc_indexed(): pavone@214: return [Indexed(Register('pc', 0), index, index_size, randint(-128, 127)) for index in all_dregs + all_aregs for index_size in ('w','l')] pavone@214: pavone@214: def rand_abs_short(): pavone@214: return [Absolute(0xFFFF8000 + randint(0, 32767), 'w') for x in xrange(0, 8)] pavone@214: pavone@214: def rand_abs_long(): pavone@214: return [Absolute(0xFF0000 + randint(0, 65535), 'l') for x in xrange(0, 8)] pavone@214: pavone@214: def get_size_range(size): pavone@214: if size == 'b': pavone@214: return (-128, 127) pavone@214: elif size == 'w': pavone@214: return (-32768, 32767) pavone@214: else: pavone@214: return (-2147483648, 2147483647) pavone@214: pavone@214: def rand_immediate(size): pavone@214: minv,maxv = get_size_range(size) pavone@214: pavone@214: return [Immediate(randint(minv, maxv)) for x in xrange(0,8)] pavone@214: pavone@214: def get_variations(mode, size): pavone@214: mapping = { pavone@214: 'd':all_dregs, pavone@214: 'a':all_aregs, pavone@214: '(a)':all_indirect, pavone@214: '-(a)':all_predec, pavone@214: '(a)+':all_postinc, pavone@214: '(n,a)':all_disp, pavone@214: '(n,a,x)':all_indexed, pavone@214: '(n,pc)':rand_pc_disp, pavone@214: '(n,pc,x)':all_pc_indexed, pavone@214: '(n).w':rand_abs_short, pavone@214: '(n).l':rand_abs_long pavone@214: } pavone@214: if mode in mapping: pavone@214: ret = mapping[mode] pavone@214: if type(ret) != list: pavone@214: ret = ret() pavone@214: return ret pavone@214: elif mode == '#n': pavone@214: return rand_immediate(size) pavone@214: elif mode.startswith('#(') and mode.endswith(')'): pavone@214: inner = mode[2:-1] pavone@224: start,sep,end = inner.rpartition('-') pavone@220: start,end = int(start),int(end) pavone@220: if end-start > 16: pavone@220: return [Immediate(randint(start, end)) for x in range(0,8)] pavone@220: else: pavone@220: return [Immediate(num) for num in range(start, end+1)] pavone@217: else: pavone@217: print "Don't know what to do with source type", mode pavone@217: return None pavone@214: pavone@214: class Inst2Op(object): pavone@214: def __init__(self, name, size, src, dst): pavone@214: self.name = name pavone@214: self.size = size pavone@214: self.src = src pavone@214: self.dst = dst pavone@214: pavone@214: def __str__(self): pavone@214: return self.name + '.' + self.size + ' ' + str(self.src) + ', ' + str(self.dst) pavone@214: pavone@214: def write_init(self, outfile, already): pavone@214: self.src.write_init(outfile, self.size, already) pavone@214: self.dst.write_init(outfile, self.size, already) pavone@214: pavone@214: def invalidate_dest(self, already): pavone@214: if type(self.dst) == Register: pavone@214: del already[str(self.dst)] pavone@214: pavone@214: def save_result(self, reg, always): pavone@214: if always or type(self.dst) != Register: pavone@217: if type(self.dst) == Decrement: pavone@217: src = Increment(self.dst.reg) pavone@217: elif type(self.dst) == Increment: pavone@217: src = Decrement(self.dst.reg) pavone@217: else: pavone@217: src = self.dst pavone@217: return 'move.' + self.size + ' ' + str(src) + ', ' + str(reg) pavone@214: else: pavone@214: return '' pavone@214: pavone@214: def consume_regs(self, program): pavone@214: self.src.consume_regs(program) pavone@214: self.dst.consume_regs(program) pavone@214: pavone@439: class Inst1Op(Inst2Op): pavone@439: def __init__(self, name, size, dst): pavone@439: super(Inst1Op, self).__init__(name, size, dummy_op, dst) pavone@439: pavone@439: def __str__(self): pavone@439: return self.name + '.' + self.size + ' ' + str(self.dst) pavone@439: pavone@214: class Entry(object): pavone@214: def __init__(self, line): pavone@214: fields = split_fields(line) pavone@214: self.name = fields[0] pavone@214: sizes = fields[1] pavone@214: sources = fields[2].split(';') pavone@439: if len(fields) > 3: pavone@439: dests = fields[3].split(';') pavone@439: else: pavone@439: dests = None pavone@214: combos = [] pavone@214: for size in sizes: pavone@214: for source in sources: pavone@214: if size != 'b' or source != 'a': pavone@439: if dests: pavone@439: for dest in dests: pavone@439: if size != 'b' or dest != 'a': pavone@439: combos.append((size, source, dest)) pavone@439: else: pavone@439: combos.append((size, None, source)) pavone@214: self.cases = combos pavone@214: pavone@214: def programs(self): pavone@214: res = [] pavone@214: for (size, src, dst) in self.cases: pavone@214: dests = get_variations(dst, size) pavone@439: if src: pavone@439: sources = get_variations(src, size) pavone@439: for source in sources: pavone@439: for dest in dests: pavone@439: res.append(Program(Inst2Op(self.name, size, source, dest))) pavone@439: else: pavone@214: for dest in dests: pavone@439: res.append(Program(Inst1Op(self.name, size, dest))) pavone@214: return res pavone@214: pavone@214: def process_entries(f): pavone@214: entries = [] pavone@214: for line in f: pavone@214: if not line.startswith('Name') and not line.startswith('#') and len(line.strip()) > 0: pavone@214: entries.append(Entry(line)) pavone@214: return entries pavone@214: pavone@224: from os import path, mkdir pavone@214: def main(args): pavone@214: entries = process_entries(open('testcases.txt')) pavone@214: for entry in entries: pavone@214: programs = entry.programs() pavone@214: for program in programs: pavone@224: dname = program.dirname() pavone@224: if not path.exists('generated_tests/' + dname): pavone@224: mkdir('generated_tests/' + dname) pavone@224: f = open('generated_tests/' + dname + '/' + program.name() + '.s68', 'w') pavone@214: program.write_rom_test(f) pavone@214: f.close() pavone@214: pavone@214: if __name__ == '__main__': pavone@214: import sys pavone@214: main(sys.argv) pavone@214: