some more array asm

This commit is contained in:
Irmen de Jong 2019-08-04 15:33:00 +02:00
parent b842493cf0
commit a1cd202cd2
8 changed files with 367 additions and 86 deletions

View File

@ -827,6 +827,13 @@ internal class AstChecker(private val program: Program,
else else
printWarning("result values of subroutine call are discarded", functionCallStatement.position) 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) super.visit(functionCallStatement)
} }

View File

@ -60,7 +60,7 @@ fun compileProgram(filepath: Path,
programAst.removeNopsFlattenAnonScopes() programAst.removeNopsFlattenAnonScopes()
// if you want to print the AST, do it before shuffling the statements around below // 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 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.checkValid(compilerOptions) // check if final tree is valid
programAst.checkRecursion() // check if there are recursive subroutine calls programAst.checkRecursion() // check if there are recursive subroutine calls
printAst(programAst)
if(writeAssembly) { if(writeAssembly) {
// asm generation directly from the Ast, no need for intermediate code // asm generation directly from the Ast, no need for intermediate code
val zeropage = MachineDefinition.C64Zeropage(compilerOptions) val zeropage = MachineDefinition.C64Zeropage(compilerOptions)

View File

@ -21,11 +21,12 @@ class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor {
super.visit(program) super.visit(program)
for((scope, decls) in varsToMove) { for((scope, decls) in varsToMove) {
val sub = scope.definingSubroutine()!! val sub = scope.definingSubroutine()!!
val existingVariables = sub.statements.filterIsInstance<VarDecl>().map { it.name }.toSet() val existingVariables = sub.statements.filterIsInstance<VarDecl>().associate { it.name to it }
var conflicts = false var conflicts = false
decls.forEach { decls.forEach {
if (it.name in existingVariables) { val existing = existingVariables[it.name]
checkResult.add(NameError("variable ${it.name} already exists in subroutine ${sub.name}", it.position)) if (existing!=null) {
checkResult.add(NameError("variable ${it.name} already defined in subroutine ${sub.name} at ${existing.position}", it.position))
conflicts = true conflicts = true
} }
} }

View File

@ -233,7 +233,7 @@ internal class AsmGen2(val program: Program,
} }
} }
else { 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? // it was already allocated on the zp, what to do?
// out("${variable.name} = ${zpVar.first}\t; zp ${zpVar.second}") // out("${variable.name} = ${zpVar.first}\t; zp ${zpVar.second}")
} }
@ -469,7 +469,7 @@ internal class AsmGen2(val program: Program,
+ sta $destination + sta $destination
""" """
private fun asmIdentifierName(identifier: IdentifierReference): String { internal fun asmIdentifierName(identifier: IdentifierReference): String {
val name = if(identifier.memberOfStruct(program.namespace)!=null) { val name = if(identifier.memberOfStruct(program.namespace)!=null) {
identifier.targetVarDecl(program.namespace)!!.name identifier.targetVarDecl(program.namespace)!!.name
} else { } else {
@ -519,7 +519,8 @@ internal class AsmGen2(val program: Program,
return false 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()) { when (ArrayElementTypes.getValue(arrayDt).memorySize()) {
1 -> {} 1 -> {}
2 -> out(" asl a") 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 -> DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B ->
out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | dex") out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | dex")
DataType.ARRAY_UW, DataType.ARRAY_W -> 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 -> DataType.ARRAY_F ->
out(""" out("""
sta $ESTACK_LO_HEX,x sta $ESTACK_LO_HEX,x
dex dex
lda #<$variablename
ldy #>$variablename
jsr c64flt.push_float_from_indexed_var jsr c64flt.push_float_from_indexed_var
""") """)
else -> else ->
@ -1526,15 +1529,38 @@ $endLabel""")
} }
} }
is PrefixExpression -> { is PrefixExpression -> {
// TODO optimize common cases
translateExpression(assign.value as PrefixExpression) translateExpression(assign.value as PrefixExpression)
assignFromEvalResult(assign.target) assignFromEvalResult(assign.target)
} }
is BinaryExpression -> { is BinaryExpression -> {
// TODO optimize common cases
translateExpression(assign.value as BinaryExpression) translateExpression(assign.value as BinaryExpression)
assignFromEvalResult(assign.target) assignFromEvalResult(assign.target)
} }
is ArrayIndexedExpression -> { 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) assignFromEvalResult(assign.target)
} }
is TypecastExpression -> { 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 arrayDt = expr.identifier.targetVarDecl(program.namespace)!!.datatype
val sourceName = asmIdentifierName(expr.identifier)
val index = expr.arrayspec.index val index = expr.arrayspec.index
when (index) { when (index) {
is NumericLiteralValue -> { is NumericLiteralValue -> throw AssemblyError("this should be optimized directly")
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 RegisterExpr -> { is RegisterExpr -> {
when (index.register) { when (index.register) {
Register.A -> {} Register.A -> {}
Register.X -> out(" txa") Register.X -> out(" txa")
Register.Y -> out(" tya") Register.Y -> out(" tya")
} }
readAndPushArrayvalueWithIndexA(arrayDt, sourceName)
} }
is IdentifierReference -> { is IdentifierReference -> {
val indexName = asmIdentifierName(index) val indexName = asmIdentifierName(index)
out(" lda $indexName") out(" lda $indexName")
readAndPushArrayvalueWithIndexA(arrayDt, sourceName)
} }
else -> { else -> {
translateExpression(index) translateExpression(index)
out(" inx | lda $ESTACK_LO_HEX,x") out(" inx | lda $ESTACK_LO_HEX,x")
readAndPushArrayvalueWithIndexA(arrayDt, sourceName)
} }
} }
} }
@ -1659,7 +1669,12 @@ $endLabel""")
when(expression) { when(expression) {
is PrefixExpression -> translateExpression(expression) is PrefixExpression -> translateExpression(expression)
is BinaryExpression -> 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 TypecastExpression -> translateExpression(expression)
is AddressOf -> translateExpression(expression) is AddressOf -> translateExpression(expression)
is DirectMemoryRead -> translateExpression(expression) is DirectMemoryRead -> translateExpression(expression)
@ -1954,7 +1969,20 @@ $endLabel""")
storeRegisterInMemoryAddress(Register.Y, target.memoryAddress) storeRegisterInMemoryAddress(Register.Y, target.memoryAddress)
} }
target.arrayindexed!=null -> { 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") else -> throw AssemblyError("weird assignment target $target")
} }
@ -2043,9 +2071,6 @@ $endLabel""")
sta $targetName+4 sta $targetName+4
""") """)
} }
target.memoryAddress!=null -> {
TODO("assign floatvar $sourceName to memory ${target.memoryAddress}")
}
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier) val targetName = asmIdentifierName(targetArrayIdx.identifier)
@ -2256,7 +2281,16 @@ $endLabel""")
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier) 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") else -> TODO("assign word $word to $target")
} }
@ -2280,7 +2314,14 @@ $endLabel""")
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier) 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") else -> TODO("assign byte $byte to $target")
} }
@ -2303,9 +2344,6 @@ $endLabel""")
sta $targetName+4 sta $targetName+4
""") """)
} }
target.memoryAddress!=null -> {
TODO("assign float 0.0 to memory ${target.memoryAddress}")
}
targetArrayIdx!=null -> { targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier) val targetName = asmIdentifierName(targetArrayIdx.identifier)
@ -2316,26 +2354,80 @@ $endLabel""")
} else { } else {
// non-zero value // non-zero value
val constFloat = getFloatConst(float) val constFloat = getFloatConst(float)
if (targetIdent != null) { when {
val targetName = asmIdentifierName(targetIdent) targetIdent != null -> {
out(""" val targetName = asmIdentifierName(targetIdent)
lda $constFloat out("""
sta $targetName lda $constFloat
lda $constFloat+1 sta $targetName
sta $targetName+1 lda $constFloat+1
lda $constFloat+2 sta $targetName+1
sta $targetName+2 lda $constFloat+2
lda $constFloat+3 sta $targetName+2
sta $targetName+3 lda $constFloat+3
lda $constFloat+4 sta $targetName+3
sta $targetName+4 lda $constFloat+4
""") sta $targetName+4
} else { """)
TODO("assign float $float ($constFloat) to $target") }
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?) { private fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) {
val targetIdent = target.identifier val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed val targetArrayIdx = target.arrayindexed

View File

@ -4,17 +4,16 @@ import prog8.ast.IFunctionCall
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.ByteDatatypes import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.ast.base.Register
import prog8.ast.base.WordDatatypes import prog8.ast.base.WordDatatypes
import prog8.ast.expressions.Expression import prog8.ast.expressions.*
import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.FunctionCallStatement
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage import prog8.compiler.Zeropage
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX 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_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.toHex
import prog8.functions.FunctionSignature import prog8.functions.FunctionSignature
internal class BuiltinFunctionsAsmGen(private val program: Program, internal class BuiltinFunctionsAsmGen(private val program: Program,
@ -76,6 +75,154 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
translateFunctionArguments(fcall.arglist) translateFunctionArguments(fcall.arglist)
asmgen.out(" jsr c64flt.func_$functionName") 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 -> { else -> {
translateFunctionArguments(fcall.arglist) translateFunctionArguments(fcall.arglist)
asmgen.out(" jsr prog8_lib.func_$functionName") asmgen.out(" jsr prog8_lib.func_$functionName")

View File

@ -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, 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. 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) - blocks (top-level named scope)
- subroutines (nested named scopes) - subroutines (nested named scope)
- for, while, repeat loops (anonymous scope)
- if statements and branching conditionals (anonymous 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 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 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! 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) (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 Conditional Execution

View File

@ -66,23 +66,28 @@ main {
; plot the points of the 3d cube ; plot the points of the 3d cube
; first the points on the back, then the points on the front (painter algorithm) ; 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 { for i in 0 to len(xcoor)-1 {
float rz = rotatedz[i] rz = rotatedz[i]
if rz >= 0.1 { if rz >= 0.1 {
float persp = (5.0+rz)/height persp = (5.0+rz)/height
ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte
ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte
c64scr.setcc(sx, sy, 46, i+2) c64scr.setcc(sx, sy, 46, i+2)
} }
} }
for ubyte i in 0 to len(xcoor)-1 { for i in 0 to len(xcoor)-1 {
float rz = rotatedz[i] rz = rotatedz[i]
if rz < 0.1 { if rz < 0.1 {
float persp = (5.0+rz)/height persp = (5.0+rz)/height
ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte
ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte
c64scr.setcc(sx, sy, 81, i+2) c64scr.setcc(sx, sy, 81, i+2)
} }
} }

View File

@ -1,25 +1,42 @@
%import c64lib
%import c64utils %import c64utils
%import c64flt %import c64flt
%zeropage basicsafe %zeropage basicsafe
%option enable_floats
main { main {
ubyte[10] barray
uword[10] warray
float[10] farray
&ubyte memubarray = 1000
&uword memuwarray = 1000
&float memfltarray = 1000
sub start() { sub start() {
delay1(1) ubyte i
delay2(1) uword uw
delay3(1) float fl = farray[2]
sub delay1(ubyte note1) { barray[4] = 4
A= note1 barray[i] = 4
} barray[i+4] = 4
sub delay2(ubyte note1) { memubarray[4] = 4
A= note1 memubarray[i] = 4
} memubarray[i+4] = 4
sub delay3(ubyte note1) {
A= note1
}
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
} }
} }