Contents
========
Labels and Constants
Addressing Modes
Program Control
Loops
Basic Math
Some Bios Routines
The Program Skeleton
Your First Program
Indexed Addressing and Tables
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.
|
|