diff --git a/compiler/examples/cube3d-novm.p8 b/compiler/examples/cube3d-novm.p8 new file mode 100644 index 000000000..872e69c8a --- /dev/null +++ b/compiler/examples/cube3d-novm.p8 @@ -0,0 +1,124 @@ +%import c64utils +%option enable_floats + +~ irq { + uword global_time + ubyte time_changed + + sub irq() { + global_time++ + time_changed = 1 + } +} + + +~ main { + + const uword width = 320 + const uword height = 200 + + ; 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 ] + + ; edges (msb=from vertex, lsb=to vertex) + uword[12] edges = [$0001, $0103, $0302, $0200, $0405, $0507, $0706, $0604, $0004, $0105, $0206, $0307] + + ; storage for rotated coordinates + float[len(xcoor)] rotatedx + float[len(ycoor)] rotatedy + float[len(zcoor)] rotatedz + + sub start() { + while(1) { + if irq.time_changed { + irq.time_changed = 0 + ;vm_gfx_clearscr(0) + ;vm_gfx_text(8, 6, 1, "Spin") + ;vm_gfx_text(29, 11, 1, "to Win !") + + for uword i in 0 to width//10 { + uword x=i*2+width//2-width//10 + ;vm_gfx_line(x, 130, i*10.w, 199, 6) + } + + rotate_vertices(flt(irq.global_time) / 30.0) + draw_edges() + } + } + } + + sub rotate_vertices(t: float) { + ; 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 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 { + rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i] + rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i] + rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i] + } + } + + + sub draw_edges() { + + sub toscreenx(x: float, z: float) -> word { + return floor(x/(4.2+z) * flt(height)) + width // 2 + } + + sub toscreeny(y: float, z: float) -> word { + return floor(y/(4.2+z) * flt(height)) + height // 2 + } + + ; draw all edges of the object + for uword edge in edges { + ubyte e_from = msb(edge) + ubyte e_to = lsb(edge) + + word x1 = toscreenx(rotatedx[e_from], rotatedz[e_from]) + word y1 = toscreeny(rotatedy[e_from], rotatedz[e_from]) + word x2 = toscreenx(rotatedx[e_to], rotatedz[e_to]) + word y2 = toscreeny(rotatedy[e_to], rotatedz[e_to]) + ubyte color = e_from+e_to + ;vm_gfx_line(x1, y1, x2, y2) + } + + ; accentuate the vertices a bit with small boxes + for ubyte i in 0 to len(xcoor)-1 { + word sx = toscreenx(rotatedx[i], rotatedz[i]) + word sy = toscreeny(rotatedy[i], rotatedz[i]) + ubyte color=i+2 +; vm_gfx_pixel(sx-1, sy-1, color) +; vm_gfx_pixel(sx, sy-1, color) +; vm_gfx_pixel(sx+1, sy-1, color) +; vm_gfx_pixel(sx-1, sy, color) +; vm_gfx_pixel(sx, sy, color) +; vm_gfx_pixel(sx+1, sy, color) +; vm_gfx_pixel(sx-1, sy+1, color) +; vm_gfx_pixel(sx, sy+1, color) +; vm_gfx_pixel(sx+1, sy+1, color) +; vm_gfx_pixel(sx, sy-2, color) +; vm_gfx_pixel(sx+2, sy, color) +; vm_gfx_pixel(sx, sy+2, color) +; vm_gfx_pixel(sx-2, sy, color) + } + } +} diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 1bb1acba1..50c46e5ba 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -8,7 +8,7 @@ sub start() { ubyte pixely = 255 - ubyte derp = 0 + ubyte ub = 0 byte b = 99 byte b2 = 100 word w = 999 @@ -18,6 +18,22 @@ sub start() { float fl1 = 1.1 float fl2 = 2.2 + byte[5] barr1 + byte[5] barr2 + ubyte[5] ubarr1 + ubyte[5] ubarr2 + word[5] warr1 + word[5] warr2 + uword[5] uwarr1 + uword[5] uwarr2 + float[5] farr1 + float[5] farr2 + byte[2,3] bmatrix1 + byte[2,3] bmatrix2 + ubyte[2,3] ubmatrix1 + ubyte[2,3] ubmatrix2 + + memory byte mbyte = $c000 memory byte mbyte2 = $d000 memory ubyte mubyte = $c001 @@ -29,20 +45,59 @@ sub start() { memory float mfloat = $c006 memory float mfloat2 = $d006 + + barr1[2]=42 + ubarr1[2]=42 + warr1[2]=12555 + uwarr1[2]=42555 + farr1[2]=42.5678 + + barr1[2] = b + ubarr1[2] = ub + warr1[2] = w + uwarr1[2] = uw + farr1[2] = fl1 + + barr1[2] = mbyte + ubarr1[2] = mubyte + warr1[2] = mword + uwarr1[2] = muword + farr1[2] = mfloat + + b= barr1[2] + ub = ubarr1[2] + w = warr1[2] + uw = uwarr1[2] + fl1 = farr1[2] + + mbyte= barr1[2] + mubyte = ubarr1[2] + mword = warr1[2] + muword = uwarr1[2] + mfloat = farr1[2] + + barr1[2] = barr2[3] + ubarr1[2] = ubarr2[3] + warr1[2] = warr2[3] + uwarr1[2] = uwarr2[3] + farr1[2] = farr2[3] + + + ; b = 1 -; derp = 1 +; ub = 1 ; w = 1 ; uw = 1 ; fl1 = 2.345 ; ; b = b2 -; derp = pixely +; ub = pixely ; w = w2 ; uw = uw2 ; fl1 = fl2 ; ; b = mbyte -; derp = mubyte +; ub = mubyte ; w = mword ; uw = muword ; fl1 = mfloat @@ -53,22 +108,22 @@ sub start() { ; muword = 1 ; mfloat = 3.456 - %breakpoint - - mbyte = b - mubyte = derp - mword = w - muword = uw - mfloat = fl2 - - %breakpoint - - mbyte = mbyte2 - mubyte = mubyte2 - mword = mword2 - muword = muword2 - mfloat = mfloat2 - +; %breakpoint +; +; mbyte = b +; mubyte = ub +; mword = w +; muword = uw +; mfloat = fl2 +; +; %breakpoint +; +; mbyte = mbyte2 +; mubyte = mubyte2 +; mword = mword2 +; muword = muword2 +; mfloat = mfloat2 +; return } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 2649aadb0..664ec9153 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -8,6 +8,7 @@ import prog8.ast.DataType import prog8.ast.Register import prog8.compiler.* import prog8.compiler.intermediate.* +import prog8.stackvm.Syscall import prog8.stackvm.syscallsForStackVm import java.io.File import java.io.PrintWriter @@ -391,58 +392,58 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.SYSCALL -> { if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr }) throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}") - TODO("syscall $ins") + val call = Syscall.values().find { it.callNr==ins.arg.numericValue() } + " jsr prog8_lib.${call.toString().toLowerCase()}" } Opcode.BREAKPOINT -> { breakpointCounter++ "_prog8_breakpoint_$breakpointCounter\tnop" } - // todo weer aanzetten? -// Opcode.PUSH_BYTE -> { -// " lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex" -// } -// Opcode.PUSH_WORD -> { -// val value = ins.arg!!.integerValue().toHex() -// " lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex" -// } -// Opcode.PUSH_FLOAT -> { -// val floatConst = getFloatConst(ins.arg) -// " lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float" -// } -// Opcode.PUSH_VAR_BYTE -> { -// when(ins.callLabel) { -// "X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") -// "A" -> " sta ${ESTACK_LO.toHex()},x | dex" -// "Y" -> " tya | sta ${ESTACK_LO.toHex()},x | dex" -// else -> " lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | dex" -// } -// } -// Opcode.PUSH_VAR_WORD -> { -// when (ins.callLabel) { -// "AX" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") -// "XY" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") -// "AY" -> " sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex" -// else -> " lda ${ins.callLabel} | ldy ${ins.callLabel}+1 | sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex" -// } -// } -// Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float" -// Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> { -// """ -// lda ${ins.arg!!.integerValue().toHex()} -// sta ${ESTACK_LO.toHex()},x -// dex -// """ -// } -// Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> { -// """ -// lda ${ins.arg!!.integerValue().toHex()} -// sta ${ESTACK_LO.toHex()},x -// lda ${(ins.arg.integerValue()+1).toHex()} -// sta ${ESTACK_HI.toHex()},x -// dex -// """ -// } + Opcode.PUSH_BYTE -> { + " lda #${ins.arg!!.integerValue().toHex()} | sta ${ESTACK_LO.toHex()},x | dex" + } + Opcode.PUSH_WORD -> { + val value = ins.arg!!.integerValue().toHex() + " lda #<$value | sta ${ESTACK_LO.toHex()},x | lda #>$value | sta ${ESTACK_HI.toHex()},x | dex" + } + Opcode.PUSH_FLOAT -> { + val floatConst = getFloatConst(ins.arg!!) + " lda #<$floatConst | ldy #>$floatConst | jsr prog8_lib.push_float" + } + Opcode.PUSH_VAR_BYTE -> { + when(ins.callLabel) { + "X" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") + "A" -> " sta ${ESTACK_LO.toHex()},x | dex" + "Y" -> " tya | sta ${ESTACK_LO.toHex()},x | dex" + else -> " lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | dex" + } + } + Opcode.PUSH_VAR_WORD -> { + when (ins.callLabel) { + "AX" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") + "XY" -> throw CompilerException("makes no sense to push X, it's used as a stack pointer itself") + "AY" -> " sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex" + else -> " lda ${ins.callLabel} | ldy ${ins.callLabel}+1 | sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex" + } + } + Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float" + Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> { + """ + lda ${ins.arg!!.integerValue().toHex()} + sta ${ESTACK_LO.toHex()},x + dex + """ + } + Opcode.PUSH_MEM_W, Opcode.PUSH_MEM_UW -> { + """ + lda ${ins.arg!!.integerValue().toHex()} + sta ${ESTACK_LO.toHex()},x + lda ${(ins.arg.integerValue()+1).toHex()} + sta ${ESTACK_HI.toHex()},x + dex + """ + } Opcode.POP_MEM_B, Opcode.POP_MEM_UB -> { """ @@ -635,6 +636,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, sta ${(ESTACK_LO+1).toHex()},x """ } + Opcode.NEG_F -> " jsr prog8_lib.neg_f" Opcode.INV_BYTE -> { """ lda ${(ESTACK_LO + 1).toHex()},x @@ -768,7 +770,8 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // check for operations that modify a single value, by putting it on the stack (and popping it afterwards) if((opcodes[0]==Opcode.PUSH_VAR_BYTE && opcodes[2]==Opcode.POP_VAR_BYTE) || - (opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD)) { + (opcodes[0]==Opcode.PUSH_VAR_WORD && opcodes[2]==Opcode.POP_VAR_WORD) || + (opcodes[0]==Opcode.PUSH_VAR_FLOAT && opcodes[2]==Opcode.POP_VAR_FLOAT)) { if (segment[0].callLabel == segment[2].callLabel) { val fragment = sameVarOperation(segment[0].callLabel!!, segment[1]) if (fragment != null) { @@ -778,7 +781,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, } } else if((opcodes[0]==Opcode.PUSH_MEM_UB && opcodes[2]==Opcode.POP_MEM_UB) || - (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_UW)) { + (opcodes[0]==Opcode.PUSH_MEM_B && opcodes[2]==Opcode.POP_MEM_B) || + (opcodes[0]==Opcode.PUSH_MEM_UW && opcodes[2]==Opcode.POP_MEM_UW) || + (opcodes[0]==Opcode.PUSH_MEM_W && opcodes[2]==Opcode.POP_MEM_W) || + (opcodes[0]==Opcode.PUSH_MEM_FLOAT && opcodes[2]==Opcode.POP_MEM_FLOAT)) { if(segment[0].arg==segment[2].arg) { val fragment = sameMemOperation(segment[0].arg!!.integerValue(), segment[1]) if(fragment!=null) { @@ -1004,6 +1010,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, else -> AsmFragment(" lda $variable | sta ${C64Zeropage.SCRATCH_W1} | lda $variable+1 | sta ${C64Zeropage.SCRATCH_W1+1} | jsr prog8_lib.ror2_word | lda ${C64Zeropage.SCRATCH_W1} | sta $variable | lda ${C64Zeropage.SCRATCH_W1+1} | sta $variable+1", 30) } } +// Opcode.SYSCALL -> { +// TODO("optimize SYSCALL $ins in-place on variable $variable") +// } else -> null } } @@ -1182,6 +1191,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, """ }, + // @todo add all indexed assignment forms // assignment: var = bytearray[index] AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.READ_INDEXED_VAR_BYTE, Opcode.POP_VAR_BYTE)) { segment ->