2

I'm trying to write a calculator program in assembly for the Apple //e. I know that there are built-in subroutines for performing all kinds of math operations involving the floating-point accumulator (FAC), and I'd like to use those.

I'm trying to use FRMNUM ($DD67) and PRNTFAC ($ED2E) to carry out the math and print the result, but it's not working.

Below is a sample program designed just to add 1 and 1 and print 2, but the program winds up in a loop.

It puts the data 31 c8 31 00 (= 1 + 1) at memory address $7000, points TXTPTR (which is the pointer used by the FRMNUM subroutine) at that address, runs FRMNUM and then runs PRNTFAC which should print the result on the screen.

It doesn't. It winds up in a loop somewhere in the $DD's, ie in FRMNUM.

EDIT 1: Here is a link to the calculator program I'm working on. I can't copy and paste it into here because it's too long.

EDIT: Here's the commented data in text format.

*=============
* PRNTFAC TEST

        ORG $6000

HOME    EQU $FC58
FRMNUM  EQU $DD67
PRNTFAC EQU $ED2E
TXTPTR  EQU $B8
PTR     EQU $06

* CLEAR SCREEN

START    JSR    HOME

* MAKE BOTH POINTER AND TXTPTR
* POINT TO $7000

         LDA    #$00
         STA    PTR
         STA    TXTPTR
         LDA    #$70
         STA    PTR+1
         STA    TXTPTR+1

* LOAD CONTENT OF DATA
* TO $7000

         LDX    #$00
         LDY    #$00
]LOOP    LDA    DATA,X
         STA    (PTR),Y
         BEQ    NEXT
         INX
         INY
         JMP    ]LOOP

* $0700 NOW CONTAINS
* 31 C8 31 00 (I HAVE CHECKED
* THIS USING THE DEBUGGER)

* RUN FRMNUM

NEXT    JSR FRMNUM

* RUN PRNTFAC
* IF PRNTFAC OPERATES LIKE
* COUT, A "2" SHOULD BE PRINTED
* AT THE TOP LEFT CORNER OF THE
* SCREEN

        JSR PRNTFAC

END     RTS

DATA    HEX 31C83100
15
  • 2
    Doing floating-point decimal input in hex seems to be an unusual choice. Did you really mean that? It seems to be contradicted by your last sentence.
    – dave
    Commented Apr 3, 2021 at 14:33
  • 2
    What are you trying to do that FRMNUM doesn't? Are you looking for a something like FIN (6502disassembly.com/a2-rom/Applesoft.html#SymFIN)?
    – fadden
    Commented Apr 3, 2021 at 14:51
  • 5
    So the input is decimal? The user types "123.456" on the keyboard, not "7B.1CB"?
    – dave
    Commented Apr 3, 2021 at 16:02
  • 2
    Applesoft BASIC stores expressions in tokenized form, but numeric constants are just strings of ASCII digits. FRMNUM will evaluate a numeric constant or expression into a value in FAC. You'd need a '+' token ($c8) rather than a '+' character ($2b/ab) if you wanted FRMNUM to add two numbers. Use the "command-line" tokenizer routine if you want to evaluate plain text (and aren't in a hurry). (Also: I suggest you refer to a string of ASCII digits as a string of ASCII digits, rather than "hex format", which is a bit unclear.)
    – fadden
    Commented Apr 3, 2021 at 16:06
  • 1
    @AlGorithm At this point you've pivoted from "how do I solve this problem" to "why doesn't my code work". Other forums may be better for that type of question; perhaps comp.sys.apple2 or reddit (it looks like you've already found the latter... reddit.com/r/apple2/comments/mivith/…). I don't see anything obviously wrong with your code; my advise would be to set a breakpoint at $6000 and walk through it. And be sure you're invoking it from the monitor, not Applesoft (since you're trashing TXTPTR).
    – fadden
    Commented Apr 4, 2021 at 21:14

1 Answer 1

3

but I don't know how to convert the set of hex digits the user inputs into memory into the format required for the FAC

I have a strong feeling that this is not about hex, but binary integers, 16 bit or more.

I know about FRMNUM ($DD67) and PRNTFAC ($ED2E), but I can't find the subroutine that Applesoft uses to take a decimal number and convert it to the six-bit exponent-mantissa format.

You're already on the right track. For example GIVAYF ($E2F2 *1) converts a 16 bit integer held in A/Y (High/Low) into a floating point number in FAC.

; Converting a 16 bit value to FAC
; IN:  -
; OUT: $1234 as FP value in FAC

     LDA   #$12       ; 16 Bit $1234 in A/Y
     LDY   #$34
     JSR   GIVAYF     ; Convert it to FAC

     ...

