Atari: Supercharger

starpath
In 1997 I did some VCS 2600 “research”. I started programming a game for the machine and on an other note started examining the starpath supercharger (a piece of hardware, that allowed software (games) on tapes to be played on the VCS).

I tampered with the Stella sources and got the first version going that allowed starpath games to be played with it. My contribution now is probably obsolete and not noticeable anymore (haven’t looked at the credits or sources lately), but still that was once (to my knowledge) the first working supercharger emulation.

Here the original document where I presented the information gathered by me:

(I “xxxxx” some adresses)

-----------------------------------------------------------------------
Some notes about Starpaths Supercharger for Atari VCS 2600
-----------------------------------------------------------------------

Preface:
========
Copyright (c) 1997 by Malban, and others where
noted.

The data contained herein is provided for information purposes
only. No warranty is made with regards to the accuracy of this
information.

Standard disclaimers apply, don't take anything you find here
for granted, perhaps some things may still be wrong, if so
please email me for corrections.
(Malban (email: xxxxxxxx@aol.com))

All trademarks, copyrights names or whatever belong to their
owners. :-)
(Atari, Video Computer System, VCS and Atari 2600 are
trademarks of Atari Inc.
Frogger is a trademark of Sega Inc.)
(probably some others,... you know who you are, and where you
belong to)

Special thanks to the 'CyberPuNKS', whose compilation CD
'Stella gets a new Brain' inspired me to look at
Starpaths supercharger a bit closer in the first place.
Much information contained in this document is derived from
the material they released on that CD. All quoted
documents (marked as: 'tapedocs.txt', 'cntlbyte.doc',
'excal48a.asm', 'frogger.asm') are contained on that CD.
These documents are copyrighted material, the copyright
belongs to the CyberPuNKS, Jim Nitchals in special
(who edited/created them).
The CyberPuNKS are:
Glenn Saunders, Russ Perry Jr., Jim Nitchals and Dan Skelton
(no specific order)

Other information:
==================

There is now a Starpath FAQ available, for further information look
at it:
-----------------------------------------------------------------------
Atari 2600 VCS-STARPATH/ARCADIA FAQ
by xxxxxx@primenet.com (Glenn Saunders)
URL:http://www.geocities.com/Hollywood/1698/faq.html
-----------------------------------------------------------------------

And there is a mailing list:
-----------------------------------------------------------------------
The Stella Mailing list
Subscribe via xxxxxx@biglist.com
post to xxxxx@biglist.com

This is a discussion area for CD owners for the purpose of
developing new 2600 games.
-----------------------------------------------------------------------

There are a couple of documents available for Atari VCS 2600. Like
Hardware information and bankswitch schemes in general.
like:
-----------------------------------------------------------------------
STELLA PROGRAMMER'S GUIDE
URL:http://www.iquest.net/~khorton/stella.txt

Info about cart sizes and bankswitching methods by Kevin Horton.
URL:http://www.iquest.net/~khorton/sizes.txt<

Atari 2600/5200/7800 FAQ
by A. Karl Heller (heller@cdnow.com) and Zube (Zube@cs.colostate.edu)
URL:http://www.cs.colostate.edu/~dzubera/2600faq.html

2600Programming
by Frank Seipel
URL:http://www.sponsor.net/~gchance/2600Stuff/2600Programming
-----------------------------------------------------------------------

Atari VCS 2600 Information
==========================

Just a few things I didn't know before I started this thing.

The Atari VCS 2600 has a 6507 processor. This is a little brother
of a 6502 found in many popular veteran computers (like C64).

The 6507 processor can only address 8KB (and has some other
limitations). Since that, only addresses $0000-$1fff make sense, all
higher addresses are seen modulo $1fff (in this document also).

The 128 byte RAM of the Atari is located at $80-$ff (in the zero-page).
$80 and up is general RAM area, $ff down is the stack area,
hopefully this two never collide.

Memory is organized in pages, each page has 256 byte. Addressing over
a page boundary adds one cycle to the corresponding instruction.

Indirect accesses are only available over zero page addresses.

