!pr3
!bm-1
Using Apple's Protocol Converter..........Bob Sander-Cederlof

The "Protocol Converter" is a firmware-controlled method of turning the //c disk port into a multi-drop peripheral bus able to support up to 127 external I/O devices.  The bus connects devices which have enough intelligence:  an "Integrated WOZ Machine" (IWM) chip, a 6502-type chip, RAM, and ROM.  Data is transferred in a serial bit-stream at roughly 250,000 bits per second.  So far, the only device anyone is building to run on the P/C bus is the Unidisk 3.5 from Apple.

As far as I have been able to determine, Apple's only published information about the protocol converter is in the Apple //c Technical Reference Manual, pages 114-142.  The listing of the //c firmware in the same Manual also is informative.  A prelim- inary document was available to developers, but most of the material is now given in the //c manual.  Tom Weishaar ("Uncle DOS") promises a future article on the P/C in his "Open Apple" newsletter.  (By the way, the June issue of "Open Apple" used the term "Smartport" as synonymous with "Protocol Converter".)

The Apple //e interface card for the UniDisk 3.5 also supports a "real" Protocol Converter.  The Apple Memory Expansion Card, CirTech Flipster, and Applied Engineering RamFactor provide the same software interface with most of the features of the protocol converter for one I/O device (the memory card itself).

Apple briefly mentions the Protocol Converter in the Apple Memory Expansion Card manual (Appendix B, last paragraph), but warns against using it.  They say "using the assembly-language protocol is fairly complicated".  Nevertheless, a significant amount of the Apple firmware is used to implement the protocol converter features.  It appears that someone inside Apple intends that the P/C will be included in the firmware of most future block-oriented devices.  From a software stand-point, it could be used regardless of whether the actual hardware used the IWM-based bus, a SCSI bus, or no bus at all.

In order to use the protocol converter firmware, you need first to find it.  The first step in finding it is to find which slot it is in.  All of the cards with P/C firmware (so far) are also cards which control or emulate disk drives and have firmware supporting the ProDOS device driver protocol.  Cards with ProDOS device driver firmware can be identified by four bytes:  $Cs01 = $20, $Cs03 = $00, $Cs05 = $03, and $Cs07 = $00.  The first three bytes in that list are the same for all disk drive controllers.  The zero value at $Cs07 distinguishes it as a disk controller with protocol converter firmware.

The next step is to find the entry point in the firmware for protocol converter calls.  The byte at $CsFF is the key.  That byte is the offset in the firmware page for ProDOS calls.  If $CsFF = $45, for example, ProDOS device driver calls would be "JSR $Cs45".  To get the address of the protocol converter entry point, add 3 to the ProDOS entry point.  In my example, "JSR $Cs48" would enter the protocol converter firmware.  The actual value will probably be different for each kind of card, so you have to use software to find out what it is.

A program to find the slot and build the address of the protocol converter could look like this:

       pcaddr  .eq $01,$02
       find.pc lda #0
               sta pcaddr
               ldx #$C7   slot = 7 to 1 step -1
       .1      stx pcaddr+1
               ldy #7
       .2      lda (pcaddr),y  $Cs07,05,03,01
               cmp pc.sig,y
               beq .3
               dex
               cpx #$c1
               bcs .1     try next slot
               sec        signal could not find pc
               rts

       .3      dey
               dey
               bpl .2
               lda (pcaddr),y   $CsFF
               adc #2     carry was set
               sta pcaddr
               rts        carry clear signals pc found

       pc.sig  .HS FF.20.FF.00.FF.03.FF.00

Once you have the address of the protocol converter firmware, you call it in a manner similar to ProDOS MLI calls.  You must plug the address of the protocol converter entry into a "JSR" instruction, which is followed by a one-byte command code and a two-byte address.  The command code is a number from $00 to $09 which specifies which action you want the protocol converter to take.  The address is the address of a parameter block, which provides additional information for processing the command, or a place for the information returned by the command.  After the protocol converter has finished processing your command, it returns control to the next byte after the pointer to the parameter block.  If carry is clear, there was no error.  If carry is set, the A-register contains an error code.

Since my FIND.PC program left the address in two page zero locations, we could simply put a JMP opcode ($4C) in front of the address to make it into a JMP instruction.  Then our calls to the protocol converter would look like this:

       callpc  .eq $00         (just before pcaddr)
               jsr find.pc
               bcs ...         ...no pc found
               lda #$4C        JMP opcode
               sta callpc
               ...     ...other code
               jsr callpc
               .da #cmd,parameters
               ...     ...more code

Apple warns programmers NOT to use any page zero locations when calling the protocol converter firmware, saying that some page zero locations are used by that firmware.  They do not say what locations they use, but my investigations show that they use bytes in the range from $40 to $4F.  What they do is push those on the stack, put in their own data, and at the end restore the original contents from the stack.  They use an awful lot of stack, up to 35 bytes.  (The RamFactor firmware uses no more than 17 bytes of stack for protocol converter calls, including the two used by your JSR.)  If you want be safe rather than possibly sorry, you can copy the PCADDR bytes up into your own program.  You could even plug them into every JSR which calls protocol converter.  A cleaner way might be like this:

               jsr find.pc
               bcs ...         ...no pc found
               lda pcaddr
               sta callp+1
               lda pcaddr+1
               sta callpc+2
               ...
               jsr callpc
               .da #cmd,parameters
               ...
       callpc  jmp *   address filled in

Description of Protocol Converter Commands

Apple defines ten commands for the protocol converter firmware.  These are not necessarily identical in function for all devices which use the protocol converter.  In fact, Apple's memory card uses two of the commands differently than the UniDisk 3.5 does.  The protocol converter firmware in the RamFactor functions exactly the same as that in the Apple Memory Expansion Card.

