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.

This commit is contained in:
Irmen de Jong 2020-12-22 12:44:03 +01:00
parent bba4f84503
commit 5a2f8fdfe1
5 changed files with 36 additions and 97 deletions

View File

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

View File

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

View File

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

View File

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

View File

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