TI-85 Assembler Programming
Data and Memory
Data and Registers
The LD instruction
The INC and DEC instructions
ROM Calls and Numeric Output
Program jumps
"IF" statements
Loops using "if" statements
Key Input
Using TASM
Loops using DJNZ
Keycodes
Glossary

Data and Memory

In other programming languages, you store data in variables. You can do stuff with variables like adding two of them together and storing the result in a third variable.

In assembler, variables aren't as simple. The "variable" is actually an abstract concept. Inside the computer or calculator, variables don't exist. Instead, you directly access the memory and store your data there.

On the TI-85, "memory" means the 32K of RAM that is built-in. This memory is divided into 1-byte chunks. One byte allows you to store an eight digit binary number, so the largest number you can store in each location is a binary 11111111, or 255 in decimal. The lowest is 0. If you want to use larger numbers, you group several chunks together. One common grouping is two bytes, or a "word". Two bytes together can hold a value between 0 and 65535 (2^16).

Each one-byte chunk has a unique number, or address. We access these bytes by using the addresses, just like we use variable names to access variables. Addresses are usually given as hexadecimal numbers for convenience, so a typical address might be $80DF. Addresses used with the Z80 chip are two bytes long.

Data and Registers

In the previous lesson, you learned about the memory, where nearly all data is stored. Unfortunately, memory access is relatively slow for the processor. So, when we want the processor to manipulate data, like add two numbers together, we don't want to do it in the memory. Instead, we load the data into special high-speed memory locations inside the processor itself called registers.

In the Z80 chip there are 14 registers. They have names instead of addresses, and are called A, F, B, C, D, E, H, L, PC, SP, IX, IY, I, and R. The one-letter ones are each one byte, and the two-letter ones are each two bytes.

For programmers, the most important register is the A register. A is also called the Accumulator. A is the focus point for nearly all data operations. For example, when we add two numbers together, one of them is stored in A, and the final answer is also stored in A.

B, C, D, E are used for temporary data, like holding the second number when adding. They are grouped in two-byte pairs - BC and DE - when we need to store larger numbers, like memory addresses.

H and L are separate registers, but they are almost always used as the two-byte pair HL and should always be used to store addresses when moving data between the memory and the registers.

The rest of the registers are unimportant for now. Some of them are used by the chip and not us. PC is the Program Counter. It stores which instruction is being executed. SP is the Stack Pointer. It is the memory address of the top of the stack. We will use the stack later, but we never actually change SP ourselves. I is the Interrupt Vector, which I won't even try to explain. The R register is the Refresh register. I won't explain it because I have no idea what it does!

F is the Flags byte. Each of its bits mean something different. For example, the Zero flag bit tells us whether the last instruction generated a zero result. The Carry bit tells us whether the last math operation required a carry. We will use those two flags later. The other flags aren't used very often by us.

IX is used for special purpose memory access, which we might do later. IY is used internally by the TI-85.

That's how data is stored and used on the TI-85. The addressed memory contains numbered one-byte chunks and is where data is stored. The registers are high-speed named memory locations where data can be manipulated. In the next lesson, you will learn the LD instruction, which is used to move data between registers and memory and from register to register.

The LD instruction

Now that you know how data is stored in assembler, you can learn how to move it around. In assembler, you can't just assign any value to a memory location like you can with variables. Instead, you have to use the LD instruction. LD stands for Load. It loads data from one place into another.

There are several different ways to use the LD operation. The simplest one is loading a specific value into a register. Here is an example:

     LD   A, 17

This gives register A the value 17. We can do the same thing with any register and any value. The value can be hexadecimal if we want.

     LD   B, 32
     LD   C, $18
     LD   H, 213

We can do the same with any register pair:

     LD   BC, 14238
     LD   HL, $80DF

Another way to use LD is to load data from one register to another:

     LD   B, A

This puts whatever value is in register A into register B. As you can see, with any use of LD, data is moved right to left - 17 into A or A into B or whatever. We can load any single register into any other register.

The INC and DEC instructions

Moving data around using LD is useful, but programs have to change data in order to be interesting. The INC and DEC instructions are a common and simple way to change a value.

