diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 806dca1cd..e3837f0f5 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -1575,8 +1575,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private fun outputAddressAndLenghtOfArray(arg: Expression) { // address in P8ZP_SCRATCH_W1, number of elements in A arg as IdentifierReference + val arrayVar = arg.targetVarDecl(program)!! + if(!arrayVar.isArray) + throw AssemblyError("length of non-array requested") + val size = arrayVar.arraysize!!.constIndex()!! val identifierName = asmgen.asmVariableName(arg) - val size = arg.targetVarDecl(program)!!.arraysize!!.constIndex()!! asmgen.out(""" lda #<$identifierName ldy #>$identifierName diff --git a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt index b527c2ae2..71fa3499f 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFuncGen.kt @@ -12,11 +12,13 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { return when(call.name) { - "cmp" -> TODO("cmp() can't be used on vm because no processor status bits implemented") - "max" -> TODO() + "max" -> funcMax(call, resultRegister) "min" -> TODO() "sum" -> TODO() - "abs" -> TODO() + "any" -> TODO() + "all" -> TODO() + "abs" -> TODO("abs once we can compare plus minus") + "cmp" -> TODO("cmp() can't be used on vm because no processor status bits implemented") "sgn" -> funcSgn(call, resultRegister) "sin" -> TODO("floats not yet implemented") "cos" -> TODO("floats not yet implemented") @@ -31,8 +33,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: "round" -> TODO("floats not yet implemented") "floor" -> TODO("floats not yet implemented") "ceil" -> TODO("floats not yet implemented") - "any" -> TODO() - "all" -> TODO() "pop" -> funcPop(call) "popw" -> funcPopw(call) "push" -> funcPush(call) @@ -59,8 +59,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: "pokew" -> funcPokeW(call) "pokemon" -> VmCodeChunk() "mkword" -> funcMkword(call, resultRegister) - "sin8u" -> funcSin8u(call, resultRegister) - "cos8u" -> funcCos8u(call, resultRegister) "sort" -> funcSort(call) "reverse" -> funcReverse(call) "swap" -> funcSwap(call) @@ -72,6 +70,25 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: } } + private fun funcMax(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { + val code = VmCodeChunk() + val arrayName = (call.args.single() as PtIdentifier).targetName + val array = codeGen.symbolTable.flat.getValue(arrayName) as StStaticVariable + when (array.dt) { + DataType.ARRAY_UW, DataType.ARRAY_W -> { + TODO("max word array") + } + DataType.STR -> { + TODO("max string") + } + else -> { + TODO("max byte array") + } + } + + return code + } + private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { val code = VmCodeChunk() code += exprGen.translateExpression(call.args.single(), 0) @@ -164,24 +181,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: return code } - private fun funcCos8u(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() - code += exprGen.translateExpression(call.args[0], 0) - code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.COS8U.ordinal) - if(resultRegister!=0) - code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0) - return code - } - - private fun funcSin8u(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { - val code = VmCodeChunk() - code += exprGen.translateExpression(call.args[0], 0) - code += VmCodeInstruction(Opcode.SYSCALL, value=Syscall.SIN8U.ordinal) - if(resultRegister!=0) - code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0) - return code - } - private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk { val msbReg = codeGen.vmRegisters.nextFree() val lsbReg = codeGen.vmRegisters.nextFree() diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 8ea50507a..e55764590 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -214,6 +214,67 @@ math Low level math routines. You should not normally have to bother with this directly. The compiler needs it to implement most of the math operations in your programs. +However there's a bunch of integer trig functions in here too that use lookup tables +to quickly calculate sine and cosines. Usually a custom lookup table is the way to go if your +application needs this, but perhaps the provided ones can be of service too: + +sin8u(x) + Fast 8-bit ubyte sine of angle 0..255, result is in range 0..255 + +sin8(x) + Fast 8-bit byte sine of angle 0..255, result is in range -127..127 + +sin16u(x) + Fast 16-bit uword sine of angle 0..255, result is in range 0..65535 + +sin16(x) + Fast 16-bit word sine of angle 0..255, result is in range -32767..32767 + +sinr8u(x) + Fast 8-bit ubyte sine of angle 0..179 (each is a 2 degree step), result is in range 0..255 + Angles 180..255 will yield a garbage result! + +sinr8(x) + Fast 8-bit byte sine of angle 0..179 (each is a 2 degree step), result is in range -127..127 + Angles 180..255 will yield a garbage result! + +sinr16u(x) + Fast 16-bit uword sine of angle 0..179 (each is a 2 degree step), result is in range 0..65535 + Angles 180..255 will yield a garbage result! + +sinr16(x) + Fast 16-bit word sine of angle 0..179 (each is a 2 degree step), result is in range -32767..32767 + Angles 180..255 will yield a garbage result! + + +cos8u(x) + Fast 8-bit ubyte cosine of angle 0..255, result is in range 0..255 + +cos8(x) + Fast 8-bit byte cosine of angle 0..255, result is in range -127..127 + +cos16u(x) + Fast 16-bit uword cosine of angle 0..255, result is in range 0..65535 + +cos16(x) + Fast 16-bit word cosine of angle 0..255, result is in range -32767..32767 + +cosr8u(x) + Fast 8-bit ubyte cosine of angle 0..179 (each is a 2 degree step), result is in range 0..255 + Angles 180..255 will yield a garbage result! + +cosr8(x) + Fast 8-bit byte cosine of angle 0..179 (each is a 2 degree step), result is in range -127..127 + Angles 180..255 will yield a garbage result! + +cosr16u(x) + Fast 16-bit uword cosine of angle 0..179 (each is a 2 degree step), result is in range 0..65535 + Angles 180..255 will yield a garbage result! + +cosr16(x) + Fast 16-bit word cosine of angle 0..179 (each is a 2 degree step), result is in range -32767..32767 + Angles 180..255 will yield a garbage result! + cx16logo -------- diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 3c430b570..7aa010cc2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,9 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- vm: add support for all builtin functions +- min/max/any/all should give error when string arg is given instead of array - can't use abs() etc in pipe expression because return type depends on argument type +- vm: add support for all builtin functions - pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls. - createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. - allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type diff --git a/examples/test.p8 b/examples/test.p8 index e1eb846b0..35ae2eb42 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,14 +7,21 @@ main { sub start() { - word zz = 0 - txt.print_b(sgn(zz)) + word[] values = [1111, -222, -9999, 88, 20222, 0, 0, 1111] + word[] values2 = [0,0,0,0,0,1,0,0,0] + txt.print_w(max("abcde")) txt.nl() - zz = -100 - txt.print_b(sgn(zz)) + txt.print_w(max(values)) txt.nl() - zz = 9999 - txt.print_b(sgn(zz)) + txt.print_w(min(values)) + txt.nl() + txt.print_w(sum(values)) + txt.nl() + txt.print_ub(any(values)) + txt.nl() + txt.print_ub(any(values2)) + txt.nl() + txt.print_ub(all(values)) txt.nl() ; uword other = $fe4a diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index 63c81d6ee..c6e04753f 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -21,14 +21,12 @@ SYSCALLS: 12 = rndw ; random WORD 13 = wait ; wait certain amount of jiffies (1/60 sec) 14 = waitvsync ; wait on vsync -15 = sin8u -16 = cos8u -17 = sort_ubyte array -18 = sort_byte array -19 = sort_uword array -20 = sort_word array -21 = reverse_bytes array -22 = reverse_words array +15 = sort_ubyte array +16 = sort_byte array +17 = sort_uword array +18 = sort_word array +19 = reverse_bytes array +20 = reverse_words array */ enum class Syscall { @@ -47,14 +45,12 @@ enum class Syscall { RNDW, WAIT, WAITVSYNC, - SIN8U, - COS8U, SORT_UBYTE, SORT_BYTE, SORT_UWORD, SORT_WORD, - REVERSE_BYTES, - REVERSE_WORDS + REVERSE_BYTES, // TODO not as syscall + REVERSE_WORDS // TODO not as syscall } object SysCalls { @@ -112,18 +108,6 @@ object SysCalls { Thread.sleep(millis) } Syscall.WAITVSYNC -> vm.waitvsync() - Syscall.SIN8U -> { - val arg = vm.registers.getUB(0).toDouble() - val rad = arg /256.0 * 2.0 * PI - val answer = truncate(128.0 + 127.5 * sin(rad)) - vm.registers.setUB(0, answer.toUInt().toUByte()) - } - Syscall.COS8U -> { - val arg = vm.registers.getUB(0).toDouble() - val rad = arg /256.0 * 2.0 * PI - val answer = truncate(128.0 + 127.5 * cos(rad)) - vm.registers.setUB(0, answer.toUInt().toUByte()) - } Syscall.SORT_UBYTE -> { val address = vm.registers.getUW(0).toInt() val length = vm.registers.getUB(1).toInt()