Introduction to Vectrex Programming

by Christopher L. Tumber, copyright 1998 all rights reserved.



Contents
========
Introduction
Hexadecimal Notation
Signed or Two's Compliment
Memory
The Instruction Set
The Assembler
Labels and Constants
Registers
Some Instructions
Addressing Modes
Program Control
Loops
Basic Math
Some Bios Routines
The Program Skeleton
Your First Program
Indexed Addressing and Tables



Introduction
============

This is my attempt at an introductory tutorial on programming the Vectrex and 
the 6809. It should hopefully put you over the "hump" of just getting started.
However, this should not be considered a comprehensive text of Vectrex 
programming. My own knowledge of the Vectrex is hardly expert and there are 
plenty of other resources out there.

The most important piece of advice I can give someone learning assembly 
language for the first time is to go slowly and be sure you understand 
everything before you move on. There are a lot of very fundamental concepts 
which will be completely new to you, even if you have programming experience 
in high level languages (like C, BASIC, PASCAL) and it is vitally important 
that you have a firm grasp of the basics or what comes later will just be 
gibberish to you.



Hexadecimal Notation
====================

Learning and getting comfortable with hexadecimal notation is perhaps the 
single most important step to learning assembly language programming. What's 
more, it has been my experience in teaching people assembly that it is one 
of the most difficult subjects to learn.

This is because counting and numbers were one of the first things we ever 
learned. What's more, we all learned them by wrote when we were 4 or 5 years 
old and the concepts behind numbers were never explained to us. Instead, 
we've been using numbers over and over again every day of our lives without 
ever really thinking about what numbers are or why we use them the way we do.

In order to understand hexadecimal, you have to understand what numbers 
really mean and why we use the numbers we do.

To begin with, you have to realise that the numbers 1 or 2 or 5 or 397 are 
arbitrary symbols and don't in and of themselves mean ANYTHING.

Sometime thousands of years ago a couple guys were sitting around and needed 
a way of counting. They had a bunch of sheep or a heard or cattle and needed 
to keep track of how many they had. If they had enough for breeding. If they 
had enough to feed themselves throughout the winter. That kind of thing.
So, they came up with some symbols. They called the symbol 1 "One" and the 
symbol 2 "Two" and so on but that decision was completely arbitrary. They 
could just as easily decided to call the symbol 5 "One" and the symbol @ 
"Two".

What's more, the decision that the symbol 1 or "One" would mean "A single 
unit of something" and 2 or "Two" would mean "A single unit PLUS another unit 
of something" is also completely arbitrary. 1 or "One" could have just as 
easily meant "A single unit PLUS another unit PLUS another unit". Or the 
symbol 5 could have mean't "I don't have any of these at all" (what we call 
ZERO).

It's the same with words, really. Why does the word "Apple" mean "A round red 
fruit that grows on trees"? Because, sometime hundreds or thousands of years 
ago someone decided "Apple" would be a good name for that fruit and we've 
been using it ever since. They could just as easily decided "Orange" or 
"Mustard" was a good name and we'd be using that instead. Yup, my mom bakes a 
great mustard pie....

The only reason the word "Apple" or "One" or the symbol 1 means anything is 
because we all agree on the meaning. If you ask someone who only speaks 
French for an "Apple" he's not going to know what you are talking about. Not 
because the word "Apple" doesn't have any meaning anymore, but because his 
language doesn't agree that "A round red fruit that grows on trees" is called 
an "Apple" but instead he calls it a "Pomme".

Similarily, we have all agreed that the numbers 0,1,2,3,4,5,6,7,8,9 all have 
a certain meaning.

However, sometime ago in the days of the Roman Empire we would have been
counting I,II,III,IV,V,VI,VII,VII,IX,X. (Most people have seen Roman Numerals
before, if not, they still appear often on clocks and watches...)

Both systems of counting refer to the same thing. Both are just as valid.

We use our system primarily because we have ten fingers. This system of 
counting is known as Base 10 or Decimal because there are ten different 
symbols used (0 through 9).

When we count in decimal, we start with 0 and go 1,2,3,4,5,6,7,8 up to 9. 
However, when we reach the number TEN we have a problem. We don't have a 
single, simple symbol for the number TEN. Instead, we have to start to RE-USE 
symbols. So, we use two symbols instead of just one and come up with: 10.

Why?

The most obvious answer is "Because my first grade teacher said so" but that 
doesn't really address what's going on here. We counted from 0 to 9 and then 
ran out of symbols. So, we had to come up with something to do because we 
need to be able to count A LOT higher than just 9.

So, what we do when we get "Stuck" at 9 is instead of using just one symbol 
as we do to represent 0 through 9 we use TWO symbols side by side to 
represent the numbers 10 through 99. This is important! We get around the 
fact that we REALLY only can count from 0 to 9 by adding a new column of 
symbols, by using two symbols instead of just one. So, instead of having a 
different symbol for every possible number there is (billions or trillions 
of symbols) we only have TEN symbols and we just re-use these TEN by symbols 
by putting more and more of them next to each other. So we can make a number 
like 145 or 32354654.

What's more, the symbol and position of the symbol is important. The first of
two symbols is the "Tens column". This is the number of TEN items we have,
or, it's the number of times we got "Stuck" and nine and had to carry over to
the tens column because we ran out of symbols. The second symbol is the "Ones 
columns" or the number of single items, just as when we were counting from 0 
to 9.

Using this system, we can express ANY number using just the symbols 0 through 
9. So the symbols 324 means we counted up from 0 to 9 and had to carry 
over to 10. Then, we counted up from 10 to 19 and AGAIN had to carry over to 
get 20. We repeated this process all the way up to 99. At 99, we were again 
out of symbols so we need to use THREE symbols now and carried over to 100. 
We keep up this process of counting up and carrying over until we reached 324.

As I mentioned, we use this system primarily because we have 10 fingers. 
Well, what if we DIDN'T have 10 fingers? What if we only had 8 (Octal) or 
what if we had 16 (Hexadecimal)...

You can see where this is going....

Well, a computer actually only has two fingers. Or to be more precise, a 
computer has switches. Switches are either on or off. All of a computer's
operations, including counting, are just turning switches on or off.
So, a computer can only really count from 0 to 1. Unlike us, where we can 
count from 0 to 9. However, just as we can "fudge" it and count higher than 9
by using more than one symbol (324) so too a computer can count higher than 1
by using more symbols.

However, just as we get "Stuck" when we reach 9 and have to start over at 0
with another symbol 1 in front, a computer has to start over after it hits 1.

So a computer counts:   0     When we count:  0
                        1                     1
                       10                     2
                       11                     3
                      100                     4
                      101                     5
                      110                     6

This is called "Binary" or "Binary Notation" and it is the way all digital 
computers actually count. Counting in binary, we can't use the symbols 2 
through 9 (We just can't, okay, that's the rule!) we can only use 0 and 1. 
So, every time we hit 1 it's just like hitting 9 in decimal and we have to 
carry and add another symbol if we want to count any higher; going from 1 
to 10 or 11 to 100. When a computer counts from 11 to 100 it's just the same 
carry over as when we count 9 then 10 except the computer runs out of symbols
earlier so it has to carry and add a symbol at "two" instead of at "ten".

So, if all computers actually count in Binary, why is Hexadecimal so 
important?

Well, it turns out that Binary and Hexadecimal happen to fit together really 
nicely.

As you may know, a single Binary digit is called one "Bit" so 0 is a bit or 1 
is a bit and 11 is two bits. 111 is three bits and so on.

