BANKSBAS/DOC  91-09-18             Copyright 1991 by Chris Fara
===============================================================
Bank switch subroutines for use with BASIC on 128-K Model 4
Published by MICRODEX, 1212 N. Sawtelle, Tucson AZ 85716, USA
---------------------------------------------------------------

     Using the routines
     ==================

/CMD files are self-installing, self-protecting modules:
     BANK4BAS/CMD  for BASIC in Mod-4 mode on 128-K Model 4
     BANK3BAS/CMD  for BASIC in Mod-III mode on 128-K Model 4

Mod-4 version is for TRSDOS/LS-DOS 6. Mod-III version can be
used as-is with LDOS 5.3, or with TRSDOS 1.3 after CONVERTing
it to a TRSDOS 1.3 disk.

To install the routine, from DOS enter depending on mode...
     BANK4BAS         ...or...            BANK3BAS
This should be done only once after any power-up or reset of
computer. The module protects itself in high memory and uses
about 100 bytes. A message shows the address for calling it
from BASIC. Make a note of this address, enter BASIC (no need
to protect memory) and call the routine as outlined below. A
detailed discussion was published by Chris Fara in "Programming
Tutor" (Computer News 80, Oct'91-Jan'92). Reprints may be also
available from Microdex (address at top of this file).

The extra memory banks #1 and #2 in a 128-K Model 4 are not
normally accessible to BASIC. That extra memory can be used to
store data in form of "arrays". Since each bank has 32-K of
memory (32768 bytes), one bank can hold...
     an integer array with subscripts 0 up to 32767/2-1=16383
     single precision array with subscripts 0 to 8191
     double precision array with subscripts 0 to 4095
String arrays can be also stored, provided ALL strings have the
same fixed length. For example if strings have 32 characters
each, then one bank can hold...
     a string array with subscripts 0 up to 32767/32-1=1023

One bank can hold several arrays, each starting on a different
"page". A page is a 256-byte portion of memory. One page can
hold 128 integer elements, 64 single-precision elements, 32
double-precision elements, eight 32-character string elements,
four 64-character strings, etc. There are 128 pages in one
bank, numbered from 0 to 127. Thus, for example, to store two
arrays of equal size in one bank, the first should start at
page 0 and the second should start at page 64. Obviously in
this case the highest possible subscript for each array will be
half of what's possible when one whole bank is used for only
one array.

The arrays stored in a bank are not "real" BASIC arrays and are
not DIMensioned. The "bank", "page" and "subscript" are merely
identification codes for addressing data in the extra memory.
The routines calculate the address as...
     (256 * page) + (subscript * size of element)
Thus for example, in an integer array starting at page 0 in
bank 1, subscript 150 identifies the same 2-byte integer
element as subscript 22 in an array starting at page 1 in the
same bank, because in both cases the address in the bank is...
     (256*0)+(150*2) = (256*1)+(22*2) = 300

To move (copy) data between BASIC and a bank, we pass to the
subroutine 3 variables...
     S% = Subscript
     V  = Variable holding a numeric value or string to move
     D% = Control value = 256*page + 2*bank + direction
The "direction" is 0 to store data from BASIC to an array
element in the bank, or 1 to retrieve it from the bank.


     BASIC in Mod-4 mode
     ===================

Suppose that the address displayed after installing BANK4BAS
was 64321-65536. Near the beginning of a BASIC program define a
variable to hold that entry address to the routine...
     Z% = 64321 - 65536
Later in the program, for example to store (direction = 0) a
single-precision value at subscript 32 in an array which begins
at page 0 in bank 1, write something like this...
     S% = 32
     V! = 123456
     D% = 256*0 + 2*1 + 0    ...or simply...  D% = 2*1
     CALL Z% (S%, V!, D%)
To retrieve (direction = 1) the stored value write...
     S% = 32
     V! = 0
     D% = 2*1 + 1
     CALL Z% (S%, V!, D%)
Upon return from the call V! will contain 123456.

Here is another example. To load an integer array with
subscripts 0-8191 from a file into bank 2 starting at page 64,
write something like this...
     OPEN "I", 1, "SOMEFILE"
     D% = 256*64 + 2*2 + 0
     FOR  S% = 0 TO 8191
     INPUT #1, V%
     CALL  Z% (S%, V%, D%)
     NEXT: CLOSE
To save this array from the bank to a file...
     OPEN "O", 1, "SOMEFILE"
     D% = 256*64 + 2*2 + 1: V% = 0
     FOR  S% = 0 TO 8191
     CALL Z% (S%, V%, D%)
     PRINT #1, V%
     NEXT: CLOSE
And so on.


     BASIC in Mod-III mode
     ===================

Suppose that the address displayed after installing BANK3BAS
was 64321-65536. Near the beginning of a BASIC program define
the entry address for a USR call and a variable which will be
needed in the USR call...
     DEF USR = 64321 - 65536
     Z% = 0
Since USR can pass to the routine only one value but we need
three, define also a small 3-element "transfer" array...
     DIM Z%(2)
