git @ Cat's Eye Technologies SixtyPical / adb53f7
Almost compile `for` loops correctly. Chris Pressey 3 years ago
5 changed file(s) with 116 addition(s) and 52 deletion(s). Raw diff Collapse all Expand all
653653 context.assert_meaningful(instr.dest)
654654
655655 bottom, top = context.get_range(instr.dest)
656 final = instr.final.value
656657
657658 if instr.direction > 0:
658 if top >= instr.final:
659 raise RangeExceededError(self.routine, "Top of range of {} is {} but must be lower than {}".format(
660 instr.dest, top, instr.final
659 if top >= final:
660 raise RangeExceededError(instr, "Top of range of {} is {} but must be lower than {}".format(
661 instr.dest, top, final
661662 ))
662 top = instr.final
663 top = final
663664
664665 if instr.direction < 0:
665 if bottom <= instr.final:
666 raise RangeExceededError(self.routine, "Bottom of range of {} is {} but must be higher than {}".format(
667 instr.dest, bottom, instr.final
666 if bottom <= final:
667 raise RangeExceededError(instr, "Bottom of range of {} is {} but must be higher than {}".format(
668 instr.dest, bottom, final
668669 ))
669 bottom = instr.final
670 bottom = final
670671
671672 subcontext = context.clone()
672673 subcontext.set_range(instr.dest, bottom, top)
7373
7474
7575 class If(Instr):
76 value_attrs = ('src', 'inverted')
76 value_attrs = ('src', 'inverted',)
7777 child_attrs = ('block1', 'block2',)
7878
7979
8080 class Repeat(Instr):
81 value_attrs = ('src', 'inverted')
81 value_attrs = ('src', 'inverted',)
8282 child_attrs = ('block',)
8383
8484
8585 class For(Instr):
86 value_attrs = ('dest', 'direction', 'final')
86 value_attrs = ('dest', 'direction', 'final',)
8787 child_attrs = ('block',)
8888
8989
00 # encoding: UTF-8
11
2 from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, WithInterruptsOff
2 from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, For, WithInterruptsOff
33 from sixtypical.model import (
44 ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
55 TYPE_BIT, TYPE_BYTE, TYPE_WORD,
147147 return self.compile_if(instr)
148148 elif isinstance(instr, Repeat):
149149 return self.compile_repeat(instr)
150 elif isinstance(instr, For):
151 return self.compile_for(instr)
150152 elif isinstance(instr, WithInterruptsOff):
151153 return self.compile_with_interrupts_off(instr)
152154 else:
299301 else:
300302 raise UnsupportedOpcodeError(instr)
301303 elif opcode == 'inc':
302 if dest == REG_X:
303 self.emitter.emit(INX())
304 elif dest == REG_Y:
305 self.emitter.emit(INY())
306 else:
307 self.emitter.emit(INC(Absolute(self.get_label(dest.name))))
304 self.compile_inc(instr, instr.dest)
308305 elif opcode == 'dec':
309 if dest == REG_X:
310 self.emitter.emit(DEX())
311 elif dest == REG_Y:
312 self.emitter.emit(DEY())
313 else:
314 self.emitter.emit(DEC(Absolute(self.get_label(dest.name))))
306 self.compile_dec(instr, instr.dest)
315307 elif opcode == 'cmp':
316 cls = {
317 'a': CMP,
318 'x': CPX,
319 'y': CPY,
320 }.get(dest.name)
321 if cls is None:
322 raise UnsupportedOpcodeError(instr)
323 if isinstance(src, ConstantRef):
324 self.emitter.emit(cls(Immediate(Byte(src.value))))
325 else:
326 self.emitter.emit(cls(Absolute(self.get_label(src.name))))
308 self.compile_cmp(instr, instr.src, instr.dest)
327309 elif opcode in ('and', 'or', 'xor',):
328310 cls = {
329311 'and': AND,
368350 else:
369351 raise NotImplementedError
370352 elif opcode == 'copy':
371 self.compile_copy_op(instr)
353 self.compile_copy(instr, instr.src, instr.dest)
372354 elif opcode == 'trash':
373355 pass
374356 else:
375357 raise NotImplementedError(opcode)
376358
377 def compile_copy_op(self, instr):
378
379 opcode = instr.opcode
380 dest = instr.dest
381 src = instr.src
382
359 def compile_cmp(self, instr, src, dest):
360 """`instr` is only for reporting purposes"""
361 cls = {
362 'a': CMP,
363 'x': CPX,
364 'y': CPY,
365 }.get(dest.name)
366 if cls is None:
367 raise UnsupportedOpcodeError(instr)
368 if isinstance(src, ConstantRef):
369 self.emitter.emit(cls(Immediate(Byte(src.value))))
370 else:
371 self.emitter.emit(cls(Absolute(self.get_label(src.name))))
372
373 def compile_inc(self, instr, dest):
374 """`instr` is only for reporting purposes"""
375 if dest == REG_X:
376 self.emitter.emit(INX())
377 elif dest == REG_Y:
378 self.emitter.emit(INY())
379 else:
380 self.emitter.emit(INC(Absolute(self.get_label(dest.name))))
381
382 def compile_dec(self, instr, dest):
383 """`instr` is only for reporting purposes"""
384 if dest == REG_X:
385 self.emitter.emit(DEX())
386 elif dest == REG_Y:
387 self.emitter.emit(DEY())
388 else:
389 self.emitter.emit(DEC(Absolute(self.get_label(dest.name))))
390
391 def compile_copy(self, instr, src, dest):
383392 if isinstance(src, ConstantRef) and isinstance(dest, IndirectRef) and src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
384393 ### copy 123, [ptr] + y
385394 dest_label = self.get_label(dest.ref.name)
539548 raise UnsupportedOpcodeError(instr)
540549 self.emitter.emit(cls(Relative(top_label)))
541550
551 def compile_for(self, instr):
552 top_label = self.emitter.make_label()
553
554 self.compile_block(instr.block)
555
556 if instr.direction > 0:
557 self.compile_inc(instr, instr.dest)
558 elif instr.direction < 0:
559 self.compile_dec(instr, instr.dest)
560 self.compile_cmp(instr, instr.final, instr.dest)
561 self.emitter.emit(BNE(Relative(top_label)))
562
542563 def compile_with_interrupts_off(self, instr):
543564 self.emitter.emit(SEI())
544565 self.compile_block(instr.block)
136136 return Defn(self.scanner.line_number, name=name, addr=addr, initial=initial, location=location)
137137
138138 def literal_int(self):
139 self.scanner.check_type('integer literal')
140 c = int(self.scanner.token)
141 self.scanner.scan()
142 return c
139 self.scanner.check_type('integer literal')
140 c = int(self.scanner.token)
141 self.scanner.scan()
142 return c
143
144 def literal_int_const(self):
145 value = self.literal_int()
146 type_ = TYPE_WORD if value > 255 else TYPE_BYTE
147 loc = ConstantRef(type_, value)
148 return loc
143149
144150 def defn_size(self):
145151 self.scanner.expect('[')
292298 self.scanner.scan()
293299 return loc
294300 elif self.scanner.on_type('integer literal'):
295 value = int(self.scanner.token)
296 type_ = TYPE_WORD if value > 255 else TYPE_BYTE
297 loc = ConstantRef(type_, value)
298 self.scanner.scan()
299 return loc
301 return self.literal_int_const()
300302 elif self.scanner.consume('word'):
301303 loc = ConstantRef(TYPE_WORD, int(self.scanner.token))
302304 self.scanner.scan()
384386 else:
385387 self.syntax_error('expected "up" or "down", found "%s"' % self.scanner.token)
386388 self.scanner.expect('to')
387 final = self.literal_int()
389 final = self.literal_int_const()
388390 block = self.block()
389391 return For(self.scanner.line_number, dest=dest, direction=direction, final=final, block=block)
390392 elif self.scanner.token in ("ld",):
350350 = $080D JMP $080D
351351 = $0810 RTS
352352
353 Compiling `for ... up to`.
354
355 | byte table[256] tab
356 |
357 | define main routine
358 | inputs tab
359 | trashes a, x, c, z, v, n
360 | {
361 | ld x, 0
362 | for x up to 15 {
363 | ld a, tab + x
364 | }
365 | }
366 = $080D LDX #$00
367 = $080F LDA $0818,X
368 = $0812 INX
369 = $0813 CPX #$10
370 = $0815 BNE $080F
371 = $0817 RTS
372
373 Compiling `for ... down to`.
374
375 | byte table[256] tab
376 |
377 | define main routine
378 | inputs tab
379 | trashes a, x, c, z, v, n
380 | {
381 | ld x, 15
382 | for x down to 0 {
383 | ld a, tab + x
384 | }
385 | }
386 = $080D LDX #$0F
387 = $080F LDA $0818,X
388 = $0812 DEX
389 = $0813 CPX #$FF
390 = $0815 BNE $080F
391 = $0817 RTS
392
353393 Indexed access.
354394
355395 | byte one