vm: implementing more fp instructions

This commit is contained in:
Irmen de Jong 2022-05-02 20:16:45 +02:00
parent fa357a450b
commit 86cc2f1075
8 changed files with 259 additions and 115 deletions

View File

@ -380,10 +380,22 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun multiplyByConstFloat(fpReg: Int, factor: Float): VmCodeChunk {
val code = VmCodeChunk()
if(factor==1f)
return code
if(factor==0f) {
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
} else {
val factorReg = vmRegisters.nextFreeFloat()
code += VmCodeInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpReg2 = fpReg, fpReg3 = factorReg)
}
return code
}
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk {
// TODO support floating-point factors
val code = VmCodeChunk()
if(factor==1)
return code

View File

@ -62,7 +62,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
is PtTypeCast -> code += translate(expr, resultRegister)
is PtPrefix -> code += translate(expr, resultRegister)
is PtArrayIndexer -> code += translate(expr, resultRegister)
is PtBinaryExpression -> code += translate(expr, resultRegister)
is PtBinaryExpression -> code += translate(expr, resultRegister, resultFpRegister)
is PtBuiltinFunctionCall -> code += codeGen.translateBuiltinFunc(expr, resultRegister)
is PtFunctionCall -> code += translate(expr, resultRegister, resultFpRegister)
is PtContainmentCheck -> code += translate(expr, resultRegister, resultFpRegister)
@ -269,13 +269,13 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return code
}
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int): VmCodeChunk {
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val vmDt = codeGen.vmType(binExpr.left.type)
val signed = binExpr.left.type in SignedDatatypes
return when(binExpr.operator) {
"+" -> operatorPlus(binExpr, vmDt, resultRegister)
"-" -> operatorMinus(binExpr, vmDt, resultRegister)
"*" -> operatorMultiply(binExpr, vmDt, resultRegister)
"*" -> operatorMultiply(binExpr, vmDt, resultRegister, resultFpRegister )
"/" -> operatorDivide(binExpr, vmDt, resultRegister)
"%" -> operatorModulo(binExpr, vmDt, resultRegister)
"|", "or" -> operatorOr(binExpr, vmDt, resultRegister)
@ -398,6 +398,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
if(vmDt==VmDataType.FLOAT)
throw IllegalArgumentException("floating-point modulo not supported")
val code = VmCodeChunk()
val leftResultReg = codeGen.vmRegisters.nextFree()
val rightResultReg = codeGen.vmRegisters.nextFree()
@ -410,6 +412,9 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun operatorDivide(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val constFactorRight = binExpr.right as? PtNumber
if(vmDt==VmDataType.FLOAT) {
TODO("div float")
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, resultRegister, -1)
val factor = constFactorRight.number.toInt()
@ -421,13 +426,31 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
}
return code
}
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val constFactorLeft = binExpr.left as? PtNumber
val constFactorRight = binExpr.right as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorLeft!=null) {
code += translateExpression(binExpr.right, -1, resultFpRegister)
val factor = constFactorLeft.number.toFloat()
code += codeGen.multiplyByConstFloat(resultFpRegister, factor)
} else if(constFactorRight!=null) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
val factor = constFactorRight.number.toFloat()
code += codeGen.multiplyByConstFloat(resultFpRegister, factor)
} else {
val leftResultFpReg = codeGen.vmRegisters.nextFreeFloat()
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, leftResultFpReg)
code += translateExpression(binExpr.right, -1, rightResultFpReg)
code += VmCodeInstruction(Opcode.MUL, vmDt, fpReg1 = resultFpRegister, reg2=leftResultFpReg, reg3=rightResultFpReg)
}
} else {
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
code += translateExpression(binExpr.right, resultRegister, -1)
val factor = constFactorLeft.number.toInt()
@ -443,11 +466,15 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
}
return code
}
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
if(vmDt==VmDataType.FLOAT) {
TODO("minus float")
} else {
if((binExpr.right as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
@ -459,11 +486,15 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
}
return code
}
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
if(vmDt==VmDataType.FLOAT) {
TODO("plus float")
} else {
if((binExpr.left as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.right, resultRegister, -1)
code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
@ -479,6 +510,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg)
}
}
return code
}

