comparison gentests.py @ 2449:bb6cc45518e6

Avoid address errors in generated tests
author Michael Pavone <pavone@retrodev.com>
date Sun, 18 Feb 2024 22:30:16 -0800
parents ab577e2ed66a
children 3b1b7b272311
comparison
equal deleted inserted replaced
2448:d1eec03dca09 2449:bb6cc45518e6
13 def __init__(self, instruction): 13 def __init__(self, instruction):
14 self.avail_dregs = {0,1,2,3,4,5,6,7} 14 self.avail_dregs = {0,1,2,3,4,5,6,7}
15 self.avail_aregs = {0,1,2,3,4,5,6,7} 15 self.avail_aregs = {0,1,2,3,4,5,6,7}
16 instruction.consume_regs(self) 16 instruction.consume_regs(self)
17 self.inst = instruction 17 self.inst = instruction
18 18
19 def dirname(self): 19 def dirname(self):
20 return self.inst.name + '_' + self.inst.size 20 return self.inst.name + '_' + self.inst.size
21 def name(self): 21 def name(self):
22 return str(self.inst).replace('.', '_').replace('#', '_').replace(',', '_').replace(' ', '_').replace('(', '[').replace(')', ']') 22 return str(self.inst).replace('.', '_').replace('#', '_').replace(',', '_').replace(' ', '_').replace('(', '[').replace(')', ']')
23 23
24 def write_rom_test(self, outfile): 24 def write_rom_test(self, outfile):
25 outfile.write('\tdc.l $0, start\n') 25 outfile.write('\tdc.l $0, start\n')
26 needdivzero = self.inst.name.startswith('div') 26 needdivzero = self.inst.name.startswith('div')
27 needchk = self.inst.name.startswith('chk') 27 needchk = self.inst.name.startswith('chk')
28 for i in range(0x8, 0x100, 0x4): 28 for i in range(0x8, 0x100, 0x4):
60 if 'label' in already: 60 if 'label' in already:
61 outfile.write('lbl_' + str(already['label']) + ':\n') 61 outfile.write('lbl_' + str(already['label']) + ':\n')
62 outfile.write('\t'+str(self.inst)+'\n') 62 outfile.write('\t'+str(self.inst)+'\n')
63 outfile.write('\t'+self.inst.save_result(self.get_dreg(), False) + '\n') 63 outfile.write('\t'+self.inst.save_result(self.get_dreg(), False) + '\n')
64 outfile.write('\treset\nforever:\n\tbra.s forever\n') 64 outfile.write('\treset\nforever:\n\tbra.s forever\n')
65 65
66 def consume_dreg(self, num): 66 def consume_dreg(self, num):
67 self.avail_dregs.discard(num) 67 self.avail_dregs.discard(num)
68 68
69 def consume_areg(self, num): 69 def consume_areg(self, num):
70 self.avail_aregs.discard(num) 70 self.avail_aregs.discard(num)
71 71
72 def get_dreg(self): 72 def get_dreg(self):
73 return Register('d', self.avail_dregs.pop()) 73 return Register('d', self.avail_dregs.pop())
74 74
75 class Dummy(object): 75 class Dummy(object):
76 def __str__(self): 76 def __str__(self):
84 84
85 class Register(object): 85 class Register(object):
86 def __init__(self, kind, num): 86 def __init__(self, kind, num):
87 self.kind = kind 87 self.kind = kind
88 self.num = num 88 self.num = num
89 89
90 def __str__(self): 90 def __str__(self):
91 if self.kind == 'd' or self.kind == 'a': 91 if self.kind == 'd' or self.kind == 'a':
92 return self.kind + str(self.num) 92 return self.kind + str(self.num)
93 return self.kind 93 return self.kind
94 94
95 def write_init(self, outfile, size, already): 95 def write_init(self, outfile, size, already):
96 if not str(self) in already: 96 if not str(self) in already:
97 minv,maxv = get_size_range(size) 97 minv,maxv = get_size_range(size)
98 val = randint(minv,maxv) 98 val = randint(minv,maxv)
99 already[str(self)] = val 99 already[str(self)] = val
100 outfile.write('\tmove.'+size+' #'+str(val)+', ' + str(self) + '\n') 100 outfile.write('\tmove.'+size+' #'+str(val)+', ' + str(self) + '\n')
101 101
102 def consume_regs(self, program): 102 def consume_regs(self, program):
103 if self.kind == 'd': 103 if self.kind == 'd':
104 program.consume_dreg(self.num) 104 program.consume_dreg(self.num)
105 elif self.kind == 'a': 105 elif self.kind == 'a':
106 program.consume_areg(self.num) 106 program.consume_areg(self.num)
115 def __init__(self, base, index, index_size, disp): 115 def __init__(self, base, index, index_size, disp):
116 self.base = base 116 self.base = base
117 self.index = index 117 self.index = index
118 self.index_size = index_size 118 self.index_size = index_size
119 self.disp = disp 119 self.disp = disp
120 120
121 def write_init(self, outfile, size, already): 121 def write_init(self, outfile, size, already):
122 if self.base.kind == 'pc': 122 if self.base.kind == 'pc':
123 if str(self.index) in already: 123 if str(self.index) in already:
124 index = already[str(self.index)] 124 index = already[str(self.index)]
125 if self.index_size == 'w': 125 if self.index_size == 'w':
149 self.write_init(outfile, size, already) 149 self.write_init(outfile, size, already)
150 return 150 return
151 else: 151 else:
152 base = index = already[str(self.base)] 152 base = index = already[str(self.base)]
153 else: 153 else:
154 base = index = already[str(self.base)] = random_ram_address()//2 154 base = index = already[str(self.base)] = 2 * (random_ram_address()//4)
155 outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n') 155 outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n')
156 else: 156 else:
157 if str(self.base) in already: 157 if str(self.base) in already:
158 if not valid_ram_address(already[str(self.base)]): 158 if not valid_ram_address(already[str(self.base)]):
159 del already[str(self.base)] 159 del already[str(self.base)]
170 index = index & 0xFFFF 170 index = index & 0xFFFF
171 #sign extend index 171 #sign extend index
172 if index & 0x8000: 172 if index & 0x8000:
173 index -= 65536 173 index -= 65536
174 if not valid_ram_address(base + index): 174 if not valid_ram_address(base + index):
175 index = already[str(self.index)] = randint(-64, 63) 175 index = already[str(self.index)] = randint(-32, 31) * 2
176 outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n') 176 outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n')
177 else: 177 else:
178 index = already[str(self.index)] = randint(-64, 63) 178 index = already[str(self.index)] = randint(-32, 31) * 2
179 outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n') 179 outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n')
180 address = base + index + self.disp 180 address = base + index + self.disp
181 if (address & 0xFFFFFF) < 0xE00000: 181 if (address & 0xFFFFFF) < 0xE00000:
182 if (address & 0xFFFFFF) < 128: 182 if (address & 0xFFFFFF) < 128:
183 self.disp -= (address & 0xFFFFFF) 183 self.disp -= (address & 0xFFFFFF)
198 if size != 'b' and address & 1: 198 if size != 'b' and address & 1:
199 self.disp = self.disp ^ 1 199 self.disp = self.disp ^ 1
200 address = base + index + self.disp 200 address = base + index + self.disp
201 minv,maxv = get_size_range(size) 201 minv,maxv = get_size_range(size)
202 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') 202 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
203 203
204 def __str__(self): 204 def __str__(self):
205 return '(' + str(self.disp) + ', ' + str(self.base) + ', ' + str(self.index) + '.' + self.index_size + ')' 205 return '(' + str(self.disp) + ', ' + str(self.base) + ', ' + str(self.index) + '.' + self.index_size + ')'
206 206
207 def consume_regs(self, program): 207 def consume_regs(self, program):
208 self.base.consume_regs(program) 208 self.base.consume_regs(program)
209 self.index.consume_regs(program) 209 self.index.consume_regs(program)
210 210
211 class Displacement(object): 211 class Displacement(object):
212 def __init__(self, base, disp): 212 def __init__(self, base, disp):
213 self.base = base 213 self.base = base
214 if disp & 1: 214 if disp & 1:
215 disp += 1 215 disp += 1
216 self.disp = disp 216 self.disp = disp
217 217
218 def write_init(self, outfile, size, already): 218 def write_init(self, outfile, size, already):
219 if self.base.kind == 'pc': 219 if self.base.kind == 'pc':
220 num = already.get('label', 0)+1 220 num = already.get('label', 0)+1
221 already['label'] = num 221 already['label'] = num
222 address = 'lbl_' + str(num) + ' + 2 + ' + str(self.disp) 222 address = 'lbl_' + str(num) + ' + 2 + ' + str(self.disp)
244 if size != 'b' and address & 1: 244 if size != 'b' and address & 1:
245 self.disp = self.disp ^ 1 245 self.disp = self.disp ^ 1
246 address = base + self.disp 246 address = base + self.disp
247 minv,maxv = get_size_range(size) 247 minv,maxv = get_size_range(size)
248 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') 248 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
249 249
250 def __str__(self): 250 def __str__(self):
251 return '(' + str(self.disp) + ', ' + str(self.base) + ')' 251 return '(' + str(self.disp) + ', ' + str(self.base) + ')'
252 252
253 def consume_regs(self, program): 253 def consume_regs(self, program):
254 self.base.consume_regs(program) 254 self.base.consume_regs(program)
255 255
256 class Indirect(object): 256 class Indirect(object):
257 def __init__(self, reg): 257 def __init__(self, reg):
258 self.reg = reg 258 self.reg = reg
259 259
260 def __str__(self): 260 def __str__(self):
261 return '(' + str(self.reg) + ')' 261 return '(' + str(self.reg) + ')'
262 262
263 def write_init(self, outfile, size, already): 263 def write_init(self, outfile, size, already):
264 if str(self.reg) in already: 264 if str(self.reg) in already:
265 if not valid_ram_address(already[str(self.reg)], size): 265 if not valid_ram_address(already[str(self.reg)], size):
266 del already[str(self.reg)] 266 del already[str(self.reg)]
267 self.write_init(outfile, size, already) 267 self.write_init(outfile, size, already)
274 address = address & 0xFFFFFFFE 274 address = address & 0xFFFFFFFE
275 outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n') 275 outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n')
276 already[str(self.reg)] = address 276 already[str(self.reg)] = address
277 minv,maxv = get_size_range(size) 277 minv,maxv = get_size_range(size)
278 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') 278 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
279 279
280 def consume_regs(self, program): 280 def consume_regs(self, program):
281 self.reg.consume_regs(program) 281 self.reg.consume_regs(program)
282 282
283 class Increment(object): 283 class Increment(object):
284 def __init__(self, reg): 284 def __init__(self, reg):
285 self.reg = reg 285 self.reg = reg
286 286
287 def __str__(self): 287 def __str__(self):
288 return '(' + str(self.reg) + ')+' 288 return '(' + str(self.reg) + ')+'
289 289
290 def write_init(self, outfile, size, already): 290 def write_init(self, outfile, size, already):
291 if str(self.reg) in already: 291 if str(self.reg) in already:
292 if not valid_ram_address(already[str(self.reg)], size): 292 if not valid_ram_address(already[str(self.reg)], size):
293 del already[str(self.reg)] 293 del already[str(self.reg)]
294 self.write_init(outfile, size, already) 294 self.write_init(outfile, size, already)
301 address = address & 0xFFFFFFFE 301 address = address & 0xFFFFFFFE
302 outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n') 302 outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n')
303 already[str(self.reg)] = address 303 already[str(self.reg)] = address
304 minv,maxv = get_size_range(size) 304 minv,maxv = get_size_range(size)
305 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') 305 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
306 306
307 def consume_regs(self, program): 307 def consume_regs(self, program):
308 self.reg.consume_regs(program) 308 self.reg.consume_regs(program)
309 309
310 class Decrement(object): 310 class Decrement(object):
311 def __init__(self, reg): 311 def __init__(self, reg):
312 self.reg = reg 312 self.reg = reg
313 313
314 def __str__(self): 314 def __str__(self):
315 return '-(' + str(self.reg) + ')' 315 return '-(' + str(self.reg) + ')'
316 316
317 def write_init(self, outfile, size, already): 317 def write_init(self, outfile, size, already):
318 if str(self.reg) in already: 318 if str(self.reg) in already:
319 if not valid_ram_address(already[str(self.reg)]- 4 if size == 'l' else 2 if size == 'w' else 1, size): 319 if not valid_ram_address(already[str(self.reg)]- 4 if size == 'l' else 2 if size == 'w' else 1, size):
320 del already[str(self.reg)] 320 del already[str(self.reg)]
321 self.write_init(outfile, size, already) 321 self.write_init(outfile, size, already)
328 address = address & 0xFFFFFFFE 328 address = address & 0xFFFFFFFE
329 outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n') 329 outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n')
330 already[str(self.reg)] = address 330 already[str(self.reg)] = address
331 minv,maxv = get_size_range(size) 331 minv,maxv = get_size_range(size)
332 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n') 332 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
333 333
334 def consume_regs(self, program): 334 def consume_regs(self, program):
335 self.reg.consume_regs(program) 335 self.reg.consume_regs(program)
336 336
337 class Absolute(object): 337 class Absolute(object):
338 def __init__(self, address, size): 338 def __init__(self, address, size):
339 self.address = address 339 self.address = address
340 self.size = size 340 self.size = size
341 341
342 def __str__(self): 342 def __str__(self):
343 return '(' + str(self.address) + ').' + self.size 343 return '(' + str(self.address) + ').' + self.size
344 344
345 def write_init(self, outfile, size, already): 345 def write_init(self, outfile, size, already):
346 minv,maxv = get_size_range(size) 346 minv,maxv = get_size_range(size)
347 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', '+str(self)+'\n') 347 outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', '+str(self)+'\n')
348 348
349 def consume_regs(self, program): 349 def consume_regs(self, program):
350 pass 350 pass
351 351
352 class Immediate(object): 352 class Immediate(object):
353 def __init__(self, value): 353 def __init__(self, value):
354 self.value = value 354 self.value = value
355 355
356 def __str__(self): 356 def __str__(self):
357 return '#' + str(self.value) 357 return '#' + str(self.value)
358 358
359 def write_init(self, outfile, size, already): 359 def write_init(self, outfile, size, already):
360 pass 360 pass
361 361
362 def consume_regs(self, program): 362 def consume_regs(self, program):
363 pass 363 pass
364 364
365 all_dregs = [Register('d', i) for i in range(0, 8)] 365 all_dregs = [Register('d', i) for i in range(0, 8)]
366 all_aregs = [Register('a', i) for i in range(0, 8)] 366 all_aregs = [Register('a', i) for i in range(0, 8)]
367 all_indirect = [Indirect(reg) for reg in all_aregs] 367 all_indirect = [Indirect(reg) for reg in all_aregs]
368 all_predec = [Decrement(reg) for reg in all_aregs] 368 all_predec = [Decrement(reg) for reg in all_aregs]
369 all_postinc = [Increment(reg) for reg in all_aregs] 369 all_postinc = [Increment(reg) for reg in all_aregs]
394 else: 394 else:
395 return (-2147483648, 2147483647) 395 return (-2147483648, 2147483647)
396 396
397 def rand_immediate(size): 397 def rand_immediate(size):
398 minv,maxv = get_size_range(size) 398 minv,maxv = get_size_range(size)
399 399
400 return [Immediate(randint(minv, maxv)) for x in range(0,8)] 400 return [Immediate(randint(minv, maxv)) for x in range(0,8)]
401 401
402 def get_variations(mode, size): 402 def get_variations(mode, size):
403 mapping = { 403 mapping = {
404 'd':all_dregs, 404 'd':all_dregs,
429 else: 429 else:
430 return [Immediate(num) for num in range(start, end+1)] 430 return [Immediate(num) for num in range(start, end+1)]
431 else: 431 else:
432 print("Don't know what to do with source type", mode) 432 print("Don't know what to do with source type", mode)
433 return None 433 return None
434 434
435 class Inst2Op(object): 435 class Inst2Op(object):
436 def __init__(self, name, size, src, dst): 436 def __init__(self, name, size, src, dst):
437 self.name = name 437 self.name = name
438 self.size = size 438 self.size = size
439 self.src = src 439 self.src = src
440 self.dst = dst 440 self.dst = dst
441 441
442 def __str__(self): 442 def __str__(self):
443 return self.name + '.' + self.size + ' ' + str(self.src) + ', ' + str(self.dst) 443 return self.name + '.' + self.size + ' ' + str(self.src) + ', ' + str(self.dst)
444 444
445 def write_init(self, outfile, already): 445 def write_init(self, outfile, already):
446 self.src.write_init(outfile, self.size, already) 446 self.src.write_init(outfile, self.size, already)
447 self.dst.write_init(outfile, self.size, already) 447 self.dst.write_init(outfile, self.size, already)
448 448
449 def invalidate_dest(self, already): 449 def invalidate_dest(self, already):
450 if type(self.dst) == Register: 450 if type(self.dst) == Register:
451 del already[str(self.dst)] 451 del already[str(self.dst)]
452 452
453 def save_result(self, reg, always): 453 def save_result(self, reg, always):
454 if always or type(self.dst) != Register: 454 if always or type(self.dst) != Register:
455 if type(self.dst) == Decrement: 455 if type(self.dst) == Decrement:
456 src = Increment(self.dst.reg) 456 src = Increment(self.dst.reg)
457 elif type(self.dst) == Increment: 457 elif type(self.dst) == Increment:
459 else: 459 else:
460 src = self.dst 460 src = self.dst
461 return 'move.' + self.size + ' ' + str(src) + ', ' + str(reg) 461 return 'move.' + self.size + ' ' + str(src) + ', ' + str(reg)
462 else: 462 else:
463 return '' 463 return ''
464 464
465 def consume_regs(self, program): 465 def consume_regs(self, program):
466 self.src.consume_regs(program) 466 self.src.consume_regs(program)
467 self.dst.consume_regs(program) 467 self.dst.consume_regs(program)
468 468
469 class Inst1Op(Inst2Op): 469 class Inst1Op(Inst2Op):
470 def __init__(self, name, size, dst): 470 def __init__(self, name, size, dst):
471 super(Inst1Op, self).__init__(name, size, dummy_op, dst) 471 super(Inst1Op, self).__init__(name, size, dummy_op, dst)
472 472
473 def __str__(self): 473 def __str__(self):
474 return self.name + '.' + self.size + ' ' + str(self.dst) 474 return self.name + '.' + self.size + ' ' + str(self.dst)
475 475
476 class Entry(object): 476 class Entry(object):
477 def __init__(self, line): 477 def __init__(self, line):
492 if size != 'b' or dest != 'a': 492 if size != 'b' or dest != 'a':
493 combos.append((size, source, dest)) 493 combos.append((size, source, dest))
494 else: 494 else:
495 combos.append((size, None, source)) 495 combos.append((size, None, source))
496 self.cases = combos 496 self.cases = combos
497 497
498 def programs(self): 498 def programs(self):
499 res = [] 499 res = []
500 for (size, src, dst) in self.cases: 500 for (size, src, dst) in self.cases:
501 dests = get_variations(dst, size) 501 dests = get_variations(dst, size)
502 if src: 502 if src:
506 res.append(Program(Inst2Op(self.name, size, source, dest))) 506 res.append(Program(Inst2Op(self.name, size, source, dest)))
507 else: 507 else:
508 for dest in dests: 508 for dest in dests:
509 res.append(Program(Inst1Op(self.name, size, dest))) 509 res.append(Program(Inst1Op(self.name, size, dest)))
510 return res 510 return res
511 511
512 def process_entries(f): 512 def process_entries(f):
513 entries = [] 513 entries = []
514 for line in f: 514 for line in f:
515 if not line.startswith('Name') and not line.startswith('#') and len(line.strip()) > 0: 515 if not line.startswith('Name') and not line.startswith('#') and len(line.strip()) > 0:
516 entries.append(Entry(line)) 516 entries.append(Entry(line))
526 if not path.exists('generated_tests/' + dname): 526 if not path.exists('generated_tests/' + dname):
527 mkdir('generated_tests/' + dname) 527 mkdir('generated_tests/' + dname)
528 f = open('generated_tests/' + dname + '/' + program.name() + '.s68', 'w') 528 f = open('generated_tests/' + dname + '/' + program.name() + '.s68', 'w')
529 program.write_rom_test(f) 529 program.write_rom_test(f)
530 f.close() 530 f.close()
531 531
532 if __name__ == '__main__': 532 if __name__ == '__main__':
533 import sys 533 import sys
534 main(sys.argv) 534 main(sys.argv)
535 535