%output library header generation depends on compiler target

fileselector example tweaks
This commit is contained in:
Irmen de Jong
2025-02-02 20:46:49 +01:00
parent 75ddcda5f3
commit 74dd8fe80b
10 changed files with 59 additions and 73 deletions

View File

@@ -3,8 +3,10 @@ package prog8.codegen.cpu6502
import prog8.code.ast.PtLabel import prog8.code.ast.PtLabel
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.AtariTarget import prog8.code.target.AtariTarget
import prog8.code.target.C128Target
import prog8.code.target.C64Target import prog8.code.target.C64Target
import prog8.code.target.Neo6502Target import prog8.code.target.Neo6502Target
import prog8.code.target.PETTarget
import java.nio.file.Path import java.nio.file.Path
@@ -56,8 +58,13 @@ internal class AssemblyProgram(
binFile binFile
} }
OutputType.LIBRARY -> { OutputType.LIBRARY -> {
command.add("--cbm-prg") // include the 2-byte PRG header on library .bins, so they can be easily loaded on the correct memory address even on C64 if(compTarget.name in listOf(C64Target.NAME, C128Target.NAME, PETTarget.NAME)) {
println("\nCreating binary library file for target ${compTarget.name}.") println("\nCreating binary library file with header for target ${compTarget.name}.")
command.add("--cbm-prg")
} else {
println("\nCreating binary library file without header for target ${compTarget.name}.")
command.add("--nostart") // should be headerless bin, because basic has problems doing a normal LOAD"lib",8,1 - need to use BLOAD
}
binFile binFile
} }
else -> throw AssemblyError("invalid output type") else -> throw AssemblyError("invalid output type")

View File

