Jump to content
IGNORED

TurboForth V1.2 (Beta)--Evolution & Arcana


Lee Stewart

Recommended Posts

Here's a shorter version ...

...

I think my 'pause' code is much clearer than TI Forth's PAUSE. Do I get a prize? ;)

 

Mais oui! Very nice, indeed.

 

There are at least 4 TI Forth words that list to the display that use PAUSE . I guess your definition could be worked into 2 of them. The other 2 are, unfortunately, part of the resident vocabulary as is PAUSE , of course.

 

...lee

Link to comment
Share on other sites

Mais oui! Very nice, indeed.

 

There are at least 4 TI Forth words that list to the display that use PAUSE . I guess your definition could be worked into 2 of them. The other 2 are, unfortunately, part of the resident vocabulary as is PAUSE , of course.

 

...lee

 

Mark...

 

It works quite well!

 

: pause break? begin key? -1 = until ;

 

Now, it can be used in other words that list to the display screen. Of course, that might mean hoisting it into the resident vocabulary. :P

 

...lee

Link to comment
Share on other sites

Floating Point Math Library---

 

OK...Regarding my conversion/adaptation of the MDOS floating point library, I have pretty much cleaned out the MDOS-dependent taskframe stuff, which reduced the object file size by 310 bytes to 5882 bytes. A cursory run-through tells me I probably cannot reduce it by more than another 250-300 bytes by removing replicated inline code to a handful of short subroutines. I am not sure I am clever or masochistic enough to squeeze more out of it. I am not sure the loss in some speed is worth the 250-300 bytes saved, however. One section of code that gets executed about 50 times throughout the library is the following:

 

MOV *R1+,*R2+

MOV *R1+,*R2+

MOV *R1+,*R2+

MOV *R1,*R2

 

The best I could come up with for that is

 

BL @R1$2

...

R1$2 MOV *R1+,*R2+

MOV *R1+,*R2+

MOV *R1+,*R2+

MOV *R1,*R2

RT

 

If I figured it correctly, that saves 4 bytes per call for a total of about 200 bytes. I haven't worked out how much slower that is.

 

...lee

Edited by Lee Stewart
  • Like 1
Link to comment
Share on other sites

Floating Point Math Library---

 

The routines included in the adapted MDOS library are

 

 

FCOMP..........Floating Point Compare

FSUB...........Floating Point Subtract

FADD...........Floating Point Add

FMULT..........Floating Point Multiply

FDIV...........Floating Pont Divide

PWR............Floating Point Power

EXP............Floating Point ex

LOG............Floating Point ln(x)

SQR............Floating Point sqr(x)

COS............Floating Point cos(x)

SIN............Floating Point sin(x)

TAN............Floating Point tan(x)

ATN............Floating Point atn(x)

GRI............Floating Point Greatest Integer

CFI............Convert Floating Point to Integer

CIF............Convert Integer to Floating Point

CSINT..........Convert String to Integer

CSN............Convert String to Floating Point

CNS............Convert Floating Point to String

 

At the moment, I have left unchanged the passing of parameters through registers instead of through FAC and ARG. I may change that because FAC and ARG are used inside the routines. Of course, the internal uses do not have to be the 834Ah and 835Ch locations used by the console. I'm torn.

 

...lee

Link to comment
Share on other sites

Floating Point Math Library---

 

Scratchpad (8300h-83FFh) use is as follows:

834Ah.......FAC

8354h.......Float Divisor (currently, not used for FP error return as with console routines)

835Ch.......ARG

836Ch.......EXP

836Eh.......SIGN

83A0h.......WSG (FP workspace)

These can all be changed unless we want to pass the parameters both ways through FAC and ARG as the console routines do.

 

...lee

Link to comment
Share on other sites

Floating Point Math Library---

 

Scratchpad (8300h-83FFh) use is as follows:

 

834Ah.......FAC

8354h.......Float Divisor (currently, not used for FP error return as with console routines)

835Ch.......ARG

836Ch.......EXP

836Eh.......SIGN

83A0h.......WSG (FP workspace)

These can all be changed unless we want to pass the parameters both ways through FAC and ARG as the console routines do.

 

