From b5ce4095927072e0ae3d3de34ced70b2920a38ef Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 26 Jun 2025 20:06:36 +0200 Subject: [PATCH 1/5] clarify booleans --- docs/source/variables.rst | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/docs/source/variables.rst b/docs/source/variables.rst index 38eee3a5c..dc5a48996 100644 --- a/docs/source/variables.rst +++ b/docs/source/variables.rst @@ -244,16 +244,9 @@ you have to make sure the resulting value fits into the byte or word size of the Booleans ^^^^^^^^ -Booleans are a distinct type in Prog8 and can have only the values ``true`` or ``false``. -It can be casted to and from other integer types though -where a nonzero integer is considered to be true, and zero is false. -Logical expressions, comparisons and some other code tends to compile more efficiently if -you explicitly use ``bool`` types instead of 0/1 integers. -The in-memory representation of a boolean value is just a byte containing 0 or 1. - -If you find that you need a whole bunch of boolean variables or perhaps even an array of them, -consider using integer bit mask variable + bitwise operators instead. -This saves a lot of memory and may be faster as well. +Booleans are a distinct type called ``bool`` in Prog8 and can have only the values ``true`` or ``false``. +In memory, they are stored as a byte containing 0 or 1. +You can cast any numeric to a bool, in which case 0 will become ``false`` and any nonzero value will become ``true``. Floating point numbers From 51cb6aad502c27d22b9bff13e88b6f52bee43db8 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 27 Jun 2025 17:39:31 +0200 Subject: [PATCH 2/5] add c128.PRIMM() --- compiler/res/prog8lib/c128/syslib.p8 | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index cbbd5816a..9fc049460 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -321,6 +321,7 @@ c128 { extsub $FF6E = JSRFAR() extsub $FF68 = SETBNK(ubyte databank @A, ubyte filenamebank @X) +extsub $ff7d = PRIMM() ; ---- C128 specific system utility routines: ---- From aa36e6b19f53fbea84f2ad9a500d0c8dca22f374 Mon Sep 17 00:00:00 2001 From: markjreed Date: Fri, 27 Jun 2025 12:13:26 -0400 Subject: [PATCH 3/5] flesh out C128-specific KERNAL calls (#170) * flesh out C128-specific KERNAL calls * fix: typo in comment * fix: typo in comment * fix: include return values of INDCMP * fix: rearrange return values of INDCMP --- compiler/res/prog8lib/c128/syslib.p8 | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index 9fc049460..1f5373116 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -319,9 +319,25 @@ c128 { ; TODO c128 a bunch of kernal routines are missing here that are specific to the c128 -extsub $FF6E = JSRFAR() -extsub $FF68 = SETBNK(ubyte databank @A, ubyte filenamebank @X) -extsub $ff7d = PRIMM() +extsub $FF47 = SPIN_SPOUT() clobbers(A) ; set up serial bus for fast communications mode +extsub $FF4A = CLOSE_ALL(ubyte device @X) clobbers(X) ; close all channels to specific device +extsub $FF4D = C64_MODE() ; restart machine in C64 mode (does not return) +extsub $FF50 = DMA_CALL(ubyte bank @X, ubyte command @Y) clobbers(A,X) ; send a command to a DMA device +extsub $FF53 = BOOT_CALL(ubyte device @X, ubyte drive @A) clobbers(A,X,Y) ; try to autoboot the given disk +extsub $FF56 = PHOENIX() clobbers(A,X,Y) ; search for and autostart ROMs, cartridges, then default disk +extsub $FF59 = LKUPLA(ubyte lfn @A) -> bool @Pc, ubyte @X ; look up logical file number to see if it's open; returns device +extsub $FF5C = LKUPSA(ubyte sa @Y) -> bool @Pc, ubyte @A, ubyte @X ; look up secondary address to see if it's in use; returns lfn and device +extsub $FF5F = SWAPPER() clobbers(A,X,Y) ; swap active screen (between 40- and 80-column) +extsub $FF62 = DLCHR() clobbers(A,X,Y) ; copy character ROM into VDC video RAM +extsub $FF65 = PFKEY(ubyte zpaddr @A, ubyte key @X, ubyte length @Y) ; redefine programmable function key (string descriptor in zp, addr in A) +extsub $FF68 = SETBNK(ubyte data_bank @A, ubyte filename_bank @X) ; set memory bank for load/save +extsub $FF6B = GETCFG(ubyte bank @X) -> ubyte @A ; translate bank number to MMU configuration register value +extsub $FF6E = JSRFAR() clobbers(A,X) ; call routine in another bank (parameters set in zero page addresses 2-8) +extsub $FF71 = JMPFAR() clobbers(A,X) ; jump without return to another bank (parameters set as for JSRFAR) +extsub $FF74 = INDFET(ubyte zpaddr @A, ubyte bank @X, ubyte offset @Y) clobbers(X) -> ubyte @A ; fetch byte from another bank (address in zp, ptr in A) +extsub $FF77 = INDSTA(ubyte value @A, ubyte bank @X, ubyte offset @Y) clobbers(X) ; store byte to another bank (address in zp, ptr in $02b9) +extsub $FF7A = INDCMP(ubyte value @A, ubyte bank @X, ubyte offset @Y) clobbers(X) -> bool @Pz, bool @Pc, bool @Pv; compare byte in another bank (address in zp, ptr in $02c8) +extsub $FF7D = PRIMM() ; print immediate string ; ---- C128 specific system utility routines: ---- From 6a9a82ff9d3cc1f443be65c443576f921765f82c Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 27 Jun 2025 18:14:36 +0200 Subject: [PATCH 4/5] doc --- compiler/res/prog8lib/c128/syslib.p8 | 8 +++---- .../_static/symboldumps/skeletons-c128.txt | 21 +++++++++++++++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index 1f5373116..c6a45e8f8 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -317,13 +317,11 @@ c128 { &ubyte VM4 = $0A2F ; starting page for VDC attribute mem -; TODO c128 a bunch of kernal routines are missing here that are specific to the c128 - extsub $FF47 = SPIN_SPOUT() clobbers(A) ; set up serial bus for fast communications mode extsub $FF4A = CLOSE_ALL(ubyte device @X) clobbers(X) ; close all channels to specific device -extsub $FF4D = C64_MODE() ; restart machine in C64 mode (does not return) -extsub $FF50 = DMA_CALL(ubyte bank @X, ubyte command @Y) clobbers(A,X) ; send a command to a DMA device -extsub $FF53 = BOOT_CALL(ubyte device @X, ubyte drive @A) clobbers(A,X,Y) ; try to autoboot the given disk +extsub $FF4D = C64_MODE() ; restart machine in C64 mode (does not return) +extsub $FF50 = DMA_CALL(ubyte bank @X, ubyte command @Y) clobbers(A,X) ; send a command to a DMA device +extsub $FF53 = BOOT_CALL(ubyte device @X, ubyte drive @A) clobbers(A,X,Y) ; try to autoboot the given disk extsub $FF56 = PHOENIX() clobbers(A,X,Y) ; search for and autostart ROMs, cartridges, then default disk extsub $FF59 = LKUPLA(ubyte lfn @A) -> bool @Pc, ubyte @X ; look up logical file number to see if it's open; returns device extsub $FF5C = LKUPSA(ubyte sa @Y) -> bool @Pc, ubyte @A, ubyte @X ; look up secondary address to see if it's in use; returns lfn and device diff --git a/docs/source/_static/symboldumps/skeletons-c128.txt b/docs/source/_static/symboldumps/skeletons-c128.txt index 925b0f136..17b0b91a9 100644 --- a/docs/source/_static/symboldumps/skeletons-c128.txt +++ b/docs/source/_static/symboldumps/skeletons-c128.txt @@ -494,8 +494,25 @@ c128 { &ubyte VM2 &ubyte VM3 &ubyte VM4 - JSRFAR () = $ff6e - SETBNK (ubyte databank @A, ubyte filenamebank @X) = $ff68 + BOOT_CALL (ubyte device @X, ubyte drive @A) -> clobbers (A,X,Y) = $ff53 + C64_MODE () = $ff4d + CLOSE_ALL (ubyte device @X) -> clobbers (X) = $ff4a + DLCHR () -> clobbers (A,X,Y) = $ff62 + DMA_CALL (ubyte bank @X, ubyte command @Y) -> clobbers (A,X) = $ff50 + GETCFG (ubyte bank @X) -> ubyte @A = $ff6b + INDCMP (ubyte value @A, ubyte bank @X, ubyte offset @Y) -> clobbers (X) -> bool @Pz, bool @Pc, bool @Pv = $ff7a + INDFET (ubyte zpaddr @A, ubyte bank @X, ubyte offset @Y) -> clobbers (X) -> ubyte @A = $ff74 + INDSTA (ubyte value @A, ubyte bank @X, ubyte offset @Y) -> clobbers (X) = $ff77 + JMPFAR () -> clobbers (A,X) = $ff71 + JSRFAR () -> clobbers (A,X) = $ff6e + LKUPLA (ubyte lfn @A) -> bool @Pc, ubyte @X = $ff59 + LKUPSA (ubyte sa @Y) -> bool @Pc, ubyte @A, ubyte @X = $ff5c + PFKEY (ubyte zpaddr @A, ubyte key @X, ubyte length @Y) = $ff65 + PHOENIX () -> clobbers (A,X,Y) = $ff56 + PRIMM () = $ff7d + SETBNK (ubyte data_bank @A, ubyte filename_bank @X) = $ff68 + SPIN_SPOUT () -> clobbers (A) = $ff47 + SWAPPER () -> clobbers (A,X,Y) = $ff5f banks (ubyte banks @A) disable_basic () -> clobbers (A) getbanks () -> ubyte @A From 1b420f7fe75e59226f6dff40a892a47c7c143c77 Mon Sep 17 00:00:00 2001 From: gillham Date: Sun, 29 Jun 2025 04:14:34 -0500 Subject: [PATCH 5/5] Add a preliminary external custom target for the Foenix F256 family of modern retro computers. (#171) --- README.md | 2 +- docs/source/index.rst | 4 +- docs/source/libraries.rst | 1 + examples/customtarget/Makefile | 5 +- .../customtarget/libraries/f256/syslib.p8 | 907 ++++++++++++++++++ .../customtarget/libraries/f256/textio.p8 | 446 +++++++++ examples/customtarget/readme.txt | 5 +- examples/customtarget/src/f256-hello.p8 | 84 ++ .../targetconfigs/f256.properties | 55 ++ 9 files changed, 1503 insertions(+), 6 deletions(-) create mode 100644 examples/customtarget/libraries/f256/syslib.p8 create mode 100644 examples/customtarget/libraries/f256/textio.p8 create mode 100644 examples/customtarget/src/f256-hello.p8 create mode 100644 examples/customtarget/targetconfigs/f256.properties diff --git a/README.md b/README.md index a3bf47ef3..2a4e52db9 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ What does Prog8 provide? - "c64": Commodore-64 (6502 like CPU) - "c128": Commodore-128 (6502 like CPU - the Z80 cpu mode is not supported) - "pet32": Commodore PET (limited support) -- via external configurable targets: Atari 800 XL, Neo6502, NES, C64OS, ... +- via external configurable targets: Atari 800 XL, Neo6502, NES, C64 OS, Foenix F256, ... - If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag) diff --git a/docs/source/index.rst b/docs/source/index.rst index b76c45a77..01fc66f59 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -27,8 +27,8 @@ You can compile programs for various machines that are built in into the compile * Commodore 128 (limited support) * Commodore PET (limited support) * any other 65(C)02 target machine or setup can be configured to a great extent in a user written configuration file. - There are some examples included for the Atari 800 XL, NEO6502 and such. -* some users have been experimenting with a NES and a C64OS target as well. + There are some examples included for the Atari 800 XL, NEO6502, Foenix F256, and such. +* some users have been experimenting with a NES and a C64 OS target as well. Some language features are mentioned below, and you can also read :ref:`comparingprog8` if you want to quickly read about how Prog8 compares to well-known other languages. diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index ef1f0f834..3f0c2149b 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -1032,6 +1032,7 @@ sys (part of syslib) - 7 = Neo6502 - 8 = Atari 8 bits - 16 = Commander X16 + - 25 = Foenix F256 family - 64 = Commodore 64 - 128 = Commodore 128 - 255 = Virtual machine diff --git a/examples/customtarget/Makefile b/examples/customtarget/Makefile index 39ab78d84..8367e0f79 100644 --- a/examples/customtarget/Makefile +++ b/examples/customtarget/Makefile @@ -1,6 +1,6 @@ .PHONY: all clean -all: main-c64.prg main-cx16.prg main-pet.prg atari-hello.xex atari-fibonacci.xex neo-hello.bin +all: main-c64.prg main-cx16.prg main-pet.prg atari-hello.xex atari-fibonacci.xex neo-hello.bin f256-hello.bin clean: rm -f *.prg *.PRG *.xex *.bin *.asm *.vice-* @@ -26,6 +26,9 @@ atari-fibonacci.xex: src/atari-fibonacci.p8 neo-hello.bin: src/neo-hello.p8 prog8c -target targetconfigs/neo6502.properties src/neo-hello.p8 +f256-hello.bin: src/f256-hello.p8 + prog8c -target targetconfigs/f256.properties src/f256-hello.p8 + run-atari-hello: prog8c -target targetconfigs/atari.properties src/atari-hello.p8 -emu diff --git a/examples/customtarget/libraries/f256/syslib.p8 b/examples/customtarget/libraries/f256/syslib.p8 new file mode 100644 index 000000000..2434ceed6 --- /dev/null +++ b/examples/customtarget/libraries/f256/syslib.p8 @@ -0,0 +1,907 @@ +; Prog8 definitions for the Foenix F256x + +%option no_symbol_prefixing, ignore_unused + +; compatiblity layer +cbm { +%option no_symbol_prefixing, ignore_unused + + ; dumb hack to make some code compile. + ; TODO: figure out how the kernel clock works, not just + ; reading the RTC hardware + ubyte TIME_LO = $00 + + ; + ; Only reads keys right now. + ; + asmsub CHRIN() -> ubyte @A { + %asm {{ +- stz f256.event.type ; invalidate existing event type + jsr f256.event.NextEvent + lda f256.event.type + cmp #f256.event.key.PRESSED + bne - + lda f256.event.key.ascii ; return upper or lower ASCII + rts + }} +} + + ; I though the alias was working but it isn't. + ;alias CHROUT = f256.chrout + asmsub CHROUT(ubyte character @ A) { + %asm {{ + jmp f256.chrout + }} + } + + ; TODO: set carry properly? + ; TODO: on CBM any device other than keyboard or RS-232 should jump to CHRIN + asmsub GETIN() -> bool @Pc, ubyte @A { + %asm {{ +- stz f256.event.type ; invalidate previous event type + lda f256.event.pending ; return zero if no pending event + cmp #$ff ; $ff == no events pending + beq + ; done. + jsr f256.event.NextEvent + lda f256.event.type + cmp #f256.event.key.PRESSED + bne - + ;lda f256.event.key.raw ; return key id / scan code? (case issue?) + lda f256.event.key.ascii ; return upper or lower ASCII + clc ; clear carry when returning character + rts ; return ascii key ++ sec ; set carry when no character returned + lda #0 ; return zero if no key + rts + }} +} + + + asmsub GETINx() -> bool @Pc, ubyte @A { + %asm {{ + rts + }} + } +} + +f256 { +%option no_symbol_prefixing, ignore_unused, force_output + ; + ; Foenix F256 hardware definitions + ; + + ; MMU controls + &ubyte mem_ctrl = $0000 + &ubyte io_ctrl = $0001 + + ; text screen size + const ubyte DEFAULT_WIDTH = 80 + const ubyte DEFAULT_HEIGHT = 60 + + ; screen / color memory + const uword Colors = $C000 ; IO page 2 + const uword Screen = $C000 ; IO page 3 + + ; self tracked screen coordinates + ; potentially could be at $04/$05 in reserved ZP area? + ubyte screen_row = 0 + ubyte screen_col = 0 + ubyte screen_color = $f2 ; default text/background color + &uword screen_ptr = $02 ; and $03. used to calculate screen/color ram offsets + + ; + ; calculates screen memory pointer for the start of a row + ; in screen_ptr in zeropage. + ; ldy column + ; sta (screen_ptr), y + ; + asmsub rowptr(ubyte row @Y) { + %asm {{ + stz screen_ptr ; reset to start of screen ram + lda #>f256.Screen + sta screen_ptr+1 + cpy #0 ; row in @Y will be our loop counter + beq ptr_done + rowloop: + clc + lda screen_ptr ; load count + adc #DEFAULT_WIDTH + bcc + + inc screen_ptr+1 + + sta screen_ptr + dey + bne rowloop + ptr_done: + rts + }} + } + + ; + ; calculates screen memory pointer for the specific col/row + ; in screen_ptr in zeropage. Points directly to character after. + ; ldy #0 + ; sta (screen_ptr), y + ; + asmsub chrptr(ubyte col @X, ubyte row @Y) clobbers(A) { + %asm {{ + phx ; preserve col + jsr rowptr ; calculate pointer to row + pla ; restore col + clc + adc screen_ptr + sta screen_ptr + bcc + + inc screen_ptr+1 + + rts + }} + } + + asmsub chrout(ubyte character @ A) { + %asm {{ + phx ; preserve x + phy ; preserve y + cmp #$0d ; check for carriage return + beq crlf + cmp #$0a ; check for line feed + beq crlf + pha ; preserve a + ldy screen_row + jsr rowptr ; calculates screen pointer to start of row + ldy screen_col ; column will be our index against the row pointer + lda #2 + sta f256.io_ctrl ; map in screen memory + pla + sta (screen_ptr),y + lda #3 + sta f256.io_ctrl ; map in color memory + lda screen_color + sta (screen_ptr),y + lda #0 + sta f256.io_ctrl ; return to default map + inc screen_col + lda screen_col + cmp #DEFAULT_WIDTH + bcc + ; less than DEFAULT_WIDTH + crlf: + stz screen_col + inc screen_row + lda screen_row + cmp #DEFAULT_HEIGHT + bcc + + sec + jsr scroll_up + dec screen_row + + ply + plx + rts + }} + } + + ; + ; implement here so chrout can work without importing textio. + ; + asmsub scroll_up (bool alsocolors @ Pc) clobbers(A,X) { + ; ---- scroll the whole screen 1 character up + ; contents of the bottom row are unchanged, you should refill/clear this yourself + ; Carry flag determines if screen color data must be scrolled too + %asm {{ + bcc _scroll_screen + + + ; scroll the screen and the color memory + ldx #DEFAULT_WIDTH-1 + - + lda #2 + sta f256.io_ctrl ; map in screen memory + .for row=1, row<=DEFAULT_HEIGHT, row+=1 + lda f256.Screen + DEFAULT_WIDTH*row,x + sta f256.Screen + DEFAULT_WIDTH*(row-1),x + .next + lda #3 + sta f256.io_ctrl ; map in color memory + .for row=1, row<=DEFAULT_HEIGHT, row+=1 + lda f256.Colors + DEFAULT_WIDTH*row,x + sta f256.Colors + DEFAULT_WIDTH*(row-1),x + .next + + + dex + bpl - + lda #0 + sta f256.io_ctrl ; restore I/O configuration + rts + + _scroll_screen ; scroll only the screen memory + ldx #DEFAULT_WIDTH-1 + - + lda #2 + sta f256.io_ctrl ; map in screen memory + .for row=1, row<=DEFAULT_HEIGHT, row+=1 + lda f256.Screen + DEFAULT_WIDTH*row,x + sta f256.Screen + DEFAULT_WIDTH*(row-1),x + .next + dex + bpl - + lda #0 + sta f256.io_ctrl ; restore I/O configuration + rts + }} + } + + ; args + sub args() { + &uword ext = $00f8 + &ubyte extlen = $00fa + &uword buf = $00fb + &ubyte buflen = $00fd + &uword ptr = $00fe + } + + ; kernel event calls & event types + sub event() { + &uword dest = $00f0 + &ubyte pending = $00f2 + &ubyte[8] packet = $00e8 ; 8-byte buffer in ZP for kernel events. + + ; event buffer fields + &ubyte type = &packet ; event type (definitions below) + &ubyte buf = &packet+1 ; page id or zero + &ubyte ext = &packet+2 ; page id or zero + + ; kernel event calls + extsub $ff00 = NextEvent() ; Copy next event to application buffer. + extsub $ff04 = ReadData() ; Copy primary bulk event data to application. + extsub $ff08 = ReadExt() ; Copy secondary bulk event data to application. + + sub init() { + f256.event.dest = &f256.event.packet + } + + ; event type definitions + const uword reserved = $00 ; $01 + const uword deprecated = $02 ; $03 + const uword JOYSTICK = $04 ; $05 ; game controller changes + const uword DEVICE = $06 ; $07 ; device added or removed + sub key() { + const uword PRESSED = $08 ; $09 + const uword RELEASED = $0a ; $0b + &ubyte keyboard = &packet+3 ; keyboard id + &ubyte raw = &packet+4 ; raw key id/code + &ubyte ascii = &packet+5 ; ASCII value + &ubyte flags = &packet+6 ; flag (META) + const ubyte META = $80 ; meta key no ASCII value + } + sub mouse() { + const uword DELTA = $0c ; $0d + const uword CLICKS = $0e ; $0f + } + sub block() { + const uword NAME = $10 ; $11 + const uword SIZE = $12 ; $13 + const uword DATA = $14 ; $15 ; read request succeeded + const uword WROTE = $16 ; $17 ; write request completed + const uword FORMATTED = $18 ; $19 ; low-level format completed + const uword ERROR = $1a ; $1b + } + sub fs() { + const uword SIZE = $1c ; $1d + const uword CREATED = $1e ; $1f + const uword CHECKED = $20 ; $21 + const uword DATA = $22 ; $23 ; read request succeeded + const uword WROTE = $24 ; $25 ; write request completed + const uword ERROR = $26 ; $27 + } + sub file() { + const uword NOT_FOUND = $28 ; $29 ; file was not found + const uword OPENED = $2a ; $2b ; file successfully opened + const uword DATA = $2c ; $2d ; read request succeeded + const uword WROTE = $2e ; $2f ; write request completed + const uword EOF = $30 ; $31 ; all file data has been read + const uword CLOSED = $32 ; $33 ; close request completed + const uword RENAMED = $34 ; $35 ; renamed request completed + const uword DELETED = $36 ; $37 ; delete request completed + const uword ERROR = $38 ; $39 ; error occurred, close file if opened + const uword SEEK = $3a ; $3b ; seek request completed + } + sub directory() { + const uword OPENED = $3c ; $3d ; directory open succeeded + const uword VOLUME = $3e ; $3f ; volume record found + const uword FILE = $40 ; $41 ; file record found + const uword FREE = $42 ; $43 ; file-system free-space record found + const uword EOF = $44 ; $45 ; all data read + const uword CLOSED = $46 ; $47 ; directory file closed + const uword ERROR = $48 ; $49 ; error occurred, close if opened + const uword CREATED = $4a ; $4b ; directory created + const uword DELETED = $4a ; $4b ; directory deleted + } + sub net() { + const uword TCP = $4c ; $4d + const uword UDP = $4e ; $4f + } + sub timer() { + const uword EXPIRED = $50 ; $51 + } + sub clock() { + const uword TICK = $52 ; $53 + } + sub irq() { + const uword IRQ = $54 ; $55 + } + } + + ; kernel display calls + sub display() { + &ubyte x = $00f3 + &ubyte y = $00f4 + &uword color = &f256.args.ext + &uword text = &f256.args.buf + &ubyte buflen = &f256.args.buflen + const uword GetSize_ = $ffd0 ; Get screen dimensions + const uword DrawRow_ = $ffd4 ; Draw text/color buffers left-to-right + const uword DrawColumn_ = $ffd8 ; Draw text/color buffers top-to-bottom + } + + + + ; + &uword NMI_VEC = $FFFA ; 6502 nmi vector + &uword RESET_VEC = $FFFC ; 6502 reset vector + &uword IRQ_VEC = $FFFE ; 6502 interrupt vector + + ;%asminclude "api.asm" +} + +sys { + ; ------- lowlevel system routines -------- + + const ubyte target = 25 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 25=Foenix F256, 16=CommanderX16, 8=atari800XL, 7=Neo6502 + + const ubyte SIZEOF_BOOL = sizeof(bool) + const ubyte SIZEOF_BYTE = sizeof(byte) + const ubyte SIZEOF_UBYTE = sizeof(ubyte) + const ubyte SIZEOF_WORD = sizeof(word) + const ubyte SIZEOF_UWORD = sizeof(uword) + const ubyte SIZEOF_LONG = sizeof(long) +; const ubyte SIZEOF_POINTER = sizeof(&sys.wait) + const ubyte SIZEOF_FLOAT = 0 ; undefined, no floats supported + const byte MIN_BYTE = -128 + const byte MAX_BYTE = 127 + const ubyte MIN_UBYTE = 0 + const ubyte MAX_UBYTE = 255 + const word MIN_WORD = -32768 + const word MAX_WORD = 32767 + const uword MIN_UWORD = 0 + const uword MAX_UWORD = 65535 + ; MIN_FLOAT and MAX_FLOAT are defined in the floats module if importec + + + asmsub reset_system() { + ; Soft-reset the system back to initial power-on status + ; TODO + %asm {{ + sei + jmp (f256.RESET_VEC) + }} + } + + sub wait(uword jiffies) { + ; --- wait approximately the given number of jiffies (1/60th seconds) + ; TODO + } + + asmsub waitvsync() clobbers(A) { + ; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling. + ; TODO + %asm {{ + nop + rts + }} + } + + asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) { + ; Called when the compiler wants to assign a string value to another string. + %asm {{ + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda cx16.r0 + ldy cx16.r0+1 + jmp prog8_lib.strcpy + }} + } + + asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) { + ; note: only works for NON-OVERLAPPING memory regions! + ; note: can't be inlined because is called from asm as well + %asm {{ + ldx cx16.r0 + stx P8ZP_SCRATCH_W1 ; source in ZP + ldx cx16.r0+1 + stx P8ZP_SCRATCH_W1+1 + ldx cx16.r1 + stx P8ZP_SCRATCH_W2 ; target in ZP + ldx cx16.r1+1 + stx P8ZP_SCRATCH_W2+1 + cpy #0 + bne _longcopy + + ; copy <= 255 bytes + tay + bne _copyshort + rts ; nothing to copy + +_copyshort + dey + beq + +- lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + dey + bne - ++ lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + rts + +_longcopy + sta P8ZP_SCRATCH_B1 ; lsb(count) = remainder in last page + tya + tax ; x = num pages (1+) + ldy #0 +- lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + iny + bne - + inc P8ZP_SCRATCH_W1+1 + inc P8ZP_SCRATCH_W2+1 + dex + bne - + ldy P8ZP_SCRATCH_B1 + bne _copyshort + rts + }} + } + + asmsub memset(uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers(A,X,Y) { + %asm {{ + ldy cx16.r0 + sty P8ZP_SCRATCH_W1 + ldy cx16.r0+1 + sty P8ZP_SCRATCH_W1+1 + ldx cx16.r1 + ldy cx16.r1+1 + jmp prog8_lib.memset + }} + } + + asmsub memsetw(uword mem @R0, uword numwords @R1, uword value @AY) clobbers(A,X,Y) { + %asm {{ + ldx cx16.r0 + stx P8ZP_SCRATCH_W1 + ldx cx16.r0+1 + stx P8ZP_SCRATCH_W1+1 + ldx cx16.r1 + stx P8ZP_SCRATCH_W2 + ldx cx16.r1+1 + stx P8ZP_SCRATCH_W2+1 + jmp prog8_lib.memsetw + }} + } + + inline asmsub read_flags() -> ubyte @A { + %asm {{ + php + pla + }} + } + + inline asmsub clear_carry() { + %asm {{ + clc + }} + } + + inline asmsub set_carry() { + %asm {{ + sec + }} + } + + inline asmsub clear_irqd() { + %asm {{ + cli + }} + } + + inline asmsub set_irqd() { + %asm {{ + sei + }} + } + + inline asmsub irqsafe_set_irqd() { + %asm {{ + php + sei + }} + } + + inline asmsub irqsafe_clear_irqd() { + %asm {{ + plp + }} + } + + sub disable_caseswitch() { + ; no-op + } + + sub enable_caseswitch() { + ; no-op + } + + asmsub save_prog8_internals() { + %asm {{ + lda P8ZP_SCRATCH_B1 + sta save_SCRATCH_ZPB1 + lda P8ZP_SCRATCH_REG + sta save_SCRATCH_ZPREG + lda P8ZP_SCRATCH_W1 + sta save_SCRATCH_ZPWORD1 + lda P8ZP_SCRATCH_W1+1 + sta save_SCRATCH_ZPWORD1+1 + lda P8ZP_SCRATCH_W2 + sta save_SCRATCH_ZPWORD2 + lda P8ZP_SCRATCH_W2+1 + sta save_SCRATCH_ZPWORD2+1 + rts + .section BSS +save_SCRATCH_ZPB1 .byte ? +save_SCRATCH_ZPREG .byte ? +save_SCRATCH_ZPWORD1 .word ? +save_SCRATCH_ZPWORD2 .word ? + .send BSS + ; !notreached! + }} + } + + asmsub restore_prog8_internals() { + %asm {{ + lda save_prog8_internals.save_SCRATCH_ZPB1 + sta P8ZP_SCRATCH_B1 + lda save_prog8_internals.save_SCRATCH_ZPREG + sta P8ZP_SCRATCH_REG + lda save_prog8_internals.save_SCRATCH_ZPWORD1 + sta P8ZP_SCRATCH_W1 + lda save_prog8_internals.save_SCRATCH_ZPWORD1+1 + sta P8ZP_SCRATCH_W1+1 + lda save_prog8_internals.save_SCRATCH_ZPWORD2 + sta P8ZP_SCRATCH_W2 + lda save_prog8_internals.save_SCRATCH_ZPWORD2+1 + sta P8ZP_SCRATCH_W2+1 + rts + }} + } + + asmsub exit(ubyte returnvalue @A) { + ; -- immediately exit the program with a return code in the A register + %asm {{ + sta p8_sys_startup.cleanup_at_exit._exitcode + ldx prog8_lib.orig_stackpointer + txs + jmp p8_sys_startup.cleanup_at_exit + }} + } + + asmsub exit2(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y) { + ; -- immediately exit the program with result values in the A, X and Y registers. + %asm {{ + sta p8_sys_startup.cleanup_at_exit._exitcode + stx p8_sys_startup.cleanup_at_exit._exitcodeX + sty p8_sys_startup.cleanup_at_exit._exitcodeY + ldx prog8_lib.orig_stackpointer + txs + jmp p8_sys_startup.cleanup_at_exit + }} + } + + asmsub exit3(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc) { + ; -- immediately exit the program with result values in the A, X and Y registers, and the Carry flag in the status register. + %asm {{ + sta p8_sys_startup.cleanup_at_exit._exitcode + lda #0 + rol a + sta p8_sys_startup.cleanup_at_exit._exitcarry + stx p8_sys_startup.cleanup_at_exit._exitcodeX + sty p8_sys_startup.cleanup_at_exit._exitcodeY + ldx prog8_lib.orig_stackpointer + txs + jmp p8_sys_startup.cleanup_at_exit + }} + } + + inline asmsub progend() -> uword @AY { + %asm {{ + lda #prog8_program_end + }} + } + + inline asmsub progstart() -> uword @AY { + %asm {{ + lda #prog8_program_start + }} + } + + inline asmsub push(ubyte value @A) { + %asm {{ + pha + }} + } + + inline asmsub pushw(uword value @AY) { + %asm {{ + pha + tya + pha + }} + } + + inline asmsub push_returnaddress(uword address @XY) { + %asm {{ + ; push like JSR would: address-1, MSB first then LSB + cpx #0 + bne + + dey ++ dex + tya + pha + txa + pha + }} + } + + inline asmsub pop() -> ubyte @A { + %asm {{ + pla + }} + } + + inline asmsub popw() -> uword @AY { + %asm {{ + pla + tay + pla + }} + } + +} + +cx16 { +; the sixteen virtual 16-bit registers in both normal unsigned mode and signed mode (s) + &uword r0 = $0010 + &uword r1 = $0012 + &uword r2 = $0014 + &uword r3 = $0016 + &uword r4 = $0018 + &uword r5 = $001a + &uword r6 = $001c + &uword r7 = $001e + &uword r8 = $0020 + &uword r9 = $0022 + &uword r10 = $0024 + &uword r11 = $0026 + &uword r12 = $0028 + &uword r13 = $002a + &uword r14 = $002c + &uword r15 = $002e + + ; signed word versions + &word r0s = $0010 + &word r1s = $0012 + &word r2s = $0014 + &word r3s = $0016 + &word r4s = $0018 + &word r5s = $001a + &word r6s = $001c + &word r7s = $001e + &word r8s = $0020 + &word r9s = $0022 + &word r10s = $0024 + &word r11s = $0026 + &word r12s = $0028 + &word r13s = $002a + &word r14s = $002c + &word r15s = $002e + + ; ubyte versions (low and high bytes) + &ubyte r0L = $0010 + &ubyte r1L = $0012 + &ubyte r2L = $0014 + &ubyte r3L = $0016 + &ubyte r4L = $0018 + &ubyte r5L = $001a + &ubyte r6L = $001c + &ubyte r7L = $001e + &ubyte r8L = $0020 + &ubyte r9L = $0022 + &ubyte r10L = $0024 + &ubyte r11L = $0026 + &ubyte r12L = $0028 + &ubyte r13L = $002a + &ubyte r14L = $002c + &ubyte r15L = $002e + + &ubyte r0H = $0011 + &ubyte r1H = $0013 + &ubyte r2H = $0015 + &ubyte r3H = $0017 + &ubyte r4H = $0019 + &ubyte r5H = $001b + &ubyte r6H = $001d + &ubyte r7H = $001f + &ubyte r8H = $0021 + &ubyte r9H = $0023 + &ubyte r10H = $0025 + &ubyte r11H = $0027 + &ubyte r12H = $0029 + &ubyte r13H = $002b + &ubyte r14H = $002d + &ubyte r15H = $002f + + ; signed byte versions (low and high bytes) + &byte r0sL = $0010 + &byte r1sL = $0012 + &byte r2sL = $0014 + &byte r3sL = $0016 + &byte r4sL = $0018 + &byte r5sL = $001a + &byte r6sL = $001c + &byte r7sL = $001e + &byte r8sL = $0020 + &byte r9sL = $0022 + &byte r10sL = $0024 + &byte r11sL = $0026 + &byte r12sL = $0028 + &byte r13sL = $002a + &byte r14sL = $002c + &byte r15sL = $002e + + &byte r0sH = $0011 + &byte r1sH = $0013 + &byte r2sH = $0015 + &byte r3sH = $0017 + &byte r4sH = $0019 + &byte r5sH = $001b + &byte r6sH = $001d + &byte r7sH = $001f + &byte r8sH = $0021 + &byte r9sH = $0023 + &byte r10sH = $0025 + &byte r11sH = $0027 + &byte r12sH = $0029 + &byte r13sH = $002b + &byte r14sH = $002d + &byte r15sH = $002f + + ; boolean versions + &bool r0bL = $0010 + &bool r1bL = $0012 + &bool r2bL = $0014 + &bool r3bL = $0016 + &bool r4bL = $0018 + &bool r5bL = $001a + &bool r6bL = $001c + &bool r7bL = $001e + &bool r8bL = $0020 + &bool r9bL = $0022 + &bool r10bL = $0024 + &bool r11bL = $0026 + &bool r12bL = $0028 + &bool r13bL = $002a + &bool r14bL = $002c + &bool r15bL = $002e + + &bool r0bH = $0011 + &bool r1bH = $0013 + &bool r2bH = $0015 + &bool r3bH = $0017 + &bool r4bH = $0019 + &bool r5bH = $001b + &bool r6bH = $001d + &bool r7bH = $001f + &bool r8bH = $0021 + &bool r9bH = $0023 + &bool r10bH = $0025 + &bool r11bH = $0027 + &bool r12bH = $0029 + &bool r13bH = $002b + &bool r14bH = $002d + &bool r15bH = $002f + + + asmsub save_virtual_registers() clobbers(A,Y) { + %asm {{ + ldy #31 + - lda cx16.r0,y + sta _cx16_vreg_storage,y + dey + bpl - + rts + + .section BSS + _cx16_vreg_storage + .word ?,?,?,?,?,?,?,? + .word ?,?,?,?,?,?,?,? + .send BSS + ; !notreached! + }} + } + + asmsub restore_virtual_registers() clobbers(A,Y) { + %asm {{ + ldy #31 + - lda save_virtual_registers._cx16_vreg_storage,y + sta cx16.r0,y + dey + bpl - + rts + }} + } + + sub cpu_is_65816() -> bool { + ; Returns true when you have a 65816 cpu, false when it's a 6502. + return false + } + +} + +p8_sys_startup { + ; program startup and shutdown machinery. Needs to reside in normal system ram. + + asmsub init_system() { + ; Initializes the machine to a sane starting state. + ; Called automatically by the loader program logic. + %asm {{ + sei + cld + clc + ; TODO reset screen mode etc etc? + clv + ; TODO what about IRQ handler? + cli + rts + }} + } + + asmsub init_system_phase2() { + %asm {{ + ; initialize kernel event interface + lda # ubyte @Y { + %asm {{ + ldy f256.screen_col + rts + }} +} + +asmsub row(ubyte rownum @A) clobbers(A, X, Y) { + ; ---- set the cursor on the given row (starting with 0) on the current line + %asm {{ + sta f256.screen_row + rts + }} +} + +asmsub get_row() -> ubyte @X { + %asm {{ + ldx f256.screen_row + rts + }} +} + +asmsub get_cursor() -> ubyte @X, ubyte @Y { + %asm {{ + ldx f256.screen_row + ldy f256.screen_col + rts + }} +} + +asmsub fill_screen (ubyte character @ A, ubyte color @ Y) clobbers(A) { + ; ---- fill the character screen with the given fill character and character color. + ; (assumes screen and color matrix are at their default addresses) + + %asm {{ + pha + tya + jsr clear_screencolors + pla + jsr clear_screenchars + rts + }} +} + +asmsub clear_screenchars (ubyte character @ A) clobbers(Y) { + ; ---- clear the character screen with the given fill character (leaves colors) + ; (assumes screen matrix is at the default address) + %asm {{ + ldy f256.io_ctrl ; load current mapping + phy ; save to stack + ldy #2 + sty f256.io_ctrl ; map in screen memory + ldy #240 +- sta f256.Screen+240*0-1,y + sta f256.Screen+240*1-1,y + sta f256.Screen+240*2-1,y + sta f256.Screen+240*3-1,y + sta f256.Screen+240*4-1,y + sta f256.Screen+240*5-1,y + sta f256.Screen+240*6-1,y + sta f256.Screen+240*7-1,y + sta f256.Screen+240*8-1,y + sta f256.Screen+240*9-1,y + sta f256.Screen+240*10-1,y + sta f256.Screen+240*11-1,y + sta f256.Screen+240*12-1,y + sta f256.Screen+240*13-1,y + sta f256.Screen+240*14-1,y + sta f256.Screen+240*15-1,y + sta f256.Screen+240*16-1,y + sta f256.Screen+240*17-1,y + sta f256.Screen+240*18-1,y + sta f256.Screen+240*19-1,y + dey + bne - + ply ; previous mapping from stack + sty f256.io_ctrl ; restore previous map + rts + }} +} + +asmsub clear_screencolors (ubyte color @ A) clobbers(Y) { + ; ---- clear the character screen colors with the given color (leaves characters). + ; (assumes color matrix is at the default address) + %asm {{ + ldy f256.io_ctrl ; load current mapping + phy ; save to stack + ldy #3 + sty f256.io_ctrl ; map in color memory + ldy #240 +- sta f256.Colors+240*0-1,y + sta f256.Colors+240*1-1,y + sta f256.Colors+240*2-1,y + sta f256.Colors+240*3-1,y + sta f256.Colors+240*4-1,y + sta f256.Colors+240*5-1,y + sta f256.Colors+240*6-1,y + sta f256.Colors+240*7-1,y + sta f256.Colors+240*8-1,y + sta f256.Colors+240*9-1,y + sta f256.Colors+240*10-1,y + sta f256.Colors+240*11-1,y + sta f256.Colors+240*12-1,y + sta f256.Colors+240*13-1,y + sta f256.Colors+240*14-1,y + sta f256.Colors+240*15-1,y + sta f256.Colors+240*16-1,y + sta f256.Colors+240*17-1,y + sta f256.Colors+240*18-1,y + sta f256.Colors+240*19-1,y + dey + bne - + ply ; previous mapping from stack + sty f256.io_ctrl ; restore previous map + rts + }} +} + +sub color (ubyte txtcol) { + f256.screen_color = txtcol +} + +sub lowercase() { +; c64.VMCSB |= 2 +} + +sub uppercase() { +; c64.VMCSB &= ~2 +} + +asmsub scroll_left (bool alsocolors @ Pc) clobbers(A, X, Y) { + ; ---- scroll the whole screen 1 character to the left + ; contents of the rightmost column are unchanged, you should clear/refill this yourself + ; Carry flag determines if screen color data must be scrolled too + + %asm {{ + bcc _scroll_screen + ++ ; scroll the screen and the color memory + ldx #0 + ldy #38 +- + .for row=0, row<=24, row+=1 + lda f256.Screen + 40*row + 1,x + sta f256.Screen + 40*row + 0,x + lda f256.Colors + 40*row + 1,x + sta f256.Colors + 40*row + 0,x + .next + inx + dey + bpl - + rts + +_scroll_screen ; scroll only the screen memory + ldx #0 + ldy #38 +- + .for row=0, row<=24, row+=1 + lda f256.Screen + 40*row + 1,x + sta f256.Screen + 40*row + 0,x + .next + inx + dey + bpl - + + rts + }} +} + +asmsub scroll_right (bool alsocolors @ Pc) clobbers(A,X) { + ; ---- scroll the whole screen 1 character to the right + ; contents of the leftmost column are unchanged, you should clear/refill this yourself + ; Carry flag determines if screen color data must be scrolled too + %asm {{ + bcc _scroll_screen + ++ ; scroll the screen and the color memory + ldx #38 +- + .for row=0, row<=24, row+=1 + lda f256.Screen + 40*row + 0,x + sta f256.Screen + 40*row + 1,x + lda f256.Colors + 40*row + 0,x + sta f256.Colors + 40*row + 1,x + .next + dex + bpl - + rts + +_scroll_screen ; scroll only the screen memory + ldx #38 +- + .for row=0, row<=24, row+=1 + lda f256.Screen + 40*row + 0,x + sta f256.Screen + 40*row + 1,x + .next + dex + bpl - + + rts + }} +} + +; stub for call moved to the f256 block. +alias scroll_up = f256.scroll_up +;asmsub scroll_up (bool alsocolors @ Pc) clobbers(A,X) { +; %asm {{ +; jmp f256.scroll_up +; }} +;} + +asmsub scroll_down (bool alsocolors @ Pc) clobbers(A,X) { + ; ---- scroll the whole screen 1 character down + ; contents of the top row are unchanged, you should refill/clear this yourself + ; Carry flag determines if screen color data must be scrolled too + %asm {{ + bcc _scroll_screen + ++ ; scroll the screen and the color memory + ldx #39 +- + .for row=23, row>=0, row-=1 + lda f256.Colors + 40*row,x + sta f256.Colors + 40*(row+1),x + lda f256.Screen + 40*row,x + sta f256.Screen + 40*(row+1),x + .next + dex + bpl - + rts + +_scroll_screen ; scroll only the screen memory + ldx #39 +- + .for row=23, row>=0, row-=1 + lda f256.Screen + 40*row,x + sta f256.Screen + 40*(row+1),x + .next + dex + bpl - + + rts + }} +} + +asmsub setchr (ubyte col @X, ubyte row @Y, ubyte character @A) clobbers(A, Y) { + ; ---- sets the character in the screen matrix at the given position + %asm {{ + pha ; preserve character + jsr f256.chrptr ; calculate offset + pla ; restore character + ldy f256.io_ctrl ; load current mapping + phy ; save on stack + ldy #2 + sty f256.io_ctrl ; map in screen memory + ldy #0 + sta (f256.screen_ptr), y ; write character + ply + sty f256.io_ctrl ; restore previous mapping + rts + }} +} + +asmsub getchr (ubyte col @A, ubyte row @Y) clobbers(Y) -> ubyte @ A { + ; ---- get the character in the screen matrix at the given location + %asm {{ + phx ; preserve + tax ; move column to X for call + jsr f256.chrptr ; calculate offset to character + ldy f256.io_ctrl ; load current mapping + phy ; save on stack + ldy #2 + sty f256.io_ctrl ; map in screen memory + ldy #0 + lda (f256.screen_ptr),y ; get character + ply + sty f256.io_ctrl ; restore previous mapping + plx ; restore + rts + }} +} + +asmsub setclr (ubyte col @X, ubyte row @Y, ubyte color @A) clobbers(A, Y) { + ; ---- set the color in A on the screen matrix at the given position + %asm {{ + pha ; preserve character + jsr f256.chrptr ; calculate offset + pla ; restore character + ldy f256.io_ctrl ; load current mapping + phy ; save on stack + ldy #3 + sty f256.io_ctrl ; map in color memory + ldy #0 + sta (f256.screen_ptr), y ; write color + ply + sty f256.io_ctrl ; restore previous mapping + rts + }} +} + +asmsub getclr (ubyte col @A, ubyte row @Y) clobbers(Y) -> ubyte @ A { + ; ---- get the color in the screen color matrix at the given location + %asm {{ + phx ; preserve + tax ; move column to X for call + jsr f256.chrptr ; calculate offset to character + ldy f256.io_ctrl ; load current mapping + phy ; save on stack + ldy #3 + sty f256.io_ctrl ; map in color memory + ldy #0 + lda (f256.screen_ptr),y ; get color + ply + sty f256.io_ctrl ; restore previous mapping + plx ; restore + rts + }} +} + +sub setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor) { + ; ---- set char+color at the given position on the screen + %asm {{ + ldx col ; setup parameters + ldy row + jsr f256.chrptr ; calculate offset + ldy f256.io_ctrl ; load current mapping + phy ; save on stack + ldy #2 + sty f256.io_ctrl ; map in screen memory + ldy #0 + lda character + sta (f256.screen_ptr), y + ldy #3 + sty f256.io_ctrl ; map in color memory + ldy #0 + lda charcolor + sta (f256.screen_ptr), y + ply ; previous mapping from stack + sty f256.io_ctrl ; restore previous map + rts + }} +} + +asmsub plot (ubyte col @ Y, ubyte row @ X) { + %asm {{ + sty f256.screen_col + stx f256.screen_row + rts + }} +} + +asmsub width() clobbers(X,Y) -> ubyte @A { + ; -- returns the text screen width (number of columns) + %asm {{ + lda DEFAULT_WIDTH + rts + }} +} + +asmsub height() clobbers(X, Y) -> ubyte @A { + ; -- returns the text screen height (number of rows) + %asm {{ + lda DEFAULT_HEIGHT + rts + }} +} + +; TODO: jmp to cbm.CHRIN? +asmsub waitkey() -> ubyte @A { + %asm {{ +- stz f256.event.type ; invalidate existing event type + jsr f256.event.NextEvent + lda f256.event.type + cmp #f256.event.key.PRESSED + bne - + ;lda f256.event.key.raw ; return scan code? + lda f256.event.key.ascii ; return upper or lower ASCII + rts + }} +} +} diff --git a/examples/customtarget/readme.txt b/examples/customtarget/readme.txt index 30c7940c4..c64079bc5 100644 --- a/examples/customtarget/readme.txt +++ b/examples/customtarget/readme.txt @@ -1,5 +1,6 @@ Various examples for configurable target machines, such as the NEO6502, Atari 800, -and "tiny" example configurations for the X16 or C64 that provide more example materials. +Foenix F256, and "tiny" example configurations for the X16 or C64 that provide +more example materials. Look in the Makefile to see how to build or run the various programs. @@ -7,4 +8,4 @@ The user 'adiee5' has been working on a Nintendo Entertainment System (NES) comp and example program, you can find those efforts here on GitHub: https://github.com/adiee5/prog8-nes-target Note that the NES is a very alien architecture for Prog8 still and the support is very limited (for example, prog8 is not aware that the program code usually is going to end up in a ROM cartridge, -and currently still generates code that might nog work in ROM.) +and currently still generates code that might not work in ROM.) diff --git a/examples/customtarget/src/f256-hello.p8 b/examples/customtarget/src/f256-hello.p8 new file mode 100644 index 000000000..4bf6220fc --- /dev/null +++ b/examples/customtarget/src/f256-hello.p8 @@ -0,0 +1,84 @@ +; +; Simplistic example of some text output and +; reading keys. +; +%launcher none +%import textio + +main { + str hello = "Hello, World from Prog8!" + + sub start() { + ubyte i + ubyte key + + txt.cls() + + txt.nl() + txt.print(hello) + txt.nl() + + for i in 0 to 15 { + txt.color($f0 + i) + txt.print("This is color ") + txt.print_ub(i) + txt.nl() + } + txt.color($f2) + + txt.row(30) + txt.print("Using setchr() to draw 'ABC'") + txt.nl() + + txt.setchr(20, 20, 'A') + txt.setchr(21, 21, 'B') + txt.setchr(22, 22, 'C') + + txt.nl() + txt.print("Using setchr(getchr()) to draw 'ABC'") + txt.nl() + + txt.setchr(25, 25, txt.getchr(20, 20)) + txt.setchr(26, 26, txt.getchr(21, 21)) + txt.setchr(27, 27, txt.getchr(22, 22)) + + txt.setclr(20,20, $f3) + txt.setclr(21,21, $f4) + txt.setclr(22,22, $f5) + + txt.setclr(25,25, txt.getclr(20,20)) + txt.setclr(26,26, txt.getclr(21,21)) + txt.setclr(27,27, txt.getclr(22,22)) + + + txt.nl() + txt.print("Waiting for a key... ") + key = txt.waitkey() + txt.nl() + txt.print("KEY: ") + txt.chrout(key) + txt.nl() + txt.nl() + + txt.print("Press keys to show them, ctrl-c resets machine.") + txt.nl() + + ; look for keys forever + repeat { + void, key = cbm.GETIN() + + if key != $00 { + txt.plot(0,40) + txt.print("key: ") + txt.chrout(key) + txt.spc() + txt.print_ubhex(key, true) + } + + ; ctrl-c exists / resets machine + if key == $03 + break + } + } +} + diff --git a/examples/customtarget/targetconfigs/f256.properties b/examples/customtarget/targetconfigs/f256.properties new file mode 100644 index 000000000..ef6d78466 --- /dev/null +++ b/examples/customtarget/targetconfigs/f256.properties @@ -0,0 +1,55 @@ +# configuration file for a Foenix F256 Prog8 compilation target +# generates '.bin' files that are in '.pgz' Foenix format. + +cpu = 65C02 +encoding = iso +#output_type = LIBRARY +output_type = RAW +#load_address = $0200 +#load_address = $1000 +load_address = $2000 +memtop = $c000 +bss_highram_start = 0 +bss_highram_end = 0 +bss_goldenram_start = 0 +bss_goldenram_end = 0 + +# io_regions specifies memory-mapped I/O registers that should be treated differentely. +# it can be zero or more memory address ranges (inclusive) separated by comma +io_regions = $c000-$dfff + +# zeropage scratch variables. zp_scratch_reg must always be zp_scratch_b1+1 ! +zp_scratch_b1 = $e2 +zp_scratch_reg = $e3 +zp_scratch_w1 = $e4 +zp_scratch_w2 = $e6 + +# free zeropage locations for the various zp usage methods +# zero or more zeropage address ranges (inclusive). +# +# $00-$01 - memory & I/O control (MMU) +# $02-$07 - TODO: document (zp_scratch would fit here?) +# $08-$0f - additional (optional) hardware registers (TODO: find & document) +# ... +# $e8-$ef - event array (8 bytes for next event) +# $f0-$ff - kernel arguments table + +zp_fullsafe = $22-$e7 +zp_kernalsafe = $22-$e7 +zp_basicsafe = $22-$e7 + +# the start of the 32 bytes used by the R0-R15 virtual registers. Can be in Zeropage or elsewhere. +virtual_registers = $10 + +# Where can we find the standard library (syslib.p8). You can still add more paths manually using -srcdirs +library = ./libraries/f256 + +# if a non-empty custom launcher code string is supplied, the compiler won't output ANY launcher / init code by itself, +# and instead outputs whatever is specified here. (You can use \n here for newline and \ for line continuantions) +custom_launcher_code = + +# additional options passed to the assembler program +#assembler_options = --c256-pgx +assembler_options = --c256-pgz --output-exec=$2000 +#assembler_options = --output-exec=\$2000 --c256-pgz +#--c256-pgz --output main.pgz