Compare commits

...

35 Commits
v5.0 ... v5.1

Author SHA1 Message Date
d9a8cfed8c updated the compiled examples disk 2020-11-22 18:45:40 +01:00
122796fbba version 5.1 2020-11-22 18:36:04 +01:00
510ca042c9 stack tested for most example programs 2020-11-22 18:35:43 +01:00
125f6205f2 optimizing assigning an array value to a var 2020-11-22 17:44:55 +01:00
8136f3df5c float-const comparison optimizations 2020-11-22 16:54:02 +01:00
38d06a7e94 optimized float var comparison without translateExpression() 2020-11-22 15:05:45 +01:00
49db10539a optimized float var equality comparison without translateExpression() 2020-11-22 14:33:03 +01:00
8efe4c6267 Fixed compiler watch to work with multiple compilation modules 2020-11-22 13:11:33 +01:00
04d8bb8fbf Fixed compiler watch flag crashing when not used on a subdirectory. Fixes #20 2020-11-22 12:07:14 +01:00
08aa13c90c rnd() functions marked as having (internal) side effect 2020-11-22 02:09:32 +01:00
d1febc0208 all in-place byte assignments now without translateExpression() 2020-11-22 01:38:53 +01:00
5980e58ac6 word comparison jumps now without translateExpression() 2020-11-22 01:15:05 +01:00
e1dc283d4b byte comparison jumps now without translateExpression() 2020-11-21 23:31:26 +01:00
8be234973c rollback failed optimization of memory expressions (code size got too large) 2020-11-21 19:09:02 +01:00
7def8ff2cd beginning to optimize comparisons more 2020-11-21 18:44:17 +01:00
340b1c2e42 added balls demo/benchmark 2020-11-21 18:03:57 +01:00
7e0f7ba438 todos 2020-11-20 23:46:14 +01:00
fefd9b52a8 fix for loop with signed byte loopvar over non-const 2020-11-20 22:54:24 +01:00
afd155ac4f optimize for loops over non const range, without translateExpression() 2020-11-20 22:44:16 +01:00
ee724eb4f1 float variable casts without translateExpression() 2020-11-19 22:58:38 +01:00
2f1f20ea11 rename 2020-11-19 00:28:49 +01:00
063bcf17d8 various inplace modification for word vars now without translateExpression() 2020-11-19 00:08:10 +01:00
72509eef44 inplace modification for memory now without translateExpression() 2020-11-18 23:23:06 +01:00
2da28864e9 inplace not and invert for memory now without translateExpression() 2020-11-18 23:13:07 +01:00
4278f64682 fixed invalid value push for memreads with expression 2020-11-18 22:45:04 +01:00
59ae3c3fcd << and >> for byte values slightly optimized, no longer use translateExpression(). preparing for more operator optimizations. 2020-11-18 01:27:02 +01:00
7fa21fbdff @(...) in an expression is now more efficient, without translateExpression() 2020-11-18 00:58:04 +01:00
e95af7498e comparing function call result to 0 now more efficient, without translateExpression() 2020-11-18 00:05:48 +01:00
79c75adac1 repeat and when without translateExpression() 2020-11-17 23:52:13 +01:00
d212f69d89 ++/-- and @Pc without translateExpression() 2020-11-17 23:40:42 +01:00
edf5e69d39 optimized swap() 2020-11-15 18:04:54 +01:00
574eb0d174 refactoring asmassignment code blocks into utility functions 2020-11-15 17:44:47 +01:00
8bd4914e2f fix stack error for float casts 2020-11-15 17:34:27 +01:00
5ebaaff64b refactoring asmassignment code blocks into utility functions 2020-11-15 15:07:55 +01:00
5c9e0c9f51 emit extra nop for breakpoints so vice label list works again (requires 64tass 1.55.2257 or newer!) 2020-11-15 14:31:06 +01:00
74 changed files with 1437 additions and 671 deletions

View File

@ -55,6 +55,59 @@ w2float .proc
jmp ub2float._fac_to_mem
.pend
cast_from_uw .proc
; -- uword in A/Y into float var at (P8ZP_SCRATCH_W2)
stx P8ZP_SCRATCH_REG
jsr GIVUAYFAY
jmp ub2float._fac_to_mem
.pend
cast_from_w .proc
; -- word in A/Y into float var at (P8ZP_SCRATCH_W2)
stx P8ZP_SCRATCH_REG
jsr GIVAYFAY
jmp ub2float._fac_to_mem
.pend
cast_from_ub .proc
; -- ubyte in Y into float var at (P8ZP_SCRATCH_W2)
stx P8ZP_SCRATCH_REG
jsr FREADUY
jmp ub2float._fac_to_mem
.pend
cast_from_b .proc
; -- byte in A into float var at (P8ZP_SCRATCH_W2)
stx P8ZP_SCRATCH_REG
jsr FREADSA
jmp ub2float._fac_to_mem
.pend
cast_as_uw_into_ya .proc ; also used for float 2 ub
; -- cast float at A/Y to uword into Y/A
stx P8ZP_SCRATCH_REG
jsr MOVFM
jsr GETADR ; into Y/A
ldx P8ZP_SCRATCH_REG
rts
.pend
cast_as_w_into_ay .proc ; also used for float 2 b
; -- cast float at A/Y to word into A/Y
stx P8ZP_SCRATCH_REG
jsr MOVFM
jsr AYINT
ldy $64
lda $65
ldx P8ZP_SCRATCH_REG
rts
.pend
stack_b2float .proc
; -- b2float operating on the stack
inx
@ -96,8 +149,8 @@ stack_uw2float .proc
.pend
stack_float2w .proc ; also used for float2b
stx P8ZP_SCRATCH_REG
jsr pop_float_fac1
stx P8ZP_SCRATCH_REG
jsr AYINT
ldx P8ZP_SCRATCH_REG
lda $64
@ -109,8 +162,8 @@ stack_float2w .proc ; also used for float2b
.pend
stack_float2uw .proc ; also used for float2ub
stx P8ZP_SCRATCH_REG
jsr pop_float_fac1
stx P8ZP_SCRATCH_REG
jsr GETADR
ldx P8ZP_SCRATCH_REG
sta P8ESTACK_HI,x
@ -327,6 +380,36 @@ neg_f .proc
rts
.pend
vars_equal_f .proc
; -- are the mflpt5 numbers in P8ZP_SCRATCH_W1 and AY identical?
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldy #0
lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bne _false
iny
lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bne _false
iny
lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bne _false
iny
lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bne _false
iny
lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bne _false
lda #1
rts
_false lda #0
rts
.pend
equal_f .proc
; -- are the two mflpt5 numbers on the stack identical?
inx
@ -364,6 +447,40 @@ notequal_f .proc
rts
.pend
vars_less_f .proc
; -- is float in AY < float in P8ZP_SCRATCH_W2 ?
jsr MOVFM
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
stx P8ZP_SCRATCH_REG
jsr FCOMP
ldx P8ZP_SCRATCH_REG
cmp #255
bne +
lda #1
rts
+ lda #0
rts
.pend
vars_lesseq_f .proc
; -- is float in AY <= float in P8ZP_SCRATCH_W2 ?
jsr MOVFM
lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1
stx P8ZP_SCRATCH_REG
jsr FCOMP
ldx P8ZP_SCRATCH_REG
cmp #255
bne +
- lda #1
rts
+ cmp #0
beq -
lda #0
rts
.pend
less_f .proc
; -- is f1 < f2?
jsr compare_floats

View File

