|
| 1 | +# About This Guide |
| 2 | +This guide is meant as a starting point for programmers wanting to develop for the F256 computers. It is an overview of how the machine and its software environment is put together, something that can be difficult to otherwise piece together. It is not a kernel or SuperBASIC manual, nor is a technical hardware manual, these can be found elsewhere and studied at your leisure. |
| 3 | + |
| 4 | +* [Hardware documentation](https://raw.githubusercontent.com/pweingar/C256jrManual/main/tex/f256jr_ref.pdf) |
| 5 | +* [Kernel programming](https://github.com/ghackwrench/F256_MicroKernel/tree/master/docs) |
| 6 | +* [SuperBASIC reference](https://github.com/FoenixRetro/f256-superbasic/blob/main/source/release/documents/f256jr_basic_ref.pdf) |
| 7 | + |
| 8 | +# Introduction |
| 9 | +Programming the F256 computers can be done in several ways, and all are both challenging and, more importantly, lots of fun. |
| 10 | + |
| 11 | +The first option many will probably turn to is the flash resident SuperBASIC, the environment you see immediately after turning on the computer. This is a very powerful and fast BASIC, giving you access to most hardware features, and it also features inline assembly if you need that little extra speed. It is an excellent starting point. |
| 12 | + |
| 13 | +SuperBASIC is backed by the TinyCore kernel, which is responsible for handling the different kinds of keyboards, file access and networking. You can create programs that communicate directly with the kernel and don't require SuperBASIC. This a very good option for games and programs that need to receive input from the user and access storage, but does not use any BASIC features. The kernel does not handle text and graphics output, this is something the program will have to implement itself. |
| 14 | + |
| 15 | +Programs that use the kernel are started by the user, either from DOS or from SuperBASIC. The programs can be loaded from disk, or they can be resident in flash memory or RAM. |
| 16 | + |
| 17 | +Lastly, you can of course go full bare metal. It's your computer, you have full control. After your program has been started by the user, you can simply opt to not use the kernel and handle everything yourself. You can also upload binary programs from a PC or Mac directly to memory, and have the RESET vector point to your entry point for the ultimate bare metal experience. Or you can completely replace the kernel with your own operating system. Roads? Where we're going we don't need roads. |
| 18 | + |
| 19 | +# A Note on CPU |
| 20 | +An F256 usually comes with a 65C02 CPU, but may optionally use a 65C816 or the FNX6809 (Motorola 6809 compatible). This document covers 65C02 and 65C816. |
| 21 | + |
| 22 | +# Memory Configuration |
| 23 | +The F256s come with 512 KiB of RAM and 512 KiB of flash storage on-board. This memory is divided into 8 KiB banks. RAM is assigned bank number $00-$3F, and flash is assigned $40-$7F. |
| 24 | + |
| 25 | +The machines have a Memory Management Unit (*MMU*), which is used to map this physical address space into 64 KiB which the CPU can then access. This is done by the use of a Lookup Table (or *LUT*), of which the MMU has four. A LUT is organized into eight 8 KiB *slots*, each pointing to a specific memory bank. One LUT is active at a time, and it is possible to edit another LUT without disturbing the one that is active. |
| 26 | + |
| 27 | +# Development Environments |
| 28 | +Programs are usually developed by compiling or assembling the program on a regular PC or Mac. Most tools support all common platforms, including Linux, or can relatively easily be made to run using a program such as Bottles (Linux) or WineBottler (Mac). C compilers are available, and plenty of assemblers can also be used, possibly in combination with C. Common editors include Visual Studio Code, Emacs, Vim or Visual Studio. Programs can be tested by either using FoenixIDE (an emulator) or the real hardware, developers often use a combination of both. This document does not cover how to use the emulator, but its documentation can be found at https://github.com/Trinity-11/FoenixIDE. |
| 29 | + |
| 30 | +# SuperBASIC |
| 31 | +SuperBASIC is an excellent BASIC dialect, and can be used to write programs directly on the hardware. This is a great option that lets you experience the machine in all its glory. Using the emulator is of course also possible, and can be a good alternative when you don't have the machine with you. |
| 32 | + |
| 33 | +For information on how to program SuperBASIC, please refer to [the reference manual](https://github.com/FoenixRetro/f256-superbasic/blob/main/reference/source/f256jr_basic_ref.pdf). |
| 34 | + |
| 35 | +# C compilers |
| 36 | +Compilers that can be used write a program in C are: |
| 37 | + |
| 38 | +* Calypsi - https://www.calypsi.cc/ |
| 39 | +* WDCTools - https://wdc65xx.com/WDCTools |
| 40 | +* CC65 - https://github.com/cc65/cc65 |
| 41 | + |
| 42 | +CC65 only supports the 65816 in emulation mode. |
| 43 | + |
| 44 | +# Assemblers |
| 45 | +Some available assemblers include: |
| 46 | + |
| 47 | +* Calypsi - https://www.calypsi.cc/ |
| 48 | +* WDCTools - https://wdc65xx.com/WDCTools |
| 49 | +* tass64 - https://sourceforge.net/projects/tass64/ |
| 50 | +* merlin32 - https://github.com/lroathe/merlin32 |
| 51 | +* ASMotor - https://github.com/asmotor/asmotor |
| 52 | +* CA65 from the CC65 package - https://github.com/cc65/cc65 |
| 53 | + |
| 54 | +CA65 only has limited 65816 support. |
| 55 | + |
| 56 | +# Example Programs |
| 57 | +*Link to some simple "Hello, World!" type projects demonstrating how to set up and compile a program.* |
| 58 | + |
| 59 | +# Distributing Programs |
| 60 | +Programs should be distributed using one of the executable formats supported by the firmware. While it is possible to distribute a program as a binary blob, this requires users to tether the machine to a PC or Mac, and upload the program with a stand-alone tool. This is not very user-friendly and is discouraged. Binary files should only be used while developing a program. |
| 61 | + |
| 62 | +# Firmware Structure |
| 63 | +Several independent components make up the firmware, the most important one being the MicroKernel. The firmware includes other components that the kernel refers to as "kernel user programs" (or *KUP* for short). The kernel is responsible for switching between these when requested. These programs are currently the SuperBASIC environment, the SuperBASIC help viewer, a simple DOS commandline shell, and pexec. Further programs may be added in the future, and you are free to put whichever programs you may desire in a free slot. |
| 64 | + |
| 65 | +The kernel is *only* able to start a user program from memory - flash or RAM. |
| 66 | + |
| 67 | +These KUPs also have a name which is used to refer to them by users or code. They are: |
| 68 | + |
| 69 | +|Program|Name| |
| 70 | +|---|---| |
| 71 | +|SuperBASIC|basic| |
| 72 | +|SuperBASIC Help|help| |
| 73 | +|DOS|dos| |
| 74 | +|pexec| - | |
| 75 | + |
| 76 | +SuperBASIC can switch to another KUP by issuing the "slash" command, eg. `/dos` will execute the KUP named `dos`. |
| 77 | + |
| 78 | +DOS can switch to another program just be typing its name on the commandline, eg `basic` to enter the SuperBASIC environment. DOS also implements its own functionality that enables loading KUPs from disk, this is not handled by the kernel. |
| 79 | + |
| 80 | +`pexec` is the program responsible for loading and executing the *PGX* and *PGZ* file formats. In DOS this is done by issuing the command `- program.pgz`. This will execute the `pexec` program (remember its commandline name is actually `-`), which will load and execute the commandline parameter, in this case `program.pgz`. As previously mentioned, SuperBASIC has the ability to execute a KUP, so from SuperBASIC, the equivalent command would be `/- program.pgz`. |
| 81 | + |
| 82 | +Your code is able to switch to another program by calling the `RunNamed` kernel function. |
| 83 | + |
| 84 | +# Co-existing with the Kernel |
| 85 | +Many programs will have to interact with the kernel in some way. The kernel provides several useful services that take a great deal of work to implement, such as file handling, keyboard differences (remember, there are three different types of keyboard on the F256s!), and so forth. |
| 86 | + |
| 87 | +The kernel reserves some resources for itself. This is MMU LUT #0 and #1, and RAM banks 6 and 7. Additionally, zero page locations $F0-$FF are reserved. You must therefore stay away from these completely. |
| 88 | + |
| 89 | +A program is mapped into memory using LUT #3, and LUT #3 will be active when the program is handed control. This LUT will be configured to both contain RAM banks and the program (which may be flash or RAM). The last two slots are used by the kernel, and contains important working memory, entry points and interrupt vectors. These slots should not be modified, and they should also be copied to LUT #2, if you intend to switch to that. What slots 0-5 are configured as, depends on how and from where the program was loaded. This is covered in the "file format" section. |
| 90 | + |
| 91 | +Documentation on how to use the kernel, and the facilities it provides, can be found in the [kernel repository](https://github.com/ghackwrench/F256_MicroKernel/tree/master/docs) |
| 92 | + |
| 93 | +# File Formats |
| 94 | +The F256 line has three file formats, each with slightly different properties and use cases. Additionally, pure binary files are often used by developers. The machine will be in a slightly different state, depending on how the program was started. We will cover this in the following sections. |
| 95 | + |
| 96 | +## Binary |
| 97 | +The binary file format is not a format as such. It is an image that is loaded directly into the F256's memory by a utility program running on the PC or Mac, and the F256 is then reset. Such an image must include properly initialized interrupt vectors, especially the RESET vector. |
| 98 | + |
| 99 | +Running such an image requires knowledge of its starting address and a properly configured USB connecting between the PC or Mac and the F256. Also, a jumper on the F256 Jr. motherboard must be moved to the "Boot-to-RAM" position. This is not necessary on the F256K. |
| 100 | + |
| 101 | +Binary images should only be used by the developer while developing, as it is a very user-unfriendly method of distributing software, requiring tethering to a PC or Mac. |
| 102 | + |
| 103 | +## KUP |
| 104 | +KUPs are very simple and can contain 40 KiB code/data when run from flash, or 32 KiB when run from disk. In their header they specify a bank where they should be mapped into, the first possible bank being #1 ($2000), and an entry point. |
| 105 | + |
| 106 | +The header is very simple: |
| 107 | + |
| 108 | +``` |
| 109 | +Byte 0 signature: $F2 |
| 110 | +Byte 1 signature: $56 |
| 111 | +Byte 2 the size of program in 8k blocks |
| 112 | +Byte 3 the starting slot of the program (ie where to map it) |
| 113 | +Bytes 4-5 the start address of the program |
| 114 | +Bytes 6-9 reserved |
| 115 | +Bytes 10- the zero-terminated name of the program. |
| 116 | +``` |
| 117 | + |
| 118 | +When instructed to start a named KUP, the kernel will search through memory to find a match. First the expansion memory is searched, this could be either RAM or ROM. Then the on-board flash memory is searched. If DIP switch #1 is in the "on" position, the kernel will search memory banks 1-5 before the expansion blocks. |
| 119 | + |
| 120 | +This sequence is also performed when the kernel starts up, for instance when the machine is reset or is first powered on. |
| 121 | + |
| 122 | +Testing a KUP is therefore as easy as uploading it to a block of memory, and is an excellent choice for testing a program that interacts with the kernel. Though you should remember that this program will stay in memory as long as the machine is powered on, and may also survive a short power cut. Such a program should therefore, when testing, destroy its own header by overwriting the first two bytes with some values that are not the magic signature, to avoid being started again and again. |
| 123 | + |
| 124 | +A KUP residing in flash does not "return" in the common sense of the word. If it has to terminate, it can either reset the machine, or use `RunNamed` to start another KUP. |
| 125 | + |
| 126 | +However, when running a KUP from disk, it is able to return to DOS in a controlled manner. Distributing software intended to be run from disk as KUP is usually discouraged, as the program can only be started from DOS - not from SuperBASIC. It can however be appropriate for small utility programs mostly intended for maintenance tasks and so forth. When distributing software, you should prefer using one of the PGX or PGZ formats. |
| 127 | + |
| 128 | +A KUP loaded from disk may exit back to DOS by issuing an RTS instruction. Additionally, the carry may be set if the machine should be reset, or carry clear to continue running DOS. Be aware that you must leave the MMU configuration in the state you found it. You should also keep away from the $0200-$07FF range completely. |
| 129 | + |
| 130 | +When a KUP is started from flash, LUT #3 slots 0-5 is mapped to RAM banks 0-5, *except* where the KUP's header specifies it should be mapped. |
| 131 | + |
| 132 | +A KUP started from disk has LUT #3 slots 0-4 mapped to RAM, some of which will be the program itself. |
| 133 | + |
| 134 | +## PGX |
| 135 | +This format is a simple, single segment executable, which can be loaded as low as $0200. A PGX is loaded using `pexec`. It otherwise follows the same conventions as PGZ. |
| 136 | + |
| 137 | +Testing a PGX requires copying it to a disk or SD card, and manually running it on the machine. |
| 138 | + |
| 139 | +## PGZ |
| 140 | +This is a more advanced multi-segment executable. It can be loaded as low as $0200. It is loaded using `pexec`. |
| 141 | + |
| 142 | +When `pexec` loads a program using the kernel, the program must not load itself into RAM banks 6 & 7, as these are used by the kernel. If the program does not need the kernel, it may of course utilize these banks once it is running. `pexec` is otherwise able to load code and data into anywhere in physical memory. |
| 143 | + |
| 144 | +When the program starts, the state of the MMU LUTs is very similar to when a KUP starts. LUT #3 is active and slots 0-4 are mapped to RAM banks 0-4. The program's entry point must be in this region. |
| 145 | + |
| 146 | +Testing a PGZ requires copying it to a disk or SD card, and manually running it on the machine. |
| 147 | + |
| 148 | +A PGZ cannot "return" to another program, it can either start a KUP (if the kernel is intact) or reset the machine. |
| 149 | + |
| 150 | +# Startup Sequence |
| 151 | +Assuming "Boot-to-Flash"-mode (the usual mode) - when the machine is powered on, MMU LUT #0 will be active, RAM banks 0-6 mapped into slots 0-6, and the last block of flash mapped into slot 7, where also the interrupt vectors reside. The kernel is usually placed in the last block, which causes it to be the first program running. |
| 152 | + |
| 153 | +When the kernel has initialized itself, it looks for the first program it should start. First the expansion memory is searched, this could be either RAM or ROM. Then the on-board flash memory is searched. If DIP switch #1 is in the "on" position, the kernel will search memory banks 1-5 before the expansion blocks. In most cases no programs are present in expansion memory or main memory, and the first program started is the first one in flash memory. This is usually SuperBASIC, although you can put anything you want there, possibly DOS. |
| 154 | + |
| 155 | +# Parameter Passing |
| 156 | +Although not part of the kernel specification, a standardized method of passing commandline arguments to programs exists. |
| 157 | + |
| 158 | +Both DOS and SuperBASIC are able to pass arguments to the program to run, and `pexec` is also able to pass any further arguments after the filename on to the program. As an example, `/- program.pgz hello` in SuperBASIC would start `pexec` with the parameters `-`, `program.pgz`, and `hello`. `pexec` would then load `program.pgz`, and start it with the parameters `program.pgz` and `hello`. |
| 159 | + |
| 160 | +Arguments are passed in the `ext` and `extlen` kernel arguments. This approach is suitable for passing arguments through the `RunNamed` and `RunBlock` kernel functions, and is also used by `pexec` when starting a PGZ or PGZ program. |
| 161 | + |
| 162 | +`ext` will contain an array of pointers, one for each argument given on the commandline. The first pointer is the program name itself. The list is terminated with a null pointer. `extlen` contains the length in bytes of the array, less the null pointer. For instance, if two parameters are passed, `extlen` will be 4. |
| 163 | + |
| 164 | +`pexec` reserves $200-$2FF for parameters - programs distributed in the PGX and PGZ formats should therefore load themselves no lower than $0300, if they want to access commandline parameters. If they do not use the commandline parameters, they may load themselves as low as $0200. |
0 commit comments