<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>

SAMS Programming Library

For TurboForth V1.2.1:1

Written by Mark Wills

For Sheila


The SAMS memory expansion for the TI-99/4A is a useful, though woefully underutilised device. Despite offering a full megabyte of memory, literally only a handful of programs exist that can take advantage of it. TurboForth has built in support for the SAMS unit, allowing memory pages to be paged in and out. However, it has no inherent programming support for the SAMS unit. This paper discusses a tiny support library written in high-level Forth which allows colon definitions to be hosted in SAMS paged memory. The dictionary entries for the colon definitions continue to be defined and linked in “normal” memory, meaning that a colon definition can be found, ticked, and executed regardless of the SAMS bank in which it is hosted, and regardless of whether it is paged into memory or not. Colon definitions can be written (in any bank) which reference code in any bank, with complete disregard to the mechanics of paging memory in and out; the paging and un-paging of banks is handled completely transparently by the support library.

Declaring the Number of Banks

Before the library can be used, the number of SAMS that you wish to use must be declared. 248 banks are available, numbered from 0 to 247, giving up to 992K of usable memory. The remaining banks of the SAMS constitute the standard 32K of the TI. The declaration is made with the BANKS word.

    BANKS ( n -- )

As can be seen from the above stack comment, BANKS requires a value on the stack. For example:

    20 BANKS

This actually reserves some memory (in the standard 24K segment, which is not paged) to track the ‘HERE’ pointers for each bank. HERE in Forth parlance gives the address of the next datum to be compiled to memory.

Writing “Banked” Colon Definitions

It is very easy to write a colon definition in a particular bank. Simply use the word SETBANK to set the active bank. All colon definitions will be defined in the selected bank until another bank is selected:

    SETBANK ( n -- )

For example:


Now, any colon definition defined will be defined in bank 3:

    : test ( -- a b c ) 1 2 3 ;

This definition will be compiled into bank 3.

Note that after each colon definition is defined a report is given on the amount of free memory in the bank. A bank is 4K (4096 bytes) in size. Care should be taken not to allow code to spill outside of the 4096 byte limit. Switch to a new bank if you think the next definition will not fit in the available space.

Disabling Banked Compilation

To disable banked compilation and resume compilation in “normal” un-banked memory simply give the value -1 to SETBANK as follows:

    -1 SETBANK

At this point, compilation resumes in normal un-paged memory.

Variables, Values and Constants

Variables, values, and constants continue to be compiled into normal un-paged memory regardless of the active bank setting. Due to their small size there’s no particular advantage to putting them in banked memory, and the overhead of a bank switch to obtain their value would not make sense.

Calling Code in Different Banks

It is possible for a word in any bank to refer to a word in any other bank. No special action is required on the part of the programmer. For example:

     4 BANKS
     0 SETBANK
     : TOM ( -- ) .” Tom “ ;
     1 SETBANK
     : DICK ( -- ) .” Dick “ ;
     2 SETBANK
     : HARRY ( -- ) .” Harry “ ;
     3 SETBANK
     : TDH ( -- ) CR TOM DICK HARRY CR ;

Here, code in bank 3 refers to code in banks 0, 1 and 2. Although they all occupy the same physical address in the TI’s memory map (the 4K region at >3000 to >3FFF) the banking is all handled automatically.

Nesting of Banked Definitions

Banked words/definitions can call words in other banks, which in turn call words in other banks, which in turn call words in other banks etc. This is achieved through the use of a “bank stack” implemented in the support library which pages the banks in and out as required. No action is required on the part of the programmer.

For example:

    : TOM   ( -- )      ." TOM "  ;

    : DICK  ( -- ) TOM  ." DICK " ;

    : HARRY ( -- ) DICK ." HARRY" ;

    : GO    ( -- ) CR HARRY CR ." FINISHED!!" CR ; -1 SETBANK

In the above example, GO, which is in bank 3, immediately calls HARRY in bank 2. HARRY immediately calls DICK in bank 1. DICK immediately calls TOM in bank 0, which displays TOM then exits back to DICK in bank 1, which displays DICK, then exits back to HARRY in bank 2 which displays HARRY, then exits to GO in bank 3, which displays FINISHED!! Then exits. Note that the bank nesting and un-nesting is handled completely transparently.

Ticking and Executing Banked Words

The dictionary entries for banked words are actually compiled into normal, standard, un-banked memory. Only the executable code for a colon definition is compiled into the appropriate bank. This was a deliberate design decision as it allows words to be found with FIND (the word in the Forth system that searches the dictionary for words), allows them to be ticked with and [‘] and also allows them to be compiled with COMPILE and/or [COMPILE] and executed with EXECUTE with no special treatment required whatsoever.

The Code

The code for the SAMS programming support library is presented below. As written below, it occupies 694 bytes of memory (0.6K). It is a testament to the power and flexibility of Forth that such functionality can be ‘grafted’ into the Forth system, whilst being implemented in Forth itself.

Written: 10th March 2015
Updated (typos): 3 January 2020

<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>