Here is an example of each:

     INC  A
     DEC  B

If A was 10, it is now 11. If B was 23, it is now 22. Pretty simple, right? INC increments, or adds one to, the value in a register. DEC decrements, or subtracts one from, the value in a register. It is just like saying A = A + 1 or A + 1 -> A. INC and DEC work on any single register, and are incredibly efficient.

The other way to use INC and DEC is to change the value of a memory location by using the HL register pair to store the address:

     LD   HL, $80DF   ; the memory location to change
     INC  (HL)        ; increment the data at that location

If the data at location $80DF was 16, then the new value at location $80DF will be 17. Incrementing data in memory is slower than incrementing registers, but it is still very fast. A typical LD operation takes anywhere from 7 to 16 clock cycles, while INC (HL) takes 7 and INC A takes only one!

This table lists the legal source/destination combinations for the LD instruction. Thanks to John Powers for looking this up so we don't have to.

LD  

X marks a legal source/dest combination

         Source
Dest   imm mem A B C D E H L (BC) (DE) (HL) (IX) (IY) BC DE HL IX IY SP
      ------------------------------------------------------------------
mem  |  .   .  X . . . . . .  .    .    .    .    .   X  X  X  X  X  X
     | 
A    |  X   X  . X X X X X X  X    X    X    X    X   .  .  .  .  .  .
B    |  X   .  X . X X X X X  .    .    X    X    X   .  .  .  .  .  .
C    |  X   .  X X . X X X X  .    .    X    X    X   .  .  .  .  .  .
D    |  X   .  X X X . X X X  .    .    X    X    X   .  .  .  .  .  .
E    |  X   .  X X X X . X X  .    .    X    X    X   .  .  .  .  .  .
H    |  X   .  X X X X X . X  .    .    X    X    X   .  .  .  .  .  .
L    |  X   .  X X X X X X .  .    .    X    X    X   .  .  .  .  .  .
     | 
(BC) |  .   .  X . . . . . .  .    .    .    .    .   .  .  .  .  .  .
(DE) |  .   .  X . . . . . .  .    .    .    .    .   .  .  .  .  .  .
(HL) |  X   .  X X X X X X X  .    .    .    .    .   .  .  .  .  .  .
(IX) |  X   .  X X X X X X X  .    .    .    .    .   .  .  .  .  .  .
(IY) |  X   .  X X X X X X X  .    .    .    .    .   .  .  .  .  .  .
     | 
BC   |  X   X  . . . . . . .  .    .    .    .    .   .  .  .  .  .  .
DE   |  X   X  . . . . . . .  .    .    .    .    .   .  .  .  .  .  .
HL   |  X   X  . . . . . . .  .    .    .    .    .   .  .  .  .  .  .
IX   |  X   X  . . . . . . .  .    .    .    .    .   .  .  .  .  .  .
IY   |  X   X  . . . . . . .  .    .    .    .    .   .  .  .  .  .  .
     | 
SP   |  X   X  . . . . . . .  .    .    .    .    .   .  .  X  X  X  .

imm  = immediate data such as $80DF
mem  = memory address such as ($80DF)
(BC) = using the value in BC as a memory address

ROM Calls and Numeric Output

Moving data around with the LD instruction is useful, but it's boring by itself. If you wrote a program which just did LD all the time, you wouldn't be able to see it actually do anything, except the screen would get dimmer after a while. In order to make an interesting program, you need to know how to do output.

On the TI-85, output is not handled through Z80 assembler instructions directly. Instead, we call routines in the TI-85 ROM, which then do the output for us. This lesson introduces ROM calls in general and describes one of them which is used to print numbers.

ROM calls are a kind of subroutine. A subroutine is a is like a mini-program. When you "call" the subroutine, it is like you are running the mini-program. When the subroutine is finished, your program continues. Running a program from within a program in TI-BASIC is similar. In the case of ROM calls, the subroutine is stored in the calculator's ROM instead of in the memory.

There are twenty ROM calls available through ZShell. Most of them deal with screen output, like writing out a number or writing a character in the menu-sized text. Others read a keypress, handle the little busy indicator, or do other useful things that aren't in the Z80 instruction set.

