LLX > Neil Parker > Apple II > ADB

Inside the Apple IIGS ADB Controller

Contents

Introduction

On the Apple IIGS, the Apple Desktop Bus (ADB) hardware is not controlled directly by the CPU, but by the ADB microcontroller, a separate microprocessor running independently of the main processor. Communication between the ADB microcontroller and the main processor is handled by a custom chip called the ADB GLU.

The ADB microcrontroller in ROM 0 and ROM 1 machines is the Mitsubishi M50740 single-chip 8-bit CMOS microcomputer. ROM 3 machines use the Mitsubishi M50741, which differs from M50740 only in the amount of internal ROM.

The M50740 and M50741 are "all-in-one" devices intended for embedded controller applications. A single chip contains the processor itself, 3K or 4K of ROM, 96 bytes of RAM, three interval timers, four external 8-bit I/O ports, and sixteen 4-bit I/O ports.

The information that follows is taken from the Mitsubishi data book and the Apple IIGS Hardware Reference, from my own disassemblies of the microcontroller ROM code, and from information generously contributed by readers of this page. Note that I can't guarantee that everything below is 100% correct.

Memory

The memory map of the ADB microcontroller looks like this (all addresses are in hexadecimal):

$0000-$005F: RAM (96 bytes)
$0060-$00CF: not implemented
$00D0-$00DF: 4-bit I/O ports
$00E0:       Port P0 (8-bit I/O port)
$00E1:       Port P0 data direction register
$00E2:       Port P1 (8-bit I/O port)
$00E3:       Port P1 data direction register
$00E4:       Port P2 (8-bit I/O port)
$00E5:       Port P2 data direction register
$00E6-$00E7: not implemented
$00E8:       Port P3 (8-bit I/O port)
$00E9:       Port P3 data direction register
$00EA-$00F8: not implemented
$00F9:       Timer 1 & 2 Prescaler
$00FA:       Timer 1
$00FB:       Timer 2
$00FC:       Timer X Prescaler
$00FD:       Timer X
$00FE:       Interrupt Control Register
$00FF:       Timer Control Register
$0100-$0FFF: not implemented
$1000-$13FF: not implemented on M50740 (ROM 0 & 1), ROM on M50741 (ROM 3)
$1400-$1FFF: ROM

The highest addressable memory location is $1FFF. If memory locations above $1FFF are accessed, they are apparently reflected back into the $0000-$1FFF range by ignoring the upper three bits of the address (a correspondent reports that the ADB code in ROM 3 machines depends on this feature).

Memory locations 0 through $FF are called "page zero", and memory locations $1F00 through $1FFF are called the "special page".

ROM locations $1FF4 through $1FFF are reserved for reset and interrupt vectors:

$1FF4-$1FF5: /INT interrupt (wired to IIGS /VBL signal)
$1FF6-$1FF7: Timer 2 interrupt
$1FF8-$1FF9: Timer 1 interrupt
$1FFA-$1FFB: Timer X interrupt
$1FFC-$1FFD: /CNTR interrupt (wired to ADB data line)
$1FFE-$1FFF: /RESET

Each vector is the two-byte address (low byte first, then high byte) of the subroutine to be executed when the interrupt occurs.

Interrupts

As indicated above, there are six interrupt sources available: /RESET, /CNTR, Timer X, Timer 1, Timer 2, and /INT. /RESET, /CNTR, and /INT are external pins on the chip, and the timer interrupts are internal, generated by the built-in interval timers.

Each interrupt has a priority--if two interrupts occur simultaneously, the one with the higher priority is recognized first. The priority order is the same as the interrupt vector order--/RESET has the highest priority, and /INT has the lowest.

All interrupts except /RESET can be enabled or disabled through the Interrupt Control Register at $FE and the Timer Control Register at $FF (discussed below). Additionally, the CPU contains an interrupt disable bit which disables all interrupts except /RESET. /RESET cannot be disabled.

Interrupts work just like on the 6502: If an interrupt occurs and interrupts are not disabled, the current program counter and processor flags are saved on the stack, the interrupt disable bit is set, and execution continues at the address pointed to by the appropriate interrupt vector.