Game modules have only 4KB available. They are located at $1000-$1fff.
(I'm not sure, are 2KB cartridges mirrored so they fill up all 4KB?)

To access larger cartridges the manufacturers developed different kinds
of bankswitching schemes. For supercharger bankswitching see below,
all other types are pretty well explained in 'sizes.txt' by
Kevin Horton (see other documents).

The Supercharger
================

The supercharger has 6KB RAM on board where games are loaded to.
Furthermore there is a ROM of 2KB for startup and loading of the
programs. Thus it has 8KB of accessable memory. These 8 KB are
divided in 2KB banks. These banks can be 'bankswitched' to the
Atari VCS 2600 module area ($1000-$1fff).

For information how the tape format looks like read this:
Following is a text contained on the 'Stella gets a new brain CD'.
('tapedocs.txt')

------------------------- TAPEDOCS.TXT START --------------------------

The Supercharger Tape format

Low level format
----------------
Tapes are recorded with variable pulse widths. A pulse (or a single
cycle of a sine wave ideally) is shorter in width when encoding "0"
bits, and longer when encoding "1" bits.

The upper and lower bounds on the pulse widths are:

about 158 microseconds for a ZERO bit, and 317 microseconds for a
ONE bit

about 900 microseconds for a ZERO bit, and 2450 microseconds for a
ONE bit

While ONE bits only need to be about 90 microseconds wider, it's better
if they're at least 25% wider in order to allow the Supercharger to
adapt better to any fluctuations in tape speed.

The upper bound on pulse widths is due to limitations in the decoding
software. The lower bound is due to a filter in the Supercharger
designed to remove high frequency hum from 15KHz video interference.

The optimal widths that maximize signal strength through the filter
are:
0 bit: 227 microseconds
1 bit: 340 microseconds

Byte order
----------
Bytes are transmitted with the most significant bit ($80) first, and
the least significant bit last. There are no start or stop bits.

Initial header
--------------
Supercharger tapes start with a lower frequency start tone, but it's
not used by the tape decoder.

A pattern of alternating one's and zero's (byte value of $AA), with a
recommended minimum length of 256 bytes, allows the Supercharger to
determine the widths of one and zero bits.

After the $AA's, a byte of $00 follows. This allows the Supercharger
to synchronize to the start of the byte stream no matter where in the
$AA header it started picking up bits.

An 8 byte header packet follows. If you're offering to help with the
CD at this point I'll tell you its format in more detail. I'm not
excited about creating competition for the CD quite yet, and we've put
in a lot of serious work and don't want to lose money on the project.

The header indicates the starting point of execution, how many packets
of game data, the bank switching configuration for the game, how
quickly to scroll inward the blue progress bars, and a checksum.

Its format is:
- Low order byte of the address to start executing the game's startup
code
- High order byte of same
- Bank configuration as noted below
- Block count (number of 256 byte program data packets)
- Checksum: computed like game data checksums. Sum of whole header
is $55.
- Multiload index #. Set to 0 for first or only load of the game.
Each new multiload game was assigned new numbers sequentially so that
no other multiload stage from another game would be accidentally
loaded
- (Low, high) 16 bit speed value for progress bars. $224 is perfect
for a 6K game image. $16D is right for 4K, and $00B6 is right for 2K
game images.

After the header packet follow packets for every 256 bytes of game
data.

The game data
-------------
For each 256 bytes of data in the game, a packet is written consisting
of a block number that encodes the address page offset * 4 plus the
bank number, and a checksum that encompasses all 256 bytes of data plus
the block number as written to tape. The data then follows in normal
linear fashion, all 256 bytes being written.

The checksum is calculated by adding all checksummed data, ignoring
carries or overflows. The value [$55 minus the sum], again ignoring
carries and underflows, is the checksum to write to tape. Hence, the
sum of the whole data packet including the checksum byte itself will
be $55.

It's recommended you write a byte of 0's and some silence after the
last data packet in order to avoid glitching the audio system of your
tape deck and ruining the last data packet while recording.

Bank Configuration
------------------
D7-D5 of this byte: Write Pulse Delay (set to 0, and the tape loader
will choose the correct setting.)

D4-D0: RAM/ROM configuration:
$F000-F7FF $F800-FFFF Address range that banks map into
000wp 3 ROM
001wp 1 ROM
010wp 3 1 as used in Commie Mutants and many others
011wp 1 3 as used in Suicide Mission
100wp 3 ROM
101wp 2 ROM
110wp 3 2 as used in Killer Satellites
111wp 2 3 as we use for 2k/4k ROM cloning

w = Write Enable (1 = enabled; accesses to $F000-$F0FF cause writes
to happen. 0 = disabled, and the cart acts like ROM.)

p = ROM Power (0 = enabled, 1 = off.) Only power the ROM if you're
wanting to access the ROM for multiloads. Otherwise set to 1.

ROM = bank 4
-------------------------- TAPEDOCS.TXT END ---------------------------

And this:
Following is a text contained on the 'Stella gets a new brain CD'.
'cntlbyte.doc')