...lee

 

Does the memory footprint above indicate how the original code is currently written, or is it your proposed memory footprint?

 

From post #41 in this thread, here's the TF PAD footprint:

 

Scratchpad usage is from >8300 to >835B inclusive, as follows:

 

$8300 - $831F - Workspace registers. TF only uses one register file.

$8320 - $8325 - DOCOL

$8326 - $832B - NEXT

$832C - $8331 - EXIT

$8332 - $8339 - bridge routine to jump to an address in bank 1

$833A - $833F - bridge routine to return to the calling routine in bank 0

$8340 - $8349 - get speech synth status subroutine

$834A - $834B - data read from speech synth

$834C - $8353 - ISR despatcher for ISR in bank 1

$8354 - $835B - ISR return subroutine

 

So, there's some overlap starting at FAC (>834A). Also >8354. That's not the end of the world though!

Link to comment
Share on other sites

Does the memory footprint above indicate how the original code is currently written, or is it your proposed memory footprint?

 

From post #41 in this thread, here's the TF PAD footprint:

 

Scratchpad usage is from >8300 to >835B inclusive, as follows:

 

$8300 - $831F - Workspace registers. TF only uses one register file.

$8320 - $8325 - DOCOL

$8326 - $832B - NEXT

$832C - $8331 - EXIT

$8332 - $8339 - bridge routine to jump to an address in bank 1

$833A - $833F - bridge routine to return to the calling routine in bank 0

$8340 - $8349 - get speech synth status subroutine

$834A - $834B - data read from speech synth

$834C - $8353 - ISR despatcher for ISR in bank 1

$8354 - $835B - ISR return subroutine

 

So, there's some overlap starting at FAC (>834A). Also >8354. That's not the end of the world though!

 

My tentative memory footprint is a confabulation of MDOS and TI-99/4A scratchpad RAM. The only thing I did was to force FAC and ARG to the 4A's locations. The rest falls out of converting the MDOS F000h-based locations. If I did nothing but a one-to-one correspondence, the map would be the locations in parentheses below:

 

834Ah(8380h).......FAC

8354h(838Ah).......Float Divisor

835Ch(83C6h).......ARG

836Ch(83D6h).......EXP

836Eh(83D8h).......SIGN

83A0h(same ).......WSG (FP workspace)

 

I felt it would be useful to keep FAC and ARG where the 4A has them to maximize our options, I don't think it matters where we actually put them, particularly if we don't use the MDOS register-passing style for I/O of parameters. Using the 4A's method would save some space in the library's footprint, but probably not enough to warrant forcing the 4A's method if another would otherwise be better.

 

...lee

Link to comment
Share on other sites

Floating Point Math Library---

 

If we stay with the MDOS calling scheme, the following mechanism should work:

*

REF FPMLIB entry point for floating point math library (FPML)

FPLWS EQU >83A0 FPML workspace

FPLLNK DATA FPLWS,FPMLIB new workspace and branchpoint

*

* set up registers with input parameters (R0-R5)

* R0 = FPML subroutine #

* R1 = pointer to result

* R2 = parameter #1

* R3 = parameter #2

* R4 = parameter #3

* R5 = parameter #4

*

BLWP @FPLLNK

*

* error returned in R0 and result at address passed to FPML in R1

*

If we decide to use the old 4A way of doing business, the I/O parameters would be as described in the Editor/Assembler Manual, using FAC, ARG and other scratchpad-RAM addresses. And, the call would be done in the familiar way:

*

BLWP @FPLLNK

DATA <subroutine #>

*

At this point, as I said earlier, I'm torn.

 

...lee

Link to comment
Share on other sites

Floating Point Math Library---

 

I'm trying to figure out the easiest way to test this library without writing an AL test harness! The easiest method that came to me is straight from Rube Goldberg!

  1. AORG the library to 2700h (above E/A utilities).
     
  2. Load the object file with E/A into low memory expansion, where it fits neatly behind the E/A utilities.
     
  3. Save the memory image from 2700h-3DF5h to a program file. This requires either (1) copying all 5878 bytes to VDP RAM and using the SAVE subroutine of the disk DSR or (2) using Classic99's memory-dump option, extracting the correct memory range to another TI file and editing the FDR to force it to a "PROGRAM" file.
     
  4. Start TurboForth.
     
  5. Use a custom TF word to use the LOAD subroutine of the disk DSR to load the memory image (5878 bytes) into VDP RAM.
     
  6. Copy the image from VDP RAM to 2700h and update FFAILM.
     
  7. Test to my heart's content!

