mirror of
https://github.com/irmen/prog8.git
synced 2025-06-17 01:23:34 +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
|
jmp ub2float._fac_to_mem
|
||||||
.pend
|
.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
|
stack_b2float .proc
|
||||||
; -- b2float operating on the stack
|
; -- b2float operating on the stack
|
||||||
inx
|
inx
|
||||||
@ -96,8 +149,8 @@ stack_uw2float .proc
|
|||||||
.pend
|
.pend
|
||||||
|
|
||||||
stack_float2w .proc ; also used for float2b
|
stack_float2w .proc ; also used for float2b
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr pop_float_fac1
|
jsr pop_float_fac1
|
||||||
|
stx P8ZP_SCRATCH_REG
|
||||||
jsr AYINT
|
jsr AYINT
|
||||||
ldx P8ZP_SCRATCH_REG
|
ldx P8ZP_SCRATCH_REG
|
||||||
lda $64
|
lda $64
|
||||||
@ -109,8 +162,8 @@ stack_float2w .proc ; also used for float2b
|
|||||||
.pend
|
.pend
|
||||||
|
|
||||||
stack_float2uw .proc ; also used for float2ub
|
stack_float2uw .proc ; also used for float2ub
|
||||||
stx P8ZP_SCRATCH_REG
|
|
||||||
jsr pop_float_fac1
|
jsr pop_float_fac1
|
||||||
|
stx P8ZP_SCRATCH_REG
|
||||||
jsr GETADR
|
jsr GETADR
|
||||||
ldx P8ZP_SCRATCH_REG
|
ldx P8ZP_SCRATCH_REG
|
||||||
sta P8ESTACK_HI,x
|
sta P8ESTACK_HI,x
|
||||||
@ -327,6 +380,36 @@ neg_f .proc
|
|||||||
rts
|
rts
|
||||||
.pend
|
.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
|
equal_f .proc
|
||||||
; -- are the two mflpt5 numbers on the stack identical?
|
; -- are the two mflpt5 numbers on the stack identical?
|
||||||
inx
|
inx
|
||||||
@ -364,6 +447,40 @@ notequal_f .proc
|
|||||||
rts
|
rts
|
||||||
.pend
|
.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
|
less_f .proc
|
||||||
; -- is f1 < f2?
|
; -- is f1 < f2?
|
||||||
jsr compare_floats
|
jsr compare_floats
|
||||||
|
@ -12,11 +12,20 @@ graphics {
|
|||||||
|
|
||||||
sub enable_bitmap_mode() {
|
sub enable_bitmap_mode() {
|
||||||
; enable bitmap screen, erase it and set colors to black/white.
|
; 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
|
c64.VMCSB = (c64.VMCSB & %11110000) | %00001000 ; $2000-$3fff
|
||||||
clear_screen(1, 0)
|
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) {
|
sub clear_screen(ubyte pixelcolor, ubyte bgcolor) {
|
||||||
memset(BITMAP_ADDRESS, 320*200/8, 0)
|
memset(BITMAP_ADDRESS, 320*200/8, 0)
|
||||||
txt.fill_screen(pixelcolor << 4 | bgcolor, 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
|
; -- 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
|
; 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)
|
; (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 {{
|
%asm {{
|
||||||
jmp str2uword
|
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
|
; -- 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
|
; 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)
|
; (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 {{
|
%asm {{
|
||||||
jmp str2word
|
jmp str2word
|
||||||
}}
|
}}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%target cx16
|
%target cx16
|
||||||
%import syslib
|
%import syslib
|
||||||
|
%import textio
|
||||||
|
|
||||||
; bitmap pixel graphics module for the CommanderX16
|
; bitmap pixel graphics module for the CommanderX16
|
||||||
; wraps the graphics functions that are in ROM.
|
; wraps the graphics functions that are in ROM.
|
||||||
@ -17,6 +18,13 @@ graphics {
|
|||||||
clear_screen(1, 0)
|
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) {
|
sub clear_screen(ubyte pixelcolor, ubyte bgcolor) {
|
||||||
cx16.GRAPH_set_colors(pixelcolor, pixelcolor, bgcolor)
|
cx16.GRAPH_set_colors(pixelcolor, pixelcolor, bgcolor)
|
||||||
cx16.GRAPH_clear()
|
cx16.GRAPH_clear()
|
||||||
|
@ -30,6 +30,7 @@ write_byte_to_address_on_stack .proc
|
|||||||
.pend
|
.pend
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
neg_b .proc
|
neg_b .proc
|
||||||
lda #0
|
lda #0
|
||||||
sec
|
sec
|
||||||
@ -443,6 +444,19 @@ less_b .proc
|
|||||||
bpl equal_b._equal_b_false
|
bpl equal_b._equal_b_false
|
||||||
.pend
|
.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
|
less_uw .proc
|
||||||
lda P8ESTACK_HI+2,x
|
lda P8ESTACK_HI+2,x
|
||||||
cmp P8ESTACK_HI+1,x
|
cmp P8ESTACK_HI+1,x
|
||||||
@ -454,7 +468,29 @@ less_uw .proc
|
|||||||
bcs equal_b._equal_b_false
|
bcs equal_b._equal_b_false
|
||||||
.pend
|
.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
|
less_w .proc
|
||||||
|
; TODO is this word comparison < correct? reg_less_w is a lot larger...
|
||||||
lda P8ESTACK_LO+2,x
|
lda P8ESTACK_LO+2,x
|
||||||
cmp P8ESTACK_LO+1,x
|
cmp P8ESTACK_LO+1,x
|
||||||
lda P8ESTACK_HI+2,x
|
lda P8ESTACK_HI+2,x
|
||||||
@ -496,7 +532,24 @@ lesseq_b .proc
|
|||||||
bpl equal_b._equal_b_false
|
bpl equal_b._equal_b_false
|
||||||
.pend
|
.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
|
lesseq_uw .proc
|
||||||
|
; TODO is this comparison uword <= correct????
|
||||||
lda P8ESTACK_HI+1,x
|
lda P8ESTACK_HI+1,x
|
||||||
cmp P8ESTACK_HI+2,x
|
cmp P8ESTACK_HI+2,x
|
||||||
bcc equal_b._equal_b_false
|
bcc equal_b._equal_b_false
|
||||||
@ -507,7 +560,30 @@ lesseq_uw .proc
|
|||||||
bcc equal_b._equal_b_false
|
bcc equal_b._equal_b_false
|
||||||
.pend
|
.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
|
lesseq_w .proc
|
||||||
|
; TODO is this word compare <= correct? it is different from reg_lesseq_w
|
||||||
lda P8ESTACK_LO+1,x
|
lda P8ESTACK_LO+1,x
|
||||||
cmp P8ESTACK_LO+2,x
|
cmp P8ESTACK_LO+2,x
|
||||||
lda P8ESTACK_HI+1,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)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(watchMode && moduleFiles.size<=1) {
|
if(watchMode) {
|
||||||
val watchservice = FileSystems.getDefault().newWatchService()
|
val watchservice = FileSystems.getDefault().newWatchService()
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
val filepath = pathFrom(moduleFiles.single()).normalize()
|
println("Continuous watch mode active. Modules: $moduleFiles")
|
||||||
println("Continuous watch mode active. Main module: $filepath")
|
val results = mutableListOf<CompilationResult>()
|
||||||
|
for(filepathRaw in moduleFiles) {
|
||||||
try {
|
val filepath = pathFrom(filepathRaw).normalize()
|
||||||
val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, slowCodegenWarnings, compilationTarget, outputPath)
|
val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, slowCodegenWarnings, compilationTarget, outputPath)
|
||||||
|
results.add(compilationResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
val allImportedFiles = results.flatMap { it.importedFiles }
|
||||||
println("Imported files (now watching:)")
|
println("Imported files (now watching:)")
|
||||||
for (importedFile in compilationResult.importedFiles) {
|
for (importedFile in allImportedFiles) {
|
||||||
print(" ")
|
print(" ")
|
||||||
println(importedFile)
|
println(importedFile)
|
||||||
importedFile.parent.register(watchservice, StandardWatchEventKinds.ENTRY_MODIFY)
|
val watchDir = importedFile.parent ?: Path.of(".")
|
||||||
|
watchDir.register(watchservice, StandardWatchEventKinds.ENTRY_MODIFY)
|
||||||
}
|
}
|
||||||
println("[${LocalDateTime.now().withNano(0)}] Waiting for file changes.")
|
println("[${LocalDateTime.now().withNano(0)}] Waiting for file changes.")
|
||||||
|
|
||||||
|
var recompile=false
|
||||||
|
while(!recompile) {
|
||||||
val event = watchservice.take()
|
val event = watchservice.take()
|
||||||
for (changed in event.pollEvents()) {
|
for (changed in event.pollEvents()) {
|
||||||
val changedPath = changed.context() as Path
|
val changedPath = changed.context() as Path
|
||||||
|
if(allImportedFiles.any { it.fileName == changedPath.fileName }) {
|
||||||
println(" change detected: $changedPath")
|
println(" change detected: $changedPath")
|
||||||
|
recompile = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
event.reset()
|
event.reset()
|
||||||
println("\u001b[H\u001b[2J") // clear the screen
|
|
||||||
} catch (x: Exception) {
|
|
||||||
throw x
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println("\u001b[H\u001b[2J") // clear the screen
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,7 +17,7 @@ import kotlin.math.abs
|
|||||||
|
|
||||||
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
||||||
val comparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
val comparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
||||||
val augmentAssignmentOperators = setOf("+", "-", "/", "*", "**", "&", "|", "^", "<<", ">>")
|
val augmentAssignmentOperators = setOf("+", "-", "/", "*", "**", "&", "|", "^", "<<", ">>", "%", "and", "or", "xor")
|
||||||
|
|
||||||
sealed class Expression: Node {
|
sealed class Expression: Node {
|
||||||
abstract fun constValue(program: Program): NumericLiteralValue?
|
abstract fun constValue(program: Program): NumericLiteralValue?
|
||||||
|
@ -14,11 +14,8 @@ import prog8.compiler.target.IAssemblyGenerator
|
|||||||
import prog8.compiler.target.IAssemblyProgram
|
import prog8.compiler.target.IAssemblyProgram
|
||||||
import prog8.compiler.target.c64.AssemblyProgram
|
import prog8.compiler.target.c64.AssemblyProgram
|
||||||
import prog8.compiler.target.c64.Petscii
|
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.AsmAssignment
|
||||||
import prog8.compiler.target.c64.codegen.assignment.AssignmentAsmGen
|
import prog8.compiler.target.c64.codegen.assignment.AssignmentAsmGen
|
||||||
import prog8.compiler.target.c64.codegen.assignment.TargetStorageKind
|
|
||||||
import prog8.compiler.target.generatedLabelPrefix
|
import prog8.compiler.target.generatedLabelPrefix
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import prog8.functions.FSignature
|
import prog8.functions.FSignature
|
||||||
@ -201,11 +198,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
|
|
||||||
private fun assignInitialValueToVar(decl: VarDecl, variableName: List<String>) {
|
private fun assignInitialValueToVar(decl: VarDecl, variableName: List<String>) {
|
||||||
val asmName = asmVariableName(variableName)
|
val asmName = asmVariableName(variableName)
|
||||||
val asgn = AsmAssignment(
|
assignmentAsmGen.assignExpressionToVariable(decl.value!!, asmName, decl.datatype, decl.definingSubroutine())
|
||||||
AsmAssignSource.fromAstSource(decl.value!!, program, this),
|
|
||||||
AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, decl.datatype, decl.definingSubroutine(), variableAsmName = asmName),
|
|
||||||
false, decl.position)
|
|
||||||
assignmentAsmGen.translateNormalAssignment(asgn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var generatedLabelSequenceNumber: Int = 0
|
private var generatedLabelSequenceNumber: Int = 0
|
||||||
@ -752,6 +745,16 @@ internal class AsmGen(private val program: Program,
|
|||||||
internal fun translateNormalAssignment(assign: AsmAssignment) =
|
internal fun translateNormalAssignment(assign: AsmAssignment) =
|
||||||
assignmentAsmGen.translateNormalAssignment(assign)
|
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) {
|
private fun translateSubroutine(sub: Subroutine) {
|
||||||
out("")
|
out("")
|
||||||
outputSourceLine(sub)
|
outputSourceLine(sub)
|
||||||
@ -902,17 +905,16 @@ internal class AsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
translateExpression(stmt.iterations!!) // todo directly into AY?
|
|
||||||
val dt = stmt.iterations!!.inferType(program)
|
val dt = stmt.iterations!!.inferType(program)
|
||||||
if(!dt.isKnown)
|
if(!dt.isKnown)
|
||||||
throw AssemblyError("unknown dt")
|
throw AssemblyError("unknown dt")
|
||||||
when (dt.typeOrElse(DataType.STRUCT)) {
|
when (dt.typeOrElse(DataType.STRUCT)) {
|
||||||
in ByteDatatypes -> {
|
in ByteDatatypes -> {
|
||||||
out(" inx | lda P8ESTACK_LO,x")
|
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.A)
|
||||||
repeatByteCountInA(null, repeatLabel, endLabel, stmt.body)
|
repeatByteCountInA(null, repeatLabel, endLabel, stmt.body)
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
in WordDatatypes -> {
|
||||||
out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x")
|
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.AY)
|
||||||
repeatWordCountInAY(null, repeatLabel, endLabel, stmt.body)
|
repeatWordCountInAY(null, repeatLabel, endLabel, stmt.body)
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid loop expression datatype $dt")
|
else -> throw AssemblyError("invalid loop expression datatype $dt")
|
||||||
@ -1008,16 +1010,16 @@ $counterVar .byte 0""")
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(stmt: WhenStatement) {
|
private fun translate(stmt: WhenStatement) {
|
||||||
expressionsAsmGen.translateExpression(stmt.condition) // TODO directly into AY?
|
|
||||||
val endLabel = makeLabel("choice_end")
|
val endLabel = makeLabel("choice_end")
|
||||||
val choiceBlocks = mutableListOf<Pair<String, AnonymousScope>>()
|
val choiceBlocks = mutableListOf<Pair<String, AnonymousScope>>()
|
||||||
val conditionDt = stmt.condition.inferType(program)
|
val conditionDt = stmt.condition.inferType(program)
|
||||||
if(!conditionDt.isKnown)
|
if(!conditionDt.isKnown)
|
||||||
throw AssemblyError("unknown condition dt")
|
throw AssemblyError("unknown condition dt")
|
||||||
if(conditionDt.typeOrElse(DataType.BYTE) in ByteDatatypes)
|
if(conditionDt.typeOrElse(DataType.BYTE) in ByteDatatypes)
|
||||||
out(" inx | lda P8ESTACK_LO,x")
|
assignExpressionToRegister(stmt.condition, RegisterOrPair.A)
|
||||||
else
|
else
|
||||||
out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x")
|
assignExpressionToRegister(stmt.condition, RegisterOrPair.AY)
|
||||||
|
|
||||||
for(choice in stmt.choices) {
|
for(choice in stmt.choices) {
|
||||||
val choiceLabel = makeLabel("choice")
|
val choiceLabel = makeLabel("choice")
|
||||||
if(choice.values==null) {
|
if(choice.values==null) {
|
||||||
@ -1131,7 +1133,9 @@ $counterVar .byte 0""")
|
|||||||
"%breakpoint" -> {
|
"%breakpoint" -> {
|
||||||
val label = "_prog8_breakpoint_${breakpointLabels.size+1}"
|
val label = "_prog8_breakpoint_${breakpointLabels.size+1}"
|
||||||
breakpointLabels.add(label)
|
breakpointLabels.add(label)
|
||||||
out("$label\tnop")
|
out("""
|
||||||
|
nop
|
||||||
|
$label nop""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1161,16 +1165,12 @@ $counterVar .byte 0""")
|
|||||||
val sub = ret.definingSubroutine()!!
|
val sub = ret.definingSubroutine()!!
|
||||||
val returnType = sub.returntypes.single()
|
val returnType = sub.returntypes.single()
|
||||||
val returnReg = sub.asmReturnvaluesRegisters.single()
|
val returnReg = sub.asmReturnvaluesRegisters.single()
|
||||||
val returnValueTarget =
|
if(returnReg.registerOrPair==null)
|
||||||
when {
|
throw AssemblyError("normal subroutines can't return value in status register directly")
|
||||||
returnReg.registerOrPair!=null -> AsmAssignTarget.fromRegisters(returnReg.registerOrPair, sub, program, this)
|
|
||||||
else -> throw AssemblyError("normal subroutines can't return value in status register directly")
|
|
||||||
}
|
|
||||||
|
|
||||||
when (returnType) {
|
when (returnType) {
|
||||||
in IntegerDatatypes -> {
|
in IntegerDatatypes -> {
|
||||||
val src = AsmAssignSource.fromAstSource(returnvalue, program, this)
|
assignmentAsmGen.assignExpressionToRegister(returnvalue, returnReg.registerOrPair)
|
||||||
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
|
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
// return the float value via FAC1
|
// return the float value via FAC1
|
||||||
@ -1181,7 +1181,7 @@ $counterVar .byte 0""")
|
|||||||
out(" lda #<${asmVar} | ldy #>${asmVar} | jsr floats.MOVFM")
|
out(" lda #<${asmVar} | ldy #>${asmVar} | jsr floats.MOVFM")
|
||||||
}
|
}
|
||||||
else -> {
|
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)
|
translateExpression(returnvalue)
|
||||||
out(" jsr floats.pop_float_fac1")
|
out(" jsr floats.pop_float_fac1")
|
||||||
}
|
}
|
||||||
@ -1190,8 +1190,7 @@ $counterVar .byte 0""")
|
|||||||
else -> {
|
else -> {
|
||||||
// all else take its address and assign that also to AY register pair
|
// all else take its address and assign that also to AY register pair
|
||||||
val addrofValue = AddressOf(returnvalue as IdentifierReference, returnvalue.position)
|
val addrofValue = AddressOf(returnvalue as IdentifierReference, returnvalue.position)
|
||||||
val src = AsmAssignSource.fromAstSource(addrofValue, program, this)
|
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair)
|
||||||
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,8 +179,8 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>): List<Modification> {
|
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
|
// 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>()
|
val mods = mutableListOf<Modification>()
|
||||||
for (pair in linesByFour) {
|
for (pair in linesByFour) {
|
||||||
val first = pair[0].value.trimStart()
|
val first = pair[0].value.trimStart()
|
||||||
|
@ -101,18 +101,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
when(func.name) {
|
when(func.name) {
|
||||||
"memset" -> {
|
"memset" -> {
|
||||||
// use the ROM function of the Cx16
|
// use the ROM function of the Cx16
|
||||||
var src = AsmAssignSource.fromAstSource(fcall.args[0], program, asmgen)
|
asmgen.assignExpressionToVariable(fcall.args[0], "cx16.r0", DataType.UWORD, scope)
|
||||||
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r0")
|
asmgen.assignExpressionToVariable(fcall.args[1], "cx16.r1", DataType.UWORD, scope)
|
||||||
var assign = AsmAssignment(src, tgt, false, Position.DUMMY)
|
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.A)
|
||||||
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)
|
|
||||||
val sub = (fcall as FunctionCallStatement).definingSubroutine()!!
|
val sub = (fcall as FunctionCallStatement).definingSubroutine()!!
|
||||||
asmgen.saveRegister(CpuRegister.X, false, sub)
|
asmgen.saveRegister(CpuRegister.X, false, sub)
|
||||||
asmgen.out(" jsr cx16.memory_fill")
|
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
|
// use the ROM function of the Cx16
|
||||||
var src = AsmAssignSource.fromAstSource(fcall.args[0], program, asmgen)
|
asmgen.assignExpressionToVariable(fcall.args[0], "cx16.r0", DataType.UWORD, scope)
|
||||||
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "cx16.r0")
|
asmgen.assignExpressionToVariable(fcall.args[1], "cx16.r1", DataType.UWORD, scope)
|
||||||
var assign = AsmAssignment(src, tgt, false, Position.DUMMY)
|
asmgen.assignExpressionToVariable(fcall.args[2], "cx16.r2", DataType.UWORD, scope)
|
||||||
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)
|
|
||||||
val sub = (fcall as FunctionCallStatement).definingSubroutine()!!
|
val sub = (fcall as FunctionCallStatement).definingSubroutine()!!
|
||||||
asmgen.saveRegister(CpuRegister.X, false, sub)
|
asmgen.saveRegister(CpuRegister.X, false, sub)
|
||||||
asmgen.out(" jsr cx16.memory_copy")
|
asmgen.out(" jsr cx16.memory_copy")
|
||||||
@ -271,7 +253,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.ror2_array_ub")
|
||||||
}
|
}
|
||||||
is DirectMemoryRead -> {
|
is DirectMemoryRead -> {
|
||||||
@ -279,7 +261,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
val number = (what.addressExpression as NumericLiteralValue).number
|
val number = (what.addressExpression as NumericLiteralValue).number
|
||||||
asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #\$80 |+ | sta ${number.toHex()}")
|
asmgen.out(" lda ${number.toHex()} | lsr a | bcc + | ora #\$80 |+ | sta ${number.toHex()}")
|
||||||
} else {
|
} else {
|
||||||
translateRolRorMemoryArgs(what.addressExpression, fcall)
|
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
|
||||||
asmgen.out(" jsr prog8_lib.ror2_mem_ub")
|
asmgen.out(" jsr prog8_lib.ror2_mem_ub")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,7 +275,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.ror2_array_uw")
|
||||||
}
|
}
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
@ -314,7 +296,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.ror_array_ub")
|
||||||
}
|
}
|
||||||
is DirectMemoryRead -> {
|
is DirectMemoryRead -> {
|
||||||
@ -322,7 +304,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
val number = (what.addressExpression as NumericLiteralValue).number
|
val number = (what.addressExpression as NumericLiteralValue).number
|
||||||
asmgen.out(" ror ${number.toHex()}")
|
asmgen.out(" ror ${number.toHex()}")
|
||||||
} else {
|
} else {
|
||||||
translateRolRorMemoryArgs(what.addressExpression, fcall)
|
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta (+) + 1
|
sta (+) + 1
|
||||||
sty (+) + 2
|
sty (+) + 2
|
||||||
@ -339,7 +321,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.ror_array_uw")
|
||||||
}
|
}
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
@ -360,7 +342,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.rol2_array_ub")
|
||||||
}
|
}
|
||||||
is DirectMemoryRead -> {
|
is DirectMemoryRead -> {
|
||||||
@ -368,7 +350,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
val number = (what.addressExpression as NumericLiteralValue).number
|
val number = (what.addressExpression as NumericLiteralValue).number
|
||||||
asmgen.out(" lda ${number.toHex()} | cmp #\$80 | rol a | sta ${number.toHex()}")
|
asmgen.out(" lda ${number.toHex()} | cmp #\$80 | rol a | sta ${number.toHex()}")
|
||||||
} else {
|
} else {
|
||||||
translateRolRorMemoryArgs(what.addressExpression, fcall)
|
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
|
||||||
asmgen.out(" jsr prog8_lib.rol2_mem_ub")
|
asmgen.out(" jsr prog8_lib.rol2_mem_ub")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,7 +364,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.rol2_array_uw")
|
||||||
}
|
}
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
@ -403,7 +385,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.rol_array_ub")
|
||||||
}
|
}
|
||||||
is DirectMemoryRead -> {
|
is DirectMemoryRead -> {
|
||||||
@ -411,7 +393,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
val number = (what.addressExpression as NumericLiteralValue).number
|
val number = (what.addressExpression as NumericLiteralValue).number
|
||||||
asmgen.out(" rol ${number.toHex()}")
|
asmgen.out(" rol ${number.toHex()}")
|
||||||
} else {
|
} else {
|
||||||
translateRolRorMemoryArgs(what.addressExpression, fcall)
|
asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sta (+) + 1
|
sta (+) + 1
|
||||||
sty (+) + 2
|
sty (+) + 2
|
||||||
@ -428,7 +410,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
when (what) {
|
when (what) {
|
||||||
is ArrayIndexedExpression -> {
|
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")
|
asmgen.out(" jsr prog8_lib.rol_array_uw")
|
||||||
}
|
}
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
@ -442,22 +424,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateRolRorMemoryArgs(addressExpression: Expression, fcall: IFunctionCall) {
|
private fun translateRolRorArrayArgs(arrayvar: IdentifierReference, indexer: ArrayIndex, operation: String, dt: Char) {
|
||||||
val src = AsmAssignSource.fromAstSource(addressExpression, program, asmgen)
|
asmgen.assignExpressionToVariable(AddressOf(arrayvar, arrayvar.position), "prog8_lib.${operation}_array_u${dt}._arg_target", DataType.UWORD, null)
|
||||||
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
|
val indexerExpr = if(indexer.indexVar!=null) indexer.indexVar!! else indexer.indexNum!!
|
||||||
val assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
|
asmgen.assignExpressionToVariable(indexerExpr, "prog8_lib.${operation}_array_u${dt}._arg_index", DataType.UBYTE, null)
|
||||||
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 funcVariousFloatFuncs(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, scope: Subroutine) {
|
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 {
|
fun targetFromExpr(expr: Expression, datatype: DataType): AsmAssignTarget {
|
||||||
return when (expr) {
|
return when (expr) {
|
||||||
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine(), variableAsmName = asmgen.asmVariableName(expr))
|
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine(), variableAsmName = asmgen.asmVariableName(expr))
|
||||||
@ -681,26 +652,44 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO find alternative way to swap here without using estack
|
val datatype = first.inferType(program).typeOrElse(DataType.STRUCT)
|
||||||
asmgen.translateExpression(first)
|
when(datatype) {
|
||||||
asmgen.translateExpression(second)
|
in ByteDatatypes, in WordDatatypes -> {
|
||||||
val idatatype = first.inferType(program)
|
asmgen.assignExpressionToVariable(first, "P8ZP_SCRATCH_W1", datatype, null)
|
||||||
if(!idatatype.isKnown)
|
asmgen.assignExpressionToVariable(second, "P8ZP_SCRATCH_W2", datatype, null)
|
||||||
throw AssemblyError("unknown dt")
|
|
||||||
val datatype = idatatype.typeOrElse(DataType.STRUCT)
|
|
||||||
val assignFirst = AsmAssignment(
|
val assignFirst = AsmAssignment(
|
||||||
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, datatype),
|
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W2"),
|
||||||
targetFromExpr(first, datatype),
|
targetFromExpr(first, datatype),
|
||||||
false, first.position
|
false, first.position
|
||||||
)
|
)
|
||||||
val assignSecond = AsmAssignment(
|
val assignSecond = AsmAssignment(
|
||||||
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, datatype),
|
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W1"),
|
||||||
targetFromExpr(second, datatype),
|
targetFromExpr(second, datatype),
|
||||||
false, second.position
|
false, second.position
|
||||||
)
|
)
|
||||||
asmgen.translateNormalAssignment(assignFirst)
|
asmgen.translateNormalAssignment(assignFirst)
|
||||||
asmgen.translateNormalAssignment(assignSecond)
|
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) {
|
private fun swapArrayValues(elementDt: DataType, arrayVarName1: String, indexValue1: NumericLiteralValue, arrayVarName2: String, indexValue2: NumericLiteralValue) {
|
||||||
val index1 = indexValue1.number.toInt() * elementDt.memorySize()
|
val index1 = indexValue1.number.toInt() * elementDt.memorySize()
|
||||||
@ -971,14 +960,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMkword(fcall: IFunctionCall, resultToStack: Boolean) {
|
private fun funcMkword(fcall: IFunctionCall, resultToStack: Boolean) {
|
||||||
var src = AsmAssignSource.fromAstSource(fcall.args[0], program, asmgen) // msb
|
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.Y) // msb
|
||||||
var tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.Y, null, program, asmgen)
|
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // lsb
|
||||||
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)
|
|
||||||
if(resultToStack)
|
if(resultToStack)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
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)
|
if (resultToStack)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||||
} else {
|
} else {
|
||||||
val src = AsmAssignSource.fromAstSource(fcall.args.single(), program, asmgen)
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
|
|
||||||
val assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
|
|
||||||
asmgen.translateNormalAssignment(assign)
|
|
||||||
if (resultToStack)
|
if (resultToStack)
|
||||||
asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
||||||
else
|
else
|
||||||
@ -1019,10 +999,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
if (resultToStack)
|
if (resultToStack)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||||
} else {
|
} else {
|
||||||
val src = AsmAssignSource.fromAstSource(fcall.args.single(), program, asmgen)
|
asmgen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.AY)
|
||||||
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
|
|
||||||
val assign = AsmAssignment(src, tgt, false, (fcall as Node).position)
|
|
||||||
asmgen.translateNormalAssignment(assign)
|
|
||||||
if (resultToStack)
|
if (resultToStack)
|
||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||||
}
|
}
|
||||||
@ -1057,12 +1034,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
|||||||
else -> {
|
else -> {
|
||||||
scope.asmGenInfo.usedFloatEvalResultVar = true
|
scope.asmGenInfo.usedFloatEvalResultVar = true
|
||||||
val variable = IdentifierReference(listOf("_prog8_float_eval_result"), value.position)
|
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)
|
val addr = AddressOf(variable, value.position)
|
||||||
|
addr.linkParents(value)
|
||||||
|
asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT, scope)
|
||||||
AsmAssignSource.fromAstSource(addr, program, asmgen)
|
AsmAssignSource.fromAstSource(addr, program, asmgen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,6 @@ import prog8.ast.statements.Subroutine
|
|||||||
import prog8.compiler.AssemblyError
|
import prog8.compiler.AssemblyError
|
||||||
import prog8.compiler.target.CompilationTarget
|
import prog8.compiler.target.CompilationTarget
|
||||||
import prog8.compiler.target.CpuType
|
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.compiler.toHex
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import kotlin.math.absoluteValue
|
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) {
|
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 left = expr.left
|
||||||
var right = expr.right
|
var right = expr.right
|
||||||
var operator = expr.operator
|
var operator = expr.operator
|
||||||
@ -63,8 +60,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
val dt = idt.typeOrElse(DataType.STRUCT)
|
val dt = idt.typeOrElse(DataType.STRUCT)
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"==" -> {
|
"==" -> {
|
||||||
// if the left operand is an expression, and the right is 0, we can just evaluate that expression.
|
// 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)
|
// and use the result value directly to determine the boolean result. Shortcut only for integers.
|
||||||
if(rightConstVal?.number?.toDouble() == 0.0) {
|
if(rightConstVal?.number?.toDouble() == 0.0) {
|
||||||
when(left) {
|
when(left) {
|
||||||
is PrefixExpression,
|
is PrefixExpression,
|
||||||
@ -74,40 +71,35 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
is AddressOf,
|
is AddressOf,
|
||||||
is RangeExpr,
|
is RangeExpr,
|
||||||
is FunctionCall -> {
|
is FunctionCall -> {
|
||||||
translateExpression(left) // todo directly into AY reg?
|
|
||||||
if(dt in ByteDatatypes) {
|
if(dt in ByteDatatypes) {
|
||||||
asmgen.out("""
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
inx
|
asmgen.out(" bne $jumpIfFalseLabel")
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
bne $jumpIfFalseLabel""")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
else if(dt in WordDatatypes) {
|
else if(dt in WordDatatypes) {
|
||||||
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
inx
|
sty P8ZP_SCRATCH_B1
|
||||||
lda P8ESTACK_LO,x
|
ora P8ZP_SCRATCH_B1
|
||||||
clc
|
|
||||||
adc P8ESTACK_HI,x
|
|
||||||
bne $jumpIfFalseLabel""")
|
bne $jumpIfFalseLabel""")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO ....float?
|
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when (dt) {
|
when (dt) {
|
||||||
in ByteDatatypes -> translateByteEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
in ByteDatatypes -> translateByteEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
in WordDatatypes -> translateWordEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
in WordDatatypes -> translateWordEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.FLOAT -> translateFloatEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
DataType.FLOAT -> translateFloatEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.STR -> translateStringEquals(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
DataType.STR -> translateStringEqualsJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
||||||
else -> throw AssemblyError("weird operand datatype")
|
else -> throw AssemblyError("weird operand datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"!=" -> {
|
"!=" -> {
|
||||||
// if the left operand is an expression, and the right is 0, we can just evaluate that expression.
|
// 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)
|
// and use the result value directly to determine the boolean result. Shortcut only for integers.
|
||||||
if(rightConstVal?.number?.toDouble() == 0.0) {
|
if(rightConstVal?.number?.toDouble() == 0.0) {
|
||||||
when(left) {
|
when(left) {
|
||||||
is PrefixExpression,
|
is PrefixExpression,
|
||||||
@ -117,105 +109,244 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
is AddressOf,
|
is AddressOf,
|
||||||
is RangeExpr,
|
is RangeExpr,
|
||||||
is FunctionCall -> {
|
is FunctionCall -> {
|
||||||
translateExpression(left) // todo directly into AY?
|
|
||||||
if(dt in ByteDatatypes) {
|
if(dt in ByteDatatypes) {
|
||||||
asmgen.out("""
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
inx
|
asmgen.out(" beq $jumpIfFalseLabel")
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
beq $jumpIfFalseLabel""")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
else if(dt in WordDatatypes) {
|
else if(dt in WordDatatypes) {
|
||||||
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
inx
|
sty P8ZP_SCRATCH_B1
|
||||||
lda P8ESTACK_LO,x
|
ora P8ZP_SCRATCH_B1
|
||||||
clc
|
|
||||||
adc P8ESTACK_HI,x
|
|
||||||
beq $jumpIfFalseLabel""")
|
beq $jumpIfFalseLabel""")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO .... .float?
|
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when (dt) {
|
when (dt) {
|
||||||
in ByteDatatypes -> translateByteNotEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
in ByteDatatypes -> translateByteNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
in WordDatatypes -> translateWordNotEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
in WordDatatypes -> translateWordNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.FLOAT -> translateFloatNotEquals(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
DataType.FLOAT -> translateFloatNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.STR -> translateStringNotEquals(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
DataType.STR -> translateStringNotEqualsJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
||||||
else -> throw AssemblyError("weird operand datatype")
|
else -> throw AssemblyError("weird operand datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"<" -> {
|
"<" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE -> translateUbyteLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UBYTE -> translateUbyteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.BYTE -> translateByteLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.BYTE -> translateByteLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.UWORD -> translateUwordLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UWORD -> translateUwordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.WORD -> translateWordLess(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.WORD -> translateWordLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> translateFloatLessJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
// todo via func args
|
DataType.STR -> translateStringLessJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
||||||
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)
|
|
||||||
else -> throw AssemblyError("weird operand datatype")
|
else -> throw AssemblyError("weird operand datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"<=" -> {
|
"<=" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE -> translateUbyteLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UBYTE -> translateUbyteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.BYTE -> translateByteLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.BYTE -> translateByteLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.UWORD -> translateUwordLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UWORD -> translateUwordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.WORD -> translateWordLessOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.WORD -> translateWordLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> translateFloatLessOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
// todo via func args
|
DataType.STR -> translateStringLessOrEqualJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
||||||
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)
|
|
||||||
else -> throw AssemblyError("weird operand datatype")
|
else -> throw AssemblyError("weird operand datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
">" -> {
|
">" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE -> translateUbyteGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UBYTE -> translateUbyteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.BYTE -> translateByteGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.BYTE -> translateByteGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.UWORD -> translateUwordGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UWORD -> translateUwordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.WORD -> translateWordGreater(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.WORD -> translateWordGreaterJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> translateFloatGreaterJump(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
||||||
// todo via func args
|
DataType.STR -> translateStringGreaterJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
||||||
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)
|
|
||||||
else -> throw AssemblyError("weird operand datatype")
|
else -> throw AssemblyError("weird operand datatype")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
">=" -> {
|
">=" -> {
|
||||||
when(dt) {
|
when(dt) {
|
||||||
DataType.UBYTE -> translateUbyteGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UBYTE -> translateUbyteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.BYTE -> translateByteGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.BYTE -> translateByteGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.UWORD -> translateUwordGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.UWORD -> translateUwordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.WORD -> translateWordGreaterOrEqual(left, right, leftConstVal,rightConstVal, jumpIfFalseLabel)
|
DataType.WORD -> translateWordGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> translateFloatGreaterOrEqualJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel)
|
||||||
// todo via func args
|
DataType.STR -> translateStringGreaterOrEqualJump(left as IdentifierReference, right as IdentifierReference, jumpIfFalseLabel)
|
||||||
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)
|
|
||||||
else -> throw AssemblyError("weird operand datatype")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>=leftConstVal)
|
if(rightConstVal>=leftConstVal)
|
||||||
@ -245,13 +376,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" cmp P8ZP_SCRATCH_B1 | bcs $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.less_ub | inx | lda P8ESTACK_LO,x | beq $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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>=leftConstVal)
|
if(rightConstVal>=leftConstVal)
|
||||||
@ -275,13 +405,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.less_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>=leftConstVal)
|
if(rightConstVal>=leftConstVal)
|
||||||
@ -307,13 +441,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.less_uw | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>=leftConstVal)
|
if(rightConstVal>=leftConstVal)
|
||||||
@ -338,13 +471,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.less_w | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<=leftConstVal)
|
if(rightConstVal<=leftConstVal)
|
||||||
@ -374,13 +506,15 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or registers
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.greater_ub | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<=leftConstVal)
|
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.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(right)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.out(" jsr prog8_lib.greater_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<=leftConstVal)
|
if(rightConstVal<=leftConstVal)
|
||||||
@ -441,13 +582,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_less_uw | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.greater_uw | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<=leftConstVal)
|
if(rightConstVal<=leftConstVal)
|
||||||
@ -478,13 +618,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_less_w | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.greater_w | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>leftConstVal)
|
if(rightConstVal>leftConstVal)
|
||||||
@ -521,13 +660,16 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.lesseq_ub | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>leftConstVal)
|
if(rightConstVal>leftConstVal)
|
||||||
@ -555,13 +697,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.lesseq_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>leftConstVal)
|
if(rightConstVal>leftConstVal)
|
||||||
@ -590,13 +736,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.lesseq_uw | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal>leftConstVal)
|
if(rightConstVal>leftConstVal)
|
||||||
@ -627,13 +772,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.lesseq_w | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<leftConstVal)
|
if(rightConstVal<leftConstVal)
|
||||||
@ -658,13 +802,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" cmp P8ZP_SCRATCH_B1 | bcc $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.greatereq_ub | inx | lda P8ESTACK_LO,x | beq $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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<leftConstVal)
|
if(rightConstVal<leftConstVal)
|
||||||
@ -691,13 +834,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.greatereq_b | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<leftConstVal)
|
if(rightConstVal<leftConstVal)
|
||||||
@ -721,13 +868,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_lesseq_uw | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.greatereq_uw | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal<leftConstVal)
|
if(rightConstVal<leftConstVal)
|
||||||
@ -753,13 +899,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(left, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" jsr prog8_lib.reg_lesseq_w | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.greatereq_w | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal!=leftConstVal)
|
if(rightConstVal!=leftConstVal)
|
||||||
@ -785,13 +930,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" cmp P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.equal_b | inx | lda P8ESTACK_LO,x | beq $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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal==leftConstVal)
|
if(rightConstVal==leftConstVal)
|
||||||
@ -817,13 +961,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out(" cmp P8ZP_SCRATCH_B1 | beq $jumpIfFalseLabel")
|
||||||
asmgen.out(" jsr prog8_lib.notequal_b | inx | lda P8ESTACK_LO,x | 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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal!=leftConstVal)
|
if(rightConstVal!=leftConstVal)
|
||||||
@ -851,13 +994,16 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.equal_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal==leftConstVal)
|
if(rightConstVal==leftConstVal)
|
||||||
@ -887,13 +1033,17 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args or regs
|
asmgen.assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||||
asmgen.translateExpression(left)
|
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||||
asmgen.translateExpression(right)
|
asmgen.out("""
|
||||||
asmgen.out(" jsr prog8_lib.notequal_w | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal!=leftConstVal)
|
if(rightConstVal!=leftConstVal)
|
||||||
@ -933,13 +1083,47 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args
|
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(left)
|
||||||
translateExpression(right)
|
translateExpression(right)
|
||||||
asmgen.out(" jsr floats.equal_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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(rightConstVal!=null) {
|
||||||
if(leftConstVal!=null) {
|
if(leftConstVal!=null) {
|
||||||
if(rightConstVal==leftConstVal)
|
if(rightConstVal==leftConstVal)
|
||||||
@ -980,13 +1164,47 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo via func args
|
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(left)
|
||||||
translateExpression(right)
|
translateExpression(right)
|
||||||
asmgen.out(" jsr floats.notequal_f | inx | lda P8ESTACK_LO,x | beq $jumpIfFalseLabel")
|
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 leftNam = asmgen.asmVariableName(left)
|
||||||
val rightNam = asmgen.asmVariableName(right)
|
val rightNam = asmgen.asmVariableName(right)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
@ -1001,7 +1219,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
bne $jumpIfFalseLabel""")
|
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 leftNam = asmgen.asmVariableName(left)
|
||||||
val rightNam = asmgen.asmVariableName(right)
|
val rightNam = asmgen.asmVariableName(right)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
@ -1016,7 +1234,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
beq $jumpIfFalseLabel""")
|
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 leftNam = asmgen.asmVariableName(left)
|
||||||
val rightNam = asmgen.asmVariableName(right)
|
val rightNam = asmgen.asmVariableName(right)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
@ -1030,7 +1248,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
bpl $jumpIfFalseLabel""")
|
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 leftNam = asmgen.asmVariableName(left)
|
||||||
val rightNam = asmgen.asmVariableName(right)
|
val rightNam = asmgen.asmVariableName(right)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
@ -1045,7 +1263,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
bmi $jumpIfFalseLabel""")
|
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 leftNam = asmgen.asmVariableName(left)
|
||||||
val rightNam = asmgen.asmVariableName(right)
|
val rightNam = asmgen.asmVariableName(right)
|
||||||
asmgen.out("""
|
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 leftNam = asmgen.asmVariableName(left)
|
||||||
val rightNam = asmgen.asmVariableName(right)
|
val rightNam = asmgen.asmVariableName(right)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
@ -1131,7 +1349,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translateExpression(typecast: TypecastExpression) {
|
private fun translateExpression(typecast: TypecastExpression) {
|
||||||
translateExpression(typecast.expression) // todo avoid stack
|
translateExpression(typecast.expression)
|
||||||
when(typecast.expression.inferType(program).typeOrElse(DataType.STRUCT)) {
|
when(typecast.expression.inferType(program).typeOrElse(DataType.STRUCT)) {
|
||||||
DataType.UBYTE -> {
|
DataType.UBYTE -> {
|
||||||
when(typecast.type) {
|
when(typecast.type) {
|
||||||
@ -1214,12 +1432,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
translateExpression(expr.addressExpression) // todo directly into A
|
asmgen.assignExpressionToVariable(expr.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
|
||||||
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack")
|
if(pushResultOnEstack) {
|
||||||
if(pushResultOnEstack)
|
asmgen.out(" dex | ldy #0 | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x")
|
||||||
asmgen.out(" sta P8ESTACK_LO+1,x")
|
} else {
|
||||||
else
|
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
|
||||||
asmgen.out(" php | inx | plp")
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1547,7 +1765,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translateExpression(expr: PrefixExpression) {
|
private fun translateExpression(expr: PrefixExpression) {
|
||||||
// todo avoid using stack
|
|
||||||
translateExpression(expr.expression)
|
translateExpression(expr.expression)
|
||||||
val itype = expr.inferType(program)
|
val itype = expr.inferType(program)
|
||||||
if(!itype.isKnown)
|
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) {
|
private fun translateCompareStrings(s1: Expression, operator: String, s2: Expression) {
|
||||||
var src = AsmAssignSource.fromAstSource(s1, program, asmgen)
|
asmgen.assignExpressionToVariable(s1, "prog8_lib.strcmp_expression._arg_s1", DataType.UWORD, null)
|
||||||
var tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UWORD, null, variableAsmName = "prog8_lib.strcmp_expression._arg_s1")
|
asmgen.assignExpressionToVariable(s2, "prog8_lib.strcmp_expression._arg_s2", DataType.UWORD, null)
|
||||||
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.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A
|
asmgen.out(" jsr prog8_lib.strcmp_expression") // result of compare is in A
|
||||||
when(operator) {
|
when(operator) {
|
||||||
"==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO,x")
|
"==" -> asmgen.out(" and #1 | eor #1 | sta P8ESTACK_LO,x")
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
package prog8.compiler.target.c64.codegen
|
package prog8.compiler.target.c64.codegen
|
||||||
|
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
|
import prog8.ast.base.ArrayElementTypes
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
|
import prog8.ast.base.RegisterOrPair
|
||||||
import prog8.ast.expressions.IdentifierReference
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.ast.expressions.RangeExpr
|
import prog8.ast.expressions.RangeExpr
|
||||||
import prog8.ast.statements.ForLoop
|
import prog8.ast.statements.ForLoop
|
||||||
import prog8.compiler.AssemblyError
|
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 prog8.compiler.toHex
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
// todo reduce use of stack eval translateExpression()
|
|
||||||
|
|
||||||
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
||||||
|
|
||||||
internal fun translate(stmt: ForLoop) {
|
internal fun translate(stmt: ForLoop) {
|
||||||
@ -53,15 +49,9 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
|
|||||||
val incdec = if(stepsize==1) "inc" else "dec"
|
val incdec = if(stepsize==1) "inc" else "dec"
|
||||||
// loop over byte range via loopvar
|
// loop over byte range via loopvar
|
||||||
val varname = asmgen.asmVariableName(stmt.loopVar)
|
val varname = asmgen.asmVariableName(stmt.loopVar)
|
||||||
asmgen.translateExpression(range.to)
|
asmgen.assignExpressionToVariable(range.from, varname, ArrayElementTypes.getValue(iterableDt), null)
|
||||||
asmgen.translateExpression(range.from)
|
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayElementTypes.getValue(iterableDt), null)
|
||||||
asmgen.out("""
|
asmgen.out(loopLabel)
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta $varname
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta $modifiedLabel+1
|
|
||||||
$loopLabel""")
|
|
||||||
asmgen.translate(stmt.body)
|
asmgen.translate(stmt.body)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda $varname
|
lda $varname
|
||||||
@ -69,7 +59,7 @@ $modifiedLabel cmp #0 ; modified
|
|||||||
beq $endLabel
|
beq $endLabel
|
||||||
$incdec $varname
|
$incdec $varname
|
||||||
jmp $loopLabel
|
jmp $loopLabel
|
||||||
$endLabel inx""")
|
$endLabel""")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -77,36 +67,29 @@ $endLabel inx""")
|
|||||||
|
|
||||||
// loop over byte range via loopvar
|
// loop over byte range via loopvar
|
||||||
val varname = asmgen.asmVariableName(stmt.loopVar)
|
val varname = asmgen.asmVariableName(stmt.loopVar)
|
||||||
asmgen.translateExpression(range.to)
|
asmgen.assignExpressionToVariable(range.from, varname, ArrayElementTypes.getValue(iterableDt), null)
|
||||||
asmgen.translateExpression(range.from)
|
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayElementTypes.getValue(iterableDt), null)
|
||||||
asmgen.out("""
|
asmgen.out(loopLabel)
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta $varname
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta $modifiedLabel+1
|
|
||||||
$loopLabel""")
|
|
||||||
asmgen.translate(stmt.body)
|
asmgen.translate(stmt.body)
|
||||||
asmgen.out("""
|
|
||||||
lda $varname""")
|
|
||||||
if(stepsize>0) {
|
if(stepsize>0) {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
lda $varname
|
||||||
clc
|
clc
|
||||||
adc #$stepsize
|
adc #$stepsize
|
||||||
sta $varname
|
sta $varname
|
||||||
$modifiedLabel cmp #0 ; modified
|
$modifiedLabel cmp #0 ; modified
|
||||||
bcc $loopLabel
|
bmi $loopLabel
|
||||||
beq $loopLabel""")
|
beq $loopLabel""")
|
||||||
} else {
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
lda $varname
|
||||||
sec
|
sec
|
||||||
sbc #${stepsize.absoluteValue}
|
sbc #${stepsize.absoluteValue}
|
||||||
sta $varname
|
sta $varname
|
||||||
$modifiedLabel cmp #0 ; modified
|
$modifiedLabel cmp #0 ; modified
|
||||||
bcs $loopLabel""")
|
bpl $loopLabel""")
|
||||||
}
|
}
|
||||||
asmgen.out("""
|
asmgen.out(endLabel)
|
||||||
$endLabel inx""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||||
@ -115,13 +98,11 @@ $endLabel inx""")
|
|||||||
// words, step 1 or -1
|
// words, step 1 or -1
|
||||||
|
|
||||||
stepsize == 1 || stepsize == -1 -> {
|
stepsize == 1 || stepsize == -1 -> {
|
||||||
asmgen.translateExpression(range.to)
|
|
||||||
assignLoopvar(stmt, range)
|
|
||||||
val varname = asmgen.asmVariableName(stmt.loopVar)
|
val varname = asmgen.asmVariableName(stmt.loopVar)
|
||||||
|
assignLoopvar(stmt, range)
|
||||||
|
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda P8ESTACK_HI+1,x
|
sty $modifiedLabel+1
|
||||||
sta $modifiedLabel+1
|
|
||||||
lda P8ESTACK_LO+1,x
|
|
||||||
sta $modifiedLabel2+1
|
sta $modifiedLabel2+1
|
||||||
$loopLabel""")
|
$loopLabel""")
|
||||||
asmgen.translate(stmt.body)
|
asmgen.translate(stmt.body)
|
||||||
@ -148,21 +129,17 @@ $modifiedLabel2 cmp #0 ; modified
|
|||||||
jmp $loopLabel""")
|
jmp $loopLabel""")
|
||||||
}
|
}
|
||||||
asmgen.out(endLabel)
|
asmgen.out(endLabel)
|
||||||
asmgen.out(" inx")
|
|
||||||
}
|
}
|
||||||
stepsize > 0 -> {
|
stepsize > 0 -> {
|
||||||
|
|
||||||
// (u)words, step >= 2
|
// (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)
|
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)
|
asmgen.translate(stmt.body)
|
||||||
|
|
||||||
if (iterableDt == DataType.ARRAY_UW) {
|
if (iterableDt == DataType.ARRAY_UW) {
|
||||||
@ -181,7 +158,7 @@ $modifiedLabel2 lda #0 ; modified
|
|||||||
cmp $varname
|
cmp $varname
|
||||||
bcc $endLabel
|
bcc $endLabel
|
||||||
bcs $loopLabel
|
bcs $loopLabel
|
||||||
$endLabel inx""")
|
$endLabel""")
|
||||||
} else {
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda $varname
|
lda $varname
|
||||||
@ -198,22 +175,19 @@ $modifiedLabel lda #0 ; modified
|
|||||||
bvc +
|
bvc +
|
||||||
eor #$80
|
eor #$80
|
||||||
+ bpl $loopLabel
|
+ bpl $loopLabel
|
||||||
$endLabel inx""")
|
$endLabel""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|
||||||
// (u)words, step <= -2
|
// (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)
|
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)
|
asmgen.translate(stmt.body)
|
||||||
|
|
||||||
if(iterableDt==DataType.ARRAY_UW) {
|
if(iterableDt==DataType.ARRAY_UW) {
|
||||||
@ -231,7 +205,7 @@ $modifiedLabel cmp #0 ; modified
|
|||||||
lda $varname
|
lda $varname
|
||||||
$modifiedLabel2 cmp #0 ; modified
|
$modifiedLabel2 cmp #0 ; modified
|
||||||
bcs $loopLabel
|
bcs $loopLabel
|
||||||
$endLabel inx""")
|
$endLabel""")
|
||||||
} else {
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda $varname
|
lda $varname
|
||||||
@ -249,7 +223,7 @@ $modifiedLabel sbc #0 ; modified
|
|||||||
bvc +
|
bvc +
|
||||||
eor #$80
|
eor #$80
|
||||||
+ bpl $loopLabel
|
+ bpl $loopLabel
|
||||||
$endLabel inx""")
|
$endLabel""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,10 +585,6 @@ $endLabel""")
|
|||||||
asmgen.loopEndLabels.pop()
|
asmgen.loopEndLabels.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) {
|
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))
|
asmgen.assignExpressionToVariable(range.from, asmgen.asmVariableName(stmt.loopVar), stmt.loopVarDt(program).typeOrElse(DataType.STRUCT), stmt.definingSubroutine())
|
||||||
val src = AsmAssignSource.fromAstSource(range.from, program, asmgen).adjustSignedUnsigned(target)
|
|
||||||
val assign = AsmAssignment(src, target, false, range.position)
|
|
||||||
asmgen.translateNormalAssignment(assign)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -165,10 +165,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
throw AssemblyError("argument type incompatible")
|
throw AssemblyError("argument type incompatible")
|
||||||
|
|
||||||
val varName = asmgen.asmVariableName(sub.scopedname+"."+parameter.value.name)
|
val varName = asmgen.asmVariableName(sub.scopedname+"."+parameter.value.name)
|
||||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, parameter.value.type, sub, variableAsmName = varName)
|
asmgen.assignExpressionToVariable(value, varName, parameter.value.type, sub)
|
||||||
val source = AsmAssignSource.fromAstSource(value, program, asmgen).adjustSignedUnsigned(tgt)
|
|
||||||
val asgn = AsmAssignment(source, tgt, false, Position.DUMMY)
|
|
||||||
asmgen.translateNormalAssignment(asgn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {
|
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 -> {
|
else -> {
|
||||||
asmgen.translateExpression(value) // todo directly into A
|
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
inx
|
|
||||||
pha
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
beq +
|
beq +
|
||||||
sec
|
sec
|
||||||
bcs ++
|
bcs ++
|
||||||
+ clc
|
+ clc
|
||||||
+ pla
|
+""")
|
||||||
""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,18 +224,16 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// via register or register pair
|
// via register or register pair
|
||||||
val target = AsmAssignTarget.fromRegisters(register!!, sub, program, asmgen)
|
register!!
|
||||||
if(requiredDt largerThan valueDt) {
|
if(requiredDt largerThan valueDt) {
|
||||||
// we need to sign extend the source, do this via temporary word variable
|
// we need to sign extend the source, do this via temporary word variable
|
||||||
val scratchVar = asmgen.asmVariableName("P8ZP_SCRATCH_W1")
|
val scratchVar = asmgen.asmVariableName("P8ZP_SCRATCH_W1")
|
||||||
val scratchTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.UBYTE, sub, scratchVar)
|
asmgen.assignExpressionToVariable(value, scratchVar, DataType.UBYTE, sub)
|
||||||
val source = AsmAssignSource.fromAstSource(value, program, asmgen)
|
|
||||||
asmgen.translateNormalAssignment(AsmAssignment(source, scratchTarget, false, value.position))
|
|
||||||
asmgen.signExtendVariableLsb(scratchVar, valueDt)
|
asmgen.signExtendVariableLsb(scratchVar, valueDt)
|
||||||
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, DataType.UWORD, scratchVar)
|
asmgen.assignVariableToRegister(scratchVar, register)
|
||||||
asmgen.translateNormalAssignment(AsmAssignment(src, target, false, Position.DUMMY))
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
val target = AsmAssignTarget.fromRegisters(register, sub, program, asmgen)
|
||||||
val src = if(valueDt in PassByReferenceDatatypes) {
|
val src = if(valueDt in PassByReferenceDatatypes) {
|
||||||
if(value is IdentifierReference) {
|
if(value is IdentifierReference) {
|
||||||
val addr = AddressOf(value, Position.DUMMY)
|
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")
|
asmgen.out("+\tdec ${'$'}ffff\t; modified")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
asmgen.translateExpression(addressExpr) // todo directly into AY?
|
asmgen.assignExpressionToRegister(addressExpr, RegisterOrPair.AY)
|
||||||
asmgen.out("""
|
asmgen.out(" sta (+) + 1 | sty (+) + 2")
|
||||||
inx
|
|
||||||
lda P8ESTACK_LO,x
|
|
||||||
sta (+) + 1
|
|
||||||
lda P8ESTACK_HI,x
|
|
||||||
sta (+) + 2
|
|
||||||
""")
|
|
||||||
if(incr)
|
if(incr)
|
||||||
asmgen.out("+\tinc ${'$'}ffff\t; modified")
|
asmgen.out("+\tinc ${'$'}ffff\t; modified")
|
||||||
else
|
else
|
||||||
|
@ -68,12 +68,18 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
// constant array index value
|
// constant array index value
|
||||||
val indexValue = value.indexer.constIndex()!! * elementDt.memorySize()
|
val indexValue = value.indexer.constIndex()!! * elementDt.memorySize()
|
||||||
when (elementDt) {
|
when (elementDt) {
|
||||||
in ByteDatatypes ->
|
in ByteDatatypes -> {
|
||||||
asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | dex")
|
asmgen.out(" lda $arrayVarName+$indexValue")
|
||||||
in WordDatatypes ->
|
assignRegisterByte(assign.target, CpuRegister.A)
|
||||||
asmgen.out(" lda $arrayVarName+$indexValue | sta P8ESTACK_LO,x | lda $arrayVarName+$indexValue+1 | sta P8ESTACK_HI,x | dex")
|
}
|
||||||
DataType.FLOAT ->
|
in WordDatatypes -> {
|
||||||
asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr floats.push_float")
|
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 ->
|
else ->
|
||||||
throw AssemblyError("weird array type")
|
throw AssemblyError("weird array type")
|
||||||
}
|
}
|
||||||
@ -81,11 +87,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
when (elementDt) {
|
when (elementDt) {
|
||||||
in ByteDatatypes -> {
|
in ByteDatatypes -> {
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
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 -> {
|
in WordDatatypes -> {
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
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 -> {
|
DataType.FLOAT -> {
|
||||||
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.A)
|
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.A)
|
||||||
@ -95,13 +103,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
adc #<$arrayVarName
|
adc #<$arrayVarName
|
||||||
bcc +
|
bcc +
|
||||||
iny
|
iny
|
||||||
+ jsr floats.push_float""")
|
+""")
|
||||||
|
assignFloatFromAY(assign.target)
|
||||||
}
|
}
|
||||||
else ->
|
else ->
|
||||||
throw AssemblyError("weird array elt type")
|
throw AssemblyError("weird array elt type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignStackValue(assign.target)
|
|
||||||
}
|
}
|
||||||
SourceStorageKind.MEMORY -> {
|
SourceStorageKind.MEMORY -> {
|
||||||
val value = assign.source.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)
|
assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
asmgen.translateExpression(value.addressExpression) // TODO directly into AY
|
asmgen.assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope)
|
||||||
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | inx")
|
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
|
||||||
assignRegisterByte(assign.target, CpuRegister.A)
|
assignRegisterByte(assign.target, CpuRegister.A)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,8 +208,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// everything else just evaluate via the stack.
|
// Everything else just evaluate via the stack.
|
||||||
// TODO byte and word values not via stack but via A / AY registers?
|
// (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)
|
asmgen.translateExpression(value)
|
||||||
if(assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
|
if(assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
|
||||||
asmgen.signExtendStackLsb(assign.source.datatype)
|
asmgen.signExtendStackLsb(assign.source.datatype)
|
||||||
@ -254,6 +263,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
when(value) {
|
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 PrefixExpression -> {}
|
||||||
is BinaryExpression -> {}
|
is BinaryExpression -> {}
|
||||||
is ArrayIndexedExpression -> {}
|
is ArrayIndexedExpression -> {}
|
||||||
@ -263,16 +279,134 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
else -> {
|
else -> {
|
||||||
// TODO optimize the others further?
|
// TODO optimize the others further?
|
||||||
if(this.asmgen.options.slowCodegenWarnings)
|
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
|
// 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!!)
|
asmgen.translateExpression(origAssign.source.expression!!)
|
||||||
assignStackValue(target)
|
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) {
|
private fun assignStackValue(target: AsmAssignTarget) {
|
||||||
when(target.kind) {
|
when(target.kind) {
|
||||||
TargetStorageKind.VARIABLE -> {
|
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) {
|
private fun assignVariableFloat(target: AsmAssignTarget, sourceName: String) {
|
||||||
when(target.kind) {
|
when(target.kind) {
|
||||||
TargetStorageKind.VARIABLE -> {
|
TargetStorageKind.VARIABLE -> {
|
||||||
@ -1242,17 +1409,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg)
|
asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
asmgen.out(" lda $ldaInstructionArg | pha")
|
asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
|
||||||
asmgen.translateExpression(addressExpr) // TODO directly into AY
|
asmgen.out(" ldy #0 | lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2),y")
|
||||||
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""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1276,17 +1434,31 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()!!)
|
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.restoreRegister(CpuRegister.A, false)
|
||||||
asmgen.out("""
|
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
|
||||||
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""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 -> {
|
is IdentifierReference -> {
|
||||||
val pointer = memory.addressExpression as IdentifierReference
|
val pointer = memory.addressExpression as IdentifierReference
|
||||||
when {
|
when {
|
||||||
valueLv != null -> inplaceModification_byte_litval_to_memory(pointer, operator, valueLv.toInt())
|
valueLv != null -> inplaceModification_byte_litval_to_pointer(pointer, operator, valueLv.toInt())
|
||||||
ident != null -> inplaceModification_byte_variable_to_memory(pointer, operator, ident)
|
ident != null -> inplaceModification_byte_variable_to_pointer(pointer, operator, ident)
|
||||||
// TODO more specialized code for types such as memory read etc.
|
// TODO more specialized code for types such as memory read etc.
|
||||||
value is TypecastExpression -> {
|
value is TypecastExpression -> {
|
||||||
if (tryRemoveRedundantCast(value, target, operator)) return
|
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 -> {
|
else -> {
|
||||||
if(asmgen.options.slowCodegenWarnings)
|
if(asmgen.options.slowCodegenWarnings)
|
||||||
println("warning: slow stack evaluation used (1): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO optimize...
|
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")
|
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1")
|
||||||
val zp = CompilationTarget.instance.machine.zeropage
|
val zp = CompilationTarget.instance.machine.zeropage
|
||||||
when {
|
when {
|
||||||
@ -227,7 +227,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
return false
|
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)
|
if(asmgen.options.slowCodegenWarnings)
|
||||||
println("warning: slow stack evaluation used (3): @(${pointervar.nameInSource.last()}) $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
println("warning: slow stack evaluation used (3): @(${pointervar.nameInSource.last()}) $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||||
asmgen.translateExpression(value)
|
asmgen.translateExpression(value)
|
||||||
@ -279,7 +279,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
asmgen.out(" inx")
|
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 otherName = asmgen.asmVariableName(value)
|
||||||
val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar)
|
val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA(pointervar)
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
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) {
|
when (operator) {
|
||||||
// note: ** (power) operator requires floats.
|
// 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) {
|
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,
|
// this should be the last resort for code generation for this,
|
||||||
// because the value is evaluated onto the eval stack (=slow).
|
// 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) {
|
when (operator) {
|
||||||
// note: ** (power) operator requires floats.
|
// 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.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||||
"*" -> asmgen.out(" lda P8ESTACK_LO+1,x | ldy $name | jsr math.multiply_bytes | sta $name")
|
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)
|
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
|
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)
|
if(dt==DataType.BYTE)
|
||||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
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("""
|
asmgen.out("""
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
beq +
|
beq +
|
||||||
- asl $name
|
- asl $name
|
||||||
dey
|
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) {
|
if(dt==DataType.UBYTE) {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
beq +
|
beq +
|
||||||
- lsr $name
|
- lsr $name
|
||||||
dey
|
dey
|
||||||
@ -463,8 +467,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
+""")
|
+""")
|
||||||
} else {
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
inx
|
|
||||||
ldy P8ESTACK_LO,x
|
|
||||||
beq +
|
beq +
|
||||||
- lda $name
|
- lda $name
|
||||||
asl a
|
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.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||||
"|" -> asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name")
|
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")
|
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) {
|
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) {
|
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,
|
// this should be the last resort for code generation for this,
|
||||||
// because the value is evaluated onto the eval stack (=slow).
|
// 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)
|
val valueiDt = value.inferType(program)
|
||||||
if(!valueiDt.isKnown)
|
if(!valueiDt.isKnown)
|
||||||
throw AssemblyError("unknown dt")
|
throw AssemblyError("unknown dt")
|
||||||
val valueDt = valueiDt.typeOrElse(DataType.STRUCT)
|
val valueDt = valueiDt.typeOrElse(DataType.STRUCT)
|
||||||
|
|
||||||
|
// TODO can use registers instead of stack value?
|
||||||
fun multiplyWord() {
|
fun multiplyWord() {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda P8ESTACK_LO+1,x
|
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() {
|
fun divideWord() {
|
||||||
if (dt == DataType.WORD) {
|
if (dt == DataType.WORD) {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
@ -1153,6 +1162,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO can use registers instead of stack value?
|
||||||
fun remainderWord() {
|
fun remainderWord() {
|
||||||
if(dt==DataType.WORD)
|
if(dt==DataType.WORD)
|
||||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
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) {
|
when (operator) {
|
||||||
// note: ** (power) operator requires floats.
|
// 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)
|
if(valueDt==DataType.UBYTE)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda $name
|
lda $name
|
||||||
@ -1198,8 +1211,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
tya
|
tya
|
||||||
adc $name+1
|
adc $name+1
|
||||||
sta $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)
|
if(valueDt==DataType.UBYTE)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda $name
|
lda $name
|
||||||
@ -1223,25 +1240,38 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
lda $name+1
|
lda $name+1
|
||||||
sbc P8ZP_SCRATCH_B1
|
sbc P8ZP_SCRATCH_B1
|
||||||
sta $name+1""")
|
sta $name+1""")
|
||||||
|
asmgen.out(" inx")
|
||||||
}
|
}
|
||||||
"*" -> {
|
"*" -> {
|
||||||
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
|
// 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)
|
asmgen.signExtendStackLsb(valueDt)
|
||||||
multiplyWord()
|
multiplyWord()
|
||||||
|
asmgen.out(" inx")
|
||||||
}
|
}
|
||||||
"/" -> {
|
"/" -> {
|
||||||
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
|
// 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)
|
asmgen.signExtendStackLsb(valueDt)
|
||||||
divideWord()
|
divideWord()
|
||||||
|
asmgen.out(" inx")
|
||||||
}
|
}
|
||||||
"%" -> {
|
"%" -> {
|
||||||
// stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation
|
// 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)
|
asmgen.signExtendStackLsb(valueDt)
|
||||||
remainderWord()
|
remainderWord()
|
||||||
|
asmgen.out(" inx")
|
||||||
}
|
}
|
||||||
"<<" -> {
|
"<<" -> {
|
||||||
|
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
ldy P8ESTACK_LO+1,x
|
|
||||||
beq +
|
beq +
|
||||||
- asl $name
|
- asl $name
|
||||||
rol $name+1
|
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("""
|
asmgen.out("""
|
||||||
ldy P8ESTACK_LO+1,x
|
|
||||||
beq +
|
beq +
|
||||||
- lsr $name+1
|
- lsr $name+1
|
||||||
ror $name
|
ror $name
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
+""") }
|
+""")
|
||||||
else {
|
else
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
ldy P8ESTACK_LO+1,x
|
|
||||||
beq +
|
beq +
|
||||||
- lda $name+1
|
- lda $name+1
|
||||||
asl a
|
asl a
|
||||||
@ -1271,14 +1300,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
bne -
|
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)
|
if(dt in WordDatatypes)
|
||||||
asmgen.out(" lda #0 | sta $name+1")
|
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")
|
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1286,26 +1321,65 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
// the value is a proper 16-bit word, so use both bytes of it.
|
// the value is a proper 16-bit word, so use both bytes of it.
|
||||||
when (operator) {
|
when (operator) {
|
||||||
// note: ** (power) operator requires floats.
|
// 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")
|
if(asmgen.options.slowCodegenWarnings)
|
||||||
"*" -> multiplyWord()
|
println("warning: slow stack evaluation used (4): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||||
"/" -> divideWord()
|
asmgen.translateExpression(value)
|
||||||
"%" -> remainderWord()
|
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")
|
"<<", ">>" -> 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")
|
if(asmgen.options.slowCodegenWarnings)
|
||||||
"|" -> asmgen.out(" lda $name | ora P8ESTACK_LO+1,x | sta $name | lda $name+1 | ora P8ESTACK_HI+1,x | sta $name+1")
|
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("invalid operator for in-place modification $operator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> throw AssemblyError("can only use integer datatypes here")
|
||||||
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) {
|
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine) {
|
||||||
// this should be the last resort for code generation for this,
|
// this should be the last resort for code generation for this,
|
||||||
// because the value is evaluated onto the eval stack (=slow).
|
// because the value is evaluated onto the eval stack (=slow).
|
||||||
@ -1592,16 +1666,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if(asmgen.options.slowCodegenWarnings)
|
asmgen.assignExpressionToVariable(mem.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, target.scope)
|
||||||
println("warning: slow stack evaluation used (6): ${mem.addressExpression::class.simpleName} at ${mem.addressExpression.position}") // TODO
|
|
||||||
asmgen.translateExpression(mem.addressExpression)
|
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
jsr prog8_lib.read_byte_from_address_on_stack
|
ldy #0
|
||||||
|
lda (P8ZP_SCRATCH_W2),y
|
||||||
beq +
|
beq +
|
||||||
lda #1
|
lda #1
|
||||||
+ eor #1
|
+ eor #1
|
||||||
jsr prog8_lib.write_byte_to_address_on_stack
|
sta (P8ZP_SCRATCH_W2),y""")
|
||||||
inx""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1662,14 +1734,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if(asmgen.options.slowCodegenWarnings)
|
asmgen.assignExpressionToVariable(memory.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, target.scope)
|
||||||
println("warning: slow stack evaluation used (7): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO
|
|
||||||
asmgen.translateExpression(memory.addressExpression)
|
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
jsr prog8_lib.read_byte_from_address_on_stack
|
ldy #0
|
||||||
|
lda (P8ZP_SCRATCH_W2),y
|
||||||
eor #255
|
eor #255
|
||||||
jsr prog8_lib.write_byte_to_address_on_stack
|
sta (P8ZP_SCRATCH_W2),y""")
|
||||||
inx""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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("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("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("mkword" , true, listOf(FParam("msb", setOf(DataType.UBYTE)), FParam("lsb", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword),
|
||||||
FSignature("rnd" , true, emptyList(), DataType.UBYTE),
|
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
|
||||||
FSignature("rndw" , true, emptyList(), DataType.UWORD),
|
FSignature("rndw" , false, emptyList(), DataType.UWORD),
|
||||||
FSignature("rndf" , true, emptyList(), DataType.FLOAT),
|
FSignature("rndf" , false, emptyList(), DataType.FLOAT),
|
||||||
FSignature("exit" , false, listOf(FParam("returnvalue", setOf(DataType.UBYTE))), null),
|
FSignature("exit" , false, listOf(FParam("returnvalue", setOf(DataType.UBYTE))), null),
|
||||||
FSignature("rsave" , false, emptyList(), null),
|
FSignature("rsave" , false, emptyList(), null),
|
||||||
FSignature("rrestore" , 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
|
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) =
|
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)
|
target.isInRegularRAM(namespace)
|
||||||
else
|
else
|
||||||
false
|
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.
|
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.
|
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.
|
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
|
Other options
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
@ -143,14 +143,17 @@ Required tools
|
|||||||
`64tass <https://sourceforge.net/projects/tass64/>`_ - cross assembler. Install this on your shell path.
|
`64tass <https://sourceforge.net/projects/tass64/>`_ - cross assembler. Install this on your shell path.
|
||||||
It's very easy to compile yourself.
|
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.
|
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.
|
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.
|
If you're scared of Oracle's licensing terms, most Linux distributions ship OpenJDK in their packages repository instead.
|
||||||
Fnd for Windows it's possible to get that as well. Check out `AdoptOpenJDK <https://adoptopenjdk.net/>`_ .
|
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.
|
Finally: an **emulator** (or a real machine ofcourse) to test and run your programs on.
|
||||||
The compiler assumes the presence of the `Vice emulator <http://vice-emu.sourceforge.net/>`_.
|
In C64 mode, thhe 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>`_.
|
If you're targeting the CommanderX16 instead, there's the `x16emu <https://github.com/commanderx16/x16-emulator>`_.
|
||||||
|
|
||||||
.. important::
|
.. important::
|
||||||
**Building the compiler itself:** (*Only needed if you have not downloaded a pre-built 'fat-jar'*)
|
**Building the compiler itself:** (*Only needed if you have not downloaded a pre-built 'fat-jar'*)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
TODO
|
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 '_'
|
- 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)
|
- 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
|
- see if we can group some errors together for instance the (now single) errors about unidentified symbols
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
%import syslib
|
%import syslib
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -11,7 +12,7 @@ main {
|
|||||||
integers()
|
integers()
|
||||||
floatingpoint()
|
floatingpoint()
|
||||||
|
|
||||||
testX()
|
test_stack.test()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rotations() {
|
sub rotations() {
|
||||||
@ -251,8 +252,7 @@ main {
|
|||||||
txt.chrout('\n')
|
txt.chrout('\n')
|
||||||
txt.chrout('\n')
|
txt.chrout('\n')
|
||||||
|
|
||||||
|
test_stack.test()
|
||||||
testX()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ main {
|
|||||||
txt.print(result)
|
txt.print(result)
|
||||||
txt.chrout('\n')
|
txt.chrout('\n')
|
||||||
|
|
||||||
testX()
|
test_stack.test()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,7 +643,7 @@ main {
|
|||||||
reverse(uwarr)
|
reverse(uwarr)
|
||||||
reverse(warr)
|
reverse(warr)
|
||||||
|
|
||||||
testX()
|
test_stack.test()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub floatingpoint() {
|
sub floatingpoint() {
|
||||||
@ -831,36 +831,6 @@ main {
|
|||||||
floats.print_f(fl)
|
floats.print_f(fl)
|
||||||
txt.chrout('\n')
|
txt.chrout('\n')
|
||||||
|
|
||||||
testX()
|
test_stack.test()
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
%target c64
|
%target c64
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -23,6 +24,9 @@ main {
|
|||||||
ubyte upwards = true
|
ubyte upwards = true
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
|
;txt.plot(0,0)
|
||||||
|
;test_stack.test()
|
||||||
|
|
||||||
ubyte mountain = 223 ; slope upwards
|
ubyte mountain = 223 ; slope upwards
|
||||||
if active_height < target_height {
|
if active_height < target_height {
|
||||||
active_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 floats
|
||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -41,6 +42,8 @@ main {
|
|||||||
txt.print(" jiffies/fr = ")
|
txt.print(" jiffies/fr = ")
|
||||||
txt.print_ub(60/timer_jiffies)
|
txt.print_ub(60/timer_jiffies)
|
||||||
txt.print(" fps")
|
txt.print(" fps")
|
||||||
|
|
||||||
|
;test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%import syslib
|
%import syslib
|
||||||
%import graphics
|
%import graphics
|
||||||
|
%import test_stack
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
|
|
||||||
@ -37,6 +38,8 @@ main {
|
|||||||
anglez+=452
|
anglez+=452
|
||||||
|
|
||||||
wait_a_little_bit()
|
wait_a_little_bit()
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
%target c64
|
%target c64
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
|
|
||||||
spritedata $2000 {
|
spritedata $2000 {
|
||||||
; this memory block contains the sprite data
|
; this memory block contains the sprite data
|
||||||
@ -95,6 +96,8 @@ main {
|
|||||||
txt.print(" jiffies/fr = ")
|
txt.print(" jiffies/fr = ")
|
||||||
txt.print_ub(60/c64.TIME_LO)
|
txt.print_ub(60/c64.TIME_LO)
|
||||||
txt.print(" fps")
|
txt.print(" fps")
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%target c64
|
%target c64
|
||||||
%import syslib
|
%import syslib
|
||||||
|
%import test_stack
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -33,6 +34,8 @@ main {
|
|||||||
txt.print_ub(60/c64.TIME_LO)
|
txt.print_ub(60/c64.TIME_LO)
|
||||||
txt.print(" fps")
|
txt.print(" fps")
|
||||||
c64.TIME_LO=0
|
c64.TIME_LO=0
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%target cx16
|
%target cx16
|
||||||
%import syslib
|
%import syslib
|
||||||
|
%import test_stack
|
||||||
%import conv
|
%import conv
|
||||||
|
|
||||||
; TODO add all other Elite's ships, show their name, advance to next ship on keypress
|
; TODO add all other Elite's ships, show their name, advance to next ship on keypress
|
||||||
@ -41,6 +42,8 @@ main {
|
|||||||
anglex += 217
|
anglex += 217
|
||||||
angley -= 505
|
angley -= 505
|
||||||
anglez += 452
|
anglez += 452
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
%import graphics
|
%import graphics
|
||||||
|
%import test_stack
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
|
|
||||||
@ -6,8 +7,13 @@ main {
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
graphics.enable_bitmap_mode()
|
graphics.enable_bitmap_mode()
|
||||||
|
|
||||||
draw_lines()
|
draw_lines()
|
||||||
draw_circles()
|
draw_circles()
|
||||||
|
|
||||||
|
; graphics.disable_bitmap_mode()
|
||||||
|
; test_stack.test()
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import syslib
|
%import syslib
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -40,6 +41,8 @@ main {
|
|||||||
rect(10, 10, 10, 10, false)
|
rect(10, 10, 10, 10, false)
|
||||||
rect(6, 0, 16, 20, true)
|
rect(6, 0, 16, 20, true)
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
|
|
||||||
|
|
||||||
sub rect(ubyte x1, ubyte y1, ubyte x2, ubyte y2, ubyte fill) {
|
sub rect(ubyte x1, ubyte y1, ubyte x2, ubyte y2, ubyte fill) {
|
||||||
ubyte x
|
ubyte x
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%import graphics
|
%import graphics
|
||||||
%import floats
|
%import floats
|
||||||
|
%import test_stack
|
||||||
%zeropage floatsafe
|
%zeropage floatsafe
|
||||||
|
|
||||||
; Draw a mandelbrot in graphics mode (the image will be 256 x 200 pixels).
|
; Draw a mandelbrot in graphics mode (the image will be 256 x 200 pixels).
|
||||||
@ -44,6 +45,8 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -57,5 +58,7 @@ main {
|
|||||||
txt.print("finished in ")
|
txt.print("finished in ")
|
||||||
floats.print_f(duration)
|
floats.print_f(duration)
|
||||||
txt.print(" seconds!\n")
|
txt.print(" seconds!\n")
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import conv
|
%import conv
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; The classic number guessing game.
|
; The classic number guessing game.
|
||||||
@ -59,6 +60,8 @@ main {
|
|||||||
txt.print("Thanks for playing, ")
|
txt.print("Thanks for playing, ")
|
||||||
txt.print(name)
|
txt.print(name)
|
||||||
txt.print(".\n")
|
txt.print(".\n")
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
%target c64
|
%target c64
|
||||||
%import syslib
|
%import syslib
|
||||||
|
%import test_stack
|
||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
; converted from plasma test program for cc65.
|
; converted from plasma test program for cc65.
|
||||||
@ -26,7 +27,7 @@ main {
|
|||||||
; ubyte v = c64.VMCSB
|
; ubyte v = c64.VMCSB
|
||||||
c64.CIA2PRA = (block & $FC) | (lsb(SCREEN1 >> 14) ^ $03)
|
c64.CIA2PRA = (block & $FC) | (lsb(SCREEN1 >> 14) ^ $03)
|
||||||
|
|
||||||
repeat {
|
repeat 100 {
|
||||||
doplasma(SCREEN1)
|
doplasma(SCREEN1)
|
||||||
c64.VMCSB = PAGE1
|
c64.VMCSB = PAGE1
|
||||||
doplasma(SCREEN2)
|
doplasma(SCREEN2)
|
||||||
@ -37,6 +38,9 @@ main {
|
|||||||
;c64.VMCSB = v
|
;c64.VMCSB = v
|
||||||
;c64.CIA2PRA = block
|
;c64.CIA2PRA = block
|
||||||
;txt.print("done!\n")
|
;txt.print("done!\n")
|
||||||
|
;test_stack.test()
|
||||||
|
;repeat {
|
||||||
|
;}
|
||||||
}
|
}
|
||||||
|
|
||||||
; several variables outside of doplasma to make them retain their value
|
; several variables outside of doplasma to make them retain their value
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -26,6 +27,8 @@ main {
|
|||||||
txt.print("number of primes (expected 54): ")
|
txt.print("number of primes (expected 54): ")
|
||||||
txt.print_ub(amount)
|
txt.print_ub(amount)
|
||||||
txt.chrout('\n')
|
txt.chrout('\n')
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -31,6 +32,7 @@ main {
|
|||||||
txt.print("reversed\n")
|
txt.print("reversed\n")
|
||||||
print_arrays()
|
print_arrays()
|
||||||
|
|
||||||
|
;test_stack.test()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
%target c64
|
%target c64
|
||||||
%import syslib
|
%import syslib
|
||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -67,6 +68,9 @@ waitkey:
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawScore()
|
drawScore()
|
||||||
|
|
||||||
|
; txt.plot(0,0)
|
||||||
|
; test_stack.test()
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte key=c64.GETIN()
|
ubyte key=c64.GETIN()
|
||||||
|
@ -1,51 +1,48 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import floats
|
%import floats
|
||||||
%import syslib
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
%import test_stack
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
str s1 = "irmen"
|
ubyte[] ubarray = [1,2,3,4]
|
||||||
str s2 = "hello"
|
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)
|
ubyte ub
|
||||||
; txt.print_b(c)
|
byte bb
|
||||||
; txt.chrout('\n')
|
uword uw
|
||||||
txt.print_ub(s1<=s2)
|
word ww
|
||||||
|
float fl
|
||||||
|
|
||||||
|
const ubyte i = 2
|
||||||
|
const ubyte j = 3
|
||||||
|
|
||||||
|
ub = ubarray[i]
|
||||||
|
txt.print_ub(ub)
|
||||||
txt.chrout('\n')
|
txt.chrout('\n')
|
||||||
|
|
||||||
testX()
|
bb = barray[i]
|
||||||
}
|
txt.print_b(bb)
|
||||||
|
txt.chrout('\n')
|
||||||
|
|
||||||
asmsub testX() {
|
uw = uwarray[i]
|
||||||
%asm {{
|
txt.print_uw(uw)
|
||||||
stx _saveX
|
txt.chrout('\n')
|
||||||
lda #13
|
|
||||||
jsr txt.chrout
|
ww = warray[i]
|
||||||
lda #'x'
|
txt.print_w(ww)
|
||||||
jsr txt.chrout
|
txt.chrout('\n')
|
||||||
lda #'='
|
|
||||||
jsr txt.chrout
|
fl = farray[i]
|
||||||
lda _saveX
|
floats.print_f(fl)
|
||||||
jsr txt.print_ub
|
txt.chrout('\n')
|
||||||
lda #' '
|
|
||||||
jsr txt.chrout
|
test_stack.test()
|
||||||
lda #'s'
|
txt.chrout('\n')
|
||||||
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
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import test_stack
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -963,6 +964,9 @@ main {
|
|||||||
txt.print("ok\n")
|
txt.print("ok\n")
|
||||||
else
|
else
|
||||||
txt.print("fail!!!\n")
|
txt.print("fail!!!\n")
|
||||||
|
|
||||||
|
|
||||||
|
test_stack.test()
|
||||||
}
|
}
|
||||||
|
|
||||||
sub wait_input() {
|
sub wait_input() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%import conv
|
%import conv
|
||||||
%import diskio
|
%import diskio
|
||||||
|
%import test_stack
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
@ -26,6 +27,8 @@ main {
|
|||||||
planet.display(false)
|
planet.display(false)
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
|
; test_stack.test()
|
||||||
|
|
||||||
str input = "????????"
|
str input = "????????"
|
||||||
txt.print("\nCash: ")
|
txt.print("\nCash: ")
|
||||||
util.print_10s(ship.cash)
|
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
|
%target c64
|
||||||
%import floats
|
%import floats
|
||||||
%import graphics
|
%import graphics
|
||||||
|
%import test_stack
|
||||||
%zeropage floatsafe
|
%zeropage floatsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -18,6 +19,8 @@ main {
|
|||||||
turtle.rt(94)
|
turtle.rt(94)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; test_stack.test()
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +49,7 @@ turtle {
|
|||||||
uword xx = xpos as uword
|
uword xx = xpos as uword
|
||||||
c64.SPXY[0] = lsb(xx) + 12
|
c64.SPXY[0] = lsb(xx) + 12
|
||||||
c64.MSIGX = msb(xx) > 0
|
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) {
|
sub pos(float x, float y) {
|
||||||
|
Reference in New Issue
Block a user