From 39a8508daaf076b3166b350ec5637a4598c8af59 Mon Sep 17 00:00:00 2001 From: Irmen de Jong <irmen@razorvine.net> Date: Sat, 5 Jan 2019 02:42:58 +0100 Subject: [PATCH] sine table and bit shifting of signed values fixed --- compiler/examples/cube3d-c64-float.p8 | 93 ++++++++++ compiler/examples/cube3d-c64.p8 | 115 +++++++----- compiler/examples/sprites.p8 | 2 +- compiler/examples/swirl-c64-float.p8 | 36 ++++ compiler/examples/swirl-c64.p8 | 27 +-- compiler/examples/test.p8 | 165 +++--------------- compiler/examples/whizzine.p8 | 79 +++++++++ compiler/src/prog8/compiler/Compiler.kt | 10 +- .../src/prog8/compiler/intermediate/Opcode.kt | 21 ++- .../src/prog8/compiler/intermediate/Value.kt | 12 +- .../src/prog8/compiler/target/c64/AsmGen.kt | 56 ++++-- .../src/prog8/functions/BuiltinFunctions.kt | 12 +- compiler/src/prog8/stackvm/StackVm.kt | 52 ++++-- compiler/test/StackVMOpcodeTests.kt | 19 +- prog8lib/c64utils.p8 | 1 + prog8lib/prog8lib.p8 | 2 +- 16 files changed, 443 insertions(+), 259 deletions(-) create mode 100644 compiler/examples/cube3d-c64-float.p8 create mode 100644 compiler/examples/swirl-c64-float.p8 create mode 100644 compiler/examples/whizzine.p8 diff --git a/compiler/examples/cube3d-c64-float.p8 b/compiler/examples/cube3d-c64-float.p8 new file mode 100644 index 000000000..a69b1d8c0 --- /dev/null +++ b/compiler/examples/cube3d-c64-float.p8 @@ -0,0 +1,93 @@ +%import c64utils +%option enable_floats + +~ main { + + const uword width = 40 + const uword height = 25 + + ; vertices + float[8] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ] + float[8] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ] + float[8] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ] + + ; storage for rotated coordinates + float[len(xcoor)] rotatedx=0.0 + float[len(ycoor)] rotatedy=0.0 + float[len(zcoor)] rotatedz=-1.0 + + sub start() { + float time=0.0 + while(true) { + rotate_vertices(time) + c64.CLEARSCR() + draw_edges() + time+=0.2 + } + } + + sub rotate_vertices(float t) { + ; rotate around origin (0,0,0) + + ; set up the 3d rotation matrix values + float cosa = cos(t) + float sina = sin(t) + float cosb = cos(t*0.33) + float sinb = sin(t*0.33) + float cosc = cos(t*0.78) + float sinc = sin(t*0.78) + + float cosa_sinb = cosa*sinb + float sina_sinb = sina*sinb + float Axx = cosa*cosb + float Axy = cosa_sinb*sinc - sina*cosc + float Axz = cosa_sinb*cosc + sina*sinc + float Ayx = sina*cosb + float Ayy = sina_sinb*sinc + cosa*cosc + float Ayz = sina_sinb*cosc - cosa*sinc + float Azx = -sinb + float Azy = cosb*sinc + float Azz = cosb*cosc + + for ubyte i in 0 to len(xcoor)-1 { + float xc = xcoor[i] + float yc = ycoor[i] + float zc = zcoor[i] + rotatedx[i] = Axx*xc + Axy*yc + Axz*zc + rotatedy[i] = Ayx*xc + Ayy*yc + Ayz*zc + rotatedz[i] = Azx*xc + Azy*yc + Azz*zc + } + } + + sub draw_edges() { + + sub toscreenx(float x, float z) -> byte { + return x/(5.0+z) * (height as float) as byte + width // 2 + } + + sub toscreeny(float y, float z) -> byte { + return y/(5.0+z) * (height as float) as byte + height // 2 + } + + ; plot the points of the 3d cube + ; first the points on the back, then the points on the front (painter algorithm) + + for ubyte i in 0 to len(xcoor)-1 { + float rz = rotatedz[i] + if rz >= 0.1 { + ubyte sx = toscreenx(rotatedx[i], rz) as ubyte + ubyte sy = toscreeny(rotatedy[i], rz) as ubyte + c64scr.setchrclr(sx, sy, 46, i+2) + } + } + + for ubyte i in 0 to len(xcoor)-1 { + float rz = rotatedz[i] + if rz < 0.1 { + ubyte sx = toscreenx(rotatedx[i], rz) as ubyte + ubyte sy = toscreeny(rotatedy[i], rz) as ubyte + c64scr.setchrclr(sx, sy, 81, i+2) + } + } + } +} diff --git a/compiler/examples/cube3d-c64.p8 b/compiler/examples/cube3d-c64.p8 index a69b1d8c0..fb38bab44 100644 --- a/compiler/examples/cube3d-c64.p8 +++ b/compiler/examples/cube3d-c64.p8 @@ -1,5 +1,5 @@ %import c64utils -%option enable_floats +%option enable_floats ; @todo needed for now to avoid compile error in c64lib ~ main { @@ -7,85 +7,104 @@ const uword height = 25 ; vertices - float[8] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ] - float[8] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ] - float[8] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ] + byte[8] xcoor = [ -100, -100, -100, -100, 100, 100, 100, 100 ] + byte[8] ycoor = [ -100, -100, 100, 100, -100, -100, 100, 100 ] + byte[8] zcoor = [ -100, 100, -100, 100, -100, 100, -100, 100 ] ; storage for rotated coordinates - float[len(xcoor)] rotatedx=0.0 - float[len(ycoor)] rotatedy=0.0 - float[len(zcoor)] rotatedz=-1.0 + word[len(xcoor)] rotatedx=0 + word[len(ycoor)] rotatedy=0 + word[len(zcoor)] rotatedz=-32767 sub start() { - float time=0.0 + uword anglex + uword angley + uword anglez while(true) { - rotate_vertices(time) - c64.CLEARSCR() - draw_edges() - time+=0.2 + rotate_vertices(anglex, angley, anglez) + ; c64.CLEARSCR() + ; draw_edges() + anglex+=256 + angley+=83 + anglez+=201 } } - sub rotate_vertices(float t) { + sub rotate_vertices(uword ax, uword ay, uword az) { ; rotate around origin (0,0,0) ; set up the 3d rotation matrix values - float cosa = cos(t) - float sina = sin(t) - float cosb = cos(t*0.33) - float sinb = sin(t*0.33) - float cosc = cos(t*0.78) - float sinc = sin(t*0.78) + word cosa = cos8(msb(ax)) as word + word sina = sin8(msb(ax)) as word + word cosb = cos8(msb(ay)) as word + word sinb = sin8(msb(ay)) as word + word cosc = cos8(msb(az)) as word + word sinc = sin8(msb(az)) as word - float cosa_sinb = cosa*sinb - float sina_sinb = sina*sinb - float Axx = cosa*cosb - float Axy = cosa_sinb*sinc - sina*cosc - float Axz = cosa_sinb*cosc + sina*sinc - float Ayx = sina*cosb - float Ayy = sina_sinb*sinc + cosa*cosc - float Ayz = sina_sinb*cosc - cosa*sinc - float Azx = -sinb - float Azy = cosb*sinc - float Azz = cosb*cosc + word cosa_sinb = msb(cosa*sinb) + word sina_sinb = msb(sina*sinb) + + c64.CHROUT('>') + c64scr.print_w(cosa_sinb) + c64.CHROUT(',') + c64scr.print_w(sina_sinb) + c64.CHROUT('\n') + + word Axx = msb(cosa*cosb) + word Axy = msb(cosa_sinb*sinc - sina*cosc) + word Axz = msb(cosa_sinb*cosc + sina*sinc) + word Ayx = msb(sina*cosb) + word Ayy = msb(sina_sinb*sinc + cosa*cosc) + word Ayz = msb(sina_sinb*cosc - cosa*sinc) + word Azx = -sinb + word Azy = msb(cosb*sinc) + word Azz = msb(cosb*cosc) + + c64.CHROUT('>') + c64scr.print_w(Axx) + c64.CHROUT(',') + c64scr.print_w(Axy) + c64.CHROUT(',') + c64scr.print_w(Axz) + c64.CHROUT('\n') for ubyte i in 0 to len(xcoor)-1 { - float xc = xcoor[i] - float yc = ycoor[i] - float zc = zcoor[i] - rotatedx[i] = Axx*xc + Axy*yc + Axz*zc - rotatedy[i] = Ayx*xc + Ayy*yc + Ayz*zc - rotatedz[i] = Azx*xc + Azy*yc + Azz*zc + word xc = xcoor[i] + word yc = ycoor[i] + word zc = zcoor[i] + rotatedx[i] = Axx*xc ;+ Axy*yc + Axz*zc ; @todo wrong code generated? crash! + rotatedy[i] = Ayx*xc ;+ Ayy*yc + Ayz*zc ; @todo wrong code generated? crash! + rotatedz[i] = Azx*xc ;+ Azy*yc + Azz*zc ; @todo wrong code generated? crash! } } sub draw_edges() { - sub toscreenx(float x, float z) -> byte { - return x/(5.0+z) * (height as float) as byte + width // 2 + sub toscreenx(word x, word z) -> ubyte { + return msb(x) and 31 } - sub toscreeny(float y, float z) -> byte { - return y/(5.0+z) * (height as float) as byte + height // 2 + sub toscreeny(word y, word z) -> ubyte { + return msb(y) and 15 } ; plot the points of the 3d cube ; first the points on the back, then the points on the front (painter algorithm) for ubyte i in 0 to len(xcoor)-1 { - float rz = rotatedz[i] - if rz >= 0.1 { - ubyte sx = toscreenx(rotatedx[i], rz) as ubyte - ubyte sy = toscreeny(rotatedy[i], rz) as ubyte + word rz = rotatedz[i] + if rz >= 100 { + ubyte sx = toscreenx(rotatedx[i], rz) + ubyte sy = toscreeny(rotatedy[i], rz) c64scr.setchrclr(sx, sy, 46, i+2) } } for ubyte i in 0 to len(xcoor)-1 { - float rz = rotatedz[i] - if rz < 0.1 { - ubyte sx = toscreenx(rotatedx[i], rz) as ubyte - ubyte sy = toscreeny(rotatedy[i], rz) as ubyte + word rz = rotatedz[i] + if rz < 100 { + ubyte sx = toscreenx(rotatedx[i], rz) + ubyte sy = toscreeny(rotatedy[i], rz) c64scr.setchrclr(sx, sy, 81, i+2) } } diff --git a/compiler/examples/sprites.p8 b/compiler/examples/sprites.p8 index d3afbfeb9..5adcb41cf 100644 --- a/compiler/examples/sprites.p8 +++ b/compiler/examples/sprites.p8 @@ -40,7 +40,7 @@ c64.STROUT("balloon sprites!\n") c64.STROUT("...we are all floating...\n") - const uword sprite_address_ptr = &balloonsprite // 64 + const uword sprite_address_ptr = $0a00 // 64 c64.SPRPTR0 = sprite_address_ptr c64.SPRPTR1 = sprite_address_ptr c64.SPRPTR2 = sprite_address_ptr diff --git a/compiler/examples/swirl-c64-float.p8 b/compiler/examples/swirl-c64-float.p8 new file mode 100644 index 000000000..2e74b0e68 --- /dev/null +++ b/compiler/examples/swirl-c64-float.p8 @@ -0,0 +1,36 @@ +%import c64utils +%option enable_floats + +~ main { + + const uword width = 40 + const uword height = 25 + + sub start() { + + float t + ubyte color + + while true { + float x = sin(t) + float y = cos(t*1.1356) + ubyte xx=screenx(x) + ubyte yy=screeny(y) + + ;c64.COLOR = color + ;c64scr.PLOT(xx,yy) + ;c64.CHROUT('Q') ; shift-q = filled circle + c64scr.setchrclr(xx, yy, 81, color) + + t += 0.08 + color++ + } + } + + sub screenx(float x) -> ubyte { + return (x * width/2.2) + width/2.0 as ubyte + } + sub screeny(float y) -> ubyte { + return (y * height/2.2) + height/2.0 as ubyte + } +} diff --git a/compiler/examples/swirl-c64.p8 b/compiler/examples/swirl-c64.p8 index 2e74b0e68..99ec7f282 100644 --- a/compiler/examples/swirl-c64.p8 +++ b/compiler/examples/swirl-c64.p8 @@ -1,5 +1,5 @@ %import c64utils -%option enable_floats +%option enable_floats ; @todo needed for now to avoid compile error in c64lib ~ main { @@ -8,29 +8,20 @@ sub start() { - float t + uword anglex + uword angley ubyte color while true { - float x = sin(t) - float y = cos(t*1.1356) - ubyte xx=screenx(x) - ubyte yy=screeny(y) - - ;c64.COLOR = color - ;c64scr.PLOT(xx,yy) - ;c64.CHROUT('Q') ; shift-q = filled circle + word x = sin8(msb(anglex)) as word + word y = cos8(msb(angley)) as word + ubyte xx=msb(x*39) + 20 ; -127..127 -> 0..39 + ubyte yy=msb(y*24) + 12 ; -127..127 -> 0..24 c64scr.setchrclr(xx, yy, 81, color) - t += 0.08 + anglex+=800 + angley+=947 color++ } } - - sub screenx(float x) -> ubyte { - return (x * width/2.2) + width/2.0 as ubyte - } - sub screeny(float y) -> ubyte { - return (y * height/2.2) + height/2.0 as ubyte - } } diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 2db6e4550..edd04688b 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -5,148 +5,39 @@ ~ main { sub start() { - ubyte i=0 + memory byte b1 = $c000 + memory byte b2 = $c001 + memory word w1 = $c002 + memory word w2 = $c004 - vm_write_str("sin 0 ") - i=0 - vm_write_num(sin8(0)) - vm_write_char(':') - vm_write_num(sin8(i)) - vm_write_char('\n') - vm_write_str("sin 50 ") - i=50 - vm_write_num(sin8(50)) - vm_write_char(':') - vm_write_num(sin8(i)) - vm_write_char('\n') + b1=50 + b2=-50 + w1=100 + w2=-100 - vm_write_str("sin 128 ") - i=128 - vm_write_num(sin8(128)) - vm_write_char(':') - vm_write_num(sin8(i)) - vm_write_char('\n') + c64scr.print_b(b1) + c64.CHROUT('/') + lsr(b1) + c64scr.print_b(b1) + c64.CHROUT('\n') + c64scr.print_b(b2) + c64.CHROUT('/') + lsr(b2) + c64scr.print_b(b2) + c64.CHROUT('\n') + c64scr.print_w(w1) + c64.CHROUT('/') + lsr(w1) + c64scr.print_w(w1) + c64.CHROUT('\n') + c64scr.print_w(w2) + c64.CHROUT('/') + lsr(w2) + c64scr.print_w(w2) + c64.CHROUT('\n') - vm_write_str("sin 140 ") - i=140 - vm_write_num(sin8(140)) - vm_write_char(':') - vm_write_num(sin8(i)) - vm_write_char('\n') - vm_write_str("sin 250 ") - i=250 - vm_write_num(sin8(250)) - vm_write_char(':') - vm_write_num(sin8(i)) - vm_write_char('\n') - - vm_write_str("cos 0 ") - i=0 - vm_write_num(cos8(0)) - vm_write_char(':') - vm_write_num(cos8(i)) - vm_write_char('\n') - - vm_write_str("cos 50 ") - i=50 - vm_write_num(cos8(50)) - vm_write_char(':') - vm_write_num(cos8(i)) - vm_write_char('\n') - - vm_write_str("cos 128 ") - i=128 - vm_write_num(cos8(128)) - vm_write_char(':') - vm_write_num(cos8(i)) - vm_write_char('\n') - - vm_write_str("cos 140 ") - i=140 - vm_write_num(cos8(140)) - vm_write_char(':') - vm_write_num(cos8(i)) - vm_write_char('\n') - - vm_write_str("cos 250 ") - i=250 - vm_write_num(cos8(250)) - vm_write_char(':') - vm_write_num(cos8(i)) - vm_write_char('\n') - vm_write_char('\n') - - vm_write_str("sin16 0 ") - i=0 - vm_write_num(sin16(0)) - vm_write_char(':') - vm_write_num(sin16(i)) - vm_write_char('\n') - - vm_write_str("sin16 50 ") - i=50 - vm_write_num(sin16(50)) - vm_write_char(':') - vm_write_num(sin16(i)) - vm_write_char('\n') - - vm_write_str("sin16 128 ") - i=128 - vm_write_num(sin16(128)) - vm_write_char(':') - vm_write_num(sin16(i)) - vm_write_char('\n') - - vm_write_str("sin16 140 ") - i=140 - vm_write_num(sin16(140)) - vm_write_char(':') - vm_write_num(sin16(i)) - vm_write_char('\n') - - vm_write_str("sin16 250 ") - i=250 - vm_write_num(sin16(250)) - vm_write_char(':') - vm_write_num(sin16(i)) - vm_write_char('\n') - - vm_write_str("cos16 0 ") - i=0 - vm_write_num(cos16(0)) - vm_write_char(':') - vm_write_num(cos16(i)) - vm_write_char('\n') - - vm_write_str("cos16 50 ") - i=50 - vm_write_num(cos16(50)) - vm_write_char(':') - vm_write_num(cos16(i)) - vm_write_char('\n') - - vm_write_str("cos16 128 ") - i=128 - vm_write_num(cos16(128)) - vm_write_char(':') - vm_write_num(cos16(i)) - vm_write_char('\n') - - vm_write_str("cos16 140 ") - i=140 - vm_write_num(cos16(140)) - vm_write_char(':') - vm_write_num(cos16(i)) - vm_write_char('\n') - - vm_write_str("cos16 250 ") - i=250 - vm_write_num(cos16(250)) - vm_write_char(':') - vm_write_num(cos16(i)) - vm_write_char('\n') } } diff --git a/compiler/examples/whizzine.p8 b/compiler/examples/whizzine.p8 new file mode 100644 index 000000000..75ae1764f --- /dev/null +++ b/compiler/examples/whizzine.p8 @@ -0,0 +1,79 @@ +%import c64utils +%option enable_floats ; @todo needed for now to avoid compile error in c64lib + + +~ spritedata $0a00 { + ; this memory block contains the sprite data + ; it must start on an address aligned to 64 bytes. + %option force_output ; make sure the data in this block appears in the resulting program + + ubyte[63] balloonsprite = [ %00000000,%01111111,%00000000, + %00000001,%11111111,%11000000, + %00000011,%11111111,%11100000, + %00000011,%11100011,%11100000, + %00000111,%11011100,%11110000, + %00000111,%11011101,%11110000, + %00000111,%11011100,%11110000, + %00000011,%11100011,%11100000, + %00000011,%11111111,%11100000, + %00000011,%11111111,%11100000, + %00000010,%11111111,%10100000, + %00000001,%01111111,%01000000, + %00000001,%00111110,%01000000, + %00000000,%10011100,%10000000, + %00000000,%10011100,%10000000, + %00000000,%01001001,%00000000, + %00000000,%01001001,%00000000, + %00000000,%00111110,%00000000, + %00000000,%00111110,%00000000, + %00000000,%00111110,%00000000, + %00000000,%00011100,%00000000 ] +} + +~ main { + + sub start() { + + const uword sprite_address_ptr = $0a00 // 64 + c64.SPRPTR0 = sprite_address_ptr + c64.SPRPTR1 = sprite_address_ptr + c64.SPRPTR2 = sprite_address_ptr + c64.SPRPTR3 = sprite_address_ptr + c64.SPRPTR4 = sprite_address_ptr + c64.SPRPTR5 = sprite_address_ptr + c64.SPRPTR6 = sprite_address_ptr + c64.SPRPTR7 = sprite_address_ptr + + c64.SPENA = 255 ; enable all sprites + c64utils.set_rasterirq(240) ; enable animation + } +} + + +~ irq { + + ubyte angle=0 + +sub irq() { + const uword SP0X = $d000 + const uword SP0Y = $d001 + + c64.EXTCOL-- + + angle++ + c64.MSIGX=0 + for ubyte i in 0 to 14 step 2 { + word x = (sin8(angle*2-i*8) as word)+190 + byte y = cos8(angle*3-i*8) + lsr(y) + @(SP0X+i) = lsb(x) + @(SP0Y+i) = y+150 as ubyte + + lsr(c64.MSIGX) + if msb(x) c64.MSIGX |= %10000000 + } + + c64.EXTCOL++ +} + +} diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 5c9864d4b..eeb3760f9 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -783,8 +783,8 @@ private class StatementTranslator(private val prog: IntermediateProgram, val arg = args.single() val dt = arg.resultingDatatype(namespace, heap) when (dt) { - DataType.UBYTE -> prog.instr(Opcode.SHL_BYTE) - DataType.UWORD -> prog.instr(Opcode.SHL_WORD) + DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHL_BYTE) + DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHL_WORD) else -> throw CompilerException("wrong datatype") } // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again @@ -794,8 +794,10 @@ private class StatementTranslator(private val prog: IntermediateProgram, val arg = args.single() val dt = arg.resultingDatatype(namespace, heap) when (dt) { - DataType.UBYTE -> prog.instr(Opcode.SHR_BYTE) - DataType.UWORD -> prog.instr(Opcode.SHR_WORD) + DataType.UBYTE -> prog.instr(Opcode.SHR_UBYTE) + DataType.BYTE -> prog.instr(Opcode.SHR_SBYTE) + DataType.UWORD -> prog.instr(Opcode.SHR_UWORD) + DataType.WORD -> prog.instr(Opcode.SHR_SWORD) else -> throw CompilerException("wrong datatype") } // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index f0ccedb27..778e8946a 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -81,12 +81,18 @@ enum class Opcode { SHL_MEM_WORD, SHL_VAR_BYTE, SHL_VAR_WORD, - SHR_BYTE, - SHR_WORD, - SHR_MEM_BYTE, - SHR_MEM_WORD, - SHR_VAR_BYTE, - SHR_VAR_WORD, + SHR_UBYTE, + SHR_SBYTE, + SHR_UWORD, + SHR_SWORD, + SHR_MEM_UBYTE, + SHR_MEM_SBYTE, + SHR_MEM_UWORD, + SHR_MEM_SWORD, + SHR_VAR_UBYTE, + SHR_VAR_SBYTE, + SHR_VAR_UWORD, + SHR_VAR_SWORD, ROL_BYTE, ROL_WORD, ROL_MEM_BYTE, @@ -259,7 +265,8 @@ enum class Opcode { val opcodesWithVarArgument = setOf( Opcode.INC_VAR_B, Opcode.INC_VAR_W, Opcode.DEC_VAR_B, Opcode.DEC_VAR_W, Opcode.INC_VAR_UB, Opcode.INC_VAR_UW, Opcode.DEC_VAR_UB, Opcode.DEC_VAR_UW, - Opcode.SHR_VAR_BYTE, Opcode.SHR_VAR_WORD, Opcode.SHL_VAR_BYTE, Opcode.SHL_VAR_WORD, + Opcode.SHR_VAR_SBYTE, Opcode.SHR_VAR_UBYTE, Opcode.SHR_VAR_SWORD, Opcode.SHR_VAR_UWORD, + Opcode.SHL_VAR_BYTE, Opcode.SHL_VAR_WORD, Opcode.ROL_VAR_BYTE, Opcode.ROL_VAR_WORD, Opcode.ROR_VAR_BYTE, Opcode.ROR_VAR_WORD, Opcode.ROL2_VAR_BYTE, Opcode.ROL2_VAR_WORD, Opcode.ROR2_VAR_BYTE, Opcode.ROR2_VAR_WORD, Opcode.POP_VAR_BYTE, Opcode.POP_VAR_WORD, Opcode.POP_VAR_FLOAT, diff --git a/compiler/src/prog8/compiler/intermediate/Value.kt b/compiler/src/prog8/compiler/intermediate/Value.kt index 026888a20..8ae3eb00f 100644 --- a/compiler/src/prog8/compiler/intermediate/Value.kt +++ b/compiler/src/prog8/compiler/intermediate/Value.kt @@ -235,11 +235,13 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) { fun shr(): Value { val v = integerValue() - if(type==DataType.UBYTE) - return Value(type, (v ushr 1) and 255) - if(type==DataType.UWORD) - return Value(type, (v ushr 1) and 65535) - throw ValueException("invalid type for shr: $type") + return when(type){ + DataType.UBYTE -> Value(type, (v ushr 1) and 255) + DataType.BYTE -> TODO("shr sbyte") + DataType.UWORD -> Value(type, (v ushr 1) and 65535) + DataType.WORD -> TODO("shr sword") + else -> throw ValueException("invalid type for shr: $type") + } } fun rol(carry: Boolean): Pair<Value, Boolean> { diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 7da556aba..98d9f821b 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -922,16 +922,18 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // an in place operation that consists of a push-value / op / push-index-value / pop-into-indexed-var return when(ins.opcode) { Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8) - Opcode.SHR_BYTE -> AsmFragment(" lsr $variable+$index", 8) - Opcode.SHL_WORD -> AsmFragment(" asl $variable+$index | rol $variable+${index+1}", 8) - Opcode.SHR_WORD -> AsmFragment(" lsr $variable+${index+1},x | ror $variable+$index", 8) + Opcode.SHR_UBYTE -> AsmFragment(" lsr $variable+$index", 8) + Opcode.SHR_SBYTE -> AsmFragment(" lda $variable+$index | asl a | ror $variable+$index") + Opcode.SHL_WORD -> AsmFragment(" asl $variable+${index+1} | rol $variable+$index", 8) + Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index", 8) + Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index+1} | asl a | ror $variable+${index+1} | ror $variable+$index", 8) Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8) Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8) - Opcode.ROL_WORD -> AsmFragment(" rol $variable+$index | rol $variable+${index+1}", 8) + Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index+1} | rol $variable+$index", 8) Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index+1} | ror $variable+$index", 8) Opcode.ROL2_BYTE -> AsmFragment(" lda $variable+$index | cmp #\$80 | rol $variable+$index", 8) Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10) - Opcode.ROL2_WORD -> AsmFragment(" asl $variable+$index | rol $variable+${index+1} | bcc + | inc $variable+$index |+",20) + Opcode.ROL2_WORD -> AsmFragment(" asl $variable+${index+1} | rol $variable+$index | bcc + | inc $variable+$index |+",20) // todo wrong??? Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index+1} | ror $variable+$index | bcc + | lda $variable+${index+1} | ora #\$80 | sta $variable+${index+1} |+", 30) Opcode.INC_INDEXED_VAR_B, Opcode.INC_INDEXED_VAR_UB -> AsmFragment(" inc $variable+$index", 2) Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UB -> AsmFragment(" dec $variable+$index", 5) @@ -974,9 +976,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, return when (ins.opcode) { Opcode.SHL_BYTE -> AsmFragment(" txa | $loadX asl $variable,x | tax", 10) - Opcode.SHR_BYTE -> AsmFragment(" txa | $loadX lsr $variable,x | tax", 10) + Opcode.SHR_UBYTE -> AsmFragment(" txa | $loadX lsr $variable,x | tax", 10) + Opcode.SHR_SBYTE -> AsmFragment("$saveX $loadX lda $variable,x | asl a | ror $variable,x $restoreX", 10) Opcode.SHL_WORD -> AsmFragment("$saveX $loadXWord asl $variable,x | rol $variable+1,x $restoreX", 10) - Opcode.SHR_WORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x $restoreX", 10) + Opcode.SHR_UWORD -> AsmFragment("$saveX $loadXWord lsr $variable+1,x | ror $variable,x $restoreX", 10) + Opcode.SHR_SWORD -> AsmFragment("$saveX $loadXWord lda $variable+1,x | asl a | ror $variable+1,x | ror $variable,x $restoreX", 10) Opcode.ROL_BYTE -> AsmFragment(" txa | $loadX rol $variable,x | tax", 10) Opcode.ROR_BYTE -> AsmFragment(" txa | $loadX ror $variable,x | tax", 10) Opcode.ROL_WORD -> AsmFragment("$saveX $loadXWord rol $variable,x | rol $variable+1,x $restoreX", 10) @@ -999,14 +1003,16 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } private fun sameMemOperation(address: Int, ins: Instruction): AsmFragment? { - // an in place operation that consists of a push-mem / op / pop-mem sequence + // an in place operation that consists of push-mem / op / pop-mem val addr = address.toHex() val addrHi = (address+1).toHex() return when(ins.opcode) { Opcode.SHL_BYTE -> AsmFragment(" asl $addr", 10) - Opcode.SHR_BYTE -> AsmFragment(" lsr $addr", 10) + Opcode.SHR_UBYTE -> AsmFragment(" lsr $addr", 10) + Opcode.SHR_SBYTE -> AsmFragment(" lda $addr | asl a | ror $addr", 10) Opcode.SHL_WORD -> AsmFragment(" asl $addr | rol $addrHi", 10) - Opcode.SHR_WORD -> AsmFragment(" lsr $addrHi | ror $addr", 10) + Opcode.SHR_UWORD -> AsmFragment(" lsr $addrHi | ror $addr", 10) + Opcode.SHR_SWORD -> AsmFragment(" lda $addrHi | asl a | ror $addrHi | ror $addr", 10) Opcode.ROL_BYTE -> AsmFragment(" rol $addr", 10) Opcode.ROR_BYTE -> AsmFragment(" ror $addr", 10) Opcode.ROL_WORD -> AsmFragment(" rol $addr | rol $addrHi", 10) @@ -1030,7 +1036,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, else -> AsmFragment(" asl $variable", 10) } } - Opcode.SHR_BYTE -> { + Opcode.SHR_UBYTE -> { when (variable) { "A" -> AsmFragment(" lsr a", 10) "X" -> AsmFragment(" txa | lsr a | tax", 10) @@ -1038,12 +1044,25 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, else -> AsmFragment(" lsr $variable", 10) } } + Opcode.SHR_SBYTE -> { + // arithmetic shift right (keep sign bit) + when (variable) { + "A" -> AsmFragment(" cmp #$80 | ror a", 10) + "X" -> AsmFragment(" txa | cmp #$80 | ror a | tax", 10) + "Y" -> AsmFragment(" tya | cmp #$80 | ror a | tay", 10) + else -> AsmFragment(" lda $variable | asl a | ror $variable", 10) + } + } Opcode.SHL_WORD -> { AsmFragment(" asl $variable | rol $variable+1", 10) } - Opcode.SHR_WORD -> { + Opcode.SHR_UWORD -> { AsmFragment(" lsr $variable+1 | ror $variable", 10) } + Opcode.SHR_SWORD -> { + // arithmetic shift right (keep sign bit) + AsmFragment(" lda $variable+1 | asl a | ror $variable+1 | ror $variable", 10) + } Opcode.ROL_BYTE -> { when (variable) { "A" -> AsmFragment(" rol a", 10) @@ -2880,7 +2899,18 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment -> " lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " }, - + // push var byte | bytevalue + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.BITOR_BYTE)) { segment -> + " lda ${segment[0].callLabel} | ora #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " + }, + // push var byte & bytevalue + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.BITAND_BYTE)) { segment -> + " lda ${segment[0].callLabel} | and #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " + }, + // push var byte ^ bytevalue + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment -> + " lda ${segment[0].callLabel} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex " + }, // 16 bit addition avoiding excessive stack usage // @todo optimize this even more with longer asmpatterns (avoid stack use altogether on most common operations) diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 53c400b6e..04f770ea9 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -22,8 +22,8 @@ val BuiltinFunctions = mapOf( "ror" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "rol2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "ror2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - "lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - "lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + "lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), + "lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), // these few have a return value depending on the argument(s): "max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args @@ -303,7 +303,7 @@ private fun builtinSin8(args: List<IExpression>, position: Position, namespace:I throw SyntaxError("sin8 requires one argument", position) val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() val rad = constval.asNumericValue!!.toDouble() /256.0 * 2.0 * PI - return LiteralValue(DataType.BYTE, bytevalue = (32767.5* sin(rad)).toInt().shr(8).toShort(), position = position) + return LiteralValue(DataType.BYTE, bytevalue = (32767.0* sin(rad)).toInt().shr(8).toShort(), position = position) } private fun builtinCos8(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { @@ -311,7 +311,7 @@ private fun builtinCos8(args: List<IExpression>, position: Position, namespace:I throw SyntaxError("cos8 requires one argument", position) val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() val rad = constval.asNumericValue!!.toDouble() /256.0 * 2.0 * PI - return LiteralValue(DataType.BYTE, bytevalue = (32767.5* cos(rad)).toInt().shr(8).toShort(), position = position) + return LiteralValue(DataType.BYTE, bytevalue = (32767.0* cos(rad)).toInt().shr(8).toShort(), position = position) } private fun builtinSin16(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { @@ -319,7 +319,7 @@ private fun builtinSin16(args: List<IExpression>, position: Position, namespace: throw SyntaxError("sin16 requires one argument", position) val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() val rad = constval.asNumericValue!!.toDouble() /256.0 * 2.0 * PI - return LiteralValue(DataType.WORD, wordvalue = (32767.5* sin(rad)).toInt(), position = position) + return LiteralValue(DataType.WORD, wordvalue = (32767.0* sin(rad)).toInt(), position = position) } private fun builtinCos16(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { @@ -327,7 +327,7 @@ private fun builtinCos16(args: List<IExpression>, position: Position, namespace: throw SyntaxError("cos16 requires one argument", position) val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() val rad = constval.asNumericValue!!.toDouble() /256.0 * 2.0 * PI - return LiteralValue(DataType.WORD, wordvalue = (32767.5* cos(rad)).toInt(), position = position) + return LiteralValue(DataType.WORD, wordvalue = (32767.0* cos(rad)).toInt(), position = position) } private fun numericLiteral(value: Number, position: Position): LiteralValue { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 00f3e6a4a..454a1ac5d 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -564,16 +564,26 @@ class StackVm(private var traceOutputFile: String?) { checkDt(v, DataType.UWORD) evalstack.push(v.shl()) } - Opcode.SHR_BYTE -> { + Opcode.SHR_UBYTE -> { val v = evalstack.pop() checkDt(v, DataType.UBYTE) evalstack.push(v.shr()) } - Opcode.SHR_WORD -> { + Opcode.SHR_SBYTE -> { + val v = evalstack.pop() + checkDt(v, DataType.BYTE) + evalstack.push(v.shr()) + } + Opcode.SHR_UWORD -> { val v = evalstack.pop() checkDt(v, DataType.UWORD) evalstack.push(v.shr()) } + Opcode.SHR_SWORD -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) + evalstack.push(v.shr()) + } Opcode.ROL_BYTE -> { val v = evalstack.pop() checkDt(v, DataType.UBYTE) @@ -691,18 +701,30 @@ class StackVm(private var traceOutputFile: String?) { val newValue = value.shl() mem.setUWord(addr, newValue.integerValue()) } - Opcode.SHR_MEM_BYTE -> { + Opcode.SHR_MEM_UBYTE -> { val addr = ins.arg!!.integerValue() val value = Value(DataType.UBYTE, mem.getUByte(addr)) val newValue = value.shr() mem.setUByte(addr, newValue.integerValue().toShort()) } - Opcode.SHR_MEM_WORD -> { + Opcode.SHR_MEM_SBYTE -> { + val addr = ins.arg!!.integerValue() + val value = Value(DataType.BYTE, mem.getSByte(addr)) + val newValue = value.shr() + mem.setSByte(addr, newValue.integerValue().toShort()) + } + Opcode.SHR_MEM_UWORD -> { val addr = ins.arg!!.integerValue() val value = Value(DataType.UWORD, mem.getUWord(addr)) val newValue = value.shr() mem.setUWord(addr, newValue.integerValue()) } + Opcode.SHR_MEM_SWORD -> { + val addr = ins.arg!!.integerValue() + val value = Value(DataType.WORD, mem.getSWord(addr)) + val newValue = value.shr() + mem.setSWord(addr, newValue.integerValue()) + } Opcode.ROL_MEM_BYTE -> { val addr = ins.arg!!.integerValue() val value = Value(DataType.UBYTE, mem.getUByte(addr)) @@ -867,16 +889,26 @@ class StackVm(private var traceOutputFile: String?) { checkDt(variable, DataType.UWORD) variables[ins.callLabel] =variable.shl() } - Opcode.SHR_VAR_BYTE -> { + Opcode.SHR_VAR_UBYTE -> { val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) variables[ins.callLabel] =variable.shr() } - Opcode.SHR_VAR_WORD -> { + Opcode.SHR_VAR_SBYTE -> { + val variable = getVar(ins.callLabel!!) + checkDt(variable, DataType.BYTE) + variables[ins.callLabel] =variable.shr() + } + Opcode.SHR_VAR_UWORD -> { val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UWORD) variables[ins.callLabel] =variable.shr() } + Opcode.SHR_VAR_SWORD -> { + val variable = getVar(ins.callLabel!!) + checkDt(variable, DataType.WORD) + variables[ins.callLabel] =variable.shr() + } Opcode.ROL_VAR_BYTE -> { val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE) @@ -1529,19 +1561,19 @@ class StackVm(private var traceOutputFile: String?) { Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_SIN8 -> { val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI - evalstack.push(Value(DataType.BYTE, (32767.5* sin(rad)).toInt().shr(8).toShort())) + evalstack.push(Value(DataType.BYTE, (32767.0* sin(rad)).toInt().shr(8).toShort())) } Syscall.FUNC_SIN16 -> { val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI - evalstack.push(Value(DataType.WORD, (32767.5* sin(rad)).toInt())) + evalstack.push(Value(DataType.WORD, (32767.0* sin(rad)).toInt())) } Syscall.FUNC_COS8 -> { val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI - evalstack.push(Value(DataType.BYTE, (32767.5* cos(rad)).toInt().shr(8).toShort())) + evalstack.push(Value(DataType.BYTE, (32767.0* cos(rad)).toInt().shr(8).toShort())) } Syscall.FUNC_COS16 -> { val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI - evalstack.push(Value(DataType.WORD, (32767.5* cos(rad)).toInt())) + evalstack.push(Value(DataType.WORD, (32767.0* cos(rad)).toInt())) } Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt())) Syscall.FUNC_ABS -> { diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index 3869bc3b1..ccf216294 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -923,25 +923,26 @@ class TestStackVmOpcodes { @Test fun testSHR() { + // @todo test SHR signed byte + signed word val ins = mutableListOf( Instruction(Opcode.PUSH_FLOAT, Value(DataType.FLOAT, 9.99)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 3)), Instruction(Opcode.PUSH_WORD, Value(DataType.UWORD, 61005)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 3)), Instruction(Opcode.PUSH_BYTE, Value(DataType.UBYTE, 249)), - Instruction(Opcode.SHR_BYTE), // 124 + Instruction(Opcode.SHR_UBYTE), // 124 Instruction(Opcode.DISCARD_BYTE), - Instruction(Opcode.SHR_BYTE), // 1 - Instruction(Opcode.SHR_BYTE), // 0 - Instruction(Opcode.SHR_BYTE), // 0 + Instruction(Opcode.SHR_UBYTE), // 1 + Instruction(Opcode.SHR_UBYTE), // 0 + Instruction(Opcode.SHR_UBYTE), // 0 Instruction(Opcode.DISCARD_BYTE), - Instruction(Opcode.SHR_WORD), // 30502 + Instruction(Opcode.SHR_UWORD), // 30502 Instruction(Opcode.DISCARD_WORD), - Instruction(Opcode.SHR_WORD), // 1 - Instruction(Opcode.SHR_WORD), // 0 - Instruction(Opcode.SHR_WORD), // 0 + Instruction(Opcode.SHR_UWORD), // 1 + Instruction(Opcode.SHR_UWORD), // 0 + Instruction(Opcode.SHR_UWORD), // 0 Instruction(Opcode.DISCARD_WORD), - Instruction(Opcode.SHR_BYTE) // error on float + Instruction(Opcode.SHR_UBYTE) // error on float ) vm.load(makeProg(ins), null) vm.step(6) diff --git a/prog8lib/c64utils.p8 b/prog8lib/c64utils.p8 index 3670c643e..1a55292de 100644 --- a/prog8lib/c64utils.p8 +++ b/prog8lib/c64utils.p8 @@ -531,6 +531,7 @@ _raster_irq_handler ; @todo move to c64fp.p8 and enable float-checkin astchecker.process(decl: VarDecl) again const float PI = 3.141592653589793 + const float TWOPI = 6.283185307179586 asmsub FREADS32 () -> clobbers(A,X,Y) -> () { diff --git a/prog8lib/prog8lib.p8 b/prog8lib/prog8lib.p8 index bb9d3c9b4..469e6862b 100644 --- a/prog8lib/prog8lib.p8 +++ b/prog8lib/prog8lib.p8 @@ -936,7 +936,7 @@ func_sin16 .proc sta ESTACK_HI+1,x rts -_ := 32767.5 * sin(range(256+64) * rad(360.0/256.0)) +_ := 32767 * sin(range(256+64) * rad(360.0/256.0)) sinecos8lo .byte <_ sinecos8hi .byte >_ .pend