On the Apple IIGS, the /INT interrupt is connected to the motherboard's /VBL signal, so it generates 60 interrupts every second. The /CNTR interrupt is connected to the ADB data line, so it interrupts whenever an ADB device forces the data line to the low state. /RESET is connected to the 5-volt supply by an RC circuit--thus the controller is reset only when the computer is powered on.

Timers

Three built-in timers are available, Timer 1, Timer 2, and Timer X. Timer 1 and Timer 2 count the system clock divided by 16, and Timer X can count either the system clock or pulses on the /CNTR line.

The Mitsubishi manual is somewhat unclear on the the precise operation of the timers, but it seems to work like this:

Each timer has a timer latch, a timer value, a prescaler latch, and a prescaler value. At the start, the timer value and prescaler value are loaded from the corresponding latches. Then, whenever a pulse occurs on the timer input (either clock/16 or /CNTR), the prescaler value is decreased by one. When the prescaler reaches 0, the timer value is decreased by one, and the prescaler value is reloaded from the prescaler latch. When the timer value reaches 0, the timer generates an interrupt (if the interrupt is enabled), and the timer value is reloaded from the timer latch.

Timer 1 and Timer 2 share a single prescaler value and latch. Timer X has its own prescaler value and latch.

It takes two input cycles to reload the values from the latches, so the count rate is 1/(n+2), where n is the latch value.

Timer 1 and Timer 2 are limited to counting the clock. Timer X has four modes of operation, selectable with the Timer Control Register at $FF (discussed below):

  1. Timer mode: Timer X behaves like Timer 1 and Timer 2, counting clock/16.
  2. Pulse output mode: Like Timer mode, but every time Timer X reaches 0, the polarity on the CNTR pin reverses.
  3. Event counter mode: Timer X counts pulses on the /CNTR pin.
  4. Pulse width measurement mode: Timer X counts clock/16 when the /CNTR pin is low. When /CNTR is high, counting is suspended.

On the IIGS, the controller is clocked by the CREF signal (3.579545 MHz), so the counter input rate is 223.7215625 KHz.

Timer 1 and Timer 2 are not used on the IIGS. Timer X is used as a watchdog timer to reset the controller if it gets stuck in an endless loop.

Built-In I/O Ports

Memory locations $F9 through $FF are reserved for controlling the interval timer, interrupt sources, and chip configuration. Memory location $FE is the interrupt control register--each bit has a separate function, as follows:

Bit  Function
---  --------
 7   /CNTR interrupt request
 6   /CNTR interrupt enable
 5   Timer 1 interrupt request
 4   Timer 1 interrupt enable
 3   Timer 2 interrupt request
 2   Timer 2 interrupt enable
 1   /INT interrupt request
 0   /INT interrupt enable

(where bit 7 is the high-order bit, and bit 0 is the low-order bit). For each interrupt, the interrupt request bit is set to one when the interrupt occurs, and the program code can clear the interrupt by setting the request bit to 0. The interrupt does not actually interrupt the processor unless its enable bit is set to 1.

Memory location $FF is the timer control register, which contains the following bits:

Bit  Function
---  --------
 7   Timer X interrupt request
 6   Timer X interrupt enable
 5   Timer X count stop (0 = Timer X runs normally; 1 = Timer X is stopped)
 4   not used
3-2  Timer X mode (00 = Timer mode; 01 = Pulse output mode; 10 = Event counter
     mode; 11 = pulse width measurement mode)
1-0  Processor mode (see below)

Memory locations $F9 through $FD hold the timer values and prescalers:

$00F9: Timer 1 & 2 Prescaler
$00FA: Timer 1
$00FB: Timer 2
$00FC: Timer X Prescaler
$00FD: Timer X

