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.