(3) is pretty easy because I have already written ALC to do the first option for another situation. It's loading the memory image after TF is started that will be dicey because there's not enough space in VDP RAM (951 bytes!) to fit the image. I guess I could save the image as 7 files of 840 bytes each. :-o

 

:idea: :? :idea: Anybody got a better idea? :idea: :? :idea:

 

...lee

Link to comment
Share on other sites

It's loading the memory image after TF is started that will be dicey because there's not enough space in VDP RAM (951 bytes!) to fit the image. I guess I could save the image as 7 files of 840 bytes each. :-o

 

:idea: :? :idea: Anybody got a better idea? :idea: :? :idea:

 

...lee

 

 

Well, if you have no open blocks (and you don't, because block files are ALWAYS closed after being accessed) then you can use the entire 6K of VDP RAM that is associated with the block buffers.

 

So, you could load the program image file over the block buffers with no problems. After loading, when you return from your AL program to TF, just do an EMPTY-BUFFERS.

 

Thinking about it, EMPTY-BUFFERS probably isn't even necessary... Whilst the block buffers are in VDP, the buffer 'slot' pointers and status (the stuff that tells TF what block is in what buffer, and if the block is clean or dirty) is all in CPU RAM, and you won't be clobbering that at all. So, I say go load over the top of the block buffers in VDP. Panic not. You'll be fine!

 

The block buffers in VDP start at >1C20 and end at >341F.

 

Good luck!

Link to comment
Share on other sites

If we decide to use the old 4A way of doing business, the I/O parameters would be as described in the Editor/Assembler Manual, using FAC, ARG and other scratchpad-RAM addresses. And, the call would be done in the familiar way:

*

 

BLWP @FPLLNK

DATA <subroutine #>

*

At this point, as I said earlier, I'm torn.

 

...lee

 

I personally have no problem with leaving the old idioms behind. Since you're soliciting opinions on the interface, I'll throw my tuppence worth in!

 

Placing the Radix 100 numbers into scratch pad is not a good idea. Why? Because the R100 number will almost certainly exist elsewhere, so copying them from one place to another is just a waste of processor cycles! Take TF as an example (I can't cite TIF because I haven't used FP in TIF). In TF I implemented a seperate floating point stack. You're familiar with the implementation so I'll not wax on too much about it, except to say that a large part of the implementation is concerned with simply copying R100 numbers to FAC and ARG, and copying the results back again, which of course poses a serious performance penalty. The TI FP implementations work in their rather awkward manner purely down to the architecural limits of an un-expanded console. There's only VDP and scratchpad. The TI engineers had nothing else to work with.

 

However, we have an opportunity to move away from that very awkward, and inefficient interface. I personally strongly advocate passing pointers to the R100 numbers to the FP routines (via CPU registers). Then no copying of R100 arguments is required. The FP software can process them in-situ. Much much more efficient. In the case of TF, these FP arguments would be in the 32K somewhere, not in pad. However, by passing pointers to the FP arguments, there's nothing to stop a user of the FP routines having his FP data in PAD if he wants to; if he's working with a cartridge in an un-expanded console, for example.

 

In terms of the extra performance that using PAD gives, I believe the time saved not copying FP strings around will nullify the performance gain of hosting the FP strings in PAD! And anyway, if performance is a concern, go ahead and use PAD! If the FP software uses pointers then you have that flexibility!

 

The use of VDP for FP calculations is a definate no-no, and will result in visitations in the dead of night by angry pitch-fork weilding 4A die-hards. They're a nasty bunch when they're riled :P .

 

So, I'd rather see something like:

 

LI R7,<pointer to FP arg1>

LI R8,<pointer to FP arg2>

BLWP @FPLLNK

DATA function_code

 

There's my tuppence worth, for what it's worth! ;)