Well, 8 "Bits" make a "Byte". The term "Byte" you've certainly heard before, 
it's one of the most common computer terms. Since a byte is 8 bits, a byte is:
10001000 or 10101010 or 11111111 or any other such combination of 8 0's and 
1's.

A slightly less know term is a "Nibble", a nibble is 4 bits or half a byte. A 
Nibble is 1000 or 1111 or 0101 or...

Lets consider all the numbers that can be represented by a Nibble:

      Binary           Decimal        Hexadecimal
       0000            0 (Zero)           0
       0001            1 (One)            1
       0010            2 (Two)            2
       0011            3 (Three)          3
       0100            4 (Four)           4
       0101            5 (Five)           5
       0110            6 (Six)            6
       0111            7 (Seven)          7
       1000            8 (Eight)          8
       1001            9 (Nine)           9
       1010           10 (Ten)            A
       1011           11 (Eleven)         B
       1100           12 (Twelve)         C
       1101           13 (Thirteen)       D
       1110           14 (Fourteen)       E
       1111           15 (Fifteen)        F

In the case of 0000 or 0001 we use the leading zeros to show that the number 
is four bits (a nibble or half a byte). In the same way 009 or 09 is the same 
as 9 (in Decimal or Base 10), we just normaly drop the leading zeros because 
we don't need them. However, in Binary (and Hexadecimal) Notation we tend to 
keep them in there to show how much space the number takes up (a nibble, a 
byte or even two bytes).

As you can see, I've also included the equivalent Hexadecimal Notation.

In Hexadecimal, instead of using 10 digits (symbols) as in Decimal or using 2 
digits as in Binary we use 16 digits (symbols).

Of course, we only actually HAVE the digits 0 through 9 to use. But, we need 
16. So, we borrow the extra 6 symbols we need from the alphabet. We use the 
letters A through F.

This is a big sticking point for some reason, this using letters as numbers. 
A lot of people have trouble getting their brain around it. Remember earlier 
we decided that numbers and their meanings are completely arbitrary. 1 
doesn't REALLY mean anything except that we say so. 5 doesn't REALLY mean 
anything either, we just say it does. Well, now, we're going to say that 
the letter A means "One more than 9" and the letter B means "One more than A" and so one.

We could have used ANY symbols. We could have made up new symbols. We use 
the letters A through F because they're a lot easier to remember than some 
weird symbol just made up for that purpose. There's also no other occaision 
where you'll see numbers mixed up with letters like 2A5F.

Except Hexadecimal (and some postal codes and licence plates....!)
                                              
So there's not really any room for confusion.

Now, if you refer back to that listing of all the values that can be 
represented by a nibble, you'll see that all nibble values can be represented 
by a single Hexadecimal symbol from 0 to F.

Pretty convenient, eh? 

If order to represent those numbers in decimal, we have to use 0 to 15. (Two 
digits, where we can get away with only one in hexadecimal. Plus, decimal may 
be 1 digit or it may be 2. Hexadecimal is ALWAYS 1 digit. This is actually 
important as where computers are concerned standardisation is a REALLY good 
thing!)

In fact, if you take a Byte:

     Binary        Decimal      Hexadecimal

    00000000          0           00
    00000001          1           01
       .
       .
       .
    10001001        137           89
    10001010        138           90
       .
       .
       .
    11111110        254           FE
    11111111        255           FF

I'm not going to list all the possible values in a Byte because that would be 
256 lines long. However, as you can see any Byte value of 8 bits can be 
expressed with 2 Hexadecimal digits. It takes up to 3 decimal digits.

The only reason we use Hexadecimal is because it translates back and 
forth to Binary so nice and neatly. Trust me, it's A LOT easier to deal with 
Hexadecimal than Binary!


In order to avoid confusion, it is often neccessary to be able to tell when 
we're talking about a decimal number or a hexadecimal. The most common method
is to preceed hexadecimal numbers with a $. (There are others but I'm not 
going to go into them here. I'll only use these and if/when you come upon 
the others you'll know.)

So we would write 10 or $0A. These are really the same number.

While working on an 8-bit machine like the Vectrex you will often see 1 and 2 
byte hexadecimal values.

A 1 byte hexadecimal value looks like $2F.

A 2 byte hexadecimal value looks like $C32F.

The difference is similar to the difference between 10 and 1000, a matter 
of scale. In most computers, values tend to be divided up neatly into Bytes. 
You CAN work with just 1 bit, or with a nibble or any part thereof but most 
of the time you're working with 1 byte or 2 byte values. (You can also work 
with larger values, but probably won't be doing so very often on the 
Vectrex).

1 byte values can represent $00 to $FF (0 to 255) and 2 byte values can 
represent $0000 to $FFFF (0 to 65535). Again, it's a matter of convention 
because these values fit neatly into bytes.


If you need to translate hexadecimal values back to decimal, it is very easy 
to do so.

Remember, is decimal a number like 324 really means:

    3 X 100   (3 times 100)      (100 = 10^2)
  + 2 X 10    (Plus 2 times 10)  (10  = 10^1)
    4         (Plus 4 times 1)   (1   = 10^0)
   -------
    324

(The symbol ^ means "To the power of")

To convert a hexadecimal number back to decimal, you do the same thing, 
EXCEPT each leading digit is a factor of 16 instead of a factor of 10.

So, $C32F is

    12 X 4096  ($C=12 -> 12 times 4096)     (4096 = 16^3)
+    3 X 256   ($3=3  -> Plus 3 times 256)  (256  = 16^2)
     2 X 16    ($2=2  -> Plus 2 times 16)   (16   = 16^1)
    15         ($F=15 -> Plus 15 times 1)   (1    = 16^0)
   -----------
    49967

So $C32F = 49967

You could do all your assembly programming in decimal, however it isn't 
nearly as neat and tidy as hexadecimal simply because of the way hexadecimal 
translates back to binary. In other words, hexadecimal is a kind of 
shorthand. A compromise between binary, which is what the computer actually 
uses but is quite awkward and unwieldy for us humans and decimal which is 
what we humans normal use but is awkward for computers.


Your assembler should be able to deal with both hexadecimal and decimal (and 
binary for that matter) values equally. It's generally up to you to decide 
which is most convenient for you to use in any given situation. You'll tend 
to find that you refer to memory locations in hexadecimal but some data and
variables in decimal. It's really a matter of convenience, when telling the
computer what to do it's generally easier to "speak it's language" and use 
hexadecimal.

You'll also find hexadecimal used all over the place by other programmers so 
it's REALLY important to learn if you're going to look at anyone else's code. 
You could conceivably write all your programs using only decimal notation but 
it'd look really odd and you probably get beat up and called a geek at 
recess...


Signed or Two's Compliment
==========================

The previous description of Hexadecimal Notation has one problem.

How do you express -80 in Hexadecimal?

With a lot of CPU's you're on your own if you want to use negative numbers 
and have to come up with your own way of dealing with negatives.
The 6809 however uses Two's Compliment integers and has the capability of 
dealing with negative numbers built in.

Two's Compliment is kind of a weird format (and you thought hex was strange!)
where negative numbers are the bit-wise inverse of the positive number +1.

So,      1 = 0001
but     -1 = 1111 (1110 + 1 =1111)

and    127 = 0111
but   -127 = 1001 (1000 + 1 =1001)

The bottom line is that in 1 byte you can use -128 to 127 and in 2 bytes you 
can express -32768 to 32767 and if you're going to use positive and negative 
values (and you will!) you should probably use decimal instead of 
hexadecimal.


