Post Reply 
FORTH for the SHARP PC-E500 (S)
11-02-2021, 07:58 PM
Post: #41
RE: FORTH for the SHARP PC-E500 (S)
Happy to announce an update Smile

Forth500 with floating point

GitHub Forth500 repo

The complete Forth standard FLOAT word set and most of the FLOAT-EXT word set are now available in Forth500:
>FLOAT
D>F
F!
F*
F+
F-
F/
F0<
F0=
F<
F>D
F@
FALIGN
FALIGNED
FCONSTANT
FDEPTH
FDROP
FDUP
FLITERAL
FLOAT+
FLOATS
FLOOR
FMAX
FMIN
FNEGATE
FOVER
FROT
FROUND
FSWAP
FVARIABLE
REPRESENT
DF! (not built-in, but same as F!)
DF@ (not built-in, but same as F@)
DFALIGN (not built-in, but same as FALIGN)
DFALIGNED (not built-in, but same as FALIGNED)
DFFIELD: (not built-in, but same as FFIELD: )
DFLOAT+ (not built-in, but same as FLOAT+)
DFLOATS (not built-in, but same as FLOATS)
F**
F.
F>S
FABS
FACOS
FACOSH (not built-in, see manual how to add)
FALOG (not built-in, see manual how to add)
FASIN (not built-in, see manual how to add)
FASINH (not built-in, see manual how to add)
FATAN
FATAN2 (not built-in)
FATANH (not built-in, see manual how to add)
FCOS
FCOSH (not built-in, see manual how to add)
FE. (not built-in)
FEXP
FEXPM1 (not built-in)
FFIELD:
FLN
FLNP1 (not built-in)
FLOG
FS.
FSIN
FSINCOS (not built-in)
FSINH (not built-in, see manual how to add)
FSQRT
FTAN
FTANH (not built-in, see manual how to add)
FTRUNC
FVALUE (not built-in, see manual how to add)
F~ (not built-in, see manual how to add)
PRECISION
S>F
SET-PRECISION
SF! (not built-in, but same as F!)
SF@ (not built-in, but same as F@)
SFALIGN (not built-in, but same as FALIGN)
SFALIGNED (not built-in, but same as FALIGNED)
SFFIELD: (not built-in, but same as FFIELD: )
SFLOAT+ (not built-in, but same as FLOAT+)
SFLOATS (not built-in, but same as FLOATS)

I left the hyperbolic out to save code space and keep Forth500 under 20KB. These can be easily added, see the Forth500 manual.

Note that single (10 digit) and double (20 digit) floating point precision is supported. All Forth500 floating point words operate both on single and double precision floating point values.

Other updates
  • Added Forth standard REQUIRE and REQUIRED and extra -CHARS and PAUSE words.
  • Improved dictionary search speed
  • Support BREAK and C/CE to stop FILES and WORDS listing
  • Closes the file after INCLUDE, INCLUDED, REQUIRE and REQUIRED failed
  • OK[n] now shows as OK[n m] if the floating point stack is not empty with m values
  • Error messages show the part of the input line where the error occurred
  • Cursor blinks after an error occurred and after an ABORT or QUIT and when Forth500 starts
  • Some speed improvements and code size reductions

Notes

The Forth500.bin file size has increased to 20329 bytes, 1869 bytes more than the previous version. The additional floating point stack requires 96 bytes for up to 8 floats. This still leaves almost 1K for BASIC and 6807 bytes for Forth programs on an unexpanded E500(S) and 43671 bytes for Forth programs on an expanded E500(S).

Initially I had estimated that the floating point word sets would require up to 2K of code space with optimized assembly code.

Luckily I was able to achieve that goal, but there were many unexpected challenges along the way to get there. I had written most of the assembly code template already weeks ago shortly after announcing that it was possible to add the floating point words sets to Forth500. The floating point stack and stack manipulation words were straightforward to implement by exploiting internal RAM as a scratchpad area. The internal RAM area of 256 bytes is also used by syscalls, which means I have to avoid conflicts or save the Forth500 internal RAM values before making the syscall to restore them afterwards. This issue became apparent with the floating point arithmetic using the "function driver" syscall. This syscall uses some internal RAM areas that are not documented in the technical reference manual. With some experimentation by dumping internal RAM to external RAM and inspecting it with Forth DUMP or post-mortem dumping in BASIC, it became clear that internal RAM BP-$20 was used (BP is the internal RAM Base Pointer by which internal RAM access can be made relative to the BP, i.e. kind of like a "register file window" which is nice).

