A.N.A.L.O.G. ISSUE 39 / FEBRUARY 1986 / PAGE 53
Debug+ is a screen-oriented machine language debugging utility. It contains a program tracer that can step through almost any machine language program in three different ways. Debug+ also has a complete scrolling disassembler and memory “dumper.” It allows user program execution and can perform binary SAVEs and LOADs, plus many, many more functions. Sound too good to be true for a magazine program? Well, it’s not. Read on!
Before you start typing anything, examine the listings accompanying this article. Listing 1 is the main data and data checking routine, written in Atari BASIC. This program will create a file called DEBUG.COM. Follow the instructions below to create the DEBUG.COM file.
To LOAD Debug+ from Atari DOS 2.0S, go to DOS and type:
L DEBUG.COM
Debug+ will LOAD and RUN automatically.
For those interested in assembly language, the OSS MAC/65 source code for Debug+ is available on the ANALOG Computing TCS and is included on the disk version of this issue.
Remember, you must have the BASIC cartridge removed for Debug+ to LOAD. For XL owners, this means you must boot up while holding dawn the OPTION key.
The program resides in cartridge slot A memory locations ($A100–$C0FF) and uses addresses $BE00–$C0FF as screen memory. The program supports eighteen commands, which are listed below:
Key Function * Address Set D Display Toggle Q Quit DEBUG+, go to DOS G Go at address T Trace program P Print Disassembly E Erase Memory C Change 1 byte of RAM N Change Register Value R Display Registers B Set/Reset Break Point S Save a binary file L Load a binary file F Find a string in memory H High Speed Display " Dec/Hex, Hex/Dec convert - Scroll up in memory = Scroll down in memory
Before I explain all the functions, I’d like to tell you about the prompts that Debug+ uses. There are three basic prompts: *, ? and (opt1,opt2,opt3)?
When the * appears, in the input window, Debug+ expects a number This number may be entered in either hexadecimal or decimal. To enter a decimal number, the digits in the number must be preceded by a decimal point (a period). If the number is not preceded by a period, Debug+ will interpret it as hexadecimal. If there are any “illegal” digits in the number, Debug+ will respond with a short tone, and the command will be aborted.
When the ? appears. Debug+ expects a string of characters, a filename, for example, with a maximum of twelve characters. When you reach the maximum input length, all extra characters (except DELETE, SHIFT-DELETE and RETURN) will overwrite the previous twelfth character. (I know that’s hard to understand. Try it; you’ll see what I mean.)
The final general prompt is (opt1,opt2,opt3)? When this appears in the input window. Debug+ wants you to press one of the keys separated by commas inside the parentheses. An example of this is (D,P)? This asks you what device you want to use, the disk or printer. Pressing D specifies disk, and so on.
Debug+ has two memory display modes: disassembly and memory dump.
A disassembled line looks like this:
ADDR OP B1 B1 xMNE
where ADDR is the address, OP is the op code, B1 and B2 are the operands, and xMNE is the mnemonics. The X indicates the direction of a relative instruction (branch instruction). If the arrow points up, it’s a backwards branch; and if the arrow points down, it’s a forward branch.
A memory dumped line looks like this:
ADDR B1 B2 B3 B4 B5 B6 123456
where ADDR is the address, B1-B6 are the values in the locations, and 1-6 are the ATASCII character representations of the values.
To use one of the commands in the table printed at left, just press the key on the keyboard which corresponds to the character listed under “key.” For instance, to update the register display line, just press the R key.
Address set (*). This is how you tell Debug+ where your disassembly or memory dump will begin. After entering your address, Debug+ will display the contents of the specified location.
Display toggle (D). This command will flip the screen between disassembly and memory dump, and vice versa.
Quit DEBUG+ (Q). This command returns you to DOS. To re-enter Debug+ from DOS, do a RUN AT ADDRESS, with the address being A100. To do this from OSS OS/A+, type RUN A100 and press RETURN. From Atari DOS 2.0S, type M, hit RETURN, then type A100 and hit RETURN.
Go at address (G). When this command is entered, the 6502 registers are loaded with the contents of the user registers, then program execution begins at the address specified.
The user program will continue to execute until it is stopped by a 6502 BRK instruction, one of the break points, or by your pressing CTRL-ESC (the CONTROL and ESCape keys at the same time).
If one of these events occurs, your program will be interrupted, the 6502 registers will be saved in the user registers, and Debug+ will take control. Then the location where the program was stopped will be disassembled or dumped on the screen, and the register line will be updated with the contents of the user registers.
Trace program (T). When trace is activated, Debug+ will ask for the starting address, then begin executing the code at the given location, one instruction at a time. You’ll be asked to specify the speed of the trace in the prompt (F,S,O)? If you press F, then the trace will be as fast as possible; the S key will pause one-quarter of a second between each instruction; and the O key will cause the trace to be stepped by pressing the OPTION key
A trace will be aborted if the tracer finds: (1) a 6502 BRK instruction, (2) a break point, (3) an illegal instruction, and (4) by pressing the ESC key. Note: if you’re using the stepped mode, you must hold down OPTION and press ESC to abort. The trace can be paused by pressing the SPACE BAR.
The tracer does have some limitations. First, it cannot trace itself, so never try to trace Debug+. Second, any attempt to trace the realtime I/O routines (such as disk or cassette access) will almost certainly fail.
During a trace, the user register line will be updated before and after the execution of each instruction, so you can examine the register contents at any time.
Print disassembly (P). When this command is executed, you’re asked what device the output will go to (disk or printer) and what the starting address is. If disk output is chosen, a filename will be asked for, then disassembly will begin. During the process, the address just sent out to the device is displayed on the STAT line. To abort this command during execution, press any key.
If you choose the disk as the output device, Debug+ will create a text file of the disassembly. You can then load this into a word processor or other text editor, and edit the disassembly.
Erase memory (E). When this command is executed, you’ll be asked for a starting and ending address of the erase. After this, the memory between and including those addresses will be erased. Debug+ will fill all those addresses with zeroes (the 6502 BRK instruction). If the end address is smaller than the start address, you’ll be given an ADDRESS RANGE ERROR, and the command will be aborted.
Change one byte of RAM (C). When you enter this command, you’ll be asked what address to change and what to change it to. At this point the contents of that memory location are changed. This is similar to the BASIC POKE statement.
Make sure that you don’t change any of the memory that Debug+ uses. Also, careless choice of a change address may wipe out vital system data and cause a complete system lock-up. Take care.
Change register value (N). When this command is entered, you’ll be asked what register to change. To choose the register, simply press one of the following keys: A for Accumulator, X for X-Register, Y for Y Register, S for Stack Pointer, or P for Processor Status.
Next, you’ll be asked the new value. Enter this, and the register contents will be changed. Notice that the register line on the screen has been updated to reflect the new value.
A note about the register line. If you examine the line on the screen, you’ll see five small boxes and one large box, labelled NV_BDIZC. Under the label, there will be eight binary digits. This is the processor status, broken down into its flags. The following table tells you what each flag is:
N = Negative number flag. V = Overflow flag. _ = Unused (always shown as set). B = BRK instruction flag. D = Decimal flag. I = Interrupt flag. Z = Zero flag. C = Carry flag.
If a 1 appears under one of these flags, it indicates a “set” or “true” condition. So, if the I bit is 1, then an interrupt is occurring.
Display registers (R). All this command does is update the register line. It will display the current values of the user registers.
Set/Reset a break point (B). A break point will stop the execution (or trace) of a user program. When you enter this command, a B will appear in the input window, indicating that you must either set or reset a break point.
Setting a break point is easy. Simply type the break point number (a single digit between 1 and 6), followed by a comma, then the address where you wish the break point to be. A typical line would look like this: B1,0600[RETURN]. This tells Debug+ to set break point number 1 at location $0600 (or 1536 decimal). If break point number 1 is already set, you’ll be given an error. If location $0600 contains a BRK instruction, you will also get an error. All 6502 BRK instructions are considered break points.
When you disassemble the address where a break point is set, the mnemonics will be shown in inverse video. This is how Debug+ graphically shows the user where break points are. If you’re in memory dump mode, the value for the address where the break point is set is also in inverse video.
Resetting a break point is easier than setting one. At the B prompt, simply enter the break point number you want to reset, followed by a RETURN. An example would be B1[RETURN]. This will reset break point number 1. If it was not set, you’ll get an error.
When a break point is reset, the old opcode is restored at the break point address, and the address for the break point is reset to $0000. If you look at the break point line at the bottom of the screen when you load Debug+, you’ll notice that the addresses of all the break points are 0, and that there are six free break points.
Save a binary file (S). This command allows you to save a single-stage binary file to disk. You’ll be prompted to enter a filename, followed by the starting and ending addresses of the save. Once again, if the ending address is less than the starting address, you’ll be given an error. The file created with this function can be loaded from DOS. You cannot specify a run address for the file from Debug+, so you may want to append one to the file from BASIC or DOS.
Load a binary file (L). This will load any binary file into memory. Debug+ will not run this file. After you enter the load filename, Debug+ will load the file into memory, then the initial load address will be displayed on the STAT line.
Find a string in memory (F). This command will locate all matches of any string—up to twelve characters in length—in memory. You’ll be asked to enter the string you want to find and press RETURN. Debug+ will clear the screen, and every match of what you typed in will be displayed on the screen, in this format:
FIND # nn Hexadr Decadr
where nn is the find number, and Hexadr and Decadr are the hex and decimal address of the find. The search will continue until the end of memory is reached (address $FFFF or 65535 decimal).
You may find it useful to begin the find at a specific address. To do this, terminate your string with a comma. Debug+ will ask you what address to start from, and the search will begin as described above.
Debug+ has certain “reserved” characters that cannot be entered into your input and consequently can’t be searched for. They are: (1) RETURN (ATASCII 155), (2) DELETE (ATASCII 126), (3) SHIFT-DELETE or DELETE LINE (ATASCII 156), and (4) ESC (ATASCII 27).
All these characters are used by Debug+ as either delimiters or cursor controls. However, all other control characters and alpha-numerics are at your disposal. One other thing: if you wish to search for a character that you usually generate by pressing ESC, then the key (such as clear screen—CTRL-CLEAR), enter it without pressing ESC. So, to enter the clear screen character, just press CTRL-CLEAR.
High speed display (H). This command will continually scroll the display through memory. You’ll be asked what direction to scroll in—up or down—then the scrolling will begin. Use this command if you want to get somewhere very fast, since the screen will move at blinding speed. To pause the scroll, press SPACE; to abort scrolling, press ESC.
Decimal/Hex and Hex/Decimal conversions (.). This command will convert one number base to the other and display the results on the STAT Hue. If a hexadecimal number is entered, a decimal number will be generated, and vice versa. After the number to be converted has been entered, the STAT line will look like this: nnnn = xxxx, where nnnn is what you typed, and xxxx is its converted form.
Scroll up in memory (-). When you press the hyphen key, Debug+ will move the display window up 1 byte in memory. If you’re in memory dump, Debug+ will move the window up 6 bytes in memory.
You may notice that it will usually take several keypresses to scroll up one instruction in memory. This is because Debug+ has no idea where the previous instruction starts, or how many bytes long it is. When this command is executed, the addresses will get lower.
Scroll down in memory (=). This command will move the display window down one full instruction in memory (or 6 bytes in dump mode). When scrolling down. Debug+ knows where the next instruction starts. That’s why it can move down one full instruction. When using this command, addresses in the display window will get higher.
Well, that’s about everything you can do with Debug+. Now let me tell you what you can’t do.
Well, that’s it. Debug+ will run as advertised, unless you break one of the rules I’ve outlined above. It should prove to be an invaluable aid to you in debugging machine language programs.
10 REM *** DEBUG+ *** 20 DIM ML$(151),DAT$(91),BIN$(45):BIN$(45)=" ":TOTAL=0:PASS=TOTAL:LINE=990:? ".CHECKING DATA":POKE 752,1 30 FOR X=1 TO 135:READ N:ML$(X)=CHR$(N ):NEXT X:ML$(136)="0123456789ABCDEF":X =ADR(ML$)+135:N=INT(X/256) 40 ML$(42,42)=CHR$(N):N=X−N*256:ML$(41 ,41)=CHR$(N):RESTORE 1000 50 TRAP 110:LINE=LINE+10:POSITION 2,2: ? "LINE: ";LINE:READ DAT$:IF LEN(DAT$) <>90 THEN 160 60 DATLIN=PEEK(183)+PEEK(184)*256:IF D ATLIN<>LINE THEN ? "LINE ";LINE;" MISS ING!":POKE 752,0:END 70 TOTAL=USR(ADR(ML$),ADR(DAT$),ADR(BI N$),LEN(DAT$),TOTAL):IF TOTAL=65535 TH EN 160 80 IF PASS=2 THEN ? #1;BIN$;:READ CHKS UM:GOTO 50 90 READ CHKSUM:IF TOTAL=CHKSUM THEN 50 100 GOTO 160 110 IF PEEK(195)<>6 THEN 160 120 IF PASS=2 THEN PUT #1,224:PUT #1,2 :PUT #1,225:PUT #1,2:PUT #1,Z:PUT #1,1 61:CLOSE #1:POKE 752,Z:END 130 ? "INSERT DISK WITH DOS, PRESS RET URN":INPUT #16,DAT$:OPEN #1,8,Z,"D:DEB UG.COM" 140 PUT #1,255:PUT #1,255:PUT #1,Z:PUT #1,161:PUT #1,51:PUT #1,184 150 ? ".WRITING FILE":PASS=2:LINE=990: RESTORE 1000:TRAP 110:GOTO 50 160 READ CHKSUM:? :? "BAD DATA":? :? L INE;" DATA ";DAT$;",";CHKSUM:POKE 752, 0:END 170 DATA 104,104,133,204,104,133,203 180 DATA 104,133,206,104,133,205,104 190 DATA 104,133,207,104,133,213,104 200 DATA 133,212,216,160,0,132,210 210 DATA 162,1,134,208,202,134,209,177 220 DATA 203,162,15,221,0,0,240,5,202 230 DATA 16,248,48,75,6,209,6,209,6 240 DATA 209,6,209,138,5,209,133,209 250 DATA 200,198,208,16,224,132,208 260 DATA 164,210,165,209,145,205,164 270 DATA 208,230,210,165,212,24,101 280 DATA 209,133,212,144,2,230,213 290 DATA 165,213,201,4,176,10,201,3 300 DATA 144,19,165,212,201,232,144 310 DATA 13,165,212,56,233,232,133,212 320 DATA 165,213,233,3,133,213,196,207 330 DATA 208,161,96,9,128,145,203,169 340 DATA 255,133,212,133,213,96 1000 DATA D8A50C8D16A2A50D8D17A2AD0802 8D5EB2AD09028D5FB2AD06028D55B2AD07028D 56B2A579057AF00AA5798D9F,837 1010 DATA A9A57A8DA0A9D8A2008E57B28E44 02868D8E0ED486B1E886B286B6BA8EB9B3A9E0 8DF402A9A0856A78A9EB8D06,285 1020 DATA 02A9A68D0702A9598D0802A9A78D 0902A915850CA9A2850D58A200B5009D5AB8BD 00019D5AB9BD00029D5ABAE8,821 1030 DATA D0EC201BA2ADBBB385D4ADBCB385 D520F4A3A9408D0ED42045AE208BA7203AAE20 31AE2029AD2080A92089A929,381 1040 DATA 7FA211DDD8B1F009CA10F82070A2 4CA4A18A0AAABDEAB18DDEA1BDEBB18DDFA120 E5A8204CAC2080A920FFFF4C,947 1050 DATA A4A1A907A062A2E4205CE4AD55B2 8D0602AD56B28D0702AD16A2850CAD17A2850D 78AD5EB28D0802AD5FB28D09,938 1060 DATA 025868686C0A0020FFFF4C33A1A9 008DC602A90A8DC502A9928DC802203DA8A96C 8D3002A9B28D3102A9218D2F,529 1070 DATA 02A907A016A2A74C5CE4A220A90C 9D42034C56E4A90085D485D56085A484A5201E A9A000B1A4C99BF008201DA8,720 1080 DATA 91A2C8D0F2E65460A9648D00D2A9 AA8D01D2A9008514A514C905D0FAA2008E01D2 8E00D2602031AE203AAEA90A,230 1090 DATA 8D1EB3204FA89003686860A000A2 008690B923B8C92ED005E690C8D03D204FA285 88B923B8C99BD00160A20FDD,622 1100 DATA 7BB4F008CA10F868684C70A206D4 26D506D426D506D426D506D426D58A05D485D4 E688A588C905B0DEC84CB7A2,665 1110 DATA 204FA28588B923B8C99BD022A900 85F28489A98085F3A90585F4A688A99B9D8005 2000D8B01220D2D9B00DA489,553 1120 DATA 60A209DD7BB4F008CA10F868684C 70A2C8A6889D8005E6884CF4A2A2008690E886 8420E0A6A58585D4A58685D5,904 1130 DATA A2002060A6A99B8D41B8A0008489 204FA2A8B18585832051A9A58385D4A489C99B F003993AB820B6A6A59EF00D,692 1140 DATA A001B9820509809982058810F5A4 89BE28B2AD82059D23B8AD83059D24B820BBA4 C8C006D0B960208DA2A5D485,189 1150 DATA 8AA5D5858B208DA2A5D4A000918A 60208DA26868A5D48DBBB3A5D58DBCB378A200 BD5AB89500BD5AB99D0001BD,246 1160 DATA 5ABA9D0002E8D0EC58AEB9B39AAD BAB348AEB7B3ACB8B3ADB6B3EE57B2286CBBB3 208DA2A5D4858585A6A5D585,157 1170 DATA 8685A7A90085542076A9201EA9A0 1EB923B8C99BD002A920201DA891A28810EFE6 54A554C901D008A58585A8A5,560 1180 DATA 8685A9A554C90ED0D160A00084A1 8490B18585832051A9A583A000D95CB6F005C8 C097D0F684B020E0A6A58585,908 1190 DATA D4A58685D5A2002060A6204FA2A5 8385D4A2062060A6A4B0BEF3B6A000BDB1B599 35B8E8C8C003D0F4A0018484,153 1200 DATA B1858581C8B1858582A4B0B98BB7 0AA8B90EB28DA1A4B90FB28DA2A420FFFFA027 B923B8C920D0038810F6A99B,522 1210 DATA 9924B8A59EF00320C9A4A5851865 848585A5866900858660A012B923B849809923 B8C8C015D0F36020CAA5A923,164 1220 DATA 8D39B8A9008582A58185D4A58285 D5A2174C60A620CAA54CE1A420CAA520E1A4A0 01E8B9A5B49D24B8CA8810F6,365 1230 DATA 6020CAA520D8A54CE5A4200CA54C FEA4200CA5A92C9D24B8A9599D25B860A90085 8220CAA520E6A5E8A002D0C8,36 1240 DATA A900858220CAA520E6A5A002B9A8 B49D24B8E88810F660A9418D39B86020CAA5E6 84204FA2E6A1A91D8D34B8A5,969 1250 DATA 811012CE34B8297F497F18690185 9B38E9024C7CA5859BA5811010A58538E59B85 D4A586E90085D54C9BA51865,112 1260 DATA 8585D4A586690085D5A9021865D4 85D4859FA5D5690085D585A020EDA4C6846020 CAA520D8A520E6A5A9299D24,108 1270 DATA B86020CAA520E1A44C1EA5E68420 4FA2A58185D4A20A4C60A6E684204FA2A58285 D4A20E4C60A6A9288D39B84C,719 1280 DATA E5A4204FA284D484AD2070A220E0 A620AAD920E6D8A0FFA2FFC8E8B1F39D23B810 F7297F9D23B8A99B9D24B886,361 1290 DATA 87A211BDFFB3C5ADF005CA10F630 2A8A0AAABD12B48582BD11B48581A0FFA687A9 2C9D24B8E8C8E8B1819D24B8,736 1300 DATA 10F7297F9D24B8A99B9D25B8A90E 855420E5A8A923A0B84C56A2CA868CA590F019 20AAD920E6D8A68CA0FFC8E8,47 1310 DATA B1F39D23B810F7297F9D23B86020 B6A6A68CE8F01EE014B00EAD82059D23B8E8AD 83059D23B860A9249D23B8E8,878 1320 DATA A584C902F0E6A000B980059D23B8 E8C8C004D0F4CA60A000A2018691A9F035D44A 4A4A4AAABD7BB4998005C8A6,966 1330 DATA 91A90F35D4AABD7BB4998005C8A6 91CA10DB60A920A2279D23B8CA10FA60AD57B2 D0026840D88EB7B38CB8B368,37 1340 DATA 8DB6B3688DBAB36838E9028DBBB3 68E9008DBCB3BA8EB9B3584C4AA7EE6EB8D008 EE6DB8D003EE6CB8A5B2D020,596 1350 DATA AD2B02F008A93F85B4A93C85B3A5 B4C6B3D008A01E84B3493F85B4A4879920B34C 62E408AA6829EF4828A9008D,85 1360 DATA 57B24C33A1AD57B2F02AAD09D2C9 9CD0238CB8B38EB7B3A9FF8DFC02688DB6B368 8DBAB3688DBBB3688DBCB3BA,801 1370 DATA 8EB9B3584C4AA76C5EB2A0008489 204FA2B9B6B385D420B6A6A489BE50B2AD8205 38E9209DF6B2AD830538E920,654 1380 DATA 9DF7B2C8C004D0D7ADBBB385D4AD BCB385D520B6A6A003B9800538E92099F6B288 10F4A211A007ADBAB339C7B3,299 1390 DATA F004A911D002A9109DF6B2E88810 EBA9118D09B360A007B949B4991EB38810F720 89A9A004D962B4F0058810F8,943 1400 DATA 30F1980AA8B9BDB385D4B9BEB385 D520A0A34C8BA7202FA81DCFB3A6AA60202FA8 1DD3B3A6AA60482A2A2A2A29,570 1410 DATA 0386AAAA68299F60A900AA9D00BD 9D00BE9D00BFE8D0F4855460A900858785B220 3AAE20E0A62089A9C91BD004,36 1420 DATA E6B23860A48DD010A028D976B4F0 098810F82070A24C5BA8C97ED024C6871007A9 0085872070A220DAA8A587F0,758 1430 DATA CBA487C00CD00188A9009920B399 21B34C5BA8C99CF0A9A4879923B8C99BF01920 1DA8C00CD001889920B3C8C0,634 1440 DATA 0D900188848720DAA84C5BA8AD23 B8C99BF080A900858D9920B3E6B21860A587D0 068D20B38D21B360A017A900,66 1450 DATA 993EB38810FA60A909A2209D4203 A9239D4403A9B89D4503A9289D4803A9009D49 03AD3AB8100320C9A42056E4,590 1460 DATA 30016068684C45A2A5540AAABD2E B285A2BD2FB285A360A5B1490185B1D008A901 85B6A921D006A90685B6A930,743 1470 DATA 8D13B3A5A685D4A5A785D54CF4A3 A900859EA005A586D9DDB3D014A585D9D7B3D0 0DB9E9B3F008B9E3B38583E6,748 1480 DATA 9E608810E260A5B1D0034C34A44C 37A3A90085B9A94085BA60ADFC02C9FFF0F9A2 FF8EFC0285B7A8C0C09002A0,109 1490 DATA 9AB9FEFE85B8C980F0E2C981D009 A5B9498085B94C89A9C982D009A5BA494085BA 4C89A9C983D006A94085BAD0,909 1500 DATA BEC984D006A98085BAD0B4C985F0 B0A5B7C940B013A5B8C961900DC97BB009A5BA F00505B74C97A9A20FBDEFB3,485 1510 DATA C5B8F003CA10F6F006A5B845B985 B860A9008514A514C90FD0FA60AEB9B3E8BD5A B98585E8BD5AB985868EB9B3,81 1520 DATA 4CBBA4A58538E90148A586E900AE B9B39D5AB9CA689D5AB9CA8EB9B3A001B1AE85 85C8B1AE858660208DA2A5D4,520 1530 DATA 8585A5D58586203AAEA007B941B4 991EB38810F784802089A9C946D004E680F00C C953F008C94FD0EDA9018580,432 1540 DATA 203DA8203AAE2031AEA5858DBBB3 85AEA5868DBCB385AF2034A420F7ACA002A9EA 99A5AB8810FA2007AD208BA7,144 1550 DATA AD35B8100A20F2ACA967A0B44C56 A2C93FD005A0974CEEA5A583C960D0062012AA 4CF3ABC940D01EAEB9B3EEB9,210 1560 DATA B3BD5AB98DBAB3E8BD5AB98585E8 BD5AB985868EB9B34CF3ABC94CD0062040AA4C F3ABC920D0062027AA4CF3AB,705 1570 DATA C96CD0132040AAA000B18548C8B1 8585866885854CF3ABA5A1F02FA583A003D960 B2F01BD964B2F0038810F3AD,822 1580 DATA BAB33968B2F008A59F8585A5A085 864CF3ABADBAB33968B2F0ED4CF3ABA000B1AE 99A5ABC8C484D0F6A9008D0E,596 1590 DATA D478A200B500A8BD5AB89500989D 5AB8BD0001A8BD5AB99D0001989D5AB9BD0002 A8BD5ABA9D0002989D5ABAE8,998 1600 DATA D0D5BA8AAEB9B39A8DB9B3ACB8B3 AEB7B3ADBAB348ADB6B328EAEAEA088DB6B368 8DBAB38EB7B38CB8B3BA8AAE,522 1610 DATA B9B39A8DB9B378A200B500A8BD5A B89500989D5AB8BD0001A8BD5AB99D0001989D 5AB9BD0002A8BD5ABA9D0002,918 1620 DATA 989D5ABAE8D0D558A9408D0ED420 8BA7A5803013F014A2088E1FD0AD1FD0C903D0 F98E1FD0D0032007AA4C87AA,608 1630 DATA A90085A4A9BD85A5A5A418692085 81A5A569008582A200A01FB18191A48810F9A5 8285A5A58185A41869208581,156 1640 DATA A58269008582E8E00ED0DF60A017 A900995EB38810FA60A59085B0A9038584208D A2A9209923B89925B8A93DC8,859 1650 DATA 9923B8C884AAA59049018590A21C 2060A68687A21CA4AABD23B89924B8E487F004 E8C8D0F2A99B9925B820F2AC,84 1660 DATA A5B085904C59A6208DA2A5D48592 A5D58593208DA2A000A5D5C5939023D008A5D4 C592901BF015989192E692D0,473 1670 DATA 02E693A5D5C593D0F1A5D4C592D0 EB98919260A0994CEEA585818482A000B18199 1EB3C91FF003C8D0F460A90F,276 1680 DATA 855460A554C90ED0072013ACA90D 85544C59A6ADFC02C9FFF01B2029ADC91CF012 C921D0102029ADADFC02C921,469 1690 DATA F006C91CD0F5686848A9FF8DFC02 6860A93BA0B420DFAC2089A9C955D006A90185 BBD008C944D0EFA90085BB20,472 1700 DATA 31AE203AAE2007ADA5BBF0062021 AE4C53AD20D1AD4C53AD201DB1208DA2A90820 F2B0A5D48585A5D585862034,658 1710 DATA A4A9208D34B8AD35B8100320C9A4 20F0A8204CAC20F2ACA99B8D29B82059A6ADFC 02C9FFF0D82029AD204CAC4C,310 1720 DATA 45A2203AAEA935A0B420DFAC2089 A9C91BD0056868686860A001D951B4F0098810 F82070A24CB4AD60A2008A0A,514 1730 DATA A8B92EB2858EB92FB2858FA000B1 8EF030E8E00ED0E82076A920FDACA201BD00BD 2026A8C920F0069D22B8E8D0,578 1740 DATA F0A99B9D22B8A00020B2A2A5D485 A6A5D585A760A5A885D4A5A985D54CF4A3A5A6 38E5B685D4A5A7E90085D54C,470 1750 DATA F4A3A9008D1EB38D1FB360A014A9 009920B38810FA60A00084B58489B9D7B385D4 B9DDB385D520B6A6A489BE58,610 1760 DATA B2A000B9800538E9209D96B3E8C8 C004D0F1A489B9E9B3D002E6B5C8C006D0CDA5 B51869108DB5B3602031AEA9,992 1770 DATA 228D1EB3204FA8900160AD23B838 E931AAC906B024C9009020AD24B8C99BF034A0 02868C20A2A2A68CA000B1D4,280 1780 DATA F005BDE9B3F008A0984CEEA54C70 A2A5D49DD7B3A5D59DDDB3B1D49DE3B39891D4 FEE9B34C45AE2031AEA000BD,428 1790 DATA E9B3F01CBDD7B38581BDDDB38582 BDE3B39181989DE9B39DD7B39DDDB34C45AEA0 964CEEA52031AEA91F8D1EB3,416 1800 DATA 858D204FA8900160A000B923B8C9 9BF00CC92CF008994BB8C8C00CD0ED8480C92C D014208DA2A5D438E9018592,150 1810 DATA A5D5E9008593A0FFD006A0FF8492 8493C8849C84948495203DA8A5921869018592 A59369008593C9B8D00EA592,287 1820 DATA C923D008A95A8592A9BB8593A59C F007A5920593D00160A001849C88B192D94BB8 D0CAC8C480D0F420E0A6A205,608 1830 DATA BD9FB49D23B8CA10F7A59285D4A5 9385D520B6A6A003A211B980059D23B8CA8810 F6A9249D23B8A99B8D35B8E6,820 1840 DATA 94D002E695A59485D4A59585D5A2 0786902060A62007AD20F7AC4C57AFA9442020 B1A9008580A907859DA90420,196 1850 DATA F2B02077B0300EAD4EB2C9FFD005 CD4FB2F00CA09584892045A2A4894CEEA52077 B0A580D00CAD4EB285D4AD4F,302 1860 DATA B285D5E68020D6B020C0B02077B0 20CBB020A5B020E7B030034C10B098482045A2 68C988D02F20E0A6A006B9AB,2 1870 DATA B49923B88810F720B6A6A003A20C B980059D23B8CA8810F6A9249D23B8A99B8D30 B820F2AC4C59A6A84CEEA5A9,835 1880 DATA 4E8592A9B28593A9008599A90285 98A220A59D9D4203A5929D4403A5939D4503A5 989D4803A5999D49034C56E4,42 1890 DATA A59638E5948598A597E5958599A5 981869018598A5996900859960AD4EB28594AD 4FB2859560AD4EB28596AD4F,74 1900 DATA B2859760AE4EB2E8F00160AE4FB2 E8F001604C77B0A5948592A59585934C87B085 9C2045A2A59CA2209D4A03A9,45 1910 DATA 009D4B03A9039D4203A9539D4403 A9B49D45032056E430016068684CEEA520AAAD 488D53B4A99B8D55B468C944,868 1920 DATA F001602031AEA91F8D1EB3204FA8 9003686860A202A000B923B8C92CF014C99BF0 109D53B4C8E8E012D0ECA0A5,448 1930 DATA 68684CEEA5A99B9D53B460A94420 20B1A90B859D208DA2A5D48594A5D58595208D A2A5D48596A5D58597C59590,723 1940 DATA 45F002D006A596C594903BA90820 F2B0A9FF8D4EB28D4FB22077B0302BA5948D4E B2A5958D4FB22077B0301CA5,365 1950 DATA 968D4EB2A5978D4FB22077B0300D 20A5B020E7B030054C45A2A09998482045A268 A84CEEA55144524E2A43474C,302 1960 DATA 5342542D3D4650482E45E3A12DA9 8BA7F0A7F1A39DA3B2A3E1AF64B185AE4CAA21 AED1AD08AF66AD31AD57ACA1,277 1970 DATA ACD9A4F2A4F8A40CA515A51BA529 A538A54FA555A5B1A5B2A5C1A505080B0E1114 01BD21BD41BD61BD81BDA1BD,862 1980 DATA C1BDE1BD01BE21BE41BE61BE81BE A1BE3EB35EB3000005080B0E1100000000050A 0F14190000105090D03070B0,712 1990 DATA F0804001027070704296B2000220 4200BD020202020202020202020202022042D6 B20200020002000200020241,759 2000 DATA 6CB28080A4A5A2B5A78B80808080 E2F99A80A2F2F9E1EE80B3E3E8E1F0F0E5EC80 8080A1A4A4B28080A2918080,470 2010 DATA A2928080A2938080ADAEA5ADAFAE A9A3B3808080808080B0A3FC80A1FC80B8FC80 B9FCB3B0FCAEB6BFA2A4A9BA,8 2020 DATA A3FCADAFA4A58080000000007C00 007C00007C00007C00007C0000000000000000 7C24293321000080A9AEB0B5,89 2030 DATA B49A000000000000000000000000 0000000000000000000000000080A5B2B2AFB2 9A0000000000000000000000,579 2040 DATA 0000000000000000000000000000 8080B3B4A1B49A000000000000000000000000 000000000000000000000000,689 2050 DATA 00A2B2AB91FCA2B2AB92FCA2B2AB 93FCA2B2AB94FCA2B2AB95FCA2B2AB96FCA6B2 000000007C000000007C0000,744 2060 DATA 00007C000000007C000000007C00 0000007C101000000000000000B6B3B7B3B8B3 B9B3BAB30102040810204080,342 2070 DATA 4000206020400060000000000000 000000000000000000000000000000000000FF FEFD9F9E9D9C9B7F7E7D1F1E,712 2080 DATA 1D1C1B8082898A8B9092A2A4A5A7 A9AA9596979899B2B4C1B4D2B4E2B4F0B4FAB4 09B51AB523B534B541B54CB5,236 2090 DATA 5AB568B577B587B595B5A2B50824 0C30091F08350C24091F08330C260C2F091F08 2138393330091F4450203A20,145 2100 DATA 20202020202020202020209B4158 59535042524B20504F494E5420464F554E449B 9C7E2C2E3031323334353637,57 2110 DATA 38394142434445464748494A4B4C 4D4E4F505152535455565758595A46494E4420 232C5829592C294C4F414420,208 2120 DATA 4154425245414B204B4559204142 4F52D44E4F204445564943452048414E444C45 D25452554E43415445442052,602 2130 DATA 45434F52C4444556494345205449 4D454F55D4444556494345204E41CB57524954 452050524F5445435445C446,355 2140 DATA 554E4354494F4E204E4F5420444F 4EC54449534B2046554CCC46494C45204E554D 204D49534D415443C8424144,909 2150 DATA 2046494C45204E414DC546494C45 204C4F434B45C44449524543544F5259204655 4CCC46494C45204E4F542046,383 2160 DATA 4F554EC446494C45204E4F542042 494E4152D94E4F205345542042524B20504F49 4ED4494E56414C4944204F50,939 2170 DATA 434F44C542524B20504F494E5420 5345D44144522052414E4745204552524FD241 4443414E4441534C42434342,462 2180 DATA 4353424551424954424D49424E45 42504CC2D2CB425643425653434C43434C4443 4C49434C56434D5043505843,155 2190 DATA 5059444543444558444559454F52 494E43494E58494E594A4D504A53524C44414C 44584C44594C53524E4F504F,607 2200 DATA 5241504841504850504C41504C50 524F4C524F5252544952545353424353454353 454453454953544153545853,78 2210 DATA 5459544158544159545358545841 5458535459413F3F3F6965756D7D7961712925 352D3D3921310A06160E1E90,390 2220 DATA B0F0242C30D01000507018D858B8 C9C5D5CDDDD9C1D1E0E4ECC0C4CCC6D6CEDECA 884945554D5D594151E6F6EE,322 2230 DATA FEE8C84C6C20A9A5B5ADBDB9A1B1 A2A6B6AEBEA0A4B4ACBC4A46564E5EEA090515 0D1D190111480868282A2636,476 2240 DATA 2E3E6A66766E7E4060E9E5F5EDFD F9E1F138F87885958D9D99819186968E84948C AAA8BA8A9A98000000000000,463 2250 DATA 0000030303030303030306060606 06090C0F121215181B1E2124272A2D30333333 33333333333636363939393C,735 2260 DATA 3C3C3C3F42454545454545454548 4848484B4E51515457575757575757575A5A5A 5A5A5D5D5D5D5D6060606060,374 2270 DATA 636666666666666666696C6F7275 7575757578787878787B7E8181818181818181 84878A8D8D8D8D8D8D8D9090,873 2280 DATA 9093939396999C9FA2A5A8000102 03040506070001020304050607080102030409 090901030909090A09090A0A,751 2290 DATA 0A0A000102030405060700010300 0103010203040A0A0001020304050607010203 040A0A030B03000102030405,927 2300 DATA 060700010C030500010203040801 0203040A00010203040506070A0A0A0A080102 030408010203040A0A000102,126 2310 DATA 03040506070A0A0A010203040506 07010C030102030A0A0A0A0A0A0A0000000000 000000000000000000000000,301 2320 REM * 5940 BYTES
; DEBUG+
;
;This is an all machine
;language disassembler and
;program tracer written with
;OSS MAC/65.
;
;Written by: Bryan Schappel
;
;COMMANDS:
;
;D = display toggle
;C = change memory
;* = display address set
;Q = go to DOS
;G = run at address
;R = display registers
;N = change registers
;S = save binary file
;L = load binary file
;T = trace program
;U = un-used break points
;H = high speed display
;. = hex/dec, dec/hex convert
;B = set break point
;O = restore break point
;- = scroll up in memory
;= = scroll down in memory
;P = disassemble to device
;E = erase memory
;F = find memory
;
;** EQUATES **
;
CIOV = $E456 ;Central I/O
ICCOM = $0342 ;commamd
ICBAL = $0344 ;buf adr lo
ICBAH = $0345 ;buf adr hi
ICBLL = $0348 ;buf len lo
ICBLH = $0349 ;buf len hi
AUX1 = $034A ;aux byte 1
AUX2 = $034B ;aux byte 2
COLPF2 = $02C6 ;bkgrnd
COLPF1 = $02C5 ;text
RAMTOP = $6A ;top of RAM
CONSOL = $D01F ;consol keys
LBUFF = $0580 ;I/O buffer
PUTRC = $09 ;put rec com
EOL = $9B ;end of line
DOSVEC = $0A ;DOS jmp vec
FR0 = $D4 ;float point
AFP = $D800 ;asc to fp
FASC = $D8E6 ;fp to asc
IFP = $D9AA ;int to fp
AUDF1 = $D200 ;so. chan 0
AUDC1 = $D201 ;distortion
RTCLOK = $14 ;jiffy clock
INBUFF = $F3 ;fp result
CIX = $F2 ;fp offset
FPI = $D9D2 ;fp to int
SETVBV = $E45C ;set vblank
XITVBV = $E462 ;xit vblank
NMIEN = $D40E ;interupt go
VBRK = $0206 ;BRK vector
ZPAGE = $00 ;zero page
STACK = $0100 ;hardware stack
PAGE2 = $0200 ;page 2
ROWCRS = $54 ;y-pos
CH = $02FC ;key press
SDLSTL = $0230 ;display list
SRTIMR = $022B ;key debounce
SDMCTL = $022F ;DMA control
DOSINI = $0C ;dos init vec
COLDST = $0244 ;cold start flag
VKEYBD = $0208 ;keyboard vector
KBCODE = $D209 ;key code
KEYDEF = $79 ;key code>ascii
CHBAS = $02F4 ;character base
DDEV = $20 ;D:
;
;** PROGRAM EQUATES **
;
*= $80
SLFS .DS 1 ;slow or fast
INDR .DS 2 ;addr of mne
OP .DS 1 ;opcode
NBYTE .DS 1 ;command bytes
ADDR .DS 2 ;disa address
CEND .DS 1 ;command end
GDIGS .DS 1 ;# of digits
SAVEY .DS 1 ;temp save
SMEM .DS 2 ;temp addr
CNTLO .DS 1 ;nbyte count
NCHK .DS 1 ;check keys?
TEMP .DS 2 ;temp store
HXDC .DS 1 ;hex/dec flag
SAVEX .DS 1 ;temp X save
SL .DS 2 ;buffer address
STL .DS 2 ;start address
ENL .DS 2 ;end address
BLL .DS 2 ;buffer length
DINS .DS 2 ;2 byte arg
DISKC .DS 1 ;disk command
DISKC2 .DS 1 ;read/write?
BSET .DS 1 ;break point
BRAN .DS 2 ;branch adr
BRAFLG .DS 1 ;branck flag
SCR .DS 2 ;scr mem
IND2 .DS 2 ;indr 2
TOPADR .DS 2 ;top disa adr
LN2 .DS 2 ;2nd disa adr
SAVX2 .DS 1 ;temp X
IND3 .DS 2 ;temp addr save
ERRNUM .DS 1 ;I/O error #
SAVD .DS 2 ;trace save adr
SAVY2 .DS 1 ;temp Y 2
DTYPE .DS 1 ;display type
IPUT .DS 1 ;input flag
BLINK .DS 1 ;blink rate
CSHAPE .DS 1 ;cursor shape
FREN .DS 1 ;free brk pnts
BBCK .DS 1 ;bytes back
OLDC .DS 1 ;old key press
OLDAC .DS 1 ;old asc convert
INVS .DS 1 ;inverse flag
CAPS .DS 1 ;caps flag
PGWAY .DS 1 ;scroll dir
;
*= $A100 ;Cartridge
;
;------------
;DISASSEMBLER
;------------
DISA CLD ;no decimal.
LDA DOSINI ;save DOS INIT
STA MYINIT+1
LDA DOSINI+1
STA MYINIT+2
LDA VKEYBD ;copy keybrd adr
STA TKEY ;to hold
LDA VKEYBD+1
STA TKEY+1
LDA VBRK ;copy VBRK vec
STA BRKS ;to hold area
LDA VBRK+1
STA BRKS+1
LDA KEYDEF ;test 800 or XL?
ORA KEYDEF+1
BEQ REINIT ;have 800
LDA KEYDEF ;copy keycode to
STA K1+1 ;ascii table adr
LDA KEYDEF+1 ;to my program
STA K1+2
;
REINIT CLD
LDX #0 ;get 0
STX EXEC ;no run.
STX COLDST
STX NCHK ;check keys
STX NMIEN ;no interupts.
STX DTYPE ;display type
INX
STX IPUT
STX BBCK
TSX ;get stk pntr
STX USRS ;save.
LDA #$E0 ;restore char
STA CHBAS ;set
LDA #$A0 ;set RAMTOP on
STA RAMTOP ;my program
SEI
LDA #<BRKER ;point BRK hand
STA VBRK ;to my routine.
LDA #>BRKER
STA VBRK+1
LDA #<MKEYV ;replace keybrd
STA VKEYBD ;interrupt with
LDA #>MKEYV ;mine
STA VKEYBD+1
LDA #<MYINIT ;point RESET
STA DOSINI ;vec to my prog.
LDA #>MYINIT
STA DOSINI+1
CLI
LDX #0
C123 LDA ZPAGE,X ;now copy the
STA MYZPG,X ;first 3 pages
LDA STACK,X ;of RAM to my
STA MYPG1,X ;buffers.
LDA PAGE2,X ;(For TRACER)
STA MYPG2,X
INX
BNE C123
JSR OPSCR ;open screen
LDA USRPC ;now disa from
STA FR0 ;the users PC
LDA USRPC+1
STA FR0+1
JSR TOEDEV
LDA #$40 ;interupts on.
STA NMIEN
JSR FREBRK ;sho BRK points
JSR DOREGS ;and registers.
;
;Wait here for command
;
GETCOM JSR CLRWIN ;clear com
JSR CLRCMD ;and prompt
JSR CLRKEY
JSR SETKEY ;set keys
JSR GETKEY ;get a key
AND #$7F ;no inverse
LDX #17 ;scan 18 coms
GC2 CMP CMDTXT,X ;is it a com?
BEQ HAVCOM ;yes.
DEX ;no.
BPL GC2 ;18 coms yet?
JSR GOTERR ;sorry error.
JMP GETCOM ;go again.
HAVCOM TXA
ASL A ;mult * 2
TAX
LDA CMDADR,X ;get command
STA CMDJSR+1 ;address from
LDA CMDADR+1,X ;the table
STA CMDJSR+2 ;put in JSR
JSR CLRERR ;erase error.
JSR ERASTAT ;and status.
JSR SETKEY
CMDJSR JSR $FFFF ;go command!
JMP GETCOM ;get next one.
;
;This is the go DOS command
;
DOSCMD LDA #7 ;kill VBLANK
LDY #<XITVBV
LDX #>XITVBV
JSR SETVBV
LDA BRKS ;restore the
STA VBRK ;BRK vector.
LDA BRKS+1
STA VBRK+1
LDA MYINIT+1 ;restore RESET
STA DOSINI ;vector
LDA MYINIT+2
STA DOSINI+1
SEI
LDA TKEY ;restore key-
STA VKEYBD ;board interrupt
LDA TKEY+1
STA VKEYBD+1
CLI
PLA ;pull off RTS
PLA
JMP (DOSVEC) ;go DOS
;
;Re-init prog after RESET
;
MYINIT JSR $FFFF ;changed
JMP REINIT
;
;Open new screen
;
OPSCR LDA #0 ;black
STA COLPF2 ;background
LDA #10 ;white text
STA COLPF1
LDA #146 ;blue borders
STA COLPF2+2
JSR CLRSCR ;clear screen
LDA #<DLIST ;install my
STA SDLSTL ;Display List
LDA #>DLIST
STA SDLSTL+1
LDA #33 ;screen on
STA SDMCTL
LDA #7 ;def. mode
LDY #<VBI ;point to my VBI
LDX #>VBI
JMP SETVBV ;set it!
;
;This routine closes IOCB two.
;(Device IOCB.)
;
DCLOSE LDX #DDEV ;Device
LDA #12 ;close command
STA ICCOM,X ;store it
JMP CIOV ;close it.
;
;Zero FR0
;
ZFR LDA #0 ;zero floating
STA FR0 ;point regs.
STA FR0+1
RTS
;
;General use print routine
;
EPRINT STA IND2 ;address of mem
STY IND2+1 ;to 'print'.
JSR CLCLN ;get line adr
LDY #0 ;zero loop.
PRL LDA (IND2),Y ;get char
CMP #EOL ;is EOL?
BEQ PRD ;yes. finished.
JSR ASC2IC ;no. make icode
STA (SCR),Y ;on screen
INY ;up loop.
BNE PRL ;go again.
PRD INC ROWCRS ;up y-pos.
RTS ;bye.
;
;Error routine
;
GOTERR LDA #100 ;nice tone.
STA AUDF1
LDA #$AA ;no distortion
STA AUDC1
LDA #0 ;leave it on
STA RTCLOK ;for 5 jiffies.
TONE LDA RTCLOK
CMP #5
BNE TONE
LDX #0 ;turn it off.
STX AUDC1
STX AUDF1
RTS ;bye.
;
;Fetch address
;
GADR JSR CLRCMD ;clear prompt
JSR CLRWIN ;and window
LDA #10 ;a '*'
STA COMND
JSR INPUT ;get INPUT
BCC GDNM ;good input
PLA ;pull off RTS
PLA
RTS ;next command
GDNM LDY #0
GTDR LDX #0
STX HXDC ;signal hex #
LDA MYBUF,Y ;first char.
CMP #'. ;a '.'?
BNE GET4 ;no. in hex
INC HXDC ;signal dec #
INY
BNE GNUM ;get decimal
;
;Pull out a 4 byte hex address
;
GET4 JSR ZFR ;zero fp regs
STA GDIGS
G4LOOP LDA MYBUF,Y ;pull char
CMP #EOL ;at end?
BNE TESTIT ;no.
RTS ;bye.
TESTIT LDX #$0F ;do 16 digits.
G4SCAN CMP HEXDIG,X ;is it in
BEQ GOTG4D ;the Hex table?
DEX ;no. try next.
BPL G4SCAN ;go again.
G4ERR PLA ;Not in table,
PLA ;we have an
JMP GOTERR ;error. Sorry.
GOTG4D ASL FR0 ;multiply #
ROL FR0+1 ;by a factor
ASL FR0 ;of 16.
ROL FR0+1
ASL FR0
ROL FR0+1
ASL FR0
ROL FR0+1
TXA ;add digit
ORA FR0 ;to the
STA FR0 ;current addr
INC GDIGS ;up digs done
LDA GDIGS ;get it.
CMP #5 ;more than 4
BCS G4ERR ;yes. error.
INY ;do next one
JMP G4LOOP ;do again.
;
;Get out a decimal number
;
GNUM JSR ZFR ;zero fp regs
STA GDIGS
DONUM LDA MYBUF,Y ;pull char
CMP #EOL ;EOL?
BNE GTEST ;no.
LDA #0 ;index to str
STA CIX ;is zero
STY SAVEY
LDA #<LBUFF ;point INBUFF
STA INBUFF ;to LBUFF
LDA #>LBUFF
STA INBUFF+1
LDX GDIGS ;install EOL
LDA #EOL ;for safety
STA LBUFF,X
JSR AFP ;to fp
BCS GNERR ;error?
JSR FPI ;to integer
BCS GNERR ;error?
LDY SAVEY ;restore Y
RTS ;bye.
GTEST LDX #9 ;scan 10 digs.
GNSCAN CMP HEXDIG,X ;in table
BEQ GOTGN ;have digit
DEX ;try next
BPL GNSCAN
GNERR PLA ;error
PLA ;bad digit
JMP GOTERR
GOTGN INY ;up char index
LDX GDIGS ;save char in
STA LBUFF,X ;LBUFF.
INC GDIGS ;next digit
JMP DONUM ;go again
;
;Show memory contents
;
SHOMEM LDX #0 ;pos. 2,0
STX HXDC
INX
STX NBYTE
JSR ZBUF ;blank buffer
LDA ADDR ;in fp for
STA FR0 ;hex convert
LDA ADDR+1
STA FR0+1
LDX #0 ;at pos 0
JSR COPYNUM ;copy number
LDA #EOL ;insert EOL
STA MYBUF+30
LDY #0 ;Y = 0
COPY2 STY SAVEY ;save y
JSR ZFR ;Zero FR0
TAY ;Y = 0
LDA (ADDR),Y ;number
STA OP ;make digit
JSR FNDBRK ;BRK point?
LDA OP ;put op in FR0
STA FR0
LDY SAVEY ;restore index
CMP #EOL ;have EOL?
BEQ GOL ;yes. leave it.
STA MYBUF+23,Y ;save char
GOL JSR BIN2HEX ;make it hex
LDA BSET ;is this BRK?
BEQ NN1 ;point? no.
LDY #1 ;yes. make #
NN0 LDA LBUFF+2,Y ;inverse
ORA #$80 ;video.
STA LBUFF+2,Y
DEY
BPL NN0
NN1 LDY SAVEY ;insert in buf.
LDX STRPOS,Y ;get position
LDA LBUFF+2 ;first digit
STA MYBUF,X ;in buffer
LDA LBUFF+3 ;second digit
STA MYBUF+1,X ;in buff.
JSR NSET ;add 1 to addr
INY ;up count
CPY #6 ;done 6?
BNE COPY2 ;no.
RTS ;bye.
;
;Handle Change memory
;
CHGMEM JSR GADR
CREG LDA FR0 ;copy fp to
STA SMEM ;zpage for
LDA FR0+1 ;lookup
STA SMEM+1
JSR GADR ;get number
LDA FR0 ;take LSB
LDY #0
STA (SMEM),Y ;poke it in
RTS
;
;Go memory routine
;
GMEM JSR GADR ;run address
PLA
PLA
LDA FR0 ;copy RUN addr
STA USRPC ;for later
LDA FR0+1
STA USRPC+1
SEI ;kill interrupts
LDX #0
C321 LDA MYZPG,X ;copy USER RAM
STA ZPAGE,X ;back for the
LDA MYPG1,X ;run.
STA STACK,X
LDA MYPG2,X
STA PAGE2,X
INX
BNE C321
CLI
LDX USRS ;restore user
TXS ;registers
LDA USRP
PHA
LDX USRX ;restore X
LDY USRY ;and Y
LDA USRA ;and Acc
INC EXEC ;set RUN flag
PLP ;restore status
JMP (USRPC) ;RUN!
;
;Disassemble Memory
;
DISMEM JSR GADR ;get adr
TOEDEV LDA FR0 ;move in addr
STA ADDR
STA TOPADR ;top line
LDA FR0+1 ;hi byte
STA ADDR+1
STA TOPADR+1
LDA #0 ;pos.0
STA ROWCRS
DMEM JSR FINLIN ;disa it
JSR CLCLN ;screen line
LDY #30
DM3 LDA MYBUF,Y
CMP #EOL ;make EOL space
BNE CON2
LDA #32
CON2 JSR ASC2IC ;make icode
STA (SCR),Y ;on screen
DEY
BPL DM3 ;do next
INC ROWCRS ;up ypos.
LDA ROWCRS ;get it
CMP #1 ;second line?
BNE SECLN ;no.
LDA ADDR ;set LN2 pntr
STA LN2
LDA ADDR+1
STA LN2+1
SECLN LDA ROWCRS ;done 14 yet?
CMP #14
BNE DMEM ;no.
RTS ;yes.
;
;Memory disassembler
;
DISAMEM LDY #0 ;zero Y
STY BRAFLG ;no branch
STY HXDC ;in hex
LDA (ADDR),Y ;get opcode
STA OP ;and save
JSR FNDBRK ;BRK point?
LDA OP ;get op
LDY #0 ;zero Y
FNDOP CMP OPCODE,Y ;is op in
BEQ HAVOP ;the opcode
INY ;table?
CPY #151 ;151 yet?
BNE FNDOP ;no.
HAVOP STY SAVY2 ;save Y
JSR ZBUF ;clear buffer
LDA ADDR ;copy addr
STA FR0 ;to FP
LDA ADDR+1
STA FR0+1
LDX #0 ;pos. 0
JSR COPYNUM ;copy it
JSR ZFR ;clear FP
LDA OP ;get op
STA FR0 ;in FP
LDX #6 ;pos 8
JSR COPYNUM ;copy it
LDY SAVY2 ;get Y
LDX OFFSET,Y ;MNE offset
LDY #0 ;copy out the
ADMNE LDA MNE,X ;Mnemonic and
STA MYBUF+18,Y ;put in
INX ;buffer.
INY
CPY #3 ;3 chars?
BNE ADMNE ;no.
LDY #1 ;Y = 1
STY NBYTE ;1 byte instr
LDA (ADDR),Y ;copy next 2
STA INDR ;possible
INY ;instruction
LDA (ADDR),Y ;bytes to temp
STA INDR+1 ;hold address.
LDY SAVY2 ;restore Y
LDA ITYPE,Y ;get Itype
ASL A ;times 2
TAY ;in Y
LDA DCOMT,Y ;look up the
STA DJSR+1 ;routine addr
LDA DCOMT+1,Y ;an put in
STA DJSR+2 ;JSR
DJSR JSR $FFFF ;go command!
LDY #39 ;now insert the
AEOL3 LDA MYBUF,Y ;the EOL
CMP #32 ;character
BNE AEOL2
DEY
BPL AEOL3
AEOL2 LDA #EOL
STA MYBUF+1,Y
LDA BSET ;brk point?
BEQ NSET ;no.
JSR INV2 ;inverse it
NSET LDA ADDR ;now add the
CLC ;number of
ADC NBYTE ;byte to the
STA ADDR ;adr pointer
LDA ADDR+1 ;to get next
ADC #0 ;instr addr.
STA ADDR+1
RTS ;bye.
;
;Inverse Mnemonics
;
INV2 LDY #18 ;start w/ 18th
INVL LDA MYBUF,Y ;get char
EOR #$80 ;flip bit 7
STA MYBUF,Y ;store in buff
INY ;up index
CPY #21 ;21st yet?
BNE INVL ;not done
RTS ;done.
;
;Immediate Mode
;
IMMED JSR LOBYTE ;insert LSB
LDA #'# ;a '#'
STA MYBUF+22 ;in buffer
NUMBR LDA #0 ;zero MSB
STA INDR+1
NUMBR2 LDA INDR ;put in FR0
STA FR0
LDA INDR+1
STA FR0+1
NUMBR3 LDX #23 ;put in arg
JMP COPYNUM
;
;Zero page
;
ZPAG JSR LOBYTE ;do LSB
JMP NUMBR ;add arg
;
;Zero page,X
;
ZPAGX JSR LOBYTE ;LSB
JSR NUMBR ;add arg
ADDX2 LDY #1 ;just ,X
ADDX INX ;up X
ADDX3 LDA COMMAX,Y ;copy the
STA MYBUF+1,X ;,X into
DEX ;the buffer
DEY
BPL ADDX3
RTS ;done.
;
;Absolute
;
ABSOL JSR LOBYTE ;LSB
JSR HIBYTE ;MSB
JMP NUMBR2 ;add arg
;
;Absolute ,X
;
ABSOLX JSR ABSOL ;set up absol
JMP ADDX2 ;copy in ,X
;
;Absolute ,Y
;
ABSOLY JSR ABSOL ;do absol
ACY LDA #$2C ;a comma
STA MYBUF+1,X ;in buf
LDA #89 ;a Y
STA MYBUF+2,X ;in buf
RTS ;done
;
;Indirect X
;
INDX LDA #0 ;no MSB
STA INDR+1
JSR LOBYTE ;do LSB
JSR OPENP ;add open '('
INX ;up X
LDY #2 ;3 bytes
BNE ADDX ;copy ',X)'
;
;Indirect Y
;
INDY LDA #0 ;no MSB
STA INDR+1
JSR LOBYTE ;do LSB
JSR OPENP ;left (
LDY #2 ;copy in the
ADDY LDA COMMAY,Y ;'),Y'
STA MYBUF+1,X
INX
DEY
BPL ADDY
RTS ;done
;
;Accumulator Mode
;
ACCUM LDA #65 ;an 'A'
STA MYBUF+22 ;in buffer
RTS ;done
;
;Branch instructions
;
RELA JSR LOBYTE ;put LSB
INC NBYTE ;make 3 byte
JSR ZFR ;zero FR0
INC BRAFLG ;have branch.
LDA #29 ;add arrow
STA MYBUF+17 ;in buffer.
LDA INDR ;get operand
BPL NOBACK ;not inverse
DEC MYBUF+17 ;make up arrow
AND #$7F ;mask inverse
EOR #$7F ;flip it
CLC ;add a 1
ADC #1
STA DINS+1 ;save it
SEC ;and subtract
SBC #2 ;two.
JMP TOFP ;done
NOBACK STA DINS+1
TOFP LDA INDR ;operand
BPL FORWARD ;bran forward
LDA ADDR ;now subtract
SEC ;from addr
SBC DINS+1 ;to find out
STA FR0 ;where this
LDA ADDR+1 ;branch goes.
SBC #0
STA FR0+1
JMP BACK ;done.
FORWARD CLC ;add # to
ADC ADDR ;addr to calc
STA FR0 ;forward branch
LDA ADDR+1
ADC #0
STA FR0+1
BACK LDA #2 ;now add a 2
CLC ;to skip the
ADC FR0 ;instruction
STA FR0 ;address
STA BRAN ;and save
LDA FR0+1 ;the branch
ADC #0 ;addr for the
STA FR0+1 ;tracer.
STA BRAN+1
JSR NUMBR3 ;add number
DEC NBYTE ;make 2 bytes
;
;Implied Mode
;
IMP RTS ;do nothing
;
;Indirect instructions
;
INDI JSR LOBYTE ;copy in LSB
JSR HIBYTE ;and MSB
JSR OPENP ;do open (
LDA #') ;and add
STA MYBUF+1,X ;closing one
RTS ;leave.
;
;Zero page ,Y
;
ZPAGY JSR LOBYTE ;do LSB
JSR NUMBR ;add arg
JMP ACY ;copy ,Y
;
;Insert LSB
;
LOBYTE INC NBYTE ;up bytes
JSR ZFR ;zero FR0
LDA INDR ;do lobyte
STA FR0
LDX #10 ;at pos. 10
JMP COPYNUM ;do it!
;
;Insert MSB
;
HIBYTE INC NBYTE ;3 byter
JSR ZFR ;no FR0
LDA INDR+1 ;hibyte
STA FR0 ;in FP
LDX #14 ;at pos. 14
JMP COPYNUM ;copy it.
;
;Add Open (
;
OPENP LDA #'( ;open (
STA MYBUF+22 ;in buffer
JMP NUMBR2 ;add number
;
;Handle I/O error
;
IOERR JSR ZFR ;save errnum
STY FR0
STY ERRNUM
JSR GOTERR ;beep!
JSR ZBUF ;no buffer
JSR IFP ;Int to FP
JSR FASC ;con to asc
LDY #$FF
LDX #$FF ;copy to buf
IOLP INY
INX
LDA (INBUFF),Y
STA MYBUF,X
BPL IOLP
AND #$7F
STA MYBUF,X ;in err buf
LDA #EOL
STA MYBUF+1,X
STX CEND
LDX #17 ;search the
ERRLP1 LDA ERRS,X ;errors
CMP ERRNUM ;we have in
BEQ GERR1 ;english
DEX
BPL ERRLP1
BMI IOL5
GERR1 TXA ;we have one.
ASL A ;* 2
TAX ;get address
LDA ERRTAB+1,X
STA INDR+1
LDA ERRTAB,X
STA INDR
LDY #$FF ;and copy it
LDX CEND ;to mybuf.
LDA #',
STA MYBUF+1,X
INX
IOL4 INY
INX
LDA (INDR),Y
STA MYBUF+1,X
BPL IOL4
AND #$7F
STA MYBUF+1,X
LDA #EOL ;add EOL.
STA MYBUF+2,X
IOL5 LDA #14 ;on error line
STA ROWCRS
JSR CLRERR ;clear it
IOL3 LDA #<MYBUF ;and print
LDY #>MYBUF
JMP EPRINT
;
;Copy number to string
;
COPYNUM DEX
STX CNTLO ;save X
LDA HXDC ;hex/dec?
BEQ INHEX ;have Hex.
JSR IFP ;to FP
JSR FASC ;to ASC
LDX CNTLO ;get index
LDY #$FF ;and copy
CNLOOP INY ;the number
INX
LDA (INBUFF),Y
STA MYBUF,X
BPL CNLOOP
AND #$7F ;mask bit 7
STA MYBUF,X
RTS ;leave
INHEX JSR BIN2HEX ;make hex
LDX CNTLO ;get pos
INX ;up it.
BEQ ALL ;if 0 do all
CPX #20 ;is X > 20?
BCS ARG ;yes.
SOME LDA LBUFF+2 ;no. just copy
STA MYBUF,X ;the LSB part
INX ;of the Hex
LDA LBUFF+3 ;number.
STA MYBUF,X
RTS ;bye.
ARG LDA #'$ ;install a '$'
STA MYBUF,X
INX ;up X
LDA NBYTE ;Get # of bytes
CMP #2 ;is it 2?
BEQ SOME ;no.
ALL LDY #0 ;no. copy it
ALOOP LDA LBUFF,Y ;all to buf
STA MYBUF,X
INX
INY
CPY #4 ;done yet?
BNE ALOOP ;nope.
DEX ;dec X
RTS ;so long.
;
;Binary to hexadecimal
;
BIN2HEX LDY #0 ;buf indx=0
LDX #1 ;do 2 nums
NXTBYT STX SAVEX ;save it
LDA #240 ;get HI bits
AND FR0,X
LSR A ;divide by 16
LSR A
LSR A
LSR A
TAX ;to index
LDA HEXDIG,X ;get char
STA LBUFF,Y ;and save
INY ;up buf index
LDX SAVEX ;get X back
LDA #15 ;now LO bits
AND FR0,X
TAX
LDA HEXDIG,X ;get char and
STA LBUFF,Y ;put in buffer
INY ;up buf indx
LDX SAVEX ;get X
DEX ;down by one
BPL NXTBYT ;done?
RTS ;yes. bye.
;
;Fill buffer with blanks
;
ZBUF LDA #32 ;space
LDX #39 ;do 128 spaces
ZLOOP STA MYBUF,X ;in buf
DEX ;down count
BPL ZLOOP ;go again
RTS ;bye.
;
;Handle a 6502 BRK instruction
;
BRKER LDA EXEC ;running?
BNE SAVREG ;yes.
PLA ;no. just exit.
RTI
SAVREG CLD ;chill dec
STX USRX ;save registers
STY USRY
PLA
STA USRA
PLA
STA USRP ;calc BRK point
PLA
SEC
SBC #2
STA USRPC ;put in program
PLA ;counter.
SBC #0
STA USRPC+1
TSX ;store stck pntr
STX USRS ;for user
CLI
JMP SHOBRK ;bye.
;
;Vertical Blank Interrupt
;
;Update my RTCLOK registers
;in my zero page buffer so
;we can use real-time delay
;loops in the tracer.
;
VBI INC MYZPG+20 ;jiffies
BNE VBDN
INC MYZPG+19 ;'seconds'
BNE VBDN
INC MYZPG+18 ;'minutes'
;
;Now we check to see if there
;is an input being taken and
;if so blink the cursor
;
VBDN LDA IPUT ;inputting?
BNE VBOT ;no.
LDA SRTIMR ;key pressed?
BEQ BLINK? ;no.
LDA #63 ;yes. leave
STA CSHAPE ;cursor on for
LDA #60 ;1 second.
STA BLINK
BLINK? LDA CSHAPE ;shape
DEC BLINK ;down blink
BNE VEXIT ;not 0 leave
LDY #30 ;1/2 second
STY BLINK ;delay
EOR #63 ;flip shape
STA CSHAPE ;and save
VEXIT LDY CEND ;get posit
STA COMLN,Y ;save cursor
VBOT JMP XITVBV ;all done
;
;Show BRK information
;
SHOBRK PHP ;get status
TAX
PLA
AND #$EF ;alter it
PHA
PLP ;put it back.
LDA #0 ;stop EXEC
STA EXEC
JMP REINIT ;reinit DEBUG+
;
;Keyboard Handler
;
MKEYV LDA EXEC ;running?
BEQ MYKEYV
LDA KBCODE
CMP #$9C ;control ESC?
BNE MYKEYV ;no so get key
STY USRY ;save Y
STX USRX ;save X
LDA #$FF ;clear out key
STA CH
PLA ;pull Accum
STA USRA ;store it
PLA ;get P stat
STA USRP ;save it
PLA ;pull LSB of PC
STA USRPC ;save it
PLA ;pull MSB
STA USRPC+1 ;save it
TSX ;get S pntr
STX USRS ;save it
CLI ;clear interrupt
JMP SHOBRK ;show info
MYKEYV JMP (TKEY)
;
;Show registers
;
DOREGS LDY #0 ;zero index
DOLOP STY SAVEY
JSR ZFR ;clr FR0
LDA USRA,Y ;get reg
STA FR0 ;in FR0
JSR BIN2HEX ;to hex.
LDY SAVEY ;reload Y
LDX DRPOS,Y ;find posit.
LDA LBUFF+2 ;get byte
SEC
SBC #32
STA PCNT,X ;into buffer
LDA LBUFF+3 ;next.
SEC
SBC #32
STA PCNT+1,X
INY
CPY #4 ;done?
BNE DOLOP ;no way.
LDA USRPC ;show the
STA FR0 ;program cntr
LDA USRPC+1
STA FR0+1
JSR BIN2HEX
LDY #3 ;put it on
PCL LDA LBUFF,Y ;the screen
SEC ;make icode
SBC #32
STA PCNT,Y
DEY
BPL PCL
LDX #17 ;index for PS
LDY #7 ;do 8 bits.
BITIT LDA USRP ;get it
AND BITS,Y ;mask it
BEQ NON
LDA #17 ;a '1'
BNE PRON
NON LDA #16 ;a '0'
PRON STA PCNT,X ;on screen
INX ;up scr pntr
DEY ;dec loop
BPL BITIT ;do again.
LDA #17 ;put on a 1
STA PCNT+19 ;under unused
RTS ;status bit.
;
;Change registers
;
CREGS LDY #7 ;copy on prompt
CRGL LDA REGTXT,Y
STA COMND,Y
DEY
BPL CRGL
REGW JSR GETKEY ;get a key
LDY #4 ;test 5
CRG CMP REGIS,Y ;this one?
BEQ HAVREG ;yes!
DEY ;nope.
BPL CRG ;try next
BMI REGW ;sorry, again
HAVREG TYA ;get address
ASL A ;of register
TAY ;in memory
LDA REGTAB,Y ;and put
STA FR0 ;in fp regs
LDA REGTAB+1,Y
STA FR0+1
JSR CREG ;change memory.
JMP DOREGS ;show regs.
;
;These are the routines used
;to convert ASC to ICODE and
;ICODE to ASC. Each uses a
;4 byte table of bit masks
;located at the end of the
;program for the conversion.
;
;Asc to internal
;
ASC2IC JSR BITER ;fix up bits
ORA A2I,X ;add new mask
LDX SAVX2 ;restore X
RTS ;done!
;
;Internal to Asc
;
IC2ASC JSR BITER ;do bits.
ORA I2A,X ;add mask.
LDX SAVX2 ;get X
RTS ;and leave
;
;Ready the bits
;
BITER PHA ;save old byte
ROL A ;roll the bits
ROL A ;around 4 times
ROL A
ROL A
AND #3 ;make it index
STX SAVX2 ;save X
TAX ;X = A
PLA ;pull old byte
AND #$9F ;mask it off
RTS ;and leave
;
;Clear screen (3 pages)
;
CLRSCR LDA #0 ;get a space
TAX ;zero X
CLSC STA MYSCRN,X ;page 1
STA MYSCRN+$0100,X ;page 2
STA MYSCRN+$0200,X ;page 3
INX ;up loop
BNE CLSC ;and loop again
STA ROWCRS ;pos 0,0
RTS ;all done
;
;Input routine
;
INPUT LDA #0 ;length = 0
STA CEND
STA IPUT ;signal input
JSR CLRWIN ;clear window
JSR ZBUF ;and buffer
GETC JSR GETKEY ;get a key
CMP #27 ;ESCape?
BNE LEG0 ;nope.
INC IPUT
SEC ;signal error
RTS ;and leave
LEG0 LDY NCHK ;check legals?
BNE GOTCHR ;nope.
LEG1 LDY #40 ;is it a legal
LEGL CMP LEGAL,Y ;char?
BEQ GOTCHR ;yup.
DEY ;not this one
BPL LEGL ;try next
JSR GOTERR ;error.
JMP GETC ;go again.
GOTCHR CMP #126 ;Delete?
BNE NOTDEL ;no.
DEC CEND ;lower length
BPL TS2 ;<0? no.
LDA #0 ;make zero.
STA CEND
JSR GOTERR ;give error.
TS2 JSR TST1 ;test length
LDA CEND ;get length
BEQ GETC ;if not 0 go!
LDY CEND ;put in a spc
CPY #12
BNE DODEL
DEY
DODEL LDA #0
STA COMLN,Y ;erase char
STA COMLN+1,Y ;erase cursor
JMP GETC ;get next.
NOTDEL CMP #156 ;Delete Line?
BEQ INPUT ;yes.
LDY CEND
STA MYBUF,Y
CMP #EOL ;EOL?
BEQ ATEND ;done!
JSR ASC2IC ;make icode
CPY #12
BNE SHCH
DEY
SHCH STA COMLN,Y ;to screen
INY
CPY #13
BCC TST9
DEY
TST9 STY CEND
JSR TST1 ;length?
JMP GETC ;do again.
ATEND LDA MYBUF
CMP #EOL
BEQ INPUT
LDA #0 ;check 'em
STA NCHK ;next time
STA COMLN,Y ;and erase cursr
INC IPUT
CLC ;show good input
RTS ;bye.
;
;Test input length
;
TST1 LDA CEND ;get length
BNE TL2 ;no.
STA COMLN ;erase 1st char
STA COMLN+1 ;and cursor
TL2 RTS ;bye.
;
;Erase error line
;
CLRERR LDY #23 ;24 chars.
LDA #0 ;to clear
CLE STA ERRLN,Y ;on line
DEY
BPL CLE ;loop.
RTS ;so long.
;
;Print to device
;
DPRINT LDA #PUTRC ;put record
LDX #DDEV
STA ICCOM,X ;CIO command
LDA #<MYBUF ;mybuf is
STA ICBAL,X ;the buffer
LDA #>MYBUF ;hi byte
STA ICBAH,X
LDA #40 ;40 bytes max
STA ICBLL,X
LDA #0
STA ICBLH,X
LDA MYBUF+23 ;if chr is
BPL PRT ;>128 invert
JSR INV2
PRT JSR CIOV ;print it.
BMI STOP ;on error stop
RTS
STOP PLA
PLA
JMP DCLOSE
;
;Calculate line address
;
CLCLN LDA ROWCRS ;y-pos
ASL A ;* 2
TAX ;look up the
LDA SCRN,X ;screen memory
STA SCR ;address in
LDA SCRN+1,X ;table and
STA SCR+1 ;store it.
RTS ;bye.
;
;Change display between
;Disassembly and display mem
;
ALTER LDA DTYPE ;display type
EOR #1
STA DTYPE
BNE HAVMEM ;in display
LDA #1
STA BBCK
LDA #33
BNE ALT2 ;finish
HAVMEM LDA #6
STA BBCK
LDA #48
ALT2 STA PCNT+29
LDA TOPADR
STA FR0
LDA TOPADR+1
STA FR0+1
JMP TOEDEV
;
;Find Break point
;
FNDBRK LDA #0 ;say none found
STA BSET
LDY #5 ;try 6 B.P's
SET? LDA ADDR+1 ;check if
CMP SETHI,Y ;MSB is same?
BNE UPLP ;not same.
LDA ADDR ;match. try LSB
CMP SETLO,Y
BNE UPLP ;no go.
LDA OPSET,Y ;match.set yet?
BEQ UPLP ;no.
LDA OLDOP,Y ;yes. restore
STA OP ;old opcode.
INC BSET ;say set.
RTS ;leave.
UPLP DEY ;decrease loop
BPL SET? ;done? no.
RTS ;yes. leave.
;
;Go to correct DISA routine
;
FINLIN LDA DTYPE ;type flag
BNE FINL2 ;1 = display
JMP DISAMEM ;disassemble
FINL2 JMP SHOMEM ;and display
;
;Set default GETKEY data
;
SETKEY LDA #0 ;set normal vid
STA INVS
LDA #$40 ;and upper case
STA CAPS
RTS
;
;--------------
;PROGRAM TRACER
;--------------
;
;Get Key Routine
;
;This routine accepts a raw
;key press and converts it
;to ATASCII using the table
;supplied in the OS.
;
GETKEY LDA CH ;get key press
CMP #$FF ;$FF?
BEQ GETKEY ;yes. loop
LDX #$FF ;now clear key
STX CH ;press
STA OLDC ;save press
K0 TAY
CPY #$C0 ;192?
BCC K1 ;no.
LDY #$9A ;error 136
K1 LDA $FEFE,Y ;make ascii
STA OLDAC ;save it
CMP #$80 ;128?
BEQ GETKEY ;yes. try again
CMP #$81 ;129?
BNE K2 ;no.
LDA INVS ;yes.
EOR #$80 ;flip inverse
STA INVS ;status
JMP GETKEY ;go again
K2 CMP #$82 ;130?
BNE K3
LDA CAPS ;yes. flip caps
EOR #$40 ;status
STA CAPS
JMP GETKEY ;go again
K3 CMP #$83 ;131?
BNE K4 ;shift caps.
LDA #$40 ;make caps
STA CAPS
BNE GETKEY
K4 CMP #$84 ;132?
BNE K5
LDA #$80 ;control-caps
STA CAPS
BNE GETKEY
K5 CMP #$85 ;skip this one
BEQ GETKEY
LDA OLDC ;get press
CMP #$40 ;64?
BCS K6 ;yes. +>
LDA OLDAC ;get ascii
CMP #$61 ;97?
BCC K6
CMP #$7B
BCS K6
LDA CAPS ;lower case
BEQ K6
ORA OLDC ;mask bits
JMP K0 ;and do again
K6 LDX #$0F ;scan for a
K7 LDA KEYS,X ;special
CMP OLDAC ;key press
BEQ K8
DEX
BPL K7
K8 BEQ K9
LDA OLDAC ;get ascii
EOR INVS ;inverse bit
STA OLDAC ;save it
K9 RTS ;and done
;
;Wait 15 jiffies
;
WAIT5 LDA #0 ;get 0
STA RTCLOK ;zero clok
W1 LDA RTCLOK
CMP #15 ;at 15?
BNE W1 ;no.
RTS ;so long!
;
;Perform manual RTS
;
DORTS LDX USRS ;get pointer
INX
LDA MYPG1,X ;RTS lo byte
STA ADDR ;in trace adr
INX
LDA MYPG1,X ;RTS hi byte
STA ADDR+1 ;in trace adr
STX USRS ;update SP
JMP NSET ;add a 1 to adr
;
;Perform manual JSR
;
DOJSR LDA ADDR ;calc return
SEC ;address and
SBC #1 ;store it in
PHA ;the users
LDA ADDR+1 ;stack.
SBC #0
LDX USRS ;stk pntr
STA MYPG1,X ;install MSB
DEX ;down 1
PLA ;get LSB
STA MYPG1,X ;put it in
DEX
STX USRS ;new stk pntr
DOJMP LDY #1 ;copy new trace
LDA (SAVD),Y ;address into
STA ADDR ;pointers.
INY ;HI byte.
LDA (SAVD),Y
STA ADDR+1
RTS ;bye.
;
;Thread an ML program
;
TRACE JSR GADR ;get trace adr
LDA FR0 ;save it.
STA ADDR
LDA FR0+1
STA ADDR+1
JSR CLRWIN
LDY #7 ;slo or fast?
FSL LDA SLOF,Y
STA COMND,Y
DEY
BPL FSL
STY SLFS
;
;SLFS = $FF for Slow mode
; = $00 for Fast mode
; = $01 for Option step mode
;
FSW JSR GETKEY ;get choice
CMP #'F ;FAST?
BNE SLO? ;no.
INC SLFS ;fast mode
BEQ TN
SLO? CMP #'S ;SLOW?
BEQ TN ;wrong!
CMP #'O ;O=option for
BNE FSW ;step thru
LDA #1
STA SLFS
TN JSR CLRSCR ;clear screen
JSR CLRWIN ;clear input
JSR CLRCMD ;and prompt
TLOOP LDA ADDR ;take addr and
STA USRPC ;put in Program
STA SAVD ;Counter, and
LDA ADDR+1 ;instruction
STA USRPC+1 ;save address.
STA SAVD+1
JSR DISAMEM ;disa this adr
JSR SCROLL ;move screen
LDY #2 ;install NOP's
LDA #234 ;(a NOP)
DNOP STA NOPS,Y ;in area
DEY
BPL DNOP ;done?
JSR PAUSE ;wait?
JSR DOREGS ;up date USRPC
LDA MYBUF+18 ;get disa chr
BPL GINS ;inverse?
JSR POS15 ;on status line
LDA #<BRKPNT ;BRK REACHED
LDY #>BRKPNT
JMP EPRINT ;print it.
GINS CMP #63 ;a '?' ?
BNE NOBR ;no.
LDY #151 ;yes. a No-inst
JMP IOERR ;give error.
NOBR LDA OP ;get the Opcode
CMP #96 ;is it RTS?
BNE NORTS ;no.
JSR DORTS ;do the RTS
JMP TDNE ;all done.
NORTS CMP #$40 ;RTI?
BNE IJMP ;no.
LDX USRS ;get USRP
INC USRS ;off stack.
LDA MYPG1,X ;proc status.
STA USRP ;in REG
INX
LDA MYPG1,X
STA ADDR
INX
LDA MYPG1,X
STA ADDR+1
STX USRS
JMP TDNE ;all done.
IJMP CMP #76 ;JMP?
BNE CPN2 ;nope.
JSR DOJMP ;do JMP
JMP TDNE ;done.
CPN2 CMP #32 ;JSR?
BNE CPN6 ;nope.
JSR DOJSR ;make JSR
JMP TDNE ;finished.
CPN6 CMP #108 ;JMP ()?
BNE CPN7 ;no.
JSR DOJMP ;yes. get adr
LDY #0 ;look up JMP
LDA (ADDR),Y ;addr thru
PHA ;this adr.
INY ;up Y
LDA (ADDR),Y ;get HI byte
STA ADDR+1 ;in addr
PLA ;restore LSB
STA ADDR ;in addr
JMP TDNE ;done.
CPN7 LDA BRAFLG ;branch?
BEQ CPN4 ;not this one.
LDA OP ;get Op.
LDY #3 ;loop 4 times
FBRA CMP BRAL,Y ;bit not set?
BEQ HAVBRA2 ;YES.
CMP BRAH,Y ;bit set?
BEQ HAVBRA ;YES.
DEY ;no.
BPL FBRA ;try next one.
;
;Branch if bit set
;
HAVBRA LDA USRP ;get processor
AND BBIT,Y ;mask bit.
BEQ NOTE ;off? yes.
NEWADR LDA BRAN ;set up the
STA ADDR ;new branch
LDA BRAN+1 ;address for
STA ADDR+1 ;next time.
NOTE JMP TDNE ;jam!
;
;Branch if bit not set
;
HAVBRA2 LDA USRP ;processor
AND BBIT,Y ;mask it.
BEQ NEWADR ;off? yes.
JMP TDNE ;no.
CPN4 LDY #0 ;ready to copy
CIN LDA (SAVD),Y ;the instr
STA NOPS,Y ;into NOP area
INY ;for fall thru.
CPY NBYTE ;done?
BNE CIN ;not yet.
;
;Run the instruction
;
LDA #0 ;kill ints
STA NMIEN
SEI ;set interrupt
LDX #0 ;copy user mem
CPZ1 LDA ZPAGE,X ;into pages
TAY ;0 - 2.
LDA MYZPG,X ;PAGE 0
STA ZPAGE,X
TYA
STA MYZPG,X
;
LDA STACK,X ;PAGE 1
TAY ;(the stack)
LDA MYPG1,X
STA STACK,X
TYA
STA MYPG1,X
;
LDA PAGE2,X ;PAGE 2
TAY ;(interrupts)
LDA MYPG2,X ;(and stuff)
STA PAGE2,X
TYA
STA MYPG2,X
;
INX
BNE CPZ1
TSX ;get stack
TXA ;in A
LDX USRS ;user stack
TXS ;pointer.
STA USRS ;save my stack.
LDY USRY ;get Y,
LDX USRX ;get X,
LDA USRP ;put on the
PHA ;processor stat
LDA USRA ;get A
PLP ;pull status
NOPS NOP ;* here is *
NOP ;* where the *
NOP ;* instr goes *
PHP ;push status
STA USRA ;save A
PLA ;save status
STA USRP
STX USRX ;save X
STY USRY ;save Y
TSX ;put back stack
TXA ;pointers
LDX USRS
TXS
STA USRS
SEI ;set for safety
LDX #0 ;now copy back
; ;pages 0 - 2
CZP LDA ZPAGE,X ;zero page
TAY
LDA MYZPG,X
STA ZPAGE,X
TYA
STA MYZPG,X
;
LDA STACK,X ;the stack
TAY
LDA MYPG1,X
STA STACK,X
TYA
STA MYPG1,X
;
LDA PAGE2,X ;page 2
TAY
LDA MYPG2,X
STA PAGE2,X
TYA
STA MYPG2,X
;
INX
BNE CZP
CLI ;clr interrupts
LDA #64 ;turn on the
STA NMIEN ;interrupts
TDNE JSR DOREGS ;show registers
LDA SLFS ;mode.
BMI TDN1 ;Slow.
BEQ TDN2 ;Fast!
LDX #8 ;consol clear
STX CONSOL ;clear it.
CNW LDA CONSOL ;get it
CMP #3 ;OPTION?
BNE CNW ;no.
STX CONSOL ;yes. zero it.
BNE TDN2
TDN1 JSR WAIT5 ;wait 1/4 sec
TDN2 JMP TLOOP ;next instr
;
;Move screen up 32 bytes
;
MOVE32 LDA #<MYSCRN ;screen
STA IND2 ;address in
LDA #>MYSCRN ;Zpage addr
STA IND2+1 ;so we can
LDA IND2 ;the screen up
CLC ;40 bytes
ADC #32
STA INDR
LDA IND2+1
ADC #0
STA INDR+1
LDX #0 ;line 0
MOVE LDY #31 ;32 bytes
MOVIT LDA (INDR),Y
STA (IND2),Y
DEY
BPL MOVIT ;loop.
LDA INDR+1 ;copy to
STA IND2+1
LDA INDR
STA IND2 ;add a 32
CLC ;to copy
ADC #32 ;from.
STA INDR
LDA INDR+1
ADC #0
STA INDR+1
INX ;up line
CPX #14 ;line 13?
BNE MOVE ;no.
RTS ;bye.
;
;Clear status line
;
ERASTAT LDY #23 ;24 characters
LDA #0 ;a zero
ERAS1 STA STATLN,Y ;in line
DEY ;next
BPL ERAS1 ;go to it.
RTS ;bye.
;
;Decimal/Hexadecimal Convert
;
PRDH LDA HXDC ;# type
STA SAVY2 ;save it
LDA #3 ;full number
STA NBYTE ;length
JSR GADR ;get number
LDA #32 ;make EOL a spc
STA MYBUF,Y
STA MYBUF+2,Y
LDA #'= ;install =
INY
STA MYBUF,Y
INY
STY SAVX2 ;save Y
LDA HXDC ;# type
EOR #1 ;flip it
STA HXDC ;and save again
LDX #28 ;copy in #
JSR COPYNUM
STX CEND
LDX #28 ;now move #
LDY SAVX2 ;down in string
CPN9 LDA MYBUF,X
STA MYBUF+1,Y
CPX CEND ;at end?
BEQ AEND ;yes!
INX
INY
BNE CPN9 ;go again.
AEND LDA #EOL ;install EOL
STA MYBUF+2,Y
JSR POS15 ;on status line
LDA SAVY2 ;restore # type
STA HXDC
JMP IOL3 ;print it.
;
;Erase memory
;
ERASE JSR GADR ;start addr
LDA FR0 ;transfer to
STA SL ;2 Zpage locs
LDA FR0+1
STA SL+1
JSR GADR ;End addr
LDY #0
LDA FR0+1 ;is End<Start?
CMP SL+1
BCC NEWERR ;yes!
BNE NEWOK ;no.
LDA FR0 ;equal check
CMP SL ;LSB.
BCC NEWERR ;error!
BEQ NEW2 ;equal 1 byte
NEWOK TYA ;get 0
STA (SL),Y ;in loc
INC SL ;up loc
BNE NEW1 ;wrap around?
INC SL+1 ;yes.
NEW1 LDA FR0+1 ;check to see
CMP SL+1 ;if done yet.
BNE NEWOK ;not done.
LDA FR0 ;check LSB
CMP SL
BNE NEWOK ;not yet.
NEW2 TYA ;and do last
STA (SL),Y ;location.
RTS ;bye.
NEWERR LDY #153 ;ADR RANGE
JMP IOERR ;show it.
;
;-----------
;I/O CONTROL
;-----------
;
;Print to command window
;
PCOMW STA INDR ;save address
STY INDR+1
LDY #0
PCA LDA (INDR),Y ;get a char
STA COMND,Y ;on screen
CMP #31 ;a '?'?
BEQ PCN ;yes. done.
INY ;up count
BNE PCA ;try again
PCN RTS ;leave
;
;Position cursor at line 15
;
POS15 LDA #15
STA ROWCRS
RTS
;
;Scroll Screen?
;
SCROLL LDA ROWCRS ;Y-pos
CMP #14 ;14th line?
BNE SCRL ;no.
SCRL2 JSR MOVE32 ;yes. scroll
LDA #13 ;pos. 13
STA ROWCRS
SCRL JMP IOL3 ;print buffer
;
;Pause screen scroll
;
PAUSE LDA CH ;key scan
CMP #$FF ;no touch?
BEQ CLRKEY ;yes.
JSR CLRKEY ;clear it.
CMP #28 ;was it ESC?
BEQ PA2 ;yup.
CMP #33 ;space bar?
BNE CLRKEY ;no.
JSR CLRKEY ;clear.
PA3 LDA CH ;wait again
CMP #33 ;space?
BEQ CLRKEY ;yes.
CMP #28 ;ESC?
BNE PA3 ;no. wait.
PA2 PLA ;have an ESC.
PLA ;pull RTS
;
;Clear key
;
CLRKEY PHA ;save A
LDA #$FF ;clear CH
STA CH ;to no touch
PLA ;restore A
RTS ;leave.
;
;Page thru Disa
;
PGTHRU LDA #<PGTR ;print option
LDY #>PGTR ;Up or Down?
JSR PCOMW
PGL2 JSR GETKEY ;get choice
CMP #'U ;Up?
BNE TDN? ;no.
LDA #1 ;put scroll up
STA PGWAY ;flag
BNE PGLOOP ;do it!
TDN? CMP #'D ;Down?
BNE PGL2 ;no.
LDA #0 ;insert scroll
STA PGWAY ;down flag
PGLOOP JSR CLRCMD ;clear stuff
JSR CLRWIN
PGJSR JSR PAUSE ;scroll!
LDA PGWAY
BEQ DWAY ;pause screen?
JSR SCRUP ;do again.
JMP PGJSR
DWAY JSR SCRDN
JMP PGJSR
;
;Disassemble to a device
;
DISDEV JSR COPFIL ;get filename
JSR GADR ;and start adr
LDA #8 ;open IOCB for
JSR OPENFIL ;write only
LDA FR0 ;copy in adr
STA ADDR
LDA FR0+1
STA ADDR+1
OLP JSR DISAMEM ;disa a line
LDA #32 ;remove arrow
STA MYBUF+17 ;in disa
LDA MYBUF+18 ;
BPL DPR
JSR INV2
DPR JSR DPRINT ;print it
JSR ERASTAT ;clear line
JSR POS15 ;on status
LDA #EOL ;set so only
STA MYBUF+6 ;addr is shown
JSR IOL3 ;print disa
LDA CH ;key?
CMP #$FF ;no touch?
BEQ OLP ;yes. go again
JSR CLRKEY ;clear it
JSR ERASTAT ;clear line
JMP DCLOSE ;close IOCB
;
;Get device
;
GETDEV JSR CLRWIN ;no junk
LDA #<DEVNAMS ;copy devices
LDY #>DEVNAMS ;onto the
JSR PCOMW ;screen
DEV2 JSR GETKEY ;get a key
CMP #27 ;ESC?
BNE FNDEV ;no.
PLA ;pull of the 2
PLA ;RTS's from
PLA ;the stack
PLA
RTS ;and leave
FNDEV LDY #1 ;check if legal
DEV3 CMP DEVS,Y ;device
BEQ HAVDEV ;got one!
DEY ;not this
BPL DEV3 ;try next one
JSR GOTERR ;sorry wrong
JMP DEV2 ;go again
HAVDEV RTS ;bye.
;
;Scroll down
;
SCRDN LDX #0 ;check if scr
SCK TXA ;has info all
ASL A ;the way down
TAY ;to the last
LDA SCRN,Y ;screen line.
STA TEMP ;get the line
LDA SCRN+1,Y ;address from
STA TEMP+1 ;table.
LDY #0 ;zero index
LDA (TEMP),Y ;get a char
BEQ DOWHL ;have a space
INX ;try next line
CPX #14 ;at 14 yet?
BNE SCK ;no.
JSR FINLIN
JSR SCRL2
LDX #1 ;copy the addr
GX1 LDA MYSCRN,X ;from the scr
JSR IC2ASC ;into mybuf
CMP #32 ;a space?
BEQ GX2 ;yes, done.
STA MYBUF-1,X ;save it
INX ;next char
BNE GX1
GX2 LDA #EOL ;insert EOL
STA MYBUF-1,X ;in mybuf
LDY #0
JSR GET4 ;make integer
LDA FR0 ;now copy this
STA TOPADR ;to TOPADR
LDA FR0+1 ;for next time.
STA TOPADR+1
RTS ;done!
DOWHL LDA LN2 ;put second
STA FR0 ;address in FR0
LDA LN2+1
STA FR0+1 ;and disa all
JMP TOEDEV ;16 lines.
;
;Scroll up
;
SCRUP LDA TOPADR ;move down
SEC ;byte in memory
SBC BBCK
STA FR0 ;save in FR0
LDA TOPADR+1
SBC #0 ;take care of
STA FR0+1 ;Hi byte
JMP TOEDEV ;do it!
;
;Clear Command type
;
CLRCMD LDA #0 ;make command
STA COMND ;2 spaces
STA COMND+1
RTS ;bye.
;
;Clear Command Window
;
CLRWIN LDY #20 ;do 21 chars
LDA #0 ;a blank
CW STA COMLN,Y ;in command
DEY ;line buffer
BPL CW ;do next
RTS ;so long.
;
;Free break points
;
FREBRK LDY #0
STY FREN ;none free
FRE1 STY SAVEY ;save Y
LDA SETLO,Y ;get addr
STA FR0 ;and put in FR0
LDA SETHI,Y
STA FR0+1
JSR BIN2HEX ;convert to hex
LDY SAVEY ;get Y
LDX BRKLN,Y ;get pos on scr
LDY #0
FRE2 LDA LBUFF,Y ;hex digit
SEC ;make icode
SBC #32
STA FRLN,X ;on screen
INX
INY
CPY #4 ;4 chars?
BNE FRE2 ;no.
LDY SAVEY ;restore Y
LDA OPSET,Y ;BRK set?
BNE FRE3 ;yes.
INC FREN ;inc free points
FRE3 INY ;up Y
CPY #6 ;6 BRK's yet?
BNE FRE1 ;no
LDA FREN ;get free
CLC
ADC #16 ;make icode
STA FRLN+31 ;on screen
RTS ;all done
;
;Break Point Handler
;
BKPHAN JSR CLRCMD ;clear comms
LDA #34 ;a 'B'
STA COMND
JSR INPUT ;get a line
BCC BKG ;good? yes!
RTS ;no. bye
BKG LDA MYBUF ;get number
SEC ;subtr 49 (0-5)
SBC #49
TAX ;save in X
CMP #6
BCS NUMER ;>5? yes.
CMP #0 ;<0?
BCC NUMER ;yes.
LDA MYBUF+1 ;next char
CMP #EOL ;EOL?
BEQ DORESET ;yes. reset it
LDY #2
STX CNTLO ;save X
JSR GTDR ;get addr
LDX CNTLO ;restore X
LDY #0
LDA (FR0),Y ;get opcode
BEQ SETER ;BRK? yes.
LDA OPSET,X ;set already?
BEQ SETIT ;no.
SETER LDY #152
JMP IOERR
NUMER JMP GOTERR ;BEEP!
SETIT LDA FR0 ;save address
STA SETLO,X
LDA FR0+1
STA SETHI,X
LDA (FR0),Y ;get opcode
STA OLDOP,X ;save it
TYA ;zero Acc
STA (FR0),Y ;insert BRK
INC OPSET,X ;show set
JMP FREBRK ;and leave
;
DORESET JSR CLRCMD ;no junk
LDY #0 ;zero Y
LDA OPSET,X ;Set yet?
BEQ RESER2 ;no. error
LDA SETLO,X ;get address
STA INDR ;of Bpoint
LDA SETHI,X ;and save in
STA INDR+1 ;2 Zpage locs
LDA OLDOP,X ;get old opcode
STA (INDR),Y ;put it back.
TYA ;A = 0
STA OPSET,X ;not set.
STA SETLO,X
STA SETHI,X
JMP FREBRK ;update free
RESER2 LDY #150 ;give user
JMP IOERR ;Error # 150
;
;Find memory
;
FINDIT JSR CLRCMD ;clear line
LDA #31 ;a '?'
STA COMND
STA NCHK ;don't check
JSR INPUT ;keys on input
BCC FCS ;good input
RTS ;bye
FCS LDY #0 ;check to see
FCP LDA MYBUF,Y ;if input ends
CMP #EOL ;with an EOL
BEQ FCP2 ;or a comma.
CMP #$2C ;if comma the
BEQ FCP2 ;get an address
STA MBF2,Y ;also copy line
INY ;into a temp
CPY #12 ;buffer
BNE FCP
FCP2 STY SLFS ;save Y
CMP #$2C ;a comma?
BNE FCP3 ;no.
JSR GADR ;get address
LDA FR0 ;to start from
SEC ;subtract 1
SBC #1 ;from it.
STA SL ;and save it
LDA FR0+1
SBC #0
STA SL+1
LDY #$FF ;force a
BNE FCP4 ;branch
FCP3 LDY #$FF ;set up $FFFF
STY SL
STY SL+1
FCP4 INY
STY DISKC
STY STL
STY STL+1 ;end at $FFFF
JSR CLRSCR
FC1 LDA SL ;add one to
CLC ;current addr
ADC #1
STA SL
LDA SL+1
ADC #0
STA SL+1
CMP #>MYBUF ;at buffers
BNE FC9 ;yet? no.
LDA SL
CMP #<MYBUF
BNE FC9 ;no.
LDA #<ENDBUF ;skip over
STA SL ;the input
LDA #>ENDBUF ;and page 0-2
STA SL+1 ;buffers.
FC9 LDA DISKC ;first run?
BEQ FC3 ;yes.
LDA SL ;at $0000?
ORA SL+1
BNE FC3 ;no.
RTS ;yes. done.
FC3 LDY #1 ;second pass
STY DISKC
DEY ;Y = 0
FC4 LDA (SL),Y ;a char
CMP MBF2,Y ;= to mbf2?
BNE FC1 ;no.
INY ;a match?
CPY SLFS ;done yet?
BNE FC4 ;no.
JSR ZBUF ;set up buffer
LDX #5 ;to show what
FC5 LDA FTXT,X ;find this
STA MYBUF,X ;was and at
DEX ;what address
BPL FC5 ;the string
LDA SL ;was found at.
STA FR0
LDA SL+1 ;address
STA FR0+1
JSR BIN2HEX
LDY #3
LDX #17
FC6 LDA LBUFF,Y ;Hex address
STA MYBUF,X
DEX
DEY
BPL FC6
LDA #'$ ;add '$'
STA MYBUF,X
LDA #EOL ;add in the
STA MYBUF+18 ;eol
INC STL ;up # of finds
BNE NH4
INC STL+1
NH4 LDA STL ;now add in
STA FR0 ;the find #.
LDA STL+1
STA FR0+1
LDX #7
STX HXDC
JSR COPYNUM
JSR PAUSE ;pause?
JSR SCROLL ;scroll screen
JMP FC1 ;go again
;
;Load a binary file
;
DOLOAD LDA #'D ;filename
JSR COPFL
LDA #0 ;signal first
STA SLFS ;pass
LDA #7 ;get bytes
STA DISKC2 ;save
LDA #4 ;read only
JSR OPENFIL ;open file!
JSR READ2 ;get 2 bytes
BMI BLO2 ;error? yes.
LDA BAL ;is header?
CMP #$FF ;$FF?
BNE BDLO ;no.
CMP BAL+1 ;other one?
BEQ DLOAD ;yes. = $FF
BDLO LDY #149 ;ERROR 149
BLO2 STY SAVEY ;save it
JSR DCLOSE ;close Device
LDY SAVEY ;get error
JMP IOERR ;and leave
DLOAD JSR READ2 ;2 more bytes
LDA SLFS ;pass = 1?
BNE CHD ;no.
LDA BAL ;copy load
STA FR0 ;addr to safe
LDA BAL+1 ;place
STA FR0+1
INC SLFS ;pass = 2
CHD JSR CHKHED ;$FF?
JSR STRAD ;set start
JSR READ2 ;2 more bytes
JSR ENDAD ;set end adr
JSR BUFLEN ;calc buf len
JSR GETDAT ;get stuff
BMI LOADD ;if error done
JMP DLOAD ;keep going.
LOADD TYA ;error in A
PHA ;save it
JSR DCLOSE ;close dev
PLA ;get error
CMP #136 ;EOF?
BNE LODERR ;no. Error!
JSR ZBUF ;clear buffer
LDY #6 ;'LOAD AT'
LLP LDA LODAD,Y
STA MYBUF,Y
DEY
BPL LLP
JSR BIN2HEX ;convert addr
LDY #3 ;to hex©
LDX #12
LLP1 LDA LBUFF,Y ;insert #
STA MYBUF,X
DEX
DEY
BPL LLP1
LDA #'$ ;add a '$'
STA MYBUF,X
LDA #EOL ;install EOL
STA MYBUF+13
JSR POS15 ;on STAT:
JMP IOL3 ;print it.
LODERR TAY ;in Y
JMP IOERR ;show error
;
;Read in 2 file bytes
;
READ2 LDA #<BAL ;point to
STA SL ;2 byte buffer
LDA #>BAL
STA SL+1
LDA #0 ;only 2 bytes
STA BLL+1 ;in length
LDA #2 ;and fall thru
STA BLL ;to getrec
;
;Get file segment
;
GETREC LDX #DDEV ;Device
LDA DISKC2 ;command
STA ICCOM,X
LDA SL ;buffer adr
STA ICBAL,X
LDA SL+1
STA ICBAH,X
LDA BLL ;buffer length
STA ICBLL,X
LDA BLL+1
STA ICBLH,X
JMP CIOV ;get it
;
;Calculate buffer length
;
BUFLEN LDA ENL ;take end and
SEC ;subtract start
SBC STL ;to calc length
STA BLL
LDA ENL+1
SBC STL+1
STA BLL+1
LDA BLL ;then add 1
CLC ;for CIO
ADC #1
STA BLL
LDA BLL+1
ADC #0 ;add carry
STA BLL+1
RTS ;and leave
;
;Put in start addr
;
STRAD LDA BAL ;move in start
STA STL ;address
LDA BAL+1
STA STL+1
RTS
;
;Put in end addr
;
ENDAD LDA BAL ;move in end
STA ENL ;addr.
LDA BAL+1
STA ENL+1
RTS
;
;Check if header
;
CHKHED LDX BAL ;first byte
INX ;up by 1
BEQ TNXT ;zero? yes.
RTS ;nope.
TNXT LDX BAL+1 ;second byte
INX ;up it
BEQ ITSFF ;zero? yes.
RTS ;no.
ITSFF JMP READ2 ;2 more bytes
;
;Get DATA
;
GETDAT LDA STL ;set up start
STA SL ;loadind addr
LDA STL+1
STA SL+1
JMP GETREC ;and load it
;
;Open Disk
;
OPENFIL STA DISKC ;save I/O
JSR DCLOSE ;close IOCB
LDA DISKC ;get I/O type
LDX #DDEV ;device chan
STA AUX1,X ;in AUX1
LDA #0 ;AUX2 = 0
STA AUX2,X
LDA #3 ;open command
STA ICCOM,X
LDA #<FILNAM ;point to
STA ICBAL,X ;filename
LDA #>FILNAM
STA ICBAH,X
JSR CIOV ;open it!
BMI OPENR ;sorry error.
RTS ;good open.
OPENR PLA ;pull RTS
PLA ;and show error
JMP IOERR
;
;Copy filename
;
COPFIL JSR GETDEV ;device.
COPFL PHA ;save it
STA FILNAM ;in filename
LDA #EOL ;3 char is EOL
STA FILNAM+2
PLA ;device
CMP #'D ;to Disk?
BEQ TOD ;yes.
RTS ;no fname.
TOD JSR CLRCMD ;clr window
LDA #31 ;a ?
STA COMND
JSR INPUT ;get name
BCC CQP1 ;if good branch
PLA ;pull RTS
PLA
RTS ;next command
CQP1 LDX #2 ;offset is 2
LDY #0 ;zero Y
COPL LDA MYBUF,Y ;char
CMP #', ;a comma?
BEQ GNAME ;yes.
CMP #EOL ;EOL?
BEQ GNAME ;yes.
STA FILNAM,X ;save in name
INY ;up pointers
INX
CPX #18 ;18 chars yet?
BNE COPL ;no.
LDY #165 ;Fname error
PLA
PLA
JMP IOERR ;show it
GNAME LDA #EOL ;add EOL
STA FILNAM,X ;to Fname
RTS ;leave
;
;Save a File
;
DOSAVE LDA #'D ;Fname
JSR COPFL
LDA #11 ;put bytes
STA DISKC2
JSR GADR ;save start
LDA FR0 ;copy it
STA STL
LDA FR0+1
STA STL+1
JSR GADR ;save end
LDA FR0 ;copy it
STA ENL
LDA FR0+1 ;is end<start?
STA ENL+1
CMP STL+1
BCC SIOR2 ;yes.
BEQ TESTLO ;equal.
BNE DSAV ;save it.
TESTLO LDA ENL ;try LSB's
CMP STL
BCC SIOR2 ;error!
DSAV LDA #8 ;write only
JSR OPENFIL ;open it!
LDA #$FF ;Install header
STA BAL
STA BAL+1
JSR READ2 ;put it out
BMI SIOR ;error
LDA STL ;start bytes
STA BAL
LDA STL+1
STA BAL+1
JSR READ2 ;put them
BMI SIOR
LDA ENL ;end bytes
STA BAL
LDA ENL+1
STA BAL+1
JSR READ2 ;put them
BMI SIOR
JSR BUFLEN ;calc length
JSR GETDAT ;and save it
BMI SIOR
JMP DCLOSE ;close it
SIOR2 LDY #153 ;ADR ERROR
SIOR TYA
PHA
JSR DCLOSE
PLA
TAY
JMP IOERR ;show it
;
;This is the command text and
;addresses of routines
;plus string positions for
;Show command.
;
CMDTXT .BYTE "QDRN*CGLS"
.BYTE "BT-=FPH.E"
CMDADR .WORD DOSCMD ;Quit
.WORD ALTER ;Display
.WORD DOREGS ;Registers
.WORD CREGS ;New register
.WORD DISMEM ;*=addr
.WORD CHGMEM ;Change
.WORD GMEM ;Go
.WORD DOLOAD ;Load
.WORD DOSAVE ;Save
.WORD BKPHAN ;Break pnt han
.WORD TRACE ;Trace
.WORD SCRUP ;-
.WORD SCRDN ;=
.WORD FINDIT ;Find
.WORD DISDEV ;Print
.WORD PGTHRU ;High speed
.WORD PRDH ;.
.WORD ERASE ;Erase
;
;Disassembler Vectors
;
DCOMT .WORD IMMED ;immediate
.WORD ZPAG ;Zpage
.WORD ZPAGX ;Zpage,X
.WORD ABSOL ;Absolute
.WORD ABSOLX ;Absolute,X
.WORD ABSOLY ;Absolute,Y
.WORD INDX ;(indirect,X)
.WORD INDY ;(indirect),Y
.WORD ACCUM ;Accumulator
.WORD RELA ;Relative
.WORD IMP ;Implied
.WORD INDI ;(indirect)
.WORD ZPAGY ;Zpage,Y
STRPOS .BYTE 5,8,11,14,17,20
;
;Screen line address table
;
SCRN .WORD [MYSCRN+1] ;ln 0
.WORD [MYSCRN+33] ;ln 1
.WORD [MYSCRN+65] ;ln 2
.WORD [MYSCRN+97] ;ln 3
.WORD [MYSCRN+129] ;ln 4
.WORD [MYSCRN+161] ;ln 5
.WORD [MYSCRN+193] ;ln 6
.WORD [MYSCRN+225] ;ln 7
.WORD [MYSCRN+257] ;ln 8
.WORD [MYSCRN+289] ;ln 9
.WORD [MYSCRN+321] ;ln 10
.WORD [MYSCRN+353] ;ln 11
.WORD [MYSCRN+385] ;ln 12
.WORD [MYSCRN+417] ;ln 13
.WORD ERRLN ;ln 14
.WORD STATLN ;ln 15
BAL .BYTE 0,0
DRPOS .BYTE 5,8,11,14,17
BRKS .BYTE 0,0
EXEC .BYTE 0
BRKLN .BYTE 0,5,10,15,20,25
TKEY .BYTE 0,0
;
;Branch Instrs + branch bits
;
BRAL .BYTE $10,$50,$90,$D0
BRAH .BYTE $30,$70,$B0,$F0
BBIT .BYTE $80,$40,$01,$02
;
;Custom Display List
;
DLIST .BYTE $70,$70,$70,$42
.WORD LINE1
.BYTE $00,$02,$20,$42
.WORD MYSCRN
.BYTE $02,$02,$02,$02
.BYTE $02,$02,$02,$02
.BYTE $02,$02,$02,$02
.BYTE $02,$20,$42
.WORD LINE2
.BYTE $02,$00,$02
.BYTE $00,$02,$00,$02
.BYTE $00,$02,$02,$41
.WORD DLIST
;
;Screen Memory
;
LINE1 .SBYTE +$80," DEBUG+ by: Bryan Schappel "
.SBYTE +$80," ADDR B1 B2 B3 MNEMONICS "
LINE2 .SBYTE +$80," PC| A| X| Y|SP|NV_BDIZC|MODE "
PCNT .SBYTE " | | | | | |DISA "
.SBYTE +$80," INPUT:"
.BYTE 0
COMND .SBYTE " "
COMLN .SBYTE " "
.SBYTE " "
.SBYTE +$80," ERROR:"
.BYTE 0
ERRLN .SBYTE " "
.SBYTE +$80," STAT:"
.BYTE 0
STATLN .SBYTE " "
.SBYTE +$80,"BRK1|BRK2|BRK3|BRK4|BRK5|BRK6|FR"
FRLN .SBYTE " | | | | | |00"
;
;Run and trace data tables
;
USRA .BYTE 0
USRX .BYTE 0
USRY .BYTE 0
USRS .BYTE 0
USRP .BYTE 0
USRPC .BYTE 0,0
;
;Register Table
;
REGTAB .WORD USRA
.WORD USRX
.WORD USRY
.WORD USRS
.WORD USRP
BITS .BYTE 1,2,4,8,16,32,64,128
;
;Icode/Asc convert tables
;
A2I .BYTE $40,$00,$20,$60
I2A .BYTE $20,$40,$00,$60
;
;BRK point data tables
;
SETLO .BYTE 0,0,0,0,0,0 ;LSB
SETHI .BYTE 0,0,0,0,0,0 ;MSB
OLDOP .BYTE 0,0,0,0,0,0 ;opcode
OPSET .BYTE 0,0,0,0,0,0 ;flag
;
;Special Key presses
;
KEYS .BYTE $FF,$FE,$FD,$9F,$9E
.BYTE $9D,$9C,$9B,$7F,$7E
.BYTE $7D,$1F,$1E,$1D,$1C
.BYTE $1B
;
;Error codes numbers
;
ERRS .BYTE 128,130,137,138,139
.BYTE 144,146,162,164,165
.BYTE 167,169,170,149
.BYTE 150,151,152,153
;
;Error code addresses
;
ERRTAB .WORD I128,I130,I137
.WORD I138,I139,I144
.WORD I146,I162,I164
.WORD I165,I167,I169
.WORD I170,I149,I150
.WORD I151,I152,I153
;
;Miscellaneous Text & Devs
;
DEVNAMS .SBYTE "(D,P)?"
PGTR .SBYTE "(U,D)?"
SLOF .SBYTE "(S,F,O)?"
REGTXT .SBYTE "(AXYSP)?"
DEVS .BYTE "DP"
FILNAM .BYTE " : "
.BYTE " ",EOL
REGIS .BYTE "AXYSP"
BRKPNT .BYTE "BRK POINT FOUND"
LEGAL .BYTE $9B,$9C,$7E,",."
HEXDIG .BYTE "0123456789ABCDEF"
.BYTE "GHIJKLMNOPQRSTUVWXYZ"
FTXT .BYTE "FIND #"
COMMAX .BYTE ",X)"
COMMAY .BYTE "Y,)"
LODAD .BYTE "LOAD AT"
;
;English Error Codes
;
I128 .CBYTE "BREAK KEY ABORT"
I130 .CBYTE "NO DEVICE HANDLER"
I137 .CBYTE "TRUNCATED RECORD"
I138 .CBYTE "DEVICE TIMEOUT"
I139 .CBYTE "DEVICE NAK"
I144 .CBYTE "WRITE PROTECTED"
I146 .CBYTE "FUNCTION NOT DONE"
I162 .CBYTE "DISK FULL"
I164 .CBYTE "FILE NUM MISMATCH"
I165 .CBYTE "BAD FILE NAME"
I167 .CBYTE "FILE LOCKED"
I169 .CBYTE "DIRECTORY FULL"
I170 .CBYTE "FILE NOT FOUND"
I149 .CBYTE "FILE NOT BINARY"
I150 .CBYTE "NO SET BRK POINT"
I151 .CBYTE "INVALID OPCODE"
I152 .CBYTE "BRK POINT SET"
I153 .CBYTE "ADR RANGE ERROR"
;
;These are the mnemonics for
;the disassembler. They are
;arranged here in alphabetical
;order.
;
MNE .BYTE "ADCANDASLBCCBCS"
.BYTE "BEQBITBMIBNEBPL"
.BYTE "BRKBVCBVSCLCCLD"
.BYTE "CLICLVCMPCPXCPY"
.BYTE "DECDEXDEYEORINC"
.BYTE "INXINYJMPJSRLDA"
.BYTE "LDXLDYLSRNOPORA"
.BYTE "PHAPHPPLAPLPROL"
.BYTE "RORRTIRTSSBCSEC"
.BYTE "SEDSEISTASTXSTY"
.BYTE "TAXTAYTSXTXATXS"
.BYTE "TYA???"
;
;Opcodes
;
OPCODE
.BYTE $69,$65,$75,$6D ;ADC
.BYTE $7D,$79,$61,$71
.BYTE $29,$25,$35,$2D ;AND
.BYTE $3D,$39,$21,$31
.BYTE $0A,$06,$16,$0E ;ASL
.BYTE $1E
.BYTE $90 ;BCC
.BYTE $B0 ;BCS
.BYTE $F0 ;BEQ
.BYTE $24,$2C ;BIT
.BYTE $30 ;BMI
.BYTE $D0 ;BNE
.BYTE $10 ;BPL
.BYTE $00 ;BRK
.BYTE $50 ;BVC
.BYTE $70 ;BVS
.BYTE $18 ;CLC
.BYTE $D8 ;CLD
.BYTE $58 ;CLI
.BYTE $B8 ;CLV
.BYTE $C9,$C5,$D5,$CD ;CMP
.BYTE $DD,$D9,$C1,$D1
.BYTE $E0,$E4,$EC ;CPX
.BYTE $C0,$C4,$CC ;CPY
.BYTE $C6,$D6,$CE,$DE ;DEC
.BYTE $CA ;DEX
.BYTE $88 ;DEY
.BYTE $49,$45,$55,$4D ;EOR
.BYTE $5D,$59,$41,$51
.BYTE $E6,$F6,$EE,$FE ;INC
.BYTE $E8 ;INX
.BYTE $C8 ;INY
.BYTE $4C,$6C ;JMP
.BYTE $20 ;JSR
.BYTE $A9,$A5,$B5,$AD ;LDA
.BYTE $BD,$B9,$A1,$B1
.BYTE $A2,$A6,$B6,$AE ;LDX
.BYTE $BE
.BYTE $A0,$A4,$B4,$AC ;LDY
.BYTE $BC
.BYTE $4A,$46,$56,$4E ;LSR
.BYTE $5E
.BYTE $EA ;NOP
.BYTE $09,$05,$15,$0D ;ORA
.BYTE $1D,$19,$01,$11
.BYTE $48 ;PHA
.BYTE $08 ;PHP
.BYTE $68 ;PLA
.BYTE $28 ;PLP
.BYTE $2A,$26,$36,$2E ;ROL
.BYTE $3E
.BYTE $6A,$66,$76,$6E ;ROR
.BYTE $7E
.BYTE $40 ;RTI
.BYTE $60 ;RTS
.BYTE $E9,$E5,$F5,$ED ;SBC
.BYTE $FD,$F9,$E1,$F1
.BYTE $38 ;SEC
.BYTE $F8 ;SED
.BYTE $78 ;SEI
.BYTE $85,$95,$8D ;STA
.BYTE $9D,$99,$81,$91
.BYTE $86,$96,$8E ;STX
.BYTE $84,$94,$8C ;STY
.BYTE $AA ;TAX
.BYTE $A8 ;TAY
.BYTE $BA ;TSX
.BYTE $8A ;TXA
.BYTE $9A ;TXS
.BYTE $98 ;TYA
;
;Offsets into Mnemonic table
;
OFFSET
.BYTE 0,0,0,0,0,0,0,0 ;ADC
.BYTE 3,3,3,3,3,3,3,3 ;AND
.BYTE 6,6,6,6,6 ;ASL
.BYTE 9 ;BCC
.BYTE 12 ;BCS
.BYTE 15 ;BEQ
.BYTE 18,18 ;BIT
.BYTE 21 ;BMI
.BYTE 24 ;BNE
.BYTE 27 ;BPL
.BYTE 30 ;BRK
.BYTE 33 ;BVC
.BYTE 36 ;BVS
.BYTE 39 ;CLC
.BYTE 42 ;CLD
.BYTE 45 ;CLI
.BYTE 48 ;CLV
.BYTE 51,51,51,51 ;CMP
.BYTE 51,51,51,51
.BYTE 54,54,54 ;CPX
.BYTE 57,57,57 ;CPY
.BYTE 60,60,60,60 ;DEC
.BYTE 63 ;DEX
.BYTE 66 ;DEY
.BYTE 69,69,69,69 ;EOR
.BYTE 69,69,69,69
.BYTE 72,72,72,72 ;INC
.BYTE 75 ;INX
.BYTE 78 ;INY
.BYTE 81,81 ;JMP
.BYTE 84 ;JSR
.BYTE 87,87,87,87 ;LDA
.BYTE 87,87,87,87
.BYTE 90,90,90,90,90 ;LDX
.BYTE 93,93,93,93,93 ;LDY
.BYTE 96,96,96,96,96 ;LSR
.BYTE 99 ;NOP
.BYTE 102,102,102,102 ;ORA
.BYTE 102,102,102,102
.BYTE 105 ;PHA
.BYTE 108 ;PHP
.BYTE 111 ;PLA
.BYTE 114 ;PLP
.BYTE 117,117,117,117 ;ROL
.BYTE 117
.BYTE 120,120,120,120 ;ROR
.BYTE 120
.BYTE 123 ;RTI
.BYTE 126 ;RTS
.BYTE 129,129,129,129 ;SBC
.BYTE 129,129,129,129
.BYTE 132 ;SEC
.BYTE 135 ;SED
.BYTE 138 ;SEI
.BYTE 141,141,141,141 ;STA
.BYTE 141,141,141
.BYTE 144,144,144 ;STX
.BYTE 147,147,147 ;STY
.BYTE 150 ;TAX
.BYTE 153 ;TAY
.BYTE 156 ;TSX
.BYTE 159 ;TXA
.BYTE 162 ;TXS
.BYTE 165 ;TYA
.BYTE 168 ;???
;
;Instruction Types
;
; 0 = Immediate
; 1 = Zero page
; 2 = Zero page,X
; 3 = Absolute
; 4 = Absolute,X
; 5 = Absolute,Y
; 6 = Indirect,X
; 7 = Indirect,Y
; 8 = Accumulator
; 9 = Relative
;10 = Implied
;11 = Indirect
;12 = Zero page,Y
;
ITYPE
.BYTE 0,1,2,3,4,5,6,7 ;ADC
.BYTE 0,1,2,3,4,5,6,7 ;AND
.BYTE 8,1,2,3,4 ;ASL
.BYTE 9 ;BCC
.BYTE 9 ;BCS
.BYTE 9 ;BEQ
.BYTE 1,3 ;BIT
.BYTE 9 ;BMI
.BYTE 9 ;BNE
.BYTE 9 ;BPL
.BYTE 10 ;BRK
.BYTE 9 ;BVC
.BYTE 9 ;BVS
.BYTE 10 ;CLC
.BYTE 10 ;CLD
.BYTE 10 ;CLI
.BYTE 10 ;CLV
.BYTE 0,1,2,3,4,5,6,7 ;CMP
.BYTE 0,1,3 ;CPX
.BYTE 0,1,3 ;CPY
.BYTE 1,2,3,4 ;DEC
.BYTE 10 ;DEX
.BYTE 10 ;DEY
.BYTE 0,1,2,3,4,5,6,7 ;EOR
.BYTE 1,2,3,4 ;INC
.BYTE 10 ;INX
.BYTE 10 ;INY
.BYTE 3,11 ;JMP
.BYTE 3 ;JSR
.BYTE 0,1,2,3,4,5,6,7 ;LDA
.BYTE 0,1,12,3,5 ;LDX
.BYTE 0,1,2,3,4 ;LDY
.BYTE 8,1,2,3,4 ;LSR
.BYTE 10 ;NOP
.BYTE 0,1,2,3,4,5,6,7 ;ORA
.BYTE 10 ;PHA
.BYTE 10 ;PHP
.BYTE 10 ;PLA
.BYTE 10 ;PLP
.BYTE 8,1,2,3,4 ;ROL
.BYTE 8,1,2,3,4 ;ROR
.BYTE 10 ;RTI
.BYTE 10 ;RTS
.BYTE 0,1,2,3,4,5,6,7 ;SBC
.BYTE 10 ;SEC
.BYTE 10 ;SED
.BYTE 10 ;SEI
.BYTE 1,2,3,4,5,6,7 ;STA
.BYTE 1,12,3 ;STX
.BYTE 1,2,3 ;STY
.BYTE 10 ;TAX
.BYTE 10 ;TAY
.BYTE 10 ;TSX
.BYTE 10 ;TXA
.BYTE 10 ;TXS
.BYTE 10 ;TYA
.BYTE 10 ;???
;
MYBUF .DS 40 ;I/O buffer
MBF2 .DS 15 ;temp save buff
MYZPG .DS 256 ;zero page
MYPG1 .DS 256 ;stack
MYPG2 .DS 256 ;page two
ENDBUF = * ;end of buffers
MYSCRN = $BD00 ;scr mem 3pgs
;
*= $02E0
.WORD DISA
.END