                         
                                           
                                
                                         
                            
  (c) by Andreas Ess, Sam Davies, Jimmy Mrdell, Austin Butler and Mel Tsai

This documentation describes the differences in programming Usgard programs
and ZShell programs. Before reading this document, you should be familiar with
the basics of programming for other Z80 shells, like ZShell. If you aren't,
first go to Yarins homepage and download the ZShell school, which is a very
good start at programming Z80 assembler. Furthermore, I can recommend the
books "Programming the Z80" by Rodnay Zaks and "Z80 Assembly Language
Subroutines".

[- INDEX -----------------------------------------------------------------]

 1) The basic format of an Usgard program
 2) Compiling an Usgard program
 3) Relocation
 4) SRCWIZ - extend TASMs capabilities!
 5) STRING85
 6) Using the VAR_* functions
 7) Other stuff

What's NOT in this documentation:
 * A complete list of Usgard functions   - see USGARDFN.TXT
 * Interrupt/TSR programming             - see USGINT.TXT

[- THE BASIC FORMAT OF AN USGARD PROGRAM -------------------------[ 1 ]---]

This is nearly the same as ZShell, since libraries have been removed in
this Usgard release:

#include "usgard.h"      ; The replacement for ti-85.h

.org 0                   ; Important!
.db "Program title",0    ; The title of the program, Zero terminated

 (code)

.end                     ; Important! (see section 4)

[- COMPILING AN USGARD PROGRAM -----------------------------------[ 2 ]---]

Included in the Usgard distribution ZIP file, all necessary files for
compilation are needed. You should use the batch file C.BAT which makes
everything a lot easier. To compile a program (in this example called
MYGAME.ASM), you simply type

 C:\TI-85\USGARD\>c mygame

and you will end up with the file MYGAME.85S if your program has been
correctly written. To compile, you need the following files in the
compiling directory (or that their locations are in the PATH environment
variable):

  C.BAT
  SRCWIZ.EXE    (see section 4)
  TASM.EXE
  STRING85.EXE  (see section 5)

You also need the file TASM80.TAB in either the same directory or that
it's location is set by the TASMTABS environment variable.

[- RELOCATION -----------------------------------------------------[ 3 ]--]

One of the most important features in Usgard is relocation. In ZShell
you had to use CALL_() and JUMP_() macros to call/jump to subroutines,
and to access labels in the program, you had to add the relative address
with (PROGRAM_ADDR) to get it to work.

In Usgard however, forget about those macros, forget about adding
(PROGRAM_ADDR) to get the absolute address to a label. All you have
to do is to put a & char in front of a label, and Usgard will take care
of the rest. Some examples:

   IN ZSHELL             IN USGARD
   ---------             ---------
 ld hl,label            ld hl,&label
 ld de,(PROGRAM_ADDR)
 add hl,de

 CALL_(PutSprite)       call &PutSprite

 JUMP_Z(DoThat)         jp z,&DoThat

and so on. It's not only easier, it's also smaller and faster. In the
first example, the Usgard version is 4 byte shorter, and in the two last
examples, one byte shorter each. And it's also faster, although most
of the time, that's insignificant.

Using the & char requires you to use a program called SRCWIZ (previously
RELOC) which changes the source temporary so the new STRING85 understands
that the address should be relocated.

In Usgard, you don't have to use the ZShell macro ROM_CALL either when
making a ROM call (although that is still possible). You simply type,
for example:

 call D_ZT_STR

to display a zeroterminated string.

[- SRCWIZ - EXTEND TASMS CAPABILITIES! ----------------------------[ 4 ]--]

SRCWIZ makes relocation easy, allowing the user to use the & char. But there
is more! Have you ever missed the possibility to include binary files?
In any case, you don't need to miss it any more! SRCWIZ "adds" a compiler
instruction called #incbin, which includes a binary file in the source.
For example, suppose you have a picture which you've converted to raw binary.
At that stage, you usually had to find (or make) a program which converts the
binary file to a textfile. To make it more conveniant, SRCWIZ helps you with
that - it replaces the binary file with the corresponding data in textformat.

An example:

 ld hl,&picture
 ld de,VIDEO_MEM
 ld bc,1024
 ldir

picture:
 #incbin picture.bin

But there is more! SRCWIZ also allows you to use external function stored
as binary OBJ files. An example will help:

 #fncall putsprite

When SRCWIZ finds that line, it will search in the directory OBJ\ for the file
PUTSPRITE.OBJ. If it doesn't exist an error message will be displayed. If it
exist, the OBJ file will be included with #incbin at the end of the program
(it uses .END to determinate the end of the program - that's why that row
is necessary) and then #fncall row will be replaced with call &putsprite.

Why should you use OBJ files? Well, it's an easy way use external routines
without having to bother to include them. Also, the programmer of a routine
might not want to release the source code to it for some reason. A disadvantage
is of course that you can't make changes to the OBJ file. If that's the case,
you have to either write the routine yourself, or find a text copy of it.

