[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Apple 2 firmware reference Question.



[Please don't post HTML-formatted messages to the Apple II newsgroups.
Note also that followups are going to comp.sys.apple2.programmer.]

-= Paul =- <gavp@gis.net> wrote:
> 
> A year ago I bought a book at one computer warehouse called
> "AppleIIgs Firmware Reference".  [...]
> So my question is HOW TO USE IT ??

I'll take it as read that you are a proficient assembly language
programmer.  The majority of the material in the firmware reference
manual is of limited use to someone writing purely in BASIC.

Almost all of it is only useful for 8-bit software.  Native GS/OS-based
software should be using the toolbox or GS/OS calls, not using the
firmware.

> For example "Generic Smart Port calls"  ... Well we all know what port 5
> is so i found some call that dont make sense to me..
> 
> Init
> 
>     Standard call                            Extended Call
> CMDNUM $05                                    $45
> CMDLIST Parameter count            Parameter count
>                     Unit numbers                    Unit number

You don't want to use this particular call anyway.  It reinitializes the
SmartPort firwmware, rechecking for attached devices.  The only time
this call should ever be used is when the machine is booted, and the
system already does it for you.  (It can be used on SCSI cards after
repartitioning a drive, so the firmware updates its cached partition
tables, but this has to be done very carefully.)

Let's look at a more useful example: a Status call, which gives you
information about a device.  (See pages 121-125.)

The first point to note is that the SmartPort command set is implemented
by lots of different I/O cards and firmware.  Apart from the IIgs slot 5
firmware, I'm aware of the following implementations: "Liron" card in
the IIe, IIc slot 5 firmware, standard slot "slinky" RAM cards, Apple
SCSI cards, SuperDrive card.  (There are bound to be others.)

Each of these implementations differs slightly in capabilities.  The
base documentation for all SmartPort implementations is the IIgs
firmware reference, plus additional information in the ROM 3 update to
the IIgs firmware reference, and a series of technical notes.

The parts that are common to every implementation are the way of
identifying a SmartPort device, and how to call the driver.

See page 114 for information on how to identify whether there is a
SmartPort device in a particular slot.  You need to check four
identification bytes.

You then need to look at the SmartPort ID byte if you want to know what
general class of SmartPort driver you are dealing with, and in
particular whether it supports extended calls.

The "standard" calls are the original command set.  They are limited to
accessing the 64K address space of 8-bit Apple II models, and cannot
handle devices with more than 2^24 blocks (8 gigabytes).

The "extended" calls were added with the IIgs.  They can access the full
16MB address space of the IIgs, and can support devices with up to 2^32
blocks (2 terabytes).

To use the extended calls, you must be running on a IIgs.  As far as I
know, they are only implemented by the IIgs firmware and some recent
Apple cards (High-Speed SCSI and SuperDrive).  It is also important to
check whether the specific device supports extended calls before making
use of them.

Unless you need to access data outside bank 0, there is no practical
reason to use the extended calls, so I'll stick to standard calls for
the rest of this discussion.

After locating a SmartPort device, you need to get the entry point for
the driver.  This is described on page 115.  The correct way to
implement this is to set up a JSR instruction somewhere in your code and
patch the address of the driver into the instruction.  The low byte of
the driver address is calculated by looking up the contents of $CnFF and
adding 3.  The high byte of the driver address is $Cn.  (n is the slot
number.)

As described on page 120, SmartPort calls work in a similar way to a
ProDOS MLI call.  The JSR call to the driver is followed by a byte which
contains the command number, and the address of the command list (two
bytes for a standard call, four bytes for an extended call).  After the
driver returns, code will continue to execute after these fields (at the
BCS ERROR instruction in both examples shown).

So, given that you have located a SmartPort device and patched in the
entry point, we want to do a Status call.

The command number is zero, so the byte after the patched JSR must be
set to zero.  The command list pointer should be set to point to another
memory area where you will set up the command list.

The command list starts with a parameter count (always a byte).  In the
case of the Status call, this is followed by a Unit number (byte),
Status List pointer (word) and status code (byte).  You must set up all
these fields before issuing the call.

The parameter count must be set to 3.  The unit number must be set to
the logical device number you want to get status from (the first device
is 1, or you can sometimes use 0 to refer to the SmartPort itself).  The
status list pointer points to yet another buffer area, which varies in
size depending on the call.  The status code is one of the values given
on page 122.  Let's say we want the device information block, so that
would be status code 3.

For this call, SmartPort will be returning 25 bytes of data (see page
123), so there must be at least 25 bytes that can be safely overwritten,
starting at the location pointed to by the status list pointer.

All done!  We can now call the SmartPort driver, via our patched JSR
instruction.  On return, the carry flag is set if there is an error
(with A containing the error code).  If there was no error, then the
status list will have been filled in as shown on pages 122-124.

This is most interesting (and safest) if you put a write-protected 3.5"
disk into the drive.  You will get a status byte indicating a write
protected disk, with other information as appropriate.

Note that the infomration on page 124 which describes the device type
and subtype bytes is misleading.  There is a more accurate description
in one of the SmartPort technical notes.


Here are some code snippets that do the necessary parts (Merlin
assembler syntax, apart from the comment lines probably being too long).
I'll limit it to 6502 instructions, so it will work on any Apple II, and
I'm not trying to break any speed or efficiency records.

This is completely untested, so make sure you don't have any important
data accessible when running it.  I suggest turning off any hard drives
as a safety precaution.

SLOTPTR   EQU  $00           ; Pointer to my slot (word)

FIND_SMARTPORT
* This function scans the slots to locate a SmartPort.
* On entry, X=$Cx, where x is the first slot to be checked. 
* On exit, X=$Cy, where y is the highest numbered slot less than or
* equal to x which contains SmartPort firmware.  If no SmartPort
* is found, C=1 and A=$00.
          LDA  #$00
          STA  SLOTPTR       ; Set up the pointer
TRYSLOT   STX  SLOTPTR+1
          LDY  #$01
          LDA  (SLOTPTR),Y   ; Check the first ID byte
          CMP  #$20
          BNE  NOT_HERE
          LDY  #$03
          LDA  (SLOTPTR),Y   ; and the second one
          CMP  #$00
          BNE  NOT_HERE
          LDY  #$05
          LDA  (SLOTPTR),Y   ; and the third one
          CMP  #$03
          BNE  NOT_HERE
          LDY  #$07
          LDA  (SLOTPTR),Y   ; and the fourth one
          CMP  #$00
          BNE  NOT_HERE
          LDX  SLOTPTR+1     ; Match!  Get the address back
          CLC
          RTS
NOT_HERE  LDX  SLOTPTR+1     ; Mismatch
          DEX                ; Go down one slot
          CPX  #$C1
          BCS  TRY_SLOT      ; Stop once we have gone past slot 1
          LDX  #$00
          SEC                ; Error - no SmartPort found
          RTS

SETUP_SMARTPORT
* This function sets up the SP_CALL function for calling the
* SmartPort driver.  On entry, X=$Cx, where x is the slot number
* containing a SmartPort driver.  This should be checked via
* FIND_SMARTPORT if necessary - don't assume there is a SmartPort
* device in slot 5, for example!
          LDA  #$00
          STA  SLOTPTR       ; Set up the pointer
          STX  SLOTPTR+1
          LDY  #$FF
          LDA  (SLOTPTR),Y   ; Get the ProDOS driver entry point
          CLC 
          ADC  #$03          ; Get the SmartPort driver entry point
          STA  SP_CALL+1     ; Store in the JSR
          STX  SP_CALL+2     ; also store the high byte
          RTS

SP_GETDIB
* This function gets the device information block from a specified
* device on the active SmartPort.  The SETUP_SMARTPORT routine must
* have been called first.
* On entry, A contains the device number (1, 2, 3, ...).
* On exit, the STATLIST variable is filled in with the device
* information block, unless an error occurred.  C=1 if there was
* an error, and A contains the error code.
          STA  ST_UNIT       ; Store the unit number
          LDA  #$00
          STA  CMDNUM        ; Set up the command number
          LDA  #<STATUS_PB
          STA  CMDLISTP
          LDA  #>STATUS_PB
          STA  CMDLISTP+1    ; Set up the command list pointer
          LDA  #<STATLIST
          STA  ST_LISTP
          LDA  #>STATLIST
          STA  ST_LISTP+1    ; Set up the status list pointer
          LDA  #$03
          STA  ST_CODE       ; Set up the status code (GetDIB)
          JMP  SP_CALL       ; Go to the generic SmartPort call handler

* Insert additional functions here to implement other SmartPort calls
* as desired

SP_CALL
* This function is patched to call an arbitrary SmartPort driver,
* using an arbitrary command number and command list.
          JSR  $FF58         ; Operand is patched with driver address
CMDNUM    DS   1             ; Patched with command number
CMDLISTP  DS   2             ; Patched with command list pointer
          RTS                ; Return to caller

STATUS_PB
* Parameter block for issuing status calls
          DFB  $03           ; Parameter count
ST_UNIT   DS   1             ; Unit number goes here
ST_LISTP  DS   2             ; Status list pointer goes here
ST_CODE   DS   1             ; Status code goes here

STATLIST  DS   25            ; General purpose status list buffer


With a little wrapper code, this could be extended into a program that
searches for every SmartPort in the system, determines the number of
devices supported by each SmartPort (using a Status call to unit 0 with
status code 0 - see page 125), gets information about each device, and
prints the whole lot out on the screen.

-- 
David Empson
dempson@actrix.gen.nz
Snail mail: P.O. Box 27-103, Wellington, New Zealand