add cosr8, sinr8, cosr16 and sinr16 builtin functions that take a degree 0..179 (= 0..358 in 2 degree steps)

to more easily scale halves/quarters etc of a circle than possible with the ones that take 0..255 'degrees'.
This commit is contained in:
Irmen de Jong 2021-11-09 23:36:47 +01:00
parent 84dafda0e4
commit 8df3da11e3
8 changed files with 373 additions and 7 deletions

View File

@ -46,7 +46,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
"sum" -> funcSum(fcall, resultToStack, resultRegister, sscope)
"any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope)
"sin8", "sin8u", "sin16", "sin16u",
"cos8", "cos8u", "cos16", "cos16u" -> funcSinCosInt(fcall, func, resultToStack, resultRegister, sscope)
"sinr8", "sinr8u", "sinr16", "sinr16u",
"cos8", "cos8u", "cos16", "cos16u",
"cosr8", "cosr8u", "cosr16", "cosr16u" -> funcSinCosInt(fcall, func, resultToStack, resultRegister, sscope)
"sgn" -> funcSgn(fcall, func, resultToStack, resultRegister, sscope)
"sin", "cos", "tan", "atan",
"ln", "log2", "sqrt", "rad",
@ -283,11 +285,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
asmgen.out(" jsr prog8_lib.func_${func.name}_stack")
else
when(func.name) {
"sin8", "sin8u", "cos8", "cos8u" -> {
"sin8", "sin8u", "sinr8", "sinr8u", "cos8", "cos8u", "cosr8", "cosr8u" -> {
asmgen.out(" jsr prog8_lib.func_${func.name}_into_A")
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A)
}
"sin16", "sin16u", "cos16", "cos16u" -> {
"sin16", "sin16u", "sinr16", "sinr16u", "cos16", "cos16u", "cosr16", "cosr16u" -> {
asmgen.out(" jsr prog8_lib.func_${func.name}_into_AY")
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
}

View File

@ -91,6 +91,13 @@ func_sin8_into_A .proc
_sinecos8 .char trunc(127.0 * sin(range(256+64) * rad(360.0/256.0)))
.pend
func_sinr8_into_A .proc
tay
lda _sinecosR8,y
rts
_sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
.pend
func_sin8u_into_A .proc
tay
lda _sinecos8u,y
@ -98,6 +105,13 @@ func_sin8u_into_A .proc
_sinecos8u .byte trunc(128.0 + 127.5 * sin(range(256+64) * rad(360.0/256.0)))
.pend
func_sinr8u_into_A .proc
tay
lda _sinecosR8u,y
rts
_sinecosR8u .byte trunc(128.0 + 127.5 * sin(range(180+45) * rad(360.0/180.0)))
.pend
func_sin8_stack .proc
tay
lda func_sin8_into_A._sinecos8,y
@ -106,6 +120,14 @@ func_sin8_stack .proc
rts
.pend
func_sinr8_stack .proc
tay
lda func_sinr8_into_A._sinecosR8,y
sta P8ESTACK_LO,x
dex
rts
.pend
func_sin8u_stack .proc
tay
lda func_sin8u_into_A._sinecos8u,y
@ -114,18 +136,38 @@ func_sin8u_stack .proc
rts
.pend
func_sinr8u_stack .proc
tay
lda func_sinr8u_into_A._sinecosR8u,y
sta P8ESTACK_LO,x
dex
rts
.pend
func_cos8_into_A .proc
tay
lda func_sin8_into_A._sinecos8+64,y
rts
.pend
func_cosr8_into_A .proc
tay
lda func_sinr8_into_A._sinecosR8+45,y
rts
.pend
func_cos8u_into_A .proc
tay
lda func_sin8u_into_A._sinecos8u+64,y
rts
.pend
func_cosr8u_into_A .proc
tay
lda func_sinr8u_into_A._sinecosR8u+45,y
rts
.pend
func_cos8_stack .proc
tay
lda func_sin8_into_A._sinecos8+64,y
@ -134,6 +176,14 @@ func_cos8_stack .proc
rts
.pend
func_cosr8_stack .proc
tay
lda func_sinr8_into_A._sinecosR8+45,y
sta P8ESTACK_LO,x
dex
rts
.pend
func_cos8u_stack .proc
tay
lda func_sin8u_into_A._sinecos8u+64,y
@ -142,6 +192,14 @@ func_cos8u_stack .proc
rts
.pend
func_cosr8u_stack .proc
tay
lda func_sinr8u_into_A._sinecosR8u+45,y
sta P8ESTACK_LO,x
dex
rts
.pend
func_sin16_into_AY .proc
tay
lda _sinecos8lo,y
@ -155,6 +213,19 @@ _sinecos8lo .byte <_
_sinecos8hi .byte >_
.pend
func_sinr16_into_AY .proc
tay
lda _sinecosR8lo,y
pha
lda _sinecosR8hi,y
tay
pla
rts
_ := trunc(32767.0 * sin(range(180+45) * rad(360.0/180.0)))
_sinecosR8lo .byte <_
_sinecosR8hi .byte >_
.pend
func_sin16u_into_AY .proc
tay
lda _sinecos8ulo,y
@ -168,6 +239,18 @@ _sinecos8ulo .byte <_
_sinecos8uhi .byte >_
.pend
func_sinr16u_into_AY .proc
tay
lda _sinecosR8ulo,y
pha
lda _sinecosR8uhi,y
tay
pla
rts
_ := trunc(32768.0 + 32767.5 * sin(range(180+45) * rad(360.0/180.0)))
_sinecosR8ulo .byte <_
_sinecosR8uhi .byte >_
.pend
func_sin16_stack .proc
tay
@ -179,6 +262,16 @@ func_sin16_stack .proc
rts
.pend
func_sinr16_stack .proc
tay
lda func_sinr16_into_AY._sinecosR8lo,y
sta P8ESTACK_LO,x
lda func_sinr16_into_AY._sinecosR8hi,y
sta P8ESTACK_HI,x
dex
rts
.pend
func_sin16u_stack .proc
tay
lda func_sin16u_into_AY._sinecos8ulo,y
@ -189,6 +282,16 @@ func_sin16u_stack .proc
rts
.pend
func_sinr16u_stack .proc
tay
lda func_sinr16u_into_AY._sinecosR8ulo,y
sta P8ESTACK_LO,x
lda func_sinr16u_into_AY._sinecosR8uhi,y
sta P8ESTACK_HI,x
dex
rts
.pend
func_cos16_into_AY .proc
tay
lda func_sin16_into_AY._sinecos8lo+64,y
@ -199,6 +302,16 @@ func_cos16_into_AY .proc
rts
.pend
func_cosr16_into_AY .proc
tay
lda func_sinr16_into_AY._sinecosR8lo+45,y
pha
lda func_sinr16_into_AY._sinecosR8hi+45,y
tay
pla
rts
.pend
func_cos16u_into_AY .proc
tay
lda func_sin16u_into_AY._sinecos8ulo+64,y
@ -209,6 +322,16 @@ func_cos16u_into_AY .proc
rts
.pend
func_cosr16u_into_AY .proc
tay
lda func_sinr16u_into_AY._sinecosR8ulo+45,y
pha
lda func_sinr16u_into_AY._sinecosR8uhi+45,y
tay
pla
rts
.pend
func_cos16_stack .proc
tay
lda func_sin16_into_AY._sinecos8lo+64,y
@ -219,6 +342,16 @@ func_cos16_stack .proc
rts
.pend
func_cosr16_stack .proc
tay
lda func_sinr16_into_AY._sinecosR8lo+45,y
sta P8ESTACK_LO,x
lda func_sinr16_into_AY._sinecosR8hi+45,y
sta P8ESTACK_HI,x
dex
rts
.pend
func_cos16u_stack .proc
tay
lda func_sin16u_into_AY._sinecos8ulo+64,y
@ -229,6 +362,16 @@ func_cos16u_stack .proc
rts
.pend
func_cosr16u_stack .proc
tay
lda func_sinr16u_into_AY._sinecosR8ulo+45,y
sta P8ESTACK_LO,x
lda func_sinr16u_into_AY._sinecosR8uhi+45,y
sta P8ESTACK_HI,x
dex
rts
.pend
abs_b_stack .proc
; -- push abs(A) on stack (as byte)
jsr abs_b_into_A

View File

@ -429,7 +429,7 @@ internal class AstChecker(private val program: Program,
if(targetDt.isIterable)
errors.err("cannot assign value to string or array", assignment.value.position)
else if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD))
errors.err("type of value doesn't match target", assignment.value.position)
errors.err("type of value $valueDt doesn't match target $targetDt", assignment.value.position)
}
if(assignment.value is TypecastExpression) {

View File

@ -87,6 +87,9 @@ class TestCompilerOnExamplesCx16: FunSpec({
"kefrenbars",
"mandelbrot-gfx-colors",
"multipalette",
"rasterbars",
"sincos",
"tehtriz",
"testgfx2",
),
listOf(false, true)

View File

@ -109,11 +109,19 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("sin8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSin8u ),
FSignature("sin16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinSin16 ),
FSignature("sin16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinSin16u ),
FSignature("sinr8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinSinR8 ),
FSignature("sinr8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSinR8u ),
FSignature("sinr16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinSinR16 ),
FSignature("sinr16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinSinR16u ),
FSignature("cos" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) },
FSignature("cos8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinCos8 ),
FSignature("cos8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCos8u ),
FSignature("cos16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinCos16 ),
FSignature("cos16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinCos16u ),
FSignature("cosr8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinCosR8 ),
FSignature("cosr8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCosR8u ),
FSignature("cosr16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinCosR16 ),
FSignature("cosr16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinCosR16u ),
FSignature("tan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) },
FSignature("atan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) },
FSignature("ln" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) },
@ -372,6 +380,24 @@ private fun builtinSin8u(args: List<Expression>, position: Position, program: Pr
return NumericLiteralValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toInt().toShort(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinSinR8(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("sinr8 requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.BYTE, (127.0 * sin(rad)).toInt().toShort(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinSinR8u(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("sinr8u requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toInt().toShort(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinCos8(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
@ -390,6 +416,24 @@ private fun builtinCos8u(args: List<Expression>, position: Position, program: Pr
return NumericLiteralValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toInt().toShort(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinCosR8(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("cosr8 requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.BYTE, (127.0 * cos(rad)).toInt().toShort(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinCosR8u(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("cosr8u requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toInt().toShort(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinSin16(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
@ -408,6 +452,24 @@ private fun builtinSin16u(args: List<Expression>, position: Position, program: P
return NumericLiteralValue(DataType.UWORD, (32768.0 + 32767.5 * sin(rad)).toInt(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinSinR16(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("sinr16 requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.WORD, (32767.0 * sin(rad)).toInt(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinSinR16u(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("sinr16u requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.UWORD, (32768.0 + 32767.5 * sin(rad)).toInt(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinCos16(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
@ -426,6 +488,24 @@ private fun builtinCos16u(args: List<Expression>, position: Position, program: P
return NumericLiteralValue(DataType.UWORD, (32768.0 + 32767.5 * cos(rad)).toInt(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinCosR16(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("cosr16 requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.WORD, (32767.0 * cos(rad)).toInt(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinCosR16u(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)
throw SyntaxError("cosr16u requires one argument", position)
val constval = args[0].constValue(program) ?: throw NotConstArgumentException()
val rad = constval.number.toDouble() / 180.0 * 2.0 * PI
return NumericLiteralValue(DataType.UWORD, (32768.0 + 32767.5 * cos(rad)).toInt(), position)
}
@Suppress("UNUSED_PARAMETER")
private fun builtinSgn(args: List<Expression>, position: Position, program: Program): NumericLiteralValue {
if (args.size != 1)

View File

@ -704,6 +704,22 @@ cos16u(x)
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!
deg(x)
Radians to degrees.
@ -740,6 +756,22 @@ sin16u(x)
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!
sqrt16(w)
16 bit unsigned integer Square root. Result is unsigned byte.
To do the reverse, squaring an integer, just write ``x*x``.

View File

@ -3,9 +3,6 @@ TODO
For next compiler release (7.3)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- add cosr8, sinr8, cosr16 and sinr16 that take a degree 0..179 (= 0..359 in 2 degree steps)
to more easily scale halves/quarters etc of a circle than possible with the ones that take 0..255 'degrees'.
- if-statement expression simplification sometimes increases code size (Petaxian) FIX THIS!
- add expression simplification to while and until loops as well.
- let typecasting code use expression.typecastTo()

109
examples/cx16/sincos.p8 Normal file
View File

@ -0,0 +1,109 @@
%import graphics
; Note: this program is compatible with CX16 only.
; it doesn't work correctly on C64 because the bitmap screen data overlaps
; the program itself in memory $2000-...
main {
const uword width = 320
const ubyte height = 200
sub start() {
graphics.enable_bitmap_mode()
sincos255()
sys.wait(120)
graphics.clear_screen(1, 0)
sincos180()
sys.wait(120)
graphics.clear_screen(1, 0)
circles()
repeat {
}
}
sub sincos255() {
graphics.line(256,0,256,height-1)
ubyte pixelyb
uword pixelyw
ubyte pixelxb
for pixelxb in 0 to 255 {
pixelyb = cos8u(pixelxb) / 2
graphics.plot(pixelxb, pixelyb)
pixelyb = sin8u(pixelxb) / 2
graphics.plot(pixelxb, pixelyb)
}
for pixelxb in 0 to 255 {
pixelyw = cos16u(pixelxb) / 1024 + 120
graphics.plot(pixelxb, lsb(pixelyw))
pixelyw = sin16u(pixelxb) / 1024 + 120
graphics.plot(pixelxb, lsb(pixelyw))
}
}
sub sincos180() {
graphics.line(180,0,180,height-1)
ubyte pixelyb
uword pixelyw
ubyte pixelxb
for pixelxb in 0 to 179 {
pixelyb = cosr8u(pixelxb) / 2
graphics.plot(pixelxb, pixelyb)
pixelyb = sinr8u(pixelxb) / 2
graphics.plot(pixelxb, pixelyb)
}
for pixelxb in 0 to 179 {
pixelyw = cosr16u(pixelxb) / 1024 + 120
graphics.plot(pixelxb, lsb(pixelyw))
pixelyw = sinr16u(pixelxb) / 1024 + 120
graphics.plot(pixelxb, lsb(pixelyw))
}
}
sub circles() {
ubyte pixelyb
uword pixelxw
ubyte r
; circles with "degrees" from 0 to 255
; TODO FIX WHEN USING NO-OPT! (CORRECT WHEN USING OPTIMIZATION..)
for r in 0 to 255 {
pixelxw = (sin8(r)/2 + 80) as uword
pixelyb = (cos8(r)/2 + height/2) as ubyte
graphics.plot(pixelxw, pixelyb)
}
for r in 0 to 255 {
pixelxw = (sin16(r)/1024 + 80) as uword
pixelyb = (cos16(r)/1024 + height/2) as ubyte
graphics.plot(pixelxw, pixelyb)
}
; circles with half-degrees from 0 to 179 (=full degrees 0..358 with steps of 2 degrees)
; TODO FIX WHEN USING NO-OPT! (CORRECT WHEN USING OPTIMIZATION..)
for r in 0 to 179 {
pixelxw = (sinr8(r) as word /2 + 220) as uword
pixelyb = (cosr8(r)/2 + height/2) as ubyte
graphics.plot(pixelxw, pixelyb)
}
for r in 0 to 179 {
pixelxw = (sinr16(r) as word /1024 + 220) as uword
pixelyb = (cosr16(r)/1024 + height/2) as ubyte
graphics.plot(pixelxw, pixelyb)
}
}
}