The following chart summarizes the ten commands as implemented in the Apple Memory Expansion Card and RamFactor firmware.  A more detailed description of each command follows the chart.  I am particularly pointing this at the memory cards rather than the Unidisk 3.5, because I believe these cards will be more popular with hackers like you and me.  Furthermore, the Unidisk 3.5 information is available in the //c manual, but Apple has not released this detail for owners of the memory card.

   Parameters:   +0  +1  +2   +3   +4   +5   +6   +7   +8
            cmd cnt unit
PC Status   $00   3   0 bufl bufh code
RAM Status  $00   3   1 bufl bufh code
Read Block  $01   3   1 bufl bufh blkh blkm blkl
Write Block $02   3   1 bufl bufh blkh blkm blkl
Format      $03   1   1
Control     $04   3 0/1 bufl bufh code
Init        $05   1 0/1
Read Bytes  $08   4   1 bufl bufh cnth cntl adrh adrm adrl
Write Bytes $09   4   1 bufl bufh cnth cntl adrh adrm adrl

Error Codes $01 Command not $00-$05,$08, or $09
            $04 Wrong parameter count
            $11 Invalid Unit Number
            $21 Invalid Status or Control code
            $2D Block Number too large
PC Status (cmd $00, unit $00, code $00):  reads the status of the protocol converter itself into your buffer.  The status of a memory card is always 8 bytes, with the first byte = $01 and all the others = $00.  Also returns with $08 in the X-register and $00 in the Y-register.  ($0008 is the number of bytes stored in your buffer.)  This is of value only for compatibi- lity with other devices supporting protocol converter firmware.

RAM Status (cmd $00, unit $01, code $00 or $03):  reads the status of the memory card into your buffer.  Code $00 stores four bytes:  the first is always $F8, and the other three are the number of blocks in the current partition (lo, mid, hi order).  (Y,X) will equal ($00,$04) when it is finished, showing that four bytes were stored.  Code $03 will store 25 bytes:  the first four are the same as code $00 returned; the next 17 are the name of the card in "ProDOS Volume Name" format (length of name in first byte, ASCII characters of name with hi-bit off, padded with blanks); and finally, four zero bytes.  The card name is "RAMCARD".  (Y,X) will return ($00,$19) when finished, indicating that 25 bytes were stored.

Obviously, the Status commands will operate differently on a real P/C bus, and the actual details will vary according to the device you interrogate.

Read Block (cmd $01):  reads the specified block from the memory card.  (In RamFactor, the block number is relative, inside the currently selected RamFactor partition.)  You can read a block into a buffer in //e Auxiliary Memory by calling the P/C with the RAMWRT soft-switch set to AuxMem.

Write Block (cmd $02):  writes the specified block from your buffer into the memory card.  (In RamFactor, the block number is relative, inside the current RamFactor partition.)  If you are careful and follow all the rules, you can write a block from a buffer in Auxiliary Memory by calling the protocol con- verter with the RAMRD soft-switch set to AuxMem.  You have to put the code that sets the RAMRD switch and calls the protocol converter, and its parameter block, in zero-page or stack-page motherboard RAM ($0000-01FF), or in the language card RAM area.  Or, you can have both RAMRD and RAMWRT set for AuxMem and be executing a program from within AuxMem.  I always have a conceptual battle dealing with this kind of bank switching.

Format (cmd $03):  does nothing in a memory card.

Control (cmd $04):  does nothing in a memory card.  If the code is not $00, you get error code $21.  The buffer is never used.

Init (cmd $05):  does nothing in a memory card.

Open or Close (cmd $06 or $07):  cause error code $01 in a memory card.  These commands only apply to character-oriented devices, and memory is a block-oriented device (so says Apple).  Maybe someday someone will build a peripheral which is character-oriented and includes P/C firmware.

Read Bytes (cmd $08):  reads a specified number of bytes starting at a specified memory-card address into your buffer.  The byte count may be as high as $FFFF, but this would obviously wreak havoc inside your Apple.  No checks are made inside the protocol firmware for reasonableness of the buffer address or the byte count, so be careful.  You would NEVER read into a buffer in the I/O address range ($C000-$CFFF).

The memory-card address may be as high as $7FFFFF.  (In RamFactor, the address is relative inside the current partition.)  This corresponds to a total of 8 megabytes, which is only half the maximum capacity of a RamFactor card.  Apple has arbitrarily limited us to this maximum, because they use the top bit of the card address to specify whether the buffer is in MainMem (bit 23 = 0) or AuxMem (bit 23 = 1).  (Bit 23 of the address is bit 7 of the last byte of the parameter block.)

Write Bytes (cmd $09):  writes a specified number of bytes from your buffer starting at a specified memory-card address.  The details of byte count, buffer location, and memory-card address are the same as for the Read Bytes ($08) command.

The Unidisk 3.5 firmware interprets commands $08 and $09 differently.  Unidisk uses this pair to read and write Macintosh disks, which have 524-byte blocks.

All of the RamFactor protocol converter commands operate within the current active partition.  In the Apple card there is only one partition (the whole card).  RamFactor has nine partitions, and you are always in one of them.  If you start with a blank card, the first call to the RamFactor protocol converter will set up the first partition with all but 1024 bytes, make that partition the current active one, and empty all the others.

Bill Morgan's articles on interfacing the Unidisk 3.5 with DOS 3.3 illustrate the use of protocol converter calls with that device.  The real power of the protocol converter concept will not be realized until a variety of devices are available which use it.  Maybe its real future is bound up in the new 65816-based Apple //.