With TASM, ROM calls are incredibly simple, one of the few simple things in assembler. There are two ways of making a ROM call, depending on which routine you are calling:

     ROM_CALL(D_HL_DECI)
     call GET_KEY

5 routines use call; the rest use ROM_CALL(). The other part of the call is the name of the routine. The names are usually arcane. D_HL_DECI stands for Display HL in DECImal form. It prints the value in HL onto the screen at a specified location. GET_KEY reads which key is pressed, if any, like the TI-BASIC GetKy instruction. You'll learn about it and the other ROM calls later.

One drawback of ROM calls and other subroutines in assembly is that there is no such thing as a parameter list passed to the routine. TI-BASIC people don't have to worry about this; you didn't have parameter lists either. A parameter list is a list of values that are given to the subroutine to tell the subroutine what its task is. The only way to get values to and from subroutines in assembler is to use the registers and the memory. The registers are usually used instead of the memory, because it is faster and more convenient.

The D_HL_DECI ROM call uses HL as a parameter. Before calling D_HL_DECI, you set HL to the value you want printed. The function looks at HL while it is executing to find out what value to print.

D_HL_DECI also uses memory for parameters. Memory locations $800C and $800D always hold the coordinates of the large sized text cursor. $800C is the row and $800D is the column. If you want the number is a specific place, you change those memory locations. D_HL_DECI looks at those locations to find out where to put the number. When the function is done, the coordinates are changed to reflect the new position.

The number printed by D_HL_DECI is right-formatted and padded with spaces to make it 5 characters long.

Here is an example of D_HL_DECI in action:

     LD   HL, 14238     ; load the number to print
     LD   ($800C), 1    ; load cursor coordinates
     LD   ($800D), 1    ; (1, 1) is upper left
     ROM_CALL(D_HL_DECI); print the number
          ; at this point, 14238 is printed in upper left
          ; cursor is after the number
          ; $800C and $800D hold the new cursor position   

That's about all there is to subroutines. If you want to know more about the ROM calls, check out the ZShell Function Library. It documents all of the ROM calls. You will want to download this page later, anyway.

Now you are almost ready to write a complete program. Almost, but not quite. If you really want to write a program and don't mind using code that you won't understand yet, then go to the lesson about writing programs in TASM. The lessons after the sample program will explain the stuff that was ignored.

If you want to know what every part of your program is doing, continue with the lesson on Program Jumps. After a few lessons, you will get the same sample program.

Program Jumps

ROM calls are nice. They let you do something without worrying how it does it. You don't really care how D_HL_DECI prints the number onscreen, as long as it does. Also, you can do it many times without having to type in the whole process each time; you only have to type in ROM_CALL(). In this lesson, you will learn how to write your own subroutines that have the same qualities.

In previous lessons, programs were completely straightforward. An instruction would execute, and then the next one, and then the next one, and so on. With ROM calls, you could change the execution order slightly by running ROM code ni the middle, but the program still went in a straight line. In order to make execution deviate from the straight path, we need to use program jumps. Jumps allow us to go to a different place in the program and continue from there. They are exactly like goto's in various languages.

In assembler, jumps are done by instruction number. Counting instructions to figure out where to jump to is not fun, so TASM allows us to assign labels to instructions and jump to them. Here is an example of a program jump:

     ; start of program somewhere above
     ...

     LD   A, 45
MyLabel:            ; program label 
     LD   HL, 17
     ROM_CALL(D_HL_DECI)

     ...
     ; more program
     ...

     LD   C, 42
     JR   MyLabel   ; jump to MyLabel
     LD   D, 15
     ...

The program executes along merrily until it gets to the JR instruction. At that point, the program continues running at the label. Here, the program will store 42 in C just before it jumps to MyLabel. There, it will continue by storing 17 in HL and executing a ROM call. The instruction LD D, 15 does not get executed. MyLabel is identified as a label by the :.

In this way, we can set up simple loops. It is not a good idea at this point, but we can do it anyway:

Loop:
     INC  A
     LD   B, A
     JR   Loop

