mirror of
https://github.com/irmen/prog8.git
synced 2024-07-05 22:29:04 +00:00
some more array asm
This commit is contained in:
parent
b842493cf0
commit
a1cd202cd2
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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<VarDecl>().map { it.name }.toSet()
|
||||
val existingVariables = sub.statements.filterIsInstance<VarDecl>().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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user