IR: added float<>long casts, cx16: blink_cursor extapi tested in test.p8

This commit is contained in:
Irmen de Jong
2025-11-15 21:27:45 +01:00
parent fb5290e17b
commit 99e037489b
9 changed files with 111 additions and 45 deletions

View File

@@ -2003,9 +2003,9 @@ $repeatLabel""")
lda #<$leftName
ldy #>$leftName""")
if(lessOrEquals)
out("jsr floats.vars_lesseq_f")
out(" jsr floats.vars_lesseq_f")
else
out("jsr floats.vars_less_f")
out(" jsr floats.vars_less_f")
}
fun lessf(expr: PtExpression, rightName: String) {
assignExpressionToRegister(expr, RegisterOrPair.FAC1, true)

View File

@@ -1325,8 +1325,8 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
fun divide(signed: Boolean) {
// on entry here: number placed in P8ZP_SCRATCH_PTR, divisor placed in AY
if(signed) asmgen.out("jsr prog8_math.divmod_w_asm")
else asmgen.out("jsr prog8_math.divmod_uw_asm")
if(signed) asmgen.out(" jsr prog8_math.divmod_w_asm")
else asmgen.out(" jsr prog8_math.divmod_uw_asm")
asmgen.out("""
tax
tya

View File

@@ -819,6 +819,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
actualResultReg2 = codeGen.registers.next(IRDataType.LONG)
addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.WORD, reg1 = actualResultReg2, reg2=tr.resultReg), null)
}
BaseDataType.FLOAT -> {
actualResultReg2 = codeGen.registers.next(IRDataType.LONG)
addInstr(result, IRInstruction(Opcode.FTOSL, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
}
else -> throw AssemblyError("weird cast $valueDt to long ${cast.position}")
}
}
@@ -837,6 +841,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
BaseDataType.WORD -> {
addInstr(result, IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
}
BaseDataType.LONG -> {
addInstr(result, IRInstruction(Opcode.FFROMSL, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
}
else -> throw AssemblyError("weird cast value type ${cast.position}")
}
}

View File

@@ -459,17 +459,19 @@ jump p8_label_gen_2
return null
}
val immediate1 = getImmediateLoad(ins.reg1!!)
if(immediate1!=null) {
chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg2, immediate = immediate1.second)
chunk.instructions.removeAt(immediate1.first)
changed=true
} else {
val immediate2 = getImmediateLoad(ins.reg2!!)
if (immediate2 != null) {
chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg1, immediate = immediate2.second)
chunk.instructions.removeAt(immediate2.first)
if(ins.reg1!=null) {
val immediate1 = getImmediateLoad(ins.reg1!!)
if(immediate1!=null) {
chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg2, immediate = immediate1.second)
chunk.instructions.removeAt(immediate1.first)
changed=true
} else {
val immediate2 = getImmediateLoad(ins.reg2!!)
if (immediate2 != null) {
chunk.instructions[idx] = IRInstruction(replacementOpcode, ins.type, reg1 = ins.reg1, immediate = immediate2.second)
chunk.instructions.removeAt(immediate2.first)
changed=true
}
}
}
}

View File

@@ -814,6 +814,7 @@ asmsub blink_enable(bool enable @X) clobbers(A,X) {
; requires rom v49+
%asm {{
txa
and #1
eor #1
tax
lda #EXTAPI_blink_enable

View File

@@ -1,11 +1,13 @@
TODO
====
- IR BUG: bool negative = sgn(f)<0 register type error
- before final release: test all examples and programs again with final version of the compiler!
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
- implement float to long casting and vice versa (6502)
- make $8000000 a valid long integer (-2147483648) this is more involved than you think. To make this work: long \|= $80000000
- implement rest of long comparisons in IfElseAsmGen compareLongValues(): expressions operands that might clobber the R14-R15 registers...
- struct/ptr: implement the remaining TODOs in PointerAssignmentsGen.
@@ -58,6 +60,7 @@ Future Things and Ideas
IR/VM
-----
- make SGN set the N,Z flags and then optimize float<0 float==0 float>0 to use SGN instruction. Check what code is generated for other data types.
- getting it in shape for code generation: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
- fix call() return value handling (... what's wrong with it again?)
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
@@ -112,6 +115,7 @@ Libraries
Optimizations
-------------
- change float<0, float==0, float>0 to use sgn(float) instead? (also see IR)
- optimize inplaceLongShiftRight() for byte aligned cases
- more optimized operator handling of different types, for example uword a ^ byte b now does a type cast of b to word first
- optimize longEqualsValue() for const and variable operands to not assign needlessly to R0-R3.

View File

@@ -1,39 +1,63 @@
%import diskio
%import textio
%zeropage basicsafe
main {
sub start() {
void diskio.f_open("t8s.wav")
long size, pos
repeat test()
}
pos, size = diskio.f_tell()
txt.print_l(pos)
txt.spc()
txt.print_l(size)
txt.nl()
sub test() {
txt.cls()
txt.plot(10, 10)
txt.print("enter four digit access code:")
txt.plot(20, 12)
txt.print("╭──────╮")
txt.plot(20, 13)
txt.print("│ │")
txt.plot(20, 14)
txt.print("╰──────╯")
diskio.f_seek(999999)
pos, size = diskio.f_tell()
txt.print_l(pos)
txt.spc()
txt.print_l(size)
txt.nl()
long lba, cluster
lba, cluster = diskio.f_fatlba()
txt.print_l(lba)
txt.spc()
txt.print_l(cluster)
txt.nl()
diskio.f_seek(0)
lba, cluster = diskio.f_fatlba()
txt.print_l(lba)
txt.spc()
txt.print_l(cluster)
txt.nl()
txt.plot(22, 13)
cx16.blink_enable(true)
str code = "????"
diskio.f_close()
ubyte numbers = 0
repeat {
ubyte char = txt.waitkey()
when char {
'0' to '9' -> {
if numbers<4 {
cx16.blink_enable(false)
txt.chrout(char)
cx16.blink_enable(true)
code[numbers] = char
numbers++
}
}
'\r' -> {
if numbers==4 {
cx16.blink_enable(false)
break
}
}
20, 25 -> {
if numbers>0 {
cx16.blink_enable(false)
txt.chrout(157) ; cursor left
txt.spc() ; clear digit
txt.chrout(157) ; cursor left
cx16.blink_enable(true)
numbers--
}
}
}
}
txt.print("\n\n\ncode entered: ")
txt.print(code)
sys.wait(120)
}
}

View File

@@ -220,10 +220,12 @@ ffromub fpreg1, reg1 - fpreg1 = reg1 from usigned byte
ffromsb fpreg1, reg1 - fpreg1 = reg1 from signed byte
ffromuw fpreg1, reg1 - fpreg1 = reg1 from unsigned word
ffromsw fpreg1, reg1 - fpreg1 = reg1 from signed word
ffromsl fpreg1, reg1 - fpreg1 = reg1 from signed long
ftoub reg1, fpreg1 - reg1 = fpreg1 as unsigned byte
ftosb reg1, fpreg1 - reg1 = fpreg1 as signed byte
ftouw reg1, fpreg1 - reg1 = fpreg1 as unsigned word
ftosw reg1, fpreg1 - reg1 = fpreg1 as signed word
ftosl reg1, fpreg1 - reg1 = fpreg1 as signed long
fpow fpreg1, fpreg2 - fpreg1 = fpreg1 to the power of fpreg2
fabs fpreg1, fpreg2 - fpreg1 = abs(fpreg2)
fcomp reg1, fpreg1, fpreg2 - reg1 = result of comparison of fpreg1 and fpreg2: 0.b=equal, 1.b=fpreg1 is greater, -1.b=fpreg1 is smaller
@@ -398,10 +400,12 @@ enum class Opcode {
FFROMSB,
FFROMUW,
FFROMSW,
FFROMSL,
FTOUB,
FTOSB,
FTOUW,
FTOSW,
FTOSL,
FPOW,
FABS,
FSIN,
@@ -787,10 +791,12 @@ val instructionFormats = mutableMapOf(
Opcode.FFROMSB to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FFROMUW to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FFROMSW to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FFROMSL to InstructionFormat.from("F,>fr1,<r1"),
Opcode.FTOUB to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOSB to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOUW to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOSW to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FTOSL to InstructionFormat.from("F,>r1,<fr1"),
Opcode.FPOW to InstructionFormat.from("F,<>fr1,<fr2"),
Opcode.FABS to InstructionFormat.from("F,>fr1,<fr2"),
Opcode.FCOMP to InstructionFormat.from("F,>r1,<fr1,<fr2"),
@@ -1086,10 +1092,20 @@ data class IRInstruction(
private fun determineReg1Type(): IRDataType? {
if(type==IRDataType.FLOAT) {
// some float instructions have an integer (byte or word) register as well in reg1
return if(opcode in arrayOf(Opcode.FFROMUB, Opcode.FFROMSB, Opcode.FTOUB, Opcode.FTOSB, Opcode.FCOMP, Opcode.LOADIX, Opcode.LOADX, Opcode.STOREX, Opcode.STOREIX, Opcode.STOREZX))
IRDataType.BYTE
else
IRDataType.WORD
return when (opcode) {
Opcode.FFROMUB,
Opcode.FFROMSB,
Opcode.FTOUB,
Opcode.FTOSB,
Opcode.FCOMP,
Opcode.LOADIX,
Opcode.LOADX,
Opcode.STOREX,
Opcode.STOREIX,
Opcode.STOREZX -> IRDataType.BYTE
Opcode.FFROMSL, Opcode.FTOSL -> IRDataType.LONG
else -> IRDataType.WORD
}
}
if(type==IRDataType.WORD) {
// some word instructions have byte reg1

View File

@@ -330,10 +330,12 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.FFROMSB -> InsFFROMSB(ins)
Opcode.FFROMUW -> InsFFROMUW(ins)
Opcode.FFROMSW -> InsFFROMSW(ins)
Opcode.FFROMSL -> InsFFROMSL(ins)
Opcode.FTOUB -> InsFTOUB(ins)
Opcode.FTOSB -> InsFTOSB(ins)
Opcode.FTOUW -> InsFTOUW(ins)
Opcode.FTOSW -> InsFTOSW(ins)
Opcode.FTOSL -> InsFTOSL(ins)
Opcode.FPOW -> InsFPOW(ins)
Opcode.FABS -> InsFABS(ins)
Opcode.FSIN -> InsFSIN(ins)
@@ -2686,6 +2688,11 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsFFROMSL(i: IRInstruction) {
registers.setFloat(i.fpReg1!!, registers.getSL(i.reg1!!).toDouble())
nextPc()
}
private fun InsFTOUB(i: IRInstruction) {
registers.setUB(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toUByte())
nextPc()
@@ -2706,6 +2713,11 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsFTOSL(i: IRInstruction) {
registers.setSL(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt())
nextPc()
}
private fun InsFPOW(i: IRInstruction) {
val value = registers.getFloat(i.fpReg1!!)
val exponent = registers.getFloat(i.fpReg2!!)