@@ -275,6 +275,7 @@ class AstPreprocessor(val program: Program,
if(targetStatement is Subroutine) { if(targetStatement is Subroutine) {
for(arg in call.args.zip(targetStatement.parameters)) { for(arg in call.args.zip(targetStatement.parameters)) {
if(arg.first.inferType(program).isBytes && arg.second.type.isString) { if(arg.first.inferType(program).isBytes && arg.second.type.isString) {
if((arg.first as? NumericLiteral)?.number!=0.0)
errors.err("cannot use byte value for string parameter", arg.first.position) errors.err("cannot use byte value for string parameter", arg.first.position)
} }
} }

View File

@@ -48,21 +48,22 @@ Binary output and loaded into a fixed memory address
it is not ran like a normal program. it is not ran like a normal program.
Also, because it is not possible to create position independent code with prog8, Also, because it is not possible to create position independent code with prog8,
a fixed load address has to be decided on and the library must be compiled a fixed load address has to be decided on and the library must be compiled
with that address as the load address. For convenience (and compatibility with older CBM with that address as the load address.
target machines such as the C64 and C128) it's easiest if the resulting library
program includes a PRG load header: 2 bytes at the start of the library that contain
the load address. This allows BASIC to load the library via a simple ``LOAD "LIB.BIN",8,1`` for example.
``%output library`` ``%output library``
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
Most (but not all) of the above requirements can be fulfilled by setting various directives in your Most of the above requirements can be fulfilled by setting various directives in your
source code such as %launcher, %zeropage and so on. But there is a single directive that does it correctly for you in one go source code such as %launcher, %zeropage and so on. But there is a single directive that does it correctly for you in one go
(and makes sure there won't be any initialization code left at all): ``%output library`` (and makes sure there won't be any initialization code left at all): ``%output library``
Together with ``%address`` and possibly ``%memtop`` -to tell the compiler what the load address of the library should be- Together with ``%address`` and possibly ``%memtop`` -to tell the compiler what the load address of the library should be-
it will create a "library.bin" file that fulfills the requirements of a loadable binary library program as listed above. it will create a "library.bin" file that fulfills the requirements of a loadable binary library program as listed above.
For older CBM targets (C64, C128 and PET) the library file will have a load address header,
because these targets require a header to easily load files. For the other targets such as the Commander X16,
the library will be a headerless binary file that can then be loaded given the correct load address.
The entrypoint (= the start subroutine) that must be called to initialize the variables, The entrypoint (= the start subroutine) that must be called to initialize the variables,
will be the very first thing at the beginning of the library. will be the very first thing at the beginning of the library.
@@ -89,21 +90,16 @@ But the users of the library are none the wiser and it just seems as if it is pa
Loading and using the library Loading and using the library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Assuming the load address of the library is $A000 (40960): These examples below assume the target is the Commander X16.
Assuming the load address of the library is $A000:
**From BASIC** (the example is from the Commander X16):: **From BASIC**::
LOAD "LIBRARY.BIN",8,1 BLOAD "LIBRARY.BIN",8,1,$A000
SYS $A000 : REM TO INITIALIZE VARIABLES, REQUIRED! SYS $A000 : REM TO INITIALIZE VARIABLES, REQUIRED!
SYS $A004 : REM CALL FIRST ROUTINE SYS $A004 : REM CALL FIRST ROUTINE
SYS $A008 : REM CALL SECOND ROUTINE, ETC. SYS $A008 : REM CALL SECOND ROUTINE, ETC.
For the Commodore 64 and such this works the same but you'll have to type the SYS addresses as decimal numbers.
The Commander X16 also has the BLOAD command to load binary data files, where you have to specify the memory
location where the file has to be loaded to. But for Prog8 library files you don't have to do that, just use LOAD;
the correct address is in the header of the library file. Loading the library to a different memory address
is not possible, because it will only work on the address it was compiled for (it's not possible to create
position independent code on the 6502).
**From Prog8**:: **From Prog8**::
@@ -116,10 +112,12 @@ position independent code on the 6502).
extsub $A008 = lib_func2() clobbers(A,X,Y) extsub $A008 = lib_func2() clobbers(A,X,Y)
sub start() { sub start() {
if diskio.load("library.bin", 0) != 0 { if diskio.load_raw("library.bin", $a000) != 0 {
lib_init() lib_init()
lib_func1() lib_func1()
lib_func2() lib_func2()
repeat { }
} }
} }
} }
@@ -132,7 +130,11 @@ position independent code on the 6502).
void (*lib_init)(void) = (void (*)()) 0xa000; void (*lib_init)(void) = (void (*)()) 0xa000;
void (*lib_func1)(void) = (void (*)()) 0xa004; void (*lib_func1)(void) = (void (*)()) 0xa004;
void (*lib_func2)(void) = (void (*)()) 0xa008; void (*lib_func2)(void) = (void (*)()) 0xa008;
cbm_load("library.bin", 8, 0);
cbm_k_setlfs(0, 8, 2);
cbm_k_setnam("library.bin");
cbm_k_load(0, 0xa000);
lib_init(); lib_init();
lib_func1(); lib_func1();
lib_func2(); lib_func2();
@@ -146,13 +148,13 @@ position independent code on the 6502).
ldx #<libname ldx #<libname
lda #11 lda #11
jsr $ffbd ; SETNAM jsr $ffbd ; SETNAM
ldy #1 lda #0
ldx #8 ldx #8
lda #1 ldy #2 ; load address override
jsr $ffba ; SETLFS jsr $ffba ; SETLFS
lda #0 lda #0
ldx #0 ldx #<$a000
ldy #0 ldy #>$a000
jsr $ffd5 ; LOAD jsr $ffd5 ; LOAD
lda #13 lda #13
jsr $ffd2 ; CHROUT jsr $ffd2 ; CHROUT

View File

@@ -419,7 +419,7 @@ Directives
- type ``raw`` : no header at all, just the raw machine code data - type ``raw`` : no header at all, just the raw machine code data
- type ``prg`` : C64 program (with load address header) - type ``prg`` : C64 program (with load address header)
- type ``xex`` : Atari xex program - type ``xex`` : Atari xex program
- type ``library`` : loadable library file (with CBM style load address header) See :ref:`loadable_library`. - type ``library`` : loadable library file. See :ref:`loadable_library`.
.. data:: %zeropage <style> .. data:: %zeropage <style>

View File

@@ -0,0 +1,11 @@
10 BLOAD"FSELECTOR-A000.BIN",8,1,$A000
20 SYS$A000 : REM INIT
30 GOSUB 1000
40 PRINT:PRINT:PRINT:PRINT"SELECTED: ";F$
50 END
1000 POKE$400,ASC("*"):POKE$401,0 : REM PATTERN
1010 POKE$30E,4:POKE$30C,0:SYS$A00C : REM SELECT
1020 ADDR=PEEK($30E)*256+PEEK($30C):F$="" : REM FILENAME
1030 C=PEEK(ADDR):IFC=0 THEN RETURN
1040 F$=F$+CHR$(C):ADDR=ADDR+1:GOTO 1030

View File

