From 5a2f8fdfe130fe50ae397492a169a266288e082b Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 22 Dec 2020 12:44:03 +0100 Subject: [PATCH] asm-subroutines that ONLY return a value in the Carry or Overflow status register can now be used in an assignment to store that value. --- compiler/src/prog8/ast/base/Base.kt | 4 +- .../c64/codegen/assignment/AsmAssignment.kt | 2 +- .../codegen/assignment/AssignmentAsmGen.kt | 29 +++++- docs/source/todo.rst | 2 +- examples/test.p8 | 96 +------------------ 5 files changed, 36 insertions(+), 97 deletions(-) diff --git a/compiler/src/prog8/ast/base/Base.kt b/compiler/src/prog8/ast/base/Base.kt index d3c21f4e2..a41405d3a 100644 --- a/compiler/src/prog8/ast/base/Base.kt +++ b/compiler/src/prog8/ast/base/Base.kt @@ -95,9 +95,9 @@ enum class RegisterOrPair { enum class Statusflag { Pc, - Pz, + Pz, // don't use Pv, - Pn; + Pn; // don't use companion object { val names by lazy { values().map { it.toString()} } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt index e186ad5b1..26328ecff 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt @@ -150,7 +150,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, is FunctionCall -> { when (val sub = value.target.targetStatement(program.namespace)) { is Subroutine -> { - val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null }?.first + val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first ?: throw AssemblyError("can't translate zero return values in assignment") AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index ca83cc1c4..9838b4fd3 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -143,7 +143,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen when (val sub = value.target.targetStatement(program.namespace)) { is Subroutine -> { asmgen.translateFunctionCall(value) - val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.registerOrPair!=null } + val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?: + sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.statusflag!=null } when (returnValue.first) { DataType.STR -> { when(assign.target.datatype) { @@ -177,7 +178,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX) RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY) - else -> throw AssemblyError("should be just one register byte result value") + else -> { + val sflag = returnValue.second.statusflag + if(sflag!=null) + assignStatusFlagByte(assign.target, sflag) + else + throw AssemblyError("should be just one register byte result value") + } } } } @@ -228,6 +235,24 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } + private fun assignStatusFlagByte(target: AsmAssignTarget, statusflag: Statusflag) { + when(statusflag) { + Statusflag.Pc -> { + asmgen.out(" lda #0 | rol a") + } + Statusflag.Pv -> { + asmgen.out(""" + bvs + + lda #0 + beq ++ ++ lda #1 ++""") + } + else -> throw AssemblyError("can't use Z or N flags as return 'values'") + } + assignRegisterByte(target, CpuRegister.A) + } + private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origTypeCastExpression: TypecastExpression) { val valueIDt = value.inferType(program) if(!valueIDt.isKnown) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4f1e0fe43..9ef9096b6 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,7 +2,7 @@ TODO ==== -- Cx16 target: support full-screen 640x480 and 320x240 graphics? That requires our own custom graphics routines though to draw lines. +- Cx16 target: support full-screen 640x480 and 320x240 graphics? That requires our own custom graphics routines though to draw lines, and plot pixels. - hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine) - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) diff --git a/examples/test.p8 b/examples/test.p8 index d6c4f9e94..10d7f9ee6 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -8,98 +8,12 @@ main { - ;romsub $ff14 = FB_set_8_pixels_opaque(ubyte pattern @R0, ubyte mask @A, ubyte color1 @X, ubyte color2 @Y) clobbers(A,X,Y) - ;romsub $ff14 = FB_set_8_pixels_opaque_OLD(ubyte mask @A, ubyte color1 @X, ubyte color2 @Y) clobbers(A,X,Y) - - asmsub set_8_pixels_opaque(ubyte pattern @R0, ubyte mask @A, ubyte color1 @X, ubyte color2 @Y) clobbers(A,X,Y) { - - %asm {{ - sta _a - stx _x - sty _y - - lda _a - jsr txt.print_ub - lda #13 - jsr c64.CHROUT - lda _x - jsr txt.print_ub - lda #13 - jsr c64.CHROUT - lda _y - jsr txt.print_ub - lda #13 - jsr c64.CHROUT - lda cx16.r0 - ldy cx16.r0+1 - jsr txt.print_uw - lda #13 - jsr c64.CHROUT - rts - -_a .byte 0 -_x .byte 0 -_y .byte 0 - }} - } - - asmsub set_8_pixels_opaque_OLD(ubyte mask @A, ubyte color1 @X, ubyte color2 @Y) clobbers(A,X,Y) { - %asm {{ - sta _a - stx _x - sty _y - - lda _a - jsr txt.print_ub - lda #13 - jsr c64.CHROUT - lda _x - jsr txt.print_ub - lda #13 - jsr c64.CHROUT - lda _y - jsr txt.print_ub - lda #13 - jsr c64.CHROUT - rts - -_a .byte 0 -_x .byte 0 -_y .byte 0 - }} - } - - asmsub withasm(uword foo @R0, ubyte arg1 @A, ubyte arg2 @Y) clobbers(X) -> ubyte @A { - %asm {{ - sty P8ZP_SCRATCH_REG - clc - adc P8ZP_SCRATCH_REG - rts - }} - } - - sub derp(uword aa)-> uword { - return 9999+aa - } - sub start () { - txt.print_ub(target()) - txt.chrout('\n') - -; cx16.r0 = 65535 -; set_8_pixels_opaque_OLD(111,222,33) -; txt.chrout('\n') -; ;ubyte qq=c64.CHKIN(3) ;; TODO fix compiler crash "can't translate zero return values in assignment" -; -; test_stack.test() -; ubyte bb = 44 -; set_8_pixels_opaque(bb,111,222,33) -; txt.chrout('\n') -; test_stack.test() -; -; set_8_pixels_opaque(c64.CHRIN(),111,222,33) -; txt.chrout('\n') - + ubyte qq + void c64.CHKIN(3) + qq++ + qq=c64.CHKIN(3) + qq=c64.OPEN() ; TODO DO NOT REMOVE SECOND ASSIGNMENT IF ITS NOT A SIMPLE VALUE test_stack.test() } }