Later in the program, for example to store (direction = 0) a
single-precision value at subscript 32 in an array which begins
at page 0 in bank 1, write something like this...
     Z%(0) = 32
     V! = 123456: Z%(1) = VARPTR (V!)
     Z%(2) = 256*0 + 2*1 + 0    ...or simply...  Z%(2) = 2*1
     Z% = USR ( VARPTR ( Z%(0) ) )
To retrieve (direction = 1) the stored value write...
     Z%(0) = 32
     V! = 0: Z%(1) = VARPTR (V!)
     Z%(2) = 2*1 + 1
     Z% = USR ( VARPTR ( Z%(0) ) )
Upon return from the call V! will contain 123456.

Here is another example. To load an integer array with
subscripts 0-8191 from a file into bank 2 starting at page 64,
write something like this...
     OPEN "I", 1, "SOMEFILE"
     Z%(2) = 256*64 + 2*2 + 0
     FOR  S% = 0 TO 8191: Z%(0) = S%
     INPUT #1, V%: Z%(1) = VARPTR (V%)
     Z% = USR ( VARPTR ( Z%(0) ) )
     NEXT: CLOSE
To save this array from the bank to a file...
     OPEN "O", 1, "SOMEFILE"
     Z%(2) = 256*64 + 2*2 + 1: V% = 0
     FOR  S% = 0 TO 8191: Z%(0) = S%
     Z%(1) = VARPTR (V%)
     Z% = USR ( VARPTR ( Z%(0) ) )
     PRINT #1, V%
     NEXT: CLOSE
And so on.


     String arrays
     =============

To make sure that all strings in a given array have the same
fixed length, pre-define a "transfer string". For example if
the length will be 64 characters...
     V$ = STRING$ (64, " ")
Then, before moving any string between BASIC and bank, set the
text into that string...
     LSET V$ = "Christopher Fara"
or set the contents from another variable...
     LSET V$ = A$
Text longer than the pre-defined string will be chopped off to
fit, shorter text will be padded with blanks to the right to
fill the whole length. Then to store it in Mod-4 BASIC...
     CALL Z% (S%, V$, D%)
and in Mod-III mode...
     Z%(1) = VARPTR (V$)
     Z% = USR (VARPTR ( Z%(0) ) )
Upon retrieving a text via "transfer string", immediately copy
it to another string...
     A$ = V$
Never use the "transfer string" for anything except the
transfer to and from banks. Never assign any text directly to
the "transfer string": don't use V$="Text". Use only LSET.



     General remarks
     ===============

Contrary to the popular wisdom, the routines switch the extra
banks into the LOWER half of the 64-K memory space, and not
into the upper half (the "Tutor" essays mentioned above explain
why it's done this way). Countless runs never caused any
problems in the author's applications. Still, it's possible
that with some systems, add-ons and what-nots the scheme might
bomb. If so then tough luck: don't use the routines anymore in
the system configuration that caused a conflict.

The routines don't do any error checking. If 128-K memory is
NOT installed then the routines will probably crash the system.
Also: the starting "page" of an array, and the "subscript" and
"size" of elements must be coordinated to assure storage of
data within a bank, i.e. at an address 0-32767 (otherwise the
routine will mess up BASIC or your program). The "page" number
must be within the range 0-127. The highest "subscript" for an
array with elements of a given "size" is...
     32768 / size - 1              ... starting at page 0
    (32768 - 256*A) / size -1      ... starting at page A
     256 * ( B - A) / size -1      ... starting at page A, if
another array starts at a higher page B. For example an integer
array ("size" = 2 bytes per element) starting at page A=32 can
have subscripts from 0 up to...
    (32768 - 256*32) / 2 - 1 = 12287
if there are no other arrays at any higher page, or...
    256 * (64-32) / 2 - 1 = 4095
if some other array starts at page B=64 (otherwise the lower
array would overwrite the higher one). And so on. Do some
planning before using the arrays.

In Mod-III BASIC, when a program is short then some variables
may end up in the lower half of memory and would conflict with
a bank switched into that memory. To find out where are the
variables in any given Mod-III program, LOAD that program into
BASIC and enter...
     PRINT PEEK (16634)
If the displayed value is 128 or greater, then all variables
are located at the address 128*256=32768 or higher, i.e. in the
upper half of memory. Otherwise some variables are in the lower
half. But string text is always way up in the high memory, so
the easy solution is to convert a number into a string before
accessing a bank. For example to store an integer...
     V$ = MKI$ (V%): Z%(1) = VARPTR ( V$ )
To convert a retrieved string back into an integer...
     V% = CVI ( V$ )
Again, this is needed only with numeric variables and short
programs in Mod-III mode. In Mod-4 BASIC all variables are
always in the upper half of memory.

Data stored in a bank remain there even after a BASIC program
is changed, even after exit to DOS, even after the computer is
reset, even after it is re-booted from Mod-4 mode to Mod-III
mode or the other way around, until power is turned off, or
until some other program overwrites the banks (eg. MEMDISK,
Visicalc, etc). This provides and easy way to chain related
programs using common data, especially in Mod-III BASIC which
does not have the CHAIN and COMMON commands like Mod-4. Just
leave data from one program in a bank and then simply RUN
another program that needs the same data.