@@ -3,15 +3,16 @@
all: main.prg fselector.bin standalone.prg all: main.prg fselector.bin standalone.prg
clean: clean:
rm -f main.asm main.vice* main.prg fselector.asm fselector.vice* fselector.bin standalone.asm standalone.vice* standalone.prg rm -f main.asm main.vice* main.prg fselector.asm fselector.vice* fselector*.bin standalone.asm standalone.vice* standalone.prg
fselector.bin: fselector.p8 fselector-a000.bin: fselector.p8
prog8c -target cx16 $< prog8c -target cx16 $<
mv fselector.bin fselector-a000.bin
standalone.prg: standalone.p8 standalone.prg: standalone.p8
prog8c -target cx16 $< prog8c -target cx16 $<
main.prg: main.p8 fselector.bin main.prg: main.p8 fselector-a000.bin
prog8c -target cx16 $< prog8c -target cx16 $<
run: main.prg run: main.prg

View File

@@ -36,7 +36,7 @@ main {
fileselector { fileselector {
; these buffer sizes are chosen to fill up the rest of the hiram bank after the fileselector code ; these buffer sizes are chosen to fill up the rest of the hiram bank after the fileselector code
const uword filenamesbuf_size = $eb0 const uword filenamesbuf_size = $ea0
const ubyte max_num_files = 128 const ubyte max_num_files = 128
uword @shared filenamesbuffer = memory("filenames_buffer", filenamesbuf_size, 0) uword @shared filenamesbuffer = memory("filenames_buffer", filenamesbuf_size, 0)
@@ -71,6 +71,10 @@ fileselector {
} }
sub select(str pattern) -> uword { sub select(str pattern) -> uword {
str defaultpattern="*"
if pattern==0
pattern = &defaultpattern
num_visible_files = 0 num_visible_files = 0
diskio.list_filename[0] = 0 diskio.list_filename[0] = 0
name_ptr = diskio.diskname() name_ptr = diskio.diskname()

View File

@@ -5,7 +5,7 @@
main { main {
sub start() { sub start() {
if diskio.load("fselector.bin", 0) != 0 { if diskio.load_raw("fselector-a000.bin", $a000) != 0 {
fselector.init() fselector.init()
;; fselector.config_types(fselector.TYPE_ALL) ;; fselector.config_types(fselector.TYPE_ALL)
uword filename = fselector.select("*") uword filename = fselector.select("*")
@@ -30,6 +30,6 @@ fselector {
; configure the position and appearance of the dialog ; configure the position and appearance of the dialog
extsub $a008 = config_appearance(ubyte column @R0, ubyte row @R1, ubyte max_entries @R2, ubyte normalcolors @R3, ubyte selectedcolors @R4) clobbers(A) extsub $a008 = config_appearance(ubyte column @R0, ubyte row @R1, ubyte max_entries @R2, ubyte normalcolors @R3, ubyte selectedcolors @R4) clobbers(A)
; show the file selector dialog. Normal pattern would be "*" to include everything. ; show the file selector dialog. Normal pattern would be "*" to include everything. Returns the selected entry name, or 0 if error or nothing selected.
extsub $a00c = select(str pattern @AY) clobbers(X) -> uword @AY extsub $a00c = select(str pattern @AY) clobbers(X) -> uword @AY
} }

View File

@@ -77,6 +77,9 @@ fileselector {
} }
sub select(str pattern) -> uword { sub select(str pattern) -> uword {
str defaultpattern="*"
if pattern==0
pattern = &defaultpattern
sys.push(cx16.getrambank()) sys.push(cx16.getrambank())
cx16.r0 = internal_select(pattern) cx16.r0 = internal_select(pattern)
cx16.rambank(sys.pop()) cx16.rambank(sys.pop())

View File

@@ -1,45 +1,3 @@
%import textio
%import diskio
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
txt.lowercase()
diskio.directory_dirs()
txt.nl()
diskio.directory_files()
txt.nl()
diskio.lf_start_list_dirs(0)
while diskio.lf_next_entry() {
txt.print(diskio.list_filetype)
txt.spc()
txt.spc()
txt.print(diskio.list_filename)
txt.nl()
}
diskio.lf_end_list()
txt.nl()
txt.nl()
diskio.lf_start_list_files(0)
while diskio.lf_next_entry() {
txt.print(diskio.list_filetype)
txt.spc()
txt.spc()
txt.print(diskio.list_filename)
txt.nl()
}
diskio.lf_end_list()
}
}
/*
%address $A000 %address $A000
%memtop $C000 %memtop $C000
%output library %output library
@@ -74,4 +32,3 @@ library {
txt.print("lib func 2\n") txt.print("lib func 2\n")
} }
} }
*/