Path: blue.weeg.uiowa.edu!news.uiowa.edu!uunet!usc!howland.reston.ans.net!europa.eng.gtefsd.com!news.uoregon.edu!cie-2.uoregon.edu!nparker
From: nparker@cie-2.uoregon.edu (Neil Parker)
Newsgroups: comp.sys.apple2
Subject: Useful info for USR (was Re: Two ways to torture a comp teacher)
Date: 3 Aug 1994 10:11:06 GMT
Organization: University of Oregon Campus Information Exchange
Lines: 156
Message-ID: <31nqfq$1cg@pith.uoregon.edu>
References: <9408011509.AA10580@phy.mtu.edu> <1994Aug1.125938.30290@cobra.uni.edu>
NNTP-Posting-Host: cie-2.uoregon.edu
In article <1994Aug1.125938.30290@cobra.uni.edu> fishern3485@cobra.uni.edu
writes:
>>>also try ?usr(1) and that sometimes will do it.
>>
>> Quick question: Has anyone ever used USR() to do anything useful? I've
>> been using Apple II's for a long time, and I've never, ever, seen this
>> function appear.
>>
>> Also, how 'bout a quick demo of how to use USR()? I have a general idea,
>> but none of the documentation I've seen has included an example.
>
>I recall that the USR function basically starts by doing a call 10.
>When you RTS from your code, I think it returns the number stored
>around $A5 or so. (in floating point, of course; ick!)
>
>It's a good way to call a routine if you don't want any return, or if
>you feel like fiddling around with floats. There is also a routine
>I forget where, that you can call that encodes a 16 bit integer you supply
>and loads it into the above location. Definitely don't quote me on the
>location, I'm probably wrong.
When Applesoft encounter the USR token, it evaluates the expression between
the parentheses, and then JSR's to location $A. Normally location $A
contains a JMP $E199, which immediately causes ?ILLEGAL QUANTITY ERROR.
You can set up your own handler by poking a JMP instruction to it into
locations $A, $B, and $C (it works almost exactly like the "&" vector at
$3F5).
The argument of USR (and also of just about every other arithmetic function
in Applesoft) is found in the Floating-Point Accumulator, or FAC:
FACEXP EQU $9D ;Exponent
FACHO EQU $9E ;Mantissa (high byte)
FACMOH EQU $9F ;Mantissa
FACMO EQU $A0 ;Mantissa
FACLO EQU $A1 ;Mantissa (low byte)
FACSGN EQU $A2 ;Sign
If the exponent is zero, the number is zero.
If the exponent is not zero, then the number is 2^(exponent-$80)*manitssa
(i.e. the exponent has $80 added to it, so that an exponent of $80 means
2^0).
The decimal point in the mantissa is assumed to be to the left of the high-
order bit. The high-order bit is always 1 (i.e. denormalized numbers are
not allowed).
Only bit 7 of the sign is significant--0 means a positive number, and 1
means negative.
Examples: The number 1 is stored as $81 80 00 00 00 00. This is
interpreted as 2^1*.5.
The number -10 is stored as $84 A0 00 00 00 FF. This is interpreted as
2^4*(.5+.125)*(-1).
The number 0.375 is stored as $7F C0 00 00 00 00. This is interpreted as
2^(-1)*(.5+.25).
This format differs slightly from how numbers are stored in variables.
Since the high bit of the mantissa is always 1, we don't really need to
save it...instead, Applesoft stores the sign in the high bit of the
mantissa instead of in a separate byte, so real variables only require 5
bytes instead of 6. Thus, 1 is represented as $81 00 00 00 00, -10 is
represented as $84 A0 00 00 00, and 0.375 is represented as $7F 40 00 00
00.
For more information on Applesoft real variables, see Apple II
Miscellaneous Technical Note #9: Applesoft Real Variable Storage.
Several routines are available for converting numbers in the FAC to
integers, and vice versa:
QINT EQU $EBF2 ;Convert FAC to signed int in FACHO(hi), FACMO, & FACLO.
AYINT EQU $E10C ;Convert FAC to signed int in FACMO(hi) and FACLO.
GETADR EQU $E752 ;Convert FAC to unsigned int in LINNUM ($50, $51).
SNGFLT EQU $E301 ;Convert signed int in Y to FAC.
GIVAYF EQU $E2F2 ;Convert signed int in A(hi) and Y(lo) to FAC.
SNGFLT EQU $E301 ;Convert unsigned int in Y to FAC.
If you want to do math directly on the floating-point number in the FAC,
there are plenty of routines to help. Several of these routines use a
second floating-point accumulator, called ARG:
ARGEXP EQU $A5 ;Exponent
ARGHO EQU $A6 ;Mantissa (high byte)
ARGMOH EQU $A7 ;Mantissa
ARGMO EQU $A8 ;Mantissa
ARGLO EQU $A9 ;Mantissa (low byte)
ARGEXP EQU $AA ;Sign
The single-argument routines take the argument in the FAC, and return it in
the FAC. The two-argument routines take one argument in the FAC and one in
ARG, and return the result in the FAC.
FADDT EQU $E7C1 ;FAC = ARG + FAC (must LDA FACEXP first)
FSUBT EQU $E7AA ;FAC = ARG - FAC (must LDA FACEXP first)
FMULT EQU $E982 ;FAC = ARG * FAC (must LDA FACECP first)
FDIVT EQU $EA69 ;FAC = ARG / FAC (must LDA FACEXP first)
FPWRT EQU $EE97 ;FAC = ARG ^ FAC (must LDA FACEXP first)
FANDT EQU $DF55 ;FAC = ARG AND FAC
FORT EQU $DF4F ;FAC = ARG OR FAC
NEGOP EQU $EED0 ;FAC = -FAC
NOTOP EQU $DE98 ;FAC = NOT FAC
SIGN EQU $EB82 ;A=1 if FAC>0, A=0 if FAC=0, A=$FF if FAC<0
FADDH EQU $E7A0 ;FAC = FAC + 1/2
DIV10 EQU $EA55 ;FAC = FAC / 10 (returns positive numbers only)
MUL10 EQU $EA39 ;FAC = FAC * 10
SGN EQU $EB90 ;FAC = SGN(FAC)
INT EQU $EC23 ;FAC = INT(FAC)
ABS EQU $EBAF ;FAC = ABS(FAC)
FRE EQU $E2DE ;FAC = free memory (forces garbage collection)
PDL EQU $DFCD ;FAC = PDL(FAC)
POS EQU $E2FF ;FAC = current cursor column
SQR EQU $EE8D ;FAC = SQR(FAC)
RND EQU $EFAE ;FAC = RND(FAC)
LOG EQU $E941 ;FAC = LOG(FAC)
EXP EQU $EF09 ;FAC = EXP(FAC)
COS EQU $EFEA ;FAC = COS(FAC)
SIN EQU $EFF1 ;FAC = SIN(FAC)
TAN EQU $F03A ;FAC = TAN(FAC)
ATN EQU $F09E ;FAC = ATN(FAC)
PEEK EQU $E764 ;FAC = PEEK(FAC)
Many of these routines exit to the Applesoft error handler instead of
returning to the caller if anything goes wrong. This is probably fine for
USR functions, but if you're writing a standalone program that isn't called
from Applesoft, you'll need to range-check your arguments before calling
any of these routines.
Before using the contents of the FAC, it's a good idea to make first make
sure that the FAC actually contains a number (rather than a string). You
can check this by looking at the zero-page location VALTYP ($11). VALTYP
contains 0 if the FAC contains a number or $FF if the FAC contains a
string. (Note that a few of the above function handlers fail to do this--
thus EXP(A$) causes ?TYPE MISMATCH ERROR, as it should, but LOG(A$) in
immediate mode causes ?ILLEGAL QUANTITY ERROR, and on my IIGS, PEEK("")
actually succeeds and returns a value...)
Similarly, your USR handler should always store a 0 in VALTYP when it's
done, to tell Applesoft that you're returning a number.
If the preceeding two paragraphs make you suspect that USR functions can
handle strings too, you're right--they can accept strings as arguments, and
return strings as results. Unfortunately, dealing with strings is harder
than dealing with numbers, because you have to make make special calls to
handle allocating and freeing up string space, and to deal with Applesoft's
internal string-descriptor stack. I won't discuss strings any further,
mainly because I don't yet fully understand how the string-management
routines interact.
Reference: Apple Computer, Inc. (from contact John Crossley), "Applesoft
Internal Entry Points", _The_Apple_Orchard_, March/April 1980, pp. 12-18.
- Neil Parker
--
Neil Parker No cute ASCII art...no cute quote...no cute
nparker@cie-2.uoregon.edu disclaimer...no deposit, no return...
nparker@cie.uoregon.edu (This space intentionally left blank: )