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: )