We increment A, store A into B, and then jump back where we were before and sttart again. Do you see why we don't want to do this? The program will get stuck in this loop because there is no way out of it. We just keep executing these three instructions over and over again. Since it doesn't stop, it is called an infinite loop. The only way to stop an infinite loop is to take out the batteries and reset the calculator. In the next lesson, you will learn to control loops and make them stop.

Jumps done using JR have limited range. They can't jump too far away from themselves. If you need to jump a long way (more than about 120 program bytes) then you need to use the JP instruction. JP is slower but can jump anywhere in the program, no matter how far away. Using ZShell, the JP instruction is replaced by the JUMP_ macro. It does the same thing but takes into account special circumstances encountered on the TI-85.

JR doesn't work very well for subroutines, though. When the program jumps to a label using JR, there is no way to find out where it can from. If we want to jump to a subroutine, we have to store where we were so we can go back when the subroutine is done.

The way to handle subroutines is with the CALL and RET statements. CALL is the same as JR, in that it jumps to a label, except that it stores the program's previous location on the stack. Don't worry about what the stack is yet, just remember that the old location is stored. The number that is stored is called the return address. The RET statement is used at the end of a subroutine. It looks at the stack to find out what the old location was and jumps back to there. Here's an example:

     ;... the program
     INC  C
     CALL MySub    ; jump to the subroutine
     INC  A     
     ;... more stuff
MySub:
     INC  B      
     ;... do stuff in the subroutine
     RET           ; go back where we came from     

First comes INC C. Then we jump to MySub, remembering where we came from. In MySub we INC B and do other stuff. At the end of MySub is the RET instruction, so we find out where we came from and go back. When we get back we INC A and continue with the program.

If we want, we can call subroutines from within subroutines. One warning - make sure each CALL has a RET and each RET has a CALL. If CALL is missing the program will get confused, because it won't know where to go back to. If RET is missing, the program will keep going, either running part of the following subroutine or falling off of the end of the program. All of those things result in buggy programs.

"IF" statements

If statements are not simple in assembler. In fact, the code never actually says "if". Instead, you use JP or JR or CALL with a condition. The conditions aren't simple, either. For example, you can't just say jump if A = B. Instead, you have to subtract A from B and see if the answer if 0. Luckily, there are a few things that make it a little bit easier.

One thing that helps us is the Flag register. It stores, among other things, whether the last result was zero or positive, and also the carry and parity of the answer. The other thing us is the CP instruction. CP stands for Compare. It subtracts a register from A and throws away the answer. The use of this is that it still changes the flags. So, if you wanted to see if A = B, you would compare A and B and see if the Zero flag is set. The conditions used with JP, JR and CALL all check the flags.

Here it is in assembler code:

          ; check if 17 = 23     
     LD   A, 17     ; load one number
     LD   B, 23     ; load other number
     CP   B         ; compare A with B
     JR   Z, Equal  ; jump to Equal if zero result

CP B compares B with A by subtracting them. If the two numbers are equal, the subtraction is zero, so the Zero flag is set. The Z next to JR is a condition. Z stands for Zero. JR Z, label only jumps if the Zero flag is set. If the two numbers were equal, the condition would be true, and the jump would occur. Otherwise, the program keeps going straight ahead.

CP always compares something to A by subtracting it from A. The flags are changed but A is not. It can compare raw values, any register, or memory by using HL to hold the address.

There are 8 different conditions that check 4 flags. They are Z and NZ, which check for zero and non-zero; C and NC, which check for carry and no carry; PO and PE, which check for parity odd and parity even; P and M, which check for positive and negative (plus and minus). The only ones I have used are Z and NZ, for checking equality. I have heard that C and NC are useful for greater and less than, but I have not used those. If anyone knows uses for PO/PE and P/M, let me know.

To put it simply, "CP B JR Z, label" can be translated as "if B = A, then goto label". Changing the Z to NZ makes it "if B ­ A..."

The most common usage of if statements is probably the construction of rudimentary loops. You will learn how to create these loops in the next lesson.

Loops using "if" statements

