💾 Archived View for mirrors.apple2.org.za › archive › ground.icaen.uiowa.edu › MiscInfo › Empson › p… captured on 2024-07-09 at 04:23:09.

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

Newsgroups: comp.sys.apple2.programmer
Path: news.uiowa.edu!news.physics.uiowa.edu!math.ohio-state.edu!howland.reston.ans.net!newsfeed.internetmci.com!in2.uu.net!comp.vuw.ac.nz!actrix.gen.nz!dempson
From: dempson@atlantis.actrix.gen.nz (David Empson)
Subject: Re: What do PR# and IN# do inside?
Message-ID: <DKnAEM.4AJ@actrix.gen.nz>
Sender: news@actrix.gen.nz (News Administrator)
Organization: Actrix - Internet Services
Date: Thu, 4 Jan 1996 07:06:21 GMT
References: <4cdsrc$cpi@yama.mcc.ac.uk>
X-Nntp-Posting-Host: atlantis.actrix.gen.nz
Lines: 146

In article <4cdsrc$cpi@yama.mcc.ac.uk>,
Duncan Entwisle <duncane@jumper.mcc.ac.uk> wrote:
> I'm thinking of creating my own mouse card to mimic Apples. I just need 
> to know how IN# and PR# work. I know that they are meant to initialise 
> the card in the slot by calling Cn00, but..

IN# and PR# don't do anything to the card at all.  They just change
the I/O hooks (CSW, locations $36 and $37, points to the output
routine, and KSW, locations $38 and $39, points to the input routine).

If you use BASIC's built-in PR#/IN# commands, the I/O hooks are
changed, and the disk operating system is disconnected (DOS and ProDOS
use these hooks to retain control over BASIC).  DOS 3.3 and ProDOS
provide their own PR#/IN# commands which you use via PRINT CHR$(4),
which work in the same way, but don't cause the operating system to be
disconnected.

With either method, the sequence of events is as follows:

1. The program uses PR# or IN# to set the output or input slot.
   This causes CSW or KSW to be changed to $Cn00, where n is the
   specifed slot.  (If you use PR#0 or IN#0, the monitor's internal
   COUT1 and KEYIN routines are selected.)

2. When the program next using a PRINT statement which outputs
   anything (for PR#; INPUT or GET is used for IN#), the current
   output or input routine is called via the output/input hook.

   Assuming you had done PR#1, the next character printed will be
   sent to the routine at location $C100.

   With most I/O cards, this location is the initialization entry
   point.  The firmware sets itself up, then outputs the character
   (or inputs a character - see below for details).  In the process
   of doing this, the appropriate I/O vector is modified to point to
   the start of the actual output or input routine within the $CnXX
   page.  Subsequent output (or input) goes directly to the appropriate
   routine and doesn't invoke the initialization routine again.

3. If you were using DOS or ProDOS's PR#/IN# commands, the operating
   system regains control after the firmware has been initialized.  The
   output or input vector is copied elsewhere and DOS/ProDOS's own
   vector is restored.  The I/O card doesn't need to know about this.

On to your questions:

> 	(1)	How does it know whether called by IN or PR?

The firmware checks the I/O vectors (CSW for output, KSW for input) and
behaves according to whichever of them is pointing to $Cn00.

e.g. if you used PR#1 followed by a PRINT statement, the sequence of
events is (ignoring DOS/ProDOS):

1. PR#1: sets $36/$37 to $C100.
2. PRINT: calls $C100.  This checks $36/$37 and sees $C100, meaning
   this is an output call.  After initialization, the output vector is
   updated and the character in A is output.

There is no rule about which vector to check first.  If the programmer
uses PR#1 followed by IN#1 without doing a PRINT first, then the card
cannot tell whether this is an input or output call, so it will
probably assume one or the other (depending on the order in which the
vectors are checked).  I think this sort of problem is avoided by
using the DOS/ProDOS versions of the command.

> 	(2)	Where are the vectors located that my card software would
> 		change for future accesses by input/print.

$36/$37 (CSW) is the output vector, $38/$39 (KSW) is the input vector,
both in the usual low/high order.

You need to know which slot you are in, which can be determined by
calling a known RTS instruction in the ROM, and looking back on the
stack for the high byte of the return address.  You must disable
interrupts while doing this.  The code goes something like this:

    PHP
    SEI
    JSR $FF58
    TSX
    LDA $0100,X

A now contains $Cn, where n is your slot number.  This works because
the stack pointer is the index into page 1 of the NEXT byte to be
pushed onto the stack, so after a JSR/RTS, [$0100+S] contains the high
order byte of the return address.  This is accessed by transferring
the stack pointer to the X register, and indexing into page 1 to get
the byte.

The reason that interrupts must be disabled is that if an interrupt
occurred between the RTS and the LDA instruction, the byte at
[$0100+S] would be overwritten.

(You would have to PHA before doing any of this, to save the original
value in the accumulator, which might be an output byte.)

> 	(3)	Would I need to deal with ascii characters, or would print/
> 		input automatically do the type conversions for me?

It depends where the text is coming from.  Applesoft BASIC will always
output data through CSW with bit 7 set, as printed by the BASIC
program, e.g. CR at the end of each line (same format as a DOS 3.3 text
file).  Bit 7 probably doesn't matter on input.

A machine code program could output text with bit 7 in either state,
and may decide to output other control characters (e.g. line feeds)
though this is not likely.

The X/Y registers don't matter.  A is defined on entry for output, and
must be set on exit for input.


Note: this is only one of the I/O methods commonly supported by I/O
cards in the Apple II.  The other methods are the "Pascal 1.0 firmware
interface" (somewhat rare, poorly documented, and hardly ever required)
and the "Pascal 1.1 firmware interface" (much more common).

The Pascal 1.1 firmware interface involves a series of identification
bytes at known points in the ROM space, and a table of entry point
offsets to INIT, READ, WRITE and STATUS routines.  These are more
flexible than the BASIC entry point, allowing non-blocking I/O, for
example, by polling the STATUS routine to find out whether input is
ready or the card is ready for output.

The Apple Mouse supports these entry points, but they don't do
anything.  It extends the entry point table to provide a lot of
additional routines for performing mouse operations such as setting
the mode, positioning the mouse, getting the mouse status, handling
interrupts, etc.  Nearly all 8-bit programs that use the mouse expect
this set of routines, so implementing the PR#/IN# "BASIC" interface
will not get you very far.

> Sorry if this is all basic "in-the-manual-stuff", but there aren't
> many 8-bit apples in the UK, and decent documenatation is even rarer. 

Most of this is covered (rather more tersely) in the Apple IIe
Technical Reference, which is not available any more.  It is also
covered in the 2nd edition of the Apple IIc Technical Reference, which
IS available (from Byte Works), and the IIgs Firmware Reference (which
isn't).

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