A86: OP Registers Explained


[Prev][Next][Index][Thread]

A86: OP Registers Explained



In a message dated 97-09-28 15:48:51 EDT, you write:

> 
>  To get the value of 2 into OP1, do this:
>  
>  ld	hl,_OP1
>  ld	(hl),2
>  
>  To get the value of OP1 into A do this:
>  
>  ld	hl,_OP1
>  ld	A,(hl)
>  
>  Someone correct me if I'm wrong about moving it into A.

That doesn't work.  OP1 is an 11-byte area in RAM, as is all the other 5 OPs.

In other mails, I saw things like:

ld _OP1,(N)

and the like.  These also don't work.

_OP1, _OP2, etc. are contants representing addresses in RAM.  When you say
"ld hl,_OP1" then you point hl to that op register, so that (hl) is the FIRST
byte in OP!, which is the sign byte.  The sign byte is either $00, $01, $80,
$81, given that there is a real/complex value stored in that OP.  The sign
byte is composed of the following bits:

7 (MSB): Sign bit - 1 if neg, 0 is pos
6-1: 0
0 (LSB): Real/Cplx bit - 0 if real, 1 if complex

The next 2 bytes are the exponent bytes.  They are swapped in mem, because
they form a word, so if it was $FC00 (exponent of 0), it would be stored as
00 FC.  Anyway, from here, the exponent is gotten by subtracting FC00 from
this word.  (ex. 1 is $FC01, 255 is $FCFF, 256 is $FD00, -1 is $FBFF, and
-255 is $FB01.)  The next 7 byts form the mantissa, in BCD.  It's a sequence
of 14 digits.  For example, if the mantissa was 12345678901234, it would be
stored 12 34 56 78 90 12 34.  There should be no hex digits (A-F) in this
part.  Finally, the last byte is, I think, just an extra byte that has no
effect on the number, as real # var in mem are only 10 bytes.

To translate from these 10 bytes to a real number, you do the following:
1. Get the sign byte and check the 7th bit to get the sign (-/+). We'll say
that it's + in this example
2. Get the exponent from the next word.  We'll use 5 in the example.
3. Get the mantissa from the next 7 bytes.  We'll say that it's 12 30 00 00
00 00 00.

That number would translate to 1.2300000000000e+5  (123000)

To store a number, say 4, in OP1, there are 2 options.
If the number is something like 4, you can just use the call that does just
that:
"call _OP1SET4".  If there is no call, you could use a combination of calls,
such as

call _OP1SET2
call _OP2SET5
call _FPMULT

to set OP1 to 10.  This probably isn't in the bestinterest for speed, but it
probably cuts down on the code length.  Finally, you could do this:

 ld de,_OP1         ;Destination
 ld hl,RealNum4   ;Source
 ld bc,10              ;Num bytes to load
 ldir                     lload bc (10) bytes from (hl) (RealNum4) to (de)
(OP1)

;More code

RealNum4:
 .db $00,$00,$FC,$40,$00,$00,$00,$00,$00,$00      ;4.0000000000000e+00

That works for any real #.

If you have a # in a register, like b, then it is a little more difficult.  I
had a hard time getting it to work for me, but it's in Chem86 at the
CpdMultDone label (or something like that).  I believe this is about what I
did:

;This loads b into OP1.  It doesn't work is b is 0, so you'd need to test it
beforehand
LD_OP1_B:
 push bc
 call _OP1SET0
 call _OP2SET1
 pop bc
Loop:
 push bc
 call _FPADD
 pop bc
 djnz Loop

I had to add all the pushes/pops because SOMETHING in ther destroys b and I
was having a hard time finding out what.  One pair is probably superfluous,
though.

Finally, to load an OP register into a real register (real meaning a, bc,
etc., not floating point), I'd use the following code:

 call _CONVOP1    ;I think this is in either ti86ops.inc or ti86math.inc, if
not, it's posted earlier.

Now, AHL holds the value (probably rounded, otherwise, I don't know what it
does if it's not an integer) of OP1.  If you know that it is less than 65536,
then you can just forget about A, and HL is the #.  (Same if you know it's
<256, then just L is the #)

I think that about covers all the misconceptions flying about this list in
the last day or so.

~Stephen Hicks

Geez that was a long mail!


Follow-Ups: