begun with converting builtin functions to new call convention

This commit is contained in:
Irmen de Jong 2020-11-02 22:45:46 +01:00
parent ebc2c614d7
commit e0c5ccc16b
8 changed files with 139 additions and 107 deletions

View File

@ -343,20 +343,16 @@ neg_f .proc
rts rts
.pend .pend
abs_f .proc abs_f_cc .proc
; -- strip the sign bit on the stack ; -- push abs(AY) on stack
lda P8ESTACK_HI+3,x jsr abs_f_into_fac1_cc
and #$7f jmp push_fac1
sta P8ESTACK_HI+3,x
rts
.pend .pend
abs_f_into_fac1 .proc abs_f_into_fac1_cc .proc
; -- strip the sign bit on the stack, push stack into FAC1 ; -- FAC1 = abs(AY)
lda P8ESTACK_HI+3,x jsr floats.MOVFM
and #$7f jmp floats.ABS
sta P8ESTACK_HI+3,x
jmp pop_float_fac1
.pend .pend
equal_f .proc equal_f .proc

View File

@ -245,24 +245,27 @@ xor_w .proc
.pend .pend
abs_b .proc abs_b_cc .proc
; -- push abs(byte) on stack (as byte) ; -- push abs(A) on stack (as byte)
lda P8ESTACK_LO+1,x jsr abs_b_into_A_cc
bmi neg_b sta P8ESTACK_LO,x
dex
rts rts
.pend .pend
abs_w .proc abs_w_cc .proc
; -- push abs(word) on stack (as word) ; -- push abs(AY) on stack (as word)
lda P8ESTACK_HI+1,x jsr abs_w_into_AY_cc
bmi neg_w sta P8ESTACK_LO,x
tya
sta P8ESTACK_HI,x
dex
rts rts
.pend .pend
abs_b_into_A .proc abs_b_into_A_cc .proc
; -- A = abs(pop stack byte) ; -- A = abs(A)
inx cmp #0
lda P8ESTACK_LO,x
bmi + bmi +
rts rts
+ eor #$ff + eor #$ff
@ -271,11 +274,9 @@ abs_b_into_A .proc
rts rts
.pend .pend
abs_w_into_AY .proc abs_w_into_AY_cc .proc
; -- AY = abs(pop stack word) ; -- AY = abs(AY)
inx cpy #0
lda P8ESTACK_LO,x
ldy P8ESTACK_HI,x
bmi + bmi +
rts rts
+ eor #$ff + eor #$ff
@ -1388,20 +1389,19 @@ func_rndw .proc
.pend .pend
func_memcopy255 .proc func_memcopy255_cc .proc
; fast memcopy of up to 255 bytes, note: clobbers A,Y ; fast memcopy of up to 255 bytes, note: clobbers A,Y
inx ; note: also uses the _arg variables from regular func_memcopy
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
lda P8ESTACK_LO+2,x lda func_memcopy_cc._arg_from
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x lda func_memcopy_cc._arg_from+1
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x lda func_memcopy_cc._arg_to
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
lda P8ESTACK_HI+1,x lda func_memcopy_cc._arg_to+1
sta P8ZP_SCRATCH_W2+1 sta P8ZP_SCRATCH_W2+1
lda P8ESTACK_LO,x ldx func_memcopy_cc._arg_numbytes
tax
ldy #0 ldy #0
- lda (P8ZP_SCRATCH_W1), y - lda (P8ZP_SCRATCH_W1), y
sta (P8ZP_SCRATCH_W2), y sta (P8ZP_SCRATCH_W2), y
@ -1409,31 +1409,23 @@ func_memcopy255 .proc
dex dex
bne - bne -
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
inx
inx
rts rts
.pend .pend
func_memcopy .proc func_memcopy_cc .proc
; memcopy of any number of bytes, note: clobbers A,Y ; memcopy of any number of bytes, note: clobbers A,Y
inx
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
lda P8ESTACK_LO+2,x lda _arg_from
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x lda _arg_from+1
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x lda _arg_to
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
lda P8ESTACK_HI+1,x lda _arg_to+1
sta P8ZP_SCRATCH_W2+1 sta P8ZP_SCRATCH_W2+1
lda P8ESTACK_LO,x
pha
lda P8ESTACK_HI,x
pha
ldy #0 ldy #0
pla ldx _arg_numbytes+1
tax
beq _remain beq _remain
- lda (P8ZP_SCRATCH_W1),y ; move a page at a time - lda (P8ZP_SCRATCH_W1),y ; move a page at a time
sta (P8ZP_SCRATCH_W2),y sta (P8ZP_SCRATCH_W2),y
@ -1443,8 +1435,7 @@ func_memcopy .proc
inc P8ZP_SCRATCH_W2+1 inc P8ZP_SCRATCH_W2+1
dex dex
bne - bne -
_remain pla _remain ldx _arg_numbytes
tax
beq _done beq _done
- lda (P8ZP_SCRATCH_W1),y ; move the remaining bytes - lda (P8ZP_SCRATCH_W1),y ; move the remaining bytes
sta (P8ZP_SCRATCH_W2),y sta (P8ZP_SCRATCH_W2),y
@ -1453,54 +1444,52 @@ _remain pla
bne - bne -
_done ldx P8ZP_SCRATCH_REG _done ldx P8ZP_SCRATCH_REG
inx
inx
rts rts
_arg_from .word 0
_arg_to .word 0
_arg_numbytes .word 0
.pend .pend
func_memset .proc func_memset_cc .proc
; note: clobbers A,Y ; note: clobbers A,Y
inx
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
lda P8ESTACK_LO+2,x lda _arg_address
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x lda _arg_address+1
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x ldx _arg_numbytes
sta P8ZP_SCRATCH_B1 ldy _arg_numbytes+1
ldy P8ESTACK_HI+1,x lda _arg_bytevalue
lda P8ESTACK_LO,x
ldx P8ZP_SCRATCH_B1
jsr memset jsr memset
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
inx
inx
rts rts
_arg_address .word 0
_arg_numbytes .word 0
_arg_bytevalue .byte 0
.pend .pend
func_memsetw .proc func_memsetw_cc .proc
; note: clobbers A,Y ; note: clobbers A,Y
; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY.
inx
lda P8ESTACK_LO+2,x
sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x
sta P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x
sta P8ZP_SCRATCH_W2
lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_W2+1
txa txa
pha pha
lda P8ESTACK_LO,x lda _arg_address
ldy P8ESTACK_HI,x sta P8ZP_SCRATCH_W1
lda _arg_address+1
sta P8ZP_SCRATCH_W1+1
lda _arg_numwords
sta P8ZP_SCRATCH_W2
lda _arg_numwords+1
sta P8ZP_SCRATCH_W2+1
lda _arg_wordvalue
ldy _arg_wordvalue+1
jsr memsetw jsr memsetw
pla pla
tax tax
inx
inx
rts rts
_arg_address .word 0
_arg_numwords .word 0
_arg_wordvalue .word 0
.pend .pend
strlen .proc strlen .proc
@ -1518,7 +1507,7 @@ strlen .proc
memcopy16_up .proc memcopy16_up .proc
; -- copy memory UP from (SCRATCH_ZPWORD1) to (SCRATCH_ZPWORD2) of length X/Y (16-bit, X=lo, Y=hi) ; -- copy memory UP from (P8ZP_SCRATCH_W1) to (P8ZP_SCRATCH_W2) of length X/Y (16-bit, X=lo, Y=hi)
; clobbers register A,X,Y ; clobbers register A,X,Y
source = P8ZP_SCRATCH_W1 source = P8ZP_SCRATCH_W1
dest = P8ZP_SCRATCH_W2 dest = P8ZP_SCRATCH_W2
@ -1546,7 +1535,7 @@ memcopy16_up .proc
memset .proc memset .proc
; -- fill memory from (SCRATCH_ZPWORD1), length XY, with value in A. ; -- fill memory from (P8ZP_SCRATCH_W1), length XY, with value in A.
; clobbers X, Y ; clobbers X, Y
stx P8ZP_SCRATCH_B1 stx P8ZP_SCRATCH_B1
sty _save_reg sty _save_reg
@ -1573,7 +1562,7 @@ _save_reg .byte 0
memsetw .proc memsetw .proc
; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY. ; -- fill memory from (P8ZP_SCRATCH_W1) number of words in P8ZP_SCRATCH_W2, with word value in AY.
; clobbers A, X, Y ; clobbers A, X, Y
sta _mod1+1 ; self-modify sta _mod1+1 ; self-modify
sty _mod1b+1 ; self-modify sty _mod1b+1 ; self-modify

