Final Cartridge III Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is version 1.0 of this document, dated 19 Apr 98. The author is Michael Steil . This document may still contain some errors, I give no warranty that the supplied information is correct. I appreciate corrections and additional information on the topic described. This document may be republished if it is free of charge if it is not altered in any way. Otherwise my written permission is required. If you can use the information supplied in this document in your own software, please refer to this document in the credits of your software. The latest version of this document can be downloaded using anonymous ftp at ftp://ftp.funet.fi/pub/cbm/documents/chipdata/ Abstract ~~~~~~~~ This document contains information about the BANKING functions of the FC3 and is supposed to help writers of C64 emulators to implement FC3 emulation. Table of Contents ~~~~~~~~~~~~~~~~~ 1. Overview 2. The FC3 ROM Management Register 2.1 Writing into the ROM Management Register 2.2 Reading from the ROM Management Register 3. The FC3 ROM 3.1 Contents of the FC3 ROM 3.2 The ROM at $DE00 to $DFFF 4. Practical use of FC3 banking 4.1 Behavior on RESET 4.2 Turning the ROM off 4.3 Turning the ROM on 4.4 Bank to bank jumps 5. Model of FC3 used for this 1. Overview ~~~~~~~~ The Final Cartridge III has got 64 KB of ROM that contains all code and data for its additional functions. The C64 can only work with up to 16 KB of external ROM at a time, so the FC3 ROM is divided into four parts, 16 KB each. These are shown in memory at $8000 to $BFFF. The second 8 KB from $A000 to $BFFF logically fully replace the built-in BASIC ROM and the first 8 KB behave exactly like normal internal ROM. Since ROM at $8000 would cause incompatibility of normal C64 programs (this can be seen if you look at the Simons' BASIC cartridge, which has permanent ROM at $8000), the ROM must not been visible by external applications. Therefore the FC3 ROM can be turned off and on by an additional register mapped into the C64 I/O expansion area, at $DFFF. In this area, there are also 512 bytes of ROM that manages turning off and on of the ROM at $8000. The usual C64 BASIC ROM is not really replaced by the FC3 ROM, it remains functional the whole time. But during the RESET routine, the FC3, who gains control at a RESET, installs several vectors at $0300 so that some routines of the operating system are replaced by superiour routines executed in the FC3 ROM. These vectors all point into the ROM at the C64 I/O expansion area. The code there sets up the FC3 ROM Managing Register to show the right bank, calls the routine there, turns the ROM off again and continues behaving just as the original routine, i.e. returning to the caller or jumping into a loop in the original ROM. 2. The FC3 ROM Management Register ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2.1 Writing into the ROM Management Register ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $DFFF: Bits #0-1 number of bank to show at $8000 $3 2-3 unassigned $C 4-5 what ROM to turn on/off 00 turn on all 16 KB of FC3 ROM $00 01 start Freezer $10 10 turn on first 8 KB of FC3 ROM $20 11 turn off FC3 ROM $30 6 unassigned $40 7 =1 -> always show 16 KB of Bank 0 $80 Bits 2-3 and bit 6 have no function, although the FC3 ROM itself always sets bits 2-3 to 0 and bit 6 to 1. Bits 4-5 are show a special behavior if the bit combination 01 is stored into them. This does not just change the ROM configuration, but also start the built-in Freezer module immediately. If bit 7 is 1, the other bits will have no function. Then the FC3 logic shows the first FC3 ROM bank (16 KB) at $8000, just like the value $00 for $DFFF. Obviously, this is needed during RESET. The FC3 logic sets bit 7 to 1 after a RESET, so that the FC3 ROM gains control. The normal value of $DFFF in BASIC is $40, all FC3 ROM is turned off for compatibility. 2.2 Reading from the ROM Management Register ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ROM Management Register does not return the same values that were written into it. It can only hold the values $00 and $FF, depending on the last value written into it. For written values of $00 to $7F the value returned is value returned = ((last value written-1) and 2)/2*$FF (This is only valid for $00-$0F, $20-$4F and $60-$7F, since all other values below $80 start the freezer and don't let the testing program read the value of $DFFF.) For written values of $80 to $FF, the value returned is always $FF (just as the written value $00, which has the same effect!) 3. The FC3 ROM ~~~~~~~~~~~ 3.1 Contents of the FC3 ROM ~~~~~~~~~~~~~~~~~~~~~~~ The FC3 ROM is divided into 4 banks of 16 KB each, showing the following contents: BANK 0 BASIC, Monitor BANK 1 Notepad, BASIC (Bar) BANK 2 Desktop, Freezer/Print BANK 3 Freezer Bank 0 contains the modified RESET routine that gains control over the computer during startup. Therefore it has the CBM80 signature at $8004. It also contains all additional and modified BASIC commands as well as the fast disk access routines and the built-in machine language monitor. Bank 1 contains the Desktop Notepad program as well as the menu bar routines for BASIC. Bank 2 contains the whole Desktop with all its extensions, including Calculator, Clock, Preferences, BASIC Preferences and Disk Operations (Notepad is on bank 1), and the print menu and printing routines of the Freezer. Bank 3 contains the Freezer program and the compression routines. 3.2 The ROM at $DE00 to $DFFF ~~~~~~~~~~~~~~~~~~~~~~~~~ The 512 bytes of ROM at $DE00 to $DFFF cannot be turned off. This piece of ROM is always visible. It is mirrored from $1E00 to $1EFF of bank 0. 4. Practical use of FC3 banking ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4.1 Behavior on RESET ~~~~~~~~~~~~~~~~~ On a RESET, the FC3 logic sets bit 7 of the FC3 ROM Management Register to 1. This means that the cartridge turns on bank 0 of ROM, shown at $8000 to $BFFF. The C64 KERNAL ROM sees the CBM80 signature at $8004 and jumps into the FC3 ROM. The FC3 RESET routine copies its own vectors into the vector table and jumps back to the normal C64 RESET routine at $E397, after turning itself off. 4.2 Turning the ROM off ~~~~~~~~~~~~~~~~~~~ Turning itself off and continuing execution in normal ROM is achieved this way: .,80D5 A9 E3 LDA #$E3 .,80D7 48 PHA .,80D8 A9 96 LDA #$96 .,80DA 48 PHA .,80DB 4C 0F DE JMP $DE0F The routine first pushes the value $E396 onto the stack and jumps to the FC3 ROM in the C64 I/O expansion area. The routine there looks like this: .,DE0F 48 PHA .,DE10 A9 70 LDA #$70 .,DE12 D0 F4 BNE $DE08 (branch always) (continued there) .,DE08 8D FF DF STA $DFFF .,DE0B 68 PLA .,DE0C 60 RTS This piece of code turns off the FC3 ROM at $8000, preserving A. Since the caller routine has pushed the value $E396 onto the stack, the processor will continue executing code at $E397. The ROM stays turned off until the KERNAL RESET routine reaches $A480. The program uses the vector at $0302 to jump to the INPUT routine. This jump is trapped by the FC3: Table of vectors at $0300 occupied by the FC3: :0302 -> $DE41 INPUT :0304 -> $DF8D convert BASIC line into tokens :0306 -> $DE49 LIST :0308 -> $DE73 get address of BASIC statement :030a -> $DE4F evaluate expression :0330 -> $DE21 LOAD :0332 -> $DE35 SAVE 4.3 Turning the ROM on ~~~~~~~~~~~~~~~~~~ The routines in the $DE00 ROM all work much the same. They all set $DFFF, so that the right ROM bank is shown at $8000 and execute the routine there. As an example, this is where the INPUT vector points at: .,DE41 A5 01 LDA $01 .,DE43 20 1A DE JSR $DE1A .,DE46 4C FE 81 JMP $81FE (the subroutine) .,DE1A 09 07 ORA #$07 .,DE1C 85 01 STA $01 .,DE1E D0 E5 BNE $DE05 (continued there) .,DE05 48 PHA .,DE06 A9 40 LDA #$40 .,DE08 8D FF DF STA $DFFF .,DE0B 68 PLA .,DE0C 60 RTS As you can see, this piece of code (that is highly optimizied for size!) turns on all ROM's using the 6510 I/O Port, turns on bank 0 of the FC3 ROM at $8000 and jumps there. The routine there must return using the same piece of code as the routine shown above at $80D5. 4.4 Bank to bank jumps ~~~~~~~~~~~~~~~~~~ If a routine situated in the FC3 ROM wants to jump to a routine on another bank, it will do it like this: It has to push the address of the routine that has to be called (minus 1) onto the stack first. Then it loads the value that has to be stored in $DFFF (containing the number of the bank of the routine that has to be called) into A and jumps to $DE01: .,DE01 8D FF DF STA $DFFF .,DE04 60 RTS This small routine stores the value into the FC3 ROM Management Register and jumps to the routine whose address has been pushed on the stack, using the RTS instruction. Note that that the second routine cannot jump back using a RTS, but has to do the same to jump onto another bank as the first routine has done before. 5. Model of FC3 used for this ~~~~~~~~~~~~~~~~~~~~~~~~~~ For the experiments, the following model of an FC3 was used: DESKTOP V1.0 Calculator V1.2 Clock V1.0 Notepad V1.2 Preferences V1.2 Disk Operations V1.1 Basic V1.2 DATE: DEC 1988 CRC-32 Bank 0 3d3b0cbb Bank 1 439d1b97 Bank 2 033952e7 Bank 3 7e99ec76 -------------------------------------------------------------------------------- Help me make this document grow! Greetings to RRBYC,FTGLJRWUAH,M -------------------------------------------------------------------------------- End of "Final Cartridge III Internals", (C)M. Steil