@ -12,11 +12,20 @@ graphics {
sub enable_bitmap_mode() {
; enable bitmap screen, erase it and set colors to black/white.
c64.SCROLY |= %00100000
c64.SCROLY = %00111000
c64.SCROLX = %00001000
c64.VMCSB = (c64.VMCSB & %11110000) | %00001000 ; $2000-$3fff
clear_screen(1, 0)
}
sub disable_bitmap_mode() {
; enables text mode, erase the text screen, color white
c64.SCROLY = %00011000
c64.SCROLX = %00001000
c64.VMCSB = (c64.VMCSB & %11110000) | %00000100 ; $1000-$2fff
txt.fill_screen(' ', 1)
}
sub clear_screen(ubyte pixelcolor, ubyte bgcolor) {
memset(BITMAP_ADDRESS, 320*200/8, 0)
txt.fill_screen(pixelcolor << 4 | bgcolor, 0)

View File

@ -254,7 +254,6 @@ asmsub str2ubyte(str string @ AY) clobbers(Y) -> ubyte @A {
; -- returns the unsigned byte value of the string number argument in AY
; the number may NOT be preceded by a + sign and may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO implement optimized custom version of this instead of simply reusing str2uword
%asm {{
jmp str2uword
}}
@ -264,7 +263,6 @@ asmsub str2byte(str string @ AY) clobbers(Y) -> ubyte @A {
; -- returns the signed byte value of the string number argument in AY
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO implement optimized custom version of this instead of simply reusing str2word
%asm {{
jmp str2word
}}

View File

@ -1,5 +1,6 @@
%target cx16
%import syslib
%import textio
; bitmap pixel graphics module for the CommanderX16
; wraps the graphics functions that are in ROM.
@ -17,6 +18,13 @@ graphics {
clear_screen(1, 0)
}
sub disable_bitmap_mode() {
; enables text mode, erase the text screen, color white
void cx16.screen_set_mode(2)
txt.fill_screen(' ', 1) ; TODO doesn't seem to fully clear the text screen after returning from gfx mode
}
sub clear_screen(ubyte pixelcolor, ubyte bgcolor) {
cx16.GRAPH_set_colors(pixelcolor, pixelcolor, bgcolor)
cx16.GRAPH_clear()

View File

@ -30,6 +30,7 @@ write_byte_to_address_on_stack .proc
.pend
neg_b .proc
lda #0
sec
@ -443,6 +444,19 @@ less_b .proc
bpl equal_b._equal_b_false
.pend
reg_less_uw .proc
; AY < P8ZP_SCRATCH_W2?
cpy P8ZP_SCRATCH_W2+1
bcc _true
bne _false
cmp P8ZP_SCRATCH_W2
bcc _true
_false lda #0
rts
_true lda #1
rts
.pend
less_uw .proc
lda P8ESTACK_HI+2,x
cmp P8ESTACK_HI+1,x
@ -454,7 +468,29 @@ less_uw .proc
bcs equal_b._equal_b_false
.pend
reg_less_w .proc
; -- AY < P8ZP_SCRATCH_W2?
sta P8ZP_SCRATCH_B1
tya
sec
sbc P8ZP_SCRATCH_W2+1
bvc +
eor #$80
+ bmi _true
bvc +
eor #$80
+ bne _false
lda P8ZP_SCRATCH_B1
sbc P8ZP_SCRATCH_W2
bcs _false
_true lda #1
rts
_false lda #0
rts
.pend
less_w .proc
; TODO is this word comparison < correct? reg_less_w is a lot larger...
lda P8ESTACK_LO+2,x
cmp P8ESTACK_LO+1,x
lda P8ESTACK_HI+2,x
@ -496,7 +532,24 @@ lesseq_b .proc
bpl equal_b._equal_b_false
.pend
reg_lesseq_uw .proc
; AY <= P8ZP_SCRATCH_W2?
cpy P8ZP_SCRATCH_W2+1
beq +
bcc _true
lda #0
rts
+ cmp P8ZP_SCRATCH_W2
bcc _true
beq _true
lda #0
rts
_true lda #1
rts
.pend
lesseq_uw .proc
; TODO is this comparison uword <= correct????
lda P8ESTACK_HI+1,x
cmp P8ESTACK_HI+2,x
bcc equal_b._equal_b_false
@ -507,7 +560,30 @@ lesseq_uw .proc
bcc equal_b._equal_b_false
.pend
reg_lesseq_w .proc
; -- AY <= P8ZP_SCRATCH_W2?
sta P8ZP_SCRATCH_B1
tya
sec
sbc P8ZP_SCRATCH_W2+1
bvc +
eor #$80
+ bmi _true
bvc +
eor #$80
+ bne _false
lda P8ZP_SCRATCH_B1
sbc P8ZP_SCRATCH_W2
beq _true ; TODO is this correct word compare <= for all cases?
bcs _false
_true lda #1
rts
_false lda #0
rts
.pend
lesseq_w .proc
; TODO is this word compare <= correct? it is different from reg_lesseq_w
lda P8ESTACK_LO+1,x
cmp P8ESTACK_LO+2,x
lda P8ESTACK_HI+1,x

View File

@ -0,0 +1,48 @@
%import textio
test_stack {
asmsub test() {
%asm {{
stx _saveX
lda #13
jsr txt.chrout
lda #'-'
ldy #12
- jsr txt.chrout
dey
bne -
lda #13
jsr txt.chrout
lda #'x'
jsr txt.chrout
lda #'='
jsr txt.chrout
lda _saveX
jsr txt.print_ub
lda #' '
jsr txt.chrout
lda #'s'
jsr txt.chrout
lda #'p'
jsr txt.chrout
lda #'='
jsr txt.chrout
tsx
txa
jsr txt.print_ub
lda #13
jsr txt.chrout
lda #'-'
ldy #12
- jsr txt.chrout
dey
bne -
lda #13
jsr txt.chrout
ldx _saveX
rts
_saveX .byte 0
}}
}
}

View File

@ -1 +1 @@
5.0
5.1

View File

@ -55,32 +55,42 @@ private fun compileMain(args: Array<String>) {
exitProcess(1)
}
if(watchMode && moduleFiles.size<=1) {
if(watchMode) {
val watchservice = FileSystems.getDefault().newWatchService()
while(true) {
val filepath = pathFrom(moduleFiles.single()).normalize()
println("Continuous watch mode active. Main module: $filepath")
try {
println("Continuous watch mode active. Modules: $moduleFiles")
val results = mutableListOf<CompilationResult>()
for(filepathRaw in moduleFiles) {
val filepath = pathFrom(filepathRaw).normalize()
val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, slowCodegenWarnings, compilationTarget, outputPath)
println("Imported files (now watching:)")
for (importedFile in compilationResult.importedFiles) {
print(" ")
println(importedFile)
importedFile.parent.register(watchservice, StandardWatchEventKinds.ENTRY_MODIFY)
}
println("[${LocalDateTime.now().withNano(0)}] Waiting for file changes.")
results.add(compilationResult)
}
val allImportedFiles = results.flatMap { it.importedFiles }
println("Imported files (now watching:)")
for (importedFile in allImportedFiles) {
print(" ")
println(importedFile)
val watchDir = importedFile.parent ?: Path.of(".")
watchDir.register(watchservice, StandardWatchEventKinds.ENTRY_MODIFY)
}
println("[${LocalDateTime.now().withNano(0)}] Waiting for file changes.")
var recompile=false
while(!recompile) {
val event = watchservice.take()
for(changed in event.pollEvents()) {
for (changed in event.pollEvents()) {
val changedPath = changed.context() as Path
println(" change detected: $changedPath")
if(allImportedFiles.any { it.fileName == changedPath.fileName }) {
println(" change detected: $changedPath")
recompile = true
}
}
event.reset()
println("\u001b[H\u001b[2J") // clear the screen
} catch (x: Exception) {
throw x
}
println("\u001b[H\u001b[2J") // clear the screen
}
} else {

View File

@ -17,7 +17,7 @@ import kotlin.math.abs
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
val comparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
val augmentAssignmentOperators = setOf("+", "-", "/", "*", "**", "&", "|", "^", "<<", ">>")
val augmentAssignmentOperators = setOf("+", "-", "/", "*", "**", "&", "|", "^", "<<", ">>", "%", "and", "or", "xor")
sealed class Expression: Node {
abstract fun constValue(program: Program): NumericLiteralValue?

View File

@ -14,11 +14,8 @@ import prog8.compiler.target.IAssemblyGenerator
import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.c64.AssemblyProgram
import prog8.compiler.target.c64.Petscii
import prog8.compiler.target.c64.codegen.assignment.AsmAssignSource
import prog8.compiler.target.c64.codegen.assignment.AsmAssignTarget
import prog8.compiler.target.c64.codegen.assignment.AsmAssignment
import prog8.compiler.target.c64.codegen.assignment.AssignmentAsmGen
import prog8.compiler.target.c64.codegen.assignment.TargetStorageKind
import prog8.compiler.target.generatedLabelPrefix
import prog8.functions.BuiltinFunctions
import prog8.functions.FSignature
@ -201,11 +198,7 @@ internal class AsmGen(private val program: Program,
private fun assignInitialValueToVar(decl: VarDecl, variableName: List<String>) {
val asmName = asmVariableName(variableName)
val asgn = AsmAssignment(
AsmAssignSource.fromAstSource(decl.value!!, program, this),
AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, decl.datatype, decl.definingSubroutine(), variableAsmName = asmName),
false, decl.position)
assignmentAsmGen.translateNormalAssignment(asgn)
assignmentAsmGen.assignExpressionToVariable(decl.value!!, asmName, decl.datatype, decl.definingSubroutine())
}
private var generatedLabelSequenceNumber: Int = 0
@ -752,6 +745,16 @@ internal class AsmGen(private val program: Program,
internal fun translateNormalAssignment(assign: AsmAssignment) =
assignmentAsmGen.translateNormalAssignment(assign)
internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair) =
assignmentAsmGen.assignExpressionToRegister(expr, register)
internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) =
assignmentAsmGen.assignExpressionToVariable(expr, asmVarName, dt, scope)
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair) =
assignmentAsmGen.assignVariableToRegister(asmVarName, register)
private fun translateSubroutine(sub: Subroutine) {
out("")
outputSourceLine(sub)
@ -902,17 +905,16 @@ internal class AsmGen(private val program: Program,
}
}
else -> {
translateExpression(stmt.iterations!!) // todo directly into AY?
val dt = stmt.iterations!!.inferType(program)
if(!dt.isKnown)
throw AssemblyError("unknown dt")
when (dt.typeOrElse(DataType.STRUCT)) {
in ByteDatatypes -> {
out(" inx | lda P8ESTACK_LO,x")
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.A)
repeatByteCountInA(null, repeatLabel, endLabel, stmt.body)
}
in WordDatatypes -> {
out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x")
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.AY)
repeatWordCountInAY(null, repeatLabel, endLabel, stmt.body)
}
else -> throw AssemblyError("invalid loop expression datatype $dt")
@ -1008,16 +1010,16 @@ $counterVar .byte 0""")
}
private fun translate(stmt: WhenStatement) {
expressionsAsmGen.translateExpression(stmt.condition) // TODO directly into AY?
val endLabel = makeLabel("choice_end")
val choiceBlocks = mutableListOf<Pair<String, AnonymousScope>>()
val conditionDt = stmt.condition.inferType(program)
if(!conditionDt.isKnown)
throw AssemblyError("unknown condition dt")
if(conditionDt.typeOrElse(DataType.BYTE) in ByteDatatypes)
out(" inx | lda P8ESTACK_LO,x")
assignExpressionToRegister(stmt.condition, RegisterOrPair.A)
else
out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x")
assignExpressionToRegister(stmt.condition, RegisterOrPair.AY)
for(choice in stmt.choices) {
val choiceLabel = makeLabel("choice")
if(choice.values==null) {
@ -1131,7 +1133,9 @@ $counterVar .byte 0""")
"%breakpoint" -> {
val label = "_prog8_breakpoint_${breakpointLabels.size+1}"
breakpointLabels.add(label)
out("$label\tnop")
out("""
nop
$label nop""")
}
}
}
@ -1161,16 +1165,12 @@ $counterVar .byte 0""")
val sub = ret.definingSubroutine()!!
val returnType = sub.returntypes.single()
val returnReg = sub.asmReturnvaluesRegisters.single()
val returnValueTarget =
when {
returnReg.registerOrPair!=null -> AsmAssignTarget.fromRegisters(returnReg.registerOrPair, sub, program, this)
else -> throw AssemblyError("normal subroutines can't return value in status register directly")
}
if(returnReg.registerOrPair==null)
throw AssemblyError("normal subroutines can't return value in status register directly")
when (returnType) {
in IntegerDatatypes -> {
val src = AsmAssignSource.fromAstSource(returnvalue, program, this)
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
assignmentAsmGen.assignExpressionToRegister(returnvalue, returnReg.registerOrPair)
}
DataType.FLOAT -> {
// return the float value via FAC1
@ -1181,7 +1181,7 @@ $counterVar .byte 0""")
out(" lda #<${asmVar} | ldy #>${asmVar} | jsr floats.MOVFM")
}
else -> {
// todo evaluate directly into fac1 instead of via stack intermediate
// todo evaluate directly into fac1 instead of via stack intermediate (add RegisterOrPair.FAC1/FAC2 ??)
translateExpression(returnvalue)
out(" jsr floats.pop_float_fac1")
}
@ -1190,8 +1190,7 @@ $counterVar .byte 0""")
else -> {
// all else take its address and assign that also to AY register pair
val addrofValue = AddressOf(returnvalue as IdentifierReference, returnvalue.position)
val src = AsmAssignSource.fromAstSource(addrofValue, program, this)
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair)
}
}
}

View File

@ -179,8 +179,8 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
}
private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>): List<Modification> {
// TODO not sure if this is correct in all situations....:
// sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can be eliminated
// TODO this is not true if X is not a regular RAM memory address (but instead mapped I/O or ROM)
val mods = mutableListOf<Modification>()
for (pair in linesByFour) {
val first = pair[0].value.trimStart()

View File

@ -101,18 +101,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
when(func.name) {
"memset" -> {
// use the ROM function of the Cx16
var src = AsmAssignSource.fromAstSource(fcall.args[0], program, asmgen)
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r0")
var assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(fcall.args[1], program, asmgen)
tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r1")
assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(fcall.args[2], program, asmgen)
tgt = AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.UBYTE, null, register = RegisterOrPair.A)
assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
asmgen.assignExpressionToVariable(fcall.args[0], "cx16.r0", DataType.UWORD, scope)
asmgen.assignExpressionToVariable(fcall.args[1], "cx16.r1", DataType.UWORD, scope)
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.A)
val sub = (fcall as FunctionCallStatement).definingSubroutine()!!
asmgen.saveRegister(CpuRegister.X, false, sub)
asmgen.out(" jsr cx16.memory_fill")
@ -129,18 +120,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
// use the ROM function of the Cx16
var src = AsmAssignSource.fromAstSource(fcall.args[0], program, asmgen)
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r0")
var assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(fcall.args[1], program, asmgen)
tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r1")
assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(fcall.args[2], program, asmgen)
tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r2")
assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
asmgen.assignExpressionToVariable(fcall.args[0], "cx16.r0", DataType.UWORD, scope)
asmgen.assignExpressionToVariable(fcall.args[1], "cx16.r1", DataType.UWORD, scope)
asmgen.assignExpressionToVariable(fcall.args[2], "cx16.r2", DataType.UWORD, scope)
val sub = (fcall as FunctionCallStatement).definingSubroutine()!!
asmgen.saveRegister(CpuRegister.X, false, sub)
asmgen.out(" jsr cx16.memory_copy")
@ -271,7 +253,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UBYTE -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "ror2", 'b')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror2", 'b')
asmgen.out(" jsr prog8_lib.ror2_array_ub")
}
is DirectMemoryRead -> {
@ -279,7 +261,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #\$80 |+ | sta ${number.toHex()}")
} else {
translateRolRorMemoryArgs(what.addressExpression, fcall)
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.ror2_mem_ub")
}
}
@ -293,7 +275,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UWORD -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "ror2", 'w')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror2", 'w')
asmgen.out(" jsr prog8_lib.ror2_array_uw")
}
is IdentifierReference -> {
@ -314,7 +296,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UBYTE -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "ror", 'b')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror", 'b')
asmgen.out(" jsr prog8_lib.ror_array_ub")
}
is DirectMemoryRead -> {
@ -322,7 +304,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" ror ${number.toHex()}")
} else {
translateRolRorMemoryArgs(what.addressExpression, fcall)
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out("""
sta (+) + 1
sty (+) + 2
@ -339,7 +321,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UWORD -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "ror", 'w')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "ror", 'w')
asmgen.out(" jsr prog8_lib.ror_array_uw")
}
is IdentifierReference -> {
@ -360,7 +342,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UBYTE -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "rol2", 'b')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol2", 'b')
asmgen.out(" jsr prog8_lib.rol2_array_ub")
}
is DirectMemoryRead -> {
@ -368,7 +350,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" lda ${number.toHex()} | cmp #\$80 | rol a | sta ${number.toHex()}")
} else {
translateRolRorMemoryArgs(what.addressExpression, fcall)
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.rol2_mem_ub")
}
}
@ -382,7 +364,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UWORD -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "rol2", 'w')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol2", 'w')
asmgen.out(" jsr prog8_lib.rol2_array_uw")
}
is IdentifierReference -> {
@ -403,7 +385,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UBYTE -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "rol", 'b')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol", 'b')
asmgen.out(" jsr prog8_lib.rol_array_ub")
}
is DirectMemoryRead -> {
@ -411,7 +393,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val number = (what.addressExpression as NumericLiteralValue).number
asmgen.out(" rol ${number.toHex()}")
} else {
translateRolRorMemoryArgs(what.addressExpression, fcall)
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
asmgen.out("""
sta (+) + 1
sty (+) + 2
@ -428,7 +410,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
DataType.UWORD -> {
when (what) {
is ArrayIndexedExpression -> {
translateRolRorArrayArgs(what.arrayvar, what.indexer, fcall, "rol", 'w')
translateRolRorArrayArgs(what.arrayvar, what.indexer, "rol", 'w')
asmgen.out(" jsr prog8_lib.rol_array_uw")
}
is IdentifierReference -> {
@ -442,22 +424,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
}
private fun translateRolRorMemoryArgs(addressExpression: Expression, fcall: IFunctionCall) {
val src = AsmAssignSource.fromAstSource(addressExpression, program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
}
private fun translateRolRorArrayArgs(arrayvar: IdentifierReference, indexer: ArrayIndex, fcall: IFunctionCall, operation: String, dt: Char) {
var src = AsmAssignSource.fromAstSource(AddressOf(arrayvar, (fcall as Node).position), program, asmgen)
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "prog8_lib.${operation}_array_u${dt}._arg_target")
var assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(indexer, program, asmgen)
tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UBYTE, null, variableAsmName = "prog8_lib.${operation}_array_u${dt}._arg_index")
assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
private fun translateRolRorArrayArgs(arrayvar: IdentifierReference, indexer: ArrayIndex, operation: String, dt: Char) {
asmgen.assignExpressionToVariable(AddressOf(arrayvar, arrayvar.position), "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null)
val indexerExpr = if(indexer.indexVar!=null) indexer.indexVar!! else indexer.indexNum!!
asmgen.assignExpressionToVariable(indexerExpr, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null)
}
private fun funcVariousFloatFuncs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, scope: Subroutine) {
@ -671,7 +641,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
}
// all other types of swap() calls are done via the evaluation stack
// all other types of swap() calls are done via a temporary variable
fun targetFromExpr(expr: Expression, datatype: DataType): AsmAssignTarget {
return when (expr) {
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine(), variableAsmName = asmgen.asmVariableName(expr))
@ -681,25 +652,43 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
}
// TODO find alternative way to swap here without using estack
asmgen.translateExpression(first)
asmgen.translateExpression(second)
val idatatype = first.inferType(program)
if(!idatatype.isKnown)
throw AssemblyError("unknown dt")
val datatype = idatatype.typeOrElse(DataType.STRUCT)
val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, datatype),
targetFromExpr(first, datatype),
false, first.position
)
val assignSecond = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, datatype),
targetFromExpr(second, datatype),
false, second.position
)
asmgen.translateNormalAssignment(assignFirst)
asmgen.translateNormalAssignment(assignSecond)
val datatype = first.inferType(program).typeOrElse(DataType.STRUCT)
when(datatype) {
in ByteDatatypes, in WordDatatypes -> {
asmgen.assignExpressionToVariable(first, "P8ZP_SCRATCH_W1", datatype, null)
asmgen.assignExpressionToVariable(second, "P8ZP_SCRATCH_W2", datatype, null)
val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W2"),
targetFromExpr(first, datatype),
false, first.position
)
val assignSecond = AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W1"),
targetFromExpr(second, datatype),
false, second.position
)
asmgen.translateNormalAssignment(assignFirst)
asmgen.translateNormalAssignment(assignSecond)
}
DataType.FLOAT -> {
// via evaluation stack
asmgen.translateExpression(first)
asmgen.translateExpression(second)
val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, DataType.FLOAT),
targetFromExpr(first, datatype),
false, first.position
)
val assignSecond = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, DataType.FLOAT),
targetFromExpr(second, datatype),
false, second.position
)
asmgen.translateNormalAssignment(assignFirst)
asmgen.translateNormalAssignment(assignSecond)
}
else -> throw AssemblyError("weird swap dt")
}
}
private fun swapArrayValues(elementDt: DataType, arrayVarName1: String, indexValue1: NumericLiteralValue, arrayVarName2: String, indexValue2: NumericLiteralValue) {
@ -971,14 +960,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
private fun funcMkword(fcall: IFunctionCall, resultToStack: Boolean) {
var src = AsmAssignSource.fromAstSource(fcall.args[0], program, asmgen) // msb
var tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.Y, null, program, asmgen)
var assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(fcall.args[1], program, asmgen) // lsb
tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.A, null, program, asmgen)
assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
if(resultToStack)
asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
}
@ -995,10 +978,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
if (resultToStack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
} else {
val src = AsmAssignSource.fromAstSource(fcall.args.single(), program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
if (resultToStack)
asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
else
@ -1019,10 +999,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
if (resultToStack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
} else {
val src = AsmAssignSource.fromAstSource(fcall.args.single(), program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
asmgen.translateNormalAssignment(assign)
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
if (resultToStack)
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
@ -1057,12 +1034,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
else -> {
scope.asmGenInfo.usedFloatEvalResultVar = true
val variable = IdentifierReference(listOf("_prog8_float_eval_result"), value.position)
variable.linkParents(value)
val assign = AsmAssignment(AsmAssignSource.fromAstSource(value, program, asmgen),
AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.FLOAT, null, variableAsmName = asmgen.asmVariableName(variable)),
false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
val addr = AddressOf(variable, value.position)
addr.linkParents(value)
asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT, scope)
AsmAssignSource.fromAstSource(addr, program, asmgen)
}
}

View File

@ -9,10 +9,6 @@ import prog8.ast.statements.Subroutine
import prog8.compiler.AssemblyError
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.CpuType
import prog8.compiler.target.c64.codegen.assignment.AsmAssignSource
import prog8.compiler.target.c64.codegen.assignment.AsmAssignTarget
import prog8.compiler.target.c64.codegen.assignment.AsmAssignment
import prog8.compiler.target.c64.codegen.assignment.TargetStorageKind
import prog8.compiler.toHex
import prog8.functions.BuiltinFunctions
import kotlin.math.absoluteValue
@ -36,7 +32,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
internal fun translateComparisonExpressionWithJumpIfFalse(expr: BinaryExpression, jumpIfFalseLabel: String) {
// first, if it is of the form: <constvalue> <comparison> X , swap the operands around
// first, if it is of the form: <constvalue> <comparison> X , swap the operands around,
// so that the constant value is always the right operand.
var left = expr.left
var right = expr.right
var operator = expr.operator
@ -63,8 +60,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
val dt = idt.typeOrElse(DataType.STRUCT)
when (operator) {
"==" -> {
// if the left operand is an expression, and the right is 0, we can just evaluate that expression.
// (the extra comparison is not required as the result of the expression is already the required boolean value)
// if the left operand is an expression, and the right is 0, we can just evaluate that expression,
// and use the result value directly to determine the boolean result. Shortcut only for integers.
if(rightConstVal?.number?.toDouble() == 0.0) {
when(left) {
is PrefixExpression,
@ -74,40 +71,35 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
is AddressOf,
is RangeExpr,
is FunctionCall -> {
translateExpression(left) // todo directly into AY reg?
if(dt in ByteDatatypes) {
asmgen.out("""
inx
lda P8ESTACK_LO,x
bne $jumpIfFalseLabel""")
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out(" bne $jumpIfFalseLabel")
return
}
else if(dt in WordDatatypes) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out("""
inx
lda P8ESTACK_LO,x
clc
adc P8ESTACK_HI,x
sty P8ZP_SCRATCH_B1
ora P8ZP_SCRATCH_B1
bne $jumpIfFalseLabel""")
return
}
// TODO ....float?
}
else -> {}
}
}
when (dt) {
in ByteDatatypes -> translateByteEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringEquals(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
in ByteDatatypes -> translateByteEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringEqualsJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
"!=" -> {
// if the left operand is an expression, and the right is 0, we can just evaluate that expression.
// (the extra comparison is not required as the result of the expression is already the required boolean value)
// if the left operand is an expression, and the right is 0, we can just evaluate that expression,
// and use the result value directly to determine the boolean result. Shortcut only for integers.
if(rightConstVal?.number?.toDouble() == 0.0) {
when(left) {
is PrefixExpression,
@ -117,105 +109,244 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
is AddressOf,
is RangeExpr,
is FunctionCall -> {
translateExpression(left) // todo directly into AY?
if(dt in ByteDatatypes) {
asmgen.out("""
inx
lda P8ESTACK_LO,x
beq $jumpIfFalseLabel""")
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out(" beq $jumpIfFalseLabel")
return
}
else if(dt in WordDatatypes) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out("""
inx
lda P8ESTACK_LO,x
clc
adc P8ESTACK_HI,x
sty P8ZP_SCRATCH_B1
ora P8ZP_SCRATCH_B1
beq $jumpIfFalseLabel""")
return
}
// TODO .... .float?
}
else -> {}
}
}
when (dt) {
in ByteDatatypes -> translateByteNotEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordNotEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatNotEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringNotEquals(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
in ByteDatatypes -> translateByteNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
in WordDatatypes -> translateWordNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringNotEqualsJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
"<" -> {
when(dt) {
DataType.UBYTE -> translateUbyteLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> {
// todo via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.less_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
DataType.STR -> translateStringLess(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
"<=" -> {
when(dt) {
DataType.UBYTE -> translateUbyteLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> {
// todo via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.lesseq_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
DataType.STR -> translateStringLessOrEqual(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringLessOrEqualJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
">" -> {
when(dt) {
DataType.UBYTE -> translateUbyteGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> {
// todo via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.greater_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
DataType.STR -> translateStringGreater(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterJump(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
">=" -> {
when(dt) {
DataType.UBYTE -> translateUbyteGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> {
// todo via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.greatereq_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
DataType.STR -> translateStringGreaterOrEqual(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
DataType.UBYTE -> translateUbyteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.BYTE -> translateByteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.UWORD -> translateUwordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.WORD -> translateWordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.FLOAT -> translateFloatGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
DataType.STR -> translateStringGreaterOrEqualJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
else -> throw AssemblyError("weird operand datatype")
}
}
}
}
private fun translateUbyteLess(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateFloatLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away")
}
else if(leftConstVal!=null && right is IdentifierReference) {
throw AssemblyError("const-compare should have been optimized to have const as right operand")
}
else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.getFloatAsmConst(rightConstVal.number.toDouble())
asmgen.out("""
lda #<$rightName
ldy #>$rightName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$leftName
ldy #>$leftName
jsr floats.vars_less_f
beq $jumpIfFalseLabel""")
}
else if(left is IdentifierReference && right is IdentifierReference) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.asmVariableName(right)
asmgen.out("""
lda #<$rightName
ldy #>$rightName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$leftName
ldy #>$leftName
jsr floats.vars_less_f
beq $jumpIfFalseLabel""")
} else {
if (asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (e1): '<' at ${left.position}") // TODO float via func args?
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.less_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
}
private fun translateFloatLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away")
}
else if(leftConstVal!=null && right is IdentifierReference) {
throw AssemblyError("const-compare should have been optimized to have const as right operand")
}
else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.getFloatAsmConst(rightConstVal.number.toDouble())
asmgen.out("""
lda #<$rightName
ldy #>$rightName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$leftName
ldy #>$leftName
jsr floats.vars_lesseq_f
beq $jumpIfFalseLabel""")
}
else if(left is IdentifierReference && right is IdentifierReference) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.asmVariableName(right)
asmgen.out("""
lda #<$rightName
ldy #>$rightName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$leftName
ldy #>$leftName
jsr floats.vars_lesseq_f
beq $jumpIfFalseLabel""")
} else {
if (asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (e1): '<=' at ${left.position}") // TODO float via func args?
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.lesseq_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
}
private fun translateFloatGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away")
}
else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.getFloatAsmConst(rightConstVal.number.toDouble())
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_less_f
beq $jumpIfFalseLabel""")
}
else if(leftConstVal!=null && right is IdentifierReference) {
throw AssemblyError("const-compare should have been optimized to have const as right operand")
}
else if(left is IdentifierReference && right is IdentifierReference) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.asmVariableName(right)
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_less_f
beq $jumpIfFalseLabel""")
} else {
if (asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (e1): '>' at ${left.position}") // TODO float via func args?
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.greater_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
}
private fun translateFloatGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away")
}
else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.getFloatAsmConst(rightConstVal.number.toDouble())
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_lesseq_f
beq $jumpIfFalseLabel""")
}
else if(leftConstVal!=null && right is IdentifierReference) {
throw AssemblyError("const-compare should have been optimized to have const as right operand")
}
else if(left is IdentifierReference && right is IdentifierReference) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.asmVariableName(right)
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_lesseq_f
beq $jumpIfFalseLabel""")
} else {
if (asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (e1): '>=' at ${left.position}") // TODO float via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.greatereq_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
}
private fun translateUbyteLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>=leftConstVal)
@ -245,13 +376,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.less_ub | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out(" cmp P8ZP_SCRATCH_B1 | bcs $jumpIfFalseLabel")
}
private fun translateByteLess(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateByteLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>=leftConstVal)
@ -275,13 +405,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.less_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out("""
sec
sbc P8ZP_SCRATCH_B1
bvc +
eor #$80
+ bpl $jumpIfFalseLabel""")
}
private fun translateUwordLess(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUwordLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>=leftConstVal)
@ -307,13 +441,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.less_uw | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel")
}
private fun translateWordLess(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateWordLessJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>=leftConstVal)
@ -338,13 +471,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.less_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel")
}
private fun translateUbyteGreater(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUbyteGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<=leftConstVal)
@ -374,13 +506,15 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or registers
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greater_ub | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out("""
cmp P8ZP_SCRATCH_B1
bcc $jumpIfFalseLabel
beq $jumpIfFalseLabel""")
}
private fun translateByteGreater(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateByteGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<=leftConstVal)
@ -405,13 +539,20 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greater_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out("""
clc
sbc P8ZP_SCRATCH_B1
bvc +
eor #$80
+ bpl +
bmi $jumpIfFalseLabel
+""")
}
private fun translateUwordGreater(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUwordGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<=leftConstVal)
@ -441,13 +582,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greater_uw | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel")
}
private fun translateWordGreater(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateWordGreaterJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<=leftConstVal)
@ -478,13 +618,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greater_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel")
}
private fun translateUbyteLessOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUbyteLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>leftConstVal)
@ -521,13 +660,16 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.lesseq_ub | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out("""
cmp P8ZP_SCRATCH_B1
beq +
bcs $jumpIfFalseLabel
+""")
}
private fun translateByteLessOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateByteLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>leftConstVal)
@ -555,13 +697,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.lesseq_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out("""
clc
sbc P8ZP_SCRATCH_B1
bvc +
eor #$80
+ bpl $jumpIfFalseLabel""")
}
private fun translateUwordLessOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUwordLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>leftConstVal)
@ -590,13 +736,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.lesseq_uw | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel")
}
private fun translateWordLessOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateWordLessOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal>leftConstVal)
@ -627,13 +772,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.lesseq_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel")
}
private fun translateUbyteGreaterOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUbyteGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<leftConstVal)
@ -658,13 +802,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greatereq_ub | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out(" cmp P8ZP_SCRATCH_B1 | bcc $jumpIfFalseLabel")
}
private fun translateByteGreaterOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateByteGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<leftConstVal)
@ -691,13 +834,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greatereq_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out("""
sec
sbc P8ZP_SCRATCH_B1
bvc +
eor #$80
+ bmi $jumpIfFalseLabel""")
}
private fun translateUwordGreaterOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateUwordGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<leftConstVal)
@ -721,13 +868,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greatereq_uw | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel")
}
private fun translateWordGreaterOrEqual(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateWordGreaterOrEqualJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal<leftConstVal)
@ -753,13 +899,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.greatereq_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel")
}
private fun translateByteEquals(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateByteEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal!=leftConstVal)
@ -785,13 +930,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// TODO via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.equal_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out(" cmp P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel")
}
private fun translateByteNotEquals(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateByteNotEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal==leftConstVal)
@ -817,13 +961,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.notequal_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
asmgen.out(" cmp P8ZP_SCRATCH_B1 | beq $jumpIfFalseLabel")
}
private fun translateWordEquals(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateWordEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal!=leftConstVal)
@ -851,13 +994,16 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.equal_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out("""
cmp P8ZP_SCRATCH_W2
bne $jumpIfFalseLabel
cpy P8ZP_SCRATCH_W2+1
bne $jumpIfFalseLabel""")
}
private fun translateWordNotEquals(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateWordNotEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal==leftConstVal)
@ -887,13 +1033,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args or regs
asmgen.translateExpression(left)
asmgen.translateExpression(right)
asmgen.out(" jsr prog8_lib.notequal_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
asmgen.out("""
cmp P8ZP_SCRATCH_W2
bne +
cpy P8ZP_SCRATCH_W2+1
beq $jumpIfFalseLabel
+""")
}
private fun translateFloatEquals(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateFloatEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal!=leftConstVal)
@ -933,13 +1083,47 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.equal_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away")
}
else if(leftConstVal!=null && right is IdentifierReference) {
throw AssemblyError("const-compare should have been optimized to have const as right operand")
}
else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.getFloatAsmConst(rightConstVal.number.toDouble())
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_equal_f
beq $jumpIfFalseLabel""")
}
else if(left is IdentifierReference && right is IdentifierReference) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.asmVariableName(right)
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_equal_f
beq $jumpIfFalseLabel""")
} else {
if (asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (e22): '==' at ${left.position}") // TODO float via func args?
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.equal_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
}
private fun translateFloatNotEquals(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
private fun translateFloatNotEqualsJump(left: Expression, right: Expression, leftConstVal: NumericLiteralValue?, rightConstVal: NumericLiteralValue?, jumpIfFalseLabel: String) {
if(rightConstVal!=null) {
if(leftConstVal!=null) {
if(rightConstVal==leftConstVal)
@ -980,13 +1164,47 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
}
// todo via func args
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.notequal_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
if(leftConstVal!=null && rightConstVal!=null) {
throw AssemblyError("const-compare should have been optimized away")
}
else if(leftConstVal!=null && right is IdentifierReference) {
throw AssemblyError("const-compare should have been optimized to have const as right operand")
}
else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.getFloatAsmConst(rightConstVal.number.toDouble())
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_equal_f
bne $jumpIfFalseLabel""")
}
else if(left is IdentifierReference && right is IdentifierReference) {
val leftName = asmgen.asmVariableName(left)
val rightName = asmgen.asmVariableName(right)
asmgen.out("""
lda #<$leftName
ldy #>$leftName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<$rightName
ldy #>$rightName
jsr floats.vars_equal_f
bne $jumpIfFalseLabel""")
} else {
if (asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (e23): '!=' at ${left.position}") // TODO float via func args?
translateExpression(left)
translateExpression(right)
asmgen.out(" jsr floats.notequal_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
}
}
private fun translateStringEquals(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
private fun translateStringEqualsJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
val leftNam = asmgen.asmVariableName(left)
val rightNam = asmgen.asmVariableName(right)
asmgen.out("""
@ -1001,7 +1219,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
bne $jumpIfFalseLabel""")
}
private fun translateStringNotEquals(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
private fun translateStringNotEqualsJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
val leftNam = asmgen.asmVariableName(left)
val rightNam = asmgen.asmVariableName(right)
asmgen.out("""
@ -1016,7 +1234,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
beq $jumpIfFalseLabel""")
}
private fun translateStringLess(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
private fun translateStringLessJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
val leftNam = asmgen.asmVariableName(left)
val rightNam = asmgen.asmVariableName(right)
asmgen.out("""
@ -1030,7 +1248,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
bpl $jumpIfFalseLabel""")
}
private fun translateStringGreater(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
private fun translateStringGreaterJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
val leftNam = asmgen.asmVariableName(left)
val rightNam = asmgen.asmVariableName(right)
asmgen.out("""
@ -1045,7 +1263,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
bmi $jumpIfFalseLabel""")
}
private fun translateStringLessOrEqual(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
private fun translateStringLessOrEqualJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
val leftNam = asmgen.asmVariableName(left)
val rightNam = asmgen.asmVariableName(right)
asmgen.out("""
@ -1061,7 +1279,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
+""")
}
private fun translateStringGreaterOrEqual(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
private fun translateStringGreaterOrEqualJump(left: IdentifierReference, right: IdentifierReference, jumpIfFalseLabel: String) {
val leftNam = asmgen.asmVariableName(left)
val rightNam = asmgen.asmVariableName(right)
asmgen.out("""
@ -1131,7 +1349,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
private fun translateExpression(typecast: TypecastExpression) {
translateExpression(typecast.expression) // todo avoid stack
translateExpression(typecast.expression)
when(typecast.expression.inferType(program).typeOrElse(DataType.STRUCT)) {
DataType.UBYTE -> {
when(typecast.type) {
@ -1214,12 +1432,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
asmgen.out(" sta P8ESTACK_LO,x | dex")
}
else -> {
translateExpression(expr.addressExpression) // todo directly into A
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack")
if(pushResultOnEstack)
asmgen.out(" sta P8ESTACK_LO+1,x")
else
asmgen.out(" php | inx | plp")
asmgen.assignExpressionToVariable(expr.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
if(pushResultOnEstack) {
asmgen.out(" dex | ldy #0 | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x")
} else {
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
}
}
}
}
@ -1547,7 +1765,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
private fun translateExpression(expr: PrefixExpression) {
// todo avoid using stack
translateExpression(expr.expression)
val itype = expr.inferType(program)
if(!itype.isKnown)
@ -1730,14 +1947,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
}
private fun translateCompareStrings(s1: Expression, operator: String, s2: Expression) {
var src = AsmAssignSource.fromAstSource(s1, program, asmgen)
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "prog8_lib.strcmp_expression._arg_s1")
var assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
src = AsmAssignSource.fromAstSource(s2, program, asmgen)
tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "prog8_lib.strcmp_expression._arg_s2")
assign = AsmAssignment(src, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(assign)
asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD, null)
asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD, null)
asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A
when(operator) {
"==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO,x")

View File

@ -1,20 +1,16 @@
package prog8.compiler.target.c64.codegen
import prog8.ast.Program
import prog8.ast.base.ArrayElementTypes
import prog8.ast.base.DataType
import prog8.ast.base.RegisterOrPair
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.RangeExpr
import prog8.ast.statements.ForLoop
import prog8.compiler.AssemblyError
import prog8.compiler.target.c64.codegen.assignment.AsmAssignSource
import prog8.compiler.target.c64.codegen.assignment.AsmAssignTarget
import prog8.compiler.target.c64.codegen.assignment.AsmAssignment
import prog8.compiler.target.c64.codegen.assignment.TargetStorageKind
import prog8.compiler.toHex
import kotlin.math.absoluteValue
// todo reduce use of stack eval translateExpression()
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: ForLoop) {
@ -53,23 +49,17 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
val incdec = if(stepsize==1) "inc" else "dec"
// loop over byte range via loopvar
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.translateExpression(range.to)
asmgen.translateExpression(range.from)
asmgen.assignExpressionToVariable(range.from, varname, ArrayElementTypes.getValue(iterableDt), null)
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayElementTypes.getValue(iterableDt), null)
asmgen.out(loopLabel)
asmgen.translate(stmt.body)
asmgen.out("""
inx
lda P8ESTACK_LO,x
sta $varname
lda P8ESTACK_LO+1,x
sta $modifiedLabel+1
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname
$modifiedLabel cmp #0 ; modified
beq $endLabel
$incdec $varname
jmp $loopLabel
$endLabel inx""")
lda $varname
$modifiedLabel cmp #0 ; modified
beq $endLabel
$incdec $varname
jmp $loopLabel
$endLabel""")
} else {
@ -77,36 +67,29 @@ $endLabel inx""")
// loop over byte range via loopvar
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.translateExpression(range.to)
asmgen.translateExpression(range.from)
asmgen.out("""
inx
lda P8ESTACK_LO,x
sta $varname
lda P8ESTACK_LO+1,x
sta $modifiedLabel+1
$loopLabel""")
asmgen.assignExpressionToVariable(range.from, varname, ArrayElementTypes.getValue(iterableDt), null)
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayElementTypes.getValue(iterableDt), null)
asmgen.out(loopLabel)
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname""")
if(stepsize>0) {
asmgen.out("""
clc
adc #$stepsize
sta $varname
$modifiedLabel cmp #0 ; modified
bcc $loopLabel
beq $loopLabel""")
lda $varname
clc
adc #$stepsize
sta $varname
$modifiedLabel cmp #0 ; modified
bmi $loopLabel
beq $loopLabel""")
} else {
asmgen.out("""
sec
sbc #${stepsize.absoluteValue}
sta $varname
$modifiedLabel cmp #0 ; modified
bcs $loopLabel""")
lda $varname
sec
sbc #${stepsize.absoluteValue}
sta $varname
$modifiedLabel cmp #0 ; modified
bpl $loopLabel""")
}
asmgen.out("""
$endLabel inx""")
asmgen.out(endLabel)
}
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
@ -115,13 +98,11 @@ $endLabel inx""")
// words, step 1 or -1
stepsize == 1 || stepsize == -1 -> {
asmgen.translateExpression(range.to)
assignLoopvar(stmt, range)
val varname = asmgen.asmVariableName(stmt.loopVar)
assignLoopvar(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
asmgen.out("""
lda P8ESTACK_HI+1,x
sta $modifiedLabel+1
lda P8ESTACK_LO+1,x
sty $modifiedLabel+1
sta $modifiedLabel2+1
$loopLabel""")
asmgen.translate(stmt.body)
@ -148,21 +129,17 @@ $modifiedLabel2 cmp #0 ; modified
jmp $loopLabel""")
}
asmgen.out(endLabel)
asmgen.out(" inx")
}
stepsize > 0 -> {
// (u)words, step >= 2
asmgen.translateExpression(range.to)
asmgen.out("""
lda P8ESTACK_HI+1,x
sta $modifiedLabel+1
lda P8ESTACK_LO+1,x
sta $modifiedLabel2+1
""")
assignLoopvar(stmt, range)
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.out(loopLabel)
assignLoopvar(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
$loopLabel""")
asmgen.translate(stmt.body)
if (iterableDt == DataType.ARRAY_UW) {
@ -181,7 +158,7 @@ $modifiedLabel2 lda #0 ; modified
cmp $varname
bcc $endLabel
bcs $loopLabel
$endLabel inx""")
$endLabel""")
} else {
asmgen.out("""
lda $varname
@ -198,22 +175,19 @@ $modifiedLabel lda #0 ; modified
bvc +
eor #$80
+ bpl $loopLabel
$endLabel inx""")
$endLabel""")
}
}
else -> {
// (u)words, step <= -2
asmgen.translateExpression(range.to)
asmgen.out("""
lda P8ESTACK_HI+1,x
sta $modifiedLabel+1
lda P8ESTACK_LO+1,x
sta $modifiedLabel2+1
""")
assignLoopvar(stmt, range)
val varname = asmgen.asmVariableName(stmt.loopVar)
asmgen.out(loopLabel)
assignLoopvar(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
$loopLabel""")
asmgen.translate(stmt.body)
if(iterableDt==DataType.ARRAY_UW) {
@ -231,7 +205,7 @@ $modifiedLabel cmp #0 ; modified
lda $varname
$modifiedLabel2 cmp #0 ; modified
bcs $loopLabel
$endLabel inx""")
$endLabel""")
} else {
asmgen.out("""
lda $varname
@ -249,7 +223,7 @@ $modifiedLabel sbc #0 ; modified
bvc +
eor #$80
+ bpl $loopLabel
$endLabel inx""")
$endLabel""")
}
}
}
@ -611,10 +585,6 @@ $endLabel""")
asmgen.loopEndLabels.pop()
}
private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) {
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, stmt.loopVarDt(program).typeOrElse(DataType.STRUCT), stmt.definingSubroutine(), variableAsmName=asmgen.asmVariableName(stmt.loopVar))
val src = AsmAssignSource.fromAstSource(range.from, program, asmgen).adjustSignedUnsigned(target)
val assign = AsmAssignment(src, target, false, range.position)
asmgen.translateNormalAssignment(assign)
}
private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) =
asmgen.assignExpressionToVariable(range.from, asmgen.asmVariableName(stmt.loopVar), stmt.loopVarDt(program).typeOrElse(DataType.STRUCT), stmt.definingSubroutine())
}

View File

@ -165,10 +165,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
throw AssemblyError("argument type incompatible")
val varName = asmgen.asmVariableName(sub.scopedname+"."+parameter.value.name)
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, parameter.value.type, sub, variableAsmName = varName)
val source = AsmAssignSource.fromAstSource(value, program, asmgen).adjustSignedUnsigned(tgt)
val asgn = AsmAssignment(source, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(asgn)
asmgen.assignExpressionToVariable(value, varName, parameter.value.type, sub)
}
private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {
@ -213,17 +210,13 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
""")
}
else -> {
asmgen.translateExpression(value) // todo directly into A
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out("""
inx
pha
lda P8ESTACK_LO,x
beq +
sec
bcs ++
+ clc
+ pla
""")
beq +
sec
bcs ++
+ clc
+""")
}
}
}
@ -231,18 +224,16 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
}
else -> {
// via register or register pair
val target = AsmAssignTarget.fromRegisters(register!!, sub, program, asmgen)
register!!
if(requiredDt largerThan valueDt) {
// we need to sign extend the source, do this via temporary word variable
val scratchVar = asmgen.asmVariableName("P8ZP_SCRATCH_W1")
val scratchTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UBYTE, sub, scratchVar)
val source = AsmAssignSource.fromAstSource(value, program, asmgen)
asmgen.translateNormalAssignment(AsmAssignment(source, scratchTarget, false, value.position))
asmgen.assignExpressionToVariable(value, scratchVar, DataType.UBYTE, sub)
asmgen.signExtendVariableLsb(scratchVar, valueDt)
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, DataType.UWORD, scratchVar)
asmgen.translateNormalAssignment(AsmAssignment(src, target, false, Position.DUMMY))
asmgen.assignVariableToRegister(scratchVar, register)
}
else {
val target = AsmAssignTarget.fromRegisters(register, sub, program, asmgen)
val src = if(valueDt in PassByReferenceDatatypes) {
if(value is IdentifierReference) {
val addr = AddressOf(value, Position.DUMMY)

View File

@ -54,14 +54,8 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
asmgen.out("+\tdec ${'$'}ffff\t; modified")
}
else -> {
asmgen.translateExpression(addressExpr) // todo directly into AY?
asmgen.out("""
inx
lda P8ESTACK_LO,x
sta (+) + 1
lda P8ESTACK_HI,x
sta (+) + 2
""")
asmgen.assignExpressionToRegister(addressExpr, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
if(incr)
asmgen.out("+\tinc ${'$'}ffff\t; modified")
else

View File

@ -68,12 +68,18 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
// constant array index value
val indexValue = value.indexer.constIndex()!! * elementDt.memorySize()
when (elementDt) {
in ByteDatatypes ->
asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | dex")
in WordDatatypes ->
asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | lda $arrayVarName+$indexValue+1 | sta P8ESTACK_HI,x | dex")
DataType.FLOAT ->
asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr floats.push_float")
in ByteDatatypes -> {
asmgen.out(" lda $arrayVarName+$indexValue")
assignRegisterByte(assign.target, CpuRegister.A)
}
in WordDatatypes -> {
asmgen.out(" lda $arrayVarName+$indexValue | ldy $arrayVarName+$indexValue+1")
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
}
DataType.FLOAT -> {
asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue")
assignFloatFromAY(assign.target)
}
else ->
throw AssemblyError("weird array type")
}
@ -81,11 +87,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
when (elementDt) {
in ByteDatatypes -> {
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
asmgen.out(" lda $arrayVarName,y | sta P8ESTACK_LO,x | dex")
asmgen.out(" lda $arrayVarName,y")
assignRegisterByte(assign.target, CpuRegister.A)
}
in WordDatatypes -> {
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
asmgen.out(" lda $arrayVarName,y | sta P8ESTACK_LO,x | lda $arrayVarName+1,y | sta P8ESTACK_HI,x | dex")
asmgen.out(" lda $arrayVarName,y | pha | lda $arrayVarName+1,y | tay | pla")
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
}
DataType.FLOAT -> {
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.A)
@ -95,13 +103,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
adc #<$arrayVarName
bcc +
iny
+ jsr floats.push_float""")
+""")
assignFloatFromAY(assign.target)
}
else ->
throw AssemblyError("weird array elt type")
}
}
assignStackValue(assign.target)
}
SourceStorageKind.MEMORY -> {
val value = assign.source.memory!!
@ -114,8 +122,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
}
else -> {
asmgen.translateExpression(value.addressExpression) // TODO directly into AY
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | inx")
asmgen.assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope)
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
assignRegisterByte(assign.target, CpuRegister.A)
}
}
@ -200,8 +208,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
else -> {
// everything else just evaluate via the stack.
// TODO byte and word values not via stack but via A / AY registers?
// Everything else just evaluate via the stack.
// (we can't use the assignment helper functions to do it via registers here,
// because the code here is the implementation of exactly that...)
asmgen.translateExpression(value)
if(assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
asmgen.signExtendStackLsb(assign.source.datatype)
@ -254,6 +263,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
when(value) {
is IdentifierReference -> {
if(target.kind==TargetStorageKind.VARIABLE) {
val sourceDt = value.inferType(program).typeOrElse(DataType.STRUCT)
if (sourceDt != DataType.STRUCT)
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), sourceDt, origAssign.source.expression!!)
}
}
is PrefixExpression -> {}
is BinaryExpression -> {}
is ArrayIndexedExpression -> {}
@ -263,16 +279,134 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
else -> {
// TODO optimize the others further?
if(this.asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used for typecast: into $targetDt at ${value.position}")
println("warning: slow stack evaluation used for typecast: $value into $targetDt at ${value.position}")
}
}
// give up, do it via eval stack
// TODO byte and word values not via stack but directly via A or AY registers?
asmgen.translateExpression(origAssign.source.expression!!)
assignStackValue(target)
}
private fun assignTypeCastedIdentifier(targetAsmVarName: String, targetDt: DataType,
sourceAsmVarName: String, sourceDt: DataType,
origExpr: Expression) {
if(sourceDt == targetDt)
throw AssemblyError("typecast to identical value")
// also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression)
when(sourceDt) {
DataType.UBYTE -> {
when(targetDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
}
DataType.UWORD, DataType.WORD -> {
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName+1")
else
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
}
DataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldy $sourceAsmVarName
jsr floats.cast_from_ub""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.BYTE -> {
when(targetDt) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
}
DataType.UWORD, DataType.WORD -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
asmgen.signExtendVariableLsb(targetAsmVarName, DataType.BYTE)
}
DataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $sourceAsmVarName
jsr floats.cast_from_b""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.UWORD -> {
when(targetDt) {
DataType.BYTE, DataType.UBYTE -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
}
DataType.WORD, DataType.UWORD -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
}
DataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $sourceAsmVarName
ldy $sourceAsmVarName+1
jsr floats.cast_from_uw""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.WORD -> {
when(targetDt) {
DataType.BYTE, DataType.UBYTE -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
}
DataType.WORD, DataType.UWORD -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
}
DataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda $sourceAsmVarName
ldy $sourceAsmVarName+1
jsr floats.cast_from_w""")
}
else -> throw AssemblyError("weird type")
}
}
DataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
ldy #>$targetAsmVarName
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda #<$sourceAsmVarName
ldy #>$sourceAsmVarName""")
when(targetDt) {
DataType.UBYTE -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName")
DataType.BYTE -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName")
DataType.UWORD -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1")
DataType.WORD -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1")
else -> throw AssemblyError("weird type")
}
}
DataType.STR -> {
if (targetDt != DataType.UWORD && targetDt == DataType.STR)
throw AssemblyError("cannot typecast a string into another incompatitble type")
}
else -> throw AssemblyError("weird type")
}
}
private fun assignStackValue(target: AsmAssignTarget) {
when(target.kind) {
TargetStorageKind.VARIABLE -> {
@ -600,6 +734,39 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun assignFloatFromAY(target: AsmAssignTarget) {
when(target.kind) {
TargetStorageKind.VARIABLE -> {
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<${target.asmVarname}
ldy #>${target.asmVarname}
jsr floats.copy_float""")
}
TargetStorageKind.ARRAY -> {
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<${target.asmVarname}
ldy #>${target.asmVarname}
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1""")
if(target.array!!.indexer.indexNum!=null) {
val index = target.array.indexer.constIndex()!!
asmgen.out(" lda #$index")
} else {
val asmvarname = asmgen.asmVariableName(target.array.indexer.indexVar!!)
asmgen.out(" lda $asmvarname")
}
asmgen.out(" jsr floats.set_array_float")
}
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to mem byte")
TargetStorageKind.REGISTER -> throw AssemblyError("can't assign float to register")
TargetStorageKind.STACK -> asmgen.out(" jsr floats.push_float")
}
}
private fun assignVariableFloat(target: AsmAssignTarget, sourceName: String) {
when(target.kind) {
TargetStorageKind.VARIABLE -> {
@ -1242,17 +1409,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg)
}
else -> {
asmgen.out(" lda $ldaInstructionArg | pha")
asmgen.translateExpression(addressExpr) // TODO directly into AY
asmgen.out("""
inx
lda P8ESTACK_LO,x
sta P8ZP_SCRATCH_W2
lda P8ESTACK_HI,x
sta P8ZP_SCRATCH_W2+1
ldy #0
pla
sta (P8ZP_SCRATCH_W2),y""")
asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.out(" ldy #0 | lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2),y")
}
}
}
@ -1276,17 +1434,31 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
else -> {
asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()!!)
asmgen.translateExpression(addressExpr) // TODO directly into AY
asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
asmgen.restoreRegister(CpuRegister.A, false)
asmgen.out("""
inx
ldy P8ESTACK_LO,x
sty P8ZP_SCRATCH_W2
ldy P8ESTACK_HI,x
sty P8ZP_SCRATCH_W2+1
ldy #0
sta (P8ZP_SCRATCH_W2),y""")
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
}
}
}
internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair) {
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(register, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, expr.position)
translateNormalAssignment(assign)
}
internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) {
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, scope, variableAsmName = asmVarName)
val assign = AsmAssignment(src, tgt, false, expr.position)
translateNormalAssignment(assign)
}
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair) {
val tgt = AsmAssignTarget.fromRegisters(register, null, program, asmgen)
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName)
val assign = AsmAssignment(src, tgt, false, Position.DUMMY)
translateNormalAssignment(assign)
}
}

