From a560982b7e561bcd7cbb6d120b6144a59233f1ae Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 3 Feb 2018 01:44:14 +0100 Subject: [PATCH] incrdecr codegen --- il65/compile.py | 4 ++- il65/emit/incrdecr.py | 73 +++++++++++++++++++++++++++++++++++------ il65/lib/il65lib.ill | 75 +++++++++++++++++++++++++++++++++++++++++++ todo.ill | 28 +++++++++++++--- 4 files changed, 165 insertions(+), 15 deletions(-) diff --git a/il65/compile.py b/il65/compile.py index b5061fdcd..4feb3a4bf 100644 --- a/il65/compile.py +++ b/il65/compile.py @@ -83,7 +83,6 @@ class PlyParser: if node.datatype == DataType.FLOAT: raise ParseError("floating point numbers not enabled via option", node.sourceref) - def coerce_values(self, module: Module) -> None: for node in module.all_nodes(): try: @@ -182,6 +181,9 @@ class PlyParser: elif isinstance(node, VarDef): if node.value is not None and not node.value.is_compile_constant(): raise ParseError("variable initialization value should be a compile-time constant", node.value.sourceref) + elif isinstance(node, Dereference): + if isinstance(node.operand, Register) and node.operand.datatype == DataType.BYTE: + raise ParseError("can't dereference a single register; use a register pair", node.operand.sourceref) previous_stmt = node def check_subroutine_arguments(self, call: SubCall, subdef: Subroutine) -> None: diff --git a/il65/emit/incrdecr.py b/il65/emit/incrdecr.py index b52b1a9ee..fc551bb1e 100644 --- a/il65/emit/incrdecr.py +++ b/il65/emit/incrdecr.py @@ -8,9 +8,9 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0 """ from typing import Callable -from ..plyparse import Scope, VarType, VarDef, Register, IncrDecr, SymbolName, Dereference, datatype_of +from ..plyparse import Scope, VarType, VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue, datatype_of from ..datatypes import DataType, REGISTER_BYTES -from . import CodeError, preserving_registers +from . import CodeError, preserving_registers, to_hex def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope, floats_enabled: bool) -> None: @@ -25,6 +25,7 @@ def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope, floats_enable target = symdef # type: ignore else: raise CodeError("cannot incr/decr this", symdef) + if stmt.howmuch > 255: if datatype_of(target, scope) != DataType.FLOAT: raise CodeError("only supports integer incr/decr by up to 255 for now") @@ -212,13 +213,65 @@ def generate_incrdecr(out: Callable, stmt: IncrDecr, scope: Scope, floats_enable raise CodeError("cannot in/decrement memory of type " + str(target.datatype), stmt.howmuch) elif isinstance(target, Dereference): - if target.datatype == DataType.BYTE: - pass # @todo - elif target.datatype == DataType.WORD: - pass # @todo - elif target.datatype == DataType.FLOAT: - pass # @todo + if isinstance(target.operand, (LiteralValue, SymbolName)): + if isinstance(target.operand, LiteralValue): + what = to_hex(target.operand.value) + else: + symdef = target.my_scope().lookup(target.operand.name) + if isinstance(symdef, VarDef) and symdef.vartype == VarType.MEMORY: + what = to_hex(symdef.value.value) # type: ignore + else: + what = target.operand.name + if stmt.howmuch == 1: + if target.datatype == DataType.FLOAT: + if not floats_enabled: + raise CodeError("floating point numbers not enabled via option") + with preserving_registers({'A', 'X', 'Y'}, scope, out, loads_a_within=True): + out("\vldx " + what) + out("\vldy {:s}+1".format(what)) + if stmt.operator == "++": + out("\vjsr c64flt.float_add_one") + else: + out("\vjsr c64flt.float_sub_one") + else: + with preserving_registers({'A', 'Y'}, scope, out, loads_a_within=True): + out("\vlda " + what) + out("\vsta c64.SCRATCH_ZPWORD1") + out("\vlda {:s}+1".format(what)) + out("\vsta c64.SCRATCH_ZPWORD1+1") + if target.datatype == DataType.BYTE: + if stmt.operator == "++": + out("\vjsr il65_lib.incr_deref_byte") + else: + out("\vjsr il65_lib.decr_deref_byte") + elif target.datatype == DataType.WORD: + if stmt.operator == "++": + out("\vjsr il65_lib.incr_deref_word") + else: + out("\vjsr il65_lib.decr_deref_word") + else: + raise CodeError("cannot inc/decrement dereferenced literal of type " + str(target.datatype), stmt) + else: + raise CodeError("can't inc/dec this by something else as 1 right now", stmt) # XXX + elif isinstance(target.operand, Register): + if target.operand.datatype == DataType.BYTE: + raise CodeError("can't dereference just a single register, need combined register", target) + reg = target.operand.name + if stmt.howmuch == 1: + if stmt.operator == "++": + out("\vclc") + else: + out("\vsec") + if target.datatype == DataType.BYTE: + with preserving_registers({'A', 'Y'}, scope, out, loads_a_within=True): + out("\vjsr il65_lib.incrdecr_deref_byte_reg_" + reg) + else: + with preserving_registers({'A', 'Y'}, scope, out, loads_a_within=True): + out("\vjsr il65_lib.incrdecr_deref_word_reg_" + reg) + else: + raise CodeError("can't inc/dec this by something else as 1 right now", stmt) # XXX else: - raise CodeError("cannot inc/decrement dereferenced " + str(target.datatype), stmt) + raise TypeError("invalid dereference target type", target) + else: - raise CodeError("cannot inc/decrement", target) # @todo support more such as [dereference]++ + raise CodeError("cannot inc/decrement", target) # @todo support more diff --git a/il65/lib/il65lib.ill b/il65/lib/il65lib.ill index 5b3eef1a7..823f2cb2f 100644 --- a/il65/lib/il65lib.ill +++ b/il65/lib/il65lib.ill @@ -167,6 +167,81 @@ _mod2b lda #0 ; self-modified _done rts +; increments/decrements a byte referenced by indirect register pair by 1 +; clobbers A/Y, Carry flag determines incr or decr +incrdecr_deref_byte_reg_AX + sta SCRATCH_ZPWORD1 + stx SCRATCH_ZPWORD1+1 + bcc incr_deref_byte + bcs decr_deref_byte +incrdecr_deref_byte_reg_AY + sta SCRATCH_ZPWORD1 + sty SCRATCH_ZPWORD1+1 + bcc incr_deref_byte + bcs decr_deref_byte +incrdecr_deref_byte_reg_XY + stx SCRATCH_ZPWORD1 + sty SCRATCH_ZPWORD1+1 + bcs decr_deref_byte + +incr_deref_byte + ldy #0 + lda (c64.SCRATCH_ZPWORD1), y + adc #1 ; carry's cleared already + sta (c64.SCRATCH_ZPWORD1), y + rts +decr_deref_byte + ldy #0 + lda (c64.SCRATCH_ZPWORD1), y + sbc #1 ; carry's set already + sta (c64.SCRATCH_ZPWORD1), y + rts + +; increments/decrements a word referenced by indirect register pair by 1 +; clobbers A/Y, Carry flag determines incr or decr +incrdecr_deref_word_reg_AX + sta SCRATCH_ZPWORD1 + stx SCRATCH_ZPWORD1+1 + bcc incr_deref_word + bcs decr_deref_word +incrdecr_deref_word_reg_AY + sta SCRATCH_ZPWORD1 + sty SCRATCH_ZPWORD1+1 + bcc incr_deref_word + bcs decr_deref_word +incrdecr_deref_word_reg_XY + stx SCRATCH_ZPWORD1 + sty SCRATCH_ZPWORD1+1 + bcs decr_deref_word + +incr_deref_word + ldy #0 + lda (c64.SCRATCH_ZPWORD1), y + adc #1 ; carry's cleared already + sta (c64.SCRATCH_ZPWORD1), y + bcc + + iny + lda (c64.SCRATCH_ZPWORD1), y + adc #0 ; carry is set + sta (c64.SCRATCH_ZPWORD1), y ++ rts + +decr_deref_word + ldy #0 + lda (c64.SCRATCH_ZPWORD1), y + bne + + pha + iny + lda (c64.SCRATCH_ZPWORD1), y + sbc #1 ; carry's set already + sta (c64.SCRATCH_ZPWORD1), y + dey + pla ++ sec + sbc #1 + sta (c64.SCRATCH_ZPWORD1), y + rts + } %noreturn diff --git a/todo.ill b/todo.ill index c4c001d2d..b7db904de 100644 --- a/todo.ill +++ b/todo.ill @@ -1,3 +1,4 @@ +%output basic %import c64lib ~ main { @@ -8,6 +9,8 @@ ; var .float initfloat2 = -555.666 ; @todo constant-fold before semantic check / fix float parse? ; var .text guess = '?' * 80 ; @todo constant-fold before semantic check const .word border = $d020 + var .word border2 = $d020 + memory screenm = $d021 start: ; @todo float incrdecr/augassign @@ -18,10 +21,27 @@ start: ; flt += 1000.1 ; flt *= 2.34 - [border] ++; @todo suport incr/decr on deref constant - [$d020] ++ ; @todo suport incr/decr on deref memory - [XY] ++ - [X] ++ + screenm ++ + screenm ++ + border2 ++ + border2 ++ + screenm -- + border2 -- + + [$55 .float] ++ + [screenm .float]-- + + ;[border] ++ + ;[border] ++ + ;[border] -- + [$d020] ++ + [$d020] ++ + [$d020] -- + ;[border2] ++ ;@todo suport incr/decr on deref var WORD + ;[border2] ++ ;@todo suport incr/decr on deref var WORD + ;[border2] -- ;@todo suport incr/decr on deref var WORD + ;[XY] ++ + ;[XY] -- return 44.123 }