Document Title: [AtariBWvec.html (html file)]
(Extreme thanks to Duncan Brown for passing along this time consuming information!!)
VECTOR ROM OR DISPLAY LIST CODE (as seen by the State Machine):
Byte 1 Byte 2
8 7 6 5 4 3 2 1 8 7 6 5 4 3 2 1
| | | | | | | | |
| | | | | | +--+--+- Y length (or rise)
| | | | | |
| | | | +---------------------------+---------- Overall scale factor
| | | |
| | | | (8 7 6 5)
| | | | | | | |
| | | | +--+--+--+------------- Command (or scale)
| | | | (3 2 1)
| | | | | | |
| | | | +--+--+----------------------------- X length (or run)
| | | |
+--+--+--+----------------------------------------- Brightness
For the X and Y values, it's like taking the byte1bit4 and byte2bit4
bits and prepending them to EACH of the X and Y values (i.e. both
directions scale the same simultaneously.) If a Y value is 111, and
the other two bits are 00, then it has a length of 7 units (which is
something like 1/1024th of the screen width if I recall correctly???),
but if those bits are 01, then it is twice as long, if they are 10 it
is 4 times as long, and if they are 11 it is 8 times as long.
The brightness is just 16 levels, the few bottom of which are all
invisible anyway, and the top couple of which all look the same, and of
course all of which depends on your monitor brightness setting!
The command-or-scale byte is the one I'm a tad hazy on. Commands can
have the values A through F, and some of the other (lower) values have
some bearing on overall size, but not all of them do, and you can
easily make the state machine crash by playing around...
COMMAND NYBBLE:
A- Position the beam at the X/Ypos contained in these two bytes.
*RARELY* used in the ROM, since most drawing routines were subroutines
to "draw relative to current beam position", but used by the program to
position the beam for drawing each object.
B- HALT. Usually placed at the end of the display list (and again,
rarely if ever found in the ROM)
C- JSR. This is a "state machine format" address in two bytes.
D- RTS. Seen typically as 00 D0. Lots of these in ROM, needless to
say! Can also be meshed with a drawing command to save 2
bytes where possible.
E- JMP. Jump absolute to the "state machine format" address contained
in these two bytes.
F- Draw immediate. I have no idea what this note to myself means...ALL
codes that aren't one of the special codes above are "draw immediate
using data contained in these bytes"! I vaguely remember that maybe
the F-code lines were the smallest, 0 was next, then 1, and so on, but
invariably by the time you got to 9 it was too big... Actually, maybe
F was just a drawing command, but the others also set an overall scale
factor, which applied to all further drawing commands, until a
different scale factor was set. Or something like that... Yeah, so
F=DRAW, 0-9= SET OVERALL SCALE TO LEVEL <0..9>. That sounds about
right.
STATE MACHINE FORMAT ADDRESSES:
Whenever you had an address in a display list or a subroutine that was
going to be executed by the state machine, you had to format it NOT in
the realm of the 6502 addresses, but rather in the sense that made
sense to what the state machine could "see". To turn a 6502-address
into a state machine address, start by subtracting $4000. SO a
display-list address in the $4000's becomes a $0000's address. A ROM
address in the $5000's becomes a $1000's address. This is because of
how the addressing is wired. Now shift right a bit because all state
machine commands take two bytes, so we can save a bit here! So for
instance, $5314 (0101 0011 0001 0100) has become $098A
(000 1001 1000 1010) Add the "C" command for instance for a JSR, and
now you have C9 8A. Swap the bytes in little-endian fashion, and now
you have 8A C9, and you're done! So if you ever see 8A C9 in a display
list or in the ROM, you know that's a State Machine "JSR $5314"
command.
Simple as that (cough cough)...
DISPLAY LISTS AND VECTOR ROMS:
The state machine processes commands it finds in the DISPLAY LIST,
which is an area of dual-port RAM addressed starting at $4000 (for the
6502; it's $0000 for the state machine!) The State machine can munch
on this independently of the main processor's actions. Consider it a
"display coprocessor". So the main program can write drawing
instructions directly into the display list and create whatever it
wants.
But there are some things it knows it's going to want over and over and
over...like characters, and rocks, and ships, and explosion pictures,
and... So those are saved in the vector ROM as callable SUBROUTINES
(all with an RTS [00 D0] command at the end). SO the main program
writes some commands to the display list to position the beam, followed
by a "8A C9", which tells it to JSR $5314, i.e draw picture number 4 of
the player ship. When the display list gets processed, it hits the JSR
and starts processing the commands at $5314 until it reaches RTS (00
D0), then it reverts to where it left off in the display list. So the
stored shape subroutines are inherently RELATIVE- they draw a picture
by moving the beam in increments from wherever it happened to be when
the routine was invoked.
A QUICK MAP OF THE VECTOR ROMS (version 2/3):
$5000-$508F: test pattern direct draw instructions, ends in 00 00 which
I guess halts drawing? Hmmmm
$5090-$50A3: JSR's to write "BANK ERROR" on the screen (final call is
actually JMP to the "R" routine.)
$50A4-$50DF: drawing instructions for copyright symbol, followed by
JSR's to write "1979 ATARI IN", followed by a JMP to $551A, which is
the routine for "C"
$50E0-$50EB: state machine commands for pieces of wrecked ship
$50EC-$50F7: ???? (Maybe more wrecked ship pieces)
$50F8-$50FF: JSR table for the various ship explosion pictures (the
main game uses this table, which is all compact and easily handled by
an indexed addressing instruction, so supply the JSR code for each of
the 4 explosion pictures, which take up too much room to allow direct
indexed addressing to them. So it's inexed indirect addressing!
Holy shades of later processors Batman!)
$5100-$512B,
$512C-$5169,
$516A-$519F,
$51A0-$51DD: four explosion pictures.
$51DE-$51E5: indirect JSR table for 4 rocks.
$51E6-$51FD: subroutine for rock with V notch in top (10 sides)
$51FE-$5219: subroutine for X-shaped rock (12 sides)
$521A-$5233: subroutine for with bottom and left notches (11 sides)
$5234-$524F: subroutine for rock with left and right notches (12 sides)
$5250-$5251: indirect JSR table (one entry long!) for saucer.
$5252-$526D: subroutine for saucer (preceeded in display list by sizing
instructions, to allow two types of saucers!)
$526D-$528F: table of addresses for the 17 different pictures of the
player ship. But they're in 6502 format! But at least the
nybbles are reversed... 17 pictures covered a 90 degree
span (with a picture at BOTH axes and 15 in between), and
then they just get mirrored about one or both axes to make
the others. That explains the 6502-compatible address
table! It has to index into these routines and COPY THEM
to the display list, altering them along the way for
mirroring about an axis or two.
$5290-$54C1: 17 ship picture routines, spelled out individually in the
table above.
$54C2-$54EF: Extra ship picture (as in "I have 43 extra ships")
$54F0-$56D3: subroutines for drawing character set (in A-Z, space, 1-9
order)
$56D4-$571D: indirect table of addresses (state machine format) for the
character set (in space, 0-9, A-Z order). Yes, they just
point the 0 entry at the routine for O!
$571E-$5728: table of "offset from $571E" for each of the messages
$5729-$57B8: 11 different canned messages, "Asteroids packed text"
format.
$57B9-$57F9: table of values for, um, well, it escapes me at the
moment. Drag? Thrust? A smooth(ish) sweep from 00 to 7F
[Sin or cosine or something...]
$57FA-$57FF: all 00's. This is the extra space!
Note that starting at $571E, this is stuff that belongs in the main
ROMS, but they obviously ran out of space! Ooops....
ASTEROIDS PACKED TEXT FORMAT:
This belongs in a discussion about the main game, but since it happens
to be stored in the vector ROM, here goes!
Make a list, in the order space, 0-9, A-Z. Assign space the value 01,
and go up from there.
Write your message down. Now write the code from above for each
letter, but only the first 5 bits are used so write just those down.
Now group the char's in threes, and add a "0" bit at the end of each
group of 3 (15 bits), and re-block back into two 8-bit bytes. Use
those for two bytes of the message. If your message is over, use the
code 00. If your message does not contain a multiple of 3 characters,
use 0 *bits* as filler on the last byte for any missing characters,
this will also end the string. (Any 00 code for a character ends the
string). If you have an exact multiple of 3 characters, you can
make the last BIT a one instead of the normal 0. This saves a byte, so
you don't have to also add a 00 at the end!
Example:
"012"
= 00001 00010 00011 0
= 0000 1000 1000 0110
= 08 86
If it's in the middle of a string...or 08 87 to MARK the end of a
string with that very character.
That's it for tonight! Next up, a memory map of $00-FF (scratchpad
space) and $200-$2FF (player state variables; replicated for player 2
in $300-$3FF)...and the cute trick they use to save code space when
dealing with 2 players!