From 0b55372b3bc8dc4e74ae3e9326d134d7b339993e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 28 Aug 2020 21:42:53 +0200 Subject: [PATCH] cleanup cx16 things and added call signatures. c64graphics moved into built-in libraries. --- .../res/prog8lib}/c64graphics.p8 | 28 ++-- compiler/res/prog8lib/cx16lib.p8 | 155 ++++++++---------- compiler/res/prog8lib/math.asm | 2 +- compiler/res/prog8lib/prog8lib.asm | 2 +- compiler/res/version.txt | 2 +- .../src/prog8/ast/processing/AstChecker.kt | 3 - .../src/prog8/ast/statements/AstStatements.kt | 1 + .../compiler/target/IMachineDefinition.kt | 7 +- .../target/c64/C64MachineDefinition.kt | 3 +- .../compiler/target/c64/codegen/AsmGen.kt | 7 +- .../target/c64/codegen/ExpressionsAsmGen.kt | 39 ++++- .../target/c64/codegen/FunctionCallAsmGen.kt | 2 +- .../codegen/assignment/AssignmentAsmGen.kt | 13 +- .../assignment/AugmentableAssignmentAsmGen.kt | 43 ++++- .../target/cx16/CX16MachineDefinition.kt | 3 +- docs/source/index.rst | 1 + examples/cube3d-gfx.p8 | 2 +- examples/cx16/graphics.p8 | 30 ++++ examples/cx16/textclock.p8 | 64 +++++--- 19 files changed, 255 insertions(+), 152 deletions(-) rename {examples => compiler/res/prog8lib}/c64graphics.p8 (93%) create mode 100644 examples/cx16/graphics.p8 diff --git a/examples/c64graphics.p8 b/compiler/res/prog8lib/c64graphics.p8 similarity index 93% rename from examples/c64graphics.p8 rename to compiler/res/prog8lib/c64graphics.p8 index 15970ce6c..4c478a012 100644 --- a/examples/c64graphics.p8 +++ b/compiler/res/prog8lib/c64graphics.p8 @@ -2,9 +2,7 @@ ; bitmap pixel graphics module for the C64 ; only black/white monchrome for now - -; you could put this code at $4000 which is after the bitmap screen in memory ($2000-$3fff), -; this leaves more space for user program code. + ; assumes bitmap screen memory is $2000-$3fff graphics { const uword bitmap_address = $2000 @@ -13,26 +11,27 @@ graphics { ; enable bitmap screen, erase it and set colors to black/white. c64.SCROLY |= %00100000 c64.VMCSB = (c64.VMCSB & %11110000) | %00001000 ; $2000-$3fff - clear_screen() + clear_screen(1, 0) } - sub clear_screen() { + sub clear_screen(ubyte pixelcolor, ubyte bgcolor) { memset(bitmap_address, 320*200/8, 0) - txt.clear_screen($10, 0) ; pixel color $1 (white) backround $0 (black) + txt.clear_screen(pixelcolor << 4 | bgcolor, 0) } - sub line(uword x1, ubyte y1, uword x2, ubyte y2) { + sub line(uword @zp x1, ubyte @zp y1, uword @zp x2, ubyte @zp y2) { ; Bresenham algorithm. ; This code special cases various quadrant loops to allow simple ++ and -- operations. + ; TODO rewrite this in optimized assembly if y1>y2 { ; make sure dy is always positive to avoid 8 instead of just 4 special cases swap(x1, x2) swap(y1, y2) } - word d = 0 + word @zp d = 0 ubyte positive_ix = true - word dx = x2 - x1 as word - word dy = y2 as word - y1 as word + word @zp dx = x2 - x1 as word + word @zp dy = y2 as word - y1 as word if dx < 0 { dx = -dx positive_ix = false @@ -99,10 +98,10 @@ graphics { sub circle(uword xcenter, ubyte ycenter, ubyte radius) { ; Midpoint algorithm - ubyte ploty - ubyte xx = radius - ubyte yy = 0 - byte decisionOver2 = 1-xx as byte + ubyte @zp ploty + ubyte @zp xx = radius + ubyte @zp yy = 0 + byte @zp decisionOver2 = 1-xx as byte while xx>=yy { plotx = xcenter + xx @@ -219,6 +218,7 @@ _ormask .byte 128, 64, 32, 16, 8, 4, 2, 1 ; note: this can be even faster if we also have a 256 byte x-lookup table, but hey. ; see http://codebase64.org/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics ; the y lookup tables encodes this formula: bitmap_address + 320*(py>>3) + (py & 7) (y from 0..199) +; TODO can we use an assembly function for this to calc this? _y_lookup_hi .byte $20, $20, $20, $20, $20, $20, $20, $20, $21, $21, $21, $21, $21, $21, $21, $21 .byte $22, $22, $22, $22, $22, $22, $22, $22, $23, $23, $23, $23, $23, $23, $23, $23 diff --git a/compiler/res/prog8lib/cx16lib.p8 b/compiler/res/prog8lib/cx16lib.p8 index 2f439c82e..a5c8eccae 100644 --- a/compiler/res/prog8lib/cx16lib.p8 +++ b/compiler/res/prog8lib/cx16lib.p8 @@ -62,54 +62,22 @@ cx16 { ; spelling of the names is taken from the Commander X-16 rom sources ; the sixteen virtual 16-bit registers -&ubyte r0 = $02 -&ubyte r0L = $02 -&ubyte r0H = $03 -&ubyte r1 = $04 -&ubyte r1L = $04 -&ubyte r1H = $05 -&ubyte r2 = $06 -&ubyte r2L = $06 -&ubyte r2H = $07 -&ubyte r3 = $08 -&ubyte r3L = $08 -&ubyte r3H = $09 -&ubyte r4 = $0a -&ubyte r4L = $0a -&ubyte r4H = $0b -&ubyte r5 = $0c -&ubyte r5L = $0c -&ubyte r5H = $0d -&ubyte r6 = $0e -&ubyte r6L = $0e -&ubyte r6H = $0f -&ubyte r7 = $10 -&ubyte r7L = $10 -&ubyte r7H = $11 -&ubyte r8 = $12 -&ubyte r8L = $12 -&ubyte r8H = $13 -&ubyte r9 = $14 -&ubyte r9L = $14 -&ubyte r9H = $15 -&ubyte r10 = $16 -&ubyte r10L = $16 -&ubyte r10H = $17 -&ubyte r11 = $18 -&ubyte r11L = $18 -&ubyte r11H = $19 -&ubyte r12 = $1a -&ubyte r12L = $1a -&ubyte r12H = $1b -&ubyte r13 = $1c -&ubyte r13L = $1c -&ubyte r13H = $1d -&ubyte r14 = $1e -&ubyte r14L = $1e -&ubyte r14H = $1f -&ubyte r15 = $20 -&ubyte r15L = $20 -&ubyte r15H = $21 + &uword r0 = $02 + &uword r1 = $04 + &uword r2 = $06 + &uword r3 = $08 + &uword r4 = $0a + &uword r5 = $0c + &uword r6 = $0e + &uword r7 = $10 + &uword r8 = $12 + &uword r9 = $14 + &uword r10 = $16 + &uword r11 = $18 + &uword r12 = $1a + &uword r13 = $1c + &uword r14 = $1e + &uword r15 = $20 ; TODO subroutine args + soubroutine returnvalues + clobber registers @@ -118,7 +86,7 @@ cx16 { romsub $ff4a = close_all() romsub $ff59 = lkupla() romsub $ff5c = lkupsa() -romsub $ff5f = screen_set_mode() +romsub $ff5f = screen_set_mode(ubyte mode @A) clobbers(A, X, Y) -> ubyte @Pc romsub $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) ; incompatible with C128 dlchr() romsub $ff65 = pfkey() romsub $ff6e = jsrfar() @@ -129,44 +97,59 @@ romsub $ff7d = primm() ; X16 additions romsub $ff44 = macptr() -romsub $ff47 = enter_basic() -romsub $ff68 = mouse_config() -romsub $ff6b = mouse_get() -romsub $ff71 = mouse_scan() -romsub $ff53 = joystick_scan() -romsub $ff56 = joystick_get() -romsub $ff4d = clock_set_date_time() -romsub $ff50 = clock_get_date_time() +romsub $ff47 = enter_basic(ubyte cold_or_warm @Pc) +romsub $ff68 = mouse_config(ubyte shape @A, ubyte scale @X) clobbers (A, X, Y) +romsub $ff6b = mouse_get(ubyte zpdataptr @X) clobbers(A) +romsub $ff71 = mouse_scan() clobbers(A, X, Y) +romsub $ff53 = joystick_scan() clobbers(A, X, Y) +romsub $ff56 = joystick_get(ubyte joynr @A) -> ubyte @A, ubyte @X, ubyte @Y +romsub $ff4d = clock_set_date_time() clobbers(A, X, Y) ; args: r0, r1, r2, r3L +romsub $ff50 = clock_get_date_time() clobbers(A) ; outout args: r0, r1, r2, r3L ; high level graphics & fonts -romsub $ff20 = GRAPH_init() +romsub $ff20 = GRAPH_init() ; uses vectors=r0 romsub $ff23 = GRAPH_clear() -romsub $ff26 = GRAPH_set_window() -romsub $ff29 = GRAPH_set_colors() -romsub $ff2c = GRAPH_draw_line() -romsub $ff2f = GRAPH_draw_rect() -romsub $ff32 = GRAPH_move_rect() -romsub $ff35 = GRAPH_draw_oval() -romsub $ff38 = GRAPH_draw_image() -romsub $ff3b = GRAPH_set_font() -romsub $ff3e = GRAPH_get_char_size() -romsub $ff41 = GRAPH_put_char() +romsub $ff26 = GRAPH_set_window() ; uses x=r0, y=r1, width=r2, height=r3 +romsub $ff29 = GRAPH_set_colors(ubyte stroke @A, ubyte fill @X, ubyte background @Y) +romsub $ff2c = GRAPH_draw_line() ; uses x1=r0, y1=r1, x2=r2, y2=r3 +romsub $ff2f = GRAPH_draw_rect(ubyte fill @Pc) ; uses x=r0, y=r1, width=r2, height=r3, cornerradius=r4 +romsub $ff32 = GRAPH_move_rect() ; uses sx=r0, sy=r1, tx=r2, ty=r3, width=r4, height=r5 +romsub $ff35 = GRAPH_draw_oval(ubyte fill @Pc) ; uses x=r0, y=r1, width=r2, height=r3 +romsub $ff38 = GRAPH_draw_image() ; uses x=r0, y=r1, ptr=r2, width=r3, height=r4 +romsub $ff3b = GRAPH_set_font() ; uses ptr=r0 +romsub $ff3e = GRAPH_get_char_size(ubyte baseline @A, ubyte width @X, ubyte height_or_style @Y, ubyte is_control @Pc) +romsub $ff41 = GRAPH_put_char(ubyte char @A) ; uses x=r0, y=r1 -; TODO framebuffer API not yet included, include it +; framebuffer +romsub $fef6 = FB_init() +romsub $fef9 = FB_get_info() -> byte @A ; also outputs width=r0, height=r1 +romsub $fefc = FB_set_palette(ubyte index @A, ubyte bytecount @X) ; also uses pointer=r0 +romsub $feff = FB_cursor_position() ; uses x=r0, y=r1 +romsub $ff02 = FB_cursor_next_line() ; uses x=r0 +romsub $ff05 = FB_get_pixel() -> ubyte @A +romsub $ff08 = FB_get_pixels() ; uses ptr=r0, count=r1 +romsub $ff0b = FB_set_pixel(ubyte color @A) +romsub $ff0e = FB_set_pixels() ; uses ptr=r0, count=r1 +romsub $ff11 = FB_set_8_pixels(ubyte pattern @A, ubyte color @X) +romsub $ff14 = FB_set_8_pixels_opaque(ubyte pattern @A, ubyte color1 @X, ubyte color2 @Y) ; also uses mask=r0L +romsub $ff17 = FB_fill_pixels(ubyte color @A) ; also uses count=r0, step=r1 +romsub $ff1a = FB_filter_pixels() ; uses ptr=r0, count=r1 +romsub $ff1d = FB_move_pixels() ; uses sx=r0, sy=r1, tx=r2, ty=r3, count=r4 -romsub $fef0 = sprite_set_image() -romsub $fef3 = sprite_set_position() -romsub $fee4 = memory_fill() -romsub $fee7 = memory_copy() -romsub $feea = memory_crc() -romsub $feed = memory_decompress() -romsub $fedb = console_init() -romsub $fede = console_put_char() -romsub $fee1 = console_get_char() -romsub $fed8 = console_put_image() -romsub $fed5 = console_set_paging_message() -romsub $fed2 = kbdbuf_put() -romsub $fecf = entropy_get() +; misc +romsub $fef0 = sprite_set_image(ubyte number @A, ubyte width @X, ubyte height @Y, ubyte apply_mask @Pc) -> ubyte @Pc ; also uses pixels=r0, mask=r1, bpp=r2L +romsub $fef3 = sprite_set_position(ubyte number @A) ; also uses x=r0 and y=r1 +romsub $fee4 = memory_fill(ubyte value @A) ; uses address=r0, num_bytes=r1 +romsub $fee7 = memory_copy() ; uses source=r0, target=r1, num_bytes=r2 +romsub $feea = memory_crc() ; uses address=r0, num_bytes=r1 result->r2 +romsub $feed = memory_decompress() ; uses input=r0, output=r1 result->r1 +romsub $fedb = console_init() ; uses x=r0, y=r1, width=r2, height=r3 +romsub $fede = console_put_char(ubyte char @A, ubyte wrapping @Pc) +romsub $fee1 = console_get_char() -> ubyte @A +romsub $fed8 = console_put_image() ; uses ptr=r0, width=r1, height=r2 +romsub $fed5 = console_set_paging_message() ; uses messageptr=r0 +romsub $fed2 = kbdbuf_put(ubyte key @A) +romsub $fecf = entropy_get() -> ubyte @A, ubyte @X, ubyte @Y romsub $fecc = monitor() @@ -179,9 +162,8 @@ asmsub init_system() { %asm {{ sei cld - lda #0 - sta $00 - sta $01 + stz $00 + stz $01 jsr c64.IOINIT jsr c64.RESTOR jsr c64.CINT @@ -191,9 +173,6 @@ asmsub init_system() { clc clv cli - lda #66 - clc - jsr console_put_char rts }} } diff --git a/compiler/res/prog8lib/math.asm b/compiler/res/prog8lib/math.asm index 0ea72e68e..d33933785 100644 --- a/compiler/res/prog8lib/math.asm +++ b/compiler/res/prog8lib/math.asm @@ -59,7 +59,7 @@ multiply_words .proc sty P8ZP_SCRATCH_W2+1 stx P8ZP_SCRATCH_REG_X -mult16 lda #$00 +mult16 lda #0 sta result+2 ; clear upper bits of product sta result+3 ldx #16 ; for all 16 bits... diff --git a/compiler/res/prog8lib/prog8lib.asm b/compiler/res/prog8lib/prog8lib.asm index e098bb36d..bc5dc48ee 100644 --- a/compiler/res/prog8lib/prog8lib.asm +++ b/compiler/res/prog8lib/prog8lib.asm @@ -960,7 +960,7 @@ _result_maxuw .word 0 .pend func_max_w .proc - lda #$00 + lda #0 sta _result_maxw lda #$80 sta _result_maxw+1 diff --git a/compiler/res/version.txt b/compiler/res/version.txt index 5186d0706..23a343444 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -4.0 +4.1-SNAPSHOT diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 1466a8f4a..c0fa32a61 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -915,9 +915,6 @@ internal class AstChecker(private val program: Program, val argIDt = arg.first.value.inferType(program) if (!argIDt.isKnown) return - if (target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X) - && arg.first.value !is NumericLiteralValue && arg.first.value !is IdentifierReference) - errors.warn("calling a subroutine that expects X as a parameter is problematic. If you see a compiler error/crash about this later, try to change this call", position) } } } diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index c2ce6d307..10240ad76 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -657,6 +657,7 @@ class Subroutine(override val name: String, } fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } fun amountOfRtsInAsm(): Int = statements .asSequence() diff --git a/compiler/src/prog8/compiler/target/IMachineDefinition.kt b/compiler/src/prog8/compiler/target/IMachineDefinition.kt index 94459ea3d..d4d5727bb 100644 --- a/compiler/src/prog8/compiler/target/IMachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/IMachineDefinition.kt @@ -11,6 +11,11 @@ internal interface IMachineFloat { fun makeFloatFillAsm(): String } +internal enum class CpuType { + CPU6502, + CPU65c02 +} + internal interface IMachineDefinition { val FLOAT_MAX_NEGATIVE: Double val FLOAT_MAX_POSITIVE: Double @@ -24,7 +29,7 @@ internal interface IMachineDefinition { val opcodeNames: Set var zeropage: Zeropage val initSystemProcname: String - val cpu: String + val cpu: CpuType fun initializeZeropage(compilerOptions: CompilationOptions) fun getFloat(num: Number): IMachineFloat diff --git a/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt index 2898b35ea..9e9f6f4e3 100644 --- a/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt @@ -2,6 +2,7 @@ package prog8.compiler.target.c64 import prog8.ast.Program import prog8.compiler.* +import prog8.compiler.target.CpuType import prog8.compiler.target.IMachineDefinition import prog8.compiler.target.IMachineFloat import prog8.parser.ModuleImporter @@ -12,7 +13,7 @@ import kotlin.math.pow internal object C64MachineDefinition: IMachineDefinition { - override val cpu = "6502" + override val cpu = CpuType.CPU6502 // 5-byte cbm MFLPT format limitations: override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 48f5a6cd9..0d0d14a10 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -9,6 +9,7 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.compiler.* import prog8.compiler.target.CompilationTarget +import prog8.compiler.target.CpuType import prog8.compiler.target.IAssemblyGenerator import prog8.compiler.target.IAssemblyProgram import prog8.compiler.target.c64.AssemblyProgram @@ -78,7 +79,11 @@ internal class AsmGen(private val program: Program, private fun header() { val ourName = this.javaClass.name - val cpu = CompilationTarget.machine.cpu + val cpu = when(CompilationTarget.machine.cpu) { + CpuType.CPU6502 -> "6502" + CpuType.CPU65c02 -> "65c02" + else -> "unsupported" + } out("; $cpu assembly code for '${program.name}'") out("; generated by $ourName on ${LocalDateTime.now().withNano(0)}") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 234e00b77..a32ee5948 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -4,6 +4,8 @@ import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.compiler.AssemblyError +import prog8.compiler.target.CompilationTarget +import prog8.compiler.target.CpuType import prog8.compiler.toHex import prog8.functions.BuiltinFunctions import kotlin.math.absoluteValue @@ -45,15 +47,28 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") RegisterOrPair.X -> { // return value in X register has been discarded, just push a zero - asmgen.out(" lda #0 | sta P8ESTACK_LO,x | dex") + if(CompilationTarget.machine.cpu==CpuType.CPU65c02) + asmgen.out(" stz P8ESTACK_LO,x") + else + asmgen.out(" lda #0 | sta P8ESTACK_LO,x") + asmgen.out(" dex") } RegisterOrPair.AX -> { // return value in X register has been discarded, just push a zero in this place - asmgen.out(" sta P8ESTACK_LO,x | lda #0 | sta P8ESTACK_HI,x | dex") + asmgen.out(" sta P8ESTACK_LO,x") + if(CompilationTarget.machine.cpu==CpuType.CPU65c02) + asmgen.out(" stz P8ESTACK_HI,x") + else + asmgen.out(" lda #0 | sta P8ESTACK_HI,x") + asmgen.out(" dex") } RegisterOrPair.XY -> { // return value in X register has been discarded, just push a zero in this place - asmgen.out(" lda #0 | sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") + if(CompilationTarget.machine.cpu==CpuType.CPU65c02) + asmgen.out(" stz P8ESTACK_LO,x") + else + asmgen.out(" lda #0 | sta P8ESTACK_LO,x") + asmgen.out(" tya | sta P8ESTACK_HI,x | dex") } } } @@ -69,7 +84,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge DataType.UBYTE -> { when(expr.type) { DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") + DataType.UWORD, DataType.WORD -> { + if(CompilationTarget.machine.cpu==CpuType.CPU65c02) + asmgen.out(" stz P8ESTACK_HI+1,x") + else + asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") + } DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_ub2float") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") else -> throw AssemblyError("weird type") @@ -83,9 +103,14 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge asmgen.out(""" lda P8ESTACK_LO+1,x ora #$7f - bmi + - lda #0 -+ sta P8ESTACK_HI+1,x""") + bmi +""") + if(CompilationTarget.machine.cpu==CpuType.CPU65c02) + asmgen.out(""" ++ stz P8ESTACK_HI+1,x""") + else + asmgen.out(""" + lda #0 ++ sta P8ESTACK_HI+1,x""") } DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index 8d3018115..3a0a125de 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -16,7 +16,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg // output the code to setup the parameters and perform the actual call // does NOT output the code to deal with the result values! val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") - val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() + val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam() if(saveX) asmgen.out(" stx P8ZP_SCRATCH_REG_X") // we only save X for now (required! is the eval stack pointer), screw A and Y... diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index 113b1cbde..d54d875be 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -5,6 +5,8 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.compiler.AssemblyError +import prog8.compiler.target.CompilationTarget +import prog8.compiler.target.CpuType import prog8.compiler.target.c64.codegen.AsmGen import prog8.compiler.toHex @@ -706,7 +708,16 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen // optimized case for float zero when(target.kind) { TargetStorageKind.VARIABLE -> { - asmgen.out(""" + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(""" + stz ${target.asmVarname} + stz ${target.asmVarname}+1 + stz ${target.asmVarname}+2 + stz ${target.asmVarname}+3 + stz ${target.asmVarname}+4 + """) + else + asmgen.out(""" lda #0 sta ${target.asmVarname} sta ${target.asmVarname}+1 diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index 070b9b286..b6c5bf4ad 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -5,6 +5,7 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.compiler.AssemblyError import prog8.compiler.target.CompilationTarget +import prog8.compiler.target.CpuType import prog8.compiler.target.c64.codegen.AsmGen import prog8.compiler.toHex @@ -736,9 +737,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } "&" -> { when { - value == 0 -> asmgen.out(" lda #0 | sta $name | sta $name+1") - value and 255 == 0 -> asmgen.out(" lda #0 | sta $name | lda $name+1 | and #>$value | sta $name+1") - value < 0x0100 -> asmgen.out(" lda $name | and #$value | sta $name | lda #0 | sta $name+1") + value == 0 -> { + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(" stz $name | stz $name+1") + else + asmgen.out(" lda #0 | sta $name | sta $name+1") + } + value and 255 == 0 -> { + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(" stz $name") + else + asmgen.out(" lda #0 | sta $name") + asmgen.out(" lda $name+1 | and #>$value | sta $name+1") + } + value < 0x0100 -> { + asmgen.out(" lda $name | and #$value | sta $name") + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(" stz $name+1") + else + asmgen.out(" lda #0 | sta $name+1") + } else -> asmgen.out(" lda $name | and #<$value | sta $name | lda $name+1 | and #>$value | sta $name+1") } } @@ -1259,12 +1277,25 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, when (outerCastDt) { DataType.UBYTE, DataType.BYTE -> { when(target.kind) { - TargetStorageKind.VARIABLE -> asmgen.out(" lda #0 | sta ${target.asmVarname}+1") + TargetStorageKind.VARIABLE -> { + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(" stz ${target.asmVarname}+1") + else + asmgen.out(" lda #0 | sta ${target.asmVarname}+1") + } TargetStorageKind.ARRAY -> { asmgen.loadScaledArrayIndexIntoRegister(target.array!!, target.datatype, CpuRegister.Y, true) - asmgen.out(" lda #0 | sta ${target.asmVarname},y") + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(" stz ${target.asmVarname},y") + else + asmgen.out(" lda #0 | sta ${target.asmVarname},y") + } + TargetStorageKind.STACK -> { + if(CompilationTarget.machine.cpu == CpuType.CPU65c02) + asmgen.out(" stz P8ESTACK_HI+1,x") + else + asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") } - TargetStorageKind.STACK -> asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") else -> throw AssemblyError("weird target") } } diff --git a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt index 5cc03ba5e..705bbb26b 100644 --- a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt @@ -2,6 +2,7 @@ package prog8.compiler.target.cx16 import prog8.ast.Program import prog8.compiler.* +import prog8.compiler.target.CpuType import prog8.compiler.target.IMachineDefinition import prog8.compiler.target.c64.C64MachineDefinition import prog8.parser.ModuleImporter @@ -9,7 +10,7 @@ import java.io.IOException internal object CX16MachineDefinition: IMachineDefinition { - override val cpu = "65c02" + override val cpu = CpuType.CPU65c02 // 5-byte cbm MFLPT format limitations: override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 diff --git a/docs/source/index.rst b/docs/source/index.rst index c121eb00a..55d6c032d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,6 +12,7 @@ What is Prog8? This is an experimental compiled programming language targeting the 8-bit `6502 `_ / +`65c02 `_ / `6510 `_ microprocessor. This CPU is from the late 1970's and early 1980's and was used in many home computers from that era, such as the `Commodore-64 `_. diff --git a/examples/cube3d-gfx.p8 b/examples/cube3d-gfx.p8 index 1f721f05a..15b4aa004 100644 --- a/examples/cube3d-gfx.p8 +++ b/examples/cube3d-gfx.p8 @@ -32,7 +32,7 @@ main { repeat { rotate_vertices(msb(anglex), msb(angley), msb(anglez)) - graphics.clear_screen() + graphics.clear_screen(1, 0) draw_lines() anglex-=500 angley+=217 diff --git a/examples/cx16/graphics.p8 b/examples/cx16/graphics.p8 new file mode 100644 index 000000000..9681c501a --- /dev/null +++ b/examples/cx16/graphics.p8 @@ -0,0 +1,30 @@ +; CommanderX16 text clock example! +; make sure to compile with the cx16 compiler target. + +%zeropage basicsafe + +main { + + sub start() { + + cx16.screen_set_mode($80) + cx16.r0=0 + cx16.GRAPH_init() + cx16.GRAPH_set_colors(0, 0, 0) + + uword xx + for xx in 0 to 319 step 32 { + cx16.GRAPH_clear() + ubyte q + for q in 0 to 31 { + cx16.GRAPH_set_colors(q, 2, 0) + cx16.r0 = xx+q + cx16.r1=0 + cx16.r2=rnd() + cx16.r3=199 + cx16.GRAPH_draw_line() + } + } + } +} + diff --git a/examples/cx16/textclock.p8 b/examples/cx16/textclock.p8 index 916ed986b..0f3dff8f6 100644 --- a/examples/cx16/textclock.p8 +++ b/examples/cx16/textclock.p8 @@ -8,18 +8,34 @@ main { sub start() { - cx16.r0L = 2020 - 1900 - cx16.r0H = 8 - cx16.r1L = 27 - cx16.r1H = 19 - cx16.r2L = 16 - cx16.r2H = 0 - cx16.r3L = 0 +; %asm {{ +; lda #$80 +; jsr cx16.screen_set_mode +; }} +; cx16.r0=0 +; cx16.GRAPH_init() +; %asm {{ +; lda #4 +; ldy #0 +; ldx #1 +; jsr cx16.GRAPH_set_colors +; }} +; cx16.GRAPH_clear() +; cx16.r0=10 +; cx16.r1=10 +; cx16.r2=100 +; cx16.r3=150 +; cx16.GRAPH_draw_line() +; +; repeat { +; } + + cx16.r0 = mkword(8, 2020 - 1900) + cx16.r1 = mkword(19, 27) + cx16.r2 = mkword(0, 16) + cx16.r3 = 0 cx16.clock_set_date_time() - - - cx16.screen_set_charset(3, 0) - ; c64.CHROUT(14) ; lowercase charset + cx16.screen_set_charset(3, 0) ; lowercase charset repeat { c64.CHROUT(19) ; HOME @@ -33,33 +49,33 @@ main { } sub print_date() { - txt.print_uw(1900 + cx16.r0L) + txt.print_uw(1900 + lsb(cx16.r0)) c64.CHROUT('-') - if cx16.r0H < 10 + if msb(cx16.r0) < 10 c64.CHROUT('0') - txt.print_ub(cx16.r0H) + txt.print_ub(msb(cx16.r0)) c64.CHROUT('-') - if cx16.r1L < 10 + if lsb(cx16.r1) < 10 c64.CHROUT('0') - txt.print_ub(cx16.r1L) + txt.print_ub(lsb(cx16.r1)) } sub print_time() { - if cx16.r1H < 10 + if msb(cx16.r1) < 10 c64.CHROUT('0') - txt.print_ub(cx16.r1H) + txt.print_ub(msb(cx16.r1)) c64.CHROUT(':') - if cx16.r2L < 10 + if lsb(cx16.r2) < 10 c64.CHROUT('0') - txt.print_ub(cx16.r2L) + txt.print_ub(lsb(cx16.r2)) c64.CHROUT(':') - if cx16.r2H < 10 + if msb(cx16.r2) < 10 c64.CHROUT('0') - txt.print_ub(cx16.r2H) + txt.print_ub(msb(cx16.r2)) c64.CHROUT('.') - if cx16.r3L < 10 + if lsb(cx16.r3) < 10 c64.CHROUT('0') - txt.print_ub(cx16.r3L) + txt.print_ub(lsb(cx16.r3)) } }