NAVIGATION
LOG IN
SEARCH
SHARE

@gft

DOWNLOAD

Download as DocBook

CITATIONS

ACagliano. "The Z80 Files." ClrHome. ClrHome, 14 Feb. 2015. Web. 28 Apr. 2024. <http://clrhome.org/tutorials/asm/>

Introduction

Interested in learning assembly? Well you've come to the right place! This tutorial will seek to familiarize you with the instrumental parts of assembly and the syntax required. Then, it will explore the more complicated parts of assembly.

Before we start, you will need a few things in order to create, assemble, and test your programs:

1. A plain text editor: gedit for Linux or OSX, TextEdit for OSX, TextWrangler for OSX, WordPad or Notepad for Windows. Any type of plain text editor will work.

2. The DoorCS SDK (http://www.cemetech.net/projects/item.php?id=32): provides a variety of programming aids, including tools to assemble and link your programs (assembling means translating assembly into machine code, linking means converting a machine code binary into a calculator program).

3. An emulator: A program that lets you test your programs without risking damage to your actual device. We recommend WabbitEmu (https://wabbit.codeplex.com).

What is Assembly

Assembly is a programming language consisting of mnemonics that translate to processor-level instructions. Assembly is very different than your average language, such as C++ or Java for the computer or TI-Basic for the calculator. These languages are considered high-level languages, or compiled languages. If you make a mistake in the code, they will throw a warning or an error and stop running. Also, it is fairly simple to do complex tasks in them.

Assembly however, is an entirely different thing. Assembly's instructions (or moreover, the machine code that assembly represents) sends instructions directly to the processor of the device it is running on. The benefit of this is sheer speed. Since the language isn't being interpreted first, it runs much quicker. However, there are two very big drawbacks. First, it takes ten or more lines of assembly to do something that can be done in one line with the other languages. Second, errors in assembly result in memory or program corruption, or worse, damage to the device's hardware. Since assembly sends its instructions to the processor, there is no warning that an instruction it is about to execute will overwrite a part of the operating system or fry the LCD...it just happens.

These things notwithstanding, assembly is a fun and powerful language to learn and work with, and it is fairly safe as long as you test your programs on an emulator first.

(Math 1) Numerical Representation

As with any computer, the core of learning to program assembly is understanding how the math works. Programming math heavily involves bytes. For those of you who don't know, a byte looks like this:

.db %00101001

This is the bit representation. A bit is the smallest possible representation of computer coding or memory, equating to a boolean state of TRUE or FALSE. On the hardware, the bit values that make up all data or programming simply instruct the processor to pass or halt electrical current beyond a transistor and it is that mechanic that allows a programmable unit to control program flow and decipher the contents of memory. Bitwise programming is also referred to as binary. The % character is used to indicate that the data is in binary format. As an aside, %00000000 is the lowest binary byte value possible and %11111111 is the highest.

There is a second way to represent a byte. Below is a representation of the exact same value as the binary above:
.db $29

This particular representation is hexadecimal. Here, the eight-bit value is a two-digit value, with each "digit" being half-a-byte, or a nibble. Each digit is not the same as digit you are used to, as hex is not a "base 10" number system. It is actually a base-16 number system. While the number system you are used to can go from 0 to 9 before looping back to 0 and incrementing the tens place value, hexadecimal can actually go from 0 to F. Therefore, $00 is the lowest possible hex byte value and $FF is the highest. The $ character is used to denote a hex value.

Last but not least, we have decimal, which is the number system you are used to. Below is the decimal value that is equivalent to the last two:
.db 41

The lowest decimal byte value that is possible is 0 and the highest is 255. There is no character to denote decimal, as it is the default.

(Math 2) Programming Math

Continuing the math topics, we will now explore what actually happens when we do math with bytes. The first thing you must understand is that, at the core of programming, decimals, fractions, mixed numbers, and floats do not exist. All that exists are integers. Yet, computers and calculators are quite capable of doing math with decimals. This is where data structures come in. We will discuss this later, but to make a long story short, a data structure is a series of bytes utilized in a programmer-chosen fashion to represent non-integer data.

Back onto the topic of byte math with integer values... we have already discussed that the byte range goes from 0 to 255. Adding 1 to 255 results in 0 and subtracting one from 0 results in 255. This "sorcery" is called a carry. It is similar to what happens when you add the ones column of 13+29 in basic math. The result is 2 and there is a carry. When you do the math, you have been taught that the "carry" gets added to the next place (tens, in this case). Assembly, however, has no idea what it is supposed to do with that carry, but it sets (value of 1) a special flag, called the carry flag so that you may deal with the carry yourself.

Assembly also has other flags to indicate the results of a mathematical operation. The most used one is the zero flag. This one becomes set when the last instruction processed returns 0. For instance, adding 255 and 1 would set the zero flag. There is also a signed flag which is set if the result is positive and reset if negative.

The CPU (Registers)

As with any computerized device, a calculator has a CPU that makes programmability possible. The CPU does math, controls program flow, reads and writes data, and more. It does this using things called registers.

Your calculator has two sets of registers, 8-bit (1-byte) registers and 16-bit (2-byte) registers. All registers and their function are listed below:

8-Bit Registers
a: accumulator, math register
b: 1-byte counter
c: arbitrary use/hardware interfacing
d: arbitrary use
e: arbitrary use
f: flags register (contains zero, carry, parity, signed flags)

------------------------------------
16-Bit Registers
bc: 2-byte counter
hl: source pointer in read-write routines
de: destination pointer in read-write routines
pc: memory address the processor is executing code at
sp: pointer to the top of the stack
ix: Index register, use similar to hl, but also has other uses
iy: Index register like ix, points to start of system flags

Please note that the 16-bit registers are just two 8-bit registers paired. This means that while one is needed, you cannot use it in another form. For example, the following code would not work correctly because bc's value changes.

add23and10_twice:
ld hl,23 ; loads 23 into hl
ld bc,10 ; loads 10 into bc
ld b,2 ; loads 2 into b (corrupts bc)
add_loop:
add hl,bc ; adds bc to hl, result in hl
dec b ; decrements b by 1
jr nz,add_loop ; if result of dec b was non-zero, repeat

One of the caveats of assembly is that you cannot do math with the memory directly. You must first load the values in memory into the CPU, do the math there, then load the result back into memory. Take the following code as an example:

#define operator1 $8800
#define operator2 $8801
#define result $8802

addoperator1operator2:
ld a,(operator1)
ld b,a
ld a,(operator2)
add a,b
ld (result),a

This routine first loads the value at the memory address $8800 (which we define to be operator1) into a. Since you can only load an address into a, we then move a into b. We then load the value at $8801 (operator2) into a. After that, we add a and b together. The result is in a, which we then load into the memory address $8802 which we defined as "result".

A First Step: The Template

As with any program, there are some preliminary things that an assembly program needs. So, to make things easier, I will show you the simplest form of the assembly header, and then explain each part.

.nolist
#include "ti83plus.inc"
#include "dcs7.inc"
.list

.org progstart ; or .org $9D95-2 if
.db $BB, $6D ; dcs7.inc not included

Start:
// your code here

.end
.END


Now the explanation. First comes the .nolist directive. This tells the assembler to omit everything between that and the next .list directive from the list file (which contains the hex for all your code). After that comes two #include directives. The include directive tells the assembler to fetch the file specified and paste its contents into the current file. The first include allows you to use TI-defined RAM equates, system variables, and system routines. The second allows you to use equates defined by the DCS7. Finally comes the .list directive.

The .org directive instructs the processor to move the program to a certain area in RAM when executing it. Following the .org is an equate, 'progstart'. This is defined by dcs7.inc. If you have not included that file, you will need to use the actual memory address specified above.

The .db directive inserts bytes into a program. In the template above, .db $BB, $6D inserts those two bytes into the program. Those bytes make up the two-byte AsmPrgm token on the calculator, which allows the calculator to know that it is assembly.

Start is a label. We will discuss labels in a later section. After that comes your code. At the end of your code, you need the .end directive. This tells the assembler to stop. There are reports of some assemblers glitching with .end and not stopping, so a second .END is added for good measure.

Let's Load Stuff (LD)

Congrats! You made it through the introductory stuff! Now it is time to move on to actual assembly syntax. The first instruction you will learn (and perhaps the most used) is the ld instruction. Its use is very simple:

ld destination, source

To explain, the ld instruction takes the second argument and loads it into the first. However, there are a few restrictions.