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:
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:

View File

@ -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

View File

@ -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

View File

@ -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
}