Вы находитесь на странице: 1из 6

TI-85 Assembler Programming - Using TASM

TASM (Table Assembler) is a program that we use to turn the text files we type i
nto binary numbers that the calculator can understand. In this lesson you will l
earn how to make your code TASM-friendly and how to use TASM to assemble your co
de.
TASM requires that you add a few commands into your code. Most of them aren't se
en by the calculator - they're just directions for TASM. They include lists of o
ther code files, the name of the program, the beginning and the end of the progr
am, etc. Below is a small program that uses most of these things:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Hello.asm
;; The programmer's greeting
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Include TI function definitions


#include "TI-85.h"

;; Title of program
.org 0
.db "Hello", 0

;; Main program

ROM_CALL(CLEARLCD) ; clear screen


ld HL, 3 ; set text cursor position
ld (CURSOR_ROW), HL
ld HL, 3
ld (CURSOR_COL), HL
ld HL, (PROGRAM_ADDR) ; get program's memory address
ld DE, Message ; get difference between address of program, string
add HL, DE ; add to get address of string
ROM_CALL(D_ZT_STR) ; print the string

GetLoop: ; wait for keypress


call GET_KEY
or A
jr z, GetLoop ; if no key, try again
ret ; key pressed - end program

;; String data
Message:
.db "Hello, world", 0
;; Mark the end of the file for TASM
.end

Now for the explanation of the TASM stuff here. The first thing to note is all o
f the semicolons. When the code is being assembled, everything after a semicolon
on that line is ignored. We can (and should) put notes to ourselves and others
explaining what the program does at each point.
The '#include "TI-85.h"' statement tells TASM to add all of the code in TI-85.h
to the top of the program. The rest of our program can then use anything which i
s in TI-85.h. This is useful because we don't have to retype the contents of TI-
85.h at the top of every program. It's like a big copy-and-paste done just befor
e the code is assembled.
'.org 0' and '.db "Hello", 0' are header information about the program. ".org 0"
tells TASM that this is the start of the real code. The .db statement tells TAS
M to put data directly into this location of the program. '.db "Hello", 0' puts
the string "Hello" at this point of the program followed by a zero. In ZShell, t
his string is the internal program name, on the right side of the ZShell menu. T
he zero marks the end of the string data and the beginning of normal code again.
Near the end of the program comes more unusual stuff. At the bottom is the tradi
tional place for storing strings that the program uses while it runs. They are c
reated with the same .db statement used in the title, but these ones are marked
with labels so we can access them.
At the very end of the program comes the .end statement, which tells TASM that t
he program is done.
Using TASM to assemble code is a time-consuming process if you have to type it i
n by hand. Most people set up a batch file instead. A batch file, make85s.bat is
available from the Unofficial IT-Calculator Home Page. I'll describe here what
needs to happen, in case you want to make your own batch file or need to modify
make85s.bat.
First, you need to run TASM. The command line looks like this:
tasm -80 -g3 -r12 myfile.asm
The -80 means assemble Z80 code. -g3 means create a binary file. -r12 sets some
memory thing that someone told me needed to be set. myfile.asm is the source cod
e file to be assembled.
TASM creates two files - myfile.obj and myfile.lst. If everything worked OK, the
n myfile.obj is the assembled code and myfile.lst is a listing of the code and c
an be thrown away. If something went wrong, then myfile.obj will be a bad file a
nd should be deleted immediately, and myfile.lst is a copy of the source code wi
th the error messages listed inside. Looking at this file usually tells you what
was wrong with your code.
Once you have a good .obj file, you need to rename it so you can run string85 to
create a .85s string file which can be read by the calculator. The myfile.obj f
ild should be renamed simply myfile (without any extension). Then the command li
ne for string85 looks like this:
string85 myfile
This creates the myfile.85s file, which is ready to be sent to the calculator. T
he old myfile file can be deleted after this.
After assembly is complete, only two myfile.anythings should exist - myfile.asm
and myfile.85s. All the others can be deleted.
Now you know everything you need to write small TI-85 assembly programs. Run thi
s small program; make a few changes to it. Also run the sample program, which is
listed in the next lesson. It does stuff with variables in memory and has more
complex key input operations besides "press any key to continue."
One last but important note - ALWAYS back up your calculator's memory to a compu
ter before running any assembly program. If a program crashes, pressing the ON k
ey will NOT halt the program. The only way to halt a bad assembly program is to
take out the batteries, which will erase everything in the memory.

TI-85 Assembler Programming - Sample Program