Writing to one of the above registers stores the written value into the corresponding latch, and reading retrieves the current value of the timer or prescalar. The timer values and prescalers should not be set to 0 (but the Mitsubishi data book doesn't say what goes wrong if this advice is not heeded).

When /RESET occurs (only at power-on on the IIGS), the interrupt control register and timer control register are initialized to 0, the Timer X prescaler is initialized to $FF, and the Timer X value is initialized to 1.

The processor mode bits (mentioned above in the description of the timer control register) allow the processor to access external memory. No such external memory is connected on the IIGS, so the processor mode bits are always set to 0, but for the sake of completeness here are the possible values:

The processor normally powers on in single chip mode. It can be wired to power on in EVA chip mode, but this is not done on the IIGS.

External I/O Ports

There are sixteen four-bit I/O ports available, known collectively as Port R, and four eight-bit I/O ports, known as P0 through P3.

Port R occupies memory locations $D0-$DF. Externally, there are four Port R pins, which are multiplexed--when the processor clock is high, the Port R pins contain the four low-order bits of the address referenced, and when the processor clock is low, they contain the data read or written. The Mitsubishi data book does not indicate how the four data bits map to the eight bits available at each Port R memory location. In the Apple IIGS, Port R is not used (except maybe for its effect on timing--the clock cycle when the access occurs is stretched to twice its usual length), and the Port R pins are not connected to anything.

The eight-bit I/O ports, P0 through P3, each have their own set of eight external pins. Internally, each port has a data register and a data direction register. Each bit in the data direction register controls whether the corresponding data register bit is used for input or output: 0 indicates an input bit, and 1 indicates an output bit. Writing to an output bit also writes to an internal latch, so that reading an output bit always returns the value last written to that bit, regardless of the signal on the external pin.

When the processor is in microprocessor mode, only port P3 is still useable as an I/O port. Since the IIGS never puts the processor into microprocessor mode, this usually isn't an issue.

In the Apple IIGS, communication with the ADB hardware, the ADB GLU, and (on ROM 0 and ROM 1 machines) the Apple IIE keyboard connector, is done through ports P0-P3. Here's how the ports are connected:

Port P0 (data register at $E0, direction register at $E1):
Bit  Function
---  --------
7-0  Data to/from ADB GLU

Port P1 (data register at $E2, direction register at $E3):
Bit  Function
---  --------
 7   IIE keyboard X7 line (ROM 0/1) or always 0 (ROM 3)
 6   IIE keyboard X6 line (ROM 0/1) or not connected (ROM 3)
 5   IIE keyboard X5 line (ROM 0/1) or not connected (ROM 3)
 4   IIE keyboard X4 line (ROM 0/1) or not connected (ROM 3)
 3   IIE keyboard X3 line (ROM 0/1) or not connected (ROM 3)
 2   IIE keyboard X2 line (ROM 0/1) or always 1 (ROM 3)
 1   IIE keyboard X1 line (ROM 0/1) or always 1 (ROM 3)
 0   IIE keyboard X0 line (ROM 0/1) or always 0 (ROM 3)

Port P2 (data register at $E4, direction register at $E5):
Bit  Function
---  --------
 7   ADB data line (input)
 6   IIE keyboard /KRESET line (ROM 0/1) or always 0 (ROM 3)
 5   IIGS /RESET line
 4   ADB GLU STB line
3-0  ADB GLU address lines (SEL3-SEL0)

Port P3 (data register at $E8, direction register at $E9):
Bit  Function
---  --------
 7   IIE keyboard KSW0 line (ROM 0/1) or always 0 (ROM 3)
 6   IIE keyboard KSW1 line (ROM 0/1) or control panel disable jumper (ROM 3)
 5   IIGS button 0 / open-apple / command line
 4   IIGS button 1 / solid-apple / option line
 3   ADB data line (output)
 2   IIE keyboard CAPLOCK line (ROM 0/1) or always 0 (ROM 3)
 1   IIE keyboard CNTRL line (ROM 0/1) or always 0 (ROM 3)
 0   IIE keyboard SHIFT line (ROM 0/1) or always 0 (ROM 3)

ADB GLU Registers

The ADB microcontroller can access sixteen internal registers in the ADB GLU. Some of these registers are used to communicate with the main CPU, and others seem to be for the private use of the ADB microcontroller.

The protocol for reading an ADB GLU register is as follows:

  1. Put the register number of the ADB GLU register in port P2 bits 0-3.
  2. Clear bit 4 of port P2, read the data from P0, and set bit 4 of P0.

The protocol for writing a GLU register is similar:

  1. Write the register number to port P2 bits 0-3.
  2. Write the data to port P0.
  3. Configure port P0 for output by writing $FF to $E1.
  4. Clear bit 4 of P2, and immediately set it again.
  5. Configure port P0 for input by writing 0 to $E1.

Both of these procedures depend on the fact that port P0 is normally kept configured for input, and bits 0-4 of P2 are normally configured for output. When writing the register number to bits 0-3 of P2, bit 4 should always be written as 1.

Here are the ADB GLU register functions known to me so far:

Register 0: keyboard data (visible to main CPU at $C000)

Register 1: ADB command register (visible to main CPU at $C026)

Register 2: mouse X register (visible to main CPU at $C024)

Register 3: mouse Y register (visible to main CPU at $C024)

Register 4: GLU status register (not visible to main CPU)
Bit  Function
---  --------
 7   1 = mouse X-axis register full
 6   1 = command register full
 5   1 = data register full
 4   1 = keyboard strobe set
3-1  always 0
 0   1 = any key down

Register 5: any key down register (visible to main CPU at $C010)

Register 6: keyboard modifier register (visible to main CPU at $C025)

Register 7: ADB data register (visible to main CPU at $C026)

The IIGS wiring diagram shows that 16 GLU registers ought to be addressable, but the ROM only accesses the eight listed above. What registers 8-15 might do, or whether they even exist at all, is not known.

Note that the mapping between the main CPU keyboard/mouse/ADB I/O locations and the GLU registers is not quite direct or one-to-one. Clearly some of the behaviour of the main CPU's keyboard/mouse/ADB I/O locations is implemented by the GLU hardware.

Instruction Set

The ADB microcontroller instruction set is a superset of the 6502 instruction set, with a few additional instructions borrowed from the Rockwell version of the 65C02 (but not always assigned to the same opcode bytes), and a few more instructions not found on any other 6502-based processor.

Registers

The processor has the same registers as the 6502:

The PC is 13 bits wide, and all other registers are eight bits wide.

The status register is like that of the 6502, but has one additional status bit. From high-order to low-order:

The stack pointer works just like it does on the 6502, except that the stack is on page 0 rather than page 1. The stack grows downward, and the S register points to the first unused location (i.e. the last value pushed is at memory location S+1).

Addressing modes

The addressing modes include all those of the 6502, and a few extras.

Many instruction have two operands, but most of them implicitly use the accumulator as the second operand. A few, however, require a second operand to be specified explicitly. Here are the combinations that can occur:

Instructions

The Instruction column lists each instruction and describes its function. The notation "M(foo)" means the contents of memory location "foo".

The NVZC column shows the instruction's effects on the flag bits. 0 means the bit is cleared; 1 means the bit is set, - means the bit is unchanged, and X means the bit's value depends on the operands.

The Addressing Mode column shows the available addressing modes for the instruction.

The Opcode column shows the instruction byte in hexadecimal, except for BBC, BBS, CLB, and SEB, where the byte is shown in binary.

The Cycles column indicates how long the instruction takes to execute. The notations "+t", "+2t", and "+3t" indicate that the instruction takes (respectively) one, two, or three extra cycles if the T bit is set. The notation "+2b" indicates that the instruction takes two extra cycles if a branch is taken. One instruction cycle is four input clock cycles; on the IIGS this works out to 894866.25 cycles per second.

Instruction                             NVZC  Addressing  Opcode    Cycles
                                              Mode
-----------                             ----  ----------  ------    ------
ADC: ADd with Carry                     XXXX  (zp,X)      61        6+3t
If T=0: A = A+Operand+C                       zp          65        3+3t
If T=1: M(X) = M(X)+Operand+C                 #           69        2+3t
There is no "add without carry"--             abs         6D        4+3t
make sure C=0 before starting an              (zp),Y      71        6+3t
addition.                                     zp,X        75        4+3t
Addition is BCD if D=1.                       abs,Y       79        5+3t
                                              abs,X       7D        5+3t

AND: bitwise AND                        X-X-  (zp,X)      21        6+3t
If T=0: A = A AND Operand                     zp          25        3+3t
If T=1: M(X) = M(X) AND Operand               #           29        2+3t
                                              abs         2D        4+3t
                                              (zp),Y      31        6+3t
                                              zp,X        35        4+3t
                                              abs,Y       39        5+3t
                                              abs,X       3D        5+3t

ASL: Arithmetic Shift Left              X-XX  zp          06        5
The operand is shifted left one bit.          A           0A        2
0 is shifted into the low-order bit.          abs         0E        6
The high-order bit is shifted into C.         zp,X        16        6
                                              abs,X       1E        7

BBC: Branch if Bit Clear                ----  bbb,A,rel   bbb10011  4+2b
PC = PC+Operand if the indicated bit          bbb,zp,rel  bbb10111  5+2b
is 0

BBS: Branch if Bit Set                  ----  bbb,A,rel   bbb00011  4+2b
PC = PC+Operand if the indicated bit          bbb,zp,rel  bbb00111  5+2b
is 1

BCC: Branch if Carry Clear              ----  rel         90        2+2b
PC = PC+Operand if C=0

BCS: Branch if Carry Set                ----  rel         B0        2+2b
PC = PC+Operand if C=1 

BEQ: Branch if EQual                    ----  rel         F0        2+2b
PC = PC+Operand if Z=1

BIT: BITwise and, discarding result     XXX-  zp          24        3
A AND Operand; discard result                 abs         2C        4 
Z = 1 if result=0, else Z = 0
N = Operand bit 7
V = Operand bit 6

BMI: Branch if MInus                    ----  rel         30        2+2b
PC = PC+Operand if N=1

BNE: Branch if Not Equal                ----  rel         D0        2+2b
PC = PC+Operand if Z=0

BPL: Branch if PLus                     ----  rel         10        2+2b
PC = PC+Operand if N=0

BRA: BRanch Always                      ----  rel         80        4
PC = PC+Operand          

BRK: BReaK                              ----              00        7
Simulates /INT interrupt.
M(S) = PCH
S = S-1
M(S) = PCL
S = S-1
M(S) = P (with B = 1)
S = S-1
I = 1
PCL = M($1FF4)
PCH = M($1FF5)
Works even if I=1.  PC on the stack
is address of BRK plus 2.

BVC: Branch if oVerflow Clear           ----  rel         50        2+2b
PC = PC+Operand if V=0

BVS: Branch if oVerflow Set             ----  rel         70        2+2b
PC = PC+Operand if V=1

CLB: CLear Bit                          ----  bbb,A       bbb11011  2
Operand bit bbb = 0                           bbb,zp      bbb11111  5

CLC: CLear Carry                        ---0              18        2
C = 0

CLD: CLear Decimal mode                 ----              D8        2
D = 0

CLI: CLear Interrupt disable            ----              58        2
I = 0

CLT: Clear T bit                        ----              12        2
T = 0

CLV: Clear oVerflow                     -0--              B8        2
V = 0

CMP: CoMPare                            X-XX  (zp,X)      C1        6+t
If T=0, A-Operand, discard result             zp          C5        3+t
If T=1, M(X)-Operand, discard result          #           C9        2+t
Sets N, Z, and C according to result.         abs         CD        4+t
                                              (zp),Y      D1        6+t
                                              zp,X        D5        4+t
                                              abs,Y       D9        5+t
                                              abs,X       DD        5+t

COM: COMplement                         X-X-  zp          44        5
Operand = NOT Operand
(bitwise NOT)

CPX: ComPare X                          X-XX  #           E0        2
X-Operand, discard result                     zp          E4        3
Sets N, Z, and C according to result.         abs         EC        4

CPY: ComPare Y                          X-XX  #           C0        2
Y-Operand, discard result                     zp          C4        3
Sets N, Z, and C according to result.         abs         CC        4

DEC: DECrement                          X-X-  A           1A        2
Operand = Operand-1                           zp          C6        5
                                              abs         CE        6
                                              zp,X        D6        6
                                              abs,X       DE        7

DEX: DEcrement X                        X-X-              CA        2
X = X-1

DEY: DEcrement Y                        X-X-              88        2
Y = Y-1

EOR: bitwise Exclusive OR               X-X-  (zp,X)      41        6+3t
If T=0: A = A XOR Operand                     zp          45        3+3t
If T=1: M(X) = M(X) XOR Operand               #           49        2+3t
                                              abs         4D        4+3t
                                              (zp),Y      51        6+3t
                                              zp,X        55        4+3t
                                              abs,Y       59        5+3t
                                              abs,X       5D        5+3t

FST: FaST                               ----              E2        2
Use fast oscillator circuit.
Has no effect on IIGS.

INC: INCrement                          X-X-  A           3A        2
Operand = Operand+1                           zp          E6        5
                                              abs         EE        6
                                              zp,X        F6        6
                                              abs,X       FE        7

INX: INcrement X                        X-X-              E8        2
X = X+1

INY: INcrement Y                        X-X-              C8        2
Y = Y+1

JMP: JuMP to new address                ----  abs         4C        3
PC = address of operand                       (abs)       6C        5
                                              (zp)        B2        4

JSR: Jump to SubRoutine                 ----  (zp)        02        7
M(S) = PCH                                    abs         20        6
S = S-1                                       \sp         22        5
M(S) = PCL
S = S-1
PC = address of operand

LDA: LoaD Accumulator                   X-X-  (zp,X)      A1        6+2t
If T=0: A = Operand                           zp          A5        3+2t
If T=1: M(X) = Operand                        #           A9        2+2t
                                              abs         AD        4+2t
                                              (zp),Y      B1        6+2t
                                              zp,X        B5        4+2t
                                              abs,Y       B9        5+2t
                                              abs,X       BD        5+2t

LDM: LoaD Memory                        ----  #,zp        3C        4
Operand2 = Operand1

LDX: LoaD X                             X-X-  #           A2        2
X = Operand                                   zp          A6        3
                                              abs         AE        4
                                              zp,Y        B6        4
                                              abs,Y       BE        5

LDY: LoaD Y                             X-X-  #           A0        2
Y = Operand                                   zp          A4        3
                                              abs         AC        4
                                              zp,X        B4        4
                                              abs,X       BC        5

LSR: Logical Shift Right                X-XX  zp          46        5
The operand is shifted right 1 bit.           A           4A        2
0 is shifted into the high bit.               abs         4E        6
The low bit is shifted into C.                zp,X        56        6
                                              abs,X       5E        7

NOP: No OPeration                       ----              EA        2
The CPU does nothing for 2 cycles.

ORA: bitwise OR Accumulator             X-X-  (zp,X)      01        6+3t
If T=0: A = A OR Operand                      zp          05        3+3t
If T=1: M(X) = M(X) OR Operand                #           09        2+3t
                                              abs         0D        4+3t
                                              (zp),Y      11        6+3t
                                              zp,X        15        4+3t
                                              abs,Y       19        5+3t
                                              abs,X       1D        5+3t

PHA: PusH Accumulator                   ----              48        3
M(S) = A
S = S-1

PHP: PusH P register                    ----              08        3
M(S) = P
S = S-1

PLA: PuLl Accumulator                   X-X-              68        4
S = S+1
A = M(S)

PLP: PuLl P register                    XXXX              28        4
S = S+1
P = M(S)

ROL: ROtate Left                        X-XX  zp          26        5
The operand is shifted left 1 bit.            A           2A        2
C is shifted into the low bit.                abs         2E        6
The high bit is shifted into C.               zp,X        36        6
                                              abs,X       3E        7

ROR: ROtate Right                       X-XX  zp          66        5
The operand is shifted right 1 bit.           A           6A        2
C is shifted into the high bit.               abs         6E        6
The low bit is shifted into C.                zp,X        76        6
                                              abs,X       7E        7

RRF: Rotate Right by Four bits          ----  zp          82        8
The high 4 bits of the operand are
swapped with the low 4 bits.

RTI: ReTurn from Interrupt              XXXX              40        6
S = S+1
P = M(S)
S = S+1
PCL = M(S)
S = S+1
PCH = M(S)

RTS: ReTurn from Subroutine             ----              60        6
S = S+1
PCL = M(S)
S = S+1
PCH = M(S)

SBC: SuBtract with Carry                XXXX  (zp,X)      E1        6+3t
If T=0: A = A-Operand-(NOT C)                 zp          E5        3+3t
If T=1: M(X) = M(X)-Operand-(NOT C)           #           E9        2+3t
There is no "subtract without carry"--        abs         ED        4+3t
make sure C=1 before starting a               (zp),Y      F1        6+3t
subtraction.                                  zp,X        F5        4+3t
Subtraction is BCD if D=1.                    abs,Y       F9        5+3t
                                              abs,X       FD        5+3t

SEB: SEt Bit                            ----  bbb,A       bbb01011  2
Operand bit bbb = 1                           bbb,zp      bbb01111  5

SEC: SEt Carry                          ---1              38        2
C = 1

SED: SEt Decimal mode                   ----              F8        2
D = 1

SEI: SEt Interrupt disable              ----              78        2
I = 1

SET: SEt T bit                          ----              32        2
T = 1

SLW: SLoW                               ----              C2        2
Use slow oscillator circuit.
Has no effect on IIGS.

STA: STore Accumulator                  ----  (zp,X)      81        7
Operand = A                                   zp          85        4
                                              abs         8D        5
                                              (zp),Y      91        7
                                              zp,X        95        5
                                              abs,Y       99        6
                                              abs,X       9D        6

STP: SToP the processor                 ----              42        2
Stops the processor.  Only /RESET can
resume execution.

STX: STore X                            ----  zp          86        4
Operand = X                                   abs         8E        5
                                              zp,Y        96        5

STY: STore Y                            ----  zp          84        4
Operand = Y                                   abs         8C        5
                                              zp,X        94        5

TAX: Transfer A to X                    X-X-              AA        2
X = A

TAY: Transfer A to Y                    X-X-              A8        2
Y = A

TST: TeST for zero                      X-X-  zp          64        3
Z = 1 if Operand=0, else Z = 0

TSX: Transfer S to X                    X-X-              BA        2
X = S

TXA: Transfer X to A                    X-X-              8A        2
A = X

TXS: Transfer X to S                    ----              9A        2
S = X

TYA: Transfer Y to A                    X-X-              98        2
A = Y

Notes

Instruction Table

    $x0 $x1 $x2 $x3 $x4 $x5 $x6 $x7 $x8 $x9 $xA $xB $xC $xD $xE $xF
$0x BRK ORA JSR BBS  -  ORA ASL BBS PHP ORA ASL SEB  -  ORA ASL SEB
        (X) (z) 0Ar      z   z  0zr      #   A  0,A     abs abs 0,z
$1x BPL ORA CLT BBC  -  ORA ASL BBC CLC ORA DEC CLB  -  ORA ASL CLB
     r  ()Y     0Ar     z,X z,X 0zr     a,Y  A  0,A     a,X a,X 0,z
$2x JSR AND JSR BBS BIT AND ROL BBS PLP AND ROL SEB BIT AND ROL SEB
    abs (X) \sp 1Ar  z   z   z  1zr      #   A  1,A abs abs abs 1,z
$3x BMI AND SET BBC  -  AND ROL BBC SEC AND INC CLB LDM AND ROL CLB
     r  ()Y     1Ar     z,X z,X 1zr     a,Y  A  1,A #,z a,X a,X 1,z
$4x RTI EOR STP BBS COM EOR LSR BBS PHA EOR LSR SEB JMP EOR LSR SEB
        (X)     2Ar  z   z   z  2zr      #   A  2,A abs abs abs 2,z
$5x BVC EOR  -  BBC  -  EOR LSR BBC CLI EOR  -  CLB  -  EOR LSR CLB
     r  ()Y     2Ar     z,X z,X 2zr     a,Y     2,A     a,X a,X 2,z
$6x RTS ADC  -  BBS TST ADC ROR BBS PLA ADC ROR SEB JMP ADC ROR SEB
        (X)     3Ar  z   z   z  3zr      #   A  3,A (a) abs abs 3,z
$7x BVS ADC  -  BBC  -  ADC ROR BBC SEI ADC  -  CLB  -  ADC ROR CLB
     r  ()Y     3Ar     z,X z,X 3zr     a,Y     3,A     a,X a,X 3,z
$8x BRA STA RRF BBS STY STA STX BBS DEY  -  TXA SEB STY STA STX SEB
     r  (X)  z  4Ar  z   z   z  4zr             4,A abs abs abs 4,z
$9x BCC STA  -  BBC STY STA STX BBC TYA STA TXS CLB  -  STA  -  CLB
     r  ()Y     4Ar z,X z,X z,Y 4zr     a,Y     4,A     a,X     4,z
$Ax LDY LDA LDX BBS LDY LDA LDX BBS TAY LDA TAX SEB LDY LDA LDX SEB
     #  (X)  #  5Ar  z   z   z  5zr      #      5,A abs abs abs 5,z
$Bx BCS LDA JMP BBC LDY LDA LDX BBC CLV LDA TSX CLB LDY LDA LDX CLB
     r  ()Y (z) 5Ar z,X z,X z,Y 5zr     a,Y     5,A a,X a,X a,Y 5,z
$Cx CPY CMP SLW BBS CPY CMP DEC BBS INY CMP DEX SEB CPY CMP DEC SEB
     #  (X)     6Ar  z   z   z  6zr      #      6,A abs abs abs 6,z
$Dx BNE CMP  -  BBC  -  CMP DEC BBC CLD CMP  -  CLB  -  CMP DEC CLB
     r  ()Y     6Ar     z,X z,X 6zr     a,Y     6,A     a,X a,X 6,z
$Ex CPX SBC FST BBS CPX SBC INC BBS INX SBC NOP SEB CPX SBC INC SEB
     #  (X)     7Ar  z   z   z  7zr      #      7,A abs abs abs 7,z
$Fx BEQ SBC  -  BBC  -  SBC INC BBC SED SBC  -  CLB  -  SBC INC CLB
     r  ()Y     7Ar     z,X z,X 7zr     a,Y     7,A     a,X a,X 7,z

Disassembler

For those who want to explore the ADB ROM code, a disassembler is available. Pick your favorite format:

Here's the README file from the archive:

================================================
ADB Microcontroller (M50740/M50741) Disassembler

by Neil Parker
================================================

Contents:
     README: this file
     ADB.DISASM: the disassembler
     ADB.DISASM.LSF: source code (for LISA816 4.0 assembler)
     ADB.DISASM.TXT: source code in text form

Requirements: Loading the microcontroller code into main memory requires an
Apple IIGS.  The disassembler itself should run on any Apple II.

Usage:
     ]BRUN ADB.DISASM
     (wait a few seconds)
     ]CALL-151
     *1400(control-Y)

