mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
proper initialization of block-level global variables
This commit is contained in:
parent
f0d4c3aba9
commit
8bfa2c4c02
@ -6,7 +6,6 @@ import prog8.ast.processing.*
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.target.AsmInitialValuesGatherer
|
||||
import prog8.compiler.target.AsmVariablePreparer
|
||||
import prog8.optimizer.FlattenAnonymousScopesAndNopRemover
|
||||
|
||||
@ -22,12 +21,6 @@ internal fun Program.prepareAsmVariables(errors: ErrorReporter) {
|
||||
mover.applyModifications()
|
||||
}
|
||||
|
||||
internal fun Program.gatherInitialValues(): Map<Block, Map<String, VarDecl>> {
|
||||
val gather = AsmInitialValuesGatherer(this)
|
||||
gather.visit(this)
|
||||
return gather.initialValues
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements() {
|
||||
val initvalueCreator = AddressOfInserter(this)
|
||||
initvalueCreator.visit(this)
|
||||
|
@ -376,6 +376,9 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
if(assignment.value.inferType(program) != assignment.target.inferType(program, assignment))
|
||||
errors.err("assignment value is of different type as the target", assignment.value.position)
|
||||
|
||||
super.visit(assignment)
|
||||
}
|
||||
|
||||
@ -502,37 +505,12 @@ internal class AstChecker(private val program: Program,
|
||||
if(decl.zeropage==ZeropageWish.PREFER_ZEROPAGE || decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE)
|
||||
err("struct can not be in zeropage")
|
||||
}
|
||||
if (decl.value == null) {
|
||||
when {
|
||||
decl.datatype in NumericDatatypes -> {
|
||||
// initialize numeric var with value zero by default.
|
||||
val litVal =
|
||||
when (decl.datatype) {
|
||||
in ByteDatatypes -> NumericLiteralValue(decl.datatype, 0, decl.position)
|
||||
in WordDatatypes -> NumericLiteralValue(decl.datatype, 0, decl.position)
|
||||
else -> NumericLiteralValue(decl.datatype, 0.0, decl.position)
|
||||
}
|
||||
litVal.parent = decl
|
||||
decl.value = litVal
|
||||
}
|
||||
decl.datatype == DataType.STRUCT -> {
|
||||
// structs may be initialized with an array, but it's okay to not initialize them as well.
|
||||
}
|
||||
decl.type == VarDeclType.VAR -> {
|
||||
if(decl.datatype in ArrayDatatypes) {
|
||||
// array declaration can have an optional initialization value
|
||||
// if it is absent, the size must be given, which should have been checked earlier
|
||||
if(decl.value==null && decl.arraysize==null)
|
||||
throw FatalAstException("array init check failed")
|
||||
}
|
||||
}
|
||||
else -> err("var/const declaration needs a compile-time constant initializer value for type ${decl.datatype}")
|
||||
// const fold should have provided it!
|
||||
}
|
||||
super.visit(decl)
|
||||
return
|
||||
}
|
||||
|
||||
when(decl.value) {
|
||||
null -> {
|
||||
// a vardecl without an initial value, don't bother with the rest
|
||||
return super.visit(decl)
|
||||
}
|
||||
is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value")
|
||||
is StringLiteralValue -> {
|
||||
checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue)
|
||||
@ -565,6 +543,8 @@ internal class AstChecker(private val program: Program,
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errors.err("struct literal is wrong type to initialize this variable", decl.value!!.position)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@ -602,6 +582,10 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
val declValue = decl.value
|
||||
if(declValue!=null && decl.type==VarDeclType.VAR && !declValue.inferType(program).istype(decl.datatype))
|
||||
throw FatalAstException("initialisation value $declValue is of different type (${declValue.inferType(program)} as the variable (${decl.datatype}) at ${decl.position}")
|
||||
|
||||
super.visit(decl)
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,15 @@ class VarDecl(val type: VarDeclType,
|
||||
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array,
|
||||
isArray = true, autogeneratedDontRemove = true, position = array.position)
|
||||
}
|
||||
|
||||
fun defaultZero(dt: DataType, position: Position) = when(dt) {
|
||||
DataType.UBYTE -> NumericLiteralValue(DataType.UBYTE, 0, position)
|
||||
DataType.BYTE -> NumericLiteralValue(DataType.BYTE, 0, position)
|
||||
DataType.UWORD -> NumericLiteralValue(DataType.UWORD, 0, position)
|
||||
DataType.WORD -> NumericLiteralValue(DataType.WORD, 0, position)
|
||||
DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, 0.0, position)
|
||||
else -> throw FatalAstException("can only determine default zero value for a numeric type")
|
||||
}
|
||||
}
|
||||
|
||||
val datatypeErrors = mutableListOf<SyntaxError>() // don't crash at init time, report them in the AstChecker
|
||||
@ -274,20 +283,7 @@ class VarDecl(val type: VarDeclType,
|
||||
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, struct=$structName, value=$value, pos=$position)"
|
||||
}
|
||||
|
||||
fun asDefaultValueDecl(parent: Node?): VarDecl {
|
||||
val constValue = when(declaredDatatype) {
|
||||
DataType.UBYTE -> NumericLiteralValue(DataType.UBYTE, 0, position)
|
||||
DataType.BYTE -> NumericLiteralValue(DataType.BYTE, 0, position)
|
||||
DataType.UWORD -> NumericLiteralValue(DataType.UWORD, 0, position)
|
||||
DataType.WORD -> NumericLiteralValue(DataType.WORD, 0, position)
|
||||
DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, 0.0, position)
|
||||
else -> throw FatalAstException("can only set a default value for a numeric type")
|
||||
}
|
||||
val decl = VarDecl(type, declaredDatatype, zeropage, arraysize, name, structName, constValue, isArray, false, position)
|
||||
if(parent!=null)
|
||||
decl.linkParents(parent)
|
||||
return decl
|
||||
}
|
||||
fun zeroElementValue() = defaultZero(declaredDatatype, position)
|
||||
|
||||
fun flattenStructMembers(): MutableList<Statement> {
|
||||
val result = struct!!.statements.withIndex().map {
|
||||
|
@ -120,11 +120,9 @@ fun compileProgram(filepath: Path,
|
||||
val zeropage = CompilationTarget.machine.getZeropage(compilerOptions)
|
||||
programAst.prepareAsmVariables(errors)
|
||||
errors.handle()
|
||||
val initialValues = programAst.gatherInitialValues()
|
||||
val assembly = CompilationTarget.asmGenerator(
|
||||
programAst,
|
||||
zeropage,
|
||||
initialValues,
|
||||
compilerOptions,
|
||||
outputDir).compileToAssembly(optimize)
|
||||
assembly.assemble(compilerOptions)
|
||||
|
@ -1,31 +0,0 @@
|
||||
package prog8.compiler.target
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.NumericDatatypes
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.processing.IAstVisitor
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.VarDecl
|
||||
|
||||
internal class AsmInitialValuesGatherer(val program: Program): IAstVisitor {
|
||||
val initialValues = mutableMapOf<Block, MutableMap<String, VarDecl>>()
|
||||
|
||||
override fun visit(decl: VarDecl) {
|
||||
// collect all variables that have an initialisation value
|
||||
super.visit(decl)
|
||||
val declValue = decl.value
|
||||
if(declValue!=null
|
||||
&& decl.type== VarDeclType.VAR
|
||||
&& decl.datatype in NumericDatatypes
|
||||
&& declValue.constValue(program)!=null) {
|
||||
|
||||
val block = decl.definingBlock()
|
||||
var blockInits = initialValues[block]
|
||||
if(blockInits==null) {
|
||||
blockInits = mutableMapOf()
|
||||
initialValues[block] = blockInits
|
||||
}
|
||||
blockInits[decl.makeScopedName(decl.name)] = decl
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package prog8.compiler.target
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ErrorReporter
|
||||
import prog8.ast.base.NumericDatatypes
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.AnonymousScope
|
||||
@ -12,6 +14,14 @@ import prog8.ast.statements.VarDecl
|
||||
|
||||
class AsmVariablePreparer(val program: Program, val errors: ErrorReporter): AstWalker() {
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
if(decl.value==null && decl.type==VarDeclType.VAR && decl.datatype in NumericDatatypes) {
|
||||
// a numeric vardecl without an initial value is initialized with zero.
|
||||
decl.value = decl.zeroElementValue()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||
val decls = scope.statements.filterIsInstance<VarDecl>()
|
||||
val sub = scope.definingSubroutine()
|
||||
|
@ -8,15 +8,12 @@ import prog8.compiler.Zeropage
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
typealias InitialValues = Map<Block, Map<String, VarDecl>>
|
||||
|
||||
|
||||
internal interface CompilationTarget {
|
||||
companion object {
|
||||
lateinit var name: String
|
||||
lateinit var machine: IMachineDefinition
|
||||
lateinit var encodeString: (str: String, altEncoding: Boolean) -> List<Short>
|
||||
lateinit var decodeString: (bytes: List<Short>, altEncoding: Boolean) -> String
|
||||
lateinit var asmGenerator: (Program, Zeropage, InitialValues, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
lateinit var asmGenerator: (Program, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import prog8.ast.statements.*
|
||||
import prog8.compiler.*
|
||||
import prog8.compiler.target.IAssemblyGenerator
|
||||
import prog8.compiler.target.IAssemblyProgram
|
||||
import prog8.compiler.target.InitialValues
|
||||
import prog8.compiler.target.c64.AssemblyProgram
|
||||
import prog8.compiler.target.c64.C64MachineDefinition
|
||||
import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX
|
||||
@ -28,7 +27,6 @@ import kotlin.math.absoluteValue
|
||||
|
||||
internal class AsmGen(private val program: Program,
|
||||
private val zeropage: Zeropage,
|
||||
private val initialValues: InitialValues,
|
||||
private val options: CompilationOptions,
|
||||
private val outputDir: Path): IAssemblyGenerator {
|
||||
|
||||
@ -44,6 +42,7 @@ internal class AsmGen(private val program: Program,
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this)
|
||||
internal val loopEndLabels = ArrayDeque<String>()
|
||||
internal val loopContinueLabels = ArrayDeque<String>()
|
||||
internal val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||
|
||||
override fun compileToAssembly(optimize: Boolean): IAssemblyProgram {
|
||||
assemblyLines.clear()
|
||||
@ -127,8 +126,11 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
out(" ldx #\$ff\t; init estack pointer")
|
||||
|
||||
out(" ; initialize the variables in each block")
|
||||
program.allBlocks().filter { it in initialValues }.forEach { out(" jsr ${it.name}.prog8_init_vars") }
|
||||
out(" ; initialize the variables in each block that has globals")
|
||||
program.allBlocks().forEach {
|
||||
if(it.statements.filterIsInstance<VarDecl>().any { vd->vd.value!=null && vd.type==VarDeclType.VAR && vd.datatype in NumericDatatypes})
|
||||
out(" jsr ${it.name}.prog8_init_vars")
|
||||
}
|
||||
|
||||
out(" clc")
|
||||
when (zeropage.exitProgramStrategy) {
|
||||
@ -175,10 +177,10 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
// if any global vars need to be initialized, generate a subroutine that does this
|
||||
// it will be called from program init.
|
||||
if(block in initialValues) {
|
||||
if(block in blockLevelVarInits) {
|
||||
out("prog8_init_vars\t.proc\n")
|
||||
initialValues.getValue(block).forEach { (scopedName, decl) ->
|
||||
val scopedFullName = scopedName.split('.')
|
||||
blockLevelVarInits.getValue(block).forEach { decl ->
|
||||
val scopedFullName = decl.makeScopedName(decl.name).split('.')
|
||||
require(scopedFullName.first()==block.name)
|
||||
val target = AssignTarget(null, IdentifierReference(scopedFullName.drop(1), decl.position), null, null, decl.position)
|
||||
val assign = Assignment(target, null, decl.value!!, decl.position)
|
||||
@ -314,7 +316,7 @@ internal class AsmGen(private val program: Program,
|
||||
(decl.value as ArrayLiteralValue).value
|
||||
else {
|
||||
// no init value, use zeros
|
||||
val zero = decl.asDefaultValueDecl(decl.parent).value!!
|
||||
val zero = decl.zeroElementValue()
|
||||
Array(decl.arraysize!!.size()!!) { zero }
|
||||
}
|
||||
val floatFills = array.map {
|
||||
@ -389,7 +391,7 @@ internal class AsmGen(private val program: Program,
|
||||
(decl.value as ArrayLiteralValue).value
|
||||
else {
|
||||
// no array init value specified, use a list of zeros
|
||||
val zero = decl.asDefaultValueDecl(decl.parent).value!!
|
||||
val zero = decl.zeroElementValue()
|
||||
Array(decl.arraysize!!.size()!!) { zero }
|
||||
}
|
||||
return when (decl.datatype) {
|
||||
@ -416,7 +418,7 @@ internal class AsmGen(private val program: Program,
|
||||
(decl.value as ArrayLiteralValue).value
|
||||
else {
|
||||
// no array init value specified, use a list of zeros
|
||||
val zero = decl.asDefaultValueDecl(decl.parent).value!!
|
||||
val zero = decl.zeroElementValue()
|
||||
Array(decl.arraysize!!.size()!!) { zero }
|
||||
}
|
||||
return when (decl.datatype) {
|
||||
@ -602,7 +604,8 @@ internal class AsmGen(private val program: Program,
|
||||
internal fun translate(stmt: Statement) {
|
||||
outputSourceLine(stmt)
|
||||
when(stmt) {
|
||||
is VarDecl, is StructDecl, is NopStatement -> {}
|
||||
is VarDecl -> translate(stmt)
|
||||
is StructDecl, is NopStatement -> {}
|
||||
is Directive -> translate(stmt)
|
||||
is Return -> translate(stmt)
|
||||
is Subroutine -> translateSubroutine(stmt)
|
||||
@ -820,6 +823,27 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(stmt: VarDecl) {
|
||||
if(stmt.value!=null && stmt.type==VarDeclType.VAR && stmt.datatype in NumericDatatypes) {
|
||||
// generate an assignment statement to (re)initialize the variable's value.
|
||||
// if the vardecl is not in a subroutine however, we have to initialize it globally.
|
||||
if(stmt.definingSubroutine()==null) {
|
||||
val block = stmt.definingBlock()
|
||||
var inits = blockLevelVarInits[block]
|
||||
if(inits==null) {
|
||||
inits = mutableSetOf()
|
||||
blockLevelVarInits[block] = inits
|
||||
}
|
||||
inits.add(stmt)
|
||||
} else {
|
||||
val target = AssignTarget(null, IdentifierReference(listOf(stmt.name), stmt.position), null, null, stmt.position)
|
||||
val assign = Assignment(target, null, stmt.value!!, stmt.position)
|
||||
assign.linkParents(stmt.parent)
|
||||
translate(assign)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(stmt: Directive) {
|
||||
when(stmt.directive) {
|
||||
"%asminclude" -> {
|
||||
|
@ -140,6 +140,13 @@ internal class ConstantFoldingOptimizer(private val program: Program, private va
|
||||
}
|
||||
}
|
||||
|
||||
val declValue = decl.value
|
||||
if(declValue!=null && decl.type==VarDeclType.VAR
|
||||
&& declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) {
|
||||
// cast the numeric literal to the appropriate datatype of the variable
|
||||
decl.value = declValue.cast(decl.datatype)
|
||||
}
|
||||
|
||||
return super.visit(decl)
|
||||
}
|
||||
|
||||
|
@ -2,44 +2,23 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
; This example computes the first 20 values of the Fibonacci sequence.
|
||||
; It uses the feature that variables that don't have an initialization value,
|
||||
; will retain their previous value over multiple invocations of the program or subroutine.
|
||||
; This is extremely handy for the Fibonacci sequence because it is defined
|
||||
; in terms of 'the next value is the sum of the previous two values'
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
c64scr.print("fibonacci sequence\n")
|
||||
fib_setup()
|
||||
for A in 0 to 20 {
|
||||
c64scr.print_uw(fib_next())
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
check_eval_stack()
|
||||
}
|
||||
|
||||
sub fib_setup() {
|
||||
; (re)start the sequence
|
||||
main.fib_next.prev=0
|
||||
main.fib_next.current=1
|
||||
}
|
||||
uword fib_prev = 0 ; TODO fix initialization of block-global vars (outside of a subroutine)
|
||||
uword fib_current = 1 ; TODO fix initialization of block-global vars (outside of a subroutine)
|
||||
|
||||
sub fib_next() -> uword {
|
||||
uword prev ; no init value so will retain previous value
|
||||
uword current ; no init value so will retain previous value
|
||||
uword new = current + prev
|
||||
prev = current
|
||||
current = new
|
||||
return prev
|
||||
uword new = fib_current + fib_prev
|
||||
fib_prev = fib_current
|
||||
fib_current = new
|
||||
return fib_prev
|
||||
}
|
||||
|
||||
sub check_eval_stack() {
|
||||
if X!=255 {
|
||||
c64scr.print("stack x=")
|
||||
c64scr.print_ub(X)
|
||||
c64scr.print(" error!\n")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,10 +8,14 @@ main {
|
||||
sub start() {
|
||||
c64scr.print("mid-point\ncircle\n and\nbresenham\nline\nalgorithms.\n")
|
||||
|
||||
ubyte r
|
||||
for r in 3 to 12 step 3 {
|
||||
circle(20, 12, r)
|
||||
}
|
||||
circle(20, 12, 6)
|
||||
circle(20, 12, 6) ; TODO FIX ERROR IN LOCALS
|
||||
circle(20, 12, 6) ; TODO FIX ERROR IN LOCALS
|
||||
|
||||
; ubyte r
|
||||
; for r in 3 to 12 step 3 {
|
||||
; circle(20, 12, r)
|
||||
; }
|
||||
|
||||
c64scr.print("enter for disc:")
|
||||
void c64.CHRIN()
|
||||
@ -108,6 +112,13 @@ main {
|
||||
byte y = 0
|
||||
byte decisionOver2 = 1-x
|
||||
|
||||
c64scr.print_b(x)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_b(y)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_b(decisionOver2)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
while x>=y {
|
||||
c64scr.setcc(xcenter + x as ubyte, ycenter + y as ubyte, 81, 1)
|
||||
c64scr.setcc(xcenter - x as ubyte, ycenter + y as ubyte, 81, 2)
|
||||
|
@ -5,45 +5,67 @@
|
||||
|
||||
main {
|
||||
|
||||
sub subje() {
|
||||
ubyte yy=33 ; TODO reinitialize var here
|
||||
ubyte zz ; TODO reinitialize var here
|
||||
ubyte[5] array1 = [1,2,3,4,5]
|
||||
|
||||
c64scr.print_ub(yy)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(zz)
|
||||
c64.CHROUT('\n')
|
||||
yy++
|
||||
A=zz
|
||||
Y=array1[2]
|
||||
}
|
||||
|
||||
sub start() {
|
||||
ubyte ub1
|
||||
ubyte ub2 = 99
|
||||
uword uw1
|
||||
uword uw2 = 9999
|
||||
ubyte[5] array1
|
||||
ubyte[5] array2 = [22,33,44,55,66]
|
||||
ubyte zz2
|
||||
A=zz2
|
||||
subje()
|
||||
subje()
|
||||
subje()
|
||||
subje()
|
||||
return
|
||||
|
||||
c64scr.print_ub(ub1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(ub2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array1[0])
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array2[0])
|
||||
c64.CHROUT('\n')
|
||||
|
||||
ub1++
|
||||
ub2++
|
||||
uw1++
|
||||
uw2++
|
||||
array1[0]++
|
||||
array2[0]++
|
||||
|
||||
c64scr.print_ub(ub1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(ub2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_uw(uw2)
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array1[0])
|
||||
c64.CHROUT(',')
|
||||
c64scr.print_ub(array2[0])
|
||||
c64.CHROUT('\n')
|
||||
; ubyte ub1
|
||||
; ubyte ub2 = 99
|
||||
; uword uw1
|
||||
; uword uw2 = 9999
|
||||
; ubyte[5] array1
|
||||
; ubyte[5] array2 = [22,33,44,55,66]
|
||||
;
|
||||
; c64scr.print_ub(ub1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(ub2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array1[0])
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array2[0])
|
||||
; c64.CHROUT('\n')
|
||||
;
|
||||
; ub1++
|
||||
; ub2++
|
||||
; uw1++
|
||||
; uw2++
|
||||
; array1[0]++
|
||||
; array2[0]++
|
||||
;
|
||||
; c64scr.print_ub(ub1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(ub2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw1)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_uw(uw2)
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array1[0])
|
||||
; c64.CHROUT(',')
|
||||
; c64scr.print_ub(array2[0])
|
||||
; c64.CHROUT('\n')
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,9 @@ main {
|
||||
|
||||
irq {
|
||||
|
||||
ubyte angle
|
||||
|
||||
sub irq() {
|
||||
ubyte angle ; no initialization value so it keeps the previous one.
|
||||
ubyte @zp spri
|
||||
|
||||
c64.EXTCOL--
|
||||
|
Loading…
Reference in New Issue
Block a user