From 26b42926816662ce878e814938a1ebc0aa1847c2 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Mon, 29 Aug 2016 15:00:13 -0400 Subject: finally made a git repo for this --- Makefile | 29 + da65.txt | 628 ++++ equates.inc | 1386 ++++++++ jumpmanjr.cart | Bin 0 -> 16400 bytes jumpmanjr.dasm | 7360 +++++++++++++++++++++++++++++++++++++++++ jumpmanjr.inc | 68 + jumpmanjr.info | 908 +++++ jumpmanjr.rom | Bin 0 -> 16384 bytes jumpmanjr_manual.pdf | Bin 0 -> 3135749 bytes level_descriptors.txt | 127 + level_maps.txt | 188 ++ leveldesc.info | 406 +++ main.info | 501 +++ mapping.txt | 8814 +++++++++++++++++++++++++++++++++++++++++++++++++ mklevelinfo.pl | 91 + mkmusiclabels.pl | 15 + porting_ideas.txt | 50 + 17 files changed, 20571 insertions(+) create mode 100644 Makefile create mode 100644 da65.txt create mode 100644 equates.inc create mode 100644 jumpmanjr.cart create mode 100644 jumpmanjr.dasm create mode 100644 jumpmanjr.inc create mode 100644 jumpmanjr.info create mode 100644 jumpmanjr.rom create mode 100644 jumpmanjr_manual.pdf create mode 100644 level_descriptors.txt create mode 100644 level_maps.txt create mode 100644 leveldesc.info create mode 100644 main.info create mode 100644 mapping.txt create mode 100644 mklevelinfo.pl create mode 100644 mkmusiclabels.pl create mode 100644 porting_ideas.txt 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 Binary files /dev/null and b/jumpmanjr.cart 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 ..# `.. + .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 ..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 ...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 |. + .byte $00,$00,$18,$3C,$66,$66,$7E,$66 ; 9F07 00 00 18 3C 66 66 7E 66 .... + 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%,. + 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 .. + .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 ./ + .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 . + .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 Binary files /dev/null and b/jumpmanjr.rom differ diff --git a/jumpmanjr_manual.pdf b/jumpmanjr_manual.pdf new file mode 100644 index 0000000..1a607a5 Binary files /dev/null and b/jumpmanjr_manual.pdf 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 = < $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. -- cgit v1.2.3