diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 4069f3334..29035588d 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -827,6 +827,13 @@ internal class AstChecker(private val program: Program, else printWarning("result values of subroutine call are discarded", functionCallStatement.position) } + + if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap")) { + // in-place modification, can't be done on literals + if(functionCallStatement.arglist.any { it !is IdentifierReference && it !is RegisterExpr && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) { + checkResult.add(ExpressionError("can't use that as argument to a in-place modifying function", functionCallStatement.position)) + } + } super.visit(functionCallStatement) } diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 58550b3ca..6a4d6fbcb 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -60,7 +60,7 @@ fun compileProgram(filepath: Path, programAst.removeNopsFlattenAnonScopes() // if you want to print the AST, do it before shuffling the statements around below - // printAst(programAst) + printAst(programAst) programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later @@ -88,6 +88,8 @@ fun compileProgram(filepath: Path, programAst.checkValid(compilerOptions) // check if final tree is valid programAst.checkRecursion() // check if there are recursive subroutine calls + printAst(programAst) + if(writeAssembly) { // asm generation directly from the Ast, no need for intermediate code val zeropage = MachineDefinition.C64Zeropage(compilerOptions) diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt index d03f5d768..6c1231f9f 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt @@ -21,11 +21,12 @@ class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor { super.visit(program) for((scope, decls) in varsToMove) { val sub = scope.definingSubroutine()!! - val existingVariables = sub.statements.filterIsInstance().map { it.name }.toSet() + val existingVariables = sub.statements.filterIsInstance().associate { it.name to it } var conflicts = false decls.forEach { - if (it.name in existingVariables) { - checkResult.add(NameError("variable ${it.name} already exists in subroutine ${sub.name}", it.position)) + val existing = existingVariables[it.name] + if (existing!=null) { + checkResult.add(NameError("variable ${it.name} already defined in subroutine ${sub.name} at ${existing.position}", it.position)) conflicts = true } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index 9a96f4cef..4b42fea94 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -233,7 +233,7 @@ internal class AsmGen2(val program: Program, } } else { - throw AssemblyError("huh, var is already on zp $zpVar") + throw AssemblyError("huh, var is already in zp $fullName") // it was already allocated on the zp, what to do? // out("${variable.name} = ${zpVar.first}\t; zp ${zpVar.second}") } @@ -469,7 +469,7 @@ internal class AsmGen2(val program: Program, + sta $destination """ - private fun asmIdentifierName(identifier: IdentifierReference): String { + internal fun asmIdentifierName(identifier: IdentifierReference): String { val name = if(identifier.memberOfStruct(program.namespace)!=null) { identifier.targetVarDecl(program.namespace)!!.name } else { @@ -519,7 +519,8 @@ internal class AsmGen2(val program: Program, return false } - private fun readAndPushArrayvalueWithIndexA(arrayDt: DataType, variablename: String) { + private fun readAndPushArrayvalueWithIndexA(arrayDt: DataType, variable: IdentifierReference) { + val variablename = asmIdentifierName(variable) when (ArrayElementTypes.getValue(arrayDt).memorySize()) { 1 -> {} 2 -> out(" asl a") @@ -530,11 +531,13 @@ internal class AsmGen2(val program: Program, DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | dex") DataType.ARRAY_UW, DataType.ARRAY_W -> - out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | iny | lda $variablename,y | sta $ESTACK_HI_HEX,x | dex") + out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | lda $variablename+1,y | sta $ESTACK_HI_HEX,x | dex") DataType.ARRAY_F -> out(""" sta $ESTACK_LO_HEX,x dex + lda #<$variablename + ldy #>$variablename jsr c64flt.push_float_from_indexed_var """) else -> @@ -1526,15 +1529,38 @@ $endLabel""") } } is PrefixExpression -> { + // TODO optimize common cases translateExpression(assign.value as PrefixExpression) assignFromEvalResult(assign.target) } is BinaryExpression -> { + // TODO optimize common cases translateExpression(assign.value as BinaryExpression) assignFromEvalResult(assign.target) } is ArrayIndexedExpression -> { - translateExpression(assign.value as ArrayIndexedExpression) + // TODO optimize common cases + val arrayExpr = assign.value as ArrayIndexedExpression + val arrayDt = arrayExpr.identifier.targetVarDecl(program.namespace)!!.datatype + val index = arrayExpr.arrayspec.index + if(index is NumericLiteralValue) { + // constant array index value + val arrayVarName = asmIdentifierName(arrayExpr.identifier) + val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize() + when (arrayDt) { + DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> + out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | dex") + DataType.ARRAY_UW, DataType.ARRAY_W -> + out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | lda $arrayVarName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex") + DataType.ARRAY_F -> + out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float") + else -> + throw AssemblyError("weird array type") + } + } else { + translateCalcArrayIndexIntoA(arrayExpr) + readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier) + } assignFromEvalResult(assign.target) } is TypecastExpression -> { @@ -1561,41 +1587,25 @@ $endLabel""") } } - private fun translateExpression(expr: ArrayIndexedExpression) { + private fun translateCalcArrayIndexIntoA(expr: ArrayIndexedExpression) { val arrayDt = expr.identifier.targetVarDecl(program.namespace)!!.datatype - val sourceName = asmIdentifierName(expr.identifier) val index = expr.arrayspec.index when (index) { - is NumericLiteralValue -> { - val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize() - when (arrayDt) { - DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> - out(" lda $sourceName+$indexValue | sta $ESTACK_LO_HEX,x | dex") - DataType.ARRAY_UW, DataType.ARRAY_W -> - out(" lda $sourceName+$indexValue | sta $ESTACK_LO_HEX,x | lda $sourceName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex") - DataType.ARRAY_F -> - out(" lda #<$sourceName+$indexValue | ldy #>$sourceName+$indexValue | jsr c64flt.push_float") - else -> - throw AssemblyError("weird array type") - } - } + is NumericLiteralValue -> throw AssemblyError("this should be optimized directly") is RegisterExpr -> { when (index.register) { Register.A -> {} Register.X -> out(" txa") Register.Y -> out(" tya") } - readAndPushArrayvalueWithIndexA(arrayDt, sourceName) } is IdentifierReference -> { val indexName = asmIdentifierName(index) out(" lda $indexName") - readAndPushArrayvalueWithIndexA(arrayDt, sourceName) } else -> { translateExpression(index) out(" inx | lda $ESTACK_LO_HEX,x") - readAndPushArrayvalueWithIndexA(arrayDt, sourceName) } } } @@ -1659,7 +1669,12 @@ $endLabel""") when(expression) { is PrefixExpression -> translateExpression(expression) is BinaryExpression -> translateExpression(expression) - is ArrayIndexedExpression -> translateExpression(expression) + is ArrayIndexedExpression -> { + // assume *reading* from an array + translateCalcArrayIndexIntoA(expression) + val arrayDt = expression.identifier.targetVarDecl(program.namespace)!!.datatype + readAndPushArrayvalueWithIndexA(arrayDt, expression.identifier) + } is TypecastExpression -> translateExpression(expression) is AddressOf -> translateExpression(expression) is DirectMemoryRead -> translateExpression(expression) @@ -1954,7 +1969,20 @@ $endLabel""") storeRegisterInMemoryAddress(Register.Y, target.memoryAddress) } target.arrayindexed!=null -> { - TODO("put result in arrayindexed $target") + val targetDt = target.arrayindexed!!.inferType(program)!! + val arrayVarName = asmIdentifierName(target.arrayindexed!!.identifier) + when(targetDt) { + in ByteDatatypes -> { + TODO("pop byte into array ${target.arrayindexed}") + } + in WordDatatypes -> { + TODO("pop word into array ${target.arrayindexed}") + } + DataType.FLOAT -> { + TODO("pop float into array ${target.arrayindexed}") + } + else -> throw AssemblyError("weird datatype") + } } else -> throw AssemblyError("weird assignment target $target") } @@ -2043,9 +2071,6 @@ $endLabel""") sta $targetName+4 """) } - target.memoryAddress!=null -> { - TODO("assign floatvar $sourceName to memory ${target.memoryAddress}") - } targetArrayIdx!=null -> { val index = targetArrayIdx.arrayspec.index val targetName = asmIdentifierName(targetArrayIdx.identifier) @@ -2256,7 +2281,16 @@ $endLabel""") targetArrayIdx!=null -> { val index = targetArrayIdx.arrayspec.index val targetName = asmIdentifierName(targetArrayIdx.identifier) - TODO("assign word $word to array $targetName [ $index ]") + // TODO optimize common cases + translateExpression(index) + out(""" + inx + ldy $ESTACK_LO_HEX,x + lda #<${word.toHex()} + sta $targetName,y + lda #>${word.toHex()} + sta $targetName+1,y + """) } else -> TODO("assign word $word to $target") } @@ -2280,7 +2314,14 @@ $endLabel""") targetArrayIdx!=null -> { val index = targetArrayIdx.arrayspec.index val targetName = asmIdentifierName(targetArrayIdx.identifier) - TODO("assign byte $byte to array $targetName [ $index ]") + // TODO optimize common cases + translateExpression(index) + out(""" + inx + ldy $ESTACK_LO_HEX,x + lda #${byte.toHex()} + sta $targetName,y + """) } else -> TODO("assign byte $byte to $target") } @@ -2303,9 +2344,6 @@ $endLabel""") sta $targetName+4 """) } - target.memoryAddress!=null -> { - TODO("assign float 0.0 to memory ${target.memoryAddress}") - } targetArrayIdx!=null -> { val index = targetArrayIdx.arrayspec.index val targetName = asmIdentifierName(targetArrayIdx.identifier) @@ -2316,26 +2354,80 @@ $endLabel""") } else { // non-zero value val constFloat = getFloatConst(float) - if (targetIdent != null) { - val targetName = asmIdentifierName(targetIdent) - out(""" - lda $constFloat - sta $targetName - lda $constFloat+1 - sta $targetName+1 - lda $constFloat+2 - sta $targetName+2 - lda $constFloat+3 - sta $targetName+3 - lda $constFloat+4 - sta $targetName+4 - """) - } else { - TODO("assign float $float ($constFloat) to $target") + when { + targetIdent != null -> { + val targetName = asmIdentifierName(targetIdent) + out(""" + lda $constFloat + sta $targetName + lda $constFloat+1 + sta $targetName+1 + lda $constFloat+2 + sta $targetName+2 + lda $constFloat+3 + sta $targetName+3 + lda $constFloat+4 + sta $targetName+4 + """) + } + targetArrayIdx!=null -> { + val index = targetArrayIdx.arrayspec.index + val arrayVarName = asmIdentifierName(targetArrayIdx.identifier) + if(index is NumericLiteralValue) { + val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize + out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.pop_float") + } else { + translateCalcArrayIndexIntoA(targetArrayIdx) + out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}") + out(""" + tay + lda $constFloat + sta $arrayVarName,y + lda $constFloat+1 + iny + sta $arrayVarName,y + lda $constFloat+2 + iny + sta $arrayVarName,y + lda $constFloat+3 + iny + sta $arrayVarName,y + lda $constFloat+4 + iny + sta $arrayVarName,y + """) // TODO use a subroutine for this + } + } + else -> TODO("assign float $float to $target") } } } + private fun popAndWriteArrayvalueWithIndexA(arrayDt: DataType, variablename: String) { + when (ArrayElementTypes.getValue(arrayDt).memorySize()) { + 1 -> {} + 2 -> out(" asl a") + 5 -> out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}") + else -> throw AssemblyError("invalid memory size") + } + when (arrayDt) { + DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B -> + out(" tay | inx | lda $ESTACK_LO_HEX,x | sta $variablename,y") + DataType.ARRAY_UW, DataType.ARRAY_W -> + out(" tay | inx | lda $ESTACK_LO_HEX,x | sta $variablename,y | lda $ESTACK_HI_HEX,x | sta $variablename+1,y") + DataType.ARRAY_F -> + out(""" + sta $ESTACK_LO_HEX,x + dex + lda #<$variablename + ldy #>$variablename + jsr c64flt.pop_float_to_indexed_var + """) + else -> + throw AssemblyError("weird array type") + } + } + private fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt index 28a073f8f..6e7ea1dc2 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/BuiltinFunctionsAsmGen.kt @@ -4,17 +4,16 @@ import prog8.ast.IFunctionCall import prog8.ast.Program import prog8.ast.base.ByteDatatypes import prog8.ast.base.DataType +import prog8.ast.base.Register import prog8.ast.base.WordDatatypes -import prog8.ast.expressions.Expression -import prog8.ast.expressions.FunctionCall -import prog8.ast.expressions.IdentifierReference -import prog8.ast.expressions.NumericLiteralValue +import prog8.ast.expressions.* import prog8.ast.statements.FunctionCallStatement import prog8.compiler.CompilationOptions import prog8.compiler.Zeropage import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX +import prog8.compiler.toHex import prog8.functions.FunctionSignature internal class BuiltinFunctionsAsmGen(private val program: Program, @@ -76,6 +75,154 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, translateFunctionArguments(fcall.arglist) asmgen.out(" jsr c64flt.func_$functionName") } +/* + TODO this was the old code for bit rotations: + Opcode.SHL_BYTE -> AsmFragment(" asl $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 * 2 + 1} | rol $variable+${index * 2}", 8) + Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index * 2 + 1} | ror $variable+${index * 2}", 8) + Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index * 2 + 1} | asl a | ror $variable+${index * 2 + 1} | ror $variable+${index * 2}", 8) + Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8) + Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8) + Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index * 2 + 1} | rol $variable+${index * 2}", 8) + Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index * 2 + 1} | ror $variable+${index * 2}", 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 * 2 + 1} | rol $variable+${index * 2} | bcc + | inc $variable+${index * 2 + 1} |+", 20) + Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index * 2 + 1} | ror $variable+${index * 2} | bcc + | lda $variable+${index * 2 + 1} | ora #\$80 | sta $variable+${index * 2 + 1} |+", 30) + + */ + "lsl" -> { + // in-place + val what = fcall.arglist.single() + val dt = what.inferType(program)!! + when(dt) { + in ByteDatatypes -> { + when(what) { + is RegisterExpr -> { + when(what.register) { + Register.A -> asmgen.out(" asl a") + Register.X -> asmgen.out(" txa | asl a | tax") + Register.Y -> asmgen.out(" tya | asl a | tay") + } + } + is IdentifierReference -> asmgen.out(" asl ${asmgen.asmIdentifierName(what)}") + is DirectMemoryRead -> { + if(what.addressExpression is NumericLiteralValue) { + asmgen.out(" asl ${(what.addressExpression as NumericLiteralValue).number.toHex()}") + } else { + TODO("lsl memory byte $what") + } + } + is ArrayIndexedExpression -> { + TODO("lsl byte array $what") + } + else -> throw AssemblyError("weird type") + } + } + in WordDatatypes -> { + TODO("lsl word $what") + } + else -> throw AssemblyError("weird type") + } + } + "lsr" -> { + // in-place + val what = fcall.arglist.single() + val dt = what.inferType(program)!! + when(dt) { + DataType.UBYTE -> { + when(what) { + is RegisterExpr -> { + when(what.register) { + Register.A -> asmgen.out(" lsr a") + Register.X -> asmgen.out(" txa | lsr a | tax") + Register.Y -> asmgen.out(" tya | lsr a | tay") + } + } + is IdentifierReference -> asmgen.out(" lsr ${asmgen.asmIdentifierName(what)}") + is DirectMemoryRead -> { + if(what.addressExpression is NumericLiteralValue) { + asmgen.out(" lsr ${(what.addressExpression as NumericLiteralValue).number.toHex()}") + } else { + TODO("lsr memory byte $what") + } + } + is ArrayIndexedExpression -> { + TODO("lsr byte array $what") + } + else -> throw AssemblyError("weird type") + } + } + DataType.BYTE -> { + TODO("lsr sbyte $what") + } + DataType.UWORD -> { + TODO("lsr sword $what") + } + DataType.WORD -> { + TODO("lsr word $what") + } + else -> throw AssemblyError("weird type") + } + } + "rol" -> { + // in-place + val what = fcall.arglist.single() + val dt = what.inferType(program)!! + when(dt) { + DataType.UBYTE -> { + TODO("rol ubyte") + } + DataType.UWORD -> { + TODO("rol uword") + } + else -> throw AssemblyError("weird type") + } + } + "rol2" -> { + // in-place + val what = fcall.arglist.single() + val dt = what.inferType(program)!! + when(dt) { + DataType.UBYTE -> { + TODO("rol2 ubyte") + } + DataType.UWORD -> { + TODO("rol2 uword") + } + else -> throw AssemblyError("weird type") + } + } + "ror" -> { + // in-place + val what = fcall.arglist.single() + val dt = what.inferType(program)!! + when(dt) { + DataType.UBYTE -> { + TODO("ror ubyte") + } + DataType.UWORD -> { + TODO("ror uword") + } + else -> throw AssemblyError("weird type") + } + } + "ror2" -> { + // in-place + val what = fcall.arglist.single() + val dt = what.inferType(program)!! + when(dt) { + DataType.UBYTE -> { + TODO("ror2 ubyte") + } + DataType.UWORD -> { + TODO("ror2 uword") + } + else -> throw AssemblyError("weird type") + } + } else -> { translateFunctionArguments(fcall.arglist) asmgen.out(" jsr prog8_lib.func_$functionName") diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 36d77ce4d..2b6be5fb1 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -127,12 +127,20 @@ The address must be >= ``$0200`` (because ``$00``--``$ff`` is the ZP and ``$100` to them by their 'short' name directly. If the symbol is not found in the same scope, the enclosing scope is searched for it, and so on, until the symbol is found. -Scopes are created using several statements: +Scopes are created using either of these two statements: - blocks (top-level named scope) -- subroutines (nested named scopes) -- for, while, repeat loops (anonymous scope) -- if statements and branching conditionals (anonymous scope) +- subroutines (nested named scope) + +.. note:: + In contrast to many other programming languages, a new scope is *not* created inside + for, while and repeat statements, nor for the if statement and branching conditionals. + This is a bit restrictive because you have to think harder about what variables you + want to use inside a subroutine. But it is done precisely for this reason; memory in the + target system is very limited and it would be a waste to allocate a lot of variables. + + Right now the prog8 compiler is not advanced enough to be able to 'share' or 'overlap' + variables intelligently by itself. So for now, it's something the programmer has to think about. Program Start and Entry Point @@ -400,7 +408,9 @@ You can also create loops by using the ``goto`` statement, but this should usual The value of the loop variable or register after executing the loop *is undefined*. Don't use it immediately after the loop without first assigning a new value to it! (this is an optimization issue to avoid having to deal with mostly useless post-loop logic to adjust the loop variable's value) - Loop variables that are declared inline are scoped in the loop body so they're not accessible at all after the loop finishes. + Loop variables that are declared inline are not different to them being + defined in a separate var declaration in the subroutine, it's just a readability convenience. + (this may change in the future if the compiler gets more advanced with additional sub-scopes) Conditional Execution diff --git a/examples/cube3d-float.p8 b/examples/cube3d-float.p8 index 44f53c0c2..f27a68f12 100644 --- a/examples/cube3d-float.p8 +++ b/examples/cube3d-float.p8 @@ -66,23 +66,28 @@ main { ; plot the points of the 3d cube ; first the points on the back, then the points on the front (painter algorithm) + ubyte i + float rz + float persp + ubyte sx + ubyte sy - for ubyte i in 0 to len(xcoor)-1 { - float rz = rotatedz[i] + for i in 0 to len(xcoor)-1 { + rz = rotatedz[i] if rz >= 0.1 { - float persp = (5.0+rz)/height - ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte - ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte + persp = (5.0+rz)/height + sx = rotatedx[i] / persp + width/2.0 as ubyte + sy = rotatedy[i] / persp + height/2.0 as ubyte c64scr.setcc(sx, sy, 46, i+2) } } - for ubyte i in 0 to len(xcoor)-1 { - float rz = rotatedz[i] + for i in 0 to len(xcoor)-1 { + rz = rotatedz[i] if rz < 0.1 { - float persp = (5.0+rz)/height - ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte - ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte + persp = (5.0+rz)/height + sx = rotatedx[i] / persp + width/2.0 as ubyte + sy = rotatedy[i] / persp + height/2.0 as ubyte c64scr.setcc(sx, sy, 81, i+2) } } diff --git a/examples/test.p8 b/examples/test.p8 index 193464552..cd1f3da3c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,25 +1,42 @@ -%import c64lib %import c64utils %import c64flt %zeropage basicsafe +%option enable_floats main { + ubyte[10] barray + uword[10] warray + float[10] farray + &ubyte memubarray = 1000 + &uword memuwarray = 1000 + &float memfltarray = 1000 + sub start() { - delay1(1) - delay2(1) - delay3(1) + ubyte i + uword uw + float fl = farray[2] - sub delay1(ubyte note1) { - A= note1 - } - sub delay2(ubyte note1) { - A= note1 - } - sub delay3(ubyte note1) { - A= note1 - } + barray[4] = 4 + barray[i] = 4 + barray[i+4] = 4 + memubarray[4] = 4 + memubarray[i] = 4 + memubarray[i+4] = 4 + + warray[4] = 4 + warray[i] = 4 + warray[i+4] = 4 + memuwarray[4] = 4 + memuwarray[i] = 4 + memuwarray[i+4] = 4 + + farray[4] = 4 + farray[i] = 4 + farray[i+4] = 4 + memfltarray[4] = 4 + memfltarray[i] = 4 + memfltarray[i+4] = 4 } - }