View File

@ -110,7 +110,7 @@ internal object C64MachineDefinition: IMachineDefinition {
internal class C64Zeropage(options: CompilationOptions) : Zeropage(options) { internal class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
override val SCRATCH_B1 = 0x02 // temp storage for a single byte override val SCRATCH_B1 = 0x02 // temp storage for a single byte
override val SCRATCH_REG = 0x03 // temp storage for a register override val SCRATCH_REG = 0x03 // temp storage for a register, must be B1+1
override val SCRATCH_W1 = 0xfb // temp storage 1 for a word $fb+$fc override val SCRATCH_W1 = 0xfb // temp storage 1 for a word $fb+$fc
override val SCRATCH_W2 = 0xfd // temp storage 2 for a word $fb+$fc override val SCRATCH_W2 = 0xfd // temp storage 2 for a word $fb+$fc

View File

@ -117,7 +117,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
if((count!=null && count <= 255) || countDt.istype(DataType.UBYTE) || countDt.istype(DataType.BYTE)) { if((count!=null && count <= 255) || countDt.istype(DataType.UBYTE) || countDt.istype(DataType.BYTE)) {
// fast memcopy of up to 255 // fast memcopy of up to 255
translateArguments(fcall.args, func) translateArguments(fcall.args, func)
asmgen.out(" jsr prog8_lib.func_memcopy255") asmgen.out(" jsr prog8_lib.func_memcopy255_cc")
return return
} }
@ -141,7 +141,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
} }
"memsetw" -> { "memsetw" -> {
translateArguments(fcall.args, func) translateArguments(fcall.args, func)
asmgen.out(" jsr prog8_lib.func_memsetw") asmgen.out(" jsr prog8_lib.func_memsetw_cc")
} }
} }
} else { } else {
@ -150,12 +150,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val countDt = fcall.args[2].inferType(program) val countDt = fcall.args[2].inferType(program)
if((count!=null && count <= 255) || countDt.istype(DataType.UBYTE) || countDt.istype(DataType.BYTE)) { if((count!=null && count <= 255) || countDt.istype(DataType.UBYTE) || countDt.istype(DataType.BYTE)) {
translateArguments(fcall.args, func) translateArguments(fcall.args, func)
asmgen.out(" jsr prog8_lib.func_memcopy255") asmgen.out(" jsr prog8_lib.func_memcopy255_cc")
return return
} }
} }
translateArguments(fcall.args, func) translateArguments(fcall.args, func)
asmgen.out(" jsr prog8_lib.func_${func.name}") asmgen.out(" jsr prog8_lib.func_${func.name}_cc")
} }
} }
@ -937,16 +937,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val dt = fcall.args.single().inferType(program).typeOrElse(DataType.STRUCT) val dt = fcall.args.single().inferType(program).typeOrElse(DataType.STRUCT)
if(resultToStack) { if(resultToStack) {
when (dt) { when (dt) {
in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b") in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b_cc")
in WordDatatypes -> asmgen.out(" jsr prog8_lib.abs_w") in WordDatatypes -> asmgen.out(" jsr prog8_lib.abs_w_cc")
DataType.FLOAT -> asmgen.out(" jsr floats.abs_f") DataType.FLOAT -> asmgen.out(" jsr floats.abs_f_cc")
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
} }
} else { } else {
when (dt) { when (dt) {
in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b_into_A") in ByteDatatypes -> asmgen.out(" jsr prog8_lib.abs_b_into_A_cc")
in WordDatatypes -> asmgen.out(" jsr prog8_lib.abs_w_into_AY") in WordDatatypes -> asmgen.out(" jsr prog8_lib.abs_w_into_AY_cc")
DataType.FLOAT -> asmgen.out(" jsr floats.abs_f_into_fac1") DataType.FLOAT -> asmgen.out(" jsr floats.abs_f_into_fac1_cc")
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
} }
} }
@ -1052,7 +1052,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val value = it.first.first val value = it.first.first
when { when {
conv.variable -> { conv.variable -> {
val varname = "prog8_lib.func_${signature.name}_cc.arg_${paramName}" // TODO after all builtin funcs have been changed into _cc, remove that suffix again val varname = "prog8_lib.func_${signature.name}_cc._arg_${paramName}" // TODO after all builtin funcs have been changed into _cc, remove that suffix again
val src = AsmAssignSource.fromAstSource(value, program, asmgen) val src = AsmAssignSource.fromAstSource(value, program, asmgen)
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, conv.dt, null, variableAsmName = varname) val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, conv.dt, null, variableAsmName = varname)
val assign = AsmAssignment(src, tgt, false, value.position) val assign = AsmAssignment(src, tgt, false, value.position)

View File

@ -75,7 +75,7 @@ internal object CX16MachineDefinition: IMachineDefinition {
internal class CX16Zeropage(options: CompilationOptions) : Zeropage(options) { internal class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
override val SCRATCH_B1 = 0x79 // temp storage for a single byte override val SCRATCH_B1 = 0x79 // temp storage for a single byte
override val SCRATCH_REG = 0x7a // temp storage for a register override val SCRATCH_REG = 0x7a // temp storage for a register, must be B1+1
override val SCRATCH_W1 = 0x7c // temp storage 1 for a word $7c+$7d override val SCRATCH_W1 = 0x7c // temp storage 1 for a word $7c+$7d
override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f

View File

@ -5,8 +5,6 @@ import org.hamcrest.Matchers.closeTo
import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
@ -18,8 +16,8 @@ import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5 import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5
import prog8.compiler.target.c64.Petscii import prog8.compiler.target.c64.Petscii
import prog8.compiler.target.cx16.CX16MachineDefinition
import java.io.CharConversionException import java.io.CharConversionException
import java.nio.file.Path
import kotlin.test.* import kotlin.test.*
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ -288,6 +286,22 @@ class TestC64Zeropage {
assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null, errors)) assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null, errors))
assertEquals(0, zp.available()) assertEquals(0, zp.available())
} }
@Test
fun testReservedLocations() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false))
assertEquals(zp.SCRATCH_REG, zp.SCRATCH_B1+1, "zp _B1 and _REG must be next to each other to create a word")
}
}
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestCx16Zeropage {
@Test
fun testReservedLocations() {
val zp = CX16MachineDefinition.CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false))
assertEquals(zp.SCRATCH_REG, zp.SCRATCH_B1+1, "zp _B1 and _REG must be next to each other to create a word")
}
} }

