Site hosted by Angelfire.com: Build your free website today!

The Assembly Tutor

By: Mike Smeen

 

As you and I already know, you would like to learn to program in assembly on the TI-83, otherwise you wouldn’t be reading this. Starting out a language, especially this one, is always the hardest in the beginning. My job is to make it easier for you to learn to program in assembly on a Texas Instrument calculator (in this case, the TI-83). Assembly is different on the other TI calculators, so if you are looking to program on anything other than the TI-83, this isn’t the tutorial for you.

This document is not really a column. It will only consist of two parts, this one, which will get the user more than started with assembly, and part II, which will be for intermediate users. I might make one for advanced users, even though I am not an advanced user myself (yes, it’s true). First, I will start out with what you need to make your first assembly program, then I will start explaining header information followed by specific functions and commands that are used in making a successful assembly program.

General

Let’s start out with the word "program" in general. A program is a set of instructions, that no matter what language you are using, tells the processor of the machine to do specific tasks to solve a problem. You should definitely know the definition of "program" if you want to learn to program in assembly.

Learning assembly (as well as any other programming language) will improve critical thinking skills tremendously. If you are not very good at solving problems, then you might have a slight problem with programming in assembly, but if you are willing to dedicate yourself to learning, it could be just as painless as someone who is good at it. Let me stop the small talk and get down to business. Good luck, you’re gonna need it!

 

What you need

Here is what I tell you what you need to make an assembly program. Assembly is not programmed directly on the calculator. Assembly programs are made on the computer. The program is typed into a text editor (note I said "text editor" and not a "word processor"). What do I mean by this, may you ask? Well, there is a big difference. A text editor, such as notepad, which is standard on all Windows 95 machines, is just plain text. Word processors, on the other hand, such as Microsoft Word or Word Perfect, use different formatting techniques. You must use a text editor to successfully compile and run an assembly program. The program is typed into the text editor, assembled into hexidecimal (a form of code the processor can understand), and then made into a program with either Devpac83 or 83lnk.

Now I will tell you exactly what you need, where to get them, and what they do, so you are not confused at all when you begin to program. First item on the list is the Table Assembler (v3.01), otherwise known as TASM. This is the assembler, which turns the code that you made in your text editor into hexidecimal code. You will also need Devpac83. This turns the already assembled file into a TI-83 program file (filename.83p). You will also need a batch file called "zasm.bat". This file makes everything easier for you. Instead of having to type a long string just to assemble the program, then having to type various other things to turn it into something the calculator can run. You then need to get a file called "include.zip", which contains two necessary files to compile a program.

Unzip all these things (tasm, devpac83, include.zip, and zasm.bat) into the same directory (for now, let’s just name it c:\asm). Assuming your program’s file name is "test.z80", you would type ‘zasm test’ in a DOS prompt at your directory. After the assembler finishes, you will have test.83p in your directory. These files can all be found at the The TI-Philes archives.

 

 

About the assembly language

 

Now, I hope you have a basic idea of what assembly is, because you want to learn it, but we’ll just pretend right now that you have no idea what assembly is. I would like to start out talking about the calculator itself. The TI-83 has a processor called the z80 processor (yes, it is the same processor that the gameboy has). Processors need to be told what to do, which is usually done by some sort of programming language. In this case, the language that we will be learning is called "assembly". You probably heard of TI-BASIC, which is the standard language used to create a program on the Texas Instruments calculators. This language is very slow, because the program needs to go through what is called the "Basic interpreter". What this does is reads the BASIC program, converts it to something it can understand, and then follows the commands. Now that you know this, you can just imagine how much slower it is to do this than to just access the processor directly, without the BASIC interpreter. Assembly accesses the TI-83’s processor directly, allowing faster and better looking programs.

 

 

Programming in assembly

 

Well, let’s start out with your first program. I will give you the code, and you will type it into your text editor (notice I say "type", because the more you type in, the better you learn. Please do not paste). I will explain after you type it in:

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	call _clrLCDFull
	ret

