ticalc.org
Basics Archives Community Services Programming
Hardware Help About Search Your Account
   Home :: Programming :: Columns and Tutorials :: TI-85 ZShell Programming with CAZ
TI-85 ZShell Programming with CAZ

by Miklos Bergou

Welcome to my first lesson in ZShell programming using CAZ! This just introduces assembly language programming and just gets you started. Future lessons will get more complicated. Oh yeah, if you don't have a mac, you're probably at the wrong place!

-Miklos Bergou

CONTENTS

INTRODUCTION TO ASM

So, you want to program some cool games on the calculator to show off to your friends? Well, you've come to the right place (if you're using a mac, that is). Basically, assembly language is just something pretty low-level but very fast. There are times when it does get complicated, but it is pretty simple and straightforward. Actually, if you already know ti-basic, then you have a head start because basic has many similar commands as asm. I do recommend that you know basic because it will make things easier for you, but it is not necessary. You can also learn assembly langauge by studying the source code of programs. I have uploaded one of my programs (Faklear) to ticalc.org and included the source code, so you can also take a look at that. It should work if you compile it on CAZ.

MATERIALS NEEDED

First of all, you need a mac because this column is for assembly programming on macs, obviously. You will need the program CAZ, a Z80 assembler, and Mac String85. Both of these are available at ticalc.org if you don't have them already. You need a word processor to write the programs, CAZ to assemble them, and Mac String85 to convert them to into .85s format. You can set caz to make it into .85s format automatically, but it didn't work quite correctly, so just get all the programs. You should write the program in your favorite word processor and then save it as a text file because CAZ can't open documents from certain word processors.

NUMBER BASES

I won't explain much here because there are other sites which explain it really well, so I won't bother. Humans use the base number ten (0-9). Computers, however, also use two other ones which we are concerned with, hexadecimal and binary. Binary uses the base number two (0 or 1). One binary number is called a bit. 8 bits grouped together are called a byte (ex 10010101). A byte can have a value from 0 to 255. 16 bits grouped together are a word (0-65535). In hexadecimal, a group of four bits, called a nibble, is grouped as one hexadecimal digit. Hexadecimal digits are represented by the numbers from 0 to 9 and the letters A-10...F-15. A byte can be written as two hexdigits (ex 3C=0011 1100).

MEMORY AND REGISTERS

If you are working with assemly language, "variables" are stored directly in the calculator's memory. The addresses of memory locations are defined as four hexadecimal digits (ex 0x80DF) and can hold one byte of data each. If a word must be stored, you can store one byte into a memory slot and another into a memory slot right "next" to it. For example, if you wanted to store 0x80FC (34556), you would need to put 0x80 in 0x80DF and 0xFC in 0x80E0. Since working with the memory is usually slow, there are also high-speed memory locations called registers. The ones we are concerned with now are called A, B, C, D, E, F, H, and L. Each register can hold one byte of information. You can also group two registers as follows: AF, DC, DE, and HL. Each register pair can hold one word of information. A is the most frequently used register because most rom calls (more about those later) involve the A register or some register pair. F is called the "Flags bit." It is not usually used directly by a programmer. Its function is to tell the calculator whether an opertaion performed resulted in zero or required a carry (there are other uses, but those are not used very often). More about that in a little while.

The simplest function on a calculator is LD. It tells the calculator to load a value into a memory location or register. For example:


LD A,4
LD (0x80DF),A

This tells the calculator to load the value 4 into the A register and then A into the memory location 0x80DF. The parentheses around the hex number tell the calculator to use that as a memory address, not a number. You must either use a register pair or the A register to load data into the memory. If you use a register pair, the memory location you are loading to and the one right "next" to it will be changed (ex LD (0x80DF),HL changes 0x80DF and 0x80E0).

HL is a special register pair because you can use it to hold a memory address. For example:

LD HL,0x80DF
LD A,98
LD (HL),A

This tells the calculator to use the number stored in HL as a memory address and load 98 into it.

Back to the Flags bit. To check if two numbers are equal, you would have to write:

LD A,12
CP 12
JR Z,EQUAL

The LD part you know. CP tells the calculator to compare the contents of A with a value which can be a register. You can only compare something with the A register or compare HL and DE as follows:

LD HL,4000
LD DE,3500
CALL CP_HL_DE
JR Z,EQUAL

This does the same thing as normal CP just with HL and DE. JR just means jump, like GOTO in basic. The Z tells the calcuator to check the Flags bit to see if the zero flag was set (if the previous operation resulted in zero). If it was, then jump to EQUAL. So JR Z,EQUAL just means, if the previous operation resulted in zero, then go to to place labeled EQUAL. (Note: to label something, just put the name followed by a colon (:) you can label any line you want, it does not take up any memory) JR can also be used without the Z and then it would jump to the label no matter what.

ROM CALLS

Rom calls are sort of like subroutines in a program. They tell the calculator to do something, like clear the screen, and you don't have to make up your own code for it. You need the file "TI-85.H" to do this (included in caz package). At the beginning of your program, write: INCLUDE 'TI-85.H'

Then, you can use anything defined in TI-85.H. You should also take a look at that file because it briefly explains every rom call and other things. Some of the most used rom calls are CLEARLCD (clear screen), GET_KEY (get value of last keystroke into A register), D_ZT_STR (display zero-terminated string in normal style), and D_ZM_STR (display zero-terminated string in menu style).

You write a rom call like this:

CALL ROM_CALL
DEFW CLEARLCD

Caz doesn't support #DEFINE's, so you can't just write rom_call(clearlcd) like in TASM. For GET_KEY, however, all you have to do is write:

CALL GET_KEY

To display a zero-terminated string, you need to do this:

LD DE,STRINGNAME
LD HL,(PROGRAM_ADDR)
ADD HL,DE
CALL ROM_CALL
DEFW D_ZT_STR
....            ;more code
STRINGNAME:
DEFM "This is a string",0

First, you load the address of the string into the DE register. Then, you get the address of the program into the HL register and add them in the HL register. Then, do the rom call. Usually at the end of your program, you define your string with the label and DEFM "(whatever)",0.

HELLO WORLD!

Okay, I think you could understand things a little better if you saw them in action, so here is a classic hello world program. You may copy the source code, because I didn't make it up or anything. You can complile this directly because anything after a ; is ignored by CAZ.


INCLUDE 'TI-85.H'      ; need this so you can use all the rom calls

ORG 0                  ; tells calc that this
                       ; is start of program
DEFM "Hello people",0  ; zshell menu text

CALL ROM_CALL
DEFW CLEARLCD          ; clear the screen

LD HL,0x0303           ; load value into HL
LD (CURSOR_ROW),HL     ; load HL into memory where
                       ; cursor positions are stored
                       ; (4th row, 4th column)
LD HL,(PROGRAM_ADDR)   ; get program's address into HL register
LD DE,TEXT             ; get string's address into DE regiser
ADD HL,DE              ; get absolute location of string
CALL ROM_CALL          ; do rom call
DEFW D_ZT_STR          ; display the string whose address is in HL

KEYLOOP:               ; label of loop
CALL GET_KEY           ; load value of last key pressed into A register
CP K_EXIT              ; compare it to exit key
RET Z                  ; if result is zero, return (to ZShell)
JR KEYLOOP             ; go back to start of loop

TEXT:                  ; label the text
DEFM "Hello, world :)",0 ; string to be displayed

END                      ; tells caz where end is,
                         ; leave few blank lines after

A FEW WORDS

So, that's it for now. In future lessons, I plan to do some simple graphics and show more complicated code. I hope this helped you out. Basically, CAZ isn't really all that different from TASM. What I recommend is that you get a copy of some code in TASM and try to convert it to caz readable type. To do this, just change all the "rom_call()"'s to "CALL ROM_CALL DEFW "'s. Also, if you see call_() or jump_(), change it to CALL JUMP_ DEFW and CALL CALL_ DEFW. JUMP_ does the same thing as JR except that JR has limited range and JUMP_ can go anywhere. CALL_ tells the calculator to go to a subroutine. At the end of the subroutine, just put RET to go back to where you put in the CALL_ function.

  Copyright © 1996-2012, the ticalc.org project. All rights reserved. | Contact Us | Disclaimer