diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index e83fb3c2c..174e99fac 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -1,52 +1,150 @@ %import c64utils +%import c64flt ~ main { + const uword width = 40 + const uword height = 25 + + ; vertices + byte[8] xcoor = [ -50, -50, -50, -50, 50, 50, 50, 50 ] + byte[8] ycoor = [ -50, -50, 50, 50, -50, -50, 50, 50 ] + byte[8] zcoor = [ -50, 50, -50, 50, -50, 50, -50, 50 ] + + ; storage for rotated coordinates + word[len(xcoor)] rotatedx=0 + word[len(ycoor)] rotatedy=0 + word[len(zcoor)] rotatedz=-1 + sub start() { - - ubyte a=200 - ubyte b=33 - ubyte c - - byte ab=100 - byte bb=-6 - byte cb - - uword wa=50000 - uword wb=999 - uword wc - word wab=30000 - word wbb=-99 - word wcb - - c=a//b - c64scr.print_ub(c) - c64.CHROUT('\n') - a=155 - b=11 - c=a//b - c64scr.print_ub(c) - c64.CHROUT('\n') - cb=ab//bb - c64scr.print_b(cb) - c64.CHROUT('\n') - ab=-100 - bb=6 - cb=ab//bb - c64scr.print_b(cb) - c64.CHROUT('\n') - ab=-100 - bb=-6 - cb=ab//bb - c64scr.print_b(cb) - c64.CHROUT('\n') - ab=100 - bb=6 - cb=ab//bb - c64scr.print_b(cb) - c64.CHROUT('\n') - c64scr.print_ub(X) - c64.CHROUT('\n') + uword anglex + uword angley + uword anglez + while(true) { + rotate_vertices(msb(anglex), msb(angley), msb(anglez)) + c64.CLEARSCR() + draw_edges() + anglex+=1000 + angley+=333 + anglez+=807 + } } + sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) { + ; rotate around origin (0,0,0) + + ; set up the 3d rotation matrix values + word wcosa = cos8(ax) as word + word wsina = sin8(ax) as word + word wcosb = cos8(ay) as word + word wsinb = sin8(ay) as word + word wcosc = cos8(az) as word + word wsinc = sin8(az) as word + + word wcosa_sinb = wcosa*wsinb + lsr(wcosa_sinb) + lsr(wcosa_sinb) + lsr(wcosa_sinb) + lsr(wcosa_sinb) + lsr(wcosa_sinb) + lsr(wcosa_sinb) + lsr(wcosa_sinb) ; / 128 + word wsina_sinb = wsina*wsinb + lsr(wsina_sinb) + lsr(wsina_sinb) + lsr(wsina_sinb) + lsr(wsina_sinb) + lsr(wsina_sinb) + lsr(wsina_sinb) + lsr(wsina_sinb) ; / 128 + + float cosa_sinb = wcosa_sinb as float / 128.0 + float sina_sinb = wsina_sinb as float / 128.0 + float Axx = wcosa*wcosb as float / 16384.0 + float Axy = cosa_sinb*(wsinc as float / 128.0) - (wsina*wcosc as float / 16384.0) + float Axz = cosa_sinb*(wcosc as float / 128.0) + (wsina*wsinc as float / 16384.0) + float Ayx = wsina*wcosb as float / 16384.0 + float Ayy = sina_sinb*(wsinc as float / 128.0) + (wcosa*wcosc as float / 16384.0) + float Ayz = sina_sinb*(wcosc as float / 128.0) - (wcosa*wsinc as float / 16384.0) + float Azx = -wsinb as float / 128.0 + float Azy = wcosb*wsinc as float / 16384.0 + float Azz = wcosb*wcosc as float / 16384.0 + + word wAxx = Axx * 128.0 as word + word wAxy = Axy * 128.0 as word + word wAxz = Axz * 128.0 as word + word wAyx = Ayx * 128.0 as word + word wAyy = Ayy * 128.0 as word + word wAyz = Ayz * 128.0 as word + word wAzx = Azx * 128.0 as word + word wAzy = Azy * 128.0 as word + word wAzz = Azz * 128.0 as word + + for ubyte i in 0 to len(xcoor)-1 { + word xc = xcoor[i] as word + word yc = ycoor[i] as word + word zc = zcoor[i] as word + word zz = wAxx*xc + wAxy*yc + wAxz*zc + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) ; /128 + rotatedx[i] = zz + zz=wAyx*xc + wAyy*yc + wAyz*zc + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) ; /128 + rotatedy[i] = zz + zz = wAzx*xc + wAzy*yc + wAzz*zc + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) + lsr(zz) ; /128 + rotatedz[i] = zz + } + } + + sub draw_edges() { + + sub toscreenx(float x, float z) -> byte { + return x/(250.0+z) * (height as float) as byte + width // 2 + } + + sub toscreeny(float y, float z) -> byte { + return y/(250.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 { + word rz = rotatedz[i] + if rz >= 10 { + ubyte sx = toscreenx(rotatedx[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! + ubyte sy = toscreeny(rotatedy[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! + c64scr.setchrclr(sx, sy, 46, i+2) + } + } + + ; @todo integer / integer should usually result in a FLOAT, not INT. the // operator is for integer division! + + for ubyte i in 0 to len(xcoor)-1 { + word rz = rotatedz[i] + if rz < 10 { + ubyte sx = toscreenx(rotatedx[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! + ubyte sy = toscreeny(rotatedy[i] as float, rz as float) as ubyte ; @todo crash when not using 'as float' for the param! + c64scr.setchrclr(sx, sy, 81, i+2) + } + } + } } diff --git a/compiler/examples/whizzine.p8 b/compiler/examples/whizzine.p8 index 983792e83..128bb43ff 100644 --- a/compiler/examples/whizzine.p8 +++ b/compiler/examples/whizzine.p8 @@ -62,9 +62,8 @@ sub irq() { 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) + word x = (sin8(angle*2-i*8) as word)+190 ; @todo will/should be using shifts for faster multiplication + byte y = cos8(angle*3-i*8) // 2 ; @todo will/should be using shifts for faster multiplication @(SP0X+i) = lsb(x) @(SP0Y+i) = y+150 as ubyte diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 968e6efb9..308b0dc0e 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -153,10 +153,11 @@ private class StatementTranslator(private val prog: IntermediateProgram, override fun process(block: Block): IStatement { prog.newBlock(block.scopedname, block.name, block.address, block.options()) processVariables(block) // @todo optimize initializations with same value: load the value only once (sort on initalization value, datatype ?) - prog.label("block."+block.scopedname) + prog.label("block."+block.scopedname, false) prog.line(block.position) translate(block.statements) - return super.process(block) + val r = super.process(block) + return r } private fun processVariables(scope: INameScope) { @@ -168,18 +169,22 @@ private class StatementTranslator(private val prog: IntermediateProgram, override fun process(subroutine: Subroutine): IStatement { if(subroutine.asmAddress==null) { - prog.label(subroutine.scopedname) + prog.label(subroutine.scopedname, true) + prog.instr(Opcode.START_PROCDEF) prog.line(subroutine.position) // note: the caller has already written the arguments into the subroutine's parameter variables. translate(subroutine.statements) + val r= super.process(subroutine) + prog.instr(Opcode.END_PROCDEF) + return r } else { // asmsub if(subroutine.isNotEmpty()) throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine") prog.memoryPointer(subroutine.scopedname, subroutine.asmAddress, DataType.UBYTE) // the datatype is a bit of a dummy in this case + return super.process(subroutine) } - return super.process(subroutine) } private fun translate(statements: List) { @@ -1809,6 +1814,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, } // TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH_BYTE / SUB opcodes and make use of the wrapping around of the value. + // TODO: ubyte/uword can't count down to 0 with negative step because test value will be <0 which causes "value out of range" crash prog.instr(opcodePush(varDt), Value(varDt, range.last + range.step)) prog.instr(opcodePushvar(varDt), callLabel = varname) prog.instr(opcodeSub(varDt)) diff --git a/compiler/src/prog8/compiler/intermediate/Instruction.kt b/compiler/src/prog8/compiler/intermediate/Instruction.kt index ac9a48dfb..a39648c47 100644 --- a/compiler/src/prog8/compiler/intermediate/Instruction.kt +++ b/compiler/src/prog8/compiler/intermediate/Instruction.kt @@ -34,7 +34,7 @@ open class Instruction(val opcode: Opcode, } } -class LabelInstr(val name: String) : Instruction(Opcode.NOP, null, null) { +class LabelInstr(val name: String, val asmProc: Boolean) : Instruction(Opcode.NOP, null, null) { override fun toString(): String { return "\n$name:" } diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 24a58f30e..933b97e5c 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -358,8 +358,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap currentBlock.instructions.add(Instruction(opcode, arg, callLabel = callLabel)) } - fun label(labelname: String) { - val instr = LabelInstr(labelname) + fun label(labelname: String, asmProc: Boolean=false) { + val instr = LabelInstr(labelname, asmProc) currentBlock.instructions.add(instr) currentBlock.labels[labelname] = instr } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index c542b0322..0cf4c46f2 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -239,10 +239,12 @@ enum class Opcode { JNZW, // branch if value is not zero (word) - // subroutine calling + // subroutines CALL, RETURN, SYSCALL, + START_PROCDEF, + END_PROCDEF, // misc SEC, // set carry status flag NOTE: is mostly fake, carry flag is not affected by any numeric operations diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 8d39dd65e..53bd9b816 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -33,7 +33,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val newlabels = block.labels.map { symname(it.key, block) to it.value}.toMap().toMutableMap() val newinstructions = block.instructions.asSequence().map { when { - it is LabelInstr -> LabelInstr(symname(it.name, block)) + it is LabelInstr -> LabelInstr(symname(it.name, block), it.asmProc) it.opcode == Opcode.INLINE_ASSEMBLY -> it else -> Instruction(it.opcode, it.arg, it.arg2, @@ -394,16 +394,21 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, if(ins is LabelInstr) { if(ins.name.startsWith("block.")) return "" - return if(ins.name.startsWith("${block.shortname}.")) - ins.name.substring(block.shortname.length+1) - else - ins.name + + val labelresult = + if(ins.name.startsWith("${block.shortname}.")) + ins.name.substring(block.shortname.length+1) + else + ins.name + return if(ins.asmProc) labelresult+"\t\t.proc" else labelresult } // simple opcodes that are translated directly into one or a few asm instructions return when(ins.opcode) { Opcode.LINE -> " ;\tsrc line: ${ins.callLabel}" Opcode.NOP -> " nop" // shouldn't be present anymore though + Opcode.START_PROCDEF -> "" // is done as part of a label + Opcode.END_PROCDEF -> " .pend" Opcode.TERMINATE -> " brk" Opcode.SEC -> " sec" Opcode.CLC -> " clc" diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index 3d13bacc8..869428307 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -19,7 +19,7 @@ class Program (val name: String, { init { // add end of program marker and some sentinel instructions, to correctly connect all others - program.add(LabelInstr("____program_end")) + program.add(LabelInstr("____program_end", false)) program.add(Instruction(Opcode.TERMINATE)) program.add(Instruction(Opcode.NOP)) connect() diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index eefff0fd5..cf39f9cc1 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -254,6 +254,7 @@ class StackVm(private var traceOutputFile: String?) { traceOutput?.println("\n$ins") when (ins.opcode) { Opcode.NOP -> {} + Opcode.START_PROCDEF, Opcode.END_PROCDEF -> {} Opcode.PUSH_BYTE -> { checkDt(ins.arg, DataType.UBYTE, DataType.BYTE) evalstack.push(ins.arg) diff --git a/prog8lib/prog8lib.p8 b/prog8lib/prog8lib.p8 index 69ce4d278..e9d413b30 100644 --- a/prog8lib/prog8lib.p8 +++ b/prog8lib/prog8lib.p8 @@ -156,9 +156,9 @@ mul_word .proc stx c64.SCRATCH_ZPREGX jsr math.multiply_words ldx c64.SCRATCH_ZPREGX - lda math.multiply_words_result + lda math.multiply_words.multiply_words_result sta c64.ESTACK_LO+1,x - lda math.multiply_words_result+1 + lda math.multiply_words.multiply_words_result+1 sta c64.ESTACK_HI+1,x rts .pend