When creating a external function, remember to not include a title, as that
would most likely crash the calc! Also, since it's a function, the execution
will start at the top of the code, so if you want to make several similiar
functions, you either have to create more than one file, or use registers as a
parameter.

If you need to use temporary variables in a function, you should store them
inside the function and access them with relocation. You could use memory in
TEXT_MEM (or somewhere else), but that location will be a fixed one, and can't
be changed by the one who use the function.

When distributing an external function, you should include a file (the
extension .FN has become standard for Fargo libraries) which describes
Input and Output registers.

The next section will show how to create such OBJ files.

[- STRING85 -------------------------------------------------------[ 5 ]--]

STRING85 is the program that converts the OBJ file produced by TASM into
a .85s file, ready to send to the TI-85. STRING85 also handles relocation,
so you can't use the ZShell version of this program.

When using STRING85, you can use different options:

  0       Generates a plain string, without an Usgard header
  4       Save as ZShell 4.0 string
  l       Make an Usgard function string - see below
  t       Generate a string usable by Notepad
  hxx,yy  Creates a string with the header $xx,$yy
  u       Creates an Usgard string (which also is default)

All options above will create a .85s file, although if using the option
l (function string), it's the .OBJ file that's important. The OBJ file
is automatically moved into the OBJ\ directory.

Creating an OBJ file also requires the external program INSERT. This
is very stupid, because it should be done by String85. However, at the
moment I don't have the newest String85 so I had to come up with a simple
solution :)

[- USING THE VAR_* FUNCTIONS --------------------------------------[ 6 ]--]

Usgard has very powerful external routines, which allows the user to create,
delete and resize external TI variables. In the LITE version of Usgard,
VAR_DELETE and VAR_RESIZE aren't possible, because they rearrange the memory
on the calc, and that's exactly what the LITE version not supports. Creating
a variable is another matter however, because it is always added to the
end of the memory, thus no need to rearrange it.

When using VAR_NEW to create a variable, you MUST be sure that the variable
you create doesn't exist, because VAR_NEW will create the variable anyway.
You might end up with two variables with the same name, and then VAR_GET
and such functions may point to the "wrong" variable. Also, when creating
a variable it's recommended to create a string. Creating a matrix, vector,
list etc may result in calc crash, errors and/or other strange things.
The created variable will be filled with trash.

Deleting a variable with VAR_DELETE is very simple. Just let HL point
to the name of the variable (Zero terminated) and call VAR_DELETE and
the Carry flag will tell you if it succeeded or not (if not, the variable
didn't exist).

Executing a variable with VAR_EXEC must be done with care, especially
if you develop a shell using it. First, all registers (except IX) will be
destroyed when the program you execute start (USG_BITS will also be cleared).
Second, if you call VAR_EXEC within a subroutine, that subroutine should be
called with the RCALL_ (which only works, and is only necessary, for the
STANDARD version). The reason for this is that upon returning to the main
program, it might be at another location in the RAM. All calls in the program
so far will thus point to the wrong return address which will surely lead to
calc crash.

When a program returns to the previous executed program, USG_BITS will
NOT change. Also, the shell must quit itself if bit 1 in USG_BITS is set
(the warp out bit). This is done on purpose as it gives the shell more
power over the programs that are executed from it, as it should be.
See the source to USGSHELL for details (and how to use APD in a shell).

VAR_GET is a simple call that finds out where a variable is in the memory,
both the data area and the location in the RAM. If you want to find out
the size of the variable you could use VAR_LENGTH, although that is most
of the time unnecessary. If the variable is a string (which it usually is),
you could find that out with the following code:

 ld hl,&varname
 call VAR_GET
 dec hl
 ld b,(hl
 dec hl
 ld c,(hl)

If you want to use VAR_LENGTH, you would still have to decrease HL with 2
after the VAR_GET call, and the call VAR_LENGTH - that would be one byte
longer. It's only necessary when finding out the size of other data types,
as the size of those aren't stored as one single word.

The last VAR_ function is VAR_RESIZE, which also is the most complex
function. To use it, let HL point to the name of the variable and let
BC be the new size of it (greater or smaller than the previous size
doesn't matter). If the function returns with the carry set, the operation
failed (out of memory, variable not found, or the user runs the LITE version
of Usgard).

To find out if the user is running the LITE version, you simple check
the first bit in USG_VER:

 ld hl,USG_VER
 bit 0,(hl)
 jr z,LITE

[- OTHER STUFF ----------------------------------------------------[ 7 ]--]

Since many programs uses FIND_PIXEL they have to change to ROM page 4 in
the beginning. Since it doesn't matter what the current ROM page is
anywhere else, Usgard has ROM page 4 as the default page. Thus, you don't
have to do the swap yourself, and thus saving four (wow) bytes in the
program.

A slight warning however... some ZShell programs could switch ROM page
to something else, and then you would end up with the wrong ROM page
which isn't very pleasant. To solve this, the two standard shells sets
ROM page 4 after the execution of a program.

And if you in an Usgard program changes ROM page, be sure to set it to
page 4 again (even though the default shells do this).