View File

@ -171,20 +171,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
is IdentifierReference -> {
val pointer = memory.addressExpression as IdentifierReference
when {
valueLv != null -> inplaceModification_byte_litval_to_memory(pointer, operator, valueLv.toInt())
ident != null -> inplaceModification_byte_variable_to_memory(pointer, operator, ident)
valueLv != null -> inplaceModification_byte_litval_to_pointer(pointer, operator, valueLv.toInt())
ident != null -> inplaceModification_byte_variable_to_pointer(pointer, operator, ident)
// TODO more specialized code for types such as memory read etc.
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_byte_value_to_memory(pointer, operator, value)
inplaceModification_byte_value_to_pointer(pointer, operator, value)
}
else -> inplaceModification_byte_value_to_memory(pointer, operator, value)
else -> inplaceModification_byte_value_to_pointer(pointer, operator, value)
}
}
else -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (1): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO optimize...
asmgen.translateExpression(memory.addressExpression)
asmgen.translateExpression(memory.addressExpression) // TODO directly into P8ZP_SCRATCH_W2?
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1")
val zp = CompilationTarget.instance.machine.zeropage
when {
@ -227,15 +227,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
return false
}
private fun inplaceModification_byte_value_to_memory(pointervar: IdentifierReference, operator: String, value: Expression) {
private fun inplaceModification_byte_value_to_pointer(pointervar: IdentifierReference, operator: String, value: Expression) {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (3): @(${pointervar.nameInSource.last()}) $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar)
when (operator) {
// note: ** (power) operator requires floats.
"+" -> asmgen.out(" clc | adc P8ESTACK_LO+1,x")
"-" -> asmgen.out(" sec | sbc P8ESTACK_LO+1,x")
"+" -> asmgen.out(" clc | adc P8ESTACK_LO+1,x")
"-" -> asmgen.out(" sec | sbc P8ESTACK_LO+1,x")
"*" -> asmgen.out(" pha | lda P8ESTACK_LO+1,x | tay | pla | jsr math.multiply_bytes | ldy #0")
"/" -> asmgen.out(" pha | lda P8ESTACK_LO+1,x | tay | pla | jsr math.divmod_ub_asm | tya | ldy #0")
"%" -> asmgen.out(" pha | lda P8ESTACK_LO+1,x | tay | pla | jsr math.divmod_ub_asm | ldy #0")
@ -279,14 +279,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" inx")
}
private fun inplaceModification_byte_variable_to_memory(pointervar: IdentifierReference, operator: String, value: IdentifierReference) {
private fun inplaceModification_byte_variable_to_pointer(pointervar: IdentifierReference, operator: String, value: IdentifierReference) {
val otherName = asmgen.asmVariableName(value)
val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar)
when (operator) {
// note: ** (power) operator requires floats.
"+" -> asmgen.out(" clc | adc $otherName")
"-" -> asmgen.out(" sec | sbc $otherName")
"+" -> asmgen.out(" clc | adc $otherName")
"-" -> asmgen.out(" sec | sbc $otherName")
"*" -> asmgen.out(" ldy $otherName | jsr math.multiply_bytes | ldy #0")
"/" -> asmgen.out(" ldy $otherName | jsr math.divmod_ub_asm | tya | ldy #0")
"%" -> asmgen.out(" ldy $otherName | jsr math.divmod_ub_asm | ldy #0")
@ -319,7 +319,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
}
private fun inplaceModification_byte_litval_to_memory(pointervar: IdentifierReference, operator: String, value: Int) {
private fun inplaceModification_byte_litval_to_pointer(pointervar: IdentifierReference, operator: String, value: Int) {
when (operator) {
// note: ** (power) operator requires floats.
"+" -> {
@ -420,30 +420,36 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) {
// this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow).
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (5): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
when (operator) {
// note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name")
"*" -> asmgen.out(" lda P8ESTACK_LO+1,x | ldy $name | jsr math.multiply_bytes | sta $name")
"+" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" clc | adc $name | sta $name")
}
"-" -> {
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", dt, null)
asmgen.out(" lda $name | sec | sbc P8ZP_SCRATCH_B1 | sta $name")
}
"*" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" ldy $name | jsr math.multiply_bytes | sta $name")
}
"/" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
if(dt==DataType.UBYTE)
asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_ub_asm | sty $name")
asmgen.out(" lda $name | jsr math.divmod_ub_asm | sty $name")
else
asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_b_asm | sty $name")
asmgen.out(" lda $name | jsr math.divmod_b_asm | sty $name")
}
"%" -> {
if(dt==DataType.BYTE)
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
asmgen.out(" lda P8ESTACK_LO+1,x | tay | lda $name | jsr math.divmod_ub_asm | sta $name")
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
asmgen.out(" lda $name | jsr math.divmod_ub_asm | sta $name")
}
"<<" -> {
asmgen.translateExpression(value) // todo directly into Y
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
asmgen.out("""
inx
ldy P8ESTACK_LO,x
beq +
- asl $name
dey
@ -451,11 +457,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
+""")
}
">>" -> {
asmgen.translateExpression(value) // todo directly into Y
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
if(dt==DataType.UBYTE) {
asmgen.out("""
inx
ldy P8ESTACK_LO,x
beq +
- lsr $name
dey
@ -463,8 +467,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
+""")
} else {
asmgen.out("""
inx
ldy P8ESTACK_LO,x
beq +
- lda $name
asl a
@ -474,12 +476,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
+""")
}
}
"&" -> asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name")
"^" -> asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name")
"|" -> asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name")
"&" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" and $name | sta $name")
}
"^" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" eor $name | sta $name")
}
"|" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" ora $name | sta $name")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
asmgen.out(" inx")
}
private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) {
@ -1100,15 +1110,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceModification_word_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) {
// this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow).
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
val valueiDt = value.inferType(program)
if(!valueiDt.isKnown)
throw AssemblyError("unknown dt")
val valueDt = valueiDt.typeOrElse(DataType.STRUCT)
// TODO can use registers instead of stack value?
fun multiplyWord() {
asmgen.out("""
lda P8ESTACK_LO+1,x
@ -1125,6 +1133,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
""")
}
// TODO can use registers instead of stack value?
fun divideWord() {
if (dt == DataType.WORD) {
asmgen.out("""
@ -1153,6 +1162,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
// TODO can use registers instead of stack value?
fun remainderWord() {
if(dt==DataType.WORD)
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
@ -1177,6 +1187,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when (operator) {
// note: ** (power) operator requires floats.
"+" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
if(valueDt==DataType.UBYTE)
asmgen.out("""
lda $name
@ -1198,8 +1211,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
tya
adc $name+1
sta $name+1""")
asmgen.out(" inx")
}
"-" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
if(valueDt==DataType.UBYTE)
asmgen.out("""
lda $name
@ -1223,25 +1240,38 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
lda $name+1
sbc P8ZP_SCRATCH_B1
sta $name+1""")
asmgen.out(" inx")
}
"*" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.signExtendStackLsb(valueDt)
multiplyWord()
asmgen.out(" inx")
}
"/" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.signExtendStackLsb(valueDt)
divideWord()
asmgen.out(" inx")
}
"%" -> {
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.signExtendStackLsb(valueDt)
remainderWord()
asmgen.out(" inx")
}
"<<" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
asmgen.out("""
ldy P8ESTACK_LO+1,x
beq +
- asl $name
rol $name+1
@ -1250,18 +1280,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
+""")
}
">>" -> {
if(dt==DataType.UWORD) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
if(dt==DataType.UWORD)
asmgen.out("""
ldy P8ESTACK_LO+1,x
beq +
- lsr $name+1
ror $name
dey
bne -
+""") }
else {
+""")
else
asmgen.out("""
ldy P8ESTACK_LO+1,x
beq +
- lda $name+1
asl a
@ -1270,15 +1299,21 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
dey
bne -
+""")
}
}
"&" -> {
asmgen.out(" lda P8ESTACK_LO+1,x | and $name | sta $name")
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" and $name | sta $name")
if(dt in WordDatatypes)
asmgen.out(" lda #0 | sta $name+1")
}
"^" -> asmgen.out(" lda P8ESTACK_LO+1,x | eor $name | sta $name")
"|" -> asmgen.out(" lda P8ESTACK_LO+1,x | ora $name | sta $name")
"^" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" eor $name | sta $name")
}
"|" -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
asmgen.out(" ora $name | sta $name")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
@ -1286,24 +1321,63 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// the value is a proper 16-bit word, so use both bytes of it.
when (operator) {
// note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name | lda $name+1 | adc P8ESTACK_HI+1,x | sta $name+1")
"-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name | lda $name+1 | sbc P8ESTACK_HI+1,x | sta $name+1")
"*" -> multiplyWord()
"/" -> divideWord()
"%" -> remainderWord()
"+" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | clc | adc P8ESTACK_LO+1,x | sta $name | lda $name+1 | adc P8ESTACK_HI+1,x | sta $name+1 | inx")
}
"-" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name | lda $name+1 | sbc P8ESTACK_HI+1,x | sta $name+1 | inx")
}
"*" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
multiplyWord()
asmgen.out(" inx")
}
"/" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
divideWord()
asmgen.out(" inx")
}
"%" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
remainderWord()
asmgen.out(" inx")
}
"<<", ">>" -> throw AssemblyError("shift by a word value not supported, max is a byte")
"&" -> asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name | lda $name+1 | and P8ESTACK_HI+1,x | sta $name+1")
"^" -> asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name | lda $name+1 | eor P8ESTACK_HI+1,x | sta $name+1")
"|" -> asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | lda $name+1 | ora P8ESTACK_HI+1,x | sta $name+1")
"&" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | and P8ESTACK_LO+1,x | sta $name | lda $name+1 | and P8ESTACK_HI+1,x | sta $name+1 | inx")
}
"^" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | eor P8ESTACK_LO+1,x | sta $name | lda $name+1 | eor P8ESTACK_HI+1,x | sta $name+1 | inx")
}
"|" -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value)
asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | lda $name+1 | ora P8ESTACK_HI+1,x | sta $name+1 | inx")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
else -> {
throw AssemblyError("can only use integer datatypes here")
}
else -> throw AssemblyError("can only use integer datatypes here")
}
asmgen.out(" inx")
}
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine) {
@ -1592,16 +1666,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
}
else -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (6): ${mem.addressExpression::class.simpleName} at ${mem.addressExpression.position}") // TODO
asmgen.translateExpression(mem.addressExpression)
asmgen.assignExpressionToVariable(mem.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, target.scope)
asmgen.out("""
jsr prog8_lib.read_byte_from_address_on_stack
ldy #0
lda (P8ZP_SCRATCH_W2),y
beq +
lda #1
+ eor #1
jsr prog8_lib.write_byte_to_address_on_stack
inx""")
sta (P8ZP_SCRATCH_W2),y""")
}
}
}
@ -1662,14 +1734,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
}
else -> {
if(asmgen.options.slowCodegenWarnings)
println("warning: slow stack evaluation used (7): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO
asmgen.translateExpression(memory.addressExpression)
asmgen.assignExpressionToVariable(memory.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, target.scope)
asmgen.out("""
jsr prog8_lib.read_byte_from_address_on_stack
ldy #0
lda (P8ZP_SCRATCH_W2),y
eor #255
jsr prog8_lib.write_byte_to_address_on_stack
inx""")
sta (P8ZP_SCRATCH_W2),y""")
}
}
}

