mirror of
https://github.com/irmen/prog8.git
synced 2025-11-24 06:17:39 +00:00
%output library header generation depends on compiler target
fileselector example tweaks
This commit is contained in:
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
11
examples/cx16/fileselector/EXAMPLE.BAS
Normal file
11
examples/cx16/fileselector/EXAMPLE.BAS
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
Reference in New Issue
Block a user