[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