------------------------- CNTLBYTE.DOC START --------------------------

*-------------------------------
* L' BYTE DE CONTROL
*-------------------------------

D7-D5 . . . WRITE PULSE DELAY

D4-D2 . . . RAM/ROM CONFIGURATION
VALUE $F000 $F800
000XX 3 ROM
001XX 1 ROM
010XX 3 1 used in Frogger, Suicide Mission
011XX 1 3
100XX 3 ROM
101XX 2 ROM
110XX 3 2 used in Killer Satellites
111XX 2 3

D1 . . . . WRITE ENABLED (=1)

D0 . . . . ROM POWER (OFF=1)

*-------------------------------
* MULTILOAD FORMATS
*-------------------------------

PREPARATION
. . . . . POWER UP ROM
. . . . . WAIT > 1000 CYCLES
. . . . . $80 - D7-D5 ONE SHOT (leave location $80, bits 5-7 intact!)
. . . . . $FA - SEQUENCE BYTE (multiload number to load next in
location $80)
. . . . . STACK POINTER > $FD

PRESS PLAY
. . . . . JMP $F800

REWIND TAPE
. . . . . LDA $80
. . . . . AND #$E0
. . . . . STA $80
. . . . . JMP $F80A

MEMORY
. . . . . $80 POWERUP FROM TAPE (bank number and write pulse delay)
. . . . . $81-$9D ZEROED
. . . . . $FA-$FF VALUES:
$FA: LDA $FFF8
$FD: JMP <ADDR>
<ADDR> IS FROM TAPE (starting address to run code at in
first header)
. . . . . PAGE 7 OF R1 IS USED
FOR STARS AND MUST
BE RELOADED (last page in bank 1 gets trashed when
doing multiloads)
. . . . . REGISTERS
A: SEED FOR RANDOM #
X: $FF
Y: $00

-------------------------- CNTLBYTE.DOC END ---------------------------

And this:
Following is part of a text contained on the 'Stella gets a new
brain CD'. ('frogger.asm')

------------------------- FROGGER.ASM START ---------------------------

org TAPE_HEADERS
dc.b START&255,START/256

dc.b $0B ; RAM bank select control

; We don't have to send all 6K. If the program's smaller, so is
; the tape.
dc.b 24 ; number of 256 byte blocks to send
; (24 for 6K tapes)

dc.b $00 ; checksum (computed by tape gen tool.)

; Leave this 0 unless you're up to the challenge of writing a multiload
; game.
dc.b $00 ; multiload index number
; (0 for single-load games or first load)

; $224 is the correct speed for a 6K tape image.
dc.w $224 ; $110-$224 for real fast to normal
; progress indicator bars

; Checksums for the individual 256 byte blocks are recalculated by
; the tape generation software. Ignore warnings about the checksums
; being wrong. That's there only to verify the accuracy of transcribed
; audio tapes.

; 256 byte bank offsets for the image data to load into.
org TAPE_HEADERS+$10
hex 00 04 08 0c 10 14 18 1c ; page numbers for bank 1
hex 01 05 09 0d 11 15 19 1d ; page numbers for bank 2
hex 02 06 0a 0e 12 16 1a 1e ; page numbers for bank 3

-------------------------- FROGGER.ASM END ----------------------------

If you have *.bin files on your computer (like from the
'Stella Gets a new Brain' CD), these files should be 8448 bytes long.
(the *.bin files on the stella CD can be truncated to that size)

These 8448 bytes contain 4 banks of 2048 bytes and one tape header of
the above format, which has 256 bytes.

2048 bytes bank 1
2048 bytes bank 2
2048 bytes bank 3
2048 bytes bank 4 (all zeros, since that is the ROM part)
256 bytes tape header information
----
8448 bytes ($2100 bytes)