.end
END

I know what you are thinking right now. You are saying to yourself, "What in God’s name is that?" Well, give me a chance to explain. I promised I would completely explain everything, line by line, in precise detail, and that’s exactly what I will do. Let’s start out with the first line.

.NOLIST

This line tells the processor that you are going to be defining some things here, and not to recognize the next few lines as commands.

#define equ .equ
#define EQU .equ
#define end .end

Well, these few lines are very important. When the processor looks in the include files (which I will get to in a bit), it can get mixed up between "equ" and "EQU". This tells the processor that they are the same thing. The last line tells the processor that "end" is the same as ".end".

#include "ti83asm.inc"
#include "tokens.inc"

These lines are the include files. When you do any command, such as "ld", which loads something into a register (variable), the processor will not know what it is, so it searches through the include files for it. The include files contain any and every important command needed to program in assembly.

.LIST

This tells the processor to recognize the next lines as commands. Just as .NOLIST told the processor not to recognize them as commands, this does the opposite.

.org 9327h

This one line begins the program. It is really unnecessary to know what exactly this does, but "beginning the program" is enough for you to know for now. These first 8 lines are going to be in every single ASM program that you come across, so remember these. All lines after the ".org" line must be tabbed. Let’s see them all together:

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST
.org 9327h

And that is the basic header for any assembly program that you will write. Now let’s get to the body of the program.

	call _clrLCDFull

This is a simple line that calls the function to clear the home screen. We will get into exactly what call does later in the tutorial, but know this line, for it will be important in future programs.

	ret

This little line tells the processor "I’m done with this program (or section of the program) now, so you can return to your normal mode". Very simple, you would use this command before ending your program and before ending loops, which will be discussed in further detail later on.

.end
END

These lines end the program. It is not always necessary to use the last "END", but sometimes the program won’t compile without it, so it’s best to just keep it there.

 

Commenting a program

 

Now that you’ve written your first program (hurray!), you should learn early on that it is very important to comment your program, not only for your own purposes, but so others can understand your code. Comments are made anywhere after a semicolon, but the comment ends at the end of that same line. I will now write the program that you just made with comments.

 

.NOLIST  			;  This tells the processor not to recognize the next lines as commands
#define equ .equ    		;  These next few lines make sure the processor does
#define EQU .equ   		;  doesn’t get confused when looking through the include
#define end .end     		;  files.
#include "ti83asm.inc"  	;  Include file, required for program
#include "tokens.inc"    	;  Include file, required for program
.LIST 				;  Start recognizing lines as commands

.org 9327			;  Starts the program

	call _clrLCDFull        ;  Clears the [home] screen
	ret                     ;  Return from the program

.end    			;  End the program
END   				;  End the program

 

It’s that easy, and it will help you very much when you need to go back and review your code for further programming, especially when you are writing a large program. This is very important and you should comment where ever you can.

 

Compiling your program

 

If you got all the files that I told you to get earlier and unzipped them all to the same directory, compiling the program will be very easy. Name your program to ‘clrscr.z80’, and copy the file to the directory where all your files are (in this case, we will call it c:\asm). Simply type "zasm clrscr", and clrscr.83p will appear. Send this program to your calculator. You can’t just run the program directly, so refer to the next section to learn how to run your program.

 

Running your program

Well, I know your saying "How much more do I have to learn, Mike?" Well, fortunately, this is the last thing when it comes to compiling the program. To run a program on your calculator, you can do one of two things. The hardest way would be to use "Send(9prgmCLRSCR", because of the fact that you need to use the catalogue to search for the send command. So, for our sake, we will use a BASIC program. Hit the PRGM button on your calculator, and go to new. Name this program "CLEAR". This is what your basic program will look like:

