Bill Fernandez Design
Home Services Testimonials Portfolio About Contacts Notices Hobbies Login

Apple Desktop Bus (ADB) Device Simulator
Apple Computer, Inc. -- 1988

By early 1987, all new Macintoshes were using the Apple Desktop Bus (ADB) for attaching mice and keyboards. The ADB is a simple, low-speed, bus-topology network with a single Macintosh acting as the bus master for up to 16 attached devices.

In mid-1987, Apple was considering new kinds of ADB devices that would utilize some of the advanced features of the ADB specification and needed to know how the various Macintosh models would behave with a large complement of more sophisticated ADB devices attached. So we decided to build a simulator that could pretend to be up to 16 ADB devices and exercise the full capabilities of the ADB specification. Around that time Bill wanted to try his hand at some serious programming and was able to get this project.

Bill evaluated a number of alternatives, and for a number of reasons ended up building a simple hardware adapter that plugged into the Game Port of an Apple-2GS computer and writing a simulation program, entirely in assembly language, that ran on a port of the Macintosh User Interface Toolbox.

Some Key Results

  • The simulator was written in 10 months. The source code is 600K of assembly language for the 65816 processor.
  • The executable object code is 71K.
  • The program simulates up to 16 ADB devices with a combined bandwidth of 8 MHz, using only the 2 MHz processor built into the Apple-2GS.
  • The program runs in real time.
  • The program presents a Macintosh-style point-and-click graphical interface with all the trimmings: It uses a main event loop, handles window updates, pull-down menus, and so forth.
  • Bill never received any bug reports on this program.
  • Apple used it successfully for many years.

Sample Source Code

; Bus Poller
; Poll the bus for about 1mS.  If it does not go low within that time, then
; return to EngineLoop.  Otherwise count how many microseconds (in 10uS
; increments) the bus is low.  Once the bus goes high, determine if it
; was a valid Attention or Reset pulse.
; Prepare for polling:
InitCounters   ANOP
               STA >AN2Low              ; We are not responding to a command.
               STA >DevSimFree          ; We are not ignoring the bus.
               LDA #$01                 ; Initialize the three-byte
               STA LowCounter           ; counter to $000001,
               LDA #$00                 ; because it counts 10uS periods
               STA MedCounter           ; and one such period will already
               STA HighCounter          ; have passed when we start counting.
               LDX #$FF                 ; Initialize the 1mS loop counter.
; Wait up to (approx) 1mS for the bus to go low:
LookForLow     LDA >ADBDataLine         ; Read the ADB Data line,
               BPL BusWentLow           ; and branch if it is low.
               BNE LookForLow
               BRL AbortCatcher         ; Time's up: abort the poll.
; Wait for the bus to go high:
BusWentLow     NOP
               STZ ZPTemp1              ; (pad loop by three cycles)
LowCntLoop     STZ ZPTemp1              ; (pad loop by three cycles)
MedCntLoop     NOP
LookForHigh    LDA >ADBDataLine         ; Read the ADB Data line.
               BMI BusWentHigh          ; if high, go evaluate the count.
IncCounter     INC LowCounter           ; Add 1 to the current count...
               BNE LowCntLoop           ; if no carry, then poll the bus again.
               INC MedCounter           ; Add the carry here...
               BNE MedCntLoop           ; if no carry, then poll the bus again.
               INC HighCounter          ; Add  the carry here...
TooLongCheck   LDA HighCounter          ; get the num where we can examine it...
               CMP #8                   ; has the bus been low too long?...
               BLT LookForHigh          ; no, so poll the bus again...
LowTooLong     ANOP
;              (log the error)          ; yes, so log the error
;               PrtMsg  'Too long for RESET.'
               BRL AbortCatcher         ; and abort the transaction.
; Figure out what kind of pulse we got:
BusWentHigh    ANOP
; Was it an Attention pulse?
ChkForAtten    ANOP
               LDA HighCounter          ; If the high counter is not zero,
               BNE ChkForReset          ; then it is not an Attention pulse.
               LDA MedCounter           ; If the medium counter is not zero,
               BNE ChkForReset          ; then it is not an Attention pulse.
               LDA LowCounter           ; If the bus was low for more than
               CMP #82                  ; 824us, then it was too long to be
               BGE ChkForReset          ; an Attention pulse.
               CMP #39                  ; If low for less than 390us, then it
               BLT AttenTooShort        ; was too short for an Attention pulse.
               BRL HandleAtten          ; It was an Attention pulse.
; Was it a Reset pulse?
ChkForReset    ANOP
               LDA LowCounter
               SBC #25
               LDA MedCounter
               SBC #01
               LDA HighCounter
               SBC #00
               BLT ResetTooShort
               LDA #$00                 ; We respond to the Reset pulse
               STA NewByte              ; by pretending that we received
               BRL SaveCmdByte          ; a Reset command.
AttenTooShort  ANOP
;               PrtMsg  'Too short for ATTEN.'
               BRL AbortCatcher         ; Too short to be Atten, so abort poll.
ResetTooShort  ANOP
.              (Too short for Reset, too long for Atten.  Log the error)
               PrtMsg  'Too long for ATTEN, too short for RESET.'
               BRL AbortCatcher


Go to Top Services  •  Testimonials  •  Portfolio  •  About  •  Contact