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

Re: Innovative Systems FPE...



mdj wrote:
On Aug 17, 5:39 am, "Michael J. Mahon" <mjma...@aol.com> wrote:


Right. I was considering that they may have mapped the register
directly to the IO space, which would then have endianness
implications....

Ah, yes.  The "operand" register is allocated 4 bytes of /devsel
space (since the 68881 memory interface was 32 bits), and the
bytes are big-endian within that window.  For all datatypes larger
than 4 bytes, the window is reused, with the most-significant words
presented first.

I think the only way to change this with the glue chip would have
been to buffer the entire result on the chip, which would have
been considerably more complex, both in amount of logic and in the
decoding of 68881 status information to derive operand length.

Because of the order of presentation, it is necessary to deal with
the 68881 data higher-significands first, so to use little-endian
representation on the 6502 requires accessing the 6502 data from
highest to lowest address.


I see. I had figured it would make the most sense to byte-swap that
window so one could loop using one register for copy in/out but I
suppose you can simply unroll the loop.

That was the approach used in the iS FPE macros.

My plan is to represent 2-byte and 4-byte integers in little-endian
(since it is pretty easy to deal with those transfers), and all FP
datatypes in big-endian, which is the natural order for the 68881.




Upon reviewing the macros converted for Merlin, it's apparent
that they were never used or tested, since they have numerous
errors.  They also suffer from the delusion that floating-point
numbers should be represented in little-endian form on the 6502,
which Applesoft contradicts.

Curious, since the 68k is big-endian, but I suppose you can load the
registers more quickly on an 816 that way...

Since the 65816 has no notion of the meaning of floating point data,
that choice is arbitrary.  Did Apple choose little-endian representation
for SANE FP numbers?

It's little, and the call interface is essentially push two addresses
onto the stack plus an operand code and call the entry point.

I suspect that this allows some slight optimisations since in little
endian the floating point mantissa has the same address as an integer
type does, though I admit this is 'gut feel'

Actually, I doubt it.

The only data endianness "enforced" by the 6502 is that involved in
indirect addressing, which has nothing to do with FP.

True. Since access to FP data is likely to be indirect in code, I was
considering there may be differences in type conversion situations.
Consider for instance the conversion of an integer to a single
precision float can be a no-op if the high order byte is zero, which
can be done quickly in big endian if you can avoid initializing an
index register. Of course that applies only to the C02 and 816...

But then the number should be normalized, requiring all the usual
apparatus.


Of course, little endian in software is faster on an 816 due to being
able to exploit 16 bit addition/subtraction, although this is a very
small gain in practice I'd imagine.

Good points.  ;-)


Many FP implementations choose big-endian just because it's a lot
easier to visualize the shifts, etc., than in little-endian mode.  ;-)

;-) If one is prepared to visualise memory addresses bassackwards I
agree ;-)

I guess I don't see any "backwardness".  Little-endian has always seemed
"backward" to me, since in "real life" we always write numbers big-
endian.  (And the 68881 supports packed BCD extended FP numbers!)


My mental model of (computer) memory runs either left-right or bottom-
up so it feels natural to me to place higher order bytes in higher
order addresses. So if you consider for example addition on an
arbitrary length number, the code looks more 'right' to me in little-
endian. It's also a much more 'natural' fit for evolved architectures
where the word size has been increased through several generations.

Interesting.  I often envision it with increasing addresses going
down, as in a code listing or a memory dump--and, of course, left-
to-right within a line.

About the only time I might consider addresses to increase going "up"
would be a graphical memory map, but even then, I usually rotate it
so that addresses increase from left-to-right.  ;-)

Of course, ever since elementary school, numbers have been written
left-to-right and arithmetic operations have proceeded from right-
to-left and top-to-bottom.  ;-)

As an aside, I once programmed extensively on a machine (B3500) that
was a storage-to-storage BCD machine with variable field lengths.  It
addressed all fields in memory by their lowest-addressed digit, which
was the most significant digit, and even did all arithmetic from left-
to-right.

This sounds quite difficult until you realize that a carry out from a
later (lower-significance) digit can only propagate through a contiguous
string of 9s, so it is only necessary to keep a count of how many such
9s would have been produced until a digit less than 9 is produced, when
all the delayed result digits can be written as either 9, if no carry,
or 0 with the previous result incremented by one, if a carry occurred.

That said, I would happily agree that if one has the luxury of
designing a modern processor from scratch, I would favour big-endian
representation ;-)

On the occasions when I've been able to do that, I did!

Does anyone know how many of these things were made, and if
anyone ever used one successfully with a //e?  My serial number
is 890005, so I'm guessing they weren't very popular.  ;-)

I'm making progress, but feel like completely redesigning
the macros to use a small runtime FPE package.

I'm liking this approach more and more.  A simple calling sequence
like:
     LDA #~          ; Half of opcode
     LDY #~          ; Other half of opcode
     JSR KindOfFPop  ; RegReg, MemReg, RegMem, + Other ops
     DA  memaddr     ; (only for ops with memory refs)

This has the advantage of being relatively compact, very fast for
RegReg and Other ops (like compares), and fast enough for memory ops.