PROGRAM: CLEAR
:Send(9prgmCLRSCR
:

That’s it! Your first program is done. How does it feel? Feel good about yourself for as long as you can, because if you decide to continue learning assembly, you have a lot to learn. Next, I will be going into some specific commands. The first command that we will be learning is the "ld" command, or otherwise known as ‘load’. Then we will be learning about getkey, direct input, and of course, our favorite, loops. Bear with me please.

 

 

All about registers

 

Like in almost 99% of other languages, assembly has "variables". These aren’t really variables, but just like all the other tutorials say, we’ll just call them variables for now. These ‘variables’ are known as registers in assembly. The main registers are: a, b, c, d, e, f, h, and l (yes, that’s an "L"). Some registers can be combined. These registers are: b and c, d and e, and h & l. The most important combination of registers that you will use is the hl combination. I will get into that soon enough.

Of all the registers, ‘a’ is the most important. This is called the "accumulator". This is most important when you use the ‘cp’ (compare) command, which is similar to an "if/then" statement in various other languages. You would load something into a, then compare it.

A single register is known as an 8-bit register. This can hold up to 255 bytes of information. The registers that were combined (that I explained earlier), are known as 16-bit registers. These can hold up to 65,536 bytes of information, which can be a big help in certain cases.

 

 

The "load" command

 

The "load" command in assembly is ‘ld’, and it is used to store a number into a register. You should, by know, have a pretty good understanding of what registers are and how they work, but if you don’t, please feel free to look back and re-read the last section. It is critical that you understand registers in order to use the load command. Let’s make a single program, using the load command, that loads 10 into the register ‘a’. This will not do anything for you, nor will it be any use to anyone, but this is only to show how the load command is used.

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	ld a,10
	ret

.end
END

And that’s it. Now if you wanted to add 4 and 6 to get 10, there are different ways to do it. I will show you both ways. The first way is the shortest way. This is the way I would recommend for most beginners:

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	ld a,4
	ld b,6
	add a,b
	ret

.end
END

The second way is a little harder, but it demonstrates just how much the accumulator is actually used in many programs:

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	ld a,4
	ld b,a
	ld a,6
	add a,b
	ret

.end
END

What was done this time, is that 4 was loaded into ‘a’, then whatever ‘a’ was (in this case it was 4), was loaded into ‘b’. Then 6 was loaded into ‘a’ and they were added. The accumulator is used in this fashion very often, and this method also should be taken into consideration.

 

 

Displaying text

There are two different places in which text can be displayed, the home screen and the graph screen. The home screen is ideal for simple things, but if you were to make a game or something more professional looking, the graph screen would be used.

 

On the Home Screen

 

For our purposes, we will start by displaying text on the home screen. This is done using the variables (CURROW) and (CURCOL). These numbers determine exactly where on the home screen the text will be displayed. I will show a sample program that says the string "assembly" on the home screen, and then I will take you through it, line by line, and I will make sure you know everything in the program. Type this program in and name it ‘hometext.z80’:

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h 

	call _clrlcdfull ; If you wanted to have a clear screen 
	ld hl,0102h 
	ld (CURROW),hl 
	ld hl,String 
	call _puts 
	ret

String: 
	.db "assembly",0
.end
END

By now, you should know all the header stuff, so let’s start with the first new line.

ld hl,0102h

This is the first example of how important the hl combination-register is. This is a little weird. In this case, we are putting the text at 2,3 (2 rows down, 3 columns across), but since the first column is 0, we need to subtract one from each.

ld (CURROW),hl

This takes the 0102h, and puts the 01 into CURROW, and puts the 02 into CURCOL, which is the variable for columns, and is automatically understood.

ld hl,String

This loads this string. Simple enough?

call _puts

This is a call function that takes the loaded string (which is now in the register ‘hl’), and puts it on the screen. All strings are placed at the bottom of the program. There are several ways to point to a string. This is the way that I do it:

String:
	.db "assembly",0

This can also be done in other ways. One example of another way that someone might do this is this:

String: .db "assembly",0

Note: if you don’t have the ",0", it will put the string on the next line of the program.

 

 

On the Graph Screen

 

Now, on to the graph screen. This is the place where you will put text the most. Text also looks the best on the graph screen, because of the fact that you can change the size of the text that you are writing. Let’s start out with a sample program. You will type this program into a text editor, with the name ‘grphscr.z80’.

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	call _clrLCDFull
	ld hl,0925h
	ld (PENCOL),hl
	ld hl,String
	call _vputs
	ret

String:
	.db "Assembly",0

.end
END

Let’s go through this program line by line. The first 8 lines of the program are the things you already know, otherwise known as the header of the assembly program. Let’s start with the first line of the body of the program:

This is the all-famous line to clear the screen. This also goes for the graph screen, so use this whenever necessary.

ld hl,0925h

This line takes the coordinates (where you want the text to be displayed), and loads it into ‘hl’, which is of course our favorite 16-bit register. Now, just like on the home screen, the coordinates start at ‘0,0’, so we need to subtract one from each side. In this case, we will be placing the text at 10 pixels down, 26 pixels across.

ld (PENCOL),hl

This takes the value of ‘hl’ and puts it into PENCOL. PENROW and PENCOL are just like CURROW and CURCOL, except these are for the graph screen and they are reversed. We use PENCOL instead of PENROW. Why, I do not know, but just remember this, cause it’s important.

ld hl,String

This loads the string into hl so it may be displayed on the graph screen.

call _vputs

This is the call that corresponds to the ‘puts’ call for the home screen, except that this is used for the graph screen.

That’s about it. Pretty simple, huh? Well, even if you don’t know what every single line does, try and remember these groups of lines so you can display text when you want. Let’s move onto something else.

 

Comparing registers and loops

Loops are the most important part of making a decent and successful assembly program. Loops consist of the actual loop itself and a compare command that will jump to that loop if something is true. This is the closest thing to an if/then statement that you will get in assembly, until you get more advanced. I will show you an example of a program that loads a number into ‘a’ and compares ‘a’ with another number.

.NOLIST
#define end .end
#define END .end
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	ld a,10
	cp 10
	ret

.end
END

Well, that’s the simple part. After 10 is loaded into ‘a’, it is compared with 10. What this does is takes the value of ‘a’, and subtracts it from the number you are comparing it with. If the difference is 0, then it is true. In this case, it would be true because 10 – 10 = 0. Now we will use the ‘jp’ command to jump to a loop if something is true. Type in the following program, and we will go through it line by line.

.NOLIST
#define end .end
#define END .end
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

.org 9327h

	ld a,10
	cp 10
	jp z,ten
	
ten:
	ld b,10
	add a,b
	ret

.end
END

Ok, here we go. Let’s start with the first line. First, 10 is loaded into ‘a’ and compared with 10. Let me explain the next line:

jp z,ten

What this means is, if this is true, then jump to the loop ‘ten’. If you wanted it to go to the loop ‘twenty’ if this was not true, you would type in the following after the ‘jp z,ten’ line: jp nz,twenty

Ten:
	ld b,10
	add a,b
	ret

This is a loop. "Ten:" defines the loop, and everything after that until "ret" is the contents of the loop. "ret" returns to the program, which is just the end commands. Loops aren’t really that hard of a concept. Once you get used to them, you will realize that you will be using them in all of the programs you make, and they will make your life much easier. Next on the list is getkey and direct input, which wait for a key to be pressed on the calculator.

 

Get-key and Direct Input

There are many different ways to get a key from the calculator. These ways are really useful in their own separate ways, but let me show you the easiest. The first, and easiest (this doesn’t mean it’s the most effective) way to do it. The way this would be done is like this:

call _getkey
cp 05h
jr z,label

This looks for the enter key. There is a different hex number for each key, which can be found at TI’s webpage (http://www.ti.com/calc/docs/83asmkey.htm), which is a listing for each key. First, the getkey function is called, compared with the enter key, and if it is true, then go to "label", which is otherwise known as a loop. Pretty easy, huh? Well, this method won’t get you very far. For now, let’s assume you need the calculator to wait (or repeat what it is doing), until a certain key is pressed. This is how you would do that:

.NOLIST
#define equ .equ
#define EQU .equ
#define end .end
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

kRight .equ 251
kEnter .equ 254

loop:
	call _clrLCDFull
	call _getkey
	cp kRight
	jp z,right
	cp kEnter
	jp z,quit
	jp nz,loop

right:
	loop here!

quit:
	ret
.end
END

This isn’t that hard. What this does is defines the right and enter keys, compares the key pressed with both, and if it is right, it goes to the ‘right’ loop, if it is enter, it goes to the ‘quit’ loop, which exits the program. If it is neither, it repeats the loop until it is.

You should define keys as their respective decimal number with both direct input and getkey. This is done after the ".LIST" command. These are what all of the defines for each and every one of the TI-83’s keys:

kDown .equ 254
kLeft .equ 253
kRight .equ 251
kUp .equ 247
kEnter .equ 254
kPlus .equ 253
kMinus .equ 251
kMul .equ 247
kDiv .equ 239
kPower .equ 223
kClear .equ 191
kMinus2 .equ 254
kThree .equ 253
kSix .equ 251 
kNine .equ 247 
kRbracket .equ 239
kTan .equ 223 
kVars .equ 191 
kPoint .equ 254 
kTwo .equ 253 
kFive .equ 251
kEight .equ 247
kLbracket .equ 239
kCos .equ 223
kPrgm .equ 191
kStat .equ 127 
kZero .equ 254
kOne .equ 253
kFour .equ 251
kSeven .equ 247
kComma .equ 239
kSin .equ 223
kMatrx .equ 191
kX .equ 127 
kSto .equ 253
kLn .equ 251
kLog .equ 247
kX2 .equ 239
kX-1 .equ 223
kMath .equ 191
kAlpha .equ 127
kGraph .equ 254
kTrace .equ 253
kZoom .equ 251
kWindow .equ 247
kY .equ 239
k2nd .equ 223
kMode .equ 191
kDel .equ 127

Now let’s learn about direct input. Direct input is quicker and more effective, but instead of learning all the lines, it’s better to just memorize them for now. Well, until you get really good at assembly, anyway.

.NOLIST
#define equ .equ
#define EQU .equ
#define equ .equ
#include "ti83asm.inc"
#include "tokens.inc"
.LIST

kRight .equ 251
kEnter .equ 254

.org 9327h

Loop:
	ld a,0ffh
	out (1),a
	ld a,0feh
	out (1),a
	in a,(1)
	cp kRight
	jp z,right
	ld a,0ffh
	out (1),a
	ld a,0fdh
	out (1),a
	in a,(1)
	cp kEnter
	jp z,enter
	jp nz,loop

right:
	loop here!
enter:
	loop here!
	ret
.end
END

 

Right now, all you should be worrying about is memorizing this. You already know what the ‘cp kEnter’ does, and things like it, so just concentrate on learning the other things. You also may copy/paste this for your program if you need it, but it’s good to get in the habit of learning it yourself.

 

Closing

Well, it’s been really fun and all, but there isn’t much I can write about that you will understand (hehe). I definitely plan on releasing a part II (which will be at the ‘intermediate’ level), and it should be out within a few weeks. By the time I release it, you all will be ready to move on to the next level. I worked very hard to write this column (16 pages J ), and I hope that you will refer your friends to this, so they can learn this way.

 

Note: During your journey to learning assembly, you will find that not everyone writes there code the same way. You too will develop your own style of writing your programs, but just because a program source you see isn’t exactly the way I do it, don’t think it’s wrong, because it isn’t. There are many different ways of writing code, and I hope you find the way I taught you to be the best, because I think it is. If you are viewing this on the internet, please keep coming back, because I will add topics weekly. Happy programming!