This chapter gives a technical description of the various files supported by the emulators.
(This section is based on v1.1 TAP specification by Per Hakan Sundell and Markus Brenner, additional format v2 expansion by Markus Brenner, plus some editing by groepaz, with some more VICE extensions)
Designed by Per Hakan Sundell (author of the CCS64 C64 emulator) in 1997, this format attempts to duplicate the data stored on a cassette tape, bit for bit. Since it is simply a representation of the raw serial data from a tape, it should handle *any* custom tape loaders that exist.
The TAP images are generally very large, being a minimum of eight times, and up to sixteen times as large as what a raw PRG file would be. This is due to the way the data is stored, with each bit of the original file now being one byte large in the TAP file. The layout is fairly simple, with a small 14-byte header followed by file data.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 2D 54 41 50 45 2D 52 41 57 00 00 00 00 C64-TAPE-RAW???? 0010: 51 21 08 00 2F 0F 0D 31 64 1D 26 0D 07 21 0A 12 Q!??/??1d?&??!?? 0020: 4A 2F 2C 34 07 18 0D 31 07 04 23 04 0D 42 0D 1E J/,4???1??#??B?? 0030: 34 04 42 0D 20 15 5E 04 0D 18 61 0D 26 29 34 0D 4?B???^???a?&)4? 0040: 23 0D 07 0A 3F 55 04 0A 13 3F 07 0D 12 2B 18 0A #????U???????+??
Offset | Description |
$0000-000B | File signature (C64-TAPE-RAW (v0 and v1) or C16-TAPE-RAW (v2 only)) |
$000C | TAP version (see below for description), $00 - Original layout, |
$01 - Updated, $02 - Halfwave Extension
$000D | Computer Platform (0 = C64, 1 = VIC-20, 2 = C16, Plus/4, 3 = PET, 4 = C5x0, 5 = C6x0, C7x0) |
$000E | Video Standard (0 = PAL, 1 = NTSC, 2 = OLD NTSC, 3 = PALN) |
$000F | reserved for future expansion |
$0010-0013 | File data size (not including this header, in LOW/HIGH format) i.e. The | above example image is $00082151 bytes long.
$0014-xxxx | File data |
In TAP version $00 files, each data byte in the file data area represents the length of a pulse, when the hardware will trigger again. This pulse length is determined by the following formula:
pulse length (in seconds) = (8 * data byte) / (clock cycles)
A data value of $00 represents an "overflow" condition, any pulse length which is more that 255 * 8 in length.
For example, assuming the image was made on a PAL C64, a data value of $2F (47 in decimal) would be:
(47 * 8) / 985248 = .00038975 seconds.
The number of clock cycles per second refer to the clock rate the timers used for the tape routines in the respective computer system count with, and can be derived from the given computer platform and video standard, as in the following table:
Computer platform | Video standard | Timer clock speed |
0 = C64 | 0 = PAL | 985248 kHz |
1 = NTSC | 1022730 kHz | |
2 = OLD NTSC | 1022730 kHz | |
3 = PAL N | 1023440 kHz | |
1 = VIC-20 | 0 = PAL | 1108405 kHz |
1 = NTSC | 1022727 kHz | |
2 = C16 / Plus4 (*) | 0 = PAL | 886724 kHz |
1 = NTSC | 894886 kHz | |
3 = PET | 0 = PAL | 1000000 kHz |
1 = NTSC | 1000000 kHz | |
4 = C5x0 | 0 = PAL | 985248 kHz |
1 = NTSC | 1022730 kHz | |
5 = C6x0 / C7x0 | 0 = PAL | 2000000 kHz |
1 = NTSC | 2000000 kHz |
(*) The TED timers always run with the slower clock rate (886724 Hz for PAL machines), so the length of one TAP pulse should be relative to this frequency.
The original format did not include the "computer platform" and "video system" field, and the number of clock cycles per second was assumed to always be 985248, as if the tape was recorded on a PAL C64.
In TAP version $01 files, the data value of $00 has been re-purposed to represent cycle exact values, which may also be greater than 255 * 8. When a $00 is encountered, three bytes will follow which are the actual time (in cycles) of a pulse, and the above formula does not apply. The three bytes are stored in LOW/HIGH format.
TAP Version 2 is an extension made by Markus Brenner for C16 tapes. It is version 1, but each value represents a halfwave, starting with a '0'->'1' transition. The time encoding doesn't change.
The actual interpretation of the serial data takes a little more work to explain. The typical ROM tape loader (and some of the turbo loaders) will initialize a timer with a specified value and start it counting down. If either the tape data changes or the timer runs out, an IRQ will occur. The loader will determine which condition caused the IRQ. If the tape data changed before the timer ran out, we have a short pulse, or a "0" bit. If the timer ran out first, we have a long pulse, or a "1" bit. Doing this continuously and we decode the entire file.
Plus4 implementation hints: When playing back a TAP on a Plus/4 emulator, you should write a routine that sets the CAS_READ line to '0' for half of the time and '1' for the other half. This should be easy to implement, as your emulator probably counts in units of clock cycles anyway :) As for writing to a TAP file, you need to watch the CAS_WRITE register (processor port, bit 0x02) and start counting whenever a 0->1 transition happens.
(This section was taken from the C64S distribution.)
The T64
File Structure was developed by Miha Peternel for use in the
C64S emulator. It is easy to use and allows future extensions.
Offset | Size | Description |
0 | 64 | tape record |
64 | 32*n | file records for n directory entries |
64+32*n | varies | binary contents of the files |
Offset | Size | Description |
0 | 32 | DOS tape description + EOF (for type) |
32 | 2 | tape version ($0200) |
34 | 2 | number of directory entries |
36 | 2 | number of used entries (can be 0 in my loader) |
38 | 2 | free |
40 | 24 | user description as displayed in tape menu |
Offset | Size | Description |
0 | 1 | entry type (see below) |
1 | 1 | C64 file type |
2 | 2 | start address |
4 | 2 | end address |
6 | 2 | free |
8 | 4 | offset of file contents start within T64 file |
12 | 4 | free |
16 | 16 | C64 file name |
Valid entry types are:
Code | Explanation |
0 |
free entry |
1 |
normal tape file |
2 |
tape file with header: header is saved just before file data |
3 |
memory snapshot v0.9, uncompressed |
4 |
tape block |
5 |
digitized stream |
6 ... 255 |
reserved |
Notes:
1
.
3
, 4
and 5
are subject to change (and
are rarely used).
(This section was contributed by Peter Schepers and slightly edited by Ettore Perazzoli.)
This format was defined in 1998 as a cooperative effort between several
emulator people, mainly Per Håkan Sundell, author of the CCS64 C64
emulator, Andreas Boose of the VICE CBM emulator team and Joe
Forster/STA, the author of Star Commander. It was the first real public
attempt to create a format for the emulator community which removed
almost all of the drawbacks of the other existing image formats, namely
D64
.
The intention behind G64
is not to replace the widely used
D64
format, as D64
works fine with the vast majority of
disks in existence. It is intended for those small percentage of
programs which demand to work with the 1541 drive in a non-standard way,
such as reading or writing data in a custom format. The best example is
with speeder software such as Action Cartridge in Warp Save mode or
Vorpal which write track/sector data in another format other than
standard GCR. The other obvious example is copy-protected software
which looks for some specific data on a track, like the disk ID, which
is not stored in a standard D64
image.
G64
has a deceptively simply layout for what it is capable of
doing. We have a signature, version byte, some predefined size values,
and a series of offsets to the track data and speed zones. It is what's
contained in the track data areas and speed zones which is really at the
heart of this format.
Each track entry in simply the raw stream of GCR data, just what a read head would see when a diskette is rotating past it. How the data gets interpreted is up to the program trying to access the disk. Because the data is stored in such a low-level manner, just about anything can be done. Most of the time I would suspect the data in the track would be standard sectors, with SYNC, GAP, header, data and checksums. The arrangement of the data when it is in a standard GCR sector layout is beyond the scope of this document.
Since it is a flexible format in both track count and track byte size, there is no "standard" file size. However, given a few constants like 42 tracks and halftracks, a track size of 7928 bytes and no speed offset entries, the typical file size will a minimum of 333744 bytes.
Below is a dump of the header, broken down into its various parts. After that will be an explanation of the track offset and speed zone offset areas, as they demand much more explanation.
Addr 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ---- ----------------------------------------------- 0000: 47 43 52 2D 31 35 34 31 00 54 F8 1E .. .. .. ..
Offset | Description |
$0000-0007 | File signature (GCR-1541 ) |
$0008 | G64 version (presently only $00 defined) |
$0009 | Number of tracks in image (usually $54, decimal 84) |
$000A-000B | Size of each stored track in bytes (usually 7928, or $1EF8) in LO/HI format. |
An obvious question here is "why are there 84 tracks defined when a
normal D64
disk only has 35 tracks?" Well, by definition, this
image includes all half-tracks, so there are actually 42 tracks and 42
half tracks. The 1541 stepper motor can access up to 42 tracks and the
in-between half-tracks. Even though using more than 35 tracks is not
typical, it was important to define this format from the start with what
the 1541 is capable of doing, and not just what it typically does.
At first, the defined track size value of 7928 bytes may seem to be arbitrary, but it is not. It is determined by the fastest write speed possible (speed zone 0), coupled with the average rotation speed of the disk (300 rpm). After some math, the answer that actually comes up is 7692 bytes. Why the discrepency between the actual size of 7692 and the defined size of 7928? Simply put, not all drives rotate at 300 rpm. Some can be faster or slower, so a upper safety margin of +3% was built added, in case some disks rotate slower and can write more data. After applying this safety factor, and some rounding-up, 7928 bytes per track was arrived at.
Also note that this upper limit of 7928 bytes per track really only applies to 1541 and compatible disks. If this format were applied to another disk type like the SFD1001, this value would be higher.
Below is a dump of the first section of a G64
file, showing the offsets
to the data portion for each track and half-track entry. Following that
is a dump of the speed zone offsets.
Addr 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ---- ----------------------------------------------- 0000: .. .. .. .. .. .. .. .. .. .. .. .. AC 02 00 00 0010: 00 00 00 00 A6 21 00 00 00 00 00 00 A0 40 00 00 0020: 00 00 00 00 9A 5F 00 00 00 00 00 00 94 7E 00 00 0030: 00 00 00 00 8E 9D 00 00 00 00 00 00 88 BC 00 00 0040: 00 00 00 00 82 DB 00 00 00 00 00 00 7C FA 00 00 0050: 00 00 00 00 76 19 01 00 00 00 00 00 70 38 01 00 0060: 00 00 00 00 6A 57 01 00 00 00 00 00 64 76 01 00 0070: 00 00 00 00 5E 95 01 00 00 00 00 00 58 B4 01 00 0080: 00 00 00 00 52 D3 01 00 00 00 00 00 4C F2 01 00 0090: 00 00 00 00 46 11 02 00 00 00 00 00 40 30 02 00 00A0: 00 00 00 00 3A 4F 02 00 00 00 00 00 34 6E 02 00 00B0: 00 00 00 00 2E 8D 02 00 00 00 00 00 28 AC 02 00 00C0: 00 00 00 00 22 CB 02 00 00 00 00 00 1C EA 02 00 00D0: 00 00 00 00 16 09 03 00 00 00 00 00 10 28 03 00 00E0: 00 00 00 00 0A 47 03 00 00 00 00 00 04 66 03 00 00F0: 00 00 00 00 FE 84 03 00 00 00 00 00 F8 A3 03 00 0100: 00 00 00 00 F2 C2 03 00 00 00 00 00 EC E1 03 00 0110: 00 00 00 00 E6 00 04 00 00 00 00 00 E0 1F 04 00 0120: 00 00 00 00 DA 3E 04 00 00 00 00 00 D4 5D 04 00 0130: 00 00 00 00 CE 7C 04 00 00 00 00 00 C8 9B 04 00 0140: 00 00 00 00 C2 BA 04 00 00 00 00 00 BC D9 04 00 0150: 00 00 00 00 B6 F8 04 00 00 00 00 00 .. .. .. ..
Offset | Description |
$000C-000F | Offset to stored track 1.0 ($000002AC, in LO/HI format, see below for more) |
$0010-0013 | Offset to stored track 1.5 ($00000000) |
$0014-0017 | Offset to stored track 2.0 ($000021A6) |
... | |
$0154-0157 | Offset to stored track 42.0 ($0004F8B6) |
$0158-015B | Offset to stored track 42.5 ($00000000) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 0150: .. .. .. .. .. .. .. .. .. .. .. .. 03 00 00 00 0160: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 0170: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 0180: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 0190: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 01A0: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 01B0: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 01C0: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 01D0: 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00 00 01E0: 00 00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 01F0: 00 00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 0200: 00 00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 0210: 00 00 00 00 02 00 00 00 00 00 00 00 01 00 00 00 0220: 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 0230: 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 0240: 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 0250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02A0: 00 00 00 00 00 00 00 00 00 00 00 00 .. .. .. ..
Offset | Description |
$015C-015F | Speed zone entry for track 1 ($03, in LO/HI format, see below for more) |
$0160-0163 | Speed zone entry for track 1.5 ($03) |
... | |
$02A4-02A7 | Speed zone entry for track 42 ($00) |
$02A8-02AB | Speed zone entry for track 42.5 ($00) |
Starting here at $02AC is the first track entry (from above, it is the first entry for track 1.0)
The track offsets (from above) require some explanation. When one is set to all 0's, no track data exists for this entry. If there is a value, it is an absolute reference into the file (starting from the beginning of the file). From the track 1.0 entry we see it is set for $000002AC. Going to that file offset, here is what we see...
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 02A0: .. .. .. .. .. .. .. .. .. .. .. .. 0C 1E FF FF 02B0: FF FF FF 52 54 B5 29 4B 7A 5E 95 55 55 55 55 55 02C0: 55 55 55 55 55 55 FF FF FF FF FF 55 D4 A5 29 4A 02D0: 52 94 A5 29 4A 52 94 A5 29 4A 52 94 A5 29 4A 52
Offset | Description |
$02AC-02AD | Actual size of stored track (7692 or $1E0C, in LO/HI format) |
$02AE-02AE+$1E0C | Track data |
Following the track data is filler bytes. In this case, there are 368 bytes of unused space. This space can contain anything, but for the sake of those wishing to compress these images for storage, they should all be set to the same value. In the sample I used, these are all set to $FF.
Below is a dump of the end of the track 1.0 data area. Note the actual track data ends at address $20B9, with the rest of the block being unused, and set to $FF.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 1FE0: 52 94 A5 29 4A 52 94 A5 29 4A 52 94 A5 29 4A 52 1FF0: 94 A5 29 4A 52 94 A5 29 4A 52 94 A5 29 4A 52 94 2000: A5 29 4A 52 94 A5 29 4A 52 94 A5 29 4A 52 94 A5 2010: 29 4A 52 94 A5 29 4A 52 94 A5 29 4A 52 94 A5 29 2020: 4A 52 94 A5 29 4A 52 94 A5 29 4A 52 94 A5 29 4A 2030: 55 55 55 55 55 55 FF FF FF FF FF FF FF FF FF FF 2040: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2050: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2060: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2070: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2080: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2090: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 20A0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 20B0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 20C0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 20D0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 20E0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 20F0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2100: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2110: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2120: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2130: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2140: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2150: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2160: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2170: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2180: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2190: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 21A0: FF FF FF FF FF FF .. .. .. .. .. .. .. .. .. ..
The speed offset entries can be a little more complex. The 1541 has four speed zones defined, which means the drive can write data at four distinct speeds. On a normal 1541 disk, these zones are as follows:
Track Range | Speed Zone |
1-17 | 3 (highest writing speed) |
18-24 | 2 |
25-30 | 1 |
31 and up | 0 (lowest writing speed) |
Note that you can, through custom programming of the 1541, change the speed zone of any track to something different (change the 3 to a 0) and write data differently. From the dump of the speed offset entries above, we see that all the entries are in the range of 0-3. If any entry is less than 4, this is not considered a speed offset but defines the whole track to be recorded at that one speed.
In the example I had, there were no offsets defined, so no speed zone dump can be shown. However, I can define what should be there. You will have a block of data, 1982 bytes long. Each byte is encoded to represent the speed of 4 bytes in the track offset area, and is broken down as follows:
Speed entry $FF: in binary %11111111 |'|'|'|' | | | | | | | +- 4'th byte speed (binary 11, 3 dec) | | +--- 3'rd byte speed (binary 11, 3 dec) | +----- 2'nd byte speed (binary 11, 3 dec) +------- 1'st byte speed (binary 11, 3 dec)
It was very smart thinking to allow for two speed zone settings, one in the offset block and another defining the speed on a per-byte basis. If you are working with a normal disk, where each track is one constant speed, then you don't need the extra blocks of information hanging around the image, wasting space.
What may not be obvious is the flexibility of this format to add tracks and speed offset zones at will. If a program decides to write a track out with varying speeds, and no speed offset exist, a new block will be created by appending it to the end of the image, and the offset pointer for that track set to point to the new block. If a track has no offset yet, meaning it doesn't exist (like a half-track), and one needs to be added, the same procedure applies. The location of the actual track or speed zone data is not important, meaning they do not have to be in any particular order since they are all referenced by the offsets at the beginning of the image.
Given that a Commodore VIC 1541/1570/1571 can read/write at most 42 tracks per side, it is quite natural to use the half-tracks from 1 to 84 for the first side and the following 84 half-tracks (i. e. half-track 85 to 168) for the second side.
In order for this to work, byte 9 of the image (i. e. the maximum number of tracks) usually contains 168 for double sided disks.
To make identifying such images easy, the file signature in the first 8 bytes of
such files is GCR-1571
).
G64s created by the DTC tool from Kryoflux dumps contain extra info for each track, usually at offset $02ac right after the speedzone entries.
First comes the extra info tag:
Offset | Description |
$00-$02 | extra info tag (EXT) $45,$58,$54 |
$03 | extra info version ($01) |
Followed by 16 bytes of extra info for each track in the image:
Offset | Description |
$00 | write splice position |
$04 | write area size |
$08 | bitcell size in nanoseconds (eg 3500 means 3.5us) |
$0c | track fill value |
$0d | n/a |
$0e | format code |
$0f | format extension |
A zero value in any of these fields means that the respective default/standard value applies.
Format codes:
ID | Description |
0 | Unknown format |
1 | GCR Data |
2 | CBM DOS |
3 | CBM DOS Extended |
4 | MicroProse |
5 | RapidLok |
6 | Datasoft |
7 | Vorpal |
8 | V-MAX! |
9 | Teque |
10 | TDP |
11 | Big Five |
12 | OziSoft |
Format Extensions:
ID | Description |
0 | Unknown protection |
1 | Datasoft with Weak bits |
2 | CBM DOS with Cyan loader, Weak bits |
3 | CBM DOS with Datasoft, Weak bits |
4 | RapidLok Key |
5 | Data Duplication |
6 | Melbourne House |
7 | Melbourne House, Weak bits |
8 | PirateBusters v1.0 |
9 | PirateBusters v2.0, Track A |
10 | PirateBusters v2.0, Track B |
11 | PirateSlayer |
12 | CBM DOS, XEMAG |
This section is taken from "P64 file format specification" by Benjamin 'BeRo' Rosseaux.
All values are in little endian order !
0 1 2 3 4 5 6 7 8 9 A B C D E F +---------------------------------------------------------------+ 0000: |'P'|'6'|'4'|'-'|'1'|'5'|'4'|'1'| Version | Flags | +---------------+---------------+-------------------------------+ 0010: | Size | CRC32Checksum | +-------------------------------+
Version: File format version, current is 0x00000000
Size Size of the following whole chunk content stream
Flags: Bit 0 = Write protect Bit 1 = Number of sides (0 for single sided, 1 for double sided) Bit 2-31 = Reserved, all set to 0 when creating a file, preserve existing value when updating
CRC32CheckSum: CRC32 checksum of the following whole chunk content stream
0 1 2 3 4 5 6 7 8 9 A B C D E F +-----------------------------------------------+ 0000: |Chunk Signature| Size | CRC32Checksum | +-----------------------------------------------+
Chunk signature: Signature of chunk
Size: Size of the chunk data
CRC32CheckSum: CRC32 checksum of the chunk data
| x = half track index byte | +---------------------------+ Bit 7 of the half track index byte contains the side.
Track 18 = Half track 36 = Half track index byte decimal value 36
Half track NRZI transition flux pulse data chunk block
0 1 2 3 4 5 6 7 8 9 A B C D E F +---------------------------------------------------------------+ 0000: | Count pulses | Size | ..... Range-encoded data .... | +---------------------------------------------------------------+
Count pulses: Count of the NRZI transition flux pulses in half track
Size: Size of the range-encoded data
Hint: For a working C implememtation see p64.c and p64.h
The range coder is a FPAQ0-style range coder combined with 12-bit 0-order models, one model per byte with one bit per byte processing.
+--------------------------------------------------------------------------+ | Sub stream | Count of models | Size per model | Total value bits | +------------------+-----------------+------------------+------------------+ | Position | 4 | 65536 | 32 | +------------------+-----------------+------------------+------------------+ | Strength | 4 | 65536 | 32 | +------------------+-----------------+------------------+------------------+ | Position flag | 1 | 2 | 1 | +------------------+-----------------+------------------+------------------+ | Strenth flag | 1 | 2 | 1 | +------------------+-----------------+------------------+------------------+ +===Total models===| 10 |==================|==================| +--------------------------------------------------------------------------+
All initial model state values are initialized with zero.
All initial model probability values are initialized with 2048.
These model probability values will be updating in a adaptive way on the fly and not precalculated before the encoding and even not loaded before the decoding, see pseudo code below.
16000000 Hz / 5 rotations per second at 300 RPM = maximal 3200000 flux pulses
So NRZI transition flux pulse positions are in the 0 .. 3199999 value range, which is also a exact single rotation, where each time unit is a cycle at 16 MHz with 300 RPM as a mapping for the ideal case.
The NRZI transition flux pulse stength are in the 0x00000000 .. 0xffffffff value range, where 0xffffffff indices a strong flux pulse, that always triggers, and 0x00000001 indices a weak flux pulse, that almost never triggers, and 0x00000000 indices a flux pulse, that absolutly never triggers.
For 32-bit values, the model sub streams are subdivided byte wide in a little-endian manner, and each byte is processed bitwise with model probability shifting of 4 bits, just as:
Pascal-Style pseudo code:
procedure WriteDWord(Model, Value : longword); var ByteValue, ByteIndex, Context, Bit : longword; begin for ByteIndex := 0 to 3 do begin ByteValue := (Value shr (ByteIndex shl 3)) and $ff; Context := 1; for Bit := 7 downto 0 do begin Context := (Context shl 1) or RangeCoderEncodeBit( RangeCoderProbabilities[ RangeCoderProbabilityOffsets[Model + ByteIndex] + (((RangeCoderProbabilityStates[Model + ByteIndex] shl 8) or Context) and $ffff)], 4, (ByteValue shr Bit) and 1); end; RangeCoderProbabilityStates[Model+ByteIndex] := ByteValue; end; end;
And for 1-bit flag values it is much simpler, but also with model probability shifting of 4 bits, just as:
Pascal-Style pseudo code:
procedure WriteBit(Model, Value : longword); begin RangeCoderProbabilityStates[Model] := RangeCoderEncodeBit(RangeCoderProbabilities[ RangeCoderProbabilityOffsets[Model] + RangeCoderProbabilityStates[Model]], 4, Value and 1); end;
The position and strength values are delta-encoded. If a value is equal to the last previous value, then the value will not encoded, instead, a flag for this will encoded. First the position value will encoded, then the stength value. If the last position delta is 0, then it is a track stream end marker.
Pascal-Style pseudo code:
LastPosition := 0; PreviousDeltaPosition := 0 LastStrength := 0; for PulseIndex := 0 to PulseCount - 1 do begin DeltaPosition := Pulses[PulseIndex].Position - LastPosition; if PreviousDeltaPosition <> DeltaPosition then begin PreviousDeltaPosition := DeltaPosition; WriteBit(ModelPositionFlag, 1) WriteDWord(ModelPosition, DeltaPosition); end else begin WriteBit(ModelPositionFlag, 0); end; LastPosition := Pulses[PulseIndex].Position; if LastStrength <> Pulses[PulseIndex].Strength then begin WriteBit(ModelStrengthFlag, 1) WriteDWord(ModelStrength, Pulses[PulseIndex].Strength - LastStrength); end else begin WriteBit(ModelStrengthFlag, 0); end; LastStrength := Pulses^[PulseIndex].Strength; end; // End code WriteBit(ModelPositionFlag, 1); WriteDWord(ModelPosition, 0);
The decoding is simply just in the another direction way.
Pseudo code for a FPAQ0-style carryless range coder:
Pascal-Style pseudo code:
procedure RangeCoderInit; // At encoding and decoding start begin RangeCode := 0; RangeLow := 0; RangeHigh := $ffffffff; end; procedure RangeCoderStart; // At decoding start var Counter : longword; begin for Counter := 1 to 4 do begin RangeCode := (RangeCode shl 8) or ReadByteFromInput; end; end; procedure RangeCoderFlush; // At encoding end var Counter : longword; begin for Counter := 1 to 4 do begin WriteByteToOutput(RangeHigh shr 24); RangeHigh := RangeHigh shl 8; end; end; procedure RangeCoderEncodeNormalize; begin while ((RangeLow xor RangeHigh) and $ff000000) = 0 do begin WriteByteToOutput(RangeHigh shr 24); RangeLow := RangeLow shl 8; RangeHigh := (RangeHigh shl 8) or $ff; end; end; function RangeCoderEncodeBit(var Probability : longword; Shift, BitValue : longword) : longword; begin RangeMiddle := RangeLow + (((RangeHigh - RangeLow) shr 12) * Probability); if BitValue <> 0 then begin inc(Probability, ($fff - Probability) shr Shift); RangeHigh := RangeMiddle; end else begin dec(Probability, Probability shr Shift); RangeLow := RangeMiddle + 1; end; RangeCoderEncodeNormalize; result := BitValue; end; procedure RangeCoderDecodeNormalize; begin while ((RangeLow xor RangeHigh) and $ff000000) = 0 do begin RangeLow := RangeLow shl 8; RangeHigh := (RangeHigh shl 8) or $ff; RangeCode := (RangeCode shl 8) or ReadByteFromInput; end; end; function RangeCoderDecodeBit(var Probability : longword; Shift : longword) : longword; begin RangeMiddle := RangeLow + (((RangeHigh - RangeLow) shr 12) * Probability); if RangeCode <= RangeMiddle then begin inc(Probability, ($fff - Probability) shr Shift); RangeHigh := RangeMiddle; result := 1; end else begin dec(Probability, Probability shr Shift); RangeLow := RangeMiddle + 1; result := 0; end; RangeCoderDecodeNormalize; end;
The probability may be never zero! But that can't happen here with this adaptive model in this P64 file format, since the adaptive model uses a shift factor of 4 bits and initial probabilities value of 2048, so the probability has a value range from 15 up to 4080 here. If you do want to use the above range coder routines for other stuff with other probability models, then you must to ensure that the probability output value is never zero, for example with "probability |= (probability < 1); " in C.
This is the last empty chunk for to signalize that the correct file end is reached.
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel. Added 42 track info by groepaz)
First and foremost we have D64, which is basically a sector-for-sector copy of a 1540/1541 disk. There are several versions of these which I will cover shortly. The standard D64 is a 174848 byte file comprised of 256 byte sectors arranged in 35 tracks with a varying number of sectors per track for a total of 683 sectors. Track counting starts at 1, not 0, and goes up to 35. Sector counting starts at 0, not 1, for the first sector, therefore a track with 21 sectors will go from 0 to 20.
The original media (a 5.25" disk) has the tracks laid out in circles, with track 1 on the very outside of the disk (closest to the sides) to track 35 being on the inside of the disk (closest to the inner hub ring). Commodore, in their infinite wisdom, varied the number of sectors per track and data densities across the disk to optimize available storage, resulting in the chart below. It shows the sectors/track for a standard D64. Since the outside diameter of a circle is the largest (versus closer to the center), the outside tracks have the largest amount of storage.
Track | Sectors/track | # Sectors |
1-17 | 21 | 357 |
18-24 | 19 | 133 |
25-30 | 18 | 108 |
31-35 | 17 | 85 |
36-40(*) | 17 | 85 |
41-42(*) | 17 | 34 |
Track | #Sect | #SectorsIn | D64 Offset |
1 | 21 | 0 | $00000 |
2 | 21 | 21 | $01500 |
3 | 21 | 42 | $02A00 |
4 | 21 | 63 | $03F00 |
5 | 21 | 84 | $05400 |
6 | 21 | 105 | $06900 |
7 | 21 | 126 | $07E00 |
8 | 21 | 147 | $09300 |
9 | 21 | 168 | $0A800 |
10 | 21 | 189 | $0BD00 |
11 | 21 | 210 | $0D200 |
12 | 21 | 231 | $0E700 |
13 | 21 | 252 | $0FC00 |
14 | 21 | 273 | $11100 |
15 | 21 | 294 | $12600 |
16 | 21 | 315 | $13B00 |
17 | 21 | 336 | $15000 |
18 | 19 | 357 | $16500 |
19 | 19 | 376 | $17800 |
20 | 19 | 395 | $18B00 |
21 | 19 | 414 | $19E00 |
22 | 19 | 433 | $1B100 |
23 | 19 | 452 | $1C400 |
24 | 19 | 471 | $1D700 |
25 | 18 | 490 | $1EA00 |
26 | 18 | 508 | $1FC00 |
27 | 18 | 526 | $20E00 |
28 | 18 | 544 | $22000 |
29 | 18 | 562 | $23200 |
30 | 18 | 580 | $24400 |
31 | 17 | 598 | $25600 |
32 | 17 | 615 | $26700 |
33 | 17 | 632 | $27800 |
34 | 17 | 649 | $28900 |
35 | 17 | 666 | $29A00 |
36(*) | 17 | 683 | $2AB00 |
37(*) | 17 | 700 | $2BC00 |
38(*) | 17 | 717 | $2CD00 |
39(*) | 17 | 734 | $2DE00 |
40(*) | 17 | 751 | $2EF00 |
41(*) | 17 | 768 | $30000 |
42(*) | 17 | 785 | $31100 |
(*) Tracks 36-40 apply to 40- and 42-track images only. (*) Tracks 41-42 apply to 42-track images only.
The directory track should be contained totally on track 18. Sectors 1-18 contain the entries and sector 0 contains the BAM (Block Availability Map) and disk name/ID. Since the directory is only 18 sectors large (19 less one for the BAM), and each sector can contain only 8 entries (32 bytes per entry), the maximum number of directory entries is 18 * 8 = 144. The first directory sector is always 18/1, even though the t/s pointer at 18/0 (first two bytes) might point somewhere else. It then follows the same chain structure as a normal file, using a sector interleave of 3. This makes the chain links go 18/1, 18/4, 18/7 etc.
Note that you can extend the directory off of track 18, but only when reading the disk or image. Attempting to write to a directory sector not on track 18 will cause directory corruption. Each directory sector has the following layout (18/1 partial dump):
00: 12 04 81 11 00 4E 41 4D 45 53 20 26 20 50 4F 53 <- notice the T/S link 10: 49 54 A0 A0 A0 00 00 00 00 00 00 00 00 00 15 00 <- to 18/4 ($12/$04) 20: 00 00 84 11 02 41 44 44 49 54 49 4F 4E 41 4C 20 <- and how its not here 30: 49 4E 46 4F A0 11 0C FE 00 00 00 00 00 00 61 01 <- ($00/$00)
The first two bytes of the sector ($12/$04) indicate the location of the next track/sector of the directory (18/4). If the track is set to $00, then it is the last sector of the directory. It is possible, however unlikely, that the directory may *not* be competely on track 18 (some disks do exist like this). Just follow the chain anyhow.
When the directory is done, the track value will be $00. The sector link should contain a value of $FF, meaning the whole sector is allocated, but the actual value doesn't matter. The drive will return all the available entries anyways.
This is a breakdown of a standard directory sector:
Bytes | Description |
$00-$1F | First directory entry |
$20-$3F | Second dir entry |
$40-$5F | Third dir entry |
$60-$7F | Fourth dir entry |
$80-$9F | Fifth dir entry |
$A0-$BF | Sixth dir entry |
$C0-$DF | Seventh dir entry |
$E0-$FF | Eighth dir entry |
This is a breakdown of a standard directory entry:
Bytes | Description |
$00-$01 | Track/Sector location of next directory sector ($00 $00 if not the first entry in the sector) |
$02 | File type |
$03-$04 | Track/sector location of first sector of file |
$05-$14 | 16 character filename (in PETASCII, padded with $A0) |
$15-$16 | Track/Sector location of first side-sector block (REL file only) |
$17 | REL file record length (REL file only, max. value 254) |
$18-$1D | Unused (except with GEOS disks) |
$1E-$1F | File size in sectors, low/high byte order ($1E+$1F*256). The approx. filesize in bytes is <= #sectors * 254 |
The file type field is used as follows:
Bits | Description |
0-3 | The actual file type |
4 | Unused |
5 | Used only during SAVE-@ replacement |
6 | Locked flag (Set produces ">" locked files) |
7 | Closed flag (Not set produces "*", or "splat" files) |
The actual file type can be one of the following:
Binary | Decimal | File type |
0000 | 0 | DEL |
0001 | 1 | SEQ |
0010 | 2 | PRG |
0011 | 3 | USR |
0100 | 4 | REL |
Values 5-15 are illegal, but if used will produce very strange results. The 1541 is inconsistent in how it treats these bits. Some routines use all 4 bits, others ignore bit 3, resulting in values from 0-7.
Files, on a standard 1541, are stored using an interleave of 10. Assuming a starting track/sector of 17/0, the chain would run 17/0, 17/10, 17/20, 17/8, 17/18, etc.
Most Commdore floppy disk drives use a single dedicated directory track where all filenames are stored. This limits the number of files stored on a disk based on the number of sectors on the directory track. There are some disk images that contain more files than would normally be allowed. This requires extending the directory off the default directory track by changing the last directory sector pointer to a new track, allocating the new sectors in the BAM, and manually placing (or moving existing) file entries there. The directory of an extended disk can be read and the files that reside there can be loaded without problems on a real drive. However, this is still a very dangerous practice as writing to the extended portion of the directory will cause directory corruption in the non-extended part. Many of the floppy drives core ROM routines ignore the track value that the directory is on and assume the default directory track for operations.
To explain: assume that the directory has been extended from track 18 to track 19/6 and that the directory is full except for a few slots on 19/6. When saving a new file, the drive DOS will find an empty file slot at 19/6 offset $40 and correctly write the filename and a few other things into this slot. When the file is done being saved the final file information will be written to 18/6 offset $40 instead of 19/6 causing some directory corruption to the entry at 18/6. Also, the BAM entries for the sectors occupied by the new file will not be saved and the new file will be left as a SPLAT (*) file.
Attempts to validate the disk will result in those files residing off the directory track to not be allocated in the BAM, and could also send the drive into an endless loop. The default directory track is assumed for all sector reads when validating so if the directory goes to 19/6, then the validate code will read 18/6 instead. If 18/6 is part of the normal directory chain then the validate routine will loop endlessly.
The layout of the BAM area (sector 18/0) is a bit more complicated...
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 12 01 41 00 12 FF F9 17 15 FF FF 1F 15 FF FF 1F 10: 15 FF FF 1F 12 FF F9 17 00 00 00 00 00 00 00 00 20: 00 00 00 00 0E FF 74 03 15 FF FF 1F 15 FF FF 1F 30: 0E 3F FC 11 07 E1 80 01 15 FF FF 1F 15 FF FF 1F 40: 15 FF FF 1F 15 FF FF 1F 0D C0 FF 07 13 FF FF 07 50: 13 FF FF 07 11 FF CF 07 13 FF FF 07 12 7F FF 07 60: 13 FF FF 07 0A 75 55 01 00 00 00 00 00 00 00 00 70: 00 00 00 00 00 00 00 00 01 08 00 00 03 02 48 00 80: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 90: 53 48 41 52 45 57 41 52 45 20 31 20 20 A0 A0 A0 A0: A0 A0 56 54 A0 32 41 A0 A0 A0 A0 00 00 00 00 00 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$01 | Track/Sector location of the first directory sector (should be set to 18/1 but it doesn't matter, and don't trust what is there, always go to 18/1 for first directory entry) |
$02 | Disk DOS version type (see note below) $41 ("A") |
$03 | Unused |
$04-$8F | BAM entries for each track, in groups of four bytes per track, starting on track 1 (see below for more details) |
$90-$9F | Disk Name (padded with $A0) |
$A0-$A1 | Filled with $A0 |
$A2-$A3 | Disk ID |
$A4 | Usually $A0 |
$A5-$A6 | DOS type, usually "2A" |
$A7-$AA | Filled with $A0 |
$AB | Unused ($00) |
$AC-$BF | For DOLPHIN DOS track 36-40 BAM entries, otherwise unused ($00) |
$C0-$D3 | For SPEED DOS track 36-40 BAM entries, otherwise unused ($00) |
$D4-$FF Unused ($00) |
Note: The BAM entries for SPEED, DOLPHIN and ProLogic DOS use the same layout as standard BAM entries. One of the interesting things from the BAM sector is the byte at offset $02, the DOS version byte. If it is set to anything other than $41 or $00, then we have what is called "soft write protection". Any attempt to write to the disk will return the "DOS Version" error code 73 ,"CBM DOS V 2.6 1541". The 1541 is simply telling you that it thinks the disk format version is incorrect. This message will normally come up when you first turn on the 1541 and read the error channel. If you write a $00 or a $41 into 1541 memory location $00FF (for device 0), then you can circumvent this type of write-protection, and change the DOS version back to what it should be.
The BAM entries require a bit (no pun intended) more of a breakdown. Take the first entry at bytes $04-$07 ($12 $FF $F9 $17). The first byte ($12) is the number of free sectors on that track. Since we are looking at the track 1 entry, this means it has 18 (decimal) free sectors. The next three bytes represent the bitmap of which sectors are used/free. Since it is 3 bytes (8 bits/byte) we have 24 bits of storage. Remember that at most, each track only has 21 sectors, so there are a few unused bits.
Bytes | Data | Description |
$04-$07 | $12 $FF $F9 $17 | Track 1 BAM |
$08-$0B | $15 $FF $FF $FF | Track 2 BAM |
$0C-$0F | $15 $FF $FF $1F | Track 3 BAM |
... | ... | ... |
$8C-$8F | $11 $FF $FF $01 | Track 35 BAM |
These entries must be viewed in binary to make any sense. We will use the first entry (track 1) at bytes 04-07:
FF=11111111, F9=11111001, 17=00010111
In order to make any sense from the binary notation, flip the bits around.
111111 11112222 01234567 89012345 67890123 -------------------------- 11111111 10011111 11101000 ^ ^ sector 0 sector 20
Since we are on the first track, we have 21 sectors, and only use up to the bit 20 position. If a bit is on (1), the sector is free. Therefore, track 1 has sectors 9, 10 and 19 used, all the rest are free. Any leftover bits that refer to sectors that don't exist, like bits 21-23 in the above example, are set to allocated.
Each filetype has its own unique properties, but most follow one simple structure. The first file sector is pointed to by the directory and follows a t/s chain, until the track value reaches $00. When this happens, the value in the sector link location indicates how much of the sector is used. For example, the following chain indicates a file 6 sectors long, and ends when we encounter the $00/$34 chain. At this point the last sector occupies from bytes $02-$34.
1 | 2 | 3 | 4 | 5 | 6 |
---- | ---- | ---- | ---- | ---- | ---- |
17/0 | 17/10 | 17/20 | 17/1 | 17/11 | 0/52 |
(11/00) | (11/0A) | (11/14) | (11/01) | (11/0B) | (0/34) |
These are some variations of the D64 layout:
1. Standard 35 track layout but with 683 error bytes added on to the end of the file. Each byte of the error info corresponds to a single sector stored in the D64, indicating if the sector on the original disk contained an error. The first byte is for track 1/0, and the last byte is for track 35/16.
2. A 40 track layout, following the same layout as a 35 track disk, but with 5 extra tracks. These contain 17 sectors each, like tracks 31-35. Some of the PC utilities do allow you to create and work with these files. This can also have error bytes attached like variant #1.
3. A 42 track layout, with two extra tracks of 17 sectors each. This is extremely uncommon, since real drives often have problems with accessing these tracks, software that uses them is very rare.
4. The Commodore 128 allowed for "auto-boot" disks. With this, t/s 1/0 holds a specific byte sequence which the computer recognizes as boot code.
Below is a small chart detailing the standard file sizes of D64 images, 35, 40 or 42 tracks, with or without error bytes.
Disk type | Size |
35 track, no errors | 174848 |
35 track, 683 error bytes | 175531 |
40 track, no errors | 196608 |
40 track, 768 error bytes | 197376 |
42 track, no errors | 205312 |
42 track, 802 error bytes | 206114 |
The following table (provided by Wolfgang Moser) outlines the differences between the standard 1541 DOS and the various "speeder" DOS's that exist. The 'header 7/8' category is the 'fill bytes' as the end of the sector header of a real 1541 disk.
Disk format | tracks | header 7/8 | Dos type | Diskdos vs. type |
Original CBM DOS v2.6 | 35 | $0f $0f | "2A" | $41/'A' |
*SpeedDOS+ | 40 | $0f $0f | "2A" | $41/'A' |
Professional DOS Initial | 35 | $0f $0f | "2A" | $41/'A' |
Professional DOS Version 1/Prototype | 40 | $0f $0f | "2A" | $41/'A' |
ProfDOS Release | 40 | $0f $0f | "4A" | $41/'A' |
Dolphin-DOS 2.0/3.0 | 35 | $0f $0f | "2A" | $41/'A' |
Dolphin-DOS 2.0/3.0 | 40 | $0d $0f | "2A" | $41/'A' |
PrologicDOS 1541 | 35 | $0f $0f | "2A" | $41/'A' |
PrologicDOS 1541 | 40 | $0f $0f | "2P" | $50/'P' |
ProSpeed 1571 2.0 | 35 | $0f $0f | "2A" | $41/'A' |
ProSpeed 1571 2.0 | 40 | $0f $0f | "2P" | $50/'P' |
*Note: There are also clones of SpeedDOS that exist, such as RoloDOS and DigiDOS. Both are just a change of the DOS startup string.
The location of the extra BAM information in sector 18/0, for 40 track images, will be different depending on what standard the disks have been formatted with. SPEED DOS stores them from $C0 to $D3, DOLPHIN DOS stores them from $AC to $BF and PrologicDOS stored them right after the existing BAM entries from $90-A3. PrologicDOS also moves the disk label and ID forward from the standard location of $90 to $A4. 64COPY and Star Commander let you select from several different types of extended disk formats you want to create/work with.
All three of the speeder DOS's mentioned above don't alter the standard sector interleave of 10 for files and 3 for directories. The reason is that they use a memory cache installed in the drive which reads the entire track in one pass. This alleviates the need for custom interleave values. They do seem to alter the algorithm that finds the next available free sector so that the interleave value can deviate from 10 under certain circumstances, but I don't know why they would bother.
Below is a HEX dump of a Speed DOS BAM sector. Note the location of the extra BAM info from $C0-D3.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 0070: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01 0080: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 0090: A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 00A0: A0 A0 30 30 A0 32 41 A0 A0 A0 A0 00 00 00 00 00 00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00C0: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 00D0: 11 FF FF 01 00 00 00 00 00 00 00 00 00 00 00 00
Below is a HEX dump of a Dolphin DOS BAM sector. Note the location of the extra BAM info from $AC-BF.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 0070: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01 0080: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 0090: A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 00A0: A0 A0 30 30 A0 32 41 A0 A0 A0 A0 00 11 FF FF 01 00B0: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Below is a HEX dump of a PrologicDOS BAM sector. Note that the disk name and ID are now located at $A4 instead of starting at $90.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 0070: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01 0080: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 0090: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 00A0: 11 FF FF 01 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 00B0: A0 A0 A0 A0 A0 A0 30 30 A0 32 50 A0 A0 A0 A0 00 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Here is the meaning of the error bytes added onto the end of any extended D64. The CODE is the same as that generated by the 1541 drive controller... it reports these numbers, not the error code we usually see when an error occurs.
Some of what comes below is taken from Immers/Neufeld book "Inside Commodore DOS". Note the descriptions are not completely accurate as to what the drive DOS is actually doing to seek/read/decode/write sectors, but serve as simple examples only. The "type" field is where the error usually occurs, whether it's searching for any SYNC mark, any header ID, any valid header, or reading a sector.
Code | Error | Type | D64 | Description |
$01 | 00 | N/A | * | No error. |
$02 | 20 | Seek | * | Header block not found / Header descriptor byte not found |
$03 | 21 | Seek | * | No SYNC sequence found |
$04 | 22 | Read | * | Data descriptor byte not found |
$05 | 23 | Read | * | Checksum error in data block |
$06 | 24 | Write | Write verify on format (never occurs on 1541) | |
$07 | 25 | Write | Write verify error | |
$08 | 26 | Write | Write protect on | |
$09 | 27 | Seek | * | Checksum error in header block |
$0A | 28 | Write | Write error (never occurs on 1541) | |
$0B | 29 | Seek | * | Disk sector ID mismatch |
$0F | 74 | Read | Drive Not Ready (no disk in drive or no device 1) |
Codes $0 and $C to $E are unused and never occur.
These first errors are "seek" errors, where the disk controller is simply reading headers and looking at descriptor bytes, checksums, format ID's and reporting what errors it sees. These errors do *not* necessarily apply to the exact sector being looked for. This fact makes duplication of these errors very unreliable.
Code : $03 Error : 21 Type : Seek Message : No SYNC sequence found.
Each sector data block and header block are preceeded by SYNC marks. If *no* sync sequence is found within 20 milliseconds (only ~1/10 of a disk rotation!) then this error is generated. This error used to mean the entire track is bad, but it does not have to be the case. Only a small area of the track needs to be without a SYNC mark and this error will be generated.
Converting this error to a D64 is very problematic because it depends on where the physical head is on the disk when a read attempt is made. If it is on valid header/sectors then it won't occur. If it happens over an area without SYNC marks, it will happen.
Code : $02 Error : 20 Type : Seek Message : Header descriptor byte not found (HEX $08, GCR $52)
Each sector is preceeded by an 8-byte GCR header block, which starts with the value $52 (GCR). If this value is not found after 90 attempts, this error is generated.
Basically, what a track has is SYNC marks, and possibly valid data blocks, but no valid header descriptors.
Code : $09 Error : 27 Type : Seek Message : Checksum error in header block
The header block contains a checksum value, calculated by XOR'ing the TRACK, SECTOR, ID1 and ID2 values. If this checksum is wrong, this error is generated.
Code : $0B Error : 29 Type : Seek Message : Disk sector ID mismatch
The ID's from the header block of the currently read sector are compared against the ones from the low-level header of 18/0. If there is a mismatch, this error is generated.
Code : $02 Error : 20 Type : Seek Message : Header block not found
This error can be reported again when searching for the correct header block. An image of the header is built and searched for, but not found after 90 read attempts. Note the difference from the first occurance. The first one only searches for a valid ID, not the whole header.
Note that error 20 occurs twice during this phase. The first time is when a header ID is being searched for, the second is when the proper header pattern for the sector being searched for is not found.
From this point on, all the errors apply to the specific sector you are looking for. If a read passed all the previous checks, then we are at the sector being searched for.
Note that the entire sector is read before these errors are detected. Therefore the data, checksum and off bytes are available.
Code : $04 Error : 22 Type : Read Message : Data descriptor byte not found (HEX $07, GCR $55)
Each sector data block is preceeded by the value $07, the "data block" descriptor. If this value is not there, this error is generated. Each encoded sector has actually 260 bytes. First is the descriptor byte, then follows the 256 bytes of data, a checksum, and two "off" bytes.
Code : $05 Error : 23 Type : Read Message : Checksum error in data block
The checksum of the data read of the disk is calculated, and compared against the one stored at the end of the sector. If there's a discrepancy, this error is generated.
Code : $0F Error : 74 Type : Read Message : Drive Not Ready (no disk in drive or no device 1)
These errors only apply when writing to a disk. I don't see the usefulness of having these as they cannot be present when only *reading* a disk.
Code : $06 Error : 24 Type : Write Message : Write verify (on format)
Code : $07 Error : 25 Type : Write Message : Write verify error
Once the GCR-encoded sector is written out, the drive waits for the sector to come around again and verifies the whole 325-byte GCR block. Any errors encountered will generate this error.
Code : $08 Error : 26 Type : Write Message : Write protect on
Self explanatory. Remove the write-protect tab, and try again.
Code : $0A Error : 28 Type : Write Message : Write error
In actual fact, this error never occurs, but it is included for completeness.
This is not an error at all, but it gets reported when the read of a sector is ok.
Code : $01 Error : 00 Type : N/A Message : No error.
Self explanatory. No errors were detected in the reading and decoding of the sector.
The advantage with using the 35 track D64 format, regardless of error bytes, is that it can be converted directly back to a 1541 disk by either using the proper cable and software on the PC, or send it down to the C64 and writing it back to a 1541. It is the best documented format since it is also native to the C64, with many books explaining the disk layout and the internals of the 1541.
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)
This file type, created by Teemu Rantanen, was used on the X64 emulator (a UNIX-based emulator) which has been superceeded by VICE. Both VICE and X64 support the X64 file standard, with VICE also supporting the regular D64 and T64 files.
Note that this ancient format is deprecated and subject for removal. It never got any momentum in the emulation community, and VICE never supported it for anything but 1541 disks.
X64 is not a specific type of file, but rather encompasses *all* known C64 disk types (hard disk, floppies, etc). An X64 is created by prepending a 64-byte header to an existing image (1541, 1571, etc) and setting specific bytes which describe what type of image follows. This header has undergone some revision, and this description is based on the 1.02 version, which was the last known at the time of writing.
The most common X64 file you will see is the D64 variety, typically 174912 bytes long (174848 for the D64 and 64 bytes for the header, assuming no error bytes are appended). The header layout (as used in 64COPY) is as follows:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 0000: 43 15 41 64 01 02 01 23 00 00 00 00 00 00 00 00 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0040: XX XX XX <- standard C64 image starts here....
Bytes | Description |
$00-$03 | This is the "Magic header" ($43 $15 $41 $64) |
$04 | Header version major ($01) |
$05 | Header version minor ($01, now its up to $02) |
$06 | Device type represented |
$07 | Maximum tracks in image (only in version 1.02 or greater) 1540/41/70: 35 1571: 35 1581: 80 (Logical single-sided disk) |
$08 | Number of disk sides in image. This value must be $00 for all 1541 and 1581 formats. $00=No second side $01=Second side |
$09 | Error data flag. |
$0A-$1F | Unused, set to $00 |
$20-$3E | Disk image description (in ASCII or ISO Latin/1) |
$3F | Always set to $00 |
$40- | Standard C64 file begins here. |
The device types are:
Value | Drive type |
$00 | 1540 See note below... |
$01 | 1541 (Default) |
$02 | 1542 |
$03 | 1551 |
$04 | 1570 |
$05 | 1571 |
$06 | 1572 |
$08 | 1581 |
$10 | 2031 or 4031 |
$11 | 2040 or 3040 |
$12 | 2041 |
$18 | 4040 |
$20 | 8050 |
$21 | 8060 |
$22 | 8061 |
$30 | SFD-1001 |
$31 | 8250 |
$32 | 8280 |
The first four bytes used for the device type at position $06 ($00 to $03) are functionally the same, and are compatible with older version of X64 files. Some old X64 files might have $00 for the device type (instead of $01), but it makes no real difference.
As most instances of X64 files will be strictly 1541 images, bytes $08-$3F are set to zero, and some versions of the X64 emulator don't use bytes $08-$3F.
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)
Similar to the D64 (1541), the 1571 drive can operate in either single-sided (1541 compatible) mode or double-sided (1571) mode. In this section I will be dealing with the double-sided mode only. For the breakdown of the single-sided mode, see the D64 section.
The D71 has 70 tracks, double that of the 1541, with a DOS file size of 349696 bytes. If the error byte block (1366 bytes) is attached, this makes the file size 351062 bytes. The track range and offsets into the D71 files are as follows:
Track | Sec/trk | # Sectors |
1-17 (side 0) | 21 | 357 |
18-24 (side 0) | 19 | 133 |
25-30 (side 0) | 18 | 108 |
31-35 (side 0) | 17 | 85 |
36-52 (side 1) | 21 | 357 |
53-59 (side 1) | 19 | 133 |
60-65 (side 1) | 18 | 108 |
66-70 (side 1) | 17 | 85 |
Track | #Sect | #SectorsIn | D71 Offset |
1 | 21 | 0 | $00000 |
2 | 21 | 21 | $01500 |
3 | 21 | 42 | $02A00 |
4 | 21 | 63 | $03F00 |
5 | 21 | 84 | $05400 |
6 | 21 | 105 | $06900 |
7 | 21 | 126 | $07E00 |
8 | 21 | 147 | $09300 |
9 | 21 | 168 | $0A800 |
10 | 21 | 189 | $0BD00 |
11 | 21 | 210 | $0D200 |
12 | 21 | 231 | $0E700 |
13 | 21 | 252 | $0FC00 |
14 | 21 | 273 | $11100 |
15 | 21 | 294 | $12600 |
16 | 21 | 315 | $13B00 |
17 | 21 | 336 | $15000 |
18 | 19 | 357 | $16500 |
19 | 19 | 376 | $17800 |
20 | 19 | 395 | $18B00 |
21 | 19 | 414 | $19E00 |
22 | 19 | 433 | $1B100 |
23 | 19 | 452 | $1C400 |
24 | 19 | 471 | $1D700 |
25 | 18 | 490 | $1EA00 |
26 | 18 | 508 | $1FC00 |
27 | 18 | 526 | $20E00 |
28 | 18 | 544 | $22000 |
29 | 18 | 562 | $23200 |
30 | 18 | 580 | $24400 |
31 | 17 | 598 | $25600 |
32 | 17 | 615 | $26700 |
33 | 17 | 632 | $27800 |
34 | 17 | 649 | $28900 |
35 | 17 | 666 | $29A00 |
36 | 21 | 683 | $2AB00 |
37 | 21 | 704 | $2C000 |
38 | 21 | 725 | $2D500 |
39 | 21 | 746 | $2EA00 |
40 | 21 | 767 | $2FF00 |
41 | 21 | 788 | $31400 |
42 | 21 | 809 | $32900 |
43 | 21 | 830 | $33E00 |
44 | 21 | 851 | $35300 |
45 | 21 | 872 | $36800 |
46 | 21 | 893 | $37D00 |
47 | 21 | 914 | $39200 |
48 | 21 | 935 | $3A700 |
49 | 21 | 956 | $3BC00 |
50 | 21 | 977 | $3D100 |
51 | 21 | 998 | $3E600 |
52 | 21 | 1019 | $3FB00 |
53 | 19 | 1040 | $41000 |
54 | 19 | 1059 | $42300 |
55 | 19 | 1078 | $43600 |
56 | 19 | 1097 | $44900 |
57 | 19 | 1116 | $45C00 |
58 | 19 | 1135 | $46F00 |
59 | 19 | 1154 | $48200 |
60 | 18 | 1173 | $49500 |
61 | 18 | 1191 | $4A700 |
62 | 18 | 1209 | $4B900 |
63 | 18 | 1227 | $4CB00 |
64 | 18 | 1245 | $4DD00 |
65 | 18 | 1263 | $4EF00 |
66 | 17 | 1281 | $50100 |
67 | 17 | 1298 | $51200 |
68 | 17 | 1315 | $52300 |
69 | 17 | 1332 | $53400 |
70 | 17 | 1349 | $54500 |
The directory structure is the same as a D64/1541. All the same filetypes apply, the directory still only holds 144 files per disk and should only exist on track 18.
The first two bytes of the sector ($12/$04 or 18/4) indicate the location of the next track/sector of the directory. If the track value is set to $00, then it is the last sector of the directory. It is possible, however unlikely, that the directory may *not* be competely on track 18 (some disks do exist like this). Just follow the chain anyhow.
When the directory is done, the track value will be $00. The sector link should contain a value of $FF, meaning the whole sector is allocated, but the actual value doesn't matter. The drive will return all the available entries anyways. This is a breakdown of a standard directory sector and entry:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 12 04 82 11 00 4A 45 54 20 53 45 54 20 57 49 4C 10: 4C 59 A0 A0 A0 00 00 00 00 00 00 00 00 00 2B 00 20: 00 00 82 0F 01 4A 53 57 20 31 A0 A0 A0 A0 A0 A0 30: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 BF 00 40: 00 00 82 06 03 53 4F 4E 20 4F 46 20 42 4C 41 47 50: 47 45 52 A0 A0 00 00 00 00 00 00 00 00 00 AE 00 60: 00 00 82 15 0D 50 4F 54 54 59 20 50 49 47 45 4F 70: 4E A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 A2 00 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$1F | First directory entry |
$20-$3F | Second dir entry |
$40-$5F | Third dir entry |
$60-$7F | Fourth dir entry |
$80-$9F | Fifth dir entry |
$A0-$BF | Sixth dir entry |
$C0-$DF | Seventh dir entry |
$E0-$FF | Eighth dir entry |
This is a breakdown of a standard directory entry:
Bytes | Description |
$00-$01 | Track/Sector location of next directory sector ($00/$FF if its the last sector) |
$02 | File type |
$03-$04 | Track/sector location of first sector of file |
$05-$14 | 16 character filename (in PETASCII, padded with $A0) |
$15-$16 | Track/Sector location of first side-sector block (REL file only) |
$17 | REL file record length (REL file only, max. value 254) |
$18-$1D | Unused (except with GEOS disks) |
$1E-$1F | File size in sectors, low/high byte order ($1E+$1F*256). The approx. filesize in bytes is <= #sectors * 254 |
The file type field is used as follows:
Bits | Description |
0-3 | The actual file type |
4 | Unused |
5 | Used only during SAVE-@ replacement |
6 | Locked flag (Set produces ">" locked files) |
7 | Closed flag (Not set produces "*", or "splat" files) |
The actual file type can be one of the following:
Binary | Decimal | File type |
0000 | 0 | DEL |
0001 | 1 | SEQ |
0010 | 2 | PRG |
0011 | 3 | USR |
0100 | 4 | REL |
Values 5-15 are illegal, but if used will produce very strange results. The 1571 is inconsistent in how it treats these bits. Some routines use all 4 bits, others ignore bit 3, resulting in values from 0-7.
When the 1571 is in is native ("1571") mode, files are stored with a sector interleave of 6, rather than 10 which the 1541 (and the 1571 in "1541" mode) uses. The directory still uses an interleave of 3.
Most Commodore floppy disk drives use a single dedicated directory track where all filenames are stored. This limits the number of files stored on a disk based on the number of sectors on the directory track. There are some disk images that contain more files than would normally be allowed. This requires extending the directory off the default directory track by changing the last directory sector pointer to a new track, allocating the new sectors in the BAM, and manually placing (or moving existing) file entries there. The directory of an extended disk can be read and the files that reside there can be loaded without problems on a real drive. However, this is still a very dangerous practice as writing to the extended portion of the directory will cause directory corruption in the non- extended part. Many of the floppy drives core ROM routines ignore the track value that the directory is on and assume the default directory track for operations.
To explain: assume that the directory has been extended from track 18 to track 19/6 and that the directory is full except for a few slots on 19/6. When saving a new file, the drive DOS will find an empty file slot at 19/6 offset $40 and correctly write the filename and a few other things into this slot. When the file is done being saved the final file information will be written to 18/6 offset $40 instead of 19/6 causing some directory corruption to the entry at 18/6. Also, the BAM entries for the sectors occupied by the new file will not be saved and the new file will be left as a SPLAT (*) file.
Attempts to validate the disk will result in those files residing off the directory track to not be allocated in the BAM, and could also send the drive into an endless loop. The default directory track is assumed for all sector reads when validating so if the directory goes to 19/6, then the validate code will read 18/6 instead. If 18/6 is part of the normal directory chain then the validate routine will loop endlessly.
The BAM is somewhat different as it now has to take 35 new tracks into account. In order to do this, most of the extra BAM information is stored on track 53/0, and the remaining sectors on track 53 are marked in the BAM as allocated. This does mean that except for one allocated sector on track 53, the rest of the track is unused and wasted. (Track 53 is the equivalent to track 18, but on the flip side of the disk). Here is a dump of the first BAM sector...
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 12 01 41 80 12 FF F9 17 15 FF FF 1F 15 FF FF 1F 10: 15 FF FF 1F 15 FF FF 1F 15 FF FF 1F 15 FF FF 1F 20: 15 FF FF 1F 15 FF FF 1F 15 FF FF 1F 15 FF FF 1F 30: 15 FF FF 1F 15 FF FF 1F 15 FF FF 1F 15 FF FF 1F 40: 15 FF FF 1F 15 FF FF 1F 11 FC FF 07 13 FF FF 07 50: 13 FF FF 07 13 FF FF 07 13 FF FF 07 13 FF FF 07 60: 13 FF FF 07 12 FF FF 03 12 FF FF 03 12 FF FF 03 70: 12 FF FF 03 12 FF FF 03 12 FF FF 03 11 FF FF 01 80: 11 FF FF 01 11 FF FF 01 11 FF FF 01 11 FF FF 01 90: A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0 A0: A0 A0 30 30 A0 32 41 A0 A0 A0 A0 00 00 00 00 00 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 15 15 15 E0: 15 15 15 15 15 15 15 15 15 15 15 15 15 15 00 13 F0: 13 13 13 13 13 12 12 12 12 12 12 11 11 11 11 11
Bytes | Description |
$00-$01 | Track/Sector location of the first directory sector (should be set to 18/1 but it doesn't matter, and don't trust what is there, always go to 18/1 for first directory entry) |
$02 | Disk DOS version type (see note below) $41 ('A') = 1541 |
$03 | Double-sided flag $00 - Single sided disk $80 - Double sided disk |
$04-8F | BAM entries for each track, in groups of four bytes per track, starting on track 1. |
$90-$9F | Disk Name (padded with $A0) |
$A0-$A1 | Filled with $A0 |
$A2-$A3 | Disk ID |
$A4 | Usually $A0 |
$A5-$A6 | DOS type, usually "2A" |
$A7-$AA | Filled with $A0 |
$AB-$DC | Not used ($00's) |
$DD-$FF | Free sector count for tracks 36-70 (1 byte/track). |
The "free sector" entries for tracks 36-70 are likely included here in the first BAM sector due to some memory restrictions in the 1571 drive. There is only enough memory available for one BAM sector, but in order to generate the "blocks free" value at the end of a directory listing, the drive needs to know the extra track "free sector" values. It does make working with the BAM a little more difficult, though.
These are the values that would normally be with the 4-byte BAM entry, but the rest of the entry is contained on 53/0.
Note: If the DOS version byte is set to anything other than $41 or $00, then we have what is called "soft write protection". Any attempt to write to the disk will return the "DOS Version" error code 73. The 1571 is simply telling you that it thinks the disk format version is incorrect.
The BAM entries require some explanation. Take the first entry at bytes $04-$07 ($12 $FF $F9 $17). The first byte ($12) is the number of free sectors on that track. Since we are looking at the track 1 entry, this means it has 18 (decimal) free sectors.
The next three bytes represent the bitmap of which sectors are used/free. Since it is 3 bytes (8 bits/byte) we have 24 bits of storage. Remember that at most, each track only has 21 sectors, so there are a few unused bits. These entries must be viewed in binary to make any sense. We will use the first entry (track 1) at bytes 04-07:
FF=11111111, F9=11111001, 17=00010111
In order to make any sense from the binary notation, flip the bits around.
111111 11112222 01234567 89012345 67890123 -------------------------- 11111111 10011111 11101000 ^ ^ sector 0 sector 20
Since we are on the first track, we have 21 sectors, and only use up to the bit 20 position. If a bit is on (1), the sector is free. Therefore, track 1 has sectors 9,10 and 19 used, all the rest are free.
In order to complete the BAM, we must check 53/0.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: FF FF 1F FF FF 1F FF FF 1F FF FF 1F FF FF 1F FF 10: FF 1F FF FF 1F FF FF 1F FF FF 1F FF FF 1F FF FF 20: 1F FF FF 1F FF FF 1F FF FF 1F FF FF 1F FF FF 1F 30: FF FF 1F 00 00 00 FF FF 07 FF FF 07 FF FF 07 FF 40: FF 07 FF FF 07 FF FF 07 FF FF 03 FF FF 03 FF FF 50: 03 FF FF 03 FF FF 03 FF FF 03 FF FF 01 FF FF 01 60: FF FF 01 FF FF 01 FF FF 01 00 00 00 00 00 00 00 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Each track from 36-70 has 3 byte entries, starting at address $00.
Byte: $00-$02: $FF $FF $1F - BAM map for track 36 $03-$05: $FF $FF $1F - BAM map for track 37 ... $33-$35: $00 $00 $00 - BAM map for track 53 ... $66-$68: $FF $FF $01 - BAM map for track 70 $69-$FF: - Not used
You can break down the entries for tracks 36-70 the same way as track 1, just combine the free sector bytes from 18/0 and the BAM usage from 53 to get the full 4-byte entry.
Just like a D64, you can attach error bytes to the file, for sector error information. This block is 1366 bytes long, 1 byte for each of the 1366 sectors in the image. With the error bytes, the file size is 351062 bytes.
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)
Like D64 and D71, this is a byte for byte copy of a physical 1581 disk. It consists of 80 tracks, 40 sectors each (0 to 39) for a size of 819200 bytes, or 3200 sectors. If the error byte block is attached, this makes the file size 822400 bytes.
There are three sectors on the directory track used for disk internals (header and BAM), leaving 37 sectors for filename entries, thus allowing for 296 files (37 * 8) to be stored at the root level of the disk.
The actual physical layout on the disk is quite different from what the user sees, but this is unimportant to the scope of this section. One important difference from the D64 and D71 is all the sector interleaves are now 1 for both files and directory storage (rather than 3 for directory and 10 for file on a D64/D71). This is due to the built-in buffering in the 1581. When reading a sector, the whole track will be buffered in memory, and any sectors being modified will be done in memory. Once it has to be written, the whole track will be written out in one step.
The track range and offsets into the D81 files are as follows:
Track | #Sect | #SectorsIn | D81 Offset |
1 | 40 | 0 | $00000 |
2 | 40 | 40 | $02800 |
3 | 40 | 80 | $05000 |
4 | 40 | 120 | $07800 |
5 | 40 | 160 | $0A000 |
6 | 40 | 200 | $0C800 |
7 | 40 | 240 | $0F000 |
8 | 40 | 280 | $11800 |
9 | 40 | 320 | $14000 |
10 | 40 | 360 | $16800 |
11 | 40 | 400 | $19000 |
12 | 40 | 440 | $1B800 |
13 | 40 | 480 | $1E000 |
14 | 40 | 520 | $20800 |
15 | 40 | 560 | $23000 |
16 | 40 | 600 | $25800 |
17 | 40 | 640 | $28000 |
18 | 40 | 680 | $2A800 |
19 | 40 | 720 | $2D000 |
20 | 40 | 760 | $2F800 |
21 | 40 | 800 | $32000 |
22 | 40 | 840 | $34800 |
23 | 40 | 880 | $37000 |
24 | 40 | 920 | $39800 |
25 | 40 | 960 | $3C000 |
26 | 40 | 1000 | $3E800 |
27 | 40 | 1040 | $41000 |
28 | 40 | 1080 | $43800 |
29 | 40 | 1120 | $46000 |
30 | 40 | 1160 | $48800 |
31 | 40 | 1200 | $4B000 |
32 | 40 | 1240 | $4D800 |
33 | 40 | 1280 | $50000 |
34 | 40 | 1320 | $52800 |
35 | 40 | 1360 | $55000 |
36 | 40 | 1400 | $57800 |
37 | 40 | 1440 | $5A000 |
38 | 40 | 1480 | $5C800 |
39 | 40 | 1520 | $5F000 |
40 | 40 | 1560 | $61800 |
41 | 40 | 1600 | $64000 |
42 | 40 | 1640 | $66800 |
43 | 40 | 1680 | $69000 |
44 | 40 | 1720 | $6B800 |
45 | 40 | 1760 | $6E000 |
46 | 40 | 1800 | $70800 |
47 | 40 | 1840 | $73000 |
48 | 40 | 1880 | $75800 |
49 | 40 | 1920 | $78000 |
50 | 40 | 1960 | $7A800 |
51 | 40 | 2000 | $7D000 |
52 | 40 | 2040 | $7F800 |
53 | 40 | 2080 | $82000 |
54 | 40 | 2120 | $84800 |
55 | 40 | 2160 | $87000 |
56 | 40 | 2200 | $89800 |
57 | 40 | 2240 | $8C000 |
58 | 40 | 2280 | $8E800 |
59 | 40 | 2320 | $91000 |
60 | 40 | 2360 | $93800 |
61 | 40 | 2400 | $96000 |
62 | 40 | 2440 | $98800 |
63 | 40 | 2480 | $9B000 |
64 | 40 | 2520 | $9D800 |
65 | 40 | 2560 | $A0000 |
66 | 40 | 2600 | $A2800 |
67 | 40 | 2640 | $A5000 |
68 | 40 | 2680 | $A7800 |
69 | 40 | 2720 | $AA000 |
70 | 40 | 2760 | $AC800 |
71 | 40 | 2800 | $AF000 |
72 | 40 | 2840 | $B1800 |
73 | 40 | 2880 | $B4000 |
74 | 40 | 2920 | $B6800 |
75 | 40 | 2960 | $B9000 |
76 | 40 | 3000 | $BB800 |
77 | 40 | 3040 | $BE000 |
78 | 40 | 3080 | $C0800 |
79 | 40 | 3120 | $C3000 |
80 | 40 | 3160 | $C5800 |
The header sector is stored at 40/0, and contains the disk name, ID and DOS version bytes, but the BAM is no longer contained here (like the D64).
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 28 03 44 00 31 35 38 31 20 55 54 49 4C 49 54 59 10: 20 56 30 31 A0 A0 47 42 A0 33 44 A0 A0 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$01 | Track/Sector location of the first directory sector (should be set to 40/3 but it doesn't matter, and don't trust what is there, always go to 40/3 for first directory entry) |
$02 | Disk DOS version type (see note below) $44 ('D')=1581 |
$03 | $00 |
$04-$13 | 16 character Disk Name (padded with $A0) |
$14-$15 | $A0 |
$16-$17 | Disk ID |
$18 | $A0 |
$19 | DOS Version ("3") |
$1A | Disk version ("D") |
$1B-$1C | $A0 |
$1D-$FF | Unused (usually $00) |
The following might be set if the disk is a GEOS format (this info is based on the D64 layout, and might not prove to be true)
Bytes | Description |
$AB-$AC | Border sector (GEOS only, else set to $00) |
$AD-$BC | GEOS ID string ("geos FORMAT V1.x" GEOS only, else $00) |
$BD-$FF | Unused (usually $00) |
Note: If the DOS version byte is changed to anything other than a $44 (or $00), then we have what is called "soft write protection". Any attempt to write to the disk will return the "DOS Version" error code 73. The drive is simply telling you that it thinks the disk format version is incompatible.
The directory track should be contained totally on track 40. Sectors 3-39 contain the entries and sector 1 and 2 contain the BAM (Block Availability Map). Sector 0 holds the disk name and ID. The first directory sector is always 40/3, even though the t/s pointer at 40/0 (first two bytes) might point somewhere else. It goes linearly up the sector count, 3-4-5-6-etc. Each sector holds up to eight entries.
The first two bytes of the sector ($28/$04) indicate the location of the next track/sector of the directory (40/4). If the track is set to $00, then it is the last sector of the directory. It is possible, however unlikely, that the directory may *not* be competely on track 40. Just follow the chain anyhow.
When the directory is done (track=$00), the sector should contain an $FF, meaning the whole sector is allocated. Theactual value doesn't matter as all the entries will be returned anyways. Each directory sector has the following layout:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 28 04 81 2B 00 53 43 52 45 45 4E 20 20 33 A0 A0 10: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 02 00 20: 00 00 81 2B 01 53 43 52 45 45 4E 20 20 34 A0 A0 30: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 03 00 40: 00 00 81 2B 02 53 43 52 45 45 4E 20 20 35 A0 A0 50: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 07 00 60: 00 00 81 2B 08 53 43 52 45 45 4E 20 20 36 A0 A0 70: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 08 00 80: 00 00 81 2B 14 53 43 52 45 45 4E 20 20 37 A0 A0 90: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 07 00 A0: 00 00 81 24 00 53 43 52 45 45 4E 20 20 38 A0 A0 B0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 0B 00 C0: 00 00 82 24 04 46 49 4C 45 34 32 39 33 36 39 30 D0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 07 00 E0: 00 00 82 24 06 46 49 4C 45 32 35 37 38 38 31 35 F0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 05 00
Bytes | Description |
$00-$1F | First directory entry |
$20-$3F | Second dir entry |
$40-$5F | Third dir entry |
$60-$7F | Fourth dir entry |
$80-$9F | Fifth dir entry |
$A0-$BF | Sixth dir entry |
$C0-$DF | Seventh dir entry |
$E0-$FF | Eighth dir entry |
This is a breakdown of a standard directory entry:
Bytes | Description |
$00-$01 | Track/Sector location of next directory sector |
$02 | File type |
$03-$04 | Track/sector location of first sector of file or partition |
$05-$14 | 16 character filename (in PETASCII, padded with $A0) |
$15-$16 | Track/Sector location of first SUPER SIDE SECTOR block (REL file only) |
$17 | REL file record length (REL file only) |
$18-$1B | Unused (except with GEOS disks) |
$1C-$1D | (Used during an SAVE or OPEN, holds the new t/s link) |
$1E-$1F | File or partition size in sectors, low/high byte order ($1E+$1F*256). The approx. file size in bytes is <= #sectors * 254 |
The file type field is used as follows:
Bits | Description |
0-3 | The actual file type |
4 | Unused |
5 | Used only during SAVE-@ replacement |
6 | Locked flag (Set produces ">" locked files) |
7 | Closed flag (Not set produces "*", or "splat" files) |
The actual file type can be one of the following:
Binary | Decimal | File type |
0000 | 0 | DEL |
0001 | 1 | SEQ |
0010 | 2 | PRG |
0011 | 3 | USR |
0100 | 4 | REL |
0101 | 5 | CBM (partition or sub-directory) |
Values 6-15 are illegal, but if used will produce very strange results.
Most Commdore floppy disk drives use a single dedicated directory track where all filenames are stored. This limits the number of files stored on a disk based on the number of sectors on the directory track. There are some disk images that contain more files than would normally be allowed. This requires extending the directory off the default directory track by changing the last directory sector pointer to a new track, allocating the new sectors in the BAM, and manually placing (or moving existing) file entries there. The directory of an extended disk can be read and the files that reside there can be loaded without problems on a real drive. However, this is still a very dangerous practice as writing to the extended portion of the directory will cause directory corruption in the non-extended part. Many of the floppy drives core ROM routines ignore the track value that the directory is on and assume the default directory track for operations.
The BAM is located on 40/1 (for side 0, tracks 1-40) and 40/2 (for side 1, tracks 41-80). Each entry takes up six bytes, one for the "free sector" count and five for the allocation bitmap.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 28 02 44 BB 47 42 C0 00 00 00 00 00 00 00 00 00 10: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 20: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF 30: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 40: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 50: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF 60: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 70: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 80: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF 90: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF A0: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF B0: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF C0: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF D0: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF E0: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF F0: FF FF FF FF 28 FF FF FF FF FF 24 F0 FF 2D FF FE
Bytes: $00-$01: Track/sector of next bam sector (40/2) $02: Version # ('D') $03: One's complement of version# ($BB) $04-$05: Disk ID bytes (same as 40/0 Disk ID) $06: I/O byte bit 7 set - Verify on bit 7 clear - Verify off bit 6 set - Check header CRC bit 6 clear - Don't check header CRC $07: Auto-boot-loader flag $08-$0F: Reserved for future (set to $00) $10-$15: BAM entry for track 1 (track 41, side 1) $16-$1B: BAM entry for track 2 (track 42, side 1) ... $46-$4B: BAM entry for track 10 (track 50, side 1) ... $82-$87: BAM entry for track 20 (track 60, side 1) ... $BE-$C3: BAM entry for track 30 (track 70, side 1) ... $FA-$FF: BAM entry for track 40 (track 80, side 1)
The BAM entries require some explanation, so lets look at the track 40 entry at bytes $FA-FF ($24 $F0 $FF $2D $FF $FE). The first byte ($24, or 36 decimal) is the number of free sectors on that track. The next five bytes represent the bitmap of which sectors are used/free. Since it is five bytes (8 bits/byte) we have 40 bits of storage. Since this format has 40 sectors/track, the whole five bytes are used.
F0: .. .. .. .. .. .. .. .. .. .. 24 F0 FF 2D FF FE
The last five bytes of any BAM entry must be viewed in binary to make any sense. We will once again use track 40 as our reference:
F0=11110000, FF=11111111, 2D=00101101, FF=11111111, FE=11111110
In order to make any sense from the binary notation, flip the bits around.
111111 11112222 22222233 33333333 Sector 01234567 89012345 67890123 45678901 23456789 -------------------------- -------- -------- 00001111 11111111 10110100 11111111 01111111
Note that if a bit is on (1), the sector is free. Therefore, track 40 has sectors 0-3, 17, 20, 22, 23 and 32 used, all the rest are free.
The second BAM (for side 1) contains the entries for tracks 41-80.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 00 FF 44 BB 47 42 C0 00 00 00 00 00 00 00 00 00 10: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 20: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF 30: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 40: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 50: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF 60: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 70: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 80: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF 90: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF A0: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF B0: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF C0: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF D0: 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF E0: FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF 28 FF F0: FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF FF FF
It is laid out exactly as the side 0 BAM except for one difference. The track/sector reference for the next sector should be set to $00/$FF, indicating there is no next sector.
The REL filetype requires some extra explaining. It was designed to make access to data *anywhere* on the disk very fast. Take a look at this directory entry...
00: 00 FF 84 27 00 41 44 44 49 54 49 4F 4E 41 4C 20 10: 49 4E 46 4F A0 27 02 FE 00 00 00 00 00 00 D2 0B
The third byte ($84) indicates this entry is a REL file and that the three normally empty entries at offset $15, $16 and $17 are now used as they are explained above. It's the track/sector chain that this entry points to, called the SUPER SIDE SECTOR, which is of interest here (in this case, 39/2). The SUPER SIDE SECTOR is very different from the D64 format. If you check the D64 entry for a REL file and do the calculations, you will find that the maximum file size of the REL file is 720 data sectors. With the new SUPER SIDE SECTOR, you can now have 126 groups of these SIDE SECTORS chains, allowing for file sizes up to (theoretically) 90720 sectors, or about 22.15 Megabytes.
Here is a dump of the beginning of the SUPER SIDE SECTOR...
00: 27 01 FE 27 01 15 09 03 0F 38 16 4A 1C 00 00 00 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes: $00-$01: Track/sector of first side sector in group 0 $02: Always $FE $03-$04: Track/sector of first side sector in group 0 (again) ... $FD-$FE: Track/sector of first side sector in group 125 $FF: Unused (likely $00)
The side sector layout is the same as the D64/1571.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 12 0A 00 FE 15 09 12 0A 0F 0B 0C 0C 09 0D 06 0E 10: 15 07 15 08 15 0A 15 0B 15 0C 15 0D 15 0E 15 0F 20: 15 10 15 11 15 12 15 13 15 14 15 15 15 16 15 17 30: 15 18 15 19 15 1A 15 1B 15 1C 15 1D 15 1E 15 1F 40: 15 20 15 21 15 22 15 23 15 24 15 25 15 26 15 27 50: 14 00 14 01 14 02 14 03 14 04 14 05 14 06 14 07 60: 14 08 14 09 14 0A 14 0B 14 0C 14 0D 14 0E 14 0F 70: 14 10 14 11 14 12 14 13 14 14 14 15 14 16 14 17 80: 14 18 14 19 14 1A 14 1B 14 1C 14 1D 14 1E 14 1F 90: 14 20 14 21 14 22 14 23 14 24 14 25 14 26 14 27 A0: 13 00 13 01 13 02 13 03 13 04 13 05 13 06 13 07 B0: 13 08 13 09 13 0A 13 0B 13 0C 13 0D 13 0E 13 0F C0: 13 10 13 11 13 12 13 13 13 14 13 15 13 16 13 17 D0: 13 18 13 19 13 1A 13 1B 13 1C 13 1D 13 1E 13 1F E0: 13 20 13 21 13 22 13 23 13 24 13 25 13 26 13 27 F0: 12 00 12 01 12 02 12 03 12 04 12 05 12 06 12 07
Bytes: $00: Track location of next side-sector ($00 if last sector) $01: Sector location of next side-sector $02: Side-sector block number (first sector is $00, the next is $01, then $02, etc) $03: REL file RECORD size (from directory entry) $04-$0F: Track/sector locations of the six other side-sectors. Note the first entry is this very sector we have listed here. The next is the next t/s listed at the beginning of the sector. All of this information must be correct. If one of these chains is $00/$00, then we have no more side sectors. Also, all of these (up to six) side sectors must have the same values in this range. $10-$FF: T/S chains of *each* sector of the data portion. When we get a $00/$00, we are at the end of the file.
At the beginning of this section it was stated that the 1581 can hold 296 entries "at the root level". The 1581 also has the ability to partition areas of the disk. Under the right conditions these can become sub-directories, acting as a small diskette, complete with its own directory and BAM. When you are inside of a sub-directory, no other files except those in that directory are visible, or can be affected.
To the 1581, this file will show up as a "CBM" filetype in a directory. All this does is tell the disk that a file, starting at X/Y track/sector and Z sectors large exists. Doing a validate will not harm these files as they have a directory entry, and are fully allocated in the BAM.
There are two main uses for partitions. One is to simply allocate a section of the disk to be used for direct-access reads/writes, and lock it away from being overwritten after a VALIDATE. The second is as a sub-directory, basically a small "disk within a disk".
In order to use a partition as a sub-directory, it must adhere to the following four rules:
1. If must start on sector 0 2. It's size must be in multiples of 40 sectors 3. It must be a minimum of 120 sectors long (3 tracks) 4. If must not start on or cross track 40, which limits the biggest directory to 1600 sectors (tracks 1-39).
This is a dump of a sub-directory entry:
00: 00 FF 85 29 00 50 41 52 54 49 54 49 4F 4E 20 31 10: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 40 06
It is a partition starting on track 41/0, extends for 1600 sectors, and has been formatted as a sub-directory. Note that when a partition is created, the area being allocated is not touched in any way. If you want it set up as a sub-directory, you must issue the FORMAT command to the 1581 to create the central directory and BAM. Also note that from the directory entry you can't tell whether it is a sub-directory or not, just that it fits the sub-directory parameters.
The BAM track for the sub-directory exists on the first track of the partition, and has the same layout as the disk BAM on track 40. The biggest difference is the "disk name" is what what given when the partition was formatted rather than what the actual disk name is. Also, except for the free sectors in the partition area, all other sectors in the BAM will be allocated.
If the partition size doesn't match the above rules for a sub-directory, it will simply exist as a "protected" area of the disk, and can't be used as a sub-directory. Either way, it still shows up as a "CBM" type in a directory listing. Below is a dump of a 10-sector partition starting on track 5/1, which does not qualify as a sub-directory...
00: 00 00 85 05 01 53 4D 41 4C 4C 50 41 52 54 20 32 10: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 0A 00
The master BAM shows the entry for this partition on track 5...
00: 28 02 44 BB 43 44 C0 00 00 00 00 00 00 00 00 00 10: 23 C1 FF FF FF FF 28 FF FF FF FF FF 28 FF FF FF 20: FF FF 28 FF FF FF FF FF 1E 01 F8 FF FF FF 28 FF ^^^^^^^^^^^^^^^^^
The breakdown of the BAM shows the allocation for this track, with sectors 1-10 allocated, as it should be.
10000000 00011111 11111111 11111111 11111111 ^ ^ ^ ^ ^ 0 10 20 30 39
Partitions and sub-directories share one very important trait. When created, the sub-directory entry simply has the starting track/sector and the size of the partition in sectors. Partitions are created linearly, meaning if one starts on 30/1 and is of size 15 sectors, then the sector range from 1 through 15 on track 30 will be allocated. If a partition size crosses a track boundary, the allocation will continue on the next track starting on sector 0, and going up.
The section allocated will *not* have a track/sector chain like a file would, but rather is dependant on the directory entry to keep it from being overwritten. You can store whatever you want to in the allocated area.
If byte $07 in the BAM is set, then when the drive is reset (and other circumstances) it will look for a USR file called "COPYRIGHT CBM 86". This file will then be loaded into the drive RAM and executed.
The format for this auto-loader file is fairly basic. It starts with a two-byte load address, a size byte, program data, and a checksum at the end.
Bytes: $00-$01: Load address, low/high format $02: Size of program (SZ) (smaller than 256 bytes) $03-($03+SZ-1): Program data $03+SZ: Checksum byte
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)
This is a sector-for-sector copy of an 8050 floppy disk. The file size for an 8050 image is 533248 bytes. It is comprised of 256-byte sectors arranged across 77 tracks, with a varying number of sectors per track for a total of 2083 sectors. Track counting starts at 1 (not 0) and sector counting starts at 0 (not 1), therefore a track with 29 sectors will go from 0 to 28.
The original media (a 5.25" disk) has the tracks laid out in circles, with track 1 on the very outside of the disk (closest to the sides) to track 77 being on the inside of the disk (closest to the inner hub ring). Commodore, in their infinite wisdom, varied the number of sectors per track and data densities across the disk to optimize available storage, resulting in the chart below. It shows the sectors/track for a D80. Since the outside diameter of a circle is the largest (versus closer to the center), the outside tracks have the largest amount of storage.
Track Range | Sectors/track | # Sectors |
1-39 | 29 | 1131 |
40-53 | 27 | 378 |
54-64 | 25 | 275 |
65-77 | 23 | 299 |
Track | #Sect | #SectorsIn | D8x Offset |
1 | 29 | 0 | $00000 |
2 | 29 | 29 | $01D00 |
3 | 29 | 58 | $03A00 |
4 | 29 | 87 | $05700 |
5 | 29 | 116 | $07400 |
6 | 29 | 145 | $09100 |
7 | 29 | 174 | $0AE00 |
8 | 29 | 203 | $0CB00 |
9 | 29 | 232 | $0E800 |
10 | 29 | 261 | $10500 |
11 | 29 | 290 | $12200 |
12 | 29 | 319 | $13F00 |
13 | 29 | 348 | $15C00 |
14 | 29 | 377 | $17900 |
15 | 29 | 406 | $19600 |
16 | 29 | 435 | $1B300 |
17 | 29 | 464 | $1D000 |
18 | 29 | 493 | $1ED00 |
19 | 29 | 522 | $20A00 |
20 | 29 | 551 | $22700 |
21 | 29 | 580 | $24400 |
22 | 29 | 609 | $26100 |
23 | 29 | 638 | $27E00 |
24 | 29 | 667 | $29B00 |
25 | 29 | 696 | $2B800 |
26 | 29 | 725 | $2D500 |
27 | 29 | 754 | $2F200 |
28 | 29 | 783 | $30F00 |
29 | 29 | 812 | $32C00 |
30 | 29 | 841 | $34900 |
31 | 29 | 870 | $36600 |
32 | 29 | 899 | $38300 |
33 | 29 | 928 | $3A000 |
34 | 29 | 957 | $3BD00 |
35 | 29 | 986 | $3DA00 |
36 | 29 | 1015 | $3F700 |
37 | 29 | 1044 | $41400 |
38 | 29 | 1073 | $43100 |
39 | 29 | 1102 | $44E00 |
40 | 27 | 1131 | $46B00 |
41 | 27 | 1158 | $48600 |
42 | 27 | 1185 | $4A100 |
43 | 27 | 1212 | $4BC00 |
44 | 27 | 1239 | $4D700 |
45 | 27 | 1266 | $4F200 |
46 | 27 | 1293 | $50D00 |
47 | 27 | 1320 | $52800 |
48 | 27 | 1347 | $54300 |
49 | 27 | 1374 | $55E00 |
50 | 27 | 1401 | $57900 |
51 | 27 | 1428 | $59400 |
52 | 27 | 1455 | $5AF00 |
53 | 27 | 1482 | $5CA00 |
54 | 25 | 1509 | $5E500 |
55 | 25 | 1534 | $5FE00 |
56 | 25 | 1559 | $61700 |
57 | 25 | 1584 | $63000 |
58 | 25 | 1609 | $64900 |
59 | 25 | 1634 | $66200 |
60 | 25 | 1659 | $67B00 |
61 | 25 | 1684 | $69400 |
62 | 25 | 1709 | $6AD00 |
63 | 25 | 1734 | $6C600 |
64 | 25 | 1759 | $6DF00 |
65 | 23 | 1784 | $6F800 |
66 | 23 | 1807 | $70F00 |
67 | 23 | 1830 | $72600 |
68 | 23 | 1853 | $73D00 |
69 | 23 | 1876 | $75400 |
70 | 23 | 1899 | $76B00 |
71 | 23 | 1922 | $78200 |
72 | 23 | 1945 | $79900 |
73 | 23 | 1968 | $7B000 |
74 | 23 | 1991 | $7C700 |
75 | 23 | 2014 | $7DE00 |
76 | 23 | 2037 | $7F500 |
77 | 23 | 2060 | $80C00 |
The BAM (Block Availability Map) is on track 38. The D80 is only 77 tracks and so the BAM is contained on 38/0 and 38/3. The BAM interleave is 3.
The directory is on track 39, with 39/0 contains the header (DOS type, disk name, disk ID's) and sectors 1-28 contain the directory entries. Both files and the directory use an interleave of 1. Since the directory is only 28 sectors large (29 less one for the header), and each sector can contain only 8 entries (32 bytes per entry), the maximum number of directory entries is 28 * 8 = 224. The first directory sector is always 39/1. It then follows a chain structure using a sector interleave of 1 making the links go 39/1, 39/2, 39/3 etc.
When reading a disk, you start with 39/0 (disk label/ID) which points to 38/0 (BAM0), 38/3 (BAM1), and finally to 39/1 (first dir entry sector). When writing a file to a blank disk, it will start at 38/1 because 38/0 is already allocated.
Below is a dump of the header sector 39/0:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 26 00 43 00 00 00 73 61 6D 70 6C 65 20 64 38 30 10: A0 A0 A0 A0 A0 A0 A0 A0 65 72 A0 32 43 A0 A0 A0 20: A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$01 | T/S pointer to first BAM sector (38/0) |
$02 | $43 'C' is for DOS format version |
$03 | Reserved |
$04-$05 | Unused |
$06-$16 | Disk name, padded with 0xA0 ("sample d80") |
$17 | 0xA0 |
$18-$19 | Disk ID bytes "er" |
$1A | 0xA0 |
$1B-$1C | DOS version bytes "2C" |
$1D-$20 | 0xA0 |
$21-$FF | Unused |
Below is a dump of the first directory sector, 39/1
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 27 02 82 26 01 54 45 53 54 A0 A0 A0 A0 A0 A0 A0 10: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 20: 00 00 82 26 02 54 45 53 54 32 A0 A0 A0 A0 A0 A0 30: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 40: 00 00 82 26 04 54 45 53 54 33 A0 A0 A0 A0 A0 A0 50: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 05 00 60: 00 00 82 26 0B 54 45 53 54 34 A0 A0 A0 A0 A0 A0 70: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 09 00 80: 00 00 82 26 14 54 45 53 54 35 A0 A0 A0 A0 A0 A0 90: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 0C 00 A0: 00 00 82 28 00 54 45 53 54 36 A0 A0 A0 A0 A0 A0 B0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 C0: 00 00 82 28 01 54 45 53 54 37 A0 A0 A0 A0 A0 A0 D0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 E0: 00 00 82 28 02 54 45 53 54 38 A0 A0 A0 A0 A0 A0 F0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00
The first two bytes of the directory sector ($27/$02) indicate the location of the next track/sector of the directory (39/2). If the track is set to $00, then it is the last sector of the directory.
When the directory is done, the track value will be $00. The sector link should contain a value of $FF, meaning the whole sector is allocated, but the actual value doesn't matter. The drive will return all the available entries anyways. This is a breakdown of a standard directory sector:
Bytes | Description |
$00-$1F | First directory entry |
$20-$3F | Second dir entry |
$40-$5F | Third dir entry |
$60-$7F | Fourth dir entry |
$80-$9F | Fifth dir entry |
$A0-$BF | Sixth dir entry |
$C0-$DF | Seventh dir entry |
$E0-$FF | Eighth dir entry |
This is a breakdown of a standard directory entry:
Bytes | Description |
$00-$01 | Track/Sector location of next directory sector ($00 $00 if not the first entry in the sector) |
$02 | File type |
$03-$04 | Track/sector location of first sector of file |
$05-$14 | 16 character filename (in PETASCII, padded with $A0) |
$15-$16 | Track/Sector location of first side-sector block (REL file only) |
$17 | REL file record length (REL file only, max. value 254) |
$18-$1D | Unused |
$1E-$1F | File size in sectors, low/high byte order ($1E+$1F*256). The approx. filesize in bytes is <= #sectors * 254 |
The file type field is used as follows:
Bits | Description |
0-3 | The actual file type |
4 | Unused |
5 | Used only during SAVE-@ replacement |
6 | Locked flag (Set produces ">" locked files) |
7 | Closed flag (Not set produces "*", or "splat" files) |
The actual file type can be one of the following:
Binary | Decimal | File type |
0000 | 0 | DEL |
0001 | 1 | SEQ |
0010 | 2 | PRG |
0011 | 3 | USR |
0100 | 4 | REL |
Values 5-15 are illegal, but if used will produce very strange results.
Most Commdore floppy disk drives use a single dedicated directory track where all filenames are stored. This limits the number of files stored on a disk based on the number of sectors on the directory track. There are some disk images that contain more files than would normally be allowed. This requires extending the directory off the default directory track by changing the last directory sector pointer to a new track, allocating the new sectors in the BAM, and manually placing (or moving existing) file entries there. The directory of an extended disk can be read and the files that reside there can be loaded without problems on a real drive. However, this is still a very dangerous practice as writing to the extended portion of the directory will cause directory corruption in the non-extended part. Many of the floppy drives core ROM routines ignore the track value that the directory is on and assume the default directory track for operations.
The BAM only occupies up to four sectors on track 38, so the rest of the track is empty and is available for file storage. Below is a dump of the first BAM block, 38/0. A D80 will only contain two BAM sectors, 38/0 and 38/3. Each entry takes 5 bytes, 1 for the free count on that track, and 4 for the BAM bits.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 26 03 43 00 01 33 1D FF FF FF 1F 1D FF FF FF 1F 10: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D 20: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF 30: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF 40: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 50: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 60: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D 70: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF 80: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF 90: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF A0: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F B0: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1B C0: F6 FF FF 1F 1B FC FF FF 1F 1B FF FF FF 07 1B FF D0: FF FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF E0: FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF F0: 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF 07
Bytes | Description |
$00-$01 | T/S pointer to second BAM sector (38/3) |
$02 | DOS version byte (0x43='C') |
$03 | Reserved |
$04 | Lowest track covered by this BAM (0x01=1) |
$05 | Highest+1 track covered by this BAM (0x33=51) |
$06-$0A | BAM for track 1. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track. |
$0B-$0F | BAM for track 2 |
... | ... |
$FB-$FF | BAM for track 50 |
Being bit-based, the BAM entries need some explanation. The first track entry in the above BAM sector is at offset 06, "1D FF FF FF 1F". The first number is how many blocks are free on this track ($1D=29) and the remainder is the bit representation of the usage map for the track. These entries must be viewed in binary to make any sense. First convert the values to binary:
FF=11111111, FF=11111111, FF=11111111, 1F=00011111
In order to make any sense from the binary notation, flip the bits around.
111111 11112222 222222 01234567 89012345 67890123 456789... -------------------------- --------- 11111111 11111111 11111111 11111000 ^ ^ sector 0 sector 28
Since we are on the first track, we have 29 sectors, and only use up to the bit 28 position. If a bit is on (1), the sector is free. Therefore, track 1 is clean, all sectors are free. Any leftover bits that refer to sectors that don't exist, like bits 29-31 in the above example, are set to allocated.
Second BAM block 38/3.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 27 01 43 00 33 4E 1B FF FF FF 07 1B FF FF FF 07 10: 1B FF FF FF 07 19 FF FF FF 01 19 FF FF FF 01 19 20: FF FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF 30: FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF FF 40: FF 01 19 FF FF FF 01 19 FF FF FF 01 17 FF FF 7F 50: 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 60: 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17 70: FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF 80: FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 00 00 00 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$01 | T/S pointer to second BAM sector (39/1) |
$02 | DOS version byte (0x43='C') |
$03 | Reserved |
$04 | Lowest track covered by this BAM (0x33=51) |
$05 | Highest+1 track covered by this BAM (0x43=78) |
$06-$0A | BAM for track 51. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track. |
$0B-$0F | BAM for track 52 |
... | ... |
$88-$8C | BAM for track 77 |
$8D-$FF | Not used |
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)
This is a sector-for-sector copy of an 8250 floppy disk. The file size for an 8250 image is 1066496 bytes. It is comprised of 256-byte sectors arranged across 154 tracks, with a varying number of sectors per track for a total of 4166 sectors. Track counting starts at 1 (not 0) and sector counting starts at 0 (not 1), therefore a track with 29 sectors will go from 0 to 28.
The original media (a 5.25" disk) has the tracks laid out in circles, with track 1 on the very outside of the disk (closest to the sides) to track 77 being on the inside of the disk (closest to the inner hub ring). Commodore, in their infinite wisdom, varied the number of sectors per track and data densities across the disk to optimize available storage, resulting in the chart below. It shows the sectors/track for a D82. Since the outside diameter of a circle is the largest (versus closer to the center), the outside tracks have the largest amount of storage.
Track Range | Sectors/track | # Sectors |
1-39 | 29 | 1131 |
40-53 | 27 | 378 |
55-64 | 25 | 275 |
65-77 | 23 | 299 |
78-116 | 29 | 1131 |
117-130 | 27 | 378 |
131-141 | 25 | 275 |
142-154 | 23 | 299 |
Track | #Sect | #SectorsIn | D82 Offset |
1 | 29 | 0 | $000000 |
2 | 29 | 29 | $001D00 |
3 | 29 | 58 | $003A00 |
4 | 29 | 87 | $005700 |
5 | 29 | 116 | $007400 |
6 | 29 | 145 | $009100 |
7 | 29 | 174 | $00AE00 |
8 | 29 | 203 | $00CB00 |
9 | 29 | 232 | $00E800 |
10 | 29 | 261 | $010500 |
11 | 29 | 290 | $012200 |
12 | 29 | 319 | $013F00 |
13 | 29 | 348 | $015C00 |
14 | 29 | 377 | $017900 |
15 | 29 | 406 | $019600 |
16 | 29 | 435 | $01B300 |
17 | 29 | 464 | $01D000 |
18 | 29 | 493 | $01ED00 |
19 | 29 | 522 | $020A00 |
20 | 29 | 551 | $022700 |
21 | 29 | 580 | $024400 |
22 | 29 | 609 | $026100 |
23 | 29 | 638 | $027E00 |
24 | 29 | 667 | $029B00 |
25 | 29 | 696 | $02B800 |
26 | 29 | 725 | $02D500 |
27 | 29 | 754 | $02F200 |
28 | 29 | 783 | $030F00 |
29 | 29 | 812 | $032C00 |
30 | 29 | 841 | $034900 |
31 | 29 | 870 | $036600 |
32 | 29 | 899 | $038300 |
33 | 29 | 928 | $03A000 |
34 | 29 | 957 | $03BD00 |
35 | 29 | 986 | $03DA00 |
36 | 29 | 1015 | $03F700 |
37 | 29 | 1044 | $041400 |
38 | 29 | 1073 | $043100 |
39 | 29 | 1102 | $044E00 |
40 | 27 | 1131 | $046B00 |
41 | 27 | 1158 | $048600 |
42 | 27 | 1185 | $04A100 |
43 | 27 | 1212 | $04BC00 |
44 | 27 | 1239 | $04D700 |
45 | 27 | 1266 | $04F200 |
46 | 27 | 1293 | $050D00 |
47 | 27 | 1320 | $052800 |
48 | 27 | 1347 | $054300 |
49 | 27 | 1374 | $055E00 |
50 | 27 | 1401 | $057900 |
51 | 27 | 1428 | $059400 |
52 | 27 | 1455 | $05AF00 |
53 | 27 | 1482 | $05CA00 |
54 | 25 | 1509 | $05E500 |
55 | 25 | 1534 | $05FE00 |
56 | 25 | 1559 | $061700 |
57 | 25 | 1584 | $063000 |
58 | 25 | 1609 | $064900 |
59 | 25 | 1634 | $066200 |
60 | 25 | 1659 | $067B00 |
61 | 25 | 1684 | $069400 |
62 | 25 | 1709 | $06AD00 |
63 | 25 | 1734 | $06C600 |
64 | 25 | 1759 | $06DF00 |
65 | 23 | 1784 | $06F800 |
66 | 23 | 1807 | $070F00 |
67 | 23 | 1830 | $072600 |
68 | 23 | 1853 | $073D00 |
69 | 23 | 1876 | $075400 |
70 | 23 | 1899 | $076B00 |
71 | 23 | 1922 | $078200 |
72 | 23 | 1945 | $079900 |
73 | 23 | 1968 | $07B000 |
74 | 23 | 1991 | $07C700 |
75 | 23 | 2014 | $07DE00 |
76 | 23 | 2037 | $07F500 |
77 | 23 | 2060 | $080C00 |
78 | 29 | 2083 | $082300 |
79 | 29 | 2112 | $084000 |
80 | 29 | 2141 | $085D00 |
81 | 29 | 2170 | $087A00 |
82 | 29 | 2199 | $089700 |
83 | 29 | 2228 | $08B400 |
84 | 29 | 2257 | $08D100 |
85 | 29 | 2286 | $08EE00 |
86 | 29 | 2315 | $090600 |
87 | 29 | 2344 | $092800 |
88 | 29 | 2373 | $094500 |
89 | 29 | 2402 | $096200 |
90 | 29 | 2431 | $097F00 |
91 | 29 | 2460 | $099C00 |
92 | 29 | 2489 | $09B900 |
93 | 29 | 2518 | $09D600 |
94 | 29 | 2547 | $09F300 |
95 | 29 | 2576 | $0A1000 |
96 | 29 | 2605 | $0A2D00 |
97 | 29 | 2634 | $0A4A00 |
98 | 29 | 2663 | $0A6700 |
99 | 29 | 2692 | $0A8400 |
100 | 29 | 2721 | $0AA100 |
101 | 29 | 2750 | $0ABE00 |
102 | 29 | 2779 | $0ADB00 |
103 | 29 | 2808 | $0AF800 |
104 | 29 | 2837 | $0B1500 |
105 | 29 | 2866 | $0B3200 |
106 | 29 | 2895 | $0B4F00 |
107 | 29 | 2924 | $0B6C00 |
108 | 29 | 2953 | $0B8900 |
109 | 29 | 2982 | $0BA600 |
110 | 29 | 3011 | $0BC300 |
111 | 29 | 3040 | $0BE000 |
112 | 29 | 3069 | $0BFD00 |
113 | 29 | 3098 | $0C1A00 |
114 | 29 | 3137 | $0C3700 |
115 | 29 | 3156 | $0C5400 |
116 | 29 | 3185 | $0C7100 |
117 | 27 | 3214 | $0C8E00 |
118 | 27 | 3241 | $0CA900 |
119 | 27 | 3268 | $0CC400 |
120 | 27 | 3295 | $0CDF00 |
121 | 27 | 3322 | $0CFA00 |
122 | 27 | 3349 | $0D1500 |
123 | 27 | 3376 | $0D3000 |
124 | 27 | 3403 | $0D4B00 |
125 | 27 | 3430 | $0D6600 |
126 | 27 | 3457 | $0D8100 |
127 | 27 | 3484 | $0D9C00 |
128 | 27 | 3511 | $0DB700 |
129 | 27 | 3538 | $0DD200 |
130 | 27 | 3565 | $0DED00 |
131 | 25 | 3592 | $0E0800 |
132 | 25 | 3617 | $0E2100 |
133 | 25 | 3642 | $0E3A00 |
134 | 25 | 3667 | $0E5300 |
135 | 25 | 3692 | $0E6C00 |
136 | 25 | 3717 | $0E8500 |
137 | 25 | 3742 | $0E9E00 |
138 | 25 | 3767 | $0EB700 |
139 | 25 | 3792 | $0ED000 |
140 | 25 | 3817 | $0EE900 |
141 | 25 | 3842 | $0F0200 |
142 | 23 | 3867 | $0F1B00 |
143 | 23 | 3890 | $0F3200 |
144 | 23 | 3913 | $0F4900 |
145 | 23 | 3936 | $0F6000 |
146 | 23 | 3959 | $0F7700 |
147 | 23 | 3982 | $0F8E00 |
148 | 23 | 4005 | $0FA500 |
149 | 23 | 4028 | $0FBC00 |
150 | 23 | 4051 | $0FD300 |
151 | 23 | 4074 | $0FEA00 |
152 | 23 | 4097 | $100100 |
153 | 23 | 4120 | $101800 |
154 | 23 | 4143 | $102F00 |
The BAM (Block Availability Map) is on track 38. The D82 is 154 tracks and so the BAM is contained on 38/0, 38/3, 38/6 and 38/9. The BAM interleave is 3.
The directory is on track 39, with 39/0 contains the header (DOS type, disk name, disk ID's) and sectors 1-28 contain the directory entries. Both files and the directory use an interleave of 1. Since the directory is only 28 sectors large (29 less one for the header), and each sector can contain only 8 entries (32 bytes per entry), the maximum number of directory entries is 28 * 8 = 224. The first directory sector is always 39/1. It then follows a chain structure using a sector interleave of 1 making the links go 39/1, 39/2, 39/3 etc.
When reading a disk, you start with 39/0 (disk label/ID) which points to 38/0 (BAM0), 38/3 (BAM1), 38/6 (BAM2), 38/9 (BAM3, and finally to 39/1 (first dir entry sector). When writing a file to a blank disk, it will start at 38/1 because 38/0 is already allocated.
Below is a dump of the header sector 39/0:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 26 00 43 00 00 00 73 61 6D 70 6C 65 20 64 38 30 10: A0 A0 A0 A0 A0 A0 A0 A0 65 72 A0 32 43 A0 A0 A0 20: A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$01 | T/S pointer to first BAM sector (38/0) |
$02 | $43 'C' is for DOS format version |
$03 | Reserved |
$04-$05 | Unused |
$06-$16 | Disk name, padded with 0xA0 ("sample d82") |
$17 | 0xA0 |
$18-$19 | Disk ID bytes "er" |
$1A | 0xA0 |
$1B-$1C | DOS version bytes "2C" |
$1D-$20 | 0xA0 |
$21-$FF | Unused |
Below is a dump of the first directory sector, 39/1
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 27 02 82 26 01 54 45 53 54 A0 A0 A0 A0 A0 A0 A0 10: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 20: 00 00 82 26 02 54 45 53 54 32 A0 A0 A0 A0 A0 A0 30: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 40: 00 00 82 26 04 54 45 53 54 33 A0 A0 A0 A0 A0 A0 50: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 05 00 60: 00 00 82 26 0B 54 45 53 54 34 A0 A0 A0 A0 A0 A0 70: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 09 00 80: 00 00 82 26 14 54 45 53 54 35 A0 A0 A0 A0 A0 A0 90: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 0C 00 A0: 00 00 82 28 00 54 45 53 54 36 A0 A0 A0 A0 A0 A0 B0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 C0: 00 00 82 28 01 54 45 53 54 37 A0 A0 A0 A0 A0 A0 D0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00 E0: 00 00 82 28 02 54 45 53 54 38 A0 A0 A0 A0 A0 A0 F0: A0 A0 A0 A0 A0 00 00 00 00 00 00 00 00 00 01 00
The first two bytes of the directory sector ($27/$02) indicate the location of the next track/sector of the directory (39/2). If the track is set to $00, then it is the last sector of the directory.
When the directory is done, the track value will be $00. The sector link should contain a value of $FF, meaning the whole sector is allocated, but the actual value doesn't matter. The drive will return all the available entries anyways. This is a breakdown of a standard directory sector:
Bytes | Description |
$00-$1F | First directory entry |
$20-$3F | Second dir entry |
$40-$5F | Third dir entry |
$60-$7F | Fourth dir entry |
$80-$9F | Fifth dir entry |
$A0-$BF | Sixth dir entry |
$C0-$DF | Seventh dir entry |
$E0-$FF | Eighth dir entry |
This is a breakdown of a standard directory entry:
Bytes | Description |
$00-$01 | Track/Sector location of next directory sector ($00 $00 if not the first entry in the sector) |
$02 | File type |
$03-$04 | Track/sector location of first sector of file |
$05-$14 | 16 character filename (in PETASCII, padded with $A0) |
$15-$16 | Track/Sector location of first side-sector block (REL file only) |
$17 | REL file record length (REL file only, max. value 254) |
$18-$1D | Unused |
$1E-$1F | File size in sectors, low/high byte order ($1E+$1F*256). The approx. filesize in bytes is <= #sectors * 254 |
The file type field is used as follows:
Bits | Description |
0-3 | The actual file type |
4 | Unused |
5 | Used only during SAVE-@ replacement |
6 | Locked flag (Set produces ">" locked files) |
7 | Closed flag (Not set produces "*", or "splat" files) |
The actual file type can be one of the following:
Binary | Decimal | File type |
0000 | 0 | DEL |
0001 | 1 | SEQ |
0010 | 2 | PRG |
0011 | 3 | USR |
0100 | 4 | REL |
Values 5-15 are illegal, but if used will produce very strange results.
Most Commdore floppy disk drives use a single dedicated directory track where all filenames are stored. This limits the number of files stored on a disk based on the number of sectors on the directory track. There are some disk images that contain more files than would normally be allowed. This requires extending the directory off the default directory track by changing the last directory sector pointer to a new track, allocating the new sectors in the BAM, and manually placing (or moving existing) file entries there. The directory of an extended disk can be read and the files that reside there can be loaded without problems on a real drive. However, this is still a very dangerous practice as writing to the extended portion of the directory will cause directory corruption in the non-extended part. Many of the floppy drives core ROM routines ignore the track value that the directory is on and assume the default directory track for operations.
The BAM only occupies up to four sectors on track 38, so the rest of the track is empty and is available for file storage. Below is a dump of the first BAM block, 38/0. A D82 will contain four BAM sectors, 38/0, 38/3, 38/6 and 38/9. Each entry takes 5 bytes, 1 for the free count on that track, and 4 for the BAM bits.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 26 03 43 00 01 33 1D FF FF FF 1F 1D FF FF FF 1F 10: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D 20: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF 30: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF 40: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 50: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 60: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D 70: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF 80: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF 90: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF A0: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F B0: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1B C0: F6 FF FF 1F 1B FC FF FF 1F 1B FF FF FF 07 1B FF D0: FF FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF E0: FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF F0: 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF 07
Bytes | Description |
$00-$01 | T/S pointer to second BAM sector (38/3) |
$02 | DOS version byte (0x43='C') |
$03 | Reserved |
$04 | Lowest track covered by this BAM (0x01=1) |
$05 | Highest+1 track covered by this BAM (0x33=51) |
$06-$0A | BAM for track 1. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track. |
$0B-$0F | BAM for track 2 |
... | ... |
$FB-$FF | BAM for track 50 |
Being bit-based, the BAM entries need some explanation. The first track entry in the above BAM sector is at offset 06, "1D FF FF FF 1F". The first number is how many blocks are free on this track ($1D=29) and the remainder is the bit representation of the usage map for the track. These entries must be viewed in binary to make any sense. First convert the values to binary:
FF=11111111, FF=11111111, FF=11111111, 1F=00011111
In order to make any sense from the binary notation, flip the bits around.
111111 11112222 222222 01234567 89012345 67890123 456789... -------------------------- --------- 11111111 11111111 11111111 11111000 ^ ^ sector 0 sector 28
Since we are on the first track, we have 29 sectors, and only use up to the bit 28 position. If a bit is on (1), the sector is free. Therefore, track 1 is clean, all sectors are free. Any leftover bits that refer to sectors that don't exist, like bits 29-31 in the above example, are set to allocated.
Second BAM block 38/3
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 26 06 43 00 33 65 1B FF FF FF 07 1B FF FF FF 07 10: 1B FF FF FF 07 19 FF FF FF 01 19 FF FF FF 01 19 20: FF FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF 30: FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF FF 40: FF 01 19 FF FF FF 01 19 FF FF FF 01 17 FF FF 7F 50: 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 60: 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17 70: FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF 80: FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 1D FF FF 90: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF A0: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F B0: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D C0: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF D0: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF E0: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF F0: 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F
Bytes | Description |
$00-$01 | T/S pointer to third BAM sector (38/6) |
$02 | DOS version byte (0x43='C') |
$03 | Reserved |
$04 | Lowest track covered by this BAM (0x33=51) |
$05 | Highest+1 track covered by this BAM (0x65=101) |
$06-$0A | BAM for track 51. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track. |
$0B-$0F | BAM for track 52 |
... | ... |
$FB-$FF | BAM for track 100 |
Third BAM block 38/6
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 26 09 43 00 65 97 1D FF FF FF 1F 1D FF FF FF 1F 10: 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D 20: FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF 30: FF FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF 40: FF 1F 1D FF FF FF 1F 1D FF FF FF 1F 1D FF FF FF 50: 1F 1D FF FF FF 1F 1B FF FF FF 07 1B FF FF FF 07 60: 1B FF FF FF 07 1B FF FF FF 07 1B FF FF FF 07 1B 70: FF FF FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF 80: FF FF 07 1B FF FF FF 07 1B FF FF FF 07 1B FF FF 90: FF 07 1B FF FF FF 07 1B FF FF FF 07 19 FF FF FF A0: 01 19 FF FF FF 01 19 FF FF FF 01 19 FF FF FF 01 B0: 19 FF FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 C0: FF FF FF 01 19 FF FF FF 01 19 FF FF FF 01 19 FF D0: FF FF 01 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF E0: 7F 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F F0: 00 17 FF FF 7F 00 17 FF FF 7F 00 17 FF FF 7F 00
Bytes | Description |
$00-$01 | T/S pointer to fourth BAM sector (38/9) |
$02 | DOS version byte (0x43='C') |
$03 | Reserved |
$04 | Lowest track covered by this BAM (0x65=101) |
$05 | Highest+1 track covered by this BAM (0x97=151) |
$06-$0A | BAM for track 101. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track. |
$0B-$0F | BAM for track 102 |
... | ... |
$FB-$FF | BAM for track 150 |
Fourth BAM block 38/9
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 27 01 43 00 97 9B 17 FF FF 7F 00 17 FF FF 7F 00 10: 17 FF FF 7F 00 17 FF FF 7F 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bytes | Description |
$00-$01 | T/S pointer to first directory sector (39/1) |
$02 | DOS version byte (0x43='C') |
$03 | Reserved |
$04 | Lowest track covered by this BAM (0x97=151) |
$05 | Highest+1 track covered by this BAM (0x9B=155) |
$06-$0A | BAM for track 151. The first byte shows the "blocks free" for this track, the remaining 4 show the BAM for the track. |
$0B-$0F | BAM for track 152 |
... | ... |
$15-$19 | BAM for track 154 |
$1A-$FF | Not used |
The D90 image is bit-for-bit copy of the hard drives in the D9090 and D9060. The specifications are as follows:
Specifications | D9060 | D9090 |
Hard Disk Mechanism | Tandom TM602S | Tandom TM603S |
Cylinders | 153 | 153 |
Heads | 4 | 6 |
Sectors | 32 | 32 |
Sector Size | 256 | 256 |
Disk Interface | ST-506 | ST-506 |
Unformatted Capacity | 6.4 MB | 9.6 MB |
Formatted Capacity | 5.01 MB | 7.52 MB |
Available Physical Sectors | 19584 | 29376 |
Usable CBM Blocks | 19441 | 29162 |
Note that the unformatted capacity is simply the total raw storage and makes no accommodation for the management of the information. A disk needs to be low-level formatted to include sync bits, sector identifiers, error checking, and correcting bits to reliably find and hold data. This results in an overall loss of about 22% of space, which wasn't unusual for ST-506 MFM hard disks at the time. Modern drives use more advanced storage techniques to reduce this overhead. Earlier published information stating these drives didn't use their full capacity was incorrect.
It can be seen that the only difference between this two mechanisms was the number of heads. In fact the only difference between the two D9090/60 models is the hard drive mechanism and the setting of the J14 configuration jumper which reflects which head count to use. Jumper J13 is connected to the FDC, but in the latest ROM it has no function.
The slight difference between the physical sectors and available blocks is due to the overhead of the CBM filing system (BAM, directory sectors, and bad block list).
The D9090/60 hard disk is the only Commodore drive which uses a "track 0". Sector 0 of this track contains the track and sector information for the header, directory, beginning of the BAM, and the beginning of the bad sector list.
Below is a dump of the configuration sector (track 0, sector 0):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 00 01 00 FF 4C 0A 4C 14 01 00 49 44 00 00 00 00 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...
Bytes | Description |
$00-$01 | T/S pointer to bad blocks list |
$02 | Always 0x00 |
$03 | Always 0xff (DOS version?) |
$04-$05 | T/S pointer to first directory entry |
$06-$07 | T/S pointer to header |
$08-$08 | T/S pointer to first BAM sector |
$0A-$0B | Disk ID, "ID" in this example |
$0C-$FF | Always 0x00 |
This sector is the same for both the D9090 and D9060 as the two hard drives had the same number of cylinders. The the header and directory are placed in the middle of the disk (track 76) to minimize access times. The on-board DOS was designed to accommodate for different cylinder configurations so it was easy to install larger disks by only modifying the FDC ROM. The number of sectors can not exceed 32, and the number of heads can not exceed 7 as they would cause unhandled numeric overflow in the DOS. This variation in configuration values makes it difficult to determine them based solely on the D90 file size. At this point only the stock image sizes of 5,013,504, and 7,520,256 will be attachable in VICE.
Regardless of the size, access to the drive is translated from CHS (cylinder, head, sector) to LBA (logical block address) in the FDC. Although the drive mechanism interface is ST-506, the AM2910 bridges the SASI communication from the FDC.
Since most hard disks of that era had some type of physical defect, and no defect management system, a bad blocks list is included in the DOS. This list begins at track 0, sector 1 as seen from the configuration sector. Below is a dump of an empty bad blocks list (track 0, sector 1):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ...
The list begins as a typical T/S linking sector, however, it is terminated with a T/S of $FF/$FF unlike the typical $00/$xx normally seen in other standard files. The following is a more practical example:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 00 02 10 20 FF 02 30 40 FF 08 50 60 FF 14 70 80 ...
The actual information starts at offset $02. "Bad" blocks are simply marked as "allocated" in the BAM so the DOS doesn't try to put any new data in them. This file is processed by setting the "working" track to 0. Starting at the beginning (offset $02), a byte is read. If this value is not $FF, it is interpreted as the "working" sector. The "working" track/sector is marked as bad (used). We continue on by reading the next byte as the "working" sector and marking it until a $FF is encountered. In the above example, track $0/$10 and $0/$20 would be marked as bad. Once the $FF is found, the next byte is the new "working" track if it is not $FF; if it is, the list is finished. Otherwise we continue processing the list just as we did when the "working" track was 0. In the above example, track $2/$30, $2/$40, $8/$50, $8/$60, $14/70, and $14/$80 would be marked as bad. Note that the list in this example would continue onto track 0, sector 2 at offset $2 as the T/S link is set. This list is processed during a "validation" as the current BAM is erased and rebuilt. It also appears to be processed after a format, but it is not certain if the DOS generates the list or if it was generated in factory by a diagnostic system prior to the drives distribution.
The BAM (Block Availability Map) generally begins on track 1, sector 0, and continues on as necessary based on the disk configuration. Below is a dump of that first BAM sector with a configuration of 32 sectors per head, and 6 heads:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 09 00 FF FF 00 08 00 00 00 00 00 00 00 00 00 00 10: 1E FC FF FF FF 20 FF FF FF FF 20 FF FF FF FF 20 20: FF FF FF FF 20 FF FF FF FF 20 FF FF FF FF 1F FE 30: FF FF FF 20 FF FF FF FF 20 FF FF FF FF 20 FF FF ... F0: FF 20 FF FF FF FF 20 FF FF FF FF 20 FF FF FF FF
Bytes | Description |
$00-$01 | T/S pointer to next BAM sector ($9/$0) |
$02-$03 | T/S pointer to previous BAM sector ($FF/$FF) |
$04 | Lowest track covered by this BAM ($0) |
$05 | Highest+1 track covered by this BAM ($8) |
$06 | Possible start of bitmap data |
$10-$14 (first entry based on this example) | BAM for track 0, head 0. The first byte shows the "blocks free" for this head, the remaining 4 show the BAM for this track and head. |
$24-$08 | BAM for track 0, head 1. |
... | ... |
$2E-$32 | BAM for track 1, head 0. |
... | ... |
$FB-$FF | BAM for track 7, head 5. |
If the T/S pointer is $FF/$FF, it means the end of the BAM. So in this case, there is no previous BAM sector, whereas in the last BAM sector, bytes $01-$02 will be $FF/$FF indicating that there is no next BAM sector.
Bytes $4 and $5 show the range of which tracks this BAM sector applies to. There are 250 bytes to hold this information. The size of each bitmap entry is calculated by "ceiling(sectors_per_head/8)+1"; the "1" is to include the block count. This value is then multipled by the head number and divided into 250. The remainder is added to 6 (the offset for the start of bitmap data). For this example, the bitmap entry size would be "ceiling(32/8)+1" which is 5 bytes. The offset is "(250%(5*6))+6" which is 16 or $10. The goal of this calculation is to place the maximum number of whole tracks inside each BAM. In this case, "int(250/(5*6))" is 8, so we can store 8 tracks per BAM sector. Therefore the lowest track is 0, and the highest is 0 + 8. The next BAM sector will handle tracks 8 to 15 (16 - 1). The position of the BAMs will start at track 1, and the second will be at track 9 (8 + 1), the third will be at track 17 (2 * 8 + 1), and so on. For this example with 153 tracks, we will need at least 20 (153 divided by 8) BAM sectors. BAM sectors are always placed on sector 0. The header and directory will never start on sector 0, so we don't have to worry if one of the BAM sectors will end up on track 76 for example.
Being bit-based, the BAM entries need some explanation. The first track (track 0) entry in the above BAM sector is at offset $10, "1E FC FF FF FF". The first number is how many blocks are free on this track and head ($1E=30) and the remainder is the bit representation of the usage map for the track. These entries must be viewed in binary to make any sense. First convert the values to binary:
FC=11111100, FF=11111111, FF=11111111, FF=11111111
In order to make any sense from the binary notation, flip the bits around.
111111 11112222 22222233 01234567 89012345 67890123 45678901 -------------------------- --------- 00111111 11111111 11111111 11111111 ^ ^ sector 0 sector 31
If a bit is on (1), the sector is free. We can see all but sectors 0 and 1 are free here as it holds the configuration sector, and one sector for the bad block list respectively.
At offset $24, "1F FE FF FF FF" describes the allocation at track 1, sector 0. The first value is the number of free blocks ($1F=31) and the next 4 indicate which sectors are used (or available); in this case sector 0 is allocated as it is used by the first BAM sector.
Below is the dump of the last BAM sector (track 152, sector 0):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: FF FF 91 00 98 99 00 00 00 00 00 00 00 00 00 00 10: 1F FE FF FF FF 20 FF FF FF FF 20 FF FF FF FF 20 20: FF FF FF FF 20 FF FF FF FF 20 FF FF FF FF 00 00 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...
Here we can see it only covers tracks 152 ($98) to 152 ($99-1). So only 6 entries are valid, and the rest are all zeros. The next T/S pointer is $FF/$FF indicating this is the last BAM sector.
When the blocks free is calculated, only track 0 is excluded. Other Commodore drives exclude the dedicated directory track.
The directory is generally on track 76 (152 divided by 2), with sector 20 containing the header (disk name, disk ID's). The directory entries begin at sector 10. The drives interleave is 10 sectors and it appears the directory entry is allocated before the header on a format. Once the directory grows, the interleave becomes 3, as on most Commodore drives. Unlike most Commodore drives, the directory is not limited to track 76, nor is file data limited to be else where. Once track 76 is filled with directory entries, it will look in other tracks to place more entries. Filling the disk to capacity will also place data into track 76. Be warned though as the directory listing can exceed the amount of memory available on the Commodore machine which is "loading" the directory. It is wise to use a DOS wedge which displays the directory as it is being read but doesn't store it in memory.
The D9090/60 emulation in VICE was tested to see how many one block files could be created on a D9090 image. The disk was filled with 25922 files which required 3241 blocks for the directory entries.
Below is a dump of the header at track 76, sector 20:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 00: 4C 0A 00 00 00 00 54 45 53 54 A0 A0 A0 A0 A0 A0 10: A0 A0 A0 A0 A0 A0 A0 A0 49 44 A0 33 41 A0 A0 A0 20: A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
This is very similar to the D80/D82 header in placement but without the DOS version value. Also note that the dos version bytes are "3A". For the D90, it is believed that the $FF at offset $3 in the configuration sector dictates the DOS version.
The directory entry generally starts at track 76, sector 10. It has the identical layout as all other Commodore drives. There are no files specific to the D90 image other than super side sectors for larger REL files.
The DHD image is bit-for-bit copy of a Creative Micro Designs (CMD) Hard Drive (HD). CMD designed their DOS so that it could co-exist with other operating systems from other computer platforms. At the time, SCSI HDs were very expensive, making this a likely scenario for some. In this section, a block refers to a SCSI HD data block which is 512 bytes. A SCSI HD refers to the location of a blocks on the disk as logical block address (LBA). A sector refers to a commodore disk sector which is 256 bytes. SCSI, being a smarter disk system (compared to earlier ones), translates the LBAs into physical head, sector, cylinder coordinates internally thus simplifying the host's interface. So, for example, a 40 MB HD of that era would have had 82332 (or $1419C) LBAs. As HD technology improved, the number of sectors per cylinder became variable depending on the cylinder which allowed for greater capacity. The host therefore has no information about the HD geometry other than the total number of LBAs. Most operating systems place their partition tables or boot code near the beginning of the HD. Because of this variability, CMD designed their DOS to begin at any location in increments of 128 blocks. It was therefore possible to configure foreign partitions on various operating system so that the CMD data was ignored. The starting location of the CMD whole disk partition will be referred to as X blocks.
Upon reset, the boot ROM looks for the CMD whole partition by examining LBA X+2 (starting at X=0) and checking for a special signature in the block. If it does not find it, X will increase by 128, and it will try again. It will do this until it finds the signature, or until it gets a read error from the HD signaling the end of disk space. The device will the switch to installation mode.
The following is an example configuration block of a 40 MB drive:
X * 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII $200 + ----------------------------------------------- ---------------- 000400: 94 6C 00 0E 7D E7 00 00 00 00 00 00 00 00 00 00 000410: 20 20 20 20 31 2E 39 32 30 33 2F 32 32 2F 39 36 ....1.9203/22/96 000420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000440: 03 02 00 7E C9 55 00 00 00 00 00 00 00 00 00 00 000450: 20 20 20 20 32 2E 30 30 30 33 2F 32 32 2F 39 36 ....2.0003/22/96 000460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 000500: 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 000510: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 000530: FF FF FF FF FF FF FF FF 00 01 FF FF FF FF FF FF 000540: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 000570: 00 41 FF FF FF FF FF FF FF FF FF FF FF FF FF FF 000580: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 0005A0: FF FF FF FF FF FF FF FF 00 9C FF FF FF FF FF FF 0005B0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 0005E0: 00 0C 01 01 0C 80 01 00 00 00 00 00 00 00 00 00 0005F0: 43 4D 44 20 48 44 20 20 8D 03 88 8E 02 88 EA 60 CMD HD.......... ... 000E00: < start of first OS, n=0, CMD DOS, see $402-$403 > 007E00: < start of second OS, n=1, GEOS overlay, see $442-$443 > 010000: < start of partition table, see $5E6-$5E7 >
The first 256 bytes of the configuration block appear to be a list of loadable operating systems for the drive. Each entry, "n", uses 64 bytes, so there can be at most 4. The first is the standard CMD DOS, while the second is an overlay for GEOS. The boot ROM explicitly loads the first (n=0).
The CMD DOS supports up to 56 connected HDs: 7 devices with 8 logical units (LUNs) each. For that era, most HDs only supported a single LUN (0), whereas more exotic array devices would allow for multiple LUNs. The relative location of the disk, "d", in the whole drive map, is stored in the next 224 bytes. For example, the first disk would start at location 0. The next disk following the first, would start at LBA $01419C (the size of the first disk plus its starting point in the map). The 24-bit values used here for the placement are adequate since a fully populated CMD HD can only access 255 16 MB partitions, which his just under 4 GiB.
The last portion of the configuration block holds the device parameters (device number, partition location, default partition) as well as the CMD HD signature.
Bytes | Description |
(X*$200)+($400-$4FF) | Operating System Table |
(X*$200+$400+n*$40)+$00 | Destination memory page |
(X*$200+$400+n*$40)+$01 | Number of pages |
(X*$200+$400+n*$40)+$02-$03 | Location of data offset from X in sectors (256 bytes); MSB format |
(X*$200+$400+n*$40)+$04-$05 | Checksum of data; MSB format |
(X*$200+$400+n*$40)+$06-$0F | All 0x00 |
(X*$200+$400+n*$40)+$10-$17 | ASCII of version number |
(X*$200+$400+n*$40)+$18-$1F | ASCII of date |
(X*$200+$400+n*$40)+$20-$3F | All 0x00 |
(X*$200+$500+d*$38)+$00 | SCSI ID of HD in bits 7-4, LUN in bits 3-0; $FF means not present |
(X*$200+$500+d*$38)+$38 | MSB of disk location in drive map |
(X*$200+$500+d*$38)+$70 | Middle byte of disk location in drive map |
(X*$200+$500+d*$38)+$A8 | LSB of disk location in drive map |
(X*$200+$500)+$E0 | 0x00 (unknown) |
(X*$200+$500)+$E1 | Device number (12 or 0x0C by default) |
(X*$200+$500)+$E2 | 0x01 (unknown) |
(X*$200+$500)+$E3 | 0x01 (unknown) |
(X*$200+$500)+$E4 | Device number (12 or 0x0C by default) |
(X*$200+$500)+$E5 | 0x80: 2 to the power of the SCSI ID of host (which is always 7) |
(X*$200+$500)+$E6-$E7 | Location of CMD partition table offset from X in sectors (256 bytes); MSB format |
(X*$200+$500)+$E8 | Default partition number |
(X*$200+$500)+$E9-$EF | All 0x00 |
(X*$200+$500)+$F0-$F7 | 0x43 0x4D 0x44 0x20 0x48 0x44 0x20 0x20: First half of signature |
(X*$200+$500)+$F8-$FF | 0x8D 0x03 0x88 0x8E 0x02 0x88 0xEA 0x60: Second half of signature; decodes to STA $8803, STX $8802, NOP, RTS |
The CMD partition table is a special disk image with one track and 32 sectors. It is very similar the standard directory structure of most CBM drives. The first two bytes of the sector indicate the location of the next track/sector of the partition table; it is usually in sequence. If the next track is set to $00 (the next sector will be $ff), then it is the last sector of the partition table.
The standard partition table sectors:
Bytes | Description |
$00-$1F | First partition entry for this sector |
$20-$3F | Second partition entry for this sector |
$40-$5F | Third partition entry for this sector |
$60-$7F | Fourth partition entry for this sector |
$80-$9F | Fifth partition entry for this sector |
$A0-$BF | Sixth partition entry for this sector |
$C0-$DF | Seventh partition entry for this sector |
$E0-$FF | Eighth partition entry for this sector |
The standard partition entry:
Bytes | Description |
$00-$01 | Track/Sector location of next partition sector ($00 $00 if not the first entry in the sector) |
$02 | Partition type: 0x00=none, 0x01=native, 0x02=1541, 0x03=1571, 0x04=1581, 0x05=1581CPM, 0x06=Print Queue, 0x07=Foreign, 0xFF=System. Only partition 0 can be a system type, and type 6 isn't known to be implemented on any CMD DOS. |
$03-$04 | 0x00 0x00 |
$05-$14 | 16 character partition name (in PETASCII, padded with $A0) |
$15-$17 | Location of the partition data offset from X in sectors (256 bytes); MSB format; partition 0, the system partition always starts a 0. |
$18-$1D | All 0x00 |
$1E-$1F | Size of partition (in blocks) in MSB format. Partition 0, the system partition is always 0x90 blocks, which includes blocks from X to the end of the partition table. |
When a partition is deleted, its entry is removed and all others stay in their existing place. The partition data following the deleted partition is moved back to fill in the gap from the deletion; this can be very time consuming. So, when deleting a partition, it is suggested to start with the one with the highest start LBA.
The data at the starting LBA is simply the associated disk image of the partition type. It follows the formats (D64, D71, and D81) documented previously.
(This section was contributed by Peter Schepers and slightly edited by Marco van den Heuvel.)
These files were created for use in the PC64 emulator, written by Wolfgang Lorenz. Each one has the same layout with the filetype being stored in the DOS extension (i.e. Pxx is a PRG, Sxx is a SEQ, Uxx is a USR and Rxx is a RELative file), and the header is only 26 bytes long.
This is a dump of a Pxx file (PRG)...
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----------------------------------------------- 0000: 43 36 34 46 69 6C 65 00 43 52 49 53 49 53 20 4D 0010: 4F 55 4E 54 41 49 4E 00 00 00
Bytes | Description |
$00-$06 | ASCII string "C64File" |
$07 | Always $00 |
$08-$17 | Filename in PETASCII, padded with $00 (not $A0, like a D64) |
$18 | Always $00 |
$19 | REL file record size ($00 if not a REL file) |
$1A-?? | Program data |
The 'xx' in the extension of the file is usually 00, except when we have two DOS filenames which would be the same, but the C64 filenames are different! If we have two C64 filenames which are the same, they *cannot* co-exist in the same directory. If we have two files which do convert down to be the same DOS filename, the extension is incremented until an unused one is found (x01, x02, x03, up to x99). We can have up to 99 different C64 files with the same corresponding DOS names as that's all the extension will hold (from P00 to P99).
Each PC64 file only has one entry, there are no multi-file containers allowed. This could result in a large number of these files in a directory, even for only a few programs, as each C64 file will result in a PC64 file entry. The best use for a PC64 file is a single-file program, one which does not load anything else.
This chapter is based on CRT.txt (rev1.14) compiled by Peter Schepers, with additional contributions from Per Hakan Sundell, Markus Brenner, Marco Van Den Heuvel, Groepaz.
Cartridge files were introduced in the CCS64 emulator, written by Per Hakan Sundell, and use the ".CRT" file extension. This format was created to handle the various ROM cartridges that exist, such as Action Replay, the Power cartridge, and the Final Cartridge.
The file format was extended to support other CBM machines by the VICE team in version 2.0
Normal game cartridges can load into several different memory ranges (on the C64 this is $8000-9FFF, $A000-BFFF or $E000-FFFF). Newer utility and freezer cartridges were less intrusive, hiding themselves until called upon, and still others used bank-switching techniques to allow much larger ROMs than normal. Because of these "stealthing" and bank-switching methods, a special cartridge format was necessary, to let the emulator know where the cartridge should reside, the control line states to enable it and any special hardware features it uses.
For example, here is a dump of a sample 8KiB generic C64 cartridge, "Attack Of The Mutant Camels"...
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 00 00 01 00 00 00 00 00 00 ...@............ 0020: 41 54 54 41 43 4B 20 4F 46 20 54 48 45 20 4D 55 ATTACK OF THE MU 0030: 54 41 4E 54 20 43 41 4D 45 4C 53 00 00 00 00 00 TANT CAMELS..... 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: D3 9B BC FE C3 C2 CD 38 30 EA EA EA A9 01 85 13 .......80....... 0060: 4C B3 9B A9 08 85 5A 88 D0 FD C6 5A D0 F9 60 D0 L.....Z....Z..`.
$0000-$000F - 16-byte cartridge signature (padded with space characters) "C64 CARTRIDGE " - indicates a C64 cartridge "C128 CARTRIDGE " - indicates a C128 cartridge (added in v2.0) "CBM2 CARTRIDGE " - indicates a CBMII cartridge (added in v2.0) "VIC20 CARTRIDGE " - indicates a VIC20 cartridge (added in v2.0) "PLUS4 CARTRIDGE " - indicates a C16/PLUS4 cartridge (added in v2.0) $0010-$0013 - File header length (in high/low format, counting from offset $0000). The default (and also the minimum) value is $40, which should always be used for compatibility reasons. Some cartridge images exist which use a value of $00000020, which is wrong. $0014-$0015 - Cartridge version (high/low, presently 02.00) $01 $00 - original v1.0 specs $01 $01 - VICE v1.1 specs (adds CRT sub type/hardware revision) $02 $00 - VICE v2.0 specs (introduces VIC20, PLUS4, C128, CBM2) $0016-$0017 - Cartridge hardware type ($0000, high/low) - see below for details $0018 - Cartridge port EXROM line status (C64 only) $0019 - Cartridge port GAME line status (C64 only) Determines the mode the cartridge starts in: exrom / game 0 0 - 16k Game 0 1 - 8k Game 1 0 - ultimax 1 1 - ram/off Emulators should only use this field with "generic" C64 cartridges (type 0), for all others the startup mode is implied by the type of the cartridge. It should still be filled correctly in the crt file, but a lot of files with wrong values exist "in the wild". $001A - Cartridge Hardware Revision/Subtype (usually 0) (added in v1.01) $001B-$001F - Reserved for future use $0020-$003F - 32-byte cartridge name (uppercase, padded with null characters) $0040- xxxx - Cartridge contents (called CHIP PACKETS, as there can be more than one per CRT file). See below for a breakdown of the CHIP format.
The following is the contents of the CHIP packet, from position $0040 on in the CRT file. Note I have re-adjusted the starting address to be $0000, since we are now looking at a file contained in the .CRT file, and all size references are from where it starts.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0010: D3 9B BC FE C3 C2 CD 38 30 EA EA EA A9 01 85 13 .......80....... 0020: 4C B3 9B A9 08 85 5A 88 D0 FD C6 5A D0 F9 60 D0 L.....Z....Z..`. 0030: F2 60 A9 04 85 49 A9 00 85 48 A2 00 A5 48 9D 40 .`...I...H...H.@ 0040: 03 A5 49 9D 60 03 A5 48 18 69 28 85 48 A5 49 69 ..I.`..H.i(.H.Ii 0050: 00 85 49 E8 E0 18 D0 E4 60 A6 03 A4 02 BD 40 03 ..I.....`.....@. ...
$0000-$0003 - Contained ROM signature "CHIP" (note there can be more than one CHIP image in a .CRT file) $0004-$0007 - Total packet length (high/low format) Length of ROM image size and header combined, this should always be equal to "ROM image size" + $10 $0008-$0009 - Chip type 0 - ROM 1 - RAM 2 - Flash ROM 3 - EEPROM This is informal only. A RAM chunk may be empty, but doesn't have to be. $000A-$000B - Bank number ($0000 - normal cartridge) Number of the bank this CHIP package appears in. This should be a logical bank number, not the value stored into some banking register which might have its bit-order rearranged. $000C-$000D - Starting load address (high/low format) The load address tells the loader which part of the given bank is to be used for this chunk. It is only really important in formats where actually more than one CHIP chunk exists for each bank - most notable the "generic" (type 0) cartridges. $000E-$000F - ROM image size in bytes (high/low format, typically $2000 or $4000) $0010- xxxx - ROM data
CRT ID | Cartridge Type |
0 | generic cartridge |
1 | Action Replay |
2 | KCS Power Cartridge |
3 | Final Cartridge III |
4 | Simons' BASIC |
5 | Ocean type 1* |
6 | Expert Cartridge |
7 | Fun Play, Power Play |
8 | Super Games |
9 | Atomic Power |
10 | Epyx Fastload |
11 | Westermann Learning |
12 | Rex Utility |
13 | Final Cartridge I |
14 | Magic Formel |
15 | C64 Game System, System 3 |
16 | Warp Speed |
17 | Dinamic** |
18 | Zaxxon, Super Zaxxon (SEGA) |
19 | Magic Desk, Domark, HES Australia |
20 | Super Snapshot V5 |
21 | Comal-80 |
22 | Structured BASIC |
23 | Ross |
24 | Dela EP64 |
25 | Dela EP7x8 |
26 | Dela EP256 |
27 | Rex EP256 |
28 | Mikro Assembler |
29 | Final Cartridge Plus |
30 | Action Replay 4 |
31 | Stardos |
32 | EasyFlash |
33 | EasyFlash Xbank |
34 | Capture |
35 | Action Replay 3 |
36 | Retro Replay (Subtype 1: Nordic Replay) |
37 | MMC64 |
38 | MMC Replay |
39 | IDE64 |
40 | Super Snapshot V4 |
41 | IEEE-488 |
42 | Game Killer |
43 | Prophet64 |
44 | EXOS |
45 | Freeze Frame |
46 | Freeze Machine |
47 | Snapshot64 |
48 | Super Explode V5.0 |
49 | Magic Voice |
50 | Action Replay 2 |
51 | MACH 5 |
52 | Diashow-Maker |
53 | Pagefox |
54 | Kingsoft |
55 | Silverrock 128K Cartridge |
56 | Formel 64 |
57 | RGCD (Subtype 1: Hucky) |
58 | RR-Net MK3 |
59 | EasyCalc |
60 | GMod2 |
61 | MAX Basic |
62 | GMod3 |
63 | ZIPP-CODE 48 |
64 | Blackbox V8 |
65 | Blackbox V3 |
66 | Blackbox V4 |
67 | REX RAM-Floppy |
68 | BIS-Plus |
69 | SD-BOX |
70 | MultiMAX |
71 | Blackbox V9 |
72 | Lt. Kernal Host Adaptor |
73 | RAMLink |
74 | H.E.R.O. |
75 | IEEE Flash! 64 |
76 | Turtle Graphics II |
77 | Freeze Frame MK2 |
78 | Partner 64 |
79 | Hyper-BASIC |
(*Note: Ocean type 1 includes Navy Seals, Robocop 2 & 3, Shadow of the Beast, Toki, Terminator 2 and more)
(**Note: Dinamic includes Narco Police and more)
generic cartridges can contain one or two 8k CHIP packets, one for ROML and one for ROMH. ROML start address is always $8000, ROMH start address is either $a000 or $e000 depending on the GAME/EXROM config.
The following is a chart taken from the "Commodore Programmers Reference Guide". It details the state of various areas of memory depending on the state of the control lines.
Legend: L - ROML (low) H - ROMH (high) G - GAME E - EXROM
Addr LHGE LHGE LHGE LHGE LHGE LHGE LHGE LHGE LHGE Range 1111 101X 1000 011X 001X 1110 0100 1100 XX01 default 00X0 Ultimax ------------------------------------------------------------------------- E000-FFFF Kernal RAM RAM Kernal RAM Kernal Kernal Kernal ROMH(*) D000-DFFF IO/CHR IO/CHR IO/RAM IO/CHR RAM IO/CHR IO/CHR IO/CHR I/O C000-CFFF RAM RAM RAM RAM RAM RAM RAM RAM - A000-BFFF BASIC RAM RAM RAM RAM BASIC ROMH ROMH - 8000-9FFF RAM RAM RAM RAM RAM ROML RAM ROML ROML(*) 4000-7FFF RAM RAM RAM RAM RAM RAM RAM RAM - 1000-3FFF RAM RAM RAM RAM RAM RAM RAM RAM - 0000-0FFF RAM RAM RAM RAM RAM RAM RAM RAM RAM
(*) Internal memory does not respond to write accesses in these areas
From the above chart, the following table can be built. It shows standard cartridges, either 8KiB or 16KiB in size, and the memory ranges they load into.
Type Size Game EXRom Low Bank High Bank in K Line Line (ROML) (ROMH) ------------------------------------------------- Normal 8KiB hi lo $8000 ---- Normal 16KiB lo lo $8000 $A000 Ultimax 8KiB lo hi $E000 ----
The ROMH and ROML lines are CPU-controlled status lines, used to bank in/out RAM, ROM or I/O, depending on what is needed at the time.
generic 8K GAME cartridge
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 00 00 01 00 00 00 00 00 00 ...@............ 0020: 41 54 54 41 43 4B 20 4F 46 20 54 48 45 20 4D 55 ATTACK OF THE MU 0030: 54 41 4E 54 20 43 41 4D 45 4C 53 00 00 00 00 00 TANT CAMELS..... 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: D3 9B BC FE C3 C2 CD 38 30 EA EA EA A9 01 85 13 .......80.......
generic 16K GAME cartridge
This sample is a dump of "Adventure Creator", a 16KiB standard cartridge.
Size | 16KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 00 00 00 00 00 00 00 00 00 ...@............ 0020: 41 64 76 65 6E 74 75 72 65 20 43 72 65 61 74 6F Adventure Creato 0030: 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r............... 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 09 80 81 EA C3 C2 CD 38 30 A2 00 78 D8 8E 11 D0 .......80..x....
ULTIMAX cartridge
Ultimax cartridges typically are situated in the $E000-FFFF (8KiB) ROM address range. There are some cartridges which only use 4KiB of the 8KiB allocation. If the cartridge is 16KiB in size, then it will reside in both $8000-9FFF and $E000-FFFF.
This sample below is a dump of "Music Machine", a 4KiB ULTIMAX mode cartridge. It is still identified as a "generic cartridge" according to the ID.
Size | 4KiB (ULTIMAX mode) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $F000-F7FF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 00 01 00 00 00 00 00 00 00 ...@............ 0020: 4D 55 53 49 43 20 4D 41 43 48 49 4E 45 00 00 00 MUSIC MACHINE... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 10 10 00 00 00 00 F0 00 10 00 CHIP............ 0050: 3C 66 C3 C3 66 3C FF FF 18 3C 66 7E 66 66 66 00 <f..f<...<f~fff.
Size | 32KiB (4 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 01 00 01 00 00 00 00 00 00 ...@............ 0020: 41 63 74 69 6F 6E 20 52 65 70 6C 61 79 20 56 00 Action Replay V. 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 0C 80 C3 C2 CD 38 30 4C 60 80 4C 63 80 4C .......80L`.Lc.L
This cart has 32KiB of ROM, and 8KiB of RAM. The bank switching is done by writing to the I/O-1 range as follows:
bit meaning --- ------- 7 extra ROM bank selector (A15) (unused) 6 1 = resets FREEZE-mode (turns back to normal mode) 5 1 = enable RAM at ROML ($8000-$9FFF) & I/O-2 ($DF00-$DFFF = $9F00-$9FFF) 4 ROM bank selector high (A14) 3 ROM bank selector low (A13) 2 1 = disable cartridge (turn off $DE00) 1 1 = /EXROM high 0 1 = /GAME low
Additionally the RAM or ROM can be available through a window in the I/O-2 range.
Size | 16KiB (2 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | module #1 - $8000-9FFF | module #2 - $A000-BFFF
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 20 01 00 00 02 00 00 00 00 00 00 00 00 ... ............ 0020: 4B 43 53 20 50 6F 77 65 72 20 43 61 72 74 72 69 KCS Power Cartri 0030: 64 67 65 00 00 00 00 00 00 00 00 00 00 00 00 00 dge............. 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 5E FE C3 C2 CD 38 30 78 D8 A2 FF 9A A9 27 ..^....80x.....' ... 2050: 43 48 49 50 00 00 20 10 00 00 00 00 A0 00 20 00 CHIP.. ....... . 2060: 97 E3 16 A1 FF FF FF 20 13 A0 A5 01 09 01 85 01 ....... ........
Size | 64KiB (4 banks of 16KiB each) |
EXROM | inactive (hi) (1) |
GAME | inactive (hi) (1) |
Load address | $8000-BFFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 03 00 00 00 00 00 00 00 00 ...@............ 0020: 46 69 6E 61 6C 20 43 61 72 74 72 69 64 67 65 20 Final Cartridge 0030: 49 49 49 20 31 39 38 37 00 00 00 00 00 00 00 00 III 1987........ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 09 80 5E FE C3 C2 CD 38 30 4C 4C 80 4C 55 95 4C ..^....80LL.LU.L ... 4050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP..@.......@. 4060: 01 02 00 81 5D 81 61 81 99 81 D8 81 0B 82 33 82 ....].a.......3. ... 8060: 43 48 49 50 00 00 40 10 00 00 00 02 80 00 40 00 CHIP..@.......@. 8070: 20 43 80 20 52 80 A9 4E 20 05 DE 20 FD BF AD 39 C. R..N .. ...9 ... C070: 43 48 49 50 00 00 40 10 00 00 00 03 80 00 40 00 CHIP..@.......@. C080: A2 06 BD DD 85 95 05 CA 10 F8 AE A0 02 E8 EC A2 ................
A total of 64 KiB of ROM memory is organized into four $4000 banks located at $8000-$BFFF.
The banks are arranged in the following way:
Bank 0: BASIC, Monitor, Disk-Turbo Bank 1: Notepad, BASIC (Menu Bar) Bank 2: Desktop, Freezer/Print Bank 3: Freezer, Compression
The cartridges uses the entire I/O-1 and I/O-2 range. Bank switching is done by writing the bank number plus $40 into memory location $DFFF. For instance, to select bank 2, $DFFF is set to $42.
The CRT file contains four CHIP blocks, each block with a start address of $8000, length $4000 and the bank number in the bank field. In the cartridge header, both EXROM ($18) and GAME ($19) are set to 1 to enable the 16 KiB ROM configuration.
The registers are arranged in the following way:
One register at $DFFF:
bit meaning --- ------- 7 Hide this register (1 = hidden) 6 NMI line (0 = low = active) *1) 5 GAME line (0 = low = active) *2) 4 EXROM line (0 = low = active) 2-3 unassigned (usually set to 0) 0-1 number of bank to show at $8000
1) if either the freezer button is pressed, or bit 6 is 0, then an NMI is generated
2) if the freezer button is pressed, GAME is also forced low
The rest of I/O-1/I/O-2 contain a mirror of the last 2 pages of the currently selected ROM bank (also at $dfff, contrary to what some other documents say)
Size | 16KiB (2 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | module #1 - $8000-9FFF | module #2 - $A000-BFFF
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 04 00 00 00 00 00 00 00 00 ...@............ 0020: 53 69 6D 6F 6E 27 73 20 42 61 73 69 63 00 00 00 Simon's Basic... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 52 81 52 81 C3 C2 CD 38 30 41 4C 52 81 20 2C 81 R.R....80ALR. ,. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 00 A0 00 20 00 CHIP.. ....... . 2060: 20 A4 A6 99 9E CB A0 05 A5 A8 91 20 A4 A6 99 A2 .......... ....
Simons' BASIC permanently uses 16 KiB ($4000) bytes of cartridge memory from $8000-$BFFF. However, through some custom bank-switching logic the upper area ($A000-$BFFF) may be disabled so Simons' BASIC may use it as additional RAM. Writing a value of $01 to address location $DE00 banks in ROM, $00 disables ROM and enables RAM.
The CRT file contains two CHIP blocks of length $2000 each, the first block having a start address of $8000, the second block $A000. In the cartridge header, EXROM ($18) is set to 0, GAME ($19) is set to 1 to indicate the RESET/power-up configuration of 8 KiB ROM.
Size | 32KiB, 128KiB, 256KiB or 512KiB sizes (4, 16, 32 or 64 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | Banks 00-15 - $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 05 00 00 00 00 00 00 00 00 ...@............ 00020: 53 48 41 44 4F 57 20 4F 46 20 54 48 45 20 42 45 SHADOW OF THE BE 00030: 41 53 54 00 00 00 00 00 00 00 00 00 00 00 00 00 AST............. 00040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 00050: 09 80 83 81 C3 C2 CD 38 30 4C 83 81 4C 76 82 80 .......80L..Lv.. ... 02050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 02060: 59 6D 00 56 AD 00 55 AE F0 00 01 A0 FE 00 01 F8 Ym.V..U......... ... 20140: 43 48 49 50 00 00 20 10 00 00 00 10 A0 00 20 00 CHIP.. ....... . 20150: 0A 9A 55 FF 9B 69 57 FE AA 65 96 FE 65 0F D6 D9 ..U..iW..e..e...
Here is a list of the known OCEAN cartridges:
Batman The Movie (128 KiB) Battle Command (128 KiB) Double Dragon (128 KiB) Navy Seals (128 KiB) Pang (128 KiB) Robocop 3 (128 KiB) Space Gun (128 KiB) Toki (128 KiB) Chase H.Q. II (256 KiB) Robocop 2 (256 KiB) Shadow of the Beast (256 KiB) Terminator 2 (512 KiB)
The 32KiB type of cart has 4 banks of 8KiB ($2000), banked in at $8000-$9FFF.
The 128KiB type of cart has 16 banks of 8KiB ($2000), banked in at $8000-$9FFF.
The 256KiB type of cart has 32 banks of 8KiB ($2000), 16 banked in at $8000-$9FFF, and 16 banked in at $A000-$BFFF.
The 512KiB type of cart has 64 banks of 8KiB ($2000), banked in at $8000-$9FFF.
Bank switching is done by writing to $DE00. The lower six bits give the bank number (ranging from 0-63). Bit 7 in this selection word is always set.
Size | 8KiB |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 06 01 00 00 00 00 00 00 00 ...@............ 0020: 45 78 70 65 72 74 20 43 61 72 74 72 69 64 67 65 Expert Cartridge 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 01 00 00 80 00 20 00 CHIP..@....... . 0050: 00 00 00 0A F3 00 00 00 00 00 00 00 00 00 00 00 ................
Size | 128KiB (16 banks of 8KiB modules) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 07 00 01 00 00 00 00 00 00 ...@............ 00020: 46 55 4E 20 50 4C 41 59 00 00 00 00 00 00 00 00 FUN PLAY........ 00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 00050: 1E 80 86 EA C3 C2 CD 38 30 1B 00 81 0D 08 80 00 .......80....... ... 02050: 43 48 49 50 00 00 20 10 00 00 00 08 80 00 20 00 CHIP.. ....... . 02060: 78 A2 F0 86 01 BD 1D 08 9D F8 00 CA D0 F7 4C 00 x.............L. ... 04060: 43 48 49 50 00 00 20 10 00 00 00 10 80 00 20 00 CHIP.. ....... . 04070: 38 E5 68 85 03 B0 11 27 03 12 C0 18 69 27 42 90 8.h....'....i'B. ... 06070: 43 48 49 50 00 00 20 10 00 00 00 18 80 00 20 00 CHIP.. ....... . 06080: 44 D0 5E 06 02 C0 44 11 40 04 11 44 01 5F 1C 73 D.^...D.@..D._.s ... 1E130: 43 48 49 50 00 00 20 10 00 00 00 39 80 00 20 00 CHIP.. ....9.. . 1E140: 85 EB 41 EA 9E 08 03 00 C0 06 18 01 00 C0 08 03 ..A.............
The FUN PLAY Cartridge uses $DE00 for bank selection, and uses 8KiB banks ($2000) at $8000-$9FFF. There are 16 banks of ROM memory and are referenced by the following values:
$00 -> Bank 0 $08 -> Bank 1 $10 -> Bank 2 $18 -> Bank 3 $20 -> Bank 4 $28 -> Bank 5 $30 -> Bank 6 $38 -> Bank 7 $01 -> Bank 8 $09 -> Bank 9 $11 -> Bank 10 $19 -> Bank 11 $21 -> Bank 12 $29 -> Bank 13 $31 -> Bank 14 $39 -> Bank 15
The bank field in the chip headers is set according to the value written to $DE00. The following bits are used for bank decoding in $DE00 (0 being the LSB, 3 being the MSB).
Bit# 76543210 xx210xx3
After copying memory from the ROM banks, the selection program writes a value of $86 to $DE00. This seems either to reset or disable the cartridge ROM.
Size | 64KiB (4 banks of 16KiB each) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Startup mode | 16KiB game |
Load address | $8000-BFFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 08 00 00 00 00 00 00 00 00 ...@............ 0020: 53 55 50 45 52 20 47 41 4D 45 53 00 00 00 00 00 SUPER GAMES..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 0A 80 0A 80 C3 C2 CD 38 30 00 A9 80 A0 00 85 FB .......80....... ... 4050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP..@.......@. 4060: 27 80 A8 80 C3 C2 CD 38 30 00 40 C0 40 C0 40 C0 '......80.@.@.@. ... 8060: 43 48 49 50 00 00 40 10 00 00 00 02 80 00 40 00 CHIP..@.......@. 8070: 00 00 00 49 4D C7 64 47 46 45 F3 48 DC 08 7E 0B ...IM.dGFE.H..~. ... C070: 43 48 49 50 00 00 40 10 00 00 00 03 80 00 40 00 CHIP..@.......@. C080: D5 F9 F0 C1 D5 F7 F0 BD E8 B5 02 F0 FB C9 05 30 ...............0
The Super Games cartridge uses 4 16KiB banks ($8000-$BFFF) of ROM memory. Bank selecting is done by writing to $DF00.
$DF00 register is as follows:
bit meaning --- ------- 0 bank bit 0 1 bank bit 1 2 mode (0 = EXROM/GAME (bridged on the same wire - 16KiB config) 1 = cartridge disabled) 3 write-protect-latch (1 = no more changes are possible until the next hardware-reset ) 4-7 unused
Size | 32KiB (4 banks of 8KiB modules) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 09 00 01 00 00 00 00 00 00 ...@............ 0020: 41 74 6F 6D 69 63 20 50 6F 77 65 72 00 00 00 00 Atomic Power.... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 0C 80 C3 C2 CD 38 30 4C 41 80 4C 1E 80 4C .......80LA.L..L ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 09 80 0C 80 C3 C2 CD 38 30 4C 3F 80 4C 91 80 4C .......80L?.L..L ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: EF FC 09 80 C3 C2 CD 38 30 4C 27 80 4C DB 81 4C .......80L'.L..L ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: 09 80 0C 80 C3 C2 CD 38 30 4C 73 86 4C 30 80 4C .......80Ls.L0.L
This cart has 32KiB of ROM and 8KiB of RAM
Writing to I/O-1 will do the following:
bit meaning --- ------- 7 extra ROM bank selector (A15) (unused) 6 1 = resets FREEZE-mode (turns back to normal mode) 5 1 = enable RAM at ROML ($8000-$9FFF) & I/O-2 ($DF00-$DFFF = $9F00-$9FFF) 4 ROM bank selector high (A14) 3 ROM bank selector low (A13) 2 1 = disable cartridge (turn off $DE00) 1 1 = /EXROM high 0 1 = /GAME low
If bit 5 (RAM enable) is 1, bit 0,1 (exrom/game) is == 2 (cart off), bit 2,6,7 (cart disable, freeze clear) are 0, then cart ROM (Bank 0..3) is mapped at 8000-9FFF, and cart RAM (Bank 0) is mapped at A000-BFFF and cart RAM (Bank 0) is is enabled in the I/O-2 area using 16KiB game config.
The cart RAM or ROM is available through a window in the I/O-2 range.
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 0A 00 01 00 00 00 00 00 00 ...@............ 0020: 45 50 59 58 20 46 41 53 54 4C 4F 41 44 00 00 00 EPYX FASTLOAD... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 30 80 5E FE C3 C2 CD 38 30 20 04 90 4C 38 DF AB 0.^....80 ..L8..
The Epyx FastLoad cart uses a simple capacitor to toggle the ROM on and off:
the capacitor is discharged, and 8KiB game config enabled, by either reading ROML or reading I/O-1. If none of those accesses happen the capacitor will charge, and if it is charged (after 512 cycles) then the ROM will get disabled.
Size | 16KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 0B 00 00 00 00 00 00 00 00 ...@............ 0020: 57 45 53 54 45 52 4D 41 4E 4E 00 00 00 00 00 00 WESTERMANN...... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 40 00 CHIP.. .......@. 0050: 09 80 9C 80 C3 C2 CD 38 30 A2 00 8E 16 D0 20 84 .......80..... .
Any read from the I/O-2 range will switch the cart off.
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 0C 00 01 00 00 00 00 00 00 ...@............ 0020: 52 45 58 00 00 00 00 00 00 00 00 00 00 00 00 00 REX............. 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 08 80 C1 FE C3 C2 CD 38 30 6C 95 E3 20 A3 FD 20 .......80l.. ..
Reading from $DF00-DFBF disables ROM, reading from $DFC0-DFFF enables ROM (8KiB game config).
Size | 16KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 0D 00 00 00 00 00 00 00 00 ...@............ 0020: 54 68 65 20 46 69 6E 61 6C 20 43 61 72 74 72 69 The Final Cartri 0030: 64 67 65 20 49 00 00 00 00 00 00 00 00 00 00 00 dge I........... 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 80 BA 5E FE C3 C2 CD 38 30 00 A0 A0 20 2D FE 58 ..^....80... -.X
Any access to I/O-1 turns cartridge ROM off. Any access to I/O-2 turns cartridge ROM on.
The cart ROM is visible in I/O-1 and I/O-2.
Size | 64KiB (8 banks of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load Address | $E000-FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 0E 01 00 00 00 00 00 00 00 ...@............ 0020: 4D 61 67 69 63 20 46 6F 72 6D 65 6C 00 00 00 00 Magic Formel.... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 E0 00 20 00 CHIP.. ....... . 0050: 4D 46 30 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF0...`...`...`. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 E0 00 20 00 CHIP.. ....... . 2060: 4C 5F E4 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D L_....`...`...`. ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 E0 00 20 00 CHIP.. ....... . 4070: 4D 46 32 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF2...`...`...`. ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 E0 00 20 00 CHIP.. ....... . 6080: 4D 46 33 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF3...`...`...`. ... 8080: 43 48 49 50 00 00 20 10 00 00 00 04 E0 00 20 00 CHIP.. ....... . 8090: 4D 46 34 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF4...`...`...`. ... A090: 43 48 49 50 00 00 20 10 00 00 00 05 E0 00 20 00 CHIP.. ....... . A0A0: 4D 46 35 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF5...`...`...`. ... C0A0: 43 48 49 50 00 00 20 10 00 00 00 06 E0 00 20 00 CHIP.. ....... . C0B0: 4D 46 36 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF6...`...`...`. ... E0B0: 43 48 49 50 00 00 20 10 00 00 00 07 E0 00 20 00 CHIP.. ....... . E0C0: 4D 46 37 8D 00 DF 60 8D 01 DF 60 8D 02 DF 60 8D MF7...`...`...`.
Size | 512KiB (64 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 0F 00 01 00 00 00 00 00 00 ...@............ 00020: 43 36 34 47 53 20 43 61 72 74 72 69 64 67 65 00 C64GS Cartridge. 00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 00050: 6D 80 C5 80 C3 C2 CD 38 30 4C CB 80 4C 36 84 4C m......80L..L6.L ... 02050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 02060: 18 D0 A9 FF 8D 15 D0 8D 1D D0 8D 17 D0 A2 07 A9 ................ ... 04060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 04070: E0 08 19 21 77 84 52 98 9F 80 A5 21 31 01 31 89 ...!w.R....!1.1. ... 06070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 06080: C0 08 1C 1D A0 92 03 03 D8 AA 04 C0 B8 01 40 EA ..............@. ... 7E430: 43 48 49 50 00 00 20 10 00 00 00 3F 80 00 20 00 CHIP.. ....?.. . 7E440: 45 20 41 20 42 49 47 20 58 FE 4F 4E 20 54 48 49 E A BIG X.ON THI
Here is a list of the known cartridges:
C64GS 4-in-1 (Commodore) (512 KiB) Last Ninja Remix (System 3) (512 KiB) Myth (System 3) (512 KiB)
ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. Bank switching is done by writing to address $DE00+X, where X is the bank number (STA $DE00,X). For instance, to read from bank 3, address $DE03 is written to. Reading from anywhere in the I/O-1 range will disable the cart.
The CRT file contains a string of CHIP blocks, each block with a start address of $8000, length $2000 and the bank number in the bank field. In the cartridge header, EXROM ($18) is set to 0, GAME ($19) is set to 1 to enable the 8 KiB ROM configuration.
Size | 16KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 10 00 00 00 00 00 00 00 00 ...@............ 0020: 57 61 72 70 73 70 65 65 64 00 00 00 00 00 00 00 Warpspeed....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 4C 22 80 4C 22 80 FF 43 42 4D 20 53 E4 20 18 E5 L".L"..CBM S. ..
After RESET or POWER ON, 16KiB of cartridge ROM is visible at $8000-$BFFF. Additionally, ROM normally located at $9E00-$9FFF is mirrored into I/O-1 and I/O-2 at $DE00-$DFFF. ROM at $8000-$BFFF is disabled by writing into the I/O-2 area (typically $DF00) and may be re-enabled by writing into I/O-1 ($DE00). However, the $DE00-$DFFF (I/O-1/I/O-2) area itself always remains mapped to cartridge ROM.
Note: the actual cartridge contains both a C64 and a C128 ROM, which can be selected with a switch. We implement them as if these two ROMs were different cartridges - this way they can be selected by using the other .crt file, instead of having to flip the switch in the user interface.
Size | 128KiB (16 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF (all modules) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 11 00 01 00 00 00 00 00 00 ...@............ 00020: 4E 61 72 63 6F 20 50 6F 6C 69 63 65 00 00 00 00 Narco Police.... 00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 00050: 0B 80 0B 80 C3 C2 CD 38 30 00 00 78 A2 FF 9A D8 .......80..x.... .. 02050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 02060: 1C 8C 1B 8C 16 16 8F 16 16 88 1C 1C 86 1C 1C 89 ................ .. 04060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 04070: B6 02 07 08 07 07 00 0A 0A B6 00 05 0A 00 07 07 ................ .. 1E130: 43 48 49 50 00 00 20 10 00 00 00 0F 80 00 20 00 CHIP.. ....... . 1E140: 00 D5 70 03 F5 70 0F 5F 70 0F F7 70 35 FD F0 37 ..p..p._p..p5..7
Here is a list of the known DINAMIC cartridges:
Narco Police (128 KiB) Satan (128 KiB)
ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. Bank switching is done by reading from address $DE00+X, where X is the bank number (LDA $DE00,X). For instance, to read from bank 3, address $DE03 is accessed.
The CRT file contains a string of CHIP blocks, each block with a start address of $8000, length $2000 and the bank number in the bank field. In the cartridge header, EXROM ($18) is set to 0, GAME ($19) is set to 1 to enable the 8 KiB ROM configuration.
Size | 20KiB (3 banks of different sizes) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-8FFF (mirrored in $9000-9FFF, module 0, chip U1) | $A000-BFFF (banked modules 1 and 2, chip U2)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 12 00 00 00 00 00 00 00 00 ...@............ 0020: 5A 61 78 78 6F 6E 00 00 00 00 00 00 00 00 00 00 Zaxxon.......... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 10 10 00 00 00 00 80 00 10 00 CHIP............ 0050: 0D 80 29 80 C3 C2 CD 38 30 78 4C 09 80 78 A9 00 ..)....80xL..x.. .. 1050: 43 48 49 50 00 00 20 10 00 00 00 00 A0 00 20 00 CHIP.. ....... . 1060: A2 0F BD 00 20 D0 04 CA 10 F8 60 BD 70 20 F0 0D .... .....`.p .. .. 3060: 43 48 49 50 00 00 20 10 00 00 00 01 A0 00 20 00 CHIP.. ....... . 3070: 65 A2 36 A3 E7 A3 CB A4 94 A5 86 A6 5E A7 35 A8 e.6.........^.5.
The (Super) Zaxxon carts use a 4KiB ($1000) ROM at $8000-$8FFF (mirrored in $9000-$9FFF) along with two 8KiB ($2000) cartridge banks located at $A000-$BFFF. One of the two banks is selected by doing a read access to either the $8000-$8FFF area (bank 0 is selected) or to $9000-$9FFF area (bank 1 is selected). EXROM ($18 = $00) and GAME ($19 = $00) lines are always pulled to GND to select the 16 KiB ROM configuration.
The CRT file includes three CHIP blocks:
a) bank = 0, load address = $8000, size = $1000 b) bank = 0, load address = $A000, size = $2000 c) bank = 1, load address = $A000, size = $2000
Size | 32KiB, 64KiB or 128KiB sizes (4 to 16 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | (banks 00-15) - $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 13 00 01 00 00 00 00 00 00 ...@............ 0020: 4D 61 67 69 63 20 44 65 73 6B 00 00 00 00 00 00 Magic Desk...... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 C6 CA C3 C2 CD 38 30 8E 16 D0 20 A3 FD 20 .......80... .. .. 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 00 3F 0A 01 00 86 4E 24 28 31 30 29 3A 4A 4F 59 .?....N$(10):JOY .. 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: 00 8B C9 28 4E 24 2C 31 29 B3 B1 22 FF 22 A7 32 ...(N$,1)..".".2 .. 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: AE 01 83 33 2C 37 2C 22 32 29 20 44 45 4C 20 4B ...3,7,"2) DEL K
This cartridge type is very similar to the OCEAN cart type: ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. Bank switching is done by writing the bank number to $DE00. Deviant from the Ocean type, bit 7 is cleared for selecting one of the ROM banks. If bit 7 is set ($DE00 = $80), the GAME/EXROM lines are disabled, turning on RAM at $8000-$9FFF instead of ROM.
In the cartridge header, EXROM ($18) is set to 0, GAME ($19) is set to 1 to indicate the RESET/power-up configuration of 8 KiB ROM.
Here is a list of the known cartridges:
Ghosbusters (HES Australia) (32 KiB) Magic Desk (Commodore) (32 KiB) Badlands (Domark) (64 KiB) Vindicators (Domark) (64 KiB) Wonderboy (HES Australia) (64 KiB) Cyberball (Domark) (128 KiB)
Size | 64KiB or 128KiB (4 or 8 banks of 16KiB each) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 14 00 00 00 00 00 00 00 00 ...@............ 0020: 53 75 70 65 72 20 53 6E 61 70 73 68 6F 74 20 35 Super Snapshot 5 0030: 20 4E 54 53 43 00 00 00 00 00 00 00 00 00 00 00 NTSC........... 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 09 80 59 80 C3 C2 CD 38 30 20 03 9F 00 FA F4 20 ..Y....80 ..... ... 4050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP..@.......@. 4060: 79 DE BC FE C3 C2 CD 38 30 A9 05 8D 20 D0 8D 21 y......80... ..! ... 8060: 43 48 49 50 00 00 40 10 00 00 00 02 80 00 40 00 CHIP..@.......@. 8070: 50 DE BC FE C3 C2 CD 38 30 A9 0A 85 6A A9 0D 85 P......80...j... ... C070: 43 48 49 50 00 00 40 10 00 00 00 03 80 00 40 00 CHIP..@.......@. C080: 50 DE BC FE C3 C2 CD 38 30 85 07 20 1A AD A5 76 P......80.. ...v
The first page of the currently selected ROM bank is mirrored in the I/O-1 range when reading.
The control Register is the I/O-1 range when writing:
bit meaning --- ------- 7-6 unused 5 ROM/RAM bank bit 2 (usually unused, for 128KiB ROM) 4 ROM/RAM bank bit 1 3 ROM enable 2 ROM/RAM bank bit 0 1 RAM enable, EXROM 0 release freeze, !GAME
Size | 64KiB (4 banks of 16KiB each) |
EXROM | active (low) (0) |
GAME | active (low) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 15 00 00 00 00 00 00 00 00 ...@............ 0020: 43 6F 6D 61 6C 20 38 30 00 00 00 00 00 00 00 00 Comal 80........ 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 87 87 70 CF C3 C2 CD 38 30 4C AA CF 4C 70 CF 4C ..p....80L..Lp.L ... 4050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP..@.......@. 4060: AA CF 70 CF C3 C2 CD 38 30 01 29 01 28 01 2C 04 ..p....80.).(.,. ... 8060: 43 48 49 50 00 00 40 10 00 00 00 02 80 00 40 00 CHIP..@.......@. 8070: AA CF 70 CF C3 C2 CD 38 30 91 92 92 92 92 92 92 ..p....80....... ... C070: 43 48 49 50 00 00 40 10 00 00 00 03 80 00 40 00 CHIP..@.......@. C080: 7B C8 7E C8 C3 C2 CD 38 30 43 4F 4D 41 4C 80 93 {.~....80COMAL..
The Comal-80 Cartridge uses 16KiB banks ($4000) at $8000-$BFFF. There are 4 banks of ROM memory and the cart has 1 (write-only) bank control register which is located at $DE00 and mirrored throughout the $DE00-$DEFF range.
bit meaning --- ------- 7 exrom? 6 game? 5 unknown function (used by the software to disable the cartridge) 4 unused? 3 unused? 2 unknown function (used by the software however) 0-1 selects bank
Size | 16KiB (2 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 16 00 01 00 00 00 00 00 00 ...@............ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 0d 80 a2 80 c3 c2 cd 38 30 00 4c a0 84 a2 05 8e .......80.L..... 0060: 16 d0 20 a3 fd 20 50 fd 20 5b ff 20 7e 80 58 20 .. .. P. [. ~.X 0070: 53 e4 20 bf e3 20 ed 83 8d f4 07 a5 2b a4 2c 20 S. .. ......+., 0080: 08 a4 20 80 91 a9 00 85 14 a9 80 85 15 20 75 93 .. .......... u. 0090: a9 8f a0 8a 20 2d e4 a2 0b bd 7d 8a 9d 00 03 ca .... -.......... ... 4040: db 9f 8e 00 de ea 4c e2 9f 8e 00 de ea 4c e9 9f ......L......L.. 4050: 8d 00 de ea 4c 43 fe 8d 00 de ea 4c e2 fc 2d 2a ....LC.....L..-*
Any read/write access to $DE00 or $DE01 will switch in bank 0. Any read/write access to $DE02 will switch in bank 1. Any read/write access to $DE03 will switch off EXROM.
Size | 16KiB or 32KiB sizes (1 or 2 banks of 16KiB each) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 17 00 00 00 00 00 00 00 00 ...@............ 0020: 52 6F 73 73 20 31 34 00 00 00 00 00 00 00 00 00 Ross 14......... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 09 80 09 80 C3 C2 CD 38 30 A2 00 BD 20 80 4D 0E .......80... .M. ... 4050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP..@.......@. 4060: 3F 5A 4D 4D 50 4D 8D 25 3F 1A 1F 77 3F CD E0 3F ?ZMMPM.%?..w?..?
Any read access to $DE00 will switch in bank 1 (if cart is 32KiB). Any read access to $DF00 will switch off EXROM and GAME.
Size | 8KiB to 72KiB sizes (1 to 9 banks of 8KiB each, | or 1 bank of 8KiB and 1 or 2 banks of 32KiB each)
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 18 00 01 00 00 00 00 00 00 ...@............ 0020: 44 45 4C 41 20 45 50 36 34 00 00 00 00 00 00 00 DELA EP64....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 00 85 5E FE C3 C2 CD 38 30 FF FF FF FF FF FF FF ..^....80....... ... 2050: 43 48 49 50 00 00 80 10 00 00 00 01 80 00 80 00 CHIP............ 2060: 54 45 53 54 0D 2A 0D 54 45 20 36 34 0D 00 00 00 TEST.*.TE 64....
This is an eprom cartridge. It has 1 2764 (8KiB) which holds the base eprom with the base menu, and 2 27256 eproms of which 8KiB parts are banked into the $8000-9FFF area.
The bank selecting is done by writing to $DE00. The following bits are used for bank decoding in $DE00 (0 being the LSB, 3 being the MSB).
Bit# 76543210 xx10xx32
Any bank value below 4 or above 11 switches in the base bank (bank 0).
The bit values for each eprom bank are :
eprom bank 1 : xx00xx01 eprom bank 2 : xx01xx01 eprom bank 3 : xx10xx01 eprom bank 4 : xx11xx01 eprom bank 5 : xx00xx10 eprom bank 6 : xx01xx10 eprom bank 7 : xx10xx10 eprom bank 8 : xx11xx10
Setting bit 7 high will switch off EXROM.
Size | 8KiB to 64KiB sizes (1 to 8 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 19 00 01 00 00 00 00 00 00 ...@............ 0020: 44 45 4C 41 20 45 50 37 78 38 00 00 00 00 00 00 DELA EP7x8...... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 5E FE C3 C2 CD 38 30 78 A2 FF 9A D8 8E 16 ..^....80x...... ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 94 83 A0 83 C3 C2 CD 38 30 02 BB 5A 30 5F EE 3D .......80..Z0_.=
This is an eprom cartridge. It has 8 8KiB banks of which the first holds the base menu, the other eproms can be banked into the $8000-9FFF area.
The bank selecting is done by writing to $DE00. Each low bit is used to bank in the respective eprom. If all bits are high then the EXROM is switched off.
The bit values for each eprom bank is:
eprom bank 1 : 11111110 ($FE) (base eprom) eprom bank 2 : 11111101 ($FD) eprom bank 3 : 11111011 ($FB) eprom bank 4 : 11110111 ($F7) eprom bank 5 : 11101111 ($EF) eprom bank 6 : 11011111 ($DF) eprom bank 7 : 10111111 ($BF) eprom bank 8 : 01111111 ($7F) EXROM off : 11111111 ($FF)
Size | 8KiB to 262KiB sizes (1 to 33 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 1A 00 01 00 00 00 00 00 00 ...@............ 0020: 44 45 4C 41 20 45 50 32 35 36 00 00 00 00 00 00 DELA EP256...... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 00 85 5E FE C3 C2 CD 38 30 93 0D 2B 2B 2B 20 45 ..^....80..+++ E ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 09 80 28 80 C3 C2 CD 38 30 78 A2 05 8E 16 D0 20 ..(....80x..... ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: 0B 80 BC FE C3 C2 CD 38 30 DC 10 8E 16 D0 20 87 .......80..... . ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: 09 80 F6 8E C3 C2 CD 38 30 A2 C8 8E 16 D0 20 .. ?.?....80...?.?. ... 8080: 43 48 49 50 00 00 20 10 00 00 00 04 80 00 20 00 CHIP.. ....... . 8090: 94 83 A0 83 C3 C2 CD 38 30 02 BB 5A 30 5F EE 3D .......80..Z0_.=
This is an eprom cartridge. It has 33 8KiB banks of which the first holds the base menu, the other eproms can be banked into the $8000-9FFF area.
The bank selecting is done by writing to $DE00.
The values for the (extra) eprom banks are:
eprom banks 1- 8 : $38-3F eprom banks 9-16 : $28-2F eprom banks 17-24 : $18-1F eprom banks 25-32 : $08-0F
Setting bit 7 high will switch off EXROM.
Size | 8KiB to 262KiB sizes (1 bank of 8KiB and 1 to 8 banks of either | 8KiB, 16KiB or 32KiB)
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 1B 00 01 00 00 00 00 00 00 ...@............ 0020: 52 45 58 20 45 50 32 35 36 00 00 00 00 00 00 00 REX EP256....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 C1 FE C3 C2 CD 38 30 20 A3 FD 20 50 FD 20 .......80 .. P. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 09 80 F2 8F C3 C2 CD 38 30 A2 C8 8E 16 D0 20 A3 .......80..... . ... 4060: 43 48 49 50 00 00 40 10 00 00 00 02 80 00 40 00 CHIP..@.......@. 4070: 09 80 09 80 C3 C2 CD 38 30 58 D8 20 84 FF 20 8A .......80X. .. .
This is an eprom cartridge. It has 9 eprom sockets, of which the first holds the base eprom with the base menu which is an 8KiB eprom, the other eprom sockets can handle 8KiB, 16KiB or 32KiB eproms, of which 8KiB can be banked into the $8000-9FFF area.
The bank selecting is done by writing to $DFA0. Bits 2, 1 and 0 determine which socket is used and bits 5 and 4 are used to select an 8KiB piece of the eprom.
The possible values for bits 5 and 4 for the (extra) eprom banks are:
8KiB : 3, 2, 1, 0 16KiB bank 0 : 2, 0 16KiB bank 1 : 3, 1 32KiB bank 0 : 0 32KiB bank 1 : 1 32KiB bank 2 : 2 32KiB bank 3 : 3
Reading from $DFC0 switches off the EXROM. Reading from $DFE0 switches on the EXROM.
Size | 8KiB (1 bank of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 1C 00 01 00 00 00 00 00 00 ...@............ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 60 80 FE 80 C3 C2 CD 38 30 4C 07 87 4C CA 82 41 `......80L..L..A
The $9E00-$9EFF range is mirrored at $DE00-$DEFF. The $9F00-$9FFF range is mirrored at $DF00-$DFFF.
Size | 32KiB (1 bank of 32KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $0000-$7FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 1D 01 00 00 00 00 00 00 00 ...@............ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 80 10 00 00 00 00 00 00 80 00 CHIP............ 0050: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................
This cart has 32KiB of ROM, bank 0 is in the cart image but is unused. The first 8KiB of the cart image is unused, the second 8KiB of the cart image is mapped to $E000-$FFFF, the third 8KiB of the cart image is mapped to $8000-$9FFF and the fourth 8KiB of the cart image is mapped to $A000-$BFFF. An NMI can be triggered by the cart, if address $0001 is written to and the cartridge is enabled. The cart can be disabled by software, by clearing bit 4 when writing to $DF00-$DFFF. Cart ROM at $E000-$FFFF can be disabled by setting bit 5 to 0 when writing to $DF00-$DFFF. Cart ROM at $8000-$BFFF can be disabled by setting bit 6 to 1 when writing to $DF00-$DFFF. Bit 7 of a byte written to $DF00-$DFFF can be read back from the cartridge if enabled (like a memory cell).
Size | 32KiB (4 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 1E 00 01 00 00 00 00 00 00 ...@............ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: EA 78 48 A9 7F 8D 0D DD D0 0E 48 AD 0D DD 10 04 .xH.......H..... ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 09 80 0C 80 C3 C2 CD 38 30 4C E9 80 4C 81 81 4C .......80L..L..L ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: 09 80 0E 80 C3 C2 CD 38 30 A2 00 4C EF FC 20 BC .......80..L.. . ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: 09 80 0C 80 C3 C2 CD 38 30 4C 70 88 4C 3F 80 4C .......80Lp.L?.L
The control register is the I/O-1 range:
bit meaning --- ------- 0 Eprom banking bit 0 (bank address 13) 1 Controls the GAME line (0 sets GAME low, 1 sets GAME high) 2 Freeze-end bit (disables the register and hides any rom bank) 3 Controls the Exrom line (1 sets EXROM low, 0 sets EXROM high) 4 Eprom banking bit 1 (bank address 14) 5-7 Unused
The first page of the currently banked ROM block can be read in the I/O-2 range.
Size | 16KiB (2 banks of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF (bank 0), | $E000-$FFFF (bank 1)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 1F 01 00 00 00 00 00 00 00 ...@............ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: F9 80 B6 80 C3 C2 CD 38 30 FD 80 89 80 4C 0C 88 .......80....L.. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 00 E0 00 20 00 CHIP.. ....... . 2060: 85 56 20 0F BC A5 61 C9 88 90 03 20 D4 BA 20 CC .V ...a.... .. .
This cart has 16KiB of ROM, of which the first 8KiB is mapped in at $8000-$9FFF and the second 8KiB is used as a kernel replacement. The kernel replacement is achieved by a clip that needs to be installed inside the C64.
Reading from I/O-1 causes a capacitor to get charged with every read, once the capacitor is charged enough it switches the cart on.
Reading from I/O-2 causes a different capacitor to get charged with every read, once the capacitor is charged enough it switched the cart off.
Size | 1024KiB (64 banks of 2 * 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF (ROML), $A000-$BFFF or $E000-$FFFF (ROMH) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 20 01 00 00 00 00 00 00 00 ...@... ........ 0020: 45 61 73 79 46 6C 61 73 68 20 43 61 72 74 72 69 EasyFlash Cartri 0030: 64 67 65 00 00 00 00 00 00 00 00 00 00 00 00 00 dge............. 0040: 43 48 49 50 00 00 20 10 00 02 00 01 80 00 20 00 CHIP.. ....... . 0050: 00 85 5E FE C3 C2 CD 38 30 93 0D 2B 2B 2B 20 45 ..^....80..+++ E
EasyFlash is a 1 MiB Flash EPROM card with multiple configurations and banks possible, it also has 256 bytes of RAM which is mapped into the I/O-2 range.
There are two control registers, one at $DE00 and one at $DE02.
The register at $DE00 controls which bank is mapped into ROMH and ROML.
The register at $DE02 does the following:
bit meaning --- ------- 7 LED control 6-3 Unused 2 Mode (0/1) 1 Exrom line control 0 Game line control
Size | - |
EXROM | - |
GAME | - |
Load address | - |
This CRT type is not actually related to a seperate hardware, it is used by some EasyFlash related tools as a container format. Consequently VICE does (can) not load files of this type.
Size | 8KiB (1 bank of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | inactive (hi) (1) |
Load address | $E000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 22 00 00 00 00 00 00 00 00 ...@..."........ 0020: 4D 61 67 69 63 20 46 6F 72 6D 65 6C 00 00 00 00 Magic Formel.... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 01 E0 00 20 00 CHIP.. ....... . 0050: 00 0A 0D 8A B4 A1 20 80 00 0A 82 8A 8D 20 9E 20 ...... ...... .
This cart has 8KiB of ROM which is mapped to $E000, and 8KiB of RAM which is mapped to $6000. The cartridge is disabled after a reset.
When the freeze button is pressed the following happens:
Size | 16KiB (2 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 23 00 01 00 00 00 00 00 00 ...@...#........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: EA A9 E3 48 A9 7B 48 08 4C 1A 80 EA EA EA 48 AD ...H.{H.L.....H. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 09 80 5E FE C3 C2 CD 38 30 78 A2 FB D8 9A A9 27 ..^....80x.....'
This cart has 16KiB of ROM of which 8KiB is mapped in at both ROML and ROMH. Bank switching and control register is done through the I/O-1 range:
bit meaning --- ------- 7-4 unused 3 Exrom line control 2 Disable cart 1 Unused 0 Bank
Size | 32KiB, 64KiB or 128KiB (4, 8 or 16 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 24 00 01 00 00 00 00 00 00 ...@...$........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 0C 80 C3 C2 CD 38 30 4C 7F 81 4C 87 81 4C .......80L..L..L
Note: When the Cartridge Hardware Subtype/Revision (Offset 0x1A in the CRT Header) is 1, then the image utilizes features only present in the "Nordic Replay" (see description of Nordic/Atomic Power)
The Retro Replay has three registers: Two write-only ($DE00 & $DE01) and one read-only register ($DE00 & $DE01 giving the same results).
The register at $DE00 is reset to $00 on a hard reset if not in flash mode. If in flash mode, it is set to $02 in order to prevent the computer from starting the normal cartridge. Flash mode is selected with a jumper.
Register at $DE00:
bit meaning --- ------- 0 Controls the GAME line: A 1 asserts the line, a 0 will deassert it. 1 Controls the EXROM line: A 0 will assert it, a 1 will deassert it. 2 Writing a 1 will disable further write accesses to all registers of the Retro Replay, and set the memory map of the C64 to standard, as if there is no cartridge installed at all. 3 Controls bank-address 13 for ROM and RAM banking. 4 Controls bank-address 14 for ROM and RAM banking. 5 Switches between ROM and RAM: 0=ROM, 1=RAM 6 Must be written once to "1" after a successful freeze in order to set the correct memory map and enable bits 0 and 1 of this register. Otherwise no effect. 7 Controls bank-address 15 for ROM banking.
The register at $DE01 is the extended control register. If not in Flash mode, bits 1, 2 and 6 can only be written once. If in Flash mode, the REUcomp bit cannot be set, but the register will not be disabled by the first write. Bit 5 is always set to 0 if not in Flash mode.
Register at $DE01:
bit meaning --- ------- 0 Enable clockport connector. 1 AllowBank (1 allows banking of RAM in $DF00/$DE02 area) 2 NoFreeze (1 disables Freeze function) 3 Bank-address 13 for RAM and ROM (mirror of $DE00) 4 Bank-address 14 for RAM and ROM (mirror of $DE00) 5 Bank-address 16 for ROM (only in flash mode) 6 REU compatibility bit. 0=standard memory map, 1 = REU compatible memory map 7 Bank-address 15 for ROM (mirror of $DE00)
Reading from the registers at either $DE00 or $DE01 will return the content of the status register.
Status register:
bit meaning --- ------- 0 1=Flashmode active (jumper set) 1 feedback of AllowBank bit 2 1=Freeze button pressed 3 feedback of banking bit 13 4 feedback of banking bit 14 5 feedback of banking bit 16 6 1=REU compatible memory map active 7 feedback of banking bit 15
The following memory maps are available:
Size | 8KiB (1 bank of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 25 00 01 00 00 00 00 00 00 ...@...%........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 64 97 C3 C2 CD 38 30 78 D8 A2 FF 9A 20 D4 ..d....80x.... .
The clockport registers of this cart can be switched to either $DE01-$DE0F or $DF21-$DF2F. The control registers are available at $DF10-$DF13.
The register at $DE01 / $DF21 is write only:
bit meaning --- ------- 7-1 Unused 0 0 = disable clock port, 1 = enable clockport
The registers at $DE02-$DE0F / $DF22-$DF2F are for the clock port and are read/write.
The register at $DF10 is the MMC64 SPI transfer register, a byte written to this registers is sent to the card & response from the card is read here.
The register at $DF11 is the MMC64 control register:
bit meaning --- ------- 0 0 = MMC64 BIOS active, 1 = external ROM active 1 0 = card selected, 1 = card not selected 2 0 = 250khz transfer, 1 = 8mhz transfer 3 0 = clock port @ $DE00, 1 = clock port @ $DF20 4 0 = normal Operation, 1 = flash mode (*) 5 0 = allow external rom when BIOS is disabled, 1 = disable external ROM 6 0 = SPI write trigger mode, 1 = SPI read trigger mode 7 0 = MMC64 is active, 1 = MMC64 is completely disabled (**)
(*) bit can only be programmed when flash jumper is set (**) bit can only be modified after unlocking
The register at $DF12 is the MMC64 status register, which is read-only:
bit meaning --- ------- 0 0 = SPI ready, 1 = SPI busy 1 external GAME line 2 external EXROM line 3 0 = card inserted, 1 = no card inserted 4 0 = card write enabled, 1 = card write disabled 5 0 = flash jumper not set, 1 = flash jumper set 6-7 unused
The register at $DF13 is the MMC64 identification register, which when reading from it can have the following values:
$64 when bit 1 of $DF11 is 0. $01 when bit 1 of $DF11 is 1 and REV A hardware is used. $02 when bit 1 of $DF11 is 1 and REV B hardware is used.
when writing to it it can be used to unlock bit 7 of $DF11 or to re-enable the cart:
Write $55 & $AA into this register to unlock bit 7 of $DF11. Write $0A & $1C into this register to re-enable MMC64 hardware.
Size | 64KiB or 512KiB (8 or 64 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 26 00 00 00 00 00 00 00 00 ...@...&........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . 0050: 1A 80 6E 9E C3 C2 CD 38 30 4D 4D 43 52 45 50 4C ..n....80MMCREPL
The cart uses the following registers:
$DE00 - RR control register write
bit meaning --- ------- 0 GAME line 1 EXROM line 2 1 = disable RR, bit can be reset by setting bit 6 of $DF12 3 bank address 13 4 bank address 14 5 0 = rom enable, 1 = ram enable 6 1 = exit freeze mode 7 bank address 15
$DE01 - extended RR control register write
bit meaning --- ------- 0 0 = disable clockport, 1 = enable clockport 1 0 = disable I/O RAM banking, 1 = enable I/O RAM banking 2 0 = enable freeze, 1 = disable freeze 3 bank address 13 (mirror of $DE00) 4 bank address 14 (mirror of $DE00) 5 0 = enable MMC registers, 1 = disable MMC registers. Can only be written when bit 6 of $DF12 is 1. Register becomes effective when bit 0 of $DF11 is 1. 6 0 = RAM/ROM at $DFxx, 1 = RAM/ROM at $DExx 7 bank address 15 (mirror of $DE00)
$DE02-$DE0F - Clockport memory area (when enabled)
$DF10 - MMC SPI transfer register, a byte written is sent to the card & response from the card is read here.
$DF11 - MMC control register
bit meaning --- ------- 0 0 = MMC BIOS enabled, 1 = MMC BIOS disabled. Enabling MMC BIOS sets ROM banking to the last 64KiB bank. 1 0 = card selected, 1 = card not selected. This bit also controls the green activity LED. 2 0 = 250khz transfer, 1 = 8mhz transfer 3 ALWAYS 0 4 ALWAYS 0 5 (in RR-Mode:) 0 = allow RR rom when MMC BIOS disabled , 1 = disable RR ROM (in mmcreplay bios mode:) RAM banking (0 = $E000 - $FFFF, 1 = $8000 - $9FFF) (in 16KiB mode:) enable RAM at $A000 - $BFFF 6 0 = SPI write trigger mode, 1 = SPI read trigger mode 7 ALWAYS 0
$DF12 - MMC status register
bit meaning --- ------- 0 0 = SPI ready, 1 = SPI busy (read) 1 = forbid ROM write accesses (write). Setting this bit will disable writes to ROM until next reset 1 feedback of $DE00 bit 0 (GAME) 2 feedback of $DE00 bit 1 (EXROM) 3 0 = card inserted, 1 = no card inserted 4 0 = card write enabled, 1 = card write disabled 5 EEPROM DATA line / DDR register. Setting DATA to "1" enables reading data bit from EEPROM at this position. 6 0 = RR compatibility mode, 1 = Extended mode Selecting RR compatibility mode limits RAM to 32KiB and disables writes to extended banking register. Selecting Extended mode enables full RAM banking and enables Nordic Power mode in RR mode. 7 EEPROM CLK line
$DF13 - Extended banking register Can only be read/written to when bit 6 of $DF12 is 1
bit meaning --- ------- 0 bank address 16 1 bank address 17 2 bank address 18 3 ALWAYS 0 4 ALWAYS 0 5 16KiB rom mapping 6 1 = enable RR register. Disabling RR register disables ALL ROM/RAM banking too. 7 ALWAYS 0
NOTE THAT THE MMC REPLAY EMULATION IS CURRENTLY INCOMPLETE AND CONSIDERED BROKEN.
Size | 64KiB or 128KiB (4 or 8 banks of 16KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 27 00 01 00 00 00 00 00 00 ...@...'........ 0020: 49 44 45 36 34 20 43 41 52 54 52 49 44 47 45 20 IDE64 CARTRIDGE 0030: 49 44 45 44 4f 53 20 32 30 31 33 31 32 31 32 00 IDEDOS 20131212? 0040: 43 48 49 50 00 00 40 10 00 02 00 00 80 00 40 00 CHIP..@.......@. 0050: 63 80 5E FE C3 C2 CD 38 30 20 49 44 45 36 34 20 c.^....80 IDE64
The IDE64 cart uses the following registers:
$DE20 - $DE2F IDE BUS Registers $DE30 - Low Data HDD register $DE31 - High Data HDD register
$DE32 register:
bit meaning --- ------- 7 unused (0) 6 unused (0) 5 unused (0) 4 version number (1) 3 romaddr15 2 romaddr14 1 game 0 exrom
$DE32 - $DE35 = IDE64 ROM bank select registers $DE5F = RTC access (bit 0 only to serial accessed RTC) $DE60 - $DEFF = ROM used by software $DEFB = IDE64 clock reset, kill the cartridge $DEFC - $DEFF = IDE64 memory configuration registers
Size | 32KiB (2 banks of 16KiB) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 28 00 00 00 00 00 00 00 00 ...@...(........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.. ....... . 0050: 80 AD B5 80 C3 C2 CD 38 30 08 48 A9 06 8D 00 DF .......80.H..... ... 2050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP.. ....... . 2060: 13 80 BC FE C3 C2 CD 38 30 08 48 A9 02 8D 00 DF .......80.H.....
This cart has 32KiB of ROM and 8KiB of RAM, it uses I/O-1 as a mirror of the last page of cart RAM. It has the following registers in the I/O-2 range:
ROM config register at $DF00 (can only be written to):
bit meaning --- ------- 0 ? 1 ? (write 1 to release freeze mode) 2 ROM bank select 3 write 1 to disable cartridge 4-6 unused 7 ?
Note: if bit0, bit1, bit7 are all 0, then ultimax mapping is selected and RAM is enabled at ROML, otherwise if bit 0 is 0, then 16KiB mapping is enabled, or if bit 0 is 1, then 8KiB mapping is enabled.
RAM config register at $DF01 (read/write):
If written value == last value - 1, then ultimax mapping is selected and RAM is enabled at ROML, if written value == last value + 1, then ROM is enabled at ROML and exrom is deasserted (switch to either 8KiB or 16KiB mapping)
$DF02-$DFFF holds the last page of the first 8KiB of the current bank.
Size | 4KiB (1 bank of 4KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$8FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 29 00 01 00 00 00 00 00 00 ...@...)........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 10 10 00 00 00 00 80 00 10 00 CHIP............ 0050: 09 80 7A 80 C3 C2 CD 38 30 8E 16 D0 20 84 FF 20 ..z....80... ..
The cart uses a TPI for the IEEE488 interface/communication in the I/O-2 range:
$DF00 - Port A Data $DF01 - Port B Data $DF02 - Port C Data $DF03 - Port A Direction $DF04 - Port B Direction $DF05 - Port C Direction $DF06 - Control register $DF07 - Active Interrupt register
Size | 8KiB (1 bank of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $E000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2A 01 00 00 00 00 00 00 00 ...@...*........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 E0 00 20 00 CHIP.. ....... . 0050: 00 25 08 CF 07 9E 32 30 38 38 20 4D 43 2E 43 52 .%....2088 MC.CR
When the cartridge is active, ultimax is enabled when the address being accessed is is the $E000-$FFFF range, so the ROM is visible at $E000, below is normal C64 RAM. The cart can be disabled by writing to either I/O-1 or I/O-2 range. When the freezer button is pressed, the cartridge will be enabled and an NMI will be triggered.
Size | 256KiB (32 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2B 00 01 00 00 00 00 00 00 ...@...+........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 09 80 C3 C2 CD 38 30 78 A0 00 84 F8 84 FA .......80x......
The control register is the I/O-2 range:
bit meaning --- ------- 7-6 unused 5 disable cart 4-0 bank select
Size | 8KiB (1 bank of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $E000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2C 01 00 00 00 00 00 00 00 ...@...,........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 E0 00 20 00 CHIP.. ....... . 0050: 85 56 20 0F BC A5 61 C9 88 90 03 20 D4 BA 20 CC .V ...a.... .. .
This cart has 8KiB of ROM, mapped in at $E000-$FFFF only when hirom is selected. The cart uses a clip that needs to be installed inside the C64.
Size | 8KiB (1 bank of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2D 00 01 00 00 00 00 00 00 ...@...-........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 10 80 10 80 C3 C2 CD 38 30 20 00 00 00 00 00 00 .......80 ......
When reading from the I/O-1 range the cart is enabled, when reading from the I/O-2 range the cart is disabled. When the freeze button is pressed the ROM is mapped to both $8000-$9FFF and $E000-$FFFF.
Size | 16KiB or 32KiB (1 or 2 banks of 16KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2E 00 01 00 00 00 00 00 00 ...@............ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.. ....... . 0050: 3A 83 60 80 C3 C2 CD 38 30 20 00 00 40 00 00 00 :.`....80 ..@... ... 2050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP.. ....... . 2060: 3A 83 60 80 C3 C2 CD 38 30 20 00 00 40 00 00 00 :.`....80 ..@...
Warning, the following information is based on guess-work and might be incorrect, any further information and/or corrections are appreciated.
When the cart starts, the first half of the active ROM is banked to ROML ($8000-$9fff). When reading from the I/O-1 range the second half of the active ROM bank is enabled in RMH ($A000-$BFFF). When reading from the I/O-2 range the cart is disabled.
The 32k variant swaps the 16k bank with a second one when a reset happens.
When a freeze happens the first half of the ROM is mapped to ROML ($8000-$9FFF) and the second half to ROMH ($E000-$FFFF).
Size | 4KiB (1 bank of 4KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $E000-$EFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2F 01 00 00 00 00 00 00 00 ...@.../........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 10 10 00 00 00 00 E0 00 10 00 CHIP............ 0050: 78 D8 48 8A 48 98 48 AC 0D DD 10 03 4C EE F2 AD x.H.H.H.....L...
Warning, the following information is based on guess-work and might be incorrect, any further information and/or corrections are appreciated.
The cart has a control bit (bit 0) in the I/O-2 range which is used to disable or enable the cart.
Size | 16KiB (2 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 30 00 01 00 00 00 00 00 00 ...@...0........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: D7 86 5E FE C3 C2 CD 38 30 A9 00 2C A9 FF 85 FE ..^....80..,.... ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: E8 96 5E FE C3 C2 CD 38 30 20 6C 81 A9 09 8D 99 ..^....80 l.....
Warning, the following information is based on guess-work and might be incorrect, any further information and/or corrections are appreciated.
The cart has 16KiB of ROM which are used as two banks of 8KiB, they are mapped into $8000-$9FFF and the last page of the current ROM bank is mirrored in $DF00-$DFFF. The cart has a control bit (bit 7) at $DF00, which is used to select what ROM bank is used.
Size | 16KiB |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 31 01 00 00 00 00 00 00 00 ...@...1........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: EA 2C 80 DF 50 FB A0 00 8C 80 DF B9 E3 A3 29 0F .,..P.........). ... 2050: 43 48 49 50 00 00 40 10 00 00 00 00 A0 00 40 00 CHIP.. ....... . 2060: 4A EB C0 49 6A EA BB FB 4E CA 43 1E 75 63 15 97 J..Ij...N.C.uc..
This cart has 16KiB of ROM, mapped in at reset at $8000-$BFFF. The cart is controled through a TPI at $DF80-$DF87:
$DF80 - Port A Data $DF81 - Port B Data $DF82 - Port C Data $DF83 - Port A Direction $DF84 - Port B Direction $DF85 - Port C Direction $DF86 - Control register $DF87 - Active Interrupt register
The cart has a pass-through port and does the following at start-up:
Size | 16KiB (2 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 32 00 01 00 00 00 00 00 00 ...@...2........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: EA EA 68 AA 68 85 94 68 85 95 68 85 96 68 85 97 ..h.h..h..h..h.. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 30 80 5E FE C3 C2 CD 38 30 20 04 90 4C 38 DF 1A 0.^....80 ..L8..
Warning, the following information is based on guess-work and might be incorrect, any further information and/or corrections are appreciated.
I/O-1 is somehow used to enable the cart, the exact way in which this is done is unknown. Reading from the I/O-2 range will give you the last page of the current ROM bank, and writing to it will disable the cart.
Size | 4KiB or 8KiB (1 bank of 4KiB or 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$8FFF (4KiB), | $8000-$9FFF (8KiB)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 33 00 01 00 00 00 00 00 00 ...@...3........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: AF 83 5E FE C3 C2 CD 38 30 4D 41 43 48 35 A5 93 ..^....80MACH5..
This cart has 8KiB ROM mapped at $8000-$9FFF, the $9E00-$9EFF range is mirrored at $DE00-$DEFF and the $9F00-$9FFF range is mirrored at $DF00-$DFFF.
Size | 8KiB (1 bank of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 34 00 01 00 00 00 00 00 00 ...@...4........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 09 80 C3 C2 CD 38 30 AD 11 D0 29 10 D0 62 .......80...)..b
Accessing I/O-1 (the software uses $DE00 only it seems) disables cartridge ROM. A reset enables 8KiB game mode and the ROM bank is mapped to $8000. A freeze causes ROM to be mapped to $8000.
Size | 64KiB (4 banks of 16KiB) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Startup mode | 16KiB Game |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 35 00 00 00 00 00 00 00 00 ...@...5........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 31 80 BB 0E C3 C2 CD 38 30 50 46 20 56 31 2E 30 1......80PF V1.0 ... 4050: 43 48 49 50 00 00 40 10 00 00 00 01 80 00 40 00 CHIP..@.......@. 4060: A2 FE 9A 20 EC AE 20 82 80 20 74 86 20 A5 8B 4C ... .. .. t. ..L ... 8060: 43 48 49 50 00 00 40 10 00 00 00 02 80 00 40 00 CHIP..@.......@. 8070: 5A 01 02 03 04 06 0A 0B 10 14 1E 28 3C 00 00 00 Z..........(<... ... C070: 43 48 49 50 00 00 40 10 00 00 00 03 80 00 40 00 CHIP..@.......@. C080: 1E 03 14 82 09 05 09 0F 0C 0D 0F 05 09 09 0B 0A ................
This cart has 64KiB ROM (2 32KiB Eproms, mapped to $8000 and $A000 in 16KiB Game Mode), and 32KiB RAM (mapped to $8000 and $A000 in 16KiB Game Mode). The cart has 1 (write-only) bank control register which is located at $DE80 and mirrored throughout the $DE80-$DEFF range:
Bit 0: unused/don't care Bit 1: Bank select: 0=upper, 1=lower (not correct ?!) Bit 2: chip select 0 Bit 3: chip select 1 Bit 4: cartridge enable/disable: 0=enable, 1=disable Bits 5-7: unused/don't care
Chip select combinations of 0/1 are:
00: Eprom "79" 01: Eprom "ZS3" 10: Ram 11: empty space (reading returns VIC-II data)
note: on the original hardware "disabling" the cartridge by setting bit 4 of the control register does NOT prevent write accesses to the cartridge RAM!. So to actually disable the RAM, it is suggested to write $FF to the register.
Size | 24KiB (3 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Startup mode | 16KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 36 00 00 00 00 00 00 00 00 ...@...6........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 A2 89 C3 C2 CD 38 30 20 D3 83 78 8D 00 DE .......80 ..x... ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 72 A2 05 A5 45 10 01 CA A5 46 10 02 CA CA 86 28 r...E....F.....( ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: 78 A2 FF 9A D8 A9 08 8D 16 D0 A0 00 98 99 02 00 x...............
This cart has 24KiB ROM (3 8KiB Eproms)
reading io1: - switches to 16KiB game mode - first eprom mapped to 8000 (ROML) - second eprom mapped to A000 (ROMH) writing io1: - switches to ultimax mode _only_: - if 0xc000 > address >= 0x8000 - if address >= 0xe000 (meaning 0x0000-0x7fff and 0xc000-0xdfff gives normal c64 ram/io) - first eprom mapped to 8000 (ROML) - third eprom mapped to e000 (ROMH)
Size | 128KiB (16 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 37 00 01 00 00 00 00 00 00 ...@...7........ 00020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 00050: 09 80 09 80 C3 C2 CD 38 30 78 A2 FF 9A D8 A9 00 .......80x...... ... 02050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 02060: 00 21 1D A9 90 1B 67 70 FD B0 04 C3 19 B9 11 2D .!....gp.......- ... 04060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 04070: 00 41 62 92 AD 71 32 87 08 20 BE 90 4C 36 8F 20 .Ab..q2.. ..L6. ... 06070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 06080: 00 61 00 02 02 03 0D 40 82 15 D0 A1 08 40 84 00 .a.....@.....@.. ... 08080: 43 48 49 50 00 00 20 10 00 00 00 04 80 00 20 00 CHIP.. ....... . 08090: 00 81 8A 85 0D F0 8A 28 83 F8 8A 00 8B 58 83 60 .......(.....X.` ... 0A090: 43 48 49 50 00 00 20 10 00 00 00 05 80 00 20 00 CHIP.. ....... . 0A0A0: 00 A1 C2 E3 C4 86 32 14 00 C5 40 EA 13 CA CB CC ......2...@..... ... 0C0A0: 43 48 49 50 00 00 20 10 00 00 00 06 80 00 20 00 CHIP.. ....... . 0C0B0: 00 C1 81 59 60 00 81 5D D9 58 5E EE 58 6E 3C 28 ...Y`..].X^.Xn<( ... 0E0B0: 43 48 49 50 00 00 20 10 00 00 00 07 80 00 20 00 CHIP.. ....... . 0E0C0: 00 E1 0F BF 3D 56 00 7E 52 FD 50 03 AA 00 0D 40 ....=V.~R.P....@ ... 100C0: 43 48 49 50 00 00 20 10 00 00 00 08 80 00 20 00 CHIP.. ....... . 100D0: 01 01 B9 D1 0D 15 89 55 65 45 41 C5 01 45 45 A8 .......UeEA..EE. ... 120D0: 43 48 49 50 00 00 20 10 00 00 00 09 80 00 20 00 CHIP.. ....... . 120E0: 01 21 0C C7 29 54 41 29 4D C5 06 24 C7 24 8F 81 .!..)TA)M..$.$.. ... 140E0: 43 48 49 50 00 00 20 10 00 00 00 0A 80 00 20 00 CHIP.. ....... . 140F0: 01 41 EA 87 7A AF 95 67 BD F7 00 7D 6E C4 5D A6 .A..z..g...}n.]. ... 160F0: 43 48 49 50 00 00 20 10 00 00 00 0B 80 00 20 00 CHIP.. ....... . 16100: 01 61 6A 92 6B 93 6B 94 6C 95 6D 96 6E 97 6E 98 .aj.k.k.l.m.n.n. ... 18100: 43 48 49 50 00 00 20 10 00 00 00 0C 80 00 20 00 CHIP.. ....... . 18110: 01 81 0E 83 0D 0B 0F 81 FF 28 28 1E E3 0A 14 62 .........((....b ... 1A110: 43 48 49 50 00 00 20 10 00 00 00 0D 80 00 20 00 CHIP.. ....... . 1A120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... 1C120: 43 48 49 50 00 00 20 10 00 00 00 0E 80 00 20 00 CHIP.. ....... . 1C130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... 1E130: 43 48 49 50 00 00 20 10 00 00 00 0F 80 00 20 00 CHIP.. ....... . 1E140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Cartridge hardware is designed around a 128KiB ROM (PROM or Mask ROM) which is divided into 16 banks each of 8KiB. When adressing the onboard bank-switching logic the requested ROM bank is mapped at address range $8000-$9fff (8KiB)
The cartridge PCB layout was cost-optimized for mass-production purposes.
The address-/data-lines and bank-switching logic uses the closest address-/data-lines with shortest and most direct path/distance in order to avoid too much PCB re-routing and keep production costs as low as possible.
This means that the respective address-/data-lines from the cartridge port may not necessarily connect with the corresponding address-/data-line of the ROM according to the official specs of the ROM.
This has over the years given some headaches and invalid dumps when cartridge dumpers that wanted to dump the cartridge contents by de-soldering the ROM and dumping it using an EPROM programmer/reader.
The image extracted from such an operation would need transformation according to the actual cartridge PCB re-routing of address-/data-lines. Alternatively one can make an adapter that implements this applied re-routing of the address-/data-lines.
This mass-production cost optimization also results in an obscured bank-switching address pattern/values more info on that later.
[HWrev1]: The original "Hugo" PCB [HWrev1] is labeled "HUGO Copyright 1990" on both sides of the PCB. PCB production date is stamped on the back og PCB in the format: "YYMM" 1Mib 27C010 EPROM or PROM (typical Atmel) "Hugo" PCB [HWrev1] contains the following discrete logic IC components: 74LS00N (DIP) and 74LS237N (DIP) DIP pitch (pin spacing) 2.54mm (0.1 inch) Assembly/production facilities: Philips, Strandlodsvej (Amager), Copenhagen, Denmark
[HWrev1] Bank-switching pattern: In order for the rom contents to appear as a continuous memory layout the following ROM bank-switching pattern must be applied by writing to adress 0xDE00: Cartridge bank-switching values: 00 80 10 90 20 a0 30 b0 40 c0 50 d0 60 e0 70 f0 Writing the bank-switch value to any address in address-range 0xDE00-0xDEFF will work.
[HWrev2]: Revised PCB [HWrev2] for SMD mount is labeled "SO-A4-1" on both sides of PCB. 1Mib Mask ROM (SOIC-32) PCB contains the following discrete logic SMD IC components: 74HCT02T (SOIC-14) and 74HCT174T (SOIC-16) SOIC (pitch) pin spacing 1.27mm (SMD mounted) Assembly/production facilities: Sono Press, Germany.
[HWrev2] Uses alternative bank-switching pattern: Writing *ANY* value to address 0xDE0y (offset y) will select ROM bank y Cartridge still has 16 banks and the lower four bits in the address selects the right bank. Hence the valid address range is 0xDE00-0xDE0F
Size | 32KiB (4 banks of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Startup mode | Ultimax |
Load address | $E000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 38 00 00 00 00 00 00 00 00 ...@...8........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 E0 00 20 00 CHIP.. ....... . 0050: 48 A9 FC 0C A9 FE 8D C2 DF 68 48 C9 8C F0 1C C9 H........hH..... ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 E0 00 20 00 CHIP.. ....... . 2060: EA EA 58 48 A9 FC 8D C2 DF 4C 6E E2 EA EA A9 FA ..XH.....Ln..... ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 E0 00 20 00 CHIP.. ....... . 4070: 4C 86 E4 A9 FE 78 8D C2 DF 60 78 8C C3 DF A9 FA L....x...`x..... ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 E0 00 20 00 CHIP.. ....... . 6080: EA EA 48 58 A9 FC 8D C2 DF 68 48 C9 46 D0 7E 68 ..HX.....hH.F.~h
the following is a quick overview of how the cartridge works, as its a bit unusual and different from most other cartridges:
- 27256 EPROM (32KiB) - 7430 TTL - MC6821 - 1 button (reset) rom bank 0x00 - 0x03 (0x04) 8192* 4 32KiB mapped to e000 MC6821 registers mapped to io2 at dfc0..dfc4 - press reset and hold delete to get the main menu - press reset and hold control to skip cbm80 check (dont start additional cartridge) - press RESTORE, then... - left arrow, return show disk directory - delete, 1 load"*" from disk, run - f1/f2 ? (disk stuff?) - f3/f4 ? (disk stuff?) - f5/f6, q enter monitor - f7/f8, 2 show drive error channel - control, cursor back to basic - type "help" in basic to get a list of available commands *** MC6821 Port usage Port A (parallel cable to floppy drive): dfc0 port a ddr dfc1 port a (in/out) Port B (controls banking) dfc2 port b ddr ($7f) dfc3 port b (out) bit3 1 = rom at $e000 enabled, 0 = cartridge disabled bit1-2 rom bank number bit0 ?
Size | 64KiB (8 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 39 00 01 00 00 00 00 00 00 ...@...9........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 0C 80 0C 80 C3 C2 CD 38 30 31 30 34 8E 16 D0 20 .......80104... ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: B9 0A 72 AB 0B F0 08 C9 2F 0C 10 27 E8 EF 5A C5 ..r...../..'..Z. ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: C0 B4 6C A6 6A 0A 14 5E 65 AD 94 02 86 C8 30 1F ..l.j..^e.....0. ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: A4 89 C6 3A C4 60 F0 10 4D F5 89 F0 13 6C E0 78 ...:.`..M....l.x ... 8080: 43 48 49 50 00 00 20 10 00 00 00 04 80 00 20 00 CHIP.. ....... . 8090: 00 0B 08 14 00 9E 32 30 36 31 00 00 00 A0 35 BA ......2061....5. ... A090: 43 48 49 50 00 00 20 10 00 00 00 05 80 00 20 00 CHIP.. ....... . A0A0: 1B 4A 00 53 90 77 8E 1A 1D 94 00 A6 E2 50 29 11 .J.S.w.......P). ... C0A0: 43 48 49 50 00 00 20 10 00 00 00 06 80 00 20 00 CHIP.. ....... . C0B0: 14 F7 2E 1A 34 B4 60 53 07 88 C4 F0 21 F6 88 20 ....4.`S....!.. ... E0B0: 43 48 49 50 00 00 20 10 00 00 00 07 80 00 20 00 CHIP.. ....... . E0C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
This cartridge type is very similar to the Magic Desk cart type: ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. Bank switching is done by writing the bank number to $DE00.
bit 0-2 bank number bit 3 exrom latch (1 = cart disabled until reset or powercycle)
If the Cartridge Hardware Subtype/Revision (Offset 0x1A in the CRT Header) is 1, then the banks are addressed in reverse order and the emulated cartridge works like the eprom cartridge by "Hucky". This cartridge can also be equipped with 8Kib, 16Kib, 32Kib EPROMs.
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 3A 00 01 00 00 00 00 00 00 ...@...:........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 09 80 C3 C2 CD 38 30 78 A2 FF 9A D8 8E 16 .......80x......
This cartridge has a CS8900a based RR-Net compatible network interface, and on 8KiB ($2000) bank ROM located at $8000-$9FFF. The ROM can be switched on/off by writing to the IO1 space:
a write to $de80 enables the ROM a write to $de88 disables the ROM
Size | 24KiB (3 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Startup mode | 16KiB Game |
Load address | $8000-$9FFF (bank 1), | $A000-$BFFF (banks 2/3)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 3B 00 00 00 00 00 00 00 00 ...@...;........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 59 89 BC FE C3 C2 CD 38 30 0B 80 B1 84 48 E6 84 Y......80....H.. ... 2050: 43 48 49 50 00 00 20 10 00 00 00 00 A0 00 20 00 CHIP.. ....... . 2060: 04 0B 20 52 45 50 4C 49 43 41 54 45 20 FB 89 0F .. REPLICATE ... ... 4060: 43 48 49 50 00 00 20 10 00 00 00 01 A0 00 20 00 CHIP.. ....... . 4070: 02 10 B5 00 C9 E3 D0 01 C8 C9 E2 D0 01 C8 C9 E0 ................
This cart uses 8KiB mapped in at $8000-$9FFF and 2 banks of 8KiB mapped in at $A000-$BFFF.
The bank at $A000-$BFFF is selected by bit 0 of the address of a write access to I/O-1.
A0 | bank --------- 0 | 0 1 | 1
Size | 512KiB (64 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 3C 00 01 00 00 00 00 00 00 ...@...<........ 00020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . 00050: 09 80 09 80 C3 C2 CD 38 30 78 8E 16 D0 20 A3 FD .......80x... .. ... 02050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 02060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... 7E430: 43 48 49 50 00 00 20 10 00 00 00 3F 80 00 20 00 CHIP.. ....?.. . 7E440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
GMod2 (Individual Computers)
This cart uses 512KiB Flash ROM (29F040) in 64 banks, mapped in at $8000-$9fff and has a 2KiB serial EEPROM (m93C86).
io1 - register at de00 bit7 (rw) write enable (write 1), EEPROM data output (read) bit6 (ro) EXROM (0=active) and EEPROM chip select (1=selected) bit5-0 (ro) rom bank bit5 EEPROM clock bit4 EEPROM data input see http://wiki.icomp.de/wiki/GMod2
Size | 16KiB (ULTIMAX mode) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF (bank 1), | $E000-$FFFF (bank 2)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 3D 01 00 00 00 00 00 00 00 ...@...=........ 0020: 4D 41 58 20 42 41 53 49 43 00 00 00 00 00 00 00 MAX BASIC....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 94 E3 7B E3 43 42 4D 42 41 53 49 43 30 88 41 87 ....CBMBASIC0.A.
This cartridge uses two 8KiB ROMs that contain BASIC and KERNAL for the MAX Machine. It also provides additional 2KiB RAM which will be mapped to $0800.
Size | 2MiB/4MiB/8MiB/16MiB (256/512/1024/2048 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 00000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 00010: 00 00 00 40 01 00 00 3E 00 01 00 00 00 00 00 00 ...@...<........ 00020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . 00050: 09 80 09 80 C3 C2 CD 38 30 78 8E 16 D0 20 A3 FD .......80x... .. ... 02050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 02060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... 001FF030: 43 48 49 50 00 00 20 10 00 00 00 FF 80 00 20 00 CHIP.. ....?.. . 001FF040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
GMod3 (Individual Computers)
This cart uses 2MiB/4MiB/8MiB/16MiB Flash ROM (EN25QH128A(2T)) in 256/512/1024/2048 banks, mapped in at $8000-$9fff.
io1 - register at de00-de07 (write) To select the ROM bank, write to de00-7. The lower 3 bits of the address are the upper three bits of the bank, as in: ldx #bankhi ; upper 3 bits of the bank number lda #banklo ; lower 8 bits of the bank number sta $de00,x - register at de00/de08 (read) The current ROM bank can be read from de00/de08, as in: ldx $de08 ; upper 3 bits of the bank number lda $de00 ; lower 8 bits of the bank number - register at de08 (write) bit7 (w) bitbang mode enabled bit6 (w) EXROM (0=active) bit5 (w) enable cartridge irq vectors - register at de00 (bitbang mode) bit7 (r) EEPROM data output bit6 (w) EEPROM chip select (0=selected) bit5 (w) EEPROM clock bit4 (w) EEPROM data input see http://wiki.icomp.de/wiki/GMod3
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 3f 00 01 00 00 00 00 00 00 ...@...?........ 0020: 5a 49 50 50 2d 43 4f 44 45 20 34 38 00 00 00 00 ZIPP-CODE 48.... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 11 de 7b e3 c3 c2 cd 38 30 41 80 00 00 03 81 31 ..?....80A.....1
reading IO1 enables the cartridge ROM reading IO2 disables the cartridge ROM the second last page of the ROM is mirrored in IO1
Size | 32KiB or 64KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 40 00 00 00 00 00 00 00 00 ...@...@........ 0020: 42 4c 41 43 4b 42 4f 58 20 56 38 00 00 00 00 00 BLACKBOX V8..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 09 80 22 80 c3 c2 cd 38 30 8e 16 d0 20 a3 fd 20 ..?....80... ..
writing to IO2 sets the cartridge config: A0 - EXROM A1 - GAME A2 - bank lsb A3 - bank msb
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 41 00 01 00 00 00 00 00 00 ...@...A........ 0020: 42 4c 41 43 4b 42 4f 58 20 56 33 00 00 00 00 00 BLACKBOX V3..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: a7 85 2b 80 c3 c2 cd 38 30 8e 16 d0 20 a3 fd 20 ..+....80... ..
writing IO1 disables the cartridge ROM writing IO2 enables the cartridge ROM
Size | 16KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 42 00 00 00 00 00 00 00 00 ...@...B........ 0020: 42 4c 41 43 4b 42 4f 58 20 56 34 00 00 00 00 00 BLACKBOX V4..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: a7 85 2b 80 c3 c2 cd 38 30 8e 16 d0 20 a3 fd 20 ..+....80... ..
reading IO1 enables the cartridge ROM reading IO2 disables the cartridge ROM
Size | 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 43 00 01 00 00 00 00 00 00 ...@...C........ 0020: 52 45 58 20 52 41 4d 2d 46 4c 4f 50 50 59 00 00 REX RAM-FLOPPY.. 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 09 fe c3 c2 cd 38 30 20 a3 fd 20 50 fd 20 .......80 .. P.
This cartridge contains an 8KiB ROM which contains the software, plus up to 256KiB RAM which can then be used to store up to 100 programs. The RAM is battery buffered, and the cartridge can be disabled with a switch on the board.
dfa0 (write) selects RAM bank df50 (read) toggles RAM writeable dfc0 (read) toggles cartridge enable dfe0 (read) toggles RAM enable
Size | 2, 4 or 8KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 44 00 01 00 00 00 00 00 00 ...@...D........ 0020: 42 49 53 2d 50 4c 55 53 00 00 00 00 00 00 00 00 BIS-PLUS........ 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 5e fe c3 c2 cd 38 30 8e 16 d0 20 a3 fd a0 ..^....80... ...
This cartridge contains a 2, 4 or 8KiB ROM. The software is copied to RAM and then the cartridge disables itself by writing to IO1 (de00).
Size | 128KiB |
EXROM | active (lo) (0) |
GAME | active (lo) (0) |
Load address | $8000-BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 45 00 00 00 00 00 00 00 00 ...@...E........ 0020: 53 44 2d 42 4f 58 00 00 00 00 00 00 00 00 00 00 SD-BOX.......... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 09 80 81 ea c3 c2 cd 38 30 a9 00 8d 00 de a9 40 .......80......@
This cartridge contains a 128KiB banked ROM with a filebrowser and some extra software on it. It also contains a sd2iec clone, which seems to be seperate and runs the original sd2iec firmware.
there is one register at de00: bit 0-3 ROM bank bit 4 reset SD bit 5 CE ROM bit 6 EXROM bit 7 register enable additionally there are 3 "ram cells" at de01-de03
Size | 1MiB, 64*16KiB (ULTIMAX mode) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF (odd banks), | $E000-$FFFF (even banks)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 46 01 00 00 00 00 00 00 00 ...@...F........ 0020: 4d 55 4c 54 49 4d 41 58 00 00 00 00 00 00 00 00 MULTIMAX........ 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 48 80 48 83 48 83 48 83 64 85 64 85 f5 87 aa 88 H.H.H.H.d.d.....
This cartridge contains 1MiB ROM organised in 64 16KiB banks. It operates in ultimax mode and contains all known ultimax releases. It also provides additional 2KiB RAM for MAX-Basic, which will be mapped to $0800.
there is one register mirrored in the entire IO1 space: bit 7 when set, the register is disabled and can only be reenabled by reset bit 0-5 select ROM bank 0-63
Size | 32KiB, 2*16KiB |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF | $E000-$FFFF
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 47 01 00 00 00 00 00 00 00 ...@...G........ 0020: 42 4c 41 43 4b 42 4f 58 20 56 39 00 00 00 00 00 BLACKBOX V9..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP..@.......@. 0050: 00 9a b6 fe c3 c2 cd 38 30 c3 ff 00 ff 00 ff 00 .......80.......
The cartridge starts in ultimax mode in the last bank. The IO1 area also contains a mirror of the second last ROM page.
a register is mapped to IO1, which is changed by accessing an address in the IO space, the address bits are mapped like this: bit 7 - bank (inverted on write) bit 6 - exrom bit 0 - game
Size | 8KiB ROM, 16KiB RAM |
EXROM | active (lo) (0) Initially |
GAME | inactive (hi) (1) Initially |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 48 00 01 00 00 00 00 00 00 ...@...H........ 0020: 4c 54 2e 20 4b 45 52 4e 41 4c 20 48 4f 53 54 20 LT. KERNAL HOST 0030: 41 44 41 50 54 4f 52 20 36 2e 32 20 52 4f 4d 00 ADAPTOR 6.2 ROM. 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP............ 0050: 14 80 14 80 c3 c2 cd 38 30 00 38 37 30 30 30 30 .......80.......
The Lt. Kernal Host Adaptor (SCSI ID 7) boot rom looks on sector 0 of drive 0 (ID 0) to find the partition (LU or logical unit) information and DOS. If the drive is not found, it will start up in stock mode. See src/c64/cart/ltkernal.c for more details.
The Lt. Kernal Host Adaptor uses the following registers:
$DF00 = MC6821 Port A: Data and DDR $DF01 = MC6821 Port A: Control $DF02 = MC6821 Port B: Data and DDR $DF03 = MC6821 Port B: Control $DF04..7 = LTK Port and Freeze state
MC6821 Port A connects to the SCSI data bus (inverted). Data is saved to hard disk inverted to save data processing time.
signal meaning ------ ------- PA 7-0 /Data bus on SCSI (input/output) CA2 Pulses SCSI ACK (low to high)
MC6821 Port B connects to mostly the SCSI control bus. PB2.6 controls write access to 16KiB SRAM. When low (0), no writes are permitted, when high (1) writes are permitted to $8000-$9FFF AND $E000-$FFFF. Initially, this signal is low, which keeps the boot ROM mapped to $8000-$9FFF (lower 4KiB for the C64, upper 4KiB for the C128). Once a high (1) is written, the boot ROM is mapped out permanently until a reset. CB2 controls which KERNAL is in place. A high (1) uses the stock KERNAL while a low (0) maps in one of the 8K RAMs as the KERNAL. The other RAM at $8000-$9FFF memory is ONLY mapped in when PB2.6 is high (1). The HIRAM line from the PLA goes to the adaptor so it can determine the proper write action to the main RAM or adaptor RAM. Writing a high (1) to CB2 while PB2.6 is low (0) queues up a system reset. If CB2 is not set back to a low (0) or PB2.6 to a high (1), a reset will be asserted in 57 cycles. On startup, the existing kernal is copied and patched by the LTK DOS. On the C64, all known kernal versions work, however in C128 mode, only the original kernal is compatible with the latest LTK DOS (7.2). Make sure to use the 318020-03 kernal (also known as the first version). The LTK DOS overwrites the new patches to the second and third kernal versions.
signal meaning ------ ------- PB 7 /REQ on SCSI (input) PB 6 SRAM control PB 5 RST on SCSI (output) PB 4 SEL on SCSI (output) PB 3 /BUSY on SCSI (input) PB 2 /CD on SCSI (input) PB 1 /MSG on SCSI (input) PB 0 /IO on SCSI (input) CB2 KERNAL control
$DF04 - $DF07:
The LTK Port can be between 0 and 15. Only adaptors set to port 0 are allowed to change the host configuration.
bit meaning --- ------- 3-0 LTK port number (input) 4 Freeze state (0: active, 1: inactive)
Size | 64KiB ROM, 8KiB RAM |
EXROM | inactive (hi) (1) Initially |
GAME | active (lo) (0) Initially |
Load address | $8000-$BFFF and $E000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 49 01 00 00 00 00 00 00 00 ................ 0020: 43 4d 44 20 52 41 4d 4c 49 4e 4b 20 32 2e 30 31 CMD RAMLink 2.01 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 20 00 CHIP............ 0050: 00 00 00 00 00 00 00 00 ee 42 df 20 1c b9 ee 42 ................ ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP............ 2060: 03 4c 75 9c 88 f0 01 88 8c 80 de a9 8d 20 38 8f ................ ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP............ 4070: 0a 17 d8 8d 64 8c be 00 ce 42 df 20 48 88 ce 42 ................ ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP............ 6080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ ... 8080: 43 48 49 50 00 00 20 10 00 00 00 04 80 00 20 00 CHIP............ 8090: 40 48 20 c9 ff aa 68 90 01 8a 60 20 bd ff 20 64 ................ ... a090: 43 48 49 50 00 00 20 10 00 00 00 05 80 00 20 00 CHIP............ a0a0: 85 56 20 0f bc a5 61 c9 88 90 03 20 d4 ba 20 cc ................ ... c0a0: 43 48 49 50 00 00 20 10 00 00 00 06 80 00 20 00 CHIP............ c0b0: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... e0b0: 43 48 49 50 00 00 20 10 00 00 00 07 80 00 20 00 CHIP............ e0c0: a2 ff 78 9a d8 a9 00 8d 00 ff a2 0a bd 4b e0 9d ................ or 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 49 00 01 00 00 00 00 00 00 ................ 0020: 43 4d 44 20 52 41 4d 4c 49 4e 4b 20 31 2e 34 30 CMD RAMLink 1.40 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 20 00 CHIP............ 0050: 52 41 4d 4c 49 4e 4b 20 44 4f 53 20 28 43 29 31 ................ ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP............ 2060: 4e 54 41 58 20 45 52 52 4f 52 00 57 52 49 54 45 ................ ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP............ 4070: aa 09 f9 10 ec b9 9e 1b ec ce 3f 70 8d 84 df a9 ................ ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP............ 6080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ ... 8080: 43 48 49 50 00 00 20 10 00 00 00 04 80 00 20 00 CHIP............ 8090: 40 48 20 c9 ff aa 68 90 01 8a 60 20 bd ff 20 64 ................ ... a090: 43 48 49 50 00 00 20 10 00 00 00 05 80 00 20 00 CHIP............ a0a0: 85 56 20 0f bc a5 61 c9 88 90 03 20 d4 ba 20 cc ................ ... c0a0: 43 48 49 50 00 00 20 10 00 00 00 06 80 00 20 00 CHIP............ c0b0: 80 8d 3f de a9 1b 8d 32 de 8d 34 de a9 ee 8d 33 ................ ... e0b0: 43 48 49 50 00 00 20 10 00 00 00 07 80 00 20 00 CHIP............ e0c0: a2 ff 78 9a d8 a9 00 8d 00 ff a2 0a bd 4b e0 9d ................
The RAMLink CRT file is 64 KiB and consists of eight 8 KiB banks. The first two are for the RAMLink DOS which is banked in from $8000-$BFFF (16 KiB). The third and forth are the configuration portion of the DOS which also banks in at $8000-$BFFF, however only the first 8 KiB is officially used. The banks are the 64 shadow kernal, 64 trap kernal, 128 shadow kernal, and 128 trap kernal respectively. The first bytes of the configuration DOS bank contain 16-bit checksums of various parts of the ROM. The precise mapping is specific to the particular version of the ROM as the code resides there. The ROMs verify these checksums on boot up. Should this fail, the firmware turns on the error LED and goes into an infinite loop. Since vice doesn't provide an error or activity LED for RAMLink, the system would just appear to hang.
The actual RAMLink appears to have the ability to upgrade to a 128 KiB ROM, but no firmware which utilizes it is known to exist.
The RAMLink uses many locations in IO2 primarily so that it can co-exist with other cartridges. Most of these registers are write only, that is to say, all that is required to activate them is a write; the contents of the write are not important. This technique minimizes the coding required to interact with the device. Although RAMLink has 2 pass-thru ports, they are not complete shorts to the cartridge bus, some of the control lines are altered based on the state of the device. Initially, RAMLink is disabled, the trap kernal is active and only one of its registers is visible:
$DF7E = Enable RAMLink registers and switch to shadow kernal
Once a write is done to $DF7E, all the other registers become active. The shadow kernal also switches in. This happens regardless of the state of the microprocessor IO port ($1). Even if the kernal ROM is mapped out, the shadow kernal will appear.
$DF20 = NMI Trap Enable? (not certain as to its function) $DF21 = Mirror to $DF01 (for REU) when NMI trap is on $DF22 = NMI Trap Disable? (not certain as to its function) $DF40 = I8255A Port A (Main board and parallel interface) $DF41 = I8255A Port B $DF42 = I8255A Port C $DF43 = I8255A Control $DF60 = Enable DOS mapping (maps in $8000-$BFFF) $DF70 = Disable DOS mapping $DF7F = Disable RAMLink registers and switch to trap kernal (also disables DOS mapping) $DF80..9F = Switch SRAM page ($DF80 selects page 0, $DF81 selects page 1, $DF82 selects page 2, etc.) $DFA0 = I8255A Port A (RAMCard 1; RAMCard 2 uses custom circuit but same interface) $DFA1 = I8255A Port B $DFA2 = I8255A Port C $DFA3 = I8255A Control $DFB0..BF = 72421 RTC interface (RAMCard 2 only) $DFC0 = Maps in SRAM to $DE00-$DEFF $DFC1 = Maps in RAMCard to $DE00-$DEFF $DFC2 = Maps in RAM Port $DE00-$DEFF (GEORAM, RAMDrive) $DFC3 = Maps in Pass-Thru to $DE00-$DEFF
Note that only address $DF40..42, $DFB0..BF present valid information when read. Addresses $DFA0..$DFA3 also require valid data when being written to. See src/c64/cart/ramlink.c for more details.
When kernal swiching, the ROMs change inbetween instructions. This is possible as the CPU does not cache any incoming instructions. The following is an example of a JSR to the trap kernal at $E000:
PC TRAP SHADOW DETAILS KERNAL KERNAL ----- --------- --------- ------------------------------------------ $C000 JSR $E000 JSR $E000 Same code $E000 STA $DF7E STA $DF7F In trap kernel, next instruction in shadow $E003 INC $D021 INC $D020 Increment $D020 $E006 STA $DF7E STA $DF7F Switch back to trap on next instruction $E009 RTS NOP Return to $C003
If the shadow kernal was active, a JSR to $E000 would result in $D021 being incremented and continuing on back to the NOP in the shadow kernal. The use of write only registers allows the RAMLink Kernal and DOS to perform ROM switching with minimal instructions and time.
The RAMLink includes two switches: "Enable/Disable" and "Normal/Direct". "Enable/Disable" controls whether or not RAMLink is active. In the "Disabled" state, control will be given back to the stock ROMs. "Normal/Direct" controls how the IO cartidge lines to the RAM Port (REU, GEORAM, RAMDrive) are passed. In "Normal" mode, these lines are connected only when the RAMLink registers are active. This prevents any unauthorized access to these devices while RAMLink code isn't running. "Direct" connects the IO lines all the time.
Size | 32KiB (4 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 4a 00 01 00 00 00 00 00 00 ......J........ 0020: 44 52 45 41 4e 20 48 45 52 4f 00 00 00 00 00 00 DREAN HERO...... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 0b 80 bc fe c3 c2 cd 38 30 03 49 8e 16 d0 bd 00 .......80.I..... .. 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP.. ....... . 2060: 32 aa 5a aa 00 00 ff 00 90 d9 68 d9 00 00 90 05 2.Z.......h..... .. 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: ff 7f 7f ff ff 3f 00 00 00 00 00 c0 00 c0 ff 3f .....?.........? .. 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This cartridge type was found in an argentinian H.E.R.O. clone cartridge, ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. There appears to be one register mirrored over IO2 (the software uses $DFFF). Banks are selected by writing to the lower 2 bits of the register, bit 5 disables the cartridge.
Size | 8KiB (1 bank of 8KiB) |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $E000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 2D 01 00 00 00 00 00 00 00 ...@...,........ 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 E0 00 20 00 CHIP.. ....... . 0050: 85 56 20 0F BC A5 61 C9 88 90 03 20 D4 BA 20 CC .V ...a.... .. .
This cart has 8KiB of ROM, mapped in at $E000-$FFFF only when hirom is selected. The cart uses a clip that needs to be installed inside the C64.
Size | 16KiB (2 banks of 8KiB each) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 4c 00 01 00 00 00 00 00 00 ......L........ 0020: 48 45 53 20 54 75 72 74 6c 65 20 47 72 61 70 68 HES Turtle Graph 0030: 69 63 73 20 49 49 00 00 00 00 00 00 00 00 00 00 ics II.......... 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 09 80 bc fe c3 c2 cd 38 30 78 a9 80 85 11 a9 30 .......80x.....0 0060: 85 10 a9 0e 85 13 a9 00 85 12 aa a8 b1 10 91 12 ................ 0070: c8 d0 f9 e6 11 e6 13 e8 e0 09 d0 f0 4c 90 15 ea ............L... 0080: 01 c0 00 01 a0 00 01 90 00 03 88 00 03 84 00 05 ................ 0090: 82 00 05 81 00 09 80 80 09 80 40 11 80 20 11 80 ............. .. ... 4040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Any read/write access to IO1 area will switch to bank 1. Reset will switch to bank 0.
Size | 16KiB |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CART RIDGE 0010: 00 00 00 40 01 00 00 4d 00 01 00 00 00 00 00 00 ......M ........ 0020: 46 72 65 65 7a 65 20 46 72 61 6d 65 20 4d 4b 32 Freeze F rame MK2 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP... ....... 0050: 10 80 0c 80 c3 c2 cd 38 30 20 00 00 40 00 00 00 .......8 0 ..... ... 4030: 02 b0 02 c6 03 60 00 00 a9 ff 85 00 a4 01 68 aa .....`.. ......h. 4040: 68 98 09 20 48 8a 48 4c 1b ff e0 fe 10 80 10 80 h.. H.HL ........
Warning, the following information is based on guess-work and might be incorrect, any further information and/or corrections are appreciated.
When the cart starts, the first half of the active ROM is banked to ROML ($8000-$9fff). When reading from the I/O-2 range the second half of the active ROM bank is enabled in RMH ($A000-$BFFF). When reading from the I/O-1 range the cart is disabled.
When a freeze happens the first half of the ROM is mapped to ROML ($8000-$9FFF) and the second half to ROMH ($E000-$FFFF).
Size | 16KiB |
EXROM | inactive (hi) (1) |
GAME | active (lo) (0) |
Load address | $8000-$9FFF (ROML), $E000-$FFFF (ROMH) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 4e 01 00 00 00 00 00 00 00 ......N........ 0020: 50 61 72 74 6e 65 72 20 36 34 00 00 00 00 00 00 Partner 64...... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 78 48 a5 00 48 a5 01 48 a9 2f 85 00 a9 37 85 01 xH..H..H./...7.. ... 4040: 00 00 00 00 00 00 00 00 00 00 01 00 eb 06 c7 06 ................ 4050: ff ff ff ff ff ff ff 4c 5d ea 00 80 12 84 e0 84 .......L].......
Warning, the following information is based on guess-work and might be incorrect, any further information and/or corrections are appreciated.
This cartridge has 16KiB of ROM and 8KiB of RAM. It starts in ultimax mode with ROML at $8000, ROMH at $e000 and the extra RAM at $a000.
Size | 64KiB (8 banks of 8KiB) |
EXROM | active (lo) (0) |
GAME | inactive (hi) (1) |
Startup mode | 8KiB Game |
Load address | $8000-$9FFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 4F 00 01 00 00 00 00 00 00 ......O........ 0020: 48 79 70 65 72 2D 42 41 53 49 43 00 00 00 00 00 Hyper-BASIC..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP............ 0050: 44 CF 4C 4F 4F D0 45 58 49 D4 43 41 53 C5 47 4B D.LOO.EXI.CAS.GK ... 2050: 43 48 49 50 00 00 20 10 00 00 00 01 80 00 20 00 CHIP............ 2060: A9 FF 2C A9 01 85 FF A5 D6 48 A5 D3 48 20 9E B7 ..,............. ... 4060: 43 48 49 50 00 00 20 10 00 00 00 02 80 00 20 00 CHIP.. ....... . 4070: A9 01 A0 A1 A2 A1 20 BD FF A0 0F A2 04 20 BA FF .. ... .. ... .. ... 6070: 43 48 49 50 00 00 20 10 00 00 00 03 80 00 20 00 CHIP.. ....... . 6080: 09 80 BC FE C3 C2 CD 38 30 A2 FF 8E 02 DC E8 8E .......80....... ... 8080: 43 48 49 50 00 00 20 10 00 00 00 04 80 00 20 00 CHIP.. ....... . 8090: A0 0F B9 40 80 99 00 01 88 10 F7 AE 01 08 E0 09 .............. ... A090: 43 48 49 50 00 00 20 10 00 00 00 05 80 00 20 00 CHIP.. ....... . A0A0: A0 00 B9 00 9E 99 00 9E B9 00 9F 99 00 9F C8 D0 ............... ... C0A0: 43 48 49 50 00 00 20 10 00 00 00 06 80 00 20 00 CHIP.. ....... . C0B0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ ... E0B0: 43 48 49 50 00 00 20 10 00 00 00 07 80 00 20 00 CHIP.. ....... . E0C0: 2C CA 91 AD 0A 03 AE 0B 03 8D B8 02 8E B9 02 A9 ,...............
This cartridge is organized in 8KiB ($2000) banks located at $8000-$9FFF. Bank switching is done by writing to the register at $de00, which is mirrored across the entire IO1 range. Somewhat uncommon is that the register directly exposes the chip-enable for the two ROMs.
bit 0 - _CE for ROM2, 0 = enable (don't select both) bit 1 - _CE for ROM1, 0 = enable (don't select both) (bit 2 - probably unused) (bit 3 - probably unused) bit 4 - A13 bit 5 - A14 bit 6 and/or 7 - _EXROM, 0 = make cart visible
Note: Cartridges that work on both C64 and C128 get "C64 Cartridge" type and get a CRT-ID in the C64 list! ONLY Cartridges that exclusively work in C128 mode get a CRT-ID in the C128 list and "C128 Cartridge" header type.
CRT ID | Cartridge Type |
0 | generic cartridge |
1 | Warpspeed128 |
2 | Partner 128 |
3 | Comal 80 |
4 | Magic Desk 128 |
5 | Gmod2-C128 |
Generic cartridges for the C128 can use two 16KiB ROM blocks named ROML and ROMH, which are mapped to $8000-$BFFF and $C000-$FFFF respectively.
Commonly such cartridges contain one or two 8KiB or 16KiB CHIP packets, one for ROML and one for ROMH. When a block uses a ROM smaller than the block (like 8KiB ROM), then mirrors should be created within that ROM block.
Typical cartridges are 32KiB (ROML+ROMH) or 16KiB (ROML only), although smaller cartridges exist.
8KiB lo function ROM
Size | 8KiB |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 0010: 00 00 00 40 02 00 00 00 00 00 00 00 00 00 00 00 ............... 0020: 47 65 6e 65 72 69 63 20 43 31 32 38 20 43 61 72 Generic C128 Car 0030: 74 72 69 64 67 65 00 00 00 00 00 00 00 00 00 00 tridge.......... 0040: 43 48 49 50 00 00 20 10 00 00 00 00 80 00 20 00 CHIP.. ....... . 0050: 4c 0a 80 4c 0a 80 02 43 42 4d 78 a2 ff 9a d8 a9 L..L...CBMx..... ... 2030: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................ 2040: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
16KiB lo function ROM
Size | 16KiB |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 0010: 00 00 00 40 02 00 00 00 00 00 00 00 00 00 00 00 ............... 0020: 47 65 6e 65 72 69 63 20 43 31 32 38 20 43 61 72 Generic C128 Car 0030: 74 72 69 64 67 65 00 00 00 00 00 00 00 00 00 00 tridge.......... 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 0a 80 60 ea ea ff 43 42 4d a5 d4 c9 48 d0 01 L..`...CBM...H.. ... 4030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
32KiB lo+hi function ROM
Size | 32KiB |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 0010: 00 00 00 40 02 00 00 00 00 00 00 00 00 00 00 00 ............... 0020: 47 65 6e 65 72 69 63 20 43 31 32 38 20 43 61 72 Generic C128 Car 0030: 74 72 69 64 67 65 00 00 00 00 00 00 00 00 00 00 tridge.......... 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 0a 80 d2 d7 d7 30 43 42 4d ad 00 ff 85 fe ad L.....0CBM...... ... 8040: 32 39 3a 89 31 00 ee 26 50 00 d6 31 32 00 00 00 29:.1..&P..12... 8050: a9 01 a0 00 91 2d 20 4f 4f 4c 82 4f 00 00 00 00 .....- OOL.O....
Size | 16KiB |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 0010: 00 00 00 40 02 00 00 01 00 00 00 00 00 00 00 00 ............... 0020: 57 61 72 70 20 53 70 65 65 64 20 31 32 38 00 00 Warp Speed 128.. 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 22 80 4c 22 80 ff 43 42 4d 20 53 e4 20 18 e5 L".L"..CBM S. .. ... 4030: 19 ad 00 1c 29 fd 05 19 8d 00 1c a2 02 bd 03 01 ....)........... 4040: 95 15 95 11 ca d0 f6 8e 00 07 60 41 54 21 21 21 ..........`AT!!!
This is a 16KiB ROM starting at $8000. The part at $9e00-$9fff is mirrored to $de00-$dfff in I/O space.
Note: the actual cartridge contains both a C64 and a C128 ROM, which can be selected with a switch. We implement them as if these two ROMs were different cartridges - this way they can be selected by using the other .crt file, instead of having to flip the switch in the user interface.
Size | 16KiB ROM, 8KiB RAM |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 0010: 00 00 00 40 02 00 00 02 00 00 00 00 00 00 00 00 ............... 0020: 50 61 72 74 6e 65 72 20 31 32 38 00 00 00 00 00 Partner 128..... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 5a 87 4c 5a 87 02 43 42 4d 85 1a 84 1b a0 00 LZ.LZ..CBM...... ... 4030: 22 20 4b f2 8a 0a 0a 0a 0a 0a 85 c2 ad 00 1c 29 " K............) 4040: 9f 05 c2 8d 00 1c 60 8d 03 ff 91 ae 8d 04 ff 60 ......`........`
$8000-$9fff contains the ROM $de00-$de7f contains 128 bytes ram $de80-$deff contains a mirror of $9e80-$9eff Writing to $de80 selects which one of 64 blocks of 128 byte ram is visible in $de00-$de7f.
Size | 96KiB (6 banks of 16KiB) |
Load address | $C000-$FFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 000000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 000010: 00 00 00 40 02 00 00 03 00 00 00 00 00 00 00 00 ............... 000020: 43 6f 6d 61 6c 20 38 30 20 28 43 31 32 38 29 00 Comal 80 (C128). 000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000040: 43 48 49 50 00 00 40 10 00 00 00 00 c0 00 40 00 CHIP.......... 000050: 4c 8c c9 4c 85 1f 01 43 42 4d 4c 5d d2 4c b9 cd L..L...CBML].L.. ... 018080: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 018090: 20 20 20 20 20 20 20 20 20 20 05 ff 3d ff 17 ff ..=...
This cartridge contains 3 32KiB ROMs, each containing two 16KiB banks, which are mapped to $C000 (ROMH). Bankswitching is done via one register at $DE00.
Size | 16KiB ROM, up to 64 banks (=1MiB) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 000000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 000010: 00 00 00 40 02 00 00 04 00 00 00 00 00 00 00 00 ............... 000020: 4d 61 67 69 63 20 44 65 73 6b 20 31 32 38 00 00 Magic Desk 128.. 000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 000050: 4c 0a 80 4c 12 81 01 43 42 4d d8 a9 3a 8d 00 ff L..L...CBM..:... ... 040120: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 040130: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This cartridge contains two ROM sockets with 19 address lines (A0..A18) each. A19 selects which of the two ROM sockets is selected.
D0..D5 of the register at $de00 go to A14..A19. D6/D7 of the register are not used
That means: D0..D4 select the ROM bank D5 selects the ROM socket
The common use-case would be to fill the first ROM first (with 512KiB), and only then add a second ROM. This way you can use linear values in the register to select the respective banks.
Size | 16KiB ROM, up to 32 banks (=512KiB) |
Load address | $8000-$BFFF |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 000000: 43 31 32 38 20 43 41 52 54 52 49 44 47 45 20 20 C128 CARTRIDGE 000010: 00 00 00 40 02 00 00 05 00 00 00 00 00 00 00 00 ............... 000020: 47 6d 6f 64 32 2d 43 31 32 38 00 00 00 00 00 00 Gmod2-C128...... 000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 000050: 4c 0a 80 4c 0a 80 02 43 42 4d 78 a9 0a 8d 00 ff L..L...CBMx..... ... 080220: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 080230: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This is similar to the C64 Gmod2 Cartridge. The differences are: - Banks are 16KiB instead of 8. Because of that one bit less in the register is used for banking - The ROM is always mapped to ROML area
CRT ID | Cartridge Type |
0 | generic cartridge |
1 | Mega-Cart |
2 | Behr Bonz |
3 | Vic Flash Plugin |
4 | UltiMem |
5 | Final Expansion |
Generic VIC20 cartridges are a bit more complex than the ones from the other machines. Since the VIC20 has so little internal memory, most of it is available to be used for ROM and/or RAM at the expansion port:
Block | Start | End | Size |
0 | $0400 | $0FFF | 3k |
1 | $2000 | $3FFF | 8k |
2 | $4000 | $5FFF | 8k |
3 | $6000 | $7FFF | 8k |
5 | $A000 | $BFFF | 8k |
Common start addresses for cartridge ROMs are $2000, $4000, $6000, $7000, $A000, $B000. Also common, for 16KiB cartridges, is a combination of block 1 or 3 with block 5.
Generic VIC20 .crt files may contain one or more CHIP packets fitting into the above blocks. If only the beginning of a block is used for ROM, then the reminder should be filled with mirrors (as it would happen on the real hardware when using a smaller rom and not decoding the unused lines).
Size | 2MiB |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 56 49 43 32 30 20 43 41 52 54 52 49 44 47 45 20 VIC20 CARTRIDGE 0010: 00 00 00 40 02 00 00 01 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 a0 00 20 00 CHIP.. ....... . 0050: fd be 0e bf 41 30 c3 c2 cd 81 00 81 55 c1 5a 81 ....A0......U.Z. ... 201020: a7 ac b0 b5 b9 bd c1 c4 c7 ca cd d0 d3 d5 d8 da ................ 201030: dc de e0 e2 e3 e5 fe 24 17 00 00 00 00 00 00 00 .......$........
Size | 2MiB (128 banks) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 56 49 43 32 30 20 43 41 52 54 52 49 44 47 45 20 VIC20 CARTRIDGE 0010: 00 00 00 40 02 00 00 02 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 a0 00 20 00 CHIP.. ....... . 0050: 10 b0 10 b0 41 30 c3 c2 cd ff ff ff ff ff ff ff ....A0.......... ... 201020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 201030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
This cartridge has one bank register, mirrored over the whole IO3 ($9c00-$9fff)
Size | 4MiB |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 56 49 43 32 30 20 43 41 52 54 52 49 44 47 45 20 VIC20 CARTRIDGE 0010: 00 00 00 40 02 00 00 03 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 a0 00 20 00 CHIP.. ....... . 0050: 66 a1 31 a1 41 30 c3 c2 cd 00 00 01 03 00 01 8d f.1.A0.......... ... 402020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 402030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This cartridge has two registers, which are mirrored over the whole IO2 ($9800-$9bff) area:
$9800 current bank (A20..A13) $9801 configuration register b7 1: I/O2 disabled until RESET b6 1: ROM write protect (set by default) b5 1: RAM at BLK5 (instead of ROM) b4 0: 3k (RAM123), 1: 8k+ (BLK1) b3 1: BLK1/RAM123 enable b2 unused (always 0) b1 unused (always 0) b0 A21
Size | 8MiB or 16MiB |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 56 49 43 32 30 20 43 41 52 54 52 49 44 47 45 20 VIC20 CARTRIDGE 0010: 00 00 00 40 02 00 00 04 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 a0 00 20 00 CHIP.. ....... . 0050: 09 a0 09 a0 41 30 c3 c2 cd 78 a2 ff 9a d8 a9 7f ....A0...x...... ... 1008020: a7 00 a2 07 a3 74 a3 57 a1 55 a1 be a9 ea a0 da .....t.W.U...... 1008030: ff ea a0 d0 ff b6 a3 aa aa aa aa aa aa aa aa aa ................
This cartridge has 512KiB or 1MiB of RAM and 8MiB or 16MiB of flash rom.
Size | 512KiB (ROM) and 512KiB (RAM) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 56 49 43 32 30 20 43 41 52 54 52 49 44 47 45 20 VIC20 CARTRIDGE 0010: 00 00 00 40 02 00 00 05 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 20 10 00 00 00 00 a0 00 20 00 CHIP.. ....... . 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ ... 80420: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 80430: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This cartridge has 512KiB Flash ROM and 512KiB RAM.
It has two registers mirrored every 4 Bytes in the while IO3 ($9c00-$9fff) range.
$9c02 bit 7..5 mode 000: Start Mode 001: Flash-Write-Mode 010: Super ROM Mode 011: RAM/ROM Mode 100: RAM 1 Mode 101: Super RAM Mode 110: RAM 2 Mode bit 4 block5 select bit 3 block3 select bit 2 block2 select bit 1 block1 select bit 0 block0 select $9c03 bit 7 1: register off bit 6 1: invert A14 bit 5 1: invert A13 bit 4 1: block5 off bit 3 1: block3 off bit 2 1: block2 off bit 1 1: block1 off bit 0 1: block0 off
CRT ID | Cartridge Type |
0 | generic cartridge |
1 | c264 magic cart |
2 | Plus4 multi cart |
3 | 1MB Cartridge |
For all Plus4 binary formats (non .crt) the convention is to store all banks of c1lo first, then all banks of c1hi, c2lo, c2hi.
generic cartridges can use 4 different ROM spaces, which are c1lo, c1hi, c2lo, c2hi. most cartridges will use c1lo only, c2 is really uncommon. to indicate which chip chunk goes where, the bank number is used - bank 1 means c2.
32KiB C1 cartridge
Size | 32KiB |
Load address | $8000-$FFFF (C1) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 50 4c 55 53 34 20 43 41 52 54 52 49 44 47 45 20 PLUS4 CARTRIDGE 0010: 00 00 00 40 02 00 00 00 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 47 80 4c f4 80 06 43 42 4d 53 59 53 31 35 32 LG.L...CBMSYS152 ... 8040: ff 20 40 ff 20 40 ff 20 40 ff 20 40 ff 20 40 ff . . . . . . 8050: 20 40 ff 20 40 ff 8d 3e ff 4c a4 f2 f6 ff b3 fc . ..>.L......
Size | 128KiB/256KiB/512KiB/1MiB/2MiB (32/64/128 banks of 16KiB) |
Load address | $8000-$BFFF (C1LO) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 50 4c 55 53 34 20 43 41 52 54 52 49 44 47 45 20 PLUS4 CARTRIDGE 0010: 00 00 00 40 02 00 00 01 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 13 80 4c 13 80 01 43 42 4d 38 42 49 54 43 48 L..L...CBM8BITCH ... 200820: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 200830: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This cartridge has one banking register at $fdfe.
Size | 2MiB/4MiB (64/128 banks of 32KiB) |
Load address | $8000-$FFFF (C1) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 50 4c 55 53 34 20 43 41 52 54 52 49 44 47 45 20 PLUS4 CARTRIDGE 0010: 00 00 00 40 02 00 00 02 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 6b 80 4c 6b 80 01 43 42 4d 0a 0a ee f1 00 20 Lk.Lk..CBM..... ... 401020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 401030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
This cartridge has one banking register at $fda0.
Size | 1MiB (64 banks of 16KiB) |
Load address | $8000-$BFFF (C1LO) |
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- 0000: 50 4c 55 53 34 20 43 41 52 54 52 49 44 47 45 20 PLUS4 CARTRIDGE 0010: 00 00 00 40 02 00 00 03 00 00 00 00 00 00 00 00 ............... 0020: 56 49 43 45 20 43 41 52 54 00 00 00 00 00 00 00 VICE CART....... 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0040: 43 48 49 50 00 00 40 10 00 00 00 00 80 00 40 00 CHIP.......... 0050: 4c 4f 80 00 00 00 0c 43 42 4d 53 59 53 31 35 32 LO.....CBMSYS152 ... 100420: 2f ef ee da db 20 20 20 20 20 20 da db 2f d8 2f /...........././ 100430: 2f ef 2f da db 20 20 20 20 20 20 da db 2f 2f 2f /./..........///
This cartridge has one banking register at $fe00.
TODO
TODO
This section describes the SID file format used for SID tunes in the HVSC (High Voltage SID Collection - http://hvsc.de). It is based mostly on Michael Schwendt's document that describes the file format and the PSID v2NG extensions described by Simon White and Dag Lem and was further extended by Wilfred Bos (PSID v3/v4, RSID v3/v4) and LaLa (assembled most of the following text) and last not least tweaked a bit by Groepaz to fit into the VICE documentation.
The original documentation maintained by the HVSC team can be found here: http://www.hvsc.de/download/C64Music/DOCUMENTS/SID_file_format.txt
SID files use the .sid file extension.
Since PSID v2 is simply an extension of PSID v1, PSID v2NG is an extension of PSID v2, RSID is a restricted version of PSID v2NG, PSID v3/v4 and RSID v3/v4 are extentions of PSID v2NG and RSID v2, all of the formats are discussed together below. RSID in specific is discussed in detail under the 'magicID' field description.
The information presented here targets programmers or other people with reasonable background. It is not suitable for newbies who have never before used a machine code monitor, a disassembler, or a hexadecimal editor.
The detailed structure of the SID header looks like the following. Header offsets are in hexadecimal notation. Other integer values are decimal unless explicitly marked otherwise. Any stored integer values are in big-endian format:
+00 magicID: ``PSID'' or ``RSID''
This is a four byte long ASCII character string containing the value 0x50534944 or 0x52534944. 'RSID' (Real SID) denotes that the file strictly requires a true Commodore-64 environment to run properly. 'PSID' files will generally run trouble-free on older PlaySID and libsidplay1 based emulators, too.
Some words about the Real C64 SID file format (RSID):
The RSID format was designed to contain tunes that are not PlaySID compatible, but strictly require a real C64 environment to run. Tunes that are multi-speed and/or contain samples and/or use additional interrupt sources or do busy looping will cause older SID emulators to lock up or play very wrongly (if at all).
By using the name RSID for such rips all existing SID emulators will reject these tunes safely until they can be upgraded to cope with the additional requirements.
Due to the nature of these tunes, every effort must be made to make sure they are directly runnable on an actual C64 computer. As such the tunes will only be presented with the default C64 power-on environment and expected to configure and use all hardware appropriately.
RSID is based on PSIDv2NG with the following modifications:
The above fields MUST be checked and if any differ from the above then the tune MUST be rejected. The definitions above will force tunes to contain proper hardware configuration code and install valid interrupt handlers.
See section "The SID file environment" below for the default C64 power-on environment for each SID file format.
+04 WORD version
Available version number can be 0001, 0002, 0003 or 0004. Headers of version 2, 3 and 4 provide additional fields. RSID and PSID v2NG files must have 0002, 0003 or 0004 here.
+06 WORD dataOffset
This is the offset from the start of the file to the C64 binary data area. Because of the fixed size of the header, this is either 0x0076 for version 1 and 0x007C for version 2, 3 and 4.
+08 WORD loadAddress
The C64 memory location where to put the C64 data. 0 means the data are in original C64 binary file format, i.e. the first two bytes of the data contain the little-endian load address (low byte, high byte). This must always be true for RSID files. Furthermore, the actual load address must NOT be less than $07E8 in RSID files.
You must be absolutely sure what to enter here. There is no way to detect automatically whether the first two bytes in a C64 data file are meant to be a load address or some arbitrary bytes of code or data. Unless your C64 file is not a normal binary file and thus has no load address in front, you need not enter anything else than 0 here. The SID tune will not play if you specify a load address which is present in the C64 file already.
Normal C64 binary data files have a load address in their first two bytes, so they can be loaded to a pre-defined destination address by executing LOAD"FILE",8,1, for instance. If a load address is explicitly specified in the sidtune info file, some sidtune converters and utilities conjecture that the C64 data don't have a load address in their first two bytes. Hence, the explicit load address from the info file is moved in front of the C64 data to create a valid C64 binary file which can be easily loaded on a C64, too. If that C64 file were to be saved, it would contain two superfluous data bytes at offset 2 if an original load address had been in the first two bytes of the old file. This process of adding a duplicate load address can be repeated. The file loader strips off the first two bytes (the used load address) and puts the rest of the file contents (including the now obsolete load address at file offset 2) into memory. If the new load address is the same than the old one the two added bytes cause the whole data to be displaced by two bytes, which most likely results in malfunctioning code. Also, superfluous bytes in memory then can confuse disassemblers which start at the beginning of the file or memory buffer.
+0A WORD initAddress
The start address of the machine code subroutine that initializes a song, accepting the contents of the 8-bit 6510 Accumulator as the song number parameter. 0 means the address is equal to the effective load address.
In RSID files initAddress must never point to a ROM area ($A000-$BFFF or $D000-$FFFF) or be lower than $07E8. Also, if the C64 BASIC flag is set, initAddress must be 0.
+0C WORD playAddress
The start address of the machine code subroutine that can be called frequently to produce a continuous sound. 0 means the initialization subroutine is expected to install an interrupt handler, which then calls the music player at some place. This must always be true for RSID files.
+0E WORD songs
The number of songs (or sound effects) that can be initialized by calling the init address. The minimum is 1. The maximum is 256.
+10 WORD startSong
The song number to be played by default. This value is optional. It often specifies the first song you would hear upon starting the program is has been taken from. It has a default of 1.
+12 LONGWORD speed
This is a 32 bit big endian number.
For version 1 and 2 and for version 2NG, 3 and 4 with PlaySID specific flag (+76) set, the 'speed' should be handled as follows:
Each bit in 'speed' specifies the speed for the corresponding tune number, i.e. bit 0 specifies the speed for tune 1. If there are more than 32 tunes, the speed specified for tune 32 is the same as tune 1, for tune 33 it is the same as tune 2, etc.
For version 2NG, 3 and 4 with PlaySID specific flag (+76) cleared, the 'speed' should be handled as follows:
Each bit in 'speed' specifies the speed for the corresponding tune number, i.e. bit 0 specifies the speed for tune 1. If there are more than 32 tunes, the speed specified for tune 32 is also used for all higher numbered tunes.
For all version counts:
Note that if 'play' = 0, the bits in 'speed' should still be set for backwards compatibility with older SID players. New SID players running in a C64 environment will ignore the speed bits in this case.
WARNING: This field does not work in PlaySID for Amiga like it was intended, therefore the above is a redefinition of the original 'speed' field in SID v2NG! See also the 'clock' (video standard) field described below for 'flags'.
+16 ``<name>'' +36 ``<author>'' +56 ``<released>'' (once known as ``<copyright>'')
These are 32 byte long ASCII character strings. Upon evaluating the header, these fields may hold a character string of 32 bytes which is not zero terminated. For less than 32 characters the string should be zero terminated. The maximum number of available free characters is 32.
+76 <data>
Version 1 of the SID header is complete at this point. The binary C64 data starts here.
Version 2, 3 and 4 of the header incorporates the v1 header fields and provides additional fields. Some of these are actually v2NG, v3 or v4 specific - those are noted below.
+76 WORD flags
This is a 16 bit big endian number containing the following bitfields:
If this bit is set, the appended binary data are in Compute!'s Sidplayer MUS format, and does not contain a built-in music player. An external player machine code must be merged to replay such a sidtune.
This is a v2NG and RSID specific field.
PlaySID samples were invented to facilitate playback of C64 volume register samples with the original Amiga PlaySID software. PlaySID samples made samples a reality on slow Amiga hardware with a player that was updated only once a frame.
Unfortunately, converting C64 volume samples to PlaySID samples means that they can no longer be played on a C64, and furthermore the conversion might potentially break the non-sample part of a tune if the timing between writes to the SID registers is at all altered. This follows from the ADSR bugs in the SID chip.
Today, the speed of common hardware and the sophistication of the SID players is such that there is little need for PlaySID samples. However, with all the PlaySID sample PSIDs in existence there's a need to differentiate between SID files containing only original C64 code and PSID files containing PlaySID samples or having other PlaySID specific issues. As stated above, bit 1 in 'flags' is reserved for this purpose.
Since RSID files do not have the need for PlaySID samples, this flag is used for a different purpose: tunes that include a BASIC executable portion will be played (with the BASIC portion executed) if the C64 BASIC flag is set. At the same time, initAddress must be 0.
This is a v2NG specific field.
As can be seen from the 'speed' field, it is not possible to specify NTSC C64 playback. This is unfortunate, since the different clock speeds means that a tune written for the NTSC C64 will be slightly detuned if played back on a PAL C64. Furthermore, NTSC C64 tunes driven by a vertical blank interrupt have to be converted to use the CIA 1 timer to fit into this scheme. This can cause severe problems, as the NTSC refresh rate is once every 17045 cycles, while the CIA 1 timer A is latched with 17095 cycles. Apart from the difference in timing itself, the SID ADSR bugs can actually break the tune.
The 'clock' (video standard) field was introduced to circumvent this problem.
This is a v2NG specific field.
If bits 6-7 are set to Unknown then the second SID will be set to the same SID model as the first SID.
This is a v3 specific field.
If bits 8-9 are set to Unknown then the third SID will be set to the same SID model as the first SID.
This is a v4 specific field.
The MOS6581 and the MOS8580 have three notable differences. First, combined waveforms are generally louder on a MOS8580, to the extent that some combinations that are clearly audible on a MOS8580 are completely silent on a MOS6581. Second, the internal DC levels in the MOS8580 are so small that software or hardware tricks must be used to play volume samples. Third, the MOS8580 analog filter has totally different characteristics from the MOS6581 analog filter.
To ensure that music specifically written for one of the two SID versions can be played back correctly, bits 4-9 in 'flags' are used as stated above.
+78 BYTE startPage (relocStartPage)
This is a v2NG specific field.
This is an 8 bit number. If 'startPage' is 0, the SID file is clean, i.e. it does not write outside its data range within the driver ranges. In this case the largest free memory range can be determined from the start address and the data length of the SID binary data. If 'startPage' is 0xFF, there is not even a single free page, and driver relocation is impossible. Otherwise, 'startPage' specifies the start page of the single largest free memory range within the driver ranges. For example, if 'startPage' is 0x1E, this free memory range starts at $1E00.
+79 BYTE pageLength (relocPages)
This is a v2NG specific field.
This is an 8 bit number indicating the number of free pages after 'startPage'. If 'startPage' is not 0 or 0xFF, 'pageLength' is set to the number of free pages starting at 'startPage'. If 'startPage' is 0 or 0xFF, 'pageLength' must be set to 0.
The relocation range indicated by 'startPage' and 'pageLength' should never overlap or encompass the load range of the C64 data. For RSID files, the relocation range should also not overlap or encompass any of the ROM areas ($A000-$BFFF and $D000-$FFFF) or the reserved memory area ($0000-$03FF).
+7A BYTE secondSIDAddress
This is a v3 specific field. For v2NG, it should be set to 0.
This is an 8 bit number indicating the address of the second SID. It specifies the middle part of the address, $Dxx0, starting from value $42 for $D420 to $FE for $DFE0). Only even values are valid. Ranges $00-$41 ($D000-$D410) and $80-$DF ($D800-$DDF0) are invalid. Any invalid value means that no second SID is used, like $00.
+7B BYTE thirdSIDAddress
This is a v4 specific field. For v2NG and v3, it should be set to 0.
This is an 8 bit number indicating the address of the third SID. It specifies the middle part of the address, $Dxx0, starting from value $42 for $D420 to $FE for $DFE0). Only even values are valid. Ranges $00-$41 ($D000-$D410) and $80-$DF ($D800-$DDF0) are invalid. Any invalid value means that no third SID is used, like $00. The address of the third SID cannot be the same as the second SID.
+7C <data>
Version 2, 3 and 4 of the SID header ends here. This offset is the start of the binary C64 data. See also 'loadAddress' for what the first 2 bytes of 'data' might indicate.
Before the data of a SID file is loaded in memory of a C64, certain addresses and chips must be initialized in order to play the SID tune correctly.
For RSID and PSID files the following address must be set:
$02A6 | depending on the PAL/NTSC flag in the SID file header, it is set to | 0x01 for PAL and set to 0x00 for NTSC.
The default C64 environment for PSID files is as follows:
VIC | IRQ set to any raster value less than 0x100. Enabled when speed | flag is 0, otherwise disabled.
CIA 1 timer A | set to 60Hz (0x4025 for PAL and 0x4295 for NTSC) with the | counter running. IRQs active when speed flag is 1, otherwise IRQs are disabled.
Other timers | disabled and loaded with 0xFFFF. |
When the init and play addresses are called the bank register value must be written for every call and the value is calculated as follows:
if address < $A000 -> 0x37 // I/O, Kernal-ROM, Basic-ROM else address < $D000 -> 0x36 // I/O, Kernal-ROM else address >= $E000 -> 0x35 // I/O only else -> 0x34 // RAM only
The default C64 environment for RSID files is as follows:
VIC | IRQ set to raster 0x137, but not enabled. |
CIA 1 timer A | set to 60Hz (0x4025 for PAL and 0x4295 for NTSC) with the | counter running and IRQs active.
Other timers | disabled and loaded with 0xFFFF. |
Bank register | 0x37 |
"Swaplist" or "Fliplist" files contain filenames of (mostly) disk images that belong to a program (game/demo) so the can be easily swapped/changed by a button press. They were first introduced by VICE, and have since then been adopted and expanded by other devices. This is an attempt to unify the efforts and create a standard for a format that will work with all OSs and across all devices that can use these files, so eg a SD-Card containing a software collection will work with all of them.
The format itself is pretty straightforward and almost trivial: it is simply a text file containing one filename per line.
Some devices introduced custom extensions on the format, which are considered completely optional. Most notable is the #PETSCII tag introduced by sd2iec, which parsers that don't support it should simply ignore.
Details on the various devices/emulators that support swaplists follow:
After 3.5 r40450 VICE will still accept (read) files in the old format, but only create files in the new, more compatible format.
The comment delimiter (;) is recognized in firmware since April 22nd, 2021
(some of the following needs more explanation and/or will perhaps change in the future):
example: barebones minimal swaplist
FOO.D64 BAR.D64 BAZ.D64
example: simple VICE fliplist
; Vice fliplist file FOO.D64 BAR.D64 BAZ.D64
example: VICE fliplist for multiple drives + comments
; Vice fliplist file ;UNIT 8 FOO.D64 BAR.D64 BAZ.D64 ;UNIT 9 FUU.D64 BOR.D64 BOZ.D64 ; don't forget this one ;UNIT 10 BUZ.D64
example: sd2iec style pathes + comment
//NEATGAME/:DISK1A.D64 //NEATGAME/:DISK1B.D64 //NEATGAME/:DISK2A.D64 //NEATGAME/:DISK2B.D64 ; save disk in separate directory for easier backup //SAVEDISKS/:NEATGAME.D64
Go to the first, previous, next, last section, table of contents.