Startup
=======

An extract of an example tape header (frogger.bin):

00002000: E2 F2 0B 18 38 00 24 02 00 00 00 00 00 00 00 00
\_/ I I
I I ---- Multiload Index (0=first or only)
I I (Sequence number)
I I
I ---- Write Pulse Delay, bankswitch scheme,
I RAM enable/disable, ROM configuration
I
---- Start address low/high

Bankswitchscheme on startup
---------------------------
After loading the tape, the value contained in the 3rd byte of the
header is loaded to $80. And bankswitching is set according to the
value of that byte.

(remember?)

D7-D5 . . . WRITE PULSE DELAY

D4-D2 . . . RAM/ROM CONFIGURATION
VALUE $F000 $F800
1. XXX0 00XX 3 ROM
2. XXX0 01XX 1 ROM
3. XXX0 10XX 3 1
4. XXX0 11XX 1 3
5. XXX1 00XX 3 ROM
6. XXX1 01XX 2 ROM
7. XXX1 10XX 3 2
8. XXX1 11XX 2 3

D1 . . . . WRITE ENABLED (=1)

D0 . . . . ROM POWER (OFF=1)

For example a $0b found in the header at position 3 would
correspond to:

$0b = 0000 1011
XXX? ??XX
---------
0 10 == bankswitch scheme 3

Startaddress of Cartridge
-------------------------
The first two bytes of the header contain the startlocation of the
cartridge. Low byte first, high byte second.

Thus a $ef at location $2000
and a $f2 at location $2001

would result in a startaddress of: $f2ef (which in turn would
correspond to $12ef on a
real VCS 2600, since
addressing is done via
modulo $1fff)

Bankswitching while running (accessing $fff8)
=============================================

Someone told me that $fff9 is a redundant address for $fff8. I know
of no game using this and I have no further information. I have not
tested it in any way. If it is indeed so, than in the following
text $fff8 might be replaced with $fff9.

Like several other bankswitch schemes, supercharger has a so called hot
spot. This is an address which initiates a bankswitch upon accessing
that address(es). Supercharger has only one hot spot, it is located at
$fff8. The bankswitch scheme is chosen in a somewhat different manner
than in other bankswitch methods.
Perhaps it is easiest to just provide an example:

ldx $80 ; load value at $80 to X register
; $80 is located in the zero page and in the
; native RAM area of Atari VCS 2600
; let us assume a value of $0b is stored there

cmp $f010,x ; than this instruction will compare the accumulator
; with the value stored in $f01b
; the result is of no concern for bankswitching,
; we are only concerned with the low order byte
; of the resulting address (which is $1b)
; even the compare is of no matter, this could
; have also been a 'lda' instruction, the
; bankswitch access which follows only needs
; the low order byte of the last accessed operand
; address (for special cases see below)

cmp $fff8 ; this now does the actual bankswitching
; accessing memory location $fff8 will trigger
; bankswitching
; this will set the bankswitching scheme
; to $1b (the lower byte of the lastoperandaddress)
; $1b = 0001 1011
; that is
; 7. XXX1 10XX 3 2
; which means that VCS 4KB $1000-$1fff contains:
;
; Supercharger memory
; Bank 1 Bank 2 Bank 3 Bank 4 (ROM)
; $0000-07ff $0800-$0fff $1000-$17ff $1800-$1fff
; _______I__________/
; / \_______________
; / \
; $1000-$17ff $1800-$1fff
; VCS memory
;
; how $fff8 is accessed does not matter
; some programs even run over that location...
; be aware however that the bankswitching occurs
; spontanously, so if you run into the code
; and switch the bank which loads to
; $1800 - $1fff you will end up being on another
; bank
; furthermore, the above 3 instruction sequence
; pokes (stores) the value to location $fff8
; in the supercharger RAM (see below)

Again:
The above code is an example for bankswitching
What it does:
- it combines on the second line $1010 with the value of x
that is $101b (this is the lastoperandaddress, see below)
- the instruction on the third line selects the bankswitch
scheme ($1b)
(only the lower byte of the lastoperandaddress counts):
XXXX1=110XX that means scheme 3 2

Don't worry about the compares, they are just a way to combine to an
address, and/or to 'call' a visit to location $fff8.

lastoperandaddress is stored while accessing via:

absolut \
absolut,x \
absolut,y I-
indirect,x / Indirect addresses store the value found at the
indirect,y / addressed location plus the values of x or y
operandaddress=
what's_in_there(what's_in_there(zeropage address)+x)
or
operandaddress=
what's_in_there(what's_in_there(zeropage address))+y

NOTE:
(not sure for bankswitching about the following, for RAM access
it applies)

The access to location $fff8 must be within 4-6 cycles after
addressing the lastoperandaddress, otherwise it might not be known
what bankswitching scheme will be used!

Furthermore:
Bit 0 and bit 1 are very important too.
(remember?)

D1 . . . . WRITE ENABLED (=1) DISABLE (=0)

D0 . . . . ROM POWER (OFF=1) (ON=0)

Bit 0
-----
This bit is explained further down again. In non multiload
games this will usually be set to 1, which means the superchargers
internal ROM is switched off. If you want to access the ROM again
after loading the game in the first place, for example for
a multiload game, you have to clear this bit.
Clearing this bit will enable the internal supercharger ROM.
When the ROM is enabled the programm must at least wait for 1000 Cycles
before it can access the ROM routines.
(for further information about loading see below)

Bit 1
-----
Setting this bit will enable access to the superchargers inherent
6KB of RAM. This can have strange effects if not done on purpose.
Well, and clearing it will disable this ability, the supercharger
than will act as any other ROM module.

NOTE:
Location $fff8 is allways write enabled, no matter what state bit 1
may have been set to.

Supercharger RAM access
=======================

In order to be able to access the superchargers 6KB of RAM, you have to
set bit 1 while switching to another (or the same) bankswitching
scheme. (see a few lines further up)

The general idea of how to access RAM is the same as with setting
a new bankswitch scheme. Here again an example:

ldx #$2f ; this loads a value $2f to x register
; this is in no way needed, just an example
; don't worry, fake, just for fun, has no meaning
; (not with RAM access anyway :-))

cmp $f010,x ; access a memory location
; usually the format for this is like
; 'cmp RAM,x', where RAM must be a value between
; 0xf000-0xf0ff
; whether it is a cmp, a lda or something
; else does not matter, as in the bankswitch section
; the only thing that counts is the lower byte of
; the resulting operand address, in this
; case:
; $f010 + $2f = $f03f | only lower byte
; -----
; $3f
; this is the value we will poke to a yet to
; be chosen RAM location
;
; the above RAM parameter MUST be
; from 0xf000-0xf0ff the access to
; these locations enable RAM access for the next
; instruction

lda $f77b ; this instruction triggers the actual
; poking, the value from above is stored
; to location $f77b, in good old plain
; BASIC:
; poke $f77b, $3f
; (well, BASIC wouldn't understand the '$'s, but
; who cares...)
;
; NOTE: the poking instruction must be at least
; 4 cycles <away> from the accessed operand address
; and at most 6 cycles.
; you can fill up to the needed cycle count with
; any instuction that doesn't use an operand address
; by itself (mostly a NOP, but sometimes a DEX or so
; will be used...)

Again:
The above code is an example for poking to location $f77b a
value of $3f.
What it does:
- it combines on the second line $f010 (which is in between
$f000-$f0ff, and thus prepares a poke) with the value of x
that is $f03f (this is the lastoperandaddress, see below)
- this selects poke value $3f
(only the lower byte of the resulting address counts)
- with a memory access the value is written to
that memory (when write bit is set)
that might be a lda, cmp, and, bit...

lastoperandaddress is stored while accessing via:

absolut \ the value before the ',y' and ',x' must be
absolut,x \ an address from 0xf000 to 0xf0ff to enable RAM!
absolut,y I-
indirect,x / Indirect addresses store the value found at the
indirect,y / addressed location plus the values of x or y
operandaddress=
what's_in_there(what's_in_there(zeropage address)+x)
or
operandaddress=
what's_in_there(what's_in_there(zeropage address))+y

The instruction that triggers the poking process may also be of the
above kind (absolut, absolut_x, absolut_y, indirect_x, indirect_y).

And another thing again...:
The cycles, be sure your instructions need more cycles than 3
and less than 7, otherwise no value will be stored.

Loading a second (third, fourth...) part
========================================