View File

@ -184,47 +184,76 @@ sub str2ubyte(str string) -> ubyte {
; -- returns in A the unsigned byte value of the string number argument in AY
; the number may NOT be preceded by a + sign and may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
return str2uword(string) as ubyte
}
sub str2byte(str string) -> byte {
; -- returns in A the signed byte value of the string number argument in AY
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
return str2word(string) as byte
}
sub str2uword(str string) -> uword {
; -- returns the unsigned word value of the string number argument in AY
; the number may NOT be preceded by a + sign and may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
%asm {{
loadm.w r0, {conv.str2uword.string}
syscall 11
return
}}
}
sub str2word(str string) -> word {
; -- returns the signed word value of the string number argument in AY
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
%asm {{
loadm.w r0, {conv.str2word.string}
syscall 12
return
}}
}
sub hex2uword(str string) -> uword {
; -- hexadecimal string (with or without '$') to uword.
; string may be in petscii or c64-screencode encoding.
; stops parsing at the first character that's not a hex digit (except leading $)
; TODO
return 0
; TODO fix this result
uword result
ubyte char
if @(string)=='$'
string++
repeat {
char = @(string)
if char==0
return result
result <<= 4
if char>='0' and char<='9'
result |= char-'0'
else
result |= char-'a'+10
string++
}
}
sub bin2uword(str string) -> uword {
; -- binary string (with or without '%') to uword.
; stops parsing at the first character that's not a 0 or 1. (except leading %)
; TODO
return 0
; TODO fix this result
uword result
ubyte char
if @(string)=='%'
string++
repeat {
char = @(string)
if char==0
return result
result <<= 1
if char=='1'
result |= 1
string++
}
}
}

View File

