A.N.A.L.O.G. ISSUE 18 / MAY 1984 / PAGE 78
HBUG is a simple debugging utility designed for readers of ANALOG’s Boot Camp column who do not own the Atari Assembler Editor cartridge. The program’s syntax is the same as DEBUG, allowing Boot Camp readers to execute the examples and observe the results.
Why write another debug package? I’m sure quite a few readers own the MAC/65 assembler from Optimized Systems Software. This is a fine package (I use it myself, and recommend it highly). As you may know, MAC/65 comes with its own debug package, BUG/65. BUG/65 is a very powerful debugging tool, but it has a couple of shortcomings.
First, the only way to stop a program that is running in an infinite loop is to press SYSTEM RESET. As a result, there is no way to determine register contents or where the program was looping.
Second, many of Boot Camp’s illustrative programs rely on the use of the BRK instruction to stop execution at selected locations. BUG/65 doesn’t recognize the BRK instruction, and any attempt to perform a BRK locks up the system. BUG/65 allows you to set breakpoints, but these are generally cumbersome to use.
HBUG overcomes these shortcomings, making life easier for those new to assembly language.
Before you start typing anything in, take a look at 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 on your disk called HBUG.COM.
Listing 2 is the assembly source code for HBUG, written with OSS’s MAC/65. You don’t have to type this in to use HBUG, but the adventuresome types out there (you know who you are) may like the assembly typing experience.
Follow the instructions below to create the HBUG.COM file.
Usually, you’ll want to load the object code of the program to be executed before loading HBUG. If the program is already in memory, simply skip ahead to the HBUG loading instructions.
If you want to load the object code in Atari DOS, go to the DOS menu screen and type:
L RETURN Filename.OBJ RETURN
If you’re using OS/A+, type:
LOA Filename.OBJ RETURN
To load HBUG with Atari DOS, go to the DOS menu screen and type:
L RETURN HBUG.COM RETURN
HBUG will load and run automatically.
To load HBUG with OS/A+, go to the OS/A+ input screen and type:
HBUG RETURN
HBUG will load and run automatically.
When running, HBUG supports 6 commands, which are a subset of the Atari assembler editor DEBUG program’s commands. These commands are:
DOS (RETURN TO DOS) DR (DISPLAY REGISTER CONTENTS) CR< (CHANGE REGISTER CONTENTS) D (DISPLAY MEMORY CONTENTS) C (CHANGE MEMORY CONTENTS) G (EXECUTE AT ADDRESS)
These commands are the most important ones, as far as we’re concerned. I would have liked to include the “disassemble memory” command, but it would have increased the size of the program considerably. The use of these commands is described below.
If any invalid commands are entered, HBUG will “beep” at you and show the line you entered with the invalid character highlighted in inverse video.
This command is simple — it transfers control to the disk operating system. Once there, you can perform any function allowed by DOS. If you’re using OS/A+, typing RUN restarts HBUG. If you’re using Atari DOS, you’ll have to reload HBUG to start it up again.
You can set the registers (A, X, Y, Processor status [P], and Stack pointer [S]) to any values you like before executing a test program. Be careful about changing the P and S registers, since invalid values placed here can cause a system crash.
The format of the Change Registers command is:
CR< Ra, Rx, Ry, Rp, Rs Where Ra = Accumulator Rx = K register Ry = Y register Rp = Processor status register Rs = stack pointer
The values entered for the registers must be hexadecimal, from 0 through FF.
Figure 1 shows several forms of the CR command and their effect on the registers.
- CR<1F,6E
- Changes the Accumulator to $1F and the X register to $6E.
- CR<,,,4C
- Changes the P register to $40. All other registers are unchanged.
Figure 1.
You can see that by inserting commas, you can leave certain registers unchanged while altering others.
This command is the companion of the CR command. Its format is:
DR
Whenever you want to see what the current settings of the user registers, simply type DR and press return. The computer will display something like this:
A=03 X=32 Y=81 P=33 S=E2
HBUG allows you to display the contents of any memory byte or group of bytes. The formats of this command are:
FORMAT 1: Dxxxx FORMAT 2: D FORMAT 3: Dxxxx, yyyy
Format 1 displays eight bytes of memory starting at address xxxx.
Format 2 displays the eight bytes of memory starting at the last specified address plus 8.
Format 3 displays the memory block from address xxxx to yyyy. The display can be paused by pressing CTRL-1 and stopped by pressing the BREAK key.
This command differs from the cartridge command in that the ATASCII characters corresponding to the displayed bytes are shown to the right of the hex values.
You can change any memory byte in system RAM with the Change Memory command. Its format is:
Cxxxx< byte1, byte2, ... , byte n
This command changes the memory starting at address xxxx to the hex values following the “<” symbol. Like the CR command, the C command allows you to skip memory locations by using commas to indicate skipped bytes. Figure 2 shows several examples of the Change memory command.
- C 5000<1F,45,DE
- Change location $5000 to $1F, $5001 to $45, and $5002 to $DE.
- C 600<20,,,,F6
- Change location $0600 to $20 and location $0604 to $F6. Leave all other locations as is.
Figure 2.
Use care when changing memory bytes! Be sure you’re using the address you want, because careless changes could wipe out vital system data, causing a fatal lockup. Also, take care not to change any locations from $2000-26FF, since this is where HBUG is located.
This command is what HBUG is all about. It allows you to execute assembly code you have placed in memory. Its format is:
Gxxxx
When the G command is entered, the computer (1) changes the 6502 registers to the values contained in the user registers (see CR and DR), and (2) jumps to the address specified by xxxx.
The user program will continue to execute until it is stopped by the BREAK key or tries to execute a 6502 BRK instruction. If either of these events occurs, the program will be interrupted, HBUG will place the 6502 register contents in the user registers and HBUG will take control. The location where the program was executing and the user registers will be displayed in the following format:
40F5 A=1B X=6F Y=2D P=04 S=EA
HBUG will perform as advertised unless the user program violates the HBUG rules, outlined below.
If you follow these instructions and avoid careless alteration of HBUG’s memory, HBUG should help you debug the programs that BUG/65 couldn’t.
10 REM *** HBUG *** 20 DATA 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15 30 DIM DAT$(91),HEX(22):FOR X=0 TO 22: READ N:HEX(X)=N:NEXT X:LINE=990:RESTOR E 1000:TRAP 110:? "CHECKING DATA" 40 LINE=LINE+10:? "LINE:";LINE:READ DA T$:IF LEN(DAT$)<>90 THEN 160 50 DATLIN=PEEK(183)+PEEK(184)*256:IF D ATLIN<>LINE THEN ? "LINE ";LINE;" MISS ING!":END 60 FOR X=1 TO 89 STEP 2:D1=ASC(DAT$(X, X))-48:D2=ASC(DAT$(X+1,X+1))-48:BYTE=H EX(D1)*16+HEX(D2) 70 IF PASS=2 THEN PUT #1,BYTE:NEXT X:R EAD CHKSUM:GOTO 40 80 TOTAL=TOTAL+BYTE:IF TOTAL>999 THEN TOTAL=TOTAL-1000 90 NEXT X:READ CHKSUM:IF TOTAL=CHKSUM THEN 40 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,0:PUT #1,3 2:CLOSE #1:END 130 ? "INSERT DISK, PRESS RETURN";:DIM IN$(1):INPUT IN$:OPEN #1,8,0,"D:HBUG. COM" 140 PUT #1,255:PUT #1,255:PUT #1,0:PUT #1,32:PUT #1,159:PUT #1,37 150 ? :? "WRITING FILE":PASS=2:LINE=99 0:RESTORE 1000:TRAP 110:GOTO 40 160 ? "BAD DATA: LINE ";LINE:END 1000 DATA A9008D0ED48D8325BA8E7925AD06 028D1326AD07028D1426A9248D0702A9478D06 02A224A07DA907205CE4A940,79 1010 DATA 8D0ED420B82320132420EF23A200 A9878D4403A9258D4503A9058D4203A97F8D48 038E49032056E430E2A200BD,272 1020 DATA 8725C99BF003E810F6E000F0CC8E 8225A200BD8725C920D0148AA8B98825998725 C8CC8225D0F4CE82254C6C20,99 1030 DATA E8EC8225D0DFAD8225D0034C3320 A9008D7E25AC7E25B9D4248D7F25BED324A000 B98725DDC824D01BC8E8EC7F,862 1040 DATA 25D0F1AD7E250AAABDDA248D8025 BDDB248D81256C8025EE7E25AD7E25C907D0C5 20F6234C3320B98725C99BF0,412 1050 DATA 034CD520A2E4A062A907205CE4AD 13268D0602AD14268D07026C0A00086829EF48 2820B823AD7A25203024AD7D,291 1060 DATA 258D0025AD7C258DFF24AD7B2520 3024AD7D258DFE24AD7C258DFD242051212013 24A2FDA0242017244C3320B9,530 1070 DATA 8725C99BF0034CD520205121A205 A0252017244C3320A000B97525203024BE6025 AD7C259D0525AD7D259D0625,388 1080 DATA C8C005D0E660A204BD75259D0726 CA10F7A200A9008D0D268D0C26B98725C99BF0 0AC92CF00620BD214C8321AD,330 1090 DATA 0C26F006AD0D269D0726B98725C9 9BD00EA204BD07269D7525CA10F74C3320E8C8 E005D0C14CD5208E8525A20F,194 1100 DATA DD6525F006CA10F84CEF210E0D26 0E0D260E0D260E0D268A0D0D268D0D26EE0C26 AD0C26C903B005AE8525C860,803 1110 DATA 68684CD520B98725C99BD01DA5D4 18690885D4A5D5690085D5A9008D1126A9078D 10264C50224CD520206123AE,555 1120 DATA 1226F0F5AE0E2686D4AE0F2686D5 C99BF0DAC92CD0E3C8206123AE1226F0DAC99B D0D6AD0E2638E5D48D1026AD,656 1130 DATA 0F26E5D58D1126A920A22C9D3225 CA10FAA91BA20E9D4F25CACA10F9A5D4203024 AD7D258D3525AD7C258D3425,403 1140 DATA A5D5203024AD7D258D3325AD7C25 8D3225A000B1D4C99BF006BE2A259D4F252030 24BE2225AD7D259D3825AD7C,975 1150 DATA 259D3725C8AD102638E9018D1026 AD1126E9008D11261006200C244C3320C008D0 C4200C2410034C3320A5D418,354 1160 DATA 690885D4A5D5690085D54C5022B9 8725C93CF016206123AE1226F04BC93CD047AE 0E2686D4AE0F2686D5C8A200,468 1170 DATA A9008D0D268D0C26B98725C99BF0 0AC92CF00620BD214C0523AD0C26F00D8C8625 8AA8AD0D2691D4AC8625B987,181 1180 DATA 25C99BD0034C3320E8C84CFD224C D520206123C99BD01DAD1226F018AE79259AAD 782548AE7625AC7725AD7525,182 1190 DATA EE8325286C0E264CD520A9008D0E 268D0F268D1226B98725C99BF008C92CF004C9 3CD00160A20FDD6525F008CA,864 1200 DATA 10F868684CD5200E0E262E0F260E 0E262E0F260E0E262E0F260E0E262E0F268A0D 0E268D0E26EE1226AD1226C9,437 1210 DATA 05B0D2C84C6C23D820D923A200A9 E68D4403A9248D4503A9038D4203A90C8D4A03 8E4B032056E460A2078E8425,861 1220 DATA A90C9D42032056E4CE8425AE8425 10F060A2EAA0244C1724A980198725998725A2 EFA024201724A287A0254C17,511 1230 DATA 24A232A0254C1724A2E9A0248E44 038C4503A200A9098D4203A97F8D48038E4903 2056E46048290FAABD65258D,595 1240 DATA 7D25684A4A4A4AAABD65258D7C25 60AD8325D0026840D8A9008D83258E76258C77 25688D7525688D78256838E9,252 1250 DATA 028D7A2568E9008D7B258E8525BA 8E7925AE8525584CFD20AD8325F043A511D03F A9808511A9008D8325BABD01,185 1260 DATA 018D7725BD02018D7625BD03018D 7525BD04018D7825BD05018D7A25BD06018D7B 258A1869068D7925A9209D06,879 1270 DATA 01A9FD9D05014C62E4444F534452 43523C44434700030508090A0BDB203A216E21 F421DD223A23453A9B9B4842,393 1280 DATA 55479BFD494E505554204552524F 52219B202020202020202020202020413D2020 20583D202020593D20202050,148 1290 DATA 3D202020533D20209B000306090C 0F121501030507090B0D0F2020202020202020 202020202020202020202020,456 1300 DATA 2020202020202020202020202020 20202020202020202020209B060B10151A3031 323334353637383941424344,282 1310 DATA 4546000000000000000000000000 00000000000000000000000000000000000000 000000000000000000000000,421
10 DATA 445,957,808,431,727,198,599,553,272,701,611,112,74,561,36,7085 160 DATA 165,899,670,50,200,953,769,78 8,545,908,10,936,728,156,4,7781 1140 DATA 914,480,888,896,938,985,945, 703,671,650,801,931,906,613,145,11466 1290 DATA 871,748,340,1959
.OPT NOLIST *= $2000 ; ;----------------------------- ;HUDSON'S DEBUG PROGRAM (HBUG) ;----------------------------- ; DOSVEC = $0A ;DOS run address BRKKEY = $11 ;BREAK key status STACK = $0100 ;hardware stack VBREAK = $0206 ;BRK inst vector RUNAD = $02E0 ;prog run addr ICCOM = $0342 ;CIO command ICBADR = $0344 ;CIO buffer address ICBLEN = $0348 ;CIO buffer length ICAUX1 = $034A ;CIO aux. byte 1 ICAUX2 = $034B ;CIO aux. byte 2 NMIEN = $D40E ;interrupt enable CIOV = $E456 ;CIO entry point SETVBV = $E45C ;VBLANK setup XITVBV = $E462 ;VBLANK exit ; ;Page zero usage ; CML = $D4 ;my two-byte CMH = $D5 ;address work area ; ;------------------- ;Program entry point ;------------------- ; HBUG LDA #$00 ;turn off... STA NMIEN ;interrupts STA EXEC ;and execute flag TSX ;get stack pointer STX USERS ;put in user area LDA VBREAK ;save old BRK STA BRKSVL ;vector in my LDA VBREAK+1 ;work area STA BRKSVH ;for later LDA # >BRKHAN ;now point to STA VBREAK+1 ;my BRK inst. LDA # <BRKHAN ;routine STA VBREAK LDX # >VBI ;set up LDY # <VBI ;vertical LDA #7 ;blank JSR SETVBV ;interrupt LDA #$40 ;turn on the STA NMIEN ;VBLANK interrupt JSR NEWSCR ;open GR.0 screen INPUT JSR PRTCR ;carriage return JSR PROMPT ;print HBUG prompt INPT2 LDX #0 LDA # <MYBUFF ;point to STA ICBADR ;my input LDA # >MYBUFF ;buffer STA ICBADR+1 LDA #5 ;GET RECORD command STA ICCOM LDA #$7F ;my buffer's STA ICBLEN ;length STX ICBLEN+1 JSR CIOV ;get input! BMI INPT2 ;go back if error ; ;This section 'squishes' all the ;spaces out of the input line. ; LDX #0 ;first find end FINDBE LDA MYBUFF,X ;of line CMP #$9B ;CR? BEQ GOTEND ;yes! INX ;no, next char. BPL FINDBE ;keep looking! GOTEND CPX #0 ;CR first char? BEQ INPUT ;yes, try again. STX ENDPTR ;save end index LDX #0 ;start w/1st char SQUISH LDA MYBUFF,X ;get the character CMP #32 ;space? BNE NOSQSH ;no! TXA ;move index TAY ;to Y register SQSHLP LDA MYBUFF+1,Y ;shift all STA MYBUFF,Y ;characters INY ;back to remove CPY ENDPTR ;the space. BNE SQSHLP DEC ENDPTR ;line 1 shorter JMP SQUISH ;keep squishing! NOSQSH INX ;next char CPX ENDPTR ;end? BNE SQUISH ;no, keep going! LDA ENDPTR ;was line all spaces? BNE GETCMD ;no, get command JMP INPUT ;get another input! ; ;Now find command & process it ; GETCMD LDA #0 ;start with 1st STA CMDPTR ;command. CHKCMD LDY CMDPTR ;get command pointer LDA CMDST+1,Y ;get index of STA CEND ;command text end LDX CMDST,Y ;and start. LDY #0 ;point to 1st char CMDCMP LDA MYBUFF,Y ;is buffer char CMP CMDTXT,X ;= command char? BNE NOTCMD ;no! INY ;yes, try next char INX ;next command char CPX CEND ;end of command? BNE CMDCMP ;no, keep comparing! LDA CMDPTR ;yes, mult command ASL A ;index by 2 to point TAX ;into jump table LDA CMDADR,X ;get command routine STA CMDJMP ;address low byte LDA CMDADR+1,X ;and high byte STA CMDJMP+1 ;and save. JMP (CMDJMP) ;jump to routine! NOTCMD INC CMDPTR ;try next command LDA CMDPTR ;get pointer CMP #7 ;more commands? BNE CHKCMD ;yes! GOTERR JSR ERRMSG ;oops! bad command! JMP INPUT ;get another input ; ;This section handles the DOS ;command. It shuts off the HBUG ;VBLANK and BRK vectors and JMPs ;to DOS. ; GODOS LDA MYBUFF,Y ;get next char CMP #$9B ;CR? BEQ DOSOK ;yes, go to DOS JMP GOTERR ;no, invalid command! DOSOK LDX # >XITVBV ;point VBLANK LDY # <XITVBV ;back to the LDA #7 ;system exit JSR SETVBV ;point. LDA BRKSVL ;restore old STA VBREAK ;system LDA BRKSVH ;BRK vector from STA VBREAK+1 ;save area JMP (DOSVEC) ;go to DOS! ; ;Show regs after BREAK key or ;BRK instruction. ; SHOBRK PHP ;get processor PLA ;status in A, AND #$EF ;turn off BRK flag PHA ;and put back in PLP ;status register! JSR NEWSCR ;re-open screen LDA USRPCL ;get prog counter low JSR BINHEX ;convert to hex LDA HEX2 ;get low digit STA BRK4 ;put in line LDA HEX1 ;get high digit STA BRK3 ;put in line, too LDA USRPCH ;get PC high JSR BINHEX ;convert to hex LDA HEX2 ;put low digit STA BRK2 ;in line LDA HEX1 ;and high digit STA BRK1 ;in line. JSR SETREG ;set rest of line JSR PRTCR ;carriage return LDX # <BRKTXT ;point to LDY # >BRKTXT ;BREAK text JSR PRINT ;print it JMP INPUT ;and get input ; ;Display registers (DR) ; SHOREG LDA MYBUFF,Y ;is next char CMP #$9B ;a CR? BEQ DROKAY ;yes, it's OK! JMP GOTERR ;otherwise ERROR DROKAY JSR SETREG ;get registers LDX # <DRTXT ;point to the LDY # >DRTXT ;DR text JSR PRINT ;print it JMP INPUT ;and get input ; ;Set up register disp area ; SETREG LDY #0 ;start w/user byte 0 SETLP LDA USER,Y ;get data JSR BINHEX ;convert to hex LDX DRPTR,Y ;get its position LDA HEX1 ;get first digit STA DRTXT,X ;put in line LDA HEX2 ;get second digit STA DRTXT+1,X ;put in line INY ;next byte CPY #5 ;done 5? BNE SETLP ;not yet! RTS ;all done! ; ;Change registers (CR) ; CHGREG LDX #4 ;first copy user INITMP LDA USER,X ;registers STA TMPUSR,X ;to temporary DEX ;hold area BPL INITMP LDX #0 ;1st user byte CRSTRT LDA #0 ;zero out... STA BHOLD ;byte hold STA HDIG ;and digit count CRLOOK LDA MYBUFF,Y ;get input char CMP #$9B ;CR? BEQ STOTRY ;yes, all done. CMP #$2C ;comma? BEQ STOTRY ;yes, try store JSR CTOBIN ;convert it to binary JMP CRLOOK ;and do next one STOTRY LDA HDIG ;any digits? BEQ NXTCCK ;no, skip it! LDA BHOLD ;yes, save the byte STA TMPUSR,X ;in temporary table NXTCCK LDA MYBUFF,Y ;was this CMP #$9B ;a CR? BNE NXTCHR ;no, keep going. LDX #4 ;otherwise, SETUSR LDA TMPUSR,X ;copy the STA USER,X ;temporary table DEX ;back to the BPL SETUSR ;user registers JMP INPUT ;get another line NXTCHR INX ;next user register INY ;next character CPX #5 ;done 5 regs? BNE CRSTRT ;no, loop back. JMP GOTERR ;UH-OH! too many! ; ;Convert char. to binary # ; CTOBIN STX XHOLD ;save X register LDX #$0F ;set scan index HDSCAN CMP HEXDIG,X ;compare ASCII BEQ GOTHD ;got it! DEX ;next char BPL HDSCAN ;scan all 16 JMP CBERR ;not in table! GOTHD ASL BHOLD ;shift current # ASL BHOLD ;left 4 times to ASL BHOLD ;multiply it by ASL BHOLD ;16 TXA ;get this digit ORA BHOLD ;and add it to STA BHOLD ;the hold area. INC HDIG ;one more digit LDA HDIG ;are there more CMP #3 ;than 2? BCS CBERR ;yes--too big! LDX XHOLD ;restore X reg INY ;next buffer char RTS ;and exit CBERR PLA ;remove return addr PLA ;from stack JMP GOTERR ;and do error routine ; ;Display memory contents ; SHOMEM LDA MYBUFF,Y ;is character... CMP #$9B ;a CR? BNE GETSAD ;no, get address. LDA CML ;get last address CLC ;and add 8 to it ADC #8 ;since no address STA CML ;was specified LDA CMH ADC #0 STA CMH SHOW8 LDA #0 ;show only 8 STA COUNTH ;bytes LDA #7 STA COUNTL JMP SHOWLN ;go show 'em! SMERR JMP GOTERR ;jump to err routine GETSAD JSR GET4 ;get 4-byte address LDX G4DIGS ;any digits found? BEQ SMERR ;no! LDX ADL ;save address STX CML ;in page zero LDX ADH ;work area STX CMH CMP #$9B ;CR after address? BEQ SHOW8 ;yes, show 8 bytes. CMP #$2C ;comma? BNE SMERR ;no, bad command INY ;next char JSR GET4 ;get end address LDX G4DIGS ;got any digits? BEQ SMERR ;no! CMP #$9B ;CR after end addr? BNE SMERR ;no! LDA ADL ;now subtract SEC ;end address SBC CML ;from start STA COUNTL ;to get number LDA ADH ;of bytes to SBC CMH ;display. STA COUNTH SHOWLN LDA #32 ;clear out LDX #44 ;display line CLRML STA SHOM1,X DEX BPL CLRML LDA #$1B ;and set up ESC LDX #14 ;characters SETESC STA ASCII,X ;in the ASCII DEX ;display area DEX BPL SETESC LDA CML ;convert the JSR BINHEX ;current address LDA HEX2 ;to ascii hex STA SHOM4 ;characters LDA HEX1 ;and put in STA SHOM3 ;the memory LDA CMH ;display line. JSR BINHEX ;this is done LDA HEX2 ;2 times, for STA SHOM2 ;the low and high LDA HEX1 ;bytes of the STA SHOM1 ;address LDY #0 ;start showing! BILDLN LDA (CML),Y ;get mem byte CMP #$9B ;CR? BEQ NO9B ;yes, don't show it! LDX ASCPOS,Y ;put in ASCII STA ASCII,X ;display area NO9B JSR BINHEX ;convert byte to hex LDX SMPOS,Y ;get position LDA HEX2 ;get low char STA SMDATA+1,X ;and store LDA HEX1 ;get high char STA SMDATA,X ;and store. INY ;next byte LDA COUNTL ;now decrement SEC ;the byte count SBC #1 ;by 1 STA COUNTL LDA COUNTH SBC #0 STA COUNTH BPL MORESM ;more? yes! JSR PDATA ;no more, print line JMP INPUT ;and get next command MORESM CPY #8 ;done 8 bytes? BNE BILDLN ;no, loop back JSR PDATA ;done 8, print 'em BPL NOSTOP ;no BREAK key JMP INPUT ;get next command NOSTOP LDA CML ;increment display CLC ;address by 8 ADC #8 STA CML LDA CMH ADC #0 STA CMH JMP SHOWLN ;and loop back. ; ;Change memory contents (Cnnnn<) ; CHGMEM LDA MYBUFF,Y ;get char CMP #$3C ;'<'? BEQ CMDFLT ;yes, default address JSR GET4 ;get the address LDX G4DIGS ;got any digits? BEQ CMERR ;no! CMP #$3C ;next char '<'? BNE CMERR ;no! LDX ADL ;save the STX CML ;change memory LDX ADH ;address on STX CMH ;page zero. CMDFLT INY ;next buffer char LDX #0 ;1st memory byte CMSTRT LDA #0 ;zero out... STA BHOLD ;byte hold STA HDIG ;and digit count CMLOOK LDA MYBUFF,Y ;get char CMP #$9B ;CR? BEQ CMTRY ;yes, all done! CMP #$2C ;comma? BEQ CMTRY ;yes, store last byte JSR CTOBIN ;convert char to binary JMP CMLOOK ;and get next CMTRY LDA HDIG ;any digits? BEQ NEXTCM ;no! don't store STY YHOLD ;save Y register TXA ;move X... TAY ;to Y LDA BHOLD ;get byte to store STA (CML),Y ;and store it! LDY YHOLD ;get Y back NEXTCM LDA MYBUFF,Y ;get last char CMP #$9B ;was it CR? BNE NXTLOC ;no, continue JMP INPUT ;all done! NXTLOC INX ;next mem byte INY ;next input char JMP CMSTRT ;loop back! CMERR JMP GOTERR ;go to error routine ; ;Execute at address (Gnnnn) ; EXECUT JSR GET4 ;get the run address CMP #$9B ;is that all? BNE EXERR ;no! LDA G4DIGS ;got any digits? BEQ EXERR ;no! LDX USERS ;put user stack TXS ;pointer in S LDA USERP ;put user status PHA ;on stack LDX USERX ;set user X reg LDY USERY ;and user Y reg LDA USERA ;and accumulator INC EXEC ;set execute flag PLP ;get status off stack JMP (ADL) ;go to run address! EXERR JMP GOTERR ;go to error routine ; ;Get 4-character address ; GET4 LDA #0 ;zero out... STA ADL ;address low byte STA ADH ;address high byte STA G4DIGS ;digit count G4LOOP LDA MYBUFF,Y ;get char CMP #$9B ;CR? BEQ G4END ;yes, all done! CMP #$2C ;comma? BEQ G4END ;yes, all done! CMP #$3C ;'<'? BNE TESTIT ;no, check digit G4END RTS ;exit! TESTIT LDX #$0F ;set hex digit pointer G4SCAN CMP HEXDIG,X ;is it this char? BEQ GOTG4D ;yes! DEX ;try next hex digit BPL G4SCAN ;loop if more. G4ERR PLA ;discard return PLA ;address, JMP GOTERR ;show error. GOTG4D ASL ADL ;this code ROL ADH ;shifts the ASL ADL ;current address ROL ADH ;left 4 bits ASL ADL ;in order to ROL ADH ;multiply it ASL ADL ;by 16. ROL ADH TXA ;get this digit ORA ADL ;and add it to STA ADL ;the address. INC G4DIGS ;one more digit LDA G4DIGS ;how many total? CMP #5 ;more than 4? BCS G4ERR ;yes! error! INY ;ok, do next character JMP G4LOOP ;and loop back. ; ;Set up new graphics 0 screen ; NEWSCR CLD JSR NOIOCB ;close all IOCB's ; ;now open screen! ; LDX #0 LDA # <EADR ;'E:' filename STA ICBADR LDA # >EADR STA ICBADR+1 LDA #3 ;OPEN command STA ICCOM LDA #12 ;I/O STA ICAUX1 STX ICAUX2 ;zero aux byte JSR CIOV ;open it! RTS ;and return. ; ;Close all IOCB's ; NOIOCB LDX #7 ;first close STX SAVEX ;all IOCB's. CLOOP LDA #12 ;CLOSE command STA ICCOM,X JSR CIOV ;close it! DEC SAVEX ;next IOCB LDX SAVEX ;more IOCB's? BPL CLOOP ;yes! RTS ;all done! ; ;Show HBUG prompt ; PROMPT LDX # <HMSG ;point to LDY # >HMSG ;HBUG message JMP PRINT ;and print it! ; ;Show error message ; ERRMSG LDA #$80 ;set high bit ORA MYBUFF,Y ;inverse the STA MYBUFF,Y ;invalid character LDX # <ERRTXT ;point to LDY # >ERRTXT ;error message JSR PRINT ;print it LDX # <MYBUFF ;point to LDY # >MYBUFF ;input buffer JMP PRINT ;print it, too! ; ;Print memory display line ; PDATA LDX # <SHOM1 ;point to memory LDY # >SHOM1 ;display line JMP PRINT ;print it! ; ;Print carriage return only ; PRTCR LDX # <CR ;point to CR and LDY # >CR ;fall thru to print ; ;General-use print routine ; PRINT STX ICBADR ;save print area lo STY ICBADR+1 ;and high LDX #0 ;zero X reg. LDA #9 ;PUT RECORD command STA ICCOM LDA #$7F ;set up... STA ICBLEN ;buffer length STX ICBLEN+1 JSR CIOV ;print it! RTS ;and exit. ; ;Binary-to-hex converter ; BINHEX PHA ;save byte AND #$0F ;get low 4 bits TAX ;put in index LDA HEXDIG,X ;lookup hex STA HEX2 ;and save PLA ;get byte again LSR A ;shift right LSR A ;4 times LSR A ;to get LSR A ;high 4 bits TAX ;put in index LDA HEXDIG,X ;lookup hex STA HEX1 ;and save RTS ;all done! ; ;Handle 6502 BRK interrupt ; BRKHAN LDA EXEC ;executing? BNE SAVREG ;yes! PLA ;no, restore accum. RTI ;and return from int. SAVREG CLD ;no decimal mode! LDA #0 ;reset the STA EXEC ;executing flag STX USERX ;save X STY USERY ;and Y PLA STA USERA ;and accumulator PLA STA USERP ;and status reg. PLA SEC ;now get program SBC #2 ;counter from stack STA USRPCL ;and subtract 2 PLA ;to get BREAK SBC #0 ;address. STA USRPCH STX XHOLD ;save X reg. TSX ;now store stack pntr STX USERS ;in the user area. LDX XHOLD ;restore X CLI ;clear interrupt JMP SHOBRK ;and show break info ; ;Handle BREAK key in VBI ; VBI LDA EXEC ;executing? BEQ NOBKEY ;no! LDA BRKKEY ;BREAK pressed? BNE NOBKEY ;no! LDA #$80 ;reset BREAK STA BRKKEY ;press flag LDA #0 ;and STA EXEC ;execute flag TSX ;get stack pntr LDA STACK+1,X ;get Y register STA USERY ;and save it LDA STACK+2,X ;get X register STA USERX ;and save it LDA STACK+3,X ;get accumulator STA USERA ;and save it LDA STACK+4,X ;get status register STA USERP ;and save it LDA STACK+5,X ;get program STA USRPCL ;counter LDA STACK+6,X ;and STA USRPCH ;store it! TXA ;move stack pntr CLC ;to A, add 6 to ADC #6 ;get true value STA USERS ;and save it! LDA # >SHOBRK ;change return STA STACK+6,X ;address to LDA # <SHOBRK ;go to SHOBRK STA STACK+5,X ;after VBLANK. NOBKEY JMP XITVBV ;all done! ; ;Data areas ; ;Command text & pointers ; CMDTXT .BYTE "DOSDRCR<DCG" CMDST .BYTE 0,3,5,8,9,10,11 CMDADR .WORD GODOS .WORD SHOREG .WORD CHGREG .WORD SHOMEM .WORD CHGMEM .WORD EXECUT ; ;Miscellaneous text ; EADR .BYTE "E:",$9B CR .BYTE $9B HMSG .BYTE "HBUG",$9B ERRTXT .BYTE $FD,"INPUT ERROR!",$9B BRKTXT BRK1 .BYTE 32 BRK2 .BYTE 32 BRK3 .BYTE 32 BRK4 .BYTE 32 .BYTE " " DRTXT .BYTE " A= X= Y= " .BYTE "P= S= ",$9B SMPOS .BYTE 0,3,6,9,12,15,18,21 ASCPOS .BYTE 1,3,5,7,9,11,13,15 SHOM1 .BYTE 32 SHOM2 .BYTE 32 SHOM3 .BYTE 32 SHOM4 .BYTE 32 FILL1 .BYTE 32 SMDATA .BYTE " " .BYTE " " FILL2 .BYTE 32 ASCII .BYTE " " .BYTE $9B DRPTR .BYTE 6,11,16,21,26 HEXDIG .BYTE "0123456789ABCDEF" ; ;Misc. memory usage ; USER ; user registers USERA .BYTE 0 ;accumulator USERX .BYTE 0 ;X register USERY .BYTE 0 ;Y register USERP .BYTE 0 ;status register USERS .BYTE 0 ;stack pointer USRPCL *= *+1 ;program counter low USRPCH *= *+1 ;program counter high HEX1 *= *+1 ;hex digit 1 HEX2 *= *+1 ;hex digit 2 CMDPTR *= *+1 ;command pointer CEND *= *+1 ;command end index CMDJMP *= *+2 ;command jump addr ENDPTR *= *+1 ;end of input pointer EXEC *= *+1 ;user prog execute flag SAVEX *= *+1 ;X reg. hold area XHOLD *= *+1 ;another X reg hold YHOLD *= *+1 ;Y reg hold MYBUFF *= *+128 ;input buffer TMPUSR *= *+5 ;user reg temp storage HDIG *= *+1 ;hex digit count BHOLD *= *+1 ;byte hold area ADL *= *+1 ;address low ADH *= *+1 ;address high COUNTL *= *+1 ;disp mem count, COUNTH *= *+1 ;low and high G4DIGS *= *+1 ;4-digit count BRKSVL *= *+1 ;BRK interrupt... BRKSVH *= *+1 ;vector save ; ;Tell computer where to run HBUG ; *= RUNAD .WORD HBUG ; ;That's all, folks! ; .END