cleanup cx16 things and added call signatures. c64graphics moved into built-in libraries.

This commit is contained in:
Irmen de Jong
2020-08-28 21:42:53 +02:00
parent 3ad7fb010f
commit 0b55372b3b
19 changed files with 255 additions and 152 deletions

View File

@@ -2,9 +2,7 @@
; bitmap pixel graphics module for the C64 ; bitmap pixel graphics module for the C64
; only black/white monchrome for now ; only black/white monchrome for now
; assumes bitmap screen memory is $2000-$3fff
; 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.
graphics { graphics {
const uword bitmap_address = $2000 const uword bitmap_address = $2000
@@ -13,26 +11,27 @@ graphics {
; 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 |= %00100000
c64.VMCSB = (c64.VMCSB & %11110000) | %00001000 ; $2000-$3fff 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) 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. ; Bresenham algorithm.
; This code special cases various quadrant loops to allow simple ++ and -- operations. ; This code special cases various quadrant loops to allow simple ++ and -- operations.
; TODO rewrite this in optimized assembly
if y1>y2 { if y1>y2 {
; make sure dy is always positive to avoid 8 instead of just 4 special cases ; make sure dy is always positive to avoid 8 instead of just 4 special cases
swap(x1, x2) swap(x1, x2)
swap(y1, y2) swap(y1, y2)
} }
word d = 0 word @zp d = 0
ubyte positive_ix = true ubyte positive_ix = true
word dx = x2 - x1 as word word @zp dx = x2 - x1 as word
word dy = y2 as word - y1 as word word @zp dy = y2 as word - y1 as word
if dx < 0 { if dx < 0 {
dx = -dx dx = -dx
positive_ix = false positive_ix = false
@@ -99,10 +98,10 @@ graphics {
sub circle(uword xcenter, ubyte ycenter, ubyte radius) { sub circle(uword xcenter, ubyte ycenter, ubyte radius) {
; Midpoint algorithm ; Midpoint algorithm
ubyte ploty ubyte @zp ploty
ubyte xx = radius ubyte @zp xx = radius
ubyte yy = 0 ubyte @zp yy = 0
byte decisionOver2 = 1-xx as byte byte @zp decisionOver2 = 1-xx as byte
while xx>=yy { while xx>=yy {
plotx = xcenter + xx 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. ; 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 ; 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) ; 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 _y_lookup_hi
.byte $20, $20, $20, $20, $20, $20, $20, $20, $21, $21, $21, $21, $21, $21, $21, $21 .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 .byte $22, $22, $22, $22, $22, $22, $22, $22, $23, $23, $23, $23, $23, $23, $23, $23

View File

@@ -62,54 +62,22 @@ cx16 {
; spelling of the names is taken from the Commander X-16 rom sources ; spelling of the names is taken from the Commander X-16 rom sources
; the sixteen virtual 16-bit registers ; the sixteen virtual 16-bit registers
&ubyte r0 = $02 &uword r0 = $02
&ubyte r0L = $02 &uword r1 = $04
&ubyte r0H = $03 &uword r2 = $06
&ubyte r1 = $04 &uword r3 = $08
&ubyte r1L = $04 &uword r4 = $0a
&ubyte r1H = $05 &uword r5 = $0c
&ubyte r2 = $06 &uword r6 = $0e
&ubyte r2L = $06 &uword r7 = $10
&ubyte r2H = $07 &uword r8 = $12
&ubyte r3 = $08 &uword r9 = $14
&ubyte r3L = $08 &uword r10 = $16
&ubyte r3H = $09 &uword r11 = $18
&ubyte r4 = $0a &uword r12 = $1a
&ubyte r4L = $0a &uword r13 = $1c
&ubyte r4H = $0b &uword r14 = $1e
&ubyte r5 = $0c &uword r15 = $20
&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
; TODO subroutine args + soubroutine returnvalues + clobber registers ; TODO subroutine args + soubroutine returnvalues + clobber registers
@@ -118,7 +86,7 @@ cx16 {
romsub $ff4a = close_all() romsub $ff4a = close_all()
romsub $ff59 = lkupla() romsub $ff59 = lkupla()
romsub $ff5c = lkupsa() 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 $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) ; incompatible with C128 dlchr()
romsub $ff65 = pfkey() romsub $ff65 = pfkey()
romsub $ff6e = jsrfar() romsub $ff6e = jsrfar()
@@ -129,44 +97,59 @@ romsub $ff7d = primm()
; X16 additions ; X16 additions
romsub $ff44 = macptr() romsub $ff44 = macptr()
romsub $ff47 = enter_basic() romsub $ff47 = enter_basic(ubyte cold_or_warm @Pc)
romsub $ff68 = mouse_config() romsub $ff68 = mouse_config(ubyte shape @A, ubyte scale @X) clobbers (A, X, Y)
romsub $ff6b = mouse_get() romsub $ff6b = mouse_get(ubyte zpdataptr @X) clobbers(A)
romsub $ff71 = mouse_scan() romsub $ff71 = mouse_scan() clobbers(A, X, Y)
romsub $ff53 = joystick_scan() romsub $ff53 = joystick_scan() clobbers(A, X, Y)
romsub $ff56 = joystick_get() romsub $ff56 = joystick_get(ubyte joynr @A) -> ubyte @A, ubyte @X, ubyte @Y
romsub $ff4d = clock_set_date_time() romsub $ff4d = clock_set_date_time() clobbers(A, X, Y) ; args: r0, r1, r2, r3L
romsub $ff50 = clock_get_date_time() romsub $ff50 = clock_get_date_time() clobbers(A) ; outout args: r0, r1, r2, r3L
; high level graphics & fonts ; high level graphics & fonts
romsub $ff20 = GRAPH_init() romsub $ff20 = GRAPH_init() ; uses vectors=r0
romsub $ff23 = GRAPH_clear() romsub $ff23 = GRAPH_clear()
romsub $ff26 = GRAPH_set_window() romsub $ff26 = GRAPH_set_window() ; uses x=r0, y=r1, width=r2, height=r3
romsub $ff29 = GRAPH_set_colors() romsub $ff29 = GRAPH_set_colors(ubyte stroke @A, ubyte fill @X, ubyte background @Y)
romsub $ff2c = GRAPH_draw_line() romsub $ff2c = GRAPH_draw_line() ; uses x1=r0, y1=r1, x2=r2, y2=r3
romsub $ff2f = GRAPH_draw_rect() romsub $ff2f = GRAPH_draw_rect(ubyte fill @Pc) ; uses x=r0, y=r1, width=r2, height=r3, cornerradius=r4
romsub $ff32 = GRAPH_move_rect() romsub $ff32 = GRAPH_move_rect() ; uses sx=r0, sy=r1, tx=r2, ty=r3, width=r4, height=r5
romsub $ff35 = GRAPH_draw_oval() romsub $ff35 = GRAPH_draw_oval(ubyte fill @Pc) ; uses x=r0, y=r1, width=r2, height=r3
romsub $ff38 = GRAPH_draw_image() romsub $ff38 = GRAPH_draw_image() ; uses x=r0, y=r1, ptr=r2, width=r3, height=r4
romsub $ff3b = GRAPH_set_font() romsub $ff3b = GRAPH_set_font() ; uses ptr=r0
romsub $ff3e = GRAPH_get_char_size() 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() 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() ; misc
romsub $fef3 = sprite_set_position() 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 $fee4 = memory_fill() romsub $fef3 = sprite_set_position(ubyte number @A) ; also uses x=r0 and y=r1
romsub $fee7 = memory_copy() romsub $fee4 = memory_fill(ubyte value @A) ; uses address=r0, num_bytes=r1
romsub $feea = memory_crc() romsub $fee7 = memory_copy() ; uses source=r0, target=r1, num_bytes=r2
romsub $feed = memory_decompress() romsub $feea = memory_crc() ; uses address=r0, num_bytes=r1 result->r2
romsub $fedb = console_init() romsub $feed = memory_decompress() ; uses input=r0, output=r1 result->r1
romsub $fede = console_put_char() romsub $fedb = console_init() ; uses x=r0, y=r1, width=r2, height=r3
romsub $fee1 = console_get_char() romsub $fede = console_put_char(ubyte char @A, ubyte wrapping @Pc)
romsub $fed8 = console_put_image() romsub $fee1 = console_get_char() -> ubyte @A
romsub $fed5 = console_set_paging_message() romsub $fed8 = console_put_image() ; uses ptr=r0, width=r1, height=r2
romsub $fed2 = kbdbuf_put() romsub $fed5 = console_set_paging_message() ; uses messageptr=r0
romsub $fecf = entropy_get() romsub $fed2 = kbdbuf_put(ubyte key @A)
romsub $fecf = entropy_get() -> ubyte @A, ubyte @X, ubyte @Y
romsub $fecc = monitor() romsub $fecc = monitor()
@@ -179,9 +162,8 @@ asmsub init_system() {
%asm {{ %asm {{
sei sei
cld cld
lda #0 stz $00
sta $00 stz $01
sta $01
jsr c64.IOINIT jsr c64.IOINIT
jsr c64.RESTOR jsr c64.RESTOR
jsr c64.CINT jsr c64.CINT
@@ -191,9 +173,6 @@ asmsub init_system() {
clc clc
clv clv
cli cli
lda #66
clc
jsr console_put_char
rts rts
}} }}
} }

View File

@@ -59,7 +59,7 @@ multiply_words .proc
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG_X
mult16 lda #$00 mult16 lda #0
sta result+2 ; clear upper bits of product sta result+2 ; clear upper bits of product
sta result+3 sta result+3
ldx #16 ; for all 16 bits... ldx #16 ; for all 16 bits...

View File

@@ -960,7 +960,7 @@ _result_maxuw .word 0
.pend .pend
func_max_w .proc func_max_w .proc
lda #$00 lda #0
sta _result_maxw sta _result_maxw
lda #$80 lda #$80
sta _result_maxw+1 sta _result_maxw+1

View File

@@ -1 +1 @@
4.0 4.1-SNAPSHOT

View File

@@ -915,9 +915,6 @@ internal class AstChecker(private val program: Program,
val argIDt = arg.first.value.inferType(program) val argIDt = arg.first.value.inferType(program)
if (!argIDt.isKnown) if (!argIDt.isKnown)
return 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)
} }
} }
} }

View File

@@ -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 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 fun amountOfRtsInAsm(): Int = statements
.asSequence() .asSequence()

View File

@@ -11,6 +11,11 @@ internal interface IMachineFloat {
fun makeFloatFillAsm(): String fun makeFloatFillAsm(): String
} }
internal enum class CpuType {
CPU6502,
CPU65c02
}
internal interface IMachineDefinition { internal interface IMachineDefinition {
val FLOAT_MAX_NEGATIVE: Double val FLOAT_MAX_NEGATIVE: Double
val FLOAT_MAX_POSITIVE: Double val FLOAT_MAX_POSITIVE: Double
@@ -24,7 +29,7 @@ internal interface IMachineDefinition {
val opcodeNames: Set<String> val opcodeNames: Set<String>
var zeropage: Zeropage var zeropage: Zeropage
val initSystemProcname: String val initSystemProcname: String
val cpu: String val cpu: CpuType
fun initializeZeropage(compilerOptions: CompilationOptions) fun initializeZeropage(compilerOptions: CompilationOptions)
fun getFloat(num: Number): IMachineFloat fun getFloat(num: Number): IMachineFloat

View File

@@ -2,6 +2,7 @@ package prog8.compiler.target.c64
import prog8.ast.Program import prog8.ast.Program
import prog8.compiler.* import prog8.compiler.*
import prog8.compiler.target.CpuType
import prog8.compiler.target.IMachineDefinition import prog8.compiler.target.IMachineDefinition
import prog8.compiler.target.IMachineFloat import prog8.compiler.target.IMachineFloat
import prog8.parser.ModuleImporter import prog8.parser.ModuleImporter
@@ -12,7 +13,7 @@ import kotlin.math.pow
internal object C64MachineDefinition: IMachineDefinition { internal object C64MachineDefinition: IMachineDefinition {
override val cpu = "6502" override val cpu = CpuType.CPU6502
// 5-byte cbm MFLPT format limitations: // 5-byte cbm MFLPT format limitations:
override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255

View File

@@ -9,6 +9,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.* import prog8.compiler.*
import prog8.compiler.target.CompilationTarget import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.CpuType
import prog8.compiler.target.IAssemblyGenerator 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
@@ -78,7 +79,11 @@ internal class AsmGen(private val program: Program,
private fun header() { private fun header() {
val ourName = this.javaClass.name 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("; $cpu assembly code for '${program.name}'")
out("; generated by $ourName on ${LocalDateTime.now().withNano(0)}") out("; generated by $ourName on ${LocalDateTime.now().withNano(0)}")

View File

@@ -4,6 +4,8 @@ import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.compiler.AssemblyError import prog8.compiler.AssemblyError
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.CpuType
import prog8.compiler.toHex import prog8.compiler.toHex
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import kotlin.math.absoluteValue 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.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
RegisterOrPair.X -> { RegisterOrPair.X -> {
// return value in X register has been discarded, just push a zero // 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 -> { RegisterOrPair.AX -> {
// return value in X register has been discarded, just push a zero in this place // 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 -> { RegisterOrPair.XY -> {
// return value in X register has been discarded, just push a zero in this place // 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 -> { DataType.UBYTE -> {
when(expr.type) { when(expr.type) {
DataType.UBYTE, DataType.BYTE -> {} 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") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_ub2float")
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
@@ -83,9 +103,14 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
asmgen.out(""" asmgen.out("""
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
ora #$7f ora #$7f
bmi + bmi +""")
lda #0 if(CompilationTarget.machine.cpu==CpuType.CPU65c02)
+ sta P8ESTACK_HI+1,x""") 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") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float")
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")

View File

@@ -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 // output the code to setup the parameters and perform the actual call
// does NOT output the code to deal with the result values! // 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 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) 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... asmgen.out(" stx P8ZP_SCRATCH_REG_X") // we only save X for now (required! is the eval stack pointer), screw A and Y...

View File

@@ -5,6 +5,8 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.AssemblyError import prog8.compiler.AssemblyError
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.CpuType
import prog8.compiler.target.c64.codegen.AsmGen import prog8.compiler.target.c64.codegen.AsmGen
import prog8.compiler.toHex import prog8.compiler.toHex
@@ -706,7 +708,16 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
// optimized case for float zero // optimized case for float zero
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { 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 lda #0
sta ${target.asmVarname} sta ${target.asmVarname}
sta ${target.asmVarname}+1 sta ${target.asmVarname}+1

View File

@@ -5,6 +5,7 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
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.c64.codegen.AsmGen import prog8.compiler.target.c64.codegen.AsmGen
import prog8.compiler.toHex import prog8.compiler.toHex
@@ -736,9 +737,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"&" -> { "&" -> {
when { when {
value == 0 -> asmgen.out(" lda #0 | sta $name | sta $name+1") value == 0 -> {
value and 255 == 0 -> asmgen.out(" lda #0 | sta $name | lda $name+1 | and #>$value | sta $name+1") if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
value < 0x0100 -> asmgen.out(" lda $name | and #$value | sta $name | lda #0 | sta $name+1") 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") 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) { when (outerCastDt) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
when(target.kind) { 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 -> { TargetStorageKind.ARRAY -> {
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, target.datatype, CpuRegister.Y, true) 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") else -> throw AssemblyError("weird target")
} }
} }

View File

@@ -2,6 +2,7 @@ package prog8.compiler.target.cx16
import prog8.ast.Program import prog8.ast.Program
import prog8.compiler.* import prog8.compiler.*
import prog8.compiler.target.CpuType
import prog8.compiler.target.IMachineDefinition import prog8.compiler.target.IMachineDefinition
import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.c64.C64MachineDefinition
import prog8.parser.ModuleImporter import prog8.parser.ModuleImporter
@@ -9,7 +10,7 @@ import java.io.IOException
internal object CX16MachineDefinition: IMachineDefinition { internal object CX16MachineDefinition: IMachineDefinition {
override val cpu = "65c02" override val cpu = CpuType.CPU65c02
// 5-byte cbm MFLPT format limitations: // 5-byte cbm MFLPT format limitations:
override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255 override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255

View File

@@ -12,6 +12,7 @@ What is Prog8?
This is an experimental compiled programming language targeting the 8-bit This is an experimental compiled programming language targeting the 8-bit
`6502 <https://en.wikipedia.org/wiki/MOS_Technology_6502>`_ / `6502 <https://en.wikipedia.org/wiki/MOS_Technology_6502>`_ /
`65c02 <https://en.wikipedia.org/wiki/MOS_Technology_65C02>`_ /
`6510 <https://en.wikipedia.org/wiki/MOS_Technology_6510>`_ microprocessor. `6510 <https://en.wikipedia.org/wiki/MOS_Technology_6510>`_ microprocessor.
This CPU is from the late 1970's and early 1980's and was used in many home computers from that era, 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 <https://en.wikipedia.org/wiki/Commodore_64>`_. such as the `Commodore-64 <https://en.wikipedia.org/wiki/Commodore_64>`_.

View File

@@ -32,7 +32,7 @@ main {
repeat { repeat {
rotate_vertices(msb(anglex), msb(angley), msb(anglez)) rotate_vertices(msb(anglex), msb(angley), msb(anglez))
graphics.clear_screen() graphics.clear_screen(1, 0)
draw_lines() draw_lines()
anglex-=500 anglex-=500
angley+=217 angley+=217

30
examples/cx16/graphics.p8 Normal file
View File

@@ -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()
}
}
}
}

View File

@@ -8,18 +8,34 @@ main {
sub start() { sub start() {
cx16.r0L = 2020 - 1900 ; %asm {{
cx16.r0H = 8 ; lda #$80
cx16.r1L = 27 ; jsr cx16.screen_set_mode
cx16.r1H = 19 ; }}
cx16.r2L = 16 ; cx16.r0=0
cx16.r2H = 0 ; cx16.GRAPH_init()
cx16.r3L = 0 ; %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.clock_set_date_time()
cx16.screen_set_charset(3, 0) ; lowercase charset
cx16.screen_set_charset(3, 0)
; c64.CHROUT(14) ; lowercase charset
repeat { repeat {
c64.CHROUT(19) ; HOME c64.CHROUT(19) ; HOME
@@ -33,33 +49,33 @@ main {
} }
sub print_date() { sub print_date() {
txt.print_uw(1900 + cx16.r0L) txt.print_uw(1900 + lsb(cx16.r0))
c64.CHROUT('-') c64.CHROUT('-')
if cx16.r0H < 10 if msb(cx16.r0) < 10
c64.CHROUT('0') c64.CHROUT('0')
txt.print_ub(cx16.r0H) txt.print_ub(msb(cx16.r0))
c64.CHROUT('-') c64.CHROUT('-')
if cx16.r1L < 10 if lsb(cx16.r1) < 10
c64.CHROUT('0') c64.CHROUT('0')
txt.print_ub(cx16.r1L) txt.print_ub(lsb(cx16.r1))
} }
sub print_time() { sub print_time() {
if cx16.r1H < 10 if msb(cx16.r1) < 10
c64.CHROUT('0') c64.CHROUT('0')
txt.print_ub(cx16.r1H) txt.print_ub(msb(cx16.r1))
c64.CHROUT(':') c64.CHROUT(':')
if cx16.r2L < 10 if lsb(cx16.r2) < 10
c64.CHROUT('0') c64.CHROUT('0')
txt.print_ub(cx16.r2L) txt.print_ub(lsb(cx16.r2))
c64.CHROUT(':') c64.CHROUT(':')
if cx16.r2H < 10 if msb(cx16.r2) < 10
c64.CHROUT('0') c64.CHROUT('0')
txt.print_ub(cx16.r2H) txt.print_ub(msb(cx16.r2))
c64.CHROUT('.') c64.CHROUT('.')
if cx16.r3L < 10 if lsb(cx16.r3) < 10
c64.CHROUT('0') c64.CHROUT('0')
txt.print_ub(cx16.r3L) txt.print_ub(lsb(cx16.r3))
} }
} }