aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2016-08-29 15:00:13 -0400
committerB. Watson <yalhcru@gmail.com>2016-08-29 15:00:13 -0400
commit26b42926816662ce878e814938a1ebc0aa1847c2 (patch)
treed4f451ab2820704f5b680b8ae0ceda037c78d9e9
downloadjumpmanjr-26b42926816662ce878e814938a1ebc0aa1847c2.tar.gz
finally made a git repo for this
-rw-r--r--Makefile29
-rw-r--r--da65.txt628
-rw-r--r--equates.inc1386
-rw-r--r--jumpmanjr.cartbin0 -> 16400 bytes
-rw-r--r--jumpmanjr.dasm7360
-rw-r--r--jumpmanjr.inc68
-rw-r--r--jumpmanjr.info908
-rw-r--r--jumpmanjr.rombin0 -> 16384 bytes
-rw-r--r--jumpmanjr_manual.pdfbin0 -> 3135749 bytes
-rw-r--r--level_descriptors.txt127
-rw-r--r--level_maps.txt188
-rw-r--r--leveldesc.info406
-rw-r--r--main.info501
-rw-r--r--mapping.txt8814
-rw-r--r--mklevelinfo.pl91
-rw-r--r--mkmusiclabels.pl15
-rw-r--r--porting_ideas.txt50
17 files changed, 20571 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ece7548
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+all: clean jumpmanjr.dasm
+
+clean:
+ rm -f jumpmanjr.dasm
+
+distclean: clean
+ rm -f jumpmanjr.info leveldesc.info jmjtest.* tmp.lbl 1 2 1.* 2.* atari???.png strace.out
+
+jumpmanjr.dasm: jumpmanjr.info jumpmanjr.inc
+ da65 -i jumpmanjr.info
+
+jumpmanjr.info: main.info leveldesc.info
+ ( echo '### GENERATED FILE, do not edit, edit main.info and mklevelinfo.pl instead' ;\
+ cat main.info leveldesc.info ) > jumpmanjr.info
+
+leveldesc.info: mklevelinfo.pl
+ perl mklevelinfo.pl > leveldesc.info
+
+test: all
+ cp jumpmanjr.dasm jmjtest.s
+ ca65 -t none -o jmjtest.o -g jmjtest.s
+ ld65 -t none -o jmjtest.bin -Ln tmp.lbl --start-addr 0x8000 jmjtest.o
+ grep -v '\.__' tmp.lbl | sed 's, \., ,' > jmjtest.lbl
+ @echo
+ @cmp jumpmanjr.rom jmjtest.bin && echo "=== Binary reassembles correctly" || echo "*** Binary FAILS to reassemble correctly ***"
+ @echo ; echo "-----------------------"
+ @echo labels load jmjtest.lbl
+ @echo "-----------------------" ; echo
+ @atari800 -nobasic jumpmanjr.cart
diff --git a/da65.txt b/da65.txt
new file mode 100644
index 0000000..19115f7
--- /dev/null
+++ b/da65.txt
@@ -0,0 +1,628 @@
+ da65 Users Guide
+
+Ullrich von Bassewitz,
+Greg King
+
+2014-11-23
+
+ ----------------------------------------------------------------------------
+
+da65 is a 6502/65C02 disassembler that is able to read user-supplied information
+about its input data, for better results. The output is ready for feeding into
+ca65, the macro assembler supplied with the cc65 C compiler.
+
+ ----------------------------------------------------------------------------
+
+1. Overview
+
+2. Usage
+
+ * 2.1 Command line option overview
+ * 2.2 Command line options in detail
+
+3. Detailed workings
+
+ * 3.1 Supported CPUs
+ * 3.2 Attribute map
+ * 3.3 Labels
+ * 3.4 Info File
+
+4. Info File Format
+
+ * 4.1 Comments
+ * 4.2 Specifying global options
+ * 4.3 Specifying Ranges
+ * 4.4 Specifying Labels
+ * 4.5 Specifying Segments
+ * 4.6 Specifying Assembler Includes
+ * 4.7 An Info File Example
+
+5. Copyright
+
+ ----------------------------------------------------------------------------
+
+1. Overview
+
+da65 is a disassembler for 6502/65C02 code. It is supplied as a utility with the
+cc65 C compiler and generates output that is suitable for the ca65 macro
+assembler.
+
+Besides generating output for ca65, one of the design goals was that the user is
+able to feed additional information about the code into the disassembler, for
+improved results. This information may include the location and size of tables,
+and their format.
+
+One nice advantage of this concept is that disassembly of copyrighted binaries
+may be handled without problems: One can just pass the information file for
+disassembling the binary, so everyone with a legal copy of the binary can
+generate a nicely formatted disassembly with readable labels and other
+information.
+
+2. Usage
+
+2.1 Command line option overview
+
+The assembler accepts the following options:
+
+ ---------------------------------------------------------------------------
+ Usage: da65 [options] [inputfile]
+ Short options:
+ -g Add debug info to object file
+ -h Help (this text)
+ -i name Specify an info file
+ -o name Name the output file
+ -v Increase verbosity
+ -F Add formfeeds to the output
+ -S addr Set the start/load address
+ -V Print the disassembler version
+
+ Long options:
+ --argument-column n Specify argument start column
+ --comment-column n Specify comment start column
+ --comments n Set the comment level for the output
+ --cpu type Set cpu type
+ --debug-info Add debug info to object file
+ --formfeeds Add formfeeds to the output
+ --help Help (this text)
+ --hexoffs Use hexadecimal label offsets
+ --info name Specify an info file
+ --label-break n Add newline if label exceeds length n
+ --mnemonic-column n Specify mnemonic start column
+ --pagelength n Set the page length for the listing
+ --start-addr addr Set the start/load address
+ --text-column n Specify text start column
+ --verbose Increase verbosity
+ --version Print the disassembler version
+ ---------------------------------------------------------------------------
+
+2.2 Command line options in detail
+
+Here is a description of all the command line options:
+
+--argument-column n
+
+ Specifies the column where the argument for a mnemonic or pseudo
+ instruction starts.
+
+--comment-column n
+
+ Specifies the column where the comment for an instruction starts.
+
+--comments n
+
+ Set the comment level for the output. Valid arguments are 0..4. Greater
+ values will increase the level of additional information written to the
+ output file in form of comments.
+
+--cpu type
+
+ Set the CPU type. The option takes a parameter, which may be one of
+ * 6502
+ * 6502x
+ * 65sc02
+ * 65c02
+ * huc6280
+
+ 6502x is for the NMOS 6502 with unofficial opcodes. huc6280 is the CPU
+ of the PC engine. Support for the 65816 currently is not available.
+
+-F, --formfeeds
+
+ Add formfeeds to the generated output. This feature is useful together
+ with the --pagelength option. If --formfeeds is given, a formfeed is
+ added to the output after each page.
+
+-g, --debug-info
+
+ This option adds the .DEBUGINFO command to the output file, so the
+ assembler will generate debug information when re-assembling the
+ generated output.
+
+-h, --help
+
+ Print the short option summary shown above.
+
+--hexoffs
+
+ Output label offsets in hexadecimal instead of decimal notation.
+
+-i name, --info name
+
+ Specify an info file. The info file contains global options that may
+ override or replace command line options plus informations about the
+ code that has to be disassembled. See the separate section Info File
+ Format.
+
+-o name
+
+ Specify a name for an output file. The default is to use stdout, so
+ without this switch or the corresponding global option OUTPUTNAME, the
+ output will go to the terminal.
+
+--label-break n
+
+ Adds a newline if the length of a label exceeds the given length. Note:
+ If the label would run into the code in the mid column, a linefeed is
+ always inserted regardless of this setting.
+
+ This option overrides the global option LABELBREAK.
+
+--mnemonic-column n
+
+ Specifies the column where a mnemonic or pseudo instrcuction is output.
+
+--pagelength n
+
+ Sets the length of a listing page in lines. After this number of lines,
+ a new page header is generated. If the --formfeeds is also given, a
+ formfeed is inserted before generating the page header.
+
+ A value of zero for the page length will disable paging of the output.
+
+-S addr, --start-addr addr
+
+ Specify the start/load address of the binary code that is going to be
+ disassembled. The given address is interpreted as an octal value if
+ preceded with a '0' digit, as a hexadecimal value if preceded with '0x',
+ '0X', or '$', and as a decimal value in all other cases. If no start
+ address is specified, $10000 minus the size of the input file is used.
+
+--text-column n
+
+ Specifies the column where additional text is output. This additional
+ text consists of the bytes encoded in this line in text representation.
+
+-v, --verbose
+
+ Increase the disassembler verbosity. Usually only needed for debugging
+ purposes. You may use this option more than one time for even more
+ verbose output.
+
+-V, --version
+
+ Print the version number of the assembler. If you send any suggestions
+ or bugfixes, please include the version number.
+
+3. Detailed workings
+
+3.1 Supported CPUs
+
+The default (no CPU given on the command line or in the GLOBAL section of the
+info file) is the 6502 CPU. The disassembler knows all "official" opcodes for
+this CPU. Invalid opcodes are translated into .byte commands.
+
+With the command line option --cpu, the disassembler may be told to recognize
+either the 65SC02 or 65C02 CPUs. The latter understands the same opcodes as the
+former, plus 16 additional bit manipulation and bit test-and-branch commands.
+
+While there is some code for the 65816 in the sources, it is currently
+unsupported.
+
+3.2 Attribute map
+
+The disassembler works by creating an attribute map for the whole address space
+($0000 - $FFFF). Initially, all attributes are cleared. Then, an external info
+file (if given) is read. Disassembly is done in several passes. In all passes,
+with the exception of the last one, information about the disassembled code is
+gathered and added to the symbol and attribute maps. The last pass generates
+output using the information from the maps.
+
+3.3 Labels
+
+Some instructions may generate labels in the first pass, while most other
+instructions do not generate labels, but use them if they are available. Among
+others, the branch and jump instructions will generate labels for the target of
+the branch in the first pass. External labels (taken from the info file) have
+precedence over internally generated ones, They must be valid identifiers as
+specified for the ca65 assembler. Internal labels (generated by the
+disassembler) have the form Labcd, where abcd is the hexadecimal address of the
+label in upper case letters. You should probably avoid using such label names
+for external labels.
+
+3.4 Info File
+
+The info file is used to pass additional information about the input code to the
+disassembler. This includes label names, data areas or tables, and global
+options like input and output file names. See the next section for more
+information.
+
+4. Info File Format
+
+The info file contains lists of specifications grouped together. Each group
+directive has an identifying token and an attribute list enclosed in curly
+braces. Attributes have a name followed by a value. The syntax of the value
+depends on the type of the attribute. String attributes are places in double
+quotes, numeric attributes may be specified as decimal numbers or hexadecimal
+with a leading dollar sign. There are also attributes where the attribute value
+is a keyword; in this case, the keyword is given as-is (without quotes or
+anything). Each attribute is terminated by a semicolon.
+
+ group-name { attribute1 attribute-value; attribute2 attribute-value; }
+
+4.1 Comments
+
+Comments start with a hash mark (#); and, extend from the position of the mark
+to the end of the current line. Hash marks inside of strings will not start a
+comment, of course.
+
+4.2 Specifying global options
+
+Global options may be specified in a group with the name GLOBAL. The following
+attributes are recognized:
+
+ARGUMENTCOLUMN
+
+ This attribute specifies the column in the output, where the argument
+ for an opcode or pseudo instruction starts. The corresponding command
+ line option is --argument-column.
+
+COMMENTCOLUMN
+
+ This attribute specifies the column in the output, where the comment
+ starts in a line. It is only used for in-line comments. The
+ corresponding command line option is --comment-column.
+
+COMMENTS
+
+ This attribute may be used instead of the --comments option on the
+ command line. It takes a numerical parameter between 0 and 4. Higher
+ values increase the amount of information written to the output file in
+ form of comments.
+
+CPU
+
+ This attribute may be used instead of the --cpu option on the command
+ line. For possible values see there. The value is a string and must be
+ enclosed in quotes.
+
+HEXOFFS
+
+ The attribute is followed by a boolean value. If true, offsets to labels
+ are output in hex, otherwise they're output in decimal notation. The
+ default is false. The attribute may be changed on the command line using
+ the --hexoffs option.
+
+INPUTNAME
+
+ The attribute is followed by a string value, which gives the name of the
+ input file to read. If it is present, the disassembler does not accept
+ an input file name on the command line.
+
+INPUTOFFS
+
+ The attribute is followed by a numerical value that gives an offset into
+ the input file which is skipped before reading data. The attribute may
+ be used to skip headers or unwanted code sections in the input file.
+
+INPUTSIZE
+
+ INPUTSIZE is followed by a numerical value that gives the amount of data
+ to read from the input file. Data beyond INPUTOFFS + INPUTSIZE is
+ ignored.
+
+LABELBREAK
+
+ LABELBREAK is followed by a numerical value that specifies the label
+ length that will force a newline. To have all labels on their own lines,
+ you may set this value to zero.
+
+ See also the --label-break command line option. A LABELBREAK statement
+ in the info file will override any value given on the command line.
+
+MNEMONICCOLUMN
+
+ This attribute specifies the column in the output, where the mnemonic or
+ pseudo instruction is placed. The corresponding command line option is
+ --mnemonic-column.
+
+NEWLINEAFTERJMP
+
+ This attribute is followed by a boolean value. When true, a newline is
+ inserted after each JMP instruction. The default is false.
+
+NEWLINEAFTERRTS
+
+ This attribute is followed by a boolean value. When true, a newline is
+ inserted after each RTS instruction. The default is false.
+
+OUTPUTNAME
+
+ The attribute is followed by string value, which gives the name of the
+ output file to write. If it is present, specification of an output file
+ on the command line using the -o option is not allowed.
+
+ The default is to use stdout for output, so without this attribute or
+ the corresponding command line option -o the output will go to the
+ terminal.
+
+PAGELENGTH
+
+ This attribute may be used instead of the --pagelength option on the
+ command line. It takes a numerical parameter. Using zero as page length
+ (which is the default) means that no pages are generated.
+
+STARTADDR
+
+ This attribute may be used instead of the --start-addr option on the
+ command line. It takes a numerical parameter. The default for the start
+ address is $10000 minus the size of the input file (this assumes that
+ the input file is a ROM that contains the reset and irq vectors).
+
+TEXTCOLUMN
+
+ This attribute specifies the column, where the data bytes are output
+ translated into ASCII text. It is only used if COMMENTS is set to at
+ least 4. The corresponding command line option is --text-column.
+
+4.3 Specifying Ranges
+
+The RANGE directive is used to give information about address ranges. The
+following attributes are recognized:
+
+COMMENT
+
+ This attribute is only allowed if a label is also given. It takes a
+ string as argument. See the description of the LABEL directive for an
+ explanation.
+
+END
+
+ This gives the end address of the range. The end address is inclusive,
+ that means, it is part of the range. Of course, it may not be smaller
+ than the start address.
+
+NAME
+
+ This is a convenience attribute. It takes a string argument and will
+ cause the disassembler to define a label for the start of the range with
+ the given name. So a separate LABEL directive is not needed.
+
+START
+
+ This gives the start address of the range.
+
+TYPE
+
+ This attribute specifies the type of data within the range. The
+ attribute value is one of the following keywords:
+
+ ADDRTABLE
+
+ The range consists of data and is disassembled as a table
+ of words (16 bit values). The difference to the WORDTABLE
+ type is that a label is defined for each entry in the
+ table.
+
+ BYTETABLE
+
+ The range consists of data and is disassembled as a byte
+ table.
+
+ CODE
+
+ The range consists of code.
+
+ DBYTETABLE
+
+ The range consists of data and is disassembled as a table
+ of dbytes (double byte values, 16 bit values with the low
+ byte containing the most significant byte of the 16 bit
+ value).
+
+ DWORDTABLE
+
+ The range consists of data and is disassembled as a table
+ of double words (32 bit values).
+
+ RTSTABLE
+
+ The range consists of data and is disassembled as a table
+ of words (16 bit values). The values are interpreted as
+ words that are pushed onto the stack and jump to it via
+ RTS. This means that they contain address-1 of a function,
+ for which a label will get defined by the disassembler.
+
+ SKIP
+
+ The range is simply ignored when generating the output
+ file. Please note that this means that reassembling the
+ output file will not generate the original file, not only
+ because the missing piece in between, but also because the
+ following code will be located on wrong addresses. Output
+ generated with SKIP ranges will need manual rework.
+
+ TEXTTABLE
+
+ The range consists of readable text.
+
+ WORDTABLE
+
+ The range consists of data and is disassembled as a table
+ of words (16 bit values).
+
+4.4 Specifying Labels
+
+The LABEL directive is used to give names for labels in the disassembled code.
+The following attributes are recognized:
+
+ADDR
+
+ Followed by a numerical value. Specifies the value of the label.
+
+COMMENT
+
+ Attribute argument is a string. The comment will show up in a separate
+ line before the label, if the label is within code or data range, or
+ after the label if it is outside.
+
+ Example output:
+
+ foo := $0001 ; Comment for label named "foo"
+
+ ; Comment for label named "bar"
+ bar:
+
+NAME
+
+ The attribute is followed by a string value which gives the name of the
+ label. Empty names are allowed, in this case the disassembler will
+ create an unnamed label (see the assembler docs for more information
+ about unnamed labels).
+
+SIZE
+
+ This attribute is optional and may be used to specify the size of the
+ data that follows. If a size greater than 1 is specified, the
+ disassembler will create labels in the form label+offs for all bytes
+ within the given range, where label is the label name given with the
+ NAME attribute, and offs is the offset within the data.
+
+4.5 Specifying Segments
+
+The SEGMENT directive is used to specify a segment within the disassembled code.
+The following attributes are recognized:
+
+START
+
+ Followed by a numerical value. Specifies the start address of the
+ segment.
+
+END
+
+ Followed by a numerical value. Specifies the end address of the segment.
+ The end address is the last address that is a part of the segment.
+
+NAME
+
+ The attribute is followed by a string value which gives the name of the
+ segment.
+
+All attributes are mandatory. Segments must not overlap. The disassembler will
+change back to the (default) .code segment after the end of each defined
+segment. That might not be what you want. As a rule of thumb, if you're using
+segments, you should define segments for all disassembled code.
+
+4.6 Specifying Assembler Includes
+
+The ASMINC directive is used to give the names of input files containing symbol
+assignments in assembler syntax:
+
+ Name = value
+ Name := value
+
+The usual conventions apply for symbol names. Values may be specified as hex
+(leading $), binary (leading %) or decimal. The values may optionally be signed.
+
+NOTE: The include file parser is very simple. Expressions are not allowed, and
+anything but symbol assignments is flagged as an error (but see the
+IGNOREUNKNOWN directive below).
+
+The following attributes are recognized:
+
+FILE
+
+ Followed by a string value. Specifies the name of the file to read.
+
+COMMENTSTART
+
+ The optional attribute is followed by a character constant. It specifies
+ the character that starts a comment. The default value is a semicolon.
+ This value is ignored if IGNOREUNKNOWN is true.
+
+IGNOREUNKNOWN
+
+ This attribute is optional and is followed by a boolean value. It allows
+ to ignore input lines that don't have a valid syntax. This allows to
+ read in assembler include files that contain more than just symbol
+ assignments. Note: When this attribute is used, the disassembler will
+ ignore any errors in the given include file. This may have undesired
+ side effects.
+
+4.7 An Info File Example
+
+The following is a short example for an info file that contains most of the
+directives explained above:
+
+ # This is a comment. It extends to the end of the line
+ GLOBAL {
+ OUTPUTNAME "kernal.s";
+ INPUTNAME "kernal.bin";
+ STARTADDR $E000;
+ PAGELENGTH 0; # No paging
+ CPU "6502";
+ };
+
+ # One segment for the whole stuff
+ SEGMENT { START $E000; END $FFFF; NAME "kernal"; };
+
+ RANGE { START $E612; END $E631; TYPE Code; };
+ RANGE { START $E632; END $E640; TYPE ByteTable; };
+ RANGE { START $EA51; END $EA84; TYPE RtsTable; };
+ RANGE { START $EC6C; END $ECAB; TYPE RtsTable; };
+ RANGE { START $ED08; END $ED11; TYPE AddrTable; };
+
+ # Zero-page variables
+ LABEL { NAME "fnadr"; ADDR $90; SIZE 3; };
+ LABEL { NAME "sal"; ADDR $93; };
+ LABEL { NAME "sah"; ADDR $94; };
+ LABEL { NAME "sas"; ADDR $95; };
+
+ # Stack
+ LABEL { NAME "stack"; ADDR $100; SIZE 255; };
+
+ # Indirect vectors
+ LABEL { NAME "cinv"; ADDR $300; SIZE 2; }; # IRQ
+ LABEL { NAME "cbinv"; ADDR $302; SIZE 2; }; # BRK
+ LABEL { NAME "nminv"; ADDR $304; SIZE 2; }; # NMI
+
+ # Jump table at end of kernal ROM
+ LABEL { NAME "kscrorg"; ADDR $FFED; };
+ LABEL { NAME "kplot"; ADDR $FFF0; };
+ LABEL { NAME "kiobase"; ADDR $FFF3; };
+ LABEL { NAME "kgbye"; ADDR $FFF6; };
+
+ # Hardware vectors
+ LABEL { NAME "hanmi"; ADDR $FFFA; };
+ LABEL { NAME "hares"; ADDR $FFFC; };
+ LABEL { NAME "hairq"; ADDR $FFFE; };
+
+5. Copyright
+
+da65 (and all cc65 binutils) is (C) Copyright 1998-2011, Ullrich von Bassewitz.
+For usage of the binaries and/or sources, the following conditions do apply:
+
+This software is provided 'as-is', without any expressed or implied warranty. In
+no event will the authors be held liable for any damages arising from the use of
+this software.
+
+Permission is granted to anyone to use this software for any purpose, including
+commercial applications, and to alter it and redistribute it freely, subject to
+the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not claim
+ that you wrote the original software. If you use this software in a product,
+ an acknowledgment in the product documentation would be appreciated but is
+ not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
diff --git a/equates.inc b/equates.inc
new file mode 100644
index 0000000..9759a8a
--- /dev/null
+++ b/equates.inc
@@ -0,0 +1,1386 @@
+;
+; ATARI 800 EQUATE LISTING
+;
+; (version 20070530_bkw)
+;
+; This is a heavily modified copy of Appendix A of the Atari System
+; Reference Manual (with much info added from Appendix B, and from
+; Mapping the Atari and other sources)
+;
+;
+;This listing is based on the original release of Operating System,
+;version A. The vectors shown here were not changed in version B.
+;New equates for XL and XE models are included and noted. Changes
+;from version B to XL/XE are also noted.
+;
+;Most of the equate names given below are the official Atari
+;names. They are in common use but are not mandatory.
+
+; This file can be included in your assembly source, but it's also
+; got a lot of useful human-readable comments. It's meant to serve as
+; a "quick reference" to Atari programmers, particularly ones who use
+; a cross-assembler on a UNIX-ish platform and a text editor that can
+; use "ctags":
+
+; $ ctags equates.inc
+; $ vim mystuff.dasm
+
+; While in vim, press ^] (control-right-bracket) while sitting on a label,
+; to jump to that label's definition in this file. (Also, you can type
+; :tag labelname). You can also do completion on the labels in vim by
+; typing part of a label and pressing ^N (or Tab, if you use the
+; CleverTab script from vimhelp.org)
+
+; GNU Emacs and XEmacs also support ctags, but I've never used them, so
+; I dunno how to do it. I do know that you need to use "Exuberant" ctags,
+; not the ctags that comes with emacs (which doesn't grok 6502 asm).
+
+; If you're using an Atari assembler instead of a cross-assembler, you
+; don't want to use this as-is: all the extra comments make it huge, and
+; it'll be either too large for the Atari's memory, or at least will take
+; a long time to assemble. You can make a comment-less, Atari-compatible
+; version like so:
+
+; perl -lne 's/;.*//; s/\s*$//; print if $_' < equates.inc > small.inc
+
+; ...then use a8eol to convert it to ATASCII format.
+
+; 20061028 bkw: Originally downloaded from:
+
+; http://atrey.karlin.mff.cuni.cz/~pavel/atari/atrb.html
+
+; ...and converted to DASM/ATASM/CA65 format. dasm, atasm, and ca65 use
+; similar enough syntax that this file can be used as-is with any of
+; them. Unfortunately, this means I can't do conditional assembly in this
+; file, since the two assemblers use different semantics... macros are
+; even less compatible :(
+
+; If you use ca65, you need this line in your source:
+
+;; .FEATURE labels_without_colons
+
+; before including this file, or else run ca65 with
+; "--feature labels_without_colons").
+
+; 20070529 bkw: updated, added missing GTIA/POKEY/ANTIC equates,
+; documented where the shadows are for those GTIA/POKEY/ANTIC/PIA
+; registers that have them. Also added a list of error messages and
+; explanation of the cassette buffer layout, and organized the C_*
+; CIO constants. Made minor modifications to get this file to assemble
+; with ATasm as well as DASM.
+
+; I have added a few missing equates: this file only
+; contained OS ROM locations when I got it.
+; I added a few from FMS/DOS as well (e.g. RUNAD and INITAD).
+
+; XL-specific locations in the original file were duplicate labels
+; (e.g. PTIMOT was defined as both $1C and $314), which keeps DASM
+; from being able to assemble the file. I prefixed the XL/XL versions
+; with "XL_"
+
+; Also, I've prefixed the CIO command and AUX1 constants with C_, since some
+; of them conflicted with other labels in the original version.
+
+; Areas listed as "unmapped" are literally not connected to anything.
+; Trying to read from unmapped address space results in reading whatever
+; garbage was on the data bus when the read happened. On my 1200XL, this
+; generally results in all 1's ($FF or 255).
+; In a 400, 600XL or other Atari with less than 48K of RAM, the missing
+; RAM address space is also unmapped.
+
+; Still TODO:
+; - Rest of the DOS/FMS equates
+; - Mark 800-ony locations with OSB_
+; - ifdef code, so the user can set the machine type (OSB or XL),
+; then refer to e.g. PTIMOT and get either OSB_PTIMOT or XL_PTIMOT
+; - Split into separate files? I'd rather not (it's only about 1000 lines)
+
+; This file's mostly intended for new development. It could also be
+; useful for porting old ASM/ED or Mac65 code to DASM, but such code
+; may need work... you can always assemble it with ATasm, in that case,
+; since it's 99.999% source code compatible with Mac65.
+
+; References to "APPENDIX C" and such are referring to the Atari System
+; Reference Manual, a version of which can be found at:
+
+; http://atrey.karlin.mff.cuni.cz/~pavel/atari/atrtblc.html
+
+; References to "Mapping" refer to "Mapping the Atari, Revised Edition",
+; which can be found at:
+
+; http://www.atariarchives.org/mapping/index.php
+
+; I've pasted a few quotes from Mapping into this file; I consider them
+; small enough to be covered under the "fair use" provisions of copyright law
+; (I am not a lawyer, though).
+
+;
+;
+; DEVICE NAMES
+;
+;
+;SCREDT = "E" SCREEN EDITOR
+;KBD = "K" KEYBOARD
+;DISPLY = "S" DISPLAY
+;PRINTR = "P" PRINTER
+;CASSET = "C" CASSETTE
+;DISK = "D" DISK DRIVE
+;
+;
+;
+; STATUS CODES
+;
+;
+
+; 20070529 bkw: These are returned as error codes, though various DOSes
+; also define their own codes (usually in the range 160-255).
+; Errors 2-21 are defined by BASIC.
+; Errors 150-154 are defined by the R: (850 or compatible, RS-232) handler.
+SUCCES = $01 ; 1
+BRKABT = $80 ; 128 BREAK KEY ABORT
+PRVOPN = $82 ; 130 IOCB ALREADY OPEN
+NONDEV = $82 ; 130 NONEXISTANT DEVICE
+WRONLY = $83 ; 131 OPENED FOR WRITE ONLY
+NVALID = $84 ; 132 INVALID COMMAND
+NOTOPN = $85 ; 133 DEVICE OR FILE NOT OPEN
+BADIOC = $86 ; 134 INVALID IOCB NUMBER
+RDONLY = $87 ; 135 OPENED FOR READ ONLY
+EOFERR = $88 ; 136 END OF FILE
+TRNRCD = $89 ; 137 TRUNCATED RECORD
+TIMOUT = $8A ; 138 PERIPHERAL TIME OUT
+DNACK = $8B ; 139 DEVICE DOES NOT ACKNOWLEDGE
+FRMERR = $8C ; 140 SERIAL BUS FRAMING ERROR
+CRSROR = $8D ; 141 CURSOR OUT OF RANGE
+OVRRUN = $8E ; 142 SERIAL BUS DATA OVERRUN
+CHKERR = $8F ; 143 SERIAL BUS CHECKSUM ERROR
+DERROR = $90 ; 144 PERIPHERAL DEVICE ERROR
+BADMOD = $91 ; 145 NON EXISTANT SCREEN MODE
+FNCNOT = $92 ; 146 FUNCTION NOT IMPLEMENTED
+SCRMEM = $93 ; 147 NOT ENOUGH MEMORY FOR SCREEN MODE
+
+; BASIC error codes (also used by e.g. Basic XL/XE and Turbo BASIC):
+;; 2: Insufficient Memory
+;; 3: Value Error
+;; 4: Too Many Variables
+;; 5: String Length Error
+;; 6: Out of Data Error
+;; 7: Number Greater than 32767
+;; 8: Input Statement Error
+;; 9: Array or String DIM Error
+;; 10: Argument Stack Overflow
+;; 11: Floating Point Overflow or Underflow Error
+;; 12: Line Not Found
+;; 13: No Matching FOR Statement
+;; 14: Line Too Long
+;; 15: GOSUB or FOR Line Deleted
+;; 16: RETURN Error
+;; 17: Garbage Error
+;; 18: Invalid String Character
+;; 19: LOAD Program Too Long
+;; 20: Bad Channel Number
+;; 21: LOAD File Error
+
+; 850/R: error codes:
+;; 150: Serial Port Already Open
+;; 151: Concurrent Mode Not Enabled
+;; 152: Illegal User-Supplied Buffer
+;; 153: Active Concurrent Mode Error
+;; 154: Concurrent Mode Not Active
+
+; DOS error codes (DOS 2.0S only; other DOSes may define other errors)
+;; 160: Device Number Error
+;; 161: Too Many OPEN Files
+;; 162: Disk Full
+;; 163: Fatal System Error
+;; 164: File Number Mismatch
+;; 165: Bad File Name
+;; 166: POINT Data Length Error
+;; 167: File Locked
+;; 168: Invalid XIO Command
+;; 169: Directory Full
+;; 170: File Not Found
+;; 171: POINT Invalid
+;; 172: DOS 1 File
+;; 173: Bad Sector
+;; 255: FORMATTING Error (DOS 2.5)
+
+;
+;
+;
+;
+; COMMAND CODES FOR CIO
+;
+;
+
+; Command byte goes in ICCOM,x
+
+;; General-purpose commands:
+C_OPEN = $03 ; 3 OPEN (BASIC OPEN)
+C_GETREC = $05 ; 5 GET RECORD
+C_GETCHR = $07 ; 7 GET BYTE
+C_PUTREC = $09 ; 9 WRITE RECORD
+C_PUTCHR = $0B ; 11 PUT-BYTE
+C_CLOSE = $0C ; 12
+C_STATUS = $0D ; 13
+C_SPECIL = $0E ; 14 BEGINNING OF SPECIAL COMMANDS (aka XIO)
+;; Commands for S: device:
+C_DRAWLN = $11 ; 17 SCREEN DRAW (BASIC DRAWTO)
+C_FILLIN = $12 ; 18 SCREEN FILL
+;; Commands for D: device (only when DOS is loaded):
+C_RENAME = $20 ; 32
+C_DELETE = $21 ; 33
+C_LOCK = $23 ; 35
+C_UNLOCK = $24 ; 36
+C_POINT = $25 ; 37
+C_NOTE = $26 ; 38
+
+; AUX1 modes (ICAX1,x or 2nd parameter of BASIC OPEN command):
+C_OPREAD = $04 ; 4 OPEN FOR INPUT
+C_OWRITE = $08 ; 8 OPEN FOR OUTPUT
+C_APPEND = $09 ; 9 OPEN TO APPEND TO END OF DISK FILE
+C_OUPDAT = $0C ; 12 OPEN FOR INPUT AND OUTPUT AT THE SAME TIME
+;; D: (DOS) only:
+C_OPDIR = $06 ; 6 OPEN TO DISK DIRECTORY
+;; S: only:
+C_MXDMOD = $10 ; 16 OPEN TO SPLIT SCREEN (MIXED MODE)
+C_INSCLR = $20 ; 32 OPEN TO SCREEN BUT DON'T ERASE
+;; C: only:
+C_NOIRG = $80 ; 128 NO GAP CASSETTE MODE
+
+;; Command bytes (ICCOM) for the RS-232 (R:) device:
+;;
+;; Output partial block 32 $20
+;; Control RTS,XMT,DTR 34 $22
+;; Baud, stop bits, word size 36 $24
+;; Translation mode 38 $26
+;; Concurrent mode 40 $28
+;;
+;; (see the 850 Interface Manual for details)
+
+
+; SIO command bytes (not part of CIO):
+S_DFRMAT = $21 ; 33 FORMAT DISK (RESIDENT DISK HANDLER (RDH))
+S_PTSECT = $50 ; 80 RDH PUT SECTOR
+S_GTSECT = $52 ; 82 RDH GET SECTOR
+S_DSTAT = $53 ; 83 RDH GET STATUS
+S_PSECTV = $57 ; 87 RDH PUT SECTOR AND VERIFY
+; Various other SIO commands are supported by different drives
+
+; 20061028 bkw: CR/EOL not really part of CIO, but useful:
+CR = $9B ; 155 CARRIAGE RETURN (EOL)
+EOL = CR ; defined in SYSEQU.ASM
+
+;
+IOCBSZ = $10 ; 16 IOCB SIZE
+MAXIOC = $80 ; 128 MAX IOCB BLOCK SIZE
+IOCBF = $FF ; 255 IOCB FREE
+;
+LEDGE = $02 ; 2 DEFAULT LEFT MARGIN
+REDGE = $27 ; 39 DEFAULT RIGHT MARGIN
+
+; OS VARIABLES
+;
+; PAGE 0
+;
+LINZBS = $00 ; 0 (800) FOR ORIGINAL DEBUGGER
+; $00 0 (XL) RESERVED
+NGFLAG = $01 ; 1 (XL) FOR POWER-UP SELF TEST
+CASINI = $02 ; 2
+RAMLO = $04 ; 4 POINTER FOR SELF TEST
+TRAMSZ = $06 ; 6 TEMPORARY RAM SIZE
+TSTDAT = $07 ; 7 TEST DATA
+WARMST = $08 ; 8
+BOOTQ = $09 ; 9 SUCCESSFUL BOOT FLAG
+; aka BOOT? in the OS source, but some assemblers don't support ? in labels
+DOSVEC = $0A ; 10 PROGRAM RUN VECTOR
+DOSINI = $0C ; 12 PROGRAM INITIALIZATION
+APPMHI = $0E ; 14 DISPLAY LOW LIMIT
+POKMSK = $10 ; 16 IRQ ENABLE FLAGS (shadow for IRQEN)
+BRKKEY = $11 ; 17 FLAG
+RTCLOK = $12 ; 18 3 BYTES, MSB FIRST
+BUFADR = $15 ; 21 INDIRECT BUFFER ADDRESS
+ICCOMT = $17 ; 23 COMMAND FOR VECTOR
+DSKFMS = $18 ; 24 DISK FILE MANAGER POINTER
+DSKUTL = $1A ; 26 DISK UTILITY POINTER (DUP.SYS)
+PTIMOT = $1C ; 28 (800) PRINTER TIME OUT REGISTER
+ABUFPT = $1C ; 28 (XL) RESERVED
+PBPNT = $1D ; 29 (800) PRINTER BUFFER POINTER
+; $1D ; 29 (XL) RESERVED
+PBUFSZ = $1E ; 30 (800) PRINTER BUFFER SIZE
+; $1E ; 30 (XL) RESERVED
+PTEMP = $1F ; 31 (800) TEMPORARY REGISTER (PTEMP deleted in XL OS)
+; $1F ; 31 (XL) RESERVED
+ZIOCB = $20 ; 32 ZERO PAGE IOCB
+ICHIDZ = $20 ; 32 HANDLER INDEX NUMBER (ID)
+ICDNOZ = $21 ; 33 DEVICE NUMBER
+ICCOMZ = $22 ; 34 COMMAND
+ICSTAZ = $23 ; 35 STATUS
+ICBALZ = $24 ; 36 BUFFER POINTER LOW BYTE
+ICBAHZ = $25 ; 37 BUFFER POINTER HIGH BYTE
+ICPTLZ = $26 ; 38 PUT ROUTINE POINTER LOW
+ICPTHZ = $27 ; 39 PUT ROUTINE POINTER HIGH
+ICBLLZ = $28 ; 40 BUFFER LENGTH LOW
+ICBLHZ = $29 ; 41
+ICAX1Z = $2A ; 42 AUXILIARY INFORMATION BYTE 1
+ICAX2Z = $2B ; 43
+ICSPRZ = $2C ; 44 TWO SPARE BYTES (CIO USE)
+ICIDNO = $2E ; 46 IOCB NUMBER X 16
+CIOCHR = $2F ; 47 CHARACTER BYTE FOR CURRENT OPERATION
+;
+STATUS = $30 ; 48 STATUS STORAGE
+CHKSUM = $31 ; 49 SUM WITH CARRY ADDED BACK
+BUFRLO = $32 ; 50 DATA BUFFER LOW BYTE
+BUFRHI = $33 ; 51
+BFENLO = $34 ; 52 ADDRESS OF LAST BUFFER BYTE +1 (LOW)
+BFENHI = $35 ; 53
+CRETRY = $36 ; 54 (800) NUMBER OF COMMAND FRAME RETRIES
+XL_LTEMP = $36 ; 54 (XL) LOADER TEMPORARY STORAGE, 2 BYTES
+DRETRY = $37 ; 55 (800) DEVICE RETRIES
+BUFRFL = $38 ; 56 BUFFER FULL FLAG
+RECVDN = $39 ; 57 RECEIVE DONE FLAG
+XMTDON = $3A ; 58 TRANSMISSION DONE FLAG
+CHKSNT = $3B ; 59 CHECKSUM-SENT FLAG
+NOCKSM = $3C ; 60 CHECKSUM-DOES-NOT-FOLLOW-DATA FLAG
+BPTR = $3D ; 61
+FTYPE = $3E ; 62
+FEOF = $3F ; 63
+FREQ = $40 ; 64
+;
+SOUNDR = $41 ; 65 0=QUIET I/O
+CRITIC = $42 ; 66 CRITICAL FUNCTION FLAG, NO DEFFERED VBI
+FMSZPG = $43 ; 67 DOS ZERO PAGE, 7 BYTES
+CKEY = $4A ; 74 (800) START KEY FLAG
+XL_ZCHAIN = $4A ; 74 (XL) HANDLER LOADER TEMP, 2 BYTES
+CASSBT = $4B ; 75 (800) CASSETTE BOOT FLAG
+DSTAT = $4C ; 76 DISPLAY STATUS
+;
+ATRACT = $4D ; 77
+DRKMSK = $4E ; 78 ATTRACT MASK
+COLRSH = $4F ; 79 ATTRACT COLOR SHIFTER (EORed WITH GRAPHICS)
+;
+TMPCHR = $50 ; 80
+HOLD1 = $51 ; 81
+LMARGN = $52 ; 82 SCREEN LEFT MARGIN REGISTER
+RMARGN = $53 ; 83 SCREEN RIGHT MARGIN
+ROWCRS = $54 ; 84 CURSOR ROW
+COLCRS = $55 ; 85 CURSOR COLUMN, 2 BYTES
+DINDEX = $57 ; 87 DISPLAY MODE
+SAVMSC = $58 ; 88 SCREEN ADDRESS
+OLDROW = $5A ; 90 CURSOR BEFORE DRAW OR FILL
+OLDCOL = $5B ; 91
+OLDCHR = $5D ; 93 DATA UNDER CURSOR
+OLDADR = $5E ; 94 CURSOR ADDRESS
+XL_FKDEF = $60 ; 96 (XL) FUNCTION KEY DEFINITION POINTER (LSB/MSB)
+NEWROW = $60 ; 96 (800) DRAWTO DESTINATION
+NEWCOL = $61 ; 97 (800) DRAWTO DESTINATION, 2 BYTES
+XL_PALNTS = $62 ; 98 (XL) EUROPE/NORTH AMERICA TV FLAG
+LOGCOL = $63 ; 99 LOGICAL LINE COLUMN POINTER
+MLTTMP = $66 ; 102
+OPNTMP = $66 ; 102 TEMPORARY STORAGE FOR CHANNEL OPEN
+SAVADR = $68 ; 104
+RAMTOP = $6A ; 106 START OF ROM (END OF RAM + 1), HIGH BYTE ONLY
+BUFCNT = $6B ; 107 BUFFER COUNT
+BUFSTR = $6C ; 108 POINTER USED BY EDITOR
+BITMSK = $6E ; 110 POINTER USED BY EDITOR
+SHFAMT = $6F ; 111
+ROWAC = $70 ; 112
+COLAC = $72 ; 114
+ENDPT = $74 ; 116
+DELTAR = $76 ; 118
+DELTAC = $77 ; 119
+ROWINC = $79 ; 121 (800)
+XL_KEYDEF = $79 ; 121 (XL) KEY DEFINITION POINTER, 2 BYTES
+COLINC = $7A ; 122 (800)
+SWPFLG = $7B ; 123 NON 0 IF TEXT AND REGULAR RAM IS SWAPPED
+HOLDCH = $7C ; 124 CH MOVED HERE BEFORE CTRL AND SHIFT
+INSDAT = $7D ; 125 used by S: handler, tmp for char under cursor
+COUNTR = $7E ; 126 used by XIO DRAW command (2 bytes)
+
+; $80 to $FF are free if BASIC and floating point are not used.
+; If BASIC is not used, but FP is, $80 to $D0 are still free.
+; There is no way to use BASIC without constantly using FP, as all BASIC
+; numbers are FP (even "integers" such as line numbers).
+ZROFRE = $80 ; 128 FREE ZERO PAGE, 84 BYTES
+
+; BASIC zero page variables:
+LOMEM = $80 ; 128 LSB, BASIC start-of-memory pointer
+; $81 ; 129 MSB, LOMEM (not to be confused with the OS's MEMLO!)
+VNTP = $82 ; 130 LSB, BASIC start of Variable Name Table pointer
+; $83 ; 131 MSB, VNTP
+VNTD = $84 ; 132 LSB, BASIC end of Variable Name Table pointer (+1 byte)
+; $85 ; 133 MSB, VNTP
+VVTP = $86 ; 134 LSB, BASIC start of Variable Value Table pointer
+; $87 ; 135 MSB, VVTP
+STMTAB = $88 ; 136 LSB, BASIC start of Statement Table pointer
+; $89 ; 137 MSB, STMTAB
+STMCUR = $8A ; 138 LSB, BASIC current statement pointer
+; $8B ; 139 MSB, STMCUR
+STARP = $8C ; 140 LSB, BASIC current string/array table pointer
+; $8D ; 141 MSB, STARP (also points to end of BASIC program)
+RUNSTK = $8E ; 142 LSB, BASIC runtime stack pointer
+; $8F ; 143 MSG, RUNSTK
+; BASIC and the OS both use the name MEMTOP; I've renamed the BASIC one.
+BAS_MEMTOP = $90 ; 144 LSB, pointer to top of BASIC memory
+; $91 ; 145 MSB, BAS_MEMTOP
+MEOLFLG = $92 ; 146 "modified EOL flag register", whatever that is
+; $93 ; 147 listed as "spare" by Mapping's Errata
+;COX = $94 ; 148 current output index (?)
+POKADR = $95 ; 149 LSB, address of last POKE location
+; ; 150 MSB, POKADR
+
+; Locations $96 to $B5 are used for various purposes by BASIC,
+; and most of them are of little or no interest, even for someone
+; writing assembly code meant to run as a USR() routine, so I haven't
+; bothered listing them all here. See Compute! Books' "Atari BASIC Sourcebook"
+; for the gory details. In fact, you can see it here:
+
+; http://users.telenet.be/kim1-6502/6502/absb.html
+
+; It's fascinating (at least it is to me)... includes full source code
+; to Atari BASIC!
+
+; DATAD and DATALN are reset to 0 by BASIC RESTORE command.
+DATAD = $B6 ; 182 the data element being read (e.g. 10 for 10th item
+ ; in a DATA statement)
+DATALN = $B7 ; 183 LSB current DATA statement line number
+; $B8 ; 184 MSB, DATALN
+;ERRNUM = $B9 ; 185 Most recent error number. Gets cleared before you
+ ; can PEEK it; use ERRSAVE instead.
+STOPLN = $BA ; 186 LSB, line where a program stopped by STOP/break/error
+; $BB ; 187 MSB, STOPLN
+; what are $BC and $BD for?
+SAVCUR = $BE ; 190 Saves the current line address (LSB?)
+; $BF ; 191 presumably, the MSB of SAVCUR?
+IOCMD = $C0 ; 192, I/O Command (Mapping Errata)
+IODVC = $C1 ; 193, I/O Device (Mapping Errata)
+PROMPT = $C2 ; 194, Prompt character (Mapping Errata, presumably INPUT?)
+ERRSAVE = $C3 ; 195 Error code that caused a stop or TRAP
+;TEMPA = $C4 ; 196 a 2-byte temp
+;ZTEMP2 = $C6 ; 198 a 2-byte temp
+COLOR = $C8 ; 200 Stores color from COLOR command
+PTABW = $C9 ; 201 Number of columns between tab stops
+ ; (for PRINT with commas, not the TAB key)
+LOADFLG = $CA ; 202 Load in progress flag. I can tell you from bitter
+ ; experience that BASIC clears this often.
+
+; $CB - $CF are unused by BASIC or the ASM/ED cart.
+; $D0 and $D1 are unused by BASIC (does that mean they *are* used by ASM/ED?)
+
+; $D2 and $D3 are used by BASIC. Mapping Errata calls them the "BASIC
+; floating-point work area". They get cleared to 0 by BASIC, probably
+; every time a FP number is used (e.g. "POKE 210,1:? PEEK(210)" prints 0).
+; The BASIC source code labels $D2 as TVTYPE and VTYPE, and $D3 as
+; TVNUM and VNUM.
+
+; Floating point zero page variables:
+FPZRO = $D4 ; 212 FLOATING POINT RAM, 43 BYTES
+ ; (20070530 bkw: pretty sure that comment is wrong, and
+ ; should read 44 bytes; see $FF below)
+FR0 = $D4 ; 212 FP REGISTER 0 (also used by BASIC for USR() return val)
+ ; (FR0/FRE/FR1/FR2 are each 6 bytes long)
+FRE = $DA ; 218
+FR1 = $E0 ; 224 FP REGISTER 1
+FR2 = $E6 ; 230 FP REGISTER 2
+FRX = $EC ; 236 SPARE
+EEXP = $ED ; 237 VALUE OF E
+NSIGN = $ED ; 237 SIGN OF FP NUMBER
+ESIGN = $EF ; 239 SIGN OF FP EXPONENT
+FCHFLG = $F0 ; 240 FIRST CHARACTER FLAG
+DIGRT = $F1 ; 241 NUMBER OF DIGITS RIGHT OF DECIMAL POINT
+CIX = $F2 ; 242 INPUT INDEX
+INBUFF = $F3 ; 243 POINTER TO ASCII FP NUMBER
+ZTEMP1 = $F5 ; 245
+ZTEMP4 = $F7 ; 247
+ZTEMP3 = $F9 ; 249
+DEGFLG = $FB ; 251
+RADFLG = $FB ; 251 0=RADIANS, 6=DEGREES
+FLPTR = $FC ; 252 POINTER TO BCD FP NUMBER (2 bytes)
+FPTR2 = $FE ; 254 maybe a 2nd pointer to an FP number? (2 bytes)
+; $FF ; 255 This *definitely* is used by the FP package
+ ; Try: POKE 255,0:? SIN(1):? PEEK(255)
+
+;
+; PAGE 1
+;
+; 65O2 STACK
+;
+;
+
+;
+;
+; PAGE 2
+;
+;
+; 20070529 bkw: Bytes listed as "spare" should NOT be used for your own
+; purposes. They may not really be unused (just undocumented), and/or they
+; may be unused on the 800 but not the XL (or vice versa).
+INTABS = $0200 ; 512 INTERRUPT RAM
+VDSLST = $0200 ; 512 NMI VECTOR
+VPRCED = $0202 ; 514 PROCEED LINE IRQ VECTOR
+VINTER = $0204 ; 516 INTERRUPT LINE IRQ VECTOR
+VBREAK = $0206 ; 518 break key IRQ vector (not in OS rev. A)
+VKEYBD = $0208 ; 520 keyboard IRQ vector (not break/console keys)
+VSERIN = $020A ; 522 SERIAL INPUT READY IRQ
+VSEROR = $020C ; 524 SERIAL OUTPUT READY IRQ
+VSEROC = $020E ; 526 SERIAL OUTPUT COMPLETE IRQ
+VTIMR1 = $0210 ; 528 TIMER 1 IRQ vector
+VTIMR2 = $0212 ; 530 TIMER 2 IRQ vector
+VTIMR4 = $0214 ; 532 TIMER 4 IRQ vector
+VIMIRQ = $0216 ; 534 IRQ VECTOR
+CDTMV1 = $0218 ; 536 COUNTDOWN TIMER 1 vector
+CDTMV2 = $021A ; 538 COUNTDOWN TIMER 2 vector
+CDTMV3 = $021C ; 540 COUNTDOWN TIMER 3 vector
+CDTMV4 = $021E ; 542 COUNTDOWN TIMER 4 vector
+CDTMV5 = $0220 ; 544 COUNTDOWN TIMER 5 vector
+VVBLKI = $0222 ; 546 immediate VBLANK vector
+VVBLKD = $0224 ; 548 deferred VBLANK vector (ignore if CRITIC != 0)
+CDTMA1 = $0226 ; 550 COUNTDOWN TIMER 1 JSR ADDRESS
+CDTMA2 = $0228 ; 552 COUNTDOWN TIMER 2 JSR ADDRESS
+CDTMF3 = $022A ; 554 COUNTDOWN TIMER 3 FLAG
+SRTIMR = $022B ; 555 REPEAT TIMER
+CDTMF4 = $022C ; 556 COUNTDOWN TIMER 4 FLAG
+INTEMP = $022D ; 557 IAN'S TEMP (used by SETVBL routine)
+CDTMF5 = $022E ; 558 COUNTDOWN TIMER FLAG 5
+SDMCTL = $022F ; 559 DMACTL SHADOW
+SDLSTL = $0230 ; 560 DISPLAY LIST POINTER, LSB (shadow for DLISTL)
+SDLSTH = $0231 ; 561 display list pointer, MSB (shadow for DLISTH)
+SSKCTL = $0232 ; 562 SKCTL SHADOW
+; $0233 ; 563 (800) UNLISTED (Mapping calls this SPARE)
+XL_LCOUNT = $0233 ; 563 (XL) LOADER TEMP
+LPENH = $0234 ; 564 LIGHT PEN HORIZONTAL (shadow for PENH)
+LPENV = $0235 ; 565 LIGHT PEN VERTICAL (shadow for PENV)
+; $0236 ; 566 2 SPARE BYTES on OS rev A
+VBRKKY = $0236 ; 566 Break key interrupt vector (OS rev B and XL)
+BRKKY = VBRKKY ; "OS rev 5" listing calls it this
+; $0238 ; 568 (800) SPARE, 2 BYTES
+;XL_RELADR = $0238 ; 568 (XL) relocatable loader relative addr, 1200XL only!
+XL_VPIRQ = $0238 ; 568 (XL) PBI IRQ vector (not on 1200XL!)
+CDEVIC = $023A ; 570 DEVICE COMMAND FRAME BUFFER
+CAUX1 = $023C ; 572 DEVICE COMMAND AUX 1
+CAUX2 = $023D ; 573 DEVICE COMMAND AUX 2
+TEMP = $023E ; 574 TEMPORARY STORAGE
+ERRFLG = $023F ; 575 DEVICE ERROR FLAG (EXCEPT TIMEOUT)
+DFLAGS = $0240 ; 576 FLAGS FROM DISK SECTOR 1
+DBSECT = $0241 ; 577 NUMBER OF BOOT DISK SECTORS
+BOOTAD = $0242 ; 578 BOOT LOAD ADDRESS POINTER
+COLDST = $0244 ; 580 COLD START FLAG, 1 = COLD START IN PROGRESS
+; $0245 ; 581 (800) SPARE
+XL_RECLEN = $0245 ; 581 (XL) LOADER
+DSKTIM = $0246 ; 582 (800) DISK TIME OUT REGISTER
+; $0246 ; 582 (XL) RESERVED, 39 BYTES
+LINBUF = $0247 ; 583 (800) CHARACTER LINE BUFFER, 40 BYTES
+ ; LINBUF was deleted from the XL OS and replaced with:
+
+; $0247 - $024D are "reserved" on the 1200XL. On other XL's they are:
+XL_PDVMSK = $0247 ; 583 shadow for PBI device selection register @ $D1FF
+XL_SHPDVS = $0248 ; 584 shadow for PBI register (where??)
+XL_PDMSK = $0249 ; 585 PBI interrupt mask
+XL_RELADR = $024A ; 586 (XL) LSB, relocatable loader relative addr (NOT 1200XL)
+; $024B ; 587 MSB, XL_RELADR
+XL_PPTMPA = $024C ; 588 temporaries for relocatable loader
+XL_PPTMPX = $024D ; 589 "
+
+; $024E - $026A are "spare" on all XL/XE's
+
+; More XL stuff:
+XL_CHSALT = $026B ; 619 (XL) CHARACTER SET POINTER (ctrl-F4 on 1200XL)
+XL_VSFLAG = $026C ; 620 (XL) FINE SCROLL TEMPORARY
+XL_KEYDIS = $026D ; 621 (XL) KEYBOARD DISABLE (ctrl-F1 on 1200XL)
+XL_FINE = $026E ; 622 (XL) FINE SCROLL FLAG (POKE 622,255:GR.0)
+
+GPRIOR = $026F ; 623 P/M PRIORITY AND GTIA MODES (shadow for PRIOR)
+;GTIA = $026F ; 623 ; 20070529 bkw: does anyone define this?
+
+; Game controller shadows (joysticks/paddles)
+; Joystick directions and paddle triggers (buttons) are wired to the PIA.
+; Joystick triggers (fire buttons) and the actual paddle potentiometers
+; are wired to the GTIA.
+; If this seems a little odd, that's because it is :)
+
+; Paddles (potentiometers):
+PADDL0 = $0270 ; 624 (XL) 3 MORE PADDLES, (800) 7 MORE PADDLES
+PADDL1 = $0271 ; 625 (these are read in BASIC with PADDLE(x)
+PADDL2 = $0272 ; 626 (PADDL0-7 are shadows for POT0-7)
+PADDL3 = $0273 ; 627
+PADDL4 = $0274 ; 628 (PADDL4-7 are copies of PADDL0-3 on the XL)
+PADDL5 = $0275 ; 629
+PADDL6 = $0276 ; 630
+PADDL7 = $0277 ; 631
+
+; Joysticks (directions only)
+STICK0 = $0278 ; 632 (XL) 1 MORE STICK, (800) 3 MORE STICKS
+STICK1 = $0279 ; 633 (these are read in BASIC with STICK(x)
+STICK2 = $027A ; 634 (STICK0/1 are shadows for PORTA; STICK2/3 shadows PORTB)
+STICK3 = $027B ; 635
+; STICK0 is a shadow for bits 4-7 of PORTA (shifted 4 bits right)
+; STICK1 is a shadow for bits 0-3 of PORTA
+
+; On the 800:
+; STICK2 is a shadow for bits 4-7 of PORTB (shifted 4 bits right)
+; STICK3 is a shadow for bits 0-3 of PORTB
+
+; On the XL/XE series:
+; STICK2 and STICK3 are copies of STICK0 and STICK1, respectively.
+
+; In the XL/XE machines, there are only 2 joystick ports, and PORTB
+; (formerly joystick ports) is now used to control the MMU.
+
+; joystick directions are active low (1=not pressed) and decode as:
+
+; bit direction
+; 0 or 4 up
+; 1 or 5 down
+; 2 or 6 left
+; 3 or 7 right
+
+; A value of $0F in a STICKx register means no direction is being pressed.
+; When a direction is pressed, its bit becomes a logic 0, so e.g. $0E means
+; someone's moving the joystick up.
+
+; (bits 4-7 are only used when reading directly from the HW registers,
+; PORTA and PORTB).
+
+; Paddle triggers (buttons)
+PTRIG0 = $027C ; 636 (XL) 3 MORE PADDLE TRIGGERS, (800) 7 MORE
+PTRIG1 = $027D ; 637 (these are read in BASIC with PTRIG(x))
+PTRIG2 = $027E ; 638 (PTRIG0-3 are shadows for PORTA)
+PTRIG3 = $027F ; 639
+PTRIG4 = $0280 ; 640 (PTRIG4-7 are shadows for PORTB on the 800)
+PTRIG5 = $0281 ; 641 (they are copies of PTRIG0-3 on the XL)
+PTRIG6 = $0282 ; 642
+PTRIG7 = $0283 ; 643
+; In case someone doesn't already know this: The paddle triggers are wired
+; to the same pins on the joystick port as the left/right joystick directions.
+; Each pair of paddles uses left for the first paddle's trigger and right
+; for the second (so PTRIG0/1 are also the left/right bits in STICK0,
+; PTRIG2/3 are STICK1, etc).
+
+; Joystick triggers (buttons)
+STRIG0 = $0284 ; 644 (XL) 1 MORE STICK TRIGGER, (800) 3 MORE
+STRIG1 = $0285 ; 645 (these are read in BASIC with STRIG(x))
+STRIG2 = $0286 ; 646 (STRIG0-3 are shadows for TRIG0-3)
+STRIG3 = $0287 ; 647
+
+; C: handler variables:
+CSTAT = $0288 ; 648 (800) Cassette status register
+; note that CSTAT was deleted from the XL OS, and replaced with:
+XL_HIBYTE = $0288 ; 648 (XL) used by relocatable loader
+WMODE = $0289 ; 649 used by C: handler (0=read, 128-write)
+BLIM = $028A ; 650 cassette buffer data record size
+; $028B ; 651 (800) 5 SPARE BYTES (to $028F)
+XL_IMASK = $028B ; 651 (XL) used by relocatable loader
+XL_JVECK = $028C ; 652 (XL) (Mapping says it's unused)
+ ; 653 (XL) Presumably the MSB of JVECK (unused?)
+XL_NEWADR = $028E ; 654 (XL) LOADER RAM (2 bytes)
+
+; Misc. S: and/or E: handler variables:
+TXTROW = $0290 ; 656
+TXTCOL = $0291 ; 657
+TINDEX = $0293 ; 659 TEXT INDEX
+TXTMSC = $0294 ; 660
+TXTOLD = $0296 ; 662 OLD ROW AND OLD COL FOR TEXT, 2 BYTES
+; $0298 ; 664 4 SPARE BYTES
+TMPX1 = $029C ; 668 (800)
+; note that TMPX1 was deleted from the XL OS, and replaced with:
+XL_CRETRY = $029C ; 668 (XL) NUMBER OF COMMAND FRAME RETRIES
+ ; (moved from CRETRY on 800)
+SUBTMP = $029E ; 670
+HOLD2 = $029F ; 671
+DMASK = $02A0 ; 672
+TMPLBT = $02A1 ; 673
+ESCFLG = $02A2 ; 674
+TABMAP = $02A3 ; 675 15 BYTE BIT MAP FOR TAB SETTINGS
+LOGMAP = $02B2 ; 690 4 BYTE LOGICAL LINE START BIT MAP
+INVFLG = $02B6 ; 694 mask for inverse video ($80=inverse, 0=normal)
+FILFLG = $02B7 ; 695 FILL DURING DRAW FLAG
+TMPROW = $02B8 ; 696
+TMPCOL = $02B9 ; 697
+SCRFLG = $02BB ; 699 SCROLL FLAG
+HOLD4 = $02BC ; 700
+HOLD5 = $02BD ; 701 (800)
+; note that HOLD5 was deleted from the XL OS, and replaced with:
+XL_DRETRY = $02BD ; 701 (XL) NUMBER OF DEVICE RETRIES
+ ; (moved from DRETRY on 800)
+SHFLOC = $02BE ; 702
+BOTSCR = $02BF ; 703 24 NORM, 4 SPLIT
+
+; Color register shadows (HW registers are in GTIA)
+PCOLR0 = $02C0 ; 704 3 MORE PLAYER COLOR REGISTERS (shadows for COLPM0-3)
+PCOLR1 = $02C1 ; 705 (missiles use same color regs as same-numbered players!)
+PCOLR2 = $02C2 ; 706
+PCOLR3 = $02C3 ; 707
+COLOR0 = $02C4 ; 708 4 MORE GRAPHICS COLOR REGISTERS (shadows for COLPF0-3)
+COLOR1 = $02C5 ; 709 (text luminance in GR.0)
+COLOR2 = $02C6 ; 710 (text background and chroma in GR.0)
+COLOR3 = $02C7 ; 711
+COLOR4 = $02C8 ; 712 (background, shadow for COLBK)
+; On boot, system reset, or any time S:/E: devices are opened:
+; PCOLR0-3 are initialzed to 0 ($00, black)
+; COLOR0 is initialized to 40 ($28, orange)
+; COLOR1 is initialized to 202 ($CA, green)
+; COLOR2 is initialized to 148 ($94, blue)
+; COLOR3 is initialized to 70 ($46, red)
+; COLOR4 is initialized to 0 ($00, black)
+
+; $02C9 713 (800) 23 SPARE BYTES
+; XL relocatable handler and other variables:
+XL_RUNADR = $02C9 ; 713 (XL) LOADER VECTOR
+XL_HIUSED = $02CB ; 715 (XL) LOADER VECTOR
+XL_ZHIUSE = $02CD ; 717 (XL) LOADER VECTOR
+XL_GBYTEA = $02CF ; 719 (XL) LOADER VECTOR
+XL_LOADAD = $02D1 ; 721 (XL) LOADER VECTOR
+XL_ZLOADA = $02D3 ; 723 (XL) LOADER VECTOR
+XL_DSCTLN = $02D5 ; 725 (XL) DISK SECTOR SIZ
+XL_ACMISR = $02D7 ; 727 (XL) RESERVED
+XL_KRPDER = $02D9 ; 729 (XL) KEY AUTO REPEAT DELAY
+XL_KEYREP = $02DA ; 730 (XL) KEY AUTO REPEAT RATE
+XL_NOCLIK = $02DB ; 731 (XL) KEY CLICK DISABLE (ctrl-F3 on 1200XL)
+XL_HELPFG = $02DC ; 732 (XL) HELP KEY FLAG
+XL_DMASAV = $02DD ; 733 (XL) SDMCTL (DMA) SAVE (ctrl-F2 on 1200XL)
+XL_PBPNT = $02DE ; 734 (XL) PRINTER BUFFER POINTER (moved from PBPNT on 800)
+XL_PBUFSZ = $02DF ; 735 (XL) PRINTER BUFFER SIZE (moved from PBUFSZ on 800)
+; note that PTEMP was deleted from the XL OS
+
+; DOS/FMS variables:
+GLBABS = $02E0 ; 736 GLOBAL VARIABLES, 4 SPARE BYTES (if DOS not loaded)
+ ; If DOS/FMS is loaded:
+RUNAD = $02E0 ; 736 (DOS) Run address for binary file (LSB/MSB)
+INITAD = $02E2 ; 736 (DOS) Init address for binary file (LSB/MSB)
+
+; SYSEQU.ASM defines these:
+GOADR = RUNAD
+INITADR = INITAD
+
+; OS variables:
+RAMSIZ = $02E4 ; 740 PERMANENT START OF ROM POINTER
+MEMTOP = $02E5 ; 741 END OF FREE RAM
+MEMLO = $02E7 ; 743 LSB, points to bottom of free memory ($0700 if DOS
+ ; not booted). Not to be confused with BASIC's LOMEM!
+; $02E8 ; 744 MSB of MEMLO
+
+; $02E9 ; 745 (800) SPARE
+XL_HNDLOD = $02E9 ; 745 (XL) HANDLER LOADER FLAG
+
+DVSTAT = $02EA ; 746 DEVICE STATUS BUFFER, 4 BYTES
+CBAUDL = $02EE ; 750 CASSETTE BAUD RATE, 2 BYTES
+CRSINH = $02F0 ; 752 1 = INHIBIT CURSOR
+KEYDEL = $02F1 ; 753 KEY DELAY AND RATE (aka debounce counter)
+CH1 = $02F2 ; 754 prior keyboard character code
+CHACT = $02F3 ; 755 (shadow for CHACTL)
+CHBAS = $02F4 ; 756 CHARACTER SET POINTER (shadow for CHBASE)
+
+; These next 4 are located elsewhere on the 800 OS:
+XL_NEWROW = $02F5 ; 757 (XL) DRAW DESTINATION
+XL_NEWCOL = $02F6 ; 758 (XL) DRAW DESTINATION
+XL_ROWINC = $02F8 ; 760 (XL)
+XL_COLINC = $02F9 ; 761 (XL)
+; $02F5 - $02F9 are "spare" on the 800.
+
+CHAR = $02FA ; 762 most recent character read/written (screen code)
+ATACHR = $02FB ; 763 ATASCII CHARACTER FOR CIO
+CH = $02FC ; 764 last key pressed (internal scan code)
+FILDAT = $02FC ; 764 COLOR FOR SCREEN FILL
+DSPFLG = $02FE ; 766 DISPLAY CONTROL CHARACTERS FLAG
+SSFLAG = $02FF ; 767 DISPLAY START/STOP FLAFG
+
+;
+; PAGE 3
+;
+;
+; RESIDENT DISK HANDLER/SIO INTERFACE
+;
+; The DCB is used for SIO (serial I/O).
+DCB = $0300 ; 768 DEVICE CONTROL BLOCK
+DDEVIC = $0300 ; 768 device ID ($31-$38 for D1:-D8:)
+DUNIT = $0301 ; 769 disk/device unit numder
+DCOMND = $0302 ; 770 device command
+DSTATS = $0303 ; 771 status code (set by OS)
+DBUFLO = $0304 ; 772 data buffer LSB (set by user)
+DBUFHI = $0305 ; 773 data buffer MSB (set by user)
+DTIMLO = $0306 ; 774 timeout (set by user, units of 60/64 seconds)
+DUNUSE = $0307 ; 775 unused
+DBYTLO = $0308 ; 776 number of bytes to transfer, LSB
+DBYTHI = $0309 ; 777 number of bytes to transfer, MSB
+DAUX1 = $030A ; 778 LSB of sector number (for disk) (set by user)
+DAUX2 = $030B ; 779 MSB of sector number (for disk)
+TIMER1 = $030C ; 780 INITIAL TIMER VALUE
+ADDCOR = $030E ; 782 (800) ADDITION CORRECTION
+; note that ADDCOR was deleted from the XL OS, and replaced with:
+XL_JMPERS = $030E ; 782 (XL) OPTION JUMPERS
+CASFLG = $030F ; 783 CASSETTE MODE WHEN SET
+TIMER2 = $0310 ; 784 FINAL VALUE, TIMERS 1 & 2 DETERMINE BAUD RATE
+TEMP1 = $0312 ; 786
+XL_TEMP2 = $0313 ; 787 (XL)
+TEMP2 = $0314 ; 788 (800)
+XL_PTIMOT = $0314 ; 788 (XL) PRINTER TIME OUT
+TEMP3 = $0315 ; 789
+SAVIO = $0316 ; 790 SAVE SERIAL IN DATA PORT
+TIMFLG = $0317 ; 791 TIME OUT FLAG FOR BAUD RATE CORRECTION
+STACKP = $0318 ; 792 SIO STACK POINTER SAVE
+TSTAT = $0319 ; 793 TEMPORARY STATUS HOLDER
+HATABS = $031A ; 794 HANDLER ADDRESS TABLE, 38 BYTES
+MAXDEV = $0321 ; 801 MAXIMUM HANDLER ADDRESS INDEX
+XL_PUPBT1 = $033D ; 829 (XL) POWER-UP/RESET
+XL_PUPBT2 = $033E ; 830 (XL) POWER-UP/RESET
+XL_PUPBT3 = $033F ; 831 (XL) POWER-UP/RESET
+
+; IOCB's, 8 of them, 16 bytes each.
+; Set X register to (IOCB number * 16), and use e.g. ICCOM,x
+;
+IOCB = $0340 ; 832 ; IOCB base address
+ICHID = $0340 ; 832 ; Handler ID (set by OS)
+ICDNO = $0341 ; 833 ; Device number (set by OS)
+ICCOM = $0342 ; 834 ; Command byte (see C_* constants) (set by user)
+ICCMD = ICCOM ; ; alternate name for ICCOM, according to Mapping.
+ICSTA = $0343 ; 835 ; Status (set by OS)
+ICBAL = $0344 ; 836 ; Buffer address, LSB (set by user)
+ICBAH = $0345 ; 837 ; Buffer address, MSB (set by user)
+ICPTL = $0346 ; 838 ; Put-one-byte address minus one, LSB (set by OS)
+ICPTH = $0347 ; 839 ; Put-one-byte address minus one, MSB (set by OS)
+ICBLL = $0348 ; 840 ; Buffer length, LSB (set by user)
+ICBLH = $0349 ; 841 ; Buffer length, MSB (set by user)
+ICAX1 = $034A ; 842 ; AUX1 byte (2nd param in BASIC OPEN) (set by user)
+ICAX2 = $034B ; 843 ; AUX2 byte (4rd param in BASIC OPEN) (set by user)
+ICAX3 = $034C ; 844 ; AUX3 byte (used by NOTE/POINT) (set by user)
+ICAX4 = $034D ; 845 ; AUX4 byte (used by NOTE/POINT) (set by user)
+ICAX5 = $034E ; 846 ; AUX5 byte (used by NOTE/POINT) (set by user)
+ICAX6 = $034F ; 847 ; Spare aux byte
+; OTHER IOCB's, 112 BYTES ($300 + $10 * channel)
+
+IOCBLEN = ICAX6-IOCB+1 ; length of one IOCB (from SYSEQU.ASM)
+
+; Alternative names for the above. I found these in SYSEQU.ASM, as
+; distributed with the disk version of Mac65.
+ICBADR = ICBAL
+ICPUT = ICPTL
+ICBLEN = ICBLL
+ICAUX1 = ICAX1
+ICAUX2 = ICAX2
+ICAUX3 = ICAX3
+ICAUX4 = ICAX4
+ICAUX5 = ICAX5
+ICAUX6 = ICAX6
+
+PRNBUF = $03C0 ; 960 PRINTER BUFFER, 40 BYTES
+; $03E8 ; 1000 (800) 21 SPARE BYTES
+XL_SUPERF = $03E8 ; 1000 (XL) SCREEN EDITOR
+XL_CKEY = $03E9 ; 1001 (XL) START KEY FLAG
+XL_CASSBT = $03EA ; 1002 (XL) CASSETTE BOOT FLAG
+XL_CARTCK = $03EB ; 1003 (XL) CARTRIDGE CHECKSUM
+XL_ACMVAR = $03ED ; 1005 (XL) RESERVED, 10 BYTES (to $03F7)
+XL_BASICF = $03F8 ; 1006 (XL) 0 if ROM-BASIC enabled, 1 if not
+XL_MINTLK = $03F9 ; 1017 (XL) RESERVED
+XL_GINTLK = $03FA ; 1018 (XL) CARTRIDGE INTERLOCK
+XL_CHLINK = $03FB ; 1019 (XL) HANDLER CHAIN, 2 BYTES
+CASBUF = $03FD ; 1021 CASSETTE BUFFER, 131 BYTES TO $047F
+
+; Layout of the cassette buffer after a cassette block is read:
+
+; Baud correction ($55 $55) bytes are located at offsets 0 and 1
+; Control byte is at offset 2 ($03FF):
+; Actual data (128 bytes) runs from offset 3 ($0400) to $047F.
+; Each cassette frame has a 1 byte checksum after the 128 data bytes, but
+; the checksum is NOT stored anywhere in the cassette buffer!
+
+; CONTROL BYTE VALUES
+; Value Meaning
+; 250 ($FA) Partial record follows. The actual number of bytes is stored
+; in the last byte of the record (CASBUF+130, or $047F).
+; 252 ($FC) Record full; 128 bytes follow.
+; 254 ($FE) End of File (EOF) record; followed by 128 zero bytes.
+
+; Boot tapes normally don't have partial or EOF records, but BASIC
+; CLOAD/LOAD/LIST and data file tapes do.
+
+; Mapping the Atari says the first disk boot sector is read into CASBUF also.
+
+;
+;
+; PAGE 4
+;
+;
+USAREA = $0480 ; 1152 128 SPARE BYTES (but used by BASIC)
+;
+; SEE APPENDIX C FOR PAGES 4 AND 5 USAGE
+
+;
+;
+;
+;
+; PAGE 5
+;
+PAGE5 = $0500 ; 1280 127 FREE BYTES
+; $057E 1406 129 FREE BYTES IF FLOATING POINT ROUTINES NOT USED
+;
+;FLOATING POINT NON-ZERO PAGE RAM, NEEDED ONLY IF FP IS USED
+; (20070529 bkw: BASIC constantly uses FP! Also, it uses some of these
+; addresses for its own purposes.)
+;
+LBPR1 = $057E ; 1406 LBUFF PREFIX 1
+LBPR2 = $05FE ; 1534 LBUFF PREFIX 2
+LBUFF = $0580 ; 1408 LINE BUFFER
+PLYARG = $05E0 ; 1504 POLYNOMIAL ARGUMENTS
+FPSCR = $05E6 ; 1510 PLYARG+FPREC
+FPSCR1 = $05EC ; 1516 FPSCR+FPREC
+FSCR = $05E6 ; 1510 =FPSCR
+FSCR1 = $05EC ; 1516 =FPSCR1
+LBFEND = $05FF ; 1535 END OF LBUFF
+
+;
+; PAGE 6
+;
+;
+PAGE6 = $0600 ; 1536 256 FREE BYTES
+
+;
+;
+; PAGE 7
+;
+;
+BOOTRG = $0700 ; 1792 PROGRAM AREA
+; Boot disks (including DOS) are generally loaded here. Also, BASIC RAM
+; (variables and program) starts here, if BASIC is booted without DOS.
+
+; Page 80 (XL): Self-test (aka diagnostic) ROM is mapped at $5000,
+; if enabled with bit 7 of PORTB. Normally only happens if you boot without
+; BASIC, cartridge, tape, or disk... or if the OS detects a memory error
+; during boot.
+
+;
+;
+; UPPER ADDRESSES
+;
+;
+RITCAR = $8000 ;32768 RAM IF NO CARTRIDGE (extends to $9FFF)
+LFTCAR = $A000 ;40960 RAM IF NO CARTRIDGE (extends to $BFFF)
+
+; These 2 are from the Atari System Reference Manual, chapter 12:
+CARTA = LFTCAR
+CARTB = RITCAR
+
+CARTLOC = $BFFA ;49146 cartridge run address (from SYSEQU.ASM)
+
+; Carts were originally 8K only when the 400/800 were first released.
+; There were plans to release 16K programs on two cartridges, but this
+; never happened (the price of 16K ROMs came down, I guess). 16K cartridges
+; go in the left slot, but they actually use the address space for both
+; the right and left slots.
+
+; Mapping the Atari has this to say about cartridges:
+;; Byte Purpose
+;; Left (A) Right(B)
+;; 49146 ($BFFA) 40954 ($9FFA) Cartridge start address (low byte)
+;;
+;; 49147 ($BFFB) 40955 ($9FFB) Cartridge start address (high byte)
+;;
+;; 49148 ($BFFC) 40956 ($9FFC) Reads zero if a cartridge is
+;; inserted, non-zero when no cartridge is present. This information
+;; is passed down to the page zero RAM: if the A cartridge is plugged
+;; in, then location 6 will read one; if the B cartridge is plugged in,
+;; then location 7 will read one; otherwise they will read zero.
+;;
+;; 49149 ($BFFD) 40957 ($9FFD) Option byte. If BIT 0 equals one,
+;; then boot the disk (else there is no disk boot). If BIT 2 equals one,
+;; then initialize and start the cartridge (else initialize but do not
+;; start). If BIT 7 equals one, then the cartridge is a diagnostic
+;; cartridge which will take control, but not initialize the OS (else
+;; non-diagnostic cartridge). Diagnostic cartridges were used by
+;; Atari in the development of the system and are not available to the
+;; public.
+;;
+;; 49150 ($BFFE) 40958 ($9FFE) Cartridge initialization address
+;; low byte.
+;;
+;; 49151 ($BFFF) 40959 ($9FFF) Cartridge initialization address
+;; high byte. This is the address to which the OS will jump during all
+;; powerup and RESETs.
+;;
+;; The OS makes temporary use of locations 36876 to 36896 ($900C to
+;; $9020) to set up vectors for the interrupt handler. See the OS
+;; listings pages 31 and 81. This code was only used in the
+;; development system used to design the Atari.
+
+
+; Page 192
+
+C0PAGE = $C000 ;49152 (800) EMPTY, 4K BYTES
+ ; 20070529 bkw: unmapped address space.
+ ; Mapping the Atari erroneously lists this as "unused ROM".
+ ; There are upgrades to the 800 to give 4K of RAM here
+ ; (for a total of 52K of RAM), or ROM (Omnimon?).
+ ; Also, there is RAM here if you boot the Translator
+ ; disk on an XL.
+
+; (XL) $C000 also contains info about the ROM revision. From Mapping:
+
+;Bytes 49152-49163 ($C000-$C00B) are used to identify the computer
+;and the ROM in the $C000-$DFFF block:
+;
+;Byte Use
+;49152-3/C000-1 Checksum (LSB/MSB) of all the bytes
+; in ROM except the checksum bytes
+; themselves.
+;49154/C002 Revision date, stored in the form
+; DDMMYY. This is DD, day, usually $10.
+;49155/C003 Revision date, month; usually $05.
+;49156/C004 Revision date, year; usually $83.
+;49157/C005 Reserved option byte; reads zero for
+; the 1200, 800XL, and 130XE.
+;49158/C006 Part number in the form AANNNNNN;
+; AA is an ASCII character and
+; NNNNNN is a four-bit BCD digit. This is
+; byte A1.
+;49159-62/C007-A Part number, bytes A2, N1-N6 (each
+; byte has two N values of four bits
+; each).
+;49163/C00B Revision number. Mapping author's 800XL and 130XE say 2.
+
+;C0PAGE = $C000 ;49152 (XL) OS ROM, mostly interrupt handlers
+; $C800 51200 (XL) START OF OS ROM
+CHORG2 = $CC00 ;52224 (XL) INTERNATIONAL CHARACTER SET
+
+
+
+;
+;
+; HARDWARE REGISTERS
+;
+;
+; SEE REGISTER LIST FOR MORE INFORMATION
+;
+;
+
+; GTIA
+GTIA = $D000
+HPOSP0 = $D000 ;53248 (W) ; P/M positions (no shadows)
+HPOSP1 = $D001 ;53249 (W)
+HPOSP2 = $D002 ;53250 (W)
+HPOSP3 = $D003 ;53251 (W)
+HPOSM0 = $D004 ;53252 (W)
+HPOSM1 = $D005 ;53253 (W)
+HPOSM2 = $D006 ;53254 (W)
+HPOSM3 = $D007 ;53255 (W)
+SIZEP0 = $D008 ;53256 (W) ; P/M size regs (no shadows)
+SIZEP1 = $D009 ;53257 (W)
+SIZEP2 = $D00A ;53258 (W)
+SIZEP3 = $D00B ;53259 (W)
+SIZEM = $D00C ;53260 (W)
+M0PF = $D000 ;53248 (R) ; collision regs (no shadows)
+M1PF = $D001 ;53249 (R)
+M2PF = $D002 ;53250 (R)
+M3PF = $D003 ;53251 (R)
+P0PF = $D004 ;53252 (R)
+P1PF = $D005 ;53253 (R)
+P2PF = $D006 ;53254 (R)
+P3PF = $D007 ;53255 (R)
+M0PL = $D008 ;53256 (R)
+M1PL = $D009 ;53257 (R)
+M2PL = $D00A ;53258 (R)
+M3PL = $D00B ;53259 (R)
+P0PL = $D00C ;53260 (R)
+P1PL = $D00D ;53261 (R)
+P2PL = $D00E ;53262 (R)
+P3PL = $D00F ;53263 (R)
+GRAFP0 = $D00D ;53261 (W) ; direct (non-DMA) P/M graphics regs (no shadows)
+GRAFP1 = $D00E ;53262 (W)
+GRAFP2 = $D00F ;53263 (W)
+GRAFP3 = $D010 ;53264 (W)
+GRAFM = $D011 ;53265 (W)
+TRIG0 = $D010 ;53264 (R) ; Joystick triggers (shadows @ STRIG0-3)
+TRIG1 = $D011 ;53265 (R)
+TRIG2 = $D012 ;53266 (R)
+TRIG3 = $D013 ;53267 (R)
+PAL = $D014 ;53268 (R) ; PAL/NTSC detect (no shadow)
+ ; PAL supposedly moved to XL_PALNTS on XL; what was it
+ ; replaced with?
+COLPM0 = $D012 ;53266 (W) ; P/M colors (shadows @ PCOLR0-3)
+COLPM1 = $D013 ;53267 (W)
+COLPM2 = $D014 ;53268 (W)
+COLPM3 = $D015 ;53269 (W)
+COLPF0 = $D016 ;53270 (W) ; Playfield colors (shadows @ COLOR0-3)
+COLPF1 = $D017 ;53271 (W)
+COLPF2 = $D018 ;53272 (W)
+COLPF3 = $D019 ;53273 (W)
+COLBK = $D01A ;53274 (W) ; Background color (shadow @ COLOR4)
+PRIOR = $D01B ;53275 (W) ; GTIA priority (shadow @ GPRIOR)
+GTIAR = $D01B ;53275 (R?)
+VDELAY = $D01C ;53276 (W)
+GRACTL = $D01D ;53277 (W)
+HITCLR = $D01E ;53278 (W), latch
+CONSOL = $D01F ;53279 (W=keyclick spkr, R=console keys)
+
+; $D020 - $D0FF are mirrors of GTIA address space
+; $D100 - $D1FF are supposed to be unused (unmapped) on the 800
+; On the XL, $D100 - $D1FF is switched to device memory during PBI I/O
+
+; POKEY
+POKEY = $D200
+; no shadows for AUDC/AUDF
+AUDF1 = $D200 ;53760 (W) ; Audio frequency 1
+AUDC1 = $D201 ;53761 (W) ; Audio control 1 (distortion/volume)
+AUDF2 = $D202 ;53762 (W)
+AUDC2 = $D203 ;53763 (W)
+AUDF3 = $D204 ;53764 (W)
+AUDC3 = $D205 ;53765 (W)
+AUDF4 = $D206 ;53766 (W)
+AUDC4 = $D207 ;53767 (W)
+
+; POT0-7 shadows at PADDL0-7
+POT0 = $D200 ;53760 (R) ; Paddle positions
+POT1 = $D201 ;53761 (R)
+POT2 = $D202 ;53762 (R)
+POT3 = $D203 ;53763 (R)
+POT4 = $D204 ;53764 (R) ; pots 3-7 don't exist on XL/XE
+POT5 = $D205 ;53765 (R)
+POT6 = $D206 ;53766 (R)
+POT7 = $D207 ;53767 (R)
+
+AUDCTL = $D208 ;53768 (W) ; Audio control (no shadow)
+ALLPOT = $D208 ;53768 (R) (no shadow)
+STIMER = $D209 ;53769 (W) (no shadow)
+KBCODE = $D209 ;53769 (R) (shadow @ CH)
+SKREST = $D20A ;53770 (W) (latch)
+RANDOM = $D20A ;53770 (R) (no shadow)
+POTGO = $D20B ;53771 (W) (latch)
+; $D20C (53772) is unused
+SEROUT = $D20D ;53773 (W) (no shadow)
+SERIN = $D20D ;53773 (R) (no shadow)
+IRQEN = $D20E ;53774 (W) (shadow @ POKMSK)
+IRQST = $D20E ;53774 (R)
+SKCTL = $D20F ;53775 (W) (shadow @ SSKCTL)
+SKSTAT = $D20F ;53775 (R)
+
+; $D210 - $D2FF are mirrors of POKEY address space. The "stereo POKEY"
+; modification adds a second POKEY chip, usually addressed at $D210.
+
+; PIA
+; No shadow regs for PIA regs
+PIA = $D300
+PORTA = $D300 ;54016
+PORTB = $D301 ;54017
+PACTL = $D302 ;54018
+PBCTL = $D303 ;54019
+
+; $D304 - $D3FF are mirrors of PIA address space
+
+; ANTIC
+ANTIC = $D400
+DMACTL = $D400 ;54272 (W) (shadow @ SDMCTL)
+CHACTL = $D401 ;54273 (W) (shadow @ CHACT)
+DLISTL = $D402 ;54274 (W) (shadow @ SDLSTL)
+DLISTH = $D403 ;54275 (W) (shadow @ SDLSTH)
+HSCROL = $D404 ;54276 (W) (no shadow)
+VSCROL = $D405 ;54277 (W) (no shadow)
+; $D406 (54278) is unused
+PMBASE = $D407 ;54279 (W) (no shadow)
+; $D408 (54280) is unused
+CHBASE = $D409 ;54281 (W) (shadow @ CHBAS)
+WSYNC = $D40A ;54282 (W), latch (data written doesn't matter)
+VCOUNT = $D40B ;54283 (R) (no shadow)
+PENH = $D40C ;54284 (R) (shadow @ LPENH)
+PENV = $D40D ;54285 (R) (shadow @ LPENV)
+NMIEN = $D40E ;54286 (W) (no shadow)
+NMIRES = $D40F ;54287 (W), latch?
+NMIST = $D40F ;54287 (R) (no shadow)
+
+; $D410 - $D4FF are mirrors of ANTIC address space
+
+CCNTL = $D500 ;54528 Cartridge control (sometimes used for bankswitching)
+; $D500 - $D5FF is supposed to be all be mapped to CCNTL
+
+; $D600 - $D7FF is unmapped? used by PBI on XL? seems to read all $FF
+
+;
+; FLOATING POINT MATH ROUTINES
+;
+; From Mapping:
+; These entry points are the same on 400/800 and XL OS, though the
+; routines themselves are different (bugfixed/optimized for XL)
+; Also, on the XL, the $D800 area is bankswitched to PBI device ROM,
+; during PBI I/O. Not sure if all of $D800 - $DFFF is switched out
+; or just part of it.
+AFP = $D800 ;55296 ASCII to Floating Point (FP) conversion.
+FASC = $D8E6 ;55526 FP value to ASCII conversion.
+IFP = $D9AA ;55722 Integer to FP conversion
+FPI = $D9D2 ;55762 FP to Integer conversion
+ZFR0 = $DA44 ;55876 Clear FR0 (set all bytes to 0)
+ZF1 = $DA46 ;55878 Clear FR1 (set all bytes to 0) (aka AF1 (De Re))
+FSUB = $DA60 ;55904 FP subtract: FR0 = FR0 - FR1
+FADD = $DA66 ;55910 FP add: FR0 = FR0 + FR1
+FMUL = $DADB ;56027 FP multiply: FR0 = FR0 * FR1
+FDIV = $DB28 ;56104 FP divide: FR0 = FR0 / FR1
+PLYEVL = $DD40 ;56640 FP polynomial evaluation
+FLD0R = $DD89 ;56713 Load FP number into FR0 from 6502 X/Y registers
+FLD0P = $DD8D ;56717 Load FP number into FR0 from FLPTR
+FLD1R = $DD98 ;56728 Load FP number into FR1 from 6502 X/Y registers
+FLD1P = $DD9C ;56732 Load FP number into FR1 from FLPTR
+FST0R = $DDA7 ;56743 Store FP number into 6502 X/Y regs from FR0
+FST0P = $DDAB ;56747 Store FP number from FR0, using FLPTR
+FMOVE = $DDB6 ;56758 Move FP number from FR0 into FR1 (FR1 = FR0)
+EXP = $DDC0 ;56768 FP base e exponentiation
+EXP10 = $DDCC ;56780 FP base 10 exponentiation
+LOG = $DECD ;57037 FP natural logarithm
+LOG10 = $DED1 ;57041 FP base 10 logarithm
+
+;
+;
+; OPERATING SYSTEM
+;
+;
+; MODULE ORIGIN TABLE
+;
+CHORG = $E000 ;57344 CHARACTER SET, 1K
+VECTBL = $E400 ;58368 VECTOR TABLE
+VCTABL = $E480 ;58496 RAM VECTOR INITIAL VALUE TABLE
+CIOORG = $E4A6 ;58534 CIO HANDLER
+INTORG = $E6D5 ;59093 INTERRUPT HANDLER
+SIOORG = $E944 ;59716 SIO DRIVER
+DSKORT = $EDEA ;60906 DISK HANDLER
+PRNORG = $EE78 ;61048 PRINTER HANDLER
+CASORG = $EE78 ;61048 CASSETTE HANDLER
+MONORG = $F0E3 ;61667 MONITOR/POWER UP MODULE
+KBDORG = $F3E4 ;62436 KEYBOARD/DISPLAY HANDLER
+;
+;
+; VECTOR TABLE, CONTAINS ADDRESSES OF CIO ROUTINES IN THE
+; FOLLOWING ORDER. THE ADDRESSES IN THE TABLE ARE TRUE ADDRESSES-1
+;
+; ADDRESS + 0 OPEN
+; + 2 CLOSE
+; + 4 GET
+; + 6 PUT
+; + 8 STATUS
+; + A SPECIAL
+; + C JMP TO INITIALIZATION
+; + F NOT USED
+;
+;
+
+; 20070529 bkw: why are they address minus one? because they are called
+; via RTS: a JSR actually pushes the return address minus one, and RTS
+; increments the address on the stack after popping it. The Atari OS
+; "pretends" to have done a JSR by pushing the address-1 on the stack,
+; then executes RTS, which "returns" to the correct address.
+
+EDITRV = $E400 ;58368 EDITOR
+SCRENV = $E410 ;58384 SCREEN
+KEYBDV = $E420 ;58400 KEYBOARD
+PRINTV = $E430 ;58416 PRINTER
+CASETV = $E440 ;58432 CASSETTE
+;
+; ROM VECTORS
+;
+; 20070529 bkw: These consist of a JMP xxxx instruction in the ROM.
+DSKINV = $E453 ;58451
+CIOV = $E456 ;58454 ; Main CIO entry point!
+SIOV = $E459 ;58457 ; Main SIO entry point!
+SETVBV = $E45C ;58460
+SYSVBV = $E45F ;58463
+VBIVAL = $E460 ;58464 ADR AT VVBLKI (operand of JMP @ $E45F)
+XITVBV = $E462 ;58466 EXIT VBI
+VBIXVL = $E463 ;58467 ADR AT VVBLKD (operand of JMP @ $E462)
+SIOINV = $E465 ;58469
+SENDEV = $E468 ;58472
+INTINV = $E46B ;58475
+CIOINV = $E46E ;58478
+BLKBDV = $E471 ;58481 MEMO PAD MODE (self-test in XL)
+WARMSV = $E474 ;58484 ; warmstart (RESET key jumps here)
+COLDSV = $E477 ;58487 ; coldstart (reboot) the Atari
+RBLOKV = $E47A ;58490
+CSOPIV = $E47D ;58493
+
+; SYSEQU.ASM defines this:
+CIO = CIOV
+
+; XL-only entry points:
+XL_SELFSV = BLKBDV ; self-test (same entry point as 800 memo pad)
+XL_SELFTST = BLKBDV ; alt. name (Mapping)
+XL_PUPDIV = $E480 ;58496 (XL) Power-up ATARI logo (1200XL only), or self-test
+XL_SLFTSV = $E483 ;58499 (XL) Self-test vector (points to $5000)
+XL_PENTV = $E486 ;58502 (XL) Entry to the handler uploaded from peripheral
+ ; or disk (is this for the PBI?)
+XL_PHUNLV = $E489 ;58505 (XL) Entry to uploaded handler unlink (PBI?)
+XL_PHINIV = $E48C ;58508 (XL) Entry to uploaded handler init (PBI?)
+XL_GPDVV = $E48F ;58511 (XL) General-purpose parallel device handler
+ ; (copy to HATABS to use)
+
+;;;;; Here endeth the list of official mnemonics
+
+; Mapping has this to say about the XL ROMs:
+;Byte Use
+;65518/FFEE Revision date D1 and D2 (four-bit BCD)
+;65519/FFEF Revision date M1 and M2
+;65520/FFF0 Revision date Y1 and Y2
+;65521/FFF1 Option byte; should read 1 for the
+; 1200XL (Mapping author's 800XL reads 2)
+;65522-26/FFF2-6 Part number in the form AANNNNNN
+;65527/FFF7 Revision number (again, mine reads 2)
+;65528-9/FFF8-9 Checksum, bytes (LSB/MSB)
+; There don't seem to be any known mnemonics for the above...
+
+; 20061120 bkw: display list stuff. These are not official Atari mnemonics,
+; but they *are* somewhat based on the "Checkers Demo" by Carol Shaw,
+; in the Atari Hardware Manual (she didn't define all these, and she didn't
+; use the "DL_" prefix, probably because her assembler was limited to
+; 6-character labels and/or didn't support the underscore).
+
+; blank lines, 1-8 scanlines high
+DL_BLANK1 = $00
+DL_BLANK2 = $10
+DL_BLANK3 = $20
+DL_BLANK4 = $30
+DL_BLANK5 = $40
+DL_BLANK6 = $50
+DL_BLANK7 = $60
+DL_BLANK8 = $70
+
+; modifier bits..
+DL_VSCROLL = $10
+DL_HSCROLL = $20
+DL_LMS = $40
+DL_DLI = $80
+
+; graphics modes (these are the BASIC modes)
+; If you're more familiar with the ANTIC modes, nobody's forcing you
+; to use these :)
+DL_GR0 = $02
+DL_GR1 = $06
+DL_GR2 = $07
+DL_GR3 = $08
+DL_GR4 = $09
+DL_GR5 = $0A
+DL_GR6 = $0B
+DL_GR7 = $0D
+DL_GR8 = $0F
+DL_GR12 = $04 ; GR. 12-15 only supported by GRAPHICS command on XL/XE,
+DL_GR13 = $05 ; but they exist on all ANTIC revisions
+DL_GR14 = $0C
+DL_GR15 = $0E ; AKA "graphics 7.5"
+; No GRAPHICS mode for ANTIC $03 (true descender) mode
+
+; jump instructions
+DL_JMP = $01 ; jump without vertical blank (used to skip over 1K boundary)
+DL_JVB = $41 ; jump & wait for VBLANK (end of display list)
+
+; How to use the above: here's a sample display list for GR.0, with a DLI
+; on screen line 10.
+
+; dlist:
+; ; 4*8 = 32 blank lines at start of display
+; byte DL_BLANK8, DL_BLANK8, DL_BLANK8, DL_BLANK8
+;
+; byte DL_GR0 | DL_LMS ; display GR.0 line, and load screen memory address..
+; word screen_ram ; ...from our screen memory (declared elsewhere)
+;
+; ; 8 more GR.0 lines
+; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0
+;
+; byte DL_GR0 | DL_DLI ; another GR.0 line, with the DLI bit enabled
+;
+; ; lines 11-24 (14 more GR.0 bytes)
+; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0
+; byte DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0, DL_GR0
+;
+; ; that's 24 lines, so finish with a VBLANK
+; byte DL_JVB ; jump (and wait), to...
+; word dlist ; ...the beginning.
diff --git a/jumpmanjr.cart b/jumpmanjr.cart
new file mode 100644
index 0000000..218dbe3
--- /dev/null
+++ b/jumpmanjr.cart
Binary files differ
diff --git a/jumpmanjr.dasm b/jumpmanjr.dasm
new file mode 100644
index 0000000..b856ad9
--- /dev/null
+++ b/jumpmanjr.dasm
@@ -0,0 +1,7360 @@
+; da65 V2.15 - Git 104f898
+; Created: 2016-08-29 14:55:43
+; Input file: jumpmanjr.rom
+; Page: 1
+
+
+ .setcpu "6502"
+
+; ----------------------------------------------------------------------------
+L0000 := $0000
+dm_ypos := $0054 ; see draw_map and level_maps.txt
+dm_xpos := $0055 ; see draw_map and level_maps.txt
+SAVMSC := $0058 ; OS's idea of the start of screen memory [redundant to set here?]
+dm_count := $00BE ; graphics object definition is this long
+dm_length := $00BF ; see draw_map and level_maps.txt
+dm_progctr := $00C0 ; see draw_map and level_maps.txt
+dm_objptr := $00C2 ; see draw_map and level_maps.txt
+dm_screen_addr := $00C4 ; points to byte to write gfx data to
+dm_x_with_offset:= $00C6 ; graphics object X offset, plus dm_xpos
+dm_y_with_offset:= $00C7 ; graphics object Y offset, plus dm_xpos
+dm_delta_x := $00C9 ; see draw_map and level_maps.txt
+dm_delta_y := $00CA ; see draw_map and level_maps.txt
+zp_temp1 := $00CB ; used for (zp,y) addressing, also for checking console keys in vblank_imm_isr
+FR1 := $00E0
+VDSLST := $0200
+VKEYBD := $0208
+VKEYBD_hi := $0209
+SDMCTL := $022F
+GPRIOR := $026F
+PCOLR0 := $02C0
+PCOLR1 := $02C1
+PCOLR2 := $02C2
+PCOLR3 := $02C3
+COLOR0 := $02C4
+COLOR1 := $02C5
+COLOR2 := $02C6
+COLOR3 := $02C7
+COLOR4 := $02C8
+CHBAS := $02F4
+jiffy_timer_1 := $061A ; gets incremented every frame
+jiffy_timer_2 := $061B ; gets incremented every frame
+speed_jiffy_timer:= $061E ; counts 0..initial_speed
+player_speed := $0624
+initial_speed := $0625
+bonus_jiffy_timer:= $0626 ; gets incremented every frame when playing a level, bonus-=100 when this reaches 0
+playing_level := $0627 ; 0 = not playing, non-0 = playing
+sfx_lock := $062F ; lets other code know cue_sfx is still running? not 100% sure
+player_delta_x := $0630 ; amount to move jumpman this frame (1 or $FF aka -1)
+player_delta_y := $0631 ; amount to move jumpman this frame (1 or $FF aka -1)
+joystick_disabled:= $0632 ; nonzero = jumpman can't move (title screen or materialization, etc)
+joystick_state := $0633 ; last PORTA read (bottom 4 bits), or 0 if joystick_disabled
+trigger_disabled:= $0634 ; nonzero = jumpman can't jump (he's already jumping, or title screen or materialization, etc)
+trigger_state := $0635 ; last TRIG0 read (0 = pressed)
+sfx_ptr := $063C
+sfx_slot_tempo := $063E ; tempo of this sfx
+sfx_slot_timer := $063F
+sfx_slot_duration:= $0646
+sfx_slot_freq := $0647
+sfx_slot_curpos := $064E ; address we've got to so far, playing this sfx
+sfx_tempo_tmp := $0661 ; ??
+dlist_shadow_lo := $06AC ; stored in DLISTL if dlist_shadow_hi nonzero
+dlist_shadow_hi := $06AD ; stored in DLISTH if nonzero
+dli_vec_shadow_lo:= $06AE ; stored in VDSLST if dli_vec_shadow_hi nonzero
+dli_vec_shadow_hi:= $06AF ; stored in VDSLST if nonzero
+collision_save := $06B0 ; save_collisions copies GTIA collision regs $D000-$d00f here
+option_key_vec := $06C0 ; vblank_imm_isr jumps thru here if option key pressed
+select_key_vec := $06C2 ; vblank_imm_isr jumps thru here if select key pressed
+start_key_vec := $06C4 ; vblank_imm_isr jumps thru here if start key pressed
+option_key_enabled:= $06C6 ; non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)
+select_key_enabled:= $06C7 ; non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)
+start_key_enabled:= $06C8 ; non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)
+L06DF := $06DF
+L06E0 := $06E0
+L06E3 := $06E3
+L06E6 := $06E6
+randomizer_mode := $06F3 ; only after beating levels 1-12 in order
+number_of_players:= $06F4 ; 0 for single-player game, otherwise range 1-3 (2 to 4 players)
+level := $06F6
+speed_value := $06F9 ; decoded speed (1-8)
+current_player := $06FE ; *think* this ranges 1-4, not 0-3
+score := $0700
+lives := $070A
+work_level_desc := $0780 ; first 2 bytes are level number in screencodes
+work_level_sub0 := $0782 ; a subroutine
+work_level_sub1 := $0784 ; a subroutine
+work_level_sub2 := $0786 ; a subroutine
+work_level_sub3 := $0788 ; a subroutine
+work_level_num_bombs:= $078A ; number of bombs to pick up on this level
+work_level_bullet_chance:= $078B ; 0 = no bullets
+work_level_y_start:= $078C ; jumpman starting Y position
+work_level_x_start:= $078D ; jumpman starting X position
+work_level_offs_14:= $078E ; points to $0600
+work_level_points_per_bomb:= $0790 ; points awarded per bomb pickup (always $64 aka 100)
+work_level_time_bonus:= $0791 ; amount of time bonus at start of level
+work_level_offs_19:= $0793 ; always $00
+work_level_unkn_table0:= $0794 ; pointer to ROM table or $06xx
+work_level_map0 := $0796 ; map data
+work_level_map1 := $0798 ; map data
+work_level_map2 := $079A ; map data
+work_level_unkn_table1:= $079C ; unknown, pointer to a ROM table or $0000
+work_level_offs_30:= $079E ; always $0000
+work_level_sub4 := $07A0 ; $06E6 for most levels, or else a ROM subroutine
+work_level_sub5 := $07A2 ; $06E6 for some levels, or else a ROM subroutine
+work_level_sub6 := $07A4 ; always $9740 aka game_main_loop
+work_level_sub_eol:= $07A6 ; called at end of level (all bombs picked up). $06E6 for all but level07
+work_level_offs_40:= $07A8 ; all zeroes
+work_level_offs_46:= $07AE ; unknown
+work_level_offs_55:= $07B7 ; unknown, always $00 $00 $00
+work_level_offs_58:= $07BA ; unknown, not a ROM address
+work_level_offs_60:= $07BC ; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+cur_level_desc := $07C0 ; first 2 bytes are level number in screencodes
+cur_level_sub0 := $07C2 ; a subroutine
+cur_level_sub1 := $07C4 ; a subroutine
+cur_level_sub2 := $07C6 ; a subroutine
+cur_level_sub3 := $07C8 ; a subroutine
+cur_level_num_bombs:= $07CA ; number of bombs to pick up on this level
+cur_level_bullet_chance:= $07CB ; 0 = no bullets
+cur_level_y_start:= $07CC ; jumpman starting Y position
+cur_level_x_start:= $07CD ; jumpman starting X position
+cur_level_offs_14:= $07CE ; points to $0600
+cur_level_points_per_bomb:= $07D0 ; points awarded per bomb pickup (always $64 aka 100)
+cur_level_time_bonus:= $07D1 ; amount of time bonus at start of level
+cur_level_offs_19:= $07D3 ; always $00
+cur_level_unkn_table0:= $07D4 ; pointer to ROM table or $06xx
+cur_level_map0 := $07D6 ; map data
+cur_level_map1 := $07D8 ; map data
+cur_level_map2 := $07DA ; map data
+cur_level_unkn_table1:= $07DC ; unknown, pointer to a ROM table or $0000
+cur_level_offs_30:= $07DE ; always $0000
+cur_level_sub4 := $07E0 ; $06E6 for most levels, or else a ROM subroutine
+cur_level_sub5 := $07E2 ; $06E6 for some levels, or else a ROM subroutine
+cur_level_sub6 := $07E4 ; always $9740 aka game_main_loop
+cur_level_sub_eol:= $07E6 ; called at end of level (all bombs picked up). $06E6 for all but level07
+cur_level_offs_40:= $07E8 ; all zeroes
+cur_level_offs_46:= $07EE ; unknown
+cur_level_offs_55:= $07F7 ; unknown, always $00 $00 $00
+cur_level_offs_58:= $07FA ; unknown, not a ROM address
+cur_level_offs_60:= $07FC ; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+L0830 := $0830
+game_display_list:= $0881 ; display list for game board
+pm_memory := $2800
+HPOSP0_minus_two:= $CFFE
+HPOSP3 := $D003
+HPOSM0 := $D004
+HPOSM1 := $D005
+HPOSM2 := $D006
+HPOSM3 := $D007
+SIZEP2 := $D00A
+SIZEP3 := $D00B
+SIZEM := $D00C
+TRIG0 := $D010
+GRAFM := $D011
+COLPM0 := $D012
+COLPM1 := $D013
+COLPF0 := $D016
+COLPF1 := $D017
+COLPF2 := $D018
+COLPF3 := $D019
+COLBK := $D01A
+PRIOR := $D01B
+GRACTL := $D01D
+HITCLR := $D01E
+CONSOL := $D01F
+AUDF1_minus_two := $D1FE
+AUDF1_minus_one := $D1FF
+AUDF1 := $D200
+AUDC1 := $D201
+AUDF2 := $D202
+AUDC2 := $D203
+AUDF3 := $D204
+AUDC3 := $D205
+AUDF4 := $D206
+AUDC4 := $D207
+AUDCTL := $D208
+KBCODE := $D209
+RANDOM := $D20A
+IRQEN := $D20E
+SKCTL := $D20F
+PORTA := $D300
+DMACTL := $D400
+DLISTL := $D402
+DLISTH := $D403
+HSCROL := $D404
+PMBASE := $D407
+CHBASE := $D409
+WSYNC := $D40A
+NMIEN := $D40E
+SETVBV := $E45C
+XITVBV := $E462
+; ----------------------------------------------------------------------------
+; the entry point for parsing the level map and drawing graphics from it. see level_maps.txt.
+draw_map_jv:
+ jmp draw_map ; 8000 4C 49 80 LI.
+
+; ----------------------------------------------------------------------------
+L8003: jmp cue_sfx_lowprior ; 8003 4C 40 82 L@.
+
+; ----------------------------------------------------------------------------
+; setup to play sfx
+cue_sfx_jv:
+ jmp cue_sfx ; 8006 4C 55 82 LU.
+
+; ----------------------------------------------------------------------------
+; gets called after the level is drawn & the intro music stops, and also during the level (?)
+xxx_level_something_jv:
+ jmp xxx_level_something ; 8009 4C 00 86 L..
+
+; ----------------------------------------------------------------------------
+L800C: jmp L8CBC ; 800C 4C BC 8C L..
+
+; ----------------------------------------------------------------------------
+L800F: jmp L867E ; 800F 4C 7E 86 L~.
+
+; ----------------------------------------------------------------------------
+; bottom 2 GR.1 lines on the game board
+update_status_window_jv:
+ jmp update_status_window ; 8012 4C 94 86 L..
+
+; ----------------------------------------------------------------------------
+; for some reason there are 2 copies of the display list, at $0800 and $0881
+setup_gameboard_dlist_jv:
+ jmp setup_gameboard_dlist ; 8015 4C 00 9B L..
+
+; ----------------------------------------------------------------------------
+; setup to play whichever music is in A reg, using 5-byte sfx stuct
+cue_music_jv:
+ jmp cue_music ; 8018 4C 92 8F L..
+
+; ----------------------------------------------------------------------------
+; called after level-intro music is finished playing
+enable_joystick_jv:
+ jmp enable_joystick ; 801B 4C 75 87 Lu.
+
+; ----------------------------------------------------------------------------
+; clear the gameboard screen memory (called before drawing a level, natch)
+clear_screen_mem_jv:
+ jmp clear_screen_mem ; 801E 4C 14 87 L..
+
+; ----------------------------------------------------------------------------
+; bonus -= 100;
+decrement_time_bonus_jv:
+ jmp decrement_time_bonus ; 8021 4C CE 8D L..
+
+; ----------------------------------------------------------------------------
+init_page_7_jv:
+ jmp init_page_7 ; 8024 4C 5C 9A L\.
+
+; ----------------------------------------------------------------------------
+L8027: jmp L9AAA ; 8027 4C AA 9A L..
+
+; ----------------------------------------------------------------------------
+L802A: jmp LBA00 ; 802A 4C 00 BA L..
+
+; ----------------------------------------------------------------------------
+level_finished_jv:
+ jmp level_finished ; 802D 4C 00 8E L..
+
+; ----------------------------------------------------------------------------
+; just lost your last life
+crumble_gameboard_jv:
+ jmp crumble_gameboard ; 8030 4C 00 8D L..
+
+; ----------------------------------------------------------------------------
+L8033: jmp L87A0 ; 8033 4C A0 87 L..
+
+; ----------------------------------------------------------------------------
+L8036: jmp L8B23 ; 8036 4C 23 8B L#.
+
+; ----------------------------------------------------------------------------
+ jmp L8B2D ; 8039 4C 2D 8B L-.
+
+; ----------------------------------------------------------------------------
+L803C: jmp L8AE0 ; 803C 4C E0 8A L..
+
+; ----------------------------------------------------------------------------
+; 3 unused jump vectors, all pointed to the same RTS
+unused_vecs:
+ jmp unused_vec_rts ; 803F 4C 48 80 LH.
+
+; ----------------------------------------------------------------------------
+ jmp unused_vec_rts ; 8042 4C 48 80 LH.
+
+; ----------------------------------------------------------------------------
+ jmp unused_vec_rts ; 8045 4C 48 80 LH.
+
+; ----------------------------------------------------------------------------
+; unused jump vectors point here
+unused_vec_rts:
+ rts ; 8048 60 `
+
+; ----------------------------------------------------------------------------
+; the entry point for parsing the level map and drawing graphics from it. see level_maps.txt. caller must set $C0/$C1 to the address of the map data. modders beware: bogus map data can & will cause infinite loops.
+draw_map:
+ ldy #$00 ; 8049 A0 00 ..
+; $C0/$C1 points to $A300 (level00_desc) on the first call
+dm_get_opcode:
+ lda (dm_progctr),y ; 804B B1 C0 ..
+; map opcodes: $FC = jump, $FF = end, $FD = set drawing direction, $FE = select graphics object
+dm_switch_opcode:
+ cmp #$FC ; 804D C9 FC ..
+ bcc dm_draw_gfx ; 804F 90 3F .?
+ beq dm_jump ; 8051 F0 09 ..
+ cmp #$FD ; 8053 C9 FD ..
+ beq dm_delta ; 8055 F0 14 ..
+ cmp #$FE ; 8057 C9 FE ..
+ beq dm_obj ; 8059 F0 28 .(
+; handle gfx_end opcode
+dm_fallthru:
+ rts ; 805B 60 `
+
+; ----------------------------------------------------------------------------
+; handle gfx_jump opcode
+dm_jump:iny ; 805C C8 .
+ lda (dm_progctr),y ; 805D B1 C0 ..
+ pha ; 805F 48 H
+ iny ; 8060 C8 .
+ lda (dm_progctr),y ; 8061 B1 C0 ..
+ sta dm_progctr+1 ; 8063 85 C1 ..
+ pla ; 8065 68 h
+ sta dm_progctr ; 8066 85 C0 ..
+ jmp draw_map ; 8068 4C 49 80 LI.
+
+; ----------------------------------------------------------------------------
+; handle gfx_delta opcode
+dm_delta:
+ iny ; 806B C8 .
+ lda (dm_progctr),y ; 806C B1 C0 ..
+ sta dm_delta_x ; 806E 85 C9 ..
+ iny ; 8070 C8 .
+ lda (dm_progctr),y ; 8071 B1 C0 ..
+ sta dm_delta_y ; 8073 85 CA ..
+; all the other opcode handlers jump here
+dm_next_opcode:
+ lda dm_progctr ; 8075 A5 C0 ..
+ clc ; 8077 18 .
+ adc #$03 ; 8078 69 03 i.
+ sta dm_progctr ; 807A 85 C0 ..
+ bcc draw_map ; 807C 90 CB ..
+ inc dm_progctr+1 ; 807E E6 C1 ..
+ jmp draw_map ; 8080 4C 49 80 LI.
+
+; ----------------------------------------------------------------------------
+; handle gfx_object opcode
+dm_obj: iny ; 8083 C8 .
+ lda (dm_progctr),y ; 8084 B1 C0 ..
+ sta dm_objptr ; 8086 85 C2 ..
+ iny ; 8088 C8 .
+ lda (dm_progctr),y ; 8089 B1 C0 ..
+ sta dm_objptr+1 ; 808B 85 C3 ..
+ jmp dm_next_opcode ; 808D 4C 75 80 Lu.
+
+; ----------------------------------------------------------------------------
+; handle gfx_draw opcode
+dm_draw_gfx:
+ sta dm_xpos ; 8090 85 55 .U
+ iny ; 8092 C8 .
+ lda (dm_progctr),y ; 8093 B1 C0 ..
+ sta dm_ypos ; 8095 85 54 .T
+ iny ; 8097 C8 .
+ lda (dm_progctr),y ; 8098 B1 C0 ..
+ sta dm_length ; 809A 85 BF ..
+; loop 'dm_length' times
+dm_draw_loop:
+ jsr dm_draw_obj ; 809C 20 B4 80 ..
+ dec dm_length ; 809F C6 BF ..
+ beq dm_next_opcode ; 80A1 F0 D2 ..
+ lda dm_delta_x ; 80A3 A5 C9 ..
+ clc ; 80A5 18 .
+ adc dm_xpos ; 80A6 65 55 eU
+ sta dm_xpos ; 80A8 85 55 .U
+ lda dm_delta_y ; 80AA A5 CA ..
+ clc ; 80AC 18 .
+ adc dm_ypos ; 80AD 65 54 eT
+ sta dm_ypos ; 80AF 85 54 .T
+ jmp dm_draw_loop ; 80B1 4C 9C 80 L..
+
+; ----------------------------------------------------------------------------
+; draw current object at current x/y position
+dm_draw_obj:
+ ldy #$00 ; 80B4 A0 00 ..
+; object definition ends with $FF
+dm_draw_obj_loop:
+ lda (dm_objptr),y ; 80B6 B1 C2 ..
+ cmp #$FF ; 80B8 C9 FF ..
+ bne dm_obj_to_screen ; 80BA D0 01 ..
+ rts ; 80BC 60 `
+
+; ----------------------------------------------------------------------------
+; actually write the object's pixels to screen memory. quite hairy.
+dm_obj_to_screen:
+ sta dm_count ; 80BD 85 BE ..
+ iny ; 80BF C8 .
+ clc ; 80C0 18 .
+ lda (dm_objptr),y ; 80C1 B1 C2 ..
+ adc dm_xpos ; 80C3 65 55 eU
+ sta dm_x_with_offset ; 80C5 85 C6 ..
+ iny ; 80C7 C8 .
+ clc ; 80C8 18 .
+ lda (dm_objptr),y ; 80C9 B1 C2 ..
+ adc dm_ypos ; 80CB 65 54 eT
+ sta dm_y_with_offset ; 80CD 85 C7 ..
+ iny ; 80CF C8 .
+; calculate 40 * dm_y_with_offset + dm_x_with_offset + screen mem address, store in dm_screen_addr
+calc_screen_addr:
+ lda #$28 ; 80D0 A9 28 .(
+ sta $BD ; 80D2 85 BD ..
+ lda #$00 ; 80D4 A9 00 ..
+ sta dm_screen_addr ; 80D6 85 C4 ..
+ ldx #$08 ; 80D8 A2 08 ..
+L80DA: lsr $BD ; 80DA 46 BD F.
+ bcc L80E1 ; 80DC 90 03 ..
+ clc ; 80DE 18 .
+ adc dm_y_with_offset ; 80DF 65 C7 e.
+L80E1: ror a ; 80E1 6A j
+ ror dm_screen_addr ; 80E2 66 C4 f.
+ dex ; 80E4 CA .
+ bne L80DA ; 80E5 D0 F3 ..
+ clc ; 80E7 18 .
+ adc SAVMSC+1 ; 80E8 65 59 eY
+ sta dm_screen_addr+1 ; 80EA 85 C5 ..
+ lda dm_x_with_offset ; 80EC A5 C6 ..
+ lsr a ; 80EE 4A J
+ ror $C8 ; 80EF 66 C8 f.
+ lsr a ; 80F1 4A J
+ ror $C8 ; 80F2 66 C8 f.
+ clc ; 80F4 18 .
+ adc dm_screen_addr ; 80F5 65 C4 e.
+ sta dm_screen_addr ; 80F7 85 C4 ..
+ bcc L80FD ; 80F9 90 02 ..
+ inc dm_screen_addr+1 ; 80FB E6 C5 ..
+L80FD: asl $C8 ; 80FD 06 C8 ..
+ rol a ; 80FF 2A *
+ asl $C8 ; 8100 06 C8 ..
+ rol a ; 8102 2A *
+ and #$03 ; 8103 29 03 ).
+ sta $C8 ; 8105 85 C8 ..
+L8107: lda (dm_objptr),y ; 8107 B1 C2 ..
+ sta $BD ; 8109 85 BD ..
+ lda $C8 ; 810B A5 C8 ..
+ lsr $BD ; 810D 46 BD F.
+ rol a ; 810F 2A *
+ lsr $BD ; 8110 46 BD F.
+ rol a ; 8112 2A *
+ sta $BD ; 8113 85 BD ..
+ iny ; 8115 C8 .
+ tya ; 8116 98 .
+ pha ; 8117 48 H
+ ldy #$00 ; 8118 A0 00 ..
+ ldx $C8 ; 811A A6 C8 ..
+ lda (dm_screen_addr),y ; 811C B1 C4 ..
+ and gr7_and_masks,x ; 811E 3D 53 81 =S.
+ ldx $BD ; 8121 A6 BD ..
+ ora gr7_or_masks,x ; 8123 1D 43 81 .C.
+ sta (dm_screen_addr),y ; 8126 91 C4 ..
+ pla ; 8128 68 h
+ tay ; 8129 A8 .
+ inc $C8 ; 812A E6 C8 ..
+ lda $C8 ; 812C A5 C8 ..
+ cmp #$04 ; 812E C9 04 ..
+ bcc L813C ; 8130 90 0A ..
+ lda #$00 ; 8132 A9 00 ..
+ sta $C8 ; 8134 85 C8 ..
+ inc dm_screen_addr ; 8136 E6 C4 ..
+ bne L813C ; 8138 D0 02 ..
+ inc dm_screen_addr+1 ; 813A E6 C5 ..
+L813C: dec dm_count ; 813C C6 BE ..
+ bne L8107 ; 813E D0 C7 ..
+ jmp dm_draw_obj_loop ; 8140 4C B6 80 L..
+
+; ----------------------------------------------------------------------------
+gr7_or_masks:
+ .byte $00,$80,$40,$C0,$00,$20,$10,$30 ; 8143 00 80 40 C0 00 20 10 30 ..@.. .0
+ .byte $00,$08,$04,$0C,$00,$02,$01,$03 ; 814B 00 08 04 0C 00 02 01 03 ........
+gr7_and_masks:
+ .byte $3F,$CF,$F3,$FC ; 8153 3F CF F3 FC ?...
+; ----------------------------------------------------------------------------
+; we have 4 slots (because POKEY has 4 voices), X counts down by 2 from 10 to 2 (at 0, the loop exits)
+sfx_player_entry:
+ ldx #$0A ; 8157 A2 0A ..
+ lda sfx_lock ; 8159 AD 2F 06 ./.
+ beq next_sfx_slot ; 815C F0 01 ..
+sfx_exit:
+ rts ; 815E 60 `
+
+; ----------------------------------------------------------------------------
+next_sfx_slot:
+ dex ; 815F CA .
+ dex ; 8160 CA .
+ beq sfx_exit ; 8161 F0 FB ..
+; skip it, if slot is inactive
+is_slot_active:
+ lda sfx_slot_tempo,x ; 8163 BD 3E 06 .>.
+ beq next_sfx_slot ; 8166 F0 F7 ..
+L8168: lda sfx_slot_timer,x ; 8168 BD 3F 06 .?.
+ beq sfx_next_note ; 816B F0 10 ..
+ dec sfx_slot_timer,x ; 816D DE 3F 06 .?.
+ cmp sfx_slot_duration,x ; 8170 DD 46 06 .F.
+ bne next_sfx_slot ; 8173 D0 EA ..
+ lda #$00 ; 8175 A9 00 ..
+ sta AUDF1_minus_one,x ; 8177 9D FF D1 ...
+ jmp next_sfx_slot ; 817A 4C 5F 81 L_.
+
+; ----------------------------------------------------------------------------
+sfx_next_note:
+ lda sfx_slot_curpos,x ; 817D BD 4E 06 .N.
+ sta zp_temp1 ; 8180 85 CB ..
+ lda sfx_slot_curpos+1,x ; 8182 BD 4F 06 .O.
+ sta zp_temp1+1 ; 8185 85 CC ..
+ ldy #$00 ; 8187 A0 00 ..
+ lda (zp_temp1),y ; 8189 B1 CB ..
+ cmp #$04 ; 818B C9 04 ..
+ bcs sfx_play_note ; 818D B0 77 .w
+ cmp #$01 ; 818F C9 01 ..
+ beq sfx_change_tempo ; 8191 F0 1B ..
+ cmp #$02 ; 8193 C9 02 ..
+ beq sfx_jump ; 8195 F0 31 .1
+ cmp #$03 ; 8197 C9 03 ..
+ beq sfx_play_rest ; 8199 F0 03 ..
+ jmp sfx_finished ; 819B 4C 26 82 L&.
+
+; ----------------------------------------------------------------------------
+; y==0 on entry
+sfx_play_rest:
+ tya ; 819E 98 .
+ sta AUDF1_minus_one,x ; 819F 9D FF D1 ...
+ iny ; 81A2 C8 .
+ lda (zp_temp1),y ; 81A3 B1 CB ..
+ sta sfx_slot_timer,x ; 81A5 9D 3F 06 .?.
+ jsr inc_sfx_pos ; 81A8 20 31 82 1.
+ jmp L8168 ; 81AB 4C 68 81 Lh.
+
+; ----------------------------------------------------------------------------
+; y==0 on entry
+sfx_change_tempo:
+ iny ; 81AE C8 .
+ lda (zp_temp1),y ; 81AF B1 CB ..
+ sta sfx_slot_freq,x ; 81B1 9D 47 06 .G.
+ iny ; 81B4 C8 .
+ lda (zp_temp1),y ; 81B5 B1 CB ..
+ sta sfx_slot_duration,x ; 81B7 9D 46 06 .F.
+ jsr inc_sfx_pos ; 81BA 20 31 82 1.
+ inc sfx_slot_curpos,x ; 81BD FE 4E 06 .N.
+ bne L8168 ; 81C0 D0 A6 ..
+ inc sfx_slot_curpos+1,x ; 81C2 FE 4F 06 .O.
+ jmp L8168 ; 81C5 4C 68 81 Lh.
+
+; ----------------------------------------------------------------------------
+; I *think* this jumps to a different sfx address...
+sfx_jump:
+ iny ; 81C8 C8 .
+ lda (zp_temp1),y ; 81C9 B1 CB ..
+ sta sfx_slot_curpos,x ; 81CB 9D 4E 06 .N.
+ iny ; 81CE C8 .
+ lda (zp_temp1),y ; 81CF B1 CB ..
+ sta sfx_slot_curpos+1,x ; 81D1 9D 4F 06 .O.
+ iny ; 81D4 C8 .
+ lda $065E,x ; 81D5 BD 5E 06 .^.
+ beq L81EE ; 81D8 F0 14 ..
+ dec $065E,x ; 81DA DE 5E 06 .^.
+ bne sfx_next_note ; 81DD D0 9E ..
+ lda $0656,x ; 81DF BD 56 06 .V.
+ sta sfx_slot_curpos,x ; 81E2 9D 4E 06 .N.
+ lda $0657,x ; 81E5 BD 57 06 .W.
+ sta sfx_slot_curpos+1,x ; 81E8 9D 4F 06 .O.
+ jmp sfx_next_note ; 81EB 4C 7D 81 L}.
+
+; ----------------------------------------------------------------------------
+L81EE: nop ; 81EE EA .
+ lda (zp_temp1),y ; 81EF B1 CB ..
+ sta $065E,x ; 81F1 9D 5E 06 .^.
+ lda zp_temp1 ; 81F4 A5 CB ..
+ clc ; 81F6 18 .
+ adc #$04 ; 81F7 69 04 i.
+ sta $0656,x ; 81F9 9D 56 06 .V.
+ lda zp_temp1+1 ; 81FC A5 CC ..
+ adc #$00 ; 81FE 69 00 i.
+ sta $0657,x ; 8200 9D 57 06 .W.
+ jmp sfx_next_note ; 8203 4C 7D 81 L}.
+
+; ----------------------------------------------------------------------------
+; y==0, a>=4 on entry
+sfx_play_note:
+ sta AUDF1_minus_two,x ; 8206 9D FE D1 ...
+ iny ; 8209 C8 .
+ lda (zp_temp1),y ; 820A B1 CB ..
+ sta sfx_slot_timer,x ; 820C 9D 3F 06 .?.
+ lda sfx_slot_freq,x ; 820F BD 47 06 .G.
+ sta AUDF1_minus_one,x ; 8212 9D FF D1 ...
+ clc ; 8215 18 .
+ lda sfx_slot_curpos,x ; 8216 BD 4E 06 .N.
+ adc #$02 ; 8219 69 02 i.
+ sta sfx_slot_curpos,x ; 821B 9D 4E 06 .N.
+ bcc L8223 ; 821E 90 03 ..
+ inc sfx_slot_curpos+1,x ; 8220 FE 4F 06 .O.
+L8223: jmp L8168 ; 8223 4C 68 81 Lh.
+
+; ----------------------------------------------------------------------------
+; done playing this sfx, free up the slot, X-indexed
+sfx_finished:
+ lda #$00 ; 8226 A9 00 ..
+ sta sfx_slot_tempo,x ; 8228 9D 3E 06 .>.
+ sta AUDF1_minus_one,x ; 822B 9D FF D1 ...
+ jmp next_sfx_slot ; 822E 4C 5F 81 L_.
+
+; ----------------------------------------------------------------------------
+; point to next byte in current sfx slot indexed by X
+inc_sfx_pos:
+ clc ; 8231 18 .
+ lda sfx_slot_curpos,x ; 8232 BD 4E 06 .N.
+ adc #$02 ; 8235 69 02 i.
+ sta sfx_slot_curpos,x ; 8237 9D 4E 06 .N.
+ bcc inc_done ; 823A 90 03 ..
+ inc sfx_slot_curpos+1,x ; 823C FE 4F 06 .O.
+inc_done:
+ rts ; 823F 60 `
+
+; ----------------------------------------------------------------------------
+; if cue_sfx not already in progress, setup to play sfx at (sfx_slot_tempo, sfx_lock) tempo (?) A
+cue_sfx_lowprior:
+ pha ; 8240 48 H
+ lda sfx_ptr+1 ; 8241 AD 3D 06 .=.
+cue_ok: beq L8248 ; 8244 F0 02 ..
+ pla ; 8246 68 h
+ rts ; 8247 60 `
+
+; ----------------------------------------------------------------------------
+L8248: lda sfx_slot_tempo ; 8248 AD 3E 06 .>.
+ sta sfx_ptr ; 824B 8D 3C 06 .<.
+ lda sfx_slot_timer ; 824E AD 3F 06 .?.
+ sta sfx_ptr+1 ; 8251 8D 3D 06 .=.
+ pla ; 8254 68 h
+; setup to play sfx at *sfx_ptr, tempo (?) A
+cue_sfx:sta sfx_tempo_tmp ; 8255 8D 61 06 .a.
+ inc sfx_lock ; 8258 EE 2F 06 ./.
+ ldx #$0A ; 825B A2 0A ..
+L825D: dex ; 825D CA .
+ dex ; 825E CA .
+ beq L8281 ; 825F F0 20 .
+ lda sfx_slot_tempo,x ; 8261 BD 3E 06 .>.
+ bne L825D ; 8264 D0 F7 ..
+L8266: lda sfx_ptr ; 8266 AD 3C 06 .<.
+ sta sfx_slot_curpos,x ; 8269 9D 4E 06 .N.
+ lda sfx_ptr+1 ; 826C AD 3D 06 .=.
+ sta sfx_slot_curpos+1,x ; 826F 9D 4F 06 .O.
+ lda sfx_tempo_tmp ; 8272 AD 61 06 .a.
+ sta sfx_slot_tempo,x ; 8275 9D 3E 06 .>.
+cue_done:
+ lda #$00 ; 8278 A9 00 ..
+ sta sfx_ptr+1 ; 827A 8D 3D 06 .=.
+ dec sfx_lock ; 827D CE 2F 06 ./.
+ rts ; 8280 60 `
+
+; ----------------------------------------------------------------------------
+L8281: ldx #$0A ; 8281 A2 0A ..
+L8283: dex ; 8283 CA .
+ dex ; 8284 CA .
+ beq cue_done ; 8285 F0 F1 ..
+ lda sfx_slot_tempo,x ; 8287 BD 3E 06 .>.
+ cmp sfx_tempo_tmp ; 828A CD 61 06 .a.
+ bcc L8266 ; 828D 90 D7 ..
+ jmp L8283 ; 828F 4C 83 82 L..
+
+; ----------------------------------------------------------------------------
+ .byte $82 ; 8292 82 .
+position_missiles:
+ ldx #$05 ; 8293 A2 05 ..
+L8295: dex ; 8295 CA .
+ beq missiles_done ; 8296 F0 45 .E
+ lda $069A,x ; 8298 BD 9A 06 ...
+ cmp $06A2,x ; 829B DD A2 06 ...
+ beq L82A6 ; 829E F0 06 ..
+ sta $06A2,x ; 82A0 9D A2 06 ...
+ sta HPOSP3,x ; 82A3 9D 03 D0 ...
+L82A6: lda $06A6,x ; 82A6 BD A6 06 ...
+ cmp $069E,x ; 82A9 DD 9E 06 ...
+ beq L8295 ; 82AC F0 E7 ..
+ tay ; 82AE A8 .
+ lda $2B00,y ; 82AF B9 00 2B ..+
+ and missiles_mask_table_minus_one,x ; 82B2 3D DF 82 =..
+ sta $2B00,y ; 82B5 99 00 2B ..+
+ lda $2B01,y ; 82B8 B9 01 2B ..+
+ and missiles_mask_table_minus_one,x ; 82BB 3D DF 82 =..
+ sta $2B01,y ; 82BE 99 01 2B ..+
+ lda $069E,x ; 82C1 BD 9E 06 ...
+ sta $06A6,x ; 82C4 9D A6 06 ...
+ tay ; 82C7 A8 .
+ lda $2B00,y ; 82C8 B9 00 2B ..+
+ ora L82E3,x ; 82CB 1D E3 82 ...
+ sta $2B00,y ; 82CE 99 00 2B ..+
+ lda $2B01,y ; 82D1 B9 01 2B ..+
+ ora L82E3,x ; 82D4 1D E3 82 ...
+ sta $2B01,y ; 82D7 99 01 2B ..+
+ jmp L8295 ; 82DA 4C 95 82 L..
+
+; ----------------------------------------------------------------------------
+missiles_done:
+missiles_mask_table_minus_one:= * + 2
+ jmp position_players ; 82DD 4C E9 82 L..
+
+; ----------------------------------------------------------------------------
+missiles_mask_table:
+ .byte $FC,$F3,$CF ; 82E0 FC F3 CF ...
+L82E3: .byte $3F,$03,$0C,$30,$C0 ; 82E3 3F 03 0C 30 C0 ?..0.
+; ----------------------------------------------------------------------------
+position_done:
+ rts ; 82E8 60 `
+
+; ----------------------------------------------------------------------------
+; X counts down 5..1 (starts at 6, immediately decremented, and loop is done with 0). zp_temp1 is ZP pointer to the current player or missile being written to ($2f00..$2b00, or p3/p2/p1/p0/missiles).
+position_players:
+ lda #$00 ; 82E9 A9 00 ..
+ sta zp_temp1 ; 82EB 85 CB ..
+ lda #$30 ; 82ED A9 30 .0
+ sta zp_temp1+1 ; 82EF 85 CC ..
+ ldx #$06 ; 82F1 A2 06 ..
+L82F3: dec zp_temp1+1 ; 82F3 C6 CC ..
+ dex ; 82F5 CA .
+ beq position_done ; 82F6 F0 F0 ..
+ lda $0668,x ; 82F8 BD 68 06 .h.
+ beq L82F3 ; 82FB F0 F6 ..
+ lda $067C,x ; 82FD BD 7C 06 .|.
+ cmp $068B,x ; 8300 DD 8B 06 ...
+ beq position_pm_vert ; 8303 F0 1D ..
+ sta $068B,x ; 8305 9D 8B 06 ...
+ sta HPOSP0_minus_two,x ; 8308 9D FE CF ...
+ cpx #$01 ; 830B E0 01 ..
+ bne position_pm_vert ; 830D D0 13 ..
+ tay ; 830F A8 .
+; position the 4 missiles side-by-side
+position_player_5:
+ sty HPOSM3 ; 8310 8C 07 D0 ...
+ iny ; 8313 C8 .
+ iny ; 8314 C8 .
+ sty HPOSM2 ; 8315 8C 06 D0 ...
+ iny ; 8318 C8 .
+ iny ; 8319 C8 .
+ sty HPOSM1 ; 831A 8C 05 D0 ...
+ iny ; 831D C8 .
+ iny ; 831E C8 .
+ sty HPOSM0 ; 831F 8C 04 D0 ...
+position_pm_vert:
+ lda $0690,x ; 8322 BD 90 06 ...
+ cmp $0681,x ; 8325 DD 81 06 ...
+ bne L8338 ; 8328 D0 0E ..
+ lda $0686,x ; 832A BD 86 06 ...
+ cmp $0695,x ; 832D DD 95 06 ...
+ beq L82F3 ; 8330 F0 C1 ..
+ sta $0695,x ; 8332 9D 95 06 ...
+ lda $0690,x ; 8335 BD 90 06 ...
+L8338: sta zp_temp1 ; 8338 85 CB ..
+ lda $0677,x ; 833A BD 77 06 .w.
+ sta $CF ; 833D 85 CF ..
+ lda #$00 ; 833F A9 00 ..
+ tay ; 8341 A8 .
+; write zeroes to unused portion of this player/missile
+clear_pm:
+ sta (zp_temp1),y ; 8342 91 CB ..
+ iny ; 8344 C8 .
+ cpy $CF ; 8345 C4 CF ..
+ bne clear_pm ; 8347 D0 F9 ..
+ lda $0681,x ; 8349 BD 81 06 ...
+ sta $0690,x ; 834C 9D 90 06 ...
+ sta zp_temp1 ; 834F 85 CB ..
+ lda $066D,x ; 8351 BD 6D 06 .m.
+ sta $CD ; 8354 85 CD ..
+ lda $0672,x ; 8356 BD 72 06 .r.
+ sta $CE ; 8359 85 CE ..
+ ldy $0686,x ; 835B BC 86 06 ...
+ clc ; 835E 18 .
+L835F: dey ; 835F 88 .
+ beq L8370 ; 8360 F0 0E ..
+ lda $CF ; 8362 A5 CF ..
+ adc $CD ; 8364 65 CD e.
+ sta $CD ; 8366 85 CD ..
+ bcc L835F ; 8368 90 F5 ..
+ inc $CE ; 836A E6 CE ..
+ clc ; 836C 18 .
+ jmp L835F ; 836D 4C 5F 83 L_.
+
+; ----------------------------------------------------------------------------
+L8370: lda ($CD),y ; 8370 B1 CD ..
+ sta (zp_temp1),y ; 8372 91 CB ..
+ iny ; 8374 C8 .
+ dec $CF ; 8375 C6 CF ..
+ bne L8370 ; 8377 D0 F7 ..
+ jmp L82F3 ; 8379 4C F3 82 L..
+
+; ----------------------------------------------------------------------------
+init_hardware:
+ ldx #$18 ; 837C A2 18 ..
+; movement_direction_table+31 should read data_table_85de-1, da65 isn't perfect yet
+init_page6_loop:
+ lda movement_direction_table+31,x ; 837E BD DD 85 ...
+ sta $05FF,x ; 8381 9D FF 05 ...
+ dex ; 8384 CA .
+ bne init_page6_loop ; 8385 D0 F7 ..
+ stx AUDCTL ; 8387 8E 08 D2 ...
+ lda #$28 ; 838A A9 28 .(
+ sta PMBASE ; 838C 8D 07 D4 ...
+; std playfield, enable players + missiles, single-line p/m res, DMA enabled
+set_dma_ctl:
+ lda #$3E ; 838F A9 3E .>
+ sta SDMCTL ; 8391 8D 2F 02 ./.
+ sta DMACTL ; 8394 8D 00 D4 ...
+ lda #$11 ; 8397 A9 11 ..
+; priority $11: pl0-3, pf0-3, bak (and enable 5th player from the missiles)
+init_set_prior:
+ sta GPRIOR ; 8399 8D 6F 02 .o.
+ sta PRIOR ; 839C 8D 1B D0 ...
+ lda #$03 ; 839F A9 03 ..
+ sta SKCTL ; 83A1 8D 0F D2 ...
+ sta GRACTL ; 83A4 8D 1D D0 ...
+ lda #$09 ; 83A7 A9 09 ..
+ sta player_speed ; 83A9 8D 24 06 .$.
+ lda #$4C ; 83AC A9 4C .L
+ sta L06E0 ; 83AE 8D E0 06 ...
+ lda #$20 ; 83B1 A9 20 .
+ sta L06E3 ; 83B3 8D E3 06 ...
+; store an RTS at $06E6, which will get JSR'ed to by unused level subroutines
+store_rts:
+ lda #$60 ; 83B6 A9 60 .`
+ sta L06E6 ; 83B8 8D E6 06 ...
+; use character set at $9e00 aka charset
+set_char_base:
+ lda #$9E ; 83BB A9 9E ..
+ sta CHBAS ; 83BD 8D F4 02 ...
+ sta CHBASE ; 83C0 8D 09 D4 ...
+ lda #$9D ; 83C3 A9 9D ..
+ sta $0674 ; 83C5 8D 74 06 .t.
+ sta $0675 ; 83C8 8D 75 06 .u.
+ lda #$E8 ; 83CB A9 E8 ..
+ sta $0670 ; 83CD 8D 70 06 .p.
+ sta $066A ; 83D0 8D 6A 06 .j.
+ sta $066B ; 83D3 8D 6B 06 .k.
+ lda #$0A ; 83D6 A9 0A ..
+ sta $0679 ; 83D8 8D 79 06 .y.
+ inc $067A ; 83DB EE 7A 06 .z.
+ lda #$00 ; 83DE A9 00 ..
+ sta VKEYBD ; 83E0 8D 08 02 ...
+ sta SAVMSC ; 83E3 85 58 .X
+ sta $D5 ; 83E5 85 D5 ..
+ lda #$30 ; 83E7 A9 30 .0
+; tell OS that screen memory starts at $3000
+set_savmsc:
+ sta SAVMSC+1 ; 83E9 85 59 .Y
+ lda #$9C ; 83EB A9 9C ..
+; VKEYBD now points to $9c00 aka keyboard_isr
+set_vkeybd:
+ sta VKEYBD_hi ; 83ED 8D 09 02 ...
+ ldx #$07 ; 83F0 A2 07 ..
+L83F2: lda L8405,x ; 83F2 BD 05 84 ...
+ sta $06D8,x ; 83F5 9D D8 06 ...
+ dex ; 83F8 CA .
+ bne L83F2 ; 83F9 D0 F7 ..
+ ldy #$0D ; 83FB A0 0D ..
+ ldx #$84 ; 83FD A2 84 ..
+ lda #$06 ; 83FF A9 06 ..
+; VVBLKI now points to $840d aka vblank_imm_isr
+set_vvblki:
+ jsr SETVBV ; 8401 20 5C E4 \.
+ cld ; 8404 D8 .
+L8405: rts ; 8405 60 `
+
+; ----------------------------------------------------------------------------
+data_8406:
+ .byte $FE,$49,$9C,$00,$00,$01,$FF ; 8406 FE 49 9C 00 00 01 FF .I.....
+; ----------------------------------------------------------------------------
+; service immediate vblank interrupt
+vblank_imm_isr:
+ ldx #$09 ; 840D A2 09 ..
+; update color regs from shadow regs (X ranges 1 to 9, GRAFM+1 is COLPM0, $2bf+1 is PCOLR0)
+update_color_regs:
+ lda $02BF,x ; 840F BD BF 02 ...
+ sta GRAFM,x ; 8412 9D 11 D0 ...
+ dex ; 8415 CA .
+ bne update_color_regs ; 8416 D0 F7 ..
+ inc $0619 ; 8418 EE 19 06 ...
+ bne L841F ; 841B D0 02 ..
+ inc $A2 ; 841D E6 A2 ..
+L841F: inc jiffy_timer_1 ; 841F EE 1A 06 ...
+ inc jiffy_timer_2 ; 8422 EE 1B 06 ...
+ inc $061C ; 8425 EE 1C 06 ...
+ lda $061C ; 8428 AD 1C 06 ...
+ and #$01 ; 842B 29 01 ).
+ sta $061C ; 842D 8D 1C 06 ...
+ lda #$00 ; 8430 A9 00 ..
+ sta $0621 ; 8432 8D 21 06 .!.
+ sta $0622 ; 8435 8D 22 06 .".
+ sta $06FD ; 8438 8D FD 06 ...
+ inc $061D ; 843B EE 1D 06 ...
+ inc speed_jiffy_timer ; 843E EE 1E 06 ...
+ lda player_speed ; 8441 AD 24 06 .$.
+ cmp #$09 ; 8444 C9 09 ..
+ bcs L847E ; 8446 B0 36 .6
+ lda $061D ; 8448 AD 1D 06 ...
+ cmp player_speed ; 844B CD 24 06 .$.
+ bcc L846E ; 844E 90 1E ..
+ lda #$00 ; 8450 A9 00 ..
+ sta $061D ; 8452 8D 1D 06 ...
+ inc $0621 ; 8455 EE 21 06 .!.
+ inc $061F ; 8458 EE 1F 06 ...
+ inc $0620 ; 845B EE 20 06 . .
+ lda $061F ; 845E AD 1F 06 ...
+ and #$01 ; 8461 29 01 ).
+ sta $061F ; 8463 8D 1F 06 ...
+ lda $0620 ; 8466 AD 20 06 . .
+ and #$03 ; 8469 29 03 ).
+ sta $0620 ; 846B 8D 20 06 . .
+L846E: lda speed_jiffy_timer ; 846E AD 1E 06 ...
+ cmp initial_speed ; 8471 CD 25 06 .%.
+ bcc L847E ; 8474 90 08 ..
+ lda #$00 ; 8476 A9 00 ..
+ sta speed_jiffy_timer ; 8478 8D 1E 06 ...
+ inc $0622 ; 847B EE 22 06 .".
+L847E: lda playing_level ; 847E AD 27 06 .'.
+ beq no_dec_bonus ; 8481 F0 08 ..
+ inc bonus_jiffy_timer ; 8483 EE 26 06 .&.
+ bne no_dec_bonus ; 8486 D0 03 ..
+ jsr decrement_time_bonus_jv ; 8488 20 21 80 !.
+no_dec_bonus:
+ lda $0619 ; 848B AD 19 06 ...
+ and #$07 ; 848E 29 07 ).
+ bne check_joystick_enabled ; 8490 D0 12 ..
+ inc $0628 ; 8492 EE 28 06 .(.
+ lda $0628 ; 8495 AD 28 06 .(.
+ and #$07 ; 8498 29 07 ).
+ sta $0628 ; 849A 8D 28 06 .(.
+ tax ; 849D AA .
+ lda data_table_85b6,x ; 849E BD B6 85 ...
+ sta $062A ; 84A1 8D 2A 06 .*.
+; read the joystick if not disabled
+check_joystick_enabled:
+ lda joystick_disabled ; 84A4 AD 32 06 .2.
+ beq read_joystick ; 84A7 F0 03 ..
+ jmp store_joystick_state ; 84A9 4C B1 84 L..
+
+; ----------------------------------------------------------------------------
+; always joystick #1 (all players use the same joystick and pass it around)
+read_joystick:
+ lda PORTA ; 84AC AD 00 D3 ...
+ and #$0F ; 84AF 29 0F ).
+; store bottom 4 bits of PORTA, or 0 if joystick_disabled
+store_joystick_state:
+ sta joystick_state ; 84B1 8D 33 06 .3.
+ asl a ; 84B4 0A .
+ tax ; 84B5 AA .
+ lda movement_direction_table,x ; 84B6 BD BE 85 ...
+ sta player_delta_x ; 84B9 8D 30 06 .0.
+ lda movement_direction_table+1,x ; 84BC BD BF 85 ...
+ sta player_delta_y ; 84BF 8D 31 06 .1.
+ lda trigger_disabled ; 84C2 AD 34 06 .4.
+ beq read_trigger ; 84C5 F0 0C ..
+ cmp #$01 ; 84C7 C9 01 ..
+ beq fake_read_trigger ; 84C9 F0 02 ..
+ lda #$00 ; 84CB A9 00 ..
+; ??
+fake_read_trigger:
+ sta trigger_state ; 84CD 8D 35 06 .5.
+ jmp L84D9 ; 84D0 4C D9 84 L..
+
+; ----------------------------------------------------------------------------
+; always joystick #1
+read_trigger:
+ lda TRIG0 ; 84D3 AD 10 D0 ...
+ sta trigger_state ; 84D6 8D 35 06 .5.
+L84D9: ldx #$08 ; 84D9 A2 08 ..
+L84DB: lda work_level_desc+1,x ; 84DB BD 81 07 ...
+ beq L84EE ; 84DE F0 0E ..
+ sta $0603,x ; 84E0 9D 03 06 ...
+ lda work_level_desc,x ; 84E3 BD 80 07 ...
+ sta $0602,x ; 84E6 9D 02 06 ...
+ lda #$00 ; 84E9 A9 00 ..
+ sta work_level_desc+1,x ; 84EB 9D 81 07 ...
+L84EE: dex ; 84EE CA .
+ dex ; 84EF CA .
+ bne L84DB ; 84F0 D0 E9 ..
+ lda $0640 ; 84F2 AD 40 06 .@.
+ ora $0642 ; 84F5 0D 42 06 .B.
+ ora $0644 ; 84F8 0D 44 06 .D.
+ ora sfx_slot_duration ; 84FB 0D 46 06 .F.
+ sta $0663 ; 84FE 8D 63 06 .c.
+ ldx #$10 ; 8501 A2 10 ..
+; save contents of GTIA collision regs (X ranges 1 to $10, dli_vec_shadow_hi should read collision_save-1)
+save_collisions:
+ lda $CFFF,x ; 8503 BD FF CF ...
+ sta dli_vec_shadow_hi,x ; 8506 9D AF 06 ...
+ dex ; 8509 CA .
+ bne save_collisions ; 850A D0 F7 ..
+ inx ; 850C E8 .
+clear_collisions:
+ stx HITCLR ; 850D 8E 1E D0 ...
+; update display list, if there's a new one in the shadow reg
+update_dlist:
+ lda dlist_shadow_hi ; 8510 AD AD 06 ...
+ beq update_dli_vector ; 8513 F0 0E ..
+ sta DLISTH ; 8515 8D 03 D4 ...
+ lda dlist_shadow_lo ; 8518 AD AC 06 ...
+ sta DLISTL ; 851B 8D 02 D4 ...
+; clear the shadow now that we've updated the HW
+clear_dlist_shadow:
+ lda #$00 ; 851E A9 00 ..
+ sta dlist_shadow_hi ; 8520 8D AD 06 ...
+; update DLI vector, if there's a new one in the shadow reg
+update_dli_vector:
+ lda dli_vec_shadow_hi ; 8523 AD AF 06 ...
+ beq L853B ; 8526 F0 13 ..
+ sta VDSLST+1 ; 8528 8D 01 02 ...
+ lda dli_vec_shadow_lo ; 852B AD AE 06 ...
+ sta VDSLST ; 852E 8D 00 02 ...
+; clear the shadow now that we've updated the HW
+clear_dli_shadow:
+ lda #$00 ; 8531 A9 00 ..
+ sta dli_vec_shadow_hi ; 8533 8D AF 06 ...
+; enable DLI now that we've set up the vector
+enable_dli:
+ lda #$C0 ; 8536 A9 C0 ..
+ sta NMIEN ; 8538 8D 0E D4 ...
+L853B: lda $06FC ; 853B AD FC 06 ...
+ cmp $0888 ; 853E CD 88 08 ...
+ bcc L8551 ; 8541 90 0E ..
+ inc $06FD ; 8543 EE FD 06 ...
+ inc $06FB ; 8546 EE FB 06 ...
+ lda #$00 ; 8549 A9 00 ..
+ sta $06FC ; 854B 8D FC 06 ...
+ jmp enable_keyboard_irq ; 854E 4C 54 85 LT.
+
+; ----------------------------------------------------------------------------
+L8551: inc $06FC ; 8551 EE FC 06 ...
+; $C0 = regular keypress, break keypress
+enable_keyboard_irq:
+ lda #$C0 ; 8554 A9 C0 ..
+ sta IRQEN ; 8556 8D 0E D2 ...
+ cli ; 8559 58 X
+; 8 = silent (0 would be a click)
+silence_console_speaker:
+ lda #$08 ; 855A A9 08 ..
+ sta CONSOL ; 855C 8D 1F D0 ...
+ ldx #$FF ; 855F A2 FF ..
+; carry set = not pressed, clear = pressed
+check_start_key:
+ lda CONSOL ; 8561 AD 1F D0 ...
+ sta zp_temp1 ; 8564 85 CB ..
+ lsr zp_temp1 ; 8566 46 CB F.
+ bcs check_select_key ; 8568 B0 09 ..
+ lda start_key_enabled ; 856A AD C8 06 ...
+ beq check_select_key ; 856D F0 04 ..
+ txs ; 856F 9A .
+ jmp (start_key_vec) ; 8570 6C C4 06 l..
+
+; ----------------------------------------------------------------------------
+; carry set = not pressed, clear = pressed
+check_select_key:
+ lsr zp_temp1 ; 8573 46 CB F.
+ bcs check_option_key ; 8575 B0 09 ..
+ lda select_key_enabled ; 8577 AD C7 06 ...
+ beq check_option_key ; 857A F0 04 ..
+ txs ; 857C 9A .
+ jmp (select_key_vec) ; 857D 6C C2 06 l..
+
+; ----------------------------------------------------------------------------
+; carry set = not pressed, clear = pressed
+check_option_key:
+ lsr zp_temp1 ; 8580 46 CB F.
+ bcs L858D ; 8582 B0 09 ..
+ lda option_key_enabled ; 8584 AD C6 06 ...
+ beq L858D ; 8587 F0 04 ..
+ txs ; 8589 9A .
+ jmp (option_key_vec) ; 858A 6C C0 06 l..
+
+; ----------------------------------------------------------------------------
+L858D: ldx $0618 ; 858D AE 18 06 ...
+ cpx #$18 ; 8590 E0 18 ..
+ bne L859C ; 8592 D0 08 ..
+ lda #$00 ; 8594 A9 00 ..
+ sta $0618 ; 8596 8D 18 06 ...
+ jmp XITVBV ; 8599 4C 62 E4 Lb.
+
+; ----------------------------------------------------------------------------
+L859C: inc $0618 ; 859C EE 18 06 ...
+ inc $0618 ; 859F EE 18 06 ...
+ lda $0601,x ; 85A2 BD 01 06 ...
+ beq L858D ; 85A5 F0 E6 ..
+ sta $06E5 ; 85A7 8D E5 06 ...
+ lda $0600,x ; 85AA BD 00 06 ...
+ sta $06E4 ; 85AD 8D E4 06 ...
+ jsr L06E3 ; 85B0 20 E3 06 ..
+ jmp L858D ; 85B3 4C 8D 85 L..
+
+; ----------------------------------------------------------------------------
+; used in vblank_imm_isr, not sure for what yet
+data_table_85b6:
+ .byte $1A,$96,$28,$66,$C6,$56,$0E,$F6 ; 85B6 1A 96 28 66 C6 56 0E F6 ..(f.V..
+; ----------------------------------------------------------------------------
+; X/Y movement, indexed by joystick_state << 1, each entry is XXYY, $FF is -1
+movement_direction_table:
+ .word $0000,$0000,$0000,$0000 ; 85BE 00 00 00 00 00 00 00 00 ........
+ .word $0000,$0101,$FF01,$0001 ; 85C6 00 00 01 01 01 FF 01 00 ........
+ .word $0000,$01FF,$FFFF,$00FF ; 85CE 00 00 FF 01 FF FF FF 00 ........
+ .word $0000,$0100,$FF00,$0000 ; 85D6 00 00 00 01 00 FF 00 00 ........
+; ----------------------------------------------------------------------------
+; dunno what this is for yet, but it's copied into page 6 by init_hardware
+data_table_85de:
+ .byte $C8,$88,$05,$84,$05,$84,$05,$84 ; 85DE C8 88 05 84 05 84 05 84 ........
+ .byte $05,$84,$05,$84,$05,$84,$00,$98 ; 85E6 05 84 05 84 05 84 00 98 ........
+ .byte $93,$82,$69,$8E,$00,$89,$57,$81 ; 85EE 93 82 69 8E 00 89 57 81 ..i...W.
+; probably just filler
+zero_filler_85f6:
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 85F6 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00 ; 85FE 00 00 ..
+; ----------------------------------------------------------------------------
+; gets called after the level is drawn & the intro music stops, and also during the level (?)
+xxx_level_something:
+ ldx #$00 ; 8600 A2 00 ..
+ ldy #$00 ; 8602 A0 00 ..
+ stx $0665 ; 8604 8E 65 06 .e.
+L8607: lda #$10 ; 8607 A9 10 ..
+ clc ; 8609 18 .
+ adc $D5 ; 860A 65 D5 e.
+ sta ($D3),y ; 860C 91 D3 ..
+L860E: sec ; 860E 38 8
+ lda $D0 ; 860F A5 D0 ..
+ sbc L8702,x ; 8611 FD 02 87 ...
+ sta $D0 ; 8614 85 D0 ..
+ lda $D1 ; 8616 A5 D1 ..
+ sbc L8703,x ; 8618 FD 03 87 ...
+ sta $D1 ; 861B 85 D1 ..
+ lda $D2 ; 861D A5 D2 ..
+ sbc L8704,x ; 861F FD 04 87 ...
+ sta $D2 ; 8622 85 D2 ..
+ bcc L8633 ; 8624 90 0D ..
+ lda ($D3),y ; 8626 B1 D3 ..
+ clc ; 8628 18 .
+ adc #$01 ; 8629 69 01 i.
+ sta ($D3),y ; 862B 91 D3 ..
+ sta $0665 ; 862D 8D 65 06 .e.
+ jmp L860E ; 8630 4C 0E 86 L..
+
+; ----------------------------------------------------------------------------
+L8633: clc ; 8633 18 .
+ lda L8702,x ; 8634 BD 02 87 ...
+ adc $D0 ; 8637 65 D0 e.
+ sta $D0 ; 8639 85 D0 ..
+ lda L8703,x ; 863B BD 03 87 ...
+ adc $D1 ; 863E 65 D1 e.
+ sta $D1 ; 8640 85 D1 ..
+ lda L8704,x ; 8642 BD 04 87 ...
+ adc $D2 ; 8645 65 D2 e.
+ sta $D2 ; 8647 85 D2 ..
+ lda $0665 ; 8649 AD 65 06 .e.
+ bne L865C ; 864C D0 0E ..
+ lda ($D3),y ; 864E B1 D3 ..
+ and #$0F ; 8650 29 0F ).
+ bne L865C ; 8652 D0 08 ..
+ cpy #$05 ; 8654 C0 05 ..
+ beq L8667 ; 8656 F0 0F ..
+ lda #$00 ; 8658 A9 00 ..
+ sta ($D3),y ; 865A 91 D3 ..
+L865C: cpx #$0F ; 865C E0 0F ..
+ beq L8667 ; 865E F0 07 ..
+ inx ; 8660 E8 .
+ inx ; 8661 E8 .
+ inx ; 8662 E8 .
+ iny ; 8663 C8 .
+ jmp L8607 ; 8664 4C 07 86 L..
+
+; ----------------------------------------------------------------------------
+L8667: rts ; 8667 60 `
+
+; ----------------------------------------------------------------------------
+L8668: lda #$F5 ; 8668 A9 F5 ..
+ sta $D3 ; 866A 85 D3 ..
+ lda #$3D ; 866C A9 3D .=
+ sta $D4 ; 866E 85 D4 ..
+ ldx #$03 ; 8670 A2 03 ..
+L8672: lda $06FF,x ; 8672 BD FF 06 ...
+ sta $CF,x ; 8675 95 CF ..
+ dex ; 8677 CA .
+ bne L8672 ; 8678 D0 F8 ..
+ jsr xxx_level_something ; 867A 20 00 86 ..
+ rts ; 867D 60 `
+
+; ----------------------------------------------------------------------------
+L867E: lda #$09 ; 867E A9 09 ..
+ sta $D3 ; 8680 85 D3 ..
+ lda #$3E ; 8682 A9 3E .>
+ sta $D4 ; 8684 85 D4 ..
+ ldx #$03 ; 8686 A2 03 ..
+L8688: lda work_level_points_per_bomb,x ; 8688 BD 90 07 ...
+ sta $CF,x ; 868B 95 CF ..
+ dex ; 868D CA .
+ bne L8688 ; 868E D0 F8 ..
+ jsr xxx_level_something ; 8690 20 00 86 ..
+ rts ; 8693 60 `
+
+; ----------------------------------------------------------------------------
+; bottom 2 GR.1 lines on the game board
+update_status_window:
+ lda #$00 ; 8694 A9 00 ..
+ sta HSCROL ; 8696 8D 04 D4 ...
+ ldx #$28 ; 8699 A2 28 .(
+L869B: lda L86D9,x ; 869B BD D9 86 ...
+ sec ; 869E 38 8
+ sbc #$20 ; 869F E9 20 .
+ sta $3DE7,x ; 86A1 9D E7 3D ..=
+ dex ; 86A4 CA .
+ bne L869B ; 86A5 D0 F4 ..
+; 1 to 4
+show_current_player:
+ lda current_player ; 86A7 AD FE 06 ...
+ ora #$10 ; 86AA 09 10 ..
+ sta $3DE9 ; 86AC 8D E9 3D ..=
+ lda work_level_desc ; 86AF AD 80 07 ...
+ sta $3DED ; 86B2 8D ED 3D ..=
+ lda work_level_desc+1 ; 86B5 AD 81 07 ...
+ sta $3DEE ; 86B8 8D EE 3D ..=
+; up to 6 jumpmen, and a + if lives > 6. char $C1 = jumpman icon, $CB = plus sign
+show_lives_icons:
+ ldy #$00 ; 86BB A0 00 ..
+ lda #$C1 ; 86BD A9 C1 ..
+L86BF: cpy #$07 ; 86BF C0 07 ..
+ bcs L86CE ; 86C1 B0 0B ..
+ cpy lives ; 86C3 CC 0A 07 ...
+ beq L86D3 ; 86C6 F0 0B ..
+ sta $3DFD,y ; 86C8 99 FD 3D ..=
+ iny ; 86CB C8 .
+ bne L86BF ; 86CC D0 F1 ..
+L86CE: lda #$CB ; 86CE A9 CB ..
+ sta $3DFC,y ; 86D0 99 FC 3D ..=
+L86D3: jsr L8668 ; 86D3 20 68 86 h.
+ jsr L867E ; 86D6 20 7E 86 ~.
+L86D9: rts ; 86D9 60 `
+
+; ----------------------------------------------------------------------------
+data_table_86da:
+ .byte $20,$30,$20,$8C,$7D,$30,$30,$20 ; 86DA 20 30 20 8C 7D 30 30 20 0 .}00
+ .byte $D3,$C3,$CF,$D2,$C5,$20,$20,$20 ; 86E2 D3 C3 CF D2 C5 20 20 20 .....
+ .byte $20,$20,$20,$20,$20,$20,$20,$20 ; 86EA 20 20 20 20 20 20 20 20
+ .byte $20,$20,$20,$20,$C2,$CF,$CE,$D5 ; 86F2 20 20 20 20 C2 CF CE D5 ....
+ .byte $D3,$20,$20,$20,$20,$20,$20,$20 ; 86FA D3 20 20 20 20 20 20 20 .
+L8702: .byte $A0 ; 8702 A0 .
+L8703: .byte $86 ; 8703 86 .
+L8704: .byte $01,$10,$27,$00,$E8,$03,$00,$64 ; 8704 01 10 27 00 E8 03 00 64 ..'....d
+ .byte $00,$00,$0A,$00,$00,$01,$00,$00 ; 870C 00 00 0A 00 00 01 00 00 ........
+; ----------------------------------------------------------------------------
+; clear the gameboard screen memory (called before drawing a level, natch)
+clear_screen_mem:
+ ldx #$10 ; 8714 A2 10 ..
+ lda SAVMSC+1 ; 8716 A5 59 .Y
+ sta $AF ; 8718 85 AF ..
+ lda #$00 ; 871A A9 00 ..
+ sta $AE ; 871C 85 AE ..
+ tay ; 871E A8 .
+csm_loop:
+ sta ($AE),y ; 871F 91 AE ..
+ iny ; 8721 C8 .
+ bne csm_loop ; 8722 D0 FB ..
+ inc $AF ; 8724 E6 AF ..
+ dex ; 8726 CA .
+ bne csm_loop ; 8727 D0 F6 ..
+ rts ; 8729 60 `
+
+; ----------------------------------------------------------------------------
+; clear P/M mem
+clear_pm_mem:
+ lda #$09 ; 872A A9 09 ..
+ sta player_speed ; 872C 8D 24 06 .$.
+ ldx #$05 ; 872F A2 05 ..
+ lda #$00 ; 8731 A9 00 ..
+ sta playing_level ; 8733 8D 27 06 .'.
+L8736: sta $0681,x ; 8736 9D 81 06 ...
+ sta $0668,x ; 8739 9D 68 06 .h.
+ sta $069A,x ; 873C 9D 9A 06 ...
+ jsr hide_player ; 873F 20 B8 8D ..
+ dex ; 8742 CA .
+ bne L8736 ; 8743 D0 F1 ..
+ lda #$2B ; 8745 A9 2B .+
+ sta $B8 ; 8747 85 B8 ..
+ lda #$00 ; 8749 A9 00 ..
+ sta $B7 ; 874B 85 B7 ..
+ tay ; 874D A8 .
+ ldx #$05 ; 874E A2 05 ..
+L8750: sta ($B7),y ; 8750 91 B7 ..
+ iny ; 8752 C8 .
+ bne L8750 ; 8753 D0 FB ..
+ inc $B8 ; 8755 E6 B8 ..
+ dex ; 8757 CA .
+ bne L8750 ; 8758 D0 F6 ..
+ rts ; 875A 60 `
+
+; ----------------------------------------------------------------------------
+; set all AUDFx to 0
+silence_audio:
+ ldx #$00 ; 875B A2 00 ..
+ lda #$00 ; 875D A9 00 ..
+sa_loop:sta $0640,x ; 875F 9D 40 06 .@.
+ sta $0641,x ; 8762 9D 41 06 .A.
+ sta $0660,x ; 8765 9D 60 06 .`.
+ sta AUDF1,x ; 8768 9D 00 D2 ...
+ jsr store_audc ; 876B 20 C6 8D ..
+ inx ; 876E E8 .
+ inx ; 876F E8 .
+ cpx #$08 ; 8770 E0 08 ..
+ bne sa_loop ; 8772 D0 EB ..
+ rts ; 8774 60 `
+
+; ----------------------------------------------------------------------------
+; called after level-intro music is finished playing
+enable_joystick:
+ ldx #$08 ; 8775 A2 08 ..
+ej_loop:lda #$E6 ; 8777 A9 E6 ..
+ sta work_level_desc,x ; 8779 9D 80 07 ...
+ lda #$06 ; 877C A9 06 ..
+ sta work_level_desc+1,x ; 877E 9D 81 07 ...
+ dex ; 8781 CA .
+ dex ; 8782 CA .
+ bne ej_loop ; 8783 D0 F2 ..
+ stx joystick_disabled ; 8785 8E 32 06 .2.
+ stx sfx_lock ; 8788 8E 2F 06 ./.
+ stx work_level_bullet_chance ; 878B 8E 8B 07 ...
+ jsr clear_pm_mem ; 878E 20 2A 87 *.
+ jsr silence_audio ; 8791 20 5B 87 [.
+ lda #$30 ; 8794 A9 30 .0
+ sta SAVMSC+1 ; 8796 85 59 .Y
+; priority $11: pl0-3, pf0-3, bak (and enable 5th player from the missiles) [redundant? init_set_prior sets this, nothing appears to change it]
+set_prior:
+ lda #$11 ; 8798 A9 11 ..
+ sta PRIOR ; 879A 8D 1B D0 ...
+ jmp L88A8 ; 879D 4C A8 88 L..
+
+; ----------------------------------------------------------------------------
+L87A0: lda collision_save+4 ; 87A0 AD B4 06 ...
+ and #$04 ; 87A3 29 04 ).
+ bne L87A8 ; 87A5 D0 01 ..
+ rts ; 87A7 60 `
+
+; ----------------------------------------------------------------------------
+L87A8: lda $067E ; 87A8 AD 7E 06 .~.
+ clc ; 87AB 18 .
+ adc work_level_offs_14 ; 87AC 6D 8E 07 m..
+ and #$E0 ; 87AF 29 E0 ).
+ sta $B6 ; 87B1 85 B6 ..
+ clc ; 87B3 18 .
+ lda $0683 ; 87B4 AD 83 06 ...
+ adc work_level_offs_14+1 ; 87B7 6D 8F 07 m..
+ and #$E0 ; 87BA 29 E0 ).
+ lsr a ; 87BC 4A J
+ lsr a ; 87BD 4A J
+ lsr a ; 87BE 4A J
+ lsr a ; 87BF 4A J
+ ora $B6 ; 87C0 05 B6 ..
+ sta $B6 ; 87C2 85 B6 ..
+ lda work_level_map2 ; 87C4 AD 9A 07 ...
+ sta $B4 ; 87C7 85 B4 ..
+ lda work_level_map2+1 ; 87C9 AD 9B 07 ...
+ sta $B5 ; 87CC 85 B5 ..
+ ldy #$00 ; 87CE A0 00 ..
+L87D0: lda ($B4),y ; 87D0 B1 B4 ..
+ cmp #$FF ; 87D2 C9 FF ..
+ bne L87D7 ; 87D4 D0 01 ..
+ rts ; 87D6 60 `
+
+; ----------------------------------------------------------------------------
+L87D7: cmp $B6 ; 87D7 C5 B6 ..
+ beq L87E0 ; 87D9 F0 05 ..
+ iny ; 87DB C8 .
+ iny ; 87DC C8 .
+ jmp L87D0 ; 87DD 4C D0 87 L..
+
+; ----------------------------------------------------------------------------
+L87E0: lda work_level_map1 ; 87E0 AD 98 07 ...
+ sta $B0 ; 87E3 85 B0 ..
+ lda work_level_map1+1 ; 87E5 AD 99 07 ...
+ sta $B1 ; 87E8 85 B1 ..
+ tya ; 87EA 98 .
+ sta $B2 ; 87EB 85 B2 ..
+ lsr a ; 87ED 4A J
+ clc ; 87EE 18 .
+ adc $B2 ; 87EF 65 B2 e.
+ tay ; 87F1 A8 .
+ lda ($B0),y ; 87F2 B1 B0 ..
+ sta $06DC ; 87F4 8D DC 06 ...
+ iny ; 87F7 C8 .
+ lda ($B0),y ; 87F8 B1 B0 ..
+ sta $06DD ; 87FA 8D DD 06 ...
+ lda #$92 ; 87FD A9 92 ..
+ sta sfx_ptr ; 87FF 8D 3C 06 .<.
+ lda #$88 ; 8802 A9 88 ..
+ sta sfx_ptr+1 ; 8804 8D 3D 06 .=.
+ lda #$08 ; 8807 A9 08 ..
+ jsr cue_sfx_jv ; 8809 20 06 80 ..
+ ldy $B2 ; 880C A4 B2 ..
+ iny ; 880E C8 .
+ lda ($B4),y ; 880F B1 B4 ..
+ beq L8856 ; 8811 F0 43 .C
+ and #$F0 ; 8813 29 F0 ).
+ beq L8831 ; 8815 F0 1A ..
+ lsr a ; 8817 4A J
+ lsr a ; 8818 4A J
+ lsr a ; 8819 4A J
+ tay ; 881A A8 .
+ lda work_level_unkn_table1 ; 881B AD 9C 07 ...
+ sta $B0 ; 881E 85 B0 ..
+ lda work_level_unkn_table1+1 ; 8820 AD 9D 07 ...
+ sta $B1 ; 8823 85 B1 ..
+ lda ($B0),y ; 8825 B1 B0 ..
+ sta dm_progctr ; 8827 85 C0 ..
+ iny ; 8829 C8 .
+ lda ($B0),y ; 882A B1 B0 ..
+ sta dm_progctr+1 ; 882C 85 C1 ..
+ jsr draw_map_jv ; 882E 20 00 80 ..
+L8831: ldy $B2 ; 8831 A4 B2 ..
+ iny ; 8833 C8 .
+ lda ($B4),y ; 8834 B1 B4 ..
+ beq L8856 ; 8836 F0 1E ..
+ and #$0F ; 8838 29 0F ).
+ beq L8856 ; 883A F0 1A ..
+ asl a ; 883C 0A .
+ tay ; 883D A8 .
+ lda work_level_offs_30 ; 883E AD 9E 07 ...
+ sta $B0 ; 8841 85 B0 ..
+ lda work_level_offs_30+1 ; 8843 AD 9F 07 ...
+ sta $B1 ; 8846 85 B1 ..
+ lda ($B0),y ; 8848 B1 B0 ..
+ sta $06E4 ; 884A 8D E4 06 ...
+ iny ; 884D C8 .
+ lda ($B0),y ; 884E B1 B0 ..
+ sta $06E5 ; 8850 8D E5 06 ...
+ jsr L06E3 ; 8853 20 E3 06 ..
+L8856: lda work_level_sub4 ; 8856 AD A0 07 ...
+ sta $06E4 ; 8859 8D E4 06 ...
+ lda work_level_sub4+1 ; 885C AD A1 07 ...
+ sta $06E5 ; 885F 8D E5 06 ...
+ jsr L06E3 ; 8862 20 E3 06 ..
+ clc ; 8865 18 .
+ lda score ; 8866 AD 00 07 ...
+ adc work_level_points_per_bomb ; 8869 6D 90 07 m..
+ sta score ; 886C 8D 00 07 ...
+ bcc L8879 ; 886F 90 08 ..
+ inc score+1 ; 8871 EE 01 07 ...
+ bne L8879 ; 8874 D0 03 ..
+ inc score+2 ; 8876 EE 02 07 ...
+L8879: lda #$D9 ; 8879 A9 D9 ..
+ sta dm_progctr ; 887B 85 C0 ..
+ lda #$06 ; 887D A9 06 ..
+ sta dm_progctr+1 ; 887F 85 C1 ..
+ jsr draw_map_jv ; 8881 20 00 80 ..
+ jsr L800C ; 8884 20 0C 80 ..
+ dec work_level_num_bombs ; 8887 CE 8A 07 ...
+L888A: lda collision_save+4 ; 888A AD B4 06 ...
+ and #$04 ; 888D 29 04 ).
+ bne L888A ; 888F D0 F9 ..
+ rts ; 8891 60 `
+
+; ----------------------------------------------------------------------------
+data_8892:
+ .byte $01,$A6,$00,$1E,$03,$28,$03,$1E ; 8892 01 A6 00 1E 03 28 03 1E .....(..
+ .byte $03,$28,$03,$1E,$03,$28,$03,$1E ; 889A 03 28 03 1E 03 28 03 1E .(...(..
+ .byte $03,$28,$03,$00,$00,$00 ; 88A2 03 28 03 00 00 00 .(....
+; ----------------------------------------------------------------------------
+L88A8: ldx #$00 ; 88A8 A2 00 ..
+ txa ; 88AA 8A .
+L88AB: sta $2B00,x ; 88AB 9D 00 2B ..+
+ sta $2C00,x ; 88AE 9D 00 2C ..,
+ sta $2D00,x ; 88B1 9D 00 2D ..-
+ sta $2E00,x ; 88B4 9D 00 2E ...
+ sta $2F00,x ; 88B7 9D 00 2F ../
+ dex ; 88BA CA .
+ bne L88AB ; 88BB D0 EE ..
+ rts ; 88BD 60 `
+
+; ----------------------------------------------------------------------------
+ brk ; 88BE 00 .
+ brk ; 88BF 00 .
+ brk ; 88C0 00 .
+ brk ; 88C1 00 .
+ brk ; 88C2 00 .
+ brk ; 88C3 00 .
+ brk ; 88C4 00 .
+ brk ; 88C5 00 .
+ brk ; 88C6 00 .
+ brk ; 88C7 00 .
+check_consol:
+ lda player_delta_x ; 88C8 AD 30 06 .0.
+ ora player_delta_y ; 88CB 0D 31 06 .1.
+ bne L88DC ; 88CE D0 0C ..
+ lda CONSOL ; 88D0 AD 1F D0 ...
+ and #$07 ; 88D3 29 07 ).
+ cmp #$07 ; 88D5 C9 07 ..
+ bne L88DC ; 88D7 D0 03 ..
+ jmp L88E0 ; 88D9 4C E0 88 L..
+
+; ----------------------------------------------------------------------------
+L88DC: lda #$00 ; 88DC A9 00 ..
+ sta $A2 ; 88DE 85 A2 ..
+L88E0: lda $A0 ; 88E0 A5 A0 ..
+ bne L88E7 ; 88E2 D0 03 ..
+ sta $A2 ; 88E4 85 A2 ..
+L88E6: rts ; 88E6 60 `
+
+; ----------------------------------------------------------------------------
+L88E7: lda $A2 ; 88E7 A5 A2 ..
+ cmp #$28 ; 88E9 C9 28 .(
+ bcc L88E6 ; 88EB 90 F9 ..
+ lda #$00 ; 88ED A9 00 ..
+ sta $A0 ; 88EF 85 A0 ..
+ sta $A2 ; 88F1 85 A2 ..
+ ldx #$FF ; 88F3 A2 FF ..
+ txs ; 88F5 9A .
+ jmp init_game ; 88F6 4C 00 90 L..
+
+; ----------------------------------------------------------------------------
+ brk ; 88F9 00 .
+ brk ; 88FA 00 .
+ brk ; 88FB 00 .
+ brk ; 88FC 00 .
+ brk ; 88FD 00 .
+ brk ; 88FE 00 .
+ brk ; 88FF 00 .
+ lda $0621 ; 8900 AD 21 06 .!.
+ beq L890F ; 8903 F0 0A ..
+ lda $0623 ; 8905 AD 23 06 .#.
+ cmp #$01 ; 8908 C9 01 ..
+ beq L8910 ; 890A F0 04 ..
+ jmp L89F3 ; 890C 4C F3 89 L..
+
+; ----------------------------------------------------------------------------
+L890F: rts ; 890F 60 `
+
+; ----------------------------------------------------------------------------
+L8910: lda $06EE ; 8910 AD EE 06 ...
+ bne L8945 ; 8913 D0 30 .0
+ inc $06EE ; 8915 EE EE 06 ...
+ lda #$02 ; 8918 A9 02 ..
+ sta player_speed ; 891A 8D 24 06 .$.
+ sta $067F ; 891D 8D 7F 06 ...
+ lda #$00 ; 8920 A9 00 ..
+ sta playing_level ; 8922 8D 27 06 .'.
+ sta $06E9 ; 8925 8D E9 06 ...
+ sta $06EA ; 8928 8D EA 06 ...
+ lda RANDOM ; 892B AD 0A D2 ...
+ and #$0F ; 892E 29 0F ).
+ sta $0688 ; 8930 8D 88 06 ...
+ inc $0688 ; 8933 EE 88 06 ...
+ lda #$60 ; 8936 A9 60 .`
+ sta sfx_slot_tempo ; 8938 8D 3E 06 .>.
+ lda #$8A ; 893B A9 8A ..
+ sta sfx_slot_timer ; 893D 8D 3F 06 .?.
+ lda #$07 ; 8940 A9 07 ..
+ jsr L8003 ; 8942 20 03 80 ..
+L8945: lda $0683 ; 8945 AD 83 06 ...
+ cmp #$C6 ; 8948 C9 C6 ..
+ bcc L895D ; 894A 90 11 ..
+ lda #$00 ; 894C A9 00 ..
+ sta AUDF1 ; 894E 8D 00 D2 ...
+ sta AUDC1 ; 8951 8D 01 D2 ...
+ sta $06EF ; 8954 8D EF 06 ...
+ inc $0623 ; 8957 EE 23 06 .#.
+ jmp L89F3 ; 895A 4C F3 89 L..
+
+; ----------------------------------------------------------------------------
+L895D: lda #$70 ; 895D A9 70 .p
+ sta $0801 ; 895F 8D 01 08 ...
+ sta game_display_list ; 8962 8D 81 08 ...
+ lda $06EA ; 8965 AD EA 06 ...
+ bne L89A9 ; 8968 D0 3F .?
+L896A: inc $0683 ; 896A EE 83 06 ...
+ inc $0683 ; 896D EE 83 06 ...
+ lda $0683 ; 8970 AD 83 06 ...
+ sta AUDF1 ; 8973 8D 00 D2 ...
+ lda #$A3 ; 8976 A9 A3 ..
+ sta AUDC1 ; 8978 8D 01 D2 ...
+ lda collision_save+4 ; 897B AD B4 06 ...
+ and #$01 ; 897E 29 01 ).
+ bne falling_bounce ; 8980 D0 01 ..
+ rts ; 8982 60 `
+
+; ----------------------------------------------------------------------------
+; this looks like it hurts...
+falling_bounce:
+ lda RANDOM ; 8983 AD 0A D2 ...
+ and #$03 ; 8986 29 03 ).
+ beq falling_bounce ; 8988 F0 F9 ..
+ sta $06E9 ; 898A 8D E9 06 ...
+ lda #$00 ; 898D A9 00 ..
+ sta $06EA ; 898F 8D EA 06 ...
+ lda #$50 ; 8992 A9 50 .P
+ sta $0801 ; 8994 8D 01 08 ...
+ sta game_display_list ; 8997 8D 81 08 ...
+play_sfx_bounce_1:
+ lda #$4B ; 899A A9 4B .K
+ sta sfx_slot_tempo ; 899C 8D 3E 06 .>.
+ lda #$8A ; 899F A9 8A ..
+ sta sfx_slot_timer ; 89A1 8D 3F 06 .?.
+ lda #$04 ; 89A4 A9 04 ..
+ jsr L8003 ; 89A6 20 03 80 ..
+L89A9: ldx $06EA ; 89A9 AE EA 06 ...
+ cpx #$09 ; 89AC E0 09 ..
+ bne L89B8 ; 89AE D0 08 ..
+ lda #$00 ; 89B0 A9 00 ..
+ sta $06EA ; 89B2 8D EA 06 ...
+ jmp L896A ; 89B5 4C 6A 89 Lj.
+
+; ----------------------------------------------------------------------------
+L89B8: ldy data_table_8a39,x ; 89B8 BC 39 8A .9.
+ lda $06E9 ; 89BB AD E9 06 ...
+ cmp #$01 ; 89BE C9 01 ..
+ beq L89D1 ; 89C0 F0 0F ..
+ ldy #$00 ; 89C2 A0 00 ..
+ cmp #$02 ; 89C4 C9 02 ..
+ beq L89D1 ; 89C6 F0 09 ..
+ lda data_table_8a39,x ; 89C8 BD 39 8A .9.
+ eor #$FF ; 89CB 49 FF I.
+ clc ; 89CD 18 .
+ adc #$01 ; 89CE 69 01 i.
+ tay ; 89D0 A8 .
+L89D1: clc ; 89D1 18 .
+ tya ; 89D2 98 .
+ adc $067E ; 89D3 6D 7E 06 m~.
+ sta $067E ; 89D6 8D 7E 06 .~.
+ lda L8A42,x ; 89D9 BD 42 8A .B.
+ clc ; 89DC 18 .
+ adc $0683 ; 89DD 6D 83 06 m..
+ sta $0683 ; 89E0 8D 83 06 ...
+ sta AUDF1 ; 89E3 8D 00 D2 ...
+ inc $06EA ; 89E6 EE EA 06 ...
+ clc ; 89E9 18 .
+ lda $0620 ; 89EA AD 20 06 . .
+ adc #$12 ; 89ED 69 12 i.
+ sta $0688 ; 89EF 8D 88 06 ...
+ rts ; 89F2 60 `
+
+; ----------------------------------------------------------------------------
+L89F3: lda $0623 ; 89F3 AD 23 06 .#.
+ cmp #$02 ; 89F6 C9 02 ..
+ beq L89FB ; 89F8 F0 01 ..
+ rts ; 89FA 60 `
+
+; ----------------------------------------------------------------------------
+L89FB: lda $06EF ; 89FB AD EF 06 ...
+ bne L8A16 ; 89FE D0 16 ..
+ sta jiffy_timer_2 ; 8A00 8D 1B 06 ...
+ inc $06EF ; 8A03 EE EF 06 ...
+ lda #$00 ; 8A06 A9 00 ..
+ jsr cue_music_jv ; 8A08 20 18 80 ..
+ lda #$04 ; 8A0B A9 04 ..
+ sta player_speed ; 8A0D 8D 24 06 .$.
+ lda #$16 ; 8A10 A9 16 ..
+ sta $0688 ; 8A12 8D 88 06 ...
+ rts ; 8A15 60 `
+
+; ----------------------------------------------------------------------------
+L8A16: lda $0663 ; 8A16 AD 63 06 .c.
+ beq L8A25 ; 8A19 F0 0A ..
+ lda #$16 ; 8A1B A9 16 ..
+ clc ; 8A1D 18 .
+ adc $061F ; 8A1E 6D 1F 06 m..
+ sta $0688 ; 8A21 8D 88 06 ...
+ rts ; 8A24 60 `
+
+; ----------------------------------------------------------------------------
+L8A25: lda #$09 ; 8A25 A9 09 ..
+ sta player_speed ; 8A27 8D 24 06 .$.
+ lda #$00 ; 8A2A A9 00 ..
+ sta $0623 ; 8A2C 8D 23 06 .#.
+ sta $067E ; 8A2F 8D 7E 06 .~.
+ dec lives ; 8A32 CE 0A 07 ...
+ sta $06EE ; 8A35 8D EE 06 ...
+ rts ; 8A38 60 `
+
+; ----------------------------------------------------------------------------
+data_table_8a39:
+ .byte $02,$02,$02,$02,$02,$02,$00,$00 ; 8A39 02 02 02 02 02 02 00 00 ........
+ .byte $00 ; 8A41 00 .
+L8A42: .byte $FE,$FE,$00,$00,$02,$02,$02,$02 ; 8A42 FE FE 00 00 02 02 02 02 ........
+ .byte $02 ; 8A4A 02 .
+; used when jumpman is falling?
+sfx_bounce_1:
+ .byte $01,$8E,$00,$30,$01,$01,$8B,$00 ; 8A4B 01 8E 00 30 01 01 8B 00 ...0....
+ .byte $40,$01,$01,$88,$00,$50,$01,$01 ; 8A53 40 01 01 88 00 50 01 01 @....P..
+ .byte $85,$00,$60,$01,$00 ; 8A5B 85 00 60 01 00 ..`..
+; jumpman hit by bullet or started falling
+sfx_death:
+ .byte $01,$C8,$00,$0A,$02,$FA,$02,$14 ; 8A60 01 C8 00 0A 02 FA 02 14 ........
+ .byte $02,$F0,$02,$1E,$02,$E8,$02,$28 ; 8A68 02 F0 02 1E 02 E8 02 28 .......(
+ .byte $02,$DC,$02,$32,$02,$D2,$02,$3C ; 8A70 02 DC 02 32 02 D2 02 3C ...2...<
+ .byte $02,$C8,$02,$00,$00,$00,$00,$00 ; 8A78 02 C8 02 00 00 00 00 00 ........
+; ----------------------------------------------------------------------------
+play_sfx_bounce_2:
+ lda $061F ; 8A80 AD 1F 06 ...
+ bne L8A94 ; 8A83 D0 0F ..
+ lda #$97 ; 8A85 A9 97 ..
+ sta sfx_slot_tempo ; 8A87 8D 3E 06 .>.
+ lda #$8A ; 8A8A A9 8A ..
+ sta sfx_slot_timer ; 8A8C 8D 3F 06 .?.
+ lda #$02 ; 8A8F A9 02 ..
+ jsr L8003 ; 8A91 20 03 80 ..
+L8A94: jmp L9925 ; 8A94 4C 25 99 L%.
+
+; ----------------------------------------------------------------------------
+; used when jumpman is falling?
+sfx_bounce_2:
+ .byte $01,$81,$00,$04,$01,$00,$00,$00 ; 8A97 01 81 00 04 01 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 8A9F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 8AA7 00 00 00 00 00 00 00 00 ........
+ .byte $00 ; 8AAF 00 .
+sfx_option_pressed:
+ .byte $01,$A4,$00,$3C,$02,$00,$00,$00 ; 8AB0 01 A4 00 3C 02 00 00 00 ...<....
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 8AB8 00 00 00 00 00 00 00 00 ........
+; ----------------------------------------------------------------------------
+cart_entry_point:
+ ldx #$00 ; 8AC0 A2 00 ..
+ lda #$00 ; 8AC2 A9 00 ..
+; clear pages 6 and 7
+init_loop:
+ sta $0600,x ; 8AC4 9D 00 06 ...
+ sta score,x ; 8AC7 9D 00 07 ...
+ inx ; 8ACA E8 .
+ bne init_loop ; 8ACB D0 F7 ..
+ jsr init_hardware ; 8ACD 20 7C 83 |.
+ lda #$DD ; 8AD0 A9 DD ..
+ sta dlist_shadow_lo ; 8AD2 8D AC 06 ...
+ lda #$8A ; 8AD5 A9 8A ..
+ sta dlist_shadow_hi ; 8AD7 8D AD 06 ...
+ jmp init_game ; 8ADA 4C 00 90 L..
+
+; ----------------------------------------------------------------------------
+; yet another jump-to-itself empty display list
+blank_dlist_8add:
+ .byte $41,$DD,$8A ; 8ADD 41 DD 8A A..
+; ----------------------------------------------------------------------------
+L8AE0: lda #$EB ; 8AE0 A9 EB ..
+ sta dlist_shadow_lo ; 8AE2 8D AC 06 ...
+ lda #$8A ; 8AE5 A9 8A ..
+ sta dlist_shadow_hi ; 8AE7 8D AD 06 ...
+ rts ; 8AEA 60 `
+
+; ----------------------------------------------------------------------------
+; another jump-to-itself empty display list
+blank_dlist_8aeb:
+ .byte $41,$EB,$8A ; 8AEB 41 EB 8A A..
+; ----------------------------------------------------------------------------
+ brk ; 8AEE 00 .
+ brk ; 8AEF 00 .
+ brk ; 8AF0 00 .
+ brk ; 8AF1 00 .
+ brk ; 8AF2 00 .
+ brk ; 8AF3 00 .
+ brk ; 8AF4 00 .
+ brk ; 8AF5 00 .
+ brk ; 8AF6 00 .
+ brk ; 8AF7 00 .
+ brk ; 8AF8 00 .
+ brk ; 8AF9 00 .
+ brk ; 8AFA 00 .
+ brk ; 8AFB 00 .
+ brk ; 8AFC 00 .
+ brk ; 8AFD 00 .
+cart_start_stub:
+ clc ; 8AFE 18 .
+ rts ; 8AFF 60 `
+
+; ----------------------------------------------------------------------------
+ brk ; 8B00 00 .
+ brk ; 8B01 00 .
+ brk ; 8B02 00 .
+ brk ; 8B03 00 .
+ brk ; 8B04 00 .
+ brk ; 8B05 00 .
+ brk ; 8B06 00 .
+ brk ; 8B07 00 .
+ brk ; 8B08 00 .
+ brk ; 8B09 00 .
+ brk ; 8B0A 00 .
+ brk ; 8B0B 00 .
+ brk ; 8B0C 00 .
+ brk ; 8B0D 00 .
+ brk ; 8B0E 00 .
+ brk ; 8B0F 00 .
+ brk ; 8B10 00 .
+ brk ; 8B11 00 .
+ brk ; 8B12 00 .
+ brk ; 8B13 00 .
+ brk ; 8B14 00 .
+ brk ; 8B15 00 .
+ brk ; 8B16 00 .
+ brk ; 8B17 00 .
+ brk ; 8B18 00 .
+ brk ; 8B19 00 .
+ brk ; 8B1A 00 .
+ brk ; 8B1B 00 .
+ brk ; 8B1C 00 .
+ brk ; 8B1D 00 .
+ brk ; 8B1E 00 .
+ brk ; 8B1F 00 .
+ brk ; 8B20 00 .
+ brk ; 8B21 00 .
+ brk ; 8B22 00 .
+L8B23: ldx #$20 ; 8B23 A2 20 .
+ lda #$00 ; 8B25 A9 00 ..
+L8B27: sta $075F,x ; 8B27 9D 5F 07 ._.
+ dex ; 8B2A CA .
+ bne L8B27 ; 8B2B D0 FA ..
+L8B2D: lda work_level_unkn_table0 ; 8B2D AD 94 07 ...
+ sta $AC ; 8B30 85 AC ..
+ lda work_level_unkn_table0+1 ; 8B32 AD 95 07 ...
+ sta $AD ; 8B35 85 AD ..
+ ldy #$00 ; 8B37 A0 00 ..
+L8B39: lda ($AC),y ; 8B39 B1 AC ..
+ cmp #$FF ; 8B3B C9 FF ..
+ beq L8B7A ; 8B3D F0 3B .;
+ tax ; 8B3F AA .
+ iny ; 8B40 C8 .
+ lda ($AC),y ; 8B41 B1 AC ..
+ sta $066E,x ; 8B43 9D 6E 06 .n.
+ iny ; 8B46 C8 .
+ lda ($AC),y ; 8B47 B1 AC ..
+ sta $0673,x ; 8B49 9D 73 06 .s.
+ iny ; 8B4C C8 .
+ lda ($AC),y ; 8B4D B1 AC ..
+ sta $0678,x ; 8B4F 9D 78 06 .x.
+ iny ; 8B52 C8 .
+ lda ($AC),y ; 8B53 B1 AC ..
+ sta $067D,x ; 8B55 9D 7D 06 .}.
+ iny ; 8B58 C8 .
+ lda ($AC),y ; 8B59 B1 AC ..
+ sta $0682,x ; 8B5B 9D 82 06 ...
+ iny ; 8B5E C8 .
+ lda ($AC),y ; 8B5F B1 AC ..
+ sta $0687,x ; 8B61 9D 87 06 ...
+ iny ; 8B64 C8 .
+ tya ; 8B65 98 .
+ pha ; 8B66 48 H
+ lda ($AC),y ; 8B67 B1 AC ..
+ ldy pcolor0_table,x ; 8B69 BC 7B 8B .{.
+ sta PCOLR0,y ; 8B6C 99 C0 02 ...
+ pla ; 8B6F 68 h
+ tay ; 8B70 A8 .
+ iny ; 8B71 C8 .
+ lda #$00 ; 8B72 A9 00 ..
+ sta $0696,x ; 8B74 9D 96 06 ...
+ jmp L8B39 ; 8B77 4C 39 8B L9.
+
+; ----------------------------------------------------------------------------
+L8B7A: rts ; 8B7A 60 `
+
+; ----------------------------------------------------------------------------
+pcolor0_table:
+ .byte $07,$00,$01,$02,$03 ; 8B7B 07 00 01 02 03 .....
+; ----------------------------------------------------------------------------
+; show scores, called at end of game, also called after beating level 12 (after WELL DONE). $40 in NMIEN = disable DLI, enable VBI
+player_scores_screen:
+ lda #$40 ; 8B80 A9 40 .@
+ sta NMIEN ; 8B82 8D 0E D4 ...
+ lda #$82 ; 8B85 A9 82 ..
+ sta dlist_shadow_lo ; 8B87 8D AC 06 ...
+ lda #$8C ; 8B8A A9 8C ..
+ sta dlist_shadow_hi ; 8B8C 8D AD 06 ...
+ ldx #$06 ; 8B8F A2 06 ..
+L8B91: lda scores_msg,x ; 8B91 BD 7B 8C .{.
+ sta $3006,x ; 8B94 9D 06 30 ..0
+ dex ; 8B97 CA .
+ bne L8B91 ; 8B98 D0 F7 ..
+ ldx current_player ; 8B9A AE FE 06 ...
+ ldy struct_player_lives_offsets_minus_one,x; 8B9D BC 88 8C ...
+ ldx #$03 ; 8BA0 A2 03 ..
+ lda lives ; 8BA2 AD 0A 07 ...
+ sta $0713,y ; 8BA5 99 13 07 ...
+L8BA8: lda $06FF,x ; 8BA8 BD FF 06 ...
+ sta $070B,y ; 8BAB 99 0B 07 ...
+ dey ; 8BAE 88 .
+ dex ; 8BAF CA .
+ bne L8BA8 ; 8BB0 D0 F6 ..
+ lda #$00 ; 8BB2 A9 00 ..
+ sta $AA ; 8BB4 85 AA ..
+ sta $AB ; 8BB6 85 AB ..
+ tay ; 8BB8 A8 .
+ lda number_of_players ; 8BB9 AD F4 06 ...
+ sta $AE ; 8BBC 85 AE ..
+ inc $AE ; 8BBE E6 AE ..
+; shows PLAYER (backwards loop)
+show_reyalp_msg:
+ ldx #$14 ; 8BC0 A2 14 ..
+reyalp_msg_loop:
+ lda reyalp_msg_minus_one,x ; 8BC2 BD 67 8C .g.
+ sta $3028,y ; 8BC5 99 28 30 .(0
+; replace 10th char with the ASCII player number
+check_10th:
+ cpx #$0A ; 8BC8 E0 0A ..
+ bne continue_loop ; 8BCA D0 09 ..
+ inc $AA ; 8BCC E6 AA ..
+ lda $AA ; 8BCE A5 AA ..
+ ora #$10 ; 8BD0 09 10 ..
+ sta $3028,y ; 8BD2 99 28 30 .(0
+continue_loop:
+ iny ; 8BD5 C8 .
+ dex ; 8BD6 CA .
+ bne reyalp_msg_loop ; 8BD7 D0 E9 ..
+ sty $AD ; 8BD9 84 AD ..
+ ldx $AA ; 8BDB A6 AA ..
+ ldy struct_player_lives_offsets_minus_one,x; 8BDD BC 88 8C ...
+ lda #$00 ; 8BE0 A9 00 ..
+; $AF is the character to show after the score (space for alive, cross for dead)
+store_space:
+ sta $AF ; 8BE2 85 AF ..
+ lda $0713,y ; 8BE4 B9 13 07 ...
+ cmp #$FF ; 8BE7 C9 FF ..
+; player still has lives left?
+check_alive:
+ bne no_cross ; 8BE9 D0 04 ..
+; no, show a cross instead of a space
+not_alive:
+ lda #$5E ; 8BEB A9 5E .^
+ sta $AF ; 8BED 85 AF ..
+no_cross:
+ lda L8C84,x ; 8BEF BD 84 8C ...
+ sta $D3 ; 8BF2 85 D3 ..
+ lda #$30 ; 8BF4 A9 30 .0
+ sta $D4 ; 8BF6 85 D4 ..
+ ldx #$03 ; 8BF8 A2 03 ..
+L8BFA: lda $070B,y ; 8BFA B9 0B 07 ...
+ sta $CF,x ; 8BFD 95 CF ..
+ dey ; 8BFF 88 .
+ dex ; 8C00 CA .
+ bne L8BFA ; 8C01 D0 F7 ..
+ jsr xxx_level_something_jv ; 8C03 20 09 80 ..
+ lda $AF ; 8C06 A5 AF ..
+ iny ; 8C08 C8 .
+ sta ($D3),y ; 8C09 91 D3 ..
+ ldy $AD ; 8C0B A4 AD ..
+ dec $AE ; 8C0D C6 AE ..
+ bne show_reyalp_msg ; 8C0F D0 AF ..
+ lda #$96 ; 8C11 A9 96 ..
+ sta COLOR3 ; 8C13 8D C7 02 ...
+ lda #$C6 ; 8C16 A9 C6 ..
+ sta COLOR0 ; 8C18 8D C4 02 ...
+ lda #$08 ; 8C1B A9 08 ..
+ sta COLOR1 ; 8C1D 8D C5 02 ...
+ lda #$52 ; 8C20 A9 52 .R
+; set dlist shadow to scores_screen_dlist
+show_scores_screen:
+ sta dlist_shadow_lo ; 8C22 8D AC 06 ...
+ lda #$8C ; 8C25 A9 8C ..
+ sta dlist_shadow_hi ; 8C27 8D AD 06 ...
+ lda #$8D ; 8C2A A9 8D ..
+ sta dli_vec_shadow_lo ; 8C2C 8D AE 06 ...
+ lda #$8C ; 8C2F A9 8C ..
+; dli = score_screen_dli_sr
+set_score_screen_dli:
+ sta dli_vec_shadow_hi ; 8C31 8D AF 06 ...
+ lda #$02 ; 8C34 A9 02 ..
+ jsr cue_music_jv ; 8C36 20 18 80 ..
+; I *think* we're waiting for the music to finish playing...
+what_are_we_waiting_for:
+ lda $0640 ; 8C39 AD 40 06 .@.
+ ora $0642 ; 8C3C 0D 42 06 .B.
+ ora $0644 ; 8C3F 0D 44 06 .D.
+ ora sfx_slot_duration ; 8C42 0D 46 06 .F.
+ bne what_are_we_waiting_for ; 8C45 D0 F2 ..
+ sta jiffy_timer_1 ; 8C47 8D 1A 06 ...
+; wait 192 jiffies: 3.2 sec (ntsc), 3.84 sec (pal)
+wait_3_sec:
+ lda jiffy_timer_1 ; 8C4A AD 1A 06 ...
+ cmp #$C0 ; 8C4D C9 C0 ..
+ bne wait_3_sec ; 8C4F D0 F9 ..
+ rts ; 8C51 60 `
+
+; ----------------------------------------------------------------------------
+; a GR.2-ish DL, with DLIs, screen mem at $3000, for player scores screen
+scores_screen_dlist:
+ .byte $70,$70,$70,$30,$70,$70,$70,$70 ; 8C52 70 70 70 30 70 70 70 70 ppp0pppp
+ .byte $47,$00,$30,$87,$87,$10,$87,$10 ; 8C5A 47 00 30 87 87 10 87 10 G.0.....
+ .byte $87,$10,$07,$41,$52 ; 8C62 87 10 07 41 52 ...AR
+reyalp_msg_minus_one:
+ .byte $8C ; 8C67 8C .
+; player spelled backwards: ' 0 # REYALP '
+reyalp_msg:
+ .byte $80,$80,$10,$80,$80,$80,$80,$80 ; 8C68 80 80 10 80 80 80 80 80 ........
+ .byte $80,$80,$03,$80,$32,$25,$39,$21 ; 8C70 80 80 03 80 32 25 39 21 ....2%9!
+ .byte $2C,$30,$80 ; 8C78 2C 30 80 ,0.
+; ' SCORES' in color 3
+scores_msg:
+ .byte $80,$F3,$E3,$EF,$F2,$E5,$F3 ; 8C7B 80 F3 E3 EF F2 E5 F3 .......
+; looks like an empty jump-to-itself dlist
+blank_dlist_8c82:
+ .byte $41,$82 ; 8C82 41 82 A.
+L8C84: .byte $8C ; 8C84 8C .
+; offsets into screen memory, column 12, rows 2 3 4 5, used by code at $8BEF, loaded in $d3, hi byte in $d4 is $30
+score_offsets:
+ .byte $34,$48,$5C ; 8C85 34 48 5C 4H\
+struct_player_lives_offsets_minus_one:
+ .byte $70 ; 8C88 70 p
+; lookup table, offset from $713 to lives for indexed player
+struct_player_lives_offsets:
+ .byte $02,$0D,$18,$23 ; 8C89 02 0D 18 23 ...#
+; ----------------------------------------------------------------------------
+; used by score screen
+score_screen_dli_sr:
+ pha ; 8C8D 48 H
+ lda current_player ; 8C8E AD FE 06 ...
+ sec ; 8C91 38 8
+ sbc #$01 ; 8C92 E9 01 ..
+ sta WSYNC ; 8C94 8D 0A D4 ...
+ cmp $AB ; 8C97 C5 AB ..
+ bne L8CA4 ; 8C99 D0 09 ..
+ lda $062A ; 8C9B AD 2A 06 .*.
+ sta COLPF0 ; 8C9E 8D 16 D0 ...
+ jmp L8CAA ; 8CA1 4C AA 8C L..
+
+; ----------------------------------------------------------------------------
+L8CA4: lda COLOR0 ; 8CA4 AD C4 02 ...
+ sta COLPF0 ; 8CA7 8D 16 D0 ...
+L8CAA: inc $AB ; 8CAA E6 AB ..
+ lda $AB ; 8CAC A5 AB ..
+ and #$03 ; 8CAE 29 03 ).
+ sta $AB ; 8CB0 85 AB ..
+ pla ; 8CB2 68 h
+ rti ; 8CB3 40 @
+
+; ----------------------------------------------------------------------------
+ brk ; 8CB4 00 .
+ brk ; 8CB5 00 .
+ brk ; 8CB6 00 .
+ brk ; 8CB7 00 .
+ brk ; 8CB8 00 .
+ brk ; 8CB9 00 .
+ brk ; 8CBA 00 .
+ brk ; 8CBB 00 .
+L8CBC: ldx #$03 ; 8CBC A2 03 ..
+L8CBE: lda $06FF,x ; 8CBE BD FF 06 ...
+ cmp score+2,x ; 8CC1 DD 02 07 ...
+ bcc L8CFA ; 8CC4 90 34 .4
+ beq L8CCB ; 8CC6 F0 03 ..
+ jmp show_l_equals ; 8CC8 4C CE 8C L..
+
+; ----------------------------------------------------------------------------
+L8CCB: dex ; 8CCB CA .
+ bne L8CBE ; 8CCC D0 F0 ..
+; L= (for lives display)
+show_l_equals:
+ ldx #$00 ; 8CCE A2 00 ..
+ clc ; 8CD0 18 .
+L8CD1: lda l_equals,x ; 8CD1 BD FD 8C ...
+ adc $0703,x ; 8CD4 7D 03 07 }..
+ sta $0703,x ; 8CD7 9D 03 07 ...
+ inx ; 8CDA E8 .
+ php ; 8CDB 08 .
+ cpx #$03 ; 8CDC E0 03 ..
+ beq add_extra_life ; 8CDE F0 04 ..
+ plp ; 8CE0 28 (
+ jmp L8CD1 ; 8CE1 4C D1 8C L..
+
+; ----------------------------------------------------------------------------
+; plays sfx_extra_life
+add_extra_life:
+ plp ; 8CE4 28 (
+ inc lives ; 8CE5 EE 0A 07 ...
+ lda #$79 ; 8CE8 A9 79 .y
+ sta sfx_ptr ; 8CEA 8D 3C 06 .<.
+ lda #$BE ; 8CED A9 BE ..
+ sta sfx_ptr+1 ; 8CEF 8D 3D 06 .=.
+ lda #$0C ; 8CF2 A9 0C ..
+ jsr cue_sfx_jv ; 8CF4 20 06 80 ..
+ jsr show_lives_icons ; 8CF7 20 BB 86 ..
+L8CFA: jmp LB7C0 ; 8CFA 4C C0 B7 L..
+
+; ----------------------------------------------------------------------------
+; L= (for lives display)
+l_equals:
+ .byte $4C,$1D,$00 ; 8CFD 4C 1D 00 L..
+; ----------------------------------------------------------------------------
+; just lost your last life
+crumble_gameboard:
+ jsr enable_joystick_jv ; 8D00 20 1B 80 ..
+ lda #$86 ; 8D03 A9 86 ..
+ sta AUDC1 ; 8D05 8D 01 D2 ...
+L8D08: lda RANDOM ; 8D08 AD 0A D2 ...
+ and #$70 ; 8D0B 29 70 )p
+ sta $0801 ; 8D0D 8D 01 08 ...
+ sta game_display_list ; 8D10 8D 81 08 ...
+ lda RANDOM ; 8D13 AD 0A D2 ...
+ sta AUDF1 ; 8D16 8D 00 D2 ...
+L8D19: lda RANDOM ; 8D19 AD 0A D2 ...
+ and #$1F ; 8D1C 29 1F ).
+ cmp #$0D ; 8D1E C9 0D ..
+ bcs L8D19 ; 8D20 B0 F7 ..
+ sta $AA ; 8D22 85 AA ..
+ asl a ; 8D24 0A .
+ clc ; 8D25 18 .
+ adc $AA ; 8D26 65 AA e.
+ sta $AA ; 8D28 85 AA ..
+ jsr L8D60 ; 8D2A 20 60 8D `.
+ inc $AA ; 8D2D E6 AA ..
+ lda $AA ; 8D2F A5 AA ..
+ pha ; 8D31 48 H
+ jsr L8D60 ; 8D32 20 60 8D `.
+ pla ; 8D35 68 h
+ jsr L8D60 ; 8D36 20 60 8D `.
+ inc $AA ; 8D39 E6 AA ..
+ lda $AA ; 8D3B A5 AA ..
+ jsr L8D60 ; 8D3D 20 60 8D `.
+ ldy #$00 ; 8D40 A0 00 ..
+ tya ; 8D42 98 .
+L8D43: ora $3370,y ; 8D43 19 70 33 .p3
+ ora $3398,y ; 8D46 19 98 33 ..3
+ iny ; 8D49 C8 .
+ cpy #$28 ; 8D4A C0 28 .(
+ bne L8D43 ; 8D4C D0 F5 ..
+ cmp #$00 ; 8D4E C9 00 ..
+ bne L8D08 ; 8D50 D0 B6 ..
+ lda #$00 ; 8D52 A9 00 ..
+ sta AUDF1 ; 8D54 8D 00 D2 ...
+ sta AUDC1 ; 8D57 8D 01 D2 ...
+ jsr player_scores_screen ; 8D5A 20 80 8B ..
+ jmp afterlife ; 8D5D 4C 00 96 L..
+
+; ----------------------------------------------------------------------------
+L8D60: clc ; 8D60 18 .
+ adc #$70 ; 8D61 69 70 ip
+ sta $AC ; 8D63 85 AC ..
+ adc #$28 ; 8D65 69 28 i(
+ sta $AE ; 8D67 85 AE ..
+ lda #$3D ; 8D69 A9 3D .=
+ sta $AD ; 8D6B 85 AD ..
+ sta $AF ; 8D6D 85 AF ..
+ lda #$57 ; 8D6F A9 57 .W
+ sta $AB ; 8D71 85 AB ..
+ ldy #$00 ; 8D73 A0 00 ..
+L8D75: lda ($AC),y ; 8D75 B1 AC ..
+ sta ($AE),y ; 8D77 91 AE ..
+ sec ; 8D79 38 8
+ lda $AC ; 8D7A A5 AC ..
+ sbc #$28 ; 8D7C E9 28 .(
+ sta $AC ; 8D7E 85 AC ..
+ bcs L8D84 ; 8D80 B0 02 ..
+ dec $AD ; 8D82 C6 AD ..
+L8D84: sec ; 8D84 38 8
+ lda $AE ; 8D85 A5 AE ..
+ sbc #$28 ; 8D87 E9 28 .(
+ sta $AE ; 8D89 85 AE ..
+ bcs L8D8F ; 8D8B B0 02 ..
+ dec $AF ; 8D8D C6 AF ..
+L8D8F: dec $AB ; 8D8F C6 AB ..
+ bne L8D75 ; 8D91 D0 E2 ..
+ tya ; 8D93 98 .
+ sta ($AE),y ; 8D94 91 AE ..
+ rts ; 8D96 60 `
+
+; ----------------------------------------------------------------------------
+ brk ; 8D97 00 .
+ brk ; 8D98 00 .
+ brk ; 8D99 00 .
+ brk ; 8D9A 00 .
+ brk ; 8D9B 00 .
+ brk ; 8D9C 00 .
+ brk ; 8D9D 00 .
+ brk ; 8D9E 00 .
+ brk ; 8D9F 00 .
+L8DA0: lda level ; 8DA0 AD F6 06 ...
+ cmp #$0B ; 8DA3 C9 0B ..
+ beq L8DAA ; 8DA5 F0 03 ..
+ jmp afterlife ; 8DA7 4C 00 96 L..
+
+; ----------------------------------------------------------------------------
+L8DAA: jsr well_done_screen ; 8DAA 20 00 BC ..
+ lda #$04 ; 8DAD A9 04 ..
+ sta $0688 ; 8DAF 8D 88 06 ...
+ jsr player_scores_screen ; 8DB2 20 80 8B ..
+ jmp afterlife ; 8DB5 4C 00 96 L..
+
+; ----------------------------------------------------------------------------
+; move player selected by X reg minus one off the left edge of the screen
+hide_player:
+ lda #$02 ; 8DB8 A9 02 ..
+ sta HPOSM3,x ; 8DBA 9D 07 D0 ...
+ sta $067C,x ; 8DBD 9D 7C 06 .|.
+ lda #$00 ; 8DC0 A9 00 ..
+ sta $06EA,x ; 8DC2 9D EA 06 ...
+ rts ; 8DC5 60 `
+
+; ----------------------------------------------------------------------------
+; store A to AUDCx (and its ?shadow?)
+store_audc:
+ sta AUDC1,x ; 8DC6 9D 01 D2 ...
+ sta $0649,x ; 8DC9 9D 49 06 .I.
+ rts ; 8DCC 60 `
+
+; ----------------------------------------------------------------------------
+ brk ; 8DCD 00 .
+; bonus -= 100;
+decrement_time_bonus:
+ lda work_level_time_bonus ; 8DCE AD 91 07 ...
+ ora work_level_time_bonus+1 ; 8DD1 0D 92 07 ...
+ ora work_level_offs_19 ; 8DD4 0D 93 07 ...
+; don't decrement if bonus == 0
+check_bonus_0:
+ beq dec_done ; 8DD7 F0 20 .
+ lda work_level_time_bonus ; 8DD9 AD 91 07 ...
+ sec ; 8DDC 38 8
+ sbc #$64 ; 8DDD E9 64 .d
+ sta work_level_time_bonus ; 8DDF 8D 91 07 ...
+ bcs bonus_lt_256 ; 8DE2 B0 03 ..
+ dec work_level_time_bonus+1 ; 8DE4 CE 92 07 ...
+bonus_lt_256:
+ jsr L800F ; 8DE7 20 0F 80 ..
+ lda #$FA ; 8DEA A9 FA ..
+ sta sfx_slot_tempo ; 8DEC 8D 3E 06 .>.
+ lda #$8D ; 8DEF A9 8D ..
+ sta sfx_slot_timer ; 8DF1 8D 3F 06 .?.
+ lda #$07 ; 8DF4 A9 07 ..
+ jsr L8003 ; 8DF6 20 03 80 ..
+dec_done:
+ rts ; 8DF9 60 `
+
+; ----------------------------------------------------------------------------
+data_8dfa:
+ .byte $01,$A5,$00,$18,$03,$00 ; 8DFA 01 A5 00 18 03 00 ......
+; ----------------------------------------------------------------------------
+level_finished:
+ lda #$09 ; 8E00 A9 09 ..
+ sta player_speed ; 8E02 8D 24 06 .$.
+ sta $067F ; 8E05 8D 7F 06 ...
+ lda #$80 ; 8E08 A9 80 ..
+ sta $D5 ; 8E0A 85 D5 ..
+ jsr L800F ; 8E0C 20 0F 80 ..
+; score += time_bonus;
+add_time_bonus:
+ clc ; 8E0F 18 .
+ lda work_level_time_bonus ; 8E10 AD 91 07 ...
+ adc score ; 8E13 6D 00 07 m..
+ sta score ; 8E16 8D 00 07 ...
+ lda work_level_time_bonus+1 ; 8E19 AD 92 07 ...
+ adc score+1 ; 8E1C 6D 01 07 m..
+ sta score+1 ; 8E1F 8D 01 07 ...
+ bcc lt_64k ; 8E22 90 03 ..
+ inc score+2 ; 8E24 EE 02 07 ...
+lt_64k: lda #$00 ; 8E27 A9 00 ..
+ sta AUDF1 ; 8E29 8D 00 D2 ...
+ sta $D5 ; 8E2C 85 D5 ..
+ sta AUDC1 ; 8E2E 8D 01 D2 ...
+ sta jiffy_timer_1 ; 8E31 8D 1A 06 ...
+ sta playing_level ; 8E34 8D 27 06 .'.
+ jsr L800C ; 8E37 20 0C 80 ..
+; 533ms ntsc, 640ms pal
+wait_32_jiffies:
+ lda jiffy_timer_1 ; 8E3A AD 1A 06 ...
+ cmp #$20 ; 8E3D C9 20 .
+ bne wait_32_jiffies ; 8E3F D0 F9 ..
+; pick random sound effect between 4 and 7
+pick_random_music:
+ lda RANDOM ; 8E41 AD 0A D2 ...
+ and #$03 ; 8E44 29 03 ).
+ clc ; 8E46 18 .
+ adc #$04 ; 8E47 69 04 i.
+ jsr cue_music_jv ; 8E49 20 18 80 ..
+L8E4C: lda $0640 ; 8E4C AD 40 06 .@.
+ ora $0642 ; 8E4F 0D 42 06 .B.
+ ora $0644 ; 8E52 0D 44 06 .D.
+ ora sfx_slot_duration ; 8E55 0D 46 06 .F.
+ bne L8E4C ; 8E58 D0 F2 ..
+ sta jiffy_timer_1 ; 8E5A 8D 1A 06 ...
+L8E5D: lda jiffy_timer_1 ; 8E5D AD 1A 06 ...
+ cmp #$40 ; 8E60 C9 40 .@
+ bne L8E5D ; 8E62 D0 F9 ..
+ jmp end_of_level_bonus ; 8E64 4C 00 B8 L..
+
+; ----------------------------------------------------------------------------
+ brk ; 8E67 00 .
+ brk ; 8E68 00 .
+ lda $0622 ; 8E69 AD 22 06 .".
+ beq L8E75 ; 8E6C F0 07 ..
+ lda $0623 ; 8E6E AD 23 06 .#.
+ cmp #$02 ; 8E71 C9 02 ..
+ bne L8E76 ; 8E73 D0 01 ..
+L8E75: rts ; 8E75 60 `
+
+; ----------------------------------------------------------------------------
+L8E76: ldx #$FF ; 8E76 A2 FF ..
+L8E78: inx ; 8E78 E8 .
+ cpx work_level_bullet_chance ; 8E79 EC 8B 07 ...
+ beq L8E75 ; 8E7C F0 F7 ..
+ lda $0756,x ; 8E7E BD 56 07 .V.
+ bne L8EB9 ; 8E81 D0 36 .6
+ inc $0756,x ; 8E83 FE 56 07 .V.
+L8E86: lda RANDOM ; 8E86 AD 0A D2 ...
+ and #$03 ; 8E89 29 03 ).
+ beq L8E86 ; 8E8B F0 F9 ..
+ tay ; 8E8D A8 .
+ lda RANDOM ; 8E8E AD 0A D2 ...
+ sta $069B,x ; 8E91 9D 9B 06 ...
+ sta $069F,x ; 8E94 9D 9F 06 ...
+ lda L8F42,y ; 8E97 B9 42 8F .B.
+ beq L8E9F ; 8E9A F0 03 ..
+ sta $069B,x ; 8E9C 9D 9B 06 ...
+L8E9F: lda L8F45,y ; 8E9F B9 45 8F .E.
+ beq L8EA7 ; 8EA2 F0 03 ..
+ sta $069F,x ; 8EA4 9D 9F 06 ...
+L8EA7: lda RANDOM ; 8EA7 AD 0A D2 ...
+ and #$03 ; 8EAA 29 03 ).
+ tay ; 8EAC A8 .
+ lda L8F49,y ; 8EAD B9 49 8F .I.
+ sta $075A,x ; 8EB0 9D 5A 07 .Z.
+ lda L8F4D,y ; 8EB3 B9 4D 8F .M.
+ sta $075E,x ; 8EB6 9D 5E 07 .^.
+L8EB9: cmp #$02 ; 8EB9 C9 02 ..
+ beq L8F11 ; 8EBB F0 54 .T
+ lda $069B,x ; 8EBD BD 9B 06 ...
+ sec ; 8EC0 38 8
+ sbc #$03 ; 8EC1 E9 03 ..
+ cmp $067E ; 8EC3 CD 7E 06 .~.
+ beq L8ED6 ; 8EC6 F0 0E ..
+ lda $069F,x ; 8EC8 BD 9F 06 ...
+ sec ; 8ECB 38 8
+ sbc #$04 ; 8ECC E9 04 ..
+ cmp $0683 ; 8ECE CD 83 06 ...
+ beq L8EE4 ; 8ED1 F0 11 ..
+ jmp L8F11 ; 8ED3 4C 11 8F L..
+
+; ----------------------------------------------------------------------------
+L8ED6: ldy #$00 ; 8ED6 A0 00 ..
+ lda $069F,x ; 8ED8 BD 9F 06 ...
+ cmp $0683 ; 8EDB CD 83 06 ...
+ bcs L8EEF ; 8EDE B0 0F ..
+ iny ; 8EE0 C8 .
+ jmp L8EEF ; 8EE1 4C EF 8E L..
+
+; ----------------------------------------------------------------------------
+L8EE4: ldy #$02 ; 8EE4 A0 02 ..
+ lda $069B,x ; 8EE6 BD 9B 06 ...
+ cmp $067E ; 8EE9 CD 7E 06 .~.
+ bcs L8EEF ; 8EEC B0 01 ..
+ iny ; 8EEE C8 .
+L8EEF: lda L8F51,y ; 8EEF B9 51 8F .Q.
+ sta $075A,x ; 8EF2 9D 5A 07 .Z.
+ lda L8F55,y ; 8EF5 B9 55 8F .U.
+ sta $075E,x ; 8EF8 9D 5E 07 .^.
+ lda #$59 ; 8EFB A9 59 .Y
+ sta sfx_slot_tempo ; 8EFD 8D 3E 06 .>.
+ lda #$8F ; 8F00 A9 8F ..
+ sta sfx_slot_timer ; 8F02 8D 3F 06 .?.
+ txa ; 8F05 8A .
+ pha ; 8F06 48 H
+ lda #$02 ; 8F07 A9 02 ..
+ jsr L8003 ; 8F09 20 03 80 ..
+ pla ; 8F0C 68 h
+ tax ; 8F0D AA .
+ inc $0756,x ; 8F0E FE 56 07 .V.
+L8F11: lda $069B,x ; 8F11 BD 9B 06 ...
+ clc ; 8F14 18 .
+ adc $075A,x ; 8F15 7D 5A 07 }Z.
+ cmp #$03 ; 8F18 C9 03 ..
+ bcc code_8f38 ; 8F1A 90 1C ..
+ cmp #$FD ; 8F1C C9 FD ..
+ bcs code_8f38 ; 8F1E B0 18 ..
+ sta $069B,x ; 8F20 9D 9B 06 ...
+ lda $069F,x ; 8F23 BD 9F 06 ...
+ clc ; 8F26 18 .
+ adc $075E,x ; 8F27 7D 5E 07 }^.
+ cmp #$03 ; 8F2A C9 03 ..
+ bcc code_8f38 ; 8F2C 90 0A ..
+ cmp #$CE ; 8F2E C9 CE ..
+ bcs code_8f38 ; 8F30 B0 06 ..
+ sta $069F,x ; 8F32 9D 9F 06 ...
+ jmp L8E78 ; 8F35 4C 78 8E Lx.
+
+; ----------------------------------------------------------------------------
+code_8f38:
+ lda #$00 ; 8F38 A9 00 ..
+ sta $0756,x ; 8F3A 9D 56 07 .V.
+ sta $069B,x ; 8F3D 9D 9B 06 ...
+L8F42 := * + 2
+ jmp L8E78 ; 8F40 4C 78 8E Lx.
+
+; ----------------------------------------------------------------------------
+data_8f43:
+ .byte $04,$FC ; 8F43 04 FC ..
+L8F45: .byte $00,$00,$00,$04 ; 8F45 00 00 00 04 ....
+L8F49: .byte $FF,$00,$01,$00 ; 8F49 FF 00 01 00 ....
+L8F4D: .byte $00,$FF,$00,$01 ; 8F4D 00 FF 00 01 ....
+L8F51: .byte $00,$00,$FD,$03 ; 8F51 00 00 FD 03 ....
+L8F55: .byte $FD,$03,$00,$00,$01,$8E,$00,$14 ; 8F55 FD 03 00 00 01 8E 00 14 ........
+ .byte $02,$01,$8B,$00,$14,$03,$01,$88 ; 8F5D 02 01 8B 00 14 03 01 88 ........
+ .byte $00,$14,$05,$01,$85,$00,$14,$07 ; 8F65 00 14 05 01 85 00 14 07 ........
+ .byte $01,$82,$00,$14,$09,$00 ; 8F6D 01 82 00 14 09 00 ......
+; ----------------------------------------------------------------------------
+; did any missile hit a player, or did players 2 or 3 hit a player...
+check_collisions_1:
+ lda collision_save+14 ; 8F73 AD BE 06 ...
+L8F76: ora collision_save+15 ; 8F76 0D BF 06 ...
+L8F79: ora collision_save+8 ; 8F79 0D B8 06 ...
+ ora collision_save+9 ; 8F7C 0D B9 06 ...
+ ora collision_save+10 ; 8F7F 0D BA 06 ...
+ ora collision_save+11 ; 8F82 0D BB 06 ...
+ and #$01 ; 8F85 29 01 ).
+ beq L8F91 ; 8F87 F0 08 ..
+ lda $0623 ; 8F89 AD 23 06 .#.
+ bne L8F91 ; 8F8C D0 03 ..
+ inc $0623 ; 8F8E EE 23 06 .#.
+L8F91: rts ; 8F91 60 `
+
+; ----------------------------------------------------------------------------
+; setup to play whichever music is in A reg, using 5-byte sfx stuct (a music is a pair of sfx played simultaneously)
+cue_music:
+ sta $D6 ; 8F92 85 D6 ..
+ asl a ; 8F94 0A .
+ asl a ; 8F95 0A .
+ clc ; 8F96 18 .
+ adc $D6 ; 8F97 65 D6 e.
+ sta $D6 ; 8F99 85 D6 ..
+; y = a * 5; // offset into mus_struct_table
+set_y: tay ; 8F9B A8 .
+ lda mus00_addr1,y ; 8F9C B9 C3 8F ...
+ sta sfx_ptr ; 8F9F 8D 3C 06 .<.
+ lda mus00_addr1+1,y ; 8FA2 B9 C4 8F ...
+ sta sfx_ptr+1 ; 8FA5 8D 3D 06 .=.
+ lda mus00_len_or_tempo,y ; 8FA8 B9 C7 8F ...
+ jsr cue_sfx_jv ; 8FAB 20 06 80 ..
+ ldy $D6 ; 8FAE A4 D6 ..
+ lda mus00_addr2,y ; 8FB0 B9 C5 8F ...
+ sta sfx_ptr ; 8FB3 8D 3C 06 .<.
+ lda mus00_addr2+1,y ; 8FB6 B9 C6 8F ...
+ sta sfx_ptr+1 ; 8FB9 8D 3D 06 .=.
+ lda mus00_len_or_tempo,y ; 8FBC B9 C7 8F ...
+ jsr cue_sfx_jv ; 8FBF 20 06 80 ..
+ rts ; 8FC2 60 `
+
+; ----------------------------------------------------------------------------
+; aka mus_struct_table, 5 bytes per entry
+mus00_addr1:
+ .addr sfx13 ; 8FC3 D0 BF ..
+mus00_addr2:
+ .addr sfx14 ; 8FC5 EA BF ..
+; ----------------------------------------------------------------------------
+mus00_len_or_tempo:
+ .byte $10 ; 8FC7 10 .
+; ----------------------------------------------------------------------------
+mus01_addr1:
+ .addr sfx12 ; 8FC8 BE BF ..
+mus01_addr2:
+ .addr empty_music_entry ; 8FCA FF 8F ..
+; ----------------------------------------------------------------------------
+mus01_len_or_tempo:
+ .byte $07 ; 8FCC 07 .
+; ----------------------------------------------------------------------------
+; end of game tune
+mus02_addr1:
+ .addr sfx02 ; 8FCD 8D BE ..
+mus02_addr2:
+ .addr sfx03 ; 8FCF AF BE ..
+; ----------------------------------------------------------------------------
+mus02_len_or_tempo:
+ .byte $10 ; 8FD1 10 .
+; ----------------------------------------------------------------------------
+mus03_addr1:
+ .addr sfx01 ; 8FD2 25 BE %.
+mus03_addr2:
+ .addr sfx00 ; 8FD4 F2 BD ..
+; ----------------------------------------------------------------------------
+mus03_len_or_tempo:
+ .byte $10 ; 8FD6 10 .
+; ----------------------------------------------------------------------------
+mus04_addr1:
+ .addr sfx04 ; 8FD7 D5 BE ..
+mus04_addr2:
+ .addr sfx05 ; 8FD9 ED BE ..
+; ----------------------------------------------------------------------------
+mus04_len_or_tempo:
+ .byte $10 ; 8FDB 10 .
+; ----------------------------------------------------------------------------
+mus05_addr1:
+ .addr sfx06 ; 8FDC 14 BF ..
+mus05_addr2:
+ .addr sfx07 ; 8FDE 30 BF 0.
+; ----------------------------------------------------------------------------
+mus05_len_or_tempo:
+ .byte $10 ; 8FE0 10 .
+; ----------------------------------------------------------------------------
+mus06_addr1:
+ .addr sfx08 ; 8FE1 4A BF J.
+mus06_addr2:
+ .addr sfx09 ; 8FE3 60 BF `.
+; ----------------------------------------------------------------------------
+mus06_len_or_tempo:
+ .byte $10 ; 8FE5 10 .
+; ----------------------------------------------------------------------------
+mus07_addr1:
+ .addr sfx10 ; 8FE6 84 BF ..
+mus07_addr2:
+ .addr sfx11 ; 8FE8 A6 BF ..
+; ----------------------------------------------------------------------------
+mus07_len_or_tempo:
+ .byte $10 ; 8FEA 10 .
+; ----------------------------------------------------------------------------
+; tune that plays while level is being drawn
+mus08_addr1:
+ .addr sfx15 ; 8FEB BC BA ..
+mus08_addr2:
+ .addr sfx16 ; 8FED EA BA ..
+; ----------------------------------------------------------------------------
+mus08_len_or_tempo:
+ .byte $10 ; 8FEF 10 .
+; ----------------------------------------------------------------------------
+mus09_addr1:
+ .addr empty_music_entry ; 8FF0 FF 8F ..
+mus09_addr2:
+ .addr empty_music_entry ; 8FF2 FF 8F ..
+; ----------------------------------------------------------------------------
+mus09_len_or_tempo:
+ .byte $01 ; 8FF4 01 .
+; ----------------------------------------------------------------------------
+mus10_addr1:
+ .addr empty_music_entry ; 8FF5 FF 8F ..
+mus10_addr2:
+ .addr empty_music_entry ; 8FF7 FF 8F ..
+; ----------------------------------------------------------------------------
+mus10_len_or_tempo:
+ .byte $01 ; 8FF9 01 .
+; ----------------------------------------------------------------------------
+mus11_addr1:
+ .addr empty_music_entry ; 8FFA FF 8F ..
+mus11_addr2:
+ .addr empty_music_entry ; 8FFC FF 8F ..
+; ----------------------------------------------------------------------------
+mus11_len_or_tempo:
+ .byte $01 ; 8FFE 01 .
+; empty music table entries point here
+empty_music_entry:
+ .byte $00 ; 8FFF 00 .
+; ----------------------------------------------------------------------------
+; called from cart_entry_point routine
+init_game:
+ lda #$00 ; 9000 A9 00 ..
+ sta option_key_enabled ; 9002 8D C6 06 ...
+ sta start_key_enabled ; 9005 8D C8 06 ...
+ nop ; 9008 EA .
+ nop ; 9009 EA .
+ nop ; 900A EA .
+ nop ; 900B EA .
+; this entry point doesn't disable start/option keys
+reinit_game:
+ jsr enable_joystick_jv ; 900C 20 1B 80 ..
+ lda #$00 ; 900F A9 00 ..
+ sta $A0 ; 9011 85 A0 ..
+ sta select_key_vec ; 9013 8D C2 06 ...
+ lda #$94 ; 9016 A9 94 ..
+ sta select_key_vec+1 ; 9018 8D C3 06 ...
+; set select key vector to ask_num_players at $9400, enable select key
+setup_select_key_vec:
+ sta select_key_enabled ; 901B 8D C7 06 ...
+ ldx #$08 ; 901E A2 08 ..
+ lda #$FF ; 9020 A9 FF ..
+; seems to try to write $FF bytes to ROM that already contains $FF's (it's the solid block character in the font). possibly left over from early development before conversion to cartridge
+try_to_write_rom:
+ sta block_char_minus_one,x ; 9022 9D 0F 9E ...
+ dex ; 9025 CA .
+ bne try_to_write_rom ; 9026 D0 FA ..
+ ldx #$C0 ; 9028 A2 C0 ..
+copy_title_screen:
+ lda title_screen_data_minus_one,x ; 902A BD CE 91 ...
+ sta $2FFF,x ; 902D 9D FF 2F ../
+ dex ; 9030 CA .
+ bne copy_title_screen ; 9031 D0 F7 ..
+ lda #$46 ; 9033 A9 46 .F
+ sta COLOR1 ; 9035 8D C5 02 ...
+ lda #$C4 ; 9038 A9 C4 ..
+ sta COLOR2 ; 903A 8D C6 02 ...
+ lda #$00 ; 903D A9 00 ..
+ sta $9C ; 903F 85 9C ..
+ sta $9D ; 9041 85 9D ..
+ sta COLOR3 ; 9043 8D C7 02 ...
+ lda #$B3 ; 9046 A9 B3 ..
+ sta dlist_shadow_lo ; 9048 8D AC 06 ...
+ lda #$91 ; 904B A9 91 ..
+ sta dlist_shadow_hi ; 904D 8D AD 06 ...
+ lda #$00 ; 9050 A9 00 ..
+ sta HSCROL ; 9052 8D 04 D4 ...
+ lda #$A5 ; 9055 A9 A5 ..
+ sta AUDC1 ; 9057 8D 01 D2 ...
+ lda #$ED ; 905A A9 ED ..
+ sta dli_vec_shadow_lo ; 905C 8D AE 06 ...
+ lda #$92 ; 905F A9 92 ..
+ sta dli_vec_shadow_hi ; 9061 8D AF 06 ...
+ lda #$3C ; 9064 A9 3C .<
+ sta work_level_sub0 ; 9066 8D 82 07 ...
+ lda #$91 ; 9069 A9 91 ..
+ sta work_level_sub0+1 ; 906B 8D 83 07 ...
+; some ISR is writing to $9c...
+wait_until_9c_is_0e:
+ lda $9C ; 906E A5 9C ..
+ cmp #$0E ; 9070 C9 0E ..
+ bne wait_until_9c_is_0e ; 9072 D0 FA ..
+ lda #$E6 ; 9074 A9 E6 ..
+ sta work_level_sub0 ; 9076 8D 82 07 ...
+ lda #$06 ; 9079 A9 06 ..
+ sta work_level_sub0+1 ; 907B 8D 83 07 ...
+ lda #$00 ; 907E A9 00 ..
+ sta sfx_ptr ; 9080 8D 3C 06 .<.
+ lda #$93 ; 9083 A9 93 ..
+ sta sfx_ptr+1 ; 9085 8D 3D 06 .=.
+ jsr cue_sfx_jv ; 9088 20 06 80 ..
+ lda #$51 ; 908B A9 51 .Q
+ sta sfx_ptr ; 908D 8D 3C 06 .<.
+ lda #$93 ; 9090 A9 93 ..
+ sta sfx_ptr+1 ; 9092 8D 3D 06 .=.
+ jsr cue_sfx_jv ; 9095 20 06 80 ..
+ lda #$9C ; 9098 A9 9C ..
+ sta sfx_ptr ; 909A 8D 3C 06 .<.
+ lda #$93 ; 909D A9 93 ..
+ sta sfx_ptr+1 ; 909F 8D 3D 06 .=.
+ jsr cue_sfx_jv ; 90A2 20 06 80 ..
+ lda #$D7 ; 90A5 A9 D7 ..
+ sta sfx_ptr ; 90A7 8D 3C 06 .<.
+ lda #$93 ; 90AA A9 93 ..
+ sta sfx_ptr+1 ; 90AC 8D 3D 06 .=.
+ jsr cue_sfx_jv ; 90AF 20 06 80 ..
+ lda #$00 ; 90B2 A9 00 ..
+ sta $9C ; 90B4 85 9C ..
+ sta $9D ; 90B6 85 9D ..
+ lda #$07 ; 90B8 A9 07 ..
+ sta $B9 ; 90BA 85 B9 ..
+ lda #$72 ; 90BC A9 72 .r
+ sta work_level_sub0 ; 90BE 8D 82 07 ...
+ lda #$91 ; 90C1 A9 91 ..
+ sta work_level_sub0+1 ; 90C3 8D 83 07 ...
+ ldx #$FF ; 90C6 A2 FF ..
+; lot going on here, not understood yet
+funky_init_loop:
+ inx ; 90C8 E8 .
+ cpx #$02 ; 90C9 E0 02 ..
+ beq funky_init_loop ; 90CB F0 FB ..
+ cpx #$05 ; 90CD E0 05 ..
+ beq L910A ; 90CF F0 39 .9
+ ldy L92A3,x ; 90D1 BC A3 92 ...
+L90D4: lda $0649,y ; 90D4 B9 49 06 .I.
+ and #$0F ; 90D7 29 0F ).
+ beq L90D4 ; 90D9 F0 F9 ..
+ lda #$00 ; 90DB A9 00 ..
+ sta $066E,x ; 90DD 9D 6E 06 .n.
+ lda #$9D ; 90E0 A9 9D ..
+ sta $0673,x ; 90E2 9D 73 06 .s.
+ lda #$0A ; 90E5 A9 0A ..
+ sta $0678,x ; 90E7 9D 78 06 .x.
+ lda #$01 ; 90EA A9 01 ..
+ sta $0687,x ; 90EC 9D 87 06 ...
+ lda #$5C ; 90EF A9 5C .\
+ sta $0682,x ; 90F1 9D 82 06 ...
+ lda L929E,x ; 90F4 BD 9E 92 ...
+ sta $067D,x ; 90F7 9D 7D 06 .}.
+ sta $0669,x ; 90FA 9D 69 06 .i.
+ ldy L92E8,x ; 90FD BC E8 92 ...
+ lda #$0F ; 9100 A9 0F ..
+ sta PCOLR0,y ; 9102 99 C0 02 ...
+ inc $9C ; 9105 E6 9C ..
+ jmp funky_init_loop ; 9107 4C C8 90 L..
+
+; ----------------------------------------------------------------------------
+L910A: lda $9D ; 910A A5 9D ..
+ cmp #$1D ; 910C C9 1D ..
+ beq try_to_write_rom_again ; 910E F0 16 ..
+ cmp #$20 ; 9110 C9 20 .
+ bcc L910A ; 9112 90 F6 ..
+ lda #$E6 ; 9114 A9 E6 ..
+ sta work_level_sub0 ; 9116 8D 82 07 ...
+ lda #$06 ; 9119 A9 06 ..
+ sta work_level_sub0+1 ; 911B 8D 83 07 ...
+ lda #$08 ; 911E A9 08 ..
+ sta COLOR0 ; 9120 8D C4 02 ...
+ jmp LB96B ; 9123 4C 6B B9 Lk.
+
+; ----------------------------------------------------------------------------
+; see comment at try_to_write_rom
+try_to_write_rom_again:
+ ldx #$08 ; 9126 A2 08 ..
+L9128: lda L9133,x ; 9128 BD 33 91 .3.
+ sta block_char_minus_one,x ; 912B 9D 0F 9E ...
+ dex ; 912E CA .
+ bne L9128 ; 912F D0 F7 ..
+L9133 := * + 2
+ jmp L910A ; 9131 4C 0A 91 L..
+
+; ----------------------------------------------------------------------------
+data_9134:
+ .byte $BF,$BF,$CF,$EF,$E7,$DB ; 9134 BF BF CF EF E7 DB ......
+; ----------------------------------------------------------------------------
+; this might be more data for the above table instead of code?
+maybe_data:
+ cmp LADBF,y ; 913A D9 BF AD ...
+; this probably really is code
+probly_code:
+ rol a ; 913D 2A *
+ asl $8D ; 913E 06 8D ..
+ cpy $02 ; 9140 C4 02 ..
+ ldy $9C ; 9142 A4 9C ..
+ cpy #$07 ; 9144 C0 07 ..
+ beq L9164 ; 9146 F0 1C ..
+ clc ; 9148 18 .
+ lda $9D ; 9149 A5 9D ..
+ adc #$04 ; 914B 69 04 i.
+ sta $9D ; 914D 85 9D ..
+ beq L9164 ; 914F F0 13 ..
+ sta AUDF1 ; 9151 8D 00 D2 ...
+L9154: lsr a ; 9154 4A J
+ lsr a ; 9155 4A J
+ lsr a ; 9156 4A J
+ lsr a ; 9157 4A J
+ ora #$60 ; 9158 09 60 .`
+ sta COLOR3 ; 915A 8D C7 02 ...
+ lda L928F,y ; 915D B9 8F 92 ...
+ sta $3045,y ; 9160 99 45 30 .E0
+ rts ; 9163 60 `
+
+; ----------------------------------------------------------------------------
+L9164: lda $3045,y ; 9164 B9 45 30 .E0
+ and #$3F ; 9167 29 3F )?
+ sta $3045,y ; 9169 99 45 30 .E0
+ inc $9C ; 916C E6 9C ..
+ iny ; 916E C8 .
+ jmp L9154 ; 916F 4C 54 91 LT.
+
+; ----------------------------------------------------------------------------
+ lda $062A ; 9172 AD 2A 06 .*.
+ sta COLOR0 ; 9175 8D C4 02 ...
+ lda $9C ; 9178 A5 9C ..
+ cmp #$04 ; 917A C9 04 ..
+ beq L917F ; 917C F0 01 ..
+L917E: rts ; 917E 60 `
+
+; ----------------------------------------------------------------------------
+L917F: lda $0649 ; 917F AD 49 06 .I.
+ and #$0F ; 9182 29 0F ).
+ bne L917E ; 9184 D0 F8 ..
+ inc $B9 ; 9186 E6 B9 ..
+ lda $B9 ; 9188 A5 B9 ..
+ and #$0F ; 918A 29 0F ).
+ sta $B9 ; 918C 85 B9 ..
+ bne L917E ; 918E D0 EE ..
+ ldx $9D ; 9190 A6 9D ..
+ ldy #$FF ; 9192 A0 FF ..
+L9194: iny ; 9194 C8 .
+ cpy #$02 ; 9195 C0 02 ..
+ beq L9194 ; 9197 F0 FB ..
+ cpy #$05 ; 9199 C0 05 ..
+ beq L91B0 ; 919B F0 13 ..
+ lda L92C8,x ; 919D BD C8 92 ...
+ sta $0687,y ; 91A0 99 87 06 ...
+ clc ; 91A3 18 .
+ lda L92A8,x ; 91A4 BD A8 92 ...
+ adc $067D,y ; 91A7 79 7D 06 y}.
+ sta $067D,y ; 91AA 99 7D 06 .}.
+ jmp L9194 ; 91AD 4C 94 91 L..
+
+; ----------------------------------------------------------------------------
+L91B0: inc $9D ; 91B0 E6 9D ..
+ rts ; 91B2 60 `
+
+; ----------------------------------------------------------------------------
+; display list for title screen
+title_display_list:
+ .byte $70,$70,$70,$47,$00,$30,$06,$60 ; 91B3 70 70 70 47 00 30 06 60 pppG.0.`
+ .byte $60,$70,$70,$70,$70,$17,$17,$97 ; 91BB 60 70 70 70 70 17 17 97 `pppp...
+ .byte $70,$70,$70,$70,$70,$70,$70,$02 ; 91C3 70 70 70 70 70 70 70 02 ppppppp.
+ .byte $02,$41,$B3 ; 91CB 02 41 B3 .A.
+title_screen_data_minus_one:
+ .byte $91 ; 91CE 91 .
+; title screen data
+title_screen_data:
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 91CF 00 00 00 00 00 00 00 00 ........
+ .byte $65,$70,$79,$78,$00,$00,$00,$00 ; 91D7 65 70 79 78 00 00 00 00 epyx....
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 91DF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$70,$72,$65,$73,$65,$6E ; 91E7 00 00 70 72 65 73 65 6E ..presen
+ .byte $74,$73,$00,$00,$00,$00,$00,$00 ; 91EF 74 73 00 00 00 00 00 00 ts......
+ .byte $00,$00,$00,$82,$82,$82,$82,$82 ; 91F7 00 00 00 82 82 82 82 82 ........
+ .byte $82,$82,$82,$82,$82,$82,$82,$82 ; 91FF 82 82 82 82 82 82 82 82 ........
+ .byte $82,$82,$82,$82,$82,$00,$00,$00 ; 9207 82 82 82 82 82 00 00 00 ........
+ .byte $00,$00,$00,$82,$00,$00,$00,$00 ; 920F 00 00 00 82 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9217 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$82,$00,$00,$00 ; 921F 00 00 00 00 82 00 00 00 ........
+ .byte $00,$00,$00,$82,$82,$82,$82,$82 ; 9227 00 00 00 82 82 82 82 82 ........
+ .byte $82,$82,$82,$82,$82,$82,$82,$82 ; 922F 82 82 82 82 82 82 82 82 ........
+ .byte $82,$82,$82,$82,$82,$00,$00,$00 ; 9237 82 82 82 82 82 00 00 00 ........
+ .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 923F 40 40 40 40 40 40 40 40 @@@@@@@@
+ .byte $40,$40,$40,$40,$48,$63,$49,$40 ; 9247 40 40 40 40 48 63 49 40 @@@@HcI@
+ .byte $51,$59,$58,$53,$40,$62,$79,$40 ; 924F 51 59 58 53 40 62 79 40 QYXS@by@
+ .byte $65,$70,$79,$78,$40,$40,$40,$40 ; 9257 65 70 79 78 40 40 40 40 epyx@@@@
+ .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 925F 40 40 40 40 40 40 40 40 @@@@@@@@
+ .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 9267 40 40 40 40 40 40 40 40 @@@@@@@@
+ .byte $63,$72,$65,$61,$74,$65,$64,$40 ; 926F 63 72 65 61 74 65 64 40 created@
+ .byte $62,$79,$5A,$40,$72,$61,$6E,$64 ; 9277 62 79 5A 40 72 61 6E 64 byZ@rand
+ .byte $79,$40,$67,$6C,$6F,$76,$65,$72 ; 927F 79 40 67 6C 6F 76 65 72 y@glover
+ .byte $40,$40,$40,$40,$40,$40,$40,$40 ; 9287 40 40 40 40 40 40 40 40 @@@@@@@@
+L928F: .byte $EA,$F5,$ED,$F0,$ED,$E1,$EE,$00 ; 928F EA F5 ED F0 ED E1 EE 00 ........
+ .byte $EA,$F5,$EE,$E9,$EF,$F2,$00 ; 9297 EA F5 EE E9 EF F2 00 .......
+L929E: .byte $6A,$76,$00,$82,$8E ; 929E 6A 76 00 82 8E jv...
+L92A3: .byte $00,$02,$00,$04,$06 ; 92A3 00 02 00 04 06 .....
+L92A8: .byte $02,$02,$FE,$FE,$FE,$FE,$02,$02 ; 92A8 02 02 FE FE FE FE 02 02 ........
+ .byte $02,$02,$02,$02,$FE,$FE,$FE,$FE ; 92B0 02 02 02 02 FE FE FE FE ........
+ .byte $FE,$FE,$FE,$FE,$02,$02,$02,$02 ; 92B8 FE FE FE FE 02 02 02 02 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 92C0 00 00 00 00 00 00 00 00 ........
+L92C8: .byte $08,$09,$08,$09,$0C,$0D,$0C,$0D ; 92C8 08 09 08 09 0C 0D 0C 0D ........
+ .byte $08,$06,$09,$06,$08,$10,$09,$10 ; 92D0 08 06 09 06 08 10 09 10 ........
+ .byte $0C,$06,$0D,$06,$0C,$11,$0D,$11 ; 92D8 0C 06 0D 06 0C 11 0D 11 ........
+ .byte $12,$13,$14,$15,$04,$04,$04,$04 ; 92E0 12 13 14 15 04 04 04 04 ........
+L92E8: .byte $07,$00,$00,$02,$03,$48,$A9,$94 ; 92E8 07 00 00 02 03 48 A9 94 .....H..
+ .byte $8D,$0A,$D4,$8D,$18,$D0,$A9,$CA ; 92F0 8D 0A D4 8D 18 D0 A9 CA ........
+ .byte $8D,$17,$D0,$68,$40,$00,$00,$00 ; 92F8 8D 17 D0 68 40 00 00 00 ...h@...
+ .byte $01,$A0,$02,$0A,$80,$01,$A5,$02 ; 9300 01 A0 02 0A 80 01 A5 02 ........
+ .byte $3C,$20,$79,$20,$51,$20,$5B,$08 ; 9308 3C 20 79 20 51 20 5B 08 < y Q [.
+ .byte $60,$08,$6C,$08,$5B,$08,$60,$10 ; 9310 60 08 6C 08 5B 08 60 10 `.l.[.`.
+ .byte $79,$10,$5B,$08,$60,$08,$6C,$08 ; 9318 79 10 5B 08 60 08 6C 08 y.[.`.l.
+ .byte $5B,$08,$60,$10,$79,$10,$79,$20 ; 9320 5B 08 60 10 79 10 79 20 [.`.y.y
+ .byte $79,$20,$79,$08,$6C,$08,$60,$08 ; 9328 79 20 79 08 6C 08 60 08 y y.l.`.
+ .byte $51,$08,$3C,$20,$3C,$08,$51,$08 ; 9330 51 08 3C 20 3C 08 51 08 Q.< <.Q.
+ .byte $60,$08,$51,$08,$79,$20,$79,$08 ; 9338 60 08 51 08 79 20 79 08 `.Q.y y.
+ .byte $6C,$08,$60,$08,$5B,$08,$51,$08 ; 9340 6C 08 60 08 5B 08 51 08 l.`.[.Q.
+ .byte $48,$08,$40,$08,$51,$08,$3C,$40 ; 9348 48 08 40 08 51 08 3C 40 H.@.Q.<@
+ .byte $00,$01,$A0,$02,$0A,$60,$01,$A3 ; 9350 00 01 A0 02 0A 60 01 A3 .....`..
+ .byte $02,$51,$40,$79,$10,$A2,$10,$79 ; 9358 02 51 40 79 10 A2 10 79 .Q@y...y
+ .byte $10,$6C,$10,$79,$08,$A2,$08,$F3 ; 9360 10 6C 10 79 08 A2 08 F3 .l.y....
+ .byte $10,$F3,$20,$79,$08,$A2,$08,$F3 ; 9368 10 F3 20 79 08 A2 08 F3 .. y....
+ .byte $10,$A2,$10,$79,$10,$A2,$20,$F3 ; 9370 10 A2 10 79 10 A2 20 F3 ...y.. .
+ .byte $20,$79,$10,$A2,$10,$79,$10,$A2 ; 9378 20 79 10 A2 10 79 10 A2 y...y..
+ .byte $10,$79,$10,$A2,$10,$F3,$10,$F3 ; 9380 10 79 10 A2 10 F3 10 F3 .y......
+ .byte $10,$F3,$08,$D9,$08,$C1,$08,$B6 ; 9388 10 F3 08 D9 08 C1 08 B6 ........
+ .byte $08,$A2,$08,$90,$08,$80,$08,$A2 ; 9390 08 A2 08 90 08 80 08 A2 ........
+ .byte $08,$79,$40,$00,$01,$A0,$02,$0A ; 9398 08 79 40 00 01 A0 02 0A .y@.....
+ .byte $40,$01,$A4,$02,$60,$60,$01,$A0 ; 93A0 40 01 A4 02 60 60 01 A0 @...``..
+ .byte $02,$0A,$10,$01,$A3,$02,$F3,$20 ; 93A8 02 0A 10 01 A3 02 F3 20 .......
+ .byte $A2,$30,$A2,$10,$C1,$10,$02,$A6 ; 93B0 A2 30 A2 10 C1 10 02 A6 .0......
+ .byte $93,$01,$01,$A0,$02,$0A,$10,$01 ; 93B8 93 01 01 A0 02 0A 10 01 ........
+ .byte $A3,$02,$A2,$20,$A2,$20,$F3,$30 ; 93C0 A3 02 A2 20 A2 20 F3 30 ... . .0
+ .byte $01,$A0,$02,$0A,$40,$01,$A4,$02 ; 93C8 01 A0 02 0A 40 01 A4 02 ....@...
+ .byte $79,$10,$A2,$10,$F3,$20,$00,$01 ; 93D0 79 10 A2 10 F3 20 00 01 y.... ..
+ .byte $A0,$02,$0A,$20,$01,$A4,$02,$79 ; 93D8 A0 02 0A 20 01 A4 02 79 ... ...y
+ .byte $78,$01,$A0,$02,$0A,$FF,$0A,$FF ; 93E0 78 01 A0 02 0A FF 0A FF x.......
+ .byte $0A,$40,$00,$00,$00,$00,$00,$00 ; 93E8 0A 40 00 00 00 00 00 00 .@......
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 93F0 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 93F8 00 00 00 00 00 00 00 00 ........
+; ----------------------------------------------------------------------------
+ask_num_players:
+ ldx #$FF ; 9400 A2 FF ..
+ lda #$00 ; 9402 A9 00 ..
+ sta select_key_enabled ; 9404 8D C7 06 ...
+ sta level ; 9407 8D F6 06 ...
+ dec level ; 940A CE F6 06 ...
+; clear area where NUMBER OF PLAYERS? will be displayed
+anp_clear_loop:
+ sta $37FF,x ; 940D 9D FF 37 ..7
+ dex ; 9410 CA .
+ bne anp_clear_loop ; 9411 D0 FA ..
+ jsr enable_joystick_jv ; 9413 20 1B 80 ..
+ ldx #$2C ; 9416 A2 2C .,
+; copy NUMBER OF PLAYERS to screen RAM
+anp_copy_loop:
+ lda numplayer_screen_data_minus_one,x; 9418 BD 9A 95 ...
+ sta $37FF,x ; 941B 9D FF 37 ..7
+ dex ; 941E CA .
+ bne anp_copy_loop ; 941F D0 F7 ..
+; X is now 0
+anp_loop_done:
+ stx $B7 ; 9421 86 B7 ..
+ stx $B8 ; 9423 86 B8 ..
+ stx randomizer_mode ; 9425 8E F3 06 ...
+ stx COLOR4 ; 9428 8E C8 02 ...
+ lda #$04 ; 942B A9 04 ..
+ sta HSCROL ; 942D 8D 04 D4 ...
+ sta $A0 ; 9430 85 A0 ..
+ lda #$1A ; 9432 A9 1A ..
+ sta COLOR3 ; 9434 8D C7 02 ...
+ lda #$96 ; 9437 A9 96 ..
+ sta COLOR2 ; 9439 8D C6 02 ...
+ lda #$C6 ; 943C A9 C6 ..
+ sta COLOR1 ; 943E 8D C5 02 ...
+ jsr init_page_7_jv ; 9441 20 24 80 $.
+; set dlist shadow to point to numplayer_display_list
+setup_numplayer_dlist:
+ lda #$5F ; 9444 A9 5F ._
+ sta dlist_shadow_lo ; 9446 8D AC 06 ...
+ lda #$95 ; 9449 A9 95 ..
+ sta dlist_shadow_hi ; 944B 8D AD 06 ...
+; set dli vector to point to num_player_dli_service
+setup_numplayer_dli_sr:
+ lda #$78 ; 944E A9 78 .x
+ sta dli_vec_shadow_lo ; 9450 8D AE 06 ...
+ lda #$95 ; 9453 A9 95 ..
+ sta dli_vec_shadow_hi ; 9455 8D AF 06 ...
+; we'll jump to $9489 aka option_key_handler when option key is pressed
+setup_option_key_vec:
+ lda #$89 ; 9458 A9 89 ..
+ sta option_key_vec ; 945A 8D C0 06 ...
+ lda #$94 ; 945D A9 94 ..
+ sta option_key_vec+1 ; 945F 8D C1 06 ...
+ sta option_key_enabled ; 9462 8D C6 06 ...
+; we'll jump to $94de aka get_player_speeds when start key is pressed
+setup_start_key_vec:
+ lda #$DE ; 9465 A9 DE ..
+ sta start_key_vec ; 9467 8D C4 06 ...
+ lda #$94 ; 946A A9 94 ..
+ sta start_key_vec+1 ; 946C 8D C5 06 ...
+; play sfx_select_key at $95f1
+play_select_key_sfx:
+ lda #$F1 ; 946F A9 F1 ..
+ sta sfx_ptr ; 9471 8D 3C 06 .<.
+ lda #$95 ; 9474 A9 95 ..
+ sta sfx_ptr+1 ; 9476 8D 3D 06 .=.
+ jsr cue_sfx_jv ; 9479 20 06 80 ..
+; wait for sound to finish playing
+wait_sfx:
+ lda sfx_slot_duration ; 947C AD 46 06 .F.
+ bne wait_sfx ; 947F D0 FB ..
+ lda #$01 ; 9481 A9 01 ..
+ sta start_key_enabled ; 9483 8D C8 06 ...
+; initialization done, everything's done in interrupts from here on out
+hang_main_thread:
+ jmp hang_main_thread ; 9486 4C 86 94 L..
+
+; ----------------------------------------------------------------------------
+; called via option_key_vec when someone presses option
+option_key_handler:
+ lda #$00 ; 9489 A9 00 ..
+ sta option_key_enabled ; 948B 8D C6 06 ...
+ lda $B8 ; 948E A5 B8 ..
+ clc ; 9490 18 .
+ adc #$01 ; 9491 69 01 i.
+ and #$03 ; 9493 29 03 ).
+ sta $B8 ; 9495 85 B8 ..
+ tay ; 9497 A8 .
+ lda number_names_0,y ; 9498 B9 DD 95 ...
+ sta $381D ; 949B 8D 1D 38 ..8
+ lda number_names_1,y ; 949E B9 E1 95 ...
+ sta $381E ; 94A1 8D 1E 38 ..8
+ lda number_names_2,y ; 94A4 B9 E5 95 ...
+ sta $381F ; 94A7 8D 1F 38 ..8
+ lda number_names_3,y ; 94AA B9 E9 95 ...
+ sta $3820 ; 94AD 8D 20 38 . 8
+ lda number_names_4,y ; 94B0 B9 ED 95 ...
+ sta $3821 ; 94B3 8D 21 38 .!8
+ lda num_name_hscrol_table,y ; 94B6 B9 D9 95 ...
+ sta HSCROL ; 94B9 8D 04 D4 ...
+play_opt_key_sfx:
+ lda #$B0 ; 94BC A9 B0 ..
+ sta sfx_ptr ; 94BE 8D 3C 06 .<.
+ lda #$8A ; 94C1 A9 8A ..
+ sta sfx_ptr+1 ; 94C3 8D 3D 06 .=.
+ jsr cue_sfx_jv ; 94C6 20 06 80 ..
+ lda #$00 ; 94C9 A9 00 ..
+ sta jiffy_timer_1 ; 94CB 8D 1A 06 ...
+; wait until it's done playing
+wait_opt_key_sfx:
+ lda jiffy_timer_1 ; 94CE AD 1A 06 ...
+ cmp #$08 ; 94D1 C9 08 ..
+ bcc wait_opt_key_sfx ; 94D3 90 F9 ..
+ sta option_key_enabled ; 94D5 8D C6 06 ...
+ sta start_key_enabled ; 94D8 8D C8 06 ...
+ jmp hang_main_thread ; 94DB 4C 86 94 L..
+
+; ----------------------------------------------------------------------------
+; loop up to 4 times, ask PLAYER #n SPEED? and wait for number key press
+get_player_speeds:
+ lda $B8 ; 94DE A5 B8 ..
+ sta $B9 ; 94E0 85 B9 ..
+ sta $06FF ; 94E2 8D FF 06 ...
+ sta number_of_players ; 94E5 8D F4 06 ...
+ lda #$00 ; 94E8 A9 00 ..
+ sta $B8 ; 94EA 85 B8 ..
+; disable start and option keys
+disable_start_opt:
+ sta option_key_enabled ; 94EC 8D C6 06 ...
+ sta start_key_enabled ; 94EF 8D C8 06 ...
+ sta $BA ; 94F2 85 BA ..
+ inc $B9 ; 94F4 E6 B9 ..
+ inc $BA ; 94F6 E6 BA ..
+ tay ; 94F8 A8 .
+; copy PLAYER #n SPEED? to screen RAM
+show_player_speed_prompt:
+ ldx #$00 ; 94F9 A2 00 ..
+psprompt_loop:
+ lda player_x_speed,x ; 94FB BD C5 95 ...
+ sta $382C,y ; 94FE 99 2C 38 .,8
+ inx ; 9501 E8 .
+ iny ; 9502 C8 .
+ cpx #$14 ; 9503 E0 14 ..
+ bne psprompt_loop ; 9505 D0 F4 ..
+ lda $BA ; 9507 A5 BA ..
+ sta current_player ; 9509 8D FE 06 ...
+ ora #$90 ; 950C 09 90 ..
+ inc $BA ; 950E E6 BA ..
+ sta $3821,y ; 9510 99 21 38 .!8
+ dec $B9 ; 9513 C6 B9 ..
+ bne show_player_speed_prompt ; 9515 D0 E2 ..
+; set select key vector to ask_num_players at $9400, enable select key
+setup_select_key_vec_again:
+ lda #$00 ; 9517 A9 00 ..
+ sta select_key_vec ; 9519 8D C2 06 ...
+ lda #$94 ; 951C A9 94 ..
+ sta select_key_vec+1 ; 951E 8D C3 06 ...
+ sta select_key_enabled ; 9521 8D C7 06 ...
+ dec $BA ; 9524 C6 BA ..
+ ldy #$12 ; 9526 A0 12 ..
+ ldx #$00 ; 9528 A2 00 ..
+; initialize speed to -1
+init_speed:
+ lda #$FF ; 952A A9 FF ..
+ sta speed_value ; 952C 8D F9 06 ...
+; wait for keyboard IRQ handler to set a speed <= 8
+wait_for_speed:
+ lda speed_value ; 952F AD F9 06 ...
+ cmp #$09 ; 9532 C9 09 ..
+ bcs wait_for_speed ; 9534 B0 F9 ..
+ sta $0714,x ; 9536 9D 14 07 ...
+ pha ; 9539 48 H
+ clc ; 953A 18 .
+; 11-byte per-player struct?
+add_11_to_x:
+ txa ; 953B 8A .
+ adc #$0B ; 953C 69 0B i.
+ tax ; 953E AA .
+ pla ; 953F 68 h
+; convert to ASCII digit
+speed_to_ascii:
+ ora #$90 ; 9540 09 90 ..
+; show it to the user
+display_speed:
+ sta $382C,y ; 9542 99 2C 38 .,8
+ tya ; 9545 98 .
+ clc ; 9546 18 .
+ adc #$14 ; 9547 69 14 i.
+ tay ; 9549 A8 .
+ inc $B8 ; 954A E6 B8 ..
+ dec $BA ; 954C C6 BA ..
+ bne init_speed ; 954E D0 DA ..
+ inc $06FF ; 9550 EE FF 06 ...
+ lda $06FF ; 9553 AD FF 06 ...
+ sta current_player ; 9556 8D FE 06 ...
+ inc current_player ; 9559 EE FE 06 ...
+ jmp afterlife ; 955C 4C 00 96 L..
+
+; ----------------------------------------------------------------------------
+; display list for 'number of players' screen
+numplayer_display_list:
+ .byte $70,$70,$70,$70,$47,$00,$38,$70 ; 955F 70 70 70 70 47 00 38 70 ppppG.8p
+ .byte $70,$97,$70,$70,$87,$70,$70,$87 ; 9567 70 97 70 70 87 70 70 87 p.pp.pp.
+ .byte $70,$70,$87,$70,$70,$07,$41,$5F ; 956F 70 70 87 70 70 07 41 5F pp.pp.A_
+ .byte $95 ; 9577 95 .
+; ----------------------------------------------------------------------------
+; DLI service routine, changes COLPF2, address gets stored in $6ae/$6af by code at $944e
+num_player_dli_service:
+ pha ; 9578 48 H
+ lda $B7 ; 9579 A5 B7 ..
+ cmp $B8 ; 957B C5 B8 ..
+ sta WSYNC ; 957D 8D 0A D4 ...
+ bne L9592 ; 9580 D0 10 ..
+ lda $062A ; 9582 AD 2A 06 .*.
+ sta COLPF2 ; 9585 8D 18 D0 ...
+L9588: inc $B7 ; 9588 E6 B7 ..
+ lda $B7 ; 958A A5 B7 ..
+ and #$03 ; 958C 29 03 ).
+ sta $B7 ; 958E 85 B7 ..
+ pla ; 9590 68 h
+ rti ; 9591 40 @
+
+; ----------------------------------------------------------------------------
+L9592: lda COLOR2 ; 9592 AD C6 02 ...
+ sta COLPF2 ; 9595 8D 18 D0 ...
+numplayer_screen_data_minus_one:= * + 2 ; 1-indexed loop copies from here+1
+ jmp L9588 ; 9598 4C 88 95 L..
+
+; ----------------------------------------------------------------------------
+; 'number of players?', gets copied to $3800, see option_key_handler
+numplayer_screen_data:
+ .byte $00,$6E,$75,$6D,$62,$65,$72,$00 ; 959B 00 6E 75 6D 62 65 72 00 .number.
+ .byte $6F,$66,$00,$70,$6C,$61,$79,$65 ; 95A3 6F 66 00 70 6C 61 79 65 of.playe
+ .byte $72,$73,$5F,$00,$00,$00,$00,$00 ; 95AB 72 73 5F 00 00 00 00 00 rs_.....
+ .byte $00,$00,$00,$00,$00,$00,$EF,$EE ; 95B3 00 00 00 00 00 00 EF EE ........
+ .byte $E5,$00,$00,$00,$00,$00,$00,$00 ; 95BB E5 00 00 00 00 00 00 00 ........
+ .byte $00,$00 ; 95C3 00 00 ..
+; ' PLAYER # SPEED? ' in PF2 color
+player_x_speed:
+ .byte $00,$B0,$AC,$A1,$B9,$A5,$B2,$00 ; 95C5 00 B0 AC A1 B9 A5 B2 00 ........
+ .byte $83,$80,$80,$B3,$B0,$A5,$A5,$A4 ; 95CD 83 80 80 B3 B0 A5 A5 A4 ........
+ .byte $9F,$00,$00,$00 ; 95D5 9F 00 00 00 ....
+; used for centering ONE TWO THREE FOUR, see option_key_handler
+num_name_hscrol_table:
+ .byte $04,$04,$04,$00 ; 95D9 04 04 04 00 ....
+; space space T space (names ONE TWO THREE FOUR)
+number_names_0:
+ .byte $00,$00,$F4,$00 ; 95DD 00 00 F4 00 ....
+; O T H F
+number_names_1:
+ .byte $EF,$F4,$E8,$E6 ; 95E1 EF F4 E8 E6 ....
+; N W R O
+number_names_2:
+ .byte $EE,$F7,$F2,$EF ; 95E5 EE F7 F2 EF ....
+; E O E U
+number_names_3:
+ .byte $E5,$EF,$E5,$F5 ; 95E9 E5 EF E5 F5 ....
+; space space E R
+number_names_4:
+ .byte $00,$00,$E5,$F2 ; 95ED 00 00 E5 F2 ....
+; played when select key pressed, 4 notes, descending
+sfx_select_key:
+ .byte $01,$A4,$00,$1D,$08,$3C,$08,$79 ; 95F1 01 A4 00 1D 08 3C 08 79 .....<.y
+ .byte $08,$F3,$08,$00,$3C,$02,$00 ; 95F9 08 F3 08 00 3C 02 00 ....<..
+; ----------------------------------------------------------------------------
+; multiple code paths jump here. replay level, load next level, or go back to ask_num_players
+afterlife:
+ jsr enable_joystick_jv ; 9600 20 1B 80 ..
+ jsr L8027 ; 9603 20 27 80 '.
+ lda $06F8 ; 9606 AD F8 06 ...
+ beq L960E ; 9609 F0 03 ..
+ jmp ask_num_players ; 960B 4C 00 94 L..
+
+; ----------------------------------------------------------------------------
+L960E: lda $06F7 ; 960E AD F7 06 ...
+ beq L9616 ; 9611 F0 03 ..
+ jsr init_next_level ; 9613 20 E8 9B ..
+L9616: lda #$00 ; 9616 A9 00 ..
+ sta bonus_jiffy_timer ; 9618 8D 26 06 .&.
+ sta $06F5 ; 961B 8D F5 06 ...
+ sta COLOR4 ; 961E 8D C8 02 ...
+ jmp L9BD0 ; 9621 4C D0 9B L..
+
+; ----------------------------------------------------------------------------
+; only in multiplayer games
+show_get_ready_prompt:
+ ldx current_player ; 9624 AE FE 06 ...
+ lda color0_table_minus_one,x ; 9627 BD 27 97 .'.
+ sta COLOR4 ; 962A 8D C8 02 ...
+ sta COLOR0 ; 962D 8D C4 02 ...
+ ldy #$14 ; 9630 A0 14 ..
+L9632: lda L9713,y ; 9632 B9 13 97 ...
+ sta $0741,y ; 9635 99 41 07 .A.
+ dey ; 9638 88 .
+ bne L9632 ; 9639 D0 F7 ..
+ lda current_player ; 963B AD FE 06 ...
+ ora #$10 ; 963E 09 10 ..
+ sta $074A ; 9640 8D 4A 07 .J.
+ lda #$00 ; 9643 A9 00 ..
+ sta $B9 ; 9645 85 B9 ..
+ sta jiffy_timer_2 ; 9647 8D 1B 06 ...
+; 06ac/06ad gets address of get_ready_dlist (why not SDLSTL/H?)
+setup_get_ready_dl:
+ lda #$2C ; 964A A9 2C .,
+ sta dlist_shadow_lo ; 964C 8D AC 06 ...
+ lda #$97 ; 964F A9 97 ..
+ sta dlist_shadow_hi ; 9651 8D AD 06 ...
+ lda #$E6 ; 9654 A9 E6 ..
+ sta work_level_sub0 ; 9656 8D 82 07 ...
+ lda #$96 ; 9659 A9 96 ..
+ sta work_level_sub0+1 ; 965B 8D 83 07 ...
+ jsr clear_screen_mem_jv ; 965E 20 1E 80 ..
+ lda cur_level_map0 ; 9661 AD D6 07 ...
+ sta dm_progctr ; 9664 85 C0 ..
+ lda cur_level_map0+1 ; 9666 AD D7 07 ...
+ sta dm_progctr+1 ; 9669 85 C1 ..
+ jsr draw_map_jv ; 966B 20 00 80 ..
+L966E: lda jiffy_timer_2 ; 966E AD 1B 06 ...
+ cmp #$F2 ; 9671 C9 F2 ..
+ bne L966E ; 9673 D0 F9 ..
+L9675: ldx #$00 ; 9675 A2 00 ..
+; copy level descriptor to $0780
+copy_level_desc_2:
+ lda cur_level_desc,x ; 9677 BD C0 07 ...
+ sta work_level_desc,x ; 967A 9D 80 07 ...
+ inx ; 967D E8 .
+ cpx #$40 ; 967E E0 40 .@
+ bne copy_level_desc_2 ; 9680 D0 F5 ..
+ lda work_level_sub5 ; 9682 AD A2 07 ...
+ sta $06E1 ; 9685 8D E1 06 ...
+ lda work_level_sub5+1 ; 9688 AD A3 07 ...
+ sta $06E2 ; 968B 8D E2 06 ...
+ jsr L06E0 ; 968E 20 E0 06 ..
+ lda #$00 ; 9691 A9 00 ..
+ sta COLOR4 ; 9693 8D C8 02 ...
+ sta $06AB ; 9696 8D AB 06 ...
+ lda work_level_offs_46+1 ; 9699 AD AF 07 ...
+ sta COLOR0 ; 969C 8D C4 02 ...
+ lda work_level_offs_46+2 ; 969F AD B0 07 ...
+ sta COLOR1 ; 96A2 8D C5 02 ...
+ lda work_level_offs_46+3 ; 96A5 AD B1 07 ...
+ sta COLOR2 ; 96A8 8D C6 02 ...
+ lda work_level_offs_46 ; 96AB AD AE 07 ...
+ sta COLOR3 ; 96AE 8D C7 02 ...
+ jsr setup_gameboard_dlist_jv ; 96B1 20 15 80 ..
+ inc $06F5 ; 96B4 EE F5 06 ...
+ jmp L9BDD ; 96B7 4C DD 9B L..
+
+; ----------------------------------------------------------------------------
+; maybe this should be check_level or init_level?
+enter_level:
+ lda #$00 ; 96BA A9 00 ..
+ tay ; 96BC A8 .
+ sta $D7 ; 96BD 85 D7 ..
+ sta $D8 ; 96BF 85 D8 ..
+ inc level ; 96C1 EE F6 06 ...
+ lda level ; 96C4 AD F6 06 ...
+ cmp #$0C ; 96C7 C9 0C ..
+ bne copy_level_desc ; 96C9 D0 03 ..
+ jmp ask_num_players ; 96CB 4C 00 94 L..
+
+; ----------------------------------------------------------------------------
+; copy level descriptor from levelXX_desc at $A000+(level*$40) to $07c0-$07ff
+copy_level_desc:
+ lsr a ; 96CE 4A J
+ ror $D7 ; 96CF 66 D7 f.
+ lsr a ; 96D1 4A J
+ ror $D7 ; 96D2 66 D7 f.
+ ora #$A0 ; 96D4 09 A0 ..
+ sta $D8 ; 96D6 85 D8 ..
+sl_loop:lda ($D7),y ; 96D8 B1 D7 ..
+ sta cur_level_desc,y ; 96DA 99 C0 07 ...
+ iny ; 96DD C8 .
+ cpy #$40 ; 96DE C0 40 .@
+ bne sl_loop ; 96E0 D0 F6 ..
+ jsr L802A ; 96E2 20 2A 80 *.
+ rts ; 96E5 60 `
+
+; ----------------------------------------------------------------------------
+ lda jiffy_timer_2 ; 96E6 AD 1B 06 ...
+ cmp #$F0 ; 96E9 C9 F0 ..
+ bcs L9709 ; 96EB B0 1C ..
+ and #$1F ; 96ED 29 1F ).
+ beq L96F2 ; 96EF F0 01 ..
+ rts ; 96F1 60 `
+
+; ----------------------------------------------------------------------------
+L96F2: lda COLOR0 ; 96F2 AD C4 02 ...
+ cmp #$0F ; 96F5 C9 0F ..
+ beq L96FF ; 96F7 F0 06 ..
+ lda #$0F ; 96F9 A9 0F ..
+ sta COLOR0 ; 96FB 8D C4 02 ...
+ rts ; 96FE 60 `
+
+; ----------------------------------------------------------------------------
+L96FF: ldx current_player ; 96FF AE FE 06 ...
+ lda color0_table_minus_one,x ; 9702 BD 27 97 .'.
+ sta COLOR0 ; 9705 8D C4 02 ...
+ rts ; 9708 60 `
+
+; ----------------------------------------------------------------------------
+L9709: lda #$E6 ; 9709 A9 E6 ..
+ sta work_level_sub0 ; 970B 8D 82 07 ...
+ lda #$06 ; 970E A9 06 ..
+ sta work_level_sub0+1 ; 9710 8D 83 07 ...
+L9713: rts ; 9713 60 `
+
+; ----------------------------------------------------------------------------
+; PLAYER GET READY
+get_ready_msg:
+ .byte $00,$30,$2C,$21,$39,$25,$32,$00 ; 9714 00 30 2C 21 39 25 32 00 .0,!9%2.
+ .byte $00,$00,$27,$25,$34,$00,$32,$25 ; 971C 00 00 27 25 34 00 32 25 ..'%4.2%
+ .byte $21,$24,$39 ; 9724 21 24 39 !$9
+color0_table_minus_one:
+ .byte $00 ; 9727 00 .
+color0_table:
+ .byte $96,$24,$C6,$54 ; 9728 96 24 C6 54 .$.T
+; 112 blank scanlines, then one GR.2 line, loaded from $0742
+get_ready_dlist:
+ .byte $70,$70,$70,$70,$70,$70,$70,$70 ; 972C 70 70 70 70 70 70 70 70 pppppppp
+ .byte $70,$70,$70,$70,$70,$70,$47,$42 ; 9734 70 70 70 70 70 70 47 42 ppppppGB
+ .byte $07,$41,$2C,$97 ; 973C 07 41 2C 97 .A,.
+; ----------------------------------------------------------------------------
+game_main_loop:
+ jsr materialize_jumpman ; 9740 20 7B 97 {.
+L9743: jsr L8033 ; 9743 20 33 80 3.
+ lda work_level_num_bombs ; 9746 AD 8A 07 ...
+ beq got_all_bombs ; 9749 F0 1B ..
+ lda $0623 ; 974B AD 23 06 .#.
+ cmp #$02 ; 974E C9 02 ..
+ bne L9743 ; 9750 D0 F1 ..
+L9752: lda $0623 ; 9752 AD 23 06 .#.
+ cmp #$02 ; 9755 C9 02 ..
+ beq L9752 ; 9757 F0 F9 ..
+ lda lives ; 9759 AD 0A 07 ...
+ cmp #$FF ; 975C C9 FF ..
+ bne game_main_loop ; 975E D0 E0 ..
+ jsr call_eol_sub ; 9760 20 6C 97 l.
+ jmp crumble_gameboard_jv ; 9763 4C 30 80 L0.
+
+; ----------------------------------------------------------------------------
+got_all_bombs:
+ jsr call_eol_sub ; 9766 20 6C 97 l.
+ jmp level_finished_jv ; 9769 4C 2D 80 L-.
+
+; ----------------------------------------------------------------------------
+call_eol_sub:
+ lda work_level_sub_eol ; 976C AD A6 07 ...
+ sta $06E4 ; 976F 8D E4 06 ...
+ lda work_level_sub_eol+1 ; 9772 AD A7 07 ...
+ sta $06E5 ; 9775 8D E5 06 ...
+ jmp L06E3 ; 9778 4C E3 06 L..
+
+; ----------------------------------------------------------------------------
+materialize_jumpman:
+ jsr update_status_window_jv ; 977B 20 12 80 ..
+ ldx #$04 ; 977E A2 04 ..
+ lda #$00 ; 9780 A9 00 ..
+mj_clear_loop:
+ sta $0755,x ; 9782 9D 55 07 .U.
+ sta $069A,x ; 9785 9D 9A 06 ...
+ sta $06EA,x ; 9788 9D EA 06 ...
+ sta $06EB,x ; 978B 9D EB 06 ...
+ dex ; 978E CA .
+ bne mj_clear_loop ; 978F D0 F1 ..
+ sta $0697 ; 9791 8D 97 06 ...
+ sta $0698 ; 9794 8D 98 06 ...
+ sta PCOLR0 ; 9797 8D C0 02 ...
+ sta $BA ; 979A 85 BA ..
+ sta AUDF4 ; 979C 8D 06 D2 ...
+ lda work_level_y_start ; 979F AD 8C 07 ...
+ sta $0683 ; 97A2 8D 83 06 ...
+ lda work_level_x_start ; 97A5 AD 8D 07 ...
+ sta $067E ; 97A8 8D 7E 06 .~.
+ lda #$01 ; 97AB A9 01 ..
+ sta $0688 ; 97AD 8D 88 06 ...
+ lda #$A5 ; 97B0 A9 A5 ..
+ sta AUDC4 ; 97B2 8D 07 D2 ...
+ inc $066A ; 97B5 EE 6A 06 .j.
+ inc $066B ; 97B8 EE 6B 06 .k.
+mj_set_freq_and_color:
+ inc $BA ; 97BB E6 BA ..
+ beq mj_done ; 97BD F0 1C ..
+ lda $BA ; 97BF A5 BA ..
+ sta AUDF4 ; 97C1 8D 06 D2 ...
+ lsr a ; 97C4 4A J
+ lsr a ; 97C5 4A J
+ lsr a ; 97C6 4A J
+ lsr a ; 97C7 4A J
+ sta PCOLR0 ; 97C8 8D C0 02 ...
+ ldx #$FF ; 97CB A2 FF ..
+mj_delay:
+ dex ; 97CD CA .
+ nop ; 97CE EA .
+ nop ; 97CF EA .
+ nop ; 97D0 EA .
+ nop ; 97D1 EA .
+ nop ; 97D2 EA .
+ nop ; 97D3 EA .
+ nop ; 97D4 EA .
+ nop ; 97D5 EA .
+ bne mj_delay ; 97D6 D0 F5 ..
+ jmp mj_set_freq_and_color ; 97D8 4C BB 97 L..
+
+; ----------------------------------------------------------------------------
+mj_done:lda #$00 ; 97DB A9 00 ..
+ sta AUDF4 ; 97DD 8D 06 D2 ...
+ sta AUDC4 ; 97E0 8D 07 D2 ...
+ sta $0623 ; 97E3 8D 23 06 .#.
+ lda initial_speed ; 97E6 AD 25 06 .%.
+ sta player_speed ; 97E9 8D 24 06 .$.
+ inc playing_level ; 97EC EE 27 06 .'.
+ rts ; 97EF 60 `
+
+; ----------------------------------------------------------------------------
+ brk ; 97F0 00 .
+ brk ; 97F1 00 .
+ brk ; 97F2 00 .
+ brk ; 97F3 00 .
+ brk ; 97F4 00 .
+ brk ; 97F5 00 .
+ brk ; 97F6 00 .
+ brk ; 97F7 00 .
+ brk ; 97F8 00 .
+ brk ; 97F9 00 .
+ brk ; 97FA 00 .
+ brk ; 97FB 00 .
+ brk ; 97FC 00 .
+ brk ; 97FD 00 .
+ brk ; 97FE 00 .
+ brk ; 97FF 00 .
+ lda $0621 ; 9800 AD 21 06 .!.
+ bne L9806 ; 9803 D0 01 ..
+L9805: rts ; 9805 60 `
+
+; ----------------------------------------------------------------------------
+L9806: lda $0623 ; 9806 AD 23 06 .#.
+ bne L9805 ; 9809 D0 FA ..
+ lda $0683 ; 980B AD 83 06 ...
+ cmp #$C6 ; 980E C9 C6 ..
+ bcs L982E ; 9810 B0 1C ..
+ lda $06EB ; 9812 AD EB 06 ...
+ beq check_collisions_2 ; 9815 F0 03 ..
+ jmp L99A8 ; 9817 4C A8 99 L..
+
+; ----------------------------------------------------------------------------
+; did player 0 or 1 hit the playfield...
+check_collisions_2:
+ lda #$01 ; 981A A9 01 ..
+ sta $0688 ; 981C 8D 88 06 ...
+ lda $06ED ; 981F AD ED 06 ...
+ beq check_collisions_3 ; 9822 F0 0E ..
+ lda collision_save+4 ; 9824 AD B4 06 ...
+ ora collision_save+5 ; 9827 0D B5 06 ...
+ and #$03 ; 982A 29 03 ).
+ bne check_collisions_3 ; 982C D0 04 ..
+L982E: inc $0623 ; 982E EE 23 06 .#.
+ rts ; 9831 60 `
+
+; ----------------------------------------------------------------------------
+; did player 0 or 1 hit the playfield...
+check_collisions_3:
+ lda #$00 ; 9832 A9 00 ..
+ sta $06ED ; 9834 8D ED 06 ...
+ lda collision_save+4 ; 9837 AD B4 06 ...
+ ora collision_save+5 ; 983A 0D B5 06 ...
+ and #$03 ; 983D 29 03 ).
+ bne check_trigger_state ; 983F D0 0C ..
+ inc $06ED ; 9841 EE ED 06 ...
+ inc $0683 ; 9844 EE 83 06 ...
+ inc $0683 ; 9847 EE 83 06 ...
+ jmp L989F ; 984A 4C 9F 98 L..
+
+; ----------------------------------------------------------------------------
+; did user press the trigger?
+check_trigger_state:
+ lda trigger_state ; 984D AD 35 06 .5.
+ bne check_up_down ; 9850 D0 03 ..
+; yes, jump to handler
+trig_jmp:
+ jmp trigger_handler ; 9852 4C 85 99 L..
+
+; ----------------------------------------------------------------------------
+; did user move joystick up/down?
+check_up_down:
+ lda joystick_state ; 9855 AD 33 06 .3.
+ cmp #$0E ; 9858 C9 0E ..
+ beq L9863 ; 985A F0 07 ..
+ cmp #$0D ; 985C C9 0D ..
+ beq L9863 ; 985E F0 03 ..
+; no, jump over handler
+cud_jmp:jmp L9892 ; 9860 4C 92 98 L..
+
+; ----------------------------------------------------------------------------
+L9863: lda collision_save+4 ; 9863 AD B4 06 ...
+ ora collision_save+5 ; 9866 0D B5 06 ...
+ and #$02 ; 9869 29 02 ).
+ bne L9870 ; 986B D0 03 ..
+ jmp L98D0 ; 986D 4C D0 98 L..
+
+; ----------------------------------------------------------------------------
+L9870: jsr check_up_down_2 ; 9870 20 3B 99 ;.
+ bcs L9878 ; 9873 B0 03 ..
+ jmp L98D0 ; 9875 4C D0 98 L..
+
+; ----------------------------------------------------------------------------
+L9878: sta $067E ; 9878 8D 7E 06 .~.
+ lda player_delta_y ; 987B AD 31 06 .1.
+ asl a ; 987E 0A .
+ clc ; 987F 18 .
+ adc $0683 ; 9880 6D 83 06 m..
+ sta $0683 ; 9883 8D 83 06 ...
+ lda $0620 ; 9886 AD 20 06 . .
+ clc ; 9889 18 .
+ adc #$04 ; 988A 69 04 i.
+ sta $0688 ; 988C 8D 88 06 ...
+ jmp play_sfx_bounce_2 ; 988F 4C 80 8A L..
+
+; ----------------------------------------------------------------------------
+L9892: lda collision_save+4 ; 9892 AD B4 06 ...
+ ora collision_save+5 ; 9895 0D B5 06 ...
+ and #$01 ; 9898 29 01 ).
+ bne L989F ; 989A D0 03 ..
+ jmp L98D0 ; 989C 4C D0 98 L..
+
+; ----------------------------------------------------------------------------
+L989F: lda player_delta_x ; 989F AD 30 06 .0.
+ beq L98D0 ; 98A2 F0 2C .,
+ asl a ; 98A4 0A .
+ ldx #$08 ; 98A5 A2 08 ..
+ cmp #$02 ; 98A7 C9 02 ..
+ beq L98AD ; 98A9 F0 02 ..
+ ldx #$0C ; 98AB A2 0C ..
+L98AD: clc ; 98AD 18 .
+ adc $067E ; 98AE 6D 7E 06 m~.
+ sta $067E ; 98B1 8D 7E 06 .~.
+ txa ; 98B4 8A .
+ clc ; 98B5 18 .
+ adc $0620 ; 98B6 6D 20 06 m .
+ sta $0688 ; 98B9 8D 88 06 ...
+ lda $061F ; 98BC AD 1F 06 ...
+ bne L98D0 ; 98BF D0 0F ..
+ lda #$73 ; 98C1 A9 73 .s
+ sta sfx_slot_tempo ; 98C3 8D 3E 06 .>.
+ lda #$BE ; 98C6 A9 BE ..
+ sta sfx_slot_timer ; 98C8 8D 3F 06 .?.
+ lda #$01 ; 98CB A9 01 ..
+ jsr L8003 ; 98CD 20 03 80 ..
+L98D0: lda collision_save+4 ; 98D0 AD B4 06 ...
+ ora collision_save+5 ; 98D3 0D B5 06 ...
+ and #$02 ; 98D6 29 02 ).
+ beq L98F0 ; 98D8 F0 16 ..
+ jsr L9971 ; 98DA 20 71 99 q.
+ bcc L990F ; 98DD 90 30 .0
+ inc $0683 ; 98DF EE 83 06 ...
+ inc $0683 ; 98E2 EE 83 06 ...
+ lda $061F ; 98E5 AD 1F 06 ...
+ ora #$02 ; 98E8 09 02 ..
+ sta $0688 ; 98EA 8D 88 06 ...
+ jmp L9925 ; 98ED 4C 25 99 L%.
+
+; ----------------------------------------------------------------------------
+L98F0: lda collision_save+4 ; 98F0 AD B4 06 ...
+ and #$01 ; 98F3 29 01 ).
+ beq L990F ; 98F5 F0 18 ..
+ dec $0683 ; 98F7 CE 83 06 ...
+ dec $0683 ; 98FA CE 83 06 ...
+ lda $0688 ; 98FD AD 88 06 ...
+ cmp #$01 ; 9900 C9 01 ..
+ bne L990F ; 9902 D0 0B ..
+ lda $061F ; 9904 AD 1F 06 ...
+ ora #$02 ; 9907 09 02 ..
+ sta $0688 ; 9909 8D 88 06 ...
+ jmp L9925 ; 990C 4C 25 99 L%.
+
+; ----------------------------------------------------------------------------
+L990F: lda $0688 ; 990F AD 88 06 ...
+ cmp #$01 ; 9912 C9 01 ..
+ bne L9925 ; 9914 D0 0F ..
+ lda collision_save+4 ; 9916 AD B4 06 ...
+ ora collision_save+5 ; 9919 0D B5 06 ...
+ and #$02 ; 991C 29 02 ).
+ beq L9925 ; 991E F0 05 ..
+ lda #$04 ; 9920 A9 04 ..
+ sta $0688 ; 9922 8D 88 06 ...
+L9925: lda $0688 ; 9925 AD 88 06 ...
+ sta $0689 ; 9928 8D 89 06 ...
+ lda $067E ; 992B AD 7E 06 .~.
+ sta $067F ; 992E 8D 7F 06 ...
+ lda $0683 ; 9931 AD 83 06 ...
+ clc ; 9934 18 .
+ adc #$0A ; 9935 69 0A i.
+ sta $0684 ; 9937 8D 84 06 ...
+ rts ; 993A 60 `
+
+; ----------------------------------------------------------------------------
+; did user move joystick up/down?
+check_up_down_2:
+ lda joystick_state ; 993B AD 33 06 .3.
+ cmp #$0D ; 993E C9 0D ..
+ bne L9949 ; 9940 D0 07 ..
+ lda $0683 ; 9942 AD 83 06 ...
+ cmp #$C0 ; 9945 C9 C0 ..
+ bcs L9967 ; 9947 B0 1E ..
+L9949: lda $067E ; 9949 AD 7E 06 .~.
+ sec ; 994C 38 8
+ sbc #$30 ; 994D E9 30 .0
+ sta zp_temp1 ; 994F 85 CB ..
+ ldx #$08 ; 9951 A2 08 ..
+L9953: lda work_level_offs_46+3,x ; 9953 BD B1 07 ...
+ clc ; 9956 18 .
+ adc #$02 ; 9957 69 02 i.
+ cmp zp_temp1 ; 9959 C5 CB ..
+ bcc L9964 ; 995B 90 07 ..
+ sec ; 995D 38 8
+ sbc #$05 ; 995E E9 05 ..
+ cmp zp_temp1 ; 9960 C5 CB ..
+ bcc L9969 ; 9962 90 05 ..
+L9964: dex ; 9964 CA .
+ bne L9953 ; 9965 D0 EC ..
+L9967: clc ; 9967 18 .
+ rts ; 9968 60 `
+
+; ----------------------------------------------------------------------------
+L9969: lda work_level_offs_46+3,x ; 9969 BD B1 07 ...
+ clc ; 996C 18 .
+ adc #$30 ; 996D 69 30 i0
+ sec ; 996F 38 8
+ rts ; 9970 60 `
+
+; ----------------------------------------------------------------------------
+L9971: lda $067E ; 9971 AD 7E 06 .~.
+ sec ; 9974 38 8
+ sbc #$30 ; 9975 E9 30 .0
+ ldx #$06 ; 9977 A2 06 ..
+L9979: cmp work_level_offs_55+2,x ; 9979 DD B9 07 ...
+ beq L9983 ; 997C F0 05 ..
+ dex ; 997E CA .
+ bne L9979 ; 997F D0 F8 ..
+ clc ; 9981 18 .
+ rts ; 9982 60 `
+
+; ----------------------------------------------------------------------------
+L9983: sec ; 9983 38 8
+ rts ; 9984 60 `
+
+; ----------------------------------------------------------------------------
+; handle trigger presses (maybe start a jump)
+trigger_handler:
+ ldx #$04 ; 9985 A2 04 ..
+ lda joystick_state ; 9987 AD 33 06 .3.
+ cmp #$0E ; 998A C9 0E ..
+ beq L99A0 ; 998C F0 12 ..
+ ldx #$10 ; 998E A2 10 ..
+ lda player_delta_x ; 9990 AD 30 06 .0.
+ cmp #$01 ; 9993 C9 01 ..
+ beq L99A0 ; 9995 F0 09 ..
+ ldx #$11 ; 9997 A2 11 ..
+ cmp #$FF ; 9999 C9 FF ..
+ beq L99A0 ; 999B F0 03 ..
+ jmp check_up_down ; 999D 4C 55 98 LU.
+
+; ----------------------------------------------------------------------------
+L99A0: stx $0688 ; 99A0 8E 88 06 ...
+ lda #$01 ; 99A3 A9 01 ..
+ jsr cue_music_jv ; 99A5 20 18 80 ..
+L99A8: inc $06EB ; 99A8 EE EB 06 ...
+ lda $06EB ; 99AB AD EB 06 ...
+ cmp #$16 ; 99AE C9 16 ..
+ bne L99BD ; 99B0 D0 0B ..
+L99B2: lda #$00 ; 99B2 A9 00 ..
+ sta $06EB ; 99B4 8D EB 06 ...
+ sta $06ED ; 99B7 8D ED 06 ...
+ jmp check_collisions_2 ; 99BA 4C 1A 98 L..
+
+; ----------------------------------------------------------------------------
+L99BD: ldx $06EB ; 99BD AE EB 06 ...
+ lda L9A1B,x ; 99C0 BD 1B 9A ...
+ tay ; 99C3 A8 .
+ lda $0688 ; 99C4 AD 88 06 ...
+ cmp #$10 ; 99C7 C9 10 ..
+ beq L99DD ; 99C9 F0 12 ..
+ cmp #$11 ; 99CB C9 11 ..
+ bne L99DB ; 99CD D0 0C ..
+ tya ; 99CF 98 .
+ sta zp_temp1+1 ; 99D0 85 CC ..
+ lda #$00 ; 99D2 A9 00 ..
+ sec ; 99D4 38 8
+ sbc zp_temp1+1 ; 99D5 E5 CC ..
+ tay ; 99D7 A8 .
+ jmp L99DD ; 99D8 4C DD 99 L..
+
+; ----------------------------------------------------------------------------
+L99DB: ldy #$00 ; 99DB A0 00 ..
+L99DD: clc ; 99DD 18 .
+ tya ; 99DE 98 .
+ adc $067E ; 99DF 6D 7E 06 m~.
+ sta $067E ; 99E2 8D 7E 06 .~.
+ lda L9A31,x ; 99E5 BD 31 9A .1.
+ clc ; 99E8 18 .
+ adc $0683 ; 99E9 6D 83 06 m..
+ sta $0683 ; 99EC 8D 83 06 ...
+ txa ; 99EF 8A .
+ cmp #$08 ; 99F0 C9 08 ..
+ bcs code_99f7 ; 99F2 B0 03 ..
+ jmp L9925 ; 99F4 4C 25 99 L%.
+
+; ----------------------------------------------------------------------------
+code_99f7:
+ lda collision_save+4 ; 99F7 AD B4 06 ...
+ ora collision_save+5 ; 99FA 0D B5 06 ...
+ lsr a ; 99FD 4A J
+ bcs L99B2 ; 99FE B0 B2 ..
+ lsr a ; 9A00 4A J
+ bcc L9A19 ; 9A01 90 16 ..
+ lda $0688 ; 9A03 AD 88 06 ...
+ cmp #$04 ; 9A06 C9 04 ..
+ beq L9A19 ; 9A08 F0 0F ..
+ jsr L9971 ; 9A0A 20 71 99 q.
+ bcs L99B2 ; 9A0D B0 A3 ..
+ jsr check_up_down_2 ; 9A0F 20 3B 99 ;.
+ bcc L9A19 ; 9A12 90 05 ..
+ cmp $067E ; 9A14 CD 7E 06 .~.
+ beq L99B2 ; 9A17 F0 99 ..
+L9A19:
+L9A1B := * + 2
+ jmp L9925 ; 9A19 4C 25 99 L%.
+
+; ----------------------------------------------------------------------------
+data_9a1c:
+ .byte $02,$00,$02,$00,$02,$02,$02,$02 ; 9A1C 02 00 02 00 02 02 02 02 ........
+ .byte $02,$02,$02,$00,$02,$00,$02,$00 ; 9A24 02 02 02 00 02 00 02 00 ........
+ .byte $00,$02,$00,$00,$00 ; 9A2C 00 02 00 00 00 .....
+L9A31: .byte $02,$FE,$FE,$FE,$FE,$FE,$FE,$00 ; 9A31 02 FE FE FE FE FE FE 00 ........
+ .byte $00,$00,$02,$02,$02,$02,$02,$02 ; 9A39 00 00 02 02 02 02 02 02 ........
+ .byte $02,$02,$02,$02,$02,$02,$00,$00 ; 9A41 02 02 02 02 02 02 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9A49 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9A51 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00 ; 9A59 00 00 00 ...
+; ----------------------------------------------------------------------------
+init_page_7:
+ ldy #$00 ; 9A5C A0 00 ..
+L9A5E: ldx #$00 ; 9A5E A2 00 ..
+L9A60: lda data_9a71,x ; 9A60 BD 71 9A .q.
+ sta score,y ; 9A63 99 00 07 ...
+ inx ; 9A66 E8 .
+ iny ; 9A67 C8 .
+ cpx #$0B ; 9A68 E0 0B ..
+ bne L9A60 ; 9A6A D0 F4 ..
+ cpy #$37 ; 9A6C C0 37 .7
+ bne L9A5E ; 9A6E D0 EE ..
+ rts ; 9A70 60 `
+
+; ----------------------------------------------------------------------------
+; used by code above
+data_9a71:
+ .byte $00,$00,$00,$4C,$1D,$00,$00,$00 ; 9A71 00 00 00 4C 1D 00 00 00 ...L....
+ .byte $00,$06,$03 ; 9A79 00 06 03 ...
+; ----------------------------------------------------------------------------
+L9A7C: ldx current_player ; 9A7C AE FE 06 ...
+ lda #$00 ; 9A7F A9 00 ..
+ clc ; 9A81 18 .
+L9A82: dex ; 9A82 CA .
+ beq L9A8A ; 9A83 F0 05 ..
+ adc #$0B ; 9A85 69 0B i.
+ jmp L9A82 ; 9A87 4C 82 9A L..
+
+; ----------------------------------------------------------------------------
+L9A8A: tay ; 9A8A A8 .
+ rts ; 9A8B 60 `
+
+; ----------------------------------------------------------------------------
+L9A8C: ldx #$00 ; 9A8C A2 00 ..
+L9A8E: lda score,x ; 9A8E BD 00 07 ...
+ sta $070B,y ; 9A91 99 0B 07 ...
+ inx ; 9A94 E8 .
+ iny ; 9A95 C8 .
+ cpx #$0B ; 9A96 E0 0B ..
+ bne L9A8E ; 9A98 D0 F4 ..
+ rts ; 9A9A 60 `
+
+; ----------------------------------------------------------------------------
+L9A9B: ldx #$00 ; 9A9B A2 00 ..
+L9A9D: lda $070B,y ; 9A9D B9 0B 07 ...
+ sta score,x ; 9AA0 9D 00 07 ...
+ inx ; 9AA3 E8 .
+ iny ; 9AA4 C8 .
+ cpx #$0B ; 9AA5 E0 0B ..
+ bne L9A9D ; 9AA7 D0 F4 ..
+ rts ; 9AA9 60 `
+
+; ----------------------------------------------------------------------------
+L9AAA: jsr L9A7C ; 9AAA 20 7C 9A |.
+ jsr L9A8C ; 9AAD 20 8C 9A ..
+ lda #$00 ; 9AB0 A9 00 ..
+ sta $06F7 ; 9AB2 8D F7 06 ...
+ sta $06F8 ; 9AB5 8D F8 06 ...
+L9AB8: inc current_player ; 9AB8 EE FE 06 ...
+ lda $06FF ; 9ABB AD FF 06 ...
+ cmp current_player ; 9ABE CD FE 06 ...
+ bcs L9ACB ; 9AC1 B0 08 ..
+ lda #$01 ; 9AC3 A9 01 ..
+ sta current_player ; 9AC5 8D FE 06 ...
+ sta $06F7 ; 9AC8 8D F7 06 ...
+L9ACB: ldx number_of_players ; 9ACB AE F4 06 ...
+ inx ; 9ACE E8 .
+ ldy L9AFB,x ; 9ACF BC FB 9A ...
+L9AD2: lda $0715,y ; 9AD2 B9 15 07 ...
+ cmp #$FF ; 9AD5 C9 FF ..
+ bne L9AE5 ; 9AD7 D0 0C ..
+ tya ; 9AD9 98 .
+ sec ; 9ADA 38 8
+ sbc #$0B ; 9ADB E9 0B ..
+ tay ; 9ADD A8 .
+ dex ; 9ADE CA .
+ bne L9AD2 ; 9ADF D0 F1 ..
+ inc $06F8 ; 9AE1 EE F8 06 ...
+ rts ; 9AE4 60 `
+
+; ----------------------------------------------------------------------------
+L9AE5: stx $06FF ; 9AE5 8E FF 06 ...
+ jsr L9A7C ; 9AE8 20 7C 9A |.
+ jsr L9A9B ; 9AEB 20 9B 9A ..
+ lda lives ; 9AEE AD 0A 07 ...
+ cmp #$FF ; 9AF1 C9 FF ..
+ beq L9AB8 ; 9AF3 F0 C3 ..
+ lda $0709 ; 9AF5 AD 09 07 ...
+ sta initial_speed ; 9AF8 8D 25 06 .%.
+L9AFB: rts ; 9AFB 60 `
+
+; ----------------------------------------------------------------------------
+data_9afc:
+ .byte $00,$0B,$16,$21 ; 9AFC 00 0B 16 21 ...!
+; ----------------------------------------------------------------------------
+; for some reason there are 2 copies of the display list, at $0800 and $0881
+setup_gameboard_dlist:
+ ldx #$00 ; 9B00 A2 00 ..
+ lda dlist_shadow_lo ; 9B02 AD AC 06 ...
+ bne L9B09 ; 9B05 D0 02 ..
+ ldx #$81 ; 9B07 A2 81 ..
+L9B09: lda #$70 ; 9B09 A9 70 .p
+ stx $9F ; 9B0B 86 9F ..
+ ldy #$03 ; 9B0D A0 03 ..
+ sty $9D ; 9B0F 84 9D ..
+L9B11: sta $0800,x ; 9B11 9D 00 08 ...
+ inx ; 9B14 E8 .
+ dey ; 9B15 88 .
+ bne L9B11 ; 9B16 D0 F9 ..
+ ldy $06AB ; 9B18 AC AB 06 ...
+L9B1B: lda gameboard_dlist_data,y ; 9B1B B9 62 9B .b.
+ sta $0800,x ; 9B1E 9D 00 08 ...
+ iny ; 9B21 C8 .
+ inx ; 9B22 E8 .
+ dec $9D ; 9B23 C6 9D ..
+ bne L9B1B ; 9B25 D0 F4 ..
+L9B27: lda gameboard_dlist_data,y ; 9B27 B9 62 9B .b.
+ beq L9B3E ; 9B2A F0 12 ..
+ sta $9D ; 9B2C 85 9D ..
+ iny ; 9B2E C8 .
+ lda gameboard_dlist_data,y ; 9B2F B9 62 9B .b.
+L9B32: sta $0800,x ; 9B32 9D 00 08 ...
+ inx ; 9B35 E8 .
+ dec $9D ; 9B36 C6 9D ..
+ bne L9B32 ; 9B38 D0 F8 ..
+ iny ; 9B3A C8 .
+ jmp L9B27 ; 9B3B 4C 27 9B L'.
+
+; ----------------------------------------------------------------------------
+L9B3E: lda #$41 ; 9B3E A9 41 .A
+ sta $0800,x ; 9B40 9D 00 08 ...
+ inx ; 9B43 E8 .
+ lda $9F ; 9B44 A5 9F ..
+ sta $0800,x ; 9B46 9D 00 08 ...
+ sta dlist_shadow_lo ; 9B49 8D AC 06 ...
+ inx ; 9B4C E8 .
+ lda #$08 ; 9B4D A9 08 ..
+ sta $0800,x ; 9B4F 9D 00 08 ...
+ sta dlist_shadow_hi ; 9B52 8D AD 06 ...
+ lda L9B63,y ; 9B55 B9 63 9B .c.
+ sta dli_vec_shadow_lo ; 9B58 8D AE 06 ...
+ lda L9B64,y ; 9B5B B9 64 9B .d.
+ sta dli_vec_shadow_hi ; 9B5E 8D AF 06 ...
+ rts ; 9B61 60 `
+
+; ----------------------------------------------------------------------------
+; this isn't used as-is for a display list, see setup_gameboard_dlist
+gameboard_dlist_data:
+ .byte $4D ; 9B62 4D M
+L9B63: .byte $00 ; 9B63 00 .
+L9B64: .byte $30,$56,$0D,$01,$8D,$01,$8D,$01 ; 9B64 30 56 0D 01 8D 01 8D 01 0V......
+ .byte $06,$01,$86,$00,$72,$9B ; 9B6C 06 01 86 00 72 9B ....r.
+; ----------------------------------------------------------------------------
+; changes DLI vector to point to dli_chained_2
+dli_chained_1:
+ pha ; 9B72 48 H
+ lda #$54 ; 9B73 A9 54 .T
+ sta WSYNC ; 9B75 8D 0A D4 ...
+ sta COLBK ; 9B78 8D 1A D0 ...
+ lda #$87 ; 9B7B A9 87 ..
+ sta VDSLST ; 9B7D 8D 00 02 ...
+ lda #$9B ; 9B80 A9 9B ..
+ sta VDSLST+1 ; 9B82 8D 01 02 ...
+ pla ; 9B85 68 h
+ rti ; 9B86 40 @
+
+; ----------------------------------------------------------------------------
+; changes DLI vector to point to dli_chained_3
+dli_chained_2:
+ pha ; 9B87 48 H
+ lda #$00 ; 9B88 A9 00 ..
+ sta WSYNC ; 9B8A 8D 0A D4 ...
+ sta COLBK ; 9B8D 8D 1A D0 ...
+ lda $062A ; 9B90 AD 2A 06 .*.
+ sta COLPF0 ; 9B93 8D 16 D0 ...
+ lda #$28 ; 9B96 A9 28 .(
+ sta COLPF1 ; 9B98 8D 17 D0 ...
+ lda #$AA ; 9B9B A9 AA ..
+ sta COLPF2 ; 9B9D 8D 18 D0 ...
+ lda #$0F ; 9BA0 A9 0F ..
+ sta COLPF3 ; 9BA2 8D 19 D0 ...
+ lda #$B1 ; 9BA5 A9 B1 ..
+ sta VDSLST ; 9BA7 8D 00 02 ...
+ lda #$9B ; 9BAA A9 9B ..
+ sta VDSLST+1 ; 9BAC 8D 01 02 ...
+ pla ; 9BAF 68 h
+ rti ; 9BB0 40 @
+
+; ----------------------------------------------------------------------------
+; changes DLI vector to point to dli_chained_1
+dli_chained_3:
+ pha ; 9BB1 48 H
+ lda #$54 ; 9BB2 A9 54 .T
+ sta WSYNC ; 9BB4 8D 0A D4 ...
+ sta COLBK ; 9BB7 8D 1A D0 ...
+ lda #$72 ; 9BBA A9 72 .r
+ sta VDSLST ; 9BBC 8D 00 02 ...
+ lda #$9B ; 9BBF A9 9B ..
+ sta VDSLST+1 ; 9BC1 8D 01 02 ...
+ pla ; 9BC4 68 h
+ rti ; 9BC5 40 @
+
+; ----------------------------------------------------------------------------
+ .byte $9B ; 9BC6 9B .
+ sta VDSLST+1 ; 9BC7 8D 01 02 ...
+ pla ; 9BCA 68 h
+ rti ; 9BCB 40 @
+
+; ----------------------------------------------------------------------------
+ brk ; 9BCC 00 .
+ brk ; 9BCD 00 .
+ brk ; 9BCE 00 .
+ brk ; 9BCF 00 .
+L9BD0: lda number_of_players ; 9BD0 AD F4 06 ...
+ cmp #$00 ; 9BD3 C9 00 ..
+ beq L9BDA ; 9BD5 F0 03 ..
+ jmp show_get_ready_prompt ; 9BD7 4C 24 96 L$.
+
+; ----------------------------------------------------------------------------
+L9BDA: jmp L9675 ; 9BDA 4C 75 96 Lu.
+
+; ----------------------------------------------------------------------------
+L9BDD: lda #$06 ; 9BDD A9 06 ..
+ sta $085E ; 9BDF 8D 5E 08 .^.
+ sta $08DF ; 9BE2 8D DF 08 ...
+ jmp (work_level_sub6) ; 9BE5 6C A4 07 l..
+
+; ----------------------------------------------------------------------------
+; ...
+init_next_level:
+ lda randomizer_mode ; 9BE8 AD F3 06 ...
+ beq L9BFC ; 9BEB F0 0F ..
+; only after beating levels 1-12 in order
+randomize_level:
+ lda RANDOM ; 9BED AD 0A D2 ...
+ and #$0F ; 9BF0 29 0F ).
+ cmp #$0C ; 9BF2 C9 0C ..
+ bcs randomize_level ; 9BF4 B0 F7 ..
+ sta level ; 9BF6 8D F6 06 ...
+ dec level ; 9BF9 CE F6 06 ...
+L9BFC: jmp enter_level ; 9BFC 4C BA 96 L..
+
+; ----------------------------------------------------------------------------
+ brk ; 9BFF 00 .
+; only use of keyboard is to enter player speed before starting game
+keyboard_isr:
+ txa ; 9C00 8A .
+ pha ; 9C01 48 H
+ ldx #$08 ; 9C02 A2 08 ..
+ lda KBCODE ; 9C04 AD 09 D2 ...
+check_keycode:
+ cmp keycode_table_minus_one,x ; 9C07 DD 18 9C ...
+ beq store_speed_value ; 9C0A F0 07 ..
+ dex ; 9C0C CA .
+ bne check_keycode ; 9C0D D0 F8 ..
+keyboard_isr_exit:
+ pla ; 9C0F 68 h
+ tax ; 9C10 AA .
+ pla ; 9C11 68 h
+ rti ; 9C12 40 @
+
+; ----------------------------------------------------------------------------
+store_speed_value:
+ stx speed_value ; 9C13 8E F9 06 ...
+keycode_table_minus_one:= * + 2
+ jmp keyboard_isr_exit ; 9C16 4C 0F 9C L..
+
+; ----------------------------------------------------------------------------
+keycode_table:
+ .byte $1F,$1E,$1A,$18,$1D,$1B,$33,$35 ; 9C19 1F 1E 1A 18 1D 1B 33 35 ......35
+; definitions for level graphics objects aka shapes. (girder segment, ladder, rope, etc)
+level_gfx:
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9C21 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9C29 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00 ; 9C31 00 00 ..
+; 3 rows of pixels. 1st: 04 = 4 pixels wide, 00 00 = no X/Y offset, 01 01 01 01 = actual pixel data (4 color0 pixels). see level_maps.txt
+sh_girder:
+ .byte $04,$00,$00,$01,$01,$01,$01,$04 ; 9C33 04 00 00 01 01 01 01 04 ........
+ .byte $00,$01,$01,$00,$01,$00,$04,$00 ; 9C3B 00 01 01 00 01 00 04 00 ........
+ .byte $02,$01,$01,$01,$01,$FF ; 9C43 02 01 01 01 01 FF ......
+sh_blank_4x4:
+ .byte $04,$00,$00,$00,$00,$00,$00,$04 ; 9C49 04 00 00 00 00 00 00 04 ........
+ .byte $00,$01,$00,$00,$00,$00,$04,$00 ; 9C51 00 01 00 00 00 00 04 00 ........
+ .byte $02,$00,$00,$00,$00,$FF ; 9C59 02 00 00 00 00 FF ......
+sh_ladder:
+ .byte $02,$00,$00,$02,$02,$02,$06,$00 ; 9C5F 02 00 00 02 02 02 06 00 ........
+ .byte $02,$02,$02,$00,$01,$02,$02,$02 ; 9C67 02 02 02 00 01 02 02 02 ........
+ .byte $06,$01,$02,$02,$08,$00,$02,$02 ; 9C6F 06 01 02 02 08 00 02 02 ........
+ .byte $02,$02,$02,$02,$02,$02,$02,$02 ; 9C77 02 02 02 02 02 02 02 02 ........
+ .byte $00,$03,$02,$02,$02,$06,$03,$02 ; 9C7F 00 03 02 02 02 06 03 02 ........
+ .byte $02,$FF ; 9C87 02 FF ..
+; dunno what this is yet
+sh_9c89:.byte $02,$00,$00,$00,$00,$02,$06,$00 ; 9C89 02 00 00 00 00 02 06 00 ........
+ .byte $00,$00,$02,$00,$01,$00,$00,$02 ; 9C91 00 00 02 00 01 00 00 02 ........
+ .byte $06,$01,$00,$00,$08,$00,$02,$00 ; 9C99 06 01 00 00 08 00 02 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$02 ; 9CA1 00 00 00 00 00 00 00 02 ........
+ .byte $00,$03,$00,$00,$02,$06,$03,$00 ; 9CA9 00 03 00 00 02 06 03 00 ........
+ .byte $00,$FF ; 9CB1 00 FF ..
+sh_bomb:.byte $04,$00,$00,$00,$03,$03,$00,$04 ; 9CB3 04 00 00 00 03 03 00 04 ........
+ .byte $00,$01,$03,$00,$00,$03,$04,$00 ; 9CBB 00 01 03 00 00 03 04 00 ........
+ .byte $02,$00,$03,$03,$00,$FF ; 9CC3 02 00 03 03 00 FF ......
+sh_up_rope:
+ .byte $01,$00,$00,$01,$01,$01,$01,$01 ; 9CC9 01 00 00 01 01 01 01 01 ........
+ .byte $01,$00,$02,$01,$01,$01,$03,$01 ; 9CD1 01 00 02 01 01 01 03 01 ........
+ .byte $FF ; 9CD9 FF .
+sh_down_rope:
+ .byte $01,$00,$00,$02,$01,$00,$01,$02 ; 9CDA 01 00 00 02 01 00 01 02 ........
+ .byte $01,$01,$02,$02,$01,$01,$03,$02 ; 9CE2 01 01 02 02 01 01 03 02 ........
+ .byte $FF ; 9CEA FF .
+; dunno what this is yet
+sh_9ceb:.byte $02,$00,$00,$00,$00,$02,$00,$01 ; 9CEB 02 00 00 00 00 02 00 01 ........
+ .byte $00,$00,$02,$00,$02,$00,$00,$02 ; 9CF3 00 00 02 00 02 00 00 02 ........
+ .byte $00,$03,$00,$00,$FF ; 9CFB 00 03 00 00 FF .....
+; jumpman's animation frames and other sprites, seem to be 10 bytes per sprite
+sprite_table:
+ .byte $18,$18,$3C,$5A,$3C,$18,$18,$18 ; 9D00 18 18 3C 5A 3C 18 18 18 ..<Z<...
+ .byte $18,$3C,$1C,$1A,$3C,$58,$38,$18 ; 9D08 18 3C 1C 1A 3C 58 38 18 .<..<X8.
+ .byte $3C,$24,$14,$14,$38,$58,$3C,$1A ; 9D10 3C 24 14 14 38 58 3C 1A <$..8X<.
+ .byte $1C,$18,$3C,$24,$28,$28,$99,$5A ; 9D18 1C 18 3C 24 28 28 99 5A ..<$((.Z
+ .byte $3C,$18,$18,$18,$3C,$24,$42,$C3 ; 9D20 3C 18 18 18 3C 24 42 C3 <...<$B.
+ .byte $19,$12,$3C,$58,$98,$18,$7C,$C4 ; 9D28 19 12 3C 58 98 18 7C C4 ..<X..|.
+ .byte $04,$06,$00,$18,$3C,$5A,$99,$18 ; 9D30 04 06 00 18 3C 5A 99 18 ....<Z..
+ .byte $3C,$24,$42,$C3,$98,$48,$3C,$1A ; 9D38 3C 24 42 C3 98 48 3C 1A <$B..H<.
+ .byte $19,$18,$3E,$23,$20,$60,$18,$10 ; 9D40 19 18 3E 23 20 60 18 10 ..># `..
+ .byte $3D,$5A,$98,$18,$3C,$24,$22,$33 ; 9D48 3D 5A 98 18 3C 24 22 33 =Z..<$"3
+ .byte $18,$10,$38,$5C,$38,$18,$3C,$24 ; 9D50 18 10 38 5C 38 18 3C 24 ..8\8.<$
+ .byte $44,$66,$18,$10,$3D,$5A,$98,$18 ; 9D58 44 66 18 10 3D 5A 98 18 Df..=Z..
+ .byte $3C,$24,$22,$33,$18,$10,$38,$5C ; 9D60 3C 24 22 33 18 10 38 5C <$"3..8\
+ .byte $38,$18,$3C,$24,$44,$66,$18,$08 ; 9D68 38 18 3C 24 44 66 18 08 8.<$Df..
+ .byte $BC,$5A,$19,$18,$3C,$24,$44,$CC ; 9D70 BC 5A 19 18 3C 24 44 CC .Z..<$D.
+ .byte $18,$08,$1C,$3A,$1C,$18,$3C,$24 ; 9D78 18 08 1C 3A 1C 18 3C 24 ...:..<$
+ .byte $22,$66,$18,$08,$BC,$5A,$19,$18 ; 9D80 22 66 18 08 BC 5A 19 18 "f...Z..
+ .byte $3C,$24,$44,$CC,$18,$08,$1C,$3A ; 9D88 3C 24 44 CC 18 08 1C 3A <$D....:
+ .byte $1C,$18,$3C,$24,$22,$66,$0C,$19 ; 9D90 1C 18 3C 24 22 66 0C 19 ..<$"f..
+ .byte $3E,$58,$58,$18,$3E,$42,$83,$00 ; 9D98 3E 58 58 18 3E 42 83 00 >XX.>B..
+ .byte $30,$98,$7C,$1A,$1A,$18,$7C,$42 ; 9DA0 30 98 7C 1A 1A 18 7C 42 0.|...|B
+ .byte $C1,$00,$99,$5A,$3C,$18,$18,$99 ; 9DA8 C1 00 99 5A 3C 18 18 99 ...Z<...
+ .byte $FF,$00,$00,$00,$86,$42,$22,$FE ; 9DB0 FF 00 00 00 86 42 22 FE .....B".
+ .byte $FE,$22,$42,$86,$00,$00,$FF,$99 ; 9DB8 FE 22 42 86 00 00 FF 99 ."B.....
+ .byte $18,$18,$3C,$5A,$99,$00,$00,$00 ; 9DC0 18 18 3C 5A 99 00 00 00 ..<Z....
+ .byte $61,$42,$44,$7F,$7F,$44,$42,$61 ; 9DC8 61 42 44 7F 7F 44 42 61 aBD..DBa
+ .byte $00,$00,$08,$22,$80,$01,$58,$18 ; 9DD0 00 00 08 22 80 01 58 18 ..."..X.
+ .byte $3C,$5A,$99,$FF,$10,$44,$01,$80 ; 9DD8 3C 5A 99 FF 10 44 01 80 <Z...D..
+ .byte $1A,$18,$3C,$5A,$99,$FF,$00,$00 ; 9DE0 1A 18 3C 5A 99 FF 00 00 ..<Z....
+ .byte $3C,$3C,$3C,$E7,$06,$C3,$60,$E3 ; 9DE8 3C 3C 3C E7 06 C3 60 E3 <<<...`.
+ .byte $76,$E3,$76,$CE,$67,$CE,$67,$83 ; 9DF0 76 E3 76 CE 67 CE 67 83 v.v.g.g.
+ .byte $C1,$00,$00,$00,$00,$00,$00,$00 ; 9DF8 C1 00 00 00 00 00 00 00 ........
+; GR.1/2 font, 512 bytes
+charset:.byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9E00 00 00 00 00 00 00 00 00 ........
+ .byte $00,$0C,$19,$3E,$58,$1E,$22 ; 9E08 00 0C 19 3E 58 1E 22 ...>X."
+; couple of places in the code try to write here
+block_char_minus_one:
+ .byte $43,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; 9E0F 43 FF FF FF FF FF FF FF C.......
+ .byte $FF,$00,$66,$FF,$66,$66,$FF,$66 ; 9E17 FF 00 66 FF 66 66 FF 66 ..f.ff.f
+ .byte $00,$18,$3E,$60,$3C,$06,$7C,$18 ; 9E1F 00 18 3E 60 3C 06 7C 18 ..>`<.|.
+ .byte $00,$00,$7C,$82,$BA,$A2,$BA,$82 ; 9E27 00 00 7C 82 BA A2 BA 82 ..|.....
+ .byte $7C,$1C,$36,$1C,$38,$6F,$66,$3B ; 9E2F 7C 1C 36 1C 38 6F 66 3B |.6.8of;
+ .byte $00,$00,$30,$98,$7C,$1A,$78,$44 ; 9E37 00 00 30 98 7C 1A 78 44 ..0.|.xD
+ .byte $C2,$00,$0E,$1C,$18,$18,$18,$1C ; 9E3F C2 00 0E 1C 18 18 18 1C ........
+ .byte $0E,$00,$70,$38,$18,$18,$18,$38 ; 9E47 0E 00 70 38 18 18 18 38 ..p8...8
+ .byte $70,$00,$00,$00,$00,$00,$00,$00 ; 9E4F 70 00 00 00 00 00 00 00 p.......
+ .byte $7E,$00,$18,$18,$18,$7E,$18,$18 ; 9E57 7E 00 18 18 18 7E 18 18 ~....~..
+ .byte $18,$00,$00,$00,$00,$00,$18,$18 ; 9E5F 18 00 00 00 00 00 18 18 ........
+ .byte $30,$00,$00,$00,$00,$7E,$00,$00 ; 9E67 30 00 00 00 00 7E 00 00 0....~..
+ .byte $00,$00,$00,$00,$00,$00,$00,$18 ; 9E6F 00 00 00 00 00 00 00 18 ........
+ .byte $18,$00,$06,$0C,$18,$30,$60,$40 ; 9E77 18 00 06 0C 18 30 60 40 .....0`@
+ .byte $00,$00,$3C,$66,$66,$66,$66,$66 ; 9E7F 00 00 3C 66 66 66 66 66 ..<fffff
+ .byte $3C,$00,$18,$38,$18,$18,$18,$18 ; 9E87 3C 00 18 38 18 18 18 18 <..8....
+ .byte $7E,$00,$3C,$66,$06,$0C,$18,$30 ; 9E8F 7E 00 3C 66 06 0C 18 30 ~.<f...0
+ .byte $7E,$00,$3C,$66,$06,$1C,$06,$66 ; 9E97 7E 00 3C 66 06 1C 06 66 ~.<f...f
+ .byte $3C,$00,$0C,$1C,$3C,$6C,$7E,$0C ; 9E9F 3C 00 0C 1C 3C 6C 7E 0C <...<l~.
+ .byte $0C,$00,$7E,$60,$60,$7C,$06,$06 ; 9EA7 0C 00 7E 60 60 7C 06 06 ..~``|..
+ .byte $7C,$00,$3C,$66,$60,$7C,$66,$66 ; 9EAF 7C 00 3C 66 60 7C 66 66 |.<f`|ff
+ .byte $3C,$00,$7E,$06,$0C,$18,$30,$30 ; 9EB7 3C 00 7E 06 0C 18 30 30 <.~...00
+ .byte $30,$00,$3C,$66,$66,$3C,$66,$66 ; 9EBF 30 00 3C 66 66 3C 66 66 0.<ff<ff
+ .byte $3C,$00,$3C,$66,$66,$3E,$06,$66 ; 9EC7 3C 00 3C 66 66 3E 06 66 <.<ff>.f
+ .byte $3C,$00,$00,$18,$18,$00,$18,$18 ; 9ECF 3C 00 00 18 18 00 18 18 <.......
+ .byte $00,$00,$00,$18,$18,$00,$18,$18 ; 9ED7 00 00 00 18 18 00 18 18 ........
+ .byte $30,$06,$0C,$18,$30,$18,$0C,$06 ; 9EDF 30 06 0C 18 30 18 0C 06 0...0...
+ .byte $00,$00,$00,$00,$7E,$00,$7E,$00 ; 9EE7 00 00 00 00 7E 00 7E 00 ....~.~.
+ .byte $00,$00,$10,$7C,$10,$10,$10,$38 ; 9EEF 00 00 10 7C 10 10 10 38 ...|...8
+ .byte $7C,$00,$3C,$66,$66,$0C,$18,$00 ; 9EF7 7C 00 3C 66 66 0C 18 00 |.<ff...
+ .byte $18,$00,$3C,$66,$6E,$6E,$60,$3E ; 9EFF 18 00 3C 66 6E 6E 60 3E ..<fnn`>
+ .byte $00,$00,$18,$3C,$66,$66,$7E,$66 ; 9F07 00 00 18 3C 66 66 7E 66 ...<ff~f
+ .byte $66,$00,$7C,$66,$66,$7C,$66,$66 ; 9F0F 66 00 7C 66 66 7C 66 66 f.|ff|ff
+ .byte $7C,$00,$3C,$66,$60,$60,$60,$66 ; 9F17 7C 00 3C 66 60 60 60 66 |.<f```f
+ .byte $3C,$00,$7C,$66,$66,$66,$66,$66 ; 9F1F 3C 00 7C 66 66 66 66 66 <.|fffff
+ .byte $7C,$00,$7E,$60,$60,$78,$60,$60 ; 9F27 7C 00 7E 60 60 78 60 60 |.~``x``
+ .byte $7E,$00,$7E,$60,$60,$78,$60,$60 ; 9F2F 7E 00 7E 60 60 78 60 60 ~.~``x``
+ .byte $60,$00,$3C,$66,$60,$60,$6E,$66 ; 9F37 60 00 3C 66 60 60 6E 66 `.<f``nf
+ .byte $3C,$00,$66,$66,$66,$7E,$66,$66 ; 9F3F 3C 00 66 66 66 7E 66 66 <.fff~ff
+ .byte $66,$00,$3C,$18,$18,$18,$18,$18 ; 9F47 66 00 3C 18 18 18 18 18 f.<.....
+ .byte $3C,$00,$06,$06,$06,$06,$66,$66 ; 9F4F 3C 00 06 06 06 06 66 66 <.....ff
+ .byte $3C,$00,$66,$6C,$78,$70,$78,$6C ; 9F57 3C 00 66 6C 78 70 78 6C <.flxpxl
+ .byte $66,$00,$60,$60,$60,$60,$60,$60 ; 9F5F 66 00 60 60 60 60 60 60 f.``````
+ .byte $7E,$00,$63,$77,$7F,$6B,$63,$63 ; 9F67 7E 00 63 77 7F 6B 63 63 ~.cw.kcc
+ .byte $63,$00,$66,$66,$76,$7E,$6E,$66 ; 9F6F 63 00 66 66 76 7E 6E 66 c.ffv~nf
+ .byte $66,$00,$3C,$66,$66,$66,$66,$66 ; 9F77 66 00 3C 66 66 66 66 66 f.<fffff
+ .byte $3C,$00,$7C,$66,$66,$7C,$60,$60 ; 9F7F 3C 00 7C 66 66 7C 60 60 <.|ff|``
+ .byte $60,$00,$3C,$66,$66,$66,$66,$6C ; 9F87 60 00 3C 66 66 66 66 6C `.<ffffl
+ .byte $36,$00,$7C,$66,$66,$7C,$6C,$66 ; 9F8F 36 00 7C 66 66 7C 6C 66 6.|ff|lf
+ .byte $66,$00,$3C,$66,$60,$3C,$06,$66 ; 9F97 66 00 3C 66 60 3C 06 66 f.<f`<.f
+ .byte $3C,$00,$7E,$18,$18,$18,$18,$18 ; 9F9F 3C 00 7E 18 18 18 18 18 <.~.....
+ .byte $18,$00,$66,$66,$66,$66,$66,$66 ; 9FA7 18 00 66 66 66 66 66 66 ..ffffff
+ .byte $3C,$00,$66,$66,$66,$66,$66,$3C ; 9FAF 3C 00 66 66 66 66 66 3C <.fffff<
+ .byte $18,$00,$63,$63,$63,$6B,$7F,$77 ; 9FB7 18 00 63 63 63 6B 7F 77 ..ccck.w
+ .byte $63,$00,$66,$66,$3C,$3C,$3C,$66 ; 9FBF 63 00 66 66 3C 3C 3C 66 c.ff<<<f
+ .byte $66,$00,$66,$66,$66,$3C,$18,$18 ; 9FC7 66 00 66 66 66 3C 18 18 f.fff<..
+ .byte $18,$00,$7E,$06,$0C,$18,$30,$60 ; 9FCF 18 00 7E 06 0C 18 30 60 ..~...0`
+ .byte $7E,$00,$00,$00,$00,$00,$00,$00 ; 9FD7 7E 00 00 00 00 00 00 00 ~.......
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9FDF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9FE7 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; 9FEF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00 ; 9FF7 00 00 00 ...
+; ----------------------------------------------------------------------------
+; main entry point, note cartstart_left and cartstart_right point to the same address
+cartstart_right:
+ .addr cart_entry_point ; 9FFA C0 8A ..
+; ----------------------------------------------------------------------------
+; 0 here means 'cartridge present'
+cartpresent_right:
+ .byte $00 ; 9FFC 00 .
+; 4 here means init & start the cart, no disk boot, non-diagnostic
+cartoptions_right:
+ .byte $04 ; 9FFD 04 .
+; ----------------------------------------------------------------------------
+; points to a CLC/RTS do-nothing routine (same as cartinit_left)
+cartinit_right:
+ .addr cart_start_stub ; 9FFE FE 8A ..
+; ----------------------------------------------------------------------------
+; 64-byte level descriptors, 12 of them (1 per level). first 2 bytes are level number in screencodes
+level00_desc:
+ .byte $10,$11 ; A000 10 11 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level00_sub0:
+ .addr L0000 ; A002 00 00 ..
+; a subroutine
+level00_sub1:
+ .addr L0000 ; A004 00 00 ..
+; a subroutine
+level00_sub2:
+ .addr L0000 ; A006 00 00 ..
+; a subroutine
+level00_sub3:
+ .addr check_collisions_1 ; A008 73 8F s.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level00_num_bombs:
+ .byte $0C ; A00A 0C .
+; 0 = no bullets
+level00_bullet_chance:
+ .byte $01 ; A00B 01 .
+; jumpman starting Y position
+level00_y_start:
+ .byte $A0 ; A00C A0 .
+; jumpman starting X position
+level00_x_start:
+ .byte $7C ; A00D 7C |
+; points to $0600
+level00_offs_14:
+ .byte $00,$06 ; A00E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level00_points_per_bomb:
+ .byte $64 ; A010 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level00_time_bonus:
+ .word $03E8 ; A011 E8 03 ..
+; ----------------------------------------------------------------------------
+; always $00
+level00_offs_19:
+ .byte $00 ; A013 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level00_unkn_table0:
+ .addr L06DF ; A014 DF 06 ..
+; map data
+level00_map0:
+ .addr level00_map ; A016 00 A3 ..
+; map data
+level00_map1:
+ .addr LA366 ; A018 66 A3 f.
+; map data
+level00_map2:
+ .addr LA38B ; A01A 8B A3 ..
+; unknown, pointer to a ROM table or $0000
+level00_unkn_table1:
+ .addr LA3A4 ; A01C A4 A3 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level00_offs_30:
+ .byte $00,$00 ; A01E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level00_sub4:
+ .addr L06E6 ; A020 E6 06 ..
+; $06E6 for some levels, or else a ROM subroutine
+level00_sub5:
+ .addr L06E6 ; A022 E6 06 ..
+; always $9740 aka game_main_loop
+level00_sub6:
+ .addr game_main_loop ; A024 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level00_sub_eol:
+ .addr L06E6 ; A026 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level00_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A028 00 00 00 00 00 00 ......
+; unknown
+level00_offs_46:
+ .byte $CA,$96,$18,$5A,$0C,$24,$4C,$74 ; A02E CA 96 18 5A 0C 24 4C 74 ...Z.$Lt
+ .byte $8C ; A036 8C .
+; unknown, always $00 $00 $00
+level00_offs_55:
+ .byte $00,$00,$00 ; A037 00 00 00 ...
+; unknown, not a ROM address
+level00_offs_58:
+ .byte $1A,$7E ; A03A 1A 7E .~
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level00_offs_60:
+ .byte $00,$00,$00,$00 ; A03C 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level01_desc:
+ .byte $10,$12 ; A040 10 12 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level01_sub0:
+ .addr LA4DD ; A042 DD A4 ..
+; a subroutine
+level01_sub1:
+ .addr LA509 ; A044 09 A5 ..
+; a subroutine
+level01_sub2:
+ .addr L0000 ; A046 00 00 ..
+; a subroutine
+level01_sub3:
+ .addr LA53D ; A048 3D A5 =.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level01_num_bombs:
+ .byte $10 ; A04A 10 .
+; 0 = no bullets
+level01_bullet_chance:
+ .byte $02 ; A04B 02 .
+; jumpman starting Y position
+level01_y_start:
+ .byte $20 ; A04C 20
+; jumpman starting X position
+level01_x_start:
+ .byte $7C ; A04D 7C |
+; points to $0600
+level01_offs_14:
+ .byte $00,$06 ; A04E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level01_points_per_bomb:
+ .byte $64 ; A050 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level01_time_bonus:
+ .word $07D0 ; A051 D0 07 ..
+; ----------------------------------------------------------------------------
+; always $00
+level01_offs_19:
+ .byte $00 ; A053 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level01_unkn_table0:
+ .addr LA5C2 ; A054 C2 A5 ..
+; map data
+level01_map0:
+ .addr LA3E0 ; A056 E0 A3 ..
+; map data
+level01_map1:
+ .addr LA446 ; A058 46 A4 F.
+; map data
+level01_map2:
+ .addr LA477 ; A05A 77 A4 w.
+; unknown, pointer to a ROM table or $0000
+level01_unkn_table1:
+ .addr L0000 ; A05C 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level01_offs_30:
+ .byte $00,$00 ; A05E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level01_sub4:
+ .addr LA498 ; A060 98 A4 ..
+; $06E6 for some levels, or else a ROM subroutine
+level01_sub5:
+ .addr L8036 ; A062 36 80 6.
+; always $9740 aka game_main_loop
+level01_sub6:
+ .addr game_main_loop ; A064 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level01_sub_eol:
+ .addr L06E6 ; A066 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level01_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A068 00 00 00 00 00 00 ......
+; unknown
+level01_offs_46:
+ .byte $6A,$08,$C6,$1A,$18,$4C,$80,$00 ; A06E 6A 08 C6 1A 18 4C 80 00 j....L..
+ .byte $00 ; A076 00 .
+; unknown, always $00 $00 $00
+level01_offs_55:
+ .byte $00,$00,$00 ; A077 00 00 00 ...
+; unknown, not a ROM address
+level01_offs_58:
+ .byte $02,$94 ; A07A 02 94 ..
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level01_offs_60:
+ .byte $00,$00,$00,$00 ; A07C 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level02_desc:
+ .byte $10,$13 ; A080 10 13 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level02_sub0:
+ .addr LA6BD ; A082 BD A6 ..
+; a subroutine
+level02_sub1:
+ .addr L0000 ; A084 00 00 ..
+; a subroutine
+level02_sub2:
+ .addr L0000 ; A086 00 00 ..
+; a subroutine
+level02_sub3:
+ .addr LA724 ; A088 24 A7 $.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level02_num_bombs:
+ .byte $0C ; A08A 0C .
+; 0 = no bullets
+level02_bullet_chance:
+ .byte $00 ; A08B 00 .
+; jumpman starting Y position
+level02_y_start:
+ .byte $40 ; A08C 40 @
+; jumpman starting X position
+level02_x_start:
+ .byte $B4 ; A08D B4 .
+; points to $0600
+level02_offs_14:
+ .byte $00,$06 ; A08E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level02_points_per_bomb:
+ .byte $64 ; A090 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level02_time_bonus:
+ .word $09C4 ; A091 C4 09 ..
+; ----------------------------------------------------------------------------
+; always $00
+level02_offs_19:
+ .byte $00 ; A093 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level02_unkn_table0:
+ .addr LA66D ; A094 6D A6 m.
+; map data
+level02_map0:
+ .addr LA5F0 ; A096 F0 A5 ..
+; map data
+level02_map1:
+ .addr LA62F ; A098 2F A6 /.
+; map data
+level02_map2:
+ .addr LA654 ; A09A 54 A6 T.
+; unknown, pointer to a ROM table or $0000
+level02_unkn_table1:
+ .addr L0000 ; A09C 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level02_offs_30:
+ .byte $00,$00 ; A09E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level02_sub4:
+ .addr L06E6 ; A0A0 E6 06 ..
+; $06E6 for some levels, or else a ROM subroutine
+level02_sub5:
+ .addr LA68C ; A0A2 8C A6 ..
+; always $9740 aka game_main_loop
+level02_sub6:
+ .addr game_main_loop ; A0A4 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level02_sub_eol:
+ .addr L06E6 ; A0A6 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level02_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A0A8 00 00 00 00 00 00 ......
+; unknown
+level02_offs_46:
+ .byte $1A,$C6,$96,$1A,$0C,$8C,$00,$00 ; A0AE 1A C6 96 1A 0C 8C 00 00 ........
+ .byte $00 ; A0B6 00 .
+; unknown, always $00 $00 $00
+level02_offs_55:
+ .byte $00,$00,$00 ; A0B7 00 00 00 ...
+; unknown, not a ROM address
+level02_offs_58:
+ .byte $00,$00 ; A0BA 00 00 ..
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level02_offs_60:
+ .byte $00,$00,$00,$00 ; A0BC 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level03_desc:
+ .byte $10,$14 ; A0C0 10 14 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level03_sub0:
+ .addr LA836 ; A0C2 36 A8 6.
+; a subroutine
+level03_sub1:
+ .addr L0000 ; A0C4 00 00 ..
+; a subroutine
+level03_sub2:
+ .addr L0000 ; A0C6 00 00 ..
+; a subroutine
+level03_sub3:
+ .addr LA827 ; A0C8 27 A8 '.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level03_num_bombs:
+ .byte $10 ; A0CA 10 .
+; 0 = no bullets
+level03_bullet_chance:
+ .byte $00 ; A0CB 00 .
+; jumpman starting Y position
+level03_y_start:
+ .byte $C0 ; A0CC C0 .
+; jumpman starting X position
+level03_x_start:
+ .byte $7C ; A0CD 7C |
+; points to $0600
+level03_offs_14:
+ .byte $00,$06 ; A0CE 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level03_points_per_bomb:
+ .byte $64 ; A0D0 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level03_time_bonus:
+ .word $07D0 ; A0D1 D0 07 ..
+; ----------------------------------------------------------------------------
+; always $00
+level03_offs_19:
+ .byte $00 ; A0D3 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level03_unkn_table0:
+ .addr L06DF ; A0D4 DF 06 ..
+; map data
+level03_map0:
+ .addr LA790 ; A0D6 90 A7 ..
+; map data
+level03_map1:
+ .addr LA7D5 ; A0D8 D5 A7 ..
+; map data
+level03_map2:
+ .addr LA806 ; A0DA 06 A8 ..
+; unknown, pointer to a ROM table or $0000
+level03_unkn_table1:
+ .addr L0000 ; A0DC 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level03_offs_30:
+ .byte $00,$00 ; A0DE 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level03_sub4:
+ .addr L06E6 ; A0E0 E6 06 ..
+; $06E6 for some levels, or else a ROM subroutine
+level03_sub5:
+ .addr L8036 ; A0E2 36 80 6.
+; always $9740 aka game_main_loop
+level03_sub6:
+ .addr game_main_loop ; A0E4 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level03_sub_eol:
+ .addr L06E6 ; A0E6 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level03_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A0E8 00 00 00 00 00 00 ......
+; unknown
+level03_offs_46:
+ .byte $CA,$96,$18,$5A,$4C,$18,$2C,$80 ; A0EE CA 96 18 5A 4C 18 2C 80 ...ZL.,.
+ .byte $6C ; A0F6 6C l
+; unknown, always $00 $00 $00
+level03_offs_55:
+ .byte $00,$00,$00 ; A0F7 00 00 00 ...
+; unknown, not a ROM address
+level03_offs_58:
+ .byte $00,$00 ; A0FA 00 00 ..
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level03_offs_60:
+ .byte $00,$00,$00,$00 ; A0FC 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level04_desc:
+ .byte $10,$15 ; A100 10 15 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level04_sub0:
+ .addr L0000 ; A102 00 00 ..
+; a subroutine
+level04_sub1:
+ .addr L0000 ; A104 00 00 ..
+; a subroutine
+level04_sub2:
+ .addr L0000 ; A106 00 00 ..
+; a subroutine
+level04_sub3:
+ .addr check_collisions_1 ; A108 73 8F s.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level04_num_bombs:
+ .byte $0E ; A10A 0E .
+; 0 = no bullets
+level04_bullet_chance:
+ .byte $02 ; A10B 02 .
+; jumpman starting Y position
+level04_y_start:
+ .byte $C0 ; A10C C0 .
+; jumpman starting X position
+level04_x_start:
+ .byte $34 ; A10D 34 4
+; points to $0600
+level04_offs_14:
+ .byte $00,$06 ; A10E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level04_points_per_bomb:
+ .byte $64 ; A110 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level04_time_bonus:
+ .word $07D0 ; A111 D0 07 ..
+; ----------------------------------------------------------------------------
+; always $00
+level04_offs_19:
+ .byte $00 ; A113 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level04_unkn_table0:
+ .addr L06DF ; A114 DF 06 ..
+; map data
+level04_map0:
+ .addr LAAD0 ; A116 D0 AA ..
+; map data
+level04_map1:
+ .addr LAB42 ; A118 42 AB B.
+; map data
+level04_map2:
+ .addr LAB6D ; A11A 6D AB m.
+; unknown, pointer to a ROM table or $0000
+level04_unkn_table1:
+ .addr LAB8A ; A11C 8A AB ..
+; ----------------------------------------------------------------------------
+; always $0000
+level04_offs_30:
+ .byte $00,$00 ; A11E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level04_sub4:
+ .addr L06E6 ; A120 E6 06 ..
+; $06E6 for some levels, or else a ROM subroutine
+level04_sub5:
+ .addr L06E6 ; A122 E6 06 ..
+; always $9740 aka game_main_loop
+level04_sub6:
+ .addr game_main_loop ; A124 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level04_sub_eol:
+ .addr L06E6 ; A126 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level04_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A128 00 00 00 00 00 00 ......
+; unknown
+level04_offs_46:
+ .byte $6A,$08,$C6,$1A,$0C,$22,$84,$8E ; A12E 6A 08 C6 1A 0C 22 84 8E j...."..
+ .byte $00 ; A136 00 .
+; unknown, always $00 $00 $00
+level04_offs_55:
+ .byte $00,$00,$00 ; A137 00 00 00 ...
+; unknown, not a ROM address
+level04_offs_58:
+ .byte $96,$00 ; A13A 96 00 ..
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level04_offs_60:
+ .byte $00,$00,$00,$00 ; A13C 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level05_desc:
+ .byte $10,$16 ; A140 10 16 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level05_sub0:
+ .addr LAA3A ; A142 3A AA :.
+; a subroutine
+level05_sub1:
+ .addr LAA35 ; A144 35 AA 5.
+; a subroutine
+level05_sub2:
+ .addr LAA55 ; A146 55 AA U.
+; a subroutine
+level05_sub3:
+ .addr LAABC ; A148 BC AA ..
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level05_num_bombs:
+ .byte $10 ; A14A 10 .
+; 0 = no bullets
+level05_bullet_chance:
+ .byte $00 ; A14B 00 .
+; jumpman starting Y position
+level05_y_start:
+ .byte $80 ; A14C 80 .
+; jumpman starting X position
+level05_x_start:
+ .byte $34 ; A14D 34 4
+; points to $0600
+level05_offs_14:
+ .byte $00,$06 ; A14E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level05_points_per_bomb:
+ .byte $64 ; A150 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level05_time_bonus:
+ .word $05DC ; A151 DC 05 ..
+; ----------------------------------------------------------------------------
+; always $00
+level05_offs_19:
+ .byte $00 ; A153 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level05_unkn_table0:
+ .addr L06DF ; A154 DF 06 ..
+; map data
+level05_map0:
+ .addr LA920 ; A156 20 A9 .
+; map data
+level05_map1:
+ .addr LA974 ; A158 74 A9 t.
+; map data
+level05_map2:
+ .addr LA9A5 ; A15A A5 A9 ..
+; unknown, pointer to a ROM table or $0000
+level05_unkn_table1:
+ .addr L0000 ; A15C 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level05_offs_30:
+ .byte $00,$00 ; A15E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level05_sub4:
+ .addr LAA73 ; A160 73 AA s.
+; $06E6 for some levels, or else a ROM subroutine
+level05_sub5:
+ .addr LA9C6 ; A162 C6 A9 ..
+; always $9740 aka game_main_loop
+level05_sub6:
+ .addr game_main_loop ; A164 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level05_sub_eol:
+ .addr L06E6 ; A166 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level05_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A168 00 00 00 00 00 00 ......
+; unknown
+level05_offs_46:
+ .byte $56,$C6,$96,$28,$04,$30,$68,$94 ; A16E 56 C6 96 28 04 30 68 94 V..(.0h.
+ .byte $00 ; A176 00 .
+; unknown, always $00 $00 $00
+level05_offs_55:
+ .byte $00,$00,$00 ; A177 00 00 00 ...
+; unknown, not a ROM address
+level05_offs_58:
+ .byte $4C,$FF ; A17A 4C FF L.
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level05_offs_60:
+ .byte $FF,$FF,$FF,$FF ; A17C FF FF FF FF ....
+; first 2 bytes are level number in screencodes
+level06_desc:
+ .byte $10,$17 ; A180 10 17 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level06_sub0:
+ .addr LAD68 ; A182 68 AD h.
+; a subroutine
+level06_sub1:
+ .addr L0000 ; A184 00 00 ..
+; a subroutine
+level06_sub2:
+ .addr L0000 ; A186 00 00 ..
+; a subroutine
+level06_sub3:
+ .addr check_collisions_1 ; A188 73 8F s.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level06_num_bombs:
+ .byte $0E ; A18A 0E .
+; 0 = no bullets
+level06_bullet_chance:
+ .byte $03 ; A18B 03 .
+; jumpman starting Y position
+level06_y_start:
+ .byte $C0 ; A18C C0 .
+; jumpman starting X position
+level06_x_start:
+ .byte $7C ; A18D 7C |
+; points to $0600
+level06_offs_14:
+ .byte $00,$06 ; A18E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level06_points_per_bomb:
+ .byte $64 ; A190 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level06_time_bonus:
+ .word $05DC ; A191 DC 05 ..
+; ----------------------------------------------------------------------------
+; always $00
+level06_offs_19:
+ .byte $00 ; A193 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level06_unkn_table0:
+ .addr L06DF ; A194 DF 06 ..
+; map data
+level06_map0:
+ .addr LAC60 ; A196 60 AC `.
+; map data
+level06_map1:
+ .addr LACBA ; A198 BA AC ..
+; map data
+level06_map2:
+ .addr LACE5 ; A19A E5 AC ..
+; unknown, pointer to a ROM table or $0000
+level06_unkn_table1:
+ .addr LAD02 ; A19C 02 AD ..
+; ----------------------------------------------------------------------------
+; always $0000
+level06_offs_30:
+ .byte $00,$00 ; A19E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level06_sub4:
+ .addr L06E6 ; A1A0 E6 06 ..
+; $06E6 for some levels, or else a ROM subroutine
+level06_sub5:
+ .addr L8036 ; A1A2 36 80 6.
+; always $9740 aka game_main_loop
+level06_sub6:
+ .addr game_main_loop ; A1A4 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level06_sub_eol:
+ .addr L06E6 ; A1A6 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level06_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A1A8 00 00 00 00 00 00 ......
+; unknown
+level06_offs_46:
+ .byte $CA,$96,$18,$5A,$0C,$4C,$8C,$00 ; A1AE CA 96 18 5A 0C 4C 8C 00 ...Z.L..
+ .byte $00 ; A1B6 00 .
+; unknown, always $00 $00 $00
+level06_offs_55:
+ .byte $00,$00,$00 ; A1B7 00 00 00 ...
+; unknown, not a ROM address
+level06_offs_58:
+ .byte $1C,$7E ; A1BA 1C 7E .~
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level06_offs_60:
+ .byte $00,$00,$00,$00 ; A1BC 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level07_desc:
+ .byte $10,$18 ; A1C0 10 18 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level07_sub0:
+ .addr LAF1C ; A1C2 1C AF ..
+; a subroutine
+level07_sub1:
+ .addr L0000 ; A1C4 00 00 ..
+; a subroutine
+level07_sub2:
+ .addr L0000 ; A1C6 00 00 ..
+; a subroutine
+level07_sub3:
+ .addr check_collisions_1 ; A1C8 73 8F s.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level07_num_bombs:
+ .byte $0C ; A1CA 0C .
+; 0 = no bullets
+level07_bullet_chance:
+ .byte $02 ; A1CB 02 .
+; jumpman starting Y position
+level07_y_start:
+ .byte $20 ; A1CC 20
+; jumpman starting X position
+level07_x_start:
+ .byte $7C ; A1CD 7C |
+; points to $0600
+level07_offs_14:
+ .byte $00,$06 ; A1CE 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level07_points_per_bomb:
+ .byte $64 ; A1D0 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level07_time_bonus:
+ .word $05DC ; A1D1 DC 05 ..
+; ----------------------------------------------------------------------------
+; always $00
+level07_offs_19:
+ .byte $00 ; A1D3 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level07_unkn_table0:
+ .addr LAE8A ; A1D4 8A AE ..
+; map data
+level07_map0:
+ .addr LADE0 ; A1D6 E0 AD ..
+; map data
+level07_map1:
+ .addr LAE4C ; A1D8 4C AE L.
+; map data
+level07_map2:
+ .addr LAE71 ; A1DA 71 AE q.
+; unknown, pointer to a ROM table or $0000
+level07_unkn_table1:
+ .addr L0000 ; A1DC 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level07_offs_30:
+ .byte $00,$00 ; A1DE 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level07_sub4:
+ .addr LAF23 ; A1E0 23 AF #.
+; $06E6 for some levels, or else a ROM subroutine
+level07_sub5:
+ .addr LAE9B ; A1E2 9B AE ..
+; always $9740 aka game_main_loop
+level07_sub6:
+ .addr game_main_loop ; A1E4 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level07_sub_eol:
+ .addr LAF58 ; A1E6 58 AF X.
+; ----------------------------------------------------------------------------
+; all zeroes
+level07_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A1E8 00 00 00 00 00 00 ......
+; unknown
+level07_offs_46:
+ .byte $6A,$08,$C6,$1A,$0C,$30,$68,$8C ; A1EE 6A 08 C6 1A 0C 30 68 8C j....0h.
+ .byte $00 ; A1F6 00 .
+; unknown, always $00 $00 $00
+level07_offs_55:
+ .byte $00,$00,$00 ; A1F7 00 00 00 ...
+; unknown, not a ROM address
+level07_offs_58:
+ .byte $40,$56 ; A1FA 40 56 @V
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level07_offs_60:
+ .byte $00,$00,$00,$00 ; A1FC 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level08_desc:
+ .byte $10,$19 ; A200 10 19 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level08_sub0:
+ .addr LB140 ; A202 40 B1 @.
+; a subroutine
+level08_sub1:
+ .addr L0000 ; A204 00 00 ..
+; a subroutine
+level08_sub2:
+ .addr L0000 ; A206 00 00 ..
+; a subroutine
+level08_sub3:
+ .addr L0000 ; A208 00 00 ..
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level08_num_bombs:
+ .byte $08 ; A20A 08 .
+; 0 = no bullets
+level08_bullet_chance:
+ .byte $00 ; A20B 00 .
+; jumpman starting Y position
+level08_y_start:
+ .byte $C0 ; A20C C0 .
+; jumpman starting X position
+level08_x_start:
+ .byte $9E ; A20D 9E .
+; points to $0600
+level08_offs_14:
+ .byte $00,$06 ; A20E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level08_points_per_bomb:
+ .byte $64 ; A210 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level08_time_bonus:
+ .word $07D0 ; A211 D0 07 ..
+; ----------------------------------------------------------------------------
+; always $00
+level08_offs_19:
+ .byte $00 ; A213 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level08_unkn_table0:
+ .addr L06DF ; A214 DF 06 ..
+; map data
+level08_map0:
+ .addr LB0A2 ; A216 A2 B0 ..
+; map data
+level08_map1:
+ .addr LB072 ; A218 72 B0 r.
+; map data
+level08_map2:
+ .addr LB0A3 ; A21A A3 B0 ..
+; unknown, pointer to a ROM table or $0000
+level08_unkn_table1:
+ .addr L0000 ; A21C 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level08_offs_30:
+ .byte $00,$00 ; A21E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level08_sub4:
+ .addr LB121 ; A220 21 B1 !.
+; $06E6 for some levels, or else a ROM subroutine
+level08_sub5:
+ .addr LB0C4 ; A222 C4 B0 ..
+; always $9740 aka game_main_loop
+level08_sub6:
+ .addr game_main_loop ; A224 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level08_sub_eol:
+ .addr L06E6 ; A226 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level08_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A228 00 00 00 00 00 00 ......
+; unknown
+level08_offs_46:
+ .byte $1A,$C6,$96,$28,$0C,$3C,$00,$00 ; A22E 1A C6 96 28 0C 3C 00 00 ...(.<..
+ .byte $8C ; A236 8C .
+; unknown, always $00 $00 $00
+level08_offs_55:
+ .byte $00,$00,$00 ; A237 00 00 00 ...
+; unknown, not a ROM address
+level08_offs_58:
+ .byte $80,$00 ; A23A 80 00 ..
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level08_offs_60:
+ .byte $00,$00,$00,$00 ; A23C 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level09_desc:
+ .byte $11,$10 ; A240 11 10 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level09_sub0:
+ .addr LB27E ; A242 7E B2 ~.
+; a subroutine
+level09_sub1:
+ .addr L0000 ; A244 00 00 ..
+; a subroutine
+level09_sub2:
+ .addr L0000 ; A246 00 00 ..
+; a subroutine
+level09_sub3:
+ .addr LB2E0 ; A248 E0 B2 ..
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level09_num_bombs:
+ .byte $0C ; A24A 0C .
+; 0 = no bullets
+level09_bullet_chance:
+ .byte $02 ; A24B 02 .
+; jumpman starting Y position
+level09_y_start:
+ .byte $C0 ; A24C C0 .
+; jumpman starting X position
+level09_x_start:
+ .byte $3C ; A24D 3C <
+; points to $0600
+level09_offs_14:
+ .byte $00,$06 ; A24E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level09_points_per_bomb:
+ .byte $64 ; A250 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level09_time_bonus:
+ .word $05DC ; A251 DC 05 ..
+; ----------------------------------------------------------------------------
+; always $00
+level09_offs_19:
+ .byte $00 ; A253 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level09_unkn_table0:
+ .addr LB275 ; A254 75 B2 u.
+; map data
+level09_map0:
+ .addr LB1E0 ; A256 E0 B1 ..
+; map data
+level09_map1:
+ .addr LB237 ; A258 37 B2 7.
+; map data
+level09_map2:
+ .addr LB25C ; A25A 5C B2 \.
+; unknown, pointer to a ROM table or $0000
+level09_unkn_table1:
+ .addr L0000 ; A25C 00 00 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level09_offs_30:
+ .byte $00,$00 ; A25E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level09_sub4:
+ .addr LB2FD ; A260 FD B2 ..
+; $06E6 for some levels, or else a ROM subroutine
+level09_sub5:
+ .addr L8036 ; A262 36 80 6.
+; always $9740 aka game_main_loop
+level09_sub6:
+ .addr game_main_loop ; A264 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level09_sub_eol:
+ .addr L06E6 ; A266 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level09_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A268 00 00 00 00 00 00 ......
+; unknown
+level09_offs_46:
+ .byte $CA,$96,$18,$5A,$0C,$40,$8C,$00 ; A26E CA 96 18 5A 0C 40 8C 00 ...Z.@..
+ .byte $00 ; A276 00 .
+; unknown, always $00 $00 $00
+level09_offs_55:
+ .byte $00,$00,$00 ; A277 00 00 00 ...
+; unknown, not a ROM address
+level09_offs_58:
+ .byte $62,$00 ; A27A 62 00 b.
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level09_offs_60:
+ .byte $00,$00,$00,$00 ; A27C 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level10_desc:
+ .byte $11,$11 ; A280 11 11 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level10_sub0:
+ .addr LB457 ; A282 57 B4 W.
+; a subroutine
+level10_sub1:
+ .addr LB581 ; A284 81 B5 ..
+; a subroutine
+level10_sub2:
+ .addr L0000 ; A286 00 00 ..
+; a subroutine
+level10_sub3:
+ .addr LB57C ; A288 7C B5 |.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level10_num_bombs:
+ .byte $0F ; A28A 0F .
+; 0 = no bullets
+level10_bullet_chance:
+ .byte $00 ; A28B 00 .
+; jumpman starting Y position
+level10_y_start:
+ .byte $B6 ; A28C B6 .
+; jumpman starting X position
+level10_x_start:
+ .byte $C4 ; A28D C4 .
+; points to $0600
+level10_offs_14:
+ .byte $00,$06 ; A28E 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level10_points_per_bomb:
+ .byte $64 ; A290 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level10_time_bonus:
+ .word $03E8 ; A291 E8 03 ..
+; ----------------------------------------------------------------------------
+; always $00
+level10_offs_19:
+ .byte $00 ; A293 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level10_unkn_table0:
+ .addr data_table_b50b ; A294 0B B5 ..
+; map data
+level10_map0:
+ .addr LB320 ; A296 20 B3 .
+; map data
+level10_map1:
+ .addr LB38F ; A298 8F B3 ..
+; map data
+level10_map2:
+ .addr LB3BD ; A29A BD B3 ..
+; unknown, pointer to a ROM table or $0000
+level10_unkn_table1:
+ .addr LB3DC ; A29C DC B3 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level10_offs_30:
+ .byte $00,$00 ; A29E 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level10_sub4:
+ .addr LB44C ; A2A0 4C B4 L.
+; $06E6 for some levels, or else a ROM subroutine
+level10_sub5:
+ .addr L8036 ; A2A2 36 80 6.
+; always $9740 aka game_main_loop
+level10_sub6:
+ .addr game_main_loop ; A2A4 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level10_sub_eol:
+ .addr L06E6 ; A2A6 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level10_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A2A8 00 00 00 00 00 00 ......
+; unknown
+level10_offs_46:
+ .byte $6A,$08,$C6,$1A,$0C,$30,$54,$8C ; A2AE 6A 08 C6 1A 0C 30 54 8C j....0T.
+ .byte $00 ; A2B6 00 .
+; unknown, always $00 $00 $00
+level10_offs_55:
+ .byte $00,$00,$00 ; A2B7 00 00 00 ...
+; unknown, not a ROM address
+level10_offs_58:
+ .byte $00,$66 ; A2BA 00 66 .f
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level10_offs_60:
+ .byte $00,$00,$00,$00 ; A2BC 00 00 00 00 ....
+; first 2 bytes are level number in screencodes
+level11_desc:
+ .byte $11,$12 ; A2C0 11 12 ..
+; ----------------------------------------------------------------------------
+; a subroutine
+level11_sub0:
+ .addr LB691 ; A2C2 91 B6 ..
+; a subroutine
+level11_sub1:
+ .addr LB69B ; A2C4 9B B6 ..
+; a subroutine
+level11_sub2:
+ .addr LB709 ; A2C6 09 B7 ..
+; a subroutine
+level11_sub3:
+ .addr check_collisions_1 ; A2C8 73 8F s.
+; ----------------------------------------------------------------------------
+; number of bombs to pick up on this level
+level11_num_bombs:
+ .byte $0E ; A2CA 0E .
+; 0 = no bullets
+level11_bullet_chance:
+ .byte $00 ; A2CB 00 .
+; jumpman starting Y position
+level11_y_start:
+ .byte $C0 ; A2CC C0 .
+; jumpman starting X position
+level11_x_start:
+ .byte $7C ; A2CD 7C |
+; points to $0600
+level11_offs_14:
+ .byte $00,$06 ; A2CE 00 06 ..
+; points awarded per bomb pickup (always $64 aka 100)
+level11_points_per_bomb:
+ .byte $64 ; A2D0 64 d
+; ----------------------------------------------------------------------------
+; amount of time bonus at start of level
+level11_time_bonus:
+ .word $09C4 ; A2D1 C4 09 ..
+; ----------------------------------------------------------------------------
+; always $00
+level11_offs_19:
+ .byte $00 ; A2D3 00 .
+; ----------------------------------------------------------------------------
+; pointer to ROM table or $06xx
+level11_unkn_table0:
+ .addr LB658 ; A2D4 58 B6 X.
+; map data
+level11_map0:
+ .addr LB590 ; A2D6 90 B5 ..
+; map data
+level11_map1:
+ .addr LB5D2 ; A2D8 D2 B5 ..
+; map data
+level11_map2:
+ .addr LB5FD ; A2DA FD B5 ..
+; unknown, pointer to a ROM table or $0000
+level11_unkn_table1:
+ .addr LB61A ; A2DC 1A B6 ..
+; ----------------------------------------------------------------------------
+; always $0000
+level11_offs_30:
+ .byte $00,$00 ; A2DE 00 00 ..
+; ----------------------------------------------------------------------------
+; $06E6 for most levels, or else a ROM subroutine
+level11_sub4:
+ .addr L06E6 ; A2E0 E6 06 ..
+; $06E6 for some levels, or else a ROM subroutine
+level11_sub5:
+ .addr L8036 ; A2E2 36 80 6.
+; always $9740 aka game_main_loop
+level11_sub6:
+ .addr game_main_loop ; A2E4 40 97 @.
+; called at end of level (all bombs picked up). $06E6 for all but level07
+level11_sub_eol:
+ .addr L06E6 ; A2E6 E6 06 ..
+; ----------------------------------------------------------------------------
+; all zeroes
+level11_offs_40:
+ .byte $00,$00,$00,$00,$00,$00 ; A2E8 00 00 00 00 00 00 ......
+; unknown
+level11_offs_46:
+ .byte $08,$C6,$96,$28,$0C,$2A,$4C,$6A ; A2EE 08 C6 96 28 0C 2A 4C 6A ...(.*Lj
+ .byte $8C ; A2F6 8C .
+; unknown, always $00 $00 $00
+level11_offs_55:
+ .byte $00,$00,$00 ; A2F7 00 00 00 ...
+; unknown, not a ROM address
+level11_offs_58:
+ .byte $00,$00 ; A2FA 00 00 ..
+; unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00
+level11_offs_60:
+ .byte $00,$00,$00,$00 ; A2FC 00 00 00 00 ....
+; level map data starts here
+level00_map:
+ .byte $FE,$33,$9C,$FD,$04,$00,$44,$05 ; A300 FE 33 9C FD 04 00 44 05 .3....D.
+ .byte $06,$04,$15,$0A,$74,$15,$0A,$24 ; A308 06 04 15 0A 74 15 0A 24 ....t..$
+ .byte $22,$02,$74,$22,$02,$24,$25,$16 ; A310 22 02 74 22 02 24 25 16 ".t".$%.
+ .byte $04,$45,$04,$44,$45,$06,$8C,$45 ; A318 04 45 04 44 45 06 8C 45 .E.DE..E
+ .byte $04,$04,$55,$08,$34,$55,$0E,$7C ; A320 04 04 55 08 34 55 0E 7C ..U.4U.|
+ .byte $55,$08,$FD,$04,$FF,$34,$09,$04 ; A328 55 08 FD 04 FF 34 09 04 U....4..
+ .byte $5C,$44,$0A,$FD,$04,$01,$5C,$06 ; A330 5C 44 0A FD 04 01 5C 06 \D....\.
+ .byte $04,$1C,$3B,$0A,$FE,$5F,$9C,$FD ; A338 04 1C 3B 0A FE 5F 9C FD ..;.._..
+ .byte $00,$04,$0C,$41,$05,$8C,$41,$05 ; A340 00 04 0C 41 05 8C 41 05 ...A..A.
+ .byte $24,$01,$05,$74,$01,$05,$4C,$01 ; A348 24 01 05 74 01 05 4C 01 $..t..L.
+ .byte $15,$FE,$C9,$9C,$06,$18,$0A,$99 ; A350 15 FE C9 9C 06 18 0A 99 ........
+ .byte $18,$0A,$FE,$DA,$9C,$1D,$38,$06 ; A358 18 0A FE DA 9C 1D 38 06 ......8.
+ .byte $81,$38,$06,$FE,$B3,$9C ; A360 81 38 06 FE B3 9C .8....
+LA366: .byte $04,$12,$01,$38,$02,$01,$64,$02 ; A366 04 12 01 38 02 01 64 02 ...8..d.
+ .byte $01,$98,$12,$01,$44,$22,$01,$58 ; A36E 01 98 12 01 44 22 01 58 ....D".X
+ .byte $22,$01,$04,$42,$01,$98,$42,$01 ; A376 22 01 04 42 01 98 42 01 "..B..B.
+ .byte $04,$52,$01,$38,$52,$01,$64,$52 ; A37E 04 52 01 38 52 01 64 52 .R.8R.dR
+ .byte $01,$98,$52,$01,$FF ; A386 01 98 52 01 FF ..R..
+LA38B: .byte $24,$00,$62,$10,$82,$20,$C4,$00 ; A38B 24 00 62 10 82 20 C4 00 $.b.. ..
+ .byte $66,$30,$86,$40,$2A,$00,$CA,$00 ; A393 66 30 86 40 2A 00 CA 00 f0.@*...
+ .byte $2C,$00,$6C,$00,$8C,$00,$CC,$00 ; A39B 2C 00 6C 00 8C 00 CC 00 ,.l.....
+ .byte $FF ; A3A3 FF .
+LA3A4: .byte $00,$00,$AE,$A3,$B8,$A3,$C2,$A3 ; A3A4 00 00 AE A3 B8 A3 C2 A3 ........
+ .byte $CC,$A3,$FE,$49,$9C,$FD,$04,$01 ; A3AC CC A3 FE 49 9C FD 04 01 ...I....
+ .byte $64,$08,$02,$FF,$FE,$49,$9C,$FD ; A3B4 64 08 02 FF FE 49 9C FD d....I..
+ .byte $04,$FF,$34,$09,$02,$FF,$FE,$49 ; A3BC 04 FF 34 09 02 FF FE 49 ..4....I
+ .byte $9C,$FD,$04,$00,$2C,$25,$05,$FF ; A3C4 9C FD 04 00 2C 25 05 FF ....,%..
+ .byte $FE,$49,$9C,$FD,$04,$00,$60,$25 ; A3CC FE 49 9C FD 04 00 60 25 .I....`%
+ .byte $05,$FF,$00,$00,$00,$00,$00,$00 ; A3D4 05 FF 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00 ; A3DC 00 00 00 00 ....
+LA3E0: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; A3E0 FE 33 9C FD 04 00 04 05 .3......
+ .byte $08,$34,$05,$0E,$7C,$05,$08,$14 ; A3E8 08 34 05 0E 7C 05 08 14 .4..|...
+ .byte $15,$04,$34,$15,$04,$5C,$15,$04 ; A3F0 15 04 34 15 04 5C 15 04 ..4..\..
+ .byte $7C,$15,$04,$04,$25,$10,$5C,$25 ; A3F8 7C 15 04 04 25 10 5C 25 |...%.\%
+ .byte $10,$20,$3C,$07,$64,$3C,$07,$04 ; A400 10 20 3C 07 64 3C 07 04 . <.d<..
+ .byte $55,$09,$38,$55,$0C,$78,$55,$09 ; A408 55 09 38 55 0C 78 55 09 U.8U.xU.
+ .byte $FD,$04,$FF,$04,$19,$04,$80,$3B ; A410 FD 04 FF 04 19 04 80 3B .......;
+ .byte $07,$FD,$04,$01,$8C,$16,$04,$04 ; A418 07 FD 04 01 8C 16 04 04 ........
+ .byte $35,$07,$FE,$5F,$9C,$FD,$00,$04 ; A420 35 07 FE 5F 9C FD 00 04 5.._....
+ .byte $18,$01,$05,$4C,$01,$15,$80,$01 ; A428 18 01 05 4C 01 15 80 01 ...L....
+ .byte $05,$FE,$C9,$9C,$19,$3C,$05,$85 ; A430 05 FE C9 9C 19 3C 05 85 .....<..
+ .byte $3C,$05,$FE,$DA,$9C,$05,$30,$08 ; A438 3C 05 FE DA 9C 05 30 08 <.....0.
+ .byte $99,$30,$08,$FE,$B3,$9C ; A440 99 30 08 FE B3 9C .0....
+LA446: .byte $04,$02,$01,$38,$02,$01,$64,$02 ; A446 04 02 01 38 02 01 64 02 ...8..d.
+ .byte $01,$98,$02,$01,$04,$12,$01,$38 ; A44E 01 98 02 01 04 12 01 38 .......8
+ .byte $12,$01,$64,$12,$01,$98,$12,$01 ; A456 12 01 64 12 01 98 12 01 ..d.....
+ .byte $20,$22,$01,$7C,$22,$01,$38,$32 ; A45E 20 22 01 7C 22 01 38 32 ".|".82
+ .byte $01,$64,$32,$01,$04,$52,$01,$38 ; A466 01 64 32 01 04 52 01 38 .d2..R.8
+ .byte $52,$01,$64,$52,$01,$98,$52,$01 ; A46E 52 01 64 52 01 98 52 01 R.dR..R.
+ .byte $FF ; A476 FF .
+LA477: .byte $22,$00,$62,$00,$82,$00,$C2,$00 ; A477 22 00 62 00 82 00 C2 00 ".b.....
+ .byte $24,$00,$64,$00,$84,$00,$C4,$00 ; A47F 24 00 64 00 84 00 C4 00 $.d.....
+ .byte $46,$00,$A6,$00,$68,$00,$88,$00 ; A487 46 00 A6 00 68 00 88 00 F...h...
+ .byte $2C,$00,$6C,$00,$8C,$00,$CC,$00 ; A48F 2C 00 6C 00 8C 00 CC 00 ,.l.....
+ .byte $FF ; A497 FF .
+; ----------------------------------------------------------------------------
+LA498: ldy $B2 ; A498 A4 B2 ..
+ lda data_table_a542,y ; A49A B9 42 A5 .B.
+ clc ; A49D 18 .
+ adc #$30 ; A49E 69 30 i0
+ sta $0680 ; A4A0 8D 80 06 ...
+ lda LA543,y ; A4A3 B9 43 A5 .C.
+ asl a ; A4A6 0A .
+ adc #$20 ; A4A7 69 20 i
+ sta $0685 ; A4A9 8D 85 06 ...
+ lda LA582,y ; A4AC B9 82 A5 ...
+ sta $068A ; A4AF 8D 8A 06 ...
+ lda LA583,y ; A4B2 B9 83 A5 ...
+ sta PCOLR2 ; A4B5 8D C2 02 ...
+ lda LA562,y ; A4B8 B9 62 A5 .b.
+ clc ; A4BB 18 .
+ adc #$30 ; A4BC 69 30 i0
+ sta $0681 ; A4BE 8D 81 06 ...
+ lda LA563,y ; A4C1 B9 63 A5 .c.
+ asl a ; A4C4 0A .
+ adc #$20 ; A4C5 69 20 i
+ sta $0686 ; A4C7 8D 86 06 ...
+ lda LA5A2,y ; A4CA B9 A2 A5 ...
+ sta $068B ; A4CD 8D 8B 06 ...
+ lda LA5A3,y ; A4D0 B9 A3 A5 ...
+ sta PCOLR3 ; A4D3 8D C3 02 ...
+ sta $066C ; A4D6 8D 6C 06 .l.
+ sta $066D ; A4D9 8D 6D 06 .m.
+ rts ; A4DC 60 `
+
+; ----------------------------------------------------------------------------
+LA4DD: lda $0623 ; A4DD AD 23 06 .#.
+ bne LA4FF ; A4E0 D0 1D ..
+ lda $0621 ; A4E2 AD 21 06 .!.
+ bne LA4E8 ; A4E5 D0 01 ..
+ rts ; A4E7 60 `
+
+; ----------------------------------------------------------------------------
+LA4E8: ldx #$01 ; A4E8 A2 01 ..
+ lda collision_save+14 ; A4EA AD BE 06 ...
+ and #$03 ; A4ED 29 03 ).
+ bne LA505 ; A4EF D0 14 ..
+ inx ; A4F1 E8 .
+ lda collision_save+15 ; A4F2 AD BF 06 ...
+ and #$03 ; A4F5 29 03 ).
+ bne LA505 ; A4F7 D0 0C ..
+ lda initial_speed ; A4F9 AD 25 06 .%.
+ sta player_speed ; A4FC 8D 24 06 .$.
+LA4FF: lda #$00 ; A4FF A9 00 ..
+ sta $0770 ; A501 8D 70 07 .p.
+ rts ; A504 60 `
+
+; ----------------------------------------------------------------------------
+LA505: stx $0770 ; A505 8E 70 07 .p.
+ rts ; A508 60 `
+
+; ----------------------------------------------------------------------------
+LA509: ldx $0770 ; A509 AE 70 07 .p.
+ bne LA50F ; A50C D0 01 ..
+ rts ; A50E 60 `
+
+; ----------------------------------------------------------------------------
+LA50F: lda RANDOM ; A50F AD 0A D2 ...
+ sta COLPM1,x ; A512 9D 13 D0 ...
+ sta COLPM0 ; A515 8D 12 D0 ...
+ lda #$08 ; A518 A9 08 ..
+ sta player_speed ; A51A 8D 24 06 .$.
+ lda #$2D ; A51D A9 2D .-
+ sta sfx_slot_tempo ; A51F 8D 3E 06 .>.
+ lda #$A5 ; A522 A9 A5 ..
+ sta sfx_slot_timer ; A524 8D 3F 06 .?.
+ lda #$01 ; A527 A9 01 ..
+ jsr L8003 ; A529 20 03 80 ..
+ rts ; A52C 60 `
+
+; ----------------------------------------------------------------------------
+; dunno, referenced by routine at $A50F
+sfx_a52d:
+ .byte $01,$81,$00,$0A,$02,$01,$81,$00 ; A52D 01 81 00 0A 02 01 81 00 ........
+ .byte $32,$02,$01,$81,$00,$1E,$02,$00 ; A535 32 02 01 81 00 1E 02 00 2.......
+; ----------------------------------------------------------------------------
+LA53D: lda #$00 ; A53D A9 00 ..
+ jmp L8F79 ; A53F 4C 79 8F Ly.
+
+; ----------------------------------------------------------------------------
+; dunno, referenced by routine at $A498
+data_table_a542:
+ .byte $0C ; A542 0C .
+LA543: .byte $05,$18,$09,$58,$05,$80,$15,$18 ; A543 05 18 09 58 05 80 15 18 ...X....
+ .byte $09,$28,$25,$4C,$1D,$80,$09,$18 ; A54B 09 28 25 4C 1D 80 09 18 .(%L....
+ .byte $15,$70,$25,$2C,$3C,$4C,$45,$0C ; A553 15 70 25 2C 3C 4C 45 0C .p%,<LE.
+ .byte $55,$20,$55,$4C,$4D,$8C,$55 ; A55B 55 20 55 4C 4D 8C 55 U ULM.U
+LA562: .byte $18 ; A562 18 .
+LA563: .byte $15,$40,$05,$80,$09,$8C,$05,$18 ; A563 15 40 05 80 09 8C 05 18 .@......
+ .byte $09,$4C,$0D,$70,$25,$80,$09,$28 ; A56B 09 4C 0D 70 25 80 09 28 .L.p%..(
+ .byte $25,$80,$15,$4C,$35,$6C,$3C,$0C ; A573 25 80 15 4C 35 6C 3C 0C %..L5l<.
+ .byte $55,$4C,$4D,$78,$55,$8C,$55 ; A57B 55 4C 4D 78 55 8C 55 ULMxU.U
+LA582: .byte $01 ; A582 01 .
+LA583: .byte $08,$02,$C6,$01,$08,$01,$08,$02 ; A583 08 02 C6 01 08 01 08 02 ........
+ .byte $C6,$01,$08,$02,$C6,$02,$C6,$01 ; A58B C6 01 08 02 C6 02 C6 01 ........
+ .byte $08,$01,$08,$01,$08,$02,$C6,$01 ; A593 08 01 08 01 08 02 C6 01 ........
+ .byte $08,$01,$08,$02,$C6,$01,$08 ; A59B 08 01 08 02 C6 01 08 .......
+LA5A2: .byte $01 ; A5A2 01 .
+LA5A3: .byte $08,$01,$08,$02,$C6,$01,$08,$02 ; A5A3 08 01 08 02 C6 01 08 02 ........
+ .byte $C6,$02,$C6,$01,$08,$02,$C6,$01 ; A5AB C6 02 C6 01 08 02 C6 01 ........
+ .byte $08,$01,$08,$02,$C6,$01,$08,$01 ; A5B3 08 01 08 02 C6 01 08 01 ........
+ .byte $08,$02,$C6,$01,$08,$01,$08 ; A5BB 08 02 C6 01 08 01 08 .......
+LA5C2: .byte $03,$D3,$A5,$08,$00,$00,$01,$00 ; A5C2 03 D3 A5 08 00 00 01 00 ........
+ .byte $04,$D3,$A5,$08,$00,$00,$01,$00 ; A5CA 04 D3 A5 08 00 00 01 00 ........
+ .byte $FF,$FF,$FF,$AA,$AA,$FF,$FF,$00 ; A5D2 FF FF FF AA AA FF FF 00 ........
+ .byte $00,$C3,$C3,$C3,$C3,$FF,$FF,$C3 ; A5DA 00 C3 C3 C3 C3 FF FF C3 ........
+ .byte $C3,$00,$00,$00,$00,$00,$00,$00 ; A5E2 C3 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00 ; A5EA 00 00 00 00 00 00 ......
+LA5F0: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; A5F0 FE 33 9C FD 04 00 04 05 .3......
+ .byte $06,$84,$05,$06,$04,$15,$06,$84 ; A5F8 06 84 05 06 04 15 06 84 ........
+ .byte $15,$06,$04,$25,$0C,$6C,$25,$0C ; A600 15 06 04 25 0C 6C 25 0C ...%.l%.
+ .byte $04,$35,$0C,$6C,$35,$0C,$04,$45 ; A608 04 35 0C 6C 35 0C 04 45 .5.l5..E
+ .byte $04,$24,$45,$04,$6C,$45,$04,$8C ; A610 04 24 45 04 6C 45 04 8C .$E.lE..
+ .byte $45,$04,$04,$55,$06,$84,$55,$06 ; A618 45 04 04 55 06 84 55 06 E..U..U.
+ .byte $FE,$5F,$9C,$FD,$00,$04,$0C,$01 ; A620 FE 5F 9C FD 00 04 0C 01 ._......
+ .byte $05,$8C,$01,$05,$FE,$B3,$9C ; A628 05 8C 01 05 FE B3 9C .......
+LA62F: .byte $04,$02,$01,$04,$12,$01,$04,$22 ; A62F 04 02 01 04 12 01 04 22 ......."
+ .byte $01,$04,$32,$01,$04,$42,$01,$04 ; A637 01 04 32 01 04 42 01 04 ..2..B..
+ .byte $52,$01,$98,$02,$01,$98,$12,$01 ; A63F 52 01 98 02 01 98 12 01 R.......
+ .byte $98,$22,$01,$98,$32,$01,$98,$42 ; A647 98 22 01 98 32 01 98 42 ."..2..B
+ .byte $01,$98,$52,$01,$FF ; A64F 01 98 52 01 FF ..R..
+LA654: .byte $22,$00,$24,$00,$26,$00,$28,$00 ; A654 22 00 24 00 26 00 28 00 ".$.&.(.
+ .byte $2A,$00,$2C,$00,$C2,$00,$C4,$00 ; A65C 2A 00 2C 00 C2 00 C4 00 *.,.....
+ .byte $C6,$00,$C8,$00,$CA,$00,$CC,$00 ; A664 C6 00 C8 00 CA 00 CC 00 ........
+ .byte $FF ; A66C FF .
+LA66D: .byte $00,$00,$00,$01,$7A,$01,$01,$66 ; A66D 00 00 00 01 7A 01 01 66 ....z..f
+ .byte $03,$86,$A6,$06,$4C,$4A,$01,$66 ; A675 03 86 A6 06 4C 4A 01 66 ....LJ.f
+ .byte $04,$86,$A6,$06,$A4,$CA,$01,$66 ; A67D 04 86 A6 06 A4 CA 01 66 .......f
+; horizontally moving platforms from level02
+dw_platform_player:
+ .byte $FF,$FF,$FF,$AA,$55,$FF,$FF ; A685 FF FF FF AA 55 FF FF ....U..
+; ----------------------------------------------------------------------------
+LA68C: jsr L8036 ; A68C 20 36 80 6.
+ lda #$06 ; A68F A9 06 ..
+ sta $0760 ; A691 8D 60 07 .`.
+ ldy #$2A ; A694 A0 2A .*
+LA696: ldx #$06 ; A696 A2 06 ..
+LA698: lda LA781,x ; A698 BD 81 A7 ...
+ sta $2B00,y ; A69B 99 00 2B ..+
+ iny ; A69E C8 .
+ dex ; A69F CA .
+ bne LA698 ; A6A0 D0 F6 ..
+ tya ; A6A2 98 .
+ clc ; A6A3 18 .
+ adc #$1A ; A6A4 69 1A i.
+ tay ; A6A6 A8 .
+ dec $0760 ; A6A7 CE 60 07 .`.
+ bne LA696 ; A6AA D0 EA ..
+ lda #$FF ; A6AC A9 FF ..
+ sta SIZEM ; A6AE 8D 0C D0 ...
+ stx $068C ; A6B1 8E 8C 06 ...
+ lda #$01 ; A6B4 A9 01 ..
+ sta SIZEP2 ; A6B6 8D 0A D0 ...
+ sta SIZEP3 ; A6B9 8D 0B D0 ...
+LA6BC: rts ; A6BC 60 `
+
+; ----------------------------------------------------------------------------
+LA6BD: lda $06F5 ; A6BD AD F5 06 ...
+ beq LA6BC ; A6C0 F0 FA ..
+ cmp #$01 ; A6C2 C9 01 ..
+ bne LA6DC ; A6C4 D0 16 ..
+ inc $06F5 ; A6C6 EE F5 06 ...
+ inc $0669 ; A6C9 EE 69 06 .i.
+ inc $066C ; A6CC EE 6C 06 .l.
+ inc $066D ; A6CF EE 6D 06 .m.
+ lda #$01 ; A6D2 A9 01 ..
+ sta $0770 ; A6D4 8D 70 07 .p.
+ lda #$FF ; A6D7 A9 FF ..
+ sta $0771 ; A6D9 8D 71 07 .q.
+LA6DC: lda $0623 ; A6DC AD 23 06 .#.
+ cmp #$02 ; A6DF C9 02 ..
+ beq LA6BC ; A6E1 F0 D9 ..
+ lda $0622 ; A6E3 AD 22 06 .".
+ beq LA6BC ; A6E6 F0 D4 ..
+ ldx #$02 ; A6E8 A2 02 ..
+LA6EA: inx ; A6EA E8 .
+ cpx #$05 ; A6EB E0 05 ..
+ beq LA70F ; A6ED F0 20 .
+ clc ; A6EF 18 .
+ lda $067D,x ; A6F0 BD 7D 06 .}.
+ adc $076D,x ; A6F3 7D 6D 07 }m.
+ sta $067D,x ; A6F6 9D 7D 06 .}.
+ cmp #$4B ; A6F9 C9 4B .K
+ beq LA701 ; A6FB F0 04 ..
+ cmp #$A4 ; A6FD C9 A4 ..
+ bne LA6EA ; A6FF D0 E9 ..
+LA701: lda $076D,x ; A701 BD 6D 07 .m.
+ eor #$FF ; A704 49 FF I.
+ sta $076D,x ; A706 9D 6D 07 .m.
+ inc $076D,x ; A709 FE 6D 07 .m.
+ jmp LA6EA ; A70C 4C EA A6 L..
+
+; ----------------------------------------------------------------------------
+LA70F: lda $2BCF ; A70F AD CF 2B ..+
+ sta $2B0E ; A712 8D 0E 2B ..+
+ ldy #$CF ; A715 A0 CF ..
+ ldx #$CE ; A717 A2 CE ..
+LA719: lda $2B00,x ; A719 BD 00 2B ..+
+ sta $2B00,y ; A71C 99 00 2B ..+
+ dex ; A71F CA .
+ dey ; A720 88 .
+ bne LA719 ; A721 D0 F6 ..
+ rts ; A723 60 `
+
+; ----------------------------------------------------------------------------
+LA724: lda $0623 ; A724 AD 23 06 .#.
+ cmp #$02 ; A727 C9 02 ..
+ beq LA778 ; A729 F0 4D .M
+ lda $0622 ; A72B AD 22 06 .".
+ beq LA778 ; A72E F0 48 .H
+ lda $0778 ; A730 AD 78 07 .x.
+ beq LA73D ; A733 F0 08 ..
+ lda #$00 ; A735 A9 00 ..
+ sta $06ED ; A737 8D ED 06 ...
+ sta $0778 ; A73A 8D 78 07 .x.
+LA73D: lda collision_save+8 ; A73D AD B8 06 ...
+ ora collision_save+9 ; A740 0D B9 06 ...
+ ora collision_save+10 ; A743 0D BA 06 ...
+ ora collision_save+11 ; A746 0D BB 06 ...
+ tax ; A749 AA .
+ ora collision_save+14 ; A74A 0D BE 06 ...
+ ora collision_save+15 ; A74D 0D BF 06 ...
+ tay ; A750 A8 .
+ and #$01 ; A751 29 01 ).
+ beq LA760 ; A753 F0 0B ..
+ lda collision_save+4 ; A755 AD B4 06 ...
+ ora #$01 ; A758 09 01 ..
+ sta collision_save+4 ; A75A 8D B4 06 ...
+ inc $0683 ; A75D EE 83 06 ...
+LA760: tya ; A760 98 .
+ and #$02 ; A761 29 02 ).
+ beq LA779 ; A763 F0 14 ..
+ lda collision_save+5 ; A765 AD B5 06 ...
+ ora #$01 ; A768 09 01 ..
+ sta collision_save+5 ; A76A 8D B5 06 ...
+ txa ; A76D 8A .
+ and #$02 ; A76E 29 02 ).
+ beq LA778 ; A770 F0 06 ..
+ inc $0683 ; A772 EE 83 06 ...
+ sta $0778 ; A775 8D 78 07 .x.
+LA778: rts ; A778 60 `
+
+; ----------------------------------------------------------------------------
+LA779: lda $0683 ; A779 AD 83 06 ...
+ and #$FE ; A77C 29 FE ).
+ sta $0683 ; A77E 8D 83 06 ...
+LA781: rts ; A781 60 `
+
+; ----------------------------------------------------------------------------
+; the dumbwaiters from level02. stored upside-down.
+dumbwaiter_player:
+ .byte $18,$3C,$7E,$FF,$FF,$FF,$00,$00 ; A782 18 3C 7E FF FF FF 00 00 .<~.....
+ .byte $00,$00,$00,$00,$00,$00 ; A78A 00 00 00 00 00 00 ......
+LA790: .byte $FE,$33,$9C,$FD,$04,$00,$40,$05 ; A790 FE 33 9C FD 04 00 40 05 .3....@.
+ .byte $08,$18,$15,$0A,$04,$25,$14,$18 ; A798 08 18 15 0A 04 25 14 18 .....%..
+ .byte $35,$0A,$2C,$45,$0A,$04,$55,$0F ; A7A0 35 0A 2C 45 0A 04 55 0F 5.,E..U.
+ .byte $60,$55,$0F,$4C,$15,$0F,$60,$25 ; A7A8 60 55 0F 4C 15 0F 60 25 `U.L..`%
+ .byte $0F,$4C,$35,$0F,$60,$45,$05,$FE ; A7B0 0F 4C 35 0F 60 45 05 FE .L5.`E..
+ .byte $5F,$9C,$FD,$00,$04,$4C,$01,$05 ; A7B8 5F 9C FD 00 04 4C 01 05 _....L..
+ .byte $4C,$21,$05,$4C,$41,$05,$18,$11 ; A7C0 4C 21 05 4C 41 05 18 11 L!.LA...
+ .byte $05,$80,$11,$05,$2C,$31,$05,$6C ; A7C8 05 80 11 05 2C 31 05 6C ....,1.l
+ .byte $31,$05,$FE,$B3,$9C ; A7D0 31 05 FE B3 9C 1....
+LA7D5: .byte $40,$02,$01,$5C,$02,$01,$24,$12 ; A7D5 40 02 01 5C 02 01 24 12 @..\..$.
+ .byte $01,$3C,$12,$01,$60,$12,$01,$78 ; A7DD 01 3C 12 01 60 12 01 78 .<..`..x
+ .byte $12,$01,$04,$22,$01,$3C,$22,$01 ; A7E5 12 01 04 22 01 3C 22 01 ...".<".
+ .byte $60,$22,$01,$98,$22,$01,$18,$32 ; A7ED 60 22 01 98 22 01 18 32 `".."..2
+ .byte $01,$84,$32,$01,$3C,$42,$01,$60 ; A7F5 01 84 32 01 3C 42 01 60 ..2.<B.`
+ .byte $42,$01,$04,$52,$01,$98,$52,$01 ; A7FD 42 01 04 52 01 98 52 01 B..R..R.
+ .byte $FF ; A805 FF .
+LA806: .byte $62,$00,$82,$00,$44,$00,$64,$00 ; A806 62 00 82 00 44 00 64 00 b...D.d.
+ .byte $84,$00,$A4,$00,$26,$00,$66,$00 ; A80E 84 00 A4 00 26 00 66 00 ....&.f.
+ .byte $86,$00,$C6,$00,$48,$00,$A8,$00 ; A816 86 00 C6 00 48 00 A8 00 ....H...
+ .byte $6A,$00,$8A,$00,$2C,$00,$CC,$00 ; A81E 6A 00 8A 00 2C 00 CC 00 j...,...
+ .byte $FF ; A826 FF .
+; ----------------------------------------------------------------------------
+LA827: lda $0619 ; A827 AD 19 06 ...
+ asl a ; A82A 0A .
+ asl a ; A82B 0A .
+ asl a ; A82C 0A .
+ asl a ; A82D 0A .
+ ora #$08 ; A82E 09 08 ..
+ sta COLOR3 ; A830 8D C7 02 ...
+ jmp check_collisions_1 ; A833 4C 73 8F Ls.
+
+; ----------------------------------------------------------------------------
+LA836: lda $0623 ; A836 AD 23 06 .#.
+ cmp #$02 ; A839 C9 02 ..
+ beq LA842 ; A83B F0 05 ..
+ lda $0622 ; A83D AD 22 06 .".
+ bne LA843 ; A840 D0 01 ..
+LA842: rts ; A842 60 `
+
+; ----------------------------------------------------------------------------
+LA843: ldx #$05 ; A843 A2 05 ..
+LA845: dex ; A845 CA .
+ beq LA842 ; A846 F0 FA ..
+ lda $075F,x ; A848 BD 5F 07 ._.
+ bne LA865 ; A84B D0 18 ..
+ lda RANDOM ; A84D AD 0A D2 ...
+ and #$1F ; A850 29 1F ).
+ bne LA845 ; A852 D0 F1 ..
+ inc $075F,x ; A854 FE 5F 07 ._.
+ lda #$00 ; A857 A9 00 ..
+ sta $069E,x ; A859 9D 9E 06 ...
+ lda $067E ; A85C AD 7E 06 .~.
+ clc ; A85F 18 .
+ adc #$03 ; A860 69 03 i.
+ sta $069A,x ; A862 9D 9A 06 ...
+LA865: lda $0763,x ; A865 BD 63 07 .c.
+ bne LA89E ; A868 D0 34 .4
+ lda dli_vec_shadow_hi,x ; A86A BD AF 06 ...
+ and #$01 ; A86D 29 01 ).
+ beq LA89E ; A86F F0 2D .-
+ lda $067E ; A871 AD 7E 06 .~.
+ clc ; A874 18 .
+ adc #$03 ; A875 69 03 i.
+ ldy #$01 ; A877 A0 01 ..
+ cmp $069A,x ; A879 DD 9A 06 ...
+ beq LA882 ; A87C F0 04 ..
+ iny ; A87E C8 .
+ bcc LA882 ; A87F 90 01 ..
+ iny ; A881 C8 .
+LA882: tya ; A882 98 .
+ sta $0763,x ; A883 9D 63 07 .c.
+ lda #$00 ; A886 A9 00 ..
+ sta $0767,x ; A888 9D 67 07 .g.
+ txa ; A88B 8A .
+ pha ; A88C 48 H
+ lda #$0D ; A88D A9 0D ..
+ sta sfx_slot_tempo ; A88F 8D 3E 06 .>.
+ lda #$A9 ; A892 A9 A9 ..
+ sta sfx_slot_timer ; A894 8D 3F 06 .?.
+ lda #$03 ; A897 A9 03 ..
+ jsr L8003 ; A899 20 03 80 ..
+ pla ; A89C 68 h
+ tax ; A89D AA .
+LA89E: lda $0763,x ; A89E BD 63 07 .c.
+ bne LA8C1 ; A8A1 D0 1E ..
+LA8A3: clc ; A8A3 18 .
+ lda $069E,x ; A8A4 BD 9E 06 ...
+ adc #$02 ; A8A7 69 02 i.
+ cmp #$CE ; A8A9 C9 CE ..
+ bcs LA8B3 ; A8AB B0 06 ..
+ sta $069E,x ; A8AD 9D 9E 06 ...
+ jmp LA845 ; A8B0 4C 45 A8 LE.
+
+; ----------------------------------------------------------------------------
+LA8B3: lda #$00 ; A8B3 A9 00 ..
+ sta $069A,x ; A8B5 9D 9A 06 ...
+ sta $075F,x ; A8B8 9D 5F 07 ._.
+ sta $0763,x ; A8BB 9D 63 07 .c.
+ jmp LA845 ; A8BE 4C 45 A8 LE.
+
+; ----------------------------------------------------------------------------
+LA8C1: lda $0767,x ; A8C1 BD 67 07 .g.
+ cmp #$08 ; A8C4 C9 08 ..
+ bne LA8D4 ; A8C6 D0 0C ..
+ lda #$00 ; A8C8 A9 00 ..
+ sta $0763,x ; A8CA 9D 63 07 .c.
+ cpx #$03 ; A8CD E0 03 ..
+ bcc LA8A3 ; A8CF 90 D2 ..
+ jmp LA865 ; A8D1 4C 65 A8 Le.
+
+; ----------------------------------------------------------------------------
+LA8D4: tay ; A8D4 A8 .
+ clc ; A8D5 18 .
+ lda $069E,x ; A8D6 BD 9E 06 ...
+ adc LA905,y ; A8D9 79 05 A9 y..
+ sta $069E,x ; A8DC 9D 9E 06 ...
+ lda data_table_a8fd,y ; A8DF B9 FD A8 ...
+ tay ; A8E2 A8 .
+ beq LA8EF ; A8E3 F0 0A ..
+ tay ; A8E5 A8 .
+ lda $0763,x ; A8E6 BD 63 07 .c.
+ cmp #$03 ; A8E9 C9 03 ..
+ beq LA8EF ; A8EB F0 02 ..
+ ldy #$FE ; A8ED A0 FE ..
+LA8EF: tya ; A8EF 98 .
+ clc ; A8F0 18 .
+ adc $069A,x ; A8F1 7D 9A 06 }..
+ sta $069A,x ; A8F4 9D 9A 06 ...
+ inc $0767,x ; A8F7 FE 67 07 .g.
+ jmp LA845 ; A8FA 4C 45 A8 LE.
+
+; ----------------------------------------------------------------------------
+; dunno, referenced by routine at $A8D4
+data_table_a8fd:
+ .byte $00,$02,$02,$02,$02,$02,$02,$00 ; A8FD 00 02 02 02 02 02 02 00 ........
+LA905: .byte $FE,$FE,$FE,$00,$00,$02,$02,$02 ; A905 FE FE FE 00 00 02 02 02 ........
+ .byte $01,$83,$00,$0A,$03,$00,$00,$00 ; A90D 01 83 00 0A 03 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; A915 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00 ; A91D 00 00 00 ...
+LA920: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; A920 FE 33 9C FD 04 00 04 05 .3......
+ .byte $04,$24,$05,$04,$44,$05,$06,$6C ; A928 04 24 05 04 44 05 06 6C .$..D..l
+ .byte $05,$04,$8C,$05,$04,$30,$16,$04 ; A930 05 04 8C 05 04 30 16 04 .....0..
+ .byte $60,$16,$04,$04,$25,$09,$78,$25 ; A938 60 16 04 04 25 09 78 25 `...%.x%
+ .byte $09,$04,$35,$09,$40,$35,$08,$78 ; A940 09 04 35 09 40 35 08 78 ..5.@5.x
+ .byte $35,$09,$40,$45,$02,$58,$45,$02 ; A948 35 09 40 45 02 58 45 02 5.@E.XE.
+ .byte $04,$55,$05,$28,$55,$06,$4C,$55 ; A950 04 55 05 28 55 06 4C 55 .U.(U.LU
+ .byte $02,$60,$55,$06,$88,$55,$05,$FE ; A958 02 60 55 06 88 55 05 FE .`U..U..
+ .byte $5F,$9C,$FD,$00,$04,$04,$01,$09 ; A960 5F 9C FD 00 04 04 01 09 _.......
+ .byte $94,$01,$09,$30,$19,$0F,$68,$19 ; A968 94 01 09 30 19 0F 68 19 ...0..h.
+ .byte $0F,$FE,$B3,$9C ; A970 0F FE B3 9C ....
+LA974: .byte $24,$02,$01,$44,$02,$01,$58,$02 ; A974 24 02 01 44 02 01 58 02 $..D..X.
+ .byte $01,$78,$02,$01,$44,$12,$01,$58 ; A97C 01 78 02 01 44 12 01 58 .x..D..X
+ .byte $12,$01,$24,$22,$01,$78,$22,$01 ; A984 12 01 24 22 01 78 22 01 ..$".x".
+ .byte $40,$32,$01,$5C,$32,$01,$40,$42 ; A98C 40 32 01 5C 32 01 40 42 @2.\2.@B
+ .byte $01,$5C,$42,$01,$04,$52,$01,$3C ; A994 01 5C 42 01 04 52 01 3C .\B..R.<
+ .byte $52,$01,$60,$52,$01,$98,$52,$01 ; A99C 52 01 60 52 01 98 52 01 R.`R..R.
+ .byte $FF ; A9A4 FF .
+LA9A5: .byte $42,$00,$62,$00,$82,$00,$A2,$00 ; A9A5 42 00 62 00 82 00 A2 00 B.b.....
+ .byte $64,$00,$84,$00,$46,$00,$A6,$00 ; A9AD 64 00 84 00 46 00 A6 00 d...F...
+ .byte $68,$00,$88,$00,$6A,$00,$8A,$00 ; A9B5 68 00 88 00 6A 00 8A 00 h...j...
+ .byte $2C,$00,$6C,$00,$8C,$00,$CC,$00 ; A9BD 2C 00 6C 00 8C 00 CC 00 ,.l.....
+ .byte $FF ; A9C5 FF .
+LA9C6: .byte $20 ; A9C6 20
+; ----------------------------------------------------------------------------
+ rol $80,x ; A9C7 36 80 6.
+ lda #$02 ; A9C9 A9 02 ..
+ sta $0770 ; A9CB 8D 70 07 .p.
+ sta $0772 ; A9CE 8D 72 07 .r.
+ lda #$FE ; A9D1 A9 FE ..
+ sta $0771 ; A9D3 8D 71 07 .q.
+ sta $0773 ; A9D6 8D 73 07 .s.
+ ldx #$05 ; A9D9 A2 05 ..
+ lda #$00 ; A9DB A9 00 ..
+LA9DD: sta HPOSP3,x ; A9DD 9D 03 D0 ...
+ dex ; A9E0 CA .
+ bne LA9DD ; A9E1 D0 FA ..
+ lda #$C0 ; A9E3 A9 C0 ..
+ jsr LAA0C ; A9E5 20 0C AA ..
+ lda #$C0 ; A9E8 A9 C0 ..
+ jsr LAA0C ; A9EA 20 0C AA ..
+ lda #$30 ; A9ED A9 30 .0
+ jsr LAA0C ; A9EF 20 0C AA ..
+ lda #$30 ; A9F2 A9 30 .0
+ jsr LAA0C ; A9F4 20 0C AA ..
+ lda #$0C ; A9F7 A9 0C ..
+ jsr LAA0C ; A9F9 20 0C AA ..
+ lda #$0C ; A9FC A9 0C ..
+ jsr LAA0C ; A9FE 20 0C AA ..
+ lda #$03 ; AA01 A9 03 ..
+ jsr LAA0C ; AA03 20 0C AA ..
+ lda #$03 ; AA06 A9 03 ..
+ jsr LAA0C ; AA08 20 0C AA ..
+ rts ; AA0B 60 `
+
+; ----------------------------------------------------------------------------
+LAA0C: sta dm_progctr ; AA0C 85 C0 ..
+LAA0E: lda RANDOM ; AA0E AD 0A D2 ...
+ cmp #$AC ; AA11 C9 AC ..
+ bcs LAA0E ; AA13 B0 F9 ..
+ tay ; AA15 A8 .
+ ldx #$1E ; AA16 A2 1E ..
+LAA18: lda $2B00,y ; AA18 B9 00 2B ..+
+ ora dm_progctr ; AA1B 05 C0 ..
+ sta $2B00,y ; AA1D 99 00 2B ..+
+ iny ; AA20 C8 .
+ dex ; AA21 CA .
+ bne LAA18 ; AA22 D0 F4 ..
+ rts ; AA24 60 `
+
+; ----------------------------------------------------------------------------
+LAA25: lda $076F ; AA25 AD 6F 07 .o.
+ cmp #$04 ; AA28 C9 04 ..
+ bne LAA2D ; AA2A D0 01 ..
+ rts ; AA2C 60 `
+
+; ----------------------------------------------------------------------------
+LAA2D: tax ; AA2D AA .
+ inc $0774,x ; AA2E FE 74 07 .t.
+ inc $076F ; AA31 EE 6F 07 .o.
+ rts ; AA34 60 `
+
+; ----------------------------------------------------------------------------
+LAA35: lda $0622 ; AA35 AD 22 06 .".
+ bne LAA3B ; AA38 D0 01 ..
+LAA3A: rts ; AA3A 60 `
+
+; ----------------------------------------------------------------------------
+LAA3B: ldx #$05 ; AA3B A2 05 ..
+LAA3D: dex ; AA3D CA .
+ beq LAA3A ; AA3E F0 FA ..
+ lda $0773,x ; AA40 BD 73 07 .s.
+ beq LAA3D ; AA43 F0 F8 ..
+ lda $0777,x ; AA45 BD 77 07 .w.
+ clc ; AA48 18 .
+ adc $076F,x ; AA49 7D 6F 07 }o.
+ sta $0777,x ; AA4C 9D 77 07 .w.
+ sta HPOSP3,x ; AA4F 9D 03 D0 ...
+ jmp LAA3D ; AA52 4C 3D AA L=.
+
+; ----------------------------------------------------------------------------
+LAA55: lda $0622 ; AA55 AD 22 06 .".
+ beq LAA3A ; AA58 F0 E0 ..
+ ldx #$05 ; AA5A A2 05 ..
+LAA5C: dex ; AA5C CA .
+ beq LAA3A ; AA5D F0 DB ..
+ lda collision_save+7,x ; AA5F BD B7 06 ...
+ and #$01 ; AA62 29 01 ).
+ beq LAA5C ; AA64 F0 F6 ..
+ lda $067E ; AA66 AD 7E 06 .~.
+ clc ; AA69 18 .
+ adc $076F,x ; AA6A 7D 6F 07 }o.
+ sta $067E ; AA6D 8D 7E 06 .~.
+ jmp LAA5C ; AA70 4C 5C AA L\.
+
+; ----------------------------------------------------------------------------
+LAA73: inc $0764 ; AA73 EE 64 07 .d.
+ lda $0764 ; AA76 AD 64 07 .d.
+ and #$01 ; AA79 29 01 ).
+ beq LAA82 ; AA7B F0 05 ..
+ lda #$90 ; AA7D A9 90 ..
+ jmp LAA84 ; AA7F 4C 84 AA L..
+
+; ----------------------------------------------------------------------------
+LAA82: lda #$A6 ; AA82 A9 A6 ..
+LAA84: sta dm_progctr ; AA84 85 C0 ..
+ lda #$AA ; AA86 A9 AA ..
+ sta dm_progctr+1 ; AA88 85 C1 ..
+ jsr draw_map_jv ; AA8A 20 00 80 ..
+ jmp LAA25 ; AA8D 4C 25 AA L%.
+
+; ----------------------------------------------------------------------------
+; dunno what this is for yet
+map_aa90:
+ .byte $FE,$EB,$9C,$FD,$00,$04,$50,$00 ; AA90 FE EB 9C FD 00 04 50 00 ......P.
+ .byte $0C,$FE,$33,$9C,$4E,$05,$01,$FE ; AA98 0C FE 33 9C 4E 05 01 FE ..3.N...
+ .byte $DA,$9C,$50,$00,$0C,$FF ; AAA0 DA 9C 50 00 0C FF ..P...
+; referenced by routine at $AA82
+map_aaa6:
+ .byte $FE,$EB,$9C,$FD,$00,$04,$50,$00 ; AAA6 FE EB 9C FD 00 04 50 00 ......P.
+ .byte $0C,$FE,$33,$9C,$4E,$05,$01,$FE ; AAAE 0C FE 33 9C 4E 05 01 FE ..3.N...
+ .byte $C9,$9C,$50,$08,$0A,$FF ; AAB6 C9 9C 50 08 0A FF ..P...
+LAABC: .byte $AD,$2A,$06,$8D,$C7,$02,$60,$00 ; AABC AD 2A 06 8D C7 02 60 00 .*....`.
+ .byte $8D,$C7,$02,$60,$00,$09,$40,$45 ; AAC4 8D C7 02 60 00 09 40 45 ...`..@E
+ .byte $02,$58,$45,$02 ; AACC 02 58 45 02 .XE.
+LAAD0: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; AAD0 FE 33 9C FD 04 00 04 05 .3......
+ .byte $02,$1A,$05,$0B,$50,$05,$07,$04 ; AAD8 02 1A 05 0B 50 05 07 04 ....P...
+ .byte $25,$26,$7C,$33,$08,$20,$3B,$03 ; AAE0 25 26 7C 33 08 20 3B 03 %&|3. ;.
+ .byte $40,$3B,$03,$60,$3B,$06,$04,$47 ; AAE8 40 3B 03 60 3B 06 04 47 @;.`;..G
+ .byte $04,$20,$4B,$03,$40,$4B,$03,$60 ; AAF0 04 20 4B 03 40 4B 03 60 . K.@K.`
+ .byte $4B,$03,$80,$4A,$03,$04,$55,$26 ; AAF8 4B 03 80 4A 03 04 55 26 K..J..U&
+ .byte $FD,$04,$FF,$2C,$4A,$03,$4C,$4A ; AB00 FD 04 FF 2C 4A 03 4C 4A ...,J.LJ
+ .byte $03,$6C,$4A,$03,$FD,$04,$01,$14 ; AB08 03 6C 4A 03 FD 04 01 14 .lJ.....
+ .byte $48,$03,$38,$49,$02,$58,$49,$02 ; AB10 48 03 38 49 02 58 49 02 H.8I.XI.
+ .byte $78,$49,$02,$FE,$5F,$9C,$FD,$00 ; AB18 78 49 02 FE 5F 9C FD 00 xI.._...
+ .byte $04,$0C,$21,$0D,$84,$01,$09,$84 ; AB20 04 0C 21 0D 84 01 09 84 ..!.....
+ .byte $2F,$06,$22,$01,$05,$FE,$C9,$9C ; AB28 2F 06 22 01 05 FE C9 9C /.".....
+ .byte $3C,$08,$06,$35,$28,$04,$55,$28 ; AB30 3C 08 06 35 28 04 55 28 <..5(.U(
+ .byte $04,$FE,$DA,$9C,$9A,$30,$08,$FE ; AB38 04 FE DA 9C 9A 30 08 FE .....0..
+ .byte $B3,$9C ; AB40 B3 9C ..
+LAB42: .byte $04,$02,$01,$44,$02,$01,$24,$16 ; AB42 04 02 01 44 02 01 24 16 ...D..$.
+ .byte $01,$44,$22,$01,$64,$22,$01,$98 ; AB4A 01 44 22 01 64 22 01 98 .D".d"..
+ .byte $22,$01,$24,$32,$01,$44,$32,$01 ; AB52 22 01 24 32 01 44 32 01 ".$2.D2.
+ .byte $64,$32,$01,$24,$52,$01,$44,$52 ; AB5A 64 32 01 24 52 01 44 52 d2.$R.DR
+ .byte $01,$64,$52,$01,$84,$52,$01,$98 ; AB62 01 64 52 01 84 52 01 98 .dR..R..
+ .byte $52,$01,$FF ; AB6A 52 01 FF R..
+LAB6D: .byte $22,$10,$62,$20,$44,$30,$66,$40 ; AB6D 22 10 62 20 44 30 66 40 ".b D0f@
+ .byte $86,$50,$C6,$60,$48,$70,$68,$80 ; AB75 86 50 C6 60 48 70 68 80 .P.`Hph.
+ .byte $88,$90,$4C,$A0,$6C,$B0,$8C,$C0 ; AB7D 88 90 4C A0 6C B0 8C C0 ..L.l...
+ .byte $AC,$00,$CC,$D0,$FF ; AB85 AC 00 CC D0 FF .....
+LAB8A: .byte $00,$00,$A6,$AB,$B6,$AB,$C0,$AB ; AB8A 00 00 A6 AB B6 AB C0 AB ........
+ .byte $D3,$AB,$DD,$AB,$F0,$AB,$FA,$AB ; AB92 D3 AB DD AB F0 AB FA AB ........
+ .byte $04,$AC,$0E,$AC,$18,$AC,$22,$AC ; AB9A 04 AC 0E AC 18 AC 22 AC ......".
+ .byte $2C,$AC,$36,$AC,$FE,$49,$9C,$FD ; ABA2 2C AC 36 AC FE 49 9C FD ,.6..I..
+ .byte $04,$00,$04,$05,$02,$FE,$33,$9C ; ABAA 04 00 04 05 02 FE 33 9C ......3.
+ .byte $20,$22,$03,$FF,$FE,$49,$9C,$FD ; ABB2 20 22 03 FF FE 49 9C FD "...I..
+ .byte $04,$00,$3E,$05,$02,$FF,$FE,$89 ; ABBA 04 00 3E 05 02 FF FE 89 ..>.....
+ .byte $9C,$FD,$00,$04,$22,$11,$01,$FE ; ABC2 9C FD 00 04 22 11 01 FE ...."...
+ .byte $49,$9C,$FD,$04,$FF,$2C,$4A,$03 ; ABCA 49 9C FD 04 FF 2C 4A 03 I....,J.
+ .byte $FF,$FE,$49,$9C,$FD,$04,$00,$44 ; ABD2 FF FE 49 9C FD 04 00 44 ..I....D
+ .byte $25,$03,$FF,$FE,$33,$9C,$FD,$04 ; ABDA 25 03 FF FE 33 9C FD 04 %...3...
+ .byte $00,$6C,$05,$04,$FE,$89,$9C,$FD ; ABE2 00 6C 05 04 FE 89 9C FD .l......
+ .byte $00,$04,$84,$11,$02,$FF,$FE,$49 ; ABEA 00 04 84 11 02 FF FE 49 .......I
+ .byte $9C,$FD,$04,$00,$6C,$05,$04,$FF ; ABF2 9C FD 04 00 6C 05 04 FF ....l...
+ .byte $FE,$49,$9C,$FD,$04,$00,$60,$4B ; ABFA FE 49 9C FD 04 00 60 4B .I....`K
+ .byte $03,$FF,$FE,$49,$9C,$FD,$04,$00 ; AC02 03 FF FE 49 9C FD 04 00 ...I....
+ .byte $40,$4B,$03,$FF,$FE,$49,$9C,$FD ; AC0A 40 4B 03 FF FE 49 9C FD @K...I..
+ .byte $04,$00,$20,$4B,$03,$FF,$FE,$33 ; AC12 04 00 20 4B 03 FF FE 33 .. K...3
+ .byte $9C,$FD,$04,$00,$28,$52,$01,$FF ; AC1A 9C FD 04 00 28 52 01 FF ....(R..
+ .byte $FE,$33,$9C,$FD,$04,$00,$48,$52 ; AC22 FE 33 9C FD 04 00 48 52 .3....HR
+ .byte $01,$FF,$FE,$49,$9C,$FD,$04,$00 ; AC2A 01 FF FE 49 9C FD 04 00 ...I....
+ .byte $54,$55,$09,$FF,$FE,$33,$9C,$FD ; AC32 54 55 09 FF FE 33 9C FD TU...3..
+ .byte $04,$00,$04,$08,$02,$FE,$5F,$9C ; AC3A 04 00 04 08 02 FE 5F 9C ......_.
+ .byte $FD,$00,$04,$8E,$01,$09,$FF,$00 ; AC42 FD 00 04 8E 01 09 FF 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AC4A 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AC52 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00 ; AC5A 00 00 00 00 00 00 ......
+LAC60: .byte $FE,$33,$9C,$FD,$04,$00,$3C,$05 ; AC60 FE 33 9C FD 04 00 3C 05 .3....<.
+ .byte $0A,$04,$0C,$08,$7C,$0C,$08,$04 ; AC68 0A 04 0C 08 7C 0C 08 04 ....|...
+ .byte $15,$08,$7C,$15,$08,$38,$16,$01 ; AC70 15 08 7C 15 08 38 16 01 ..|..8..
+ .byte $64,$16,$01,$2C,$2C,$04,$64,$2C ; AC78 64 16 01 2C 2C 04 64 2C d..,,.d,
+ .byte $04,$2C,$3C,$04,$64,$3C,$04,$04 ; AC80 04 2C 3C 04 64 3C 04 04 .,<.d<..
+ .byte $55,$26,$FD,$04,$FF,$24,$0B,$06 ; AC88 55 26 FD 04 FF 24 0B 06 U&...$..
+ .byte $FD,$04,$01,$64,$06,$06,$FE,$5F ; AC90 FD 04 01 64 06 06 FE 5F ...d..._
+ .byte $9C,$FD,$00,$04,$0C,$01,$15,$4C ; AC98 9C FD 00 04 0C 01 15 4C .......L
+ .byte $01,$15,$8C,$01,$15,$FE,$C9,$9C ; ACA0 01 15 8C 01 15 FE C9 9C ........
+ .byte $39,$19,$03,$65,$19,$03,$FE,$DA ; ACA8 39 19 03 65 19 03 FE DA 9..e....
+ .byte $9C,$1F,$12,$0F,$80,$12,$0F,$FE ; ACB0 9C 1F 12 0F 80 12 0F FE ........
+ .byte $B3,$9C ; ACB8 B3 9C ..
+LACBA: .byte $04,$02,$01,$3C,$02,$01,$60,$02 ; ACBA 04 02 01 3C 02 01 60 02 ...<..`.
+ .byte $01,$98,$02,$01,$24,$22,$01,$78 ; ACC2 01 98 02 01 24 22 01 78 ....$".x
+ .byte $22,$01,$24,$32,$01,$78,$32,$01 ; ACCA 22 01 24 32 01 78 32 01 ".$2.x2.
+ .byte $24,$42,$01,$78,$42,$01,$04,$52 ; ACD2 24 42 01 78 42 01 04 52 $B.xB..R
+ .byte $01,$3C,$52,$01,$60,$52,$01,$98 ; ACDA 01 3C 52 01 60 52 01 98 .<R.`R..
+ .byte $52,$01,$FF ; ACE2 52 01 FF R..
+LACE5: .byte $22,$10,$62,$20,$82,$30,$C2,$40 ; ACE5 22 10 62 20 82 30 C2 40 ".b .0.@
+ .byte $46,$50,$A6,$50,$48,$60,$A8,$60 ; ACED 46 50 A6 50 48 60 A8 60 FP.PH`.`
+ .byte $4A,$70,$AA,$70,$2C,$80,$6C,$00 ; ACF5 4A 70 AA 70 2C 80 6C 00 Jp.p,.l.
+ .byte $8C,$00,$CC,$90,$FF ; ACFD 8C 00 CC 90 FF .....
+LAD02: .byte $00,$00,$16,$AD,$16,$AD,$20,$AD ; AD02 00 00 16 AD 16 AD 20 AD ...... .
+ .byte $20,$AD,$2A,$AD,$34,$AD,$3E,$AD ; AD0A 20 AD 2A AD 34 AD 3E AD .*.4.>.
+ .byte $48,$AD,$58,$AD,$FE,$49,$9C,$FD ; AD12 48 AD 58 AD FE 49 9C FD H.X..I..
+ .byte $04,$FF,$24,$0B,$06,$FF,$FE,$49 ; AD1A 04 FF 24 0B 06 FF FE 49 ..$....I
+ .byte $9C,$FD,$04,$01,$64,$06,$06,$FF ; AD22 9C FD 04 01 64 06 06 FF ....d...
+ .byte $FE,$89,$9C,$FD,$00,$04,$4C,$21 ; AD2A FE 89 9C FD 00 04 4C 21 ......L!
+ .byte $02,$FF,$FE,$89,$9C,$FD,$00,$04 ; AD32 02 FF FE 89 9C FD 00 04 ........
+ .byte $4C,$29,$02,$FF,$FE,$89,$9C,$FD ; AD3A 4C 29 02 FF FE 89 9C FD L)......
+ .byte $00,$04,$4C,$31,$02,$FF,$FE,$C9 ; AD42 00 04 4C 31 02 FF FE C9 ..L1....
+ .byte $9C,$FD,$00,$04,$9A,$18,$0E,$FE ; AD4A 9C FD 00 04 9A 18 0E FE ........
+ .byte $89,$9C,$0C,$31,$02,$FF,$FE,$C9 ; AD52 89 9C 0C 31 02 FF FE C9 ...1....
+ .byte $9C,$FD,$00,$04,$04,$18,$0E,$FE ; AD5A 9C FD 00 04 04 18 0E FE ........
+ .byte $89,$9C,$8C,$31,$02,$FF ; AD62 89 9C 8C 31 02 FF ...1..
+; ----------------------------------------------------------------------------
+LAD68: lda $0622 ; AD68 AD 22 06 .".
+ bne LAD6E ; AD6B D0 01 ..
+LAD6D: rts ; AD6D 60 `
+
+; ----------------------------------------------------------------------------
+LAD6E: ldx #$FF ; AD6E A2 FF ..
+LAD70: inx ; AD70 E8 .
+ cpx work_level_bullet_chance ; AD71 EC 8B 07 ...
+ beq LAD6D ; AD74 F0 F7 ..
+ lda $0756,x ; AD76 BD 56 07 .V.
+ cmp #$02 ; AD79 C9 02 ..
+ beq LAD8B ; AD7B F0 0E ..
+ sta $076C,x ; AD7D 9D 6C 07 .l.
+ lda #$00 ; AD80 A9 00 ..
+ sta $0764,x ; AD82 9D 64 07 .d.
+ sta $0768,x ; AD85 9D 68 07 .h.
+ jmp LAD70 ; AD88 4C 70 AD Lp.
+
+; ----------------------------------------------------------------------------
+LAD8B: cmp $076C,x ; AD8B DD 6C 07 .l.
+ beq LADA1 ; AD8E F0 11 ..
+ sta $076C,x ; AD90 9D 6C 07 .l.
+ lda $075A,x ; AD93 BD 5A 07 .Z.
+ beq LAD9E ; AD96 F0 06 ..
+ inc $0768,x ; AD98 FE 68 07 .h.
+ jmp LADA1 ; AD9B 4C A1 AD L..
+
+; ----------------------------------------------------------------------------
+LAD9E: inc $0764,x ; AD9E FE 64 07 .d.
+LADA1: lda $0764,x ; ADA1 BD 64 07 .d.
+ beq code_adb5 ; ADA4 F0 0F ..
+ and #$0F ; ADA6 29 0F ).
+ tay ; ADA8 A8 .
+ lda data_table_adc7,y ; ADA9 B9 C7 AD ...
+ sta $075A,x ; ADAC 9D 5A 07 .Z.
+ inc $0764,x ; ADAF FE 64 07 .d.
+ jmp LAD70 ; ADB2 4C 70 AD Lp.
+
+; ----------------------------------------------------------------------------
+code_adb5:
+ lda $0768,x ; ADB5 BD 68 07 .h.
+ and #$0F ; ADB8 29 0F ).
+ tay ; ADBA A8 .
+ lda data_table_adc7,y ; ADBB B9 C7 AD ...
+LADBF := * + 1
+ sta $075E,x ; ADBE 9D 5E 07 .^.
+code_adc1:
+ inc $0768,x ; ADC1 FE 68 07 .h.
+ jmp LAD70 ; ADC4 4C 70 AD Lp.
+
+; ----------------------------------------------------------------------------
+; dunno, referenced by routines at $AD9E and $ADB5
+data_table_adc7:
+ .byte $00,$01,$02,$03,$04,$03,$02,$01 ; ADC7 00 01 02 03 04 03 02 01 ........
+ .byte $00,$FF,$FE,$FD,$FC,$FD,$FE,$FF ; ADCF 00 FF FE FD FC FD FE FF ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; ADD7 00 00 00 00 00 00 00 00 ........
+ .byte $00 ; ADDF 00 .
+LADE0: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; ADE0 FE 33 9C FD 04 00 04 05 .3......
+ .byte $02,$44,$05,$06,$94,$05,$02,$30 ; ADE8 02 44 05 06 94 05 02 30 .D.....0
+ .byte $0A,$02,$68,$0A,$02,$28,$21,$04 ; ADF0 0A 02 68 0A 02 28 21 04 ..h..(!.
+ .byte $68,$21,$04,$04,$25,$06,$84,$25 ; ADF8 68 21 04 04 25 06 84 25 h!..%..%
+ .byte $06,$04,$45,$10,$5C,$45,$10,$04 ; AE00 06 04 45 10 5C 45 10 04 ..E.\E..
+ .byte $55,$06,$2C,$55,$04,$64,$55,$04 ; AE08 55 06 2C 55 04 64 55 04 U.,U.dU.
+ .byte $84,$55,$06,$FD,$04,$FF,$84,$09 ; AE10 84 55 06 FD 04 FF 84 09 .U......
+ .byte $04,$1C,$24,$03,$FD,$04,$01,$0C ; AE18 04 1C 24 03 FD 04 01 0C ..$.....
+ .byte $06,$04,$78,$22,$03,$FE,$5F,$9C ; AE20 06 04 78 22 03 FE 5F 9C ..x".._.
+ .byte $FD,$00,$04,$0C,$21,$09,$8C,$21 ; AE28 FD 00 04 0C 21 09 8C 21 ....!..!
+ .byte $09,$30,$41,$05,$68,$41,$05,$FE ; AE30 09 30 41 05 68 41 05 FE .0A.hA..
+ .byte $C9,$9C,$34,$0C,$04,$6B,$0C,$04 ; AE38 C9 9C 34 0C 04 6B 0C 04 ..4..k..
+ .byte $FE,$DA,$9C,$44,$02,$10,$5A,$02 ; AE40 FE DA 9C 44 02 10 5A 02 ...D..Z.
+ .byte $10,$FE,$B3,$9C ; AE48 10 FE B3 9C ....
+LAE4C: .byte $04,$02,$01,$98,$02,$01,$04,$22 ; AE4C 04 02 01 98 02 01 04 22 ......."
+ .byte $01,$98,$22,$01,$18,$34,$01,$84 ; AE54 01 98 22 01 18 34 01 84 .."..4..
+ .byte $34,$01,$04,$42,$01,$98,$42,$01 ; AE5C 34 01 04 42 01 98 42 01 4..B..B.
+ .byte $04,$52,$01,$38,$52,$01,$64,$52 ; AE64 04 52 01 38 52 01 64 52 .R.8R.dR
+ .byte $01,$98,$52,$01,$FF ; AE6C 01 98 52 01 FF ..R..
+LAE71: .byte $22,$00,$C2,$00,$26,$00,$C6,$00 ; AE71 22 00 C2 00 26 00 C6 00 "...&...
+ .byte $48,$00,$A8,$00,$2A,$00,$CA,$00 ; AE79 48 00 A8 00 2A 00 CA 00 H...*...
+ .byte $2C,$00,$6C,$00,$8C,$00,$CC,$00 ; AE81 2C 00 6C 00 8C 00 CC 00 ,.l.....
+ .byte $FF ; AE89 FF .
+LAE8A: .byte $03,$00,$00,$01,$7C,$01,$01,$00 ; AE8A 03 00 00 01 7C 01 01 00 ....|...
+ .byte $04,$0C,$AF,$10,$86,$00,$01,$0F ; AE92 04 0C AF 10 86 00 01 0F ........
+ .byte $FF ; AE9A FF .
+LAE9B: .byte $20,$36,$80,$A9,$C0,$8D,$70,$07 ; AE9B 20 36 80 A9 C0 8D 70 07 6....p.
+ .byte $60 ; AEA3 60 `
+LAEA4: .byte $18,$08,$38,$20,$00,$48,$30,$18 ; AEA4 18 08 38 20 00 48 30 18 ..8 .H0.
+ .byte $28,$10,$10 ; AEAC 28 10 10 (..
+LAEAF: .byte $40,$29,$21,$11,$19,$11,$09,$01 ; AEAF 40 29 21 11 19 11 09 01 @)!.....
+ .byte $49,$41,$39,$19,$31 ; AEB7 49 41 39 19 31 IA9.1
+LAEBC: .byte $03,$03,$03,$03,$03,$C3,$C3,$7E ; AEBC 03 03 03 03 03 C3 C3 7E .......~
+ .byte $C3,$C3,$C3,$C3,$C3,$C3,$C3,$7E ; AEC4 C3 C3 C3 C3 C3 C3 C3 7E .......~
+ .byte $C3,$C3,$E7,$FF,$DB,$C3,$C3,$C3 ; AECC C3 C3 E7 FF DB C3 C3 C3 ........
+ .byte $FE,$C3,$C3,$C3,$FE,$C0,$C0,$C0 ; AED4 FE C3 C3 C3 FE C0 C0 C0 ........
+ .byte $18,$3C,$66,$C3,$FF,$C3,$C3,$C3 ; AEDC 18 3C 66 C3 FF C3 C3 C3 .<f.....
+ .byte $C3,$C3,$E3,$F3,$DB,$CF,$C7,$C3 ; AEE4 C3 C3 E3 F3 DB CF C7 C3 ........
+ .byte $FF,$C0,$C0,$C0,$F8,$C0,$C0,$FF ; AEEC FF C0 C0 C0 F8 C0 C0 FF ........
+ .byte $C3,$66,$3C,$18,$18,$18,$18,$18 ; AEF4 C3 66 3C 18 18 18 18 18 .f<.....
+ .byte $C3,$C3,$66,$3C,$3C,$66,$C3,$C3 ; AEFC C3 C3 66 3C 3C 66 C3 C3 ..f<<f..
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AF04 00 00 00 00 00 00 00 00 ........
+ .byte $40 ; AF0C 40 @
+; ----------------------------------------------------------------------------
+ ldy #$20 ; AF0D A0 20 .
+ rti ; AF0F 40 @
+
+; ----------------------------------------------------------------------------
+ cpx #$00 ; AF10 E0 00 ..
+ sec ; AF12 38 8
+ jsr L0830 ; AF13 20 30 08 0.
+ bmi LAF1C ; AF16 30 04 0.
+ asl a ; AF18 0A .
+ asl a ; AF19 0A .
+ asl a ; AF1A 0A .
+; NMOS 6502 illegal opcode, NOP zp
+illegal_nop:
+ .byte $04 ; AF1B 04 .
+LAF1C: lda $062A ; AF1C AD 2A 06 .*.
+ sta PCOLR2 ; AF1F 8D C2 02 ...
+ rts ; AF22 60 `
+
+; ----------------------------------------------------------------------------
+LAF23: lda $B2 ; AF23 A5 B2 ..
+ lsr a ; AF25 4A J
+ tax ; AF26 AA .
+ ldy LAEA4,x ; AF27 BC A4 AE ...
+ iny ; AF2A C8 .
+ ldx $0771 ; AF2B AE 71 07 .q.
+ tya ; AF2E 98 .
+ sta $0773,x ; AF2F 9D 73 07 .s.
+ dey ; AF32 88 .
+ ldx $0770 ; AF33 AE 70 07 .p.
+ lda #$08 ; AF36 A9 08 ..
+ sta $0772 ; AF38 8D 72 07 .r.
+LAF3B: lda LAEBC,y ; AF3B B9 BC AE ...
+ sta $2E00,x ; AF3E 9D 00 2E ...
+ inx ; AF41 E8 .
+ iny ; AF42 C8 .
+ dec $0772 ; AF43 CE 72 07 .r.
+ bne LAF3B ; AF46 D0 F3 ..
+ inc $0771 ; AF48 EE 71 07 .q.
+ sec ; AF4B 38 8
+ lda $0770 ; AF4C AD 70 07 .p.
+ sbc #$0A ; AF4F E9 0A ..
+ sta $0770 ; AF51 8D 70 07 .p.
+ inc $066C ; AF54 EE 6C 06 .l.
+ rts ; AF57 60 `
+
+; ----------------------------------------------------------------------------
+LAF58: lda work_level_num_bombs ; AF58 AD 8A 07 ...
+ beq LAF5E ; AF5B F0 01 ..
+ rts ; AF5D 60 `
+
+; ----------------------------------------------------------------------------
+LAF5E: lda #$09 ; AF5E A9 09 ..
+ sta player_speed ; AF60 8D 24 06 .$.
+ lda #$00 ; AF63 A9 00 ..
+ sta playing_level ; AF65 8D 27 06 .'.
+ ldx #$0C ; AF68 A2 0C ..
+ stx $066D ; AF6A 8E 6D 06 .m.
+LAF6D: lda $0770 ; AF6D AD 70 07 .p.
+ clc ; AF70 18 .
+ adc #$0A ; AF71 69 0A i.
+ sta $0770 ; AF73 8D 70 07 .p.
+ lda $0772,x ; AF76 BD 72 07 .r.
+ cmp LAEAF,x ; AF79 DD AF AE ...
+ beq LAF96 ; AF7C F0 18 ..
+ lda #$00 ; AF7E A9 00 ..
+ sta $0681 ; AF80 8D 81 06 ...
+ jmp LAF92 ; AF83 4C 92 AF L..
+
+; ----------------------------------------------------------------------------
+LAF86: lda #$00 ; AF86 A9 00 ..
+ sta jiffy_timer_1 ; AF88 8D 1A 06 ...
+LAF8B: lda jiffy_timer_1 ; AF8B AD 1A 06 ...
+ cmp #$20 ; AF8E C9 20 .
+ bne LAF8B ; AF90 D0 F9 ..
+LAF92: dex ; AF92 CA .
+ bne LAF6D ; AF93 D0 D8 ..
+ rts ; AF95 60 `
+
+; ----------------------------------------------------------------------------
+LAF96: lda $0770 ; AF96 AD 70 07 .p.
+ sta $0686 ; AF99 8D 86 06 ...
+ lda #$86 ; AF9C A9 86 ..
+ sta $0681 ; AF9E 8D 81 06 ...
+ clc ; AFA1 18 .
+ lda score ; AFA2 AD 00 07 ...
+ adc #$FA ; AFA5 69 FA i.
+ sta score ; AFA7 8D 00 07 ...
+ bcc LAFB4 ; AFAA 90 08 ..
+ inc score+1 ; AFAC EE 01 07 ...
+ bne LAFB4 ; AFAF D0 03 ..
+ inc score+2 ; AFB1 EE 02 07 ...
+LAFB4: txa ; AFB4 8A .
+ pha ; AFB5 48 H
+ jsr L800C ; AFB6 20 0C 80 ..
+ lda #$CB ; AFB9 A9 CB ..
+ sta sfx_ptr ; AFBB 8D 3C 06 .<.
+ lda #$AF ; AFBE A9 AF ..
+ sta sfx_ptr+1 ; AFC0 8D 3D 06 .=.
+ jsr cue_sfx_jv ; AFC3 20 06 80 ..
+ pla ; AFC6 68 h
+ tax ; AFC7 AA .
+ jmp LAF86 ; AFC8 4C 86 AF L..
+
+; ----------------------------------------------------------------------------
+; referenced by routine at $AF96
+sfx_afcb:
+ .byte $01,$A5,$00,$18,$04,$F3,$04,$00 ; AFCB 01 A5 00 18 04 F3 04 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AFD3 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AFDB 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AFE3 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AFEB 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; AFF3 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00 ; AFFB 00 00 00 00 00 .....
+; referenced by routine at $B0C4
+map_b000:
+ .byte $FE,$33,$9C,$FD,$04,$00,$04,$07 ; B000 FE 33 9C FD 04 00 04 07 .3......
+ .byte $06,$24,$07,$02,$6C,$05,$04,$8C ; B008 06 24 07 02 6C 05 04 8C .$..l...
+ .byte $05,$04,$28,$18,$04,$48,$15,$06 ; B010 05 04 28 18 04 48 15 06 ..(..H..
+ .byte $7C,$15,$04,$20,$25,$07,$68,$25 ; B018 7C 15 04 20 25 07 68 25 |.. %.h%
+ .byte $04,$04,$3B,$05,$28,$3B,$01,$34 ; B020 04 04 3B 05 28 3B 01 34 ..;.(;.4
+ .byte $3B,$04,$5C,$45,$08,$8C,$4B,$02 ; B028 3B 04 5C 45 08 8C 4B 02 ;.\E..K.
+ .byte $04,$55,$06,$38,$4D,$04,$04,$55 ; B030 04 55 06 38 4D 04 04 55 .U.8M..U
+ .byte $06,$54,$55,$12,$FD,$04,$FF,$58 ; B038 06 54 55 12 FD 04 FF 58 .TU....X
+ .byte $0A,$05,$1C,$54,$07,$FD,$04,$01 ; B040 0A 05 1C 54 07 FD 04 01 ...T....
+ .byte $2C,$08,$06,$3C,$26,$04,$FE,$5F ; B048 2C 08 06 3C 26 04 FE 5F ,..<&.._
+ .byte $9C,$FD,$00,$04,$0C,$03,$0E,$3C ; B050 9C FD 00 04 0C 03 0E 3C .......<
+ .byte $37,$05,$8C,$35,$05,$FE,$C9,$9C ; B058 37 05 8C 35 05 FE C9 9C 7..5....
+ .byte $1A,$0A,$06,$5E,$18,$09,$9A,$08 ; B060 1A 0A 06 5E 18 09 9A 08 ...^....
+ .byte $0B,$FE,$DA,$9C,$83,$04,$13,$FE ; B068 0B FE DA 9C 83 04 13 FE ........
+ .byte $49,$9C ; B070 49 9C I.
+LB072: .byte $04 ; B072 04 .
+LB073: .byte $02,$01,$24,$02,$01,$44,$02,$01 ; B073 02 01 24 02 01 44 02 01 ..$..D..
+ .byte $78,$02,$01,$98,$02,$01,$3C,$12 ; B07B 78 02 01 98 02 01 3C 12 x.....<.
+ .byte $01,$5C,$12,$01,$7C,$12,$01,$24 ; B083 01 5C 12 01 7C 12 01 24 .\..|..$
+ .byte $22,$01,$78,$22,$01,$04,$38,$01 ; B08B 22 01 78 22 01 04 38 01 ".x"..8.
+ .byte $1C,$46,$01,$78,$42,$01,$04,$52 ; B093 1C 46 01 78 42 01 04 52 .F.xB..R
+ .byte $01,$58,$52,$01,$98,$52,$01 ; B09B 01 58 52 01 98 52 01 .XR..R.
+LB0A2: .byte $FF ; B0A2 FF .
+LB0A3: .byte $22,$00,$42,$00,$62,$00,$A2,$00 ; B0A3 22 00 42 00 62 00 A2 00 ".B.b...
+ .byte $C2,$00,$64,$00,$84,$00,$A4,$00 ; B0AB C2 00 64 00 84 00 A4 00 ..d.....
+ .byte $46,$00,$A6,$00,$28,$00,$4A,$00 ; B0B3 46 00 A6 00 28 00 4A 00 F...(.J.
+ .byte $AA,$00,$2C,$00,$8C,$00,$CC,$00 ; B0BB AA 00 2C 00 8C 00 CC 00 ..,.....
+ .byte $FF ; B0C3 FF .
+; ----------------------------------------------------------------------------
+LB0C4: jsr L8036 ; B0C4 20 36 80 6.
+ lda #$10 ; B0C7 A9 10 ..
+ sta SAVMSC+1 ; B0C9 85 59 .Y
+ jsr clear_screen_mem_jv ; B0CB 20 1E 80 ..
+ lda #$00 ; B0CE A9 00 ..
+ sta dm_progctr ; B0D0 85 C0 ..
+ lda #$B0 ; B0D2 A9 B0 ..
+ sta dm_progctr+1 ; B0D4 85 C1 ..
+ jsr draw_map_jv ; B0D6 20 00 80 ..
+ ldx #$07 ; B0D9 A2 07 ..
+LB0DB: lda LB119,x ; B0DB BD 19 B1 ...
+ sta $08FF,x ; B0DE 9D FF 08 ...
+ dex ; B0E1 CA .
+ bne LB0DB ; B0E2 D0 F7 ..
+ lda #$08 ; B0E4 A9 08 ..
+ sta $AA ; B0E6 85 AA ..
+LB0E8: lda RANDOM ; B0E8 AD 0A D2 ...
+ and #$0F ; B0EB 29 0F ).
+ sta $AB ; B0ED 85 AB ..
+ tax ; B0EF AA .
+ lda $0770,x ; B0F0 BD 70 07 .p.
+ bne LB0E8 ; B0F3 D0 F3 ..
+ inc $0770,x ; B0F5 FE 70 07 .p.
+ txa ; B0F8 8A .
+ asl a ; B0F9 0A .
+ clc ; B0FA 18 .
+ adc $AB ; B0FB 65 AB e.
+ tay ; B0FD A8 .
+ lda LB072,y ; B0FE B9 72 B0 .r.
+ sta $0903 ; B101 8D 03 09 ...
+ lda LB073,y ; B104 B9 73 B0 .s.
+ sta $0904 ; B107 8D 04 09 ...
+ lda #$00 ; B10A A9 00 ..
+ sta dm_progctr ; B10C 85 C0 ..
+ lda #$09 ; B10E A9 09 ..
+ sta dm_progctr+1 ; B110 85 C1 ..
+ jsr draw_map_jv ; B112 20 00 80 ..
+ dec $AA ; B115 C6 AA ..
+ bne LB0E8 ; B117 D0 CF ..
+LB119: rts ; B119 60 `
+
+; ----------------------------------------------------------------------------
+; dunno what this is for yet
+map_b11a:
+ .byte $FE,$B3,$9C,$00,$00,$01,$FF ; B11A FE B3 9C 00 00 01 FF .......
+; ----------------------------------------------------------------------------
+LB121: lda #$10 ; B121 A9 10 ..
+ sta SAVMSC+1 ; B123 85 59 .Y
+ lda #$D9 ; B125 A9 D9 ..
+ sta dm_progctr ; B127 85 C0 ..
+ lda #$06 ; B129 A9 06 ..
+ sta dm_progctr+1 ; B12B 85 C1 ..
+ jsr draw_map_jv ; B12D 20 00 80 ..
+ lda #$30 ; B130 A9 30 .0
+ sta SAVMSC+1 ; B132 85 59 .Y
+ lda #$D9 ; B134 A9 D9 ..
+ sta dm_progctr ; B136 85 C0 ..
+ jsr draw_map_jv ; B138 20 00 80 ..
+ lda #$D9 ; B13B A9 D9 ..
+ sta dm_progctr ; B13D 85 C0 ..
+ rts ; B13F 60 `
+
+; ----------------------------------------------------------------------------
+LB140: lda $0621 ; B140 AD 21 06 .!.
+ bne LB146 ; B143 D0 01 ..
+LB145: rts ; B145 60 `
+
+; ----------------------------------------------------------------------------
+LB146: lda $067E ; B146 AD 7E 06 .~.
+ cmp #$34 ; B149 C9 34 .4
+ bcc LB145 ; B14B 90 F8 ..
+ cmp #$C9 ; B14D C9 C9 ..
+ bcs LB145 ; B14F B0 F4 ..
+ lda #$0B ; B151 A9 0B ..
+ sta $97 ; B153 85 97 ..
+ lda $067E ; B155 AD 7E 06 .~.
+ sec ; B158 38 8
+ sbc #$33 ; B159 E9 33 .3
+ lsr a ; B15B 4A J
+ lsr a ; B15C 4A J
+ sta $91 ; B15D 85 91 ..
+ lda $0683 ; B15F AD 83 06 ...
+ cmp #$C3 ; B162 C9 C3 ..
+ bcs LB145 ; B164 B0 DF ..
+ jsr LB1D2 ; B166 20 D2 B1 ..
+ sec ; B169 38 8
+ sbc #$26 ; B16A E9 26 .&
+ lsr a ; B16C 4A J
+ sta $92 ; B16D 85 92 ..
+ lda #$28 ; B16F A9 28 .(
+ sta $90 ; B171 85 90 ..
+ lda #$00 ; B173 A9 00 ..
+ sta $93 ; B175 85 93 ..
+ ldx #$08 ; B177 A2 08 ..
+LB179: lsr $90 ; B179 46 90 F.
+ bcc LB180 ; B17B 90 03 ..
+ clc ; B17D 18 .
+ adc $92 ; B17E 65 92 e.
+LB180: ror a ; B180 6A j
+ ror $93 ; B181 66 93 f.
+ dex ; B183 CA .
+ bne LB179 ; B184 D0 F3 ..
+ sta $94 ; B186 85 94 ..
+ clc ; B188 18 .
+ lda $93 ; B189 A5 93 ..
+ adc $91 ; B18B 65 91 e.
+ sta $93 ; B18D 85 93 ..
+ sta $95 ; B18F 85 95 ..
+ lda $94 ; B191 A5 94 ..
+ adc #$10 ; B193 69 10 i.
+ sta $94 ; B195 85 94 ..
+ clc ; B197 18 .
+ lda $94 ; B198 A5 94 ..
+ adc #$20 ; B19A 69 20 i
+ sta $96 ; B19C 85 96 ..
+LB19E: ldx #$04 ; B19E A2 04 ..
+ ldy #$00 ; B1A0 A0 00 ..
+LB1A2: lda ($93),y ; B1A2 B1 93 ..
+ sta ($95),y ; B1A4 91 95 ..
+ iny ; B1A6 C8 .
+ dex ; B1A7 CA .
+ bne LB1A2 ; B1A8 D0 F8 ..
+ clc ; B1AA 18 .
+ lda $93 ; B1AB A5 93 ..
+ adc #$28 ; B1AD 69 28 i(
+ sta $93 ; B1AF 85 93 ..
+ bcc LB1B5 ; B1B1 90 02 ..
+ inc $94 ; B1B3 E6 94 ..
+LB1B5: clc ; B1B5 18 .
+ lda $95 ; B1B6 A5 95 ..
+ adc #$28 ; B1B8 69 28 i(
+ sta $95 ; B1BA 85 95 ..
+ bcc LB1C0 ; B1BC 90 02 ..
+ inc $96 ; B1BE E6 96 ..
+LB1C0: lda $93 ; B1C0 A5 93 ..
+ cmp #$C0 ; B1C2 C9 C0 ..
+ bne LB1CD ; B1C4 D0 07 ..
+ lda $94 ; B1C6 A5 94 ..
+ cmp #$1D ; B1C8 C9 1D ..
+ bne LB1CD ; B1CA D0 01 ..
+ rts ; B1CC 60 `
+
+; ----------------------------------------------------------------------------
+LB1CD: dec $97 ; B1CD C6 97 ..
+ bne LB19E ; B1CF D0 CD ..
+ rts ; B1D1 60 `
+
+; ----------------------------------------------------------------------------
+LB1D2: cmp #$26 ; B1D2 C9 26 .&
+ bcs LB1DE ; B1D4 B0 08 ..
+ clc ; B1D6 18 .
+ adc #$02 ; B1D7 69 02 i.
+ dec $97 ; B1D9 C6 97 ..
+ jmp LB1D2 ; B1DB 4C D2 B1 L..
+
+; ----------------------------------------------------------------------------
+LB1DE: rts ; B1DE 60 `
+
+; ----------------------------------------------------------------------------
+; dunno what this is for yet
+data_table_b1df:
+ .byte $00 ; B1DF 00 .
+LB1E0: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; B1E0 FE 33 9C FD 04 00 04 05 .3......
+ .byte $06,$38,$05,$08,$7C,$05,$06,$24 ; B1E8 06 38 05 08 7C 05 06 24 .8..|..$
+ .byte $15,$06,$64,$15,$0E,$04,$2D,$06 ; B1F0 15 06 64 15 0E 04 2D 06 ..d...-.
+ .byte $38,$35,$0C,$04,$45,$06,$30,$45 ; B1F8 38 35 0C 04 45 06 30 45 85..E.0E
+ .byte $08,$88,$3C,$05,$04,$55,$08,$38 ; B200 08 88 3C 05 04 55 08 38 ..<..U.8
+ .byte $55,$06,$68,$55,$0D,$FD,$04,$01 ; B208 55 06 68 55 0D FD 04 01 U.hU....
+ .byte $1C,$2E,$07,$FD,$04,$FF,$64,$45 ; B210 1C 2E 07 FD 04 FF 64 45 ......dE
+ .byte $09,$FE,$5F,$9C,$FD,$00,$04,$0C ; B218 09 FE 5F 9C FD 00 04 0C .._.....
+ .byte $01,$0B,$0C,$41,$05,$40,$01,$05 ; B220 01 0B 0C 41 05 40 01 05 ...A.@..
+ .byte $40,$31,$05,$8C,$01,$15,$FE,$DA ; B228 40 31 05 8C 01 15 FE DA @1......
+ .byte $9C,$66,$30,$04,$FE,$B3,$9C ; B230 9C 66 30 04 FE B3 9C .f0....
+LB237: .byte $04,$02,$01,$38,$02,$01,$7C,$02 ; B237 04 02 01 38 02 01 7C 02 ...8..|.
+ .byte $01,$38,$12,$01,$64,$12,$01,$98 ; B23F 01 38 12 01 64 12 01 98 .8..d...
+ .byte $12,$01,$04,$22,$01,$98,$39,$01 ; B247 12 01 04 22 01 98 39 01 ..."..9.
+ .byte $58,$47,$01,$04,$52,$01,$38,$52 ; B24F 58 47 01 04 52 01 38 52 XG..R.8R
+ .byte $01,$98,$52,$01,$FF ; B257 01 98 52 01 FF ..R..
+LB25C: .byte $22,$00,$62,$00,$A2,$00,$64,$00 ; B25C 22 00 62 00 A2 00 64 00 ".b...d.
+ .byte $84,$00,$C4,$00,$26,$00,$C8,$00 ; B264 84 00 C4 00 26 00 C8 00 ....&...
+ .byte $8A,$00,$2C,$00,$6C,$00,$CC,$00 ; B26C 8A 00 2C 00 6C 00 CC 00 ..,.l...
+ .byte $FF ; B274 FF .
+LB275: .byte $03,$A8,$B2,$0A,$A4,$20,$01,$56 ; B275 03 A8 B2 0A A4 20 01 56 ..... .V
+ .byte $FF ; B27D FF .
+; ----------------------------------------------------------------------------
+LB27E: lda $06F5 ; B27E AD F5 06 ...
+ sta $066C ; B281 8D 6C 06 .l.
+ bne LB287 ; B284 D0 01 ..
+ rts ; B286 60 `
+
+; ----------------------------------------------------------------------------
+LB287: inc $0760 ; B287 EE 60 07 .`.
+ lda $0760 ; B28A AD 60 07 .`.
+ and #$7F ; B28D 29 7F ).
+ beq LB292 ; B28F F0 01 ..
+ rts ; B291 60 `
+
+; ----------------------------------------------------------------------------
+LB292: inc $0761 ; B292 EE 61 07 .a.
+ lda $0761 ; B295 AD 61 07 .a.
+ and #$07 ; B298 29 07 ).
+ tax ; B29A AA .
+ lda LB2D0,x ; B29B BD D0 B2 ...
+ sta $0680 ; B29E 8D 80 06 ...
+ lda LB2D8,x ; B2A1 BD D8 B2 ...
+ sta $0685 ; B2A4 8D 85 06 ...
+ rts ; B2A7 60 `
+
+; ----------------------------------------------------------------------------
+; dunno what this is for yet
+data_table_b2a8:
+ .byte $00,$00,$00,$18,$18,$18,$18,$00 ; B2A8 00 00 00 18 18 18 18 00 ........
+ .byte $00,$00,$00,$00,$3C,$24,$24,$24 ; B2B0 00 00 00 00 3C 24 24 24 ....<$$$
+ .byte $24,$3C,$00,$00,$00,$7E,$42,$42 ; B2B8 24 3C 00 00 00 7E 42 42 $<...~BB
+ .byte $42,$42,$42,$42,$7E,$00,$FF,$81 ; B2C0 42 42 42 42 7E 00 FF 81 BBBB~...
+ .byte $81,$81,$81,$81,$81,$81,$81,$FF ; B2C8 81 81 81 81 81 81 81 FF ........
+LB2D0: .byte $A4,$4C,$52,$70,$86,$86,$A4,$82 ; B2D0 A4 4C 52 70 86 86 A4 82 .LRp....
+LB2D8: .byte $20,$20,$98,$C0,$B4,$80,$68,$40 ; B2D8 20 20 98 C0 B4 80 68 40 ....h@
+; ----------------------------------------------------------------------------
+LB2E0: lda $0619 ; B2E0 AD 19 06 ...
+ and #$0F ; B2E3 29 0F ).
+ bne LB2F2 ; B2E5 D0 0B ..
+ lda $068A ; B2E7 AD 8A 06 ...
+ and #$03 ; B2EA 29 03 ).
+ sta $068A ; B2EC 8D 8A 06 ...
+ inc $068A ; B2EF EE 8A 06 ...
+LB2F2: lda $062A ; B2F2 AD 2A 06 .*.
+ sta PCOLR2 ; B2F5 8D C2 02 ...
+ lda #$00 ; B2F8 A9 00 ..
+ jmp L8F79 ; B2FA 4C 79 8F Ly.
+
+; ----------------------------------------------------------------------------
+LB2FD: lda $0680 ; B2FD AD 80 06 ...
+ sta $067E ; B300 8D 7E 06 .~.
+ lda $0685 ; B303 AD 85 06 ...
+ sta $0683 ; B306 8D 83 06 ...
+ lda #$19 ; B309 A9 19 ..
+ sta sfx_ptr ; B30B 8D 3C 06 .<.
+ lda #$B3 ; B30E A9 B3 ..
+ sta sfx_ptr+1 ; B310 8D 3D 06 .=.
+ lda #$07 ; B313 A9 07 ..
+ jsr cue_sfx_jv ; B315 20 06 80 ..
+ rts ; B318 60 `
+
+; ----------------------------------------------------------------------------
+; referenced by routine at $B2FD
+sxf_b319:
+ .byte $01,$86,$00,$0A,$20,$00,$00 ; B319 01 86 00 0A 20 00 00 .... ..
+LB320: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; B320 FE 33 9C FD 04 00 04 05 .3......
+ .byte $08,$2C,$07,$15,$84,$05,$06,$1C ; B328 08 2C 07 15 84 05 06 1C .,......
+ .byte $15,$03,$48,$15,$0D,$04,$25,$07 ; B330 15 03 48 15 0D 04 25 07 ..H...%.
+ .byte $30,$2F,$0D,$04,$35,$06,$74,$35 ; B338 30 2F 0D 04 35 06 74 35 0/..5.t5
+ .byte $0A,$04,$45,$06,$04,$55,$06,$28 ; B340 0A 04 45 06 04 55 06 28 ..E..U.(
+ .byte $55,$06,$4C,$55,$06,$84,$50,$06 ; B348 55 06 4C 55 06 84 50 06 U.LU..P.
+ .byte $FD,$04,$FF,$1C,$34,$05,$70,$55 ; B350 FD 04 FF 1C 34 05 70 55 ....4.pU
+ .byte $05,$80,$06,$02,$FD,$04,$01,$24 ; B358 05 80 06 02 FD 04 01 24 .......$
+ .byte $06,$02,$FE,$5F,$9C,$FD,$00,$04 ; B360 06 02 FE 5F 9C FD 00 04 ..._....
+ .byte $0C,$01,$09,$0C,$41,$05,$30,$03 ; B368 0C 01 09 0C 41 05 30 03 ....A.0.
+ .byte $0B,$54,$2B,$0A,$8C,$01,$0D,$FE ; B370 0B 54 2B 0A 8C 01 0D FE .T+.....
+ .byte $C9,$9C,$04,$38,$02,$1A,$38,$02 ; B378 C9 9C 04 38 02 1A 38 02 ...8..8.
+ .byte $33,$32,$07,$74,$38,$05,$FE,$DA ; B380 33 32 07 74 38 05 FE DA 32.t8...
+ .byte $9C,$6A,$12,$0F,$FE,$B3,$9C ; B388 9C 6A 12 0F FE B3 9C .j.....
+LB38F: .byte $04,$02,$01,$3A,$02,$01,$5A,$02 ; B38F 04 02 01 3A 02 01 5A 02 ...:..Z.
+ .byte $01,$7A,$02,$01,$98,$02,$01,$20 ; B397 01 7A 02 01 98 02 01 20 .z.....
+ .byte $12,$01,$5A,$12,$01,$04,$22,$01 ; B39F 12 01 5A 12 01 04 22 01 ..Z...".
+ .byte $3A,$22,$01,$04,$32,$01,$78,$32 ; B3A7 3A 22 01 04 32 01 78 32 :"..2.x2
+ .byte $01,$98,$32,$01,$04,$52,$01,$38 ; B3AF 01 98 32 01 04 52 01 38 ..2..R.8
+ .byte $52,$01,$60,$52,$01,$FF ; B3B7 52 01 60 52 01 FF R.`R..
+LB3BD: .byte $22,$10,$62,$20,$82,$30,$A2,$40 ; B3BD 22 10 62 20 82 30 A2 40 ".b .0.@
+ .byte $C2,$50,$44,$60,$84,$70,$26,$80 ; B3C5 C2 50 44 60 84 70 26 80 .PD`.p&.
+ .byte $66,$90,$28,$A0,$A8,$B0,$C8,$C0 ; B3CD 66 90 28 A0 A8 B0 C8 C0 f.(.....
+ .byte $2C,$D0,$6C,$E0,$8C,$F0,$FF ; B3D5 2C D0 6C E0 8C F0 FF ,.l....
+LB3DC: .byte $00,$00,$FC,$B3,$06,$B4,$10,$B4 ; B3DC 00 00 FC B3 06 B4 10 B4 ........
+ .byte $06,$B4,$10,$B4,$1A,$B4,$24,$B4 ; B3E4 06 B4 10 B4 1A B4 24 B4 ......$.
+ .byte $2E,$B4,$38,$B4,$2E,$B4,$38,$B4 ; B3EC 2E B4 38 B4 2E B4 38 B4 ..8...8.
+ .byte $FC,$B3,$24,$B4,$1A,$B4,$42,$B4 ; B3F4 FC B3 24 B4 1A B4 42 B4 ..$...B.
+ .byte $FE,$49,$9C,$FD,$04,$00,$48,$15 ; B3FC FE 49 9C FD 04 00 48 15 .I....H.
+ .byte $03,$FF,$FE,$49,$9C,$FD,$04,$00 ; B404 03 FF FE 49 9C FD 04 00 ...I....
+ .byte $46,$07,$03,$FF,$FE,$49,$9C,$FD ; B40C 46 07 03 FF FE 49 9C FD F....I..
+ .byte $04,$00,$6A,$07,$03,$FF,$FE,$49 ; B414 04 00 6A 07 03 FF FE 49 ..j....I
+ .byte $9C,$FD,$04,$00,$0A,$35,$03,$FF ; B41C 9C FD 04 00 0A 35 03 FF .....5..
+ .byte $FE,$49,$9C,$FD,$04,$00,$3E,$2F ; B424 FE 49 9C FD 04 00 3E 2F .I....>/
+ .byte $04,$FF,$FE,$49,$9C,$FD,$04,$00 ; B42C 04 FF FE 49 9C FD 04 00 ...I....
+ .byte $7C,$35,$04,$FF,$FE,$89,$9C,$FD ; B434 7C 35 04 FF FE 89 9C FD |5......
+ .byte $00,$04,$54,$3F,$04,$FF,$FE,$89 ; B43C 00 04 54 3F 04 FF FE 89 ..T?....
+ .byte $9C,$FD,$00,$04,$8C,$1D,$04,$FF ; B444 9C FD 00 04 8C 1D 04 FF ........
+; ----------------------------------------------------------------------------
+LB44C: lda #$01 ; B44C A9 01 ..
+ sta $0770 ; B44E 8D 70 07 .p.
+ lda #$00 ; B451 A9 00 ..
+ sta $0771 ; B453 8D 71 07 .q.
+ rts ; B456 60 `
+
+; ----------------------------------------------------------------------------
+LB457: lda $0623 ; B457 AD 23 06 .#.
+ cmp #$02 ; B45A C9 02 ..
+ bne LB46A ; B45C D0 0C ..
+ lda #$00 ; B45E A9 00 ..
+ sta $0770 ; B460 8D 70 07 .p.
+ sta $0771 ; B463 8D 71 07 .q.
+ sta $0681 ; B466 8D 81 06 ...
+ rts ; B469 60 `
+
+; ----------------------------------------------------------------------------
+LB46A: lda $0622 ; B46A AD 22 06 .".
+ bne LB470 ; B46D D0 01 ..
+LB46F: rts ; B46F 60 `
+
+; ----------------------------------------------------------------------------
+LB470: lda $0770 ; B470 AD 70 07 .p.
+ beq LB46F ; B473 F0 FA ..
+ cmp #$09 ; B475 C9 09 ..
+ beq LB49F ; B477 F0 26 .&
+ sta $066C ; B479 8D 6C 06 .l.
+ sta $068A ; B47C 8D 8A 06 ...
+ inc $0770 ; B47F EE 70 07 .p.
+ lda $06DC ; B482 AD DC 06 ...
+ clc ; B485 18 .
+ adc #$30 ; B486 69 30 i0
+ sta $0680 ; B488 8D 80 06 ...
+ lda $06DD ; B48B AD DD 06 ...
+ asl a ; B48E 0A .
+ clc ; B48F 18 .
+ adc #$20 ; B490 69 20 i
+ sta $0685 ; B492 8D 85 06 ...
+ lda $0770 ; B495 AD 70 07 .p.
+ cmp #$09 ; B498 C9 09 ..
+ bcc LB46F ; B49A 90 D3 ..
+ inc $0771 ; B49C EE 71 07 .q.
+LB49F: lda $0771 ; B49F AD 71 07 .q.
+ beq LB46F ; B4A2 F0 CB ..
+ cmp #$05 ; B4A4 C9 05 ..
+ beq LB4C1 ; B4A6 F0 19 ..
+ clc ; B4A8 18 .
+ adc #$04 ; B4A9 69 04 i.
+ sta $068B ; B4AB 8D 8B 06 ...
+ inc $0771 ; B4AE EE 71 07 .q.
+ lda $0680 ; B4B1 AD 80 06 ...
+ sta $0681 ; B4B4 8D 81 06 ...
+ lda $0685 ; B4B7 AD 85 06 ...
+ sta $0686 ; B4BA 8D 86 06 ...
+ sta $066D ; B4BD 8D 6D 06 .m.
+ rts ; B4C0 60 `
+
+; ----------------------------------------------------------------------------
+LB4C1: lda $068B ; B4C1 AD 8B 06 ...
+ and #$03 ; B4C4 29 03 ).
+ clc ; B4C6 18 .
+ adc #$04 ; B4C7 69 04 i.
+ sta $068B ; B4C9 8D 8B 06 ...
+ inc $068B ; B4CC EE 8B 06 ...
+ cmp #$07 ; B4CF C9 07 ..
+ bne LB4E2 ; B4D1 D0 0F ..
+cue_woop_sound:
+ lda #$64 ; B4D3 A9 64 .d
+ sta sfx_slot_tempo ; B4D5 8D 3E 06 .>.
+ lda #$B5 ; B4D8 A9 B5 ..
+ sta sfx_slot_timer ; B4DA 8D 3F 06 .?.
+ lda #$03 ; B4DD A9 03 ..
+ jsr L8003 ; B4DF 20 03 80 ..
+LB4E2: ldy #$01 ; B4E2 A0 01 ..
+ lda $0681 ; B4E4 AD 81 06 ...
+ cmp $067E ; B4E7 CD 7E 06 .~.
+ bcc LB4EE ; B4EA 90 02 ..
+ ldy #$FF ; B4EC A0 FF ..
+LB4EE: sty $A0 ; B4EE 84 A0 ..
+ clc ; B4F0 18 .
+ adc $A0 ; B4F1 65 A0 e.
+ sta $0681 ; B4F3 8D 81 06 ...
+ ldy #$01 ; B4F6 A0 01 ..
+ lda $0686 ; B4F8 AD 86 06 ...
+ cmp $0683 ; B4FB CD 83 06 ...
+ bcc LB502 ; B4FE 90 02 ..
+ ldy #$FF ; B500 A0 FF ..
+LB502: sty $A0 ; B502 84 A0 ..
+ clc ; B504 18 .
+ adc $A0 ; B505 65 A0 e.
+ sta $0686 ; B507 8D 86 06 ...
+ rts ; B50A 60 `
+
+; ----------------------------------------------------------------------------
+; dunno what this is for yet
+data_table_b50b:
+ .byte $03,$1C,$B5,$08,$00,$00,$01,$56 ; B50B 03 1C B5 08 00 00 01 56 .......V
+ .byte $04,$1C,$B5,$08,$00,$00,$05,$1A ; B513 04 1C B5 08 00 00 05 1A ........
+ .byte $FF,$00,$00,$18,$18,$24,$24,$18 ; B51B FF 00 00 18 18 24 24 18 .....$$.
+ .byte $18,$00,$00,$42,$42,$42,$24,$18 ; B523 18 00 00 42 42 42 24 18 ...BBB$.
+ .byte $18,$00,$00,$00,$00,$66,$A5,$18 ; B52B 18 00 00 00 00 66 A5 18 .....f..
+ .byte $18,$00,$00,$00,$00,$00,$00,$3C ; B533 18 00 00 00 00 00 00 3C .......<
+ .byte $DB,$00,$00,$24,$18,$18,$24,$00 ; B53B DB 00 00 24 18 18 24 00 ...$..$.
+ .byte $00,$00,$08,$24,$58,$1A,$24,$10 ; B543 00 00 08 24 58 1A 24 10 ...$X.$.
+ .byte $00,$81,$42,$24,$18,$18,$24,$42 ; B54B 00 81 42 24 18 18 24 42 ..B$..$B
+ .byte $81,$04,$42,$A4,$18,$18,$25,$42 ; B553 81 04 42 A4 18 18 25 42 ..B...%B
+ .byte $20,$00,$00,$18,$18,$24,$24,$18 ; B55B 20 00 00 18 18 24 24 18 ....$$.
+ .byte $18 ; B563 18 .
+sfx_woop:
+ .byte $01,$A2,$00,$F0,$01,$01,$A4,$00 ; B564 01 A2 00 F0 01 01 A4 00 ........
+ .byte $DC,$01,$01,$A6,$00,$C8,$02,$01 ; B56C DC 01 01 A6 00 C8 02 01 ........
+ .byte $A4,$DC,$01,$01,$A2,$F0,$01,$00 ; B574 A4 DC 01 01 A2 F0 01 00 ........
+; ----------------------------------------------------------------------------
+LB57C: lda #$00 ; B57C A9 00 ..
+ jmp L8F76 ; B57E 4C 76 8F Lv.
+
+; ----------------------------------------------------------------------------
+LB581: lda $062A ; B581 AD 2A 06 .*.
+ sta PCOLR3 ; B584 8D C3 02 ...
+ rts ; B587 60 `
+
+; ----------------------------------------------------------------------------
+zero_filler_8588:
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B588 00 00 00 00 00 00 00 00 ........
+LB590: .byte $FE,$33,$9C,$FD,$04,$00,$04,$05 ; B590 FE 33 9C FD 04 00 04 05 .3......
+ .byte $08,$3C,$05,$0A,$7C,$05,$08,$04 ; B598 08 3C 05 0A 7C 05 08 04 .<..|...
+ .byte $25,$26,$04,$43,$26,$04,$55,$06 ; B5A0 25 26 04 43 26 04 55 06 %&.C&.U.
+ .byte $3C,$55,$0A,$84,$55,$06,$04,$43 ; B5A8 3C 55 0A 84 55 06 04 43 <U..U..C
+ .byte $06,$FE,$5F,$9C,$FD,$00,$04,$0C ; B5B0 06 FE 5F 9C FD 00 04 0C .._.....
+ .byte $01,$09,$4C,$01,$09,$8C,$01,$09 ; B5B8 01 09 4C 01 09 8C 01 09 ..L.....
+ .byte $2A,$1F,$09,$6A,$1F,$09,$0C,$3F ; B5C0 2A 1F 09 6A 1F 09 0C 3F *..j...?
+ .byte $05,$4C,$3F,$05,$8C,$3F,$05,$FE ; B5C8 05 4C 3F 05 8C 3F 05 FE .L?..?..
+ .byte $B3,$9C ; B5D0 B3 9C ..
+LB5D2: .byte $04,$02,$01,$20,$02,$01,$3C,$02 ; B5D2 04 02 01 20 02 01 3C 02 ... ..<.
+ .byte $01,$60,$02,$01,$7C,$02,$01,$98 ; B5DA 01 60 02 01 7C 02 01 98 .`..|...
+ .byte $02,$01,$04,$22,$01,$98,$22,$01 ; B5E2 02 01 04 22 01 98 22 01 ..."..".
+ .byte $3C,$36,$01,$60,$36,$01,$04,$52 ; B5EA 3C 36 01 60 36 01 04 52 <6.`6..R
+ .byte $01,$3C,$52,$01,$60,$52,$01,$98 ; B5F2 01 3C 52 01 60 52 01 98 .<R.`R..
+ .byte $52,$01,$FF ; B5FA 52 01 FF R..
+LB5FD: .byte $22,$10,$42,$20,$62,$00,$82,$00 ; B5FD 22 10 42 20 62 00 82 00 ".B b...
+ .byte $A2,$30,$C2,$40,$26,$00,$C6,$00 ; B605 A2 30 C2 40 26 00 C6 00 .0.@&...
+ .byte $68,$00,$88,$00,$2C,$00,$6C,$00 ; B60D 68 00 88 00 2C 00 6C 00 h...,.l.
+ .byte $8C,$00,$CC,$00,$FF ; B615 8C 00 CC 00 FF .....
+LB61A: .byte $00,$00,$24,$B6,$2E,$B6,$3E,$B6 ; B61A 00 00 24 B6 2E B6 3E B6 ..$...>.
+ .byte $4E,$B6,$FE,$49,$9C,$FD,$04,$00 ; B622 4E B6 FE 49 9C FD 04 00 N..I....
+ .byte $78,$43,$02,$FF,$FE,$49,$9C,$FD ; B62A 78 43 02 FF FE 49 9C FD xC...I..
+ .byte $04,$00,$3C,$25,$02,$FD,$04,$00 ; B632 04 00 3C 25 02 FD 04 00 ..<%....
+ .byte $1C,$25,$02,$FF,$FE,$49,$9C,$FD ; B63A 1C 25 02 FF FE 49 9C FD .%...I..
+ .byte $04,$00,$7C,$25,$02,$FD,$04,$00 ; B642 04 00 7C 25 02 FD 04 00 ..|%....
+ .byte $5C,$25,$02,$FF,$FE,$49,$9C,$FD ; B64A 5C 25 02 FF FE 49 9C FD \%...I..
+ .byte $04,$00,$5C,$43,$02,$FF ; B652 04 00 5C 43 02 FF ..\C..
+LB658: .byte $00,$71,$B6,$08,$40,$02,$01,$08 ; B658 00 71 B6 08 40 02 01 08 .q..@...
+ .byte $03,$71,$B6,$08,$14,$40,$02,$08 ; B660 03 71 B6 08 14 40 02 08 .q...@..
+ .byte $04,$71,$B6,$08,$00,$80,$03,$08 ; B668 04 71 B6 08 00 80 03 08 .q......
+ .byte $FF,$47,$EF,$3E,$1E,$1E,$0E,$02 ; B670 FF 47 EF 3E 1E 1E 0E 02 .G.>....
+ .byte $05,$40,$EE,$3F,$1E,$1C,$0C,$02 ; B678 05 40 EE 3F 1E 1C 0C 02 .@.?....
+ .byte $05,$40,$E0,$38,$1C,$1E,$0D,$02 ; B680 05 40 E0 38 1C 1E 0D 02 .@.8....
+ .byte $05,$40,$EE,$3F,$1E,$1C,$0C,$02 ; B688 05 40 EE 3F 1E 1C 0C 02 .@.?....
+ .byte $05 ; B690 05 .
+LB691: .byte $AD,$21,$06,$D0,$01,$60 ; B691 AD 21 06 D0 01 60 .!...`
+; ----------------------------------------------------------------------------
+ inc $067E ; B697 EE 7E 06 .~.
+LB69A: rts ; B69A 60 `
+
+; ----------------------------------------------------------------------------
+LB69B: lda player_speed ; B69B AD 24 06 .$.
+ cmp #$09 ; B69E C9 09 ..
+ bcs LB6A9 ; B6A0 B0 07 ..
+ lda $0623 ; B6A2 AD 23 06 .#.
+ cmp #$02 ; B6A5 C9 02 ..
+ bne LB6BA ; B6A7 D0 11 ..
+LB6A9: lda $0768 ; B6A9 AD 68 07 .h.
+ bne LB69A ; B6AC D0 EC ..
+ inc $0768 ; B6AE EE 68 07 .h.
+ lda #$00 ; B6B1 A9 00 ..
+ sta AUDC1 ; B6B3 8D 01 D2 ...
+ sta AUDF1 ; B6B6 8D 00 D2 ...
+ rts ; B6B9 60 `
+
+; ----------------------------------------------------------------------------
+LB6BA: lda $076F ; B6BA AD 6F 07 .o.
+ bne LB6DC ; B6BD D0 1D ..
+ lda #$81 ; B6BF A9 81 ..
+ sta AUDC1 ; B6C1 8D 01 D2 ...
+ sta $076C ; B6C4 8D 6C 07 .l.
+ lda #$00 ; B6C7 A9 00 ..
+ sta jiffy_timer_2 ; B6C9 8D 1B 06 ...
+ lda #$04 ; B6CC A9 04 ..
+ sta $076E ; B6CE 8D 6E 07 .n.
+ sta $076F ; B6D1 8D 6F 07 .o.
+ lda RANDOM ; B6D4 AD 0A D2 ...
+ and #$3F ; B6D7 29 3F )?
+ sta $076D ; B6D9 8D 6D 07 .m.
+LB6DC: lda #$10 ; B6DC A9 10 ..
+ sta AUDF1 ; B6DE 8D 00 D2 ...
+ lda jiffy_timer_2 ; B6E1 AD 1B 06 ...
+ cmp $076D ; B6E4 CD 6D 07 .m.
+ bne LB702 ; B6E7 D0 19 ..
+ lda $076E ; B6E9 AD 6E 07 .n.
+ beq LB6F7 ; B6EC F0 09 ..
+ inc $076C ; B6EE EE 6C 07 .l.
+ dec $076E ; B6F1 CE 6E 07 .n.
+ jmp LB6FD ; B6F4 4C FD B6 L..
+
+; ----------------------------------------------------------------------------
+LB6F7: dec $076C ; B6F7 CE 6C 07 .l.
+ dec $076F ; B6FA CE 6F 07 .o.
+LB6FD: lda #$00 ; B6FD A9 00 ..
+ sta jiffy_timer_2 ; B6FF 8D 1B 06 ...
+LB702: lda $076C ; B702 AD 6C 07 .l.
+ sta AUDC1 ; B705 8D 01 D2 ...
+ rts ; B708 60 `
+
+; ----------------------------------------------------------------------------
+LB709: lda $06F5 ; B709 AD F5 06 ...
+ cmp #$01 ; B70C C9 01 ..
+ bne LB71C ; B70E D0 0C ..
+ inc $0669 ; B710 EE 69 06 .i.
+ inc $066C ; B713 EE 6C 06 .l.
+ inc $066D ; B716 EE 6D 06 .m.
+ inc $06F5 ; B719 EE F5 06 ...
+LB71C: lda $0622 ; B71C AD 22 06 .".
+ bne LB722 ; B71F D0 01 ..
+LB721: rts ; B721 60 `
+
+; ----------------------------------------------------------------------------
+LB722: ldx #$FF ; B722 A2 FF ..
+LB724: inx ; B724 E8 .
+ cpx #$01 ; B725 E0 01 ..
+ beq LB724 ; B727 F0 FB ..
+ cpx #$02 ; B729 E0 02 ..
+ beq LB724 ; B72B F0 F7 ..
+ cpx #$05 ; B72D E0 05 ..
+ beq LB721 ; B72F F0 F0 ..
+ lda $076C ; B731 AD 6C 07 .l.
+ and #$0F ; B734 29 0F ).
+ tay ; B736 A8 .
+ clc ; B737 18 .
+ lda $067D,x ; B738 BD 7D 06 .}.
+ adc wind_table_1,y ; B73B 79 6B B7 yk.
+ sta $067D,x ; B73E 9D 7D 06 .}.
+ clc ; B741 18 .
+ lda $0682,x ; B742 BD 82 06 ...
+ adc wind_table_2,y ; B745 79 71 B7 yq.
+ cmp #$C6 ; B748 C9 C6 ..
+ bcs LB75D ; B74A B0 11 ..
+ sta $0682,x ; B74C 9D 82 06 ...
+ lda $0687,x ; B74F BD 87 06 ...
+ and #$03 ; B752 29 03 ).
+ sta $0687,x ; B754 9D 87 06 ...
+ inc $0687,x ; B757 FE 87 06 ...
+ jmp LB724 ; B75A 4C 24 B7 L$.
+
+; ----------------------------------------------------------------------------
+LB75D: lda #$02 ; B75D A9 02 ..
+ sta $067D,x ; B75F 9D 7D 06 .}.
+ lda RANDOM ; B762 AD 0A D2 ...
+ sta $0682,x ; B765 9D 82 06 ...
+ jmp LB724 ; B768 4C 24 B7 L$.
+
+; ----------------------------------------------------------------------------
+; used in level11
+wind_table_1:
+ .byte $01,$02,$03,$03,$03,$03 ; B76B 01 02 03 03 03 03 ......
+wind_table_2:
+ .byte $02,$01,$00,$00,$00,$00,$00,$00 ; B771 02 01 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B779 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B781 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B789 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B791 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B799 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B7A1 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B7A9 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B7B1 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00 ; B7B9 00 00 00 00 00 00 00 .......
+; ----------------------------------------------------------------------------
+LB7C0: lda score+2 ; B7C0 AD 02 07 ...
+ cmp #$0F ; B7C3 C9 0F ..
+ bcc LB7EE ; B7C5 90 27 .'
+ lda score+1 ; B7C7 AD 01 07 ...
+ cmp #$42 ; B7CA C9 42 .B
+ bcc LB7EE ; B7CC 90 20 .
+ lda score ; B7CE AD 00 07 ...
+ cmp #$40 ; B7D1 C9 40 .@
+ bcc LB7EE ; B7D3 90 19 ..
+ sec ; B7D5 38 8
+ lda score ; B7D6 AD 00 07 ...
+ sbc #$40 ; B7D9 E9 40 .@
+ sta score ; B7DB 8D 00 07 ...
+ lda score+1 ; B7DE AD 01 07 ...
+ sbc #$42 ; B7E1 E9 42 .B
+ sta score+1 ; B7E3 8D 01 07 ...
+ lda score+2 ; B7E6 AD 02 07 ...
+ sbc #$0F ; B7E9 E9 0F ..
+ sta score+2 ; B7EB 8D 02 07 ...
+LB7EE: jmp L8668 ; B7EE 4C 68 86 Lh.
+
+; ----------------------------------------------------------------------------
+ brk ; B7F1 00 .
+ brk ; B7F2 00 .
+ brk ; B7F3 00 .
+ brk ; B7F4 00 .
+ brk ; B7F5 00 .
+ brk ; B7F6 00 .
+ brk ; B7F7 00 .
+ brk ; B7F8 00 .
+ brk ; B7F9 00 .
+ brk ; B7FA 00 .
+ brk ; B7FB 00 .
+ brk ; B7FC 00 .
+ brk ; B7FD 00 .
+ brk ; B7FE 00 .
+ brk ; B7FF 00 .
+end_of_level_bonus:
+ lda level ; B800 AD F6 06 ...
+ asl a ; B803 0A .
+ tay ; B804 A8 .
+ lda mul_25_table,y ; B805 B9 A7 B8 ...
+ sta $A4 ; B808 85 A4 ..
+ lda mul_25_table+1,y ; B80A B9 A8 B8 ...
+ sta $A5 ; B80D 85 A5 ..
+ lda lives ; B80F AD 0A 07 ...
+ sta $A6 ; B812 85 A6 ..
+ inc $A6 ; B814 E6 A6 ..
+ lda $A4 ; B816 A5 A4 ..
+ sta $D0 ; B818 85 D0 ..
+ lda $A5 ; B81A A5 A5 ..
+ sta $D1 ; B81C 85 D1 ..
+ lda #$00 ; B81E A9 00 ..
+ sta work_level_time_bonus ; B820 8D 91 07 ...
+ sta $D2 ; B823 85 D2 ..
+ sta work_level_time_bonus+1 ; B825 8D 92 07 ...
+ lda #$E9 ; B828 A9 E9 ..
+ sta $D3 ; B82A 85 D3 ..
+ lda #$3D ; B82C A9 3D .=
+ sta $D4 ; B82E 85 D4 ..
+ jsr xxx_level_something_jv ; B830 20 09 80 ..
+ lda #$78 ; B833 A9 78 .x
+ sta $3DE9 ; B835 8D E9 3D ..=
+ jsr L800F ; B838 20 0F 80 ..
+add_life_bonus:
+ clc ; B83B 18 .
+ lda score ; B83C AD 00 07 ...
+ adc $A4 ; B83F 65 A4 e.
+ sta score ; B841 8D 00 07 ...
+ lda score+1 ; B844 AD 01 07 ...
+ adc $A5 ; B847 65 A5 e.
+ sta score+1 ; B849 8D 01 07 ...
+ bcc LB851 ; B84C 90 03 ..
+ inc score+2 ; B84E EE 02 07 ...
+LB851: clc ; B851 18 .
+ lda work_level_time_bonus ; B852 AD 91 07 ...
+ adc $A4 ; B855 65 A4 e.
+ sta work_level_time_bonus ; B857 8D 91 07 ...
+ lda work_level_time_bonus+1 ; B85A AD 92 07 ...
+ adc $A5 ; B85D 65 A5 e.
+ sta work_level_time_bonus+1 ; B85F 8D 92 07 ...
+ jsr L800C ; B862 20 0C 80 ..
+ jsr L800F ; B865 20 0F 80 ..
+; play once per life
+play_life_bonus_sfx:
+ lda #$96 ; B868 A9 96 ..
+ sta sfx_ptr ; B86A 8D 3C 06 .<.
+ lda #$B8 ; B86D A9 B8 ..
+ sta sfx_ptr+1 ; B86F 8D 3D 06 .=.
+ jsr cue_sfx_jv ; B872 20 06 80 ..
+LB875: lda sfx_slot_duration ; B875 AD 46 06 .F.
+ ora $0644 ; B878 0D 44 06 .D.
+ bne LB875 ; B87B D0 F8 ..
+ dec $A6 ; B87D C6 A6 ..
+ bne add_life_bonus ; B87F D0 BA ..
+ sta jiffy_timer_1 ; B881 8D 1A 06 ...
+LB884: lda jiffy_timer_1 ; B884 AD 1A 06 ...
+ cmp #$20 ; B887 C9 20 .
+ bne LB884 ; B889 D0 F9 ..
+ lda randomizer_mode ; B88B AD F3 06 ...
+ bne LB893 ; B88E D0 03 ..
+ jmp L8DA0 ; B890 4C A0 8D L..
+
+; ----------------------------------------------------------------------------
+LB893: jmp afterlife ; B893 4C 00 96 L..
+
+; ----------------------------------------------------------------------------
+; played when adding bonus per life at end of level
+sfx_add_life_bonus:
+ .byte $01,$E4,$00,$18,$02,$3C,$02,$79 ; B896 01 E4 00 18 02 3C 02 79 .....<.y
+ .byte $02,$F3,$02,$01,$A0,$00,$0A,$14 ; B89E 02 F3 02 01 A0 00 0A 14 ........
+ .byte $00 ; B8A6 00 .
+; ----------------------------------------------------------------------------
+; multiply by 25
+mul_25_table:
+ .word $0019,$0032,$004B,$0064 ; B8A7 19 00 32 00 4B 00 64 00 ..2.K.d.
+ .word $007D,$0096,$00AF,$00C8 ; B8AF 7D 00 96 00 AF 00 C8 00 }.......
+ .word $00E1,$00FA,$0113,$012C ; B8B7 E1 00 FA 00 13 01 2C 01 ......,.
+; ----------------------------------------------------------------------------
+; all zeroes, filler?
+zero_filler_b8bf:
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8BF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8C7 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8CF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8D7 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8DF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8E7 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8EF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8F7 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B8FF 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B907 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B90F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B917 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B91F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B927 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B92F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B937 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B93F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B947 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B94F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B957 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; B95F 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00 ; B967 00 00 00 00 ....
+; ----------------------------------------------------------------------------
+LB96B: lda #$00 ; B96B A9 00 ..
+ sta jiffy_timer_1 ; B96D 8D 1A 06 ...
+LB970: lda jiffy_timer_1 ; B970 AD 1A 06 ...
+ cmp #$60 ; B973 C9 60 .`
+ bne LB970 ; B975 D0 F9 ..
+ lda #$00 ; B977 A9 00 ..
+ sta FR1 ; B979 85 E0 ..
+ lda #$00 ; B97B A9 00 ..
+ sta $06AB ; B97D 8D AB 06 ...
+ sta $067D ; B980 8D 7D 06 .}.
+ sta $0681 ; B983 8D 81 06 ...
+ sta $067E ; B986 8D 7E 06 .~.
+ sta $0680 ; B989 8D 80 06 ...
+ lda #$A0 ; B98C A9 A0 ..
+ sta FR1+1 ; B98E 85 E1 ..
+ lda #$00 ; B990 A9 00 ..
+ sta FR1+2 ; B992 85 E2 ..
+ jsr clear_screen_mem_jv ; B994 20 1E 80 ..
+ jsr setup_gameboard_dlist_jv ; B997 20 15 80 ..
+ nop ; B99A EA .
+ nop ; B99B EA .
+ nop ; B99C EA .
+LB99D: ldy #$16 ; B99D A0 16 ..
+ lda (FR1),y ; B99F B1 E0 ..
+ sta dm_progctr ; B9A1 85 C0 ..
+ iny ; B9A3 C8 .
+ lda (FR1),y ; B9A4 B1 E0 ..
+ sta dm_progctr+1 ; B9A6 85 C1 ..
+ ldy FR1+2 ; B9A8 A4 E2 ..
+ ldx #$00 ; B9AA A2 00 ..
+LB9AC: lda level_names,y ; B9AC B9 00 BB ...
+ sec ; B9AF 38 8
+ sbc #$20 ; B9B0 E9 20 .
+ sta $3DE8,x ; B9B2 9D E8 3D ..=
+ iny ; B9B5 C8 .
+ inx ; B9B6 E8 .
+ cpx #$14 ; B9B7 E0 14 ..
+ bne LB9AC ; B9B9 D0 F1 ..
+ jsr LB9EC ; B9BB 20 EC B9 ..
+ lda #$00 ; B9BE A9 00 ..
+ sta jiffy_timer_1 ; B9C0 8D 1A 06 ...
+ jsr draw_map_jv ; B9C3 20 00 80 ..
+LB9C6: lda jiffy_timer_1 ; B9C6 AD 1A 06 ...
+ cmp #$40 ; B9C9 C9 40 .@
+ bne LB9C6 ; B9CB D0 F9 ..
+ jsr clear_screen_mem_jv ; B9CD 20 1E 80 ..
+ clc ; B9D0 18 .
+ lda FR1+2 ; B9D1 A5 E2 ..
+ adc #$14 ; B9D3 69 14 i.
+ sta FR1+2 ; B9D5 85 E2 ..
+ cmp #$F0 ; B9D7 C9 F0 ..
+ bne LB9DE ; B9D9 D0 03 ..
+ jmp reinit_game ; B9DB 4C 0C 90 L..
+
+; ----------------------------------------------------------------------------
+LB9DE: clc ; B9DE 18 .
+ lda FR1 ; B9DF A5 E0 ..
+ adc #$40 ; B9E1 69 40 i@
+ sta FR1 ; B9E3 85 E0 ..
+ bcc LB99D ; B9E5 90 B6 ..
+ inc FR1+1 ; B9E7 E6 E1 ..
+ jmp LB99D ; B9E9 4C 9D B9 L..
+
+; ----------------------------------------------------------------------------
+LB9EC: ldy #$2F ; B9EC A0 2F ./
+ lda (FR1),y ; B9EE B1 E0 ..
+ sta COLOR0 ; B9F0 8D C4 02 ...
+ iny ; B9F3 C8 .
+ lda (FR1),y ; B9F4 B1 E0 ..
+ sta COLOR1 ; B9F6 8D C5 02 ...
+ iny ; B9F9 C8 .
+ lda (FR1),y ; B9FA B1 E0 ..
+ sta COLOR2 ; B9FC 8D C6 02 ...
+ rts ; B9FF 60 `
+
+; ----------------------------------------------------------------------------
+LBA00: lda #$40 ; BA00 A9 40 .@
+ sta NMIEN ; BA02 8D 0E D4 ...
+ lda #$00 ; BA05 A9 00 ..
+ sta COLOR3 ; BA07 8D C7 02 ...
+ sta COLOR0 ; BA0A 8D C4 02 ...
+ sta COLOR1 ; BA0D 8D C5 02 ...
+ sta COLOR2 ; BA10 8D C6 02 ...
+ lda #$30 ; BA13 A9 30 .0
+ sta SAVMSC+1 ; BA15 85 59 .Y
+ jsr clear_screen_mem_jv ; BA17 20 1E 80 ..
+ lda cur_level_map0 ; BA1A AD D6 07 ...
+ sta dm_progctr ; BA1D 85 C0 ..
+ lda cur_level_map0+1 ; BA1F AD D7 07 ...
+ sta dm_progctr+1 ; BA22 85 C1 ..
+ jsr draw_map_jv ; BA24 20 00 80 ..
+ lda #$30 ; BA27 A9 30 .0
+ sta SAVMSC+1 ; BA29 85 59 .Y
+ lda #$00 ; BA2B A9 00 ..
+ sta $AA ; BA2D 85 AA ..
+ sta $06AB ; BA2F 8D AB 06 ...
+ sta COLOR4 ; BA32 8D C8 02 ...
+ jsr setup_gameboard_dlist_jv ; BA35 20 15 80 ..
+ lda level ; BA38 AD F6 06 ...
+ tay ; BA3B A8 .
+ lda level_name_hscrol_table,y ; BA3C B9 F0 BB ...
+ sta HSCROL ; BA3F 8D 04 D4 ...
+ lda #$16 ; BA42 A9 16 ..
+ sta $085E ; BA44 8D 5E 08 .^.
+ sta $08DF ; BA47 8D DF 08 ...
+ lda level ; BA4A AD F6 06 ...
+ pha ; BA4D 48 H
+ asl a ; BA4E 0A .
+ asl a ; BA4F 0A .
+ asl a ; BA50 0A .
+ asl a ; BA51 0A .
+ sta dm_progctr ; BA52 85 C0 ..
+ pla ; BA54 68 h
+ asl a ; BA55 0A .
+ asl a ; BA56 0A .
+ clc ; BA57 18 .
+ adc dm_progctr ; BA58 65 C0 e.
+ tay ; BA5A A8 .
+ ldx #$00 ; BA5B A2 00 ..
+; copy level name into screen RAM
+show_level_name:
+ lda level_names,y ; BA5D B9 00 BB ...
+ sec ; BA60 38 8
+ sbc #$20 ; BA61 E9 20 .
+ sta $3DEA,x ; BA63 9D EA 3D ..=
+ inx ; BA66 E8 .
+ iny ; BA67 C8 .
+ cpx #$14 ; BA68 E0 14 ..
+ bne show_level_name ; BA6A D0 F1 ..
+ lda #$08 ; BA6C A9 08 ..
+ jsr cue_music_jv ; BA6E 20 18 80 ..
+; level is already drawn with all color regs set to black. for each color reg, wait 1 sec before turning it visible. this syncs up with the music because the music was written to sync with this actually
+sync_to_music:
+ jsr wait_1_sec ; BA71 20 9E BA ..
+ lda cur_level_offs_46+3 ; BA74 AD F1 07 ...
+ sta COLOR2 ; BA77 8D C6 02 ...
+ jsr wait_1_sec ; BA7A 20 9E BA ..
+ lda cur_level_offs_46+2 ; BA7D AD F0 07 ...
+ sta COLOR1 ; BA80 8D C5 02 ...
+ jsr wait_1_sec ; BA83 20 9E BA ..
+ lda cur_level_offs_46+1 ; BA86 AD EF 07 ...
+ sta COLOR0 ; BA89 8D C4 02 ...
+ jsr wait_1_sec ; BA8C 20 9E BA ..
+ lda #$00 ; BA8F A9 00 ..
+ jsr wait_1_sec ; BA91 20 9E BA ..
+ jsr enable_joystick_jv ; BA94 20 1B 80 ..
+ lda #$00 ; BA97 A9 00 ..
+ tay ; BA99 A8 .
+ jsr wait_1_sec ; BA9A 20 9E BA ..
+ rts ; BA9D 60 `
+
+; ----------------------------------------------------------------------------
+; actually 64 jiffies, 1.067S ntsc, 1.28s pal
+wait_1_sec:
+ lda #$00 ; BA9E A9 00 ..
+ sta jiffy_timer_1 ; BAA0 8D 1A 06 ...
+keep_waiting:
+ lda jiffy_timer_1 ; BAA3 AD 1A 06 ...
+ cmp #$40 ; BAA6 C9 40 .@
+ bne keep_waiting ; BAA8 D0 F9 ..
+ rts ; BAAA 60 `
+
+; ----------------------------------------------------------------------------
+; filler?
+zero_filler_baab:
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; BAAB 00 00 00 00 00 00 00 00 ........
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; BAB3 00 00 00 00 00 00 00 00 ........
+ .byte $00 ; BABB 00 .
+; level intro music, melody
+sfx15: .byte $01,$A5,$02,$3C,$10,$2F,$10,$35 ; BABC 01 A5 02 3C 10 2F 10 35 ...<./.5
+ .byte $10,$2D,$10,$2F,$08,$2D,$08,$28 ; BAC4 10 2D 10 2F 08 2D 08 28 .-./.-.(
+ .byte $08,$2F,$08,$35,$08,$2F,$08,$2D ; BACC 08 2F 08 35 08 2F 08 2D ./.5./.-
+ .byte $08,$35,$08,$3C,$10,$2F,$10,$35 ; BAD4 08 35 08 3C 10 2F 10 35 .5.<./.5
+ .byte $10,$2D,$10,$28,$08,$2D,$08,$2F ; BADC 10 2D 10 28 08 2D 08 2F .-.(.-./
+ .byte $08,$35,$08,$3C,$10,$00 ; BAE4 08 35 08 3C 10 00 .5.<..
+; level intro music, bass
+sfx16: .byte $01,$A7,$02,$F3,$20,$A2,$20,$F3 ; BAEA 01 A7 02 F3 20 A2 20 F3 .... . .
+ .byte $20,$A2,$20,$F3,$20,$A2,$20,$79 ; BAF2 20 A2 20 F3 20 A2 20 79 . . . y
+ .byte $10,$A2,$10,$F3,$10,$00 ; BAFA 10 A2 10 F3 10 00 ......
+level_names:
+ .byte $20,$20,$20,$4E,$4F,$54,$48,$49 ; BB00 20 20 20 4E 4F 54 48 49 NOTHI
+ .byte $4E,$47,$20,$54,$4F,$20,$49,$54 ; BB08 4E 47 20 54 4F 20 49 54 NG TO IT
+ .byte $20,$20,$20,$20,$20,$20,$20,$45 ; BB10 20 20 20 20 20 20 20 45 E
+ .byte $4C,$45,$43,$54,$52,$4F,$43,$55 ; BB18 4C 45 43 54 52 4F 43 55 LECTROCU
+ .byte $54,$49,$4F,$4E,$20,$20,$20,$20 ; BB20 54 49 4F 4E 20 20 20 20 TION
+ .byte $20,$20,$20,$20,$20,$44,$55,$4D ; BB28 20 20 20 20 20 44 55 4D DUM
+ .byte $42,$57,$41,$49,$54,$45,$52,$20 ; BB30 42 57 41 49 54 45 52 20 BWAITER
+ .byte $20,$20,$20,$20,$20,$20,$20,$20 ; BB38 20 20 20 20 20 20 20 20
+ .byte $20,$48,$45,$4C,$4C,$53,$54,$4F ; BB40 20 48 45 4C 4C 53 54 4F HELLSTO
+ .byte $4E,$45,$53,$20,$20,$20,$20,$20 ; BB48 4E 45 53 20 20 20 20 20 NES
+ .byte $20,$20,$46,$49,$47,$55,$52,$49 ; BB50 20 20 46 49 47 55 52 49 FIGURI
+ .byte $54,$53,$20,$52,$45,$56,$45,$4E ; BB58 54 53 20 52 45 56 45 4E TS REVEN
+ .byte $47,$45,$20,$20,$20,$20,$20,$20 ; BB60 47 45 20 20 20 20 20 20 GE
+ .byte $20,$20,$20,$57,$41,$4C,$4C,$53 ; BB68 20 20 20 57 41 4C 4C 53 WALLS
+ .byte $20,$20,$20,$20,$20,$20,$20,$20 ; BB70 20 20 20 20 20 20 20 20
+ .byte $20,$20,$20,$20,$20,$20,$5A,$49 ; BB78 20 20 20 20 20 20 5A 49 ZI
+ .byte $47,$2D,$5A,$41,$47,$20,$20,$20 ; BB80 47 2D 5A 41 47 20 20 20 G-ZAG
+ .byte $20,$20,$20,$20,$20,$20,$20,$20 ; BB88 20 20 20 20 20 20 20 20
+ .byte $20,$53,$50,$45,$4C,$4C,$42,$4F ; BB90 20 53 50 45 4C 4C 42 4F SPELLBO
+ .byte $55,$4E,$44,$20,$20,$20,$20,$20 ; BB98 55 4E 44 20 20 20 20 20 UND
+ .byte $20,$20,$20,$20,$20,$20,$42,$4C ; BBA0 20 20 20 20 20 20 42 4C BL
+ .byte $41,$43,$4B,$4F,$55,$54,$20,$20 ; BBA8 41 43 4B 4F 55 54 20 20 ACKOUT
+ .byte $20,$20,$20,$20,$48,$45,$52,$45 ; BBB0 20 20 20 20 48 45 52 45 HERE
+ .byte $54,$48,$45,$52,$45,$45,$56,$45 ; BBB8 54 48 45 52 45 45 56 45 THEREEVE
+ .byte $52,$59,$57,$48,$45,$52,$45,$20 ; BBC0 52 59 57 48 45 52 45 20 RYWHERE
+ .byte $20,$20,$20,$20,$20,$48,$41,$54 ; BBC8 20 20 20 20 20 48 41 54 HAT
+ .byte $43,$48,$4C,$49,$4E,$47,$53,$20 ; BBD0 43 48 4C 49 4E 47 53 20 CHLINGS
+ .byte $20,$20,$20,$20,$20,$20,$20,$20 ; BBD8 20 20 20 20 20 20 20 20
+ .byte $20,$48,$55,$52,$52,$49,$43,$41 ; BBE0 20 48 55 52 52 49 43 41 HURRICA
+ .byte $4E,$45,$20,$20,$20,$20,$20,$20 ; BBE8 4E 45 20 20 20 20 20 20 NE
+; used for centering level name on gameboard
+level_name_hscrol_table:
+ .byte $04,$04,$00,$00,$00,$04,$04,$00 ; BBF0 04 04 00 00 00 04 04 00 ........
+ .byte $00,$04,$00,$04,$00,$00,$00,$00 ; BBF8 00 04 00 04 00 00 00 00 ........
+; ----------------------------------------------------------------------------
+; the WELL DONE screen, when you beat all the levels. after this, the game plays random levels.
+well_done_screen:
+ jsr L803C ; BC00 20 3C 80 <.
+ jsr enable_joystick_jv ; BC03 20 1B 80 ..
+ jsr clear_screen_mem_jv ; BC06 20 1E 80 ..
+ lda #$00 ; BC09 A9 00 ..
+ sta $06AB ; BC0B 8D AB 06 ...
+ jsr setup_gameboard_dlist_jv ; BC0E 20 15 80 ..
+ ldy dlist_shadow_lo ; BC11 AC AC 06 ...
+ lda #$41 ; BC14 A9 41 .A
+ sta $080A,y ; BC16 99 0A 08 ...
+ tya ; BC19 98 .
+ sta $080B,y ; BC1A 99 0B 08 ...
+ lda #$08 ; BC1D A9 08 ..
+ sta $080C,y ; BC1F 99 0C 08 ...
+ lda #$D9 ; BC22 A9 D9 ..
+ sta dm_progctr ; BC24 85 C0 ..
+ lda #$BC ; BC26 A9 BC ..
+ sta dm_progctr+1 ; BC28 85 C1 ..
+ jsr draw_map_jv ; BC2A 20 00 80 ..
+ lda #$04 ; BC2D A9 04 ..
+ sta $0688 ; BC2F 8D 88 06 ...
+ sta $066A ; BC32 8D 6A 06 .j.
+ lda #$7C ; BC35 A9 7C .|
+ sta $067E ; BC37 8D 7E 06 .~.
+ lda #$20 ; BC3A A9 20 .
+ sta $0683 ; BC3C 8D 83 06 ...
+; load dli_service_2 address into dli shadow
+setup_dli_2:
+ lda #$C7 ; BC3F A9 C7 ..
+ sta dli_vec_shadow_lo ; BC41 8D AE 06 ...
+ lda #$BD ; BC44 A9 BD ..
+ sta dli_vec_shadow_hi ; BC46 8D AF 06 ...
+ lda #$8D ; BC49 A9 8D ..
+ sta $0809 ; BC4B 8D 09 08 ...
+ sta $088A ; BC4E 8D 8A 08 ...
+LBC51: lda dli_vec_shadow_hi ; BC51 AD AF 06 ...
+ bne LBC51 ; BC54 D0 FB ..
+ lda #$96 ; BC56 A9 96 ..
+ sta COLOR0 ; BC58 8D C4 02 ...
+ sta jiffy_timer_1 ; BC5B 8D 1A 06 ...
+LBC5E: lda jiffy_timer_1 ; BC5E AD 1A 06 ...
+ cmp #$20 ; BC61 C9 20 .
+ bne LBC5E ; BC63 D0 F9 ..
+ lda #$03 ; BC65 A9 03 ..
+ jsr cue_music_jv ; BC67 20 18 80 ..
+ lda #$CD ; BC6A A9 CD ..
+ sta work_level_sub0 ; BC6C 8D 82 07 ...
+ lda #$BC ; BC6F A9 BC ..
+ sta work_level_sub0+1 ; BC71 8D 83 07 ...
+ lda #$05 ; BC74 A9 05 ..
+ sta player_speed ; BC76 8D 24 06 .$.
+ lda #$0D ; BC79 A9 0D ..
+ sta joystick_disabled ; BC7B 8D 32 06 .2.
+ lda #$00 ; BC7E A9 00 ..
+ sta $0623 ; BC80 8D 23 06 .#.
+ lda #$52 ; BC83 A9 52 .R
+ sta work_level_sub1 ; BC85 8D 84 07 ...
+ lda #$BD ; BC88 A9 BD ..
+ sta work_level_sub1+1 ; BC8A 8D 85 07 ...
+ lda #$4C ; BC8D A9 4C .L
+ sta work_level_offs_46+7 ; BC8F 8D B5 07 ...
+LBC92: lda work_level_sub1 ; BC92 AD 84 07 ...
+ cmp #$E6 ; BC95 C9 E6 ..
+ bne LBC92 ; BC97 D0 F9 ..
+ lda #$00 ; BC99 A9 00 ..
+ sta $06AB ; BC9B 8D AB 06 ...
+ jsr setup_gameboard_dlist_jv ; BC9E 20 15 80 ..
+ ldx #$0B ; BCA1 A2 0B ..
+LBCA3: lda LBDD1,x ; BCA3 BD D1 BD ...
+ sta $3DE8,x ; BCA6 9D E8 3D ..=
+ dex ; BCA9 CA .
+ bne LBCA3 ; BCAA D0 F7 ..
+ lda #$3D ; BCAC A9 3D .=
+ sta $D4 ; BCAE 85 D4 ..
+ lda #$F5 ; BCB0 A9 F5 ..
+ sta $D3 ; BCB2 85 D3 ..
+ ldx #$03 ; BCB4 A2 03 ..
+LBCB6: lda $06FF,x ; BCB6 BD FF 06 ...
+ sta $CF,x ; BCB9 95 CF ..
+ dex ; BCBB CA .
+ bne LBCB6 ; BCBC D0 F8 ..
+ jsr xxx_level_something_jv ; BCBE 20 09 80 ..
+LBCC1: lda $0663 ; BCC1 AD 63 06 .c.
+ bne LBCC1 ; BCC4 D0 FB ..
+ lda level ; BCC6 AD F6 06 ...
+ inc randomizer_mode ; BCC9 EE F3 06 ...
+ rts ; BCCC 60 `
+
+; ----------------------------------------------------------------------------
+; dunno, but referenced by code at $BC6A
+code_bccd:
+ lda $062A ; BCCD AD 2A 06 .*.
+ sta COLOR2 ; BCD0 8D C6 02 ...
+ lda #$02 ; BCD3 A9 02 ..
+ sta collision_save+4 ; BCD5 8D B4 06 ...
+ rts ; BCD8 60 `
+
+; ----------------------------------------------------------------------------
+; level map used for the WELL DONE screen, when you beat level 12
+well_done_map:
+ .byte $FE,$A0,$BD,$FD,$00,$04,$0C,$06 ; BCD9 FE A0 BD FD 00 04 0C 06 ........
+ .byte $07,$30,$06,$09,$54,$06,$09,$78 ; BCE1 07 30 06 09 54 06 09 78 .0..T..x
+ .byte $06,$09,$0C,$30,$09,$30,$38,$05 ; BCE9 06 09 0C 30 09 30 38 05 ...0.08.
+ .byte $54,$30,$09,$78,$30,$09,$FD,$04 ; BCF1 54 30 09 78 30 09 FD 04 T0.x0...
+ .byte $04,$10,$22,$02,$20,$34,$01,$34 ; BCF9 04 10 22 02 20 34 01 34 ..". 4.4
+ .byte $4C,$01,$44,$34,$01,$58,$38,$05 ; BD01 4C 01 44 34 01 58 38 05 L.D4.X8.
+ .byte $FD,$04,$FC,$1C,$26,$02,$20,$4C ; BD09 FD 04 FC 1C 26 02 20 4C ....&. L
+ .byte $01,$34,$34,$01,$44,$4C,$01,$FD ; BD11 01 34 34 01 44 4C 01 FD .44.DL..
+ .byte $04,$00,$34,$06,$06,$34,$16,$06 ; BD19 04 00 34 06 06 34 16 06 ..4..4..
+ .byte $34,$26,$06,$54,$26,$07,$78,$26 ; BD21 34 26 06 54 26 07 78 26 4&.T&.x&
+ .byte $07,$10,$30,$04,$0C,$50,$05,$38 ; BD29 07 10 30 04 0C 50 05 38 ..0..P.8
+ .byte $30,$03,$38,$50,$03,$7C,$30,$06 ; BD31 30 03 38 50 03 7C 30 06 0.8P.|0.
+ .byte $7C,$40,$06,$7C,$50,$06,$FD,$00 ; BD39 7C 40 06 7C 50 06 FD 00 |@.|P...
+ .byte $04,$24,$06,$07,$24,$38,$05,$48 ; BD41 04 24 06 07 24 38 05 48 .$..$8.H
+ .byte $38,$05,$6C,$30,$09,$18,$1A,$03 ; BD49 38 05 6C 30 09 18 1A 03 8.l0....
+ .byte $FF ; BD51 FF .
+; ----------------------------------------------------------------------------
+; referenced by code at $BC83
+code_bd52:
+ lda $0621 ; BD52 AD 21 06 .!.
+ bne LBD58 ; BD55 D0 01 ..
+ rts ; BD57 60 `
+
+; ----------------------------------------------------------------------------
+LBD58: ldy dlist_shadow_lo ; BD58 AC AC 06 ...
+ lda #$0D ; BD5B A9 0D ..
+ sta $0809,y ; BD5D 99 09 08 ...
+ lda #$8D ; BD60 A9 8D ..
+ sta $080A,y ; BD62 99 0A 08 ...
+ lda $080B,y ; BD65 B9 0B 08 ...
+ sta $080C,y ; BD68 99 0C 08 ...
+ lda #$41 ; BD6B A9 41 .A
+ sta $080B,y ; BD6D 99 0B 08 ...
+ lda #$08 ; BD70 A9 08 ..
+ sta $080D,y ; BD72 99 0D 08 ...
+ inc dlist_shadow_lo ; BD75 EE AC 06 ...
+ cpy #$4E ; BD78 C0 4E .N
+ beq LBD81 ; BD7A F0 05 ..
+ cpy #$CE ; BD7C C0 CE ..
+ beq LBD81 ; BD7E F0 01 ..
+ rts ; BD80 60 `
+
+; ----------------------------------------------------------------------------
+LBD81: lda #$E6 ; BD81 A9 E6 ..
+ sta work_level_sub1 ; BD83 8D 84 07 ...
+ lda #$06 ; BD86 A9 06 ..
+ sta work_level_sub1+1 ; BD88 8D 85 07 ...
+ lda #$09 ; BD8B A9 09 ..
+ sta player_speed ; BD8D 8D 24 06 .$.
+ lda #$C6 ; BD90 A9 C6 ..
+ sta $0683 ; BD92 8D 83 06 ...
+ lda #$00 ; BD95 A9 00 ..
+ sta $0621 ; BD97 8D 21 06 .!.
+ lda #$01 ; BD9A A9 01 ..
+ sta $0688 ; BD9C 8D 88 06 ...
+ rts ; BD9F 60 `
+
+; ----------------------------------------------------------------------------
+; used to draw the large WELL DONE banner
+well_done_shape:
+ .byte $04,$00,$00,$01,$01,$01,$01,$05 ; BDA0 04 00 00 01 01 01 01 05 ........
+ .byte $00,$01,$01,$01,$01,$01,$03,$05 ; BDA8 00 01 01 01 01 01 03 05 ........
+ .byte $00,$02,$01,$01,$01,$01,$03,$05 ; BDB0 00 02 01 01 01 01 03 05 ........
+ .byte $00,$03,$01,$01,$01,$01,$03,$04 ; BDB8 00 03 01 01 01 01 03 04 ........
+ .byte $01,$04,$03,$03,$03,$03,$FF ; BDC0 01 04 03 03 03 03 FF .......
+; ----------------------------------------------------------------------------
+; DLI service routine, changes COLBK, address gets stored in $6ae/$6af by code at $bc3c
+dli_service_2:
+ pha ; BDC7 48 H
+ lda #$C4 ; BDC8 A9 C4 ..
+ sta WSYNC ; BDCA 8D 0A D4 ...
+ sta COLBK ; BDCD 8D 1A D0 ...
+ pla ; BDD0 68 h
+LBDD1: rti ; BDD1 40 @
+
+; ----------------------------------------------------------------------------
+; not sure what displays this, but it's screen codes
+total_score_msg:
+ .byte $74,$6F,$74,$61,$6C,$00,$73,$63 ; BDD2 74 6F 74 61 6C 00 73 63 total.sc
+ .byte $6F,$72,$65,$33,$00,$26,$29,$2C ; BDDA 6F 72 65 33 00 26 29 2C ore3.&),
+ .byte $25,$33,$00,$00,$00,$00,$00,$00 ; BDE2 25 33 00 00 00 00 00 00 %3......
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 ; BDEA 00 00 00 00 00 00 00 00 ........
+sfx00: .byte $01,$A5,$02,$79,$08,$A2,$08,$79 ; BDF2 01 A5 02 79 08 A2 08 79 ...y...y
+ .byte $08,$A2,$08,$C1,$10,$C1,$10,$F3 ; BDFA 08 A2 08 C1 10 C1 10 F3 ........
+ .byte $20,$F3,$20,$02,$F5,$BD,$02,$79 ; BE02 20 F3 20 02 F5 BD 02 79 . ....y
+ .byte $08,$6C,$08,$60,$08,$5B,$08,$51 ; BE0A 08 6C 08 60 08 5B 08 51 .l.`.[.Q
+ .byte $08,$5B,$08,$60,$08,$6C,$08,$79 ; BE12 08 5B 08 60 08 6C 08 79 .[.`.l.y
+ .byte $10,$A2,$10,$F3,$20,$01,$A0,$00 ; BE1A 10 A2 10 F3 20 01 A0 00 .... ...
+ .byte $0A,$80,$00 ; BE22 0A 80 00 ...
+sfx01: .byte $01,$A6,$02,$3C,$20,$51,$20,$48 ; BE25 01 A6 02 3C 20 51 20 48 ...< Q H
+ .byte $08,$51,$08,$48,$08,$40,$08,$3C ; BE2D 08 51 08 48 08 40 08 3C .Q.H.@.<
+ .byte $10,$3C,$20,$3C,$10,$51,$10,$51 ; BE35 10 3C 20 3C 10 51 10 51 .< <.Q.Q
+ .byte $10,$48,$08,$51,$08,$48,$08,$40 ; BE3D 10 48 08 51 08 48 08 40 .H.Q.H.@
+ .byte $08,$3C,$20,$3C,$20,$51,$20,$48 ; BE45 08 3C 20 3C 20 51 20 48 .< < Q H
+ .byte $08,$51,$08,$48,$08,$40,$08,$3C ; BE4D 08 51 08 48 08 40 08 3C .Q.H.@.<
+ .byte $10,$3C,$10,$3C,$08,$35,$08,$2F ; BE55 10 3C 10 3C 08 35 08 2F .<.<.5./
+ .byte $08,$2D,$08,$28,$08,$2D,$08,$2F ; BE5D 08 2D 08 28 08 2D 08 2F .-.(.-./
+ .byte $08,$35,$08,$3C,$08,$51,$08,$60 ; BE65 08 35 08 3C 08 51 08 60 .5.<.Q.`
+ .byte $08,$51,$08,$79,$20,$00,$01,$81 ; BE6D 08 51 08 79 20 00 01 81 .Q.y ...
+ .byte $00,$32,$01,$00 ; BE75 00 32 01 00 .2..
+sfx_extra_life:
+ .byte $01,$A8,$00,$05,$02,$0F,$02,$0A ; BE79 01 A8 00 05 02 0F 02 0A ........
+ .byte $02,$14,$02,$0F,$02,$19,$02,$14 ; BE81 02 14 02 0F 02 19 02 14 ........
+ .byte $02,$1E,$02,$00 ; BE89 02 1E 02 00 ....
+; end of game tune, melody
+sfx02: .byte $01,$A5,$02,$3C,$10,$51,$10,$3C ; BE8D 01 A5 02 3C 10 51 10 3C ...<.Q.<
+ .byte $10,$51,$10,$44,$08,$44,$08,$44 ; BE95 10 51 10 44 08 44 08 44 .Q.D.D.D
+ .byte $08,$44,$08,$44,$10,$5B,$10,$4C ; BE9D 08 44 08 44 10 5B 10 4C .D.D.[.L
+ .byte $10,$66,$10,$4C,$10,$66,$10,$51 ; BEA5 10 66 10 4C 10 66 10 51 .f.L.f.Q
+ .byte $40,$00 ; BEAD 40 00 @.
+; end of game tune, bass
+sfx03: .byte $01,$A4,$02,$79,$10,$A2,$10,$F3 ; BEAF 01 A4 02 79 10 A2 10 F3 ...y....
+ .byte $10,$79,$10,$88,$10,$B6,$10,$D9 ; BEB7 10 79 10 88 10 B6 10 D9 .y......
+ .byte $10,$88,$10,$99,$10,$CC,$10,$CC ; BEBF 10 88 10 99 10 CC 10 CC ........
+ .byte $10,$99,$10,$A2,$08,$99,$08,$A2 ; BEC7 10 99 10 A2 08 99 08 A2 ........
+ .byte $08,$99,$08,$A2,$20,$00 ; BECF 08 99 08 A2 20 00 .... .
+; end level tune #1, bass
+sfx04: .byte $01,$A5,$02,$79,$14,$A2,$14,$79 ; BED5 01 A5 02 79 14 A2 14 79 ...y...y
+ .byte $14,$A2,$14,$79,$14,$A2,$14,$F3 ; BEDD 14 A2 14 79 14 A2 14 F3 ...y....
+ .byte $14,$A2,$14,$02,$D8,$BE,$01,$00 ; BEE5 14 A2 14 02 D8 BE 01 00 ........
+; end level tune #1, melody
+sfx05: .byte $01,$A0,$00,$0A,$A0,$01,$A6,$02 ; BEED 01 A0 00 0A A0 01 A6 02 ........
+ .byte $51,$0A,$55,$0A,$51,$0A,$4C,$0A ; BEF5 51 0A 55 0A 51 0A 4C 0A Q.U.Q.L.
+ .byte $51,$0A,$4C,$0A,$48,$0A,$4C,$0A ; BEFD 51 0A 4C 0A 48 0A 4C 0A Q.L.H.L.
+ .byte $48,$0A,$44,$0A,$48,$0A,$44,$0A ; BF05 48 0A 44 0A 48 0A 44 0A H.D.H.D.
+ .byte $3C,$0A,$51,$0A,$3C,$14,$00 ; BF0D 3C 0A 51 0A 3C 14 00 <.Q.<..
+; end level tune #2, melody
+sfx06: .byte $01,$A6,$02,$79,$20,$60,$14,$51 ; BF14 01 A6 02 79 20 60 14 51 ...y `.Q
+ .byte $3C,$60,$0A,$5B,$14,$60,$08,$5B ; BF1C 3C 60 0A 5B 14 60 08 5B <`.[.`.[
+ .byte $14,$60,$08,$5B,$14,$51,$08,$60 ; BF24 14 60 08 5B 14 51 08 60 .`.[.Q.`
+ .byte $14,$79,$20,$00 ; BF2C 14 79 20 00 .y .
+; end level tune #2, bass
+sfx07: .byte $01,$A6,$02,$F3,$0A,$D9,$0A,$C1 ; BF30 01 A6 02 F3 0A D9 0A C1 ........
+ .byte $0A,$A2,$14,$79,$1E,$A2,$1E,$C1 ; BF38 0A A2 14 79 1E A2 1E C1 ...y....
+ .byte $0A,$B6,$50,$C1,$08,$A2,$14,$F3 ; BF40 0A B6 50 C1 08 A2 14 F3 ..P.....
+ .byte $20,$00 ; BF48 20 00 .
+; end level tune #3, bass
+sfx08: .byte $01,$A8,$02,$79,$30,$A2,$20,$79 ; BF4A 01 A8 02 79 30 A2 20 79 ...y0. y
+ .byte $20,$51,$10,$A2,$30,$6C,$20,$A3 ; BF52 20 51 10 A2 30 6C 20 A3 Q..0l .
+ .byte $20,$6C,$10,$79,$70,$00 ; BF5A 20 6C 10 79 70 00 l.yp.
+; end level tune #3, melody
+sfx09: .byte $01,$A5,$02,$79,$10,$60,$10,$51 ; BF60 01 A5 02 79 10 60 10 51 ...y.`.Q
+ .byte $10,$3C,$20,$35,$10,$3C,$10,$44 ; BF68 10 3C 20 35 10 3C 10 44 .< 5.<.D
+ .byte $10,$40,$10,$51,$20,$5B,$20,$6C ; BF70 10 40 10 51 20 5B 20 6C .@.Q [ l
+ .byte $20,$80,$10,$79,$10,$60,$10,$51 ; BF78 20 80 10 79 10 60 10 51 ..y.`.Q
+ .byte $10,$3C,$40,$00 ; BF80 10 3C 40 00 .<@.
+; end level tune #4, melody
+sfx10: .byte $01,$A5,$02,$3C,$20,$2D,$12,$32 ; BF84 01 A5 02 3C 20 2D 12 32 ...< -.2
+ .byte $20,$3C,$20,$4C,$08,$44,$14,$4C ; BF8C 20 3C 20 4C 08 44 14 4C < L.D.L
+ .byte $09,$40,$20,$32,$20,$40,$09,$44 ; BF94 09 40 20 32 20 40 09 44 .@ 2 @.D
+ .byte $09,$4C,$09,$5B,$09,$4C,$09,$5B ; BF9C 09 4C 09 5B 09 4C 09 5B .L.[.L.[
+ .byte $48,$00 ; BFA4 48 00 H.
+; end level tune #4, bass
+sfx11: .byte $01,$A6,$02,$79,$20,$B6,$30,$99 ; BFA6 01 A6 02 79 20 B6 30 99 ...y .0.
+ .byte $20,$88,$09,$99,$20,$E6,$30,$99 ; BFAE 20 88 09 99 20 E6 30 99 ... .0.
+ .byte $20,$88,$09,$99,$20,$B6,$3A,$00 ; BFB6 20 88 09 99 20 B6 3A 00 ... .:.
+; jumping sound
+sfx12: .byte $01,$A5,$00,$79,$04,$60,$04,$51 ; BFBE 01 A5 00 79 04 60 04 51 ...y.`.Q
+ .byte $04,$3C,$04,$51,$04,$60,$04,$79 ; BFC6 04 3C 04 51 04 60 04 79 .<.Q.`.y
+ .byte $04,$00 ; BFCE 04 00 ..
+; funeral march melody
+sfx13: .byte $01,$A5,$01,$3C,$20,$3C,$10,$3C ; BFD0 01 A5 01 3C 20 3C 10 3C ...< <.<
+ .byte $10,$3C,$20,$32,$10,$35,$10,$35 ; BFD8 10 3C 20 32 10 35 10 35 .< 2.5.5
+ .byte $10,$3C,$10,$3C,$10,$40,$10,$3C ; BFE0 10 3C 10 3C 10 40 10 3C .<.<.@.<
+ .byte $40,$00 ; BFE8 40 00 @.
+; funeral march bass
+sfx14: .byte $01,$A6,$00,$79,$10,$A2,$10,$02 ; BFEA 01 A6 00 79 10 A2 10 02 ...y....
+ .byte $ED,$BF,$06,$F3,$10,$A2,$10,$00 ; BFF2 ED BF 06 F3 10 A2 10 00 ........
+; ----------------------------------------------------------------------------
+; main entry point, note cartstart_left and cartstart_right point to the same address
+cartstart_left:
+ .addr cart_entry_point ; BFFA C0 8A ..
+; ----------------------------------------------------------------------------
+; 0 here means 'cartridge present'
+cartpresent_left:
+ .byte $00 ; BFFC 00 .
+; 4 here means init & start the cart, no disk boot, non-diagnostic
+cartoptions_left:
+ .byte $04 ; BFFD 04 .
+; ----------------------------------------------------------------------------
+; points to a CLC/RTS do-nothing routine (same as cartinit_right)
+cartinit_left:
+ .addr cart_start_stub ; BFFE FE 8A ..
diff --git a/jumpmanjr.inc b/jumpmanjr.inc
new file mode 100644
index 0000000..7341855
--- /dev/null
+++ b/jumpmanjr.inc
@@ -0,0 +1,68 @@
+; DO NOT put jumpman-specific addresses here (ROM or working RAM),
+; this is only for Atari hardware and OS equates.
+
+; HW addresses
+AUDCTL = $D208
+PMBASE = $D407
+DMACTL = $D400
+PRIOR = $D01B
+SKCTL = $D20F
+GRACTL = $D01D
+DLISTL = $D402
+DLISTH = $D403
+NMIEN = $D40E
+IRQEN = $D20E
+PORTA = $D300
+TRIG0 = $D010
+CHBASE = $D409
+WSYNC = $D40A
+COLPF2 = $D018
+HSCROL = $D404
+COLBK = $D01A
+AUDF1_minus_two = $D1FE
+AUDF1_minus_one = $D1FF
+AUDF1 = $D200
+AUDC1 = $D201
+AUDF2 = $D202
+AUDC2 = $D203
+AUDF3 = $D204
+AUDC3 = $D205
+AUDF4 = $D206
+AUDC4 = $D207
+AUDCTL = $D208
+RANDOM = $D20A
+KBCODE = $D209
+CONSOL = $D01F
+SDMCTL = $022F
+HPOSP3 = $D003
+HPOSM3 = $D007
+HPOSM2 = $D006
+HPOSM1 = $D005
+HPOSM0 = $D004
+GRAFM = $D011
+HITCLR = $D01E
+COLPF0 = $D016
+COLPF1 = $D017
+COLPF3 = $D019
+COLPM1 = $D013
+COLPM0 = $D012
+SIZEM = $D00C
+SIZEP2 = $D00A
+SIZEP3 = $D00B
+
+; OS addresses
+COLOR0 = $02C4
+COLOR1 = $02C5
+COLOR2 = $02C6
+COLOR3 = $02C7
+COLOR4 = $02C8
+PCOLR0 = $02C0
+PCOLR1 = $02C1
+PCOLR2 = $02C2
+PCOLR3 = $02C3
+GPRIOR = $026F
+CHBAS = $02F4
+VKEYBD = $0208
+VKEYBD_hi = $0209
+SETVBV = $E45C
+XITVBV = $E462
diff --git a/jumpmanjr.info b/jumpmanjr.info
new file mode 100644
index 0000000..17dfa03
--- /dev/null
+++ b/jumpmanjr.info
@@ -0,0 +1,908 @@
+### GENERATED FILE, do not edit, edit main.info and mklevelinfo.pl instead
+
+# da65 info file for jumpman junior ROM.
+
+GLOBAL {
+ OUTPUTNAME "jumpmanjr.dasm";
+ INPUTNAME "jumpmanjr.rom";
+ STARTADDR $8000;
+ CPU "6502";
+ COMMENTS 4;
+};
+
+#SEGMENT { START $8000; END $BFFF; NAME "jumpmanjr"; };
+
+ASMINC { FILE "jumpmanjr.inc"; };
+
+# RANGE { START $whatever; END $whatever; TYPE Code|ByteTable|AddrTable|RtsTable; }
+
+label { name "cart_start_stub"; addr $8AFE; };
+label { name "cart_entry_point"; addr $8ac0; };
+label { name "check_keycode"; addr $9C07; };
+label { name "store_speed_value"; addr $9C13; };
+label { name "keyboard_isr_exit"; addr $9C0F; };
+label { name "check_consol"; addr $88C8; };
+label { name "ask_num_players"; addr $9400; };
+label { name "sl_loop"; addr $96D8; };
+label { name "materialize_jumpman"; addr $977B; };
+label { name "mj_clear_loop"; addr $9782; };
+label { name "mj_set_freq_and_color"; addr $97BB; };
+label { name "mj_delay"; addr $97CD; };
+label { name "mj_done"; addr $97DB; };
+label { name "game_main_loop"; addr $9740; };
+
+label { name "copy_level_desc_2"; addr $9677; comment "copy level descriptor to $0780"; };
+label { name "randomize_level"; addr $9BED; comment "only after beating levels 1-12 in order"; };
+label { name "enter_level"; addr $96BA; comment "maybe this should be check_level or init_level?"; };
+label { name "copy_level_desc"; addr $96CE; comment "copy level descriptor from levelXX_desc at $A000+(level*$40) to $07c0-$07ff"; };
+label { name "randomizer_mode"; addr $06F3; comment "only after beating levels 1-12 in order"; };
+
+label { name "init_loop"; addr $8ac4; comment "clear pages 6 and 7"; };
+label { name "set_vkeybd"; addr $83ED; comment "VKEYBD now points to $9c00 aka keyboard_isr"; };
+label { name "set_vvblki"; addr $8401; comment "VVBLKI now points to $840d aka vblank_imm_isr"; };
+label { name "vblank_imm_isr"; addr $840d; comment "service immediate vblank interrupt"; };
+
+label { name "dli_chained_1"; addr $9B72; comment "changes DLI vector to point to dli_chained_2"; };
+label { name "dli_chained_2"; addr $9B87; comment "changes DLI vector to point to dli_chained_3"; };
+label { name "dli_chained_3"; addr $9BB1; comment "changes DLI vector to point to dli_chained_1"; };
+label { name "update_color_regs"; addr $840F; comment "update color regs from shadow regs (X ranges 1 to 9, GRAFM+1 is COLPM0, $2bf+1 is PCOLR0)"; };
+
+range { name "code_99f7"; start $99F7; end $9A1B; type code; };
+range { name "data_8406"; start $8406; end $840c; type bytetable; };
+range { name "data_9a1c"; start $9a1c; end $9A5B; type bytetable; };
+range { name "gameboard_dlist_data"; start $9B62; end $9b71; type bytetable; comment "this isn't used as-is for a display list, see setup_gameboard_dlist"; };
+RANGE { NAME "cartstart_left"; START $BFFA; END $BFFB ; TYPE AddrTable; comment "main entry point, note cartstart_left and cartstart_right point to the same address"; };
+RANGE { NAME "cartstart_right"; START $9FFA; END $9FFB ; TYPE AddrTable; comment "main entry point, note cartstart_left and cartstart_right point to the same address"; };
+RANGE { NAME "cartinit_left"; START $BFFE; END $BFFF ; TYPE AddrTable; comment "points to a CLC/RTS do-nothing routine (same as cartinit_right)"; };
+RANGE { NAME "cartinit_right"; START $9FFE; END $9FFF ; TYPE AddrTable; comment "points to a CLC/RTS do-nothing routine (same as cartinit_left)"; };
+
+range { name "cartpresent_left"; start $bffc; end $bffc; type bytetable; comment "0 here means 'cartridge present'"; };
+range { name "cartpresent_right"; start $9ffc; end $9ffc; type bytetable; comment "0 here means 'cartridge present'"; };
+range { name "cartoptions_left"; start $bffd; end $bffd; type bytetable; comment "4 here means init & start the cart, no disk boot, non-diagnostic"; };
+range { name "cartoptions_right"; start $9ffd; end $9ffd; type bytetable; comment "4 here means init & start the cart, no disk boot, non-diagnostic"; };
+
+label { name "VDSLST"; addr $0200; size 2; };
+label { name "FR1"; addr $00e0; size 6; };
+label { name "player_x_speed"; addr $95C5; size 20; comment "' PLAYER # SPEED? ' in PF2 color"; };
+label { name "num_name_hscrol_table"; addr $95D9; size 4; comment "used for centering ONE TWO THREE FOUR, see option_key_handler"; };
+label { name "number_names_0"; addr $95dd; size 4; comment "space space T space (names ONE TWO THREE FOUR)"; };
+label { name "number_names_1"; addr $95e1; size 4; comment "O T H F"; };
+label { name "number_names_2"; addr $95e5; size 4; comment "N W R O"; };
+label { name "number_names_3"; addr $95e9; size 4; comment "E O E U"; };
+label { name "number_names_4"; addr $95ed; size 4; comment "space space E R"; };
+label { name "sfx_select_key"; addr $95f1; comment "played when select key pressed, 4 notes, descending"; };
+label { name "missiles_mask_table_minus_one"; addr $82df; };
+label { name "set_dma_ctl"; addr $838F; comment "std playfield, enable players + missiles, single-line p/m res, DMA enabled"; };
+
+range { name "level_names"; start $BB00; end $bbef; type bytetable; };
+range { name "pm_memory"; start $2800; end $2fff; type bytetable; };
+range { name "missiles_mask_table"; start $82e0; end $82E7; type bytetable; };
+range { name "missiles_done"; start $82DD; end $82df; type code; };
+range { name "position_missiles"; start $8293; end $82DA; type code; };
+range { name "charset"; start $9e00; end $9ff9; type bytetable; comment "GR.1/2 font, 512 bytes"; };
+range { name "game_display_list"; start $0881; end $08e3; type bytetable; comment "display list for game board"; };
+range { name "title_display_list"; start $91B3; end $91ce; type bytetable; comment "display list for title screen"; };
+range { name "numplayer_display_list"; start $955f; end $9577; type bytetable; comment "display list for 'number of players' screen"; };
+label { name "setup_numplayer_dlist"; addr $9444; comment "set dlist shadow to point to numplayer_display_list"; };
+label { name "setup_numplayer_dli_sr"; addr $944e; comment "set dli vector to point to num_player_dli_service"; };
+label { name "anp_loop_done"; addr $9421; comment "X is now 0"; };
+label { name "anp_clear_loop"; addr $940D; comment "clear area where NUMBER OF PLAYERS? will be displayed"; };
+label { name "anp_copy_loop"; addr $9418; comment "copy NUMBER OF PLAYERS to screen RAM"; };
+label { name "save_collisions"; addr $8503; comment "save contents of GTIA collision regs (X ranges 1 to $10, dli_vec_shadow_hi should read collision_save-1)"; };
+
+label { name "check_collisions_1"; addr $8F73; size 1; comment "did any missile hit a player, or did players 2 or 3 hit a player..."; };
+label { name "check_collisions_2"; addr $981A; size 1; comment "did player 0 or 1 hit the playfield..."; };
+label { name "check_collisions_3"; addr $9832; size 1; comment "did player 0 or 1 hit the playfield..."; };
+label { name "collision_save"; addr $06B0; size 16; comment "save_collisions copies GTIA collision regs $D000-$d00f here"; };
+label { name "init_next_level"; addr $9BE8; size 1; comment "..."; };
+label { name "show_get_ready_prompt"; addr $9624; size 1; comment "only in multiplayer games"; };
+range { name "gr7_or_masks"; start $8143; end $8152; type bytetable; };
+range { name "gr7_and_masks"; start $8153; end $8156; type bytetable; };
+range { name "data_8892"; start $8892; end $88A7; type bytetable; };
+range { name "data_8dfa"; start $8DFA; end $8DFF; type bytetable; };
+range { name "data_8f43"; start $8F43; end $8f72; type bytetable; };
+
+##range { name "mus0_addr1"; start $8FC3; end $8fc4; type addrtable; comment "mus struct table, 5 bytes per entry: 0/1 are an address, 2/3 are another, 5 is maybe the length? tempo?"; };
+##range { name "mus0_addr2"; start $8FC5; end $8fc6; type addrtable; };
+##range { name "mus0_len_or_tempo"; start $8FC7; end $8fc7; type bytetable; };
+##
+##range { name "mus1_addr1"; start $8FC8; end $8fc9; type addrtable; };
+##range { name "mus1_addr2"; start $8FCA; end $8fcb; type addrtable; };
+##range { name "mus1_len_or_tempo"; start $8FCC; end $8fcc; type bytetable; };
+##
+##range { name "mus2_addr1"; start $8FC8; end $8fc9; type addrtable; };
+##range { name "mus2_addr2"; start $8FCA; end $8fcb; type addrtable; };
+##range { name "mus2_len_or_tempo"; start $8FCC; end $8fcc; type bytetable; };
+
+#range { name "more_mus"; start $8FC8; end $8fff; type bytetable; comment "more 5-byte structs"; };
+
+range { name "mus00_addr1"; start $8fc3; end $8fc4; type addrtable; comment "aka mus_struct_table, 5 bytes per entry"; };
+range { name "mus00_addr2"; start $8fc5; end $8fc6; type addrtable; };
+range { name "mus00_len_or_tempo"; start $8fc7; end $8fc7; type bytetable; };
+
+range { name "mus01_addr1"; start $8fc8; end $8fc9; type addrtable; };
+range { name "mus01_addr2"; start $8fca; end $8fcb; type addrtable; };
+range { name "mus01_len_or_tempo"; start $8fcc; end $8fcc; type bytetable; };
+
+range { name "mus02_addr1"; start $8fcd; end $8fce; type addrtable; comment "end of game tune"; };
+range { name "mus02_addr2"; start $8fcf; end $8fd0; type addrtable; };
+range { name "mus02_len_or_tempo"; start $8fd1; end $8fd1; type bytetable; };
+
+range { name "mus03_addr1"; start $8fd2; end $8fd3; type addrtable; };
+range { name "mus03_addr2"; start $8fd4; end $8fd5; type addrtable; };
+range { name "mus03_len_or_tempo"; start $8fd6; end $8fd6; type bytetable; };
+
+range { name "mus04_addr1"; start $8fd7; end $8fd8; type addrtable; };
+range { name "mus04_addr2"; start $8fd9; end $8fda; type addrtable; };
+range { name "mus04_len_or_tempo"; start $8fdb; end $8fdb; type bytetable; };
+
+range { name "mus05_addr1"; start $8fdc; end $8fdd; type addrtable; };
+range { name "mus05_addr2"; start $8fde; end $8fdf; type addrtable; };
+range { name "mus05_len_or_tempo"; start $8fe0; end $8fe0; type bytetable; };
+
+range { name "mus06_addr1"; start $8fe1; end $8fe2; type addrtable; };
+range { name "mus06_addr2"; start $8fe3; end $8fe4; type addrtable; };
+range { name "mus06_len_or_tempo"; start $8fe5; end $8fe5; type bytetable; };
+
+range { name "mus07_addr1"; start $8fe6; end $8fe7; type addrtable; };
+range { name "mus07_addr2"; start $8fe8; end $8fe9; type addrtable; };
+range { name "mus07_len_or_tempo"; start $8fea; end $8fea; type bytetable; };
+
+range { name "mus08_addr1"; start $8feb; end $8fec; type addrtable; comment "tune that plays while level is being drawn"; };
+range { name "mus08_addr2"; start $8fed; end $8fee; type addrtable; };
+range { name "mus08_len_or_tempo"; start $8fef; end $8fef; type bytetable; };
+
+range { name "mus09_addr1"; start $8ff0; end $8ff1; type addrtable; };
+range { name "mus09_addr2"; start $8ff2; end $8ff3; type addrtable; };
+range { name "mus09_len_or_tempo"; start $8ff4; end $8ff4; type bytetable; };
+
+range { name "mus10_addr1"; start $8ff5; end $8ff6; type addrtable; };
+range { name "mus10_addr2"; start $8ff7; end $8ff8; type addrtable; };
+range { name "mus10_len_or_tempo"; start $8ff9; end $8ff9; type bytetable; };
+
+range { name "mus11_addr1"; start $8ffa; end $8ffb; type addrtable; };
+range { name "mus11_addr2"; start $8ffc; end $8ffd; type addrtable; };
+range { name "mus11_len_or_tempo"; start $8ffe; end $8ffe; type bytetable; };
+
+range { name "empty_music_entry"; start $8fff; end $8fff; type bytetable; comment "empty music table entries point here"; };
+
+label { name "sfx_tempo_tmp"; addr $0661; comment "??"; };
+label { name "sfx_slot_curpos"; addr $064E; size 2; comment "address we've got to so far, playing this sfx"; };
+label { name "sfx_slot_tempo"; addr $063E; size 1; comment "tempo of this sfx"; };
+label { name "sfx_lock"; addr $062F; size 1; comment "lets other code know cue_sfx is still running? not 100% sure"; };
+label { name "inc_sfx_pos"; addr $8231; size 1; comment "point to next byte in current sfx slot indexed by X"; };
+label { name "sfx_finished"; addr $8226; size 1; comment "done playing this sfx, free up the slot, X-indexed"; };
+label { name "sfx_next_note"; addr $817D; size 1; };
+label { name "sfx_player_entry"; addr $8157; size 1; comment "we have 4 slots (because POKEY has 4 voices), X counts down by 2 from 10 to 2 (at 0, the loop exits)"; };
+label { name "next_sfx_slot"; addr $815F; size 1; };
+label { name "sfx_exit"; addr $815E; size 1; };
+label { name "is_slot_active"; addr $8163; size 1; comment "skip it, if slot is inactive"; };
+label { name "sfx_slot_timer"; addr $063F; size 1; };
+label { name "sfx_slot_duration"; addr $0646; size 1; };
+label { name "sfx_play_note"; addr $8206; size 1; comment "y==0, a>=4 on entry"; };
+label { name "sfx_play_rest"; addr $819E; size 1; comment "y==0 on entry"; };
+label { name "sfx_change_tempo"; addr $81AE; size 1; comment "y==0 on entry"; };
+label { name "sfx_jump"; addr $81C8; size 1; comment "I *think* this jumps to a different sfx address..."; };
+label { name "sfx_slot_freq"; addr $0647; size 1; };
+
+range { name "sfx00"; start $BDF2; end $BE24; type bytetable; };
+range { name "sfx01"; start $BE25; end $BE78; type bytetable; };
+range { name "sfx_extra_life"; start $BE79; end $BE8C; type bytetable; };
+range { name "sfx02"; start $BE8D; end $BEAE; type bytetable; comment "end of game tune, melody"; };
+range { name "sfx03"; start $BEAF; end $BED4; type bytetable; comment "end of game tune, bass"; };
+range { name "sfx04"; start $BED5; end $BEEC; type bytetable; comment "end level tune #1, bass"; };
+range { name "sfx05"; start $BEED; end $BF13; type bytetable; comment "end level tune #1, melody"; };
+range { name "sfx06"; start $BF14; end $BF2F; type bytetable; comment "end level tune #2, melody"; };
+range { name "sfx07"; start $BF30; end $BF49; type bytetable; comment "end level tune #2, bass"; };
+range { name "sfx08"; start $BF4A; end $BF5F; type bytetable; comment "end level tune #3, bass"; };
+range { name "sfx09"; start $BF60; end $BF83; type bytetable; comment "end level tune #3, melody"; };
+range { name "sfx10"; start $BF84; end $BFA5; type bytetable; comment "end level tune #4, melody"; };
+range { name "sfx11"; start $BFA6; end $BFBD; type bytetable; comment "end level tune #4, bass"; };
+range { name "sfx12"; start $BFBE; end $BFCF; type bytetable; comment "jumping sound"; };
+range { name "sfx13"; start $BFD0; end $BFE9; type bytetable; comment "funeral march melody"; };
+range { name "sfx14"; start $BFEA; end $BFF9; type bytetable; comment "funeral march bass"; };
+range { name "sfx15"; start $BABC; end $BAE9; type bytetable; comment "level intro music, melody"; };
+range { name "sfx16"; start $BAEA; end $BAFF; type bytetable; comment "level intro music, bass"; };
+
+range { name "code_8f38"; start $8F38; end $8F42; type code; };
+range { name "try_to_write_rom_again"; start $9126; end $9133; type code; comment "see comment at try_to_write_rom"; };
+range { name "code_adb5"; start $ADB5; end $adc0; type code; };
+range { name "code_adc1"; start $adc1; end $adc3; type code; };
+range { name "data_9134"; start $9134; end $9139; type bytetable; };
+label { name "maybe_data"; addr $913A; comment "this might be more data for the above table instead of code?"; };
+label { name "probly_code"; addr $913D; comment "this probably really is code"; };
+label { name "illegal_nop"; addr $AF1B; comment "NMOS 6502 illegal opcode, NOP zp"; };
+range { name "data_9afc"; start $9AFC; end $9aff; type bytetable; };
+range { name "num_player_dli_service"; start $9578; end $959a; type code; comment "DLI service routine, changes COLPF2, address gets stored in $6ae/$6af by code at $944e"; };
+range { name "dli_service_2"; start $bdc7; end $bdd1; type code; comment "DLI service routine, changes COLBK, address gets stored in $6ae/$6af by code at $bc3c"; };
+label { name "numplayer_screen_data_minus_one"; addr $959a; comment "1-indexed loop copies from here+1"; };
+range { name "numplayer_screen_data"; start $959b; end $95ff; type bytetable; comment "'number of players?', gets copied to $3800, see option_key_handler"; };
+range { name "sfx_add_life_bonus"; start $b896; end $b8a6; type bytetable; comment "played when adding bonus per life at end of level"; };
+range { name "mul_25_table"; start $b8a7; end $b8be; type wordtable; comment "multiply by 25"; };
+range { name "data_table_8a39"; start $8a39; end $8a7f; type bytetable; };
+range { name "data_table_86da"; start $86da; end $8713; type bytetable; };
+range { name "level_name_hscrol_table"; start $BBF0; end $BBff; type bytetable; comment "used for centering level name on gameboard"; };
+range { name "zero_filler_b8bf"; start $b8bf; end $b96a; type bytetable; comment "all zeroes, filler?"; };
+range { name "zero_filler_baab"; start $baab; end $babb; type bytetable; comment "filler?"; };
+range { name "code_bccd"; start $bccd; end $bcd8; type code; comment "dunno, but referenced by code at $BC6A"; };
+range { name "well_done_map"; start $bcd9; end $bd51; type bytetable; comment "level map used for the WELL DONE screen, when you beat level 12"; };
+range { name "well_done_shape"; start $bda0; end $bdc6; type bytetable; comment "used to draw the large WELL DONE banner"; };
+range { name "total_score_msg"; start $bdd2; end $bdf1; type bytetable; comment "not sure what displays this, but it's screen codes"; };
+range { name "zero_filler_8588"; start $B588; end $B696; type bytetable; };
+range { name "wind_table_1"; start $B76B; end $b7bf; type bytetable; comment "used in level11"; };
+label { name "wind_table_2"; addr $b771; };
+range { name "level00_map"; start $A300; end $a497; type bytetable; comment "level map data starts here"; };
+range { name "sfx_a52d"; start $A52D; end $A53C; type bytetable; comment "dunno, referenced by routine at $A50F"; };
+range { name "data_table_a542"; start $A542; end $A68B; type bytetable; comment "dunno, referenced by routine at $A498"; };
+range { name "dumbwaiter_player"; start $a782; end $A826; type bytetable; comment "the dumbwaiters from level02. stored upside-down."; };
+label { name "dw_platform_player"; addr $A685; comment "horizontally moving platforms from level02"; };
+range { name "data_table_a8fd"; start $a8fd; end $A9C6; type bytetable; comment "dunno, referenced by routine at $A8D4"; };
+range { name "map_aa90"; start $aa90; end $AD67; type bytetable; comment "dunno what this is for yet"; };
+label { name "map_aaa6"; addr $aaa6; comment "referenced by routine at $AA82"; };
+range { name "data_table_adc7"; start $adc7; end $af0c; type bytetable; comment "dunno, referenced by routines at $AD9E and $ADB5"; };
+range { name "sfx_afcb"; start $AFCB; end $b0c3; type bytetable; comment "referenced by routine at $AF96"; };
+label { name "map_b000"; addr $b000; comment "referenced by routine at $B0C4"; };
+range { name "data_table_85b6"; start $85b6; end $85bd; type bytetable; comment "used in vblank_imm_isr, not sure for what yet"; };
+range { name "data_table_85de"; start $85de; end $85f5; type bytetable; comment "dunno what this is for yet, but it's copied into page 6 by init_hardware"; };
+range { name "zero_filler_85f6"; start $85f6; end $85ff; type bytetable; comment "probably just filler"; };
+range { name "movement_direction_table"; start $85be; end $85dd; type wordtable; comment "X/Y movement, indexed by joystick_state << 1, each entry is XXYY, $FF is -1"; };
+range { name "get_ready_msg"; start $9714; end $9726; type bytetable; comment "PLAYER GET READY"; };
+range { name "pcolor0_table"; start $8B7B; end $8b7f; type bytetable; };
+range { name "color0_table"; start $9728; end $972b; type bytetable; };
+range { name "color0_table_minus_one"; start $9727; end $9727; type bytetable; };
+range { name "level_gfx"; start $9C21; end $9cff; type bytetable; comment "definitions for level graphics objects aka shapes. (girder segment, ladder, rope, etc)"; };
+label { name "sh_girder"; addr $9C33; comment "3 rows of pixels. 1st: 04 = 4 pixels wide, 00 00 = no X/Y offset, 01 01 01 01 = actual pixel data (4 color0 pixels). see level_maps.txt"; };
+label { name "sh_blank_4x4"; addr $9C49; };
+label { name "sh_ladder"; addr $9C5F; };
+label { name "sh_9c89"; addr $9c89; comment "dunno what this is yet"; };
+label { name "sh_bomb"; addr $9cb3; };
+label { name "sh_up_rope"; addr $9cc9; };
+label { name "sh_down_rope"; addr $9cda; };
+label { name "sh_9ceb"; addr $9ceb; comment "dunno what this is yet"; };
+range { name "sprite_table"; start $9d00; end $9dff; type bytetable; comment "jumpman's animation frames and other sprites, seem to be 10 bytes per sprite"; };
+range { name "sxf_b319"; start $b319; end $B44B; type bytetable; comment "referenced by routine at $B2FD"; };
+range { name "data_table_b1df"; start $b1df; end $B27d; type bytetable; comment "dunno what this is for yet"; };
+range { name "data_table_b2a8"; start $b2a8; end $B2df; type bytetable; comment "dunno what this is for yet"; };
+range { name "data_table_b50b"; start $b50b; end $B57b; type bytetable; comment "dunno what this is for yet"; };
+range { name "scores_screen_dlist"; start $8C52; end $8C67; type bytetable; comment "a GR.2-ish DL, with DLIs, screen mem at $3000, for player scores screen"; };
+label { name "reyalp_msg_minus_one"; addr $8c67; };
+label { name "show_reyalp_msg"; addr $8BC0; comment "shows PLAYER (backwards loop)"; };
+label { name "reyalp_msg_loop"; addr $8BC2; };
+label { name "check_10th"; addr $8BC8; comment "replace 10th char with the ASCII player number"; };
+label { name "continue_loop"; addr $8BD5; };
+label { name "check_alive"; addr $8BE9; comment "player still has lives left?"; };
+label { name "no_cross"; addr $8BEF; };
+label { name "what_are_we_waiting_for"; addr $8C39; comment "I *think* we're waiting for the music to finish playing..."; };
+
+label { name "jiffy_timer_1"; addr $061A; comment "gets incremented every frame"; };
+label { name "jiffy_timer_2"; addr $061B; comment "gets incremented every frame"; };
+label { name "bonus_jiffy_timer"; addr $0626; comment "gets incremented every frame when playing a level, bonus-=100 when this reaches 0"; };
+label { name "speed_jiffy_timer"; addr $061E; comment "counts 0..initial_speed"; };
+label { name "playing_level"; addr $0627; comment "0 = not playing, non-0 = playing"; };
+label { name "no_dec_bonus"; addr $848B; };
+label { name "add_time_bonus"; addr $8E0F; comment "score += time_bonus;"; };
+label { name "lt_64k"; addr $8E27; };
+label { name "wait_32_jiffies"; addr $8E3A; comment "533ms ntsc, 640ms pal"; };
+label { name "pick_random_music"; addr $8E41; comment "pick random sound effect between 4 and 7"; };
+label { name "cue_music"; addr $8F92; comment "setup to play whichever music is in A reg, using 5-byte sfx stuct (a music is a pair of sfx played simultaneously)"; };
+label { name "cue_music_jv"; addr $8018; comment "setup to play whichever music is in A reg, using 5-byte sfx stuct"; };
+label { name "cue_sfx_jv"; addr $8006; comment "setup to play sfx"; };
+label { name "cue_sfx"; addr $8255; comment "setup to play sfx at *sfx_ptr, tempo (?) A"; };
+label { name "cue_sfx_lowprior"; addr $8240; comment "if cue_sfx not already in progress, setup to play sfx at (sfx_slot_tempo, sfx_lock) tempo (?) A"; };
+label { name "sfx_ptr"; addr $063C; size 2; };
+label { name "cue_ok"; addr $8244; size 1; };
+label { name "cue_done"; addr $8278; size 1; };
+label { name "inc_done"; addr $823F; size 1; };
+
+label { name "wait_3_sec"; addr $8C4A; comment "wait 192 jiffies: 3.2 sec (ntsc), 3.84 sec (pal)"; };
+label { name "not_alive"; addr $8BEB; comment "no, show a cross instead of a space"; };
+label { name "store_space"; addr $8BE2; comment "$AF is the character to show after the score (space for alive, cross for dead)"; };
+range { name "reyalp_msg"; start $8C68; end $8C7a; type bytetable; comment "player spelled backwards: ' 0 # REYALP '"; };
+range { name "scores_msg"; start $8C7b; end $8C81; type bytetable; comment "' SCORES' in color 3"; };
+range { name "blank_dlist_8add"; start $8ADD; end $8adf; type bytetable; comment "yet another jump-to-itself empty display list"; };
+range { name "blank_dlist_8aeb"; start $8AEB; end $8aed; type bytetable; comment "another jump-to-itself empty display list"; };
+range { name "blank_dlist_8c82"; start $8C82; end $8C84; type bytetable; comment "looks like an empty jump-to-itself dlist"; };
+label { name "init_game"; addr $9000; comment "called from cart_entry_point routine"; };
+label { name "reinit_game"; addr $900C; comment "this entry point doesn't disable start/option keys"; };
+label { name "try_to_write_rom"; addr $9022; comment "seems to try to write $FF bytes to ROM that already contains $FF's (it's the solid block character in the font). possibly left over from early development before conversion to cartridge"; };
+label { name "setup_select_key_vec"; addr $901b; comment "set select key vector to ask_num_players at $9400, enable select key"; };
+label { name "setup_select_key_vec_again"; addr $9517; comment "set select key vector to ask_num_players at $9400, enable select key"; };
+label { name "disable_start_opt"; addr $94EC; comment "disable start and option keys"; };
+label { name "init_speed"; addr $952a; comment "initialize speed to -1"; };
+label { name "wait_for_speed"; addr $952F; comment "wait for keyboard IRQ handler to set a speed <= 8"; };
+label { name "speed_to_ascii"; addr $9540; comment "convert to ASCII digit"; };
+label { name "add_11_to_x"; addr $953B; comment "11-byte per-player struct?"; };
+label { name "struct_player_lives_offsets_minus_one"; addr $8C88; };
+label { name "struct_player_lives_offsets"; addr $8C89; comment "lookup table, offset from $713 to lives for indexed player"; };
+label { name "show_scores_screen"; addr $8C22; comment "set dlist shadow to scores_screen_dlist"; };
+label { name "display_speed"; addr $9542; comment "show it to the user"; };
+label { name "speed_value"; addr $06F9; comment "decoded speed (1-8)"; };
+label { name "show_player_speed_prompt"; addr $94F9; comment "copy PLAYER #n SPEED? to screen RAM"; };
+label { name "psprompt_loop"; addr $94fb; };
+range { name "get_ready_dlist"; start $972c; end $973f; type bytetable; comment "112 blank scanlines, then one GR.2 line, loaded from $0742"; };
+range { name "score_offsets"; start $8C85; end $8c8c; type bytetable; comment "offsets into screen memory, column 12, rows 2 3 4 5, used by code at $8BEF, loaded in $d3, hi byte in $d4 is $30"; };
+label { name "score_screen_dli_sr"; addr $8C8D; comment "used by score screen"; };
+label { name "set_score_screen_dli"; addr $8C31; comment "dli = score_screen_dli_sr"; };
+range { name "title_screen_data"; start $91cf; end $93ff; type bytetable; comment "title screen data"; };
+
+label { name "title_screen_data_minus_one"; addr $91ce; };
+label { name "copy_title_screen"; addr $902A; };
+label { name "wait_until_9c_is_0e"; addr $906E; comment "some ISR is writing to $9c..."; };
+label { name "funky_init_loop"; addr $90C8; comment "lot going on here, not understood yet"; };
+label { name "player_scores_screen"; addr $8B80; comment "show scores, called at end of game, also called after beating level 12 (after WELL DONE). $40 in NMIEN = disable DLI, enable VBI"; };
+label { name "read_joystick"; addr $84AC; comment "always joystick #1 (all players use the same joystick and pass it around)"; };
+label { name "check_joystick_enabled"; addr $84A4; comment "read the joystick if not disabled"; };
+label { name "fake_read_trigger"; addr $84CD; comment "??"; };
+label { name "read_trigger"; addr $84D3; comment "always joystick #1"; };
+label { name "store_joystick_state"; addr $84B1; comment "store bottom 4 bits of PORTA, or 0 if joystick_disabled"; };
+label { name "clear_collisions"; addr $850D; };
+label { name "update_dlist"; addr $8510; comment "update display list, if there's a new one in the shadow reg"; };
+label { name "update_dli_vector"; addr $8523; comment "update DLI vector, if there's a new one in the shadow reg"; };
+label { name "setup_get_ready_dl"; addr $964A; comment "06ac/06ad gets address of get_ready_dlist (why not SDLSTL/H?)"; };
+label { name "end_of_level_bonus"; addr $B800; };
+label { name "keycode_table_minus_one"; addr $9c18; };
+range { name "keyboard_isr"; start $9C00; end $9c18; type code; comment "only use of keyboard is to enter player speed before starting game"; };
+range { name "keycode_table"; start $9C19; end $9c20; type bytetable; };
+#label { name "mul_25_table"; addr $B8A7; size 2; };
+
+label { name "init_hardware"; addr $837c; };
+label { name "init_page6_loop"; addr $837e; comment "movement_direction_table+31 should read data_table_85de-1, da65 isn't perfect yet"; };
+
+# these are so far only for player 1
+label { name "number_of_players"; addr $06f4; size 1; comment "0 for single-player game, otherwise range 1-3 (2 to 4 players)"; };
+label { name "score"; addr $0700; size 3; };
+label { name "level"; addr $06f6; size 1; };
+label { name "lives"; addr $070a; size 1; };
+label { name "current_player"; addr $06fe; size 1; comment "*think* this ranges 1-4, not 0-3"; };
+label { name "player_speed"; addr $0624; size 1; };
+label { name "initial_speed"; addr $0625; size 1; };
+label { name "setup_dli_2"; addr $bc3f; size 1; comment "load dli_service_2 address into dli shadow"; };
+label { name "silence_audio"; addr $875B; size 1; comment "set all AUDFx to 0"; };
+label { name "sa_loop"; addr $875F; size 1; };
+label { name "store_audc"; addr $8DC6; size 1; comment "store A to AUDCx (and its ?shadow?)"; };
+label { name "set_prior"; addr $8798; size 1; comment "priority $11: pl0-3, pf0-3, bak (and enable 5th player from the missiles) [redundant? init_set_prior sets this, nothing appears to change it]"; };
+label { name "SAVMSC"; addr $58; size 2; comment "OS's idea of the start of screen memory [redundant to set here?]"; };
+label { name "set_char_base"; addr $83BB; size 1; comment "use character set at $9e00 aka charset"; };
+label { name "set_savmsc"; addr $83E9; size 1; comment "tell OS that screen memory starts at $3000"; };
+label { name "position_player_5"; addr $8310; size 1; comment "position the 4 missiles side-by-side"; };
+label { name "init_set_prior"; addr $8399; size 1; comment "priority $11: pl0-3, pf0-3, bak (and enable 5th player from the missiles)"; };
+label { name "joystick_disabled"; addr $0632; size 1; comment "nonzero = jumpman can't move (title screen or materialization, etc)"; };
+label { name "joystick_state"; addr $0633; size 1; comment "last PORTA read (bottom 4 bits), or 0 if joystick_disabled"; };
+label { name "trigger_disabled"; addr $0634; size 1; comment "nonzero = jumpman can't jump (he's already jumping, or title screen or materialization, etc)"; };
+label { name "trigger_state"; addr $0635; size 1; comment "last TRIG0 read (0 = pressed)"; };
+label { name "check_trigger_state"; addr $984D; size 1; comment "did user press the trigger?"; };
+label { name "trig_jmp"; addr $9852; size 1; comment "yes, jump to handler"; };
+label { name "check_up_down"; addr $9855; size 1; comment "did user move joystick up/down?"; };
+label { name "check_up_down_2"; addr $993B; size 1; comment "did user move joystick up/down?"; };
+label { name "trigger_handler"; addr $9985; size 1; comment "handle trigger presses (maybe start a jump)"; };
+label { name "cud_jmp"; addr $9860; size 1; comment "no, jump over handler"; };
+label { name "player_delta_x"; addr $0630; size 1; comment "amount to move jumpman this frame (1 or $FF aka -1)"; };
+label { name "player_delta_y"; addr $0631; size 1; comment "amount to move jumpman this frame (1 or $FF aka -1)"; };
+label { name "dli_vec_shadow_hi"; addr $06AF; size 1; comment "stored in VDSLST if nonzero"; };
+label { name "dli_vec_shadow_lo"; addr $06ae; size 1; comment "stored in VDSLST if dli_vec_shadow_hi nonzero"; };
+label { name "dlist_shadow_hi"; addr $06AD; size 1; comment "stored in DLISTH if nonzero"; };
+label { name "dlist_shadow_lo"; addr $06ac; size 1; comment "stored in DLISTL if dlist_shadow_hi nonzero"; };
+label { name "clear_dlist_shadow"; addr $851E; size 1; comment "clear the shadow now that we've updated the HW"; };
+label { name "clear_dli_shadow"; addr $8531; size 1; comment "clear the shadow now that we've updated the HW"; };
+label { name "enable_dli"; addr $8536; size 1; comment "enable DLI now that we've set up the vector"; };
+label { name "enable_keyboard_irq"; addr $8554; size 1; comment "$C0 = regular keypress, break keypress"; };
+label { name "silence_console_speaker"; addr $855A; size 1; comment "8 = silent (0 would be a click)"; };
+label { name "check_start_key"; addr $8561; size 1; comment "carry set = not pressed, clear = pressed"; };
+label { name "check_select_key"; addr $8573; size 1; comment "carry set = not pressed, clear = pressed"; };
+label { name "check_option_key"; addr $8580; size 1; comment "carry set = not pressed, clear = pressed"; };
+label { name "setup_start_key_vec"; addr $9465; size 1; comment "we'll jump to $94de aka get_player_speeds when start key is pressed"; };
+label { name "get_player_speeds"; addr $94de; size 1; comment "loop up to 4 times, ask PLAYER #n SPEED? and wait for number key press"; };
+label { name "setup_option_key_vec"; addr $9458; size 1; comment "we'll jump to $9489 aka option_key_handler when option key is pressed"; };
+label { name "start_key_vec"; addr $06c4; size 2; comment "vblank_imm_isr jumps thru here if start key pressed"; };
+label { name "select_key_vec"; addr $06c2; size 2; comment "vblank_imm_isr jumps thru here if select key pressed"; };
+label { name "option_key_vec"; addr $06c0; size 2; comment "vblank_imm_isr jumps thru here if option key pressed"; };
+label { name "start_key_enabled"; addr $06C8; size 1; comment "non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)"; };
+label { name "select_key_enabled"; addr $06C7; size 1; comment "non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)"; };
+label { name "option_key_enabled"; addr $06C6; size 1; comment "non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)"; };
+label { name "zp_temp1"; addr $cb; size 2; comment "used for (zp,y) addressing, also for checking console keys in vblank_imm_isr"; };
+label { name "hang_main_thread"; addr $9486; size 1; comment "initialization done, everything's done in interrupts from here on out"; };
+label { name "option_key_handler"; addr $9489; size 1; comment "called via option_key_vec when someone presses option"; };
+
+label { name "level_finished"; addr $8E00; size 1; };
+label { name "level_finished_jv"; addr $802D; size 1; };
+label { name "decrement_time_bonus"; addr $8DCE; size 1; comment "bonus -= 100;"; };
+label { name "decrement_time_bonus_jv"; addr $8021; size 1; comment "bonus -= 100;"; };
+label { name "check_bonus_0"; addr $8DD7; size 1; comment "don't decrement if bonus == 0"; };
+label { name "dec_done"; addr $8DF9; size 1; };
+label { name "bonus_lt_256"; addr $8DE7; size 1; };
+
+label { name "set_y"; addr $8F9B; size 1; comment "y = a * 5; // offset into mus_struct_table"; };
+
+
+label { name "show_level_name"; addr $BA5D; size 1; comment "copy level name into screen RAM"; };
+label { name "sync_to_music"; addr $BA71; size 1; comment "level is already drawn with all color regs set to black. for each color reg, wait 1 sec before turning it visible. this syncs up with the music because the music was written to sync with this actually"; };
+label { name "wait_1_sec"; addr $BA9E; size 1; comment "actually 64 jiffies, 1.067S ntsc, 1.28s pal"; };
+label { name "keep_waiting"; addr $BAA3; size 1; };
+label { name "enable_joystick"; addr $8775; size 1; comment "called after level-intro music is finished playing"; };
+label { name "enable_joystick_jv"; addr $801B; size 1; comment "called after level-intro music is finished playing"; };
+label { name "ej_loop"; addr $8777; size 1; };
+label { name "hide_player"; addr $8DB8; size 1; comment "move player selected by X reg minus one off the left edge of the screen"; };
+label { name "play_select_key_sfx"; addr $946F; size 1; comment "play sfx_select_key at $95f1"; };
+label { name "wait_sfx"; addr $947C; size 1; comment "wait for sound to finish playing"; };
+label { name "play_life_bonus_sfx"; addr $B868; size 1; comment "play once per life"; };
+label { name "add_life_bonus"; addr $B83B; size 1; };
+label { name "sfx_option_pressed"; addr $8ab0; size 1; };
+label { name "play_opt_key_sfx"; addr $94BC; size 1; };
+label { name "wait_opt_key_sfx"; addr $94CE; size 1; comment "wait until it's done playing"; };
+range { name "map_b11a"; start $B11A; end $b120; type bytetable; comment "dunno what this is for yet"; };
+label { name "block_char_minus_one"; addr $9e0f; size 1; comment "couple of places in the code try to write here"; };
+label { name "position_players"; addr $82E9; size 1; comment "X counts down 5..1 (starts at 6, immediately decremented, and loop is done with 0). zp_temp1 is ZP pointer to the current player or missile being written to ($2f00..$2b00, or p3/p2/p1/p0/missiles)."; };
+label { name "HPOSP0_minus_two"; addr $CFFE; size 1; };
+label { name "position_pm_vert"; addr $8322; size 1; };
+label { name "clear_pm"; addr $8342; size 1; comment "write zeroes to unused portion of this player/missile"; };
+label { name "position_done"; addr $82E8; size 1; };
+label { name "clear_pm_mem"; addr $872A; size 1; comment "clear P/M mem"; };
+label { name "clear_screen_mem"; addr $8714; size 1; comment "clear the gameboard screen memory (called before drawing a level, natch)"; };
+label { name "clear_screen_mem_jv"; addr $801E; size 1; comment "clear the gameboard screen memory (called before drawing a level, natch)"; };
+label { name "csm_loop"; addr $871F; size 1; };
+label { name "dm_obj_to_screen"; addr $80BD; size 1; comment "actually write the object's pixels to screen memory. quite hairy."; };
+label { name "unused_vecs"; addr $803F; size 1; comment "3 unused jump vectors, all pointed to the same RTS"; };
+label { name "unused_vec_rts"; addr $8048; size 1; comment "unused jump vectors point here"; };
+label { name "sfx_bounce_1"; addr $8A4B; size 1; comment "used when jumpman is falling?"; };
+range { name "sfx_bounce_2"; start $8a97; end $8abf; type bytetable; comment "used when jumpman is falling?"; };
+label { name "sfx_death"; addr $8a60; comment "jumpman hit by bullet or started falling"; };
+label { name "play_sfx_bounce_2"; addr $8A80; };
+label { name "play_sfx_bounce_1"; addr $899A; };
+label { name "falling_bounce"; addr $8983; comment "this looks like it hurts..."; };
+label { name "afterlife"; addr $9600; comment "multiple code paths jump here. replay level, load next level, or go back to ask_num_players"; };
+label { name "code_bd52"; addr $BD52; comment "referenced by code at $BC83"; };
+label { name "crumble_gameboard"; addr $8D00; comment "just lost your last life"; };
+label { name "crumble_gameboard_jv"; addr $8030; comment "just lost your last life"; };
+label { name "init_page_7"; addr $9A5C; };
+label { name "init_page_7_jv"; addr $8024; };
+range { name "data_9a71"; start $9A71; end $9a7b; type bytetable; comment "used by code above"; };
+range { name "l_equals"; start $8CFD; end $8CFF; type bytetable; comment "L= (for lives display)"; };
+label { name "add_extra_life"; addr $8CE4; comment "plays sfx_extra_life"; };
+label { name "show_l_equals"; addr $8CCE; comment "L= (for lives display)"; };
+label { name "show_lives_icons"; addr $86BB; comment "up to 6 jumpmen, and a + if lives > 6. char $C1 = jumpman icon, $CB = plus sign"; };
+label { name "show_current_player"; addr $86A7; comment "1 to 4"; };
+label { name "update_status_window"; addr $8694; comment "bottom 2 GR.1 lines on the game board"; };
+label { name "update_status_window_jv"; addr $8012; comment "bottom 2 GR.1 lines on the game board"; };
+label { name "setup_gameboard_dlist"; addr $9B00; comment "for some reason there are 2 copies of the display list, at $0800 and $0881"; };
+label { name "setup_gameboard_dlist_jv"; addr $8015; comment "for some reason there are 2 copies of the display list, at $0800 and $0881"; };
+label { name "xxx_level_something"; addr $8600; comment "gets called after the level is drawn & the intro music stops, and also during the level (?)"; };
+label { name "xxx_level_something_jv"; addr $8009; comment "gets called after the level is drawn & the intro music stops, and also during the level (?)"; };
+label { name "draw_map"; addr $8049; comment "the entry point for parsing the level map and drawing graphics from it. see level_maps.txt. caller must set $C0/$C1 to the address of the map data. modders beware: bogus map data can & will cause infinite loops."; };
+label { name "draw_map_jv"; addr $8000; comment "the entry point for parsing the level map and drawing graphics from it. see level_maps.txt."; };
+label { name "dm_get_opcode"; addr $804B; comment "$C0/$C1 points to $A300 (level00_desc) on the first call"; };
+label { name "dm_switch_opcode"; addr $804D; comment "map opcodes: $FC = jump, $FF = end, $FD = set drawing direction, $FE = select graphics object"; };
+label { name "dm_draw_gfx"; addr $8090; comment "handle gfx_draw opcode"; };
+label { name "dm_jump"; addr $805C; comment "handle gfx_jump opcode"; };
+label { name "dm_delta"; addr $806B; comment "handle gfx_delta opcode"; };
+label { name "dm_obj"; addr $8083; comment "handle gfx_object opcode"; };
+label { name "dm_fallthru"; addr $805B; comment "handle gfx_end opcode"; };
+label { name "dm_next_opcode"; addr $8075; comment "all the other opcode handlers jump here"; };
+label { name "dm_progctr"; addr $C0; size 2; comment "see draw_map and level_maps.txt"; };
+label { name "dm_delta_x"; addr $C9; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_delta_y"; addr $CA; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_objptr"; addr $C2; size 2; comment "see draw_map and level_maps.txt"; };
+label { name "dm_xpos"; addr $55; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_ypos"; addr $54; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_length"; addr $BF; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_draw_loop"; addr $809C; size 1; comment "loop 'dm_length' times"; };
+label { name "dm_draw_obj"; addr $80B4; size 1; comment "draw current object at current x/y position"; };
+label { name "dm_draw_obj_loop"; addr $80B6; size 1; comment "object definition ends with $FF"; };
+label { name "dm_count"; addr $BE; size 1; comment "graphics object definition is this long"; };
+label { name "dm_x_with_offset"; addr $C6; size 1; comment "graphics object X offset, plus dm_xpos"; };
+label { name "dm_y_with_offset"; addr $C7; size 1; comment "graphics object Y offset, plus dm_xpos"; };
+label { name "dm_screen_addr"; addr $C4; size 2; comment "points to byte to write gfx data to"; };
+label { name "calc_screen_addr"; addr $80D0; size 1; comment "calculate 40 * dm_y_with_offset + dm_x_with_offset + screen mem address, store in dm_screen_addr"; };
+label { name "store_rts"; addr $83B6; comment "store an RTS at $06E6, which will get JSR'ed to by unused level subroutines"; };
+label { name "well_done_screen"; addr $BC00; comment "the WELL DONE screen, when you beat all the levels. after this, the game plays random levels."; };
+label { name "cue_woop_sound"; addr $B4D3; };
+label { name "sfx_woop"; addr $B564; };
+label { name "got_all_bombs"; addr $9766; };
+label { name "call_eol_sub"; addr $976C; };
+
+# end of main.info, everything below here is generated by mklevelinfo.pl
+label { name "work_level_desc"; addr $0780; size 2; comment "first 2 bytes are level number in screencodes"; };
+label { name "work_level_sub0"; addr $0782; size 2; comment "a subroutine"; };
+label { name "work_level_sub1"; addr $0784; size 2; comment "a subroutine"; };
+label { name "work_level_sub2"; addr $0786; size 2; comment "a subroutine"; };
+label { name "work_level_sub3"; addr $0788; size 2; comment "a subroutine"; };
+label { name "work_level_num_bombs"; addr $078a; size 1; comment "number of bombs to pick up on this level"; };
+label { name "work_level_bullet_chance"; addr $078b; size 1; comment "0 = no bullets"; };
+label { name "work_level_y_start"; addr $078c; size 1; comment "jumpman starting Y position"; };
+label { name "work_level_x_start"; addr $078d; size 1; comment "jumpman starting X position"; };
+label { name "work_level_offs_14"; addr $078e; size 2; comment "points to $0600"; };
+label { name "work_level_points_per_bomb"; addr $0790; size 1; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+label { name "work_level_time_bonus"; addr $0791; size 2; comment "amount of time bonus at start of level"; };
+label { name "work_level_offs_19"; addr $0793; size 1; comment "always $00"; };
+label { name "work_level_unkn_table0"; addr $0794; size 2; comment "pointer to ROM table or $06xx"; };
+label { name "work_level_map0"; addr $0796; size 2; comment "map data"; };
+label { name "work_level_map1"; addr $0798; size 2; comment "map data"; };
+label { name "work_level_map2"; addr $079a; size 2; comment "map data"; };
+label { name "work_level_unkn_table1"; addr $079c; size 2; comment "unknown, pointer to a ROM table or $0000"; };
+label { name "work_level_offs_30"; addr $079e; size 2; comment "always $0000"; };
+label { name "work_level_sub4"; addr $07a0; size 2; comment "$06E6 for most levels, or else a ROM subroutine"; };
+label { name "work_level_sub5"; addr $07a2; size 2; comment "$06E6 for some levels, or else a ROM subroutine"; };
+label { name "work_level_sub6"; addr $07a4; size 2; comment "always $9740 aka game_main_loop"; };
+label { name "work_level_sub_eol"; addr $07a6; size 2; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+label { name "work_level_offs_40"; addr $07a8; size 6; comment "all zeroes"; };
+label { name "work_level_offs_46"; addr $07ae; size 9; comment "unknown"; };
+label { name "work_level_offs_55"; addr $07b7; size 3; comment "unknown, always $00 $00 $00"; };
+label { name "work_level_offs_58"; addr $07ba; size 2; comment "unknown, not a ROM address"; };
+label { name "work_level_offs_60"; addr $07bc; size 4; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+label { name "cur_level_desc"; addr $07c0; size 2; comment "first 2 bytes are level number in screencodes"; };
+label { name "cur_level_sub0"; addr $07c2; size 2; comment "a subroutine"; };
+label { name "cur_level_sub1"; addr $07c4; size 2; comment "a subroutine"; };
+label { name "cur_level_sub2"; addr $07c6; size 2; comment "a subroutine"; };
+label { name "cur_level_sub3"; addr $07c8; size 2; comment "a subroutine"; };
+label { name "cur_level_num_bombs"; addr $07ca; size 1; comment "number of bombs to pick up on this level"; };
+label { name "cur_level_bullet_chance"; addr $07cb; size 1; comment "0 = no bullets"; };
+label { name "cur_level_y_start"; addr $07cc; size 1; comment "jumpman starting Y position"; };
+label { name "cur_level_x_start"; addr $07cd; size 1; comment "jumpman starting X position"; };
+label { name "cur_level_offs_14"; addr $07ce; size 2; comment "points to $0600"; };
+label { name "cur_level_points_per_bomb"; addr $07d0; size 1; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+label { name "cur_level_time_bonus"; addr $07d1; size 2; comment "amount of time bonus at start of level"; };
+label { name "cur_level_offs_19"; addr $07d3; size 1; comment "always $00"; };
+label { name "cur_level_unkn_table0"; addr $07d4; size 2; comment "pointer to ROM table or $06xx"; };
+label { name "cur_level_map0"; addr $07d6; size 2; comment "map data"; };
+label { name "cur_level_map1"; addr $07d8; size 2; comment "map data"; };
+label { name "cur_level_map2"; addr $07da; size 2; comment "map data"; };
+label { name "cur_level_unkn_table1"; addr $07dc; size 2; comment "unknown, pointer to a ROM table or $0000"; };
+label { name "cur_level_offs_30"; addr $07de; size 2; comment "always $0000"; };
+label { name "cur_level_sub4"; addr $07e0; size 2; comment "$06E6 for most levels, or else a ROM subroutine"; };
+label { name "cur_level_sub5"; addr $07e2; size 2; comment "$06E6 for some levels, or else a ROM subroutine"; };
+label { name "cur_level_sub6"; addr $07e4; size 2; comment "always $9740 aka game_main_loop"; };
+label { name "cur_level_sub_eol"; addr $07e6; size 2; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+label { name "cur_level_offs_40"; addr $07e8; size 6; comment "all zeroes"; };
+label { name "cur_level_offs_46"; addr $07ee; size 9; comment "unknown"; };
+label { name "cur_level_offs_55"; addr $07f7; size 3; comment "unknown, always $00 $00 $00"; };
+label { name "cur_level_offs_58"; addr $07fa; size 2; comment "unknown, not a ROM address"; };
+label { name "cur_level_offs_60"; addr $07fc; size 4; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level00_desc"; start $a000; end $a001; type bytetable; comment "64-byte level descriptors, 12 of them (1 per level). first 2 bytes are level number in screencodes"; };
+range { name "level00_sub0"; start $a002; end $a003; type addrtable; comment "a subroutine"; };
+range { name "level00_sub1"; start $a004; end $a005; type addrtable; comment "a subroutine"; };
+range { name "level00_sub2"; start $a006; end $a007; type addrtable; comment "a subroutine"; };
+range { name "level00_sub3"; start $a008; end $a009; type addrtable; comment "a subroutine"; };
+range { name "level00_num_bombs"; start $a00a; end $a00a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level00_bullet_chance"; start $a00b; end $a00b; type bytetable; comment "0 = no bullets"; };
+range { name "level00_y_start"; start $a00c; end $a00c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level00_x_start"; start $a00d; end $a00d; type bytetable; comment "jumpman starting X position"; };
+range { name "level00_offs_14"; start $a00e; end $a00f; type bytetable; comment "points to $0600"; };
+range { name "level00_points_per_bomb"; start $a010; end $a010; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level00_time_bonus"; start $a011; end $a012; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level00_offs_19"; start $a013; end $a013; type bytetable; comment "always $00"; };
+range { name "level00_unkn_table0"; start $a014; end $a015; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level00_map0"; start $a016; end $a017; type addrtable; comment "map data"; };
+range { name "level00_map1"; start $a018; end $a019; type addrtable; comment "map data"; };
+range { name "level00_map2"; start $a01a; end $a01b; type addrtable; comment "map data"; };
+range { name "level00_unkn_table1"; start $a01c; end $a01d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level00_offs_30"; start $a01e; end $a01f; type bytetable; comment "always $0000"; };
+range { name "level00_sub4"; start $a020; end $a021; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level00_sub5"; start $a022; end $a023; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level00_sub6"; start $a024; end $a025; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level00_sub_eol"; start $a026; end $a027; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level00_offs_40"; start $a028; end $a02d; type bytetable; comment "all zeroes"; };
+range { name "level00_offs_46"; start $a02e; end $a036; type bytetable; comment "unknown"; };
+range { name "level00_offs_55"; start $a037; end $a039; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level00_offs_58"; start $a03a; end $a03b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level00_offs_60"; start $a03c; end $a03f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level01_desc"; start $a040; end $a041; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level01_sub0"; start $a042; end $a043; type addrtable; comment "a subroutine"; };
+range { name "level01_sub1"; start $a044; end $a045; type addrtable; comment "a subroutine"; };
+range { name "level01_sub2"; start $a046; end $a047; type addrtable; comment "a subroutine"; };
+range { name "level01_sub3"; start $a048; end $a049; type addrtable; comment "a subroutine"; };
+range { name "level01_num_bombs"; start $a04a; end $a04a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level01_bullet_chance"; start $a04b; end $a04b; type bytetable; comment "0 = no bullets"; };
+range { name "level01_y_start"; start $a04c; end $a04c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level01_x_start"; start $a04d; end $a04d; type bytetable; comment "jumpman starting X position"; };
+range { name "level01_offs_14"; start $a04e; end $a04f; type bytetable; comment "points to $0600"; };
+range { name "level01_points_per_bomb"; start $a050; end $a050; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level01_time_bonus"; start $a051; end $a052; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level01_offs_19"; start $a053; end $a053; type bytetable; comment "always $00"; };
+range { name "level01_unkn_table0"; start $a054; end $a055; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level01_map0"; start $a056; end $a057; type addrtable; comment "map data"; };
+range { name "level01_map1"; start $a058; end $a059; type addrtable; comment "map data"; };
+range { name "level01_map2"; start $a05a; end $a05b; type addrtable; comment "map data"; };
+range { name "level01_unkn_table1"; start $a05c; end $a05d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level01_offs_30"; start $a05e; end $a05f; type bytetable; comment "always $0000"; };
+range { name "level01_sub4"; start $a060; end $a061; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level01_sub5"; start $a062; end $a063; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level01_sub6"; start $a064; end $a065; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level01_sub_eol"; start $a066; end $a067; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level01_offs_40"; start $a068; end $a06d; type bytetable; comment "all zeroes"; };
+range { name "level01_offs_46"; start $a06e; end $a076; type bytetable; comment "unknown"; };
+range { name "level01_offs_55"; start $a077; end $a079; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level01_offs_58"; start $a07a; end $a07b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level01_offs_60"; start $a07c; end $a07f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level02_desc"; start $a080; end $a081; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level02_sub0"; start $a082; end $a083; type addrtable; comment "a subroutine"; };
+range { name "level02_sub1"; start $a084; end $a085; type addrtable; comment "a subroutine"; };
+range { name "level02_sub2"; start $a086; end $a087; type addrtable; comment "a subroutine"; };
+range { name "level02_sub3"; start $a088; end $a089; type addrtable; comment "a subroutine"; };
+range { name "level02_num_bombs"; start $a08a; end $a08a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level02_bullet_chance"; start $a08b; end $a08b; type bytetable; comment "0 = no bullets"; };
+range { name "level02_y_start"; start $a08c; end $a08c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level02_x_start"; start $a08d; end $a08d; type bytetable; comment "jumpman starting X position"; };
+range { name "level02_offs_14"; start $a08e; end $a08f; type bytetable; comment "points to $0600"; };
+range { name "level02_points_per_bomb"; start $a090; end $a090; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level02_time_bonus"; start $a091; end $a092; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level02_offs_19"; start $a093; end $a093; type bytetable; comment "always $00"; };
+range { name "level02_unkn_table0"; start $a094; end $a095; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level02_map0"; start $a096; end $a097; type addrtable; comment "map data"; };
+range { name "level02_map1"; start $a098; end $a099; type addrtable; comment "map data"; };
+range { name "level02_map2"; start $a09a; end $a09b; type addrtable; comment "map data"; };
+range { name "level02_unkn_table1"; start $a09c; end $a09d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level02_offs_30"; start $a09e; end $a09f; type bytetable; comment "always $0000"; };
+range { name "level02_sub4"; start $a0a0; end $a0a1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level02_sub5"; start $a0a2; end $a0a3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level02_sub6"; start $a0a4; end $a0a5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level02_sub_eol"; start $a0a6; end $a0a7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level02_offs_40"; start $a0a8; end $a0ad; type bytetable; comment "all zeroes"; };
+range { name "level02_offs_46"; start $a0ae; end $a0b6; type bytetable; comment "unknown"; };
+range { name "level02_offs_55"; start $a0b7; end $a0b9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level02_offs_58"; start $a0ba; end $a0bb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level02_offs_60"; start $a0bc; end $a0bf; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level03_desc"; start $a0c0; end $a0c1; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level03_sub0"; start $a0c2; end $a0c3; type addrtable; comment "a subroutine"; };
+range { name "level03_sub1"; start $a0c4; end $a0c5; type addrtable; comment "a subroutine"; };
+range { name "level03_sub2"; start $a0c6; end $a0c7; type addrtable; comment "a subroutine"; };
+range { name "level03_sub3"; start $a0c8; end $a0c9; type addrtable; comment "a subroutine"; };
+range { name "level03_num_bombs"; start $a0ca; end $a0ca; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level03_bullet_chance"; start $a0cb; end $a0cb; type bytetable; comment "0 = no bullets"; };
+range { name "level03_y_start"; start $a0cc; end $a0cc; type bytetable; comment "jumpman starting Y position"; };
+range { name "level03_x_start"; start $a0cd; end $a0cd; type bytetable; comment "jumpman starting X position"; };
+range { name "level03_offs_14"; start $a0ce; end $a0cf; type bytetable; comment "points to $0600"; };
+range { name "level03_points_per_bomb"; start $a0d0; end $a0d0; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level03_time_bonus"; start $a0d1; end $a0d2; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level03_offs_19"; start $a0d3; end $a0d3; type bytetable; comment "always $00"; };
+range { name "level03_unkn_table0"; start $a0d4; end $a0d5; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level03_map0"; start $a0d6; end $a0d7; type addrtable; comment "map data"; };
+range { name "level03_map1"; start $a0d8; end $a0d9; type addrtable; comment "map data"; };
+range { name "level03_map2"; start $a0da; end $a0db; type addrtable; comment "map data"; };
+range { name "level03_unkn_table1"; start $a0dc; end $a0dd; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level03_offs_30"; start $a0de; end $a0df; type bytetable; comment "always $0000"; };
+range { name "level03_sub4"; start $a0e0; end $a0e1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level03_sub5"; start $a0e2; end $a0e3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level03_sub6"; start $a0e4; end $a0e5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level03_sub_eol"; start $a0e6; end $a0e7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level03_offs_40"; start $a0e8; end $a0ed; type bytetable; comment "all zeroes"; };
+range { name "level03_offs_46"; start $a0ee; end $a0f6; type bytetable; comment "unknown"; };
+range { name "level03_offs_55"; start $a0f7; end $a0f9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level03_offs_58"; start $a0fa; end $a0fb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level03_offs_60"; start $a0fc; end $a0ff; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level04_desc"; start $a100; end $a101; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level04_sub0"; start $a102; end $a103; type addrtable; comment "a subroutine"; };
+range { name "level04_sub1"; start $a104; end $a105; type addrtable; comment "a subroutine"; };
+range { name "level04_sub2"; start $a106; end $a107; type addrtable; comment "a subroutine"; };
+range { name "level04_sub3"; start $a108; end $a109; type addrtable; comment "a subroutine"; };
+range { name "level04_num_bombs"; start $a10a; end $a10a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level04_bullet_chance"; start $a10b; end $a10b; type bytetable; comment "0 = no bullets"; };
+range { name "level04_y_start"; start $a10c; end $a10c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level04_x_start"; start $a10d; end $a10d; type bytetable; comment "jumpman starting X position"; };
+range { name "level04_offs_14"; start $a10e; end $a10f; type bytetable; comment "points to $0600"; };
+range { name "level04_points_per_bomb"; start $a110; end $a110; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level04_time_bonus"; start $a111; end $a112; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level04_offs_19"; start $a113; end $a113; type bytetable; comment "always $00"; };
+range { name "level04_unkn_table0"; start $a114; end $a115; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level04_map0"; start $a116; end $a117; type addrtable; comment "map data"; };
+range { name "level04_map1"; start $a118; end $a119; type addrtable; comment "map data"; };
+range { name "level04_map2"; start $a11a; end $a11b; type addrtable; comment "map data"; };
+range { name "level04_unkn_table1"; start $a11c; end $a11d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level04_offs_30"; start $a11e; end $a11f; type bytetable; comment "always $0000"; };
+range { name "level04_sub4"; start $a120; end $a121; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level04_sub5"; start $a122; end $a123; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level04_sub6"; start $a124; end $a125; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level04_sub_eol"; start $a126; end $a127; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level04_offs_40"; start $a128; end $a12d; type bytetable; comment "all zeroes"; };
+range { name "level04_offs_46"; start $a12e; end $a136; type bytetable; comment "unknown"; };
+range { name "level04_offs_55"; start $a137; end $a139; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level04_offs_58"; start $a13a; end $a13b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level04_offs_60"; start $a13c; end $a13f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level05_desc"; start $a140; end $a141; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level05_sub0"; start $a142; end $a143; type addrtable; comment "a subroutine"; };
+range { name "level05_sub1"; start $a144; end $a145; type addrtable; comment "a subroutine"; };
+range { name "level05_sub2"; start $a146; end $a147; type addrtable; comment "a subroutine"; };
+range { name "level05_sub3"; start $a148; end $a149; type addrtable; comment "a subroutine"; };
+range { name "level05_num_bombs"; start $a14a; end $a14a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level05_bullet_chance"; start $a14b; end $a14b; type bytetable; comment "0 = no bullets"; };
+range { name "level05_y_start"; start $a14c; end $a14c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level05_x_start"; start $a14d; end $a14d; type bytetable; comment "jumpman starting X position"; };
+range { name "level05_offs_14"; start $a14e; end $a14f; type bytetable; comment "points to $0600"; };
+range { name "level05_points_per_bomb"; start $a150; end $a150; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level05_time_bonus"; start $a151; end $a152; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level05_offs_19"; start $a153; end $a153; type bytetable; comment "always $00"; };
+range { name "level05_unkn_table0"; start $a154; end $a155; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level05_map0"; start $a156; end $a157; type addrtable; comment "map data"; };
+range { name "level05_map1"; start $a158; end $a159; type addrtable; comment "map data"; };
+range { name "level05_map2"; start $a15a; end $a15b; type addrtable; comment "map data"; };
+range { name "level05_unkn_table1"; start $a15c; end $a15d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level05_offs_30"; start $a15e; end $a15f; type bytetable; comment "always $0000"; };
+range { name "level05_sub4"; start $a160; end $a161; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level05_sub5"; start $a162; end $a163; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level05_sub6"; start $a164; end $a165; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level05_sub_eol"; start $a166; end $a167; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level05_offs_40"; start $a168; end $a16d; type bytetable; comment "all zeroes"; };
+range { name "level05_offs_46"; start $a16e; end $a176; type bytetable; comment "unknown"; };
+range { name "level05_offs_55"; start $a177; end $a179; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level05_offs_58"; start $a17a; end $a17b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level05_offs_60"; start $a17c; end $a17f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level06_desc"; start $a180; end $a181; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level06_sub0"; start $a182; end $a183; type addrtable; comment "a subroutine"; };
+range { name "level06_sub1"; start $a184; end $a185; type addrtable; comment "a subroutine"; };
+range { name "level06_sub2"; start $a186; end $a187; type addrtable; comment "a subroutine"; };
+range { name "level06_sub3"; start $a188; end $a189; type addrtable; comment "a subroutine"; };
+range { name "level06_num_bombs"; start $a18a; end $a18a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level06_bullet_chance"; start $a18b; end $a18b; type bytetable; comment "0 = no bullets"; };
+range { name "level06_y_start"; start $a18c; end $a18c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level06_x_start"; start $a18d; end $a18d; type bytetable; comment "jumpman starting X position"; };
+range { name "level06_offs_14"; start $a18e; end $a18f; type bytetable; comment "points to $0600"; };
+range { name "level06_points_per_bomb"; start $a190; end $a190; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level06_time_bonus"; start $a191; end $a192; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level06_offs_19"; start $a193; end $a193; type bytetable; comment "always $00"; };
+range { name "level06_unkn_table0"; start $a194; end $a195; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level06_map0"; start $a196; end $a197; type addrtable; comment "map data"; };
+range { name "level06_map1"; start $a198; end $a199; type addrtable; comment "map data"; };
+range { name "level06_map2"; start $a19a; end $a19b; type addrtable; comment "map data"; };
+range { name "level06_unkn_table1"; start $a19c; end $a19d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level06_offs_30"; start $a19e; end $a19f; type bytetable; comment "always $0000"; };
+range { name "level06_sub4"; start $a1a0; end $a1a1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level06_sub5"; start $a1a2; end $a1a3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level06_sub6"; start $a1a4; end $a1a5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level06_sub_eol"; start $a1a6; end $a1a7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level06_offs_40"; start $a1a8; end $a1ad; type bytetable; comment "all zeroes"; };
+range { name "level06_offs_46"; start $a1ae; end $a1b6; type bytetable; comment "unknown"; };
+range { name "level06_offs_55"; start $a1b7; end $a1b9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level06_offs_58"; start $a1ba; end $a1bb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level06_offs_60"; start $a1bc; end $a1bf; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level07_desc"; start $a1c0; end $a1c1; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level07_sub0"; start $a1c2; end $a1c3; type addrtable; comment "a subroutine"; };
+range { name "level07_sub1"; start $a1c4; end $a1c5; type addrtable; comment "a subroutine"; };
+range { name "level07_sub2"; start $a1c6; end $a1c7; type addrtable; comment "a subroutine"; };
+range { name "level07_sub3"; start $a1c8; end $a1c9; type addrtable; comment "a subroutine"; };
+range { name "level07_num_bombs"; start $a1ca; end $a1ca; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level07_bullet_chance"; start $a1cb; end $a1cb; type bytetable; comment "0 = no bullets"; };
+range { name "level07_y_start"; start $a1cc; end $a1cc; type bytetable; comment "jumpman starting Y position"; };
+range { name "level07_x_start"; start $a1cd; end $a1cd; type bytetable; comment "jumpman starting X position"; };
+range { name "level07_offs_14"; start $a1ce; end $a1cf; type bytetable; comment "points to $0600"; };
+range { name "level07_points_per_bomb"; start $a1d0; end $a1d0; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level07_time_bonus"; start $a1d1; end $a1d2; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level07_offs_19"; start $a1d3; end $a1d3; type bytetable; comment "always $00"; };
+range { name "level07_unkn_table0"; start $a1d4; end $a1d5; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level07_map0"; start $a1d6; end $a1d7; type addrtable; comment "map data"; };
+range { name "level07_map1"; start $a1d8; end $a1d9; type addrtable; comment "map data"; };
+range { name "level07_map2"; start $a1da; end $a1db; type addrtable; comment "map data"; };
+range { name "level07_unkn_table1"; start $a1dc; end $a1dd; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level07_offs_30"; start $a1de; end $a1df; type bytetable; comment "always $0000"; };
+range { name "level07_sub4"; start $a1e0; end $a1e1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level07_sub5"; start $a1e2; end $a1e3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level07_sub6"; start $a1e4; end $a1e5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level07_sub_eol"; start $a1e6; end $a1e7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level07_offs_40"; start $a1e8; end $a1ed; type bytetable; comment "all zeroes"; };
+range { name "level07_offs_46"; start $a1ee; end $a1f6; type bytetable; comment "unknown"; };
+range { name "level07_offs_55"; start $a1f7; end $a1f9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level07_offs_58"; start $a1fa; end $a1fb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level07_offs_60"; start $a1fc; end $a1ff; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level08_desc"; start $a200; end $a201; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level08_sub0"; start $a202; end $a203; type addrtable; comment "a subroutine"; };
+range { name "level08_sub1"; start $a204; end $a205; type addrtable; comment "a subroutine"; };
+range { name "level08_sub2"; start $a206; end $a207; type addrtable; comment "a subroutine"; };
+range { name "level08_sub3"; start $a208; end $a209; type addrtable; comment "a subroutine"; };
+range { name "level08_num_bombs"; start $a20a; end $a20a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level08_bullet_chance"; start $a20b; end $a20b; type bytetable; comment "0 = no bullets"; };
+range { name "level08_y_start"; start $a20c; end $a20c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level08_x_start"; start $a20d; end $a20d; type bytetable; comment "jumpman starting X position"; };
+range { name "level08_offs_14"; start $a20e; end $a20f; type bytetable; comment "points to $0600"; };
+range { name "level08_points_per_bomb"; start $a210; end $a210; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level08_time_bonus"; start $a211; end $a212; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level08_offs_19"; start $a213; end $a213; type bytetable; comment "always $00"; };
+range { name "level08_unkn_table0"; start $a214; end $a215; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level08_map0"; start $a216; end $a217; type addrtable; comment "map data"; };
+range { name "level08_map1"; start $a218; end $a219; type addrtable; comment "map data"; };
+range { name "level08_map2"; start $a21a; end $a21b; type addrtable; comment "map data"; };
+range { name "level08_unkn_table1"; start $a21c; end $a21d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level08_offs_30"; start $a21e; end $a21f; type bytetable; comment "always $0000"; };
+range { name "level08_sub4"; start $a220; end $a221; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level08_sub5"; start $a222; end $a223; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level08_sub6"; start $a224; end $a225; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level08_sub_eol"; start $a226; end $a227; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level08_offs_40"; start $a228; end $a22d; type bytetable; comment "all zeroes"; };
+range { name "level08_offs_46"; start $a22e; end $a236; type bytetable; comment "unknown"; };
+range { name "level08_offs_55"; start $a237; end $a239; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level08_offs_58"; start $a23a; end $a23b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level08_offs_60"; start $a23c; end $a23f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level09_desc"; start $a240; end $a241; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level09_sub0"; start $a242; end $a243; type addrtable; comment "a subroutine"; };
+range { name "level09_sub1"; start $a244; end $a245; type addrtable; comment "a subroutine"; };
+range { name "level09_sub2"; start $a246; end $a247; type addrtable; comment "a subroutine"; };
+range { name "level09_sub3"; start $a248; end $a249; type addrtable; comment "a subroutine"; };
+range { name "level09_num_bombs"; start $a24a; end $a24a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level09_bullet_chance"; start $a24b; end $a24b; type bytetable; comment "0 = no bullets"; };
+range { name "level09_y_start"; start $a24c; end $a24c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level09_x_start"; start $a24d; end $a24d; type bytetable; comment "jumpman starting X position"; };
+range { name "level09_offs_14"; start $a24e; end $a24f; type bytetable; comment "points to $0600"; };
+range { name "level09_points_per_bomb"; start $a250; end $a250; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level09_time_bonus"; start $a251; end $a252; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level09_offs_19"; start $a253; end $a253; type bytetable; comment "always $00"; };
+range { name "level09_unkn_table0"; start $a254; end $a255; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level09_map0"; start $a256; end $a257; type addrtable; comment "map data"; };
+range { name "level09_map1"; start $a258; end $a259; type addrtable; comment "map data"; };
+range { name "level09_map2"; start $a25a; end $a25b; type addrtable; comment "map data"; };
+range { name "level09_unkn_table1"; start $a25c; end $a25d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level09_offs_30"; start $a25e; end $a25f; type bytetable; comment "always $0000"; };
+range { name "level09_sub4"; start $a260; end $a261; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level09_sub5"; start $a262; end $a263; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level09_sub6"; start $a264; end $a265; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level09_sub_eol"; start $a266; end $a267; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level09_offs_40"; start $a268; end $a26d; type bytetable; comment "all zeroes"; };
+range { name "level09_offs_46"; start $a26e; end $a276; type bytetable; comment "unknown"; };
+range { name "level09_offs_55"; start $a277; end $a279; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level09_offs_58"; start $a27a; end $a27b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level09_offs_60"; start $a27c; end $a27f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level10_desc"; start $a280; end $a281; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level10_sub0"; start $a282; end $a283; type addrtable; comment "a subroutine"; };
+range { name "level10_sub1"; start $a284; end $a285; type addrtable; comment "a subroutine"; };
+range { name "level10_sub2"; start $a286; end $a287; type addrtable; comment "a subroutine"; };
+range { name "level10_sub3"; start $a288; end $a289; type addrtable; comment "a subroutine"; };
+range { name "level10_num_bombs"; start $a28a; end $a28a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level10_bullet_chance"; start $a28b; end $a28b; type bytetable; comment "0 = no bullets"; };
+range { name "level10_y_start"; start $a28c; end $a28c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level10_x_start"; start $a28d; end $a28d; type bytetable; comment "jumpman starting X position"; };
+range { name "level10_offs_14"; start $a28e; end $a28f; type bytetable; comment "points to $0600"; };
+range { name "level10_points_per_bomb"; start $a290; end $a290; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level10_time_bonus"; start $a291; end $a292; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level10_offs_19"; start $a293; end $a293; type bytetable; comment "always $00"; };
+range { name "level10_unkn_table0"; start $a294; end $a295; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level10_map0"; start $a296; end $a297; type addrtable; comment "map data"; };
+range { name "level10_map1"; start $a298; end $a299; type addrtable; comment "map data"; };
+range { name "level10_map2"; start $a29a; end $a29b; type addrtable; comment "map data"; };
+range { name "level10_unkn_table1"; start $a29c; end $a29d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level10_offs_30"; start $a29e; end $a29f; type bytetable; comment "always $0000"; };
+range { name "level10_sub4"; start $a2a0; end $a2a1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level10_sub5"; start $a2a2; end $a2a3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level10_sub6"; start $a2a4; end $a2a5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level10_sub_eol"; start $a2a6; end $a2a7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level10_offs_40"; start $a2a8; end $a2ad; type bytetable; comment "all zeroes"; };
+range { name "level10_offs_46"; start $a2ae; end $a2b6; type bytetable; comment "unknown"; };
+range { name "level10_offs_55"; start $a2b7; end $a2b9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level10_offs_58"; start $a2ba; end $a2bb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level10_offs_60"; start $a2bc; end $a2bf; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level11_desc"; start $a2c0; end $a2c1; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level11_sub0"; start $a2c2; end $a2c3; type addrtable; comment "a subroutine"; };
+range { name "level11_sub1"; start $a2c4; end $a2c5; type addrtable; comment "a subroutine"; };
+range { name "level11_sub2"; start $a2c6; end $a2c7; type addrtable; comment "a subroutine"; };
+range { name "level11_sub3"; start $a2c8; end $a2c9; type addrtable; comment "a subroutine"; };
+range { name "level11_num_bombs"; start $a2ca; end $a2ca; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level11_bullet_chance"; start $a2cb; end $a2cb; type bytetable; comment "0 = no bullets"; };
+range { name "level11_y_start"; start $a2cc; end $a2cc; type bytetable; comment "jumpman starting Y position"; };
+range { name "level11_x_start"; start $a2cd; end $a2cd; type bytetable; comment "jumpman starting X position"; };
+range { name "level11_offs_14"; start $a2ce; end $a2cf; type bytetable; comment "points to $0600"; };
+range { name "level11_points_per_bomb"; start $a2d0; end $a2d0; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level11_time_bonus"; start $a2d1; end $a2d2; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level11_offs_19"; start $a2d3; end $a2d3; type bytetable; comment "always $00"; };
+range { name "level11_unkn_table0"; start $a2d4; end $a2d5; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level11_map0"; start $a2d6; end $a2d7; type addrtable; comment "map data"; };
+range { name "level11_map1"; start $a2d8; end $a2d9; type addrtable; comment "map data"; };
+range { name "level11_map2"; start $a2da; end $a2db; type addrtable; comment "map data"; };
+range { name "level11_unkn_table1"; start $a2dc; end $a2dd; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level11_offs_30"; start $a2de; end $a2df; type bytetable; comment "always $0000"; };
+range { name "level11_sub4"; start $a2e0; end $a2e1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level11_sub5"; start $a2e2; end $a2e3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level11_sub6"; start $a2e4; end $a2e5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level11_sub_eol"; start $a2e6; end $a2e7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level11_offs_40"; start $a2e8; end $a2ed; type bytetable; comment "all zeroes"; };
+range { name "level11_offs_46"; start $a2ee; end $a2f6; type bytetable; comment "unknown"; };
+range { name "level11_offs_55"; start $a2f7; end $a2f9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level11_offs_58"; start $a2fa; end $a2fb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level11_offs_60"; start $a2fc; end $a2ff; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
diff --git a/jumpmanjr.rom b/jumpmanjr.rom
new file mode 100644
index 0000000..e2367e2
--- /dev/null
+++ b/jumpmanjr.rom
Binary files differ
diff --git a/jumpmanjr_manual.pdf b/jumpmanjr_manual.pdf
new file mode 100644
index 0000000..1a607a5
--- /dev/null
+++ b/jumpmanjr_manual.pdf
Binary files differ
diff --git a/level_descriptors.txt b/level_descriptors.txt
new file mode 100644
index 0000000..4cbed12
--- /dev/null
+++ b/level_descriptors.txt
@@ -0,0 +1,127 @@
+TODO: structure-ize the descriptors in the .info file, so dasm
+will politely generate labels for all the subroutines and map data.
+
+At $A000 in the ROM, there's a block of 64 bytes per level (12 blocks,
+768 bytes total). Each block describes a level of the game, so I'm calling
+them level descriptors. Pretty much everything about a level *except* its
+name is stored here. The names are stored separately in a table at $BB00.
+
+Level descriptors get copied to $07C0 as part of level entry. Possibly
+the copy gets modified as the level plays.
+
+Swapping the descriptors for the first two levels results in Electrocution
+being the first level, except the game says it's called Nothing To
+It. It plays normally, with electric floors, and displays L=1 in the
+status window. The next level is Nothing To It (but the game calls it
+Electrocution), which also plays normally and displays L=2.
+
+Anything that refers to a level below as levelXX is using zero-based
+numbering (level00 = first level, aka Nothing To It).
+
+Level descriptor structure:
+
+Offset 0, size 2:
+Level number displayed in the status window, 2 digits, screen codes.
+Levels <10 have $10 (the 0 character) as the first byte, but the code
+that draws the status window replaces it with a $00 (space). Possibly
+the decision to use e.g. 'L= 1' rather than 'L=01' was made late in
+the development process?
+
+Offset 2, size 2:
+A subroutine that gets called during the level (or $00 $00 for 'none').
+Not sure exactly when it gets called though.
+
+Offset 4, size 2:
+Another subroutine or $00 $00 for none..
+
+Offset 6, size 2:
+Another subroutine or $00 $00 for none..
+
+Offset 8, size 2:
+Another subroutine or $00 $00 for none..
+
+Offset 10, size 1:
+Number of bombs to pick up on this level.
+
+Offset 12, size 1:
+Jumpman's starting X position.
+
+Offset 13, size 1:
+Jumpman's starting Y position.
+
+Offset 14, size 2:
+No idea, but it's always $00 $06 (looks like a pointer to page 6).
+
+Offset 16, size 1:
+Always $64. Amount of points per bomb pickup. Interesting that this
+is potentially different per level, even though nothing was done with it.
+
+Offset 17, size 2:
+Amount of time bonus, e.g. $e8 $03 for Nothing To It (1000), $d0 $07 for
+Electrocution (2000).
+
+Offset 19, size 1:
+No idea. Always zero.
+
+Offset 20, size 2: don't know yet. **TODO** looks like a ROM address after all
+
+Offset 22, size 2:
+Address of the map for this level. When I figure out how the map
+format works, I'll document it in a file that will likely be called
+level_maps.txt.
+
+Offset 24, size 2:
+ROM address, more map data? (same areas of ROM)
+
+Offset 26, size 2:
+ROM address, more map data? (same areas of ROM)
+
+Offset 28, size 2:
+$00,$00 on most levels, else a ROM data table address.
+
+Offset 30, size 2:
+Always $00 $00.
+
+Offset 32, size 2:
+$06E6 for most levels, otherwise it's a subroutine in ROM.
+
+Offset 34, size 2:
+$06E6 for a few levels, otherwise it's a subroutine in ROM.
+
+Offset 36, size 2 (?):
+$40,$97 on every level.
+
+Offset 38, size 2:
+$06E6 for all levels except level07, where it's $AF58 (which is
+a subroutine in ROM).
+
+Offset 40, size 6:
+All $00 on all levels.
+
+Offset 46, size 2 (?):
+Unknown. Not a ROM address.
+
+Offset 48, size 2 (?):
+Unknown. Not a ROM address.
+
+Offset 50, size 1:
+$0C on most levels except:
+$18 on level01
+$4C on level03
+$04 on level05
+
+Offsets 51-54: unknown.
+
+Offset 55, size 1 (?):
+$00 on every level.
+
+Offset 56, size 2:
+$00,$00 on every level.
+
+Offset 58, size 2 (?):
+Unknown. Not a ROM address.
+
+Offset 60, size 4:
+$00,$00,$00,$00 on every level except level05 (Walls) where it's
+$FF,$FF,$FF,$FF.
+
diff --git a/level_maps.txt b/level_maps.txt
new file mode 100644
index 0000000..b114485
--- /dev/null
+++ b/level_maps.txt
@@ -0,0 +1,188 @@
+Level Maps
+----------
+
+level00_map:
+ .byte $FE,$33,$9C,$FD,$04,$00,$44,$05 ; A300 FE 33 9C FD 04 00 44 05 .3....D.
+ .byte $06,$04,$15,$0A,$74,$15,$0A,$24 ; A308 06 04 15 0A 74 15 0A 24 ....t..$
+ .byte $22,$02,$74,$22,$02,$24,$25,$16 ; A310 22 02 74 22 02 24 25 16 ".t".$%.
+ .byte $04,$45,$04,$44,$45,$06,$8C,$45 ; A318 04 45 04 44 45 06 8C 45 .E.DE..E
+ .byte $04,$04,$55,$08,$34,$55,$0E,$7C ; A320 04 04 55 08 34 55 0E 7C ..U.4U.|
+ .byte $55,$08,$FD,$04,$FF,$34,$09,$04 ; A328 55 08 FD 04 FF 34 09 04 U....4..
+ .byte $5C,$44,$0A,$FD,$04,$01,$5C,$06 ; A330 5C 44 0A FD 04 01 5C 06 \D....\.
+ .byte $04,$1C,$3B,$0A,$FE,$5F,$9C,$FD ; A338 04 1C 3B 0A FE 5F 9C FD ..;.._..
+ .byte $00,$04,$0C,$41,$05,$8C,$41,$05 ; A340 00 04 0C 41 05 8C 41 05 ...A..A.
+ .byte $24,$01,$05,$74,$01,$05,$4C,$01 ; A348 24 01 05 74 01 05 4C 01 $..t..L.
+ .byte $15,$FE,$C9,$9C,$06,$18,$0A,$99 ; A350 15 FE C9 9C 06 18 0A 99 ........
+ .byte $18,$0A,$FE,$DA,$9C,$1D,$38,$06 ; A358 18 0A FE DA 9C 1D 38 06 ......8.
+ .byte $81,$38,$06,$FE,$B3,$9C ; A360 81 38 06 FE B3 9C .8....
+
+A300: FE 33 9C selects a shape (in this case, a girder)
+A303: FD 04 00 sets the X and Y delta (4 pixels X, 0 lines Y)
+A306: 44 is the X starting position
+A307: 05 is the Y starting position
+A308: 06 is the number of copies to draw (length of line)
+A309: 04 is another X position (same shape type, still drawing girders)
+A30A: 15 is another Y position (same shape type)
+A30B: 0A is the number of copies to draw
+
+...more x/y/length tuples here, all drawn with dx=4, dy=0, aka
+horizontally from left to right.
+
+A32A: $FD,$04,$FF sets a new X/Y delta. now we're drawing left and
+down, for the diagonal girders (aka ramps) that run SW to NE.
+
+A333: $FD,$04,$01 is X/Y delta, drawing left and up, for the ramps
+that run NW to SE (tilted the other way from the previous set).
+
+A33C: $FE,$5F,$9C selects a different shape (ladders)
+
+so eventually, I need ca65 macros that resemble instructions that assemble
+into map data. Something like:
+
+set_gfx $9Cee
+set_delta $04,$00
+draw_gfx $44,$05,$06
+draw_gfx $04,$15,$0A
+
+...notionally the drawing engine is a little CPU with 3 16-bit registers:
+a program counter (stored at $C0), gfx (the graphic object it draws)
+and delta (2 8-bit signed ints). It has 5 opcodes:
+
+$FC - gfx_jump (operand = 16-bit target address)
+$FD - gfx_delta (operand = 2 8-bit signed ints)
+$FE - gfx_shape (operand = 16-bit address of shape, see below)
+$FF - gfx_end (done drawing)
+Anything else - gfx_draw (opcode is X start, next 2 bytes are Y and length)
+
+All the opcodes other than gfx_end are 3 bytes. Write macros for ca65 and a
+disassembler in perl.
+
+There are 13 primary maps (one per level, plus the WELL DONE screen). Some
+(all?) levels also have secondary map data, which I think is used for
+changing parts of the map during the level (e.g. the disappearing girders
+on level 1).
+
+Shapes
+------
+
+Actual graphics data (girder sections, ladders, etc) is stored less
+efficiently. I'm not going to call these "sprites" because they don't
+move, and I'm not going to call them "tiles" because they aren't (they
+can be placed at arbitrary X/Y positions, not limited to a character
+map style grid). So I'll refer them as a "shape".
+
+Each shape is at least one pixel wide and at least 1 pixel tall. Pixels
+are 2 bits wide (4-color GR.7 mode), and are stored unpacked (2 bits
+per byte).
+
+Here's what the girder section looks like:
+
+girder: .byte $04,$00,$00,$01,$01,$01,$01,$04 ; 9C33 04 00 00 01 01 01 01 04 ........
+ .byte $00,$01,$01,$00,$01,$00,$04,$00 ; 9C3B 00 01 01 00 01 00 04 00 ........
+ .byte $02,$01,$01,$01,$01,$FF,$xx,$xx ; 9C43 02 01 01 01 01 FF xx xx ........
+
+That's from the disassembly, the xx's are "don't care" because they're
+actually part of the next shape in the table.
+
+Here's the same thing, laid out in a more human-readable way [*]
+
+girder:
+girder_row0:
+girder_row0_width: .byte $04
+girder_row0_x_offset: .byte $00
+girder_row0_y_offset: .byte $00
+girder_row0_pixels: .byte $01,$01,$01,$01
+girder_row1:
+girder_row1_width: .byte $04
+girder_row1_x_offset: .byte $00
+girder_row1_y_offset: .byte $01
+girder_row1_pixels: .byte $01,$00,$01,$00
+girder_row2:
+girder_row2_width: .byte $04
+girder_row2_x_offset: .byte $00
+girder_row2_y_offset: .byte $02
+girder_row2_pixels: .byte $01,$01,$01,$01
+girder_end: .byte $FF
+
+ [*] Getting da65 to emit this would be possible but unwieldy, it'll have
+ to wait until I've mapped out all the 'unknown' code/data sections
+ and can start manually editing the disassembly to turn it into
+ proper source.
+
+This makes a shape like this:
+
+XXXX
+X X
+XXXX
+
+...which you'll recognize as a girder segment, if you squint a little.
+
+Notice the use of $FF as an end marker. If it occurs in place of a width,
+the dm_draw_gfx routine knows it's done, and exits immediately.
+
+Here's the next shape in the table:
+
+blank:
+blank_row0:
+blank_row0_width: .byte $04
+blank_row0_x_offset: .byte $00
+blank_row0_y_offset: .byte $00
+blank_row0_pixels: .byte $00,$00,$00,$00
+blank_row1:
+blank_row1_width: .byte $04
+blank_row1_x_offset: .byte $00
+blank_row1_y_offset: .byte $01
+blank_row1_pixels: .byte $00,$00,$00,$00
+blank_row2:
+blank_row2_width: .byte $04
+blank_row2_x_offset: .byte $00
+blank_row2_y_offset: .byte $02
+blank_row2_pixels: .byte $00,$00,$00,$00
+blank_end: .byte $FF
+
+This is a 4x4 block of empty pixels. It's probably used to erase parts
+of the level (e.g. the disappearing platforms on level 1).
+
+Next:
+
+xxx:
+xxx_row0:
+xxx_row0_width: .byte $02
+xxx_row0_x_offset: .byte $00
+xxx_row0_y_offset: .byte $00
+xxx_row0_pixels: .byte $02,$02
+
+xxx_row1_width: .byte $02
+xxx_row1_x_offset: .byte $06
+xxx_row1_y_offset: .byte $00
+xxx_row1_pixels: .byte $02,$02
+
+xxx_row2_width: .byte $02
+xxx_row2_x_offset: .byte $00
+xxx_row2_y_offset: .byte $01
+xxx_row2_pixels: .byte $02,$02
+
+xxx_row3_width: .byte $02
+xxx_row3_x_offset: .byte $06
+xxx_row3_y_offset: .byte $01
+xxx_row3_pixels: .byte $02,$02
+
+xxx_row4_width: .byte $08
+xxx_row4_x_offset: .byte $00
+xxx_row4_y_offset: .byte $02
+xxx_row4_pixels: .byte $02,$02,$02,$02,$02,$02,$02,$02
+
+xxx_row5_width: .byte $02
+xxx_row5_x_offset: .byte $00
+xxx_row5_y_offset: .byte $03
+xxx_row5_pixels: .byte $02,$02
+
+xxx_row6_width: .byte $02
+xxx_row6_x_offset: .byte $06
+xxx_row6_y_offset: .byte $03
+xxx_row6_pixels: .byte $02,$02
+
+xxx_end: .byte $FF
+
+In this one, all the pixels are $02. Most of the shapes will be like
+this, only using one color.
diff --git a/leveldesc.info b/leveldesc.info
new file mode 100644
index 0000000..47b7ebc
--- /dev/null
+++ b/leveldesc.info
@@ -0,0 +1,406 @@
+label { name "work_level_desc"; addr $0780; size 2; comment "first 2 bytes are level number in screencodes"; };
+label { name "work_level_sub0"; addr $0782; size 2; comment "a subroutine"; };
+label { name "work_level_sub1"; addr $0784; size 2; comment "a subroutine"; };
+label { name "work_level_sub2"; addr $0786; size 2; comment "a subroutine"; };
+label { name "work_level_sub3"; addr $0788; size 2; comment "a subroutine"; };
+label { name "work_level_num_bombs"; addr $078a; size 1; comment "number of bombs to pick up on this level"; };
+label { name "work_level_bullet_chance"; addr $078b; size 1; comment "0 = no bullets"; };
+label { name "work_level_y_start"; addr $078c; size 1; comment "jumpman starting Y position"; };
+label { name "work_level_x_start"; addr $078d; size 1; comment "jumpman starting X position"; };
+label { name "work_level_offs_14"; addr $078e; size 2; comment "points to $0600"; };
+label { name "work_level_points_per_bomb"; addr $0790; size 1; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+label { name "work_level_time_bonus"; addr $0791; size 2; comment "amount of time bonus at start of level"; };
+label { name "work_level_offs_19"; addr $0793; size 1; comment "always $00"; };
+label { name "work_level_unkn_table0"; addr $0794; size 2; comment "pointer to ROM table or $06xx"; };
+label { name "work_level_map0"; addr $0796; size 2; comment "map data"; };
+label { name "work_level_map1"; addr $0798; size 2; comment "map data"; };
+label { name "work_level_map2"; addr $079a; size 2; comment "map data"; };
+label { name "work_level_unkn_table1"; addr $079c; size 2; comment "unknown, pointer to a ROM table or $0000"; };
+label { name "work_level_offs_30"; addr $079e; size 2; comment "always $0000"; };
+label { name "work_level_sub4"; addr $07a0; size 2; comment "$06E6 for most levels, or else a ROM subroutine"; };
+label { name "work_level_sub5"; addr $07a2; size 2; comment "$06E6 for some levels, or else a ROM subroutine"; };
+label { name "work_level_sub6"; addr $07a4; size 2; comment "always $9740 aka game_main_loop"; };
+label { name "work_level_sub_eol"; addr $07a6; size 2; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+label { name "work_level_offs_40"; addr $07a8; size 6; comment "all zeroes"; };
+label { name "work_level_offs_46"; addr $07ae; size 9; comment "unknown"; };
+label { name "work_level_offs_55"; addr $07b7; size 3; comment "unknown, always $00 $00 $00"; };
+label { name "work_level_offs_58"; addr $07ba; size 2; comment "unknown, not a ROM address"; };
+label { name "work_level_offs_60"; addr $07bc; size 4; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+label { name "cur_level_desc"; addr $07c0; size 2; comment "first 2 bytes are level number in screencodes"; };
+label { name "cur_level_sub0"; addr $07c2; size 2; comment "a subroutine"; };
+label { name "cur_level_sub1"; addr $07c4; size 2; comment "a subroutine"; };
+label { name "cur_level_sub2"; addr $07c6; size 2; comment "a subroutine"; };
+label { name "cur_level_sub3"; addr $07c8; size 2; comment "a subroutine"; };
+label { name "cur_level_num_bombs"; addr $07ca; size 1; comment "number of bombs to pick up on this level"; };
+label { name "cur_level_bullet_chance"; addr $07cb; size 1; comment "0 = no bullets"; };
+label { name "cur_level_y_start"; addr $07cc; size 1; comment "jumpman starting Y position"; };
+label { name "cur_level_x_start"; addr $07cd; size 1; comment "jumpman starting X position"; };
+label { name "cur_level_offs_14"; addr $07ce; size 2; comment "points to $0600"; };
+label { name "cur_level_points_per_bomb"; addr $07d0; size 1; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+label { name "cur_level_time_bonus"; addr $07d1; size 2; comment "amount of time bonus at start of level"; };
+label { name "cur_level_offs_19"; addr $07d3; size 1; comment "always $00"; };
+label { name "cur_level_unkn_table0"; addr $07d4; size 2; comment "pointer to ROM table or $06xx"; };
+label { name "cur_level_map0"; addr $07d6; size 2; comment "map data"; };
+label { name "cur_level_map1"; addr $07d8; size 2; comment "map data"; };
+label { name "cur_level_map2"; addr $07da; size 2; comment "map data"; };
+label { name "cur_level_unkn_table1"; addr $07dc; size 2; comment "unknown, pointer to a ROM table or $0000"; };
+label { name "cur_level_offs_30"; addr $07de; size 2; comment "always $0000"; };
+label { name "cur_level_sub4"; addr $07e0; size 2; comment "$06E6 for most levels, or else a ROM subroutine"; };
+label { name "cur_level_sub5"; addr $07e2; size 2; comment "$06E6 for some levels, or else a ROM subroutine"; };
+label { name "cur_level_sub6"; addr $07e4; size 2; comment "always $9740 aka game_main_loop"; };
+label { name "cur_level_sub_eol"; addr $07e6; size 2; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+label { name "cur_level_offs_40"; addr $07e8; size 6; comment "all zeroes"; };
+label { name "cur_level_offs_46"; addr $07ee; size 9; comment "unknown"; };
+label { name "cur_level_offs_55"; addr $07f7; size 3; comment "unknown, always $00 $00 $00"; };
+label { name "cur_level_offs_58"; addr $07fa; size 2; comment "unknown, not a ROM address"; };
+label { name "cur_level_offs_60"; addr $07fc; size 4; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level00_desc"; start $a000; end $a001; type bytetable; comment "64-byte level descriptors, 12 of them (1 per level). first 2 bytes are level number in screencodes"; };
+range { name "level00_sub0"; start $a002; end $a003; type addrtable; comment "a subroutine"; };
+range { name "level00_sub1"; start $a004; end $a005; type addrtable; comment "a subroutine"; };
+range { name "level00_sub2"; start $a006; end $a007; type addrtable; comment "a subroutine"; };
+range { name "level00_sub3"; start $a008; end $a009; type addrtable; comment "a subroutine"; };
+range { name "level00_num_bombs"; start $a00a; end $a00a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level00_bullet_chance"; start $a00b; end $a00b; type bytetable; comment "0 = no bullets"; };
+range { name "level00_y_start"; start $a00c; end $a00c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level00_x_start"; start $a00d; end $a00d; type bytetable; comment "jumpman starting X position"; };
+range { name "level00_offs_14"; start $a00e; end $a00f; type bytetable; comment "points to $0600"; };
+range { name "level00_points_per_bomb"; start $a010; end $a010; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level00_time_bonus"; start $a011; end $a012; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level00_offs_19"; start $a013; end $a013; type bytetable; comment "always $00"; };
+range { name "level00_unkn_table0"; start $a014; end $a015; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level00_map0"; start $a016; end $a017; type addrtable; comment "map data"; };
+range { name "level00_map1"; start $a018; end $a019; type addrtable; comment "map data"; };
+range { name "level00_map2"; start $a01a; end $a01b; type addrtable; comment "map data"; };
+range { name "level00_unkn_table1"; start $a01c; end $a01d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level00_offs_30"; start $a01e; end $a01f; type bytetable; comment "always $0000"; };
+range { name "level00_sub4"; start $a020; end $a021; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level00_sub5"; start $a022; end $a023; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level00_sub6"; start $a024; end $a025; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level00_sub_eol"; start $a026; end $a027; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level00_offs_40"; start $a028; end $a02d; type bytetable; comment "all zeroes"; };
+range { name "level00_offs_46"; start $a02e; end $a036; type bytetable; comment "unknown"; };
+range { name "level00_offs_55"; start $a037; end $a039; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level00_offs_58"; start $a03a; end $a03b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level00_offs_60"; start $a03c; end $a03f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level01_desc"; start $a040; end $a041; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level01_sub0"; start $a042; end $a043; type addrtable; comment "a subroutine"; };
+range { name "level01_sub1"; start $a044; end $a045; type addrtable; comment "a subroutine"; };
+range { name "level01_sub2"; start $a046; end $a047; type addrtable; comment "a subroutine"; };
+range { name "level01_sub3"; start $a048; end $a049; type addrtable; comment "a subroutine"; };
+range { name "level01_num_bombs"; start $a04a; end $a04a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level01_bullet_chance"; start $a04b; end $a04b; type bytetable; comment "0 = no bullets"; };
+range { name "level01_y_start"; start $a04c; end $a04c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level01_x_start"; start $a04d; end $a04d; type bytetable; comment "jumpman starting X position"; };
+range { name "level01_offs_14"; start $a04e; end $a04f; type bytetable; comment "points to $0600"; };
+range { name "level01_points_per_bomb"; start $a050; end $a050; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level01_time_bonus"; start $a051; end $a052; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level01_offs_19"; start $a053; end $a053; type bytetable; comment "always $00"; };
+range { name "level01_unkn_table0"; start $a054; end $a055; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level01_map0"; start $a056; end $a057; type addrtable; comment "map data"; };
+range { name "level01_map1"; start $a058; end $a059; type addrtable; comment "map data"; };
+range { name "level01_map2"; start $a05a; end $a05b; type addrtable; comment "map data"; };
+range { name "level01_unkn_table1"; start $a05c; end $a05d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level01_offs_30"; start $a05e; end $a05f; type bytetable; comment "always $0000"; };
+range { name "level01_sub4"; start $a060; end $a061; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level01_sub5"; start $a062; end $a063; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level01_sub6"; start $a064; end $a065; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level01_sub_eol"; start $a066; end $a067; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level01_offs_40"; start $a068; end $a06d; type bytetable; comment "all zeroes"; };
+range { name "level01_offs_46"; start $a06e; end $a076; type bytetable; comment "unknown"; };
+range { name "level01_offs_55"; start $a077; end $a079; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level01_offs_58"; start $a07a; end $a07b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level01_offs_60"; start $a07c; end $a07f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level02_desc"; start $a080; end $a081; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level02_sub0"; start $a082; end $a083; type addrtable; comment "a subroutine"; };
+range { name "level02_sub1"; start $a084; end $a085; type addrtable; comment "a subroutine"; };
+range { name "level02_sub2"; start $a086; end $a087; type addrtable; comment "a subroutine"; };
+range { name "level02_sub3"; start $a088; end $a089; type addrtable; comment "a subroutine"; };
+range { name "level02_num_bombs"; start $a08a; end $a08a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level02_bullet_chance"; start $a08b; end $a08b; type bytetable; comment "0 = no bullets"; };
+range { name "level02_y_start"; start $a08c; end $a08c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level02_x_start"; start $a08d; end $a08d; type bytetable; comment "jumpman starting X position"; };
+range { name "level02_offs_14"; start $a08e; end $a08f; type bytetable; comment "points to $0600"; };
+range { name "level02_points_per_bomb"; start $a090; end $a090; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level02_time_bonus"; start $a091; end $a092; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level02_offs_19"; start $a093; end $a093; type bytetable; comment "always $00"; };
+range { name "level02_unkn_table0"; start $a094; end $a095; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level02_map0"; start $a096; end $a097; type addrtable; comment "map data"; };
+range { name "level02_map1"; start $a098; end $a099; type addrtable; comment "map data"; };
+range { name "level02_map2"; start $a09a; end $a09b; type addrtable; comment "map data"; };
+range { name "level02_unkn_table1"; start $a09c; end $a09d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level02_offs_30"; start $a09e; end $a09f; type bytetable; comment "always $0000"; };
+range { name "level02_sub4"; start $a0a0; end $a0a1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level02_sub5"; start $a0a2; end $a0a3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level02_sub6"; start $a0a4; end $a0a5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level02_sub_eol"; start $a0a6; end $a0a7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level02_offs_40"; start $a0a8; end $a0ad; type bytetable; comment "all zeroes"; };
+range { name "level02_offs_46"; start $a0ae; end $a0b6; type bytetable; comment "unknown"; };
+range { name "level02_offs_55"; start $a0b7; end $a0b9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level02_offs_58"; start $a0ba; end $a0bb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level02_offs_60"; start $a0bc; end $a0bf; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level03_desc"; start $a0c0; end $a0c1; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level03_sub0"; start $a0c2; end $a0c3; type addrtable; comment "a subroutine"; };
+range { name "level03_sub1"; start $a0c4; end $a0c5; type addrtable; comment "a subroutine"; };
+range { name "level03_sub2"; start $a0c6; end $a0c7; type addrtable; comment "a subroutine"; };
+range { name "level03_sub3"; start $a0c8; end $a0c9; type addrtable; comment "a subroutine"; };
+range { name "level03_num_bombs"; start $a0ca; end $a0ca; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level03_bullet_chance"; start $a0cb; end $a0cb; type bytetable; comment "0 = no bullets"; };
+range { name "level03_y_start"; start $a0cc; end $a0cc; type bytetable; comment "jumpman starting Y position"; };
+range { name "level03_x_start"; start $a0cd; end $a0cd; type bytetable; comment "jumpman starting X position"; };
+range { name "level03_offs_14"; start $a0ce; end $a0cf; type bytetable; comment "points to $0600"; };
+range { name "level03_points_per_bomb"; start $a0d0; end $a0d0; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level03_time_bonus"; start $a0d1; end $a0d2; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level03_offs_19"; start $a0d3; end $a0d3; type bytetable; comment "always $00"; };
+range { name "level03_unkn_table0"; start $a0d4; end $a0d5; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level03_map0"; start $a0d6; end $a0d7; type addrtable; comment "map data"; };
+range { name "level03_map1"; start $a0d8; end $a0d9; type addrtable; comment "map data"; };
+range { name "level03_map2"; start $a0da; end $a0db; type addrtable; comment "map data"; };
+range { name "level03_unkn_table1"; start $a0dc; end $a0dd; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level03_offs_30"; start $a0de; end $a0df; type bytetable; comment "always $0000"; };
+range { name "level03_sub4"; start $a0e0; end $a0e1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level03_sub5"; start $a0e2; end $a0e3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level03_sub6"; start $a0e4; end $a0e5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level03_sub_eol"; start $a0e6; end $a0e7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level03_offs_40"; start $a0e8; end $a0ed; type bytetable; comment "all zeroes"; };
+range { name "level03_offs_46"; start $a0ee; end $a0f6; type bytetable; comment "unknown"; };
+range { name "level03_offs_55"; start $a0f7; end $a0f9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level03_offs_58"; start $a0fa; end $a0fb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level03_offs_60"; start $a0fc; end $a0ff; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level04_desc"; start $a100; end $a101; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level04_sub0"; start $a102; end $a103; type addrtable; comment "a subroutine"; };
+range { name "level04_sub1"; start $a104; end $a105; type addrtable; comment "a subroutine"; };
+range { name "level04_sub2"; start $a106; end $a107; type addrtable; comment "a subroutine"; };
+range { name "level04_sub3"; start $a108; end $a109; type addrtable; comment "a subroutine"; };
+range { name "level04_num_bombs"; start $a10a; end $a10a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level04_bullet_chance"; start $a10b; end $a10b; type bytetable; comment "0 = no bullets"; };
+range { name "level04_y_start"; start $a10c; end $a10c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level04_x_start"; start $a10d; end $a10d; type bytetable; comment "jumpman starting X position"; };
+range { name "level04_offs_14"; start $a10e; end $a10f; type bytetable; comment "points to $0600"; };
+range { name "level04_points_per_bomb"; start $a110; end $a110; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level04_time_bonus"; start $a111; end $a112; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level04_offs_19"; start $a113; end $a113; type bytetable; comment "always $00"; };
+range { name "level04_unkn_table0"; start $a114; end $a115; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level04_map0"; start $a116; end $a117; type addrtable; comment "map data"; };
+range { name "level04_map1"; start $a118; end $a119; type addrtable; comment "map data"; };
+range { name "level04_map2"; start $a11a; end $a11b; type addrtable; comment "map data"; };
+range { name "level04_unkn_table1"; start $a11c; end $a11d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level04_offs_30"; start $a11e; end $a11f; type bytetable; comment "always $0000"; };
+range { name "level04_sub4"; start $a120; end $a121; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level04_sub5"; start $a122; end $a123; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level04_sub6"; start $a124; end $a125; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level04_sub_eol"; start $a126; end $a127; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level04_offs_40"; start $a128; end $a12d; type bytetable; comment "all zeroes"; };
+range { name "level04_offs_46"; start $a12e; end $a136; type bytetable; comment "unknown"; };
+range { name "level04_offs_55"; start $a137; end $a139; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level04_offs_58"; start $a13a; end $a13b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level04_offs_60"; start $a13c; end $a13f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level05_desc"; start $a140; end $a141; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level05_sub0"; start $a142; end $a143; type addrtable; comment "a subroutine"; };
+range { name "level05_sub1"; start $a144; end $a145; type addrtable; comment "a subroutine"; };
+range { name "level05_sub2"; start $a146; end $a147; type addrtable; comment "a subroutine"; };
+range { name "level05_sub3"; start $a148; end $a149; type addrtable; comment "a subroutine"; };
+range { name "level05_num_bombs"; start $a14a; end $a14a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level05_bullet_chance"; start $a14b; end $a14b; type bytetable; comment "0 = no bullets"; };
+range { name "level05_y_start"; start $a14c; end $a14c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level05_x_start"; start $a14d; end $a14d; type bytetable; comment "jumpman starting X position"; };
+range { name "level05_offs_14"; start $a14e; end $a14f; type bytetable; comment "points to $0600"; };
+range { name "level05_points_per_bomb"; start $a150; end $a150; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level05_time_bonus"; start $a151; end $a152; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level05_offs_19"; start $a153; end $a153; type bytetable; comment "always $00"; };
+range { name "level05_unkn_table0"; start $a154; end $a155; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level05_map0"; start $a156; end $a157; type addrtable; comment "map data"; };
+range { name "level05_map1"; start $a158; end $a159; type addrtable; comment "map data"; };
+range { name "level05_map2"; start $a15a; end $a15b; type addrtable; comment "map data"; };
+range { name "level05_unkn_table1"; start $a15c; end $a15d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level05_offs_30"; start $a15e; end $a15f; type bytetable; comment "always $0000"; };
+range { name "level05_sub4"; start $a160; end $a161; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level05_sub5"; start $a162; end $a163; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level05_sub6"; start $a164; end $a165; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level05_sub_eol"; start $a166; end $a167; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level05_offs_40"; start $a168; end $a16d; type bytetable; comment "all zeroes"; };
+range { name "level05_offs_46"; start $a16e; end $a176; type bytetable; comment "unknown"; };
+range { name "level05_offs_55"; start $a177; end $a179; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level05_offs_58"; start $a17a; end $a17b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level05_offs_60"; start $a17c; end $a17f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level06_desc"; start $a180; end $a181; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level06_sub0"; start $a182; end $a183; type addrtable; comment "a subroutine"; };
+range { name "level06_sub1"; start $a184; end $a185; type addrtable; comment "a subroutine"; };
+range { name "level06_sub2"; start $a186; end $a187; type addrtable; comment "a subroutine"; };
+range { name "level06_sub3"; start $a188; end $a189; type addrtable; comment "a subroutine"; };
+range { name "level06_num_bombs"; start $a18a; end $a18a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level06_bullet_chance"; start $a18b; end $a18b; type bytetable; comment "0 = no bullets"; };
+range { name "level06_y_start"; start $a18c; end $a18c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level06_x_start"; start $a18d; end $a18d; type bytetable; comment "jumpman starting X position"; };
+range { name "level06_offs_14"; start $a18e; end $a18f; type bytetable; comment "points to $0600"; };
+range { name "level06_points_per_bomb"; start $a190; end $a190; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level06_time_bonus"; start $a191; end $a192; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level06_offs_19"; start $a193; end $a193; type bytetable; comment "always $00"; };
+range { name "level06_unkn_table0"; start $a194; end $a195; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level06_map0"; start $a196; end $a197; type addrtable; comment "map data"; };
+range { name "level06_map1"; start $a198; end $a199; type addrtable; comment "map data"; };
+range { name "level06_map2"; start $a19a; end $a19b; type addrtable; comment "map data"; };
+range { name "level06_unkn_table1"; start $a19c; end $a19d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level06_offs_30"; start $a19e; end $a19f; type bytetable; comment "always $0000"; };
+range { name "level06_sub4"; start $a1a0; end $a1a1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level06_sub5"; start $a1a2; end $a1a3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level06_sub6"; start $a1a4; end $a1a5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level06_sub_eol"; start $a1a6; end $a1a7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level06_offs_40"; start $a1a8; end $a1ad; type bytetable; comment "all zeroes"; };
+range { name "level06_offs_46"; start $a1ae; end $a1b6; type bytetable; comment "unknown"; };
+range { name "level06_offs_55"; start $a1b7; end $a1b9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level06_offs_58"; start $a1ba; end $a1bb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level06_offs_60"; start $a1bc; end $a1bf; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level07_desc"; start $a1c0; end $a1c1; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level07_sub0"; start $a1c2; end $a1c3; type addrtable; comment "a subroutine"; };
+range { name "level07_sub1"; start $a1c4; end $a1c5; type addrtable; comment "a subroutine"; };
+range { name "level07_sub2"; start $a1c6; end $a1c7; type addrtable; comment "a subroutine"; };
+range { name "level07_sub3"; start $a1c8; end $a1c9; type addrtable; comment "a subroutine"; };
+range { name "level07_num_bombs"; start $a1ca; end $a1ca; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level07_bullet_chance"; start $a1cb; end $a1cb; type bytetable; comment "0 = no bullets"; };
+range { name "level07_y_start"; start $a1cc; end $a1cc; type bytetable; comment "jumpman starting Y position"; };
+range { name "level07_x_start"; start $a1cd; end $a1cd; type bytetable; comment "jumpman starting X position"; };
+range { name "level07_offs_14"; start $a1ce; end $a1cf; type bytetable; comment "points to $0600"; };
+range { name "level07_points_per_bomb"; start $a1d0; end $a1d0; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level07_time_bonus"; start $a1d1; end $a1d2; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level07_offs_19"; start $a1d3; end $a1d3; type bytetable; comment "always $00"; };
+range { name "level07_unkn_table0"; start $a1d4; end $a1d5; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level07_map0"; start $a1d6; end $a1d7; type addrtable; comment "map data"; };
+range { name "level07_map1"; start $a1d8; end $a1d9; type addrtable; comment "map data"; };
+range { name "level07_map2"; start $a1da; end $a1db; type addrtable; comment "map data"; };
+range { name "level07_unkn_table1"; start $a1dc; end $a1dd; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level07_offs_30"; start $a1de; end $a1df; type bytetable; comment "always $0000"; };
+range { name "level07_sub4"; start $a1e0; end $a1e1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level07_sub5"; start $a1e2; end $a1e3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level07_sub6"; start $a1e4; end $a1e5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level07_sub_eol"; start $a1e6; end $a1e7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level07_offs_40"; start $a1e8; end $a1ed; type bytetable; comment "all zeroes"; };
+range { name "level07_offs_46"; start $a1ee; end $a1f6; type bytetable; comment "unknown"; };
+range { name "level07_offs_55"; start $a1f7; end $a1f9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level07_offs_58"; start $a1fa; end $a1fb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level07_offs_60"; start $a1fc; end $a1ff; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level08_desc"; start $a200; end $a201; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level08_sub0"; start $a202; end $a203; type addrtable; comment "a subroutine"; };
+range { name "level08_sub1"; start $a204; end $a205; type addrtable; comment "a subroutine"; };
+range { name "level08_sub2"; start $a206; end $a207; type addrtable; comment "a subroutine"; };
+range { name "level08_sub3"; start $a208; end $a209; type addrtable; comment "a subroutine"; };
+range { name "level08_num_bombs"; start $a20a; end $a20a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level08_bullet_chance"; start $a20b; end $a20b; type bytetable; comment "0 = no bullets"; };
+range { name "level08_y_start"; start $a20c; end $a20c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level08_x_start"; start $a20d; end $a20d; type bytetable; comment "jumpman starting X position"; };
+range { name "level08_offs_14"; start $a20e; end $a20f; type bytetable; comment "points to $0600"; };
+range { name "level08_points_per_bomb"; start $a210; end $a210; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level08_time_bonus"; start $a211; end $a212; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level08_offs_19"; start $a213; end $a213; type bytetable; comment "always $00"; };
+range { name "level08_unkn_table0"; start $a214; end $a215; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level08_map0"; start $a216; end $a217; type addrtable; comment "map data"; };
+range { name "level08_map1"; start $a218; end $a219; type addrtable; comment "map data"; };
+range { name "level08_map2"; start $a21a; end $a21b; type addrtable; comment "map data"; };
+range { name "level08_unkn_table1"; start $a21c; end $a21d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level08_offs_30"; start $a21e; end $a21f; type bytetable; comment "always $0000"; };
+range { name "level08_sub4"; start $a220; end $a221; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level08_sub5"; start $a222; end $a223; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level08_sub6"; start $a224; end $a225; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level08_sub_eol"; start $a226; end $a227; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level08_offs_40"; start $a228; end $a22d; type bytetable; comment "all zeroes"; };
+range { name "level08_offs_46"; start $a22e; end $a236; type bytetable; comment "unknown"; };
+range { name "level08_offs_55"; start $a237; end $a239; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level08_offs_58"; start $a23a; end $a23b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level08_offs_60"; start $a23c; end $a23f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level09_desc"; start $a240; end $a241; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level09_sub0"; start $a242; end $a243; type addrtable; comment "a subroutine"; };
+range { name "level09_sub1"; start $a244; end $a245; type addrtable; comment "a subroutine"; };
+range { name "level09_sub2"; start $a246; end $a247; type addrtable; comment "a subroutine"; };
+range { name "level09_sub3"; start $a248; end $a249; type addrtable; comment "a subroutine"; };
+range { name "level09_num_bombs"; start $a24a; end $a24a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level09_bullet_chance"; start $a24b; end $a24b; type bytetable; comment "0 = no bullets"; };
+range { name "level09_y_start"; start $a24c; end $a24c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level09_x_start"; start $a24d; end $a24d; type bytetable; comment "jumpman starting X position"; };
+range { name "level09_offs_14"; start $a24e; end $a24f; type bytetable; comment "points to $0600"; };
+range { name "level09_points_per_bomb"; start $a250; end $a250; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level09_time_bonus"; start $a251; end $a252; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level09_offs_19"; start $a253; end $a253; type bytetable; comment "always $00"; };
+range { name "level09_unkn_table0"; start $a254; end $a255; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level09_map0"; start $a256; end $a257; type addrtable; comment "map data"; };
+range { name "level09_map1"; start $a258; end $a259; type addrtable; comment "map data"; };
+range { name "level09_map2"; start $a25a; end $a25b; type addrtable; comment "map data"; };
+range { name "level09_unkn_table1"; start $a25c; end $a25d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level09_offs_30"; start $a25e; end $a25f; type bytetable; comment "always $0000"; };
+range { name "level09_sub4"; start $a260; end $a261; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level09_sub5"; start $a262; end $a263; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level09_sub6"; start $a264; end $a265; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level09_sub_eol"; start $a266; end $a267; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level09_offs_40"; start $a268; end $a26d; type bytetable; comment "all zeroes"; };
+range { name "level09_offs_46"; start $a26e; end $a276; type bytetable; comment "unknown"; };
+range { name "level09_offs_55"; start $a277; end $a279; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level09_offs_58"; start $a27a; end $a27b; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level09_offs_60"; start $a27c; end $a27f; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level10_desc"; start $a280; end $a281; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level10_sub0"; start $a282; end $a283; type addrtable; comment "a subroutine"; };
+range { name "level10_sub1"; start $a284; end $a285; type addrtable; comment "a subroutine"; };
+range { name "level10_sub2"; start $a286; end $a287; type addrtable; comment "a subroutine"; };
+range { name "level10_sub3"; start $a288; end $a289; type addrtable; comment "a subroutine"; };
+range { name "level10_num_bombs"; start $a28a; end $a28a; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level10_bullet_chance"; start $a28b; end $a28b; type bytetable; comment "0 = no bullets"; };
+range { name "level10_y_start"; start $a28c; end $a28c; type bytetable; comment "jumpman starting Y position"; };
+range { name "level10_x_start"; start $a28d; end $a28d; type bytetable; comment "jumpman starting X position"; };
+range { name "level10_offs_14"; start $a28e; end $a28f; type bytetable; comment "points to $0600"; };
+range { name "level10_points_per_bomb"; start $a290; end $a290; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level10_time_bonus"; start $a291; end $a292; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level10_offs_19"; start $a293; end $a293; type bytetable; comment "always $00"; };
+range { name "level10_unkn_table0"; start $a294; end $a295; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level10_map0"; start $a296; end $a297; type addrtable; comment "map data"; };
+range { name "level10_map1"; start $a298; end $a299; type addrtable; comment "map data"; };
+range { name "level10_map2"; start $a29a; end $a29b; type addrtable; comment "map data"; };
+range { name "level10_unkn_table1"; start $a29c; end $a29d; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level10_offs_30"; start $a29e; end $a29f; type bytetable; comment "always $0000"; };
+range { name "level10_sub4"; start $a2a0; end $a2a1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level10_sub5"; start $a2a2; end $a2a3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level10_sub6"; start $a2a4; end $a2a5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level10_sub_eol"; start $a2a6; end $a2a7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level10_offs_40"; start $a2a8; end $a2ad; type bytetable; comment "all zeroes"; };
+range { name "level10_offs_46"; start $a2ae; end $a2b6; type bytetable; comment "unknown"; };
+range { name "level10_offs_55"; start $a2b7; end $a2b9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level10_offs_58"; start $a2ba; end $a2bb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level10_offs_60"; start $a2bc; end $a2bf; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
+range { name "level11_desc"; start $a2c0; end $a2c1; type bytetable; comment "first 2 bytes are level number in screencodes"; };
+range { name "level11_sub0"; start $a2c2; end $a2c3; type addrtable; comment "a subroutine"; };
+range { name "level11_sub1"; start $a2c4; end $a2c5; type addrtable; comment "a subroutine"; };
+range { name "level11_sub2"; start $a2c6; end $a2c7; type addrtable; comment "a subroutine"; };
+range { name "level11_sub3"; start $a2c8; end $a2c9; type addrtable; comment "a subroutine"; };
+range { name "level11_num_bombs"; start $a2ca; end $a2ca; type bytetable; comment "number of bombs to pick up on this level"; };
+range { name "level11_bullet_chance"; start $a2cb; end $a2cb; type bytetable; comment "0 = no bullets"; };
+range { name "level11_y_start"; start $a2cc; end $a2cc; type bytetable; comment "jumpman starting Y position"; };
+range { name "level11_x_start"; start $a2cd; end $a2cd; type bytetable; comment "jumpman starting X position"; };
+range { name "level11_offs_14"; start $a2ce; end $a2cf; type bytetable; comment "points to $0600"; };
+range { name "level11_points_per_bomb"; start $a2d0; end $a2d0; type bytetable; comment "points awarded per bomb pickup (always $64 aka 100)"; };
+range { name "level11_time_bonus"; start $a2d1; end $a2d2; type wordtable; comment "amount of time bonus at start of level"; };
+range { name "level11_offs_19"; start $a2d3; end $a2d3; type bytetable; comment "always $00"; };
+range { name "level11_unkn_table0"; start $a2d4; end $a2d5; type addrtable; comment "pointer to ROM table or $06xx"; };
+range { name "level11_map0"; start $a2d6; end $a2d7; type addrtable; comment "map data"; };
+range { name "level11_map1"; start $a2d8; end $a2d9; type addrtable; comment "map data"; };
+range { name "level11_map2"; start $a2da; end $a2db; type addrtable; comment "map data"; };
+range { name "level11_unkn_table1"; start $a2dc; end $a2dd; type addrtable; comment "unknown, pointer to a ROM table or $0000"; };
+range { name "level11_offs_30"; start $a2de; end $a2df; type bytetable; comment "always $0000"; };
+range { name "level11_sub4"; start $a2e0; end $a2e1; type addrtable; comment "$06E6 for most levels, or else a ROM subroutine"; };
+range { name "level11_sub5"; start $a2e2; end $a2e3; type addrtable; comment "$06E6 for some levels, or else a ROM subroutine"; };
+range { name "level11_sub6"; start $a2e4; end $a2e5; type addrtable; comment "always $9740 aka game_main_loop"; };
+range { name "level11_sub_eol"; start $a2e6; end $a2e7; type addrtable; comment "called at end of level (all bombs picked up). $06E6 for all but level07"; };
+range { name "level11_offs_40"; start $a2e8; end $a2ed; type bytetable; comment "all zeroes"; };
+range { name "level11_offs_46"; start $a2ee; end $a2f6; type bytetable; comment "unknown"; };
+range { name "level11_offs_55"; start $a2f7; end $a2f9; type bytetable; comment "unknown, always $00 $00 $00"; };
+range { name "level11_offs_58"; start $a2fa; end $a2fb; type bytetable; comment "unknown, not a ROM address"; };
+range { name "level11_offs_60"; start $a2fc; end $a2ff; type bytetable; comment "unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00"; };
+
diff --git a/main.info b/main.info
new file mode 100644
index 0000000..543d4ff
--- /dev/null
+++ b/main.info
@@ -0,0 +1,501 @@
+
+# da65 info file for jumpman junior ROM.
+
+GLOBAL {
+ OUTPUTNAME "jumpmanjr.dasm";
+ INPUTNAME "jumpmanjr.rom";
+ STARTADDR $8000;
+ CPU "6502";
+ COMMENTS 4;
+};
+
+#SEGMENT { START $8000; END $BFFF; NAME "jumpmanjr"; };
+
+ASMINC { FILE "jumpmanjr.inc"; };
+
+# RANGE { START $whatever; END $whatever; TYPE Code|ByteTable|AddrTable|RtsTable; }
+
+label { name "cart_start_stub"; addr $8AFE; };
+label { name "cart_entry_point"; addr $8ac0; };
+label { name "check_keycode"; addr $9C07; };
+label { name "store_speed_value"; addr $9C13; };
+label { name "keyboard_isr_exit"; addr $9C0F; };
+label { name "check_consol"; addr $88C8; };
+label { name "ask_num_players"; addr $9400; };
+label { name "sl_loop"; addr $96D8; };
+label { name "materialize_jumpman"; addr $977B; };
+label { name "mj_clear_loop"; addr $9782; };
+label { name "mj_set_freq_and_color"; addr $97BB; };
+label { name "mj_delay"; addr $97CD; };
+label { name "mj_done"; addr $97DB; };
+label { name "game_main_loop"; addr $9740; };
+
+label { name "copy_level_desc_2"; addr $9677; comment "copy level descriptor to $0780"; };
+label { name "randomize_level"; addr $9BED; comment "only after beating levels 1-12 in order"; };
+label { name "enter_level"; addr $96BA; comment "maybe this should be check_level or init_level?"; };
+label { name "copy_level_desc"; addr $96CE; comment "copy level descriptor from levelXX_desc at $A000+(level*$40) to $07c0-$07ff"; };
+label { name "randomizer_mode"; addr $06F3; comment "only after beating levels 1-12 in order"; };
+
+label { name "init_loop"; addr $8ac4; comment "clear pages 6 and 7"; };
+label { name "set_vkeybd"; addr $83ED; comment "VKEYBD now points to $9c00 aka keyboard_isr"; };
+label { name "set_vvblki"; addr $8401; comment "VVBLKI now points to $840d aka vblank_imm_isr"; };
+label { name "vblank_imm_isr"; addr $840d; comment "service immediate vblank interrupt"; };
+
+label { name "dli_chained_1"; addr $9B72; comment "changes DLI vector to point to dli_chained_2"; };
+label { name "dli_chained_2"; addr $9B87; comment "changes DLI vector to point to dli_chained_3"; };
+label { name "dli_chained_3"; addr $9BB1; comment "changes DLI vector to point to dli_chained_1"; };
+label { name "update_color_regs"; addr $840F; comment "update color regs from shadow regs (X ranges 1 to 9, GRAFM+1 is COLPM0, $2bf+1 is PCOLR0)"; };
+
+range { name "code_99f7"; start $99F7; end $9A1B; type code; };
+range { name "data_8406"; start $8406; end $840c; type bytetable; };
+range { name "data_9a1c"; start $9a1c; end $9A5B; type bytetable; };
+range { name "gameboard_dlist_data"; start $9B62; end $9b71; type bytetable; comment "this isn't used as-is for a display list, see setup_gameboard_dlist"; };
+RANGE { NAME "cartstart_left"; START $BFFA; END $BFFB ; TYPE AddrTable; comment "main entry point, note cartstart_left and cartstart_right point to the same address"; };
+RANGE { NAME "cartstart_right"; START $9FFA; END $9FFB ; TYPE AddrTable; comment "main entry point, note cartstart_left and cartstart_right point to the same address"; };
+RANGE { NAME "cartinit_left"; START $BFFE; END $BFFF ; TYPE AddrTable; comment "points to a CLC/RTS do-nothing routine (same as cartinit_right)"; };
+RANGE { NAME "cartinit_right"; START $9FFE; END $9FFF ; TYPE AddrTable; comment "points to a CLC/RTS do-nothing routine (same as cartinit_left)"; };
+
+range { name "cartpresent_left"; start $bffc; end $bffc; type bytetable; comment "0 here means 'cartridge present'"; };
+range { name "cartpresent_right"; start $9ffc; end $9ffc; type bytetable; comment "0 here means 'cartridge present'"; };
+range { name "cartoptions_left"; start $bffd; end $bffd; type bytetable; comment "4 here means init & start the cart, no disk boot, non-diagnostic"; };
+range { name "cartoptions_right"; start $9ffd; end $9ffd; type bytetable; comment "4 here means init & start the cart, no disk boot, non-diagnostic"; };
+
+label { name "VDSLST"; addr $0200; size 2; };
+label { name "FR1"; addr $00e0; size 6; };
+label { name "player_x_speed"; addr $95C5; size 20; comment "' PLAYER # SPEED? ' in PF2 color"; };
+label { name "num_name_hscrol_table"; addr $95D9; size 4; comment "used for centering ONE TWO THREE FOUR, see option_key_handler"; };
+label { name "number_names_0"; addr $95dd; size 4; comment "space space T space (names ONE TWO THREE FOUR)"; };
+label { name "number_names_1"; addr $95e1; size 4; comment "O T H F"; };
+label { name "number_names_2"; addr $95e5; size 4; comment "N W R O"; };
+label { name "number_names_3"; addr $95e9; size 4; comment "E O E U"; };
+label { name "number_names_4"; addr $95ed; size 4; comment "space space E R"; };
+label { name "sfx_select_key"; addr $95f1; comment "played when select key pressed, 4 notes, descending"; };
+label { name "missiles_mask_table_minus_one"; addr $82df; };
+label { name "set_dma_ctl"; addr $838F; comment "std playfield, enable players + missiles, single-line p/m res, DMA enabled"; };
+
+range { name "level_names"; start $BB00; end $bbef; type bytetable; };
+range { name "pm_memory"; start $2800; end $2fff; type bytetable; };
+range { name "missiles_mask_table"; start $82e0; end $82E7; type bytetable; };
+range { name "missiles_done"; start $82DD; end $82df; type code; };
+range { name "position_missiles"; start $8293; end $82DA; type code; };
+range { name "charset"; start $9e00; end $9ff9; type bytetable; comment "GR.1/2 font, 512 bytes"; };
+range { name "game_display_list"; start $0881; end $08e3; type bytetable; comment "display list for game board"; };
+range { name "title_display_list"; start $91B3; end $91ce; type bytetable; comment "display list for title screen"; };
+range { name "numplayer_display_list"; start $955f; end $9577; type bytetable; comment "display list for 'number of players' screen"; };
+label { name "setup_numplayer_dlist"; addr $9444; comment "set dlist shadow to point to numplayer_display_list"; };
+label { name "setup_numplayer_dli_sr"; addr $944e; comment "set dli vector to point to num_player_dli_service"; };
+label { name "anp_loop_done"; addr $9421; comment "X is now 0"; };
+label { name "anp_clear_loop"; addr $940D; comment "clear area where NUMBER OF PLAYERS? will be displayed"; };
+label { name "anp_copy_loop"; addr $9418; comment "copy NUMBER OF PLAYERS to screen RAM"; };
+label { name "save_collisions"; addr $8503; comment "save contents of GTIA collision regs (X ranges 1 to $10, dli_vec_shadow_hi should read collision_save-1)"; };
+
+label { name "check_collisions_1"; addr $8F73; size 1; comment "did any missile hit a player, or did players 2 or 3 hit a player..."; };
+label { name "check_collisions_2"; addr $981A; size 1; comment "did player 0 or 1 hit the playfield..."; };
+label { name "check_collisions_3"; addr $9832; size 1; comment "did player 0 or 1 hit the playfield..."; };
+label { name "collision_save"; addr $06B0; size 16; comment "save_collisions copies GTIA collision regs $D000-$d00f here"; };
+label { name "init_next_level"; addr $9BE8; size 1; comment "..."; };
+label { name "show_get_ready_prompt"; addr $9624; size 1; comment "only in multiplayer games"; };
+range { name "gr7_or_masks"; start $8143; end $8152; type bytetable; };
+range { name "gr7_and_masks"; start $8153; end $8156; type bytetable; };
+range { name "data_8892"; start $8892; end $88A7; type bytetable; };
+range { name "data_8dfa"; start $8DFA; end $8DFF; type bytetable; };
+range { name "data_8f43"; start $8F43; end $8f72; type bytetable; };
+
+##range { name "mus0_addr1"; start $8FC3; end $8fc4; type addrtable; comment "mus struct table, 5 bytes per entry: 0/1 are an address, 2/3 are another, 5 is maybe the length? tempo?"; };
+##range { name "mus0_addr2"; start $8FC5; end $8fc6; type addrtable; };
+##range { name "mus0_len_or_tempo"; start $8FC7; end $8fc7; type bytetable; };
+##
+##range { name "mus1_addr1"; start $8FC8; end $8fc9; type addrtable; };
+##range { name "mus1_addr2"; start $8FCA; end $8fcb; type addrtable; };
+##range { name "mus1_len_or_tempo"; start $8FCC; end $8fcc; type bytetable; };
+##
+##range { name "mus2_addr1"; start $8FC8; end $8fc9; type addrtable; };
+##range { name "mus2_addr2"; start $8FCA; end $8fcb; type addrtable; };
+##range { name "mus2_len_or_tempo"; start $8FCC; end $8fcc; type bytetable; };
+
+#range { name "more_mus"; start $8FC8; end $8fff; type bytetable; comment "more 5-byte structs"; };
+
+range { name "mus00_addr1"; start $8fc3; end $8fc4; type addrtable; comment "aka mus_struct_table, 5 bytes per entry"; };
+range { name "mus00_addr2"; start $8fc5; end $8fc6; type addrtable; };
+range { name "mus00_len_or_tempo"; start $8fc7; end $8fc7; type bytetable; };
+
+range { name "mus01_addr1"; start $8fc8; end $8fc9; type addrtable; };
+range { name "mus01_addr2"; start $8fca; end $8fcb; type addrtable; };
+range { name "mus01_len_or_tempo"; start $8fcc; end $8fcc; type bytetable; };
+
+range { name "mus02_addr1"; start $8fcd; end $8fce; type addrtable; comment "end of game tune"; };
+range { name "mus02_addr2"; start $8fcf; end $8fd0; type addrtable; };
+range { name "mus02_len_or_tempo"; start $8fd1; end $8fd1; type bytetable; };
+
+range { name "mus03_addr1"; start $8fd2; end $8fd3; type addrtable; };
+range { name "mus03_addr2"; start $8fd4; end $8fd5; type addrtable; };
+range { name "mus03_len_or_tempo"; start $8fd6; end $8fd6; type bytetable; };
+
+range { name "mus04_addr1"; start $8fd7; end $8fd8; type addrtable; };
+range { name "mus04_addr2"; start $8fd9; end $8fda; type addrtable; };
+range { name "mus04_len_or_tempo"; start $8fdb; end $8fdb; type bytetable; };
+
+range { name "mus05_addr1"; start $8fdc; end $8fdd; type addrtable; };
+range { name "mus05_addr2"; start $8fde; end $8fdf; type addrtable; };
+range { name "mus05_len_or_tempo"; start $8fe0; end $8fe0; type bytetable; };
+
+range { name "mus06_addr1"; start $8fe1; end $8fe2; type addrtable; };
+range { name "mus06_addr2"; start $8fe3; end $8fe4; type addrtable; };
+range { name "mus06_len_or_tempo"; start $8fe5; end $8fe5; type bytetable; };
+
+range { name "mus07_addr1"; start $8fe6; end $8fe7; type addrtable; };
+range { name "mus07_addr2"; start $8fe8; end $8fe9; type addrtable; };
+range { name "mus07_len_or_tempo"; start $8fea; end $8fea; type bytetable; };
+
+range { name "mus08_addr1"; start $8feb; end $8fec; type addrtable; comment "tune that plays while level is being drawn"; };
+range { name "mus08_addr2"; start $8fed; end $8fee; type addrtable; };
+range { name "mus08_len_or_tempo"; start $8fef; end $8fef; type bytetable; };
+
+range { name "mus09_addr1"; start $8ff0; end $8ff1; type addrtable; };
+range { name "mus09_addr2"; start $8ff2; end $8ff3; type addrtable; };
+range { name "mus09_len_or_tempo"; start $8ff4; end $8ff4; type bytetable; };
+
+range { name "mus10_addr1"; start $8ff5; end $8ff6; type addrtable; };
+range { name "mus10_addr2"; start $8ff7; end $8ff8; type addrtable; };
+range { name "mus10_len_or_tempo"; start $8ff9; end $8ff9; type bytetable; };
+
+range { name "mus11_addr1"; start $8ffa; end $8ffb; type addrtable; };
+range { name "mus11_addr2"; start $8ffc; end $8ffd; type addrtable; };
+range { name "mus11_len_or_tempo"; start $8ffe; end $8ffe; type bytetable; };
+
+range { name "empty_music_entry"; start $8fff; end $8fff; type bytetable; comment "empty music table entries point here"; };
+
+label { name "sfx_tempo_tmp"; addr $0661; comment "??"; };
+label { name "sfx_slot_curpos"; addr $064E; size 2; comment "address we've got to so far, playing this sfx"; };
+label { name "sfx_slot_tempo"; addr $063E; size 1; comment "tempo of this sfx"; };
+label { name "sfx_lock"; addr $062F; size 1; comment "lets other code know cue_sfx is still running? not 100% sure"; };
+label { name "inc_sfx_pos"; addr $8231; size 1; comment "point to next byte in current sfx slot indexed by X"; };
+label { name "sfx_finished"; addr $8226; size 1; comment "done playing this sfx, free up the slot, X-indexed"; };
+label { name "sfx_next_note"; addr $817D; size 1; };
+label { name "sfx_player_entry"; addr $8157; size 1; comment "we have 4 slots (because POKEY has 4 voices), X counts down by 2 from 10 to 2 (at 0, the loop exits)"; };
+label { name "next_sfx_slot"; addr $815F; size 1; };
+label { name "sfx_exit"; addr $815E; size 1; };
+label { name "is_slot_active"; addr $8163; size 1; comment "skip it, if slot is inactive"; };
+label { name "sfx_slot_timer"; addr $063F; size 1; };
+label { name "sfx_slot_duration"; addr $0646; size 1; };
+label { name "sfx_play_note"; addr $8206; size 1; comment "y==0, a>=4 on entry"; };
+label { name "sfx_play_rest"; addr $819E; size 1; comment "y==0 on entry"; };
+label { name "sfx_change_tempo"; addr $81AE; size 1; comment "y==0 on entry"; };
+label { name "sfx_jump"; addr $81C8; size 1; comment "I *think* this jumps to a different sfx address..."; };
+label { name "sfx_slot_freq"; addr $0647; size 1; };
+
+range { name "sfx00"; start $BDF2; end $BE24; type bytetable; };
+range { name "sfx01"; start $BE25; end $BE78; type bytetable; };
+range { name "sfx_extra_life"; start $BE79; end $BE8C; type bytetable; };
+range { name "sfx02"; start $BE8D; end $BEAE; type bytetable; comment "end of game tune, melody"; };
+range { name "sfx03"; start $BEAF; end $BED4; type bytetable; comment "end of game tune, bass"; };
+range { name "sfx04"; start $BED5; end $BEEC; type bytetable; comment "end level tune #1, bass"; };
+range { name "sfx05"; start $BEED; end $BF13; type bytetable; comment "end level tune #1, melody"; };
+range { name "sfx06"; start $BF14; end $BF2F; type bytetable; comment "end level tune #2, melody"; };
+range { name "sfx07"; start $BF30; end $BF49; type bytetable; comment "end level tune #2, bass"; };
+range { name "sfx08"; start $BF4A; end $BF5F; type bytetable; comment "end level tune #3, bass"; };
+range { name "sfx09"; start $BF60; end $BF83; type bytetable; comment "end level tune #3, melody"; };
+range { name "sfx10"; start $BF84; end $BFA5; type bytetable; comment "end level tune #4, melody"; };
+range { name "sfx11"; start $BFA6; end $BFBD; type bytetable; comment "end level tune #4, bass"; };
+range { name "sfx12"; start $BFBE; end $BFCF; type bytetable; comment "jumping sound"; };
+range { name "sfx13"; start $BFD0; end $BFE9; type bytetable; comment "funeral march melody"; };
+range { name "sfx14"; start $BFEA; end $BFF9; type bytetable; comment "funeral march bass"; };
+range { name "sfx15"; start $BABC; end $BAE9; type bytetable; comment "level intro music, melody"; };
+range { name "sfx16"; start $BAEA; end $BAFF; type bytetable; comment "level intro music, bass"; };
+
+range { name "code_8f38"; start $8F38; end $8F42; type code; };
+range { name "try_to_write_rom_again"; start $9126; end $9133; type code; comment "see comment at try_to_write_rom"; };
+range { name "code_adb5"; start $ADB5; end $adc0; type code; };
+range { name "code_adc1"; start $adc1; end $adc3; type code; };
+range { name "data_9134"; start $9134; end $9139; type bytetable; };
+label { name "maybe_data"; addr $913A; comment "this might be more data for the above table instead of code?"; };
+label { name "probly_code"; addr $913D; comment "this probably really is code"; };
+label { name "illegal_nop"; addr $AF1B; comment "NMOS 6502 illegal opcode, NOP zp"; };
+range { name "data_9afc"; start $9AFC; end $9aff; type bytetable; };
+range { name "num_player_dli_service"; start $9578; end $959a; type code; comment "DLI service routine, changes COLPF2, address gets stored in $6ae/$6af by code at $944e"; };
+range { name "dli_service_2"; start $bdc7; end $bdd1; type code; comment "DLI service routine, changes COLBK, address gets stored in $6ae/$6af by code at $bc3c"; };
+label { name "numplayer_screen_data_minus_one"; addr $959a; comment "1-indexed loop copies from here+1"; };
+range { name "numplayer_screen_data"; start $959b; end $95ff; type bytetable; comment "'number of players?', gets copied to $3800, see option_key_handler"; };
+range { name "sfx_add_life_bonus"; start $b896; end $b8a6; type bytetable; comment "played when adding bonus per life at end of level"; };
+range { name "mul_25_table"; start $b8a7; end $b8be; type wordtable; comment "multiply by 25"; };
+range { name "data_table_8a39"; start $8a39; end $8a7f; type bytetable; };
+range { name "data_table_86da"; start $86da; end $8713; type bytetable; };
+range { name "level_name_hscrol_table"; start $BBF0; end $BBff; type bytetable; comment "used for centering level name on gameboard"; };
+range { name "zero_filler_b8bf"; start $b8bf; end $b96a; type bytetable; comment "all zeroes, filler?"; };
+range { name "zero_filler_baab"; start $baab; end $babb; type bytetable; comment "filler?"; };
+range { name "code_bccd"; start $bccd; end $bcd8; type code; comment "dunno, but referenced by code at $BC6A"; };
+range { name "well_done_map"; start $bcd9; end $bd51; type bytetable; comment "level map used for the WELL DONE screen, when you beat level 12"; };
+range { name "well_done_shape"; start $bda0; end $bdc6; type bytetable; comment "used to draw the large WELL DONE banner"; };
+range { name "total_score_msg"; start $bdd2; end $bdf1; type bytetable; comment "not sure what displays this, but it's screen codes"; };
+range { name "zero_filler_8588"; start $B588; end $B696; type bytetable; };
+range { name "wind_table_1"; start $B76B; end $b7bf; type bytetable; comment "used in level11"; };
+label { name "wind_table_2"; addr $b771; };
+range { name "level00_map"; start $A300; end $a497; type bytetable; comment "level map data starts here"; };
+range { name "sfx_a52d"; start $A52D; end $A53C; type bytetable; comment "dunno, referenced by routine at $A50F"; };
+range { name "data_table_a542"; start $A542; end $A68B; type bytetable; comment "dunno, referenced by routine at $A498"; };
+range { name "dumbwaiter_player"; start $a782; end $A826; type bytetable; comment "the dumbwaiters from level02. stored upside-down."; };
+label { name "dw_platform_player"; addr $A685; comment "horizontally moving platforms from level02"; };
+range { name "data_table_a8fd"; start $a8fd; end $A9C6; type bytetable; comment "dunno, referenced by routine at $A8D4"; };
+range { name "map_aa90"; start $aa90; end $AD67; type bytetable; comment "dunno what this is for yet"; };
+label { name "map_aaa6"; addr $aaa6; comment "referenced by routine at $AA82"; };
+range { name "data_table_adc7"; start $adc7; end $af0c; type bytetable; comment "dunno, referenced by routines at $AD9E and $ADB5"; };
+range { name "sfx_afcb"; start $AFCB; end $b0c3; type bytetable; comment "referenced by routine at $AF96"; };
+label { name "map_b000"; addr $b000; comment "referenced by routine at $B0C4"; };
+range { name "data_table_85b6"; start $85b6; end $85bd; type bytetable; comment "used in vblank_imm_isr, not sure for what yet"; };
+range { name "data_table_85de"; start $85de; end $85f5; type bytetable; comment "dunno what this is for yet, but it's copied into page 6 by init_hardware"; };
+range { name "zero_filler_85f6"; start $85f6; end $85ff; type bytetable; comment "probably just filler"; };
+range { name "movement_direction_table"; start $85be; end $85dd; type wordtable; comment "X/Y movement, indexed by joystick_state << 1, each entry is XXYY, $FF is -1"; };
+range { name "get_ready_msg"; start $9714; end $9726; type bytetable; comment "PLAYER GET READY"; };
+range { name "pcolor0_table"; start $8B7B; end $8b7f; type bytetable; };
+range { name "color0_table"; start $9728; end $972b; type bytetable; };
+range { name "color0_table_minus_one"; start $9727; end $9727; type bytetable; };
+range { name "level_gfx"; start $9C21; end $9cff; type bytetable; comment "definitions for level graphics objects aka shapes. (girder segment, ladder, rope, etc)"; };
+label { name "sh_girder"; addr $9C33; comment "3 rows of pixels. 1st: 04 = 4 pixels wide, 00 00 = no X/Y offset, 01 01 01 01 = actual pixel data (4 color0 pixels). see level_maps.txt"; };
+label { name "sh_blank_4x4"; addr $9C49; };
+label { name "sh_ladder"; addr $9C5F; };
+label { name "sh_9c89"; addr $9c89; comment "dunno what this is yet"; };
+label { name "sh_bomb"; addr $9cb3; };
+label { name "sh_up_rope"; addr $9cc9; };
+label { name "sh_down_rope"; addr $9cda; };
+label { name "sh_9ceb"; addr $9ceb; comment "dunno what this is yet"; };
+range { name "sprite_table"; start $9d00; end $9dff; type bytetable; comment "jumpman's animation frames and other sprites, seem to be 10 bytes per sprite"; };
+range { name "sxf_b319"; start $b319; end $B44B; type bytetable; comment "referenced by routine at $B2FD"; };
+range { name "data_table_b1df"; start $b1df; end $B27d; type bytetable; comment "dunno what this is for yet"; };
+range { name "data_table_b2a8"; start $b2a8; end $B2df; type bytetable; comment "dunno what this is for yet"; };
+range { name "data_table_b50b"; start $b50b; end $B57b; type bytetable; comment "dunno what this is for yet"; };
+range { name "scores_screen_dlist"; start $8C52; end $8C67; type bytetable; comment "a GR.2-ish DL, with DLIs, screen mem at $3000, for player scores screen"; };
+label { name "reyalp_msg_minus_one"; addr $8c67; };
+label { name "show_reyalp_msg"; addr $8BC0; comment "shows PLAYER (backwards loop)"; };
+label { name "reyalp_msg_loop"; addr $8BC2; };
+label { name "check_10th"; addr $8BC8; comment "replace 10th char with the ASCII player number"; };
+label { name "continue_loop"; addr $8BD5; };
+label { name "check_alive"; addr $8BE9; comment "player still has lives left?"; };
+label { name "no_cross"; addr $8BEF; };
+label { name "what_are_we_waiting_for"; addr $8C39; comment "I *think* we're waiting for the music to finish playing..."; };
+
+label { name "jiffy_timer_1"; addr $061A; comment "gets incremented every frame"; };
+label { name "jiffy_timer_2"; addr $061B; comment "gets incremented every frame"; };
+label { name "bonus_jiffy_timer"; addr $0626; comment "gets incremented every frame when playing a level, bonus-=100 when this reaches 0"; };
+label { name "speed_jiffy_timer"; addr $061E; comment "counts 0..initial_speed"; };
+label { name "playing_level"; addr $0627; comment "0 = not playing, non-0 = playing"; };
+label { name "no_dec_bonus"; addr $848B; };
+label { name "add_time_bonus"; addr $8E0F; comment "score += time_bonus;"; };
+label { name "lt_64k"; addr $8E27; };
+label { name "wait_32_jiffies"; addr $8E3A; comment "533ms ntsc, 640ms pal"; };
+label { name "pick_random_music"; addr $8E41; comment "pick random sound effect between 4 and 7"; };
+label { name "cue_music"; addr $8F92; comment "setup to play whichever music is in A reg, using 5-byte sfx stuct (a music is a pair of sfx played simultaneously)"; };
+label { name "cue_music_jv"; addr $8018; comment "setup to play whichever music is in A reg, using 5-byte sfx stuct"; };
+label { name "cue_sfx_jv"; addr $8006; comment "setup to play sfx"; };
+label { name "cue_sfx"; addr $8255; comment "setup to play sfx at *sfx_ptr, tempo (?) A"; };
+label { name "cue_sfx_lowprior"; addr $8240; comment "if cue_sfx not already in progress, setup to play sfx at (sfx_slot_tempo, sfx_lock) tempo (?) A"; };
+label { name "sfx_ptr"; addr $063C; size 2; };
+label { name "cue_ok"; addr $8244; size 1; };
+label { name "cue_done"; addr $8278; size 1; };
+label { name "inc_done"; addr $823F; size 1; };
+
+label { name "wait_3_sec"; addr $8C4A; comment "wait 192 jiffies: 3.2 sec (ntsc), 3.84 sec (pal)"; };
+label { name "not_alive"; addr $8BEB; comment "no, show a cross instead of a space"; };
+label { name "store_space"; addr $8BE2; comment "$AF is the character to show after the score (space for alive, cross for dead)"; };
+range { name "reyalp_msg"; start $8C68; end $8C7a; type bytetable; comment "player spelled backwards: ' 0 # REYALP '"; };
+range { name "scores_msg"; start $8C7b; end $8C81; type bytetable; comment "' SCORES' in color 3"; };
+range { name "blank_dlist_8add"; start $8ADD; end $8adf; type bytetable; comment "yet another jump-to-itself empty display list"; };
+range { name "blank_dlist_8aeb"; start $8AEB; end $8aed; type bytetable; comment "another jump-to-itself empty display list"; };
+range { name "blank_dlist_8c82"; start $8C82; end $8C84; type bytetable; comment "looks like an empty jump-to-itself dlist"; };
+label { name "init_game"; addr $9000; comment "called from cart_entry_point routine"; };
+label { name "reinit_game"; addr $900C; comment "this entry point doesn't disable start/option keys"; };
+label { name "try_to_write_rom"; addr $9022; comment "seems to try to write $FF bytes to ROM that already contains $FF's (it's the solid block character in the font). possibly left over from early development before conversion to cartridge"; };
+label { name "setup_select_key_vec"; addr $901b; comment "set select key vector to ask_num_players at $9400, enable select key"; };
+label { name "setup_select_key_vec_again"; addr $9517; comment "set select key vector to ask_num_players at $9400, enable select key"; };
+label { name "disable_start_opt"; addr $94EC; comment "disable start and option keys"; };
+label { name "init_speed"; addr $952a; comment "initialize speed to -1"; };
+label { name "wait_for_speed"; addr $952F; comment "wait for keyboard IRQ handler to set a speed <= 8"; };
+label { name "speed_to_ascii"; addr $9540; comment "convert to ASCII digit"; };
+label { name "add_11_to_x"; addr $953B; comment "11-byte per-player struct?"; };
+label { name "struct_player_lives_offsets_minus_one"; addr $8C88; };
+label { name "struct_player_lives_offsets"; addr $8C89; comment "lookup table, offset from $713 to lives for indexed player"; };
+label { name "show_scores_screen"; addr $8C22; comment "set dlist shadow to scores_screen_dlist"; };
+label { name "display_speed"; addr $9542; comment "show it to the user"; };
+label { name "speed_value"; addr $06F9; comment "decoded speed (1-8)"; };
+label { name "show_player_speed_prompt"; addr $94F9; comment "copy PLAYER #n SPEED? to screen RAM"; };
+label { name "psprompt_loop"; addr $94fb; };
+range { name "get_ready_dlist"; start $972c; end $973f; type bytetable; comment "112 blank scanlines, then one GR.2 line, loaded from $0742"; };
+range { name "score_offsets"; start $8C85; end $8c8c; type bytetable; comment "offsets into screen memory, column 12, rows 2 3 4 5, used by code at $8BEF, loaded in $d3, hi byte in $d4 is $30"; };
+label { name "score_screen_dli_sr"; addr $8C8D; comment "used by score screen"; };
+label { name "set_score_screen_dli"; addr $8C31; comment "dli = score_screen_dli_sr"; };
+range { name "title_screen_data"; start $91cf; end $93ff; type bytetable; comment "title screen data"; };
+
+label { name "title_screen_data_minus_one"; addr $91ce; };
+label { name "copy_title_screen"; addr $902A; };
+label { name "wait_until_9c_is_0e"; addr $906E; comment "some ISR is writing to $9c..."; };
+label { name "funky_init_loop"; addr $90C8; comment "lot going on here, not understood yet"; };
+label { name "player_scores_screen"; addr $8B80; comment "show scores, called at end of game, also called after beating level 12 (after WELL DONE). $40 in NMIEN = disable DLI, enable VBI"; };
+label { name "read_joystick"; addr $84AC; comment "always joystick #1 (all players use the same joystick and pass it around)"; };
+label { name "check_joystick_enabled"; addr $84A4; comment "read the joystick if not disabled"; };
+label { name "fake_read_trigger"; addr $84CD; comment "??"; };
+label { name "read_trigger"; addr $84D3; comment "always joystick #1"; };
+label { name "store_joystick_state"; addr $84B1; comment "store bottom 4 bits of PORTA, or 0 if joystick_disabled"; };
+label { name "clear_collisions"; addr $850D; };
+label { name "update_dlist"; addr $8510; comment "update display list, if there's a new one in the shadow reg"; };
+label { name "update_dli_vector"; addr $8523; comment "update DLI vector, if there's a new one in the shadow reg"; };
+label { name "setup_get_ready_dl"; addr $964A; comment "06ac/06ad gets address of get_ready_dlist (why not SDLSTL/H?)"; };
+label { name "end_of_level_bonus"; addr $B800; };
+label { name "keycode_table_minus_one"; addr $9c18; };
+range { name "keyboard_isr"; start $9C00; end $9c18; type code; comment "only use of keyboard is to enter player speed before starting game"; };
+range { name "keycode_table"; start $9C19; end $9c20; type bytetable; };
+#label { name "mul_25_table"; addr $B8A7; size 2; };
+
+label { name "init_hardware"; addr $837c; };
+label { name "init_page6_loop"; addr $837e; comment "movement_direction_table+31 should read data_table_85de-1, da65 isn't perfect yet"; };
+
+# these are so far only for player 1
+label { name "number_of_players"; addr $06f4; size 1; comment "0 for single-player game, otherwise range 1-3 (2 to 4 players)"; };
+label { name "score"; addr $0700; size 3; };
+label { name "level"; addr $06f6; size 1; };
+label { name "lives"; addr $070a; size 1; };
+label { name "current_player"; addr $06fe; size 1; comment "*think* this ranges 1-4, not 0-3"; };
+label { name "player_speed"; addr $0624; size 1; };
+label { name "initial_speed"; addr $0625; size 1; };
+label { name "setup_dli_2"; addr $bc3f; size 1; comment "load dli_service_2 address into dli shadow"; };
+label { name "silence_audio"; addr $875B; size 1; comment "set all AUDFx to 0"; };
+label { name "sa_loop"; addr $875F; size 1; };
+label { name "store_audc"; addr $8DC6; size 1; comment "store A to AUDCx (and its ?shadow?)"; };
+label { name "set_prior"; addr $8798; size 1; comment "priority $11: pl0-3, pf0-3, bak (and enable 5th player from the missiles) [redundant? init_set_prior sets this, nothing appears to change it]"; };
+label { name "SAVMSC"; addr $58; size 2; comment "OS's idea of the start of screen memory [redundant to set here?]"; };
+label { name "set_char_base"; addr $83BB; size 1; comment "use character set at $9e00 aka charset"; };
+label { name "set_savmsc"; addr $83E9; size 1; comment "tell OS that screen memory starts at $3000"; };
+label { name "position_player_5"; addr $8310; size 1; comment "position the 4 missiles side-by-side"; };
+label { name "init_set_prior"; addr $8399; size 1; comment "priority $11: pl0-3, pf0-3, bak (and enable 5th player from the missiles)"; };
+label { name "joystick_disabled"; addr $0632; size 1; comment "nonzero = jumpman can't move (title screen or materialization, etc)"; };
+label { name "joystick_state"; addr $0633; size 1; comment "last PORTA read (bottom 4 bits), or 0 if joystick_disabled"; };
+label { name "trigger_disabled"; addr $0634; size 1; comment "nonzero = jumpman can't jump (he's already jumping, or title screen or materialization, etc)"; };
+label { name "trigger_state"; addr $0635; size 1; comment "last TRIG0 read (0 = pressed)"; };
+label { name "check_trigger_state"; addr $984D; size 1; comment "did user press the trigger?"; };
+label { name "trig_jmp"; addr $9852; size 1; comment "yes, jump to handler"; };
+label { name "check_up_down"; addr $9855; size 1; comment "did user move joystick up/down?"; };
+label { name "check_up_down_2"; addr $993B; size 1; comment "did user move joystick up/down?"; };
+label { name "trigger_handler"; addr $9985; size 1; comment "handle trigger presses (maybe start a jump)"; };
+label { name "cud_jmp"; addr $9860; size 1; comment "no, jump over handler"; };
+label { name "player_delta_x"; addr $0630; size 1; comment "amount to move jumpman this frame (1 or $FF aka -1)"; };
+label { name "player_delta_y"; addr $0631; size 1; comment "amount to move jumpman this frame (1 or $FF aka -1)"; };
+label { name "dli_vec_shadow_hi"; addr $06AF; size 1; comment "stored in VDSLST if nonzero"; };
+label { name "dli_vec_shadow_lo"; addr $06ae; size 1; comment "stored in VDSLST if dli_vec_shadow_hi nonzero"; };
+label { name "dlist_shadow_hi"; addr $06AD; size 1; comment "stored in DLISTH if nonzero"; };
+label { name "dlist_shadow_lo"; addr $06ac; size 1; comment "stored in DLISTL if dlist_shadow_hi nonzero"; };
+label { name "clear_dlist_shadow"; addr $851E; size 1; comment "clear the shadow now that we've updated the HW"; };
+label { name "clear_dli_shadow"; addr $8531; size 1; comment "clear the shadow now that we've updated the HW"; };
+label { name "enable_dli"; addr $8536; size 1; comment "enable DLI now that we've set up the vector"; };
+label { name "enable_keyboard_irq"; addr $8554; size 1; comment "$C0 = regular keypress, break keypress"; };
+label { name "silence_console_speaker"; addr $855A; size 1; comment "8 = silent (0 would be a click)"; };
+label { name "check_start_key"; addr $8561; size 1; comment "carry set = not pressed, clear = pressed"; };
+label { name "check_select_key"; addr $8573; size 1; comment "carry set = not pressed, clear = pressed"; };
+label { name "check_option_key"; addr $8580; size 1; comment "carry set = not pressed, clear = pressed"; };
+label { name "setup_start_key_vec"; addr $9465; size 1; comment "we'll jump to $94de aka get_player_speeds when start key is pressed"; };
+label { name "get_player_speeds"; addr $94de; size 1; comment "loop up to 4 times, ask PLAYER #n SPEED? and wait for number key press"; };
+label { name "setup_option_key_vec"; addr $9458; size 1; comment "we'll jump to $9489 aka option_key_handler when option key is pressed"; };
+label { name "start_key_vec"; addr $06c4; size 2; comment "vblank_imm_isr jumps thru here if start key pressed"; };
+label { name "select_key_vec"; addr $06c2; size 2; comment "vblank_imm_isr jumps thru here if select key pressed"; };
+label { name "option_key_vec"; addr $06c0; size 2; comment "vblank_imm_isr jumps thru here if option key pressed"; };
+label { name "start_key_enabled"; addr $06C8; size 1; comment "non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)"; };
+label { name "select_key_enabled"; addr $06C7; size 1; comment "non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)"; };
+label { name "option_key_enabled"; addr $06C6; size 1; comment "non-zero = jump through start_key_vec if start key pressed (checked by vblank_imm_isr)"; };
+label { name "zp_temp1"; addr $cb; size 2; comment "used for (zp,y) addressing, also for checking console keys in vblank_imm_isr"; };
+label { name "hang_main_thread"; addr $9486; size 1; comment "initialization done, everything's done in interrupts from here on out"; };
+label { name "option_key_handler"; addr $9489; size 1; comment "called via option_key_vec when someone presses option"; };
+
+label { name "level_finished"; addr $8E00; size 1; };
+label { name "level_finished_jv"; addr $802D; size 1; };
+label { name "decrement_time_bonus"; addr $8DCE; size 1; comment "bonus -= 100;"; };
+label { name "decrement_time_bonus_jv"; addr $8021; size 1; comment "bonus -= 100;"; };
+label { name "check_bonus_0"; addr $8DD7; size 1; comment "don't decrement if bonus == 0"; };
+label { name "dec_done"; addr $8DF9; size 1; };
+label { name "bonus_lt_256"; addr $8DE7; size 1; };
+
+label { name "set_y"; addr $8F9B; size 1; comment "y = a * 5; // offset into mus_struct_table"; };
+
+
+label { name "show_level_name"; addr $BA5D; size 1; comment "copy level name into screen RAM"; };
+label { name "sync_to_music"; addr $BA71; size 1; comment "level is already drawn with all color regs set to black. for each color reg, wait 1 sec before turning it visible. this syncs up with the music because the music was written to sync with this actually"; };
+label { name "wait_1_sec"; addr $BA9E; size 1; comment "actually 64 jiffies, 1.067S ntsc, 1.28s pal"; };
+label { name "keep_waiting"; addr $BAA3; size 1; };
+label { name "enable_joystick"; addr $8775; size 1; comment "called after level-intro music is finished playing"; };
+label { name "enable_joystick_jv"; addr $801B; size 1; comment "called after level-intro music is finished playing"; };
+label { name "ej_loop"; addr $8777; size 1; };
+label { name "hide_player"; addr $8DB8; size 1; comment "move player selected by X reg minus one off the left edge of the screen"; };
+label { name "play_select_key_sfx"; addr $946F; size 1; comment "play sfx_select_key at $95f1"; };
+label { name "wait_sfx"; addr $947C; size 1; comment "wait for sound to finish playing"; };
+label { name "play_life_bonus_sfx"; addr $B868; size 1; comment "play once per life"; };
+label { name "add_life_bonus"; addr $B83B; size 1; };
+label { name "sfx_option_pressed"; addr $8ab0; size 1; };
+label { name "play_opt_key_sfx"; addr $94BC; size 1; };
+label { name "wait_opt_key_sfx"; addr $94CE; size 1; comment "wait until it's done playing"; };
+range { name "map_b11a"; start $B11A; end $b120; type bytetable; comment "dunno what this is for yet"; };
+label { name "block_char_minus_one"; addr $9e0f; size 1; comment "couple of places in the code try to write here"; };
+label { name "position_players"; addr $82E9; size 1; comment "X counts down 5..1 (starts at 6, immediately decremented, and loop is done with 0). zp_temp1 is ZP pointer to the current player or missile being written to ($2f00..$2b00, or p3/p2/p1/p0/missiles)."; };
+label { name "HPOSP0_minus_two"; addr $CFFE; size 1; };
+label { name "position_pm_vert"; addr $8322; size 1; };
+label { name "clear_pm"; addr $8342; size 1; comment "write zeroes to unused portion of this player/missile"; };
+label { name "position_done"; addr $82E8; size 1; };
+label { name "clear_pm_mem"; addr $872A; size 1; comment "clear P/M mem"; };
+label { name "clear_screen_mem"; addr $8714; size 1; comment "clear the gameboard screen memory (called before drawing a level, natch)"; };
+label { name "clear_screen_mem_jv"; addr $801E; size 1; comment "clear the gameboard screen memory (called before drawing a level, natch)"; };
+label { name "csm_loop"; addr $871F; size 1; };
+label { name "dm_obj_to_screen"; addr $80BD; size 1; comment "actually write the object's pixels to screen memory. quite hairy."; };
+label { name "unused_vecs"; addr $803F; size 1; comment "3 unused jump vectors, all pointed to the same RTS"; };
+label { name "unused_vec_rts"; addr $8048; size 1; comment "unused jump vectors point here"; };
+label { name "sfx_bounce_1"; addr $8A4B; size 1; comment "used when jumpman is falling?"; };
+range { name "sfx_bounce_2"; start $8a97; end $8abf; type bytetable; comment "used when jumpman is falling?"; };
+label { name "sfx_death"; addr $8a60; comment "jumpman hit by bullet or started falling"; };
+label { name "play_sfx_bounce_2"; addr $8A80; };
+label { name "play_sfx_bounce_1"; addr $899A; };
+label { name "falling_bounce"; addr $8983; comment "this looks like it hurts..."; };
+label { name "afterlife"; addr $9600; comment "multiple code paths jump here. replay level, load next level, or go back to ask_num_players"; };
+label { name "code_bd52"; addr $BD52; comment "referenced by code at $BC83"; };
+label { name "crumble_gameboard"; addr $8D00; comment "just lost your last life"; };
+label { name "crumble_gameboard_jv"; addr $8030; comment "just lost your last life"; };
+label { name "init_page_7"; addr $9A5C; };
+label { name "init_page_7_jv"; addr $8024; };
+range { name "data_9a71"; start $9A71; end $9a7b; type bytetable; comment "used by code above"; };
+range { name "l_equals"; start $8CFD; end $8CFF; type bytetable; comment "L= (for lives display)"; };
+label { name "add_extra_life"; addr $8CE4; comment "plays sfx_extra_life"; };
+label { name "show_l_equals"; addr $8CCE; comment "L= (for lives display)"; };
+label { name "show_lives_icons"; addr $86BB; comment "up to 6 jumpmen, and a + if lives > 6. char $C1 = jumpman icon, $CB = plus sign"; };
+label { name "show_current_player"; addr $86A7; comment "1 to 4"; };
+label { name "update_status_window"; addr $8694; comment "bottom 2 GR.1 lines on the game board"; };
+label { name "update_status_window_jv"; addr $8012; comment "bottom 2 GR.1 lines on the game board"; };
+label { name "setup_gameboard_dlist"; addr $9B00; comment "for some reason there are 2 copies of the display list, at $0800 and $0881"; };
+label { name "setup_gameboard_dlist_jv"; addr $8015; comment "for some reason there are 2 copies of the display list, at $0800 and $0881"; };
+label { name "xxx_level_something"; addr $8600; comment "gets called after the level is drawn & the intro music stops, and also during the level (?)"; };
+label { name "xxx_level_something_jv"; addr $8009; comment "gets called after the level is drawn & the intro music stops, and also during the level (?)"; };
+label { name "draw_map"; addr $8049; comment "the entry point for parsing the level map and drawing graphics from it. see level_maps.txt. caller must set $C0/$C1 to the address of the map data. modders beware: bogus map data can & will cause infinite loops."; };
+label { name "draw_map_jv"; addr $8000; comment "the entry point for parsing the level map and drawing graphics from it. see level_maps.txt."; };
+label { name "dm_get_opcode"; addr $804B; comment "$C0/$C1 points to $A300 (level00_desc) on the first call"; };
+label { name "dm_switch_opcode"; addr $804D; comment "map opcodes: $FC = jump, $FF = end, $FD = set drawing direction, $FE = select graphics object"; };
+label { name "dm_draw_gfx"; addr $8090; comment "handle gfx_draw opcode"; };
+label { name "dm_jump"; addr $805C; comment "handle gfx_jump opcode"; };
+label { name "dm_delta"; addr $806B; comment "handle gfx_delta opcode"; };
+label { name "dm_obj"; addr $8083; comment "handle gfx_object opcode"; };
+label { name "dm_fallthru"; addr $805B; comment "handle gfx_end opcode"; };
+label { name "dm_next_opcode"; addr $8075; comment "all the other opcode handlers jump here"; };
+label { name "dm_progctr"; addr $C0; size 2; comment "see draw_map and level_maps.txt"; };
+label { name "dm_delta_x"; addr $C9; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_delta_y"; addr $CA; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_objptr"; addr $C2; size 2; comment "see draw_map and level_maps.txt"; };
+label { name "dm_xpos"; addr $55; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_ypos"; addr $54; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_length"; addr $BF; size 1; comment "see draw_map and level_maps.txt"; };
+label { name "dm_draw_loop"; addr $809C; size 1; comment "loop 'dm_length' times"; };
+label { name "dm_draw_obj"; addr $80B4; size 1; comment "draw current object at current x/y position"; };
+label { name "dm_draw_obj_loop"; addr $80B6; size 1; comment "object definition ends with $FF"; };
+label { name "dm_count"; addr $BE; size 1; comment "graphics object definition is this long"; };
+label { name "dm_x_with_offset"; addr $C6; size 1; comment "graphics object X offset, plus dm_xpos"; };
+label { name "dm_y_with_offset"; addr $C7; size 1; comment "graphics object Y offset, plus dm_xpos"; };
+label { name "dm_screen_addr"; addr $C4; size 2; comment "points to byte to write gfx data to"; };
+label { name "calc_screen_addr"; addr $80D0; size 1; comment "calculate 40 * dm_y_with_offset + dm_x_with_offset + screen mem address, store in dm_screen_addr"; };
+label { name "store_rts"; addr $83B6; comment "store an RTS at $06E6, which will get JSR'ed to by unused level subroutines"; };
+label { name "well_done_screen"; addr $BC00; comment "the WELL DONE screen, when you beat all the levels. after this, the game plays random levels."; };
+label { name "cue_woop_sound"; addr $B4D3; };
+label { name "sfx_woop"; addr $B564; };
+label { name "got_all_bombs"; addr $9766; };
+label { name "call_eol_sub"; addr $976C; };
+
+# end of main.info, everything below here is generated by mklevelinfo.pl
diff --git a/mapping.txt b/mapping.txt
new file mode 100644
index 0000000..584b8a1
--- /dev/null
+++ b/mapping.txt
@@ -0,0 +1,8814 @@
+ MEMORY MAP
+
+ Locations zero to 255 ($0 to $FF) are called "page zero" and have
+ special importance for assembly language programmers since these
+ locations are accessed faster and easier by the machine.
+
+ Locations zero to 127 ($0 to $7F) are reserved as the OS page zero,
+ while 128 to 255 ($80 to $FF) are the BASIC and the user zero page
+ RAM. Locations zero to 1792 ($0 to $700) are all used as the OS and (if
+ the cartridge is present) 8K BASIC RAM (except page six). Locations
+ zero to 8191 ($0 to $1FFF) are the minimum required for operation
+ (8K).
+
+ Locations two through seven are not cleared on any start operation.
+
+ DECIMAL HEX LABEL
+
+ 0,1 0,1 LINZBS
+
+ LINBUG RAM, replaced by the monitor RAM See the OS
+ Listing, page 31. It seems to be used to store the VBLANK timer
+ value. One user application I've seen for location zero is in a
+ metronome program in De Re Atari. Also used in cross-
+ assembling the Atari OS.
+
+
+ 2,3 2,3 CASINI
+
+ Cassette initialization vector: JSR through here if the cassette
+ boot was successful. This address is extracted from the first six
+ bytes of a cassette boot file. The first byte is ignored. The second
+ contains the number of records, the third and fourth contain the
+ low and high bytes of the load address, and the fifth and sixth
+ contain the low and high bytes of the initialization address.
+ Control upon loading jumps to the load address plus six for a
+ multi-stage load and through CASINI for initialization. JSR
+ through DOSVEC (10 and 11; $A,$B) to transfer control to the
+ application.
+
+
+ 4,5 4,5 RAMLO
+
+ RAM pointer for the memory test used on powerup. Also used to
+ store the disk boot address--normally 1798 ($706)--for the
+ boot continuation routine.
+
+
+ 6 6 TRAMSZ
+
+ Temporary Register for RAM size; used during powerup
+ sequence to test RAM availability. This value is then moved to
+ RAMTOP, location 106 ($6A). Reads one when the BASIC or the
+ A (left) cartridge is plugged in.
+
+
+ 7 7 TSTDAT
+
+ RAM test data register. Reads one when the B or the right
+ cartridge is inserted.
+
+ RAMLO, TRAMSZ and TSTDAT are all used in testing the RAM
+ size on powerup. On DOS boot, RAMLO and TRAMSZ also act as
+ temporary storage for the boot continuation address. TRAMSZ
+ and TSTDAT are used later to flag whether or not the A (left)
+ and/or B (right) cartridges, respectively, are plugged in (non-
+ zero equals cartridge plugged in) and whether the disk is to be
+ hooted.
+
+ Locations eight through 15 ($8-$F) are cleared on coldstart only.
+
+
+ 8 8 WARMST
+
+ Warmstart flag. If the location reads zero, then it is in the middle
+ of powerup; 255 is the normal RESET status. Warmstart is similar
+ to pressing RESET, so should not wipe out memory, variables, or
+ programs. WARMST is initialized to zero and will not change
+ values unless POKEd or until the first time the RESET button is
+ pressed. It will then read 255 ($FF).
+
+ Warmstart normally vectors to location 58484 ($E474). WARMST
+ is checked by the NMI status register at 54287 ($D40F) when
+ RESET is pressed to see whether or not to re-initialize the
+ software or to re-boot the disk.
+
+
+ 9 9 BOOT?
+
+ Boot flag success indicator. A value of 255 in this location will
+ cause the system to lockup if RESET is pressed. If BOOT? reads
+ one, then the disk boot was successful; if it reads two, then the
+ cassette boot was successful. If it reads zero, then neither
+ peripheral was booted.
+
+ If it is set to two, then the cassette vector at locations two and
+ three will be used on RESET. Set to one, it will use the DOS
+ vector at 10 and 11 ($A and $B). Coldstart attempts both a
+ cassette and a disk boot and flags this location with the success or
+ failure of the boots. BOOT? is checked during both disk and
+ cassette boot.
+
+
+ 10,11 A,B DOSVEC
+
+ Start vector for disk (or non-cartridge) software. This is the
+ address BASIC jumps to when you call up DOS. Can be set by
+ user to point to your own routine, but RESET will return DOSVEC
+ to the original address. To prevent this, POKE 5446 with the LSB
+ and 5450 with the MSB of your vector address and re-save DOS
+ using the WRITE DOS FILES option in the menu. Locations 10
+ and 11 are usually loaded with 159 and 23 ($9F and $17),
+ respectively. This allows the DUPSYS section of DOS to be
+ loaded when called. It is initially set to blackboard mode vector
+ (58481; $E471--called by typing "BYE" or "B." from BASIC); it
+ will also vector to the cassette run address if no DOS vector is
+ loaded in. If you create an AUTORUN.SYS file that doesn't end
+ with an RTS instruction, you should set BOOT? to one and 580
+ ($244) to zero.
+
+
+ 12,13 C,D DOSINI
+
+ Initialization address for the disk boot. Also used to store the
+ cassette-boot RUN address, which is then moved to CASINI (2,
+ 3). When you powerup without either the disk or an autoboot
+ cassette tape, DOSINI will read zero in both locations.
+
+
+ 14,15 E,F APPMHI
+
+ Applications memory high limit and pointer to the end of your
+ BASIC program, used by both the OS and BASIC. It contains the
+ lowest address you can use to set up a screen and Display List
+ (which is also the highest address usable for programs and data
+ below which the display RAM may not be placed). The screen
+ handler will not OPEN the "S:" device if it would extend the
+ screen RAM or the Display List below this address; memory
+ above this address may be used for the screen display and other
+ data (PM graphics, etc.).
+
+ If an attempted screen mode change would extend the screen
+ memory below APPMHI, then the screen is set up for GRAPHICS
+ mode zero; MEMTOP (locations 741, 742; $2E5, $2E6) is updated
+ and an error is returned to the user. Otherwise, the memory is not
+ too small for the screen editor; the mode change will take effect
+ and MEMTOP will be updated. This is one of five locations used
+ by the OS to keep track of the user and display memory.
+ Initialized to zero by the OS at powerup. Remember, you cannot
+ set up a screen display below the location specified here.
+
+ If you use the area below the Display List for your character sets,
+ PM graphics or whatever, be sure to set APPMHI above the last
+ address used so that the screen or the DL data will not descend
+ and destroy your own data. See RAMTOP location 106 ($6A),
+ MEMTOP at 741, 742 ($2E5, $2E6), PMBASE at 54279 ($D407)
+ and CHBASE at 54281 ($D409) for more information.
+
+ Locations 16 through 127 ($10-$7F) are cleared on either cold- or
+ warmstart.
+
+
+ 16 10 POKMSK
+
+ POKEY interrupts: the IRQ service uses and alters this location.
+ Shadow for 53774 ($D20E). POKE with 112 ($70; also POKE this
+ same value into 53774) to disable the BREAK key. If the following
+ bits are set (to one), then these interrupts are enabled (bit
+ decimal values are in parentheses):
+
+ BIT DECIMAL FUNCTION
+ 7 128 The BREAK key is enabled.
+ 6 64 The "other key" interrupt is enabled.
+ 5 32 The serial input data ready interrupt is
+ enabled.
+ 4 16 The serial output data required interrupt is
+ enabled.
+ 3 8 The serial out transmission finished
+ interrupt is enabled.
+ 2 4 The POKEY timer four interrupt is enabled
+ (only in the "B" or later versions of the OS
+ ROMs).
+ 1 2 The POKEY timer two interrupt is enabled.
+ 0 1 The POKEY timer one interrupt is enabled.
+
+ Timer interrupt enable means the associated AUDF registers are
+ used as timers and will generate an interrupt request when they
+ have counted down to zero. See locations 528 to 535 ($210 to
+ $217) and the POKEY chip from locations 53760 ($D200) on, for a
+ full explanation. 192 ($C0) is the default on powerup.
+
+ You can also disable the BREAK key by POKEing here with 64
+ ($40; or any number less than 128; $80) and also in location
+ 53774. The problem with simple POKEs is that the BREAK key is
+ re-enabled when RESET is pressed and by the first PRINT
+ statement that displays to the screen, or any OPEN statement that
+ addresses the screen (S: or E:), or the first PRINT statement after
+ such an OPEN and any GRAPHICS command. In order to
+ continually disable the BREAK key if such commands are being
+ used, it's best to use a subroutine that checks the enable bits
+ frequently during input and output operations, and POKEs a
+ value less than 128 into the proper locations, such as:
+
+ 1000 BREAK = PEEK(16) - 128: IF BREA
+ K < 0 THEN RETURN
+ 1010 POKE 16, BREAK: POKE 53774, BRE
+ AK: RETURN
+
+ The new OS "B" version ROMs have a vector for the BREAK key
+ interrupt, which allows users to write their own routines to
+ process the interrupt in the desired manner. It is located at 566,
+ 567 ($236, $237).
+
+
+ 17 11 BRKKEY
+
+ Zero means the BREAK key is pressed; any other number means
+ it's not. A BREAK during I/O returns 128 ($80). Monitored by
+ both keyboard, display, cassette and screen handlers. See
+ location 16 ($A) for hints on disabling the BREAK key. The latest
+ editions of OS provide for a proper vector for BREAK interrupts.
+ The BREAK key abort status code is stored in STATUS (48; $30).
+ It is also checked during all I/O and scroll/draw routines. During
+ the keyboard handler routine, the status code is stored in DSTAT
+ (76; $4C). BRKKEY is turned off at powerup. BREAK key abort
+ status is flagged by setting BIT 7 of 53774 ($D20E). See the note
+ on the BREAK key vector, above.
+
+
+ 18,19,20 12,13,14 RTCLOK
+
+ Internal realtime clock. Location 20 increments every stage one
+ VBLANK interrupt (1/60 second = one jiffy) until it reaches 255
+ ($FF); then location 19 is incremented by one and 20 is reset to
+ zero (every 4.27 seconds). When location 19 reaches 255, it and
+ 20 are reset to zero and location 18 is incremented by one (every
+ 18.2 minutes or 65536 TV frames). To use these locations as a
+ timer of seconds, try:
+
+ TIME = INT((PEEK(18) * 65536 + PEEK(19) * 256 +
+ PEEK(20) )/60)
+
+ To see the count in jiffies, eliminate the "/60" at the end. To see
+ the count in minutes, change "/60" to "/360." The maximum
+ value of the RT clock is 16,777,215. When it reaches this value, it
+ will be reset to zero on the next VBLANK increment. This value is
+ the result of cubing 256 (i.e., 256 * 256 * 256), the maximum
+ number of increments in each clock register. The RT clock is
+ always updated every VBLANK regardless of the time-critical
+ nature of the code being processed.
+
+ A jiffy is actually a long time to the computer. It can perform
+ upwards of 8000 machine cycles in that time. Think of what can
+ be done in the VBLANK interval (one jiffy). In human terms, a
+ jiffy can be upwards of 20 minutes, as witnessed in the phrase "I'll
+ be ready in a jiffy." Compare this to the oft-quoted phrase, "I'll
+ be there in a minute," used by intent programmers to describe a
+ time frame upwards of one hour.
+ Users can POKE these clock registers with suitable values for
+ their own use. The realtime clock is always updated during the
+ VBLANK interval. Some of the other timer registers (locations
+ 536 to 544; $218 to $220) are not always updated when the OS is
+ executing time critical code.
+ Here's one way to use the realtime clock for a delay timer:
+
+ 10 GOSUB 100
+ .
+ .
+ .
+ 100 POKE 20,0: POKE 19,0
+ 110 IF NOT PEEK(19) THEN 110
+ 120 RETURN
+
+ Line 110 waits to see if location 19 returns to zero and, when it
+ does, passes control to the RETURN statement.
+
+ See COMPUTE!, August 1982, for a useful program to create a
+ small realtime clock that will continue to display during your
+ BASIC programming. See also De Re Atari for another realtime
+ clock application.
+
+
+ 21,22 15,16 BUFADR
+
+ Indirect buffer address register (page zero). Temporary pointer
+ to the current disk buffer.
+
+
+ 23 17 ICCOMT
+
+ Command for CIO vector. Stores the CIO command; used to find
+ the offset in the command table for the correct vector to the
+ handler routine.
+
+
+ 24,25 18,19 DSKFMS
+
+ Disk file manager pointer. Called JMPTBL by DOS; used as
+ vector to FMS.
+
+
+ 26,27 1A,1B DSKUTL
+
+ The disk utilities pointer. Called BUFADR by DOS, it points to
+ the area saved for a buffer for the utilities package (data buffer;
+ DBUF) or for the program area (MEMLO; 743, 744; $2E7, $2E8).
+
+
+ 28 1C PTIMOT
+
+ Printer timeout, called every printer status request. Initialized to
+ 30, which represents 32 seconds (the value is 64 seconds per 60
+ increments in this register); typical timeout for the Atari 825
+ printer is five seconds. The value is set by your printer handler
+ software. It is updated after each printer status request operation.
+ It gets the specific timeout status from location 748 ($2EC), which
+ is loaded there by SIO.
+
+ The new "B" type OS ROMs have apparently solved the problem
+ of timeout that haunted the "A" ROMs; you saw it when the
+ printer or the disk drive periodically went to sleep (timed out) for
+ a few seconds, causing severe anxiety attacks in the owners who
+ thought their Ataris had just mysteriously died. This is
+ compounded when one removes a disk from the drive, believing
+ the I/O process to be finished--only to have the drive start up
+ again after the timeout and trying to write to or read from a
+ nonexistent disk. Usually both the system and the user crash
+ simultaneously at this point. See the appendix for more
+ information on the new ROMs.
+
+
+ 29 1D PBPNT
+
+ Print buffer pointer; points to the current position (byte) in the
+ print buffer. Ranges from zero to the value in location 30.
+
+
+ 30 1E PBUFSZ
+
+ Print buffer size of printer record for current mode. Normal
+ buffer size and line size equals 40 bytes; double-width print
+ equals 20 bytes (most printers use their own control codes for
+ expanded print); sideways printing equals 29 bytes (Atari 820
+ printer only). Printer status request equals four. PBUFSZ is
+ initialized to 40. The printer handler checks to see if the same
+ value is in PBPNT and, if so, sends the contents of the buffer to
+ the printer.
+
+
+ 31 1F PTEMP
+
+ Temporary register used by the printer handler for the value of
+ the character being output to the printer.
+
+ ----------------------------------------------------------------------
+
+ Locations 32 to 47 ($20 to $2F) are the ZIOCB: Page zero Input-Output
+ Control Block. They use the same structure as the IOCB's at locations
+ 832 to 959 ($340 to $3BF). The ZIOCB is used to communicate I/O con-
+ trol data between CIO and the device handlers. When a CIO opera-
+ tion is initiated, the information stored in the IOCB channel is moved
+ here for use by the CIO routines. When the operation is finished, the
+ updated information is returned to the user area.
+
+
+ 32 20 ICHIDZ
+
+ Handler index number. Set by the OS as an index to the device
+ name table for the currently open file. If no file is open on this
+ IOCB (IOCB free), then this register is set to 255 ($FF).
+
+
+ 33 21 ICDNOZ
+
+ Device number or drive number Called MAXDEV by DOS to in-
+ dicate the maximum number of devices. Initialized to one.
+
+
+ 34 22 ICCOMZ
+
+ Command code byte set by the user to define how the rest of the
+ IOCB is formatted, and what I/O action is to be performed.
+
+
+ 35 23 ICSTAZ
+
+ Status of the last IOCB action returned by the device, set by the
+ OS. May or may not be the same status returned by the STATUS
+ command.
+
+
+ 36,37 24,25 ICBALZ/HZ
+
+ Buffer address for data transfer or the address of the file name for
+ commands such as OPEN, STATUS, etc.
+
+
+ 38,39 26,27 ICPTLZ/HZ
+
+ Put byte routine address set by the OS. It is the address minus
+ one byte of the device's "put one byte" routine. It points to CIO's
+ "IOCB not OPEN" on a CLOSE statement.
+
+
+ 40,41 28,29 ICBLLZ/HZ
+
+ Buffer length byte count used for PUT and GET operations;
+ decreased by one for each byte transferred.
+
+
+ 42 2A ICAX1Z
+
+ Auxiliary information first byte used in OPEN to specify the type
+ of file access needed.
+
+
+ 43 2B ICAX2Z
+
+ CIO working variables, also used by some serial port functions.
+ Auxiliary information second byte.
+
+
+ 44,45 2C,2D ICAX3Z/4Z
+
+ Used by BASIC NOTE and POINT commands for the transfer of
+ disk sector numbers. These next four bytes to location 47 are also
+ labelled as: ICSPRZ and are defined as spare bytes for local CIO
+ use.
+
+
+ 46 2E ICAX5Z
+
+ The byte being accessed within the sector noted in locations 44
+ and 45. It is also used for the IOCB Number multiplied by 16.
+ Each IOCB block is 16 bytes long. Other sources indicate that the
+ 6502 X register also contains this information.
+
+
+ 47 2F ICAX6Z
+
+ Spare byte. Also labelled CIOCHR, it is the temporary storage
+ for the character byte in the current PUT operation.
+
+ -------------------------------------------------------------------
+
+
+ 48 30 STATUS
+
+ Internal status storage. The SIO routines in ROM use this byte to
+ store the status of the current SIO operation. See page 166 of the
+ OS User's Manual for status values. STATUS uses location 793
+ ($319) as temporary storage. STATUS is also used as a storage
+ register for the timeout, BREAK abort and error values during
+ SIO routines.
+
+
+ 49 31 CHKSUM
+
+ Data frame checksum used by SIO: single byte sum with carry to
+ the least significant bit. Checksum is the value of the number of
+ bytes transmitted (255; $FF). When the number of transmitted
+ bytes equals the checksum, a checksum sent flag is set at location
+ 59 ($3B). Uses locations 53773 ($D20D) and 56 ($38) for com-
+ parison of values (bytes transmitted).
+
+
+ 50,51 32,33 BUFRLO/HI
+
+ Pointer to the data buffer, the contents of which are transmitted
+ during an I/O operation, used by SIO and the Device Control
+ Block (DCB); points to the byte to send or receive. Bytes are
+ transferred to the eight-bit parallel serial output holding register
+ or from the input holding register at 53773 ($D20D). This register
+ is a one-byte location used to hold the eight bits which will be
+ transmitted one bit at a time (serially) to or from the device. The
+ computer takes the eight bits for processing when the register is
+ full or replaces another byte in it when empty after a
+ transmission.
+
+
+ 52,53 34,35 BFENLO/HI
+
+ Next byte past the end of the SIO and DCB data buffer described
+ above.
+
+
+ 54 36 CRETRY
+
+ Number of command frame retries. Default is 13 ($0D). This is the
+ number of times a device will attempt to carry out a command
+ such as read a sector or format a disk.
+
+
+ 55 37 DRETRY
+
+ Number of device retries. The default is one.
+
+
+ 56 38 BUFRFL
+
+ Data buffer full flag (255; $FF equals full).
+
+
+ 57 39 RECVDN
+
+ Receive done flag (255; $FF equals done).
+
+
+ 58 3A XMTDON
+
+ Transmission done flag (255; $FF equals done).
+
+
+ 59 3B CHKSNT
+
+ Checksum sent flag (255; $FF equals sent).
+
+
+ 60 3C NOCKSM
+
+ Flag for "no checksum follows data." Not zero means no
+ checksum follows; zero equals checksum follows transmission
+ data.
+
+
+ 61 3D BPTR
+
+ Cassette buffer pointer: record data index into the portion of data
+ being read or written. Ranges from zero to the current value at
+ location 650 ($28A). When these values are equal, the buffer at
+ 1021 ($3FD) is empty if reading or full if writing. Initialized to 128
+ ($80).
+
+
+ 62 3E FTYPE
+
+ Inter-record gap type between cassette records, copied from
+ location 43 ($2B; ICAX2Z) in the ZIOCB, stored there from
+ DAUX2 (779; $30B) by the user. Normal gaps are a non-zero
+ positive number; continuous gaps are zero (negative number).
+
+
+ 63 3F FEOF
+
+ Cassette end of file flag. If the value is zero, an end of file (EOF)
+ has not been reached. Any other number means it has been
+ detected. An EOF record has been reached when the command
+ byte of a data record equals 254 ($FE). See location 1021 ($3FD).
+
+
+ 64 40 FREQ
+
+ Beep count retain register. Counts the number of beeps required
+ by the cassette handler during the OPEN command for play or
+ record operations; one beep for play, two for record.
+
+
+ 65 41 SOUNDR
+
+ Noisy I/O flag used by SIO to signal the beeping heard during
+ disk and cassette I/O. POKE here with zero for blessed silence
+ during these operations. Other numbers return the beep. In-
+ itialized to three. The hardware solution to this problem is to turn
+ your speaker volume down. This can also be used to silence the
+ digital track when playing synchronized voice/data tapes. See
+ location 54018.
+
+
+ 66 42 CRITIC
+
+ Critical I/O region flag; defines the current operation as a time-
+ critical section when the value here is non-zero. Checked at the
+ NMI process after the stage one VBLANK has been processed.
+ POKEing any number other than zero here will disable the repeat
+ action of the keys and change the sound of the CTRL-2 buzzer.
+
+ Zero is normal; setting CRITIC to a non-zero value suspends a
+ number of OS processes including system software timer coun-
+ ting (timers two, three, four and five; see locations 536 to 558;
+ $218 to $22E). It is suggested that you do not set CRITIC for any
+ length of time. When one timer is being set, CRITIC stops the
+ other timers to do so, causing a tiny amount of time to be "lost."
+ When CRITIC is zero, both stage one and stage two VBLANK
+ procedures will be executed. When non-zero, only the stage one
+ VBLANK will be processed.
+
+
+ 67-73 43-49 FMZSPG
+
+ Disk file manager system (FMS) page zero registers (seven
+ bytes).
+
+
+ 67,68 43,44 ZBUFP
+
+ Page zero buffer pointer to the user filename for disk I/O.
+
+
+ 69,70 45,46 ZDRVA
+
+ Page zero drive pointer. Copied to here from DBUFAL and
+ DBUFAH; 4905 and 4913 ($1329, $1331). Also used in FMS "free
+ sector," setup and "get sector" routines.
+
+
+ 71,72 47,48 ZSBA
+
+ Zero page sector buffer pointer.
+
+
+ 73 49 ERRNO
+
+ Disk I/O error number. Initialized to 159 ($9F) by FMS.
+
+
+ 74 4A CKEY
+
+ Cassette boot request flag on coldstart. Checks to see if the
+ START key is pressed and, if so, CKEY is set. Autoboot cassettes
+ are loaded by pressing the START console key while turning the
+ power on. In response to the beep, press the PLAY button on the
+ recorder.
+
+
+ 75 4B CASSBT
+
+ Cassette boot flag. The Atari attempts both a disk and a cassette
+ boot simultaneously. Zero here means no cassette boot was suc-
+ cessful. See location 9
+
+
+ 76 4C DSTAT
+
+ Display status and keyboard register used by the display handler.
+ Also used to indicate memory is too small for the screen mode,
+ cursor out of range error, and the BREAK abort status.
+
+
+ 77 4D ATRACT
+
+ Attract mode timer and flag. Attract mode rotates colors on your
+ screen at low luminance levels when the computer is on but no
+ keyboard input is read for a long time (seven to nine minutes).
+ This helps to save your TV screen from "burn-out" damage suf-
+ fered from being left on and not used. It is set to zero by IRQ
+ whenever a key is pressed, otherwise incremented every four
+ seconds by VBLANK (see locations 18 - 20; $12 - $14). When the
+ value in ATRACT reaches 127 ($7F), it is then set to 254 ($FE) un-
+ til attract mode is terminated. This sets the flag to reduce the
+ luminance and rotate the colors when the Atari is sitting idle.
+ POKE with 128 ($80) to see this effect immediately: it normally
+ takes seven to nine minutes to enable the attract mode. The OS
+ cannot "attract" color generated by DLI's, although your DLI
+ routine can, at a loss of time.
+
+ Joysticks alone will not reset location 77 to zero. You will have to
+ add a POKE 77,0 to your program periodically or frequently call
+ in a subroutine to prevent the Atari from entering attract mode if
+ you are not using any keyboard input.
+
+
+ 78 4E DRKMSK
+
+ Dark attract mask; set to 254 ($FE) for normal brightness when
+ the attract mode is inactive (see location 77). Set to 246 ($F6)
+ when the attract mode is active to guarantee screen color
+ luminance will not exceed 50% . Initialized to 254 ($FE).
+
+
+ 79 4F COLRSH
+
+ Color shift mask; attract color shifter; the color registers are
+ EORd with locations 78 and 79 at the stage two VBLANK (see
+ locations 18 - 20; $12 - $14). When set to zero and location 78
+ equals 246, color luminance is reduced 50%. COLRSH contains
+ the current value of location 19, therefore is given a new color
+ value every 4.27 seconds.
+
+ Bytes 80 to 122 ($50 to $7A) are used by the screen editor and display
+ handler.
+
+
+ 80 50 TEMP
+
+ Temporary register used by the display handler in moving data to
+ and from screen. Also called TMPCHR.
+
+
+ 81 51 HOLD1
+
+ Same as location 80. It is used also to hold the number of Display
+ List entries.
+
+
+ 82 52 LMARGN
+
+ Column of the left margin of text (GR.0 or text window only).
+ Zero is the value for the left edge of the screen; LMARGN is
+ initialized to two. You can POKE the margin locations to set them
+ to your specific program needs, such as POKE 82,10 to make the
+ left margin start ten locations from the edge of the screen.
+
+
+ 83 53 RMARGN
+
+ Right margin of the text screen initialized to 39 ($27). Both
+ locations 82 and 83 are user-alterable, but ignored in all
+ GRAPHICS modes except zero and the text window.
+ Margins work with the text window and blackboard mode and are
+ reset to their default values by pressing RESET. Margins have no
+ effect on scrolling or the printer. However, DELETE LINE and
+ INSERT LINE keys delete or insert 40 character lines (or delete
+ one program line), which always start at the left margin and wrap
+ around the screen edge back to the left margin again. The right
+ margin is ignored in the process. Also, logical lines are always
+ three physical lines no matter how long or short you make those
+ lines.
+ The beep you hear when you are coming to the end of the logical
+ line works by screen position independent of the margins. Try
+ setting your left margin at 25 (POKE 82,25) and typing a few lines
+ of characters. Although you have just a few characters beyond
+ 60, the buzzer will still sound on the third line of text.
+
+
+ 84 54 ROWCRS
+
+ Current graphics or text screen cursor row, value ranging from
+ zero to 191 ($BF) depending on the current GRAPHICS mode
+ (maximum number of rows, minus one). This location, together
+ with location 85 below, defines the cursor location for the next
+ element to be read/written to the screen. Rows run horizontally,
+ left to right across the TV screen. Row zero is the topmost line;
+ row 192 is the maximum value for the bottom-most line.
+
+
+ 85,86 55,56 COLCRS
+
+ Current graphics or text mode cursor column; values range from
+ zero to 319 (high byte, for screen mode eight) depending on
+ current GRAPHICS mode (maximum numher of columns minus
+ one). Location 86 will always be zero in modes zero through
+ seven. Home position is 0,0 (upper left-hand corner). Columns
+ run vertically from the top to the bottom down the TV screen, the
+ leftmost column being number zero, the rightmost column the
+ maximum value in that mode. The cursor has a complete top to
+ bottom, left to right wraparound on the screen.
+
+ ROWCRS and COLCRS define the cursor location for the next
+ element to be read from or written to in the main screen segment
+ of the display. For the text window cursor, values in locations 656
+ to 667 ($290 to $29B) are exchanged with the current values in
+ locations 84 to 95 ($54 to $5F), and location 123 ($7B) is set to 255
+ ($FF) to indicate the swap has taken place. ROWCRS and
+ COLCRS are also used in the DRAW and FILL functions to
+ contain the values of the endpoint of the line being drawn. The
+ color of the line is kept in location 763 ($2FB). These values are
+ loaded into locations 96 to 98 ($60 to $62) so that ROWCRS and
+ COLCRS may be altered during the operation.
+
+ BASIC's LOCATE statement not only examines the screen, but
+ also moves the cursor one position to the right at the next PRINT
+ or PUT statement. It does this by updating locations 84 and 85,
+ above. You can override the cursor advance by saving the
+ contents of the screen before the LOCATE command, then
+ restoring them after the LOCATE. Try:
+
+ 100 REM: THE SCREEN MUST HAVE BEEN 0
+ PENED FOR READ OR READ/WRITE PREV
+ IOUSLY
+ 110 LOOK = PEEK(84): SEE = PEEK(85)
+ 120 LOCATE X,Y,THIS
+ 130 POKE 84, LOOK: POKE 65, SEE
+
+ Note that CHR$(253) is a non-printing character---the bell--
+ and doesn't affect the cursor position.
+
+ See COMPUTE!, August 198l, for an example of using COLCRS
+ for dynamic data restore and updating with the screen editor and
+ the IOCBs.
+
+
+ 87 57 DINDEX
+
+ Display mode/current screen mode. Labelled CRMODE by (*M).
+ DINDEX contains the number obtained from the low order four
+ bits of most recent open AUX1 byte. It can be used to fool the OS
+ into thinking you are in a different GRAPHICS mode by
+ POKEing DINDEX with a number from zero to 11. POKE with
+ seven after you have entered GRAPHICS mode eight, and it will
+ give you a split screen with mode seven on top and mode eight
+ below. However, in order to use both halves of the screen, you
+ will have to modify location 89 (below) to point to the area of the
+ screen you wish to DRAW in. (See Your Atan 400/800, pp. 280 -
+ 283.)
+ Watch for the cursor out-of-range errors (number 141) when
+ changing GRAPHICS modes in this manner and either PRINTing
+ or DRAWing to the new mode screen. POKE 87 with the BASIC
+ mode number, not the ANTIC mode number.
+ Did you know you can use PLOT and DRAWTO in GR.0? Try
+ this:
+
+ 10 GR.0
+ 20 PLOT 0,0: DRAWTO 10,10: DRAWTO 0
+ ,10
+ 30 DRAWTO 39,0: DRAWTO 20,23: DRAWT
+ O 0,20
+ 40 GOTO 40
+
+ You can also set the text window for PRINT and PLOT modes by
+ POKEing 87 with the graphics mode for the window. Then you
+ must POKE the address of the top left corner of the text window
+ into 88 and 89 ($58, $59). The screen mode of the text window is
+ stored at location 659 ($293).
+
+ You may have already discovered that you cannot call up the
+ GTIA modes from a direct command. Like the + 16 GRAPHICS
+ modes, they can only be called up during a program, and the
+ screen display will be reset to GR.0 on the first INPUT or PRINT
+ (not PRINT#6) statement executed in these modes.
+
+ Since this location only takes BASIC modes, you can't POKE it
+ with the other ANTIC modes such as "E", the famous "seven-and-
+ a-half" mode which offers higher resolution than seven and a four
+ color display (used in Datasoft's Micropainter program). If you're
+ not drawing to the screen, simply using it for display purposes,
+ you can always go into the Display List and change the
+ instructions there. But if you try to draw to the screen, you risk an
+ out-of-bounds error (error number 141).
+
+ See Creative Computing, March 1982, for an excellent look at
+ mode 7.5. The short subroutine below can be used to change the
+ Display List to GR.7.5:
+
+ 1000 GRAPHICS 8+16: DLIST = PEEK(560)
+ ) + PEEK(561) * 256:POKE DLIST +
+ 3,78
+ 1010 FOR CHANGE = DLIST + 6 TO DLIST
+ + 204: IF PEEK(CHANGE) = 15 THE
+ N POKE CHANGE,14
+ 1020 IF PEEK (CHANGE) = 79 THEN POKE
+ CHANGE,78: NEXT CHANGE
+ 1030 POKE 87,7:RETURN
+
+ DOWNLOAD MODE75.BAS
+
+ (Actually, 15 ($F) is the DL number for the maximum memory
+ mode; it also indicates modes eight through eleven. The DL's for
+ these modes are identical.) Fourteen is the ANTIC E mode;
+ GR.7.5 This program merely changes GR.8 to mode E in the
+ Display List. The value 79 is 64 + 15; mode eight screen with BIT
+ 6 set for a Load Memory Scan (LMS) instruction (see the DL
+ information in locations 560, 561; $230, $231). It does not check
+ for other DL bits.
+
+ You can also POKE 87 with the GTIA values (nine to eleven). To
+ get a pseudo-text window in GTIA modes, POKE the mode
+ number here and then POKE 623 with 64 for mode nine, 128 for
+ mode ten, and 192 for mode eleven, then POKE 703 with four, in
+ program mode. (In command mode, you will be returned to
+ GR.0.) You won't be able to read the text in the window, but you
+ will be able to write to it. However, to get a true text window,
+ you'll need to use a Display List Interrupt (see COMPUTE!,
+ September 1982). If you don't have the GTIA chip, it is still
+ possible to simulate those GRAPHICS modes by using DINDEX
+ with changes to the Display List Interrupt. See COMPUTE!, July
+ 1981, for an example of simulating GR.10.
+
+
+ 88,89 58,59 SAVMSC
+
+ The lowest address of the screen memory, corresponding to the
+ upper left corner of the screen (where the value at this address
+ will be displayed). The upper left corner of the text window is
+ stored at locations 660, 661 ($294, $295).
+ You can verify this for yourself by:
+
+ WINDOW = PEEK(88) + PEEK(89) * 256: POKE WINDOW,33
+
+ This will put the letter "A" in the upper left corner in GR.0, 1 and
+ 2. In other GRAPHICS modes, it will print a colored block or
+ bar. To see this effect, try:
+
+ 5 REM FIRST CLEAR SCREEN
+ 10 GRAPHICS Z: IF Z > 59 THEN END
+ 15 SCREEN = PEEK (88) + PEEK (89) *
+ 256
+ 20 FOR N = 0 TO 255: POKE SCREEN + N
+ ,N
+ 25 NEXT N: FOR N = 1 TO 300: NEXT N:
+ Z = Z + 1
+ 30 GOTO 10
+
+ DOWNLOAD SAVEMSC1.BAS
+
+ You will notice that you get the Atari internal character code, not
+ the ATASCII code. See also locations 560, 561 ($230, $231) and
+ 57344 ($E000).
+
+ How do you find the entire screen RAM? First, look at the chart
+ below and find your GRAPHICS mode. Then you multiply the
+ number of rows-per-screen type by the number of bytes-per-line.
+ This will tell you how many bytes each screen uses. Add this
+ value, minus one, to the address specified by SAVMSC.
+ However, if you subtract MEMTOP (locations 741, 742; $2E5,
+ $2E6) from RAMTOP (106; $6A * 256 for the number of bytes),
+ you will see that there is more memory reserved than just the
+ screen area. The extra is taken up by the display list or the text
+ window, or is simply not used (see the second chart below).
+
+ Mode 0 1 2 3 4 5 6 7 8 9-12
+
+ Rows
+ Full 24 24 12 24 48 48 96 96 192 192
+ Split -- 20 10 20 40 40 80 80 160 --
+
+ Bytes per
+ Line 40 20 20 10 10 20 20 40 40 40
+
+ Columns
+ per Line 40 20 20 40 80 80 160 160 320 80
+
+ Memory (1) 993 513 261 273 537 1017 2025 3945 7900 7900
+
+ Memory (2)
+ Full 992 672 420 432 696 1176 2184 4200 8138 8138
+ Split -- 674 424 434 694 1174 2174 4190 8112 --
+
+ (1) According to the Atari BASIC Reference Manual, p.45; OS
+ User's Manual, p.172, and Your Atari 400/800, p.360.
+
+ (2) According to Your Atari 400/800, p.274, and Atari Microsoft
+ Basic Manual, p.69. This is also the value you get when you
+ subtract MEMTOP from RAMTOP (see above).
+
+ For example, to POKE the entire screen RAM in GR.4, you
+ would find the start address of the screen (PEEK(88) + PEEK(89)
+ * 256), then use a FOR-NEXT loop to POKE all the locations
+ specified above:
+
+ 10 GRAPHICS 4: SCRN = PEEK(88) + PE
+ EK(89) * 256
+ 20 FOR LOOP = SCRN to SCRN + 479: R
+ EM 48 ROWS * 10 BYTES - 1
+ 30 POKE LOOP,35: NEXT LOOP
+
+ DOWNLOAD SAVEMSC2.BAS
+
+ Why the minus one in the calculation? The first byte of the screen
+ is the first byte in the loop. If we add the total size, we will go one
+ byte past the end of the soreen, so we subtract one from the total.
+ Here's how to arrive at the value for the total amount ot memory
+ located for screen use, display list and Text window:
+
+ Total memory allocation for the screen
+
+ Screen display Display List
+ -----------------------------------------------------------
+ Text unused bytes screen unused used
+ GR window always cond. use bytes bytes Total
+ -----------------------------------------------------------
+ 0 ... none none 960 none 32 992
+ 1 160 none 80 400 none 34 674
+ 2 160 none 40 200 none 24 424
+ 3 160 none 40 200 none 34 434
+ 4 160 none 80 400 none 54 694
+ 5 160 none 160 800 none 54 1174
+ 6 160 none 320 1600 none 94 2174
+ 7 160 none 640 3200 96 94 4190
+ 8 160 16 1280 6400 80 176 8112
+
+ The number of bytes from RAMTOP (location 106; $6A) is counted
+ from the left text window column towards the total column.
+ MEMTOP (741, 742; $2E5, $2E6) points to one byte below
+ RAMTOP * 256 minus the number of bytes in the total column. If
+ 16 is added to the GRAPHICS mode (no text window), then the
+ conditional unused bytes are added to the total. Then the bytes
+ normally added for the text window become unused, and the
+ Display List expands slightly. (See COMPUTE!, September 1981.)
+
+ When you normally PRINT CHR$(125) (clear screen), Atari sends
+ zeroes to the memory starting at locations 88 and 89. It continues to
+ do this until it reaches one byte less than the contents of RAMTQP
+ (location 106; $6A). Here is a potential source of conflict with your
+ program, however: CHR$(125)--CLEAR SCREEN--and any
+ GRAPHICS command actually continue to clear the first 64 ($40)
+ bytes above RAMTOP!
+
+ It would have no effect on BASIC since BASIC is a ROM
+ cartridge. The OS Source Listing seems to indicate that it ends at
+ RAMTOP, but Atari assumed that there would be nothing after
+ RAMTOP, so no checks were provided. Don't reserve any data
+ within 64 bytes of RAMTOP or else it will be eaten by the CLEAR
+ SCREEN routine, or avoid using a CLEAR SCREEN or a
+ GRAPHICS command. Scrolling the text window also clears 800
+ bytes of memory above RAMTOP.
+
+ You can use this to clear other areas of memory by POKEing the
+ LSB and MSB of the area to be cleared into these locations. Your
+ routine should always end on a $FF boundary (RAMTOP indicates
+ the number of pages). Remember to POKE back the proper screen
+ locations or use a GRAPHICS command immediately after doing
+ so to set the screen right. Try this:
+
+ 10 BOTTOM = 30000: TOP = 36863: REM
+ LOWEST AND HIGHEST ADDRESS TO CLEA
+ R = $7530 & $8FFF
+ 20 RAMTOP = PEEK(106): POKE 106, INT
+ (TOP + 1 / 256)
+ 30 TEST = INT(BOTTOM / 256): POKE89,
+ TEST
+ 40 POKE 88. BOTTOM - 256 * TEST
+ 50 PRINT CHR$(125): POKE 106, RAMTOP
+ 60 GRAPHICS 0
+
+ DOWNLOAD SAVEMSC3.BAS
+
+ This will clear the specified memory area and update the address
+ of screen memory. If you don't specify TOP, the CLEAR SCREEN
+ will continue merrily cleaning out memory and, most likely, will
+ cause your program to crash. Use it with caution.
+ Here's a means to SAVE your current GR.7 screen display to disk
+ using BASIC:
+
+ 1000 SCREEN = PEEK(88) + PEEK(89) *
+ 256
+ 1010 OPEN #2,8,0,"D:picturename"
+ 1020 MODE = PEEK(87): PUT #2, MODE:
+ REM SAVE GR. MODE
+ 1030 FOR SCN = 0 TO 4: COL PEEK(70
+ 8 + SCN): PUT #2,COL: NEXT SCN:
+ REM SAVE COLOR REGISTERS
+ 1040 FOR TV = SCREEN TO SCREEN + 319
+ 9:BYTE = PEEK(TV): PUT #2, BYTE:
+ NEXT TV: CLOSE #2
+
+ DOWNLOAD SAVEMSC4.BAS
+
+ To use this with other screen modes, you will have to change the
+ value of 3199 in line 1040 to suit your screen RAM (see the chart
+ above). For example, GR.7 + 16 would require 3839 bytes (3840
+ minus one). You can use the same routine with cassette by using
+ device C:. To retrieve your picture, you use GET#2 and POKE
+ commands. You will, however, find both routines very slow. Using
+ THE CIO routine at 58454 ($E456) and the IOCBs, try this machine
+ language save routine:
+
+ 10 DIM ML$(10): B$(10): GR.8+16
+ 20 B$ = "your picture name":Q = PEEK
+ (559)
+ 30 FOR N = 1 TO 6: READ BYTE: ML$(N,
+ N) = CHR$(BYTE): NEXT N
+ 35 DATA 104,162,16,76,86,228
+ 36 REM PLA,LDX,$10,JMP $E456
+ 40 OPEN #1,4,0,B$
+ 50 POKE 849,1: POKE 850,7: POKE 852,
+ PEEK(88): POKE 853,PEEK(89): POKE
+ 856,70: POKE 857,30: POKE 858,4
+ 55 REM THESE POKES SET UP THE IOCB
+ 60 POKE 559,0: REM TURN OFF THE SCRE
+ EN TO SPEED THINGS UP
+ 70 X = USR(ADR(ML$)): CLOSE #1
+ 80 POKE 559,Q: REM TURN IT BACK ON A
+ GAIN
+
+ DOWNLOAD SAVEMSC5.BAS
+
+ Note that there is no provision to SAVE the color registers in this
+ program, so I suggest you have them SAVEd after you have
+ SAVEd the picture. It will make it easier to retrieve them if they are
+ at the end of the file. You will have to make suitable adjustments
+ when SAVEing a picture in other than GR.8 + 16 -- such as
+ changing the total amount of screen memory to be SAVEd, POKEd
+ into 856 and 857. Also, you will need a line such as 1000 GOTO
+ 1000 to keep a GTIA or + 16 mode screen intact. See the Atari
+ column in InfoAge Magazine, July 1982, for more on this idea. See
+ location 54277 ($D405) for some ideas on scrolling the screen
+ RAM.
+
+ ------------------------------------------------------------------------
+ A SHORT DIGRESSION
+ There are two techniques used in this hook for calling a machine
+ language program from BASIC with the USR command. One method
+ is to POKE the values into a specific address -- say, page six -- and
+ use the starting address for the USR call, such as X = USR(1536). For
+ an example of this technique, see location 632 ($278).
+
+ The other technique, used above, is to make a string (ML$) out of the
+ routine by assigning to the elements of the string the decimal
+ equivalents of the machine language code by using a FOR-NEXT and
+ READ-DATA loop. To call this routine, you would use X =
+ USR(ADR(ML$)). This tells the Atari to call the machine language
+ routine located at the address where ML$ is stored. This address will
+ change with program size and memory use. The string method won't
+ be overwritten by another routine or data since it floats around safely
+ in memory. The address of the string itself is stored by the string/array
+ table at location 140 ($8C).
+ ------------------------------------------------------------------------
+
+
+ 90 5A OLDROW
+
+ Previous graphics cursor row. Updated from location 84 ($54)
+ before every operation. Used to determine the starting row for
+ the DRAWTO and XIO 18 (FILL command).
+
+
+ 91,92 5B,5C OLDCOL
+
+ Previous graphics cursor column. Updated from locations 85 and
+ 86 ($55, $56) before every operation. These locations are used by
+ the DRAWTO and XIO 18 (FILL) commands to determine the
+ starting column of the DRAW or FILL
+
+
+ 93 5D OLDCHR
+
+ Retains the value of the character under the cursor used to
+ restore that character when the cursor moves
+
+
+ 94,95 5E,5F OLDADR
+
+ Retains the memory location of the current cursor location. Used
+ with location 93 (above) to restore the character under the cursor
+ when the cursor moves
+
+
+ 96 60 NEWROW
+
+ Point (row) to which DRAWTO and XIO 18 (FILL) will go.
+
+
+ 97,98 61,62 NEWCOL
+
+ Point (column) to which DRAWTO and XIO 18 (FILL) will go.
+ NEWROW and NEWCOL are initialized to the values in
+ ROWCRS and COLCRS (84 to 86; $54 to $56) above, which
+ represent the destination end point of the DRAW and FILL
+ functions. This is done so that ROWCRS and COLCRS can be
+ altered during these routines.
+
+
+ 99 63 LOGCOL
+
+ Position of the cursor at the column in a logical line. A logical
+ line can contain up to three physical lines, so LOGCOL can
+ range between zero and 119. Used by the display handler.
+
+
+ 100,101 64,65 ADRESS
+
+ Temporary storage used by the display handler for the Display
+ List address, line buffer (583 to 622; $247 to $26E), new MEMTOP
+ value after DL entry, row column address, DMASK value, data to
+ the right of cursor, scroll, delete, the clear screen routine and for
+ the screen address memory (locations 88, 89; $58, $59).
+
+
+ 102,103 66,67 MLTTMP
+
+ Also called OPNTMP and TOADR; first byte used in OPEN as
+ temporary storage. Also used by the display handler as
+ temporary storage.
+
+
+ 104,105 68,69 SAVADR
+
+ Also called FRMADR. Temporary storage, used with ADRESS
+ above for the data under the cursor and in moving line data on
+ the screen.
+
+
+ 106 6A RAMTOP
+
+ RAM size, defined by powerup as passed from TRAMSZ (location
+ 6), given in the total number of available pages (one page equals
+ 256 bytes, so PEEK(106) * 256 will tell you where the Atari thinks
+ the last usable address --byte-- of RAM is). MEMIOP (741,
+ 742; $2E5. $2E6) may not extend below this value. In a 48K Atari,
+ RAMTOP is initialized to 160 ($A0), which points to location
+ 40960 ($A000). The user's highest address will be one byte less
+ than this value.
+
+ This is initially the same value as in location 740. PEEK(740) / 4 or
+ PEEK(106) / 4 gives the number of 1K blocks. You can fool the
+ computer into thinking you have less memory than you actually
+ have, thus reserving a relatively safe area for data (for your new
+ character set or player/missile characters, for example) or
+ machine language subroutines by:
+
+ POKE(106), PEEK(106) - # of pages you want to reserve.
+
+ The value here is the number of memory pages (256-byte blocks)
+ present. This is useful to know when changing GR.7 and GR.8
+ screen RAM. If you are reserving memory for PM graphics,
+ POKE 54279, PEEK(106) - # of pages you are reserving before
+ you actually POKE 106 with that value. To test to see if you have
+ exceeded your memory by reserving too much memory space,
+ you can use:
+
+ 10 SIZE = (PEEK(106) - # of pages)
+ * 256
+ 20 IF SIZE < = PEEK(144) + PEEK(145
+ ) * 256 THEN PRINT "TOO MUCH MEMOR
+ Y USED"
+
+ If you move RAMTOP to reserve memory, always issue a
+ GRAPHICS command (even issuing one to the same GRAPHICS
+ mode you are in will work) immediately so that the display list
+ and data are moved beneath the new RAMTOP.
+
+ You should note that a GRAPHICS command and a CLEAR
+ command (or PRINT CHR$(125)) actually clear the first 64 bytes
+ above RAMTOP (see location 88; $58 for further discussion).
+ Scrolling the text window of a GRAPHICS mode clears up to 800
+ ($320) bytes above RAMTOP (the text window scroll actually
+ scrolls an entire GR.0 screen-worth of data, so the unseen 20
+ lines * 40 bytes equals 800 bytes). PM graphics may be safe
+ (unless you scroll the text window) since the first 384 or 768 bytes
+ (double or single line resolution, respectively) are unused.
+ However, you should take both of these effects into account when
+ writing your programs.
+ To discover the exact end of memory, use this routine (it's a tad
+ slow):
+
+ 10 RAMTOP = 106: TOP = PEEK(RAMTOP)
+ 20 BYTE = TOP * 256: TEST = 255 - PE
+ EK(BYTE): POKE BYTE,TEST
+ 30 IF PEEK(BYTE) = TEST THEN TOP = T
+ OP +1: POKE BYTE, 255 - TEST
+ 40 GOTO 20
+ 50 PRINT "MEMORY ENDS AT "; BYTE
+
+ One caution: BASIC cannot always handle setting up a display
+ list and display memory for GRAPHICS 7 and GRAPHICS 8
+ when you modify this location by less than 4K (16 pages; 4096
+ bytes). Some bizarre results may occur if you use PEEK(106) - 8
+ in these modes, for example. Use a minimum of 4K (PEEK(106) -
+ 16) to avoid trouble. This may explain why some people have
+ difficulties with player/missile graphics in the hi-res (high
+ resolution; GR.7 and GR.8) modes. See location 54279 ($D407).
+
+ Another alternative to reserving memory in high RAM is to save
+ an area below MEMLO, location 743 ($2E7: below your BASIC
+ program). See also MEMTOP, locations 741, 742 ($2E5, $2E6).
+
+
+ 107 6B BUFCNT
+
+ Buffer count: the screen editor current logical line size counter.
+
+
+ 108,109 6C,6D BUFSTR
+
+ Editor low byte (AM). Display editor GETCH routine pointer
+ (location 62867 for entry; $F593). Temporary storage; returns the
+ character pointed to by BUFCNT above.
+
+
+ 110 6E BITMSK
+
+ Bit mask used in bit mapping routines by the OS display handler
+ at locations 64235 to 64305 ($FAEB to $FB31). Also used as a
+ display handler temporary storage register.
+
+
+ 111 6F SHFAMT
+
+ Pixel justification: the amount to shift the right justified pixel data
+ on output or the amount to shift the input data to right justify it.
+ Prior to the justification process, this value is always the same as
+ that in 672 ($2A0).
+
+
+ 112,113 70,71 ROWAC
+
+ ROWAC and COLAC (below) are both working accumulators for
+ the control of row and column point plotting and the increment
+ and decrement functions.
+
+
+ 114,115 72,73 COLAC
+
+ Controls column point plotting.
+
+
+ 116,117 74,75 ENDPT
+
+ End point of the line to be drawn. Contains the larger value of
+ either DELTAR or DELTAC (locations 118 and 119, below) to be
+ used in conjunction with ROWAC/COLAC (locations 112 and
+ 114, above) to control the plotting of line points.
+
+
+ 118 76 DELTAR
+
+ Delta row; contains the absolute value of NEWBOW (location 96;
+ $60) minus ROWCRS (location 84; $54).
+
+
+ 119,120 77,78 DELTAC
+
+ Delta column; contains the absolute value of NEWCOL (location
+ 97; $61) minus the value in COLCRS (location 85; $55). These
+ delta register values, along with locations 121 and 122 below, are
+ used to define the slope of the line to be drawn.
+
+
+ 121 79 ROWINC
+
+ The row increment or decrement value (plus or minus one).
+
+
+ 122 7A COLINC
+
+ The column increment or decrement value (plus or minus one).
+ ROWINC and COLINC control the direction of the line drawing
+ routine. The values represent the signs derived from the value in
+ NEWROW (location 96; $60) minus the value in ROWCRS
+ (location 84; $54) and the value in NEWCOL (locations 97, 98;
+ $61, $62) minus the value in COLCRS (locations 85, 86; $55,
+ $56).
+
+
+ 123 7B SWPFLG
+
+ Split-screen cursor control. Equal to 255 ($FF) if the text window
+ RAM and regular RAM are swapped; otherwise, it is equal to
+ zero. In split-screen modes, the graphics cursor data and the text
+ window data are frequently swapped in order to get the values
+ associated with the area being accessed into the OS data base
+ locations 84 to 95 ($54 to $5F). SWPFLG helps to keep track of
+ which data set is in these locations.
+
+
+ 124 7C HOLDCH
+
+ A character value is moved here before the control and shift logic
+ are processed for it.
+
+
+ 125 7D INSDAT
+
+ Temporary storage byte used by the display handler for the
+ character under the cursor and end of line detection.
+
+
+ 126,127 7E,7F COUNTR
+
+ Starts out containing the larger value of either DELTAR (location
+ 118; $76) or DELTAC (location 119; $77). This is the number of
+ iterations required to draw a line. As each point on a line is
+ drawn, this value is decremented. When the byte equals zero, the
+ line is complete (drawn).
+
+ ---------------------------------------------------------------------
+
+ User and/or BASIC page zero RAM begins here. Locations 128 to 145
+ ($80 to $91) are for BASIC program pointers; 146 to 202 ($92 to $CA)
+ are for miscellaneous BASIC RAM; 203 to 209 ($CB to $D1) are
+ unused by BASIC, and 210 to 255 ($D2 to $FF) are the floating point
+ routine work area. The Assembler Editor cartridge uses locations 128
+ to 176 ($80 to $B0) for its page zero RAM. Since the OS doesn't use this
+ area, you are free to use it in any non-BASIC or non-cartridge
+ environment. If you are using another language such as FORTH,
+ check that program's memory map to see if any conflict will occur.
+ See COMPUTE!'s First Book of Atari, pages 26 to 53, for a discussion
+ of Atari BASIC structure, especially that using locations 130 to 137
+ ($82 to $89). Included in the tutorials are a memory analysis, a line
+ dump, and a renumber utility. See also De Re Atari, BYTE, February
+ 1982, and the locations for the BASIC ROM 40960 to 49151 ($A000 to
+ $BFFF).
+
+
+ 128,129 80,81 LOMEM
+
+ Pointer to BASIC's low memory (at the high end of OS RAM
+ space). The first 256 bytes of the memory pointed to are the token
+ output buffer, which is used by BASIC to convert BASIC
+ statements into numeric representation (tokens; see locations
+ 136, 137; $88, $89). This value is loaded from MEMLO (locations
+ 743, 744; $2E7, $2E8) on initialization or the execution of a NEW
+ command (not on RESET!). Remember to update this value when
+ changing MEMLO to reserve space for drivers or buffers.
+ When a BASIC SAVE is made, two blocks of information are
+ written: the first block is the seven pointers from LOMEM to
+ STARP (128 to 141; $80 to $8D). The value of LOMEM is
+ subtracted from each of these two-byte pointers in the process, so
+ the first two bytes written will both be zero. The second block
+ contains the following: the variable name table, the variable
+ value table, the tokenized program, and the immediate mode
+ line.
+ When a BASIC LOAD is made, BASIC adds the value at MEMLO
+ (743, 744; $2E7, $2E8) to each of the two-byte pointers SAVEd as
+ above. The pointers are placed back in page zero, and the values
+ of RUNSTK (142, 143; $8E, $8F) and MEMTOP (144, 145; $90,
+ $91) are set to the value in STARP. Then 256 bytes are reserved
+ above the value in MEMLO for the token output buffer, and the
+ program is read in immediately following this buffer.
+ When you don't have DOS or any other application program
+ using low memory loaded, LOMEM points to 1792 ($700). When
+ DOS 2.0 is present, it points to 7420 ($1CFC). When you change
+ your drive and data buffer defaults (see 1801, 1802; $709, $70A),
+ you will raise or lower this figure by 128 bytes for each buffer
+ added or deleted, respectively. When you boot up the RS-232
+ handler, add another 1728 ($6C0) bytes used.
+ LOMEM is also called ARGOPS by BASIC when used in
+ expression evaluation. When BASIC encounters any kind of
+ expression, it puts the immediate results into a stack. ARGOPS
+ points to the same 256 byte area; for this operation it is reserved
+ for both the argument and operator stack. It is also called
+ OUTBUFF for another operation, pointing to the same 256 byte
+ buffer as ARGOPS points to. Used by BASIC when checking a
+ line for syntax and converting it to tokens. This buffer
+ temporarily stores the tokens before moving them to the
+ program.
+
+
+ 130,131 82,83 VNTP
+
+ Beginning address of the variable name table. Variable names
+ are stored in the order input into your program, in ATASCII
+ format. You can have up to 128 variable names. These are stored
+ as tokens representing the variable number in the tokenized
+ BASIC program, numbered from 128 to 255 ($80 to $FF).
+
+ The table continues to store variable names, even those no longer
+ used in your program and those used in direct mode entry. It is
+ not cleared by SAVEing your program. LOADing a new program
+ replaces the current VNT with the one it retrieves from the file.
+ You must LIST the program to tape or disk to save your program
+ without these unwanted variables from the table. LIST does not
+ SAVE the variable name or variable value tables with your
+ program. It stores the program in ATASCII, not tokenized form,
+ and requires an ENTER command to retrieve it. You would use a
+ NEW statement to clear the VNT in memory once you have
+ LISTed your program.
+
+ Each variable name is stored in the order it was entered, not the
+ ATASCII order. With numeric (scalar) variables, the MSB is set
+ on the last character in a name. With string variables, the last
+ character is a "$" with the MSB (BIT 7) set. With array variables,
+ the last character is a "(" with the MSB set. Setting the MSB turns
+ the character into its inverse representation so it can be easily
+ recognized.
+ You can use variable names for GOSUB and GOTO routines,
+ such as:
+
+ 10 CALCULATE = 1000
+ .
+ .
+ 100 GOSUB CALCULATE
+
+ This can save a lot of bytes for a frequently called routine. But
+ remember, each variable used for a GOSUB or GOTO address
+ uses one of the 128 possible variable names. A disadvantage of
+ using variable names for GOTO and GOSUB references is when
+ you try to use a line renumbering program. Line renumbering
+ programs will not change references to lines with variable
+ names, only to lines with numbered references.
+
+ Here's a small routine you can add to the start of your BASIC
+ program (or the end if you change the line numbers) to print out
+ the variable names used in your program. You call it up with a
+ GOTO statement in direct mode:
+
+ 1 POKE 1664, PEEK(130): POKE 1665,
+ PEEK (131)
+ 2 IF PEEK(1664) = PEEK(132) THEN IF
+ PEEK(1665) = PEEK(133) THEN STOP
+ 3 PRINT CHR$(PEEK(PEEK(1664) + PEEK
+ (1665) * 256)));
+ 4 IF PEEK(PEEK(1664) + PEEK(1665) *
+ 256)) > 127 THEN PRINT"";
+ 5 IF PEEK(1664) = 255 THEN POKE 166
+ 4, 0: POKE 1665, PEEK(1665) + 1: GO
+ TO 2
+ 6 POKE 1664, PEEK(1664) + 1: GOTO 2
+
+ DOWNLOAD VNTP.BAS
+
+ See COMPUTE!, October 1981.
+
+
+ 132,133 84,85 VNTD
+
+ Pointer to the ending address of the variable name table plus one
+ byte. When fewer than 128 variables are present, it points to a
+ dummy zero byte. When 128 variables are present, this points to
+ the last byte of the last variable name, plus one.
+
+ It is often useful to be able to list your program variables; using
+ locations 130 to 133, you can do that by:
+
+ 10 VARI = PEEK(130) + PEEK(131) * 2
+ 56 :REM This gives you the start o
+ f the table.
+ 20 FOR VARI = VARI TO PEEK(132) + P
+ EEK(133) * 256 - 1: PRINT CHR$(PEE
+ K(VARI) - 128 * PEEK(VARI > 127));
+ CHR$(27 + 128 * PEEK(VARI) > 127)
+ );:NEXT VARI
+ 25 REM this finds the end of the va
+ ri able name table (remember table
+ is end + 1). then PRINTs ASCII cha
+ racters < 128
+ 30 NUM = 0: FOR VARI = PEEK(130) +
+ PEEK(313) * 256 TO PEEK(132) + PEE
+ K(131) * 256 - 1:NUM = NUM + (PEEK
+ (VARI) < 127):NEXT VARI: PRINT NU
+ M; "Variables in use"
+
+ DOWNLOAD VNTD1.BAS
+
+ Or try this, for a possibly less opaque example of the same
+ routine:
+
+ 1000 NUM = 0: FOR LOOP = PEEK (130) +
+ PEEK(131) * 256 TO PEEK(132) +
+ PEEK(133) * 256 - 1
+ 1010 IF PEEK(LOOP) < 128 THEN PRINT
+ CHR$(PEEK(LOOP));: GOTO 1030
+ 1020 PRINT CHR$(PEEK(LOOP) - 128): N
+ UM - NUM + 1
+ 1030 NEXT LOOP: PRINT; PRINT NUM; "
+ VARIABLES IN USE": END
+
+ DOWNLOAD VNTD2.BAS
+
+
+ 134,135 86,87 VVTP
+
+ Address for the variable value table. Eight bytes are allocated for
+ each variable in the name table as follows:
+
+ Byte 1 2 3 4 5 6 7 8
+ Variable
+ --------------------------------------------------------------
+ Scalar 00 var # six byte BCD constant
+ Array;DIMed 65 var # offset first second
+ unDIMed 64 from DIM + 1 DIM + 1
+ STARP
+ String;DIMed 129 var # offset length DIM
+ unDIMed 128 from
+ STARP
+
+ In scalar (undimensioned numeric) variables, bytes three to eight
+ are the FP number; byte three is the exponent; byte four contains
+ the least significant two decimal digits, and byte eight contains
+ the most significant two decimal digits.
+ In array variables, bytes five and six contain the size plus one of
+ the first dimension of the array (DIM + 1; LSB/MSB), and bytes
+ seven and eight contain the size plus one of the second dimension
+ (the second DIM + 1; LSB/MSB).
+ In string variables, bytes five and six contain the current length
+ of the variable (LSB MSB), and bytes seven and eight contain the
+ actual dimension (up to 32767). There is an undocumented
+ BASIC statement, "COM," mentioned only in the BASIC
+ Reference Manual's index, which executes exactly the same as
+ the "DIM" statement (see Your Atari 400/800, p.346). Originally,
+ it was to be used to implement "common" variables.
+
+ In all cases, the first byte is always one of the number listed on the
+ chart above (you will seldom, if ever, see the undimensioned
+ values in a program). This number defines what type of variable
+ information will follow. The next byte, var # (variable number), is
+ in the range from zero to 127. Offset is the number of bytes from
+ the beginning of STARP at locations 140 and 141 ($8C, $8D).
+ Since each variable is assigned eight bytes, you could find the
+ values for each variable by:
+
+ 1000 VVTP = PEEK(134) + PEEK(135) *
+ 256: INPUT VAR: REM VARIABLE NUM
+ BER
+ 1010 FOR LOOP = 0 TO 7: PRINT PEEK(V
+ VTP + LOOP + 8 * VAR): NEXT LOOP
+
+ where VAR is the variable number from zero to 127.
+ If you wish to assign the same value to every element in a DIMed
+ string variable use this simple technique:
+
+ 10 DIM TEST$(100)
+ 20 TEST$ = "*": REM or use TEST$(1)
+ 30 TEST$(100) = TEST$
+ 40 TEST$(2) = TEST$: PRINT TEST$
+
+ By assigning the first, last and second variables in the array in
+ that order, your Atari will then assign the same value to the rest of
+ the array. Make sure you make the second and last elements
+ equal to the string, not the character value (i.e don't use
+ TEXT$(2) = "*").
+ See De Re Atari for an example of SAVEing the six-byte BCD
+ numbers to a disk file -- very useful when dealing with fixed
+ record lengths.
+
+
+ 136,137 88,89 STMTAB
+
+ The address of the statement table (which is the beginning of the
+ user's BASIC program), containing all the tokenized lines of
+ code plus the immediate mode lines entered by the user. Line
+ numbers are stored as two-byte integers, and immediate mode
+ lines are given the default value of line 32768 ($8000). The first
+ two bytes of a tokenized line are the line number, and the next is
+ a dummy byte reserved for the byte count (or offset) from the start
+ of this line to the start of the next line.
+
+ Following that is another count byte for the start of this line to the
+ start of the next statement. These count values are set only when
+ tokenization for the line and statement are complete.
+ Tokenization takes place in a 256 byte ($100) buffer that resides at
+ the end of the reserved OS RAM (pointed to by locations 128,
+ 129; $80, $81).
+ To see the starting address of your BASIC line numbers use this
+ routine:
+
+ 10 STMTAB = PEEK(136) + PEEK(137)*2
+ 56
+ 20 NUM = PEEK(STMTAB) + PEEK (STMTAB
+ +1)*256
+ 30 IF NUM = 32768 THEN END
+ 40 PRINT"LINE NUMBER: ";NUM;" ADDRE
+ SS: ";STMTAB
+ 50 STMTAB = STMTAB + PEEK(STMTAB+2)
+ 60 GOTO 20
+
+ The August 1982 issue of ANTIC provided a useful program to
+ delete a range of BASIC line numbers. The routine can be
+ appended to your program and even be used to delete itself.
+
+
+ 138,139 8A,8B STMCUR
+
+ Current BASIC statement pointer, used to access the tokens
+ being currently processed within a line of the statement table.
+ When BASIC is awaiting input, this pointer is set to the
+ beginning of the immediate mode (line 32768).
+
+ Using the address of the variable name table, the length, and the
+ current statement (locations 130 to 133, 138, 139), here is a way to
+ protect your programs from being LISTed or LOADed: they can
+ only be RUN! Remember, that restricts you too, so make sure you
+ have SAVEd an unchanqed version before you do this:
+
+ 32000 FOR VARI = PEEK(130) + PEEK(1
+ 31) * 256 TO PEEK(132) + PEEK(1
+ 33) * 256:POKE VARI,155:NEXT VA
+ RI
+ 32100 POKE PEEK(138) + PEEK(139) *
+ 256 + 2,0: SAVE "D:filename": N
+ EW
+
+ This will cause all variable names to be replaced with a RETURN
+ character. Other characters may be used: simply change 155 for
+ the appropriate ATASCII code for the character desired. Make
+ sure that these are the last two lines of your program and that
+ NEW is the last statement. CLOAD will not work, but a filename
+ with C: will.
+
+
+ 140,141 8C,8D STARP
+
+ The address for the string and array table and a pointer to the end
+ of your BASIC program. Arrays are stored as six-byte binary
+ coded decimal numbers (BCD) while string characters use one
+ bye each. The address of the strings in the table are the same as
+ those returned by the BASIC ADR function. Always use this
+ function under program control, since the addresses in the table
+ change according to your program size. Try:
+
+ 10 DIM A$(10),B$(10)
+ 20 A$ = "*": A$(10) = A$: A$(2) = A
+ $
+ 30 B$ = "&": B$(10) = B$: B$(2) = B
+ $
+ 40 PRINT ADR(A$), ADR(B$)
+ 50 PRINT PEEK(140) + PEEK(141) * 25
+ 6: REM ADDRESS OF A$
+ 60 PRINT PEEK(140) + PEEK(141) * 25
+ 6 + 10: REM ADRESS OF A$ + 10 BYTE
+ S = ADDRESS OF B$
+
+ This table is expanded as each dimension is processed by
+ BASIC, reducing available memory. A ten-element numeric
+ array will require 60 bytes for storage. An array variable such as
+ DIM A(100) will cost the program 600 bytes (100 * six per
+ dimensioned number equals 600). On the other hand, a string
+ array such as DIM A$(100) will only cost 100 bytes! It would save
+ a lot of memory to write your arrays as strings and retrieve the
+ array values using the VAL statement. For example:
+
+ 10 DIM A$(10): A$ = "1234567890"
+ 20 PRINT VAL(A$)
+ 30 PRINT VAL(A$(4,4))
+ 40 PRINT VAL(A$(3,3))+VAL(A$(8,9))
+
+ See COMPUTE!, June 1982, for a discussion of STARP and
+ VVTP. See De Re Atari for a means to SAVE the string/array area
+ with your program.
+
+
+ 142,143 8E,8F RUNSTK
+
+ Address of the runtime stack which holds the GOSUB entries
+ (four bytes each) and the FOR-NEXT entries (16 bytes each). The
+ POP command in BASIC affects this stack, pulling entries off it
+ one at a time for each POP executed. The stack expands and
+ contracts as necessary while the program is running.
+
+ Each GOSUB entry consists of four bytes in this order: a zero to
+ indicate a GOSUB, a two-byte integer line number on which the
+ call occurred, and an offset into that line so the RETURN can
+ come back and execute the next statement.
+
+ Each FOR-NEXT entry contains 16 bytes in this order: first, the
+ limit the counter variable can reach; second, the step or counter
+ increment. These two are allocated six bytes each in BCD format
+ (12 bytes total). The 13th byte is the counter variable number with
+ the MSB set; the 14th and 15th are the line number and the 16th is
+ the line offset to the FOR statement.
+ RUNSTK is also called ENDSTAR; it is used by BASIC to point to
+ the end of the string/array space pointed to by STARR above.
+
+
+ 144,145 90,91 MEMTOP
+
+ Pointer to the top of BASIC memory, the end of the space the
+ program takes up. There may still be space between this address
+ and the display list, the size of which may be retrieved by the
+ FRE(0) command (which actually subtracts the MEMTOP value
+ that is at locations 741 and 742; $2E5, $2E6). Not to be confused
+ with locations 741 and 742, which have the same name but are an
+ OS variable. MEMTOP is also called TOPSTK; it points to the top
+ of the stack space pointed to by RUNSTK above.
+
+ When reserving memory using location 106 ($6A) and MEMTOP,
+ here's a short error-trapping routine you can add:
+
+ 10 SIZE = (PEEK(106) - # of pages yo
+ u are reserving) * 256
+ 20 IF SIZE < = PEEK(144) + PEEK(145
+ ) * 256 THEN PRINT " PROGRAM TOO L
+ ARGE": END
+
+ Locations 146 to 202 ($92 to $CA) are reserved for use by the 8K
+ BASIC ROM.
+ Locations 176 to 207 ($B0 to $CF) are reserved by the Assembler
+ Editor cartridge for the user's page zero use. The Assembler debug
+ routine also reserves 30 bytes in page zero, scattered from location 164
+ ($A4) to 255 ($FF), but they cannot be used outside the debug process.
+ (See De Re Atari, Rev. 1, Appendix A for a list of these available
+ bytes.)
+
+
+ 186,187 BA,BB STOPLN
+
+ The line where a program was stopped either due to an error or
+ the use of the BREAK key, or a STOP or a TRAP statement
+ occurred. You can use PEEK (186) + PEEK (187) * 256 in a
+ GOTO or GOSUB statement.
+
+
+ 195 C3 ERRSAVE
+
+ The number of the error code that caused the stop or the TRAP.
+ You can use this location in a program in a line such as:
+
+ 10 IF PEEK(195) <> 144 THEN 100
+
+
+ 201 C9 PTABW
+
+ This location specifies the number of columns between TAB
+ stops. The first tab will beat PEEK(201). The default is ten. This is
+ the value between items separated in a PRINT statement by com-
+ mas -- such as PRINT AS, LOOP, C(12) -- not by the TAB key
+ spacing.
+ The minimum number of spaces between TABS is three. If you
+ POKE 201,2, it will be treated as four spaces, and POKE 201,1 is
+ treated as three spaces. POKE 201,0 will cause the system to
+ hang when it encounters a PRINT statement with commas. To
+ change the TAB key settings, see TABMAP (locations 675 to 689;
+ $2A3 - $2B1). PTABW is not reset to the default value by pressing
+ RESET or changing GRAPHICS modes (unlike TABMAP).
+ PTABW works in all GRAPHICS modes, not merely in text
+ modes. The size of the spaces between items depends on the pixel
+ size in the GRAPHICS mode in use. For example, in GR.0, each
+ space is one character wide, while in GR.8 each space is one-half
+ color clock (one dot) wide.
+
+
+ 203-207 CB-CF ....
+
+ Unused by either the BASIC or the Assembler cartridges.
+
+
+ 208-209 D0-D1 ....
+
+ Unused by BASIC. The only time I have seen any of these unused
+ locations in use is in COMPUTE! (March 1982 and October
+ 1981), when they were used for user sort routines, and in ANTIC
+ (June 1982), where they were used as flags in a graphic
+ demonstration. The bytes from 203 to 209 ($CB to $D1) are the
+ only page zero bytes uncontestably left free by BASIC.
+
+
+ 210-211 D2-D3 ....
+
+ Reserved for BASIC or other cartridge use.
+
+ Locations 212 to 255 ($D4 to $FF) are reserved for the floating point
+ package use. The FP routines are in ROM, from locations 55296 to
+ 57393 ($D800 to $E031). These page zero locations may be used if the
+ FP package is not called by the user's program. However, do not use
+ any of these locations for an interrupt routine, since such routines
+ might occur during an FP routine called by BASIC, causing the
+ system to crash.
+
+ Floating Point uses a six-byte precision. The first byte of the Binary
+ Coded Decimal (BCD) number is the exponent (where if BIT 7 equals
+ zero, then the number is positive; if one, then it is negative). The next
+ five bytes are the mantissa. If only that were all there was to it. The
+ BCD format is rather complex and is best explained in chapter eight of
+ De Re Atari.
+
+
+ 212-217 D4-D9 FR0
+
+ Floating point register zero; holds a six-byte internal form of the
+ FP number. The value at locations 212 and 213 are used to return
+ a two-byte hexadecimal value in the range of zero to 65536
+ ($FFFF) to the BASIC program (low byte in 212, high byte in
+ 213). The floating point package, if used, requires all locations
+ from 212 to 255. All six bytes of FR0 can be used by a machine
+ language routine, provided FR0 isn't used and no FP functions
+ are used by that routine. To use 16 bit values in FP, you would
+ place the two bytes of the number into the least two bytes of FR0
+ (212, 213; $D4, $D5), and then do a JSR to $D9AA (55722), which
+ will convert the integer to its FP representation, leaving the result
+ in FR0. To reverse this operation, do a JSR to $D9D2 (55762).
+
+
+ 218-223 DA-DF FRE
+
+ FP extra register (?)
+
+
+ 224-229 E0-E5 FR1
+
+ Floating point register one; holds a six-byte internal form of the
+ FP number as does FR0. The FP package frequently transfers
+ data between these two registers and uses both for two-number
+ arithmetic operations.
+
+
+ 230-235 E6-EB FR2
+
+ FP register two.
+
+
+ 236 EC FRX
+
+ FP spare register.
+
+
+ 237 ED EEXP
+
+ The value of E (the exponent).
+
+
+ 238 EE NSIGN
+
+ The sign of the FP number.
+
+
+ 239 EF ESIGN
+
+ The sign of the exponent.
+
+
+ 240 F0 FCHRFLG
+
+ The first character flag.
+
+ 241 Fl DIGRT
+ The number of digits to the right of the decimal.
+
+
+ 242 F2 CIX
+
+ Character (current input) index. Used as an offset to the input
+ text buffer pointed to by INBUFF below.
+
+
+ 243,244 F3,F4 INBUFF
+
+ Input ASCII text buffer pointer; the user's program line input
+ buffer, used in the translation of ATASCII code to FP values. The
+ result output buffer is at locations 1408 to 1535 ($580 to $5FF).
+
+
+ 245,246 F5,F6 ZTEMP1
+
+ Temporary register.
+
+
+ 247,248 F7,F8 ZTEMP4
+
+ Temporary register.
+
+
+ 249,250 F9,FA ZTEMP3
+
+ Temporary register.
+
+
+ 251 FB RADFLG
+
+ Also called DEGFLG. When set to zero, all of the trigonometric
+ functions are performed in radians; when set to six, they are done
+ in degrees. BASIC's NEW command and RESET both restore
+ RADFLG to radians.
+
+
+ 252,253 FC,FD FLPTR
+
+ Points to the user's FP number.
+
+
+ 254,255 FE,FF FPTR2
+
+ Pointer to the user's second FP number to be used in an
+ operation.
+
+ End of the page zero RAM.
+
+ ---------------------------------------------------------------------------
+
+ PAGE ONE: THE STACK
+
+ Locations 256 to 511 ($100 to $1FF) are the stack area for the OS, DOS
+ and BASIC. This area is page one. Machine language JSR, PHA and
+ interrupts all cause data to be written to page one, and RTS, PLA and
+ RTI instructions all read data from page one. On powerup or RESET,
+ the stack pointer is initialized to point to location 511 ($1FF). The stack
+ then pushes downward with each entry to 256 ($100). In case of
+ overflow, the stack will wrap around from 256 back to 511 again.
+
+ ---------------------------------------------------------------------------
+
+ PAGES TWO TO FOUR
+
+ Locations 512 to 1151 ($200 to $47F) are used by the OS for working
+ variables, tables and data buffers. In this area, locations 512 to 553
+ ($200 to $229) are used for interrupt vectors, and locations 554 to 623
+ ($22A to $26F) are for miscellaneous use. Much of pages two through
+ five cannot be used except by the OS unless specifically noted. A
+ number of bytes are marked as "spare", i.e., not in use currently. The
+ status of these bytes may change with an Atari upgrade, so their use is
+ not recommended.
+
+ There are two types of interrupts: Non-Maskable Interrupts (NMI)
+ processed by the ANTIC chip and Interrupt Requests (IRQ) processed
+ by the POKEY and the PIA chips. NMI's are for the VBLANK interrupts
+ (VBI's; 546 to 549, $222 to $225), display list interrupts (DLI) and
+ RESET key interrupts. They initiate the stage one and stage two
+ VBLANK procedures; usually vectored through an OS service routine,
+ they can be vectored to point to a user routine. IRQ's are for the timer
+ interrupts, peripheral and serial bus interrupts, BREAK and other key
+ interrupts, and 6502 BRK instruction interrupts. They can usually be
+ used to vector to user routines. See NMIST 54287 ($D40F) and IRQEN
+ 53774 ($D20E) for more information. NMI interrupt vectors are marked
+ NMI; IRQ interrupt vectors are marked IRQ.
+ Refer to the chart below location 534 for a list of the interrupt vectors in
+ the new OS "B" version ROMs.
+
+
+ 512,513 200,201 VDSLST
+
+ The vector for NMI Display List Interrupts (DLI): containing the
+ address of the instructions to be executed during a DLI (DLI's are
+ used to interrupt the processor flow for a few microseconds at the
+ particular screen display line where the bit was set, allowing you
+ to do another short routine such as music, changing graphics
+ modes, etc.). The OS doesn't use DLI's; they must be user-
+ enabled, written and vectored through here. The NMI status
+ register at 54287 ($D40F) first tests to see if an interrupt was
+ caused by a DLI and, if so, jumps through VDSLST to the routine
+ written by the user. DLI's are disabled on powerup, but VBI's are
+ enabled (see 546 to 549; $222 to $225).
+
+ VDSLST is initialized to point to 59315 ($E7B3), which is merely
+ an RTI instruction. To enable DLI's, you must first POKE 54286
+ ($D40E) with 192 ($C0); otherwise, ANTIC will ignore your
+ request. You then POKE 512 and 513 with the address (LSB/MSB)
+ of the first assembly language routine to execute during the DLI.
+ You must then set BIT 7 of the Display List instruction(s) where
+ the DLI is to occur. You have only between 14 and 61 machine
+ cycles available for your DLI, depending on your GRAPHICS
+ mode. You must first push any 6502 registers onto the stack, and
+ you must end your DLI with an RTI instruction. Because you are
+ dealing with machine language for your DLI, you can POKE
+ directly into the hardware registers you plan to change, rather
+ than using the shadow registers that BASIC uses.
+
+ There is, unfortunately, only one DLI vector address. If you use
+ more than one DLI and they are to perform different activities,
+ then changing the vectoring to point to a different routine must
+ be done by the previous DLI's themselves.
+
+ Another way to accomplish interrupts is during the VBLANK
+ interval with a VBI. One small problem with using DLI's is that
+ the keyboard "click" routine interferes with the DLI by throwing
+ off the timing, since the click is provided by several calls to the
+ WSYNC register at 54282 ($D40A). Chris Crawford discusses
+ several solutions in De Re Atari, but the easiest of them is not to
+ allow input from the keyboard! See Micro, December 1981,
+ Creative Computing, July 1981 and December 1981.
+ Here's a short example of a DLI. It will print the lower half of your
+ text screen upside down:
+
+ 10 START = PEEK(560) + PEEK(561) *
+ 256: POKE START + 16,130
+ 20 PAGE = 1536: FOR PGM = PAGE TO P
+ AGE + 7: READ BYTE: POKE PGM, BYTE
+ : NEXT PGM
+ 30 DATA 72,169,4,141,1,212,104,64
+ 40 POKE 512,0: POKE 513,6: POKE 542
+ 86,192
+ 50 FOR TEST = 1 TO 240: PRINT"SEE "
+ ;: NEXT TEST
+ 60 GOTO 60
+
+ DOWNLOAD VDSLST.BAS
+
+ Another example of a DLI changes the color of the bottom half of
+ the screen. To use it, simply change the PAGE + 7 to PAGE + 10
+ in the program above and replace line 30 with:
+
+ 30 DATA 72,169,222,141,10,212,141,2
+ 4,208,104,64
+
+ Finally, delete lines 50 and 60. See also location 54282 ($D40A).
+
+
+ 514,515 202,203 VPRCED
+
+ Serial (peripheral) proceed line vector, initialized to 59314
+ ($E7B2), which is merely a PLA, RTI instruction sequence. It is
+ used when an IRQ interrupt occurs due to the serial I/O bus
+ proceed line which is available for peripheral use. According to
+ De Re Atari, this interrupt is not used and points to a PLA, RTI
+ instruction sequence. This interrupt is handled by the PIA chip
+ and can be used to provide more control over external devices.
+ See the OS Listing, page 33.
+
+
+ 516,517 204,205 VINTER
+
+ Serial (peripheral) interrupt vector, initialized to 59314 ($E7B2).
+ Used for the IRQ interrupt due to a serial bus I/O interrupt.
+ According to De Re Atari, this interrupt is not used and points to
+ a PLA, RTI sequence. This interrupt is processed by PIA. See the
+ OS Listing, page 33.
+
+
+ 518,519 206,207 VBREAK
+
+ Software break instruction vector for the 6502 BRK ($00)
+ command (not the BREAK key, which is at location 17; $11),
+ initialized to 59314 ($E7B2). This vector is normally used for
+ setting break points in an assembly language debug operation.
+ IRQ.
+
+
+ 520,521 208,209 VKEYBD
+
+ POKEY keyboard interrupt vector, used for an interrupt
+ generated when any keyboard key is pressed other than BREAK
+ or the console buttons. Console buttons never generate an
+ interrupt unless one is specifically user-written. VKEYBD can be
+ used to process the key code before it undergoes conversion to
+ ATASCII form. Initialized to 65470 ($FFBE) which is the OS
+ keyboard IRQ routine.
+
+
+ 522,523 20A,20B VSERIN
+
+ POKEY serial I/O bus receive data ready interrupt vector,
+ initialized to 60177 ($EB11), which is the OS code to place a byte
+ from the serial input port into a buffer. Called INTRVEC by DOS,
+ it is used as an interrupt vector location for an SIO patch. DOS
+ changes this vector to 6691 ($1A23), the start of the DOS
+ interrupt ready service routine. IRQ.
+
+
+ 524,525 20C,20D VSEROR
+
+ POKEY serial I/O transmit ready interrupt vector, initialized to
+ 60048 (EA90), which is the OS code to provide the next byte in a
+ buffer to the serial output port. DOS changes this vector to 6630
+ ($19E6), the start of the DOS output needed interrupt routine.
+ IRQ.
+
+
+ 526,527 20E,20F VSEROC
+
+ POKEY serial bus transmit complete interrupt vector, initialized
+ to 60113 ($EAD1), which sets a transmission done flag after the
+ checksum byte is sent. IRQ.
+
+ SIO uses the three last interrupts to control serial bus
+ communication with the serial bus devices. During serial bus
+ communication, all program execution is halted. The actual
+ serial I/O is interrupt driven; POKEY waits and watches for a flag
+ to be set when the requested I/O operation is completed. During
+ this wait, POKEY is sending or receiving bits along the seriai
+ bus. When the entire byte has been transmitted (or received), the
+ output needed (VSEROR) or the input ready (VSERIN) IRQ is
+ generated according to the direction of the data flow. This causes
+ the next byte to be processed until the entire buffer has been sent
+ or is full, and a flag for "transmission done" is set. At this point,
+ SIO exits back to the calling routine. You can see that SIO wastes
+ time waiting for POKEY to send or receive the information on the
+ bus.
+
+
+ 528,529 210,211 VTIMR1
+
+ POKEY timer one interrupt vector, initialized to 59314 ($E7B2),
+ which is a PLA, RTI instruction sequence. Timer interrupts are
+ established when the POKEY timer AUDF1 (53760; $D200)
+ counts down to zero. Values in the AUDF registers are loaded
+ into STIMER at 53769 ($D209). IRQ.
+
+
+ 530,531 212,213 VTIMR2
+
+ POKEY timer two vector for AUDF2 (53762, $D202), initialized to
+ 59314 ($E7B2). IRQ.
+
+
+ 532,533 214,215 VTIMR4
+
+ POKEY timer four vector for AUDF4 (53766, $D206), initialized
+ to 59314 ($E7B2). This IRQ is only vectored in the "B" version of
+ the OS ROMs.
+
+
+ 534,535 216,217 VIMIRQ
+
+ The IRQ immediate vector (general). Initialized to 59126
+ ($E6F6). JMP through here to determine cause of the IRQ
+ interrupt. Note that with the new ("B") OS ROMs, there is a
+ BREAK key interrupt vector at locations 566, 567 ($236, $237).
+ See 53774 ($D20E) for more information on IRQ interrupts.
+
+ The new "B" version OS ROMs change the vectors above as
+ follows:
+
+ VDSLST 59280 ($E790)
+ VPRCED 59279 ($E78F)
+ VINTER 59279 ($E78F)
+ VBREAK 59279 ($E78F)
+ VKEYBD NO CHANGE
+ VSERIN 60175 ($EB0F)
+ VSEROR NO CHANGE
+ VSEROC 60111 ($EACF)
+ VTIMR 1-4 59279 ($E78F)
+ VIMIRQ 59142 ($E706)
+ VVBLKI 59310 ($E7AE)
+ VVBLKD 59653 ($E905)
+
+ ---------------------------------------------------------------------------
+ The locations from 536 to 558 ($218 to $22E) are used for the system
+ software timers. Hardware timers are located in the POKEY chip and
+ use the AUDF registers. These timers count backwards every 1/60
+ second (stage one VBLANK) or 1/30 second (stage two VBLANK)
+ interval until they reach zero. If the VBLANK process is disabled or
+ intercepted, the timers will not be updated. See De Re Atari for
+ information regarding setting these timers in an assembly routine
+ using the SETVBV register (58460; $E45C). These locations are user-
+ accessible and can be made to count time for music duration, game
+ I/O, game clock and other functions.
+ Software timers are used for durations greater than one VBLANK
+ interval (1/60 second). For periods of shorter duration, use the
+ hardware registers.
+
+
+ 536,537 218,219 CDTMV1
+
+ System timer one value. Counts backwards from 255. This SIO
+ timer is decremented every stage one VBLANK. When it reaches
+ zero, it sets a flag to jump (JSR) through the address stored in
+ locations 550, 551 ($226, $227). Only the realtime clock
+ (locations 18-20; $12-14), timer one, and the attract mode
+ register (77; $4D) are updated when the VBLANK routine is cut
+ short because time-critical code (location 66; $42 set to non-zero
+ for critical code) is executed by the OS. Since the OS uses timer
+ one for its I/O routines and for timing serial bus operations
+ (setting it to different values for timeout routines), you should use
+ another timer to avoid conflicts or interference with the operation
+ of the system.
+
+
+ 538,539 21A,21B CDTMV2
+
+ System timer two. Decremented at the stage two VBLANK. Can
+ be decremented every stage one VBLANK, subject to critical
+ section test as defined by setting of CRITIC flag (location 66;
+ $42). This timer may miss (skip) a count when time-critical code
+ (CRITIC equals non-zero) is being executed. It performs a JSR
+ through location 552, 553 ($228, $229) when the value counts
+ down to zero.
+
+
+ 540,541 21C,21D CDTMV3
+
+ System timer three. Same as 538. Timers three, four, and five are
+ stopped when the OS sets the CRITIC flag to non-zero as well.
+ The OS uses timer three to OPEN the cassette recorder and to set
+ the length of time to read and write tape headers. Any prior value
+ in the register during this function will be lost.
+
+
+ 542,543 21E,21F CDTMV4
+
+ System timer four. Same as 538 ($21A).
+
+
+ 544,545 220,221 CDTMV5
+
+ System timer five. Same as 538 ($21A). Timers three, four, and
+ five all set flags at 554, 556 and 558 ($22A, $22C, $22E),
+ respectively, when they decrement to zero.
+
+
+ 546,547 222,223 VVBLKI
+
+ VBLANK immediate register. Normally jumps to the stage one
+ VBLANK vector NMI interrupt processor at location 59345
+ ($E7D1); in the new OS "B" ROMs; 59310, $E7AE). The NMI
+ status register tests to see if the interrupt was due to a VBI (after
+ testing for a DLI) and, if so, vectors through here to the VBI
+ routine, which may be user-written. On powerup, VBI's are
+ enabled and DLI's are disabled. See location 512; $200.
+
+
+ 548,549 224,225 VVBLKD
+
+ VBLANK deferred register; system return from interrupt,
+ initialized to 59710 ($E93E, in the new OS "B" ROMs; 59653;
+ $E905), the exit for the VBLANK routine. NMI.
+
+ These two VBLANK vectors point to interrupt routines that occur
+ at the beginning of the VBLANK time interval. The stage one
+ VBLANK routine is executed; then location 66 ($42) is tested for
+ the time-critical nature of the interrupt and, if a critical code
+ section has been interrupted, the stage two VBLANK routine is
+ not executed with a JMP made through the immediate vector
+ VVBLKI. If not critical, the deferred interrupt VVBLKD is used.
+ Normally the VBLANK interrupt bits are enabled (BIT 6 at
+ location 54286; $D40E is set to one). To disable them, clear BIT 6
+ (set to zero).
+
+ The normal seguence for VBLANK interrupt events is: after the
+ OS test, JMP to the user immediate VBLANK interrupt routine
+ through the vector at 546, 547 (above), then through SYSVBV at
+ 58463 ($E45F). This is directed by the OS through the VBLANK
+ interrupt service routine at 59345 ($E7D1) and then on to the
+ user-deferred VBLANK interrupt routine vectored at 548, 549. it
+ then exits the VBLANK interrupt routine through 58466 ($E462)
+ and an RTI instruction.
+
+ If you are changing the VBLANK vectors during the interrupt
+ routine, use the SETVBV routine at 58460 ($E45C). An
+ immediate VBI has about 3800 machine cycles of time to use a
+ deferred VBI has about 20,000 cycles. Since many of these cycles
+ are executed while the electron beam is being drawn, it is
+ suggested that you do not execute graphics routines in deferred
+ VBI's. See the table of VBLANK processes at the end of the map
+ area.
+
+ if you create your own VBI's, terminate an immediate VBI with a
+ JMP to 58463 ($E45F) and a deferred VBI with a JMP to 58466
+ ($E462). To bypass the OS VBI routine at 59345 ($E7D1) entirely,
+ terminate your immediate VBI with a JMP to 58466 ($E462).
+
+ Here's an example of using a VBI to create a flashing cursor. It
+ will also blink any text you display in inverse mode.
+
+ 10 FOR BLINK = 1664 TO 1680: READ B
+ YTE: POKE BLINK, BYTE: NEXT BLINK
+ 20 POKE 548,128: POKE 549,6
+ 30 DATA 8,72,165,20,41,16,74,74,74,
+ 141
+ 40 DATA 243,2,104,40,76,62,233
+
+ DOWNLOAD VVBLKD.BAS
+
+ To restore the normal cursor and display, POKE 548,62 and
+ POKE 549,233.
+
+
+ 550,551 226,227 CDTMA1
+
+ System timer one jump address, initialized to 60400 ($EBF0).
+ When locations 536, 537 ($218, $219) reach (count down to) zero,
+ the OS vectors through here (jumps to the location specified by
+ these two addresses). You can set your machine code routine
+ address here for execution when timer one reaches (counts down
+ to) zero. Your code should end with the RTS instruction.
+ Problems may occur when timer values are set greater than 255,
+ since the 6502 cannot manipulate 16-bit values directly (a
+ number in the range of zero to 255 is an eight-bit value; if a value
+ requires two bytes to store, such as a memory location, it is a
+ 16-bit value). Technically, a VBLANK interrupt could occur
+ when one timer byte is being initialized and the other not yet set.
+ To avoid this, keep timer values less than 255. See the Atari OS
+ User's Manual, page 106, for details.
+
+ Since the OS uses timer one, it is recommended that you use
+ timer two instead, to avoid conflicts with the operation of the
+ Atari. Initialized to 60396 ($EBEA) in the old ROMs, 60400
+ ($EBF0) in the new ROMs. NMI
+
+
+ 552,553 228,229 CDTMA2
+
+ System timer two jump address. Not used by the OS, available to
+ user to enter the address of his or her own routine to JMP to when
+ the timer two (538, 539; $21A, $21B) count reaches zero.
+ Initialized to zero; the address must be user specified. NMI
+
+
+ 554 22A CDTMF3
+
+ System timer three flag, set when location 540, 541 ($21C, $21D)
+ reaches zero. This register is also used by DOS as a timeout flag.
+
+
+ 555 22B SRTIMR
+
+ Software repeat timer, controlled by the IRQ device routine. It
+ establishes the initial 1/2 second delay before a key will repeat.
+ Stage two VBLANK establishes the 1/10 second repeat rate,
+ decrements the timer and implements the auto repeat logic.
+ Every time a key is pressed, STIMER is set to 48 ($30). Whenever
+ SRTIMR is equal to zero and a key is being continuously pressed,
+ the value of that key is continually stored in CH, location 764
+ ($2FC).
+
+
+ 556 22C CDTMF4
+
+ System timer four flag. Set when location 542, 543 ($21E, $21F)
+ counts down to zero.
+
+
+ 557 22D INTEMP
+
+ Temporary register used by the SETVBL routine at 58460
+ ($E45C).
+
+
+ 558 22E CDTMF5
+
+ System timer five flag. Set when location 558, 559 ($22E, $22F)
+ counts down to zero.
+
+ ---------------------------------------------------------------------------
+
+ 559 22F SDMCTL
+
+ Direct Memory Access (DMA) enable. POKEing with zero allows
+ you to turn off ANTIC and speed up processing by 30%. Of
+ course, it also means the screen goes blank when ANTIC is
+ turned off! This is useful to speed things up when you are doing a
+ calculation that would take a long time. It is also handy to turn off
+ the screen when loading a drawing, then turning it on when the
+ screen is loaded so that it appears instantly, complete on the
+ screen. To use it you must first PEEK(559) and save the result in
+ order to return your screen to you. Then POKE 559,0 to turn off
+ ANTIC. When you are ready to bring the screen back to life,
+ POKE 559 with the number saved earlier.
+
+ This location is the shadow register for 54272 ($D400), and the
+ number you PEEKed above defines the playfield size, whether or
+ not the missiles and players are enabled, and the player size
+ resolution. To enable your options by using POKE 559, simply
+ add up the values below to obtain the correct number to POKE
+ into SDMCTL. Note that you must choose only one of the four
+ playfield options appearing at the beginning of the list:
+
+ Option Decimal Bit
+ No playfield 0 0
+ Narrow playfield 1 0
+ Standard playfield 2 0,1
+ Wide playfield 3 0,1
+ Enable missle DMA 4 2
+ Enable player DMA 8 3
+ Enable player and missile
+ DMA 12 2,3
+ One line player resolution 16 4
+ Enable instructions to fetch
+ DMA 32 5 (see below)
+
+ Note that two-line player resolution is the default and that it is not
+ necessary to add a value to 559 to obtain it. I have included the
+ appropriate bits affected in the table above. The default is 34
+ ($22).
+
+ The playfield is the area of the TV screen you will use for display,
+ text, and graphics. Narrow playfield is 128 color clocks (32
+ characters wide in GR.0), standard playfield is 160 color clocks
+ (40 characters), and wide playfield is 192 color clocks wide (48
+ characters). A color clock is a physical measure of horizontal
+ distance on the TV screen. There are a total of 228 color clocks on
+ a line, but only some of these (usually 176 maximum) will be
+ visible due to screen limitations. A pixel, on the other hand, is a
+ logical unit which varies in size with the GRAPHICS mode. Due
+ to the limitations of most TV sets, you will not be able to see all of
+ the wide playfield unless you scroll into the offscreen portions.
+ BIT 5 must be set to enable ANTIC operation; it enables DMA for
+ fetching the display list instructions.
+
+
+ 560,561 230,231 SDLSTL
+
+ Starting address of the display list. The display list is an
+ instruction set to tell ANTIC where the screen data is and how to
+ display it. These locations are the shadow for 54274 and 54275
+ ($D402, $D403). You can also find the address of the DL by
+ PEEKing one byte above the top of free memory:
+
+ PRINT PEEK(741) + PEEK(742) * 256 + 1.
+
+ However, 560 and 561 are more reliable pointers since custom
+ DL's can be elsewhere in memory. Atari standard display lists
+ simply instruct the ANTIC chip as to which types of mode lines to
+ use for a screen and where the screen data may be found in
+ memory. Normally, a DL is between 24 and 256 bytes long (most
+ are less than 100 bytes, however), depending on your
+ GRAPHICS mode (see location 88,89 for a chart of DL sizes and
+ screen display use).
+
+ By altering the DL, you can mix graphics modes on the same
+ screen; enable fine scrolling; change the location of the screen
+ data; and force interrupts (DLI's) in order to perform short
+ machine language routines.
+
+ DL bytes five and six are the addresses of the screen memory
+ data, the same as in locations 88 and 89 ($58, $59). Bytes four,
+ five, and six are the first Load Memory Scan (LMS) instruction.
+ Byte four tells ANTIC what mode to use; the next two bytes are
+ the location of the first byte of the screen RAM (LSB/MSB).
+ Knowing this location allows you to write directly to the screen by
+ using POKE commands (you POKE the internal character codes,
+ not the ATASCII codes -- see the BASIC Reference Manual, p.
+ 55).
+
+ For example, the program below will POKE the internal codes to
+ the various screen modes. You can see not only how each screen
+ mode handles the codes, but also roughly where the text window
+ is in relation to the display screen (the 160 bytes below
+ RAMTOP). Note that the GTIA modes have no text window. If
+ you don't have the GTIA chip, your Atari will default to
+ GRAPHICS 8, but with GTIA formatting.
+
+ 1 TRAP 10: GRAPHICS Z
+ 5 SCREEN = PEEK(560) + PEEK(561) *
+ 256
+ 6 TV = SCREEN + 4: TELE = SCREEN + 5
+ 8 DISPLAY = PEEK(TV) + PEEK(TELE) *
+ 256
+ 10 FOR N = 0 TO 255: POKE DISPLAY +
+ N,N: NEXT N
+ 20 DISPLAY = DISPLAY + N
+ 30 IF DISPLAY > 40959 THEN Z = Z + 1
+ : GOTO 1
+ 40 GOTO 10
+ 50 Z = Z + 1:IF Z > 60 THEN END
+ 60 GOTO 1
+
+ Here's another short program which will allow you to examine the
+ DL in any GRAPHICS mode:
+
+ 10 REM CLEAR SCREEN FIRST
+ 20 PRINT"ENTER GRAPHICS MODE": REM A
+ DD 16 TO THE MODE TO SUPPRESS THE
+ TEXT WINDOW
+ 30 INPUT A: GRAPHICS A
+ 40 DLIST = PEEK(560) + PEEIK(561) * 2
+ 56
+ 50 LOOK = PEEK(DLIST): PRINT LOOK;"
+ ";
+ 60 IF LOOK <> 65 THEN DLIST = DLIST
+ + 1: GOTO 50
+ 70 LPRINT PEEK(DLIST + 1);" ";PEEK(D
+ LIST + 2)
+ 80 END
+
+ The value 65 in the DL is the last instruction encountered. It tells
+ ANTIC to jump to the address in the next two bytes to re-execute
+ the DL, and wait for the next VBLANK. If you don't have a
+ printer, change the LPRINT commands to PRINT and modify the
+ routine to save the data in an array and PRINT it to the screen
+ after (in GR.0).
+
+ If you would like to examine the locations of the start of the
+ Display List, screen, and text window, try:
+
+ 5 REM CLEAR SCREEN FIRST
+ 6 INPUT A: GRAPHICS A
+ 10 DIM DLIST$(10), SAVMSC$(10), TXT$
+ (10)
+ 15 DLIST$ = "DLIST": SAVMSC$ = "SAVM
+ SC": TXT$ = "TEXT"
+ 20 DLIST = PEEK(560) + PEEK(561) * 2
+ 56
+ 30 SAV = PEEK(88) + PEEK(89) * 256:
+ TXT = PEEK(660) + PEEK(66l) * 256
+ 40 PRINT DLIST$;" "; DLIST,SAVMSC$;"
+ ";SAV
+ 50 PRINT TXT$;" "; TEXT
+ 60 INPUT A: GRAPHICS A: GOTO 20
+
+ Since an LMS is simply a map mode (graphics) or character
+ mode (text) instruction with BIT six set, you can make any or all of
+ these instructions into LMS instructions quite easily, pointing
+ each line to a different RAM area if necessary. This is discussed
+ in De Re Atari on implementing horizontal scrolling.
+
+ DL's can be used to help generate some of the ANTIC screen
+ modes that aren't supported by BASIC, such as 7.5 (ANTIC
+ mode E) or ANTIC mode three, the lowercase with descenders
+ mode (very interesting; ten scan lines in height which allow true
+ descenders on lowercase letters).
+
+ If you create your own custom DL, you POKE its address here.
+ Hitting BESET or changing GRAPHICS modes will restore the
+ OS DL address, however. The display list instruction is loaded
+ into a special register called the Display Instruction Register (IR).
+ which processes the three DL instructions (blank, jump, or
+ display). It cannot be accessed directly by the programmer in
+ either BASIC or machine language. A DL cannot cross a 1K
+ boundary unless a jump instruction is used.
+
+ There are only four display list instructions: blank line (uses BAK
+ color), map mode, text mode, and jump. Text (character mode)
+ instructions and map mode (graphics) instructions range from
+ two to 15 ($2 to $F) and are the same as the ANTIC GRAPHICS
+ modes. A DL instruction byte uses the following conventions
+ (functions are enabled when the bit is set to one):
+
+ Bit Decimal Function
+ 7 128 Display List Interrupt when set (enabled
+ equals one)
+ 6 64 Load Memory Scan. Next two bytes are the
+ LSB/MSB of the data to load.
+ 5 32 Enable vertical fine scrolling.
+ 4 16 Enable horizontal fine scrolling.
+ 3-0 8-1 Mode
+ 0 0 1 0 Character
+ to Modes
+ 0 1 1 1
+ . . . . . . .
+ 1 0 0 0 Map
+ to Modes
+ 1 1 1 1
+
+ The above bits may be combined (i.e., DLI, scrolling and LMS
+ together) if the user wishes.
+
+ Special DL instructions (with decimal values):
+ Blank 1 line = 0 5 lines = 64
+ 2 lines = 16 6 lines = 80
+ 3 lines = 32 7 lines = 96
+ 4 lines = 48 8 lines = 112
+
+ Jump instruction (JMP) = zero (three-byte instruction).
+ Jump and wait for Vertical Blank (JVP) = 65 (three-byte
+ instruction).
+ Special instructions may be combined only with DL interrupt
+ instructions.
+
+ A Display List Interrupt is a special form of interrupt that takes
+ place during the screen display when the ANTIC encounters a
+ DL instruction with the interrupt BIT 7 set. See location 512
+ ($200) for DLI information.
+
+ Since DL's are too large a topic to cover properly in this manual,
+ I suggest you look in the many magazines (i.e., Creative
+ Computing, July 1981, August 1981; Micro, December 1981;
+ Softside, #30 to 32, and BYTE, December 1981) for a more
+ detailed explanation
+
+
+ 562 232 SSKCTL
+
+ Serial port control register, shadow for 53775 ($D20F). Setting
+ the bits in this register to one has the following effect:
+
+ Bit Decimal Function
+ 0 1 Enable the keyboard debounce circuit.
+ 1 2 Enable the keyboard scanning circuit.
+ 2 4 The pot counter completes a read within two
+ scan lines instead of one frame time.
+ 3 8 Serial output transmitted as two-tone instead
+ of logic true/false (POKEY two-tone mode).
+ 4-6 16-64 Serial port mode control.
+ 7 128 Force break; serial output to zero.
+
+ Initialized to 19 ($13) which sets bits zero, one and four.
+
+
+ 563 233 SPARE
+
+ No OS use. See the note at location 651 regarding spare bytes.
+
+
+ 564 234 LPENH
+
+ Light pen horizontal value shadow for 54284 ($D40C). Values
+ range from zero to 227.
+
+
+ 565 235 LPENV
+
+ Light pen vertical value: shadow for 54285 ($D40D). Value is the
+ same as VCOUNT register for two-line resolution (see 54283;
+ $D40B). Both light pen values are modified when the trigger is
+ pressed (pulled low). The light pen positions are not the same as
+ the normal screen row and column positions. There are 96
+ vertical positions, numbered from 16 at the top to 111 at the
+ bottom, each one equivalent to a scan line. Horizontal positions
+ are marked in color clocks. There are 228 horizontal positions,
+ numbered from 67 at the left. When the LPENH value reaches
+ 255, it is reset to zero and begins counting again by one to the
+ rightmost edge, which has a value of seven.
+
+ Obviously, because of the number of positions readable and the
+ small size of each, a certain leeway must be given by the
+ programmer when using light pen readouts on a program. At the
+ time of this writing, Atari had not yet released its light pen onto
+ the market, although other companies have.
+
+
+ 566,567 236,237 BRKKY
+
+ BREAK key interrupt vector. This vector is available only with
+ the version "B" OS ROMs, not the earlier version. You can use
+ this vector to write your own BREAK key interrupt routine.
+ Initialized to 59220 ($E754).
+
+
+ 568,569 238,239 ....
+
+ Two spare bytes.
+
+
+ 570 23A CDEVIC
+
+ Four-byte command frame buffer (CFB) address for a device --
+ used by SIO while performing serial I/O, not for user access.
+ CDEVIC is used for the SIO bus ID number The other three CFB
+ bytes are:
+
+
+ 571 23B CCOMND
+
+ The SIO bus command code.
+
+
+ 572 23C CAUX1
+
+ Command auxiliary byte one, loaded from location 778 ($30A)
+ by SIO.
+
+
+ 573 23D CAUX2
+
+ Command auxiliary byte two, loaded from location 779 ($30B) by
+ SIO.
+
+
+ 574 23E TEMP
+
+ Temporary RAM register for SIO.
+
+
+ 575 23F ERRFLG
+
+ SIO error flag; any device error except the timeout error (time
+ equals zero).
+
+
+ 576 240 DFLAGS
+
+ Disk flags read from the first byte of the boot file (sector one) of
+ the disk.
+
+
+ 577 241 DBSECT
+
+ The number of disk boot sectors read from the first disk record.
+
+
+ 578,579 242,243 BOOTAD
+
+ The address for where the disk boot loader will be put. The
+ record just read will be moved to the address specified here,
+ followed by the remaining records to be read. Normally, with
+ DOS, this address is 1792 ($700), the value also stored
+ temporarily in RAMLO at 4, 5. Address 62189 ($F2ED) is the OS
+ disk boot routine entry point (DOBOOT).
+
+
+ 580 244 COLDST
+
+ Coldstart flag. Zero is normal, if zero, then pressing RESET will
+ not result in reboot. If POKEd with one (powerup in progress
+ flag), the computer will reboot whenever the RESET key is
+ pressed. Any non-zero number indicates the initial powerup
+ routine is in progress.
+
+ If you create an AUTORUN.SYS file, it should end with an RTS
+ instruction. If not, it should POKE 580 with zero and POKE 9 with one.
+ You can turn any binary file that boots when loaded with DOS menu
+ selection "L" into an auto-boot file simply by renaming it
+ "AUTORUN.SYS". Be careful not to use the same name for any two
+ files on the same disk.
+
+ When this is combined with the disabling of the BREAK key discussed
+ in location 16 ($10) and the program protection scheme discussed in
+ location 138 ($8A), you have the means to protect your BASIC
+ software fairly effectively from being LISTed or examined, although
+ not from being copied.
+
+
+ 581 245 ....
+
+ Spare byte.
+
+
+ 582 246 DSKTIM
+
+ Disk time-out register (the address of the OS worst case disk time-
+ out). It is said by many sources to be set to 160 at initialization
+ which represents a 171 second time-out, but my system shows a
+ value of 224 on initialization. Timer values are 64 seconds for
+ each 60 units of measurement expressed.
+ It is updated after each disk status request to contain the value of
+ the third byte of the status frame (location 748; $2EC). All disk
+ operations have a seven second time-out (except FORMAT),
+ established by the disk handler (you had noticed that irritating
+ little delay, hadn't you?). The "sleeping disk syndrome" (the
+ printer suffers from this malady as well) happens when your drive
+ times out, or the timer value reaches zero. This has been cured
+ by the new OS "B" version ROMs.
+
+
+ 583-622 247-26E LINBUF
+
+ Forty-byte character line buffer, used to temporarily buffer one
+ physical line of text when the screen editor is moving screen
+ data. The pointer to this buffer is stored in 100, 101 ($64, $65)
+ during the routine.
+
+
+ 623 26F GPRIOR
+
+ Priority selection register, shadow for 53275 ($D01B). Priority
+ options select which screen objects will be "in front" of others. It
+ also enables you to use all four missiles as a fifth player and
+ allows certain overlapping players to have different colors in the
+ areas of overlap. You add your options up as in location 559,
+ prior to POKEing the total into 623. In this case, choose only one
+ of the four priorities stated at the beginning. BAK is the
+ background or border. You can also use this location to select
+ one of GTIA GRAPHICS modes nine, ten, or eleven.
+
+ Priority options in order Decimal Bit
+ Player 0 - 3, playfield 0 - 3, BAK
+ (background) 1 0
+ Player 0 - 1, playfield 0 - 3, player 2 - 3,
+ BAK 2 1
+ Playfield 0 - 3, player 0 - 3, BAK 4 2
+ Playfield 0 - 1, player 0 - 3, playfield 2 -3,
+ BAK 8 3
+ Other options
+ Four missiles = fifth player 16 4
+ Overlaps of players have 3rd color 32 5
+ GRAPHICS 9 (GTIA mode) 64 6
+ GRAPHICS 10 (GTIA mode) 128 7
+ GRAPHICS 11 (GTIA mode) 192 6, 7
+
+ It is quite easy to set conflicting priorities for players and
+ playfields. In such a case, areas where both overlap when a
+ conflict occurs will turn black. The same happens if the overlap
+ option is not chosen.
+ With the color/overlap enable, you can get a multicolor player
+ by combining players. The Atari performs a logical OR to colors
+ of players 0/1 and 2/3 when they overlap. Only the 0/1, 2/3
+ combinations are allowed; you will not get a third color when
+ players 1 and 3 overlap, for example (you will get black instead).
+ If player one is pink and player 0 is blue, the overlap is green. If
+ you don't enable the overlap option, the area of overlap for all
+ players will be black.
+ In GTIA mode nine, you have 16 different luminances of the
+ same hue. In BASIC, you would use SETCOLOR 4,HUE,0. To
+ see an example of GTIA mode nine, try:
+
+ 10 GRAPHICS 9: SETCOLOR 4,9,0
+ 20 FOR LOOP = 1 TO 15: COLOR LOOP
+ 30 FOR LINE = 1 TO 2
+ 40 FOR TEST = 1 TO 25: PLOT 4 + TES
+ T, LOOP + LINE + SPACE: NEXT TEST
+ 45 NEXT LINE
+ 50 SPACE = SPACE + 4
+ 60 NEXT LOOP
+ 70 GOTO 70: REM WITHOUT THIS LINE,
+ SCREEN WILL RETURN TO GR.0
+
+ DOWNLOAD GTIA9.BAS
+
+ In GTIA mode ten, you have all nine color registers available;
+ hue and luminance may be set separately for each (it would
+ otherwise allow 16 colors, but there are only nine registers). Try
+ this to see:
+
+ 10 N = 0: GRAPHICS 10
+ 20 FOR Q = 1 TO 2
+ 30 FOR B = 0 TO 8: POKE 704 + B, N
+ * 16 + A
+ 35 IF A > 15 THEN A = 0
+ 40 COLOR B
+ 45 A = A + 1: N = N + 1
+ 50 IF N > 15 THEN N = 0
+ 60 NEXT B
+ 65 TRAP 70: NEXT Q
+ 70 POP: N = N + 1: FOR Z = 1 TO 200
+ : NEXT Z
+ 75 GOTO 30
+
+ DOWNLOAD GTIA10.BAS
+
+ GTIA mode eleven is similar to mode nine except that it allows 16
+ different hues, all of the same luminance. In BASIC, use
+ SETCOLOR 4,O,luminance. Try this for a GTIA mode eleven
+ demonstration:
+
+ 10 GRAPHICS 11
+ 20 FOR LOOP = 0 TO 79: COLOR LOOP:
+ PLOT LOOP,0: DRAWTO LOOP,191: NEXT
+ LOOP
+ 30 GOTO 30
+
+ DOWNLOAD GTIA11.BAS
+
+ You can use these examples with the routine to rotate colors,
+ described in the text preceding location 704. GTIA mode pixels
+ are long and skinny; they have a four to one horizontal length to
+ height ratio. This obviously isn't very good for drawing curves
+ and circles!
+
+ GTIA modes are cleared on the OPEN command. How can you
+ tell if you have the GTIA chip? Try POKE 623,64. If you have the
+ GTIA, the screen will go all black. If not, you don't have it. Here
+ is a short routine, written by Craig Chamberlain and Sheldon
+ Leemon for COMPUTE!, which allows an Atari to test itself for the
+ presence of a CTIA or GTIA chip. The routine flashes the answer
+ on the screen, hut can easily be modified so a program will
+ "know" which chip is present so it can adapt itself accordingly:
+
+ 10 POKE 66,1:GRAPHICS 8:POKE 709,0:PO
+ KE 710,0:POKE 66,0:POKE 623,64:P0K
+ E 53248,42:POKE 5326l,3:PUT#6,1
+ 20 POKE 53278,0:FOR K=1 TO 300:NEXT K
+ :GRAPHICS 18:POKE 53248,0:POSITION
+ 8,5:? #6;CHR$(71-PEEK(53252));"TI
+ A"
+ 30 POKE 708,PEEK(20):GOTO 30
+
+ DOWNLOAD CTIAGTIA.BAS
+
+ How can you get the GTIA if you don't have one? Ask your local
+ Atari service representative or dealer, or write directly to Atari in
+ Sunnyvale, California.
+
+ See the GTIA/CTIA introduction at location 53248 ($D000) for
+ more discussion of the chip. See BYTE, May 1982, COMPUTE!,
+ July through September 1982, and De Re Atari for more on the
+ GTIA chip, and the GTIA Demonstration Diskette from the Atari
+ Program Exchange (APX).
+
+ ---------------------------------------------------------------------------
+ Locations 624 to 647 ($270 to $287) are used for game controllers:
+ paddle, joystick and lightpen values.
+
+
+ 624 270 PADDL0
+
+ The value of paddle 0 (paddles are also called pots, short for
+ potentiometer); PEEK 624 returns a number between zero and
+ 228 ($E4), increasing as the knob is turned counter-clockwise.
+ When used to move a player or cursor (i.e., PLOT
+ PADDLE(0),0), test your screen first. Many sets will not display
+ locations less than 48 ($30) or greater than 208 ($D0), and in
+ many GRAPHICS modes you will get an ERROR 141 -- cursor
+ out of range. Paddles are paired in the controller jacks, so paddle
+ 0 and paddle 1 both use jack one. PADDL registers are shadows
+ for POKEY locations 53760 to 53767 ($D200 to $D207).
+
+
+ 625 271 PADDL1
+
+ This and the next six bytes are the same as 624, but for the other
+ paddles.
+
+
+ 626 272 PADDL2
+
+ 627 273 PADDL3
+
+ 628 274 PADDL4
+
+ 629 275 PADDL5
+
+ 630 276 PADDL6
+
+ 631 277 PADDL7
+
+ 632 278 STICK0
+
+ The value of joystick 0. STICK registers are shadow locations for
+ PIA locations 54016 and 54017 ($D300, $D301). There are nine
+ possible decimal values (representing 45 degree incrememts)
+ read by each joystick register (using the STICKn command),
+ depending on the position of the stick:
+
+ Decimal Binary
+ 14 1110
+ | |
+ 10 | 6 1010 | 0110
+ \ |/ \ |/
+ 11-- 15 ---7 1011-- 1111 --0111
+ / |\ / |\
+ 9 | 5 1001 | 0101
+ | |
+ 13 1101
+
+ 15 (1111) equals stick in the upright (neutral) position.
+ See Micro, December 1981,for an article on making a
+ proportional joystick. For an example of a machine language
+ joystick driver you can add to your BASIC program, see
+ COMPUTE!, July 1981.
+ One machine language joystick reader is listed below, based on
+ an article in COMPUTE!, August 1981:
+
+ 1 GOSUB 1000
+ 10 LOOK = STICK(0)
+ 20 X = USR(1764,LOOK): Y = USR(1781,
+ LOOK)
+ 30 ON X GOTO 120, 100, 110
+ .
+ .
+ .
+ 100 REM YOUR MOVE LEFT ROUTINE HERE
+ 105 GOTO 10
+ 110 REM YOUR MOVE RIGHT ROUTINE HERE
+ 115 GOTO 10
+ 120 ON Y GOTO 150, 130, 140
+ 130 REM YOUR MOVE DOWN ROUTINE HERE
+ 135 GOTO 10
+ 140 REM YOUR MOVE UP ROUTINE HERE
+ 145 GOTO 10
+ 150 REM IF X <> 1 THEN NOTHING DOING.
+ BRANCH TO YOUR OTHER ROUTINES OR
+ TO 155
+ 155 GOTO 10
+ .
+ .
+ .
+ 1000 FOR LOOP = 1764 TO 1790: READ BY
+ TE: POKE LOOP, BYTE: NEXT LOOP
+ 1010 DATA 104,104,133,213,104,41,12,7
+ 4,74,73,2,24,105,1
+ 1020 DATA 133,212,96,104,104,133,213,
+ 104,41,3,76,237,6
+ 1030 RETURN
+
+ DOWNLOAD STICK0.BAS
+
+ See locations 88, 89 ($58, $59) for an example of a USR call using
+ a string instead of a fixed memory location.
+
+
+ 633 279 STICK1
+
+ This and the next two locations are the same as 632, but for the
+ other joysticks. These four locations are also used to determine if
+ a lightpen (PEN 0 - 3) switch is pressed.
+
+
+ 634 27A STICK2
+
+ 635 27B STICK3
+
+ 636 27C PTRIG0
+
+ Paddle trigger 0. Used to determine if the trigger or hutton on
+ paddle 0 is pressed (zero is returned) or not (one is returned).
+ Since these are the same lines as the joystick left/right switches,
+ you can use PTRIG for horizontal movement. PTRIG(1) -
+ PTRIG(0) returns -1 (left), 0 (center), + 1 (right). The next seven
+ locations are for the other paddle buttons. PTRIG 0 - 3 are
+ shadows for PIA register 54016 ($D300).
+
+
+ 637 27D PTRIG1
+
+ 638 27E PTRIG2
+
+ 639 27F PTRIG3
+
+ 640 280 PTRIG4
+
+ PTRIG 4-7 are shadows for PIA register 54017 ($D301).
+
+
+ 641 281 PTRIG5
+
+ 642 282 PTRIG6
+
+ 643 283 PTRIG7
+
+ 644 284 STRIG0
+
+ Stick trigger 0. This and the next three locations perform the
+ same function as the PTRIG locations except for the joysticks.
+ Like PTBIG, zero is returned when the button is pressed; one is
+ returned when it is not. STRIG registers are shadow registers for
+ GTIA/CTIA locations 53264 to 53267 ($D010 to $D013).
+
+
+ 645 285 STRIG1
+
+ 646 286 STRIG2
+
+ 647 287 STRIG3
+
+ ---------------------------------------------------------------------------
+ Locations 648 to 655 ($288 to $28F) are for miscellaneous OS use.
+
+
+ 648 288 CSTAT
+
+ Cassette status register.
+
+
+ 649 289 WMODE
+
+ Register to store either the read or the write mode for the cassette
+ handler, depending on the operation: zero equals read, 128 ($80)
+ equals write.
+
+
+ 650 28A BLIM
+
+ Cassette data record buffer size; contains the number of active
+ data bytes in the cassette buffer for the record being read or
+ written, at location 1021 ($3FD). Values range from zero to 128
+ (cassette record size is 128; $80). The pointer to the byte being
+ read or written is at 61 ($3D). The value of BLIM is drawn from
+ the control bytes that precede every cassette record, as
+ explained in location 1021.
+
+
+ 651-655 28B-28F ....
+
+ Spare bytes. It is not recommended that you use the spare bytes
+ for your own program use. In later upgrades of the OS, these
+ bytes may be used, causing a conflict with your program. For
+ example, the new OS ROMs use locations 652 and 653 ($28C,
+ $28D) in the new IRQ interrupt handler routines. It is best to use a
+ protected area of memory such as page six, locations 1536 to
+ 1791 ($600 to $6FF).
+
+ ---------------------------------------------------------------------------
+ Locations 656 to 703 ($290 to $2BF) are used for the screen RAM
+ display handler (depending on GRAPHICS mode).
+ In split-screen mode, the text window is controlled by the screen editor
+ (E:), while the graphics region is controlled by the display handler
+ (S:), using two separate IOCB's. Two separate cursors are also
+ maintained. The display handler will set AUX1 of the IOCB to split-
+ screen option. Refer to the IOCB area, locations 832 to 959 ($340 to
+ $3BF). See COMPUTE!, February 1982, for a program to put GR.1
+ and GR.2 into the text window area. The text window uses 160 bytes of
+ RAM located just below RAMTOP (see location 106; $6A). See
+ location 88 ($58) for a chart of screen RAM use.
+
+
+ 656 290 TXTROW
+
+ Text window cursor row; value ranges from zero to three (the text
+ window has only four lines). TXTROW specifies where the next
+ read or write in the text window will occur
+
+
+ 657,658 291,292 TXTCOL
+
+ Text window cursor column; value ranges from zero to 39. Unless
+ changed by the user, location 658 will always be zero (there are
+ only 40 columns in the display, so the MSB will be zero). Since
+ POSITION, PLOT, LOCATE and similar commands refer to the
+ graphics cursor in the display area above the text window, you
+ must use POKE statements to write to this area if PRINT
+ statements are insufficient.
+
+
+ 659 293 TINDEX
+
+ Contains the current split-screen text window GRAPHICS mode.
+ It is the split-screen equivalent to DINDEX (location 87; $57) and
+ is always equal to zero when location 128 ($7B) equals zero.
+ Initialized to zero (which represents GR.0). You can alter the
+ display list to change the text window into any GRAPHICS mode
+ desired. If you do so, remember to change TINDEX to reflect that
+ alteration.
+
+
+ 660,661 294,295 TXTMSC
+
+ Address of the upper left corner of the text window. Split-screen
+ equivalent of locations 88, 89 ($58, $59).
+
+
+ 662-667 296-29B TXTOLD
+
+ These locations contain the split-screen equivalents of OLDROW
+ (90; $5A), OLDCOL (91, 92; $5B, $5C), OLDCHR (location 93,
+ $5D) and OLDADR (locations 94, 95; $5E, $5F). They hold the
+ split-screen cursor data.
+
+
+ 668 29C TMPX1
+
+ Temporary register, used by the display handler for the scroll
+ loop count record.
+
+
+ 669 29D HOLD3
+
+ Temporary register.
+
+
+ 670 29E SUBTMP
+
+ Temporary storage.
+
+
+ 671 29F HOLD2
+
+ Temporary register.
+
+
+ 672 2A0 DMASK
+
+ Pixel location mask. DMASK contains zeroes tor all bits which do
+ not correspond to the specific pixel to be operated upon, and
+ ones for bits which do correspond, according to the GRAPHICS
+ mode in use, as follows:
+
+ 11111111 Modes 0, 1 and 2: one pixel per screen display
+ byte.
+ 11110000 Modes 9, 10 and 11: two pixels per byte.
+ 00001111
+ 11000000 Modes 3, 5 and 7: four pixels per byte.
+ 00110000
+ 00001100
+ 00000011
+ 10000000 Modes 4, 6 and 8: eight pixels per byte.
+ 01000000
+
+ etc. to:
+
+ 00000001
+
+ A pixel (short for picture cell or picture element) is a logical unit
+ of video size which depends on the GRAPHICS mode in use for
+ its dimensions. The smallest pixel is in GR.8 where it is only .5
+ color clock wide and one scan line high. In GR.0 it is also only .5
+ color clock wide, but it is eight scan lines high. Here is a chart of
+ the pixel sizes for each mode:
+
+ Text Modes Graphics modes
+ GR. mode 0 1 2 3 4 5 6 7 8
+ Scan lines
+ per pixel 8 8 16 8 4 4 2 2 1
+ Bits
+ per pixel 1 1 1 2 1 2 1 2 1
+ Color clocks
+ per pixel .5 1 1 4 2 2 1 1 .5
+ Characters
+ per line 40 20 20 -- -- -- -- -- --
+ Pixels
+ per width -- -- -- 40 80 80 160 160 320
+
+ The number of pixels per screen width is based on the normal
+ playfield screen. See location 559 ($22F) for information on
+ playfield size.
+
+
+ 673 2A1 TMPLBT
+
+ Temporary storage for the bit mask.
+
+
+ 674 2A2 ESCFLG
+
+ Escape flag. Normally zero, it is set to 128 ($80) if the ESC key is
+ pressed (on detection of the ESC character; 27, $1B). It is reset to
+ zero following the output of the next character. To display
+ ATASCII control codes without the use of an ESC character, set
+ location 766 ($2FE) to a non-zero value.
+
+
+ 675-689 2A3-2B1 TABMAP
+
+ Map of the TAB stop positions. There are 15 byte (120 bits) here,
+ each bit corresponding to a column in a logical line. A one in any
+ bit means the TAB is set; to clear all TABs simply POKE every
+ location with zero. There are 120 TAB locations because there
+ are three physical lines to one logical line in GRAPHICS mode
+ zero, each consisting of 40 columns. Setting the TAB locations for
+ one logical line means they will also be set for each subsequent
+ logical line until changed. Each physical line in one logical line
+ can have different TAB settings, however.
+
+ To POKE TAB locations from BASIC, you must POKE in the
+ number (i.e., set the bit) that corresponds to the location of the
+ bit in the byte (there are five bytes in each line). For example:
+ To set tabs at locations 5, 23, 27 and 32, first visualize the line as a
+ string of zeros with a one at each desired tab setting:
+
+ 0000100000000000000000100010000100000000
+
+ Then break it into groups of eight bits (one byte units). There are
+ three bytes with ones (bits set), two with all zeros:
+
+ 00001000 = 8
+ 00000000 = 0
+ 00000010 = 2
+ 00100001 = 33
+ 00000000 = 0
+
+ Converting these to decimal, we get the values listed at the right
+ of each byte. These are the numbers you'd POKE into locations
+ 675 (the first byte) to 679 (the fifth byte on the line). On powerup
+ or when you OPEN the display screen (S: or E:), each byte is
+ given a value of one (i.e., 00000001) so that there are tab default
+ tab stops at 7, 15, 23, etc., incrementing by eight to 119. Also,
+ the leftmost screen edge is also a valid TAB stop (2, 42, and 82).
+ In BASIC, these are set by the SET-TAB and CLR-TAB keys.
+ TABMAP also works for the lines in the text display window in
+ split-screen formats. TABMAP is reset to the default values on
+ pressing RESET or changing GRAPHICS modes.
+ See location 201 ($C9) about changing the TAB settings used
+ when a PRINT statement encounters a comma.
+
+
+ 690-693 2B2-2B5 LOGMAP
+
+ Logical line start bit map. These locations map the beginning
+ physical line number for each logical line on the screen (initially
+ 24, for GR.0). Each bit in the first three bytes shows the start of a
+ logical line if the bit equals one (three bytes equals eight bits *
+ three equals 24 lines on the screen). The map format is as follows:
+
+ Bit 7 6 5 4 3 2 1 0 Byte
+ ------------------------------------------------------------
+ Line 0 1 2 3 4 5 6 7 690
+ 8 9 10 11 12 13 14 15 691
+ 16 17 18 19 20 21 22 23 692
+ -- -- -- -- -- -- -- -- 693
+
+ The last byte is ignored. The map bits are all set to one when the
+ text screen is OPENed or CLEARed, when a GRAPHICS com-
+ mand is issued or RESET is pressed. The map is updated as
+ logical lines are entered, edited, or deleted.
+
+
+ 694 2B6 INVFLG
+
+ Inverse character flag; zero is normal and the initialization value
+ (i.e., normal ATASCII video codes have BIT 7 equals zero). You
+ POKE INVFLG with 128 ($80) to get inverse characters (BIT 7
+ equals one). This register is normally set by toggling the Atari
+ logo key; however, it can be user-altered. The display handler
+ XOR's the ATASCII codes with the value in INVFLG at all times.
+ See location 702 ($2BE) below.
+
+ INVFLG works to change the input, not the output. For example,
+ if you have A$ = "HELLO", POKE 694, 128 will not change A$
+ when you PRINT it to the screen. However, if you POKE 694, 128
+ before an INPUT A$, the string will be entered as inverse.
+
+
+ 695 2B7 FILFLG
+
+ Right fill flag for the DRAW command. If the current operation is
+ a DRAW, then this register reads zero. If it is non-zero, the
+ operation is a FILL.
+
+
+ 696 2B8 TMPROW
+
+ Temporary register for row used by ROWCRS (location 84; $54).
+
+
+ 697,698 2B9,2BA TMPCOL
+
+ Temporary register for column used by COLCRS (locations 85,
+ 86; $55, $56).
+
+
+ 699 2BB SCRFLG
+
+ Scroll flag; set if a scroll occurs. It counts the number of physical
+ lines minus one that were deleted from the top of the screen. This
+ moves the entire screen up one physical line for each line
+ scrolled off the top. Since a logical line has three physical lines,
+ SCRFLG ranges from zero to two.
+
+ Scrolling the text window is the equivalent to scrolling an entire
+ GR.0 screen. An additional 20-line equivalent of bytes (800) is
+ scrolled upwards in the memory below the text window address.
+ This can play havoc with any data such as P/M graphics you have
+ stored above RAMTOP
+
+
+ 700 2BC HOLD4
+
+ Temporary register used in the DRAW command only; used to
+ save and restore the value in ATACHR (location 763; $2FB)
+ during the FILL process.
+
+
+ 701 2BD HOLD5
+
+ Same as the above register.
+
+
+ 702 2BE SHFLOK
+
+ Flag for the shift and control keys. It returns zero for lowercase
+ letters, 64 ($40) for all uppercase (called caps lock: uppercase is
+ required for BASIC statements and is also the default mode on
+ powerup). SHFLOK will set characters to all caps during your
+ program if 64 is POKEd here. Returns the value 128 ($80;
+ control-lock) when the CTRL key is pressed. Forced control-lock
+ will cause all keys to output their control-code functions or
+ graphics figures. Other values POKEd here may cause the
+ system to crash. You can use this location with 694 ($2B6) above
+ to convert all keyboard entries to uppercase, normal display by:
+
+ 10 OPEN #2,4,0,"K:"
+ 20 GET #2,A
+ 30 GOSUB 1000
+ 40 PRINT CHR$(A);: GOTO 20
+ .
+ .
+ .
+ 1000 IF A = 155 THEN 1030: REM RETURN
+ KEY
+ 1010 IF A > = 128 THEN A = A - 128: R
+ EM RESTORE TO NORMAL DISPLAY
+ 1020 IF PEEK (702) = 0 AND A > 96 THEN
+ A = A - 32: REM LOWERCASE TO UP
+ PER
+ 1030 POKE 702,64: POKE 694,0
+ 1040 RETURN
+
+ DOWNLOAD SHFLOK.BAS
+
+
+ 703 2BF BOTSCR
+
+ Flag for the number of text rows available for printing. 24 ($18) is
+ normal for text mode GR.0; four for the text window, zero for all
+ graphics modes. In all GRAPHICS modes except zero, if there is
+ no text window then 703 will also read zero. The large-text
+ displays in GR.1 and GR.2 are treated as graphics displays for
+ this purpose. The display handler specifically checks for split-
+ screen mode by looking for the variable 24 or four here. If it finds
+ 24 here, it assumes there is no text window; if not, it looks for the
+ variable four.
+
+ You can add a text window to GR.0 by POKEing here with four.
+ The top portion (20 lines) of the screen will not scroll with the
+ bottom. To write to the top part of the screen you will have to use
+ the PRINT#6 statement as with modes one and two. One possible
+ application of this would be to keep a fixed menu at the top of the
+ screen while scrolling the bottom part, as done with the DOS
+ menu.
+
+ ---------------------------------------------------------------------------
+ Locations 704 to 712 ($2C0 to $2C8) are the color registers for players,
+ missiles, and playfields. These are the RAM shadow registers for
+ locations 53266 to 53274 ($D012 to $D01A). For the latter, you can use
+ the SETCOLOR command from BASIC. For all registers you can
+ POKE the desired color into the location by using this formula:
+
+ COLOR = HUE * 16 + LUMINANCE
+
+ It is possible to get more colors in GR.8 than the one (and a half) that
+ Atari says is possible by using a technique called artifacting. There is a
+ small example of artifacting shown at location 710 ($2C6). See De Re
+ Atari, Your Atari 400/800, Creative Computing, June 1981, and
+ COMPUTE!, May 1982.
+
+ Here are the 16 colors the Atari produces, along with their POKE
+ values for the color registers. The POKE values assume a luminance of
+ zero. Add the luminance value to the numbers to brighten the color.
+ The color registers ignore BIT 0; that's why there are no "odd" values
+ for luminance, just even values.
+
+ Color Value Color Value
+ Black 0, 0 Medium blue 8, 128
+ Rust 1, 16 Dark blue 9, 144
+ Red-orange 2, 32 Blue-grey 10, 160
+ Dark orange 3, 48 Olive green 11, 176
+ Red 4, 64 Medium green 12, 192
+ Dk lavender 5, 80 Dark green 13, 208
+ Cobalt blue 6, 96 Orange-green 14, 224
+ Ultramarine 7, 112 Orange 15, 240
+
+ The bit use of the PCOLR and COLOR registers is as follows:
+
+ Bit 7 6 5 4 3 2 1 0
+ --color-- luminance unused
+ Grey 0 0 0 0 0 0 0 Darkest
+ Rust 0 0 0 1 0 0 1
+ etc. to: etc. to:
+ Orange 1 1 1 1 1 1 1 Lightest
+
+ When you enable the color overlap at location 623 ($26F), ANTIC
+ performs a logical OR on the overlap areas. For example:
+
+ 01000010 Red, luminance two
+ OR 10011010 Darkblue,luminance ten
+ --------
+ Result = 10011010 Dark green, luminance ten
+
+ Here's a short machine language routine which will rotate the colors in
+ registers 705 to 712:
+
+ 10 DIM ROT$(30)
+ 20 FOR LOOP = 1 TO 27: READ BYTE: R
+ OT$(LOOP,LOOP) = CHR$(BYTE): NEXT
+ LOOP
+ .
+ . PUT YOUR GRAPHICS ROUTINE HERE
+ .
+ 100 CHANGE = USR(ADR(ROT$))
+ 105 FOR LOOP = 1 TO 200: NEXT LOOP:
+ GOTO 100
+ 110 DATA 104,162,0,172,193,2,189,194
+ ,2,157
+ 120 DATA 193,2,232,224,8,144,245,140
+ ,200,2
+ 130 DATA 96,65,65,65,65,65,65
+
+ If you wish to rotate the colors in registers 704 to 711 instead, change
+ lines 110 and 120 to read as follows:
+
+ 110 DATA 104,162,0,172,192,2,189,193
+ ,2,157
+ 120 DATA 192,2,232,224,8,144,245,140
+ ,199,2
+
+ DOWNLOAD BOTSCR.BAS
+
+ If you wish to include all of the registers 704 to 712 in the routine, make
+ the changes as above and change the eight in line 120 to nine and
+ restore the 199 to 200 in line 120. This routine works well with the
+ GTIA demos at location 623 ($26F).
+
+ For further detail, refer to your Atari BASIC Reference Manual, pp. 45
+ -56, and the GTIA Demo Disk from APX.
+
+
+ 704 2C0 PCOLR0
+
+ Color of player 0 and missile 0. Locations 704 to 707 are also
+ called COLPM# in some sources. This is the shadow for 53266
+ ($D012). In GTIA mode ten, 704 holds the background color
+ (BAK; normally held by 712). You cannot use the SETCOLOR
+ commands to change the PCOLR registers; color values must be
+ POKEd into them.
+
+
+ 705 2C1 PCOLR1
+
+ Color of player and missile 1. Shadow for 53267 ($D013).
+
+
+ 706 2C2 PCOLR2
+
+ Color of player and missile 2. Shadow for 53268 ($D014).
+
+
+ 707 2C3 PCOLR3
+
+ Color of player and missile 3. When the four missiles are
+ combined to make a fifth player, it takes on the color in location
+ 711 (COLOR3). Shadow for 53269 ($D015).
+
+
+ 708 2C4 COLOR0
+
+ Color register zero, color of playfield zero, controlled by the
+ BASIC SETCOLOR0 command. In GRAPHICS 1 and
+ GRAPHICS 2, this color is used for the uppercase letters.
+ Shadow for 53270 ($D016). You can change the values in all of
+ the COLOR registers from BASIC by using either the
+ SETCOLOR command or a POKE.
+
+
+ 709 2C5 COLOR1
+
+ The next four locations are the same as location 708 for the
+ different playfields and SETCOLOB commands. In GR.1 and
+ GR.2, this register stores the color for lowercase letters.
+ COLOR1 is also used to store the luminance value of the color
+ used in GR.0 and GR.8. Shadow for 53271 ($D017).
+
+
+ 710 2C6 COLOR2
+
+ The same as above for playfield two; in GR.1 and GR.2, this
+ register stores the color of the inverse uppercase letters. Shadow
+ for 53272 ($D018). Used for the background color in GR.0 and
+ GR.8. Both use COLOR1 for the luminance value.
+
+ Despite the official limitations of color selection in GR.8, it is
+ possible to generate additional colors by "artifacting", turning
+ on specific pixels (.5 color clock each) on the screen. Taking
+ advantage of the physical structure of the TV set itself, we
+ selectively turn on vertical lines of pixels which all show the same
+ color. For example:
+
+ 10 A = 40: B = 30: C = 70: D = 5: F
+ = 20 GRAPHICS 8: POKE 87,7: P0K
+ E 710,0: POKE 709,15: COLOR 1
+ 30 PLOT A,D: DRAWTO A,C: COLOR 2: P
+ LOT F,D: DRAWTO F,C:
+ 40 PLOT A + 1,D: DRAWTO A + 1,C
+ 50 COLOR 3: PLOT B,D: DRAWTO B,C
+ 60 GOTO 60
+
+ DOWNLOAD COLOR2.BAS
+
+ A little experimentation with this will show you that the colors
+ obtained depend on which pixels are turned on and how close
+ together the pixel columns are. There are four "colors" you can
+ obtain, as shown before. Pixels marked one are on; marked zero
+ means they are off. Each pair of pixels is one color clock. Three
+ color clocks are shown together for clarity:
+
+ 00:01:00 = color A 00:11:00 = color B
+ 00:10:00 = color C 00:01:10 = color D
+
+ See BYTE, May 1982, De Re Atari, and Your Atari 400/800.
+
+
+ 711 2C7 COLOR3
+
+ The same as the above but for playfield three. Also, the color for
+ GR.1 and GR.2 inverse lowercase letters. Shadow for 53273
+ ($D019).
+
+
+ 712 2C8 COLOR4
+
+ The same as the above but for the background (BAK) and border
+ color. Shadow for 53274 ($D01A). In GTIA mode ten, 704 stores
+ the background color (BAK), while 712 becomes a normal color
+ register.
+
+ Here are the default (powerup) values for the COLOR registers
+ (PCOL registers are all set to zero on powerup):
+
+ Register Color = Hue Luminance
+ 708 (CO.0) 40 2 8
+ 709 (CO.1) 202 12 10
+ 710 (CO.2) 148 9 4
+ 711 (CO.3) 70 4 6
+ 712 (CO.4) 0 0 0
+
+ ----------------------------------------------------------------------------
+ Locations 713 to 735 ($2C9 to $2DF) are spare bytes. Locations 736 to
+ 767 ($2E0 to $2FF) are for miscellaneous use.
+
+
+ 736-739 2E0-2E3 GLBABS
+
+ Global variables, or, four spare bytes for non DOS users. For
+ DOS users they are used as below:
+
+
+ 736-737 2E0-2E1 RUNAD
+
+ Used by DOS for the run address read from the disk sector one or
+ from a binary file. Upon completion of any binary load, control
+ will normally be passed back to the DOS menu. However, DOS
+ can be forced to pass control to any specific address by storing
+ that address here. If RUNAD is set to 40960 ($A000), then the left
+ cartridge (BASIC if inserted) will be called when the program is
+ booted.
+
+ With DOS 1.0, if you POKE the address of your binary load file
+ here, the file will be automatically run upon using the DOS
+ Binary Load (selection L). Using DOS 1.0's append (/A) option
+ when saving a binary file to disk, you can cause the load address
+ POKEd here to be saved with the data. In DOS 2.0, you may
+ specify the initialization and the run address with the program
+ name when you save it to disk (i.e.,
+ GAME.OBJ,2000,4FFF,4F00,4000). DOS 2.0 uses the /A option
+ to merge files. In order to prevent your binary files from running
+ automatically upon loading in DOS 2.0, use the /N appendage to
+ the file name when loading the file.
+
+ For users of CompuServe, there is an excellent little BASIC
+ program (with machine language subroutines) to create autoboot
+ files, chain machine language files with BASIC and to add an 850
+ autoboot file in the Popular Electronics Magazine (PEM) access
+ area. It is available free for downloading.
+
+
+ 738-739 2E2-2E3 INITAD
+
+ Initialization address read from the disk. An autoboot file must
+ load an address value into either RUNAD above or INITAD. The
+ code pointed to by INITAD will be run as soon as that location is
+ loaded. The code pointed to by RUNAD will be executed only
+ after the entire load process has been completed. To return
+ control to DOS after the execution of your program, end your
+ code with an RTS instruction.
+
+
+ 740 2E4 RAMSIZ
+
+ RAM size, high byte only; this is the number of pages that the top
+ of RAM represents (one page equals 256 bytes). Since there can
+ never be less than a whole page, it becomes practical to measure
+ RAM in those page units. This is the same value as in RAMTOP,
+ location 106 ($6A), passed here from TRAMSZ, location 6. Space
+ saved by moving RAMSIZ or RAMTOP has the advantage of
+ being above the display area. Initialized to 160 for a 48K Atari.
+
+
+ 741,742 2E5,2E6 MEMTOP
+
+ Pointer to the top of free memory used by both BASIC (which
+ calls it HIMEM) and the OS, passed here from TRAMSZ, location
+ 6 after powerup. This address is the highest free location in RAM
+ for programs and data. The value is updated on powerup, when
+ RESET is pressed, when you change GRAPHICS mode, or when
+ a channel (IOCB) is OPENed to the display. The display list starts
+ at the next byte above MEMTOP.
+
+ The screen handler will only OPEN the S: device if no RAM is
+ needed below this value (i.e. there is enough free RAM below
+ here to accommodate the requested GRAPHICS mode change).
+ Memory above this address is used for the display list and the
+ screen display RAM. Also, if a screen mode change would
+ extend the screen mode memory below APPMHI (locations 14,
+ 15: $E, $F), then the screen is set back for GR.0, MEMTOP is
+ updated, and an error is returned to the user. Otherwise the
+ mode change will take place and MEMTOP will be updated.
+
+ Space saved by moving MEMTOP is below the display list. Be
+ careful not to overwrite it if you change GRAPHICS modes in
+ mid-program. When using memory below MEMTOP for storage,
+ make sure to set APPMHI above your data to avoid having the
+ screen data descend into it and destroy it.
+
+
+ 743,744 2E7,2E8 MEMLO
+
+ Pointer to the bottom of free memory, initialized to 1792 ($700)
+ and updated by the presence of DOS or any other low-memory
+ application program. It is used by the OS; the BASIC pointer to
+ the bottom of free memory is at locations 128, 129 ($80, $81). The
+ value in MEMLO is never altered by the OS after powerup.
+
+ This is the address of the first free location in RAM available for
+ program use. Set after all FMS buffers have been allocated (see
+ locations 1801 and 1802; $709 and $70A). The address of the last
+ sector buffer is incremented by 128 (the buffer size in bytes) and
+ the value placed in MEMLO. The value updates on powerup or
+ when RESET is pressed. This value is passed back to locations
+ 128, 129 ($80, $81) on the execution of the BASIC NEW
+ command, but not RUN, LOAD or RESET.
+
+ If you are reserving space for your own device driver(s) or
+ reserving buffer space, you load your routine into the address
+ specified by MEMLO, add the size of your routine to the MEMLO
+ value, and POKE the new value plus one back into MEMLO.
+
+ When you don't have DOS or any other application program
+ using low-memory resident, MEMLO points to 1792 ($700. With
+ DOS 2.0 present, MEMLO points to 7420 ($1CFC). If you change
+ the buffer defaults mentioned earlier, you will raise or lower this
+ latter value by 128 ($80) bytes for every buffer added or deleted,
+ respectively. When you boot up the 850 Interface with or without
+ disk, you add another 1728 ($6C0) bytes to the value in MEMLO.
+
+ You can alter MEMLO to protect an area of memory below your
+ program. This is an alternative to protecting an area above
+ RAMTOP (location 106; $6A) and avoids the problem of the
+ CLEAR SCREEN routine destroying data. However, unless you
+ have created a MEM.SAV file, the data will be wiped out when
+ you call DOS. To alter MEMLO, you start by POKEing WARMST
+ (location 8) with zero, then doing a JMP to the BASIC cartridge
+ entry point at 40960($A000) after defining your area to protect.
+ For example, try this:
+
+ 10 DIM MEM$(24):PROTECT=700:REM NUMBE
+ R OF BYTES TO CHANGE
+ 15 HIBYTE=INT(PROTECT/256):LOBYTE=PRO
+ TECT-256*HIBYTE
+ 20 FOR N=1 TO 24:READ PRG:MEM$(N)=CHR
+ $(PRG):NEXT N
+ 30 MEM$(6,6)=CHR$(LOBYTE):MEM$(14,14)
+ =CHR$(HIBYTE)
+ 40 RESERVE=USR(ADR(MEM$))
+ 50 DATA 24,173,231,2,105,0,141,231,2,
+ 173,232,2,105
+ 60 DATA 0,141,232,2,169,0,133,8,76,0,
+ 160
+
+ DOWNLOAD MEMLO.BAS
+
+ You will find the address of your reserved memory by: PRINT
+ PEEK(743) + PEEK(744) * 256 before you run the program. This
+ program will wipe itself out when run. Altering MEMLO is the
+ method used by both DOS and the RS-232 port driver in the 850
+ Interface. See COMPUTE!, July 1981.
+
+
+ 745 2E9 ....
+
+ Spare byte.
+
+
+ 746-749 2EA-2ED DVSTAT
+
+ Four device status registers used by the I/O status operation as
+ follows:
+
+ 746 ($2EA) is the device error status and the command status
+ byte. If the operation is a disk I/O, then the status returned is that
+ of the 1771 controller chip in your Atari disk drive. Bits set to one
+ return the following error codes:
+
+ Bit Decimal Error
+ 0 1 An invalid command frame was received (error).
+ 1 2 An invalid data frame was received.
+ 2 4 An output operation was unsuccessful.
+ 3 8 The disk is write-protected.
+ 4 16 The system is inactive (on standby).
+ 7 32 The peripheral controller is "intelligent" (has its
+ own microprocessor: the disk drive). All Atari
+ devices are intelligent except the cassette
+ recorder, so BIT 7 will normally be one when a
+ device is attached.
+
+ 747 ($2EB) is the device status byte. For the disk, it holds the
+ value of the status register of the drive controller. For the 850
+ Interface, it holds the status for DSR,CTS,CRX and RCV when
+ concurrent I/O is not active (see the 850 Interface Manual). It also
+ contains the AUX2 byte value from the previous operation (see
+ the IOCB description at 832 to 959; $340 to $3AF).
+ 748 ($2EC) is the maximum device time-out value in seconds. A
+ value of 60 here represents 64 seconds. This value is passed back
+ to location 582 ($246) after every disk status request. Initialized to
+ 31.
+ 749 ($2ED) is used for number of bytes in output buffer. See 850
+ Manual, p. 43.
+ When concurrent I/O is active, the STATUS command returns
+ the number of characters in the input buffer to locations 747 and
+ 748, and the number of characters in the output buffer to location
+ 749.
+
+
+ 750,751 2EE,2EF CBAUDL/H
+
+ Cassette baud rate low and high bytes. Initialized to 1484
+ ($5CC), which represents a nominal 600 baud (bits per second).
+ After baud rate calculations, these locations will contain POKEY
+ values for the corrected baud rate. The baud rate is adjusted by
+ SIO to account for motor variations, tape stretch, etc. The
+ beginning of every cassette record contains a pattern of
+ alternating off/on bits (zero/one) which are used solely for speed
+ (baud) correction.
+
+
+ 752 2F0 CRSINH
+
+ Cursor inhibit flag. Zero turns the cursor on; any other number
+ turns the cursor off. A visible cursor is an inverse blank (space)
+ character. Note that cursor visibility does not change until the
+ next time the cursor moves (if changed during a program). If you
+ wish to change the cursor status without altering the screen data,
+ follow your CRSINH change with a cursor movement (i.e., up,
+ down) sequence. This register is set to zero (cursor restored) on
+ powerup, RESET, BREAK, or an OPEN command to either the
+ display handler (S:) or screen editor (E:). See location 755 for
+ another means to turn off the cursor.
+
+
+ 753 2F1 KEYDEL
+
+ Key delay flag or key debounce counter; used to see if any key
+ has been pressed. If a zero is returned, then no key has been
+ pressed. If three is returned, then any key. It is decremented
+ every stage two VBLANK (1/60 or 1/30th second) until it reaches
+ zero. If any key is pressed while KEYDEL is greater than zero, it
+ is ignored as "bounce." See COMPUTE!, December 1981, for a
+ routine to change the keyboard delay to suit your own typing
+ needs.
+
+
+ 754 2F2 CH1
+
+ Prior keyboard character code (most recently read and
+ accepted). This is the previous value passed from 764 ($2FC). If
+ the value of the new key code equals the value in CH1, then the
+ code is accepted only if a suitable key debounce delay has taken
+ place since the prior value was accepted.
+
+
+ 755 2F3 CHACT
+
+ Character Mode Register. Zero means normal inverse
+ characters, one is blank inverse characters (inverse characters
+ will be printed as blanks, i.e., invisible), two is normal
+ characters, three is solid inverse characters. Four to seven is the
+ same as zero to three, but prints the display upside down.
+ This register also controls the transparency of the cursor. It is
+ transparent with values two and six, opaque with values three
+ and seven. The cursor is absent with values zero, one, four and
+ five.
+
+ Toggling BIT 0 on and off can be a handy way to produce a
+ blinking effect for printed inverse characters (characters with
+ ATASCII values greater than 128 -- those that have BIT 7 set).
+ Shadow for 54273 ($D401). There is no visible cursor for the
+ graphics mode output. CHACT is initialized to two.
+ Here's an example of blinking text using this register:
+
+ 10 CHACT=755:REM USE INVERSE FOR WORD
+ S BELOW
+ 15 PRINT "[THIS IS A TEST OF BLINKING ]
+ [TEXT]"
+ 20 POKE CHACT,INT(RND(0)*4)
+ 30 FOR N=1 TO 100:NEXT N:GOTO 15
+
+ See COMPUTE!, December 1981.
+ Using a machine language routine and page six space, try:
+
+ 10 PAGE=1536:EXIT=1568
+ 20 FOR N=PAGE TO EXIT:READ BYTE:POKE
+ N,BYTE:NEXT N
+ 30 PGM=USR(PAGE)
+ 40 PRINT "[THIS] IS A [TEST] OF [BLINKING]
+ TEXT":REM MAKE SOME WORDS INVERSE
+ 50 GOTO 50
+ 60 DATA 104,169,17,141,40,2,169,6,141
+ ,41
+ 70 DATA 2,169,30,141,26,2,98,173,243,
+ 2
+ 80 DATA 41,1,73,1,141,243,2,169,30,14
+ 1,26,2,96
+
+ DOWNLOAD CHACT.BAS
+
+ The blink frequency is set .5 second; to change it, change the
+ 30 in line 80 to any number from one (1/30 second) to 255 (eight
+ .5 seconds). For another way to make the cursor visible or
+ invisible, see locations 752 above.
+
+
+ 756 2F4 CHBAS
+
+ Character Base Register, shadow for 54281 ($D409). The default
+ (initialization value) is 224 ($E0) for uppercase characters and
+ numbers; POKE CHBAS with 226 ($E2) to get the lowercase and
+ the graphics characters in GR.1 and GR.2. In GR.0 you get the
+ entire set displayed to the screen, but in GR.1 and GR.2, you
+ must POKE 756 for the appropriate half-set to be displayed.
+
+ How do you create an altered character set? First you must
+ reserve an area in memory for your set (512 or 1024 bytes; look at
+ location 106; $6A to see how). Then either you move the ROM set
+ (or half set, if that's all you intend to change) into that area and
+ alter the selected characters, or you fill up the space with bytes
+ which make up your own set. Then you POKE 756 with the MSB
+ of the location of your set so the computer knows where to find it.
+
+ What does an altered character set look like? Each character is a
+ block one byte wide by eight bytes high. You set the bits for the
+ points on the screen you wish to be "on" when displayed. Here
+ are two examples:
+
+ one byte wide:
+ 00100000 = 32 #
+ 00010000 = 16 #
+ 00010000 = 16 #
+ 00010000 = 16 #
+ 00011110 = 30 ####
+ 00000010 = 2 #
+ 00001100 = 12 ##
+ 00010000 = 16 #
+
+ Hebrew letter Lamed
+
+
+ one byte wide:
+ 10000001 = 129 # #
+ 10011001 = 153 # ## #
+ 10111101 = 189 # #### #
+ 11111111 = 255 ########
+ 11111111 = 255 ########
+ 10111101 = 189 # #### #
+ 10011001 = 153 # ## #
+ 10000001 = 129 # #
+
+ Tie-fighter
+
+ You can turn these characters into DATA statements to be POKEd
+ into your reserved area by using the values for the bytes as in the
+ above examples. To change the ROM set once it is moved, you
+ look at the internal code (see the BASIC Reference Manual, p.
+ 55) and find the value of the letter you want to replace--such as
+ the letter A--code 33. Multiply this by eight bytes for each code
+ number from the start of the set (33 * eight equals 264). You then
+ replace the eight bytes used by the letter A, using a FOR-NEXT
+ loop with the values for your own character. For example, add
+ these lines to the machine language found a few pages further on:
+
+ 1000 FOR LOOP=1 TO 4:READ CHAR:SET=CH
+ ACT+CHAR*8
+ 1010 FOR TIME=0 TO 7:READ BYTE:POKE S
+ ET+TIME,BYTE: NEXT TIME
+ 1020 NEXT LOOP
+ 1030 DATA 33,0,120,124,22,22,124,120,
+ 0
+ 1040 DATA 34,0,126,82,82,82,108,0,0
+ 1050 DATA 35,56,84,254,238,254,68,56,
+ 0
+ 1060 DATA 36,100,84,76,0,48,72,72,48
+ 2000 END
+
+ RUN it and type the letters A to D.
+ Why 224 and 226? Translated to hex, these values are $E0 and
+ $E2, respectively. These are the high bytes (MSB) for the location
+ of the character set stored in ROM: $E000 (57344) is the address
+ for the start of the set (which begins with punctuation, numbers
+ and uppercase letters), and $E200 (57856), for the second half of
+ the ROM set, lowercase and graphic control characters (both
+ start on page boundaries). The ROM set uses the internal order
+ given on page 55 of your BASIC Reference Manual, not the
+ ATASCII order. See also location 57344 ($E000).
+
+ You will notice that using the PRINT#6 command will show you
+ that your characters have more than one color available to them
+ in GR.1 and GR.2. Try PRINTing lowercase or inverse
+ characters when you are using the uppercase set. This effect can
+ be very useful in creating colorful text pages. Uppercase letters,
+ numbers, and special characters use color register zero (location
+ 708; $2C4 - orange) for normal display, and color register two
+ (710; $2C6 - blue) for inverse display. Lowercase letters use
+ register one (709; $2C5 - aqua) for normal display and register
+ three (711; $2C7 - pink) for inverse. See COMPUTE!, December
+ 1981, page 98, for a discussion of using the CTRL keys with letter
+ keys to get different color effects.
+
+ One problem with POKEing 756 with 226 is that there is no blank
+ space character in the second set: you get a screen full of hearts.
+ You have two choices: you can change the color of register zero
+ to the same as the background and lose those characters which
+ use register zero--the control characters--but get your blanks
+ (and you still have registers one, two and three left). Or you can
+ redefine your own set with a blank character in it. The latter is
+ obviously more work. See "Ask The Readers," COMPUTE!, July
+ 1982.
+
+ It is seldom mentioned in the manuals, but you cannot set 756 to
+ 225 ($El) or any other odd number. Doing so will only give you
+ screen garbage. The page number 756 points to must be evenly
+ divisible by two.
+
+ When you create your own character set and store it in memory,
+ you need to reserve at least 1K for a full character set (1024 bytes
+ --$400 or four pages), and you must begin on a page boundary.
+ In hex these are the numbers ending with $XX00 such as $C000
+ or $600 because you store the pointer to your set here in 756; it
+ can only hold the MSB of the address and assumes that the LSB is
+ always zero--or rather a page boundary. You can reserve
+ memory by:
+
+ POKE 106,PEEK(106)-4 (or any multiple of four)
+
+ And do a GRAPHICS command immediately after to have your
+ new memory value accepted by the computer. If you are using
+ only one half of the entire set, for GR.1 or GR.2, you need only
+ reserve 512 bytes, and it may begin on a .5K boundary (like
+ $E200; these are hexadecimal memory locations that end in
+ $X200). If you plan to switch to different character sets, you will
+ need to reserve the full 1K or more, according to the number of
+ different character sets you need to display. RAM for half-K sets
+ can be reserved by:
+
+ POKE 106,PEEK(106)-2 (or a multiple of two)
+
+ The location for your set will then begin at PEEK(106)*256.
+ Because BASIC cannot always handle setting up a display list for
+ GR.7 and GR.8 when you modify location 106 by less than 4K (16
+ pages), you may find you must use PEEK(106)-16. See location
+ 88,89 ($58,$59) and 54279 ($D407) for information regarding
+ screen use and reserving memory.
+
+ Make sure you don't have your character set overlap with your
+ player/missile graphics. Be very careful when using altered
+ character sets in high memory. Changing GRAPHICS modes, a
+ CLEAR command, or scrolling the text window all clear memory
+ past the screen display. When you scroll the text window, you
+ don't simply scroll the four lines; you actually scroll a full 24 (20
+ additional lines * 40 bytes equals 800 bytes scrolled past
+ memory)! This messes up the memory past the window display
+ address, so position your character sets below all possible
+ interference (or don't scroll or clear the screen).
+
+ You can create and store as many character sets as your memory
+ will allow. You switch back and forth between them and the ROM
+ set by simply POKEing the MSB of the address into 756. Of
+ course, you can display only one set at a time unless you use an
+ altered display list and DLI to call up other sets. There are no
+ restrictions outside of memory requirements on using altered
+ character sets with P/M graphics as long as the areas reserved for
+ them do not overlap.
+
+ A GRAPHICS command such as GR.0, RESET or a DOS call
+ restores the character set pointer to the ROM location, so you
+ must always POKE it again with the correct location of your new
+ set after any such command. A useful place to store these sets is
+ one page after the end of RAM, assuming you've gone back to
+ location 106 ($6A) and subtracted the correct number of pages
+ from the value it holds (by POKE 106,PEEK(106) minus the
+ number of pages to be reserved; see above). Then you can reset
+ the character set location by simply using POKE
+ 756,PEEK(106)+1 (the plus one simply makes sure you start at
+ the first byte of your set).
+
+ A full character set requires 1024 bytes (1K: four pages) be
+ reserved for it. Why? Because there are 128 characters, each
+ represented by eight bytes, so 128 * eight equals 1024. If you are
+ using a graphics mode that uses only half the character set, you
+ need only reserve 512 bytes (64 * eight equals 512). Remember to
+ begin either one on a page boundary (1K boundary for full sets or
+ .5K for half sets). By switching back and forth between two
+ character sets, you could create the illusion of animation.
+
+ Many magazines have published good utilities to aid in the
+ design of altered character sets, such as the January 1982
+ Creative Computing, and SuperFont in COMPUTE!, January
+ 1982. I suggest that you examine The Next Step from Online,
+ Instedit from APX, or FontEdit from the Code Works for very
+ useful set generators. One potentially useful way to alter just a
+ few of the characters is to duplicate the block of memory which
+ holds the ROM set by moving it byte by byte into RAM. A BASIC
+ FOR-NEXT loop can accomplish this, although it's very slow. For
+ example:
+
+ 5 CH=57344
+ 10 START=PEEK(106)-4:PLACE=START*256:
+ POKE 106,PEEK(106)-5:GRAPHICS 0: RE
+ M RESERVE EXTRA IN CASE OF SCREEN
+ CLEAR
+ 20 FOR LOOP=0 TO 1023:POKE PLACE+LOOP
+ ,PEEK(CH+LOOP):NEXT LOOP:REM MOVE
+ THE ROM SET
+ 30 POKE 756,PLACE/256:REM TELL ANTIC
+ WHERE CHSET IS
+
+ Here's a machine language routine to move the set:
+
+ 10 DIM BYTE$(80)
+ 15 REM MEM-1 TO PROTECT SET FROM CLEA
+ R SCREEN DESTRUCTION (SEE LOC.88)
+ 20 MEM=PEEK(106)-4:POKE 106,MEM-1: CHA
+ CT=MEM*256:GRAPHICS 0
+ 30 FOR LOOP=1 TO 32:READ PGM:BYTE$(LO
+ OP,LOOP)=CHR$(PGM):NEXT LOOP
+ 40 DATA 104,104,133,213,104,133,212
+ 50 DATA 104,133,215,104,133,214,162
+ 60 DATA 4,160,0,177,212,145,214
+ 70 DATA 200,208,249,230,213,230,215
+ 80 DATA 202,208,240,96
+ 90 Z=USR(ADR(BYTE$),224*256,CHACT)
+ .
+ . ADD YOUR OWN ALTERATION PROGRAM OR
+ THE EARLIER EXAMPLE HERE
+ .
+ .
+ 1500 POKE MEM-1,0:POKE 756,MEM
+
+ If you have Microsoft BASIC or BASIC A+, you can do this very
+ easily with the MOVE command!
+
+ Remember, when altering the ROM set, that the characters aren't
+ in ATASCII order; rather they are in their own internal order.
+ Your own set will have to follow this order if you wish to have the
+ characters correlate to the keyboard and the ATASCII values.
+ See page 55 of your BASIC Reference Manual for a listing of the
+ internal order. Creative Computing, January 1982, had a good
+ article on character sets, as well as a useful method of
+ transferring the ROM set to RAM using string manipulation. See
+ also "Using Text Plot for Animated Games" in COMPUTE!, April
+ 1982, for an example of using character sets for animated
+ graphics.
+
+
+ 757-761 2F5-2F9 ....
+
+ Spare bytes.
+
+
+ 762 2FA CHAR
+
+ Internal code value for the most recent character read or written
+ (internal code for the value in ATACHR below). This register is
+ difficult to use with PEEK statements since it returns the most
+ recent character; most often the cursor value (128, $80 for a
+ visible, zero for an invisible cursor).
+
+
+ 763 2FB ATACHR
+
+ Returns the last ATASCII character read or written or the value of
+ a graphics point. ATACHR is used in converting the ATASCII
+ code to the internal character code passed to or from CIO. It also
+ returns the value of the graphics point. The FILL and DRAW
+ commands use this location for the color of the line drawn,
+ ATACHR being temporarily loaded with the value in FILDAT,
+ location 765; $2FD. To force a color change in the line, POKE the
+ desired color number here (color * sixteen + luminance). To see
+ this register in use as character storage, try:
+
+ 10 OPEN#2,4,0,"K:"
+ 20 GET#2,A
+ 30 PRINT PEEK(763);" "; CHR$(A)
+ 40 GOTO 20
+
+ Make sure the PEEK statement comes before the PRINT CHR$
+ statement, or you will not get the proper value returned. When
+ the RETURN key is the last key pressed, ATACHR will show a
+ value of 155.
+
+
+ 764 2FC CH
+
+ Internal hardware value for the last key pressed. POKE CH with
+ 255 ($FF; no key pressed) to clear it. The keyboard handler gets
+ all of its key data from CH. It stores the value 255 here to indicate
+ the key code has been accepted, then passes the code to CH1,
+ location 754 ($2F2). If the value in CH is the same as in CH1, a
+ key code will be accepted only if the proper key debounce delay
+ time has transpired. If the code is the CTRL-1 combination (the
+ CTRL and the "1" keys pressed simultaneously), then the
+ start/stop flag at 767 ($2FF) is complemented, but the value is not
+ stored in CH. The auto repeat logic will also store store key
+ information here as a result of the continuous pressing of a key.
+ This is neither the ATASCII nor the internal code value; it is the
+ "raw" keyboard matrix code for the key pressed. The table for
+ translation of this code to ATASCII is on page 50 of the OS User's
+ Manual. In a two-key operation, BIT 7 is set if the CTRL key is
+ pressed, BIT 6 if the SHIFT key is pressed. The rest of the bytes
+ are the code (ignored if both BITs 7 and 6 are set). Only the code
+ for the last key pressed is stored here (it is a global variable for
+ keyboard).
+
+ When a read request is issued to the keyboard, CH is set to 255
+ by the handler routine. After a keycode has been read from this
+ register, it is reset to 255. BREAK doesn't show here, and CTRL
+ and SHIFT will not show here on their own. However, the inverse
+ toggle (Atari logo key), CAPS/LOWR, TAB and the ESC keys
+ will show by themselves. You can examine this register with:
+
+ 10 LOOK=PEEK(764)
+ 20 PRINT "KEY PRESSED = ";LOOK
+ 30 POKE 764,255
+ 40 FOR LOOP=1 TO 250:NEXT LOOP
+ 50 GOTO 10
+
+ See COMPUTE!'s First Book of Atari for an example of using this
+ register as a replacement for joystick input.
+
+
+ 765 2FD FILDAT
+
+ Color data for the fill region in the XIO FILL command.
+
+
+ 766 2FE DSPFLG
+
+ Display flag, used in displaying the control codes not associated
+ with an ESC character (see location 674; $2A2). If zero is
+ returned or POKEd here, then the ATASCII codes 27 - 31, 123 -
+ 127, 187 - 191 and 251 - 255 perform their normal display screen
+ control functions (i.e., clear screen, cursor movement,
+ delete/insert line, etc.). If any other number is returned, then a
+ control character is displayed (as in pressing the ESC key with
+ CTRL-CLEAR for a graphic representation of a screen clear).
+ POKEing any positive number here will force the display instead
+ of the control code action. There is, however, a small bug, not
+ associated with location 766, in Atari BASIC: a PRINTed CTRL-R
+ or CTRL-U are both treated as a semicolon.
+
+
+ 767 2FF SSFLAG
+
+ Start/stop display screen flag, used to stop the scrolling of the
+ screen during a DRAW or graphics routine, a LISTing or a
+ PRINTing. When the value is zero, the screen output is not
+ stopped. When the value is 255 ($FF; the one's complement), the
+ output to the screen is stopped, and the machine waits for the
+ value to become zero again before continuing with the scrolling
+ display. Normally SSFLAG is toggled by the user during these
+ operations by pressing the CTRL-1 keys combination to both start
+ and stop the scroll. Set to zero by RESET and powerup.
+
+ ---------------------------------------------------------------------------
+
+ PAGE THREE
+
+ Locations 768 to 831 ($300 to $33F) are used for the device handler and
+ vectors to the handler routines (devices S:, P:, E:, D:, C:, R: and K:).
+ A device handler is a routine used by the OS to control the transfer of
+ data in that particular device for the task allotted (such as read, write,
+ save, etc.). The resident D: handler does not conform entirely with the
+ other handler--SIO calling routines. Instead, you use the DCB to
+ communicate directly with the disk handler. The device handler for R:
+ is loaded in from the 850 interface module. See De Re Atari, the 850
+ Interface Manual, and the OS Listings pages 64 - 65.
+
+ Locations 768 to 779 ($300 to $30B) are the resident Device Control
+ Block (DCB) addresses, used for I/O operations that require the serial
+ bus; also used as the disk DCB. DUP.SYS uses this block to interface
+ the FMS with the disk handler. The Atari disk drive uses a serial access
+ at 19,200 baud (about 20 times slower than the Apple!). It has its own
+ microprocessor, a 6507, plus 128 bytes of RAM, a 2316 2K masked
+ ROM chip (like a 2716), a 2332 RAM-I/O timer chip with another 128
+ bytes of RAM (like the PIA chip) and a WD 1771 FD controller chip.
+ See the "Outpost Atari" column, Creative Computing, May 1982, for
+ an example of using the disk DCB.
+
+ All of the parameters passed to SIO are contained in the DCB. SIO
+ uses the DCB information and returns the status in the DCB for
+ subsequent use by the device handler.
+
+
+ 768 300 DDEVIC
+
+ Device serial bus ID (serial device type) set up by the handler,
+ not user-alterable. Values are:
+
+ Disk drives Dl - D4 49-52 ($31-$34)
+ Printer P1 64 ($40)
+ Printer P2 79 ($4F)
+ RS232 ports R1-R4 80-83 ($50-$53)
+
+
+ 769 301 DUNIT
+
+ Disk or device unit number: one to four, set up by the user.
+
+
+ 770 302 DCOMND
+
+ The number of the disk or device operation (command) to be
+ performed, set by the user or by the device handler prior to
+ calling SIO. Serial bus commands are:
+
+ Read 82 ($52)
+ Write (verily) 87 ($57)
+ Status 83 ($53)
+ Put (no verify) 80 (0)
+ Format 33 ($21)
+ Download 32 ($20)
+ Read address 84 ($54)
+ Read spin 81 ($51)
+ Motor on 85 ($55)
+ Verify sector 86 ($56)
+
+ All of the above are disk device commands, except write and
+ status, which are also printer commands (with no verify).
+
+
+ 771 303 DSTATS
+
+ The status code upon return to user. Also used to set the data
+ direction; whether the device is to send or receive a data frame.
+ This byte is used by the device handler to indicate to SIO what to
+ do after the command frame is sent and acknowledged. Prior to
+ the SIO call, the handler examines BIT 6 (one equals receive
+ data) and BIT 7 (one equals send data). If both bits are zero, then
+ no data transfer is associated with the operation. Both bits set to
+ one is invalid. SIO uses it to indicate to the handler the status of
+ the requested operation after the SIO call.
+
+
+ 772,773 304,305 DBUFLO/HI
+
+ Data buffer address of the source or destination of the data to be
+ transferred or the device status information (or the disk sector
+ data). Set by the user, it need not be set if there is no data
+ transferred, as in a status request.
+
+
+ 774 306 DTIMLO
+
+ The time-out value for the handler in one-second units, supplied
+ by the handler for use by SIO. The cassette time-out value is 35,
+ just over 37 seconds. The timer values are 64 seconds per 60 units
+ of measurement. Initialized to 31.
+
+
+ 775 307 DUNUSE
+
+ Unused byte.
+
+
+ 776,777 308,309 DBYTLO/HI
+
+ The number of bytes transferred to or from the data buffer (or the
+ disk) as a result of the most recent operation, set by the handler.
+ Also used for the count of bad sector data. There is a small bug in
+ SIO which causes incorrect system actions when the last byte in a
+ buffer is in a memory location ending with $FF, such as $A0FF.
+
+
+ 778,779 30A,30B DAUX1/2
+
+ Used for device specific information such as the disk sector
+ number for the read or write operation. Loaded down to locations
+ 572, 573 ($23C, $23D) by SIO.
+
+ There are only five commands supported by the disk handler:
+ GET sector (82; $52), PUT sector (80; $50), PUT sector with
+ VERIFY (87; $57), STATUS request (83; $53) and FORMAT entire
+ disk (33; $21). There is no command to FORMAT a portion of the
+ disk; this is done by the INS 1771-1 formatter/controller chip in
+ the drive itself and isn't user-accessible. There is a new disk drive
+ ROM to replace the current "C" version. It is the "E" ROM. Not
+ only is it faster than the older ROMs, but it also allows for
+ selective formatting of disk sectors. Atari has not announced yet
+ whether this new 810 ROM will be made available. For more
+ information, see the OS User's Manual.
+
+ Locations 780 to 793 ($30C to $319) are for miscellaneous use.
+ Locations 794 to 831 ($31A to $33F) are handler address tables. To use
+ these DCBs, the user must provide the required parameters to this
+ block and then do a machine language JSR to $E453 (58451) for disk
+ I/O or $E459 (58457; the SIO entry point) for other devices.
+
+
+ 780,781 30C,30D TIMER1
+
+ Initial baud rate timer value.
+
+
+ 782 30E ADDCOR
+
+ Addition correction flag for the baud rate calculations involving
+ the timer registers.
+
+
+ 783 30F CASFLG
+
+ Cassette mode when set. Used by SIO to control the program
+ flow through shared code. When set to zero, the current
+ operation is a standard SIO operation; when non-zero, it is a
+ cassette operation.
+
+
+ 784,785 310,311 TIMER2
+
+ Final timer value. Timer one and timer two contain reference
+ times for the start and end of the fixed bit pattern receive period.
+ The first byte of each timer contains the VCOUNT value (54283;
+ $D40B), and the second byte contains the current realtime clock
+ value from location 20 ($14). The difference between the timer
+ values is used in a lookup table to compute the interval for the
+ new values for the baud rate passed on to location 750, 751
+ ($2EE, $2EF).
+
+
+ 786,787 312,313 TEMP1
+
+ Two-byte temporary storage register used by SIO for the
+ VCOUNT calculation during baud timer routines. See location
+ 54283 ($D40B).
+
+
+ 788 314 TEMP2
+
+ Temporary storage register.
+
+
+ 789 315 TEMP3
+
+ Ditto.
+
+
+ 790 316 SAVIO
+
+ Save serial data-in port used to detect, and updated after, each
+ bit arrival. Used to retain the state of BIT 4 of location 53775
+ ($D20F; serial data-in register).
+
+
+ 791 317 TIMFLG
+
+ Time-out flag for baud rate correction, used to define an
+ unsuccessful baud rate value. Initially set to one, it is
+ decremented during the I/O operation. If it reaches zero (after
+ two seconds) before the first byte of the cassette record is read,
+ the operation will be aborted.
+
+
+ 792 318 STACKP
+
+ SIO stack pointer register. Points to a byte in the stack being
+ used in the current operation (locations 256 to 511; $100 to $1FF).
+
+
+ 793 319 TSTAT
+
+ Temporary status holder for location 48 ($30).
+
+
+ 794-831 31A-33F HATABS
+
+ Handler Address Table. Thirty-eight bytes are reserved for up to
+ 12 entries of three bytes per handler, the last two bytes being set
+ to zero. On powerup, the HATABS table is copied from ROM.
+ Devices to be booted, such as the disk drive, add their handler
+ information to the end of the table. Each entry has the character
+ device name (C,D,E,K,P,S,R) in ATASCII code and the handler
+ address (LSB/MSB). Unused bytes are all set to zero. FMS
+ searches HATABS from the top for a device "D:" entry, and when
+ it doesn't find it, it then sets the device vector at the end of the
+ table to point to the FMS vector at 1995 ($7CB). CIO searches for
+ a handler character from the bottom up. This allows new handlers
+ to take precedence over the old. Pressing RESET clears HATABS
+ of all but the resident handler entries!
+
+ 794 31A Printer device ID (P:), initialized to 58416 ($E430).
+ 797 31D Cassette device ID (C:), initialized to 58432 ($E440).
+ 800 320 Display editor ID (E:), initialized to 58368 ($E400).
+ 803 323 Screen handler ID (S:), initialized to 58384 ($E410).
+ 806 326 Keyboard handler ID (K:), initialized to 58400
+ ($E420).
+
+ HATABS unused entry points:
+ 809 ($329), 812 ($32C), 815 ($32F), 818 ($332), 821 ($335), 824
+ ($338), 827 ($33B), and 830 ($33E). These are numbered
+ sequentially from one to eight. There are only two bytes in the last
+ entry (unused), both of which are set to zero. When DOS is
+ present, it adds an entry to the table with the ATASCII code for
+ the letter "D" and a vector to address 1995 ($7CB).
+
+ The format for the HATABS table is:
+
+ Device name
+ Handler vector table address
+ More entries
+ Zero fill to the end of the table
+
+ The device handler address table entry above for the specific
+ handler points to the first byte (low byte/high byte) of the vector
+ table which starts at 58368 ($E400). Each handler is designed
+ with the following format:
+
+ OPEN vector
+ CLOSE vector
+ GET BYTE vector
+ PUT BYTE vector
+ GET STATUS vector
+ SPECIAL vector
+ Jump to initialization code (JMP LSB/MSB)
+
+ CIO uses the ZIOCB (see location 32; $20) to pass parameters to
+ the originating IOCB, the A, Y and X registers and CIO. It is
+ possible to add your own device driver(s) to OS by following
+ these rules:
+ 1) Load your routine, with necessary buffers at the address
+ pointed to by MEMLO: location 743 ($2E7).
+ 2) Add the size of your routine to the MEMLO value and POKE
+ the result back into MEMLO.
+ 3) Store the name and address of your driver in the handler
+ address table; HATABS.
+ 4) Change the vectors so that the OS will re-execute the above
+ steps if RESET has been pressed. This is usually done by
+ adjusting locations 12 ($C: DOSINIT) and 10 ($A; DOSVEC).
+
+ See the "Insight: Atari" columns in COMPUTE!, January and
+ April 1982, for details. The APX program "T: A Text Display
+ Device" is a good example of a device handler application.
+ See De Re Atari for more information on the DCB and HATABS,
+ including the use of a null handler.
+
+ ---------------------------------------------------------------------------
+ Locations 832 to 959 ($340 to $3BF) are reserved for the eight IOCB's
+ (input/output control blocks). IOCB's are channels for the transfer of
+ information (data bytes) into and out of the Atari, or between devices.
+ You use them to tell the computer what operation to perform, how
+ much data to move and, if necessary, where the data to be moved is
+ located. Each block has 16 bytes reserved for it.
+
+ What is an IOCB? Every time you PRINT something on the screen or
+ the printer, every time you LOAD or SAVE a file, every time you OPEN
+ a channel, you are using an IOCB. In some cases, operations have
+ automatic OPEN and CLOSE functions built in--like LPRINT. In
+ others, you must tell the Atari to do each step as you need it. Some
+ IOCB's are dedicated to specific use, such as zero for the screen
+ display. Others can be used for any I/O function you wish. The
+ information you place after the OPEN command tells CIO how you
+ want the data transferred to or from the device. It is SIO and the device
+ handlers that do the actual transfer of data.
+ You can easily POKE the necessary values into the memory locations
+ and use a machine language subroutine through a USR function to call
+ the CIO directly (you must still use an OPEN and CLOSE statement for
+ the channel, however). This is useful because BASIC only supports
+ either record or single byte data transfer, while the CIO will handle
+ complete buffer I/O. See the CIO entry address, location 58454
+ ($E456), for more details. These blocks are used the same way as the
+ page zero IOCB (locations 32 to 47; $20 to $2F). The OS takes the
+ information here, moves it to the ZIOCB for use by the ROM CIO, then
+ returns the updated information back to the user area when the
+ operation is done.
+ Note that when BASIC encounters a DOS command, it CLOSEs all
+ channels except zero. Refer to the Atari Hardware Manual and the 850
+ Interface Manual for more detailed use of these locations.
+
+
+ 832-847 340-34F IOCB0
+
+ I/O Control Block (IOCB) zero. Normally used for the screen
+ editor (E:). You can POKE 838,166 and POKE 839,238 and send
+ everything to the printer instead of to the screen (POKE 838,163,
+ and POKE 839,246 to send everything back to the screen again).
+ You could use this in a program to toggle back and forth between
+ screen and printed copy when prompted by user input. This will
+ save you multiple PRINT and LPRINT coding.
+
+ You can use these locations to transfer data to other devices as
+ well since they point to the address of the device's "put one byte"
+ routine. See the OS Manual for more information. Location 842
+ can be given the value 13 for read from screen and 12 for write to
+ screen. POKE 842,13 puts the Atari into "RETURN key mode" by
+ setting the auxiliary byte one (ICAX1) to screen input and
+ output. POKEing 842 with 12 returns it to keyboard input and
+ screen output mode. The former mode allows for dynamic use of
+ the screen to act upon commands the cursor is made to move
+ across.
+
+ You can use this "forced read" mode to read data on the screen
+ into BASIC without user intervention. For example, in the
+ program below, lines 100 through 200 will be deleted by the
+ program itself as it runs.
+
+ 10 GRAPHICS 0:POSITlON 2,4
+ 20 PRINT 100:PRINT 150:PRINT 200
+ 25 PRINT "CONT"
+ 30 POSITION 2,0
+ 50 POKE 842,13:STOP
+ 60 POKE 842,12
+ 70 REM THE NEXT LINES WILL BE DELETED
+ 100 PRINT "DELETING..."
+ 150 PRINT "DELETING..."
+ 200 PRINT "DELETED!"
+
+ DOWNLOAD FORCREAD.BAS
+
+ See COMPUTE!, August 1981, for a sample of this powerful
+ technique. See Santa Cruz's Tricky Tutorial #1 (display lists) for
+ another application. The last four bytes (844 to 847; $34C to $34F
+ in this case) are spare (auxiliary) bytes in all IOCB's.
+ When you are in a GRAPHICS mode other than zero, channel
+ zero is OPENed for the text window area. If the window is absent
+ and you OPEN channel zero, the whole screen returns to mode
+ zero. A BASIC NEW or RUN command closes all channels
+ except zero. OPENing a channel to S: or E: always clears the
+ display screen.
+ See COMPUTE!, October 1981,for an example of using an IOCB
+ with the cassette program recorder, and September 1981 for
+ another use with the Atari 825 printer.
+
+
+ 848-863 350-35F IOCB1
+
+ IOCB one.
+
+
+ 864-879 360-36F IOCB2
+
+ IOCB two.
+
+
+ 880-895 370-37F IOCB3
+
+ IOCB three.
+
+
+ 896-911 380-38F IOCB4
+
+ IOCB four.
+
+
+ 912-927 390-39F IOCB5
+
+ IOCB five.
+
+
+ 928-943 3A0-3AF IOCB6
+
+ IOCB six. The GRAPHICS statement OPENs channel six for
+ screen display (S:), so once you are out of mode zero, you cannot
+ use channel six unless you first issue a CLOSE#6 statement. If
+ you CLOSE this channel, you will not be able to use the
+ DRAWTO, PLOT or LOCATE commands until you reOPEN the
+ channel. The LOAD command closes channel six; it also closes
+ all channels except zero.
+
+
+ 944-959 3B0-3BF IOCB7
+
+ IOCB seven. LPRINT automatically uses channel seven for its
+ use. If the channel is OPEN for some other use and an LPRINT is
+ done, an error will occur, the channel will be CLOSEd, and
+ subsequent LPRINTs will work. The LIST command also uses
+ channel seven, even if channel seven is already OPEN. However,
+ when the LIST is done, it CLOSEs channel seven. The LOAD
+ command uses channel seven to transfer programs to and from
+ the recorder or disk. LIST (except to the display screen), LOAD
+ and LPRINT also close all sound voices. The RUN from tape or
+ disk and SAVE commands use channel seven, as does LIST.
+ The bytes within each IOCB are used as follows:
+
+ Label Offset Bytes Description
+ --------------------------------------------------------------------
+ ICHID 0 1 Index into the device name
+ table for the currently OPEN file. Set by the OS. If not in use, the
+ value is 255 ($FF), which is also the initialization value.
+
+ ICDNO 1 1 Device number such as one
+ for Dl: or two for D2:. Set by the OS.
+
+ ICCOM 2 1 Command for the type of
+ action to be taken by the device, set by the user. This is the first
+ variable after the channel number in an OPEN command. See
+ below for a command summary. Also called ICCMD.
+
+ ICSTA 3 1 The most recent status
+ returned by the device, set by the OS. May or may not be the
+ same value as that which is returned by the STATUS request in
+ BASIC. See the OS User's Manual, pp. 165-166, fora list of status
+ byte values.
+
+ ICBAL/H 4,5 2 Two-byte (LSB,MSB) buffer
+ address for data transfer or the address of the file name for OPEN,
+ STATUS, etc.
+
+ ICPTL/H 6,7 2 Address of the device's put-
+ one-byte routine minus one. Set by the OS at OPEN command,
+ but not actually used by the OS (it is used by BASIC, however).
+ Points to CIO's "IOCB NOT OPEN" message at powerup.
+
+ ICBLL/H 8,9 2 Buffer length set to the
+ maximum number of bytes to transfer in PUT and GET
+ operations. Decremented by one for each byte transferred;
+ updated after each READ or WRITE operation. Records the
+ number of bytes actually transferred in and out of the buffer after
+ each operation.
+
+ ICAX1 10 1 Auxiliary byte number one,
+ referred to as AUX1. Used in the OPEN statement to specify the
+ type of file access: four for READ, eight for WRITE, twelve for
+ both (UPDATE). Not all devices can use both kinds of operations.
+ This byte can be used in user-written drivers for other purposes
+ and can be altered in certain cases once the IOCB has been
+ OPENed (see the program example above). For the S: device, if
+ AUX1 equals 32, it means inhibit the screen clear function when
+ changing GRAPHICS modes. Bit use is as follows for most
+ applications:
+ Bit 7 6 5 4 3 2 1 0
+ Use ....unused.... W R D A
+
+ W equals write, R equals read, D equals directory, A equals
+ append.
+
+ ICAX2 11 1 Auxiliary byte two, referred
+ to as AUX2. Special use by each device driver; some serial port
+ functions may use this byte. Auxiliary bytes two to five have no
+ fixed use; they are used to contain device-dependent and/or
+ user-established data.
+
+ ICAX3/4 12,13 2 Auxiliary bytes three and
+ four; used to maintain a record of the disk sector number for the
+ BASIC NOTE and POINT commands.
+
+ ICAX5 14 1 Auxiliary byte five. Used by
+ NOTE and POINT to maintain a record of the byte within a sector.
+ It stores the relative displacement in sector from zero to 124
+ ($7C). Bytes 125 and 126 of a sector are used for sector-link
+ values, and byte 127 ($7F) is used as a count of the number of
+ data bytes in actual use in that sector.
+
+ ICAX6 15 1 Spare auxiliary byte.
+
+ Offset is the number you would add to the start of the IOCB in
+ order to POKE a value into the right field, such as POKE 832 +
+ OFFSET, 12.
+
+ The following is a list of the values associated with OPEN
+ parameter number 1. Most of these values are listed in Your Atari
+ 400/800. These are the values found in ICAX1, not the ICCOM
+ values.
+
+ Device Task # Description
+ ----------------------------------------------------------------------
+ Cassette 4 Read
+ recorder 8 Write (can do either, not both)
+
+ Disk 4 Read
+ file 6 Read disk directory
+ 8 Write new file. Any file OPENed in
+ this mode will be deleted, and the first byte written will be at the
+ start of the file.
+ 9 Write--append. In this mode the
+ file is left intact, and bytes written are put at the end of the file.
+ 12 Read and write--update. Bytes
+ read or written will start at the first byte in the file.
+
+ D: if BIT 0 equals one and BIT 3 equals one in AUX1,then
+ operation will be appended output.
+
+ Screen 8 Screen output
+ editor 12 Keyboard input and screen output
+ (E:) 13 Screen input and output
+
+ E: BIT 0 equals one is a forced read (GET command).
+
+ Keyboard 4 Read
+
+ Printer 8 Write
+
+ RS-232 5 Concurrent read
+ serial 8 Block write
+ port 9 Concurrent write
+ 13 Concurrent read and write
+
+ Clear Text Read
+ Screen Window Oper-
+ after GR. also ation
+
+ Screen 8 yes no no
+ display 12 yes no yes
+ (S:) 24 yes yes no
+ 28 yes yes yes
+ 40 no no no
+ 44 no no yes
+ 56 no yes no
+ 60 no yes yes
+
+ Note that with S:, the screen is always cleared in GR.0 and there
+ is no separate text window in GR.0 unless specifically user-
+ designed. Without the screen clear, the previous material will
+ remain on screen between GRAPHICS mode changes, but will
+ not be legible in other modes. The values with S: are placed in
+ the first auxiliary byte of the IOCB. All of the screen values above
+ are also a write operation.
+
+ The second parameter in an OPEN statement (placed in the
+ second auxiliary byte) is far more restricted in its use. Usually set
+ to zero. If set to 128 ($80) for the cassette, it changes from normal
+ to short inter-record gaps (AUX2).
+
+ With the Atari 820 printer, 83 ($53; AUX byte two) means
+ sideways characters (Atari 820 printer only). Other printer
+ variables (all for AUX2 as well) are: 70 ($4E) for normal 40
+ character per line printing and 87 ($57) for wide printing mode.
+ With the screen (S:), a number can be used to specify the
+ GRAPHICS modes zero through eleven. If mode zero is chosen,
+ then the AUX1 options as above are ignored.
+ For the ICCOM field, the following values apply (BASIC XIO
+ commands use the same values):
+
+ Command Decimal Hex
+ ----------------------------------------------------------------------
+ Open channel 3 3
+ Get text record (line) 5 5 BASIC:
+ INPUT
+ #n,A
+ Get binary record (buffer) 7 7 BASIC:
+ GET #n,A
+ Put text record (line) 9 9
+ Put binary record (buffer) 11 B BASIC:
+ PUT #n,A
+ Close 12 C
+ Dynamic (channel) status 13 D
+
+ BASIC uses a special "put byte" vector in the IOCB to talk
+ directly to the handler for the PRINT#n,A$ command.
+ Disk File Management System Commands (BASIC XIO
+ command):
+
+ Rename 32 20
+ Erase (delete) 33 21
+ Protect (lock) 35 23
+ Unprotect (unlock) 36 24
+ Point 37 25
+ Note 38 26
+ Format 254 FE
+
+ In addition, XIO supports the following commands:
+
+ Get character 7 7
+ Put character 11 B
+ Draw line 17 11 Display
+ handler
+ only.
+ Fill area 18 12 Display
+ handler
+ only.
+
+ FILL is done in BASIC with XIO 18,#6,12,0,"S:" (see the BASIC
+ Reference Manual for details).
+
+ For the RS-232 (R:), XIO supports:
+
+ Output partial block 32 20
+ Control RTS,XMT,DTR 34 22
+ Baud, stop bits, word size 36 24
+ Translation mode 38 26
+ Concurrent mode 40 28
+
+ (see the 850 Interface Manual for details)
+
+ CIO treats any command byte value greater than 13 ($D) as a
+ special case, and transfers control over to the device handler for
+ processing. For more information on IOCB use, read Bill
+ Wilkinson's "Insight: Atari" columns in COMPUTE!, November
+ and December 1981, and in Microcomputing, August 1982. Also
+ refer to the OS User's Manual and De Re Atari.
+
+ ---------------------------------------------------------------------------
+
+ 960-999 3C0-3E7 PRNBUF
+
+ Printer buffer. The printer handler collects output from LPRINT
+ statements here, sending them to the printer when an End of Line
+ (EOL; carriage return) occurs or when the buffer is full. Normally
+ this is 40 characters. However, if an LPRINT statement generates
+ fewer than 40 characters and ends with a semicolon or 38
+ characters and ends with a comma, Atari sends the entire buffer
+ on each FOR-NEXT loop, the extra bytes filled with zeros. The
+ output of the next LPRINT statement will appear in column 41 of
+ the same line. According to the Operating System User's
+ Manual, the Atari supports an 80-column printer device called
+ P2:. Using OPEN and PUT statements to P2: may solve this
+ problem. Here is a small routine for a GR.0 BASIC screen dump:
+
+ 10 DIM TEXT$(1000): OPEN#2,4,0,"S:":
+ TRAP 1050
+ .
+ .
+ .
+ 1000 FOR LINE = 1 TO 24: POSITION PE
+ EK(82),LINE
+ 1010 FOR COL = 1 TO 38: GET#2,CHAR:
+ TEXT$(COL,COL)=CHR$(CHAR)
+ 1020 NEXT COL: GET#2,COL
+ 1030 LPRINT TEXT$
+ 1040 NEXT LINE
+ 1050 RETURN
+
+ You can use the PTABW register at location 201 ($C9) to set the
+ number of spaces between print elements separated by a comma.
+ The minimum number of spaces accepted is two. LPRINT
+ automatically uses channel seven for output. No OPEN statement
+ is necessary and CLOSE is automatic.
+
+ ---------------------------------------------------------------------------
+ Locations 1000 to 1020 ($3E8 to $3FC) are a reserved spare buffer
+ area.
+
+
+ 1021-1151 3FD-47F CASBUF
+
+ Cassette buffer. These locations are used by the cassette handler
+ to read data from and write data to the program (tape) recorder.
+ The 128 ($80) data bytes for each cassette record are stored
+ beginning at 1024 ($400 - page four). The current buffer size is
+ found in location 650 ($28A). Location 61 ($3D) points to the
+ current byte being written or read.
+ CASBUF is also used in the disk boot process; the first disk
+ record is read into this buffer.
+
+ A cassette record consists of 132 bytes: two control bytes set to 85
+ ($55; alternating zeros and ones) for speed measurement in the
+ baud rate correction routine; one control byte (see below); 128
+ data bytes (compared to 125 data bytes for a disk sector), and a
+ checksum byte. Only the data bytes are stored in the cassette
+ buffer. See De Re Atari for more ~nformaUon on the cassette
+ recorder.
+
+
+
+ CONTROL BYTE VALUES
+
+ Value Meaning
+ 250 ($FA) Partial record follows. The actual number of bytes is stored
+ in the last byte of the record (127).
+ 252 ($FC) Record full; 128 bytes follow.
+ 254 ($FE) End of File (EOF) record; followed by 128 zero bytes.
+
+ ---------------------------------------------------------------------------
+ Locations 1152 to 1791 ($480 to $6FF) are for user RAM (outer
+ environment) requirements, depending on the amount of RAM
+ available in the machine. Provided you don't use the FP package or
+ BASIC, you have 640 ($280) free bytes here.
+ Locations 1152 to 1279 ($480 to $4FF) are 128 ($80) spare bytes.
+ The floating point package, when used, requires locations 1406 to 1535
+ ($57E to $5FF).
+
+
+ 1406 57E LBPR1
+
+ LBUFF prefix one.
+
+
+ 1407 57F LBPR2
+
+ LBUFF prefix two.
+
+
+ 1408-1535 580-5FF LBUFF
+
+ BASIC line buffer; 128 bytes. Used as an output result buffer for
+ the FP to ASCII routine at 55526 ($D8E6). The input buffer is
+ pointed to by locations 243, 244 ($F3, $F4).
+
+
+ 1504 5E0 PLYARG
+
+ Polynomial arguments (FP use).
+
+
+ 1510-1515 5E6-5EB FPSCR
+
+ FP scratch pad use.
+
+
+ 1516-1535 5EC-5FF FPSCR1
+
+ Ditto. The end of the buffer is named LBFEND.
+
+ ---------------------------------------------------------------------------
+
+ 1536-1791 600-6FF ....
+
+ Page six: 256 ($FF) bytes protected from OS use. Page six is not
+ used by the OS and may be safely used for machine language
+ subroutines, special I/O handlers, altered character sets, or
+ whatever the user can fit into the space. Some problem may arise
+ when the INPUT statement retrieves more than 128 characters.
+ The locations from 1536 to 1663 ($600 to $67F) are then
+ immediately used as a buffer for the excess characters. To avoid
+ overflow, keep INPUT statements from retrieving more than 128
+ characters. The valFORTH implementation of fig-FORTH (from
+ ValPar International) uses all of page six for its boot code, so it is
+ not available for your use. However, FORTH allows you to
+ reserve other blocks of memory for similar functions. BASIC A+
+ uses locations $0600 - $67F.
+
+ ---------------------------------------------------------------------------
+ Locations 1792 to the address specified by LOMEM (locations
+ 128, 129; ($80, $81) - the pointer to BASIC low memory) are also
+ used by DOS and the File Management System (FMS). Refer to
+ the DOS source code and Inside Atari DOS for details. The
+ addresses which follow are those for DOS 2.0S, the official Atari
+ DOS at the time of this writing. Another DOS is available as an
+ alternative to DOS 2.0 -- K-DOS (TM), from K-BYTE (R). K-DOS
+ is not menu driven but command driven. It does not use all of the
+ same memory locations as the Atari DOS although it does use a
+ modified version of the Atari FMS. (Another command-driven
+ DOS, called OS/A+, is completely compatible with DOS 2.OS
+ and is available from OSS, the creators of DOS 2.0S.)
+
+
+ 1792-5377 700-1501
+
+ File management system RAM (pages seven to fifteen). FMS
+ provides the interface between BASIC or DUP and the disk
+ drive. It is a sophisticated device driver for all I/O operations
+ involving the D: device. It allows disk users to use the special
+ BASIC XIO disk commands (see the IOCB area 832 to 959: $340
+ to $3BF). It is resident in RAM below your BASIC RAM and
+ provides the entry point to DOS when called by BASIC.
+
+
+ 5440-13062 1540-3306
+
+ DUP.SYS RAM. The top will vary with the amount of buffer
+ storage space allocated to the drive and sector buffers.
+
+
+ 6780-7547 1A7C-1D7B
+
+ Drive buffers and sector-data buffers. The amount of memory will
+ vary with the number of buffers allocated.
+
+
+ 7548-MEMLO 1D7C-3306 (maximum)
+
+ Non-resident portion of DUP.SYS, DOS utility routines. DUP
+ provides the utilities chosen from the DOS menu page, not from
+ BASIC. It is not resident in RAM when you are using BASIC or
+ another cartridge; rather it is loaded when DOS is called from
+ BASIC or on autoboot powerup (and no cartridge supersedes it).
+ When DUP is loaded, it overwrites the lower portion of memory.
+ If you wish to save your program from destruction, you must have
+ created a MEM.SAV file on disk before you called DOS from your
+ program. See the DOS Reference Manual.
+
+ ---------------------------------------------------------------------------
+ Locations 1792 to 2047 ($700 to $7FF; page seven) are the user boot
+ area. MEMLO and LOMEM point to 1792 when no DOS or DUP
+ program is loaded. This area can then be used for your BASIC or
+ machine language programs. The lowest free memory address is 1792,
+ and programs may extend upwards from here. There is a one-page
+ buffer before the program space used for the tokenization of BASIC
+ statements, pointed to by locations 128, 129 ($80, $81). Actually a
+ program may start from any address above 1792 and below the screen
+ display list as long as it does not overwrite this buffer if it is a BASIC
+ program. Also, 1792 is the start of the FMS portion of DOS when
+ resident.
+
+ When software is booted, the MEMLO pointer at 743,744 ($2E7,$2E8)
+ in the OS data base (locations 512 to 1151; $512 to $47F) points to the
+ first free memory location above that software; otherwise, it points to
+ 1792. The DUP portion of DOS is partly resident here, starting at 5440
+ ($1540) and running to 13062 ($1540 to $3306). The location of the OS
+ disk boot entry routine (DOBOOT) is 62189 ($F2ED). The standard
+ Atari DOS 2.OS takes up sectors one through 83 ($53) on a disk. Sector
+ one is the boot sector. Sectors two through 40 ($28) are the FMS
+ portion, and sectors 41 ($29) through 83 are the DUP.SYS portion of
+ DOS. For more information, see the DOS and OS source listings and
+ Inside Atari DOS.
+
+ ---------------------------------------------------------------------------
+
+ FMS, DOS.SYS and DUP.SYS
+
+ Disk boot records (sector one on a disk) are read into 1792 ($700).
+ Starting from $700 (1792), the format is:
+
+ Byte Hex Label and use
+ 0 700 BFLAG: Boot flag equals zero (unused).
+ 1 701 BRCNT: Number of consecutive sectors to
+ read (if the file is DOS, then BRCNT equals
+ one).
+ 2,3 702,703 BLDADR: Boot sector load address ($700).
+ 4,5 704,705 BIWTARR: Initialization address.
+ 6 706 JMP XBCONT: Boot continuation vector; $4C
+ (76): JMP command to next address in bytes seven and eight.
+
+ 7,8 707,708 Boot read continuation address
+ (LSB/MSB).
+
+ 9 709 SABYTE: Maximum number of concurrently
+ OPEN files. The default is three (see 1801 below).
+
+ 10 70A DRVBYT: Drive bits: the maximum number
+ of drives attached to the system. The default is two (see 1802
+ below).
+
+ 11 70B (unused) Buffer allocation direction, set to
+ zero.
+
+ 12,13 70C,70D SASA: Buffer allocation start address. Points
+ to 1995 ($7CB) when DOS is loaded.
+
+ 14 70E DSFLG: DOS flag. Boot flag set to non-zero
+ Must be non-zero for the second phase of boot process. Indicates
+ that the file DOS.SYS has been written to the disk; zero equals no
+ DOS file, one equals 128 byte sector disk, two equals 256 byte
+ sector disk.
+
+ 15,16 70F,710 DFLINK: Pointer to the first sector of DOS.SYS
+ file.
+
+ 17 711 BLDISP: Displacement to the sector link byte
+ 125 ($7D). The sector link byte is the pointer to the next disk
+ sector to be read. If it is zero, the end of the file has been
+ reached.
+
+ 18,19 712,713 DFLADR: Address of the start of DOS.SYS
+ file.
+
+ 20+ 714+ Continuation of the boot load file. See the
+ OS User's Manual and Chapter 20 of Inside Atari DOS.
+
+ Data from the boot sector is placed in locations 1792 to 1916 ($700
+ to $77C). Data from the rest of DOS.SYS is located starting from
+ 1917 ($77D). All binary file loads start with 255 ($FF). The next
+ four bytes are the start and end addresses (LSB/MSB),
+ respectively.
+
+
+ 1801 709 SABYTE
+
+ This records the limit on the number of files that can be open
+ simultaneously. Usually set to three, the maximum is seven (one
+ for each available IOCB -- remember IOCB0 is used for the
+ screen display). Each available file takes 128 bytes for a buffer,
+ if you increase the number of buffers, you decrease your RAM
+ space accordingly. You can POKE 1801 with your new number to
+ increase or decrease the number of files and then rewrite DOS
+ (by calling DOS from BASIC and choosing menu selection "H")
+ and have this number as your default on the new DOS.
+
+
+ 1802 70A DRVBYT
+
+ The maximum number of disk drives in your system, the DOS 2.0
+ default value is two. The least four bits are used to record which
+ drives are available, so if you have drives one, three and four,
+ this location would read:
+
+ 00001101 or 13 in decimal.
+
+ Each drive has a separate buffer of 128 bytes reserved for it in
+ RAM. If you have more or less than the default (two), then POKE
+ 1802 with the appropriate number:
+
+ 1 drive = 1 BIT 0 Binary 00000001
+ 2 drives = 3 BITS 0 & 1 00000011
+ 3 drives = 7 BITS 0, 1 & 2 00000111
+ 4 drives = 15 BITS 0, 1, 2 & 3 00001111
+
+ This assumes you have them numbered sequentially. If not,
+ POKE the appropriate decimal translation for the correct binary
+ code: each drive is specified by one of the least four bits from one
+ in BIT 0 to four in BIT 3. If you PEEK (1802) and get back three,
+ for example, it means drives one and two are allocated, not three
+ drives.
+
+ You can save your modification to a new disk by calling up DOS
+ and choosing menu selection "H." This new DOS will then boot
+ up with the number of drives and buffers you have allocated. A
+ one-drive system can save 128 bytes this way (256 if one less data
+ buffer is chosen). See the DOS Manual, page G.87.
+
+
+ 1900 76C BSIO
+
+ Entry point to FMS disk sector I/O routines.
+
+
+ 1906 772 BSIOR
+
+ Entry point to the FMS disk handler (?).
+
+
+ 1913 779 ....
+
+ Write verify flag for disk I/O operations. POKE with 80 ($50) to
+ turn off the verify function, 87 ($57) to turn it back on. Disk write
+ without verify is faster, but you may get errors in your data. I
+ have had very few errors generated by turning off the verify
+ function, but even one error in critical material can destroy a
+ whole program. Be careful about using this location. You can
+ save DOS (as above with menu selection "H") without write verify
+ as your new default by writing DOS to a new disk. See the DOS
+ Manual, page F.85. K-DOS's write-verify flag is located at 1907
+ ($773).
+
+
+ 1995 7CB DFMSDH
+
+ Entry point to a 21-byte FMS device (disk) handler. The address
+ of this handler is placed in HATABS (locations 794 to 831; $31A
+ to $33F) by the FMS initialization routine. When CIO needs to
+ call an FMS function, it will locate the address of that function via
+ the handler address table. See Chapters 8-11 of Inside Atari
+ DOS, published by COMPUTE! Books.
+
+
+ 2016 7E0 DINT
+
+ FMS initialization routine. The entry point is 1995 ($7CB). DUP
+ calls FMS at this point. K-DOS uses the same location for its
+ initialization routine.
+
+
+ 2219 8AB DFMOPN
+
+ OPEN routines, including open for append, update, and output.
+
+
+ 2508 900 DFMPUT
+
+ PUT byte routines.
+
+
+ 2591 A1F WTBUR
+
+ Burst I/O routines.
+
+
+ 2592-2773 A20-AD5 ....
+
+ In COMPUTE!, May and July 1982, Bill Wilkinson discussed
+ BURST I/O, which should not take place when a file is OPEN for
+ update, but does, due to a minor bug in DOS 2.0 (see also Inside
+ Atari DOS, Chapter 12). This will cause update writes to work
+ properly, but update reads to be bad. The following POKEs will
+ correct the problem. Remember to save DOS back to a new disk.
+
+ POKE 2592,130 ($A20,82)
+ POKE 2593,19 ($A21,13)
+ POKE 2594,73 ($A22,49)
+ POKE 2595,12 ($A23,0C)
+ POKE 2596,240 ($A24,F0)
+ POKE 2597,36 ($A25,24)
+ POKE 2598,106 ($A26,6A)
+ POKE 2599,234 ($A27,EA)
+ POKE 2625,16 ($A41,10)
+ POKE 2773,31 ($AD5,1F)
+
+ (Note that the July 1982 issue of COMPUTE! contained a typo
+ where the value to be POKEd into 2773 was mistakenly listed as
+ 13, not 31!) Wilkinson points out that one way to completely
+ disable BURST I/O (useful in some circumstances such as using
+ the DOS BINARY SAVE to save the contents of ROM to disk!) is
+ by:
+
+ POKE 2606,0 ($A2E,0)
+
+ This, however, will make the system LOAD and SAVE files
+ considerably more slowly, so it's not recommended as a
+ permanent change to DOS.
+
+
+ 2751 ABF DFMGET
+
+ GET byte routines, including GET file routines.
+
+ 2817 B0l DFMSTA
+ Disk STATUS routines.
+
+
+ 2837 B15 DFMCLS
+
+ IOCB CLOSE routines.
+
+
+ 2983 BA7 DFMDDC
+
+ Start of the device-dependent command routines, including the
+ BASIC XIO special commands:
+
+
+ 3033 BD9 XRENAME
+
+ RENAME a file.
+
+
+ 3122 C32 XDELETE
+
+ DELETE a file.
+
+
+ 3196 C7C XLOCK, XUNLOCK
+
+ LOCK and UNLOCK files. UNLOCK routines begin at 3203
+ ($C83).
+
+
+ 3258 CBA XPOINT
+
+ BASIC POINT command.
+
+
+ 3331 D03 XNOTE
+
+ BASIC NOTE command. See the DOS Manual for information
+ regarding these two BASIC commands, and see De Re Atari for a
+ sample use.
+
+
+ 3352 D18 XFORMAT
+
+ Format the entire diskette.
+
+
+ 3501 DAD LISTDIR
+
+ List the disk directory.
+
+
+ 3742 E9E FNDCODE
+
+ File name decode, including wildcard validity test. The current
+ file name is pointed to by ZBUFP at locations 67, 68 ($43, $44).
+
+
+ 3783 EC7 ....
+
+ By POKEing the desired ATASCII value here, you can change
+ the wildcard character (*; ATASCII 42, $2A) used by DOS to any
+ other character of your choice. Your altered DOS can be saved
+ back to disk with DOS menu selection "H".
+
+
+ 3818,3822 EEA,EEE ....
+
+ By POKEing 3818 with 33 and 3822 with 123 ($21 ,$7B;), you can
+ modify DOS to accept file names with punctuation, numbers and
+ lowercase as valid; 33 is the low range of the ATASCII code and
+ 127 the high range (lower or higher values are control and
+ graphics codes and inverse characters). Of course, any
+ unmodified DOS still won't accept such file names. You could
+ actually change the range to any value from zero to 255 at your
+ discretion. This, however, may cause other problems with such
+ ATASCII codes as spaces and the wildcard (*; see above). Can
+ be saved back to disk with menu selection "H".
+
+
+ 3850 F0A FDSCHAR
+
+ Store the file name characters that result from the file name
+ decode routines.
+
+
+ 3873 F21 SFDIR
+
+ Directory search routines; search for the user-specified file
+ name.
+
+
+ 3988 F94 WRTNXS
+
+ Write data sector routine.
+
+
+ 4111 100F RDNXTS
+
+ Read data sector routine.
+
+
+ 4206 106E RDDIR
+
+ Read and write directory sector routines.
+
+
+ 4235 108B RDVTOC
+
+ Read or write the volume table of contents (VTOC) sectors.
+
+
+ 4293 10C5 FRESECT
+
+ Free sector(s) routine; returns the number of free sectors on a
+ disk that are available to the user.
+
+
+ 4358 1106 GETSECTOR
+
+ Get sector routine; retrieves a free sector for use from the disk.
+
+
+ 4452 1164 SETUP
+
+ SETUP -- initialization of the FMS parameters. Prepares FMS to
+ deal with the operation to be performed and to access a
+ particular file. See Inside Atari DOS, Chapter seven.
+
+
+ 4618 120A WRTDOS
+
+ Write new DOS.SYS file to disk routine, including new FMS file
+ to DOS.SYS file.
+
+
+ 4789 12B5 ERRNO
+
+ Start of the FMS error number table.
+
+
+ 4856-4978 12F8-1372 ....
+
+ Miscellaneous FMS storage area: sector length, drive tape, stack
+ level, file number, etc.
+
+
+ 4993-5120 1381-1400 FCB
+
+ Start of the FMS File Control Blocks (FCB's). FCB's are used to
+ store information about files currently being processed. The
+ eight FCB's are 16-byte blocks that correspond in a one-on-one
+ manner with the IOCB's. Each FCB consist of:
+
+ Label Bytes Purpose
+ FCBFNO 1 File number of the current file being
+ processed.
+
+ FCBOTC 1 Which mode the file has been OPENed for:
+ append is one, directory read is two, input is four, output is
+ eight, update is twelve.
+
+ SPARE 1 Not used.
+
+ FCBSLT 1 Flag for the sector length type; 128 or 256
+ bytes
+
+ FCBFLG 1 Working flag. If equal to 128 ($80), then the
+ file has been OPENed for output or append and may acquire new
+ data sectors. If the value is 64, then sector is in the memory buffer
+ awaiting writing to disk.
+
+ FCBMLN 1 Maximum sector data length; 125 or 253 bytes
+ depending on drive type (single or double density). The last
+ three sector bytes are reserved for sector link and byte count
+ data.
+
+ FCBDLN 1 Current byte to be read or modified in the
+ operation in a data sector.
+
+ FCBBUF 1 Tell FMS which buffer has been allocated
+ to the file being processed.
+
+ FCBCSN 2 Sector number of the sector currently in the
+ buffer.
+
+ FCBLSN 2 Number of the next sector in data chain.
+
+ FCBSSN 2 Starting sectors for appended data if the file
+ has been OPENed for append.
+
+ FCBCNT 2 Sector count for the current file.
+
+ DUP doesn't use these FCB's; it writes to the IOCB's directly.
+ CIO transfers the control to FMS as the operation demands, then
+ on to SIO.
+
+
+ 5121 1401 FILDIR
+
+ File directory, a 256 ($100) byte sequential buffer for entries to
+ the disk directory.
+
+
+ 5377 1501 ENDFMS
+
+ Disk directory (VTOC -- Volume Table Of Contents) buffer. 64
+ ($40) bytes are reserved, one byte for each possible file. It also
+ marks the end of FMS. The VTOC (sector 360; $168) is a
+ sequential bit map of each of the 720 sectors on the disk. It starts
+ at byte ten and continues through to byte 99. When a bit is set
+ (one), it indicates that the sector associated is in use.
+
+
+ 5440 1540 DOS
+
+ DUP.SYS initialization address. Beginning of mini-DOS; the
+ RAM-resident portion of DUP. Used for the same purpose in K-
+ DOS.
+
+
+ 5446,5450 1546,154A ....
+
+ Contains the location (LSB/MSB) of the DOS VEC (location 10;
+ $A). This is the pointer to the address BASIC will jump to when
+ DOS is called.
+
+
+ 5533 159D DUPFLG
+
+ Flag to test if DUP is already resident in memory. Zero equals
+ DUP is not there.
+
+
+ 5534 159E OPT
+
+ Used to store the value of the disk menu option chosen by the
+ user.
+
+
+ 5535 159F LOADFLG
+
+ If this location reads 128, then a memory file (MEM.SAV) file
+ doesn't have to be loaded.
+
+
+ 5540 15A4 SFLOAD
+
+ Routines to load a MEM.SAV file if it exists.
+
+
+ 5888 1700 USRDOS
+
+ Listed in the DUP.SYS equates file but never explained in the
+ listings.
+
+
+ 5899 170B MEMLDD
+
+ Flags that the MEM.SAV file has been loaded. Zero means it has
+ not been loaded.
+
+
+ 5947 173B ....
+
+ The MEM.SAV (MEMSAVE) file creation routines begin here.
+ They start with the file name MEM.SAV stored in ATASCII
+ format. The write routines begin at MWRITE, 5958 ($1746). The
+ DOS utility MEMSAVE copies the lower 6000 bytes of memory to
+ disk to save your BASIC program from being destroyed when
+ you call DOS, which then loads DUP.SYS into that area of
+ memory.
+
+
+ 6044,6045 179C-179D INISAV
+
+ DOSINI (see location 12, 13; $C, $D) vector save location. Entry
+ point to DOS on a call from BASIC.
+
+
+ 6046 179E MEMFLG
+
+ Flag to show if memory has been written to disk using a
+ MEM.SAV file.
+
+
+ 6418 1912 CLMJMP
+
+ Test to see if DOS must load MEM.SAV from the disk before it
+ does a run at cartridge address, then jumps to the cartridge
+ address.
+
+
+ 6432 1920 LMTR
+
+ Test to see if DOS must load MEM.SAV before it performs a run at
+ address command from the DOS menu.
+
+
+ 6457 1939 LDMEM
+
+ MEMSAVE load routines (for the MEM.SAV file).
+
+
+ 6518 1979 INITIO
+
+ DUP.SYS warmstart entry. An excellent program to eliminate the
+ need for DUP.SYS and MEM.SAV (not to mention the time
+ required to load them!) was presented in COMPUTE!, July 1982,
+ called MicroDOS; it's well worth examining. See also "The Atari
+ Wedge," COMPUTE!, December 1982.
+
+ 663C 19E6 ISRODN
+ Start of the serial interrupt service routine to output data needed
+ routines in DUP.SYS.
+
+
+ 6691 1A23 ISRSIR
+
+ Start of the serial interrupt ready service routines in DUP.SYS.
+
+
+ 6781 1A7D ....
+
+ Start of the drive and data buffers. Drive buffers are numbered
+ sequentially one to four, data buffers one to eight, assuming that
+ many are allocated for each. Normally, the first two buffers are
+ allocated for drives and the next three for data. Buffers are 128
+ ($80) bytes long each and start at 6908 ($1AFC), 7036 ($1B7C),
+ 7162 ($1BFA) and 7292 ($1C7C). See locations 1801 and 1802
+ ($709, $70A).
+
+
+ 7420 1CFC ....
+
+ MEMLO (743, 744; $2E7, $2E8) points here when DOS is resident
+ unless the buffer allocation has been altered. MEMLO will point
+ to 7164 for a one drive, two data buffer setup, a saving of 256
+ bytes. Loading the RS-232 handler from the 850 Interface will
+ move MEMLO up another 1728 bytes. The RS-232 handler in the
+ 850 Interface will only boot (load into memory) if you first boot
+ the AUTORUN.SYS file on your Atari master diskette or use
+ another RS-232 boot program such as a terminal package. The
+ RS-232 handler will boot up into memory if you do not have a disk
+ attached and you have turned it on before turning on the
+ computer. You may still use the printer (parallel) port on the 850
+ even if the RS-232 handler is not booted.
+
+
+ 7548 1D7C ....
+
+ Beginning of non-resident portion of DUP; 40 ($28) byte
+ parameter buffer.
+
+
+ 7588 1DA4 LINE
+
+ 80 ($50) byte line buffer.
+
+
+ 7668 1DF4 DBUF
+
+ 256 ($100) byte data buffer for COPY routines. Copy routines
+ work in 125-byte passes, equal to the number of data bytes in
+ each sector on the disk. There are 256 bytes because Atari had
+ planned a double density drive which has 253 data bytes in each
+ sector.
+
+
+ 7924 1EF4 ....
+
+ Miscellaneous variable storage area and data buffers.
+
+
+ 7951-8278 1F0F-2056 DMENU
+
+ Disk menu screen display data is stored here.
+
+
+ 8191 1FFF ....
+
+ This is the top of the minimum RAM required for operation (8K).
+ To use DOS, you must have a minimum of 16K.
+
+ ---------------------------------------------------------------------------
+
+ DUP.SYS ROUTINES
+
+ Locations 8192 to 32767 ($2000 to $7FFF) are the largest part of the
+ RAM expansion area; this space is generally for your own use. If you
+ have DOS.SYS or DUP.SYS loaded in, they also use a portion of this
+ area to 13062 ($3306) as below:
+
+
+ 8309 2075 DOSOS
+
+ Start of the DOS utility monitor, including the utilities called
+ when a menu selection function is completed and the display of
+ the "SELECT ITEM" message.
+
+
+ 8505 2139 DIRLST
+
+ Directory listing.
+
+
+ 8649 21C9 DELFIL
+
+ Delete a file.
+
+
+ 8990 231E ....
+
+ Copy a file. This area starts with the copy messages. The copy
+ routines themselves begin at PYFIL, 9080 ($2378).
+
+
+ 9783 2637 RENFIL
+
+ Rename a disk file routines.
+
+
+ 9856 2680 FMTDSK
+
+ Format the entire disk. There is no way to format specific sectors
+ of a disk with the "C" ROMs currently used in your 810 drives.
+ There is a new ROM, the "E" version, which not only allows
+ selective sector formatting, but is also considerably faster. It was
+ not known at the time of this writing whether Atari would release
+ the "E" version.
+
+
+ 9966 26EE STCAR
+
+ Start a cartridge.
+
+
+ 10060 274C BRUN
+
+ Run a binary file at the user-specified address.
+
+
+ 10111 277F ....
+
+ Start of the write MEM.SAV file to disk routine. The entry point is
+ at MEMSAV, 10138 ($279A).
+
+
+ 10201 27D9 WBOOT
+
+ Write DOS/DUP files to disk.
+
+
+ 10483 28F3 TESTVER2
+
+ Test for version two DOS. DOS.20S is the latest official DOS,
+ considerably improved over the earlier DOS 1.0. The S stands for
+ single density. Atari had planned to release a dual density drive
+ (the 815), but pulled it out of the production line at the last minute
+ for some obscure high-level reason. A double density drive is
+ available from the Percom company.
+
+
+ 10522 291A LDFIL
+
+ Load a binary file into memory. If it has a run address specified in
+ the file, it will autoboot.
+
+
+ 10608 2970 LKFIL, ULFIL
+
+ Lock and unlock files on a disk.
+
+
+ 10690 29C2 DDMG
+
+ Duplicate a disk.
+
+
+ 11528 2D08 DFFM
+
+ Duplicate a file.
+
+
+ 11841 2E41 ....
+
+ Miscellaneous subroutines.
+
+
+ 12078 2F2E SAVFIL
+
+ Save a binary file.
+
+
+ 12348 303C ....
+
+ Miscellaneous subroutines.
+
+
+ 13062 3306 ....
+
+ End of DUP.SYS.
+ The rest of RAM is available to location 32767 ($7FFF).
+
+ ---------------------------------------------------------------------------
+
+ CARTRIDGE B: 8K
+
+ Locations 32768 to 40959 ($8000 to $9FFF) are used by the right
+ cartridge (Atari 800 only), when present. When not present, this RAM
+ area is available for use in programs. When the 8K BASIC cartridge is
+ being used, this area most frequently contains the display list and screen
+ memory. As of this writing, the only cartridge that uses this slot is
+ Monkey Wrench from Eastern House Software.
+
+ It is possible to have 16K cartridges on the Atari by either combining
+ both slots using two 8K cartridges or simply having one with large
+ enough ROM chips and using one slot. In this case, the entire area from
+ 32768 to 49151 ($8000 to $BFFF) would be used as cartridge ROM.
+
+ Technically, the right cartridge slot is checked first for a resident
+ cartridge and initialized, then the left. You can confirm this by putting
+ the Assembler Editor cartridge in the right and BASIC in the left slots.
+ BASIC will boot, but not the ASED. Using FRE(0), you will see,
+ however, that you have 8K less RAM to use; and PEEKing through this
+ area will show that the ASED program is indeed in memory, but that
+ control was passed to BASIC. Control will pass to the ASED cartridge if
+ the cartridges are reversed. This is because the last six bytes of the
+ cartridge programs tell the OS where the program begins -- in both
+ cases, it is a location in the area dedicated to the left cartridge. The six
+ bytes are as follows:
+
+ Byte Purpose
+ Left (A) Right(B)
+ 49146 ($BFFA) 40954 ($9FFA) Cartridge start address (low byte)
+ 49147 ($BFFB) 40955 ($9FFB) Cartridge start address (high byte)
+ 49148 ($BFFC) 40956,($9FFC) Reads zero if a cartridge is
+ inserted, non-zero when no cartridge is present. This information
+ is passed down to the page zero RAM: if the A cartridge is plugged
+ in, then location 6 will read one; if the B cartridge is plugged in,
+ then location 7 will read one; otherwise they will read zero.
+ 49149 ($BFFD) 40957 ($9FFD) Option byte. If BIT 0 equals one,
+ then boot the disk (else there is no disk boot). If BIT 2 equals one,
+ then initialize and start the cartridge (else initialize but do not
+ start). If BIT 7 equals one, then the cartridge is a diagnostic
+ cartridge which will take control, but not initialize the OS (else
+ non-diagnostic cartridge). Diagnostic cartridges were used by
+ Atari in the development of the system and are not available to the
+ public.
+ 49150 ($BFFE) 40958 ($9FFE) Cartridge initialization address
+ low byte.
+ 49151 ($BFFF) 40959 ($9FFF) Cartridge initialization address
+ high byte. This is the address to which the OS will jump during all
+ powerup and RESETs.
+
+ The OS makes temporary use of locations 36876 to 36896 ($900C to
+ $9020) to set up vectors for the interrupt handler. See the OS
+ listings pages 31 and 81. This code was only used in the
+ development system used to design the Atari.
+
+ ---------------------------------------------------------------------------
+
+ CARTRIDGE A: 8K
+
+ Locations 40960 to 49151 ($A000 to $BFFF) are used by the left
+ cartridge, when present. When not present, this RAM area is available
+ for other use. The display list and the screen display data will be in this
+ area when there is no cartridge present.
+
+ Most cartridges use this slot (see above) including the 8K BASIC,
+ Assembler-Editor, and many games. Below are some of the entry
+ points for the routines in Atari 8K BASIC. There is no official Atari
+ listing of the BASIC ROM yet. Many of the addresses below are listed
+ in Your Atari 400/800. Others have been provided in numerous
+ magazine articles and from disassembling the BASIC cartridge.
+
+
+ BASIC ROUTINES
+
+ 40960-41036 A000-A04C
+ Cold start.
+
+ 41037-41055 A04D-A05F
+ Warm start.
+
+ 41056-42081 A060-A461
+ Syntax checking routines.
+
+ 42082-42158 A462-A4AE
+ Search routines.
+
+ 42159-42508 A4AF-A60C
+ STATEMENT name table. The statement TOKEN list begins at 42161
+ ($A4B1). You can print a list of these tokens by:
+
+ 5 ADDRESS = 42161
+ 10 IF NOT PEEK(ADDRESS) THEN PRINT:
+ END
+ 15 PRINT TOKEN,
+ 20 BYTE = PEEK(ADDRESS): ADDRESS = A
+ DDRESS + 1
+ 30 IF BYTE < 128 THEN PRINT CHR$(BYT
+ E);: GOTO 20
+ 40 PRINT CHR$(BYTE - 128)
+ 50 ADDRESS = ADDRESS + 2: TOKEN = TO
+ KEN + 1: GOTO 10
+
+ DOWNLOAD STATMENT.BAS
+
+ 42509-43134 A60D-A87E
+ Syntax tables. The OPERATOR token list begins at 42979 ($A7E3). You
+ can print a list of these tokens by:
+
+ 5 ADDRESS = 42979: TOKEN = 16
+ 10 IF NOT PEEK (ADDRESS) THEN PRINT:
+ END
+ 15 PRINT TOKEN,
+ 20 BYTE = PEEK(ADDRESS): ADDRESS = A
+ DDRESS + 1
+ 30 IF BYTE < 128 THEN PRINT CHR$(BYT
+ E);: GOTO 20
+ 40 PRINT CHR$(BYTE - 128)
+ 50 TOKEN = TOKEN + 1
+ 60 GOTO 10
+
+ DOWNLOAD OPERATOR.BAS
+
+ See COMPUTE!, January and February 1982; BYTE, February 1982,
+ and De Re Atari for an explanation of BASIC tokens.
+
+ 43135-43358 A87F-A95E
+ Memory manager.
+
+ 43359-43519 A95F-A9FF
+ Execute CONT statement.
+
+ 43520-43631 AA00-AA6F
+ Statement table.
+
+ 43632-43743 AA70-AADF
+ Operator table.
+
+ 43744-44094 AAE0-AC3E
+ Execute expression routine.
+
+ 44095-44163 AC3F-AC83
+ Operator precedence routine.
+
+ 44164-45001 AC84-AFC9
+ Execute operator routine.
+
+ 45002-45320 AFCA-B108
+ Execute function routine.
+
+ 45321-47127 B109-B817
+ Execute statement routine.
+
+ 47128-47381 B818-B915
+ CONT statement subroutines.
+
+ 47382-47542 B916-B9B6
+ Error handling routines.
+
+ 47543-47732 B9B7-BA74
+ Graphics handling routines.
+
+ 47733-48548 BA75-BDA4
+ I/O routines.
+
+ 48549-49145 BDA5-BFF9
+ Floating point routines (see below).
+
+
+ 48551 BDA7 SIN
+
+ Calculate SIN(FR0). Checks DEGFLG (location 251; $FB) to see if
+ trigonometric calculations are in radians (DEGFLG equals zero)
+ or degrees (DEGFLG equals six).
+
+
+ 48561 BDB1 COS
+
+ Calculate Cosine (FR0) with carry. FR0 is Floating Point register
+ zero, locations 212-217; $D4-$D9. See the Floating Point package
+ entry points from location 55296 on.
+
+
+ 48759 BE77 ATAN
+
+ Calculate Atangent using FR0, with carry.
+
+
+ 48869 BEE5 SQR
+
+ Calculate square root (FR0) with carry.
+ Note that there is some conflict of addresses for the above
+ routines. The addresses given are from the first edition of De Re
+ Atari. The Atari OS Source Code Listing gives the following
+ addresses for these FP routines:
+
+ These are entry points, not actual start addresses.
+
+ SIN 48513 ($BD81)
+ COS 48499 ($BD73)
+ ATAN 48707 ($BE43)
+ SQR 48817 ($BEB1)
+
+ However, after disassembling the BASIC ROMs, I found that the
+ addresses in De Re Atari appear to be correct.
+
+ 49146,7 BFFA,B
+ Left cartridge start address.
+
+ 49148 BFFC
+ A non-zero number here tells the OS that there is no cartridge in
+ the left slot.
+
+ 49149 BFFD
+ Option byte. A cartridge which does not specify a disk boot may
+ use all of the memory from 1152 ($480) to MEMTOP any way it sees
+ fit.
+
+ 49150,1 BFFE,F
+ Cartridge initialization address. See the above section on the right
+ slot, 32768 to 40959, for more information.
+
+ ---------------------------------------------------------------------------
+ When a BASIC program is SAVEd, only 14 of the more than 50
+ page zero locations BASIC uses are written to the disk or cassette
+ with the program. The rest are all recalculated with a NEW or
+ SAVE command, sometimes with RUN or GOTO. These 14
+ locations are:
+
+ 128,129 80,81 LOMEM
+ 130,131 82,83 VNTP
+ 132,133 84,85 VNTD
+ 134,135 86,87 VVTP
+ 136,137 88,89 STMTAB
+ 138,139 8A,8B STMCUR
+ 140,141 8C,8D STARP
+
+ The string/array space is not loaded; STARP is included only to
+ point to the end of the BASIC program.
+ The two other critical BASIC page zero pointers, which are not
+ SAVEd with the program, are:
+
+ 142,143 8E,8F RUNSTK
+ 144,145 90,91 MEMTOP
+
+ For more information concerning Atari BASIC, see the appendix.
+ For detailed description, refer to the Atari BASIC Reference
+ Manual. For more technical information, see De Re Atari, BYTE,
+ February 1982, and COMPUTE!'s First Book of Atari and
+ COMPUTE!'s Second Book of Atari.
+
+ ---------------------------------------------------------------------------
+ Locations 49152 to 53247 ($C000 to $CFFF) are unused.
+ Unfortunately, this rather large 4K block of memory cannot be written
+ to by the user, so it is presently useless. Apparently, this area of ROM
+ is reserved for future expansion. Rumors abound about new Atari OS's
+ that allow 3-D graphics, 192K of on-board RAM and other delights.
+ Most likely this space will be consumed in the next OS upgrade.
+ PEEKing this area will show it not to be completely empty; it was
+ apparently used for system development in Atari's paleozoic age.
+ Although the Atari is technically a 64K machine (1K equals 1024 bytes,
+ so 64K equals 65536 bytes), you don't really have all 64K to use. The
+ OS takes up 10K; there is the 4K block here that's unused, plus a few
+ other unused areas in the ROM and, of course, there are the hardware
+ chips. BASIC (or any cartridge) uses another 8K. The bottom 1792
+ bytes are used by the OS, BASIC, and floating point package. Then
+ DOS and DUP take up their memory space, not to mention the 850
+ handler if booted -- leaving you with more or less 38K of RAM to use
+ for your BASIC programming.
+
+ ---------------------------------------------------------------------------
+ Locations 53248 to 55295 ($D000 to $D7FF) are for ROM for the special
+ I/O chips that Atari uses. The CTIA (or GTIA, depending on which
+ you have) uses memory locations 53248 to 53503 ($D000 to $D0FF).
+ POKEY uses 53760 to 54015 ($D200 to $D2FF). PIA uses 54016 to 54271
+ ($D300 to $D3FF). ANTIC uses 54272 to 54783 ($D400 to $D5FF).
+ ANTIC, POKEY and G/CTIA are Large Scale Integration (LSI) circuit
+ chips. Don't confuse this chip ROM with the OS ROM which is be
+ found in higher memory. For the most extensive description of these
+ chips, see the Atari Hardware Manual.
+
+ There are two blocks of unused, unavailable memory in the I/O areas:
+ 53504 to 53759 ($D100 to $D1FF) and 54784 to 55295 ($D600 to
+ $D7FF).
+
+ Many of the following registers can't be read directly, since they are
+ hardware registers. Writing to them can often be difficult because in
+ most cases the registers change every 30th second (stage two
+ VBLANK) or even every 60th second (stage one VBLANK)! That's
+ where the shadow registers mentioned earlier come in. The values
+ written into these ROM locations are drawn from the shadow registers;
+ to effect any "permanent" change in BASIC (i.e., while your program
+ is running), you have to write to these shadow registers (in direct mode
+ or while your program is running; these values will all be reset to their
+ initialization state on RESET or powerup).
+
+ Shadow register locations are enclosed in parentheses; see these
+ locations for further descriptions. If no shadow register is mentioned,
+ you may be able to write to the location directly in BASIC. Machine
+ language is fast enough to write to the ROM locations and may be able
+ to bypass the shadow registers entirely.
+
+ Another feature of many of these registers is their dual nature. They
+ are read for one value and written to for another. The differences
+ between these functions are noted by the (R) for read and (W) for write
+ functions. You will notice that many of these dual-purpose registers
+ also have two labels.
+
+ ---------------------------------------------------------------------------
+
+ CTIA or GTIA
+
+ 53248-53505 D000-D0FF
+
+ GTIA (or CTIA) is a special television interface chip designed
+ exclusively for the Atari to process the video signal. ANTIC
+ controls most of the C/GTIA chip functions. The GTIA shifts the
+ display by one-half color clock off what the CTIA displays, so it
+ may display a different color than the CTIA in the same piece of
+ software. However, this shift allows players and playfields to
+ overlap perfectly.
+
+ There is no text window available in GTIA modes, but you can
+ create a defined area on your screen with either a DLI (see
+ COMPUTE!, September 1982) or by POKEing the GTIA mode
+ number into location 87 ($57), POKEing 703 with four and then
+ setting the proper bits in location 623 ($26F) for that mode. Only in
+ the former method will you be able to get a readable screen,
+ however. In the latter you will only create a four line, scrolling,
+ unreadable window. You will be able to input and output as with
+ any normal text window; you just won't be able to read it! GTIA,
+ by the way, apparently stands for "George's Television Interface
+ Adapter." Whoever George is, thanks, but what is CTIA?
+ See the OS User's Manual, the Hardware Manual, De Re Atari and
+ COMPUTE!, July 1982 to September 1982, for more information.
+
+
+ 53248 D000 HPOSP0
+
+ (W) Horizontal position of player 0. Values from zero to 227 ($E3)
+ are possible but, depending on the size of the playfield, the range
+ can be from 48 ($30) as the leftmost position to 208 ($D0) as the
+ rightmost position. Other positions will be "off screen."
+ Here are the normal screen boundaries for players and missiles.
+ The values may vary somewhat due to the nature of your TV
+ screen. Players and missiles may be located outside these
+ boundaries, but will not be visible (off screen):
+
+ Top
+ 32 for single,
+ 16 for double line
+ resolution
+ +--------------------------------+
+ | |
+ | |
+ | |
+ 48 for both | | 208 for both
+ resolutions | | resolutions
+ | |
+ | |
+ | |
+ +--------------------------------+
+ Bottom
+ 224 for single,
+ 112 for double line
+ resolution
+
+ Although you can POKE to these horizontal position registers, they
+ are reset to zero immediately. The player or missile will stay on the
+ screen at the location specified by the POKE, but in order to move
+ it using the horizontal position registers, you can't use:
+
+ POKE 53248, PEEK (53248) + n (or -n)
+
+ which will end up generating an error message. Instead, you need
+ to use something like this:
+
+ 10 POKE 704,220: GRAPHICS 1: HPOS =
+ 53248: POKE 623,8
+ 20 N = 100: POKE HPOS,N: POKE 53261
+ ,255
+ 30 IF STICK(0) = 11 THEN N = N - 1:
+ POKE HPOS,N: PRINT N
+ 40 IF STICK(0) = 7 THEN N = N + 1:
+ POKE HPOS,N: PRINT N
+ 50 GOTO 30
+
+ There are no vertical position registers for P/M graphics, so you
+ must use software routines to move players vertically. One idea for
+ vertical motion is to reposition the player within the P/M region
+ rather than the screen RAM. For example, the program below uses
+ a small machine language routine to accomplish this move:
+
+ 1 REM LINES 5 TO 70 SET UP THE PLAYER
+ 5 KEEP=PEEK(106)-16
+ 10 POKE 106,KEEP:POKE 54279,KEEP
+ 20 GRAPHICS 7+16:POKE 704,78:POKE 559
+ ,46:POKE 53277,3
+ 30 PMBASE=KEEP*256
+ 40 FOR LOOP=PMBASE+512 TO PMBASE+640:
+ POKE LOOP,0:NEXT LOOP:REM CLEAR OU
+ T MEMORY FIRST
+ 50 X=100:Y=10:POKE 53248,X
+ 60 FOR LOOP=0 TO 7:READ BYTE:POKE PMB
+ ASE+512+Y+LOOP,BYTE:NEXT LOOP:REM
+ PLAYER GRAPHICS INTO MEMORY
+ 70 DATA 129,153,189,255,255,189,153,1
+ 29
+ 80 REM LINES 100 TO 170 SET UP MACHIN
+ E LANGUAGE ROUTINE
+ 100 DIM UP$(21),DOWN$(21):UP=ADR(UP$)
+ :DOWN=ADR(DOWN$)
+ 110 FOR LOOP=UP TO UP+20:READ BYTE:PO
+ KE LOOP,BYTE:NEXT LOOP
+ 120 FOR LOOP=DOWN TO DOWN+20:READ BYT
+ E:POKE LOOP,BYTE:NEXT LOOP
+ 130 DATA 104,104,133,204,104,133,203,
+ 160,1,177
+ 140 DATA 203,136,145,203,200,200,192,
+ 11,208,245,96
+ 150 DATA 104,104,133,204,104,133,203,
+ 160,10,177
+ 160 DATA 203,200,145,203,136,136,192,
+ 255,208,245,96
+ 200 REM VERTICAL CONTROL
+ 210 IF STICK(0)=14 THEN GOSUB 300
+ 220 IF STICK(0)=13 THEN D=USR(DOWN,PM
+ BASE+511+Y):Y=Y+1
+ 250 GOTO 210
+ 300 U=USR(UP,PMBASE+511+Y):Y=Y-l
+ 310 RETURN
+
+ DOWNLOAD MOVEPM.BAS
+
+ This will move any nine-line (or less) size player vertically with the
+ joystick. If you have a larger player size, increase the 11 in line 140
+ to a number two larger than the number of vertical lines the player
+ uses, and change the ten in line 150 to one greater than the
+ number of lines. To add horizontal movement, add the following
+ lines:
+
+ 6 HPOS = 53248
+ 230 IF STICK(0) = 11 THEN X = X - 1:
+ POKE HPOS, X
+ 240 IF STICK(0) = 7 THEN X = X + 1:
+ POKE HPOS, X
+
+ You can use the routine to move any player by changing the
+ number 511 in the USR calls to one less than the start address of the
+ object to be moved. See the appendix for a map of P/M graphics
+ memory use. Missiles are more difficult to move vertically with this
+ routine, since it moves an entire byte, not bits. It would be useful
+ for moving all four missiles vertically if you need to do so; they
+ could still be moved horizontally in an individual manner.
+ See COMPUTE!, December 1981, February 1982, and May 1982,
+ for some solutions and some machine language move routines, and
+ COMPUTE!, October 1981, for a solution with animation involving
+ P/M graphics.
+
+
+ M0PF
+
+ (R) Missile 0 to playfield collision. This register will tell you which
+ playfield the object has "collided" with, i.e., overlapped. If missile
+ 0 collides with playfield two, the register would read four and so
+ on. Bit use is:
+
+ Bit 7 6 5 4 3 2 1 0
+ Playfield .....unused..... 3 2 1 0
+ Decimal ................ 8 4 2 1
+
+
+ 53249 D00l HOPSP1
+
+ (W) Horizontal position of player 1.
+
+
+ M1PF
+
+ (R) Missile 1 to playfield collision.
+
+
+ 53250 D002 HPOSP2
+
+ (W) Horizontal position of player 2.
+
+
+ M2PF
+
+ (R) Missile 2 to playfield collision.
+
+
+ 53251 D003 HPOSP3
+
+ (W) Horizontal position of player 3.
+
+
+ M3PF
+
+ (R) Missile 3 to playfield collision.
+
+
+ 53252 D004 HPOSM0
+
+ (W) Horizontal position of missile 0. Missiles move horizontally like
+ players. See the note in 53248 ($D000) concerning the use of
+ horizontal registers.
+
+
+ P0PF
+
+ (R) Player 0 to playfield collisions. There are some problems using
+ collision detection in graphics modes nine to eleven. There are no
+ obviously recognized collisions in GR.9 and GR.11. In GR.10
+ collisions work only for the playfield colors that correspond to the
+ usual playfield registers. Also, the background (BAK) color is set
+ by PCOLR0 (location 704; $2C0) rather than the usual COLOR4
+ (location 712; $2C8), which will affect the priority detection. In
+ GR.10, playfield colors set by PCOLR0 to PCOLR3 (704 to 707;
+ $2C0 to $2C3) behave like players where priority is concerned. Bit
+ use is:
+
+ Bit 7 6 5 4 3 2 1 0
+ Playfield .....unused..... 3 2 1 0
+ Decimal ................ 8 4 2 1
+
+
+ 53253 D005 HPOSM1
+
+ (W) Horizontal position of missile 1.
+
+
+ P1PF
+
+ (R) Player 1 to playfield collisions.
+
+
+ 53254 D006 HPOSM2
+
+ (W) Horizonal position of missile 2.
+
+
+ P2PF
+
+ (R) Player 2 to playfield collisions.
+
+
+ 53255 D007 HPOSM3
+
+ (W) Horizontal position of missile 3.
+
+
+ P3PF
+
+ (R) Player 3 to playfield collisions.
+
+
+ 53256 D008 SIZEP0
+
+ (W) Size of player 0. POKE with zero or two for normal size (eight
+ color clocks wide), POKE with one to double a player's width
+ (sixteen color clocks wide), and POKE with three for quadruple
+ width (32 color clocks wide). Each player can have its own width set.
+ A normal size player might look something like this:
+
+ 00011000
+ 00111100
+ 01111110
+ 11111111
+ 11111111
+ 01111110
+ 00111100
+ 00011000
+
+ In double width, the same player would like this:
+
+ 0000001111000000
+ 0000111111110000
+ 0011111111111100
+ 0011111111111100
+ 0000111111110000
+ 0000001111000000
+
+ In quadruple width, the same player would become:
+
+ 00000000000011111111000000000000
+ 00000000111111111111111100000000
+ 00001111111111111111111111110000
+ 11111111111111111111111111111111
+ 11111111111111111111111111111111
+ 00001111111111111111111111110000
+ 00000000111111111111111100000000
+ 00000000000011111111000000000000
+
+ Bit use is:
+
+ Bit 7 6 5 4 3 2 1 0
+ Size: .....unused..... 0 0 Normal (8 color clocks)
+ 0 1 Double (16 color clocks)
+ 1 0 Normal
+ 1 1 Quadruple (32 color clocks)
+
+
+ M0PL
+
+ (R) Missile 0 to player collisions. There is no missile-to-missile
+ collision register. Bit use is:
+
+ Bit 7 6 5 4 3 2 1 0
+ Player ..unused.. 3 2 1 0
+ Decimal .......... 8 4 2 1
+
+
+ 53257 D009 SIZEP1
+
+ (W) Size of player 1.
+
+
+ M1PL
+
+ (R) Missile 1 to player collisions.
+
+
+ 53258 D00A SIZEP2
+
+ (W) Size of player 2.
+
+
+ M2PL
+
+ (R) Missile 2 to player collisions.
+
+
+ 53259 D00B SIZEP3
+
+ (W) Size of player 3.
+
+
+ M3PL
+
+ (R) Missile 3 to player collisions.
+
+
+ 53260 D00C SIZEM
+
+ (W) Size for all missiles; set bits as below (decimal values
+ included):
+
+ Bits Size:
+ Normal Double Quadruple
+ 7 & 6: missile 3 0,128 64 192
+ 5 & 4: missile 2 0, 32 16 48
+ 3 & 2: missile l 0, 8 4 12
+ 1 & 0: missile 0 0, 2 1 3
+
+ where turning on the bits in each each pair above does as follows:
+
+ 0 and 0: normal size -- two color clocks wide
+ 0 and 1: twice normal size -- four color clocks wide
+ 1 and 0: normal size
+ 1 and 1: four times normal size -- eight color clocks wide
+
+ So, to get a double-sized missile 2, you would set BITs 5 and 6, or
+ POKE 53260,48. Each missile can have a size set separately from
+ the other missiles or players when using the GRAF registers.
+ A number of sources, including De Re Atari, say that you can set
+ neither missile sizes nor shapes separately. Here's a routine to
+ show that you can in fact do both:
+
+ 10 POKE 53265,255: REM SHAPE START
+ 15 GR.7
+ 20 POKE 623,1: REM SET PRIORITIES
+ 30 FOR X = 1 TO 25
+ 35 F = 50
+ 40 FOR C = 704 TO 707: POKE C,F + X:
+ F = F + 50: NEXT C: REM COLOURS
+ 45 S = 100
+ 50 FOR P = 53252 TO 53255: POKE P,S
+ + X: S = S + 20: NEXT P : REM SCRE
+ EN POSITIONS
+ 60 NEXT X
+ 70 INPUT A,B: REM MISSILE SIZE AND S
+ HAPES
+ 80 POKE 53260,A: POKE 53265,5
+ 100 GOTO 30
+
+ Here's another example using DMA; GRACTL and DACTL
+ (53277 and 54272; $D0lD and $D400):
+
+ 10 POKE 623,1: POKE 559,54: POKE 542
+ 79, 224: POKE 53277,1
+ 20 FOR N = 53252 TO 53255: POKE N, 1
+ 00 + X: X = X + 10: NEXT N: X = 0
+ 30 INPUT SIZE: POKE 53260, SIZE
+ 40 GOTO 30
+
+ See 54279 ($D407) for more information on P/M graphics.
+
+
+ P0PL
+
+ (R) Player 0 to player collisions. Bit use is:
+
+ Bit 7 6 5 4 3 2 1 0
+ Player ...unused.... 3 2 1 0
+ Decimal ............. 8 4 2 1
+
+
+ 53261 D00D GRAFP0
+
+ (W) Graphics shape for player 0 written directly to the player
+ graphics register. In using these registers, you bypass ANTIC.
+ You only use the GRAFP# registers when you are not using
+ Direct Memory Access (DMA: see GRACTL at 53277). If DMA is
+ enabled, then the graphics registers will be loaded automatically
+ from the area specified by PMBASE (54279; $D407).
+
+ The GRAF registers can only write a single byte to the playfield,
+ but it runs the entire height of the screen. Try this to see:
+
+ 10 POKE 53248, 160: REM SET HORIZONT
+ AL POSITION OF PLAYER 0
+ 20 POKE 704, 245: REM SET PLAYER 0 C
+ OLOUR TO ORANGE
+ 30 POKE 53261, 203: REM BIT PATTERN
+ 11001011
+
+ To remove it, POKE 53261 with zero. The bit order runs from
+ seven to zero, left to right across the TV screen. Each bit set will
+ appear as a vertical line on the screen. A value of 255 means all
+ bits are set, creating a wide vertical line. You can also use the
+ size registers to change the player width. Using the GRAF
+ registers will allow you to use players and missiles for such things
+ as boundaries on game or text fields quite easily.
+
+
+ P1PL
+
+ (R) Player 1 to player collisions.
+
+
+ 53262 D00E GRAFP1
+
+ (W) Graphics for player 1.
+
+
+ P2PL
+
+ (R) Player 2 to player collisions.
+
+
+ 53263 D00F GRAFP2
+
+ (W) Graphics for player 3.
+
+
+ P3PL
+
+ (R) Player 3 to player collisions.
+
+
+ 53264 D010 GRAFP3
+
+ (W) Graphics for player 3.
+
+
+ TRIG0
+
+ (R) Joystick trigger 0 (644). Controller jack one, pin six. For all
+ triggers, zero equals button pressed, one equals not pressed. If
+ BIT 2 of GRACTL (53277; $D01D) is set to one, then all TRIG
+ BITs 0 are latched when the button is pressed (set to zero) and are
+ only reset to one (not pressed) when BIT 2 of GRACTL is reset to
+ zero. The effect of latching the triggers is to return a constant
+ "button pressed" read until reset.
+
+
+ 53265 D011 GRAFM
+
+ (W) Graphics for all missiles, not used with DMA. GRAFM works
+ the same as GRAFP0 above. Each pair of bits represents one
+ missile, with the same allocation as in 53260 ($D00C) above.
+
+ Bit 7 6 5 4 3 2 1 0
+ Missile -3- -2- -1- -0-
+
+ Each bit set will create a vertical line running the entire height of
+ the TV screen. Missile graphics shapes may be set separately
+ from each other by using the appropriate bit pairs. To mask out
+ unwanted players, write zeros to the bits as above.
+
+
+ TRIG1
+
+ (R) Joystick trigger 1 (645). Controller jack two, pin six.
+
+
+ 53266 D012 COLPM0
+
+ (W) Color and luminance of player and missile 0 (704). Missiles
+ share the same colors as their associated players except when
+ joined together to make a fifth player. Then they take on the same
+ value as in location 53733 ($D019; color register 3).
+
+
+ TRIG2
+
+ (R) Joystick trigger 2 (646). Controller jack three, pin six.
+
+
+ 53267 D013 COLPM1
+
+ (W) Color and luminance of player and missile 1 (705).
+
+
+ TRIG3
+
+ (R) Joystick trigger 3 (647). Controller jack four, pin six.
+
+
+ 53268 D014 COLPM2
+
+ (W) Color and luminance of player and missile 2 (706).
+
+
+ PAL
+
+ (R) Used to determine if the Atari is PAL (European and Israeli
+ TV compatible when BITs 1 - 3 equal zero) or NTSC (North
+ American compatible when BITs 1 - 3 equal one; 14 decimal, $E).
+ European Ataris run 12% slower if tied to the VBLANK cycle (the
+ PAL VBLANK cycle is every 50th second rather than every 60th
+ second). They use only one CPU clock at three MHZ, so the 6502
+ runs at 2.217 MHZ -- 25% faster than North American Ataris.
+ Also, their $E000 and $F000 ROMs are different, so there are
+ possible incompatibilities with North American Ataris in the
+ cassette handling routines. There is a third TV standard called
+ SECAM, used in France, the USSR, and parts of Africa. I am
+ unaware if there is any Atari support for SECAM standards.
+
+ PAL TV has more scan lines per frame, 312 compared to 262.
+ NTSC Ataris compensate by adding extra lines at the beginning
+ of the VBLANK routine. Display lists do not have to be altered,
+ and colors are the same because of a hardware modification.
+
+
+ 53269 D015 COLPM3
+
+ Color and luminance of player and missile 3 (707).
+
+
+ 53270 D016 COLPF0
+
+ Color and luminance of playfield zero (708).
+
+
+ 53271 D017 COLPF1
+
+ Color and luminance of playfield one (709).
+
+
+ 53272 D018 COLPF2
+
+ Color and luminance of playfield two (710).
+
+
+ 53273 D019 COLPF3
+
+ Color and luminance of playfield three (711).
+
+
+ 53274 D01A COLBK
+
+ Color and luminance of the background (BAK).(712).
+
+
+ 53275 D01B PRIOR
+
+ (W) Priority selection register. PRIOR establishes which objects
+ on the screen (players, missiles, and playfields) will be in front of
+ other objects. Values used in this register are also described at
+ location 623 ($26F), the shadow register. If you use conflicting
+ priorities, objects whose priorities are in conflict will turn black
+ in their overlap region.
+
+ Priority order
+ (Decimal values in brackets):
+
+ Bit 0 = 1 (1): Bit 1 = 1 (2):
+ Player 0 Player 0
+ Player 1 Player 1
+ Player 2 Playfield 0
+ Player 3 Playfield 1
+ Playfield 0 Playfield 2
+ Playfield 1 Playfield 3 and Player 5
+ Playfield 2 Player 2
+ Playfield 3 and Player 5 Player 3
+ Background Background
+
+ Bit 2 = 1 (4): Bit 3 = 1 (8):
+ Playfield 0 Playfield 0
+ Playfield 1 Playfield 1
+ Playfield 2 Player 0
+ Playfield 3 and Player 5 Player 1
+ Player 0 Player 2
+ Player 1 Player 3
+ Player 2 Playfield 2
+ Player 3 Playfield 3 and Player 5
+ Background Background
+
+ Bit 4 = 1: Enable a fifth player out of the four missiles.
+
+ Bit 5 = 1: Overlap of players 0 and 1, 2 and 3 is third color (else
+ overlap is black). The resulting color is a logical OR of the two
+ player colors.
+
+ Bits 6 and 7 are used to select GTIA modes:
+ 0 0 = no GTIA modes
+ 0 1 = GTIA GR.9
+ 1 0 = GTIA GR.10
+ 1 1 = GTIA GR.11
+
+
+ 53276 D01C VDELAY
+
+ (W) Vertical delay register. Used to give one-line resolution
+ movement capability in the vertical positioning of an object when
+ the two line resolution display is enabled. Setting a bit in
+ VDELAY to one moves the corresponding object down by one TV
+ line. If DMA is enabled, then moving an object by more than one
+ line is accomplished by moving bits in the memory map instead.
+
+ Bit Decimal Object
+ 7 128 Player 3
+ 6 64 Player 2
+ 5 32 Player 1
+ 4 16 Player 0
+ 3 8 Missile 3
+ 2 4 Missile 2
+ 1 2 Missile 1
+ 0 1 Missile 0
+
+
+ 53277 D01D GRACTL
+
+ (W) Used with DMACTL (location 54272; $D400) to latch all stick
+ and paddle triggers (to remember if triggers on joysticks or
+ paddles have been pressed), to turn on players and to turn on
+ missiles. To get the values to be POKEd here, add the following
+ options together for the desired function:
+
+ Decimal Bit
+ To turn on missiles 1 0
+ To turn on players 2 1
+ To latch trigger inputs 4 2
+
+ To revoke P/M authorization and turn off both players and
+ missiles, POKE 53277,0. Once latched, triggers will give a
+ continuous "button pressed" read the first time they are pressed
+ until BIT 2 is restored to zero. Triggers are placed in "latched"
+ mode when each individual trigger is pressed, but you cannot set
+ the latch mode for individual triggers.
+
+ Have you ever hit BREAK during a program and still had players
+ or their residue left on the screen? Sometimes hitting RESET
+ doesn't clear this material from the screen. There are ways to get
+ rid of it:
+
+ POKE 623,4: This moves all players behind playfields.
+ POKE 53277,0: This should turn them off.
+ POKE 559,2: This should return you to a blank screen.
+
+ Make sure you SAVE your program before POKEing, just in
+ case!
+
+
+ 53278 D01E HITCLR
+
+ (W) POKE with any number to clear all player/missile collision
+ registers. It is important to clear this register often in a program
+ -- such as a game -- which frequently tests for collisions.
+ Otherwise, old collision values may remain and confuse the
+ program. A good way to do this is to POKE HITCLR just before
+ an event which may lead to a collision; for example, right before
+ a joystick or paddle is "read" to move a player or fire a missile.
+ Then test for a collision immediately after the action has taken
+ place. Remember that multiple collisions cause sums of the
+ collision values to be written to the collision registers; if you do
+ not clear HITCLR often enough, a program checking for
+ individual collisions will be thrown off by these sums.
+
+
+ 53279 D01F CONSOL
+
+ (W/R) Used to see if one of the three yellow console buttons has
+ been pressed (not the RESET button!). To clear the register,
+ POKE CONSOL with eight. POKEing any number from zero to
+ eight will cause a click from the speaker. A FOR-NEXT loop that
+ alternately POKEs CONSOL with eight and zero or just zero,
+ since the OS put in an 8 every 1/60 second, will produce a buzz.
+ Values PEEKed will range from zero to seven according to the
+ following table:
+
+ |Key Value 0 1 2 3 4 5 6 7 |
+ | |
+ +------------------------------------------------------------+
+ | |
+ |OPTION X X X X |
+ |SELECT X X X X |
+ |START X X X X |
+ | |
+ +------------------------------------------------------------+
+ Bits 2 0 0 0 0 1 1 1 1
+ 1 0 0 1 1 0 0 1 1
+ 0 0 1 0 1 0 1 0 1
+
+
+ Where zero means all keys have been pressed, one means
+ OPTION and SELECT have been pressed, etc., to seven, which
+ means no keys have been pressed. CONSOL is updated every
+ stage two VBLANK procedure with the value eight.
+
+ It is possible to use the console speaker to generate different
+ sounds. Here is one idea based on an article in COMPUTE!,
+ August 1981:
+
+ 10 GOSUB 1000
+ 20 TEST = USR(1536)
+ 999 END
+ 1000 FOR LOOP = 0 TO 26: READ BYTE: P
+ OKE 1536 + LOOP, BYTE: NEXT LOOP
+ : RETURN
+ 1010 DATA 104,162,255,169,255,141,31,
+ 208,169
+ 1020 DATA 0,160,240,136,208,253,141,3
+ 1,208,160
+ 1030 DATA 240,136,208,253,202,208,233
+ ,96
+
+ To change the tone, you POKE 1547 and 1555 with a higher or
+ lower value (both are set to 240 above). To change the tone
+ duration, you POKE 1538 with a lower value (it is set to 255 in the
+ routine above). Do these before you do your USR call or alter the
+ DATA statements to permanently change the values in your own
+ program. Turn off DMA (see location 559) to get clearer tones.
+
+ ---------------------------------------------------------------------------
+ Locations 53280 to 53503 ($D020 to $D0FF) are repeats of locations
+ 53248 to 53279 ($D000 to $D01F). You can't use any of the repeated
+ locations; consider them "filler." They maybe used for other purposes
+ in any Atari OS upgrade.
+
+ ---------------------------------------------------------------------------
+ Locations 53504 to 53759 ($D100 to $D1FF) are unused. These loca-
+ tions are not empty; you can PEEK into them and find out what's
+ there. They cannot, however, be user-altered.
+
+ ---------------------------------------------------------------------------
+
+
+ POKEY
+
+ 53760-54015 D200-D2FF
+
+ POKEY is a digital I/O chip that controls the audio frequency and
+ control registers, frequency dividers, poly noise counters, pot
+ (paddle) controllers, the random number generator, keyboard
+ scan, serial port I/O, and the IRQ interrupts.
+
+ The AUDF# (audio frequency) locations are used for the pitch for
+ the corresponding sound channels, while the AUDC# (audio
+ control registers) are the volume and distortion values for those
+ same channels. To POKE sound values, you must first POKE zero
+ into locations 53768 ($D208) and a three into 53775 ($D20F).
+
+ Frequency values can range from zero to 255 ($FF), although the
+ value is increased by the computer by one to range from one to
+ 256. Note that the sum of the volumes should not exceed 32, since
+ volume is controlled by the least four bits. It is set from zero as no
+ volume to 15 ($F) as the highest. A POKE with 16 ($10) forces
+ sound output even if volume is not set (i.e., it pushes the speaker
+ cone out. A tiny "pop" will be heard). The upper four bits control
+ distortion: 192 ($C0) is for pure tone; other values range from 32 to
+ 192. Note that in BASIC, the BREAK key will not turn off the
+ sound; RESET will, however. See De Re Atari and BYTE, April
+ 1982, for more information on sound generation.
+
+ The AUDF registers are also used as the POKEY hardware timers.
+ These are generally used when counting an interval less than one
+ VBLANK. For longer intervals, use the software timers in locations
+ 536 to 545 ($218 to $221). You load the AUDCTL register with the
+ number for the desired clock frequency. You then set the volume
+ to zero in the AUDC register associated with the AUDF register
+ you plan to use as a timer. You load the AUDF register itself with
+ the number of clock intervals you wish to count. Then you load
+ your interrupt routine into memory, and POKE the address into the
+ appropriate timer vector between locations 528 and 533 ($210 and
+ $215). You must set the proper bit(s) in IRQEN and its shadow
+ register POKMSK at location 16 ($10) to enable the interrupt.
+ Finally, you load STIMER with any value to load and start the
+ timer(s). The OS will force a jump to the timer vector and then to
+ your routine when the AUDF register counts down to zero. Timer
+ processing can be preempted by ANTIC's DMA, a DLI, or the
+ VBLANK process.
+
+ POT values are for the paddles, ranging from zero to 240,
+ increasing as the paddle knob is turned counterclockwise, but
+ values less than 40 and greater than 200 represent an area on
+ either edge of the screen that may not be visible on all TV sets or
+ monitors.
+
+
+ 53760 D200 AUDF1
+
+ (W) Audio channel one frequency. This is actually a number (N)
+ used in a "divide by N circuit"; for every N pulses coming in (as set
+ by the POKEY clock), one pulse goes out. As N gets larger, output
+ pulses will decrease, and thus the sound produced will be a lower
+ note. N can be in the range from one to 256; POKEY adds one to
+ the value in the AUDF register. See BYTE, April 1982, for a
+ program to create chords instead of single tones.
+
+
+ POT0
+
+ (R) Pot (paddle) 0 (624); pot is short for potentiometer. Turning the
+ paddle knob clockwise results in decreasing pot values. For
+ machine language use: these pot values are valid only 228 scan
+ lines after the POTGO command or after ALLPOT changes (see
+ 53768; $D208 and 53771; $D20B). POT registers continually count
+ down to zero, decrementing every scan line. They are reset to 228
+ when they reach zero or by the values read from the shadow
+ registers. This makes them useful as system timers. See
+ COMPUTE!, February 1982, for an example of this use.
+
+ The POTGO sequence (see 53771; $D20B) resets the POT
+ registers to zero, then reads them 228 scan lines later. For the fast
+ pot scan, BIT 2 of SKCTL at 53775 ($D20F) must be set.
+
+
+ 53761 D201 AUDC1
+
+ (W) Audio channel one control. Each AUDF register has an
+ associated control register which sets volume and distortion levels.
+ The bit assignment is:
+
+ Bit 7 6 5 4 3 2 1 0
+ Distortion Volume Volume
+ (noise) only level
+ 0 0 0 0 0 0 0 0 Lowest
+ 0 0 1 0 0 0 1
+ etc. to: etc. to:
+ 1 1 1 1 1 1 1 1 Highest
+ (forced
+ output)
+
+ The values for the distortion bits are as follows. The first process is
+ to divide the clock value by the frequency, then mask the output
+ using the polys in the order below. Finally, the result is divided by
+ two.
+
+ Bit
+ 7 6 5
+ 0 0 0 five bit, then 17 bit, polys
+ 0 0 1 five bit poly only
+ 0 1 0 five bit, then four bit, polys
+ 0 1 1 five bit poly only
+ 1 0 0 l7 bit poly only
+ 1 0 1 no poly counters (pure tone)
+ 1 1 0 four bit poly only
+ 1 1 1 no poly counters (pure tone)
+
+ In general, the tones become more regular (a recognizable
+ droning becomes apparent) with fewer and lower value polys
+ masking the output. This is all the more obvious at low frequency
+ ranges. POKE with 160 ($A0) or 224 ($E0) plus the volume for pure
+ tones.
+
+ See De Re Atari and the Hardware Manual for details.
+
+
+ POT1
+
+ (R) Pot 1 register (625).
+
+
+ 53762 D202 AUDF2
+
+ (W) Audio channel two frequency. Also used with AUDF3 to store
+ the 19200 baud rate for SIO.
+
+
+ POT2
+
+ (R) Pot 2 (626).
+
+
+ 53763 D203 AUDC2
+
+ (W) Audio channel two control.
+
+
+ POT3
+
+ (R) Pot 3 (627).
+
+
+ 53764 D204 AUDF3
+
+ (W) Audio channel three frequency. Used with AUDF3 above and
+ with AUDF4 to store the 600 baud rate for SIO.
+
+
+ POT4
+
+ (R) Pot 4 (628).
+
+
+ 53765 D205 AUDC3
+
+ (W) Audio channel three control.
+
+
+ POT5
+
+ (R) Pot 5 (629).
+
+
+ 53766 D206 AUDF4
+
+ (W) Audio channel four frequency.
+
+
+ POT6
+
+ (R) Pot 6 (630).
+
+
+ 53767 D207 AUDC4
+
+ (W) Audio channel four control.
+
+
+ POT7
+
+ (R) Pot 7 (631).
+
+
+ 53768 D208 AUDCTL
+
+ (W) Audio control. To properly initialize the POKEY sound
+ capabilities, POKE AUDCTL with zero and POKE 53775,3
+ ($D20F). These two are the equivalent of the BASIC statement
+ SOUND 0,0,0,0. AUDCTL is the option byte which affects all
+ sound channels. This bit assignment is:
+
+ Bit Description:
+ 7 Makes the 17 bit poly counter into nine bit poly
+ (see below)
+ 6 Clock channel one with 1.79 MHz
+ 5 Clock channel three with 1.79 MHz
+ 4 Join channels two and one (16 bit)
+ 3 Join channels four and three (16 bit)
+ 2 Insert high pass filter into channel one, clocked by channel
+ two
+ 1 Insert high pass filter into channel two, clocked by channel
+ four
+ 0 Switch main clock base from 64 KHz to 15 KHz
+
+ Poly (polynomial) counters are used as a source of random pulses
+ for noise generation. There are three polys: four, five and 17 bits
+ long. The shorter polys create repeatable sound patterns, while the
+ longer poly has no apparent repetition. Therefore, setting BIT 7
+ above, making the 17-bit into a nine-bit poly will make the pattern
+ in the distortion more evident. You chose which poly(s) to use by
+ setting the high three bits in the AUDC registers. The 17-bit poly is
+ also used in the generation of random numbers; see 53770
+ ($D20A).
+
+ The clock bits allow the user to speed up or slow down the clock
+ timers, respectively, making higher or lower frequency ranges
+ possible. Setting the channels to the 1.79 MHz will produce a
+ much higher sound, the 64 KHz clock will be lower, and the 15
+ KHz clock the lowest. The clock is also used when setting the
+ frequency for the AUDF timers.
+
+ Two bits (three and four) allow the user to combine channels one
+ and two or three and four for what amounts to a nine octave range
+ instead of the usual five. Here's an example from De Re Atari of
+ this increased range, which uses two paddles to change the
+ frequency: the right paddle makes coarse adjustments, the left
+ paddle makes fine adjustments:
+
+ 10 SOUND 0,0,0,0:POKE 53768,80:REM SE
+ T CLOCK AND JOIN CHANNELS 1 AND 2
+ 20 POKE 53761,160:POKE 53763,168:REM
+ TURN OFF CHANNEL 1 AND SET 2 TO PU
+ RE TONE GENERATION
+ 50 POKE 53760,PADDLE(0):POKE 53762,PA
+ DDLE(1):GOTO 30
+
+ High pass filters allow only frequencies higher than the clock value
+ to pass through. These are mostly used for special effects. Try:
+
+ 10 SOUND 0,0,0,0:POKE 53768,4:REM HIG
+ H PASS FILTER ON CHANNEL 1
+ 20 POKE 53761,168:POKE 53765,168:REM
+ PURE TONES
+ 30 POKE 53760,254:POKE 53764,127
+ 40 GOTO 40
+
+ See the excellent chapter on sound in De Re Atari: it is the best
+ explanation of sound functions in the Atari available. See also the
+ Hardware Manual for complete details.
+
+
+ ALLPOT
+
+ (R) Eight line pot port state; reads all of the eight POTs together.
+ Each bit represents a pot (paddle) of the same number. If a bit is
+ set to zero, then the register value for that pot is valid (it's in use); if
+ it is one, then the value is not valid. ALLPOT is used with the
+ POTGO command at 53771 ($D20B).
+
+ ----------------------------------------------------------------------
+
+ 53769 D209 STIMER
+
+ (W) Start the POKEY timers (the AUDF registers above). You
+ POKE any non-zero value here to load and start the timers; the
+ value isn't itself used in the calculations. This resets all of the audio
+ frequency dividers to their AUDF values. If enabled by IRQEN
+ below, these AUDF registers generate timer interrupts when they
+ count down from the number you POKEd there to zero. The
+ vectors for the AUDF1, AUDF2 and AUDF4 timer interrupts are
+ located between 528 and 533 ($210 and $215). POKEY timer four
+ interrupt is only enabled in the new "B" OS ROMs.
+
+
+ KBCODE
+
+ (R) Holds the keyboard code which is then loaded into the shadow
+ register (764; $2FC) when a key is hit. Usually read in response to
+ the keyboard interrupt. Compares the value with that in CH1 at
+ 754 ($2F2). If both values are the same, then the new code is
+ accepted only if a suitable key debounce delay time has passed.
+ The routines which test to see if the key code will be accepted start
+ at 65470 ($FFBE). BIT 7 is the control key flag, BIT 6 is the shift key
+ flag.
+
+
+ 53770 D20A SKREST
+
+ (W) Reset BITs 5 - 7 of the serial port status register at 53775 to one.
+
+
+ RANDOM
+
+ (R) When this location is read, it acts as a random number
+ generator. It reads the high order eight bits of the 17 bit
+ polynomial counter (nine bit if BIT 7 of AUDCTL is set) for the
+ value of the number. You can use this location in a program to
+ generate a random integer between zero and 255 by:
+
+ 10 PRINT PEEK(53770)
+
+ This is a more elegant solution than INT(RND(0) * 256). For a test of
+ the values in this register, use this simple program:
+
+ 10 FOR N = 1 TO 20: PRINT PEEK(53770): NEXT N
+
+
+ 53771 D20B POTGO
+
+ (W) Start the POT scan sequence. You must read your POT values
+ first and then start the scan sequence, since POTGO resets the
+ POT registers to zero. Written by the stage two VBLANK
+ sequence.
+
+
+ 53772 D20C ....
+
+ Unused.
+
+
+ 53773 D20D SEROUT
+
+ (W) Serial port data output. Usually written to in the event of a
+ serial data out interrupt. Writes to the eight bit (one byte) parallel
+ holding register that is transferred to the serial shift register when a
+ full byte of data has been transmitted. This "holding" register is
+ used to contain the bits to be transmitted one at a time (serially) as
+ a one-byte unit before transmission.
+
+
+ SERIN
+
+ (R) Serial port input. Reads the one-byte parallel holding register
+ that is loaded when a full byte of serial input data has been
+ received. As above, this holding register is used to hold the bits as
+ they are received one bit at a time until a full byte is received. This
+ byte is then taken by the computer for processing. Also used to
+ verify the checksum value at location 49 ($31).
+
+ The serial bus is the port on the Atari into which you plug your
+ cassette or disk cable. For the pin values of this port, see the OS
+ User's Manual, p. 133, and the Hardware Manual.
+
+
+ 53774 D20E IRQEN
+
+ (W) Interrupt request enable. Zero turns off all interrupt requests
+ such as the BREAK key; to disable or re-enable interrupts, POKE
+ with the values according to the following chart (setting a bit to one
+ -- i.e., true -- enables that interrupt; decimal values are also
+ shown for each bit):
+
+ Bit Decimal Interrupt Vector
+ 0 1 Timer 1 (counted down to zero) VTIMR1
+ (528; $210)
+ 1 2 Timer 2 (counted down to zero) VTIMR2
+ (530; $212)
+ 2 4 Timer 4 (counted down to zero) VTIMR4
+ (532; $214), OS
+ "B" ROMs only)
+ 3 8 Serial output transmission done VSEROC (526;
+ $20E)
+ 4 16 Serial output data needed VSEROR
+ (524; $20C)
+ 5 32 Serial input data ready VSERIN
+ (522; $20A)
+ 6 64 Other key pressed VKEYBD
+ (520; $208)
+ 7 128 BREAK key pressed see below
+
+ Here is the procedure for the BREAK key interrupt: clear the
+ interrupt register. Set BRKKEY (17; $11) to zero; clear the
+ start/stop flag SSFLAG at 767 ($2FF); clear the cursor inhibit flag
+ CRSINH at 752 ($2F0); clear the attract mode flag at 77 ($4D), and
+ return from the interrupt after restoring the 6502 A register. (There
+ is now (in the OS "B" ROMs) a proper vector for BREAK key
+ interrupts at 566, 567 ($236, $237) which is initialized to point to
+ 59220 ($E754).) If the interrupt was due to a serial I/O bus proceed
+ line interrupt, then vector through VPRCED at 514 ($202). If due to
+ a serial I/O bus interrupt line interrupt, then vector through
+ VINTER at 516 ($204). If due to a 6502 BRK instruction, then vector
+ through VBREAK at 518 ($206).
+
+ Timers relate to audio dividers of the same number (an interrupt is
+ processed when the dividers count down to zero). These bits in
+ IRQEN are not set on powerup and must be initiated by the user
+ program before enabling the processor IRQ.
+ There are two other interrupts, processed by PIA, generated over
+ the serial bus Proceed and Interrupt lines, set by the bits in the
+ PACTL and PBCTL registers (54018 and 54019; $D302, $D303):
+
+ Bit Decimal Locution Interrupt
+ 0 1 PACTL Peripheral A (PORTA) interrupt enable
+ bit.
+ 7 128 PACTL Peripheral A interrupt status bit.
+ 0 1 PBCTL Peripheral B (PORTB) interrupt enable
+ bit.
+ 7 128 PBCTL Peripheral B interrupt status bit.
+
+ The latter PORT interrupts are automatically disabled on powerup.
+ Only the BREAK key and data key interrupts are enabled on
+ powerup. The shadow register is 16 ($10).
+
+
+ IRQST
+
+ (R) Interrupt request status. Bit functions are the same as IRQEN
+ except that they register the interrupt request when it is zero rather
+ than the enable when a bit equals one. IRQST is used to determine
+ the cause of interrupt request with IRQEN, PACTL and PBCTL as
+ above.
+
+ All IRQ interrupts are normally vectored through 65534 ($FFFE) to
+ the IRQ service routine at 59123 ($E6F3), which determines the
+ cause of the interrupt. The IRQ global RAM vector VIMIRQ at 534
+ ($216) ordinarily points to the IRQ processor at 59126 ($E6F6). The
+ processor then examines 53774 ($D20E) and the PIA registers at
+ 54018 and 54019 to determine the interrupt cause. Once
+ determined, the routine vectors through one of the IRQ RAM
+ vectors in locations 514 to 526 ($202 to $20E). For Non-Maskable
+ Interrupts (NMI's), see locations 54286 to 54287 ($D40E; $D40F).
+ See the OS User's Manual for complete details.
+
+
+ 53775 D20F SKCTL
+
+ (W) Serial port control. Holds the value 255 ($255) if no key is
+ pressed, 251 ($FB) for most other keys pressed, 247 ($F7) for
+ SHIFT key pressed (*M). See the (R) mode below for an
+ explanation of the bit functions. POKE with three to stop the
+ occasional noise from cassette after I/O to bring POKEY out of the
+ two-tone mode. (562).
+
+
+ SKSTAT
+
+ (R) Beads the serial port status. It also returns values governed by
+ a signal on the digital track of the cassette tape. You can generate
+ certain values using the SOUND command in BASIC and a PEEK
+ to SKSTAT:
+
+ SOUND 0,5,10,15 returns a value to here of 255 (or, on
+ occasion, 127).
+ SOUND 0,8,10,3 returns a value of 239.
+
+ This is handy for adding a voice track to Atari tapes. You use the
+ left channel for your voice track and the right for the tone(s) you
+ want to use as cuing marks. You can use the speaker on your TV to
+ generate the tones by placing the right microphone directly in
+ front of the speaker. The computer will register these tones in this
+ register when it encounters them during a later cassette load. See
+ COMPUTE!, July 1981, for some other suggestions on doing this.
+ Bemember, you can turn the cassette off by POKEing 54018
+ ($D302) with 60 ($3C) and back on with 52 ($34).
+
+ Bits in the SKCTL (W) register are normally zero and perform the
+ functions below when set to one. The status when used as (R) is
+ listed below the write (W) function:
+
+ Bit Function
+ 0 (W) Enable keyboard debounce circuits.
+ (R) Not used by SKSTAT.
+ 1 (W) Enable keyboard scanning circuit.
+ (R) Serial input shift register busy.
+ 2 (W) Fast pot scan: the pot scan counter completes its
+ sequence in two TV line times instead of one frame time (228
+ scan lines). Not as accurate as the normal pot scan,
+ however.
+ (R) the last key is still pressed.
+ 3 (W) Serial output is transmitted as a two-tone signal rather
+ than a logic true/false. POKEY two-tone mode.
+ (R) The shift key is pressed.
+ 4,5,6 (W) Serial port mode control used to set the bi-directional
+ clock lines so that you can either receive external clock data
+ or provide clock data to external devices (see the Hardware
+ Manual, p. II.27). There are two pins on the serial port for
+ Clock IN and Clock OUT data. See the OS User's Manual,
+ p. 133.
+ 4 (R) Data can be read directly from the serial input port,
+ ignoring the shift register.
+ 5 (R) Keyboard over-run. Reset BITs 7 to 5 (latches) to one
+ using SKRES at 53770 ($D20A).
+ 6 (R) Serial data input over-run. Reset latches as above.
+ 7 (W) Force break (serial output to zero).
+ (R) Serial data input frame error caused by missing or extra
+ bits. Beset latches as above.
+
+ BIT 2 is first set to zero to reset POT registers to zero (dumping the
+ capacitors used to change the POT registers). Then BIT 2 is set to
+ one to enable the fast scan. Fast scan is not as accurate as the
+ normal scan routine. BIT 2 must be reset to zero to enable the
+ normal scan mode; otherwise, the capacitors will never dump.
+
+ ---------------------------------------------------------------------------
+ Locations 53776 to 54015 ($D210 to $D2FF) are duplications of locations
+ 53760 to 53775 and have no particular use at present.
+
+ ---------------------------------------------------------------------------
+
+
+ PIA: 6520 CHIP
+
+ 54016-54271 D300-D3FF
+
+ The Peripheral Interface Adapter (PIA) integrated circuit is a
+ special microprocessor used to control the Atari ports, controller
+ jacks one to four. Ports can be used for both input and output
+ simultaneously or alternately. Barely tapped at the time of this
+ writing, the ports represent a major resource for external (and
+ internal) control and expansion. PIA also processes two of the IRQ
+ interrupts: VINTER and VPRCED, vectored at locations 514 to 517
+ ($202 to $205). These interrupts are unused by the OS, but also
+ may be used to provide greater control over external devices.
+
+
+ 54016 D300 PORTA
+
+ (W/R) Reads or writes data from controller jacks one and two if BIT
+ 2 of PACTL (location 54018) is one. Writes to direction control if
+ BIT 2 of PACTL is zero.
+
+ These two port registers also control the direction of data flow to
+ the port, if the controller register (54018, below) is POKEd with 48
+ ($30). Then, if the bits in the register read zero, it is in input (R)
+ mode; if they read one, it is in output (W) mode. A zero POKEd
+ here makes all bits input, a 255 ($FF) makes all bits output. BITs 0
+ to 3 address pins one to four on jack one, BITs 4 to 7 address pins
+ one to four on jack two. POKE 54018 with 52 to make this location
+ into a data register again. Shadow registers are: STICK0 (632;
+ $278, jack one), STICK1 (633; $279, jack two) and PTRIG0-3
+ (636-639; $27C-$27F).
+
+ Bits used as data register
+ 7 6 5 4 3 2 1 0
+ --Jack 0-- --Jack 1--
+ --Stick 1-- --Stick 0--
+
+ Forward = BIT 0, 4 = 1
+ Backward = BIT 1, 5 = 1
+ Left = BIT 2,6 = 1
+ Right = BIT 3,7 = 1
+ Neutral = All four jack bits = 1
+
+ PORTA is also used to test if the paddle 0-3 triggers (PTRIG) have
+ been pressed, using these bits:
+
+ Bit 7 6 5 4 3 2 1 0
+ PTRIG 3 2 - - 1 0 - -
+
+ Where zero in the appropriate bit equals trigger pressed, one
+ equals trigger not pressed.
+
+ The PORT registers are also used in the keyboard controller (used
+ with a keypad) operation where:
+
+ Bit 7 6 5 4 3 2 1 0
+ Row 4 3 2 Top 4 3 2 Top
+ Jack ..........2.......... ..........1...........
+
+ Columns for the keyboard operation are read through the POT
+ (PADDL) and TRIG registers. See Micro, May 1982, and the
+ Hardware Manual for more information on jacks and ports.
+
+
+ 54017 D301 PORTB
+
+ (W/R) Port B. Reads or writes data to and/or from jacks three and
+ four. Same as PORTA, above, for the respective jacks. Shadow
+ registers are: STICK2 (634; $27A, jack three), STICK3 (635, $27B,
+ jack four), and PTRIG4-7 (640-643; $280-$283).
+
+
+ 54018 D302 PACTL
+
+ (W/R) Port A controller (see 54016 above). POKE with 60 ($3C) to
+ turn the cassette motor off, POKE with 52 to turn it on. You can put
+ a music cassette in your program recorder, press PLAY and then
+ POKE 54018,52. Your music will play through the TV speaker or
+ external amplifier while you work at the Atari. You can use this
+ technique to add voice tracks to your programs. To turn off the
+ music or voice, type POKE 54018,60.
+
+ PACTL can be used for other external applications by the user. Bit
+ use is as follows:
+
+ Bit Function
+ 7 (read only) Peripheral A interrupt (IRQ) status bit. Set by
+ Peripheral (PORT) A. Reset by reading PORTA
+ (53774; $D20E).
+ 6 Set to zero.
+ 5 Set to one.
+ 4 Set to one.
+ 3 (write) Peripheral motor control line (turn the cassette on
+ or off; zero equals on).
+ 2 (write) Controls PORTA addressing. One equals PORTA
+ register; zero equals direction control register.
+ 1 Set to zero.
+ 0 (write) Peripheral A interrupt (IRQ) enable. One equals
+ enable. Set by the OS but available to the user;
+ reset on powerup.
+
+
+ 54019 D303 PBCTL
+
+ (W/R) Port B controller. Initialized to 60 ($3C) by the OS IRQ
+ code. PBCTL is the same as PACTL, above, with the following
+ exception (this may actually perform the same function as in
+ PACTL, but I am not sure of the distinction between descriptions):
+
+ Bit Function
+ 3 Peripheral command identification (serial bus
+ command), initialized to 60 ($3C).
+
+ Ports can be used for external control applications by the
+ technically minded reader who is willing to do some soldering to
+ develop cables and connectors. A good example can be found in
+ COMPUTE!, February 1981, where the author gives directions for
+ using jacks three and four as a printer port. The Macrotronic
+ printer cables use just this method, bypassing the 830 interface
+ entirely (one way of reducing your hardware costs). Theoretically,
+ the entire Atari can be controlled through the ports!
+
+ ---------------------------------------------------------------------------
+ Locations 54020 to 54271 ($D304 to $D3FF) are repeats of locations
+ 54016 to 54019 ($D300 to $D303).
+
+ ---------------------------------------------------------------------------
+
+
+ ANTIC
+
+ 54272-54783 D400-D5FF
+
+ ANTIC is a special, separate microprocessor used in your Atari
+ to control C/GTIA, the screen display, and other screen-related
+ functions including processing the NMI interrupts. It uses its own
+ instruction set, called the display list, which tells ANTIC where to
+ find the screen data in RAM and how to display it. ANTIC also
+ uses an internal four bit counter called the Delta Counter (DCTR)
+ to control the vertical dimension of each block.
+
+
+ 54272 D400 DMACTL
+
+ (W) Direct Memory Access (DMA) control. It is also used to
+ define one- or two-line resolution for players and to turn on
+ players and missiles. Values are POKEd into the shadow register,
+ 559 ($22F), and are also described there. You POKE the shadow
+ register with the following numbers in order to:
+
+ Turn off the playfield 0
+ Use narrow playfield 1
+ Use normal playfield 2
+ Use wide playfield 3
+ Enable missile DMA 4
+ Enable player DMA 8
+ Enable both player and missile DMA 12
+ Single line player resolution 16
+ Enable DMA Fetch instructions 32
+
+ Double line resolution is the default status. Use this register in
+ conjunction with GRACTL at 53277 ($D01D). Both must be set
+ properly or no display will result. BIT 5 enables DMA to fetch the
+ display list instructions. If BIT 5 is not set (BIT 5 equals zero),
+ ANTIC will not work. DMACTL is initialized to 34 ($22).
+ A player in single line resolution might look like this:
+
+ 00011000 ##
+ 00111100 ####
+ 01111110 ######
+ 11111111 ########
+ 11111111 ########
+ 01111110 ######
+ 00111100 ####
+ 00011000 ##
+
+ so that each byte is displayed on one TV line. The same player in
+ double line resolution would look like this:
+
+ 00011000 ##
+ 00011000 ##
+ 00111100 ####
+ 00111100 ####
+ 01111110 ######
+ 01111110 ######
+ 11111111 ########
+ 11111111 ########
+ 11111111 ########
+ 11111111 ########
+ 01111110 ######
+ 01111110 ######
+ 00111100 ####
+ 00111100 ####
+ 00011000 ##
+ 00011000 ##
+
+ where every byte is displayed over two TV lines.
+
+
+ 54273 D401 CHACTL
+
+ (W) Character mode control. See shadow register 755 for values
+ that can be POKEd in. Only the least three bits (decimal zero to
+ seven) are read, as below:
+
+ Decimal 0 1 2 3 4 5 6 7
+ Cursor
+ Transparent X X X X
+ Opaque X X X X
+ Present X X X X
+ Absent X X X X
+ ----------------------------------------------------------------------
+ Characters
+ Normal X X X X
+ Inverted X X X X
+
+
+ 54274,5 D402,3 DLISTL/H
+
+ Display list pointer. Tells the OS the address of the display list
+ instructions about what screen mode(s) to display and where to
+ find the screen data. See SDLIST (560, 561; $230, $231).
+
+
+ 54276 D404 HSCROL
+
+ (W) Horizontal scroll enable, POKE HSCROL with from zero to
+ 16 clock cycles for the number of cycles to scroll. Horizontal fine
+ scrolls can be used only if BIT 4 of the display list instruction is
+ set. The difficulty in horizontal scrolling lies in arranging the
+ screen data to be scrolled in such a manner as to prevent
+ wraparound (i.e., the bit or byte scrolled off screen in one line
+ becomes the bit or byte scrolled on screen in an adjacent line).
+ Normal data arranged for TV display looks like this on the screen:
+
+ +----------+
+ |..........|
+ |..........|
+ |..........|
+ |..........|
+ |..........|
+ |..........|
+ +----------+
+
+ where it is a one-dimensional memory area "folded" at the proper
+ places to create the image of a two dimensional screen. This is
+ done by the DL character or map mode instruction. Without
+ other instructions, it reads the memory continuously from the first
+ specified location, each line taking the correct number of bytes
+ for the GRAPHICS mode specified. To properly scroll it
+ horizontally, you must arrange it in relation to the TV screen like
+ this:
+
+ +----------+
+ .....|..........|.....
+ .....|..........|.....
+ .....|..........|.....
+ .....|..........|.....
+ .....|..........|.....
+ .....|..........|.....
+ +----------+
+
+ Now you will have to make each display instruction for each line
+ into a Load Memory Scan (LMS) instruction. To direct each LMS
+ to the proper screen RAM for that line, you will have to increment
+ each memory location by the total length of the line. For
+ example, if you want to scroll a 256-byte horizontal screen, each
+ LMS instruction will have to point to a location in memory 256
+ bytes above the last one. Of course, you will have to implement
+ error-trapping routines so that your screen does not extend
+ beyond your desired boundaries.
+
+ Coarse scrolling, one byte at a time, can be done without setting
+ the HSCROL register by the method described above. For
+ smooth scrolling, you will have to use this register. See De Re
+ Atari.
+
+
+ 54277 D405 VSCROL
+
+ (W) Vertical scroll enable, POKE VSCROL with from zero to 16
+ scan lines, depending on the GRAPHICS mode of the screen for
+ the number of scan lines to scroll. Vertical fine scrolls can be
+ used only if BIT 5 of the display list instruction has been set.
+
+ Coarse scrolling can be done without using this register, simply
+ by moving the top of the screen address (as defined by the DL
+ LMS instruction) up or down one mode line (plus or minus 40 or
+ 20 bytes, depending on the GRAPHICS mode). The top of the
+ screen address can be found by:
+
+ 10 DLIST = PEEK(560) + PEEK(561) * 2
+ 56
+ 20 SCRNLO = DLIST + 4: SCRNHI = DLIS
+ T + 5: REM LSB/MSB OF SCREEN ADDRE
+ SS
+ 25 PRINT "SCREEN ADDRESS = " PEEK(SC
+ RNLO) + PEEK(SCRNHI) * 256
+
+ You could then add a routine to this for a coarse - scroll vertically
+ through the memory with a joystick, such as:
+
+ 30 LOBYTE = 0: HIBYTE = 0
+ 40 IF STICK(0) = 14 THEN LOBYTE = LO
+ BYTE + 40:GOTO 100
+ 50 IF STICK(0) = 13 THEN LOBYTE = LO
+ BYTE - 40
+ 60 IF LOBYTE < 0 THEN LOBYTE = LOBYT
+ E + 256: HIBYTE = HIBYTE - 1
+ 70 IF HIBYTE < 0 THEN HIBYTE = 0
+ 80 GOTO 200
+ 100 IF LOBYTE 255 THEN LOBYTE = LOB
+ YTE - 256
+ 110 HIBYTE = HIBYTE + 1
+ 200 POKE SCRNLOW, LOBYTE: POKE SCRNHI
+ , HIBYTE
+ 210 GOTO 40
+
+ DOWNLOAD VSCROL.BAS
+
+ Coarse scrolling is relatively easy to implement in the Atari: one
+ basically alters the screen RAM to display the new material. Fine
+ scrolling is more difficult: each scroll register must be POKEd
+ with the number of units to be scrolled -- color clocks or scan
+ lines -- and the corresponding display list instructions must have
+ the proper bits set. This means you can selectively fine scroll any
+ mode lines you wish by setting only those bits of the lines you
+ intend to scroll. Other lines will be displayed normally. You can
+ set a DL instruction for both horizontal and vertical scroll enable.
+ See the Hardware Manual for a discussion of the problems in fine
+ scrolling.
+
+ Fine scrolling will allow only a certain amount of data to be
+ scrolled before the register must be reset (16 clock bits or scan
+ lines maximum). In order to make the scrolling activity
+ continuous, the register involved must be reset to zero when the
+ desired value is reached, a coarse scroll must be implemented
+ (usually during a DLI or VBLANK interval) and a new fine scroll
+ begun. This is not easily done in BASIC since it is too slow, and
+ changing registers during ANTIC's display process usually
+ causes rough or jerky motion. Assembly routines are suggested
+ for smooth display. See De Re Atari, Micro, November 1981,
+ BYTE, January 1982, and Santa Cruz's Tricky Tutorial #2 for
+ more information.
+
+
+ 54278 D406 ....
+
+ Unused.
+
+
+ 54279 D407 PMBASE
+
+ (W) MSB of the player/missile base address used to locate the
+ graphics for your players and missiles (the address equals
+ PMBASE * 256. P/M graphics are tricky to use since there are no
+ direct Atari 8K BASIC commands to either create or move them
+ (there are, however, commands for P/M graphics in BASIC A+
+ and in valFORTH utilities).
+
+ Your P/M graphics must always begin on a 1K boundary
+ (PEEK(RAMTOP)-4 for double line resolution players) or 2K
+ boundary (PEEK(RAMTOP)-5 for single line resolution), so the
+ LSB is always zero (page numbers always end in $XX00). For
+ example:
+
+ 10 POKE 106, PEEK(106) - 8: GRAPHIC
+ S 8: SETCOLOR 2,3,4
+ 20 POKE 559,62: POKE 53248,100: POK
+ E 704,160: POKE 53256,2
+ 30 MEM = PEEK(106) - 8
+ 40 POKE 54279, MEM: POKE 53277,3: S
+ TART = MEM * 256 + 1024
+ 50 FOR LOOP = 100 TO 119: READ BYTE
+ : POKE START + LOOP, BYTE: NEXT LO
+ OP
+ 60 DATA 16,16,56,40,40,56,40,40,40
+ 70 DATA 124,84,124,84,254,146,254,1
+ 70,170,68
+ 100 END
+
+ You can change the color, width, resolution, and horizontal
+ position of the player in the example by altering the registers
+ used above.
+
+ Each player is one byte (eight bits) wide. Single line resolution
+ P/M characters (POKE 559,62) can be up to 256 bytes high.
+ Double line resolution P/M characters (POKE 559,46) can be up
+ to 128 bytes high. In either case, they can map to the height of the
+ screen. Missiles have the same height, but are only two bits wide
+ each. Four missiles can be combined into a fifth player by setting
+ BIT 4 of location 623 ($26F). You need not fill the entire height of
+ a P/M character, but you should POKE unused bytes with zero to
+ eliminate any screen garbage. You can do this by:
+
+ FOR N = PMBASE + 1024 TO PMBASE + 2048:
+ POKE N,0: NEXT N
+
+ where PMBASE is the starting address of the reserve memory
+ area. In double line resolution, change the loop value to N =
+ PMBASE + 512 TO PMBASE + 1024. Here's a short machine
+ language routine to do the same thing. You would put the start
+ address of the area to be loaded with zero and the number of
+ bytes to be cleared in with the USR call as the first two
+ parameters. In this example, I have arbitrarily chosen 38012 and
+ 2048 for these values.
+
+ 10 START = 38012: BYTE = 2048: DIM
+ PGM$(42)
+ 20 FOR LOOP = 1 TO 42: READ ML: PGM
+ $(LOOP, LOOP) = CHR$(ML): NEXT LOO
+ P
+ 30 DATA 104,104,133,204,104,133,203
+ ,104,133,206,104
+ 40 DATA 133,205,166,206,160,0,169,0
+ ,145,203,136
+ 50 DATA 208,251,230,204,202,48,6,20
+ 8,244,164
+ 60 DATA 205,208,240,198,204,160,0,1
+ 45,203,96
+ 70 A = USR(ADR(PGM$),START,BYTE)
+
+ You can use this routine to clear out memory anywhere in the
+ Atari. You can also use it to load any one value into memory by
+ changing the second zero (after the 169) in line 40 to the value
+ desired.
+
+ Locating your graphics tables at the high end of memory may
+ cause addressing problems for playfield graphics, or may leave
+ some of the display unusable and cause PLOT to malfunction. If
+ you locate your tables just before the screen display, it may be
+ erased if you change graphics modes. You can look at your
+ highest RAM use graphics statement and plan accordingly. To
+ calculate a safe starting address below the display list, try:
+
+ 100 DLIST = PEEK(560) + PEEK(561) * 256: PMBASE =
+ INT (DLIST/SIZE -1) * SIZE
+
+ where SIZE is 2048 for single line resolution, 1024 for double
+ line.
+
+ Once you have the starting address, determine the ending
+ address of your table by adding the correct number of bytes for
+ the size (same as the SIZE variable above), and POKE this
+ number (LSB/MSB) into APPMHI at locations 14 and 15 ($E, $F).
+ This sets the lower limit for playfield graphics memory use. If you
+ change graphics modes in the program now, it should leave your
+ player tables intact. For example, if the DL is at 39968, the
+ PMBASE will equal 36864 in the equation above. Add 2048
+ (single line resolution) to get 38912. This is $9800. In decimal,
+ the LSB is zero and the MSB is 152. POKE these values into
+ APPMHI. This sets the lowest limit to which the screen and DL
+ data may descend.
+
+ The unused portion of the RAM set aside for P/M use, or any
+ RAM reserved for players, but not used, may be used for other
+ purposes in your program such as machine language routines.
+ See the appendix for a map of P/M memory use. The register
+ stores the address as below:
+
+ Bit 7 6 5 4 3 2 1 0
+ One line resolution: ......MSB....... ...unused...
+ Two line resolution: ........MSB......... unused..
+
+ There are some restrictions on locating your P/M data above the
+ display list. If not positioned far enough above your screen data,
+ you may end up with both the normal and screen data being
+ displayed at once, resulting in garbage on the screen. A display
+ list may not cross a 1K boundary without a jump instruction, and
+ the screen display RAM cannot cross a 4K boundary without an
+ LMS instruction to point to the proper byte(s). Due to problems
+ that arise when moving the GR.7 and GR.8 screens and data less
+ than 4K, you should never reserve less than 16 pages above
+ RAMTOP in these modes. If you are reserving more, add the
+ pages in blocks of 4K (16 pages).
+ See COMPUTE!, September 1981, for a discussion of the
+ problems of positioning P/M graphics in memory, and using P/M
+ graphics for animation.
+ See De Re Atari, COMPUTE!, June 1982, and Creative
+ Computing, April 1982, for a discussion of using string
+ manipulation with P/M graphics. See Your Atari 400/800 for a
+ general discussion of P/M graphics. Most of the popular
+ magazines have also carried articles on simplifying P/M
+ graphics.
+
+
+ 54280 D408 ....
+
+ Unused.
+
+
+ 54281 D409 CHBASE
+
+ (W) Character base address; the location of the start of the
+ character set, either the standard Atari set or a user-designed set.
+ The default is 224 ($E0), which points to the start of the Atari
+ ROM character set. Iridis, a short-lived disk -and- documentation
+ magazine, produced a good utility called FontEdit to aid in the
+ design of altered character sets. Online Systems' program The
+ Next Step is also very useful for this purpose, as is COMPUTE!'s
+ "SuperFont," January 1982. Uses shadow register 756 ($2F4).
+ Normally, this points to location 57344 or 57856 ($E000 or $E200)
+ depending on your choice of characters used in which text mode.
+ GRAPHICS mode zero uses the entire 128-character set; GR.1
+ and GR.2 use only half the set (64 characters). You POKE a
+ different number into the shadow register at 756 ($2F4) to point to
+ your own character set in RAM. This must be an even number
+ that points to a page in memory that is evenly divisible by two. In
+ GR.1 and GR.2 this number is 224 (pointing to $E000), giving
+ you uppercase, punctuation and numbers. POKEing the shadow
+ or this location (in machine language) with 226 will give you
+ lowercase and control characters.
+ See the information about the ROM character set at 57344
+ ($E000).
+
+
+ 54282 D40A WSYNC
+
+ (W) Wait for horizontal synchronization. Allows the OS to
+ synchronize the vertical TV display by causing the 6502 to halt
+ and restart seven machine cycles before the beginning of the
+ next TV line. It is used to synchronize the VBI's or DLI's with the
+ screen display.
+ To see the effect of the WSYNC register, type in the second
+ example of a Display List Interrupt at location 512. RUN it and
+ observe that it causes a clean separation of the colors at the
+ change boundary. Now change line 50 to:
+
+ 50 DATA 72,169,222,234,234,234,141,24,208,104,64
+
+ This eliminates the WSYNC command. RUN it and see the
+ difference in the boundary line.
+
+ The keyboard handler sets WSYNC repeatedly while generating
+ the keyboard click on the console speaker at 53279 ($D01F).
+ When interrupts are generated during the WSYNC period, they
+ get delayed by one scan line. To bypass this, examine the
+ VCOUNT register below and delay the interrupt processing by
+ one line when no WSYNC delay has occurred.
+
+
+ 54283 D40B VCOUNT
+
+ (R) Vertical line counter. Used to keep track of which line is
+ currently being generated on the screen. Used during Display
+ List Interrupts to change color or graphics modes. PEEKing here
+ returns the line count divided by two, ranging from zero to 130
+ ($82; zero to 155 on the PAL system; see 53268; $D014) for the
+ 262 lines per TV frame.
+
+
+ 54284 D40C PENH
+
+ (R) Light pen horizontal position (564). Holds the horizontal color
+ clock count when the pen trigger is pressed.
+
+
+ 54285 D40D PENV
+
+ (R) Light pen vertical position (565). Holds the VCOUNT value
+ (above) when the pen trigger is pressed. See the Hardware
+ Manual, p. II-32, for a description of light pen operation.
+
+
+ 54286 D40E NMIEN
+
+ (W) Non-maskable interrupt (NMI) enable. POKE with 192 to
+ enable the Display List Interrupts. When BIT 7 is set to one, it
+ means DL instruction interrupt; any display list instruction where
+ BIT 7 equals one will cause this interrupt to be enabled at the
+ start of the last video line displayed by that instruction. When BIT
+ 6 equals one, it allows the Vertical Blank Interrupt and when BIT
+ 5 equals one, it allows the RESET button interrupt. The RESET
+ interrupt is never disabled by the OS. You should never press
+ RESET during powerup since it will be acted upon.
+
+ NMIEN is set to 64 ($40) by the OS IRQ code on powerup,
+ enabling VBI's, but disabling DLI's. All NMI interrupts are
+ vectored through 65530 ($FFFA) to the NMI service routine at
+ 59316 ($E7B4) to determine their cause.
+
+ Bit 7 6 5 4 3 2 1 0
+ Interrupt: DLI VBI RESET .... unused .....
+
+
+ 54287 D40F NMIRES
+
+ (W) Reset for NMIST (below); clears the interrupt request
+ register; resets all of the NMI status together.
+
+
+ NMIST
+
+ (R) NMI status; holds cause for the NMI interrupt in BITs 5, 6 and
+ 7; corresponding to the same bits in NMIEN above. If a DLI is
+ pending, a jump is made through the global RAM vector
+ VDSLST (512; $200). The OS doesn't use DLI's, so 512 is
+ initialized to point to an RTI instruction and must be changed by
+ the user before a DLI is allowed.
+
+ If the interrupt is not a DLI, then a test is made to see if the
+ interrupt was caused by pressing RESET key and, if so, a jump is
+ made to 58484 ($E474). If not a RESET interrupt, then the system
+ assumes the interrupt was a VBLANK interrupt, and a jump is
+ made through VVBLKI at 546 ($222), which normally points to
+ the stage one VBLANK processor. From there it checks the flag at
+ CRITIC (66; $42) and, if not from a critical section, jumps
+ through VVBLKD at 548 ($224), which normally points to the
+ VBLANK exit routine. On powerup, the VBLANK interrupts are
+ enabled while the display list interrupts are disabled. See the end
+ of the memory map for a description of the VBLANK procedures.
+ For IRQ interrupts, see location 53744 ($D20E).
+
+ ---------------------------------------------------------------------------
+ Locations 54288 to 54303 ($D410 to $D41F) are repeats of locations
+ 54272 to 54287 ($D400 to $D40F).
+
+ ---------------------------------------------------------------------------
+ Locations 54784 to 55295 ($D600 to $D7FF) are unused but not empty
+ nor user alterable. See the note at 53504 ($D100).
+
+ ---------------------------------------------------------------------------
+
+ OPERATING SYSTEM ROM
+
+ Locations 55296 to 65535 ($D800 to $FFFF) are the OS ROM.
+ These locations are contained in the 10K ROM cartridge, which sits in
+ the front slot of the Atari 800 or inside the Atari 400. The OS is
+ identical for both computers.
+
+ The locations given here are for the "A" version of the OS ROMs.
+ There are changes in the new "B" version ROMs, which are explained
+ in the appendix. Most of the changes affect the interrupt handler
+ routines and SIO. In making these changes, Atari cured some bugs
+ such as the device time-out problem. Unfortunately, there is a cloud
+ with this silver lining: not all of your old software will run with the new
+ ROMs. Megalegs, one of my favorite games, cannot run under the new
+ ROMs. A pity that. There are others; I'm sure you'll find them. The
+ solution is to have both sets of ROMs so you can use all of your
+ software.
+
+
+ FLOATING POINT PACKAGE ROM
+
+ Locations 55296 to 57343 ($D800 to $DFFF) are reserved for the ROM's
+ Floating Point Mathematics Package. There are other areas used by the
+ FP package: page zero (locations 212 to 254; $D4 to $FE) and page five
+ (locations 1406 to 1535; $57E to $5FF), which are used only if FP
+ routines are called. There are also trigonometric functions in the BASIC
+ cartridge located between 48549 and 49145 ($BDA5 to $BFF9) which
+ use the FP routines. See De Re Atari for more information.
+
+ These are the entry points to some of the subroutines; unless otherwise
+ noted, they use FP register zero (FR0 at 212 to 217, $D4 to $DB):
+
+
+ 55296 D800 AFP
+
+ ASCII to Floating Point (FP) conversion.
+
+
+ 55526 D8E6 FASC
+
+ FP value to ASCII conversion.
+
+
+ 55722 D9AA IFP
+
+ Integer to FP conversion.
+
+
+ 55762 D9D2 FPI
+
+ FP to integer conversion.
+
+
+ 55876 DA44 ZFR0
+
+ Clear FR0 at 212 to 217 ($D4-$DB) by setting all bytes to zero.
+
+
+ 55878 DA46 ZF1
+
+ Clear the FP number from FR1, locations 224 to 229 ($E0 to $E5),
+ by setting all bytes to zero. Also called AF1 by De Re Atari.
+
+
+ 55904 DA60 FSUB
+
+ FP subtract routine, the value in FR0 minus the value in FR1.
+
+
+ 55910 DA66 FADD
+
+ FP addition routine; FR0 plus FR1.
+
+
+ 56027 DADB FMUL
+
+ FP multiplication routine; FR0 times FR1.
+
+
+ 56104 DB28 FDIV
+
+ FP division routine; FR0 divided by FR1.
+
+
+ 56640 DD40 PLYEVL
+
+ FP polynomial evaluation.
+
+
+ 56713 DD89 FLD0R
+
+ Load the FP number into FR0 from the 6502 X,Y registers.
+
+
+ 56717 DD8D FLD0P
+
+ Load the FP number into FR0 from user routine, using FLPTR at
+ 252 ($FC).
+
+
+ 56728 DD98 FLD1R
+
+ Load the FP number into FR1 from the 6502 X,Y registers.
+
+
+ 56732 DD9C FLD1P
+
+ Load the FP number into FR1 from user program, using FLPTR.
+
+
+ 56743 DDA7 FST0R
+
+ Store the FP number into the 6502 X,Y registers from FR0.
+
+
+ 56747 DDAB FST0P
+
+ Store the FP number from FR0, using FLPTR.
+
+
+ 56758 DDB6 FMOVE
+
+ Move the FP number from FR0 to FR1.
+
+
+ 56768 DDC0 EXP
+
+ FP base e exponentiation.
+
+
+ 56780 DDCC EXP10
+
+ FP base 10 exponentiation.
+
+
+ 57037 DECD LOG
+
+ FP natural logarithm.
+
+
+ 57041 DED1 LOG10
+
+ FP base 10 logarithm.
+
+ ---------------------------------------------------------------------------
+ Locations 57344 to 58367 ($E000 to $E3FF) hold the standard Atari
+ character set: at $E000 the special characters, punctuation and numbers
+ begin; at $E100 (57600) the capital letters begin; at $E200 (57856) the
+ special graphics begin, and at $E300 (58112) the lowercase letters
+ begin.
+
+ There are 1024 bytes here ($400), with each character requiring eight
+ bytes, for a total of 128 characters (inverse characters simply manipulate
+ the information here to reverse the bits by performing an OR with 128 --
+ the value in location 694 ($2B6) when the Atari logo key is toggled -- on
+ the bits. To return to the normal ATASCII display, the inverse characters
+ are EORed with 128). The first half of the memory is for numerals,
+ punctuation, and uppercase characters; the second half ($E200 to
+ $E3FF) is for lowercase and control characters. When you POKE 756
+ ($2F4) with 224 ($E0), you are POKEing it with the MSB of this address
+ ($E000). When you POKE it with 226 ($E2), you are moving the address
+ pointer to the second half of the character set. In GR.0, you have the
+ entire character set to use. In GR.1 and GR.2, you can use only one half
+ of the set at a time. You can't POKE it with 225 because the number
+ POKEd must be evenly divisible by two.
+
+ The characters stored here aren't in ATASCII order; they have their own
+ internal order for storage. The order of the characters is listed on page
+ 55 of your BASIC Reference Manual.
+
+ Here's an example of how a letter (A) is stored in ROM. Each line
+ represents a byte. The decimal values are those you'd find if you
+ PEEKed the eight locations where "A" is stored (starting at 57608;
+ $E108):
+
+ Bit 76543210 Decimal
+ +--------+
+ 00000000 0 | |
+ 00011000 24 | ## |
+ 00111100 60 | #### |
+ 01100110 102 | ## ## |
+ 01100110 102 | ## ## |
+ 01111110 126 | ###### |
+ 01100110 102 | ## ## |
+ 00000000 0 | |
+ +--------+
+
+ When you create your own character sets (or alter the Atari set
+ when you move it to RAM -- see location 756; $2F4 for a routine
+ to do this), you do a "bit-map" for each character as in the
+ example above. It could as easily be a spaceship, a Hebrew
+ letter, an APL character, or a face. Chris Crawford's game
+ Eastern Front 1941 (APX) shows excellent use of an altered
+ character set to create his large map of Russia, plus the symbols
+ for the armies.
+
+ Here's an example of using the bit-mapping of the character set
+ to provide text in GRAPHICS 8:
+
+ 1 GRAPHICS 8
+ 5 DLIST = PEEK(560) + PEEK(561)*256
+ 6 LOBYTE = DLIST+4: HIBYTE = DLIST +
+ 5
+ 7 REAL = PEEK(LOBYTE) + PEEK(HIBYTE)
+ *256: SCREEN = REAL: TV = SCREEN
+ 10 CHBASE = 57344
+ 20 DIM A$(128),BYTE(128),WANT(128)
+ 27 PRINT "INPUT A 40 CHARACTER STRIN
+ G:"
+ 30 INPUT A$
+ 35 TIME = TIME + 1
+ 40 FOR LOOK = 1 TO LEN(A$)
+ 50 BYTE(LOOK) = ASC(A$(LOOK,LOOK))
+ 51 IF BYTE(LOOK) > 127 THEN BYTE(LOO
+ K) = BYTE(LOOK) - 128
+ 52 IF BYTE(LOOK) < 32 THEN BYTE(LOOK
+ ) = BVTE(LOOK) + 64: GOTO 55
+ 53 IF BYTE(LOOK) < 97 THEN BVTE(LOOK
+ ) = BYTE(LOOK) - 32
+ 55 NEXT LOOK
+ 59 FOR EXTRA = 0 TO 7
+ 60 FOR LOOK = 1 TO LEN(A$)
+ 70 WANT(LOOK) = PEEK(CHBASE + EXTRA
+ + BYTE(LOOK)*8)
+ 80 POKE TV + EXTRA, WANT(LOOK): TV =
+ TV + 1
+ 82 NEXT LOOK
+ 85 SCREEN = SCREEN + 39: TV = SCREEN
+ 90 NEXT EXTRA
+ 100 SCREEN = REAL + TIME*320
+ 110 IF SCREEN > REAL + 6080 THEN TIM
+ E = 0: GOTO 100
+ 120 GOTO 30
+
+ DOWNLOAD BITMAP8.BAS
+
+ This program simply takes the bytes which represent the letters
+ you input as A$ and finds their places in the ROM character set.
+ It then proceeds to POKE the bytes into the screen RAM, using a
+ FOR-NEXT loop.
+
+ To convert ATASCII codes to the internal codes, use this table:
+
+ ATASCII value Operation for
+ internal code
+ 0 -- 31 add 64
+ 32 -- 95 subtract 32
+ 96 -- 127 remains the same
+ 128 -- 159 add 64
+ 160 -- 223 subtract 32
+ 224 -- 255 remains the same
+
+ See COMPUTE!, November 1981, for the program "TextPlot"
+ which displays text in different sizes in GRAPHICS modes three
+ to eight, and January 1982 for a program to edit character sets,
+ "SuperFont."
+
+ ---------------------------------------------------------------------------
+
+ Locations 58368 to 58447 ($E400 to $E44F) are the vector tables, stored
+ as LSB, MSB. These base addresses are used by resident handlers.
+ Handler vectors use the following format:
+
+ OPEN vector
+ CLOSE vector
+ GET BYTE vector
+ PUT BYTE vector
+ GET STATUS vector
+ SPECIAL vector
+ Jump to handler initialization routine (JMP LSB/MSB)
+
+ The device tables in location 794 ($31A) point to the particular
+ vector(s) used in each appropriate table. In each case, the 6502 X
+ register is used to point to the originating IOCB.
+
+
+ 58368 E400 EDITRV
+
+ Screen Editor (E:) entry point table.
+
+
+ 58383 E40F ....
+
+ If you PEEK here and get back 56, then you have the older "A"
+ version of the OS ROMs. If you get back zero, then you have the
+ newer "B" version that was released in January 1982. The "B"
+ version fixes some minor bugs, including the device time-out
+ problems, enables POKEY timer four, and provides a vector for
+ BREAK key interrupts. See Appendix 4.
+
+
+ 58384 E410 SCRENV
+
+ Display handler (television screen) (S:).
+
+
+ 58400 E420 KEYBDV
+
+ Keyboard handler (K:).
+
+
+ 58416 E430 PRINTV
+
+ Printer handler (P:).
+
+
+ 58432 E440 CASETV
+
+ Cassette handler (C:).
+
+ ---------------------------------------------------------------------------
+ Locations 58448 to 58533 ($E450 to $E4A5) are more vectors: those to
+ location 58495 ($E47F) are Jump vectors, those from 58496 to 58533
+ ($E480 to $E4A5) are the initial RAM vectors.
+
+
+ 58448 E450 DISKIV
+
+ Disk handler initialization vector, initialized to 60906 ($EDEA).
+
+
+ 58451 E453 DSKINV
+
+ Disk handler (interface) entry; checks the disk status. Initialized
+ to 60912 ($EDF0).
+
+
+ 58454 E456 CIOV
+
+ Central Input/Output (CIO) utility entry. CIO handles all of the
+ I/O operations or data transfers. Information placed in the
+ IOCB's tells CIO what operations are necessary. CIO passes this
+ information to the correct device driver routine and then passes
+ control to the Device Control Block (DCB). This in turn calls up
+ SIO (below) to control the actual peripheral(s). CIO treats all I/O
+ in the same manner: device independent. The differentiation
+ between operations is done by the actual device drivers.
+
+ You jump to here to use the IOCB handler routines in ROM.
+ BASIC supports only record I/O or one-byte-at-a-time I/O (GET
+ and PUT). Addressing CIOV directly will allow the user to input
+ or output a buffer of characters at a time, such as loading a
+ machine language program directly into memory from a disk file.
+ This is considerably faster than using BASIC functions such as
+ GET. Here is a typical machine language subroutine to do this:
+
+ PLA, PLA, PLA, TAX, JMP $E456
+ (104,104,104,170,76,86,228)
+ ($68,$68,$68,$AA,$4C,$56,$E4)
+
+ This gets the IOCB number into the 6502 X register and the
+ return address on the stack. CIOV expects to find the IOCB
+ number 16 in the 6502 X register (i.e., IOCB zero is zero, IOCB
+ one is 16; $10, IOCB two is 32, $20, etc.). $E456 is the CIO
+ initialization entry point (this address).
+
+ To use CIOV in a program, first you must have OPENed a
+ channel for the appropriate actions, POKEd the correct IOCB
+ (locations 848 to 959; $350 to $3BF) with the correct values, and
+ established a location in which to load your file (IOCB address
+ plus four and plus five). One use is calling up a high-res picture
+ from a disk and storing it in the screen memory (locations 88, 89;
+ $58, $59). You can POKE the appropriate decimal values into
+ memory and call it with a USR call, or make it into a string
+ (START$ = "hhh*LVd" where the * and the d are both inverse
+ characters) and call it by:
+
+ JUMP = USR(ADR(START$))
+
+ This method is used to start the concurrent mode in the RS-232 of
+ the 850 interface in the 850 Interface Manual. See location 88, 89
+ ($58, $59) for another example of the machine language routine
+ technique. Still another use of this method can be found in De Re
+ Atari. Initialized to 58564 ($E4C4).
+
+
+ 58457 E459 SIOV
+
+ Serial Input/Output (SIO) utility entry point. SIO drives the
+ serial bus and the peripherals. When a request is placed in the
+ Device Control Block (DCB) by a device handler, SIO takes
+ control and uses the data in the DCB to perform the operation
+ required. SIO takes care of the transfer of data as defined by the
+ DCB. CIO (above) is responsible for the "packaging" of the data
+ and transfers control to SIO when necessary. See the DCB
+ locations 768 to 779 ($300-$30B).
+ SIO first sends a command frame to the device, consisting of five
+ bytes: the device ID, the command BYTE, two auxiliary bytes for
+ device-specific information, then a checksum (which is the sum
+ of the first four bytes). If the device acknowledges this frame, it is
+ followed, if necessary, by the data frame of a fixed number of
+ bytes depending on the device record size, plus a checksum
+ byte. Initialized to 59737 ($E959).
+
+
+ 58460 E45C SETVBV
+
+ Set system timers during the VBLANK routine. Uses the 6502 X
+ register for the MSB of vector/times, Y for the LSB and A for the
+ number of the vector to hack (change). SETVBV insures that both
+ bytes of the vector addressed will be updated while VBLANK is
+ enabled. You can JSR here when creating your own timer
+ routines. See COMPUTE!, November 1981, for an application.
+ Initialized to 59666 ($E912) old ROMs, 59629 ($E8ED) new
+ ROMs.
+
+
+ 58463 E45F SYSVBV
+
+ Stage one VBLANK calculations entry. It performs the
+ processing of a VBLANK interrupt. Contains JMP instruction for
+ the vector in the next two addresses (58464, 58465; $E460,
+ $E461). This is the address normally found in VVBLKI (546, 547;
+ $222, $223). It is initialized to 59345 ($E7D1), which is the
+ VBLANK routine entry. Initialized to 59345 ($E7D1) old ROMs,
+ 59310 ($E7AE) new ROMs.
+
+
+ 58466 E462 XITVBV
+
+ Exit from the VBLANK routine, entry point. Contains JMP to the
+ address stored in next two locations (58467, 58468; $E463,
+ $E464). This is the address normally found in VVBLKD (548, 549;
+ $224, $225). Initialized to 59710 ($E93E), which is the VBLANK
+ exit routine. It is used to restore the computer to its pre-interrupt
+ state and to resume normal processing. Initialized to 59710
+ ($E93E) old ROMs, 59653 ($E905) new ROMs.
+
+
+ 58469 E465 SIOINV
+
+ SIO utility initialization, OS use only.
+
+
+ 58472 E468 SENDEV
+
+ Send enable routine, OS use only.
+
+
+ 58475 E46B INTINV
+
+ Interrupt handler initialization, OS use only.
+
+
+ 58478 E46E CIOINV
+
+ CIO utility initialization, OS use only.
+
+
+ 58481 E471 BLKBDV
+
+ Blackboard mode entry. Blackboard mode is the "ATARI MEMO
+ PAD" mode. It can be reached from BASIC by typing "BYE",
+ "B." or by powering up with no peripherals or cartridges.
+ Nothing you write to the screen in blackboard mode is acted
+ upon by the computer. You can enter this mode to protect your
+ programs temporarily from prying and curious fingers.
+
+ All of the screen editing commands continue to work in
+ blackboard mode. You can enter blackboard mode from any
+ graphics mode with a text window; the display screen will remain
+ intact on the screen while the text window will be in blackboard
+ mode. Pressing RESET will, of course, return the entire screen to
+ GR.0. You can also enter blackboard mode from a program, but
+ cannot get out of it in BASIC once you are in it.
+
+ If you entered blackboard mode from BASIC, you can return to it
+ by pressing RESET. Any BASIC program will still be there. So
+ will any RS-232 or DOS handlers previously booted. Initialized to
+ 61987 ($F223).
+
+
+ 58484 E474 WARMSV
+
+ Warmstart entry point (RESET button vector). Initializes the OS
+ RAM region. The RESET key produces an NMI interrupt and a
+ chip reset (see below). Jump to here on an NMI caused by
+ pressing the RESET key. Initialized to 61723 ($F11B).
+
+
+ 58487 E477 COLDSV
+
+ Coldstart (powerup) entry point. Initializes the OS and user RAM
+ regions; wipes out any program in memory. Initialized to 61733
+ ($F125).
+
+
+ 58490 E47A RBLOKV
+
+ Cassette read block routine entry, OS use only.
+
+
+ 58493 E47D CSOPIV
+
+ Cassette OPEN for input vector, OS use only.
+
+
+ 58496 E480 VCTABL
+
+ RAM vector initial value table.
+
+ ---------------------------------------------------------------------------
+
+ The following are the addresses for the handler routines:
+
+
+ 58534-59092 E4A6-E6D4 CIOORG
+
+ Addresses for the Central Input/Output routines (CIO):
+
+
+ 58534 ($E4A6) CIOINT
+
+ is the CIO initialization routine called by the monitor on powerup.
+
+
+ 58577 ($E4D1);
+
+ move the user IOCB to the ZIOCB.
+
+
+ 58596 ($E4E4);
+
+ check for a valid command.
+
+
+ 58633 ($E509);
+
+ OPEN command routines.
+
+
+ 58675 ($E533);
+
+ CLOSE command routines.
+
+
+ 58702 ($E54E);
+
+ STATUS and special command routines.
+
+
+ 58729 ($E569) CIREAD;
+
+ process the CIO commands for read and
+ write, including buffer check for full or empty.
+
+
+ 58907 ($E61B);
+
+ routine to return to the user from CIO.
+
+
+ 58941 ($E63D),
+
+ routines to compute the device handler entry point,
+ jump to the handler, transfer control, and then return to CIO after the
+ operation.
+
+
+ 59093-59715 E6D5-E943 INTORG
+
+ Addresses for the interrupt handler routines:
+
+
+ 59123 ($E6F3) PIRQ;
+
+ IRQ interrupt service routines start here.
+
+
+ 59126 ($E6F6);
+
+ the immediate IRQ vector to the IRQ handler. The
+ global NMI and IRQ RAM vectors in locations 512 to 527 ($200 to $20F)
+ are all initialized to this area (59142, $E706 for the new OS ROMs).
+
+
+ 59314 ($E7B2);
+
+ the vector for the IRQ interrupts on powerup; it
+ points to a PLA and RTI instruction sequence (new OS ROMs; 59219;
+ $E78F).
+
+
+ 59316 ($E7B4) PNMI;
+
+ the NMI handler, tests for the reason for the
+ NMI, then jumps through the appropriate RAM vector. Also called the
+ Interrupt Service Routine (ISR).
+
+
+ 59345 ($E7D1) SYSVBL;
+
+ the VBLANK routines start here,
+ including frame counter, update timer, update hardware registers
+ from shadow registers, update the attract mode counter and the
+ realtime clock. The vertical blank immediate vector, VVBLKL1,
+ normally pointed to by locations 546, 547 ($222, $223), points to here.
+ The Updated OS ROMs point to 59310 ($E7AE).
+
+
+ 59666 ($E912) SETVBL;
+
+ subroutines to set the VBLANK timers
+ and vectors.
+
+ The vertical blank deferred interrupt, normally vectored from
+ locations 548, 549 ($224, $225), points to 59710 ($E93E). In the
+ Updated OS ROMs, it points to 59653 ($E905). In both cases they point
+ to the VBLANK exit routine.
+
+ See page 104 of the OS User's Manual for a list of the vectors and
+ MICRO, January 1982, for an explanation of the VBLANK process.
+
+
+ 59716-60905 E944-EDE9 SIOORG
+
+ Routines for the Serial Input/Output (SIO) routines:
+
+
+ 60011 ($EA6B) SEND;
+
+ is the SIO send buffer routine entry.
+
+
+ 60048 ($EA90) ISRODN,
+
+ is the serial output ready IRQ vector.
+
+
+ 60113 ($EAD1) ISRTD;
+
+ is the serial output complete IRQ vector.
+ This is at 60111 ($EACF) in the new OS ROMs.
+
+
+ 60177 ($EB11) ISRSIR;
+
+ is the serial input ready IRQ vector. This
+ is 60175 ($EB0F) in the new OS ROMs.
+
+
+ 60292 ($EB84) CASENT;
+
+ is the start of the cassette handling code
+ SIO subroutine to set baud rate, tone values, inter-record gap, to load
+ the buffer from the cassette and to turn on the recorder motor. Write
+ routines are located in 61249 to 61666 ($EFF5 to $F0E2).
+
+
+ 60515 ($EC63)
+
+ is the start of the disable POKEY interrupts routine
+ entry, which also disables the send and receive functions.
+
+
+ 60583 ($ECA7) COMPUT;
+
+ is the subroutine to calculate baud
+ rate using the POKEY frequency registers and the VCOUNT timer.
+ The tables for the AUDF and VCOUNT values are between 60882 and
+ 60905 ($EDD2 and $EDE9).
+
+
+ 60906-61047 EDEA-EE77 DSKORG
+
+ Routines for the disk handler.
+ Initialization is at DINIT, 60906 ($EDEA), entry is at DSKIF, 60912
+ ($EDF0).
+
+
+ 61048-61248 EE78-EF40 PRNORG
+
+ Routines for the printer handler.
+
+
+ 61249-61666 EF41-F0E2 CASORG
+
+ Routines for the cassette handler.
+
+ The buzz used in the cassette CLOAD command can be called up from
+ BASIC by:
+
+ BUZZ = USR(61530).
+
+ You can turn it off with the RESET key. While this isn't terribly
+ exciting, it points to the potential of using the console speaker for
+ sound instead of merely for beeps (the RAM location for the speaker is
+ at 53279; $D01F). See the speaker location and COMPUTE!, August
+ 1981, for a short routine to use the speaker for sound effects.
+
+
+ 61667-62435 F0E3-F3E3 MONORG
+
+ Routines for the monitor handler. This is also the address area of
+ PWRUP, the powerup module (61733; $F125). Coldstart routines are
+ initialized to this location. The routine to check for cartridge
+ installation begins at 61845 ($F195). Hardware initialization begins at
+ 62081 ($F281).
+
+
+ 61723 ($F11B) RESET;
+
+ the RESET button routine starts here.
+
+
+ 62081 ($F281) HARDI,
+
+ the start of the hardware initialization
+ routines.
+
+
+ 62100 ($F294) OSRAM;
+
+ the start of the OS RAM initialization
+ and setup routines.
+
+
+ 62159 ($F2CF) BOOT;
+
+ the entry point for the disk boot routine.
+
+
+ 62189 ($F2ED) DOBOOT;
+
+ the disk boot routine activation.
+
+
+ 62334 ($F37E) DOPEN;
+
+ the entry point for the reinitialization
+ of disk software.
+
+
+ 62436-65535 F3E4-FFFF KBDORG
+
+ Routines for the display and keyboard handler. The display
+ handler beqins at 62454 ($F3F6) and the keyboard handler
+ begins at 63197 ($F6DD), below.
+
+
+ 63038 F63E EGETCH
+
+ Like the BASIC INPUT command, EGETCH gets a line from the
+ screen and keyboard, but only one character at a time. You must
+ do a JSR $F63E for each character input. This is also the address
+ of the beginning of the screen editor routines.
+
+
+ 63140 F6A4 EOUTCH
+
+ This routine puts the character currently in the accumulator onto
+ the screen in the next print location. Similar to the BASIC PUT
+ command.
+
+
+ 63197 F6DD KGETC2
+
+ Beginning of the keyboard handler.
+
+
+ 63202 F6E2 KGETCH
+
+ This routine waits for a key to be pressed and returns its value to
+ the accumulator (6502 register A). Similar to the BASIC GET
+ command.
+
+
+ 64428 FBAC SCROLL
+
+ The screen scroll routine starts here.
+
+
+ 64764 FCFC DRAW
+
+ Screen draw routines begin here, end at 65092 ($FE44). See
+ Creative Computing, March 1982, for an example of a
+ modification to the draw routines to avoid the "out-of-bounds"
+ error for use in GR.7+.
+
+
+ 65093-469 FE45-FFBD ....
+
+ The ROM tables for display lists, ANTIC codes, control codes,
+ and ATASCII conversion codes.
+
+
+ 65470 FFBE PIRQQ
+
+ Subroutines to test the acceptance of the last key pressed and to
+ process the debounce delay routines start here.
+ When a key is pressed, it initiates an IRQ through VKEYBD at
+ locations 520, 521 ($208, $209) to 65470 ($FFBE). This is the
+ keyboard service routine. It processes debounce, and SHIFT-
+ CTRL logic (see location 559; $22F); saves the internal keyboard
+ code in 754 ($2F2) and 764 ($2FC); sets the ATTRACT mode flag
+ at 77 ($4D) and sets location 555 ($22B -- SRTIMR) to 48 ($30).
+
+
+ 65528 FFF8 CHKSUN
+
+ According to Softside Magazine, December 1981, if a PEEK here
+ returns 255, then you have the older OS ROM(s). There were
+ some troubles with cassette loads in the older ROMs that
+ sometimes require the following to cure:
+
+ Do an LPRINT without a printer attached before CLOAD. This
+ clears the cassette buffer.
+
+ Press RESET before CSAVEing or CLOADing will restore the
+ system to its initialization parameters and help with loading and
+ saving routines.
+
+ There is a new OS available from Atari which fixes a bug that
+ would cause the I/O operations to "time out" for a few seconds. It
+ apparently does not alter any of the routines mentioned here.
+
+ The chip reset interrupt (powerup) vectors through location
+ 65532 ($FFFC) to 58487 ($E477) where a JMP vector to the
+ powerup routine is located. A chip reset is not the same as
+ pressing the RESET key, which in itself does not generate a chip
+ reset.
+
+ The NMI interrupts are vectored through 65530 ($FFFA) to the
+ NMI service routine (ISR) at 59316 ($E7B4), and all IRQ
+ interrupts are vectored through 65534 ($FFFE) to the IRQ service
+ routine at 59123 ($E6F3). In these service routine areas, the
+ cause of the interrupt is determined, and the appropriate action
+ is taken, either by the OS or through a JMP to a RAM vector
+ where a user routine exists.
+
+ ----------------------------------------------------------------------
+
+ Return to Table of Contents | Previous Chapter | Next Chapter
+
+
+
+
+
+
+
+
+
+
+
+ [IMG]
+ [IMG]
diff --git a/mklevelinfo.pl b/mklevelinfo.pl
new file mode 100644
index 0000000..56a8894
--- /dev/null
+++ b/mklevelinfo.pl
@@ -0,0 +1,91 @@
+#!/usr/bin/perl -w
+
+%struct = (
+ 0 => [ 2, 'desc', "first 2 bytes are level number in screencodes" ],
+ 2 => [ 2, 'sub0', "a subroutine" ],
+ 4 => [ 2, 'sub1', "a subroutine" ],
+ 6 => [ 2, 'sub2', "a subroutine" ],
+ 8 => [ 2, 'sub3', "a subroutine" ],
+ 10 => [ 1, 'num_bombs', "number of bombs to pick up on this level" ],
+ 11 => [ 1, 'bullet_chance', '0 = no bullets' ],
+ 12 => [ 1, 'y_start', 'jumpman starting Y position' ],
+ 13 => [ 1, 'x_start', 'jumpman starting X position' ],
+ 14 => [ 2, 'offs', 'points to $0600' ],
+ 16 => [ 1, 'points_per_bomb', 'points awarded per bomb pickup (always $64 aka 100)' ],
+ 17 => [ 2, 'time_bonus', 'amount of time bonus at start of level' ],
+ 19 => [ 1, 'offs', 'always $00' ],
+ 20 => [ 2, 'unkn_table0', 'pointer to ROM table or $06xx' ],
+ 22 => [ 2, 'map0', 'map data' ],
+ 24 => [ 2, 'map1', 'map data' ],
+ 26 => [ 2, 'map2', 'map data' ],
+ 28 => [ 2, 'unkn_table1', 'unknown, pointer to a ROM table or $0000' ],
+ 30 => [ 2, 'offs', 'always $0000' ],
+ 32 => [ 2, 'sub4', '$06E6 for most levels, or else a ROM subroutine' ],
+ 34 => [ 2, 'sub5', '$06E6 for some levels, or else a ROM subroutine' ],
+ 36 => [ 2, 'sub6', 'always $9740 aka game_main_loop' ],
+ 38 => [ 2, 'sub_eol', 'called at end of level (all bombs picked up). $06E6 for all but level07' ],
+ 40 => [ 6, 'offs', 'all zeroes' ],
+ 46 => [ 9, 'offs', 'unknown' ],
+ 55 => [ 3, 'offs', 'unknown, always $00 $00 $00' ],
+ 58 => [ 2, 'offs', 'unknown, not a ROM address' ],
+ 60 => [ 4, 'offs', 'unknown, level05 (walls) has $ff $ff $ff $ff, all others $00 $00 $00 $00' ],
+);
+
+sub mkaddr {
+ return sprintf("\$%04x", $_[0]);
+}
+
+sub mknum {
+ return sprintf("%02d", $_[0]);
+}
+
+sub mkrange {
+ my ($level, $label, $start, $len, $type, $comment) = @_;
+ my $sa = mkaddr($start);
+ my $ea = mkaddr($start + $len - 1);
+ my $llab;
+ if($level >= 0) {
+ my $ll = sprintf("%02d", $level);
+ $llab = "level$ll";
+ } else {
+ if($level == -609) {
+ $llab = "cur_level";
+ } else {
+ $llab = "work_level";
+ }
+ my $l = <<EOF;
+label { name "${llab}_$label"; addr $sa; size $len; comment "$comment"; };
+EOF
+ return $l;
+ }
+ my $range = <<EOF;
+range { name "${llab}_$label"; start $sa; end $ea; type $type; comment "$comment"; };
+EOF
+ return $range;
+}
+
+for $level (-610,-609,0..11) {
+ $addr = 0xa000 + $level * 0x40;
+ for $offset (sort { $a <=> $b } keys %struct) {
+ my ($size, $label, $comment) = @{$struct{$offset}};
+ if($level == 0 && $offset == 0) {
+ $comment = "64-byte level descriptors, 12 of them (1 per level). " . $comment;
+ }
+
+ $type = 'bytetable';
+ if(($label =~ /^sub/) or ($label =~ /^map/) or ($label =~ /^unkn_table/)) {
+ $type = 'addrtable';
+ }
+
+ if($label eq 'time_bonus') {
+ $type = 'wordtable';
+ }
+
+ if($label eq 'offs') {
+ $label .= "_" . mknum($offset);
+ }
+
+ print mkrange($level, $label, $addr + $offset, $size, $type, $comment);
+ }
+ print "\n";
+}
diff --git a/mkmusiclabels.pl b/mkmusiclabels.pl
new file mode 100644
index 0000000..f47cbfe
--- /dev/null
+++ b/mkmusiclabels.pl
@@ -0,0 +1,15 @@
+#!/usr/bin/perl -w
+
+$startaddr = 0;
+$entry = 0;
+do {
+ $startaddr = 0x8FC3 + $entry * 5;
+ printf 'range { name "mus%02d_addr1"; start $%04x; end $%04x; type addrtable; };%s',
+ $entry, $startaddr, $startaddr+1, "\n";
+ printf 'range { name "mus%02d_addr2"; start $%04x; end $%04x; type addrtable; };%s',
+ $entry, $startaddr+2, $startaddr+3, "\n";
+ printf 'range { name "mus%02d_len_or_tempo"; start $%04x; end $%04x; type bytetable; };%s',
+ $entry, $startaddr+4, $startaddr+4, "\n";
+ print "\n";
+ $entry++;
+} while($startaddr < 0x8fff);
diff --git a/porting_ideas.txt b/porting_ideas.txt
new file mode 100644
index 0000000..ecad971
--- /dev/null
+++ b/porting_ideas.txt
@@ -0,0 +1,50 @@
+
+can't really do a pure game engine that just uses the binary for data,
+because parts of the game mechanics are implemented purely as 6502
+code. also the sound effects would need the engine to execute 6502 code
+*and* emulate POKEY. however, it can at least use this much of the binary:
+
+- sprite and font bitmaps
+- level layout data
+- level names
+- possibly color data (using an atari palette)
+
+this stuff can either be read out of the binary at runtime, or be coverted
+into source and/or config files when building the engine. either way,
+the original game binary will be required, but doing it at build time
+means you don't need the binary at runtime (engine will be a standalone
+port of the game).
+
+the various specials (hail, hatchlings, invisible level, etc) will have
+to be rewritten in C (or whatever the engine ends up being written in).
+probably just hardcode which specials appear on which levels.
+
+the basic game rules that don't change from level to level will of course
+be part of the engine. running, jumping, climbing/descending ropes,
+picking up bombs, collision detection, most levels have generic bullets.
+
+the sound effects and music can just be .wav files captured from the
+original game running on the emulator.
+
+I'm thinking C with SDL2. render the game in an atari-sized window
+(320x192 or whatever it really is) and let SDL2 scale it, which seems a
+lot nicer than SDL1's basically nonexistent scaling. other possibility
+would be perl-SDL, provided it's got full SDL2 support (not sure, seems
+cpan doesn't have it)
+
+might add high-score saving a la original Jumpman (the one thing I really
+missed, for the cart-based Junior). also maybe a randomizer mode.
+
+later on down the road, the engine should support original Jumpman too.
+the https://playermissile.com/jumpman/ project has a lot of good info,
+much of which will also apply to Junior. also there's x86 asm source
+for the PC version.
+
+much later, there should be a level editor for the engine. not one that
+can export levels for the original game like omnivore does for original
+Jumpman, though. unless that turns out to be easier than I think,
+of course.
+
+also inevitably someone will want updated graphics/sound, a "high res
+apack" dd-on or such. I'm not opposed to such a thing existing but I
+really only care about the original game.