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