Of course this is less handy if your numbers are not straight integers, but some format of your own - which brings us to what might be the primary issue:

Where is your data is originated?

Is it from some internal storage, or user input. If it's from user input why not skipping the task of reading a number, turning it into some two part integer and then convert it to FP and use the Applesoft input routines directly?

Which again takes us back to the already mentioned FRMNUM, which fetches a numeric input from where TXTPTR ($B7) points to and evaluates it into a value in FAC. Of course FRMNUM is a rather complex beast, doing all sort of things, including expression evaluation (*2) not just for numbers but strings as well.

A more down to the minimum task version would be FIN ($EC4A), which reads a ASCII string and turns it into FAC. FIN expects again TXTPTR to point to the string to be converted, but as well the first character already read into A. It will use GHRGET to fetch additional characters. CHRGET reports colon (':') or end of line ($00) as terminators (*3). Numbers read are in the format of [sign]integer[.integer[E[sign]integer]]. Anything not fitting that format will terminate, so best use a colon or zero byte. It returns with the number in FAC, or an error. Calling it could look like this:

; Converting a numeric string to FAC
; IN:  String in MYBUF
; OUT: FP value in FAC

     LDA   #<MYBUF    ; Lets point to the number we've inputted
     STA   TXTPTR
     LDA   #>MYBUF
     STA   TXTPTR+1

     JSR   CHARGOT    ; Get the first byte into A
     JSR   FIN        ; Convert it to FAC

     ...


MYBUF DC '123.456E-7',':'.

That's it.


No, of course not. There's always more: A nice side effect of its use of CHRGET is that it not only moves TXTPTR along, but also ignores spaces, so one may go ahead and convert a series of numbers in sequence if they are separate by terminators (colon or NUL). This could easy be used to hold numbers between operations as text, easy for display and convert them on the fly for usage. Like holding a calculator stack in four fixed length fields.

This needs a way to turn FAC into a number again, which FOUT ($ED34) conveniently will do - it's essentially the core code of PRNTFAC, just without outputting the data.

Which brings us once again back to FRMNUM. By arranging numbers as above, but replacing the terminator bytes with applesoft token, it could be feed to FRMNUM, doing all the calculations right away. It might be a bit slower than handling everything as FP as long as possible, but then again, this might not really matter for a user input driven calculator.

Oh, possibilities are endless again :))


On a side note, it would be great if you could not only comment your source (*4), but as well add it not as picture but text. This does not only increase readability, but helps others a lot to reply with code sniplets you might love to get.


*1 - I always loved that address, it's o easy to remember: Enteger to Float too (yeah, I know, silly, can't help)

*2 - Sadly not as convenient as some other BASICs VAL()functions, as it ecpects the operators to be tokenized. Which of course could be done, essentially turning you'r calculator into a single line program, but that's a different story.

*3 - For the workings of GHRGET/GOT you might want to take a peek at the Apple Assembly Line 1/12 - which is always a good read if you want to get into Assembly on the Apple II. IIRC the whole series has been republished recently as a book. Worth a read.

*4 - I would consider some header describing input/output/task a bare minimum to each and every function. Keep in mind, you want to read your code in 10 years from now as easy as it is today - without a need to dissassemble your own thoughts.

4
  • Thank you for this. I've commented the code and also posted a link to the PDF of the big program I'm working on. The user input can be in any format. Right now, if you look at the code, it's in ASCII in the display area (eg 1 = B1) and converted to hex numbers in the memory area (e.g. 1 = 01) which I created for mathematical manipulation. It turns out I should use C1 for 1. Converting the input to the correct format isn't a problem. I just need to know how to get that data into the proper subroutines and then extract the result in a format I can print in the "calculator display."
    – Al Gorithm
    Commented Apr 4, 2021 at 14:09
  • ASCII is a 7-bit code, but it appears the Apple expects the high bit set. '1' in ASCII is 0x31, or 0xC1 if you set the high bit. But terminology note - in memory it's just bits, it's not inherently hex or decimal or anything. It only depends on how you look at it.
    – dave
    Commented Apr 4, 2021 at 15:26
  • @another-dave Yes and no. It's true, the Apple uses a set high bit on key codes, as this signals a fresh keystroke, and yes, coding in Video-RAM is even more mangled, but no, in BASIC, as the high bit is cleared. This is true for any data, as well as for tokenized BASIC. After all, it's a rather plain MS-BASIC with tokens occupying the range above $7F.
    – Raffzahn
    Commented Apr 4, 2021 at 15:56
  • I can convert the user input (eg "123" to 31 32 33) for use in with FRMNUM. That's not the issue.
    – Al Gorithm
    Commented Apr 4, 2021 at 16:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .