mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
codegen
This commit is contained in:
parent
d18876ee70
commit
938c541cc2
@ -6,9 +6,9 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||
"""
|
||||
|
||||
from typing import Callable
|
||||
from ..plyparse import Scope, Assignment, AugAssignment, Register, LiteralValue, SymbolName, VarDef
|
||||
from ..plyparse import Scope, Assignment, AugAssignment, Register, LiteralValue, SymbolName, VarDef, Dereference
|
||||
from . import CodeError, preserving_registers, to_hex, Context
|
||||
from ..datatypes import REGISTER_BYTES, VarType
|
||||
from ..datatypes import REGISTER_BYTES, VarType, DataType
|
||||
from ..compile import Zeropage
|
||||
|
||||
|
||||
@ -32,115 +32,188 @@ def generate_aug_assignment(ctx: Context) -> None:
|
||||
if isinstance(rvalue, LiteralValue):
|
||||
if type(rvalue.value) is int:
|
||||
if 0 <= rvalue.value <= 255:
|
||||
_generate_aug_reg_constant_int(out, lvalue, stmt.operator, rvalue.value, "", ctx.scope)
|
||||
if stmt.operator not in ("<<=", ">>=") or rvalue.value != 0:
|
||||
_generate_aug_reg_int(out, lvalue, stmt.operator, rvalue.value, "", ctx.scope)
|
||||
else:
|
||||
raise CodeError("aug. assignment value must be 0..255", rvalue)
|
||||
else:
|
||||
raise CodeError("constant integer literal or variable required for now", rvalue) # XXX
|
||||
elif isinstance(rvalue, SymbolName):
|
||||
symdef = ctx.scope.lookup(rvalue.name)
|
||||
if isinstance(symdef, VarDef) and symdef.vartype == VarType.CONST and symdef.datatype.isinteger():
|
||||
if 0 <= symdef.value.const_value() <= 255: # type: ignore
|
||||
_generate_aug_reg_constant_int(out, lvalue, stmt.operator, 0, symdef.name, ctx.scope)
|
||||
if isinstance(symdef, VarDef):
|
||||
if symdef.vartype == VarType.CONST:
|
||||
if symdef.datatype.isinteger() and 0 <= symdef.value.const_value() <= 255: # type: ignore
|
||||
_generate_aug_reg_int(out, lvalue, stmt.operator, symdef.value.const_value(), "", ctx.scope) # type: ignore
|
||||
else:
|
||||
raise CodeError("aug. assignment value must be integer 0..255", rvalue)
|
||||
elif symdef.datatype == DataType.BYTE:
|
||||
_generate_aug_reg_int(out, lvalue, stmt.operator, 0, symdef.name, ctx.scope)
|
||||
else:
|
||||
raise CodeError("aug. assignment value must be 0..255", rvalue)
|
||||
raise CodeError("variable must be of type byte for now", rvalue) # XXX
|
||||
else:
|
||||
raise CodeError("constant integer literal or variable required for now", rvalue) # XXX
|
||||
raise CodeError("can only use variable name as symbol for aug assign rvalue", rvalue)
|
||||
elif isinstance(rvalue, Register):
|
||||
# @todo check value range (single register; 0-255) @todo support combined registers
|
||||
if lvalue.datatype == DataType.BYTE and rvalue.datatype == DataType.WORD:
|
||||
raise CodeError("cannot assign a combined 16-bit register to a single 8-bit register", rvalue)
|
||||
_generate_aug_reg_reg(out, lvalue, stmt.operator, rvalue, ctx.scope)
|
||||
elif isinstance(rvalue, Dereference):
|
||||
if isinstance(rvalue.operand, (LiteralValue, SymbolName)):
|
||||
if isinstance(rvalue.operand, LiteralValue):
|
||||
what = to_hex(rvalue.operand.value)
|
||||
else:
|
||||
symdef = rvalue.my_scope().lookup(rvalue.operand.name)
|
||||
if isinstance(symdef, VarDef) and symdef.vartype == VarType.MEMORY:
|
||||
what = to_hex(symdef.value.value) # type: ignore
|
||||
else:
|
||||
what = rvalue.operand.name
|
||||
out("\vpha\n\vtya\n\vpha") # save A, Y on stack
|
||||
out("\vlda " + what)
|
||||
out("\vsta il65_lib.SCRATCH_ZPWORD1")
|
||||
out("\vlda {:s}+1".format(what))
|
||||
out("\vsta il65_lib.SCRATCH_ZPWORD1+1")
|
||||
out("\vldy #0")
|
||||
out("\vlda (il65_lib.SCRATCH_ZPWORD1), y")
|
||||
a_reg = Register(name="A", sourceref=stmt.sourceref) # type: ignore
|
||||
_generate_aug_reg_reg(out, lvalue, stmt.operator, a_reg, ctx.scope)
|
||||
out("\vst{:s} il65_lib.SCRATCH_ZP1".format(lvalue.name.lower()))
|
||||
out("\vpla\n\vtay\n\vpla") # restore A, Y from stack
|
||||
out("\vld{:s} il65_lib.SCRATCH_ZP1".format(lvalue.name.lower()))
|
||||
elif isinstance(rvalue.operand, Register):
|
||||
assert rvalue.operand.datatype == DataType.WORD
|
||||
if rvalue.datatype != DataType.BYTE:
|
||||
raise CodeError("aug. assignment value must be a byte, 0..255", rvalue)
|
||||
reg = rvalue.operand.name
|
||||
out("\vst{:s} il65_lib.SCRATCH_ZPWORD1".format(reg[0].lower()))
|
||||
out("\vst{:s} il65_lib.SCRATCH_ZPWORD1+1".format(reg[1].lower()))
|
||||
out("\vpha\n\vtya\n\vpha") # save A, Y on stack
|
||||
out("\vldy #0")
|
||||
out("\vlda (il65_lib.SCRATCH_ZPWORD1), y")
|
||||
a_reg = Register(name="A", sourceref=stmt.sourceref) # type: ignore
|
||||
_generate_aug_reg_reg(out, lvalue, stmt.operator, a_reg, ctx.scope)
|
||||
if lvalue.name != 'X':
|
||||
out("\vst{:s} il65_lib.SCRATCH_ZP1".format(lvalue.name.lower()))
|
||||
out("\vpla\n\vtay\n\vpla") # restore A, Y from stack
|
||||
if lvalue.name != 'X':
|
||||
out("\vld{:s} il65_lib.SCRATCH_ZP1".format(lvalue.name.lower()))
|
||||
else:
|
||||
raise CodeError("invalid dereference operand type", rvalue)
|
||||
else:
|
||||
# @todo Register += symbolname / dereference , _generate_aug_reg_mem?
|
||||
raise CodeError("invalid rvalue for aug. assignment on register", rvalue)
|
||||
raise CodeError("invalid rvalue type", rvalue)
|
||||
else:
|
||||
raise CodeError("aug. assignment only implemented for registers for now", stmt.sourceref) # XXX
|
||||
|
||||
|
||||
def _generate_aug_reg_constant_int(out: Callable, lvalue: Register, operator: str, rvalue: int, rname: str, scope: Scope) -> None:
|
||||
r_str = rname or to_hex(rvalue)
|
||||
def _generate_aug_reg_int(out: Callable, lvalue: Register, operator: str, rvalue: int, rname: str, scope: Scope) -> None:
|
||||
if rname:
|
||||
right_str = rname
|
||||
else:
|
||||
# an immediate value is provided in rvalue
|
||||
right_str = "#" + to_hex(rvalue)
|
||||
if operator == "+=":
|
||||
if lvalue.name == "A":
|
||||
out("\vclc")
|
||||
out("\vadc #" + r_str)
|
||||
out("\vadc " + right_str)
|
||||
elif lvalue.name == "X":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtxa")
|
||||
out("\vclc")
|
||||
out("\vadc #" + r_str)
|
||||
out("\vadc " + right_str)
|
||||
out("\vtax")
|
||||
elif lvalue.name == "Y":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtya")
|
||||
out("\vclc")
|
||||
out("\vadc #" + r_str)
|
||||
out("\vadc " + right_str)
|
||||
out("\vtay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo +=.word
|
||||
elif operator == "-=":
|
||||
if lvalue.name == "A":
|
||||
out("\vsec")
|
||||
out("\vsbc #" + r_str)
|
||||
out("\vsbc " + right_str)
|
||||
elif lvalue.name == "X":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtxa")
|
||||
out("\vsec")
|
||||
out("\vsbc #" + r_str)
|
||||
out("\vsbc " + right_str)
|
||||
out("\vtax")
|
||||
elif lvalue.name == "Y":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtya")
|
||||
out("\vsec")
|
||||
out("\vsbc #" + r_str)
|
||||
out("\vsbc " + right_str)
|
||||
out("\vtay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo -=.word
|
||||
elif operator == "&=":
|
||||
if lvalue.name == "A":
|
||||
out("\vand #" + r_str)
|
||||
out("\vand " + right_str)
|
||||
elif lvalue.name == "X":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtxa")
|
||||
out("\vand #" + r_str)
|
||||
out("\vand " + right_str)
|
||||
out("\vtax")
|
||||
elif lvalue.name == "Y":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtya")
|
||||
out("\vand #" + r_str)
|
||||
out("\vand " + right_str)
|
||||
out("\vtay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo &=.word
|
||||
elif operator == "|=":
|
||||
if lvalue.name == "A":
|
||||
out("\vora #" + r_str)
|
||||
out("\vora " + right_str)
|
||||
elif lvalue.name == "X":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtxa")
|
||||
out("\vora #" + r_str)
|
||||
out("\vora " + right_str)
|
||||
out("\vtax")
|
||||
elif lvalue.name == "Y":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtya")
|
||||
out("\vora #" + r_str)
|
||||
out("\vora " + right_str)
|
||||
out("\vtay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo |=.word
|
||||
elif operator == "^=":
|
||||
if lvalue.name == "A":
|
||||
out("\veor #" + r_str)
|
||||
out("\veor " + right_str)
|
||||
elif lvalue.name == "X":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtxa")
|
||||
out("\veor #" + r_str)
|
||||
out("\veor " + right_str)
|
||||
out("\vtax")
|
||||
elif lvalue.name == "Y":
|
||||
with preserving_registers({'A'}, scope, out):
|
||||
out("\vtya")
|
||||
out("\veor #" + r_str)
|
||||
out("\veor " + right_str)
|
||||
out("\vtay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo ^=.word
|
||||
elif operator == ">>=":
|
||||
if rvalue > 0:
|
||||
if rname:
|
||||
assert lvalue.name in REGISTER_BYTES, "only single registers for now" # @todo >>=.word
|
||||
if lvalue.name == "A":
|
||||
preserve_regs = {'X'}
|
||||
elif lvalue.name == "X":
|
||||
preserve_regs = {'A'}
|
||||
out("\vtxa")
|
||||
elif lvalue.name == "Y":
|
||||
preserve_regs = {'A', 'X'}
|
||||
out("\vtya")
|
||||
with preserving_registers(preserve_regs, scope, out):
|
||||
out("\vldx " + rname)
|
||||
out("\vjsr il65_lib.lsr_A_by_X")
|
||||
# out("\vbeq +")
|
||||
# out("-\vlsr a")
|
||||
# out("\vdex")
|
||||
# out("\vbne -")
|
||||
# put A back into target register
|
||||
if lvalue.name == "X":
|
||||
out("\vtax")
|
||||
if lvalue.name == "Y":
|
||||
out("\vtay")
|
||||
else:
|
||||
def shifts_A(times: int) -> None:
|
||||
if times >= 8:
|
||||
out("\vlda #0")
|
||||
@ -162,7 +235,29 @@ def _generate_aug_reg_constant_int(out: Callable, lvalue: Register, operator: st
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo >>=.word
|
||||
elif operator == "<<=":
|
||||
if rvalue > 0:
|
||||
if rname:
|
||||
assert lvalue.name in REGISTER_BYTES, "only single registers for now" # @todo <<=.word
|
||||
if lvalue.name == "A":
|
||||
preserve_regs = {'X'}
|
||||
elif lvalue.name == "X":
|
||||
preserve_regs = {'A'}
|
||||
out("\vtxa")
|
||||
elif lvalue.name == "Y":
|
||||
preserve_regs = {'A', 'X'}
|
||||
out("\vtya")
|
||||
with preserving_registers(preserve_regs, scope, out):
|
||||
out("\vldx " + rname)
|
||||
out("\vjsr il65_lib.asl_A_by_X")
|
||||
# out("\vbeq +")
|
||||
# out("-\vasl a")
|
||||
# out("\vdex")
|
||||
# out("\vbne -")
|
||||
# put A back into target register
|
||||
if lvalue.name == "X":
|
||||
out("\vtax")
|
||||
elif lvalue.name == "Y":
|
||||
out("\vtay")
|
||||
else:
|
||||
def shifts_A(times: int) -> None:
|
||||
if times >= 8:
|
||||
out("\vlda #0")
|
||||
|
@ -251,8 +251,7 @@ def generate_incrdecr(ctx: Context) -> None:
|
||||
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)
|
||||
assert target.operand.datatype == DataType.WORD
|
||||
reg = target.operand.name
|
||||
if stmt.howmuch == 1:
|
||||
out("\vclc" if stmt.operator == "++" else "\vsec")
|
||||
@ -265,7 +264,7 @@ def generate_incrdecr(ctx: Context) -> None:
|
||||
else:
|
||||
raise CodeError("can't inc/dec this by something else as 1 right now", stmt) # XXX
|
||||
else:
|
||||
raise TypeError("invalid dereference target type", target)
|
||||
raise TypeError("invalid dereference operand type", target)
|
||||
|
||||
else:
|
||||
raise CodeError("cannot inc/decrement", target) # @todo support more
|
||||
|
@ -186,15 +186,15 @@ incrdecr_deref_byte_reg_XY
|
||||
|
||||
incr_deref_byte
|
||||
ldy #0
|
||||
lda (c64.SCRATCH_ZPWORD1), y
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #1 ; carry's cleared already
|
||||
sta (c64.SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
decr_deref_byte
|
||||
ldy #0
|
||||
lda (c64.SCRATCH_ZPWORD1), y
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
sbc #1 ; carry's set already
|
||||
sta (c64.SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
|
||||
; increments/decrements a word referenced by indirect register pair by 1
|
||||
@ -216,32 +216,61 @@ incrdecr_deref_word_reg_XY
|
||||
|
||||
incr_deref_word
|
||||
ldy #0
|
||||
lda (c64.SCRATCH_ZPWORD1), y
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #1 ; carry's cleared already
|
||||
sta (c64.SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
bcc +
|
||||
iny
|
||||
lda (c64.SCRATCH_ZPWORD1), y
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
adc #0 ; carry is set
|
||||
sta (c64.SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
+ rts
|
||||
|
||||
decr_deref_word
|
||||
ldy #0
|
||||
lda (c64.SCRATCH_ZPWORD1), y
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
bne +
|
||||
pha
|
||||
iny
|
||||
lda (c64.SCRATCH_ZPWORD1), y
|
||||
lda (SCRATCH_ZPWORD1), y
|
||||
sbc #1 ; carry's set already
|
||||
sta (c64.SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
dey
|
||||
pla
|
||||
+ sec
|
||||
sbc #1
|
||||
sta (c64.SCRATCH_ZPWORD1), y
|
||||
sta (SCRATCH_ZPWORD1), y
|
||||
rts
|
||||
|
||||
|
||||
; shift bits in A right by X positions
|
||||
lsr_A_by_X
|
||||
cpx #8
|
||||
bcc _shift
|
||||
lda #0 ; x >=8, result always 0
|
||||
rts
|
||||
_shift cpx #0
|
||||
beq +
|
||||
- lsr a
|
||||
dex
|
||||
bne -
|
||||
+ rts
|
||||
|
||||
|
||||
; shift bits in A left by X positions
|
||||
asl_A_by_X
|
||||
cpx #8
|
||||
bcc _shift
|
||||
lda #0 ; x >=8, result always 0
|
||||
rts
|
||||
_shift cpx #0
|
||||
beq +
|
||||
- asl a
|
||||
dex
|
||||
bne -
|
||||
+ rts
|
||||
|
||||
|
||||
}
|
||||
|
||||
%noreturn
|
||||
|
@ -1,5 +1,6 @@
|
||||
# old deprecated code, in the process of moving this to the new emit/... modules
|
||||
|
||||
|
||||
class CodeGenerator:
|
||||
BREAKPOINT_COMMENT_SIGNATURE = "~~~BREAKPOINT~~~"
|
||||
BREAKPOINT_COMMENT_DETECTOR = r".(?P<address>\w+)\s+ea\s+nop\s+;\s+{:s}.*".format(BREAKPOINT_COMMENT_SIGNATURE)
|
||||
@ -429,130 +430,6 @@ class CodeGenerator:
|
||||
branch_emitter(targetstr, False, False)
|
||||
generate_result_assignments()
|
||||
|
||||
|
||||
|
||||
def _generate_aug_reg_mem(self, lvalue: RegisterValue, operator: str, rvalue: MemMappedValue) -> None:
|
||||
r_str = rvalue.name or Parser.to_hex(rvalue.address)
|
||||
if operator == "+=":
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tclc")
|
||||
self.p("\t\tadc " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tclc")
|
||||
self.p("\t\tadc " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tclc")
|
||||
self.p("\t\tadc " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo +=.word
|
||||
elif operator == "-=":
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tsec")
|
||||
self.p("\t\tsbc " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tsec")
|
||||
self.p("\t\tsbc " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tsec")
|
||||
self.p("\t\tsbc " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo -=.word
|
||||
elif operator == "&=":
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tand " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tand " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tand " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo &=.word
|
||||
elif operator == "|=":
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tora " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tora " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tora " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo |=.word
|
||||
elif operator == "^=":
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\teor " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\teor " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\teor " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo ^=.word
|
||||
elif operator == ">>=":
|
||||
if rvalue.datatype != DataType.BYTE:
|
||||
raise CodeError("can only shift by a byte value", str(rvalue))
|
||||
r_str = rvalue.name or Parser.to_hex(rvalue.address)
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tlsr " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tlsr " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tlsr " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported lvalue register for shift", str(lvalue)) # @todo >>=.word
|
||||
elif operator == "<<=":
|
||||
if rvalue.datatype != DataType.BYTE:
|
||||
raise CodeError("can only shift by a byte value", str(rvalue))
|
||||
r_str = rvalue.name or Parser.to_hex(rvalue.address)
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tasl " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tasl " + r_str)
|
||||
self.p("\t\ttax")
|
||||
elif lvalue.register == "Y":
|
||||
with self.preserving_registers({'A'}):
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tasl " + r_str)
|
||||
self.p("\t\ttay")
|
||||
else:
|
||||
raise CodeError("unsupported lvalue register for shift", str(lvalue)) # @todo >>=.word
|
||||
|
||||
|
||||
|
||||
def generate_assignment(self, stmt: AssignmentStmt) -> None:
|
||||
def unwrap_indirect(iv: IndirectValue) -> MemMappedValue:
|
||||
if isinstance(iv.value, MemMappedValue):
|
||||
|
Loading…
Reference in New Issue
Block a user