View File

@ -2,6 +2,7 @@
TODO TODO
==== ====
- 64tass doesn't output all labels anymore in the vice-mon-list, so %breakpoint labels are no longer present....
- calling convention for builtin functions no longer via stack but via registers or statically allocated vars inside the subroutine proc (like normal subroutines) - calling convention for builtin functions no longer via stack but via registers or statically allocated vars inside the subroutine proc (like normal subroutines)
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - 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) - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)

View File

@ -11,20 +11,37 @@ main {
sub start() { sub start() {
const uword ADDR = $0400 const uword ADDR = $0400
byte zerob=0
word zerow=0
float zerof=0
byte bb byte bb
word ww word ww
float fl float fl
bb = abs(bb) testX()
ww = abs(ww)
fl = abs(fl)
bb = -100
bb = zerob+abs(bb)
txt.print_b(bb)
txt.chrout('\n')
memset(ADDR, 40*25, 100) ww = -12345
memsetw(ADDR, 20*10, $3031) ww = zerow+abs(ww)
memcopy(ADDR, ADDR+40*12, 20*10*2) txt.print_w(ww)
txt.chrout('\n')
fl = -9.876
fl = zerof+abs(fl)
floats.print_f(fl)
txt.chrout('\n')
; memset(ADDR, 40*25, 100)
; memsetw(ADDR, 20*10, $3031)
; memcopy(ADDR, ADDR+40*12, 20*10*2)
testX() testX()
bb++
} }
asmsub testX() { asmsub testX() {
@ -32,8 +49,23 @@ main {
stx _saveX stx _saveX
lda #13 lda #13
jsr txt.chrout jsr txt.chrout
lda #'x'
jsr txt.chrout
lda #'='
jsr txt.chrout
lda _saveX lda _saveX
jsr txt.print_ub jsr txt.print_ub
lda #' '
jsr txt.chrout
lda #'s'
jsr txt.chrout
lda #'p'
jsr txt.chrout
lda #'='
jsr txt.chrout
tsx
txa
jsr txt.print_ub
lda #13 lda #13
jsr txt.chrout jsr txt.chrout
ldx _saveX ldx _saveX