In programming, loops are incredibly useful things. If you are using a high-level language, creating a loop is easy: you just have to do something like "while num = 7 do ..." and the compiler will take care of the rest. Unfortunately, there is no compiler is assembly language, so we have to set up the loops ourselves.

One method of making a loop is the same way that is used in old-style BASIC, everyone's favorite not-so-high-level language. It looks something like this:

10 A = A + 1
20 IF A != B THEN GOTO 10
30 ... 

The loop simply executes instruction 10 until the if statement is false, at which point execution continues to the rest of the program. Assembly loops are exactly the same, except we don't have simple if statements or simple goto's.

Using the information about assembly if's in the last lesson, it is easy to translate the BASIC loop into assembly:

Loop:
     INC  A
     CP   B
     JR   NZ, Loop
     ...       

This type of loop is most commonly used as a while or repeat loop - while no key has been pressed, while the player isn't dead, and so on. Creating a for loop using if statements is more complex, because you have to take care of the counter variable inside the loop. A simpler way to create a for loop is by using the DJNZ instruction, which combines a counter, CP, and JR into one instruction. It is described in the next lesson.

Key Input

Since you already know how to create loops using IF statements, use ROM calls and make your own subroutines, learning how to use GET_KEY should be a snap. Getting 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" really means "OR A, A", and anything OR'ed with itself is still itself, so the value in A doesn't change. "JR Z" checks the updated Flag register to see if A is zero. If it is, 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, meaning we read a key, then we end this procedure and return to the rest of the program, leaving the keycode stored in A.

The keycode returned by GET_KEY is different than the one return by the TI-BASIC procedure getKy. You should probably download the table of GET_KEY keycodes and print it out for a reference. The sample program you will write and assemble in the next two lessons will return scancodes of pressed keys.

As I said, in the next two lessons you will write and assemble a useable program. The first lesson deals with using TASM, the DOS-based assembler. Information for the Mac assembler will be available soon, as soon as I learn how to use it.

Using TASM

TASM (Table Assembler) is a program that we use to turn the text files we type into binary numbers that the calculator can understand. In this lesson you will learn how to make your code TASM-friendly and how to use TASM to assemble your code.

TASM requires that you add a few commands into your code. Most of them aren't seen by the calculator - they're just directions for TASM. They include lists of other code files, the name of the program, the beginning and the end of the program, 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 of 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 is 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 before 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 TASM 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, this string is the internal program name, on the right side of the ZShell menu. The 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 traditional place for storing strings that the program uses while it runs. They are created 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 the program is done.

Using TASM to assemble code is a time-consuming process if you have to type it in 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 code file to be assembled.

TASM creates two files - myfile.obj and myfile.lst. If everything worked OK, then myfile.obj is the assembled code and myfile.lst is a listing of the code and can be thrown away. If something went wrong, then myfile.obj will be a bad file and should be deleted immediately, and myfile.lst is a copy of the source code with 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 fild should be renamed simply myfile (without any extension). Then the command line for string85 looks like this:

string85 myfile

This creates the myfile.85s file, which is ready to be sent to the calculator. The 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 this 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 computer before running any assembly program. If a program crashes, pressing the ON key 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.

Loops using DJNZ

The DJNZ instruction is the simplest way to create a for loop in assembler. It combines 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 register. It first decrements B. Then, it checks if B is zero. If it is not, then the program jumps to the given label. Otherwise, the program continues straight ahead.

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 execute 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 execute - in this case, incrementing A. No other registers are affected, unlike the INC - 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 initialize 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 legal to change the value of B. There are times where this is useful, like adding one to B to keep the loop going longer, but usually it is a bug. You especially have 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 how to use the GET_KEY ROM call to get user input from the calculator keypad. After that, you will finally be ready to write a useable program.

Keycodes

Note that these codes are much different from the ones used in TI-BASIC

 Hex codes:              Decimal codes:

 ---------------------- ----------------------
