Want to make your own shell? Then keep reading!
Before you learn to search the Variable Allocation
Table (VAT or Symbol Lookup Table) we need to investigate
where it is and how it's organized.
The VAT
The VAT is on RAM
page 7. You can swap it in yourself or you can
use one of TI-OS' calls to do
the work for you saving one byte.
_RAM_Page_7 =$47f3 call _RAM_Page_7 ;swap in ram page 7 ;destroys none
Backwards, that's how it's stored. If you had a variable named 'Stupid', it would be stored as 'diputS' in memory.
Since the VAT is backwards and on RAM page 7,
it starts at address $bfff
. To swap in
RAM page 7 and go to the start of the VAT...
_RAM_Page_7 =$47f3 start_of_vat =$bfff call _RAM_Page_7 ;swap in ram page 7 ld hl,start_of_vat ;hl=beginning of first ; variable name in ; vat
There's a good reason behind making it backwards. Think of the variables' memory in the RAM as being one long block. We could store all the names in one area, and all the data in another but we might be wasting space or corrupting memory if the data runs over the name area. By having both areas (name and data) start at opposite ends and work towards the center, you will maximize the allotted memory so that each area only takes up as much space as needed. When you run out of memory for storing names, that means you're out of space to store the data. Want a visual example?
Data → | ← semaN* |
* That's 'Names' spelled backwards since the variable names are backwards in memory.
It's not just the names that are stored backwards,
it's the entire variable entry (all the info associated with that
variable). Let's say you were to swap in RAM page 7,
at $bfff
would be the first byte of
the first entry in the VAT. Here's an example of
what the first variable on page 7 would look like
on a freshly reset calculator using my
MemSee.asm program.
Address Byte ASCII $bff5 74 t $bff6 61 a $bff7 74 t $bff8 53 S $bff9 78 x $bffa 05 $bffb 00 $bffc 01 $bffd 40 @ $bffe 00 $bfff 04 The variable data comes five different parts in the following order but backwards in memory.
Description | Size (bytes) |
Variable type | 1 |
Absolute Address for start of variable data | 3 |
Trash byte you can use to store anything you want. It's not used by TI-OS. | 1 |
Length of variable name | 1 |
Name of variable | 1-8 |
After that all, the next variable follows in that same order. Download MemSee.asm to see this first hand if you're still unsure.
Searching the VAT
If you already know the variable's exact name, you ca use
_FindSym, but that's not always the
case.
There's several different ways to go about sifting through the
VAT. One way, and probably the most used, is by searching for
a certain variable type, most often a
string ($0c
) or program ($12
). Another way is to search alphabetically.
We're going to focus on searching by the variable type, and our
examples will search for programs to execute.
Let's begin this section by explaining my simple routine to search the VAT: VATSrch.inc. It's a beginner's example of how to search the VAT. The best way to understand this routine is to get the code printout with line markings from the VAT Search Routine Printout page; then, follow along with the explanations on this page.
- ↓_RAM_Page_7 =$47f3
- ↓_PTEMP_END =$d29a
- ↓vatsrch:
- ↓ call _RAM_Page_7
- ↓ ld bc,(_PTEMP_END+1)
- ↓ push hl
- ↓ or a
- ↓ sbc hl,bc
- ↓ pop bc
- ↓ ret c
- ↓ push bc
- ↓ ld b,h
- ↓ ld c,l
- ↓ pop hl
- ↓ cpdr
- ↓ ld d,a
- ↓ ld a,b
- ↓ or c
- ↓ ld a,d
- ↓ jr nz,good_found_one
- ↓ scf
- ↓ ret
- ↓good_found_one:
- ↓ dec hl
- ↓ dec hl
- ↓ dec hl
- ↓ dec hl
- ↓ ret
Line(s) | Explanation | Bytes |
↑1 | This call swaps in RAM
page 7 (the VAT) without destroying any
registers. This three byte
call is
used instead ofld a,7 out (5),a | none |
↑2 | _PTEMP_END is where the
absolute address for
the end of the VAT is.
| none |
↑4 | Swap in RAM page 7. | 3 |
↑5 | We just swapped in RAM page 7. _PTEMP_END
is an absolute pointer with
3 bytes for addressing; but, if we have the correct
memory page swapped in, we only need the last 2 bytes
to make up a valid 16 bit pointer. We get that
16 bit address which tells us where the last
byte of the VAT is. If we subtract the end
from the start (Notice that we usually
subtract the start from the end but the VAT is backwards.)
resulting in the length of the VAT.
| 4 |
↑6 | Hold everything! We need to check if there's VAT left
to search. Since that will probably destroy hl ,
save it.
| 1 |
↑7-8 | Sbc
is the only 16 bit subtractor that we have. Clear the carry
before you use it so you won't get your answer one off. The
size of the VAT will be stored in hl (if everything
went alright).
| 3 |
↑9 | This might be a little tricky. We needed to
push
the address of where we are to start searching from so
that it would not be effected in the subtraction.
If the subtraction went wrong, we will be returning
from the routine. We can't return, though, with something on
the stack so we get it
off, for a second, and then in line 11 we
put it back. Note that we are saving it as bc because
we want hl to still contain the size of the VAT.
| 1 |
↑10 | The carry flag will be set if we don't have any VAT left to search, the subtraction was invalid. | 1 |
↑11 | Put back where we are to start from. This is setting
us up for the cpdr
on line 15.
| 1 |
↑12-13 | Remember that the size of the VAT was
stored in hl from our calculations on
lines 7-8. Cpdr needs
the size of bytes to search in bc .
| 2 |
↑14 | Get back where we are to search from. Remember that we
had temporarily saved it away in line 11
as bc so we could use hl in the subtraction
on line 8.
| 1 |
↑15 | Now we perform the actual search!
Cpdr
will search, starting at address hl for
a byte with a value of a for bc amount
of bytes or until it finds a match incrementing
hl each iteration and decrementing bc at the
same time.
The Parity Odd
flag condition will occur if no match was found.
We won't be using it, however. We'll check the value
of | 2 |
↑16 | We're about to check the value of bc
now to see if there was a match found.
This routine will probably be called
several times in a row. The user will not want
to have to keep loading up | 1 |
↑17-18 | Now it's time to check the value of bc which,
if it's zero, tells us to quit searching...there's nothing left.
We'll use | 2 |
↑19 | We are still preserving the Variable
Type byte in d . Let's put it back before we exit
the routine. That way it's there if we exit or if we continue along.
It was only needed for cpdr . Remember: ld
does not affect the flags. Our
or 's results are not changed.
| 1 |
↑20 | If bc wasn't zero after the or , then
we continue right along with line 23.
| 2 |
↑21-22 | Well, bc must have been zero. There's nothing left for
us to search in the VAT. By setting the
carry flag, we signal
that there was an error of some sort.
| 2 |
↑24-28 | Recall that the VAT is backwards. We are currently at the
Type byte of the variable, the
first byte in the viariable's entry. Let's decrement the address
past the type byte, past the three bytes for the
Absolute Address pointer, and past
the trash byte so we are now at the
length index byte of the
variable's name (all the user needs to reference the variable
using _FindSym ).
| 5 |
Check out VATSrch.inc
's
VATSrch
and Copy_to_OP1
in action!
ld a,$12 ;$12 - program ;$0c - string ld hl,$bfff ;absolute start of vat ;the routine automatically ; swaps in ram page 7 (the ; vatiable allocation table) ; so this is a valid address call vatsrch ;search starting at hl for ; program ret c ;carry set tells us there was ; an error or it reached the ; end of the vat ld de,_OP1 ;where we want to store ; name at call copy_to_op1 ;copy backwards vat name to ; op1 the right way ex de,hl ;we need it in hl so we ; can display it call _putps ;display length indexed string ; at hl
Using
VATSrch.inc is very fast; however, if
speed isn't a necessity, you can use _FindAlphaUp
/Dn
_FindAlphaUp=$514b
and
_FindAlphaDn=$514f
.
WIDTH="15%">Description | Finds the variable higher (closer to 'Z') alphabetically than the one stored in OP1 in Variable Name format. |
Input | OP1 - case sensitive variable name in
Variable Name Formata - if not equal to $00 then
ignore typezero flag set - search for same type variables (real or complex) |
Destroys | a, bc, de , and hl
|
Output | Carry set - didn't
find onehl - address in VAT with RAM
page swapped inOP1 and OP3 - found variable in Variable Name format |
WIDTH="15%">Description | Finds the variable lower (closer to 'A') alphabetically than the one stored in OP1 in Variable Name format. |
Input | OP1 - case sensitive variable name in
Variable Name Formata - if not equal to $00 then
ignore typezero flag set - search for same type variables (real or complex) |
Destroys | a, bc, de , and hl
|
Output | Carry set - didn't
find onehl - address in VAT with RAM
page swapped inOP1 and OP3 - found variable in Variable Name format |
Speed is a huge drawback with these two; it's atleast 156,000 clock-cycles each time you call these which increases exponentially the deeper you are in the VAT. It's said to be the worst routine TI ever wrote; it's extremely slow! If you're only looking up one or two variables, OK. If you're making a shell that displays 30 variables, it could take upwards of 30 seconds!
ld hl,beginning_var ;the variable name ; to start searching up ; from alphabetically rst 20h ;_mov10toOP1 ld a,1 ;ignore type call _FindAlphaUp ;find a variable higher ; (closer to 'z') than the ; one in OP1 ;hl=start of VAT entry ;c - nothing found ;nc - found one ;OP1&3 - variable found ret c ;no such variable found beginning_var: .db $12,1,0 ;0 is the single ; character name ;the lowest variable name ; possible ;$12=program type vari.
For a basic rendition of a shell, check out the demo program
Shell.asm. It gives you all the basics
to make your own shell for running Asm programs. You can easily add support
for running TI-BASIC programs, displaying pictures, editing equations,
editing programs, renaming variables, folders, etc.!
Shells
A Shell is a program on the calculator that will display programs in the
VAT allowing you to browse through the names in order to execute them. There
are endless variations to the basic shell, so your imagination is the limit!