mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
cleanup cx16 things and added call signatures. c64graphics moved into built-in libraries.
This commit is contained in:
parent
3ad7fb010f
commit
0b55372b3b
@ -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
|
@ -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
|
||||
}}
|
||||
}
|
||||
|
@ -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...
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
4.0
|
||||
4.1-SNAPSHOT
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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<String>
|
||||
var zeropage: Zeropage
|
||||
val initSystemProcname: String
|
||||
val cpu: String
|
||||
val cpu: CpuType
|
||||
|
||||
fun initializeZeropage(compilerOptions: CompilationOptions)
|
||||
fun getFloat(num: Number): IMachineFloat
|
||||
|
@ -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
|
||||
|
@ -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)}")
|
||||
|
@ -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")
|
||||
|
@ -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...
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -12,6 +12,7 @@ What is Prog8?
|
||||
|
||||
This is an experimental compiled programming language targeting the 8-bit
|
||||
`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.
|
||||
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>`_.
|
||||
|
@ -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
|
||||
|
30
examples/cx16/graphics.p8
Normal file
30
examples/cx16/graphics.p8
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user