|  35  34  33  32  31  |  53  52  51  50  49  |
|                      |                      |              
|                04    |                04    |
|                      |                      |              
|  36  37  38  02  03  |  54  55  56  02  03  |
|                      |                      |              
|  30  28  20    01    |  48  40  32    01    |
|                      |                      |              
|  2F  27  1F  17  0F  |  47  39  31  23  15  |
|                      |                      |              
|  2E  26  1E  16  0E  |  46  38  30  22  14  |
|                      |                      |              
|  2D  25  1D  15  0D  |  45  37  29  21  13  |
|                      |                      |              
|  2C  24  1C  14  0C  |  44  36  28  20  12  |
|                      |                      |              
|  2B  23  1B  13  0B  |  43  35  27  19  11  |
|                      |                      |              
|  2A  22  1A  12  0A  |  42  34  26  18  10  |	
|                      |                      |              
|  xx  21  19  11  09  |  xx  33  25  17  09  |
 ---------------------- ----------------------

Keys of interest:

up    = $04 = 04
down  = $01 = 01
left  = $02 = 02
right = $03 = 03

enter = $09 = 09
2nd   = $36 = 54
exit  = $37 = 55
more  = $38 = 56

on    = no key code is returned

Glossary

Address: A number given to a location in memory. The location is accessed by using that number, like accessing a variable by using its name. On 
the TI-85, each address is two bytes long, and each address refers to a one-byte memory location.

Assembler: assembly language or  a program that converts source code that the programmer wrote into machine language that the processor can
 understand. Similar to compilers used with high-level languages.

Assembly language: A low-level language used to program microprocessors directly. Z80   assembly language can be used on the TI-85 to write
 programs that execute faster than programs written in TI-BASIC.

Character: A single letter, digit, or symbol. 'Q' is a character. '4' is a character. '%' is a character. '123' and 'yo' are not characters.

Execute: Run a program or carry out a command.

High-level language: Any programming language that tries to look like plain English so it is easier for humans to understand. Unfortunately,
 it cannot be understood by a computer unless it is compiled into machine language. See also low-level language.

Immediate: An immediate value is one that is given in the program code, instead of being loaded from somewhere else. For example, in LD A, 17,
 17 is an immediate value. In LD A, B, the value in B is not immediate, because is is not written into the code.

Instruction: A command that tells the processor to do something, like add two numbers or get some data from the memory.
   
Low-level language: Any programming language that doesn't look like English but is still able to be understood by people. It uses "words" like
 "ADD" to replace machine language instuctions like "110100" to make it easier for the human. See also high-level language.

Machine language: Any programming language that consists of of 1's and 0's representing instructions. A typical machine instruction could be
 110100, meaning "add two numbers together." It is the only language understood by the processor and is completely incomprehensible to most
 people.

Memory: Memory is where data is stored. On the TI-85, the main memory is the built-in 32K of RAM. This memory is composed of one-byte sections,
 each with a unique address. See also the Data and Memory lesson.
 
Microprocessor: See processor.

Processor: A large computer chip that does most of the work in a computer or calculator. The processor in the TI-85 is the Zilog Z80 chip.
  
Program: A thing that tells the calculator to do stuff. More specifically, a program is a list of instructions for the processor to execute.

Register: A register is a piece of high-speed memory located directly on the processor. It is used to store data while the processor mainpulates
 it. On the TI-85, there are 14 registers. See also the Data and Registers lesson.  

Register pair: Two registers being used as if they were one. In this way, larger numbers can be used than in single registers. The register
 pairs are AF, BC, DE, and HL. Register pairs are often used to hold addresses.

Source code: A text file containing the code that the programmer wrote, usually in a high-level or low-level programming language.

TASM: Table Assembler. It is a DOS program which assembles source code for the Z80 and other processors. The assembled code can be moved to the
 TI-85 and run using ZShell.

TI-85: The calculator (duh!)

TI-BASIC: The programming language commonly used on the TI-85. It is the language that is used for PROGRAM variables. Its main drawback is that
 these programs run very slowly, because they have to be translated into assembly language while the program is running, eating up valuable
 processor time.

Z80: The Zilog Z80 processor is the one used in the TI-85. Z80 assembler is the language used to program the Z80 chip.

ZShell: A program for the TI-85 which allows you to run assembly language programs stored in string variables.