@ -19,17 +19,15 @@ sub print_f(float value) {
}
sub pow(float value, float power) -> float {
; TODO fpow.f instruction
%asm {{
loadm.f fr0,{floats.pow.value}
loadm.f fr1,{floats.pow.power}
fpow.f fr0,fr0
fpow.f fr0,fr0,fr1
return
}}
}
sub fabs(float value) -> float {
; TODO fabs.f instruction
%asm {{
loadm.f fr0,{floats.fabs.value}
fabs.f fr0,fr0
@ -38,7 +36,6 @@ sub fabs(float value) -> float {
}
sub sin(float angle) -> float {
; TODO fsin.f instruction
%asm {{
loadm.f fr0,{floats.sin.angle}
fsin.f fr0,fr0
@ -47,7 +44,6 @@ sub sin(float angle) -> float {
}
sub cos(float angle) -> float {
; TODO fcos.f instruction
%asm {{
loadm.f fr0,{floats.cos.angle}
fcos.f fr0,fr0
@ -56,7 +52,6 @@ sub cos(float angle) -> float {
}
sub tan(float value) -> float {
; TODO ftan.f instruction
%asm {{
loadm.f fr0,{floats.tan.value}
ftan.f fr0,fr0
@ -65,7 +60,6 @@ sub tan(float value) -> float {
}
sub atan(float value) -> float {
; TODO fatan.f instruction
%asm {{
loadm.f fr0,{floats.atan.value}
fatan.f fr0,fr0
@ -74,7 +68,6 @@ sub atan(float value) -> float {
}
sub ln(float value) -> float {
; TODO fln.f instruction
%asm {{
loadm.f fr0,{floats.ln.value}
fln.f fr0,fr0
@ -83,16 +76,14 @@ sub ln(float value) -> float {
}
sub log2(float value) -> float {
; TODO flog2.f instruction
%asm {{
loadm.f fr0,{floats.log2.value}
flog2.f fr0,fr0
flog.f fr0,fr0
return
}}
}
sub sqrt(float value) -> float {
; TODO fsqrt.f instruction
%asm {{
loadm.f fr0,{floats.sqrt.value}
fsqrt.f fr0,fr0
@ -111,7 +102,6 @@ sub deg(float angle) -> float {
}
sub round(float value) -> float {
; TODO fround.f instruction
%asm {{
loadm.f fr0,{floats.round.value}
fround.f fr0,fr0
@ -120,7 +110,6 @@ sub round(float value) -> float {
}
sub floor(float value) -> float {
; TODO ffloor.f instruction
%asm {{
loadm.f fr0,{floats.floor.value}
ffloor.f fr0,fr0
@ -130,7 +119,6 @@ sub floor(float value) -> float {
sub ceil(float value) -> float {
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
; TODO fceil.f instruction
%asm {{
loadm.f fr0,{floats.ceil.value}
fceil.f fr0,fr0
@ -139,9 +127,8 @@ sub ceil(float value) -> float {
}
sub rndf() -> float {
; TODO frnd.f instruction
%asm {{
frnd.f fr0
rnd.f fr0
return
}}
}

View File

@ -3,8 +3,12 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: fix fp reg out of bounds
- vm: implement missing floating point functions
- vm: fix if @(string)=='$' string++ not working on ea31
- vm: fix conv hex2uword and bin2uword
- vm: implement float div, minus, plus
- vm: implement float type casts to integer types
- vm: implement float any, all, reverse, sort
- vm: fix test fp calc result being 0
- vm: get rid of intermediate floats.xxx() functions somehow, instead generate the float instructions directly?
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type

View File

@ -8,15 +8,61 @@
main {
sub start() {
float fl = 500.0
txt.print("rad 180 = ")
floats.print_f(floats.rad(180.0))
txt.print("rad 360 = ")
floats.print_f(floats.rad(360.0))
txt.print("deg 2 = ")
floats.print_f(floats.deg(2.0))
txt.print("deg pi = ")
floats.print_f(floats.deg(floats.PI))
ubyte ub = conv.str2ubyte("234")
txt.print_ub(ub)
txt.nl()
byte sb = conv.str2byte("-123")
txt.print_b(sb)
txt.nl()
uword uw = conv.str2uword("54321")
txt.print_uw(uw)
txt.nl()
word sw = conv.str2word("-12345")
txt.print_w(sw)
txt.nl()
txt.nl()
; TODO fix hex2uword and bin2uword
uw = conv.hex2uword("0")
txt.print_uw(uw)
txt.nl()
uw = conv.hex2uword("1")
txt.print_uw(uw)
txt.nl()
uw = conv.hex2uword("a")
txt.print_uw(uw)
txt.nl()
uw = conv.bin2uword("0")
txt.print_uw(uw)
txt.nl()
uw = conv.bin2uword("1")
txt.print_uw(uw)
txt.nl()
txt.nl()
uw = conv.hex2uword("$ea31")
txt.print_uw(uw)
txt.nl()
uw = conv.hex2uword("ea31")
txt.print_uw(uw)
txt.nl()
uw = conv.bin2uword("%100000111011101")
txt.print_uw(uw)
txt.nl()
uw = conv.bin2uword("100000111011101")
txt.print_uw(uw)
txt.nl()
; float fl = 500.0
; txt.print("rad 180 = ")
; floats.print_f(floats.rad(180.0))
; txt.print("rad 360 = ")
; floats.print_f(floats.rad(360.0))
; txt.print("deg 2 = ")
; floats.print_f(floats.deg(2.0))
; txt.print("deg pi = ")
; floats.print_f(floats.deg(floats.PI))
sys.exit(42)
; floats.print_f(-42.42)
; float f1 = 1.2345
@ -58,21 +104,21 @@ main {
; "deg", "round", "floor", "ceil", "rndf"
; a "pixelshader":
sys.gfx_enable(0) ; enable lo res screen
ubyte shifter
repeat {
uword xx
uword yy = 0
repeat 240 {
xx = 0
repeat 320 {
sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
xx++
}
yy++
}
shifter+=4
}
; sys.gfx_enable(0) ; enable lo res screen
; ubyte shifter
;
; repeat {
; uword xx
; uword yy = 0
; repeat 240 {
; xx = 0
; repeat 320 {
; sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
; xx++
; }
; yy++
; }
; shifter+=4
; }
}
}

View File

@ -18,8 +18,6 @@ a few fp conversion instructions to
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
TODO all floating point arithmethic functions as fp-instructions.
LOAD/STORE
----------
All have type b or w or f.
@ -130,8 +128,8 @@ rol reg1 - rotate reg1 left by 1bits, not us
roxl reg1 - rotate reg1 left by 1bits, using carry, + set Carry to shifted bit
FLOATING POINT CONVERSIONS
--------------------------
FLOATING POINT CONVERSIONS AND FUNCTIONS
----------------------------------------
ffromub fpreg1, reg1 - fpreg1 = reg1 from usigned byte
ffromsb fpreg1, reg1 - fpreg1 = reg1 from signed byte
ffromuw fpreg1, reg1 - fpreg1 = reg1 from unsigned word
@ -140,6 +138,8 @@ 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
fpow fpreg1, fpreg2, fpreg3 - fpreg1 = fpreg2 to the power of fpreg3
fabs fpreg1, fpreg2 - fpreg1 = abs(fpreg2)
MISC
@ -248,6 +248,18 @@ enum class Opcode {
FTOSB,
FTOUW,
FTOSW,
FPOW,
FABS,
FSIN,
FCOS,
FTAN,
FATAN,
FLN,
FLOG,
FSQRT,
FROUND,
FFLOOR,
FCEIL,
CLC,
SEC,
@ -512,6 +524,18 @@ val instructionFormats = mutableMapOf(
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.FPOW to InstructionFormat.from("F,fr1,fr2,fr3"),
Opcode.FABS to InstructionFormat.from("F,fr1,fr2"),
Opcode.FSIN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FCOS to InstructionFormat.from("F,fr1,fr2"),
Opcode.FTAN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FATAN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FLN to InstructionFormat.from("F,fr1,fr2"),
Opcode.FLOG to InstructionFormat.from("F,fr1,fr2"),
Opcode.FSQRT to InstructionFormat.from("F,fr1,fr2"),
Opcode.FROUND to InstructionFormat.from("F,fr1,fr2"),
Opcode.FFLOOR to InstructionFormat.from("F,fr1,fr2"),
Opcode.FCEIL to InstructionFormat.from("F,fr1,fr2"),
Opcode.MSIG to InstructionFormat.from("BW,r1,r2"),
Opcode.PUSH to InstructionFormat.from("BW,r1"),

View File

@ -16,8 +16,8 @@ SYSCALLS:
8 = gfx_enable ; enable graphics window r0.b = 0 -> lores 320x240, r0.b = 1 -> hires 640x480
9 = gfx_clear ; clear graphics window with shade in r0.b
10 = gfx_plot ; plot pixel in graphics window, r0.w/r1.w contain X and Y coordinates, r2.b contains brightness
11 = <unused 1>
12 = <unused 2>
11 = decimal string to word (unsigned)
12 = decimal string to word (signed)
13 = wait ; wait certain amount of jiffies (1/60 sec)
14 = waitvsync ; wait on vsync
15 = sort_ubyte array
@ -55,8 +55,8 @@ enum class Syscall {
GFX_ENABLE,
GFX_CLEAR,
GFX_PLOT,
UNUSED_1,
UNUSED_2,
STR_TO_UWORD,
STR_TO_WORD,
WAIT,
WAITVSYNC,
SORT_UBYTE,
@ -301,6 +301,16 @@ object SysCalls {
val value = vm.registers.getFloat(0)
print(value)
}
Syscall.STR_TO_UWORD -> {
val stringAddr = vm.registers.getUW(0)
val string = vm.memory.getString(stringAddr.toInt())
vm.registers.setUW(0, string.toUShort())
}
Syscall.STR_TO_WORD -> {
val stringAddr = vm.registers.getUW(0)
val string = vm.memory.getString(stringAddr.toInt())
vm.registers.setSW(0, string.toShort())
}
else -> TODO("syscall ${call.name}")
}
}