For information how to load a second part from tape:
Following is a text contained on the 'Stella gets a new brain CD'.
('excal48a.asm')

------------------------- EXCAL48A.ASM START --------------------------

RAM .EQ $F000
CONTROL .EQ $FFF8
...
NEWLOAD CMP RAM
CMP CONTROL ; ROM/R3
LDA #4
STA $FA ; NEXT LOAD
ldx #100
.0 ldy #8
.1 dey
bne .1
dex
bne .0
JMP $F800 ; ROM ENTRY

-------------------------- EXCAL48A.ASM END ---------------------------

Please also have a second look at the further above provided text
called 'cntlbyte.doc'.

---- short extract from the above 'cntlbyte.doc for memory refresh ----

PREPARATION
. POWER UP ROM
. WAIT > 1000 CYCLES
. $80 - D7-D5 ONE SHOT (leave location $80, bits 5-7 intact!)
. $FA - SEQUENCE BYTE (multiload number to load next in location $80)
. STACK POINTER > $FD
PRESS PLAY
. JMP $F800

---------------------- memory refresh end -----------------------------

First you have to enable the superchargers native ROM.
Why? You want to access the loading routines that come with
the supercharger. It has these loading routine stored in it's
ROM, you might call that a mini OS :-) (with I/O features).

In order to be able to access that ROM, you have to power it up, this
is done via bit 0 of the bankswitch select byte. This bit must be
cleared in order to power the ROM. (see above)

Furthermore you have to select bank 4 (ROM) so that you
can access it. (look at the bankswitch section, schemes 0,1,4,5)

In the above provided example this is all done via the first two
instruction:

NEWLOAD CMP RAM ; CMP $f000, which
; selects a value to be stored
; of 0
; 0000 0000
; XXX0 00w0 3-----ROM
; which powers the ROM (bit0=0)
; and puts the 2KB ROM into
; VCS 2600 memory $1800-$1fff

CMP CONTROL ; ROM/R3 ; which makes everything happen!

If $80 in the zero page is not properly set, you probably will
want to do that now. (in the above example this is skipped)

The sequence number must be stored to zero page location $FA.
The sequence number for single load games or first parts is 0,
the other parts have a sequential >unique< number.

Name of game multiload-number
-----------------------------------------
Mindmaster part 2 I 1
Mindmaster part 3 I 2
Mindmaster part 4 I 3
I
Dragonstomper part 2 I 4
Dragonstomper part 3 I 5
I
Survival Island part 2 I 6
Survival Island part 3 I 7

The sequence number is also stored in the tape header, location 5
(see the above header example).
For the first load or single load games this is set to 0.
For multiloads it is set to the corresponding multiload number.

Than (or before) you have to wait for those at least 1000 cycles.
So the ROM of the supercharger can <power up>.
If you skip this->your load will fail.

Than do the above mentioned $f800 jump. This is a jump to the
superchargers inbuilt ROM.

This jump will load your new part from tape, cd or whatever.

After loading supercharger starts of at location that is located
at $2000-$2001 in the header of the tape images, which is supposed to
be the starting vector.

Now have a look at the 'cntlbyte.doc' again, to see how loading
influenced your memory.

---- short extract from the above 'cntlbyte.doc for memory refresh ----

MEMORY after multiload
. $80 POWERUP FROM TAPE (bank number and write pulse delay)
. $81-$9D ZEROED
. $FA-$FF VALUES:
$FA: LDA $FFF8
$FD: JMP <ADDR>
<ADDR> IS FROM TAPE (starting address to run code at in first header)
. PAGE 7 OF R1 IS USED
FOR STARS AND MUST
BE RELOADED (last page in bank 1 gets trashed when doing multiloads)
. REGISTERS
A: SEED FOR RANDOM #
X: $FF
Y: $00

---------------------- memory refresh end -----------------------------

Taperewinding
-------------

---- short extract from the above 'cntlbyte.doc for memory refresh ----
REWIND TAPE
. LDA $80
. AND #$E0
. STA $80
. JMP $F80A
---------------------- memory refresh end -----------------------------

Another ROM routine, dunno what this does, I would imagine a message
to be displayed, that says: 'REWIND TAPE'
And after rewinding...and pressing <play> loads... whatever comes next.

That's all folks

March 1997

Leave a Reply

Your email address will not be published. Required fields are marked *