Link to comment
Share on other sites

:idea: :? :idea: Anybody got a better idea? :idea: :? :idea:

...lee

You could write the assembly code using the TF assembler :D :-o , then just load it from blocks in source form. Later you could BSAVE it for faster loading.

 

The nice thing about assembler in Forth (as I know you know) is that you can test your assembly straight from the keyboard, just like any other Forth word. Sure, you can crash the thing real hard with assembly, but hey, that's the fun of it! Also, I find the edit/save/assemble/load/test/damn/power-off/power-on/load cycle a real PITA. I think I'm spoiled by Forth!

 

Does your TI have a load interrupt switch fitted? TF initialises the load interrupt vector to point to TF so that you can reboot your console in the event of assembly armageddon, without recourse to the power switch. This has the advantage of leaving CPU RAM (the 32K) pretty much intact allowing post-mortems for seriously hard to debug assembly routines!

 

Of course, when doing all this development stuff in Classic99 it's a lot easier, too! In TI994W (Fred Kaal) you can issue a LOAD interrupt from the drop-down menus. I don't think you can in Classic99 (yet?) but I guess it would be a relatively simple feature for Tursi to add. Note to Tursi, in case he's reading this: Probably more useful to have a button in the debugger, rather than in a menu? The empty space under the breakpoints list box might a suitable place? :)

Link to comment
Share on other sites

... The FP software can process them in-situ.

The difficulty with working in situ is that for FAC, at least, the FP routines use 9 bytes of FAC(!) to accommodate a rounding digit. I haven't analyzed the library closely enough to see whether a similar practice affects ARG.

 

... The use of VDP for FP calculations is a definate no-no, and will result in visitations in the dead of night by angry pitch-fork weilding 4A die-hards. They're a nasty bunch when they're riled :P .

Nowhere did I suggest using VDP RAM. I am avoiding that like the plague.

 

...lee

Link to comment
Share on other sites

You could write the assembly code using the TF assembler :D :-o , then just load it from blocks in source form. Later you could BSAVE it for faster loading.

I definitely thought of that, but translating 6 KB of ALC to TF-ALC is a daunting prospect.

 

... Does your TI have a load interrupt switch fitted?

No.

 

... Of course, when doing all this development stuff in Classic99 it's a lot easier, too! In TI994W (Fred Kaal) you can issue a LOAD interrupt from the drop-down menus. I don't think you can in Classic99 (yet?) but I guess it would be a relatively simple feature for Tursi to add. Note to Tursi, in case he's reading this: Probably more useful to have a button in the debugger, rather than in a menu? The empty space under the breakpoints list box might a suitable place? :)

Classic99, indeed, has both a debugger menu option and a button (F12) for load interrupt.

 

...lee

Link to comment
Share on other sites

Lee:

I just started looking at the five math words mentioned in #77 and #78. I have a simple question here....just wondering..... when you use UM*

and set things up like: 10 20 UM* shouldn't the result be at the top of the data stack?

 

Rod

 

In your particular example, you're multiplying 20 by 10. Result = 200. The top stack item is the high word (i.e. the top 16 bits) of the 32 bit result (all 0), the next item on the stack being the lower word.

 

Here's another example:

 

199 465 um* .s

 

Gives:

 

26999 1 <TOP

 

That's (1*65536)+26999=92535

 

 

Another example:

 

9900 761 um* .s

 

Gives:

 

-2740 114 <TOP

 

Well, the -2740 is 62796 displayed as a signed value (try -2740 U.)

 

So, that's (114*65536)+62796=7533900

 

:grin:

Link to comment
Share on other sites

...

Lee, would you mind stress-testing the following Math words:

  • */
  • UM*
  • /MOD
  • */MOD
  • UM/MOD

...

Mark

 

*/ works fine.

 

As expected out-of-range and divide-by-zero answers are garbage numbers. Well, division by zero gives -1 but that can obviously also be a legitimate answer. I guess that in Forth you need to know what to expect. There's no way to get feedback from the math function that there was an error like there is with the FP package. It would probably slow things down.

 

...lee

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...