If you're on an Apple IIGS, "BRUN ADB.DISASM" loads the microcontroller ROM
contents into main memory (be patient--this takes several seconds) and
installs the disassembler.  On any other Apple II, it just beeps and returns
to the BASIC prompt.

Once the microcontroller code is in main memory, you can say (for example)

     BSAVE ADB.DISASM.ROM1,A$C03,L$13FD

to save the disassembler and the ROM code in a disk file.  You can then take
the disk to any other Apple II (even if it's not a IIGS) and
BRUN ADB.DISASM.ROM1 to install both the saved ROM image and the disassembler.
(Use any file name you want, but the ",A$C03,L$13FD" is vital.)

The disassembler installs itself into the Monitor control-Y vector.  It works
just like the Monitor's "L" command, except that to disassemble M50740/M50741
code, you type control-Y instead of "L".  For example, to disassemble 20 lines
of code starting at $1400, type "1400(control-Y)" at the Monitor prompt.  If
control-Y is typed without an address before it, disassembly continues from
wherever the previous control-Y command left off.

The operand formats used in the disassembly differ slightly from the formats
recommended in the Mitsubishi documentation.  Mitsubishi recommends that
accumulator addressing mode be indicated by the letter "A" in the operand
column, but the disassembler always omits the "A".

     Mitsubishi format     Disassembler format
     -----------------     -------------------
     ASL A                 ASL
     ROL A                 ROL
     LSR A                 LSR
     ROR A                 ROR
     CLB 0,A               CLB 0
     SEB 1,A               SEB 1
     BBC 2,A,$1234         BBC 2,1234
     BBS 3,A,$1234         BBS 3,1234

This means you'll have to watch carefully for how many operands CLB, SEB, BBC,
and BBS have.  For CLB and SEB, one operand means accumulator mode, and two
operands means zero page mode.  Similarly, for BBC and BBS, two operands means
accumulator mode, and three means zero page mode.

All operands are printed in hexadecimal.  No dollar signs are printed.

On an ROM 0 or ROM 1 Apple IIGS, the microcontroller code loads into main
memory locations $1400 through $1FFF.  On ROM 3, memory locations $1000
through $1FFF are used.  This means the ROM image is at the same address in
main memory that it occupies in the microcontroller memory, which should
minimize confusion about where you are while you're disassembling.

If you have the disassembler and ROM image loaded into memory, but the
control-Y vector is somehow disconnected, it can be reconnected by typing
"CALL 3075" at the BASIC prompt, or "C03G" at the Monitor prompt.

LLX > Neil Parker > Apple II > ADB

Original: August 25, 2004
Modified: April 4, 2018--Replaced BinSCII file with zipped disk image
Modified: January 5, 2020--Added a bunch of new information, most of it generously supplied by Ian Brumby