mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-03 19:16:13 +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.core.*
 | 
			
		||||
import prog8.code.target.AtariTarget
 | 
			
		||||
import prog8.code.target.C128Target
 | 
			
		||||
import prog8.code.target.C64Target
 | 
			
		||||
import prog8.code.target.Neo6502Target
 | 
			
		||||
import prog8.code.target.PETTarget
 | 
			
		||||
import java.nio.file.Path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -56,8 +58,13 @@ internal class AssemblyProgram(
 | 
			
		||||
                        binFile
 | 
			
		||||
                    }
 | 
			
		||||
                    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
 | 
			
		||||
                        println("\nCreating binary library file for target ${compTarget.name}.")
 | 
			
		||||
                        if(compTarget.name in listOf(C64Target.NAME, C128Target.NAME, PETTarget.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
 | 
			
		||||
                    }
 | 
			
		||||
                    else -> throw AssemblyError("invalid output type")
 | 
			
		||||
 
 | 
			
		||||
@@ -275,7 +275,8 @@ class AstPreprocessor(val program: Program,
 | 
			
		||||
            if(targetStatement is Subroutine) {
 | 
			
		||||
                for(arg in call.args.zip(targetStatement.parameters)) {
 | 
			
		||||
                    if(arg.first.inferType(program).isBytes && arg.second.type.isString) {
 | 
			
		||||
                        errors.err("cannot use byte value for string parameter", arg.first.position)
 | 
			
		||||
                        if((arg.first as? NumericLiteral)?.number!=0.0)
 | 
			
		||||
                            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.
 | 
			
		||||
    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
 | 
			
		||||
    with that address as the load address. For convenience (and compatibility with older CBM
 | 
			
		||||
    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.
 | 
			
		||||
    with that address as the load address.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
``%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
 | 
			
		||||
(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-
 | 
			
		||||
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,
 | 
			
		||||
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
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
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 $A004 : REM CALL FIRST ROUTINE
 | 
			
		||||
    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**::
 | 
			
		||||
 | 
			
		||||
@@ -116,10 +112,12 @@ position independent code on the 6502).
 | 
			
		||||
        extsub $A008 = lib_func2() clobbers(A,X,Y)
 | 
			
		||||
 | 
			
		||||
        sub start() {
 | 
			
		||||
            if diskio.load("library.bin", 0) != 0 {
 | 
			
		||||
            if diskio.load_raw("library.bin", $a000) != 0 {
 | 
			
		||||
                lib_init()
 | 
			
		||||
                lib_func1()
 | 
			
		||||
                lib_func2()
 | 
			
		||||
 | 
			
		||||
                repeat { }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -132,7 +130,11 @@ position independent code on the 6502).
 | 
			
		||||
        void (*lib_init)(void) = (void (*)()) 0xa000;
 | 
			
		||||
        void (*lib_func1)(void) = (void (*)()) 0xa004;
 | 
			
		||||
        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_func1();
 | 
			
		||||
        lib_func2();
 | 
			
		||||
@@ -146,13 +148,13 @@ position independent code on the 6502).
 | 
			
		||||
        ldx  #<libname
 | 
			
		||||
        lda  #11
 | 
			
		||||
        jsr  $ffbd      ; SETNAM
 | 
			
		||||
        ldy  #1
 | 
			
		||||
        lda  #0
 | 
			
		||||
        ldx  #8
 | 
			
		||||
        lda  #1
 | 
			
		||||
        ldy  #2         ; load address override
 | 
			
		||||
        jsr  $ffba      ; SETLFS
 | 
			
		||||
        lda  #0
 | 
			
		||||
        ldx  #0
 | 
			
		||||
        ldy  #0
 | 
			
		||||
        ldx  #<$a000
 | 
			
		||||
        ldy  #>$a000
 | 
			
		||||
        jsr  $ffd5      ; LOAD
 | 
			
		||||
        lda  #13
 | 
			
		||||
        jsr  $ffd2      ; CHROUT
 | 
			
		||||
 
 | 
			
		||||
@@ -419,7 +419,7 @@ Directives
 | 
			
		||||
	- type ``raw`` : no header at all, just the raw machine code data
 | 
			
		||||
	- type ``prg`` : C64 program (with load address header)
 | 
			
		||||
	- 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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
 | 
			
		||||
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 $<
 | 
			
		||||
	mv fselector.bin fselector-a000.bin
 | 
			
		||||
 | 
			
		||||
standalone.prg: standalone.p8
 | 
			
		||||
	prog8c -target cx16 $<
 | 
			
		||||
 | 
			
		||||
main.prg: main.p8 fselector.bin
 | 
			
		||||
main.prg: main.p8 fselector-a000.bin
 | 
			
		||||
	prog8c -target cx16 $<
 | 
			
		||||
 | 
			
		||||
run: main.prg
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ main {
 | 
			
		||||
 | 
			
		||||
fileselector {
 | 
			
		||||
    ; 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
 | 
			
		||||
 | 
			
		||||
    uword @shared filenamesbuffer = memory("filenames_buffer", filenamesbuf_size, 0)
 | 
			
		||||
@@ -71,6 +71,10 @@ fileselector {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sub select(str pattern) -> uword {
 | 
			
		||||
        str defaultpattern="*"
 | 
			
		||||
        if pattern==0
 | 
			
		||||
            pattern = &defaultpattern
 | 
			
		||||
 | 
			
		||||
        num_visible_files = 0
 | 
			
		||||
        diskio.list_filename[0] = 0
 | 
			
		||||
        name_ptr = diskio.diskname()
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
 | 
			
		||||
main {
 | 
			
		||||
    sub start() {
 | 
			
		||||
        if diskio.load("fselector.bin", 0) != 0 {
 | 
			
		||||
        if diskio.load_raw("fselector-a000.bin", $a000) != 0 {
 | 
			
		||||
            fselector.init()
 | 
			
		||||
            ;; fselector.config_types(fselector.TYPE_ALL)
 | 
			
		||||
            uword filename = fselector.select("*")
 | 
			
		||||
@@ -30,6 +30,6 @@ fselector {
 | 
			
		||||
    ; 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)
 | 
			
		||||
 | 
			
		||||
    ; 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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,9 @@ fileselector {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sub select(str pattern) -> uword {
 | 
			
		||||
        str defaultpattern="*"
 | 
			
		||||
        if pattern==0
 | 
			
		||||
            pattern = &defaultpattern
 | 
			
		||||
        sys.push(cx16.getrambank())
 | 
			
		||||
        cx16.r0 = internal_select(pattern)
 | 
			
		||||
        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
 | 
			
		||||
%memtop   $C000
 | 
			
		||||
%output   library
 | 
			
		||||
@@ -74,4 +32,3 @@ library {
 | 
			
		||||
        txt.print("lib func 2\n")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user