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

Re: P-Source: A Guide to the Apple Pascal System



David Schmenk wrote:
Michael J. Mahon wrote:

David Schmenk wrote:

mdj wrote:

On Nov 19, 3:03 pm, David Schmenk <dschm...@sbcglobal.net> wrote:

Anyone have a copy of this book, hardcopy or otherwise?  It has some
relevance to my latest project.  Thanks,



Mine is packed away and not easily retrievable. If you've got specific
questions about Apple Pascal I can probably answer most of them
however ...

Matt



There is a chapter on optimizing the p-code interpreter. I was curious as to what they were. I've been looking at the Apple Pascal 1.3 interpreter (thanks to Paul Santa-Maria!). I'm always interested in what others find to optimize.


For a *really* effective optimization, profile the p-code and translate
the "sufficiently hot" p-code to direct calls to the "execute" routines
or, if "extremely hot", translate the p-code to 6502 machine code.

For most programs, this approach can net a program whose code is less
than twice the size of p-code alone but within 10%-20% of being as fast
as pure (machine-generated) machine code!


I would consider that more along the lines of compilation, but of course optimization has many faces.

"Optimization" is pretty generic--meaning changing something to make
something better.  ;-)

Java bytecode is about as compact as p-code so even replacing a single byte opcode (the majority) with a three byte jump would add considerable code space. As you can imagine, memory is extremely scarce in this environment. Perhaps implementing an external bytecode->6502 compiler would be interesting for those cases that needed more performance. Doing hot-spot compilation on a 6502 seems like a lot of work for questionable trade-off.

This isn't easy, but for a compiler/interpreter programmer it's not
too hard, either.  The cutoff on how much you can optimize how far is
the available memory, since both optimizations are progressively larger
than the p-code translated.

Further complicating things is the fact that many applications will
run slower or not at all with much less available memory for data.


Not to mention the size of the optimizer. In fact, the size of the optimizer would probably approach that of the entire interpreter. Looking at about 12K for the interpreter, that leaves about 8K for bytecode and data :-)

For dynamic translation, that's true.  But great results can be
achieved (see DigiTek) with a completly static optimization based
on dynamic frequencies acquired during a profiling run.

This problem can be reduced for many programs by simply generating
code for "hot p-code" into a fixed-size cache, invalidating older
code on a LRU basis--an approach that used to be called "throwaway
compiling".  (For fast machines, re-generating code is usually faster
than "paging in" non-resident generated code.)


Running at a blazing 1 MHz here :-)

And originally doing 5.25" disk I/O at a whopping 10KB/sec.

That means if you can generate a byte in less than 100 cycles
(on average), re-generation is a win.  ;-)

If these approaches had been integrated originally, Java may not
have been necessary.  ;-)  Of course, the "machine code" optimization
is fully machine-dependent, so it's easy to see how the p-system
creators may not been interested in going there.

In the 1960s, at least one little compiler company (DigiTek) and
their successor (whose name I forget) *did* approach compilation
in this frame of mind, and as a result, they had the world's fastest
small compilers (or the world's smallest fast compilers ;), but they
kept the method pretty much to themselves as a competitive advantage.

-michael

NadaPong: Network game demo for Apple II computers!
Home page:  http://members.aol.com/MJMahon/

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


After reading through most of the book, Randy fixes the 6502 p-code interpreter, more than optimizes it. Some of the original code sequences were quite bizarre for doing comparisons. Other changes simply involved using PLA instead of adjusting the stack pointer through the X register. Still, its useful to review what he did.

I've seen tortuous sequences for compares and certain shifts, etc.,
in code translated from non-6502 architectures.  There's something to
be said for familiarity with the idioms...

There are some interesting benefits to keeping the bytecode interpreted on the Apple II. The 6502 is a pretty good interpreter machine; better than a native compile target, I think. In either case, signed comparisons are messy and the hardware stack is small. If you look at the generated code from cc65, it makes so many jumps to routines to manipulate the stack and do comparisons, it looks much like compiled bytecode.

Not only is the 6502 a good interpreter host, it's also a pretty bad
direct-compile host--primarily due to its lack of a variable stack and
a 16-bit register + 8-bit displacement addressing mode.

Most high-level language compilers take a "heavy runtime" approach,
which leads to something very much like "threaded code".

Another benefit is that pre-emptive threading is a simple exercise. Without a time-based interrupt, threading 6502 code requires cooperation. Pre-emptively threading bytecode can involve calling the scheduler after a fixed number have been emulated.

Right--but I can't think of any languages that used this approach.

One thing I've found out during this exercise is that current Java technology has really segmented itself. There are all sorts of versions out there to try and satisfy each market. A small device that runs Java has megabytes of memory and a 32 bit processor. Nano device have ~200K memory and 16 bit processors. Many of the small devices and almost all the nano devices have specialized build procedures that massage the Java class files into a more palatable native format. Doesn't that run counter to the write once, debug everywhere goal? The standard class library gets progressively smaller as the device shrinks, too. In the end, I think its a testament what the p-system was able to pull off with the technology available.

As it has always been, there is a tradeoff between portability and
efficiency--particularly for very small (but bigger than Apple II's)
platforms.

So I don't see how Java, as a platform, fits in to the modern computer world. Its all too busy being the enterprise solution for your server and entertainment solution for the cell-phone. But, nobody asked me and it seems to be everywhere.

That is, of course, it's intended purpose--since Sun introduced it
precisely to drive a wedge between Wintel platforms and the code that
runs on them.

Notice that the "incumbent" is never interested in portability, only
the "wannabe".  ;-)

Having said that, I think having a JVM (or KVM, using Java EE micro-edition 3.1415926 or is that Java Version 6p?, nomenclature) running on the Apple II is a great follow-up to Apple Pascal. Within limits, of course. The Apple II makes the nano Java devices look like big iron. As soon as I finish working out some issues with the garbage collector (I don't like automatic garbage collectors) I should have something to try out.

I completely agree.  I think that Java is a pretty "heavyweight" way
of programming a 64KB, 1MHz device.  For that matter, so is Pascal, but
the p-System (especially with RAM disk and an accelerator ;-) almost
makes it bearable.

Seen from the top down, the problems that have a size and complexity
that would require Java's structure and richness are typically much
larger than those that can be run usefully on an Apple II.

From the bottom up, disciplined low-level programming is sufficient
to avoid complexity collapse for an application that runs in 64KB.
And the space and speed advantages of doing so are worth a lot.  ;-)

-michael

NadaPong: Network game demo for Apple II computers!
Home page:  http://members.aol.com/MJMahon/

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