incrdecr codegen

This commit is contained in:
Irmen de Jong 2018-02-03 01:44:14 +01:00
parent 76755cf57d
commit a560982b7e
4 changed files with 165 additions and 15 deletions

View File

@ -83,7 +83,6 @@ class PlyParser:
if node.datatype == DataType.FLOAT: if node.datatype == DataType.FLOAT:
raise ParseError("floating point numbers not enabled via option", node.sourceref) raise ParseError("floating point numbers not enabled via option", node.sourceref)
def coerce_values(self, module: Module) -> None: def coerce_values(self, module: Module) -> None:
for node in module.all_nodes(): for node in module.all_nodes():
try: try:
@ -182,6 +181,9 @@ class PlyParser:
elif isinstance(node, VarDef): elif isinstance(node, VarDef):
if node.value is not None and not node.value.is_compile_constant(): 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) 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 previous_stmt = node
def check_subroutine_arguments(self, call: SubCall, subdef: Subroutine) -> None: def check_subroutine_arguments(self, call: SubCall, subdef: Subroutine) -> None:

View File

@ -8,9 +8,9 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
""" """
from typing import Callable 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 ..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: 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 target = symdef # type: ignore
else: else:
raise CodeError("cannot incr/decr this", symdef) raise CodeError("cannot incr/decr this", symdef)
if stmt.howmuch > 255: if stmt.howmuch > 255:
if datatype_of(target, scope) != DataType.FLOAT: if datatype_of(target, scope) != DataType.FLOAT:
raise CodeError("only supports integer incr/decr by up to 255 for now") 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) raise CodeError("cannot in/decrement memory of type " + str(target.datatype), stmt.howmuch)
elif isinstance(target, Dereference): elif isinstance(target, Dereference):
if target.datatype == DataType.BYTE: if isinstance(target.operand, (LiteralValue, SymbolName)):
pass # @todo if isinstance(target.operand, LiteralValue):
elif target.datatype == DataType.WORD: what = to_hex(target.operand.value)
pass # @todo else:
elif target.datatype == DataType.FLOAT: symdef = target.my_scope().lookup(target.operand.name)
pass # @todo 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: else:
raise CodeError("cannot inc/decrement dereferenced " + str(target.datatype), stmt) raise TypeError("invalid dereference target type", target)
else: else:
raise CodeError("cannot inc/decrement", target) # @todo support more such as [dereference]++ raise CodeError("cannot inc/decrement", target) # @todo support more

View File

@ -167,6 +167,81 @@ _mod2b lda #0 ; self-modified
_done rts _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 %noreturn

View File

@ -1,3 +1,4 @@
%output basic
%import c64lib %import c64lib
~ main { ~ main {
@ -8,6 +9,8 @@
; var .float initfloat2 = -555.666 ; @todo constant-fold before semantic check / fix float parse? ; var .float initfloat2 = -555.666 ; @todo constant-fold before semantic check / fix float parse?
; var .text guess = '?' * 80 ; @todo constant-fold before semantic check ; var .text guess = '?' * 80 ; @todo constant-fold before semantic check
const .word border = $d020 const .word border = $d020
var .word border2 = $d020
memory screenm = $d021
start: start:
; @todo float incrdecr/augassign ; @todo float incrdecr/augassign
@ -18,10 +21,27 @@ start:
; flt += 1000.1 ; flt += 1000.1
; flt *= 2.34 ; flt *= 2.34
[border] ++; @todo suport incr/decr on deref constant screenm ++
[$d020] ++ ; @todo suport incr/decr on deref memory screenm ++
[XY] ++ border2 ++
[X] ++ 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 return 44.123
} }