; Sample.asm
;
; This simple program prints text on screen and waits for key input.
; After running it, try making some modifications - more interesting text,
; wait for a special key, etc.
;
; It should work fine, unless I typed something wrong. Be sure you indent the
; indented lines, otherwise it will not compile properly. Always back up the cal
c
; memory to the computer before running a program!
;
; A link to download TASM for IBM is at the bottom of this page.

#include "TI-85.h"
ProgStart=$80DF ; Memory location to save the address of the program

.org 0
.db "Sample", 0
Main:
ROM_CALL(CLEARLCD)
ld HL, 3 ; set text cursor position
ld (CURSOR_ROW), HL
ld HL, 3
ld (CURSOR_COL), HL
ld HL, (PROGRAM_ADDR) ; get program's memory address
ld (ProgStart), HL ; save address for later
ld DE, HelloMessage ; get difference between address of program, string
add HL, DE ; add to get address of string
ROM_CALL(D_ZT_STR) ; print the string
call GetLoop ; wait for a keypress
ld HL, 4 ; set new text cursor position
ld (CURSOR_ROW), HL
ld HL, 3
ld (CURSOR_COL), HL
ld HL, (ProgStart) ; get address back
ld DE, ByeMessage ; get difference between address of program, string
add HL, DE ; add to get address of string
ROM_CALL(D_ZT_STR) ; print the string
call GetLoop ; wait for keypress again
ret ; end of program

GetLoop: ; wait for keypress


call GET_KEY
or A
jr z, GetLoop ; if no key, try again
ret ; key pressed - go back

HelloMessage:
.db "Hello, world", 0
ByeMessage:
.db "Bye!", 0

.end

TI-85 Assembler Programming - Loops using DJNZ


The DJNZ instruction is the simplest way to create a for loop in assembler. It c
ombines a counter variable, CP, and JR into one instruction. It only works with
one specific loop, but it does that loop very well.
DJNZ stands for "decrement, jump if not zero." It uses as its counter the B regi
ster. It first decrements B. Then, it checks if B is zero. If it is not, then th
e program jumps to the given label. Otherwise, the program continues straight ah
ead.
Here is an example of how to use it to make a loop:
; create a for loop that will iterate 5 times
LD B, 5 ; set B's starting value
Loop:
INC A ; do loop stuff
DJNZ Loop
... ; the rest of the program
It's really quite simple. First, store the number of times the loop is to execut
e in B. Then label the beginning of the loop. The DJNZ instruction comes at the
end of the loop. In between comes whatever actions the loop is supposed to execu
te - in this case, incrementing A. No other registers are affected, unlike the I
NC - CP - JR method which modifies the value of A.
There are a couple of bugs to watch for here. First of all, make sure you initia
lize B at the top. I know that sounds like a stupid thing not to do, but it is a
suprisingly untraceable bug. Also, in the body of the loop, it is perfectly leg
al to change the value of B. There are times where this is useful, like adding o
ne to B to keep the loop going longer, but usually it is a bug. You especially h
ave to watch for subprograms called from the loop which modify B. When you learn
the PUSH and POP instructions later you will be able to preserve the value of B
whether it is changed in the loop or not.
The next lesson will teach you basic graphics by plotting single pixels.

TI-85 Assembler Programming - Key Input


Since you already know how to create loops using IF statements, use ROM calls an
d make your own subroutines, learning how to use GET_KEY should be a snap. Getti
ng right to the point, here's the basic read key procedure:
GetLoop:
call GET_KEY
or A
jr z, GetLoop
ret
The GET_KEY routine itself returns in A the keycode of the key being pressed, or
0 if no key is being pressed. OR A causes the Zero flag to be updated, which is
used to check whether a key was pressed. OR A is shorthand for OR A, A, and any
thing OR'ed with itself is still itself, so the value in A doesn't change. Howev
er, OR A does update the Flags register. JR Z checks the updated Flag register t
o see if A is zero. If A is zero, then no key was pressed. In that case we jump
back to the top of the loop and try again. If A is not zero, we read a key, so w
e end the procedure and return to the rest of the program, leaving the keycode s
tored in A.
The keycodes returned by GET_KEY are different than the ones returned by the TI-
BASIC procedure getKy. You may want to download the table of GET_KEY keycodes an
d print it out for a reference. The sample program you will write and assemble i
n the next two lessons will return scancodes of pressed keys using this GetLoop
subroutine.
In the next lesson you will write and assemble a usable program. Choose the less
on that matches your platform.