Adapted/fixed from here.
I do not know who the original author is. My only claim is to have fixed some errors/typos, expanded it, and prettied it up for display here.
Apple peripheral cards: What goes where
Card type | Card name |
---|---|
1 | Apple Disk II controller |
2* | Apple Communications Card CCS 7710A Serial Interface |
3 | Apple Super Serial Card Apple Silentype Printer Videx Videoterm 24×80 Video Terminal Card M&R Enterprises Sup-R-Term 24×80 Video Terminal Card |
4 | Apple Parallel Printer Card |
*The CCS 7710A card is the preferred card of type 2 as it supports hardware handshaking and variable baud rates from 110 to 19200 baud. The Apple Communications Card requires hardware modification for use with baud rates other than 110 or 300 baud.
As a general rule, any card directly compatible with Apple Pascal without requiring software modifications will probably be directly compatible with Apple CP/M as well. Other peripheral cards may be used if software supplied by the card manufacturer is bound to your Apple CP/M system using the CONFIGIO utility program.
Slot | Valid card | Purpose/types |
---|---|---|
0 | Not used for I/O | Applesoft or Integer Basic ROM card Language card (used by Apple CP/M) |
1 | 2,3,4 | Line printer interface (CP/M LST: device) |
2 | 2,3,4 | General purpose I/O (CP/M PUN: and RDR: devices) |
3 | 2,3,4 | Console output device (CP/M CRT: or TTY: device) The normal Apple 24×40 screen used if no card here |
4 | 1 | Disk controller for drives E: and F: Z80 Softcard may be installed here if no disk controller here. |
5 | 1 | Disk controller dir drives C: and D: |
6 | 1 | Disk controller dir drives A: and B:, must be present. |
7 | any type | No assigned purpose. The Z-80 SoftCard may be installed here.* |
* European Apple II's in PAL mode: only a PAL color card may be inserted here!
If you do have an external terminal interface with a terminal interface card in slot 3, it is recommended to remove it and to use the normal Apple screen and keyboard until you have configured Apple CP/M for use with your terminal with the CONFIGIO utility.
CP/M name | Slot # | Drive # | |
---|---|---|---|
1st drive: | A: | 6 | 1 |
2nd drive: | B: | 6 | 2 |
3rd drive: | C: | 5 | 1 |
4th drive: | D: | 5 | 2 |
5th drive: | E: | 4 | 1 |
6th drive: | F: | 4 | 2 |
Note: SoftCard CP/M up to 2.20B allows up to 6 drives, while versions 2.23, 2.25 and 2.26 allows only up to 4 drives. Generic CP/M allows up to 16 drives.
Make sure the four small DIP switches all are switched to the OFF position. This is the standard operating position for Apple CP/M.
Turn off your Apple II, insert the SoftCard into any unused slot except slot 0. The standard slot for the SoftCard is slot 4. If slot 4 is occupied by a disk controller card, choose some other slot.
Insert the other peripheral cards according to the list above which you want to use.
Turn on your Apple II.
The four DIP switches are normally OFF for CP/M operation. Their functions are:
Switch | Function when ON |
---|---|
1-1 | Disable address translation. |
1-2 | Higher priority DMA devices cause SoftCard to relinguish bus. |
1-3 | Pass NMI line to Z80. |
1-4 | Pass IRQ line to Z80. |
Examples:
FORMAT A: | Format disk in drive A: |
The Apple CP/M disk formatter (Apple CP/M ver 2.23 and later has no FORMAT program, instead disk formatting is integrated into the COPY program)
Examples:
COPY B:=A: | Copy disk in A: to disk in B: |
COPY A:=A: | Single-drive copy |
COPY A:=A:/S | Copy only the CP/M system tracks |
COPY | Prompts user for source and dest. drives |
The Apple CP/M disk copy program. Copies the entire disk, overwriting the whole destination disk. Can copy on a single drive too (PIP requires two drives to copy from one disk to another)
Example:
CPM56 A: |
Updates the CP/M system from 44K CP/M to 56K CP/M. 56K CP/M requires a Language Card to work. CPM56 is preset only on the 16-sector Apple CP/M disk.
An MBASIC program used to:
Transfers data (files) from your Apple DOS disks to CP/M disks. May be used to transfer text and binary files only. Does not transfer files from CP/M disks to Apple DOS disks – use the Apple DOS utility CPMXFER for that.
DOWNLOAD and UPLOAD enable the user to transfer CP/M files from another CP/M machine to the Apple by means of an RS-232 serial data link. UPLOAD is not included on either of the Apple CP/M disks but should be typed in and assembled on the other CP/M machine. Using these programs requires a working knowledge of 8080 assembly language programming.
Allows 16-sector Apple CP/M to access files on a 13-sector Apple CP/M disk. Requires at least two Disk II drives to work. RW13 is present only on the 16-sector Apple CP/M disk.
Options
/filename | Loads and executes a basic program files (.BAS default ext) |
/F:<no_files> | Max number of concurrently open files (default=3) Each file requires 166+128 bytes extra |
/M:<max_mem> | Highest mem location used by MBASIC (default all TPA) |
/S:<max_recsize> | Max record size allowed by random files (default 128) |
The <no_files>
and <max_mem>
may be given as <decimal>
, &O<octal>
or &H<hexadecimal>
.
These are Microsofts MBASIC interpreter, adapted for Apple CP/M. It comes in two flavors: GBASIC supports Apple hires graphics while MBASIC does not. Both basic's support Apple's lo-res graphics plus a few other Apple specific things. GBASIC is present only on the 16-sector Apple CP/M disk.
Key | Action |
---|---|
← Ctrl+H | Backspaces one character, deleting the char under the cursor |
Ctrl+X | Backspaces to the beginning of the line, deleting the line |
Ctrl+R | Retypes the current line |
Ctrl+J | Terminates input - same as RETURN key |
Ctrl+E | Physical end-of-line. Cursor moved to the beginning of next line, but line is not terminated until RETURN is typed. |
RUBOUT | Deletes and “echoes” (reprints) the last character typed. Also referred to as DEL or DELETE (ASCII 7Fh). Type Ctrl+@ to get RUBOUT on the Apple ][/][+ keyboard |
A few characters normally unavailable on the Apple ][/][+ keyboard have been assigned to certain control characters, making them available:
Type: | To get: |
---|---|
Ctrl+K | [ |
Ctrl+@ | RUBOUT |
Ctrl+B | \ |
Ctrl+U | TAB (Ctrl+I) |
These control characters can be redefined with the CONFIGIO program
Key | Action |
---|---|
Ctrl+S | Temporarily stops character output to TTY: Output is resumed when any character is typed |
Ctrl+P | Sends all character output to LPT: as well as to TTY: This “printer echo” mode remains in effect until another Ctrl+P is typed. |
When Ctrl+C is typed as the first character on a line, CP/M performs a “warm boot”, causing CP/M to be reloaded from disk to insure that it is in working order. You should ALWAYS type Ctrl+C whenever you change disks.
On a system having the Autostart ROM hitting the RESET key while in CP/M will cause CP/M to warm boot, returning to CP/M. Hitting the RESET key while in MBASIC/GBASIC will result in a “Reset error”, which can be trapped using “ON ERROR GOTO”.
On a system having the older Monitor ROM, hitting the RESET key will land you in the Apple Monitor. You can recover by typing Ctrl+Y RETURN, after which the behavior will be the same as for the Autostart ROM.
Unlike Apple DOS you cannot indiscriminately change disks in drives with CP/M. When you change disks, you must let CP/M know that you have done so, because certain disk directory information is stored in memory at all times and used to allocate space on the disk. When you change disks, this information must be replaced by the corresponding information for the new disk.
To let CP/M know you have changed disks, type Ctrl+C to execute a CP/M “warm boot”. Do so AFTER you have changed the disks. You should get used to typing Ctrl+C often.
If you don't type Ctrl+C after having changed disks, and a WRITE is attempted to the changed disk, CP/M will display:
BDOS ERR ON x:Disk R/O
(where x: is a disk drive A:-F:)
(R/O means Read Only). When you receive this message, hit RETURN. This will perform a CP/M warm boot and return you to CP/M, terminating any application you may have been running.
The above error will apply only to changed disks which are to be WRITTEN. No error will result if you attempt to READ from the changed disk without having typed Ctrl+C first.
The SoftCard performs address translation from the Z-80 to the Apple II address bus. Below Z-80 addresses are written with a trailing 'H' while 6502 addresses are written with a leading '$':
Z-80 addr | 6502 addr | Notes |
---|---|---|
0000H-00FFFH | $1000-$1FFF | Z-80 address zero |
1000H-10FFH | $2000-$2FFF | |
2000H-20FFH | $3000-$3FFF | |
3000H-30FFH | $4000-$4FFF | |
4000H-40FFH | $5000-$5FFF | |
5000H-50FFH | $6000-$6FFF | |
6000H-60FFH | $7000-$7FFF | |
7000H-70FFH | $8000-$8FFF | |
8000H-80FFH | $9000-$9FFF | |
9000H-90FFH | $A000-$AFFF | |
0A000H-0AFFFH | $B000-$BFFF | |
0B000H-0BFFFH | $D000-$DFFF | |
0C000H-0CFFFH | $E000-$EFFF | |
0D000H-0DFFFH | $F000-$FFFF | 6502 RESET, NMI, BREAK vectors |
0E000H-0EFFFH | $C000-$CFFF | 6502 memory mapped I/O |
0F000H-0FFFFH | $0000-$0FFF | 6502 zero page, stack, Apple screen, CP/M RWTS |
This translation may be turned off by setting DIP switch S1-1 to ON.
6502 address | Z-80 address | Use |
---|---|---|
$0800-$0FFF | 0F800H-0FFFFH | Apple CP/M disk drivers and buffers (“RWTS”) |
$0400-$07FF | 0F400H-0F7FFH | Apple screen memory |
$0200-$03FF | 0F200H-0F3FFH | I/O config block, device drivers |
$0000-$01FF | 0F000H-0F1FFH | Reserved area:6502 page zero and 6502 stack |
$C000-$CFFF | 0E000H-0EFFFH | Apple memory mapped I/O |
$FFFA-$FFFF | 0DFFAH-0DFFFH | 6502 RESET, NMI and BREAK vectors |
$D400-$FFF9 | 0C400H-0DFF9H | 56K Language Card CP/M (if Lang. Card installed) |
$D000-$D3FF | 0C000H-0C3FFH | Top 1K of free RAM with 56K CP/M |
$A400-$BFFF | 9400H-0AFFFH | 44K CP/M (free memory with 56K CP/M) |
$1100-$A3FF | 0100H-93FFH | Free RAM |
$1000-$10FF | 0000H-00FFH | CP/M page zero |
CP/M Size | Language Card Usage |
---|---|
44K CP/M | does not use Language Card |
56K CP/M | uses Language Card, bank 2 only (TPA) |
60K CP/M | uses Language Card: bank 2 for TPA, bank 1 for parts of BDOS+BIOS |
Note that the Apple II hi-res graphics screens are situated right in the middle of the Softcard CP/M TPA. Hi-res graphics programming on SoftCard CP/M therefore requires special precautions. Microsoft GBASIC solves this by reserving an 8K large memory area, right in the middle of the Basic interpreter, for hi-res graphics.
Z80 addr 6502 addr ______________ ______________ 0000H |CP/M zero page| $1000 | | |______________| | | 0100H |CP/M TPA start| | | | | | | | | | | | | | | | | | | |______________| |______________| 1000H | | $2000 | | | | | | | | | Aux Hi-res | | CP/M TPA | | | | | | page 1X | | | | | | | | | |______________| |______________| 3000H | | $4000 | | | | | | | | | Aux Hi-res | | CP/M TPA | | | | | | page 2X | | | | | | | | | |______________| |______________| 5000H | | $6000 | | | | | | | CP/M TPA | | | | | | | | | | | | | | | ... ... | | | | | | | | | | | | | | | | | | | | |______________| | | 9400H | 44K BDOS | $A400 | | | starts here | | | | | | | | | | | | CP/M 56/60K | | | | TPA | | | | | | | | | | | | | | | | 44K BIOS end | | | AFFFH |______________| $BFFF |______________| ______________ B000H | | $D000 | || | | | | | | LC || LC | | | | | |bank 1||bank 2| | | | CP/M 56/60K | | || | | | | TPA | | 60K || Used | | | | | | BDOS+|| by | | | | | | BIOS || CP/M | | Applesoft | | | |______||______| | | C000H | | $E000 | | | BASIC | | | | | | | |______________| | | | ROM | C400H | 56K BDOS | $E400 | | | | | starts here | | | | | | | | Language | | | | | | | | | | | | Card | | | | | | | | | |______________| | | | | D400H | 60K BDOS | $F400 | | | | | starts here | | | |..............| D800H | | $F800 | | | Monitor | | 56K BIOS end | | | | ROM | |______________| |______________| |______________| DFFAH | 6502 vectors | $FFFA | 6502 vectors | | 6502 vectors | DFFFH |______________| $FFFF |______________| |______________| _____________ E000H $C000 | Motherboard | | I/O | |_____________| E090H $C090 | Slot I/O | | (DEVSEL) | |_____________| E100H $C100 | | | Slot CX ROM | | (IOSEL) | | | |_____________| E300H $C300 | Slot C3 ROM | | (IOSEL) | |_____________| E400H $C400 | | | | | Slot CX ROM | | (IOSEL) | | | | | | | |_____________| E800H $C800 | | | Slot ROM | | (IOSTROBE) | | | | shared | | between | | slots | EFFFH $CFFF |_____________| ______________ ______________ F000H | Unused by Z80| $0000 |6502 zero page| |______________| |______________| F100H | Unused by Z80| $0100 | 6502 stack | |______________| |______________| F200H | I/O cfg blk | $0200 | Keybd buff | | Device drvr | |______________| F300H | Patch area | $0300 | Page 3 | |______________| |______________| F400H | | | | | | | | | Text/lores GR| | Text/lores GR| | | | | | | | page 1 | | | | | | | | | |______________| |______________| F800H | | $0800 | | | | | Text/lores GR| | CP/M | | | | | | page 2 | | RWTS | |______________| FC00H | | $0C00 | | | | | | | | | | FFFFH |______________| $0FFF |______________|
Interrupts on the Z80 side are normally disabled. Setting DIP switches 1-3 and 1-4 to the ON position passes the NMI and IQR lines, respectively, to the Z-80
Because of the way the 6502 is “put to sleep” by the Z-80 SoftCard using the DMA line on the Apple bus, ALL interrupt processing must be handled by the 6502. An interrupt can occur at two times: while in Z-80 mode and while in 6502 mode:
Handling the interrupt in 6502 mode: handle the interrupt in the usual way: simply end the interrupt processing routine with an RTI instruction.
Handling the interrupt in Z-80 mode: both processors are interrupted when an interrupt occurs in Z-80 mode. Here is a step-by-step process for handling an interrupt while in Z-80 mode:
There are nine screen functions supported by Apple CP/M
The Backspace character (Ctrl-H, ASCII 8) is assumed to move the cursor backwards, and the Line Feed character (Ctrl-J, ASCII 10) is assumed to move the cursor down one line.
Screen function character sequences supported by Apple CP/M may be of two forms:
Screen function sequences longer than two characters are not supported
The internal format of each of the two 11-byte tables are identical. Below are listed the function number, the hexadecimal address and a description of each table entry.
Funct # | Software | Hardware | Description |
---|---|---|---|
0F396H | 0F3A1H | Cursor addr coordinate offset. Range 0-127. If hi bit is 0, the X/Y coordinates are expected to be transmitted Y first, X last. If high bit is 1, X first Y last is expected. | |
0F397H | 0F3A2H | Lead-in character, zero if no lead-in | |
Note: the following rules apply to the screen function table entries below: if the table entry is zero, the function is not implemented. If the entry has the high bit order set, the function requires a lead-in. An entry with the high order bit clear means the function does not require a lead-in. | |||
1 | 0F398H | 0F3A3H | Clear Screen |
2 | 0F399H | 0F3A4H | Clear to End of Page |
3 | 0F39AH | 0F3A5H | Clear to End of Line |
4 | 0F39BH | 0F3A6H | Set Normal (lo-line) Text Mode |
5 | 0F39CH | 0F3A7H | Set Inverse (hi-lite) Text Mode |
6 | 0F39DH | 0F3A8H | Home Cursor |
7 | 0F39EH | 0F3A9H | Address Cursor (see above) |
8 | 0F39FH | 0F3AAH | Move Cursor Up One Line |
9 | 0F3A0H | 0F3ABH | Non-destructively Move Cursor Forward |
The standard 24×40 Apple screen supports all nine function independent of the Hardware Screen Function Table. However if a Software Screen Function Table entry is zero, that function will be disabled.
The Hardware and Software Screen Function Tables can be examined and modified with the CONFIGIO program.
It is possible to write programs that use the information contained in these tables to perform screen functions. These programs would then work with ANY terminal, as long as the Hardware Screen Function Table was set up correctly - however such a program would work only on Apple SoftCard CP/M and not on any other CP/M system.
Keyboard redefinition take place only during input from the TTY: and CRT: devices. The Keyboard Character Redefinition Table will support up to six character redefinitions. The table is located at 0F3ACH from the Z-80. Entries in the table are two bytes: the first is the ASCII value of the character to be redefined, and the second is the redefined ASCII character. Both bytes must have their high bits cleared.
If there are less than six entries in this table, end end of the table is denoted by a byte with the high order bit set.
Modifications of the Keyboard Character Redefinition Table may be made
using the CONFIGIO
program.
The I/O Info Block also provides for support of non-standard Apple peripherals and I/O software. All the primitive character I/O functions are vectored through the I/O Vector Table within the I/O Config Block. These vectors normally point to the standard I/O routine located in the CP/M BIOS, but they can be altered by the user to point to his own drivers. Three blocks of 128 bytes each are provided within the I/O Config block for user I/O driver software:
Address | Assigned Slot | Assigned Logical Device |
---|---|---|
0F200H-0F27FH | 1 | LST: - line printer device |
0F280H-0FF7FH | 2 | PUN: and RDR: - general purpose I/O |
0F300H-0F37FH | 3 | TTY: - the console device |
Most Apple I/O interface cards have 6502 ROM drivers on the card. The easiest way to interface these types of cards to Apple CP/M is to write Z-80 code to call the 6502 subroutine on the ROM.
If no card is installed in a particular slot, its allocated 128-byte space can be used for other purposes relating to its assigned logical device. These include lower-case input drivers for Apple keyboard, cassette tape interface, etc.
I/O driver subroutines are patched to Apple CP/M by patching the appropriate I/O vector to point to the subroutine. A table of vector locations and their purposes is shown below:
Vec # | Addr | Vector Name | Description |
---|---|---|---|
1 | 0F380H | Console Status | Return 0FFH in A if char ready, 00H if not |
2 | 0F382H | Console Input #1 | Return char from console into A with |
3 | 0F384H | Console Input #2 | hi bit clear |
4 | 0F386H | Console Output #1 | Send ASCII char in C to |
5 | 0F388H | Console Output #2 | console device |
6 | 0F38AH | Reader Input #1 | Read char from “Paper Tape Reader” |
7 | 0F38CH | Reader Input #2 | device into A |
8 | 0F38EH | Punch Output #1 | Send char in C to “Paper Tape Punch” |
9 | 0F390H | Punch Output #2 | device |
10 | 0F392H | List Output #1 | Send char in C to |
11 | 0F394H | List Output #2 | “Line Printer” device |
Vec # | Addr SS BIOS | Addr PS IIe BIOS | Device |
---|---|---|---|
1 | 0F380H | 0F3C0H | Console status (no CP/M device) |
2 | 0F382H | 0F3C2H | Input TTY: = CRT: |
3 | 0F384H | 0F3C4H | Input UC1: |
4 | 0F386H | 0F3C6H | Output TTY: = CRT: |
5 | 0F388H | 0F3C8H | Output UC1: |
6 | 0F38AH | 0F3CAH | Input PTR: |
7 | 0F38CH | 0F3CCH | Input UR1: = UR2: |
8 | 0F38EH | 0F3CEH | Output PTP: |
9 | 0F390H | 0F3D0H | Output UP1: = UP2: |
10 | 0F392H | 0F3D2H | Output LPT: |
11 | 0F394H | 0F3D4H | Output UL1: |
Note: during console output, the B register contains a number corresponding to one of the nine supported screen functions during output of a screen function. B contains zero during normal character output. B is also non-zero during the output of the Cursor Address X/Y coords after executing screen function #7.
Assigning logical to physical I/O devices: the IOBYTE
IOBYTE at 0003H: | LIST | PUNCH | READER | CONSOLE | ||||
---|---|---|---|---|---|---|---|---|
bits: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
The value of each field can be in the range 0-3:
CONSOLE field (bits 0,1): | ||
---|---|---|
0 | TTY: device | |
1 | CRT: device | |
2 | BAT: | batch mode, uses RDR: for input and LST: for output |
3 | UC1: | User defined CONSOLE device |
READER field (bits 2,3): | ||
0 | TTY: device | |
1 | PTR: device | (“paper tape reader”) |
2 | UR1: | User defined READER device #1 |
3 | UR2: | User defined READER device #2 |
PUNCH field (bits 4,5): | ||
0 | TTY: device | |
1 | PTP: device | (“paper tape punch”) |
2 | UP1: | User defined PUNCH #1 |
3 | UP2: | User defined PUNCH #2 |
LIST field (bits 6,7): | ||
0 | TTY: device | |
1 | CRT: device | |
2 | LPT: device | (“line printer”) |
3 | UL1: | User defined LIST device |
Default device assignments are:
CON:
= CRT:
RDR:
= PTR:
PUN:
= PTP:
LST:
= LPT:
TTY:
Either the standard Apple screen/keyboard or an external
terminal installed in slot 3. This routine vectors through Console
Input #1 and Console Output #1. The Console status is always vectored
through the Console Status vector.
CRT:
Same as TTY:
UC1:
User defined console device. Vectored through Console Input #2 and
Console Output #2.
PTR:
A standard Apple interface capable of doing INPUT installed into
slot 2. If no card is plugged into slot 2, the PTR:
device always returns
a 1Ah end-of-file character. Input from the PTR:
device is vectored
through Reader Input vector #1. Characters are returned in the A register.
UR1:
User defined reader #1. A character read from this device is returned
in the A register.
UR2:
User defined reader #2. This device is physically the same as UR1:
.
PTP:
Any standard Apple interface capable of doing OUTPUT installed into
slot 2. If no card is plugged into slot 2, the PTP:
device does nothing.
Output to the PTP:
device is vectored through Punch Output vector #1.
UP1:
User defined punch #1. The character in register C is output
through Punch Output vector #2.
IP2:
User defined punch #2. This device is physically the same as UP1:
.
LPT:
The LPT:
device is any standard Apple interface card installed into
slot 1 capable of doing output. The character in register C is output
through the List Output vector #1.
UL1:
User defined list device. the character in register C is output via
List Output vector #2.
The IOBYTE
can be changed with the STAT
program, or it may be modified
from an assembly language program using the CP/M Get IOBYTE
and Set IOBYTE
(#7 & #8) functions.
User subroutines can be patched into the I/O Configuration Block with
the CONFIGIO
program. Any patches made can also be permanently saved
onto a CP/M system disk as well with CONFIGIO
.
To create a code file, use ASM to write the driver software,
and then use LOAD
to create a COM
file.
The code file loaded by CONFIGIO
must be of certain internal format.
Only one code segment may be patched into the I/O Configuration Block
per code file. However, as many vectors in the I/O Vector Table may be
patched as desired.
Below is outlined the format of a disk code file to be loaded with
CONFIGIO
and patched to the I/O Configuration Block:
First byte: | Number of patches to I/O Vector Table to be made |
Next 2 bytes: | Destination address of program code |
Next 2 bytes: | Length of program code |
Repeat for each I/O vector patch to be made: | |
Next byte: | Vector Patch type - either 1 or 2 |
If Vector Patch type = 1: | |
Next byte: | Vector number to be patched, 1-11 |
Next 2 bytes: | Address to be patched into the vector |
If Vector Patch type = 2: | |
Next byte: Vector number to be patched, 1-11 | |
Next 2 bytes: Address in which to place the current contents of the vector (may be the address field of a JMP , etc) | |
Next 2 bytes: | New address to be placed in the specified vector |
Next: | The actual program code is located after the patch information above. Convention restricts the size of the program code to 128 bytes per slot-dependent block. Use the block appropriate for your application and slot use. |
The 6502 is enabled from the Z-80 by a WRITE to the slot-dependent location 0EN00H, where N is the slot location of the Z-80 card. Z-80 mode is selected from 6502 mode with a WRITE to the same slot dependent location, which is addressed as $CN00 in 6502 mode. The location of the SoftCard will vary from system to system.
When the system is booted, the location of the SoftCard is determined by Apple CP/M and its address is stored in the I/O Configuration Block. This address is thus available to CP/M software for calling 6502 subroutines.
Calling the 6502 subroutine is a simple matter. Set up the address of the subroutine to be called, and then write to the address of the Z-80 SoftCard. One can also pass parameters to and from 6502 subroutines through the 6502 A, X, Y, P (Status) registers. The 6502 stack pointer is also available after a 6502 subroutine call.
Z-80 addr | 6502 addr | Purpose |
---|---|---|
0F045H | $45 | 6502 A register pass area |
0F046H | $46 | 6502 X register pass area |
0F047H | $47 | 6502 Y register pass area |
0F048H | $48 | 6502 P register pass area |
0F049H | $49 | Contains 6502 stack pointer on exit |
0F3DEH | Address of Z-80 Softcard here as 0EN00H | |
0F3D0H | Address of 6502 subroutine to be called stored here | |
$3C0 | Start address of 6502-to-Z80 mode switching routine. 6502 RESET, NMI and BREAK vectors point here. A JMP to this address puts the 6502 on “hold” and returns to Z-80 mode. |
$3C0 routine:
03C0: LDA $C083 ;Put Apple Language Card into read/write mode LDA $C083 STA SOFTCARD ;Enable SoftCard, disable 6502 START: LDA $C081 ;Enable Apple Monitor ROM JSR SET6502 ;Load the 6502 registers from $45 to $48 JSR ROUTINE ;Run the 6502 subroutine STA $C081 ;Make sure ROM is enabled SEI ;Disable 6502 interrupts JSR SAVE ;Store 6502 registers into $45 to $49 JMP $3C0 ;Loop back to beginning
Note: Locations $800-$FFF are used by the Apple CP/M disk drivers and buffers (“RWTS”) and are NOT available for use by a 6502 subroutine.
Language Card Users: When in Z-80 mode, the Language Card RAM is both read- and write-enabled. When a 6502 subroutine is called, the Apple on-board ROM is automatically enabled, making the Apple Monitor available to the 6502 subroutine. However the Language Card RAM is write-enabled during a 6502 call, i.e. a write to any location above $D000 will write in the Language Card RAM.
A side effect of read-enabling the on-board Apple ROM's is that the Z80 memory from 0C000H to 0EFFFH ($D000-$FFFF on 6502) cannot be READ by the 6502, unless the appropriate Language Card addresses can be accessed.
The first of the two available 4K banks in the Language Card is not used by 56K Apple CP/M.
The Card Type Table is located at 0F3B9H, and the entry for a given slot is located at 0F3B8H + S where S is an integer from 1 to 7. The contents are:
Value | Type |
---|---|
0 | No peripheral card ROM detected (usually there's no card here) |
1 | A peripheral card ROM of unknown type was detected |
2 | Apple Disk II Controller card |
3 | Apple Communications Card or CCS 7710A Serial Interface |
4 | Super Serial Card, or Videx Videoterm, or M&R SUp-R-Term or Apple Silentype interface card |
5 | Apple Parallell Printer Card |
6 | Firmware Card (SoftCard CP/M ver 2.23 and higher) |
The Disk Count Byte, located at 0F3B8H, is a single byte equal to the number of disk controller cards in the system times two. This value does not reflect an odd number of disk drives.
Each peripheral card has signature bytes at:
$Cn05 | $Cn07 | $Cn0B | $Cn0C |
Where n
is the slot number. Apple CP/M looks at $Cn05 and $Cn07
only. Versions 2.23 and later also inspects $Cn0B.
Card type | Signature Bytes | ||
---|---|---|---|
$Cn05 | $Cn07 | $Cn0B | |
Parallel Card | $48 | $48 | |
Communications Card | $18 | $38 | |
Super Serial Card | $38 | $18 | |
Disk Controller Card | $03 | $3C | |
Firmware Card | $01 |
The BIOS for the Microsoft Softcard 56K CP/M version 2.20B extends intp the Apple Language Card area but uses only bank 2 of the Language Card. The Language Card bank 1 is left unused.
All the logical device routines use the IOCB. The IOBYTE is used to determine which physical device is to be used. The address for that device is taken from the IOCB and a jump is made to that address.
Start | End | Use |
---|---|---|
DA00H | DA32H | BIOS vector jump tables |
DA33H | DA92H | Disk Parameter Headers for six drives |
DA93H | DAA1H | Disk Parameter Block |
DAA2H | DAC4H | Slot init routine, initializes communications and serial cards from slot 7 to slot 7. The ACIA is set to 7 data bits, even parity, 2 stop bits, xmit interrupts enabled |
DAC5H | DACBH | Routine to place En00H in HL where n = slot # passed in E |
DACCH | DB07H | WBOOT routine: Init SP Call warm loader at $E00 Init slots Init CP/M BDOS zero page Patch CCP for 2-column or 4-column DIR DAFDH = 1 for 2 cols, 3 for 4 cols Jmp to CCP at accress C400H |
DB08H | DB0BH | CONST - Console Status from IOCB at F380H |
DB0CH | DB11H | CONST routine for Apple keyboard |
DB12H | DB28H | CONIN - Console Input routine Call input char routine at DB50H Check against redefinition table at F3ACH Return with translated char in A |
DB29H | DB3AH | Default address in IOCB for console input Set DE to 3 for slot 3 If 80-col card in slot 3, patch next jump to appropriate routine If no 80-col card, go to Apple kdb input at DB2FH |
DB3BH | DB41H | Routine to set up and make call to the 6502. On entry HL contains 6502 program address |
DB42H | Routine to place A into C and fall into CONOUT | |
DB43H | DB4FH | CONOUT Checks the IOBYTE for the output device then jumps to the selected routine. |
DB50H | DB61H | Character input routine, checks IOBYTE then goes to the selected routine |
DB62H | DB65H | A jump to the physical PTR: device. May be used by the console input or logical RDR: device |
DB66H | DB74H | LIST The logical LST: device routine, checks IOBYTE then goes to the selected routine |
DB75H | DB86H | PUNCH The logical PUN: device, checks IOBYTE then goes to the selected routine |
DB87H | DB95H | READER The logical RDR: device, checks IOBYTE then goes to the selected routine |
DB96H | DBB7H | A routine for 80-column cards. Conditions the memory locations and looks to see if an escape sequence is coming. Control is passed to routines to perform specific functions depending on how the output is to be performed. |
DBB8H | DBDFH | Routine to position the cursor in the GOTOXY sequence |
DBE0H | DBF4H | Routine that checks to see if there was a terminal lead-in character sent and calls routines as requires |
DBF5H | DC3DH | Routine that considers all the possible combinations and finally prints the character to the console via physical devices TTY: or UC1: as required |
DC3EH | DC43H | Physical TTY: device. This is the general console output routine. THe jump address to the specific output routine is patched during the cold boot. Since the output routines are slot-dependent, the slot number of the console is supplied in location DC3FH. The slot number here is 3. |
DC44H | DCDEH | Screen output routine for the standard 40-column Apple screen. This is the routine patched into the former routine if no serial or 80-column card is found in slot 3. |
DCDFH | DCE9H | The comm card output routine. A status loop runs, and when ACIA is ready, character in C register is transmitted. |
DCEEH | DD03H | Preparatory routine for setting up a serial card for either input or output. |
DD04H | DD11H | The serial card output routine, performed by calling the 6502 |
DD12H | DD1BH | The comm card input routine. Resembles the output routine in structure. |
DD1CH | DD2AH | Serial card input routine. |
DD2BH | DD30H | Physical LPT: device output function. Jump is made to card driver routine. Jump address is loaded during cold boot and depends on card type in slot 1. Since the card routines are slot dependent, this routine supplies the slot number in location DD2CH |
DD31H | DD3EH | Parallell card output routine |
DD3FH | DD44H | Physical PTP: device output function. Jump is made to card driver routine. Jump address is loaded during cold boot and depends on card type found in slot 2. |
DD45H | DD4CH | Physical PTR: device output function. Jump to card drive routine. Jump address is loaded during cold boot and depends on card type found in slot 2. |
DD4BH | DD55H | HOME A disk routine to select track 0 |
DD56H | DD5AH | SETTRK A disk routine to select the track in register C |
DD5BH | DD6CH | A computational routine used by the peripheral card drivers and disk I/O routines to get needed slot and memory addresses and the numbers passed to them from the physical device routines |
DD6DH | DD88H | SELDSK Select the disk drive and set flags to notify the disk I/O routines if the drive has been changed or a nonexistent drive was called |
DD89H | DD8DH | SETSEC Select the 128-byte CP/M sector |
DD8EH | DD92H | SETDMA Select the disk I/O buffer accress |
DD93H | DDA2H | READ Set up the disk read operation according to all the CP/M protocols |
DDA3H | DDF1H | WRITE Perform the disk write operation using CP/M protocols |
DDF2H | DE72H | Used by both READ and WRITE to make sure the CP/M protocols are met. A sector skew is done with the CP/M sector skew table. The data is moved to or from the CP/M RWTS buffer at $800. The read or write operation is then called. |
DE73H | DE91H | Do the actual read or write by calling the 6502 CP/M RWTS |
DE92H | DEA1H | The CP/M logical sector skew table, which relates the 256-byte sector number to the logical 128-byte sector number used by CP/M. |
F200H | F37FH | The I/O Patch area: space for user provided routines required for special I/O situations. The IOCB must be patched to vector the device I/O to the routines in this area. |
F380H | F395H | IOCB containing the vectors to the CP/M physical devices |
F396H | F3AAH | Table used by the console routines to perform console functions. Can be adapted to a variety of terminals. |
F3C0H | F3FFH | Space used by the Apple Monitor ROM to vector the interrupts and resets. The vectors under CP/M all points to $3C0, so the Z-80 never loses control of the Apple. |
F800H | F900H | The data buffer used by the CP/M RWTS |
FA00H | FFFCH | The CP/M RWTS routines, written in 6502 assembly |
On Apple II SoftCard CP/M systems, the Standard CP/M utilities MOVCPM and SYSGEN are missing. Instead we have CPM56.COM on 56K CP/M systems. Patches are most easily stored on the system tracks by patching a copy of CPM56.COM and then running it to store the patched system on the system tracks.
The program CPM56.COM contains the entire 56K CP/M system image. It's easiest to modify the BIOS by making modifications to CPM56.COM and then running it to put the image on the system tracks of a disk. Below is a mapping of the CPM56.COM program when loaded in memory by DDT
Start | End | Use |
---|---|---|
100H | 2FFH | The command portion of CPM56.COM |
300H | 3FFH | The boot 1 portion: loads from track 0 sector 0 and is responsible for loading the CP/M RWTS sectors into the memory range $A000-$FFF and the boot 2 portion into the range $1000-$13FF. |
400H | 9FFH | The CP/M RWTS |
A00H | BFFH | The boot 2 |
C00H | D7FH | The I/O Patch area, which gets moved by boot 2 to F200H-F37FH |
D80H | The IOCB console status vector | |
D82H | The IOCB console input vector 1, or the TTY: device | |
D84H | The IOCB console input vector 2, or the UC1: device | |
D86H | The IOCB console output vector 1, or the TTY: device | |
D88H | The IOCB console output vector 1, or the UC1: device | |
D8AH | The IOCB reader vector 1, or the PTR: device | |
D8CH | The IOCB reader vector 2, or the UR1: device | |
D8EH | The IOCB punch vector 1, or the PTP: device | |
D90H | The IOCB punch vector 2, or the UP1: device | |
D92H | The IOCB list vector 1, or the LST: device | |
D94H | The IOCB list vector 2, or the UL1: device | |
D96H | DFFH | The console hardware and software definition tables and the remainder of page 3 routines and vectors. The data in the range D80H-DFFH gets moved by boot 2 to F380H-F3FFH |
E00H | 15FFH | The CCP |
1600H | 23FFH | The BDOS |
2400H | 29A7H | The BIOS |
29A8H | 29E7H | The cold boot routine |
29E8H | 29FFH | Patches required for 2.20B to run a turnkey and correct a disk read/write problem |
The Apple CP/M diskette system tracks are mapped as follows:
Start | End | |||
---|---|---|---|---|
Trk | Sec | Trk | Sec | Use |
00H | 00H | Boot 1 sector | ||
00H | 01H | 00H | 06H | CP/M RWTS |
00H | 07H | 00H | 08H | Boot 2 routine |
00H | 09H | 00H | 0AH | I/O Patch Area, page F300H routines+tables |
00H | 0BH | 01H | 02H | CCP |
01H | 03H | 02H | 00H | BDOS |
02H | 01H | 02H | 06H | BIOS |
CP/M RWTS sectors are used in this table
A list of entry points to the peripheral card drivers is useful for BIOS patching:
Addr | Entry Point |
---|---|
DCDFH | Communications Card output routine |
DD04H | Serial Card output routine |
DD12H | Communications Card input routine |
DD1CH | Serial Card input routine |
DD31H | Parallel Card output routine |
ALl these enty points require that DE contains the card slot number upon entry. The A and C registers are used as required by the CP/M protocols.
THe Microsoft 2.20B BIOS uses some ungainly fixes to correct a few problems, but still a few problems remain in the area of hardware interfacing. Most of these problems are corrected in the SoftCard 2.23 BIOS.
The hardware interfacing is greatly improved because version 2.23 uses Apple Computer's protocols for operating what Apple calls Firmware Cards. Most of the cards that can operate a host of peripheral devices and have them do all sorts of neat tricks are Firmware Cards. Version 2.20B could not identify Firmware Cards and would often use the wrong I/O drives. This caused a grinding of teeth by those unfortunates who invested in expensive equipment and could not get it to operate under CP/M. Version 2.23 will operate the Firmware Cards, if the card manufacturer followed the Apple protocols.
Another improvement in 2.23 is that the BIOS Comm Card driver uses the 6502 instead of the Z-80 to access the ACIA. The Z-80 has a memory refresh provision, which causes the address to be accessed to be preread before the actual reading or writing occurs. Reading the data port on an ACIA clears the ACIA status flags, which means the data can disappear before a second read is made. You can lose data when the ACIA is read by the Z-80; using the 6502 instead eliminates this problem.
The 60K 2.23 BIOS has a bigger TPA than the 56K 2.20B verison because both 4K banked memories in the Language Card are used. Version 2.23 uses bank 1 to store the BIOS disk-handling routines, which include the 6502 CP/M RWTS, the Z-80 BIOS routines, and two-thirds of the BDOS, which leaves bank 2 available for program memory.
Start | End | Use |
---|---|---|
F200H | F37FH | The I/O Patch area: space for user provided routines required for special I/O situations. The IOCB must be patched to vector the device I/O to the routines in this area. |
F380H | F395H | IOCB containing the vectors to the CP/M physical devices |
F396H | F3AAH | Table used by the console routines to perform console functions. Can be adapted to a variety of terminals. |
$3C0 | $3DA | Routine which calls the 6502 microprocessor |
$3F0 | $3FF | Space used by the Apple Monitor ROM to vector the interrupts and resets. The vectors under CP/M all points to $3C0, so the Z-80 never loses control of the Apple. |
$800 | $900 | Default I/O buffer area used by the CP/M RWTS |
$900 | $9FF | A nibble buffer used by the CP/M RWTS |
FA00H | FA32H | BIOS vector jump tables |
FA33H | FA92H | Disk Parameter Headers for six drives |
FA93H | FAA1H | Disk Parameter Block |
FA82H | FAB0H | Slot init routine, initializes communications and serial cards from slot 7 to slot 7. The ACIA is set to 7 data bits, even parity, 2 stop bits, xmit interrupts enabled |
FAB1H | FAB7H | Routine to place En00H in HL where n = slot # passed in E |
FAB8H | FB0FH | WBOOT routine: Init SP Call warm loader at $E00 Init slots Init CP/M BDOS zero page Patch CCP for 2-column or 4-column DIR FB05H = 1 for 2 cols, 3 for 4 cols Jmp to CCP at accress E400H |
FB10H | FB13H | CONST - Console Status from IOCB at F380H |
FB14H | FB19H | CONST routine for Apple keyboard |
FB1AH | FB32H | CONIN - Console Input routine Call input char routine at FB5AH Check against redefinition table at F3ACH Return with translated char in A |
FB33H | FB38H | Default address in IOCB for console input Set DE to 3 for slot 3 If 80-col card in slot 3, patch next jump to appropriate routine If no 80-col card, go to Apple kdb input at FB39H |
FB45H | FB4BH | Routine to set up and make call to the 6502. On entry HL contains 6502 program address |
FB4CH | Routine to place A into C and fall into CONOUT | |
FB4DH | FB59H | CONOUT Checks the IOBYTE for the output device then jumps to the selected routine. |
FB5AH | FB6BH | Character input routine, checks IOBYTE then goes to the selected routine |
FB6CH | FB6FH | A jump to the physical PTR: device. May be used by the console input or logical RDR: device |
FB70H | FB7EH | LIST The logical LST: device routine, checks IOBYTE then goes to the selected routine |
FB7FH | FB90H | PUNCH The logical PUN: device, checks IOBYTE then goes to the selected routine |
FB91H | FB9FH | READER The logical RDR: device, checks IOBYTE then goes to the selected routine |
FBA0H | FBCAH | A routine for 80-column cards. Conditions the memory locations and looks to see if an escape sequence is coming. Control is passed to routines to perform specific functions depending on how the output is to be performed. |
FBCBH | FBF1H | Routine to position the cursor in the GOTOXY sequence. The routine jumps to FCA4H. Routines required for the functioning of the routine at FBA0H are also placed out of sequence compared to ver 2.20B and start at address FC56H. This displacement is required so that room for a nibble buffer used by the RWTS can be located at $C00 |
FBF4H | FBF8H | SETSEC Select the 128-byte CP/M sector |
FBF9H | FBFDH | SETDMA Select the disk I/O buffer accress |
$C00 | $C55 | One of the CP/M RWTS nibble buffers |
FC56H | FC6AH | Routine that checks to see if there was a terminal lead-in character sent and calls routines as requires |
FC6BH | FCB4H | Routine that considers all the possible combinations and finally prints the character to the console via physical devices TTY: or UC1: as required |
FC5BH | FCBAH | Physical TTY: device. This is the general console output routine. The jump address to the specific output routine is patched during the cold boot. Since the output routines are slot-dependent, the slot number of the console is supplied in location DC3FH. The slot number here is 3. |
FCBBH | FD0DH | Screen output routine for the standard 40-column Apple screen. This is the routine patched into the former routine if no serial or 80-column card is found in slot 3. |
FD0EH | FD27H | The comm card output routine, using 6502 code. A status loop runs; when ACIA is ready, character in C register is transmitted. |
FD28H | FD70H | Screen function routines, located in the BIOS out of sequence compared to version 2.20B |
FD71H | FD82H | The serial card output routine, performs the output by calling the 6502 |
FD83H | FD98H | Preparatory routine for setting up a serial card for either input or output. |
FD99H | FDA8H | Console status routine for a Firmware Card, which calls a 6502 routine for operation |
FDA9H | FDB6H | Firmware Card output routine, calls a 6502 routine for operation |
FDB7H | FDC0H | Firmware Card input routine, calls 6502 code at $E0F |
FDC1H | FDCFH | Serial card input routine. |
$DD0 | $DE0 | Firmware Card initialization routine, followed by a routine that uses the Apple protocol for firmware I/O |
$DE1 | $DEE | Firmware Card output routine |
$DEF | $DFA | Firmware Card routine which waits for card to accept I/O |
$E00 | $E02 | CP/M entry to the warm loader routine |
$E03 | $E08 | Entry to CP/M RWTS routine on Language Card bank 1 |
$E09 | $E0E | Second entry to warm loader routine on bank 1 of Lang Card |
$E0F | $E1C | Firmware Card input routine |
$E1D | $E25 | Firmware Card routine to obtain the card's I/O status |
$E26 | $E3E | Sets up all parameters used by the Firmware Card protocol and set up the coresident ROM area at $C800 to be ready for the Firmware Card's requirements |
$E3F | $E4A | Called by the routine at $3C0 to set all the 6502 registers and flags from their respective memory areas. The 6502 interrupt is also enabled |
FE48H | FE54H | The comm card input routine. Resembles the output routine in structure. |
FE55H | FE5AH | Physical LPT: device output function. Jump is made to card driver routine. Jump address is loaded during cold boot and depends on card type in slot 1. Since the card routines are slot dependent, this routine supplies the slot number in location DD2CH |
FE5BH | FE68H | Parallell card output routine |
FE69H | FE6EH | Physical PTP: device output function. Jump is made to card driver routine. Jump address is loaded during cold boot and depends on card type found in slot 2. |
FE6FH | FE74H | Physical PTR: device output function. Jump to card drive routine. Jump address is loaded during cold boot and depends on card type found in slot 2. |
FE75H | FE7FH | HOME A disk routine to select track 0 |
FE80H | FE84H | SETTRK A disk routine to select the track in register C |
FE85H | FE96H | A computational routine used by the peripheral card drivers and disk I/O routines to get needed slot and memory addresses and the numbers passed to them from the physical device routines |
FE97H | FEC5H | SELDSK Select the disk drive and set flags to notify the disk I/O routines if the drive has been changed or a nonexistent drive was called |
FEC6H | FECBH | READ Entry point to the disk read routine found on bank 1 of the Language Card |
FECCH | FED1H | WRITE Entry point to the disk write routine found on bank 1 of the Language Card |
FED2H | FED8H | Called when the 6502 must be called by code on bank 1 |
FED9H | FEDFH | Called when a disk I/O error is encountered by disk-handling code on bank 1. Bank 2 is sswitched back on, and the BDOS error routine is called |
FEE0H | FEE3H | Bank 1 routines returns here, bank 2 is turned back on |
$FFAC | $FFE8 | CP/M RWTS prenibblizing routines, located above BDOS in memory and doesn't neatly fit into this memory map. Microsoft had to put it here to fit the second segment of BDOS on bank 1 of the Language Card. Version 2.23 gets choppy from here on. |
The following are located on bank 1 of the Langauge Card
Start | End | Use |
---|---|---|
$D000 | $D246 | The first segment of the CP/M RWTS. The RWTS is split into two segments for reasons known only to Microsoft. |
B247H | B256H | The disk read operation, set up according to the CP/M protocols |
B257H | B270H | The disk write operation, performed according to CP/M protocols |
B271H | B333H | Used by both READ and WRITE to make sure the CP/M protocols are met. A sector skew is done with the CP/M sector skew table. The data is moved to or from the CP/M RWTS buffer at $800. The read or write operation is then called. |
B334H | B358H | Do the actual read or write by calling the 6502 CP/M RWTS |
B359H | B368H | The CP/M logical sector skew table, which relates the 256-byte sector number to the logical 128-byte sector number used by CP/M. |
$D369 | $D5BC | The second segment of the CP/M RWTS |
B5C0H | BFFFH | The second BDOS segment. This is not the BIOS, but is included for completeness. |
On Apple II SoftCard CP/M systems, the Standard CP/M utilities MOVCPM and SYSGEN are missing. Instead we have CPM60.COM on 60K CP/M systems. Patches are most easily stored on the system tracks by patching a copy of CPM60.COM and then running it to store the patched system on the system tracks.
The program CPM60.COM contains the entire 60K CP/M system image. It's easiest to modify the BIOS by making modifications to CPM60.COM and then running it to put the image on the system tracks of a disk. Below is a mapping of the CPM60.COM program when loaded in memory by DDT
Start | End | Use |
---|---|---|
100H | 3FFH | The command portion of CPM60.COM |
400H | 4FFH | The boot 1 portion: loads from track 0 sector 0 and is responsible for loading the CP/M RWTS sectors into the memory range $A000-$FFF, loading boot 2 into $1000-$12FF, and loading the $300-page area into $1300-$13FF |
500H | 746H | The first segment of the CP/M RWTS |
747H | 858H | The BIOS read/write portions of the disk handling routines |
859H | AFFH | The second segment of the CP/M RWTS |
B00H | CFFH | The boot 2 |
D00H | E7FH | The I/O Patch area, which gets moved by boot 2 to F200H-F37FH |
E80H | The IOCB console status vector | |
E82H | The IOCB console input vector 1, or the TTY: device | |
E84H | The IOCB console input vector 2, or the UC1: device | |
E86H | The IOCB console output vector 1, or the TTY: device | |
E88H | The IOCB console output vector 1, or the UC1: device | |
E8AH | The IOCB reader vector 1, or the PTR: device | |
E8CH | The IOCB reader vector 2, or the UR1: device | |
E8EH | The IOCB punch vector 1, or the PTP: device | |
E90H | The IOCB punch vector 2, or the UP1: device | |
E92H | The IOCB list vector 1, or the LST: device | |
E94H | The IOCB list vector 2, or the UL1: device | |
E96H | EFFH | The console hardware and software definition tables and the remainder of page 3 routines and vectors. The data in the range D80H-DFFH gets moved by boot 2 to F380H-F3FFH |
F00H | 17FFH | The CCP |
1800H | 1BFFH | The non-Language Card BDOS segment plus the prenibblizing CP/M RWTS routines |
1C00H | 26FFH | The Language Card segment of BDOS |
2700H | 2BE9H | The BIOS |
2BEAH | 2BFFH | The cold boot routine |
The Apple CP/M diskette system tracks are mapped as follows:
Start | End | |||
---|---|---|---|---|
Trk | Sec | Trk | Sec | Use |
00H | 00H | Boot 1 sector | ||
00H | 01H | 00H | 06H | CP/M RWTS and Z-80 BIOS disk routines |
00H | 07H | 00H | 08H | Boot 2 routine |
00H | 09H | 00H | 0AH | I/O Patch Area, page F300H routines+tables |
00H | 0BH | 01H | 03H | CCP |
01H | 04H | 01H | 07H | First segment of BDOS |
01H | 08H | 02H | 02H | Second segment of BDOS |
02H | 03H | 02H | 03H | BIOS |
CP/M RWTS sectors are used in this table.
A list of entry points to the peripheral card drivers is useful for BIOS patching:
Addr | Entry Point |
---|---|
FD0EH | Communications Card output routine |
FD71H | Serial Card output routine |
FDA9H | Firmware Card output routine |
FDB7H | Firmware Card input routine |
FDC1H | Serial Card input routine |
FE4BH | Communications Card input routine |
FE5BH | Parallell Card output routine |
All these enty points require that DE contains the card slot number upon entry. The A and C registers are used as required by the CP/M protocols.
Correct bug which exchanges the PTP: and UP1: devices (usually unnoticed because they by default point to the same device): Modify 2581 from 20 to 28
DDT CPM56.COM #S2581 2581 20 (type 28) . #<Ctrl-C> SAVE 42 CPM56.COM CPM56 A:
Correct bug with Apple IIe 80-column card: ever warm boot the screen is cleared, since the BIOS initializes all peripheral cards on each warm boot: remove call to initialization routine in warm boot routine.
Addr Old New 24D8 CD 00 24D9 A2 00 24DA DA 00
An error in RDR: vectoring was introduced, and the Apple IIe warm boot problem is present as well. Change the following locations in CPM60.COM
Addr Old New 0EF4 A6 00 (corrects the IIe warm boot problem) 27C4 CD 00 27C5 82 00 27C6 DA 00 2897 08 04 (corrects the RDR: vector problem) SAVE 44 CPM60.COM CPM60 A:
Written in 6502 code, resides at $800 - $FFF including buffers. Entry point at $E03 (for BIOS ver 2.20B and 2.23) – before entry these addresses below must be filled with appropriate data. The CP/M RWTS use a 256-byte data buffer at $800 by default.
To call the CP/M RWTS from your own code, init the following memory areas before calling $E03:
$3E0 | Place track to be accessed here |
$3E1 | Place CP/M physical sector to be accessed here. The Apple sector numbers range from $0 to $F. The sector skew for CP/M physical sectors is used |
$3E1-$3E3 | Holdovers from the DOS 3.3 RWTS and were used for volume numbers. CP/M RWTS doesn't use volume numbers, so put $00 here |
$3E4 | Put the drive here. DOS 3.3 numbers are used, so put 1 or 2 here |
$3E5 | Another holdover from DOS 3.3 - put last drive used here |
$3E6 | Put the slot number times 16 here. Slot 6 =⇒ put $60 here |
$3E7 | Last slot (times 16) accessed. Slot 6 =⇒ $60 |
$3E8-$3E9 | I/O buffer address (256 bytes). If buffer is at $800, then $3E8 contains $00 and $3E9 contains $08 |
$3EA | Error code: $00 no error, $10 write protected, $40 drive error(the CP/M RWTS stores the error code here) |
$3EB | Command code: $01 read sector, $02 write sector |
$800-$900 | Default I/O buffer area used by the CP/M RWTS |
$900-$9FF | A nibble buffer used by the CP/M RWTS |
CP/M version 2.23 always reinitializes the I/O buffer address to $800 before using the CP/M RWTS. CP/M version 2.20B doesn't reinitialize the I/O buffer address, so the programmer must restore it to $800 if needed after having called the CP/M RWTS.
The CP/M warm loader is located at $E00 for ver 2.20B and 2.23. CP/M 2.23 60K reads track $0 sector $B to track $2 sector $8 to memory starting at D300H. CP/M 2.20B 56K reads track $0 sector $B to track $2 sector $0 to memory starting at C400H.
The first 3 tracks, tracks $00 to $02, are reserved for the boot routine, the CCP, BDOS and BIOS. Track $03 contain the CP/M directory, where only 6 physical sectors contains the directory (CP/M logical sectors 00H through 0BH).
SoftCard CP/M ver 2.23 and higher uses a trick to allow the system tracks for data storage: a file called cp/m.sys is created in user area 31 as a dummy file allocated to the system tracks. It is inaccessible from the CCP and unseen by the user. The BIOS is written to recognize the system tracks as accessible data areas. COPY.COM has an option to create a “data diskette” where cp/m.sys is absent, which creates 3 more tracks for data storage. Such a diskette cannot be warm booted, bit it is safe to use it in any other drive than A:
Sectors | |||
---|---|---|---|
CP/M Logical | CP/M Physical | DOS 3.3 | Apple Physical |
00,01 | 0 | 0 | 0 |
02,03 | 9 | 6 | 3 |
04,05 | 3 | C | 6 |
06,07 | C | 3 | 9 |
08,09 | 6 | 9 | C |
0A,0B | F | F | F |
0C,0D | 1 | E | 2 |
0E,0F | A | 5 | 5 |
10,11 | 4 | B | 8 |
12,13 | D | 2 | B |
14,15 | 7 | 8 | E |
16,17 | 8 | 7 | 1 |
18,19 | 2 | D | 4 |
1A,1B | B | 4 | 7 |
1C,1D | 5 | A | A |
1E,1F | E | 1 | D |
Apple CP/M has double sector skewing: the system tracks use CP/M physical sector skew while the data tracks uses the logical sector skew. The CP/M physical sector skew is fastest for reading sectors, while the logical sector skew is a compromise for getting the fastest sector read skew in conjunction with the fastest sector write skew.
The CP/M BIOS contains several Disk Parameter Tables:
DPH - Disk Parameter Header: a pointer to the DPH for a specific disk is obtained by loading C with the disk drive (0=A:, 1=B:, etc) and then call the BIOS function SELDSK (entry point at xx1BH, where xx00H is your BIOS base where xx is found at address 0002H of your CP/M system). The disk drive need not have any disk inserted, since the BIOS SELDSK function only locates the tables but does not attempt to access the disk. When SELDSK returns, HL points to the DPH, which contains:
Offset | Contents | Use |
---|---|---|
00H | XLT | Addr of logical-to-physical sector translation vector. On Apple CP/M, XLT is 0000H, which means that the CP/M BIOS does no such translation - instead sector skewing is implemented in the CP/M RWTS, which is written in 6502 code. |
02H | 0000H | Scratchpad values for use within BDOS |
04H | 0000H | Scratchpad values for use within BDOS |
06H | 0000H | Scratchpad values for use within BDOS |
08H | DIRBUF | Addr of scratchpad 128-byte directory buffer. |
0AH | DPB | Addr of Disk Parameter Block for this drive, see below. |
0CH | CSV | Addr of scratchpad area to check for changed disks |
0EH | ALV | Addr of scratchpad area for disk allocation info |
DPB - Disk Parameter Block. The address of the DPB can be found in either the DPH (see above), or by calling BDOS function 31 (=1FH) “Get addr disk params”, which will return the address of the DPB for the current drive in HL. If you want the DPB for a specific drive, first call BDOS function 14 (=0EH) “Select disk”, with the drive to select in E on entry (0=A:, 1=B:, etc) - note that the drive must have a valid CP/M disk inserted for this to work.
The Disk Parameter Block (DPB) for each drive type contains:
Offset | Contents | Use |
---|---|---|
00H | SPT 16b | Total number of 128-byte sectors per track |
02H | BSH 8b | Data allocation block shift factor, determined by the data block allocation size 3 → 1K, 4 → 2K, 5 → 4K, … |
03H | BLM 8b | Data allocation block mask (2[BSH-1]) 7 → 1K, 0FH → 2K, 01FH → 4K, … |
04H | EXM 8b | Extent mask, determined by data block allocation size and number of disk blocks |
05H | DSM 16b | Total storage capacity of disk drive, blocks minus one |
07H | DRM 16b | Total number of directory entries minus one |
09H | AL0 8b | Directory allocation bitmap, byte 0. |
0AH | AL1 8b | Directory allocation bitmap, byte 1. |
0BH | CKS 16b | Size of directory check vector |
0DH | OFF 16b | No of reserved tracks at beginning of logical disk |
BSH and BLM are determined by BLS, the block size or data allocation size
BLS | BSH | BLM | EXM | |
---|---|---|---|---|
DSM<256 | DSM>=256 | |||
1024 | 3 | 7 | 0 | n/a |
2048 | 4 | 15 | 1 | 0 |
4096 | 5 | 31 | 3 | 1 |
8192 | 6 | 63 | 7 | 3 |
16384 | 7 | 127 | 15 | 7 |
i.e.:
BLS = 2**n where n = 10 to 14
BSH = n-7
BLM = 2**BSH - 1
EXM = 2**(BHS-2) - 1 if DSM<256
EXM = 2**(BHS-3) - 1 if DSM>=256
DSM = maximum data block number supported by this particular drive, measured in BLS (Block Size) units, or simply “number of allocation blocks on drive”. Blocks are counted from 0 to DSM, and thus BLS*(DSM+1) = the number of bytes on the drive (excluding the system tracks). If DSM<256, the disk map in the directory entry of the file will be 1 byte/block. If DSM>=256 it will be 2 bytes/block.
DRM = total number of directory entries minus one.
AL0/AL1 = the directory allocation vector. Consider it a bit map of bits 16 bits, bit 0-15, where 0=hi bit of AL0, 7=lo bit of AL0, 8=hi bit of AL1, 15=lo bit of AL1. Bits are assigned starting at bit 0 up until bit 15. Suppose nbits is the number of bits set to 1:
BLS | Directory entries |
---|---|
1024 | 32 * nbits |
2048 | 64 * nbits |
4096 | 128 * nbits |
8192 | 256 * nbits |
16384 | 512 * nbits |
Example:
AL0 | AL1 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Value | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
If DRM=127 (128 directory entries) and BLS=1024 bytes, there are 32 directory entries per block, requiring 4 reserved blocks. Thus the 4 hi bits if AL0 are set, and AL0=0FH, AL1=00H
CKS = size of directory check vector If drive media is removable, then CKS = (DRM+1)/4 If drive media is fixed, then CKS=0 (no dir records checked)
OFF = number of reserved tracks. This value is automatically added whenever SETTRK is called. It can be used to skip reserved system tracks, or for partitioning a large disk into smaller segmented sections.
Several DPH's can address the same DPB if the drive characteristics are identical. The DPB can be dynamically changed when a new drive is addressed by simply changing the pointer in the DPH since the BDOS copies the DPB values to a local area whenever the SELDKS function is invoked.
The size of the CSV (scratchpad area to check changed disks) is CKS bytes. If CKS=(DRM+1)/4, this area must be reserved. If CKS=0, no storage is reserved.
The size of the ALV (scratchpad area for disk storage allocation info) is (DSM/8)+1 bytes where DSM is the disk size in allocation blocks.
Below DPB parameters are given for three different kinds of Apple CP/M formats, plus the Standard CP/M 8“ SSSD disk format as a comparison:
A: The SoftCard 13-sector Apple CP/M format, used only briefly on early SoftCard CP/M systems. No other Apple CP/M card ever used the 13-sector format. This format yielded 104K of data per diskette, excluding the system tracks.
B: The 16-sector Apple CP/M format. This was THE Apple CP/M disk format, introduced by the SoftCard and subsequently used by all other Apple CP/M systems (Appli-Card, CP/M Card, Premium SoftCard). This format yields 128K of data per diskette, excluding the system tracks.
The Apple CP/M disk formats were really too small, since the Standard CP/M 8” SSSD disk format yielded 243K of data per diskette, and many CP/M programs assumed a disk at least this big. One enhancement was to use 40 tracks instead of 35 tracks on the diskette, which would yield 148K of data per diskette, excluding the system tracks. Later, when 80-track double-sided disk drives became available, CP/M could fairly easily be modified to accept these drives. The hardest parts were to hook up the hardware, and modify the CP/M RWTS program to access all 80 tracks on both sides, and the formatter program to format 80 tracks on both sides. But once this was accomplished, it was fairly straight-forward to modify the BIOS DPH so that CP/M could access the entire 80-track double-sided disk as one disk, yielding 628K of data per diskette, making virtually any CP/M program comfortably fitting on one diskette.
C: This disk format is 16 sectors/track, 80 tracks double sided, where the tracks and sides are mapped within the modified CP/M RWTS so they appear as 160 tracks to the CP/M Z-80 BIOS (which knew nothing about double-sided disks). This format yields 628K of data per diskette, excluding the system tracks.
D: As a comparison, the DPB parameters for the Standard CP/M 8“ SSSD format is given. This disk format had 128 bytes/sector on the disk.
Physical format: | A | B | C | D |
---|---|---|---|---|
Apple CP/M | Enhanced CP/M | Standard CP/M |
||
13-sect | 16-sect | 80-trk 16-sec 2-side | 8” SSSD | |
Bytes/sector | 256 | 256 | 256 | 128 |
Sectors/track | 13 | 16 | 16 | 26 |
Tracks | 35 | 35 | 80 | 77 |
Heads | 1 | 1 | 2 | 1 |
Sector skew table:
Apple CP/M DPB - Disk Parameter Block
A | B | C | D | ||
---|---|---|---|---|---|
Apple CP/M | Enhanced CP/M | Standard CP/M | |||
SPT 16b | 26 | 32 | 32 | 26 | 128-byte Logical Sectors/Track |
BSH 8b | 3 | 3 | 4 | 3 | Block shift factor |
BLM 8b | 7 | 7 | 15 | 7 | Block shift mask |
EXM 8b | 0 | 0 | 0 | 0 | Extent mask |
DSM 16b | 103 | 127 | 313 | 242 | Disk size - 1 (in blocks) |
DRM 16b | 47 | 63 | 255 | 63 | Directory mask = dir entries - 1 |
AL0 8b | 0C0H | 0C0H | 0F0H | 0C0H | Dir Alloc 0 |
AL1 8b | 0 | 0 | 0 | 0 | Dir Alloc 1 |
CKS 16b | 12 | 16 | 64 | 16 | Directory check vector size |
OFF 16b | 3 | 3 | 3 | 2 | Track offset: # system tracks |
Block size | 1024 | 1024 | 2048 | 1024 | # bytes per allocation block |
Dir entries | 48 | 64 | 256 | 64 | Max # directory extent entries |
Dir blocks | 2 | 2 | 4 | 2 | # blocks allocated to directory |
DSM+1 | 104 | 128 | 314 | 243 | blocks |
Disk size | 104 | 128 | 628 | 243 | KBytes (excluding system tracks) |
113.75 | 140 | 640 | 250 | KBytes (including system tracks) | |
Dirbuf | 128 | 128 | 128 | 128 | bytes |
ALV | 14 | 17 | 40 | 31 | bytes |
CSV | 12 | 16 | 64 | 16 | bytes |