After a bit of fiddling with this code, I settled on assigning the floating point work/scratch area at $70 in internal RAM and set the BP address to $70 like before, but in order to accommodate the floating point working area I had to move the 8-, 16- and 20-bit internal RAM registers up by an offset of 32. My attempt to move the floating point work/scratch area above the Forth500 internal RAM registers failed because of the syscall's internal RAM usage below the current BP (again, no word about this in the technical reference manual). These failed attempts led to RAM dumps, code changes and more dumps to figure out what the "function driver" syscall changed and under what conditions.

After fixing that, I ran into another problem. Adding 2.0e+3.0e returned 15.0e. What on earth!? Apparently, the "carry byte" is still used by the syscall! The carry byte allows the mantissa to overflow so it can be shifted to the right afterwards, without overwriting the exponent. To explain this, the internal format of a BCD float is laid out in bytes as follows:

(sign)(exponent)(carry)(BCD)...(BCD)(correction)(correction)

which takes 15 bytes to accommodate double precision floating point values with 10 BCD bytes for 20 digits. Note that in Forth500 we only need to store the relevant 12 bytes of a (double) floating point value. The technical reference manual states that the carry and correction bytes are "only used during operations and calculations" but evidently they must be cleared before calling the "function driver" to avoid 2.0e+3.0e=15.0e to correctly get 2.0e+3.0e=5. Phew!

By the way, the correction bytes are for roundoff. Single precision uses one correction byte with 2 digits. Double precision uses two correction bytes with 4 digits. Therefore, internally the E500(S) uses 12 and 24 digit calculations, respectively. I remember that all SHARP calculators use 12 digits internally but only 10 to display and store values in variables. Because the correction bytes appear to affect the computation, I suppose it might be possible to actually use these extra digits. Cool! But have not tried that yet.

Next I ran into some limitations of the "function driver" syscall. Apparently (again, not documented in the technical reference manual) the binary->decimal and decimal->binary operations only support up to 20 bits. That's not good enough to convert 32 bit double cells to floats and back with D>F and F>D. So back to the drawing board to write both routines in assembly from scratch.

Finally, the "function driver" syscall to convert a string to a floating point value (the BASIC VAL keyword) did not work at all like the (very lightly) documented manual stated. The U stack pointer changes (increased by 2) for no reason and the resulting float is always zero. No error value is returned. The way a string is passed to the syscall is by populating a float with a magic byte $80, the 20 bit pointer followed by the length of the string. After some fiddling with the code and RAM dumps, nothing I tried made this string->float syscall work. So back to the drawing board to write my own routine in assembly. Because string->float conversion should support both single and double precision floats, while meeting the Forth standard, and making sure all error conditions are triggered properly, I ended up with a bit more assembly code than I had anticipated.

Along the way it was fun to come up with shorter and more efficient versions of assembly code for some common tasks in Forth500. So I incorporated these little "hacks" too to improve Forth500.

I checked the Forth500 implementation over the last couple of days, but only when I had time, to see if I could break anything. So far this version works like a charm. On the other hand, my experience with the "function driver" syscall makes me a bit uneasy to feel 100% confident to be honest. SHARP should have at least offered a bit more information about this system call interface other than a table of functions supported and a sparsely written page with very basic information about this syscall.

I realize that Forth500 can still be made to run faster by 10% or so. But I will do that later. First I'm going to enjoy it a bit more to do some actual Forth programming Smile

- Rob

"I count on old friends" -- HP 71B,Prime|Ti VOY200,Nspire CXII CAS|Casio fx-CG50...|Sharp PC-G850,E500,2500,1500,14xx,13xx,12xx...
Visit this user's website Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
FORTH for the SHARP PC-E500 (S) - Helix - 09-06-2021, 11:41 PM
RE: FORTH for the SHARP PC-E500 (S) - robve - 11-02-2021 07:58 PM



User(s) browsing this thread: 1 Guest(s)