So in the TI's case, Pascal is running on a virtual stack based cpu coded in GPL which is a software based virtual CPU running on the 9900, a 3mhz CPU!
No, the p-code system on the TI implements a PME (p-machine emulator) in TMS 9900 native code, where some parts of the code is copied to scratch-pad RAM for optimal speed.
The Pascal compiler produces p-code, which is then interpreted by the PME.
There's no GPL at all involved in the p-code system. For some reason it seems a lot of people think so. It could be because of the hardware design of the p-code card.
When the p-system is running, the PME runs assembly code on the p-code card, in RAM at >8300 and in low memory expansion. There's 12 K ROM on the p-code card, in >4000 - >5FFF. The first 4 K are always the same, the last can switch between two banks.
Then there are 48 K GROM on the p-code card too. This is probably the source of the GPL confusion, but these GROM chips simply implement a GROM-disk. This disk, showing up as the OS: volume in the system, contains the entire operating system for the p-system. Here you find files like SYSTEM.PASCAL, SYSTEM.MISCINFO etc., which define how the p-system works. Having them on GROM is actually faster than the traditional implementation, where you read everything from a floppy disk. You can still change the system, in spite of it being in ROM, since if you make a new SYSTEM.CHARAC file and store that on a disk, you redefine the character set used by the system, for example. If such a file is in the system drive on startup, it will override the file that's fixed on the OS: volume.
There's also assembly code stored in GROM. This is code that's transferred to low memory expansion on startup, and to some other places in RAM as well. But it's only read during startup.
The reasons for having code spread out everywhere are different.
- Code in RAM at >8300 is there for a speed reason. It's the inner core of the interpreter that runs here.
- Code in RAM at >2000 - >3FFF is there among other reasons to be able to run when the p-code card is disabled. Since the card is in the expansion box, it must turn off when the computer needs access to RS232 or a disk controller, for example. The interrupt service used by the p-system also runs here.
- Code in the p-code card saves space in RAM. The brunt of the PME runs here, and also some low-level intrinsics like MOVERIGHT and SCAN.
Apart from that, it's true that the PME implements a stack based machine. It's also flexible enough to run p-code from CPU RAM, VDP RAM or p-code card GROM. A lot of the opimizations done within the system are to make all the features work within the space of a 32+16 K RAM machine, not to run at highest possible speed.
When a procedure is called, an environment record is created on the stack. Inside this record, all local variables are allocated. There are special p-codes used to address a variable with a certain offset inside this environment record. This is of course less efficient than reading a memory location directly. There are also advantages with this approach, though, but you need to better understand all the capabilities of the system to appreciate them.
One thing is recursion. Since local variables are pushed on the stack when a procedure is invoked, and poped when you return from the procedure, only available memory limits how many times a procedure can call itself.
Another thing is memory management. Since only global variables are static, p-code programs are dynamically relocatable. As Pascal allows for program segmentation, which means that you can split a large program into segmented procedures, which only need to be resident in memory when they are actually running, code may be moved around in the system at runtime, if the system runs out of memory when attempting to call a procedure that's currently on disk only.
The UCSD p-system Pascal compiler also allows separate compilation, using units. That means you can have a library of functions you frequently use, like the sprite functions in this case, and make them available to you just by writing uses sprite in the code. Everything else is automatic. It's mentioned above that the p-system couldn't find the sprite unit unless the compiler disk was in drive #4:. That's because the system was started with the file SYSTEM.LIBRARY in that drive, and there's no library reference file active to tell the system where else to look for it. The p-system is flexible enough to have any number of separate libraries available, even on different drives, but if you have that, you have to write a text file that lists the libraries that are available, including the drive number or disk name where they reside, and register the name of this library map file inside the p-system.
Putting everything together, I've not found any language available to the 99/4A to be faster than Pascal. But then I count the whole software development process, not just the time it's executing. I'm not too frequently helped by a program that runs in seconds instead of minutes, if the first one takes weeks to develop and the second only days. The slow program will be ready long before the fast one anyway.
There are of course things that require faster speed than Pascal can support. Then it's good that linking assembly routines is fairly simple. I typically develop programs in Pascal only (provided I don't need some thing that can't be done in Pascal), and then, when I know it's working, convert time critical routines to assembly if I feel it's worth the effort. Sometimes you can simply code something using the special intrinsics that area in UCSD Pascal to facilitate the whole operating system to be written in Pascal to improve your own programs.
In the specific case here, moving sprites around, I don't know what takes so much time. Maybe the sprite library, which is pretty flexible, has a speed penalty for that. I've hardly ever used sprites in Pascal, so I don't know. At least 99% of the time I've stayed in the default VDP mode, which is 40 characters wide, text only.
The p-system loads code in the primary code pool first, if there's space available. For this short program, there definitely is. The alternate code pool runs slightly faster, though. I presume you haven't tried changing the language type from pseudo to m_9900, have you? Doing that forces the system to load the code in the secondary code pool.
To wrap it up, the flexibility and operating system support the p-system offers is unique within the 99/4A scope. The largest application I've written for the 99/4A is a bit above 4000 source code lines. That's quite a lot for a system with only 48 K RAM, but it runs.