Mercurial > repos > blastem
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 |