Memory
======

First of all, a computer's memory is NOTHING like a person's memory.

As noted before, a computer really only sees everything as a series of 0's and
1's. We abstract these 0's and 1's out to be hexadecimal numbers which then 
mean something to us. To the computer, they're just a bunch of on and off 
switches.

Picture a computer's memory like a school hallway filled with lockers. Each 
locker is one byte of memory and can hold one thing. Each locker is also 
individually numbered (in hexadecimal) so we can identify it. (ie: "What's in
locker $2333??")

For our purposes, there are two types of memory, RAM and ROM.

If a locker is ROM (Read Only Memory) we can look into the locker but we 
can't EVER change the contents.

If a locker is RAM (Random Access Memory) we can look in the locker AND we 
can change the contents at any time. We can store anything we want in there.

So, if your PC has 8 Megs RAM, it has 8 million lockers that can be used to 
store things (A meg is a million). 

There are two basic kinds of things we can have in each locker, a program or 
data. Our program is simply a series of instructions which tell the Vectrex 
what to do. Just like you tell your kid brother what to do you have to tell 
the Vectrex exactly what to do. This is our program.

Our lockers can also contain data. Data is a little different than program in 
that it isn't exactly instructions for the Vectrex, rather, it is information 
our program will use in some way (ie: Lines of text, musical notes in a song).

To the Vectrex, a locker is a locker, it doesn't matter what's stored there. 
All that matters is what we tell the Vectrex to do with that locker. The 
locker could contain parts of our program or it could contain some data.
We generally tell the Vectrex to execute program instructions, however, it 
will be more than happy to try and execute data as if it were instructions or
manipulate our program as if it was data. It's up to us to make sure we tell 
the Vectrex to go to the right lockers when we want it to do something or to 
go to the right locker to get some data.

Again, each of these lockers is 1 byte. So each locker actually just contains 
a number. If the locker contains program code, then that number represents an 
instruction for the computer. If the number is $01 it tells the Vectrex to 
do one thing, if it is $55 it tells the Vectrex to do something completely 
different.

If the contents of the locker is data, then it could be the circumference of 
a circle or the distance from the Earth to the Moon. It's up to us to decide. 
To the Vectrex, it's all just numbers. We just tell the Vectrex "Do the 
instructions in locker $1000" or "Get us the data in $1000".


In the high-school named "Vectrex High", locker numbers $0000 to $7FFF 
contain our program (game). These lockers are ROM. They're burned onto the 
cartridge and may never be changed. $0000 to $7FFF is 32768 lockers or 32K. 
Therefore, our maximum program size is 32K (without doing any REALLY fancy 
stuff that's well beyond the scope of this text...) We decide the contents
of these ROM lockers when we write our program. When the Vectrex starts up, it
(essentially) goes to the first locker, at $0000 and looks for the first 
instruction. It then proceeds sequentially through the lockers ($0000 then 
$0001 then $0002 then...) until or unless the instructions in those lockers 
tell it to do otherwise.

Locker numbers $C800 to $CFFF are _supposed_ to be RAM that we can use, 
however for some reason we can only ACTUALLY use $C800 to $CBFF (If you ever 
discover why, please let us all know!!).  What's more, the Vectrex itself 
actually uses lockers $C800 to $C87F for it's own storage purposes. So we 
really only can use lockers $C880 to $CBFF to store our gym shorts. These 
lockers are empty when you first turn on the Vectrex. However, throughout 
the course of our program, we can put stuff in here. Stuff like scores, 
spaceship positions, etc.

Locker numbers $E000 to $FFFF are also ROM. However, THESE lockers were 
filled by the designers of the Vectrex. These lockers contain the BIOS. The 
BIOS is a set of program instructions built into the Vectrex that we can use 
for our own programs. A handy bunch of instructions that do all kinds of 
things like draw vectors and make sounds.

Obviously, there are a whole bunch of lockers I haven't mentioned, but we 
don't need to go into those. Really!

These are the basic lockers you need to be able to get into.


The Instruction Set
===================

The Vectrex (or to be more specific the 6809) has a number of built in 
instructions. Just like you can tell your kid brother to wash the dishes 
for you but you can't get him to drive you to the mall because he's only 
8, the Vectrex can only do so many things. This is the instruction set.
You WILL need a list of the Vectrex's instruction set. I won't provide it 
here, there are a couple on my WWW site and you can get a copy from Motorola 
themselves (this is a REALLY good idea, btw! See my web site for instructions 
on how).

A single line of instruction for the Vectrex looks like this:

$1000     deca

  ^        ^  
  |        |
  |         ---------- The instruction
  |
   ------------------- The locker number 

It doesn't really matter what this actually does, I just want you to get the 
idea of the format.

The first number, $1000 is the memory location where this instruction 
resides. This is the locker number where the Vectrex will find this 
instruction. The term "deca" is an instruction, it tells the Vectrex to do 
something.

Most instructions will, at first look incomprehensible to you. In most cases
they are abbreviations which is why they don't mean anything to you right 
now. There are maybe a dozen instructions you will use all the time, and 
you'll quickly come to recognise them.

As I mentioned previously, the contents of all lockers (memory) is actually 
just a number. So why did I just tell you the contents of locker $1000 is 
"deca"?

Well, I lied!

$1000 does just contain a number. However, if you were going to try to 
memorise all instructions by their actual number you would have a REALLY hard 
time as there are hundreds of them. Instead, we use a mnemonic like "deca" 
because it's much easier to remember and understand. 

The purpose of an ASSEMBLER is to take our mnemonics like "deca" and 
translate them to their real, numeric code that the Vectrex actually sees 
(in this case "deca" becomes $4A). Meanwhile, a DISASSEMBLER will convert 
the numeric code back to mnemonic code that we can understand more easily.

In general, each of the various instructions provided do a very small task. 
Unlike a high level language like C or BASIC where the instructions can 
perform relatively complex tasks, assembly language instructions tend to be 
very simple and it is by doing several instructions in sequence that we 
accomplish large jobs.

Once the Vectrex has finished with our instruction, it will move onto the 
next locker and look there for another instruction. For example:

$1000    deca
$1001    tsta

That's generally the way it works. The Vectrex just goes sequentially through 
all our lockers executing whatever instructions it finds there.

Of course, it's a little more complex than that. 

Some instructions tell the Vectrex to go to a different locker to find the 
next instruction.

Some instructions are a little more complicated and actually take up to four 
lockers to hold.

Something like:

$1000     sta $C880
$1003     deca
$1004     tsta


The Assembler
=============

Our list of instructions for the Vectrex is know as Source Code. All this is 
is a normal text file with all your instruction for the Vectrex in it. You 
can write your source code in any text editor as long as it will save in 
standard ASCII text.

An Assembler is a program that translates our source code into the actual
machine language that the Vectrex can read.

In my case, I use the AS9 assembler which adds an intermediate stage in that 
it doesn't translate into machine code directly but instead into hexadecimal. 
The program hex2bin is then used to convert this to the true machine code.

To take my source code, run it through the assembler AND run the resulting 
program on the Vectrex emulator, I enter the following commands at the DOS 
prompt:

as9_new omega.as9
hex2bin omega.s19
vectrex omega.b00

The file omega.as9 is my source code. The file omega.b00 is the resulting 
Vectrex ready game file like BERZERK.GAM or BEDLAM.GAM for the emulator.


Labels and Constants
====================

If you look at some source code, you'll notice that every line DOES NOT start
with a locker number.

If fact most if not all lines don't have locker numbers at all.

This is because the ASSEMBLER does this for us automatically. Let's say we 
wrote a program that was 100 lines long. Having to type in every memory 
address (locker number) for each program line would be very tedious. Also, 
because some instructions take up more than 1 locker it would be very easy 
to make a mistake and wind up with instructions in the wrong locker.

Instead, we just tell the ASSEMBLER what locker to START putting our program 
into. After that, the ASSEMBLER just goes sequentially down the line of 
lockers adding more instructions according to our source code.

We tell the ASSEMBLER where to start with a line like:

        ORG     $0000

This line, which you'll find near the begining of every Vectrex program tells 
the ASSEMBLER "Start putting program code in memory location $0000".

If you were programming on a different machine, you might start at a 
different locker. However, on the Vectrex you ALWAYS start with locker $0000.

So, instead of our code looking like this:

$1000     sta $C880
$1003     deca
$1004     tsta

It's just going to look like this:

          sta $C880
          deca
          tsta

But, what if for some reason we need to find the lockers with "sta $C880" in 
it? Before, we could say it's in $1000. We always knew where it was. But, 
because the ASSEMBLER is doing the counting for us we don't really know 
exactly which locker it's going to put this instruction in. What if we move 
this piece of code around? What if we put something in the locker in front of 
it, so it all gets moved down a locker?

That's what a label is for.

If we need to be able to find this locker later, we attach a label to it like 
this:

kill_ship:
          sta $C880
          deca
          tsta

The characters "kill_ship" is the label, using the colon is what indicates 
that this is a label and isn't considered part of the label itself.

This label acts sort of like a name tag stuck onto the locker. We don't have 
to refer to the actual locker number anymore, we can just refer to the name 
tag (label). When the ASSEMBLER actually translates our source code into 
machine code, it subtitutes the actual locker numbers for any labels.

The big benefit of using labels is that they are a lot easier to remember AND 
they are a lot more meaningful than just a locker number. If at some point in 
the future, you need to find the above code you will remember that it's 
kill_ship, remembering that it was at $1000 would be a lot more difficult. 
Also, if someone else comes along and reads your code, kill_ship gives you a 
pretty good idea of what that code does. $1000 could mean anything.

Taking this one step further, there are often a lot of numbers or values 
you use over and over again. Often these will be declared as constants at the 
begining of a progrma. If you look at any Vectrex source code you will 
generally see a list of such constants. Constants look like:

user_RAM        EQU     $C880

The line above means that whenever the ASSEMBLER sees "user_RAM" later it 
interprets it as $C880. As shown in the Memory section, $C880 is the start of 
RAM available for use by the programmer.

So, by adding this line to the start of our program, whenever we need to look
in the first RAM locker we use, we can say "user_RAM" instead of $C880.

After adding this line to the start of our program, we could change:

kill_ship:
          sta $C880
          deca
          tsta

To instead read:

user_RAM        EQU     $C880


kill_ship:
          sta user_RAM
          deca
          tsta

These two snippets of code mean the very same thing. However, using labels 
and constants has made it much easier to read, and much easier for us to 
remember where things go.

In addition, constants MUST all be placed at the very begining of your source
code, BEFORE any actual instructions. This makes constants even more 
convenient because if you ever forget them, you can just go to the start of 
code and look them up.


Registers
=========

Lockers (memory) can hold either program or data.

If lockers contain data, there's generally not much you can do with it while 
it's sitting in the locker. You have to take it out to use it.

To do this, you take data out of a locker and put it in your pocket. Once in 
your pocket, you can fool around with it. Change it, manipulate it, and 
eventually if you want to, put it back in the locker.

Of course, you have several pockets. A couple in your pants, your jacket and 
of course your shirt pocket with it's pocket protector! So, you can have a 
few things in your pockets without having to put them back into a locker 
while you work with what's in another pocket.

The Vectrex's pocket's are called REGISTERS.

The registers are called (rather unimaginatively) A,B,D,X,Y,U,S,PC,DP and CC.

Some of these pockets actually have pretty specific uses.. You only put your 
wallet in your back pocket or your breast pocket for example. But some are 
very general purpose; your jacket pockets might contain your keys or change 
or...

The A and B registers are 8-bit (1 byte) registers which are the most often 
used for general purpose data manipulation. However, the A and B registers 
are a little weird. They're like how some jeans have a little "change pocket" 
inside the front right pocket. You know, anything in that little pocket, it's 
not in the same pocket as your front right pocket. But, if you think about it 
it sort of is...

A is the right hand pocket. B is the little change pocket. The D register is 
these two pockets combined! The D register is a 16-bit (2 byte) register that 
is actually a combination of A and B.

So, if the A register has a value of $A0 and the B register has a value of 
$FF then the D register has a value of $A0FF. If you change the contents of 
the D register, you ALSO change A and B. If you change A, then you change the
"top" part of D. If you change B then you change the "bottom" part of D.

Generally you are either using A and/or B for their 8-bit storage OR you're 
using D for it's 16-bit storage at any given time. It's sort of "cheating" by 
giving you a couple extra registers without using up any more space because A 
and B "overlap" with D.

Most of your data manipulation type work will be done using A, B or D.

The X and Y registers are two 16-bit registers. They're usually used as 
pointers in Indexed Mode Instructions (see below).

U and S are both Stack Pointers (more on that later).

PC is the program counter. This is the number of the current locker being 
checked to see what instruction to execute. This register can be manipulated
by a variety of instructions to cause the program to progress other than 
sequentially (for example, if you want to execute some code over and over 
again).

DP is a special register for use with Direct Addressing. More on that later 
as well.

CC is the Condition Code Register. It tells you the results of some types of 
instructions the Vectrex just did (ie: If the result was a Zero, or Negative, 
or if there's a Carry or Borrow (for addition/subtraction)).


As an example. Let's say locker number $C880 contains the number of ships a 
player has left in the game. Let's say the player has just qualified for a 
bonus ship by scoring a bunch of points.

What we do, is we go to locker $C880. We see what value is stored in that 
locker (The player could have 1 ship left or 5 or anything...). We take this 
value and put it in A. We then add 1 to A. We put whatever's in A back 
into locker $C880. We then go on to do whatever else needs to be done (play 
some special "Bonus Man" music, continue with the game, etc...)

On the other hand. Let's say the player has just been killed.

Well, then we'd go to locker $C880. Put the contents of that locker into A. 
Now, we subtract 1 from A. Next, we check if A is equal to zero. If it is, we 
go do whatever we need to do to end the game ("Got you humanoid!"). If it's 
not 0, then we put the new value in A into $C880 and continue with the game.

Somewhere else in the program, we would have a some instructions that look 
into $C880 and then print that many ships remaining onto the screen.


Seems like a lot of work, eh?

Well, it is! Nobody said this was easy!

That's why most sane people use C or BASIC or PASCAL....

Actually, it's not really that difficult. The above isn't really the best 
example. It actually IS possible to do some VERY SIMPLE things to data while 
it is still in a locker. So doing something like increasing/decreasing the 
number of ships left would actually be simpler. However, for any complex 
operations you do have to move data out of the locker (memory) and into your 
pockets (registers).


Some Instructions
=================

We've finally come to the point where you're going to have to start to learn 
some of the 6809's instruction set into to go any further. So, we'll start 
with some of the more common and more simple instructions.

The first is LD.

LD is an abbreviation for LoaD. LD simply puts a value into one of the 
Vectrex's pockets (registers). LD may be used with any of several registers:

LDA - Load a value into the A register
LDB - Load a value into the B register
LDD - Load a value into the D register
LDS - Load a value into the S register
LDU - Load a value into the U register
LDX - Load a value into the X register
LDY - Load a value into the Y register

To go back to our previous examples, suppose we were starting a game and we 
wanted to put a value of 3 into A because that's how many ships a player 
starts out with. The instruction to do this would be:

        LDA #3

Pretty simple, eh?

That sticks a 3 right into the A register. Anything that happened to be in A 
already is overwritten and lost so you want to be sure that whenever you put 
something into a register (or memory location for that matter) that you're 
done with whatever was in there before.

On the other hand, if you wanted to to take whatever's in memory location 
(locker) number $C880 the instruction would be:

        LDA $C880

That takes a copy of whatever is in $C880 and copies it into register A. 
$C880 is itself not changed and keeps whatever was there. In effect, taking 
something from a locker (memory) and putting it into your pocket (register)
only copies and doesn't actually move it.

Another ultra-common instruction is ST.

ST is an abbreviation for STore.

STore takes a value in a register and copies that value into a memory 
location. ST can be used with the A, B, D, S, U, X and Y registers.

To store the contents of register A back into $C880 the instruction is:

        STA $C880

Pretty simple, right?

Okay, two more basic instrcutions and then we're done for now. These are INC 
and DEC. Both INC and DEC may be used with register A or B or directly on 
memory. Remember I said a few instructions could be used directly on memory? 
Well, INC and DEC are two of those.

INC is and abbreviation for INCrement and DEC is an abbreviation for DECrement.

The instruction:

               DECA

Will reduce the value of register A by one.

The instruction:

              INCA

Will increase the value of register of A by one.


So, summing it all up, if we wanted to take the contents of $C880, put it in 
register A, subtract 1 and then put the result back into $C880 the 
instructions would be:

ships_left     EQU   $C880

[There'd be a whole bunch of other code in here]

kill_ship:
          LDA ships_left   ;Get number of ships remaining
          DECA             ;Subtract 1 
          STA ships_left   ;Put result back

(We could have simply used the instruction DEC $C880 or DEC ships_left. 
However, we've done it this way for a reason. So that we can do other 
things while the number of ships left is in A. Like check if the game is over 
because the player's out of ships. We'll tackle this later.)

This introduces something else new. Commenting.

Any time the ASSEMBLER sees a semi-colon (;), it ignores everything to the 
right of that semi-colon and treats it as a comment. You can use comments to 
remind yourself what sections of code do, particularly complicated sections 
whose purpose might not be obvious. Also use comments to help other people 
trying to read and decipher your code.


Addressing Modes
================

The 6809 offers 5 different addressing modes.

The addressing modes Inherent, Immediate, Extended, Direct, Indexed
and they look like this:

DECA             - Inherent
LDA #$00         - Immediate
LDA $C880        - Extended
LDA $80          - Direct
LDA #$80,X       - Indexed
LDA B,X          - Indexed
LDA ,X++         - Indexed
LDA [$C880]      - Indexed

Addressing modes are slightly different variations on each instructions. Each 
instruction may be able to use 1 or more addressing modes. No instruction can 
use all 5 modes. The simplest modes are Inherent, Immediate and Extended.

Addressing modes are just the different ways an instruction can handle data. 
For example, you go to the library to do research on the big science fair 
project. To find out about volcanos, you can go to the encyclopedias. You 
can look up the books specifically on volcanos. You can search the web for 
pages on volcanos. You can use the microfiche to look up newspaper and 
magazine stories on volcanos.

Any way you do it, it's all a very similar result. You're looking up 
information on volcanos.

Addressing modes are like those alternate sources of information. They're 
alternate targets for the assembly language instruction.

Immediate mode means that the target of the instruction is an actual value, 
and that value will follow the instruction immediately. So,

LDA #$00

Puts the actual value #$00 (Zero) into register A. If you were to pry open 
the chip and examine the A register right after executing this instruction, 
you would find it contains the number #$00.

Extended mode means the target of the instruction is a MEMORY LOCATION, and 
the memory location follows the instruction. So,

LDA $C880

Copies whatever was in memory location (locker number) $C880 into register A.
If there was a #$00 in $C880, then A will now also contain #$00. If there was 
a #$FF in $C880, then A will now also contain #$FF.


Inherent mode stands alone and unlike Immediate or Extended takes no further 
arguments like #$00 or $C880. Instead, the effect of the instruction is 
completely self-contained. These are really the simplest of instructions.

DECA

Means decrement (decrease) the A register by 1. So, if the A register 
previously contained a #$01 (One) it would now contain a #$00 (Zero). As you 
can see, the effect of the instruction is self-evident. You don't need any 
further information whether a memory address or actual value. It's all right 
there.


Direct addressing is actually very similar to Extended. Picture if you will 
some code which looks like this:

LDA $C880
STA $C881
LDA $C882
STA $C883
LDA $C884
STA $C885
LDA $C886
STA $C887
LDA $C888
STA $C889

Basically, all this does is move some values around. From $C880 to $C881, 
from $C882 to $C883. This is just an example, it doesn't really do anything. 
But it's similar to a lot of stuff you might actually want to do.

As you noticed, this code is actually VERY repetitive. In particular, $C8 is 
used over and over again. As you've probably noticed, computers are really 
good at doing repetitive tasks, and at making it easier for you to tell it to 
do repetitive tasks.

Direct addressing is just such a short-cut.

With Direct addressing, we could instead do this:

LDA #$C8
TFR A,DP
LDA $80
STA $81
LDA $82
STA $83
LDA $84
STA $85
LDA $86
STA $87
LDA $88
STA $89

Now, I've thrown a bit of a curve-ball at you here. You've never seen TFR 
before. Well, I'll explain.

Direct mode make uses of another register, the DP register. The DP register 
is a 1 byte register whose sole function is Direct mode addressing (You could 
possibly use it as an extra data register like A or B but that would probably 
be more trouble than it's worth).

When the 6809 encounters a Direct mode instruction, it consults the DP 
register and using the value in DP, acts like an Extended mode instruction, 
but with that DP value as the first two digits in the address.

So, if DP is equal to #$C8 then:

LDA $00

is the same as:

LDA #$C800

See, shortcut! Saves you typing, and saves 1 byte of memory in the program by 
not having to have #$C8 there. It's also faster. This Direct mode addressing 
can be very handy because you are often referring to memory locations that 
have the same prefix. For example, I mentioned that $C800 to $CBFF are free 
RAM that you can use. Well, if you only use $C800 to $C8FF, you can use 
Direct mode in all of you instructions involving RAM.

As for the TFR instruction. Well, unlike the A, B, D, X, Y, U and S registers
you CAN'T do a LoaD instruction directly into DP (You just can't, don't you 
argue with me young man!). So, instead, what we do is:

LDA #$C8   ;Puts #$C8 into regiuster A
TFR A,DP   ;TransFeRs the contents of A into DP

So we've just done and end-around this limitation and put the value #$C8 into
DP in a round-about way... First into A, then into DP. Think Double play 
ball: Shortstop to Second to First. You can't skip Second base or you miss 
the out...

Indexed addressing modes are a little more complicated and a bit involved. So 
we'll hold off looking at them for a while. You're better off getting 
yourself familiar with some of the other more basic instructions and concepts 
involved in 6809 and Vectrex programming.


Program Control
===============

Normally, your program will proceed sequentially from first instruction to 
last. So:

LDA $C880
STA $C881
LDA $C882
STA $C883

Starts with the LDA $C880, then does STA $C881, then LDA $C882 and finally 
STA $C883.

Often that's not enough. Sometimes you want to execute certain portions of 
code only under certain conditions. Sometimes you want to re-use code. The 
6809 offers a variety of instructions to alter the flow of the program.

The instructions to do this are:

BCC
BCS
BEQ
BGE
BGT
BHI
BHS
BLE
BLO
BLS
BLT
BMI
BNE
BPL
BRA
BRN
BSR
BVC
BVS
JMP
JSR

Yes, that's a lot of them. But you don't really need to know all of them 
right now, we'll stick with the basics.

JMP (JuMP) and BRA (BRanch Always) are unconditional jumps.

For example:

  LDA $C880
  STA $C881
  JMP another_section
.
.        ;Bunch of code in here
.
another_section:
.
.        ;More code
.

When the program hits:

JMP another_section

The next instruction that will be executed is at the label another_section:

The difference between JMP and BRA is that JMP can jump to ANY place in the 
program. BRA on the other hand is limited, it can only go a maximum of 127 
bytes ahead or behind. This makes it a shorter instruction than JMP, JMP 
takes 3 bytes while BRA only takes 2. So, if possible you generally want to 
use BRA but that's often not practical.

JSR (Jump to SubRoutine) and BSR (Branch to SubRoutine) call subroutines. 
Subroutines are sections of code which you want to re-use. Some sections 
of code can be made to serve a very general purpose and can be re-used in 
a variety of places. For example, something simple like adding two numbers. 
You don't neccessarily want to re-do that same code over and over every time 
you want to add two numbers. So, you use a subroutine:

  LDA $C880
  STA $C881
  JSR another_section
  LDA $C884
  STA $C885
.
.        ;Bunch of code in here
.
another_section:
  LDA $C882
  STA $C883
  RTS
.
.        ;More code
.

As before, when the program gets to:

  JSR another_section

It jumps immediately to:

another_section:

However, in this case things are a little different. The program will later 
come to:

  RTS

All RTS means is ReTurn from Subroutine. As soon as the program hits one of 
these, it goes back to where it hit the last JSR and resumes just after that 
JSR. So in other words, the above code has the same effect as just:

  LDA $C880
  STA $C881
  LDA $C882
  STA $C883
  LDA $C884
  STA $C885

Just as with JMP and BRA, BSR is very similar to JSR. Except JSR can go 
anywhere in the program, while BSR is limited to 127 bytes ahead or behind.

The other branching commands are all conditional. They only do the jumping if 
a certain condition has been met. As I previously mentioned, one of the 6809 
registers is the Condition Code (CC) register. This register keeps track of 
the results of previous instructions. It's compsed of several pieces 
(actually bits) one or more of which are checked by the conditional branches 
to determine their effect.

These bits are: Half Carry (H), Negative (N), Zero (Z), Overflow (V) and 
Carry (C).

If an operation results in a Zero, then the Zero bit will be set. If an 
operation results in a Negative, the the Negative bit will be set. And so 
on.


For example, BEQ (Branch on Equal) only branches if there was a Zero result.
Suppose we write some code which is executed in a video game when the player 
gets shot or collides with something. We would do something like this, a 
subroutine called kill_ship:

ships_left   EQU  $C880   ;Set up a variable which keeps track of remaining 
.                         ;ships
.
.
.
kill_ship:
  DEC ships_left    ;Decrement the number of ships left by 1
  BEQ game_over     ;Check if that was the last ship, and branch if it was
.
.                   ;Code which restarts level, etc
.
.
game_over:
.                   ;Code which ends the game
.
.

We only want to go to the game_over section of code if that was the last 
ship. Otherwise, we just continue with the game. You will use these kinds of 
conditional branches all over the place. Virtually every time you want your 
program to check if something has happened... If the player has crashed into 
a wall, i a player has been shot, if a player has moved the joystick, if the 
player has pressed fire, if the player's shot has hit anything, if the player 
deserves an extra ships, etc, etc, etc.


BNE (Branch Not Equal) is the exact opposite of BEQ. This instruction 
branches only if the Zero bit had NOT been set.

The other branch instructions are all fairly simple. The MC6809E 
Microprocessor Programming Manual from Motorola gives a description of them 
all, as will most other reference materials. So I'll leave it to you to 
discover them, basically there's a branch for ever bit in the Condition 
Code (CC) register and then some which test 2 bits.

However, I will mention a couple things when dealing with branching 
instructions.

First, all of the branching instruction begining with the letter B (That is, 
everything except JMP and JSR) are short jump instructions and are limited to 
jumping 127 bytes foreward of back. However, you CAN turn these all into long 
jump instructions by placing the letter L in front of the instruction name.

So, BRA is a short jump instruction and LBRA is the same instruction, but 
will handle long jumps. The difference is that LBRA takes an extra byte.

The other thing to keep in mind is that some assemblers treat Relative and 
Absolute jumps differently and can give you weird results if you mix them. 
The BRA, BEQ, BNE, BSR (all of the starting with B) jumps and their L 
prefixed equivalents (LBRA, LBEQ, LBNE, LBSR) are all Relative jumps. JMP and 
JSR are absolute jumps.

What this means is that:

BRA some_place

When it's assembled, actually tells the 6809 to "Jump ahead/behind a 
certain number of bytes" the number of bytes to jump is determined at the 
time of assembly by how far away the label "some_place" is. So, if some_place 
is 20 bytes ahead in the code, then this instruction is actually translated 
to machine code meaning "Jump ahead 20 bytes".

On the other hand:

JMP some_place

Is translated to mean "Jump ahead/behind to a certain address". So, if 
some_place is memory address $2000 then this instruction is translated to 
"Jump to $2000".

This is a subtle but important difference. It's important because some 
assemblers, like the AS9 assembler I use don't let you mix label destinations 
for these two kinds of jumps. So, if you have code that looks like this:

.  ;Some code here
.
  BNE some_place
.
.  ;Some code here
.
.
  JMP some_place
.
.  ;Some code here
.
some_place:

You will get a "phasing error" even though it looks perfectly reasonable! 
Instead, you need to do it like this:

.  ;Some code here
.
  BNE some_place
.
.  ;Some code here
.
.
  BRA some_place
.
.  ;Some code here
.
some_place:

Believe you me, it took a long, long time and a lot of frustration before I 
realised what this problem was! The bottom line is don't mix relative and 
absolute jumps to the same destination!

See, I've already just saved you a pile of headaches!


Loops
=====

As mentioned, one of the most important functions of computers is their 
ability to do repetitive tasks and to do them over and over and over again 
without ever getting tired.

That's really what looping is really all about. Let's say you wanted the 
computer to do something really simple over and over again. Let's say we want 
it to do this:

LDA $C880
STA $C881

Maybe 5 times. Why would we ever want the computer to do this ten times? 
Well, honestly we probably wouldn't but I want to keep this example simple 
because it's not what we are doing over and over that's important but HOW we 
are going to do it over and over. We could just as easily say we want to do 
100 lines of code 5 times, but, that 100 lines would just be distrating and 
possibly confusion so we'll stick to something really simple like:

LDA $C880
STA $C881

And do it 5 times. Well, the simplest and most obvious way is to just do this:

LDA $C880
STA $C881
LDA $C880
STA $C881
LDA $C880
STA $C881
LDA $C880
STA $C881
LDA $C880
STA $C881

That will work fine and in fact there are times when you will want to do 
something similar and do it just this way (because this is actually a little 
faster than the other way I'm about to show you). But usually only if you 
are doing something fairly simple and not very many times.

But what if I told you to do this 50 times? Or what if we were working on 
that complicated 100 lines of code instead of just 2 simple lines? Suddenly, 
this because a HUGE piece of code. Hundred and hundreds of lines!

Of course, there's a better way... If there wasn't, you wouldn't be reading 
this section!

What we do is a loop:


loop_variable     EQU   $C880   ;Create a variable for looping


  LDA #$05            ;Initialise our loop
  STA loop_variable   ;variable with a value of 5

loop_start:           ;This is the label at the start of the loop
  LDA $C880           ;These are the instructions we want to repeat 5 times
  STA $C881           ;These are the instructions we want to repeat 5 times
  DEC loop_variable   ;Subtract the loop_variable by 1
  BNE loop_start      ;If the loop variable is not Zero, jump to loop_start

And that's it. This code will execute our:

  LDA $C880
  STA $C881

Instructions 5 times. In essence, what we are doing is creating a variable 
called loop_variable. The 6809 uses this variable to keep track of how many 
times it has executed the loop. Just the same as if you were keeping track of 
how many times you were going to do something over and over by counting as 
you go.

As we've discussed several times before,

loop_variable     EQU   $C880   ;Create a variable for looping

Creates a label pointing to memory address $C880. We will later use this 
memeory address as our variable. The first two lines of actual code:

  LDA #$05            ;Initialise our loop
  STA loop_variable   ;variable with a value of 5

Put a value of 5 into this memory location. First we LoaD #$05 into register 
A and then we STore register A into loop_variable. loop_variable of course 
points to $C880. We go through register A because you can't put a value 
directly into a memory location we have to go first through one of the 
registers like A, B, D, X or Y... Just like we did when we wanted to set 
register DP back when we were talking about Direct addressing.

Next we have the label which is the start of the loop:

loop_start:           ;This is the label at the start of the loop

This is the place in the code we want to come back to when we are going to 
execute the next bit over and over again. The code that we are going to do 
over and over again being:

  LDA $C880           ;These are the instructions we want to repeat 5 times
  STA $C881           ;These are the instructions we want to repeat 5 times

Which are just the instructions from before that we want to execute a total 
of 5 times.

Now things start to get interesting. First we,

  DEC loop_variable   ;Subtract the loop_variable by 1

This decreases the value in loop_variable by 1. So the first time through, 
loop_variable will have a value of 5 (We set it to five just on the previous 
page there). When we execute this instruction, loop_variable is reduced to 4.

Next, we:

  BNE loop_start      ;If the loop variable is not Zero, jump to loop_start

This checks to see if the Zero bit of the CC register has been set. The 
previous instruct, the DEC will set the Zero bit if the result of the 
decrement was a Zero. Otherwise it will clear it.

The first time through the loop, loop_variable will have been decreased from 
5 to 4. That's not zero, so the Zero bit is cleared. This means that the BNE
instruction causes the program to jump to loop_start.

And we go through it again, back to:

loop_start:           ;This is the label at the start of the loop
  LDA $C880           ;These are the instructions we want to repeat 5 times
  STA $C881           ;These are the instructions we want to repeat 5 times

And so we execute our instructions a second time. And then a third, a fourth 
and a fifth time.

However, eventually we will get to the:

  DEC loop_variable   ;Subtract the loop_variable by 1

Instruction when loop_variable is 1 (Having previously been decreased from 5 
to 4, then 4 to 3, then 3 to 2, then 2 to 1), so this time when we decreased 
loop_counter the result is 0. This sets the Zero flag. So when we get to

  BNE loop_start      ;If the loop variable is not Zero, jump to loop_start

The Zero flag IS set! So this instruction does nothing, it does NOT branch us 
back to loop_start. Instead, it just continues on to the next instruction and 
the rest of our program. The loop is complete.

The thing about looping is that it's very compact and very easy to a 
something A LOT of times. For example, if we wanted to make this loop execute 
100 times instead of 5, all we'd have to do is:


loop_variable     EQU   $C880   ;Create a variable for looping


  LDA #100            ;Initialise our loop
  STA loop_variable   ;variable with a value of 100

loop_start:           ;This is the label at the start of the loop
  LDA $C880           ;These are the instructions we want to repeat 5 times
  STA $C881           ;These are the instructions we want to repeat 5 times
  DEC loop_variable   ;Subtract the loop_variable by 1
  BNE loop_start      ;If the loop variable is not Zero, jump to loop_start

And poof, the code will happily execute itself 100 times!

Pretty simple, eh? I hope you realise you just learned one of the most 
important concepts in computer programming...


Basic Math
==========
Some Bios Routines
==================

The Program Skeleton
====================

This is about the simplest, most basic program you can write for the Vectrex 
which will actually assemble and run:

        ORG     $0000

; Magic Init Block

        FCB     $67,$20
        FCC     "GCE XXXX"
        FCB     $80
        FDB     music
        FDB     $f850
        FDB     $30b8
        FCC     "SIMPLE"
        FCB     $80,$0
start:
        bra start
music:
        FDB     $fee8
        FDB     $feb6
        FCB     $0,$80
        FCB     $0,$80

In fact, it's so simple it doesn't really do anything at all. But it will 
work and it shows you all the parts which MUST be included in a Vectrex 
program in order for it to work.

First is the line:

        ORG     $0000

This line tells the assembler to start assembling code at memory location 
$0000. For the Vectrex, ALL code begins at $0000. However, on many other 
computers code can start in a variety of places. Or, you may want to assemble 
your code in a bunch of little pieces and then join them together later. As 
the assembler is multi-purpose it includes the option to begin assembly 
anywhere, but for our purposes with the Vectrex we will ALWAYS use:

        ORG     $0000

Next is the "Magic Init Block"

; Magic Init Block

        FCB     $67,$20
        FCC     "GCE XXXX"
        FCB     $80
        FDB     music
        FDB     $f850
        FDB     $30b8
        FCC     "SIMPLE"
        FCB     $80,$0

This actually contains all the information the Vectrex needs to compose the 
screen you see at startup. "GCE XXXX" is the copyright info. "SIMPLE" is the 
name of the program/game. music is the starting address of the music data 
that is played when the game first starts up. In this case, I've set it to 
some music data included below, but there are also several pieces of music 
built into the BIOS that you can use. Eventually, you may want to write your 
own music.

The actual program is:

start:
        bra start


Which just tells the 6809 to endlessly loop and do nothing. Like I said, a 
very simple program.

Finally is the music data:

music:
        FDB     $fee8
        FDB     $feb6
        FCB     $0,$80
        FCB     $0,$80

I won't go into the format for music here, but this code just tells the 
Vectrex not to play any music.

And that's it. That's a Vectrex program, though granted it doesn't do much 
of anything.


Your First Program
==================

So let's do something.

This is a simple program which draw a line. You can actually clip this out 
and assemble it and run it on the Vectrex emulator:


waitrecal               EQU     $f192
move_pen7f_to_d         EQU     $f2fc
intensity_to_A          EQU     $f2ab
draw_to_d               EQU     $f3df

        ORG     $0000

; Magic Init Block

        FCB     $67,$20
        FCC     "GCE XXXX"
        FCB     $80
        FDB     music
        FDB     $f850
        FDB     $30b8
        FCC     "LINE"
        FCB     $80,$0
start:

;Draws a big line from the middle of screen to right edge.
draw_line:
        jsr   waitrecal                 ;Reset the CRT
        lda   #00                       ;Get y
        ldb   #00                       ;Get x
        jsr   move_pen7f_to_d           ;go to (x,y)
        lda   #$7f                      ;Get the Intensity
        jsr   intensity_to_A            ;Set intensity
        lda   #00                       ;Get y
        ldb   #127                      ;Get x
        jsr   draw_to_d                 ;draw a line to (x,y)
        bra   draw_line


music:
        FDB     $fee8
        FDB     $feb6
        FCB     $0,$80
        FCB     $0,$80



The first bit of the program should come as no surprise to you. It's simply 
several labels describing the BIOS routines we will be using. This is a 
simple program, so there are no variables or anything, just these labels:

waitrecal               EQU     $f192
move_pen7f_to_d         EQU     $f2fc
intensity_to_A          EQU     $f2ab
draw_to_d               EQU     $f3df


Next comes the "Magic Init Block" which I won't reproduce here and then the 
program begins:

draw_line:
        jsr   waitrecal                 ;Reset the CRT

We call waitrecal first because it resets everything, moves the pen back to 
(0,0) and waits until the timer clears itself so our timing is right.

Next, we move the pen:

        lda   #00                       ;Get y
        ldb   #00                       ;Get x
        jsr   move_pen7f_to_d           ;go to (x,y)

In this case, we don't really move the pen anywhere, but you still have to 
call a move_pen routine before you draw or it won't work. If you want to get 
ambitious, try changing the #$00 values and you'll see the line start in 
different places on the screen.

Next, we set the brightness of the lines to maximum:

        lda   #$7f                      ;Get the Intensity
        jsr   intensity_to_A            ;Set intensity

Again, if you want to get ambitious, try using #$3f or #$1f instead of #$7f 
for the brightness.

Finally, having set all this up, we draw the line:

        lda   #00                       ;Get y
        ldb   #127                      ;Get x
        jsr   draw_to_d                 ;draw a line to (x,y)

This draw a horizontal line of length 127. Again, try different values 
instead of #00 or #127 and you'll draw lines of different lengths.

Of course, since this is a Vectrex, we have to go back to the start and keep 
redrawinf the screen constantly or it will fade and we do this with a jump 
back to the start of the program:

        bra   draw_line

And finally the music description which just tells the Vectrex not to play 
any music.

Now, play around with this, move the line around, make the line longer and 
shorter. And whatever you do, don't worry about hurting anything! Even if you 
screw it up, it would be next to impossible for you to damage anything.
If the assembler gives you an error check that you didn't change the wrong 
thing. If the emulator does something wierd, well it does something wierd. No 
bid deal there!

You'd be surprised how often I've had the emulator do something really wierd 
and unexpected on me because I messed something up!

Don't ever be afraid to make a mistake! You'll never learn unless you 
actually try, unless you actually mess around with and change code.


Indexed Addressing and Tables
=============================

Indexed is the most complicated addressing mode, but also the most powerful. 
It is used to determine an Address by combing or referencing other values and 
is very useful in manipulating tables or large chunks of data.

For example, lets say you have a table of values. Maybe the heights of the 
highest volcanos in the world. The table starts at memory address $C880.

If you want to look up the height of the first volcano, you would simply:

LDA $C880

If you wanted the height of the fifth volcano, you would:

LDA $C884

Which is pretty straightforeward. Unfortunately, it's also very limited. 
Suppose you don't know which volcano you want to reference? Instead, you want 
whoever's using your program to pick which volcano's height to get?

Well, you could do it the hard way, and have a the person input which 
volcano and then have a seperate section of code for each possible 
selection and execute it depending upon what he selected. So you would 
have a section which did a LDA $C880 and one which did a $C884. But what 
if you have 100 volcanos? That's suddenly an awful lot of code.

So instead, you use Indexing. Instead, you'd do this:

volcano   EQU  $C900
.
.
LDA #$05
STA volcano
.
.
LDX #$C880      ;Set register X to #$C880
LDA volcano,X   ;LoaD register A with the value stored in the memory location
                ;which is the sum of the value in register X and the value
                ;in memory location volcano

So, volcano is a label, a variable previously defined as being which volcano 
the user wants to look up. As you've probably figured out you just set the 
register X to the start of the table (in this case $C880) and then use 
volcano as a reference point from the start of that table. In this case, 
register A will wind up with whatever is in memory locarion $C885 ($C880+$05).

This kind of Indexing can be done using the registers X, Y, U and S. So you 
can easily be referencing several tables at once.

There are a couple other types of Indexing modes available to you. Instead of 
a memory address, you can use a register. For example:

LDX  #$C880
LDB  #$02
LDA  B,Y

Will LoaD the register A with whatever is in memory location $C880 ($C880+$02)

Another Indexed mode automatically increments or decrements the register 
(X, Y, U or S) being used.

For example:

LDX #$C880
LDA ,X+

Will LoaD register A with the contents of memory location $C880. Then, the 
value of X is increased by 1. This is usefull in working through an entire 
table in a loop. For example, if you wanted to get an average height of all 
the volcanoes in your list, you could use this, along with a loop, to quickly 
read through your entire table.

Similarily, 

LDA ,-X

Will do the same, but decrease X by 1.

Also, because you will often be dealing with two byte values (ie: memory 
addresses) you can do either:

LDA ,X++

or

LDA ,--X

Which increments/decrements X by 2 instead of just one. This way you can 
easily search through a table of wither large values or memory addresses.

Finally, one last Indexed mode is as follows:

LDA [$C880]

This LoaDs the register A with the value in the memory location that is 
pointed to by $C880 and $C881. So, if $C880 has a value of $E000 then 
register A is LoaDed with the value contained in memory address $E000.


Of course, you are probably wondering why you would ever use all thse 
complicated Indexed modes. Well, there's really good reasons to.

Let's say you're writing a game, and each game has a different number of 
aliens that fly around and shoot at the player. Now, you could have a section 
of code for each level that specifically tell how many ships for each level, 
something like:

number_aliens  EQU $C880
.
.
.
level1:
     LDA #10
     STA #number_aliens
.
.
.
level2:
     LDA #12
     STA #number_aliens
.
.
.
level7:
     LDA #20
     STA #number_aliens


And so on. But as you can see, this kind of thing adds up pretty quickly. 
What's more, this is a VERY simplified example. Suppose you have all kinds of 
different data for each level. Like how fast the aliens move, how often the 
shoot, how aggressively the attack. And so on. You can see that this could 
take an awful lot of code. Particularly when instead you could just:


number_aliens  EQU $C880  ;Create a variable to hold the number of aliens
level          EQU $C881  ;Create a variable to hold the level
.
.
LDA  #$01                 
STA  level                ;Set the level to 1
.
.
LDX #number_aliens_table  ;Setup the start of the table
LDA level,X               ;Get the number of aliens and put it in A
.
.
.
number_aliens_table: fcb #00,#10,#12,#14,#16,#18,#20   ;The table

The only thing you haven't seen yet is fcb. All fcb does is tell the 
assembler to put this ACTUAL VALUE in the code and not interpret it as an 
instruction. So the values of #00,#10,#12,#14,#16,#18 and #20 are put here.
That way you can put static data right into the code. Data like graphics, 
sound, or volcano heights!

As you can see, this is A LOT simpler than before. We can excute the middle 
portion of code, the:

LDX #number_aliens_table 
LDA level,x

Any time we want to set up a level, all we need is to do is set the the 
variable and execute this code. This is a lot simpler and uses a lot less 
space than doing seperate code for each level.

