mirror of
https://github.com/irmen/prog8.git
synced 2025-06-15 18:23:35 +00:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
d9a8cfed8c | |||
122796fbba | |||
510ca042c9 | |||
125f6205f2 | |||
8136f3df5c | |||
38d06a7e94 | |||
49db10539a | |||
8efe4c6267 | |||
04d8bb8fbf | |||
08aa13c90c | |||
d1febc0208 | |||
5980e58ac6 | |||
e1dc283d4b | |||
8be234973c | |||
7def8ff2cd | |||
340b1c2e42 | |||
7e0f7ba438 | |||
fefd9b52a8 | |||
afd155ac4f | |||
ee724eb4f1 | |||
2f1f20ea11 | |||
063bcf17d8 | |||
72509eef44 | |||
2da28864e9 | |||
4278f64682 | |||
59ae3c3fcd | |||
7fa21fbdff | |||
e95af7498e | |||
79c75adac1 | |||
d212f69d89 | |||
edf5e69d39 | |||
574eb0d174 | |||
8bd4914e2f | |||
5ebaaff64b | |||
5c9e0c9f51 |
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}}
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
48
compiler/res/prog8lib/test_stack.p8
Normal file
48
compiler/res/prog8lib/test_stack.p8
Normal 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
|
||||
}}
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
5.0
|
||||
5.1
|
||||
|
@ -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 {
|
||||
|
@ -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?
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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""")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
^^^^^^^^^^^^^
|
||||
|
@ -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'*)
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
103
examples/balls.p8
Normal 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
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.
BIN
examples/compiled/cxlogo.prg
Normal file
BIN
examples/compiled/cxlogo.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.
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Reference in New Issue
Block a user