diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index d9d34ba..86c3ec3 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -75,13 +75,13 @@ two hundred and fifty-six byte constants, and sixty-five thousand five hundred and thirty-six word constants, - 0 - 1 + word 0 + word 1 ... - 65535 + word 65535 -Note that all byte constants serve double duty as word constants in that -context. +Note that if a word constant is between 256 and 65535, the leading `word` +token can be omitted. ### User-defined ### diff --git a/eg/joystick.60p b/eg/joystick.60p new file mode 100644 index 0000000..8783bd7 --- /dev/null +++ b/eg/joystick.60p @@ -0,0 +1,49 @@ +word screen @ 1024 +byte joy2 @ $dc00 + +word delta + +routine read_stick + inputs joy2 + outputs delta + trashes a, x, z, n +{ + ld x, joy2 + ld a, x + and a, 1 // up + if z { + copy $ffd8, delta // -40 + } else { + ld a, x + and a, 2 // down + if z { + copy word 40, delta + } else { + ld a, x + and a, 4 // left + if z { + copy $ffff, delta // -1 + } else { + ld a, x + and a, 8 // right + if z { + copy word 1, delta + } else { + copy word 0, delta + } + } + } + } +} + +routine main + inputs joy2 + outputs delta + trashes a, x, z, n, screen +{ + repeat { + call read_stick + copy delta, screen + ld a, 1 + } until z +} diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 5ac2aad..f8ac112 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -119,6 +119,8 @@ class Context(object): elif isinstance(ref, LocationRef): if ref not in self._meaningful: message = '%s in %s' % (ref.name, self.routine.name) + if kwargs.get('message'): + message += ' (%s)' % kwargs['message'] raise exception_class(message) else: raise NotImplementedError(ref) @@ -128,6 +130,8 @@ class Context(object): for ref in refs: if ref not in self._writeable: message = '%s in %s' % (ref.name, self.routine.name) + if kwargs.get('message'): + message += ' (%s)' % kwargs['message'] raise exception_class(message) def set_touched(self, *refs): @@ -270,9 +274,13 @@ class Analyzer(object): # probably not; if it wasn't meaningful in the first place, it # doesn't really matter if you modified it or not, coming out. for ref in context1.each_meaningful(): - context2.assert_meaningful(ref, exception_class=InconsistentInitializationError) + context2.assert_meaningful( + ref, exception_class=InconsistentInitializationError, message='initialized in block 1 but not in block 2' + ) for ref in context2.each_meaningful(): - context1.assert_meaningful(ref, exception_class=InconsistentInitializationError) + context1.assert_meaningful( + ref, exception_class=InconsistentInitializationError, message='initialized in block 2 but not in block 1' + ) context.set_from(context1) elif opcode == 'repeat': # it will always be executed at least once, so analyze it having diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index fdaee3b..838da57 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -276,17 +276,29 @@ class Compiler(object): self.emitter.emit(CLI()) elif opcode == 'copy': if src.type == TYPE_BYTE and dest.type == TYPE_BYTE: - src_label = self.labels[src.name] - dest_label = self.labels[dest.name] - self.emitter.emit(LDA(Absolute(src_label))) - self.emitter.emit(STA(Absolute(dest_label))) + if isinstance(src, ConstantRef): + raise NotImplementedError + else: + src_label = self.labels[src.name] + dest_label = self.labels[dest.name] + self.emitter.emit(LDA(Absolute(src_label))) + self.emitter.emit(STA(Absolute(dest_label))) elif src.type == TYPE_WORD and dest.type == TYPE_WORD: - src_label = self.labels[src.name] - dest_label = self.labels[dest.name] - self.emitter.emit(LDA(Absolute(src_label))) - self.emitter.emit(STA(Absolute(dest_label))) - self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) - self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) + if isinstance(src, ConstantRef): + dest_label = self.labels[dest.name] + hi = (src.value >> 8) & 255 + lo = src.value & 255 + self.emitter.emit(LDA(Immediate(Byte(hi)))) + self.emitter.emit(STA(Absolute(dest_label))) + self.emitter.emit(LDA(Immediate(Byte(lo)))) + self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) + else: + src_label = self.labels[src.name] + dest_label = self.labels[dest.name] + self.emitter.emit(LDA(Absolute(src_label))) + self.emitter.emit(STA(Absolute(dest_label))) + self.emitter.emit(LDA(Absolute(Offset(src_label, 1)))) + self.emitter.emit(STA(Absolute(Offset(dest_label, 1)))) elif isinstance(src.type, VectorType) and isinstance(dest.type, VectorType): src_label = self.labels[src.name] dest_label = self.labels[dest.name] diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index a2b3b9f..c46dbeb 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -138,7 +138,13 @@ class Parser(object): self.scanner.scan() return loc elif self.scanner.on_type('integer literal'): - loc = ConstantRef(TYPE_BYTE, int(self.scanner.token)) + value = int(self.scanner.token) + type_ = TYPE_WORD if value > 255 else TYPE_BYTE + loc = ConstantRef(type_, value) + self.scanner.scan() + return loc + elif self.scanner.consume('word'): + loc = ConstantRef(TYPE_WORD, int(self.scanner.token)) self.scanner.scan() return loc else: @@ -219,7 +225,9 @@ class Parser(object): src = self.locexpr() self.scanner.expect(',') dest = self.locexpr() - return Instr(opcode=opcode, dest=dest, src=src) + i = Instr(opcode=opcode, dest=dest, src=src) + #print repr(i) + return i elif self.scanner.consume("with"): self.scanner.expect("interrupts") self.scanner.expect("off")