View File

@ -130,9 +130,9 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("lsb" , true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x and 255 }},
FSignature("msb" , true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x ushr 8 and 255}},
FSignature("mkword" , true, listOf(FParam("msb", setOf(DataType.UBYTE)), FParam("lsb", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword),
FSignature("rnd" , true, emptyList(), DataType.UBYTE),
FSignature("rndw" , true, emptyList(), DataType.UWORD),
FSignature("rndf" , true, emptyList(), DataType.FLOAT),
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
FSignature("rndw" , false, emptyList(), DataType.UWORD),
FSignature("rndf" , false, emptyList(), DataType.FLOAT),
FSignature("exit" , false, listOf(FParam("returnvalue", setOf(DataType.UBYTE))), null),
FSignature("rsave" , false, emptyList(), null),
FSignature("rrestore" , false, emptyList(), null),

View File

@ -79,7 +79,7 @@ X = BinExpr X = LeftExpr
expr is IdentifierReference || expr is NumericLiteralValue || expr is AddressOf || expr is DirectMemoryRead || expr is StringLiteralValue || expr is ArrayLiteralValue || expr is RangeExpr
private fun isSimpleTarget(target: AssignTarget, namespace: INameScope) =
if (target.identifier!=null || target.memoryAddress!=null || target.arrayindexed!=null)
if (target.identifier!=null || target.memoryAddress!=null)
target.isInRegularRAM(namespace)
else
false

View File

@ -93,6 +93,8 @@ Almost instant compilation times (less than a second) can be achieved when using
Start the compiler with the ``-watch`` argument to enable this.
It will compile your program and then instead of exiting, it waits for any changes in the module source files.
As soon as a change happens, the program gets compiled again.
It is possible to use the watch mode with multiple modules as well, but it will
recompile everything in that list even if only of the files got updated.
Other options
^^^^^^^^^^^^^

View File

@ -143,14 +143,17 @@ Required tools
`64tass <https://sourceforge.net/projects/tass64/>`_ - cross assembler. Install this on your shell path.
It's very easy to compile yourself.
A recent precompiled .exe for Windows can be obtained from my `clone <https://github.com/irmen/64tass/releases>`_ of this project.
*You need at least version 1.55.2257 of this assembler to correctly use the breakpoints feature.*
It's possible to use older versions, but it is very likely that the automatic Vice breakpoints won't work with them.
A **Java runtime (jre or jdk), version 8 or newer** is required to run the prog8 compiler itself.
If you're scared of Oracle's licensing terms, most Linux distributions ship OpenJDK instead.
Fnd for Windows it's possible to get that as well. Check out `AdoptOpenJDK <https://adoptopenjdk.net/>`_ .
If you're scared of Oracle's licensing terms, most Linux distributions ship OpenJDK in their packages repository instead.
For Windows it's possible to get that as well; check out `AdoptOpenJDK <https://adoptopenjdk.net/>`_ .
For MacOS you can use the Homebrew system to install a recent version of OpenJDK.
Finally: a **C-64 emulator** (or a real C-64 ofcourse) can be nice to test and run your programs on.
The compiler assumes the presence of the `Vice emulator <http://vice-emu.sourceforge.net/>`_.
If you're targeting the CommanderX16, there's the `x16emu <https://github.com/commanderx16/x16-emulator>`_.
Finally: an **emulator** (or a real machine ofcourse) to test and run your programs on.
In C64 mode, thhe compiler assumes the presence of the `Vice emulator <http://vice-emu.sourceforge.net/>`_.
If you're targeting the CommanderX16 instead, there's the `x16emu <https://github.com/commanderx16/x16-emulator>`_.
.. important::
**Building the compiler itself:** (*Only needed if you have not downloaded a pre-built 'fat-jar'*)

View File

@ -2,7 +2,6 @@
TODO
====
- 64tass doesn't output all labels anymore in the vice-mon-list, so %breakpoint labels are no longer present....
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
- see if we can group some errors together for instance the (now single) errors about unidentified symbols

View File

@ -1,6 +1,7 @@
%import textio
%import floats
%import syslib
%import test_stack
%zeropage basicsafe
main {
@ -11,7 +12,7 @@ main {
integers()
floatingpoint()
testX()
test_stack.test()
}
sub rotations() {
@ -251,8 +252,7 @@ main {
txt.chrout('\n')
txt.chrout('\n')
testX()
test_stack.test()
}
@ -324,7 +324,7 @@ main {
txt.print(result)
txt.chrout('\n')
testX()
test_stack.test()
}
@ -643,7 +643,7 @@ main {
reverse(uwarr)
reverse(warr)
testX()
test_stack.test()
}
sub floatingpoint() {
@ -831,36 +831,6 @@ main {
floats.print_f(fl)
txt.chrout('\n')
testX()
}
asmsub testX() {
%asm {{
stx _saveX
lda #13
jsr txt.chrout
lda #'x'
jsr txt.chrout
lda #'='
jsr txt.chrout
lda _saveX
jsr txt.print_ub
lda #' '
jsr txt.chrout
lda #'s'
jsr txt.chrout
lda #'p'
jsr txt.chrout
lda #'='
jsr txt.chrout
tsx
txa
jsr txt.print_ub
lda #13
jsr txt.chrout
ldx _saveX
rts
_saveX .byte 0
}}
test_stack.test()
}
}

View File

@ -1,6 +1,7 @@
%target c64
%import syslib
%import textio
%import test_stack
%zeropage basicsafe
main {
@ -23,6 +24,9 @@ main {
ubyte upwards = true
repeat {
;txt.plot(0,0)
;test_stack.test()
ubyte mountain = 223 ; slope upwards
if active_height < target_height {
active_height++

103
examples/balls.p8 Normal file
View File

@ -0,0 +1,103 @@
%import textio
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
main {
sub start() {
str input = ".........."
ubyte ballCount
ubyte[255] BX
ubyte[255] BY
ubyte[255] BC
ubyte[255] DX
ubyte[255] DY
txt.print("number of balls (1-255)? ")
void txt.input_chars(input)
ballCount = conv.str2ubyte(input)
txt.fill_screen(81, 0)
; Setup Starting Ball Positions
ubyte lp
for lp in 0 to ballCount-1 {
BX[lp] = rnd() % txt.DEFAULT_WIDTH
BY[lp] = rnd() % txt.DEFAULT_HEIGHT
BC[lp] = rnd() & 15
DX[lp] = rnd() & 1
DY[lp] = rnd() & 1
void rnd()
}
; start clock
c64.SETTIM(0,0,0)
; display balls
uword frame
for frame in 0 to 999 {
; Loop though all balls clearing current spot and setting new spot
for lp in 0 to ballCount-1 {
; Clear existing Location the ball is at
txt.setclr(BX[lp], BY[lp], 0)
if DX[lp] == 0 {
if (BX[lp] == 0)
{
DX[lp] = 1
} else {
BX[lp]=BX[lp]-1
}
} else if DX[lp] == 1 {
if (BX[lp] == txt.DEFAULT_WIDTH-1)
{
BX[lp] = txt.DEFAULT_WIDTH-2
DX[lp] = 0
} else {
BX[lp]=BX[lp]+1
}
}
if DY[lp] == 0 {
if (BY[lp] == 0)
{
DY[lp] = 1
} else {
BY[lp]=BY[lp]-1
}
} else if DY[lp] == 1 {
if (BY[lp] == txt.DEFAULT_HEIGHT-1)
{
BY[lp] = txt.DEFAULT_HEIGHT-2
DY[lp] = 0
} else {
BY[lp]=BY[lp]+1
}
}
; Put the new ball possition
txt.setclr(BX[lp], BY[lp], BC[lp])
}
;txt.plot(0,0)
;txt.print_uw(frame)
}
; read clock
uword jiffies
%asm {{
stx P8ZP_SCRATCH_REG
jsr c64.RDTIM
sta jiffies
stx jiffies+1
ldx P8ZP_SCRATCH_REG
}}
txt.print("\nbenchmark: ")
txt.print_uw(jiffies)
txt.print(" jiffies for 1000 frames.\n")
; test_stack.test()
}
}

Binary file not shown.

BIN
examples/compiled/balls.prg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,6 @@
%import floats
%import textio
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
@ -41,6 +42,8 @@ main {
txt.print(" jiffies/fr = ")
txt.print_ub(60/timer_jiffies)
txt.print(" fps")
;test_stack.test()
}
}

View File

@ -1,5 +1,6 @@
%import syslib
%import graphics
%import test_stack
; Note: this program is compatible with C64 and CX16.
@ -37,6 +38,8 @@ main {
anglez+=452
wait_a_little_bit()
; test_stack.test()
}
}

View File

@ -1,6 +1,7 @@
%target c64
%import syslib
%import textio
%import test_stack
spritedata $2000 {
; this memory block contains the sprite data
@ -95,6 +96,8 @@ main {
txt.print(" jiffies/fr = ")
txt.print_ub(60/c64.TIME_LO)
txt.print(" fps")
; test_stack.test()
}
}

View File

@ -1,5 +1,6 @@
%target c64
%import syslib
%import test_stack
%import textio
main {
@ -33,6 +34,8 @@ main {
txt.print_ub(60/c64.TIME_LO)
txt.print(" fps")
c64.TIME_LO=0
; test_stack.test()
}
}

View File

@ -1,5 +1,6 @@
%target cx16
%import syslib
%import test_stack
%import conv
; TODO add all other Elite's ships, show their name, advance to next ship on keypress
@ -41,6 +42,8 @@ main {
anglex += 217
angley -= 505
anglez += 452
; test_stack.test()
}
}

View File

@ -1,4 +1,5 @@
%import graphics
%import test_stack
; Note: this program is compatible with C64 and CX16.
@ -6,8 +7,13 @@ main {
sub start() {
graphics.enable_bitmap_mode()
draw_lines()
draw_circles()
; graphics.disable_bitmap_mode()
; test_stack.test()
repeat {
}
}

View File

@ -1,5 +1,6 @@
%import textio
%import syslib
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
@ -40,6 +41,8 @@ main {
rect(10, 10, 10, 10, false)
rect(6, 0, 16, 20, true)
; test_stack.test()
sub rect(ubyte x1, ubyte y1, ubyte x2, ubyte y2, ubyte fill) {
ubyte x

View File

@ -1,5 +1,6 @@
%import graphics
%import floats
%import test_stack
%zeropage floatsafe
; Draw a mandelbrot in graphics mode (the image will be 256 x 200 pixels).
@ -44,6 +45,8 @@ main {
}
}
; test_stack.test()
repeat {
}
}

View File

@ -1,5 +1,6 @@
%import textio
%import floats
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
@ -57,5 +58,7 @@ main {
txt.print("finished in ")
floats.print_f(duration)
txt.print(" seconds!\n")
; test_stack.test()
}
}

View File

@ -1,5 +1,6 @@
%import textio
%import conv
%import test_stack
%zeropage basicsafe
; The classic number guessing game.
@ -59,6 +60,8 @@ main {
txt.print("Thanks for playing, ")
txt.print(name)
txt.print(".\n")
; test_stack.test()
}
}
}

View File

@ -1,5 +1,6 @@
%target c64
%import syslib
%import test_stack
%import textio
; converted from plasma test program for cc65.
@ -26,7 +27,7 @@ main {
; ubyte v = c64.VMCSB
c64.CIA2PRA = (block & $FC) | (lsb(SCREEN1 >> 14) ^ $03)
repeat {
repeat 100 {
doplasma(SCREEN1)
c64.VMCSB = PAGE1
doplasma(SCREEN2)
@ -37,6 +38,9 @@ main {
;c64.VMCSB = v
;c64.CIA2PRA = block
;txt.print("done!\n")
;test_stack.test()
;repeat {
;}
}
; several variables outside of doplasma to make them retain their value

View File

@ -1,4 +1,5 @@
%import textio
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
@ -26,6 +27,8 @@ main {
txt.print("number of primes (expected 54): ")
txt.print_ub(amount)
txt.chrout('\n')
; test_stack.test()
}

View File

@ -1,4 +1,5 @@
%import textio
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
@ -31,6 +32,7 @@ main {
txt.print("reversed\n")
print_arrays()
;test_stack.test()
return

View File

@ -10,6 +10,7 @@
%target c64
%import syslib
%import textio
%import test_stack
main {
@ -67,6 +68,9 @@ waitkey:
}
drawScore()
; txt.plot(0,0)
; test_stack.test()
}
ubyte key=c64.GETIN()

View File

@ -1,51 +1,48 @@
%import textio
%import floats
%import syslib
%zeropage basicsafe
%import test_stack
main {
sub start() {
str s1 = "irmen"
str s2 = "hello"
ubyte[] ubarray = [1,2,3,4]
byte[] barray = [1,2,3,4]
uword[] uwarray = [1,2,3,4]
word[] warray = [1,2,3,4]
float[] farray = [1.1,2.2,3.3,4.4]
; byte c = strcmp(s1, s2)
; txt.print_b(c)
; txt.chrout('\n')
txt.print_ub(s1<=s2)
ubyte ub
byte bb
uword uw
word ww
float fl
const ubyte i = 2
const ubyte j = 3
ub = ubarray[i]
txt.print_ub(ub)
txt.chrout('\n')
testX()
}
bb = barray[i]
txt.print_b(bb)
txt.chrout('\n')
asmsub testX() {
%asm {{
stx _saveX
lda #13
jsr txt.chrout
lda #'x'
jsr txt.chrout
lda #'='
jsr txt.chrout
lda _saveX
jsr txt.print_ub
lda #' '
jsr txt.chrout
lda #'s'
jsr txt.chrout
lda #'p'
jsr txt.chrout
lda #'='
jsr txt.chrout
tsx
txa
jsr txt.print_ub
lda #13
jsr txt.chrout
ldx _saveX
rts
_saveX .byte 0
}}
uw = uwarray[i]
txt.print_uw(uw)
txt.chrout('\n')
ww = warray[i]
txt.print_w(ww)
txt.chrout('\n')
fl = farray[i]
floats.print_f(fl)
txt.chrout('\n')
test_stack.test()
txt.chrout('\n')
}
}

View File

@ -1,4 +1,5 @@
%import textio
%import test_stack
%zeropage basicsafe
; Note: this program is compatible with C64 and CX16.
@ -963,6 +964,9 @@ main {
txt.print("ok\n")
else
txt.print("fail!!!\n")
test_stack.test()
}
sub wait_input() {

View File

@ -1,6 +1,7 @@
%import textio
%import conv
%import diskio
%import test_stack
%option no_sysinit
%zeropage basicsafe
@ -26,6 +27,8 @@ main {
planet.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util.print_10s(ship.cash)
@ -981,19 +984,4 @@ util {
}}
}
asmsub testX() {
%asm {{
stx _saveX
lda #13
jsr txt.chrout
lda _saveX
jsr txt.print_ub
lda #13
jsr txt.chrout
ldx _saveX
rts
_saveX .byte 0
}}
}
}

View File

@ -1,6 +1,7 @@
%target c64
%import floats
%import graphics
%import test_stack
%zeropage floatsafe
main {
@ -18,6 +19,8 @@ main {
turtle.rt(94)
}
; test_stack.test()
repeat {
}
}
@ -46,7 +49,7 @@ turtle {
uword xx = xpos as uword
c64.SPXY[0] = lsb(xx) + 12
c64.MSIGX = msb(xx) > 0
c64.SPXY[1] = ypos as ubyte + 40
c64.SPXY[1] = ypos as ubyte + 37
}
sub pos(float x, float y) {