FloppyBuilder
Important: The rest of this documentation is going to try to explain how the whole process works, but the best example is to look at the real world sample demo Pushing The Envelope source code in the SVN depot.
The FloppyBuilder is a relatively advanced tool which can be used to generate optimized DSK files.
The Tap2Dsk tool is conceptually equivalent to the FloppyBuilder, the main difference being that Tap2Dsk generates Sedoric floppies while FloppyBuilder generates floppy files that do not rely on the disk operating system, allowing the user to use almost all the Oric memory and most of the floppy surface.
In order to use the FloppyBuilder, you need to create a description file using the syntax described in the following sections. From this description file will be generated both a DSK file and a header file.
The DSK file is a floppy disk image (in the usual Oric format at used in emulators), while the header file contains informations about the floppy layout which can be used by the programmer to load the files.
With this organisation comes an interesting chicken and egg problem: In order to generate the DSK file, the FloppyBuilder needs to have a list of files to write, but in order to access the files the user code needs to know where the files are located and how large they are, which in turn impacts the content of the DSK file which may mean that the location of the file changed. To solved this cyclical dependency the FloppyBuilder has been designed to be run in two different modes: The initialization mode and the building mode:
- The FloppyBuilder will first be called in Initialization mode, which will generate a header file with enough information to make it possible to build the project without actually requiring that all files be present.
- The user code is then assembled/compiled, it can reference and use the content of the header file, which will possibly not be entirelly correct but will allow the files to have the correct size.
- The FloppyBuilder is then called in Building mode, which will require all files to be present, this pass will update the header file which should now contains correct data.
- The user code is then assembled/compiled again, this time with all the correct information in the header file.
- The FloppyBuilder is then called in Building mode a final time, we now have a valid DSK file.
This process is admitely not very elegant, but it has the benefit of being simple and automated, and it allows for basically optimal file referencement: You do not need to load a directory and search, you can just ask the loader to load a particular file immediately, identified by a single immediate value.
The floppy builder does not take any optional switch or parameter at this point in time, the syntax is just one of these two situations:
FloppyBuilder init description_file FloppyBuilder build description_file
Description file is a simple ASCII text format containing commands followed by a number of parameters. Empty lines are ignored, and semi-colon characters (;) are considered as comments.
Here is a list of commands:
- AddDefine define_name define_value
- AddFile file address [optional_medatas]
- DefineDisk sides tracks sectors
- OutputFloppyFile dsk_file
- OutputLayoutFile header_file
- ReserveSectors number_of_sectors
- SetPosition track sector
- SetCompressionMode
- WriteSector file
Here is an example of how these commands can be used:
; ; ODSK Floppy Builder template description file ; DefineDisk 2 42 17 ; 2 sides, 42 tracks, 17 sectors OutputLayoutFile floppy_description.h ; This file will be used by the loader OutputFloppyFile ..\build\FloppyBuilderTest.dsk ; The final DSK file containing the data ; ; This defines the bootsectors to use for the various operating systems ; - Jasmin loads the sector 1 of track zero in $400 and then runs it. ; - Microdisc loads the sector 2 of track zero, the address is different on Atmos and Telestrat ; - The system requires a third sector containing valid data ; ; Since we do not yet have a valid Jasmin reading code, all this bootsector will do is to ; write a message saying that this floppy needs to be booted on a Microdisc compatible system. ; SetPosition 0 1 ; Set the head to track 0, sector 1 WriteSector ..\build\files\sector_1-jasmin.o ; Written to track 0, sector 1 WriteSector ..\build\files\sector_2-microdisc.o ; Written to track 0, sector 2 WriteSector ..\build\files\sector_3.o ; Written to track 0, sector 3 ; ; Now here is the loader code, that one is Microdisc only ; SetPosition 0 4 ; Written to track 0, sector 4 AddFile ..\build\files\loader.o $fc00 ; and will be loaded in $fc00 ; ; From now on we compress data (The loader should not be compressed) ; SetCompressionMode FilePack ; So far only two modes: 'None' and 'FilePack' ; ; Then the files used in this demo ; AddDefine LOADER_TEST_DEMO {FileIndex} ; The main application AddFile ..\build\files\testdemo.o $400 ; can be loaded by using this define AddDefine LOADER_FIRST_INTRO_PICTURE {FileIndex} ; A hires picture loaded in $a000 AddFile ..\build\files\test_picture.hir $a000 ; load with LOADER_FIRST_INTRO_PICTURE define AddDefine LOADER_LAST_PICTURE {FileIndex}
This may look a bit complicated, but the beauty of the system is that the entire process is data driven because the generated data can be used almost transparently from either your assembler or C code.
So, what does the generated header file looks like? If you would put the sample description file through the FloppyBuilder is here what you would get as a result:
// // Floppy layout generated by FloppyBuilder 0.15 // (The generated floppy is missing some files, a new build pass is required) // #ifdef ASSEMBLER // // Information for the Assembler // #ifdef LOADER FileStartSector .byt 4,8,9 FileStartTrack .byt 0,0,0 FileStoredSizeLow .byt <1024,<44,<44 FileStoredSizeHigh .byt >1024,>44,>44 FileSizeLow .byt <1024,<44,<44 FileSizeHigh .byt >1024,>44,>44 FileLoadAdressLow .byt <64512,<1024,<40960 FileLoadAdressHigh .byt >64512,>1024,>40960 #endif // LOADER #else // // Information for the Compiler // #endif // // Summary for this floppy building session: // #define FLOPPY_SIDE_NUMBER 2 // Number of sides #define FLOPPY_TRACK_NUMBER 42 // Number of tracks #define FLOPPY_SECTOR_PER_TRACK 17 // Number of sectors per track // // List of files written to the floppy // // Entry #0 '..\build\files\loader.o' // - Loads at address 64512 starts on track 0 sector 4 and is 4 sectors long (1024 bytes). // Entry #1 '..\build\files\testdemo.o' // - Loads at address 1024 starts on track 0 sector 8 and is 1 sectors long (44 bytes). // Entry #2 '..\build\files\test_picture.hir' // - Loads at address 40960 starts on track 0 sector 9 and is 1 sectors long (44 bytes). // // 9 sectors used, out of 1428. (0% of the total disk size used) // #define LOADER_TEST_DEMO 1 #define LOADER_FIRST_INTRO_PICTURE 2 #define LOADER_LAST_PICTURE 3 // // Metadata // #ifdef METADATA_STORAGE #endif // METADATA_STORAGE
As you can see, the file contains some preprocessor information, tests, defines and actual entries:
- Some #ifdef to handle both C and 6502 code. If ASSEMBLER is not defined at build time, the code will be assumed to be loaded from a C module
- Some loader specific information, in the form of arrays of data with information for each file (location on track, size, loading address, compressed size, ...)
- Some #define describing the format of the floppy (used by the loader to detect when it needs to change track or side)
- Some #define that can be used to identify the files by ID (created by the AddDefine commands)
- Some final #ifdef for the METADATA section (optional, more on that later)
We are now reaching the 'can do better' part. The loader is pretty much still a work in progress, if you take the source code of Pushing The Envelope as a base you could just keep it as is, the only thing you may need to change is the ldx #LOADER_SLIDESHOW in loader.asm if you changed the define. The rest can be kept as is.
If you kept the loader as is, you have access to two functions in the loading API:
- LoadData (in $FFF7)
- SetLoadAddress (in $FFF4)
The function calls have been wrapped in 'loader_api.s', but basically all you need to do is to load a file is to pass the file entry number in the register X and then jmp to $fff7. This will use the default address specified in the description file.
If you want to load the data at another location, you can call the SetLoadAddress function in a similar way: Set X with the file entry number, A for the lower part of the address and Y for the high part, then call $fff4. Subsequent calls to $fff7 for this file will use the new location (the call patched the loader table)
Issue #8: Use symbols in description file
Details: It is currently possible to have FloppyBuilder generate #define symbols to use from inside the program, but it would be nice to be able to use program symbols inside the description files, for example to use a label instead of a hardcoded loading address
Fixed in OSDK 1.7
Details: It would be nice to be able to reserve a certain number of sectors without having to add a file. That would be particularly useful to reserve space for saving data in a game for example.
Fixed in OSDK 1.11
Details: Hi ThomH! I'm glad to read you have tested my game. This CRC bug is something related to FloppyBuilder, so it is Dbug who should fix it.
comments powered by Disqus