I'm also planning to make the runtime a Merlin "put" file, so that
only the routines actually used will be assembled in the code.

A "full" mode for the runtime will also be provided that can be
separately assembled and used by a number of assembly programs.


That looks pretty close to perfect to me!

It's coming along...  ;-)

I'm currently trading time for space, by using loops to move
FP data, but that's an easy tradeoff--maybe even a type-by-type
compile-time option.  ;-)

                                               A further
out possibility is making an interface to Applesoft, since
the 12MHz 68881 clock compensates for the relatively weird
dance one must do with the 6502 to load operands, perform
instructions, and store results.

This might be a more interesting thing to do if there were
more of them in use...

Well, if you managed to make a patchset for Applesoft and somebody
wanted to produce some, it'd be a mighty fine accelerator
companion... How complex is the board?

Simply complex.  ;-)  It's basically a 68881 and a Xylinx XC2064
glue chip (plus a TTL transceiver).

Looking over the Applesoft listing, I see a lot of "fiddling" with
the floating-point accumulator, so it would be difficult to simply
map FAC and ARG to 68881 registers.

The easy way (?) would be to convert Applesoft's FAC and ARG into
and out of the 68881 on pretty much every operation worth speeding
up (multiply, divide, math functions, BCD conversions), which would
require a lot of annoying movement of data...

Right. A 'good' card would have a mode that presented Applesoft
compatible registers (didn't the older ones do that ?) but I suspect
optimising for SANE was the first order of business.

Since the 68881 and all contemporary FP coprocessors directly
implemented IEEE FP, which SANE is a software implementation of,
it was natural to use IEEE formats.

I don't know of any coprocessor that implemented Applesoft-format
FP numbers, except possibly by a software patch.  Certainly no
hardware ever did!

It would be possible to load/unload memory values to/from a buffer
register in the "glue" logic, which would then transform them on
their way to the coprocessor, but that would be much more complex
logic for the time, and would specialize the interface.

Maybe FP coprocessor card makers figured that if you were using
Applesoft, you weren't too interested in speed.  ;-)  But that could
certainly be said for those using SANE--it's slow as molasses!

I guess on reflection it doesn't make much sense to optimise the
hardware for Applesoft ...

Considering SANE only implements 80bit precision as an arithmetic type
(all others are storage only) one wonders how they used 8k of memory
and still managed to be slow ...

I think you said it all when you said 80-bit arithmetic.  That's a
terrible penalty right off the top when 32-bit mantissas are enough
for "all practical purposes".  ;-)

The very general interface is also pretty slow compared to a simple
accumulator/aux register approach.  The SANE package pretty much
emulates an IEEE coprocessor (and was no doubt designed to stand in
for one).

The speed-memory tradeoff is also interesting.  I note that SANE
often loops over the mantissa bytes/words rather than coding it
straight-line.  That's also a pretty sizable speed penalty.


Indeed. I suppose the main goals were portability and the capacity to
plug in hardware implementations without modifying existing
applications. The cost is that common case (no hardware) is bloatware.

All in all, a pretty poor tradeoff IMO.

Compared to what it might have been, yes.  But no one seems too upset
by the speed of recalculates in the Appleworks spreadsheet, so, as they
say, "good enough is good enough".  ;-)

It would be painful in an FP-intensive Pascal program, but I'm guessing
that there weren't too many of those.  ;-)

I'm going to be looking at conversion of IEEE to/from Applesoft format,
and I expect it to involve a shift and a little bit fiddling, but not
too much to do on-the-fly.

The main pain comes from dealing with sign extension of the exponent
when moving to/from the larger double (or extended) precision
representation...

It's not too bad, since it's just replicating sign bits in front of
the sign to get the correct exponent length.  Then there's a small
"excess" adjustment.

The biggest problem is that the IEEE sign of the mantissa is stored
ahead of the exponent instead of in place of the implicit bit of the
mantissa.  That requires a shift of the mantissa.  ;-(


I have never understood why that was the case - perhaps a result of
never having designed a hardware FP multiply circuit ...

IEEE floating-point was definitely *not* designed with much hardware
input!  Kahan was a mathematician, and, like many others, just assumed
that Moore's "Law" would take care of all the heavy lifting.  In fact,
it took a decade to learn tricks to permit *fast* IEEE FP, as opposed
to the heavily microprogrammed "hardware" of FP coprocessors.

As I'm considering how to exploit the FPE from Applesoft, however,
I find myself leaning toward simply CALLing small chunks of slow FP
computation (involving functions, etc.)--that would be both fast and
easy, with a small number of conversions from/to Applesoft format only
on entry and exit.

This would be a natural for matrix operations.  ;-)


A comprehensive solution would begreat to have 'in theory' but since
any application that depended upon the additional speed is not
'portable' in practice I think your solution is more than adequate.

Sounds like a lot of fun to play with!

Just as I'd hoped.  ;-)

-michael

NadaNet and AppleCrate II: parallel computing for Apple II computers!
Home page: http://home.comcast.net/~mjmahon

"The wastebasket is our most important design
tool--and it's seriously underused."