;ALBUG.M65.71 12-Mar-82 15:25:26, Edit by HESS .TITLE LBUG - 6502 DEBUGGER (ATARI VERSION) ; (C) Ted Hess, Hudson, Ma. 1977,1978,1979,1980,1981,1982 .LIST MB ;LIST BINARY IN MACROS .NLIST TOC ;NO TABLE OF CONTENTS .ENABL LC ;ALLOW LOWER CASE TEXT ; INVOKE SYSTEM MACROS FOR PARAMETER DEFINITIONS .MCALL ATARI .MCALL M6502 ATARI M6502 ;***** THINGS TO DO ****** ; ; 1) Re-write parser for DDT syntax and better defaults ; Make better use of ATARI keyboard! ; ;************************* ;LBUG STORAGE ASSIGNMENTS (PAGE 0) INBUF =$E0 ;INPUT BUFFER (2 BYTES) POINT =$E2 ;OPEN CELL ADDRS (2 BYTES) AC =$E4 ;ACCUMULATOR XREG =$E5 ;X INDEX YREG =$E6 ;Y INDEX PS =$E7 ;PROCESSOR STATUS REG SP =$E8 ;STACK POINTER ;RANDOM CONSTANTS AND PARAMETERS DSKCOD =$31 ;DISK DEVICE CODE DSKR ='R ;DISK READ COMMAND DSKW ='W ;DISK WRITE COMMAND MAXBP =8 ;EIGHT IS TRADITIONAL (BREAK POINTS) LNSCR =24 ;# OF LINES ON SCREEN LPP =55 ;LINES/PAGE ON PRINTER .IIF NDF,LORG, LORG= $8000 ;DEFAULT PROG ORIGIN ;MAIN ENTRY POINT - NORMAL START (LORG) ;RESET ENTRY - REMOVE BREAKPOINTS (LORG+3) SETPC PPC,LORG ;NORMAL START ENTRY START: JMP STRT1 JMP RST VERS: .ASCII <.ATCLR>"Lady Bug - V4.0, (C) Ted Hess 1981"<.ATEOL> ROF: .BLKB 1 ; REGISTER OPENED FLAG ; 0 = CLOSED ; $1 = HEX/OCTAL ; $FF = SYMBOLIC CF: .BLKB 1 ;ADDRESS FLAG ; $FF = NO ADDRESSES TYPED ; $00 = ONE ADDRESS TYPED ; $01 = COMMA TYPED PRPC: .BLKB 2 ;PROGRAM COUNTER (AT BREAK) LENGTH: .BLKB 1 ; LENGTH OF INSTR (0 := 1-BYTE) PFRMT: .BLKB 1 ; PRINT FORMAT INDEX VEB: .BLKB 2 ;4 BYTE PROGRAM BLOCK LMNEM: .BLKB 1 ;(VEB+2) TEMP FOR MNEMONIC PRINT RMNEM: .BLKB 1 ;(VEB+3) ... STARTA: .BLKB 2 ;STARTING ADDRESS ENDAD: .BLKB 2 ;ENDING ADDRESS TEMPX: .BLKB 1 ;NEED TO SAVE X AROUND OS TEMPY: .BLKB 1 ;TEMP SAVE Y SNGLF: .BLKB 1 ;SINGLE STEP FLAG BPN: .BLKB 1 ;BREAKPOINT NUMBER OR 0 DRVNO: .BLKB 1 ;DISK UNIT # PIOCB: .BLKB 1 ;IOCB INDEX FOR PRINTER/EDITOR PNTF: .BLKB 1 ; PRINTER FLAG TABPT: .BLKB 1 ;INDEX INTO TAB RING TABRNG: .BLKW 8 ;RING BUFFER FOR TAB/UNTAB ;BREAKPOINT TABLES BPINS: .BLKB MAXBP ;SAVE INSTR BPCNT: .BLKB MAXBP ;PROCEED COUNT BPLOCL: .BLKB MAXBP ;LOCATION LOW BPLOCH: .BLKB MAXBP ;LOCATION HIGH ;RESET ENTRY RST: CALL REMB ;REMOVE BREAK POINTS ; NORMAL STARTUP JOINS HERE STRT1: CALL INITS ;INITIALIZE THINGS TYPE VERS ;OUTPUT HERALD CLR ;CLEAR SS FLAG, ETC. SET2 BREAK,VBREAK ;BREAK POINT ENTRY TSX ;SAVE CURRENT STACK POINTER STX SP JMP RALL ;CLEAR ALL BREAK POINTS ;MAIN DECODER ERR: CALL ERRFST ;PRINT ? DCD: CALL CLOSEP ;CLOSE PRINTER IF OPEN CALL CRLFS ;PRINT CRLF DCD4: CLR ROF ;CLOSE OPEN REG LDX SP ;RESTORE STACK POINTER TXS SCAN: LDA #$FF ;SET UP ADDRESS FLAG STA CF CALL GETNUM ;INPUT SOMETHING LDX CF ;GET QUANITY TYPED FLAG BMI CLGL ;DO NOT DESTROY OLD VALUE FOR ' AND = SCAN1: MOV2X INBUF,STARTA ;SET UP STARTING ADDRESS ;FALL INTO SPECAIL CHARACTER DECODER ;HERE TO CHECK LEGAL CHARACTER CLGL: LDX #MAXL ;INIT INDEX LGL1: CMP LGCH,X ;MATCH? BEQ LGL2 ;YES - PROCEED DEX ;NO - STEP TO NEXT BPL LGL1 ;BRANCH IF MORE TO GO BMI ERR ;ERROR IF NONE ;FOUND MATCH - DISPATCH LGL2: TXA ;GET INDEX LGL3: ASL A ; TIMES 2 TAX ; BACK TO X LDA LDISP+1,X ;GET HIGH BYTE OF XFER PHA ;PUT ON STACK LDA LDISP,X ;GET XFER LOW PHA ;STACK NOW HAS XFER ADDRS LDA CF ;GET ARGUMENT FLAG IN AC CMP #1 ;SET FLAGS BASED ON ONE RET ;DISPATCH ERRFST: LDA #.ATBEL ;RING BELL CALL OUTSCH LDA #'? ;THEN PRINT ? JMP OUTSCH ;COMMA - SAVE INPUT AS STARTING ADDRESS COMMA: LDA CF ;GET ARGUMENT FLAG IN AC BNE ERR ;MUST BE ONE AND ONLY ONE ARGUMENT TYPED SO FAR CALL GETNUM ;GET ANOTHER ARGUMENT COMMA1: MOV2X INBUF,ENDAD ;SET UP ENDING ADDRESS LDX CF ;GET ARGUMENT FLAG CPX #2 ;CHECK TO SEE IF IT IS OPEN BPL ERR ;NO THEN IT IS AN ERROR BMI CLGL ;GO DISPATCH ON BREAK CHARACTER ;ESC SEEN (ECHO $) ESC: LDA #'$ CALL OUTSCH CALL GETSCH ;GET NEXT CHARACTER SEC ;CLEAR BORROW SBC #'1 ;CHECK FOR NUMBER BMI ERR ;IF LESS THAN THEN IT IS AN ERROR CMP #MAXBP ;IS IT LESS THAN MAXIMUM ALLOWABLE BREAKPOINT BMI ESCB ;YES GO GET BREAKPOINT B SBC #@20 ;CHECK FOR A BMI ERR ;IF LESS THAN A IT IS AN ERROR AND #@337 ;GET RID OF LOWERCASE BIT CMP #'Z-@100 ;IS IT GREATER THAN Z BPL ERR1 ;YES. REPORT ERROR TAX ;PUT IT IN THE X REGISTER LDA ARGNUM,X ;GET NUMBER OF ARGUMENTS CMP CF ;IS IT CORRECT BEQ 10$ ;YES. SKIP REST OF TEST CMP #$80 ;IS IT ONE OR NONE FLAG BNE ERR1 ;NO GIVE ERROR LDA CF ;GET FLAG CMP #1 ;LESS THAN ONE BPL ERR1 ;NO. GO GIVE ERROR 10$: TXA ;GET INDEX BACK TO A CLC ADC #/2 ;CALC TABLE OFFSET BNE LGL3 ;DISPATCH ESCB: TAX ;SAVE BP NUMBER IN X CALL GETSCH ;GET THE CHARACTER AND #@337 ;GET RID OF CASE BIT CMP #'B ;IS IT A B BNE ERR1 ;NO. THEN IT IS AN ERROR JMP BKPT1 ;YES. GO DO BREAKPOINT ;DOT (.) SEEN - SUBSTITUE CURRENT LOC DOT: MOV2 POINT,INBUF ;PUT LOC INTO BUFFER DOT1: CALL GETSCH ;GET ANOTHER CHARACTER INC CF ;SAY QUANT TYPED BNE COMMA1 ;GO SET UP ENDING ADDRESS JMP SCAN1 ;BACK TO SCAN LOOP ;PERCENT SEEN - SPECIAL REGISTER PERC: CALL GETSCH ;LOOK AT NEXT CHAR AND #@337 ;GET RID OF CASE BIT LDX #MAXS ; AND CHECK FOR SPECIAL PERC1: CMP LGPC,X ;MATCH? BEQ PERC2 ;??? DEX ;NO - STEP TO NEXT BPL PERC1 ERR1: JMP ERR ;ERROR IF NO MORE ;SETUP DESIRED REGISTER ADDRS AS INPUT TYPED PERC2: LDA PERAD,X ;GET ADDRS OF BYTE STA INBUF ;STORE AS INPUT CLR INBUF+1 BEQ DOT1 ;BACK TO INPUT LOOP ;CARRIAGE RETURN TYPED CRET: CALL CLSE ;CLOSE OPEN REG IF ANY JMP DCD ;RE-INIT THINGS ;SLASH TYPED - OPEN A REG IN SYMBOLIC SLSH: BPL ERR1 ;IF MORE THAN ONE ARGUMENT IT IS AN ERROR LDA #$FF ;SET ROF FLAG BNE SLSH1 ;JOIN COMMON CODE ;SLASH TYPED - OPEN A REG (HEX) BRAKET: BPL ERR1 ;IF MORE THAN ONE ARGUMENT IT IS AN ERROR LDA #1 ;SET REG OPEN SLSH1: STA ROF CALL OUTSSP ;TYPE A SPACE LDA CF ;ANYTHING TYPED BNE 10$ ; ?? CALL INTPT ;YES - OPEN IT 10$: CALL PRTSCN ;GO DO OUTPUT JMP SCAN ;LINE FEED - OPEN NEXT REG LFD: BPL ERR1 ;IF MORE THAN ONE ARGUMENT IT IS AN ERROR CALL CRLFS ;OUTPUT LFD0: LDA ROF ;CHECK TYPE BMI LFDS ;DO SYMBOLIC NEXT INSTR CALL CLSE ;CLOSE OPEN REG IF ANY CALL INCPT ;STEP TO NEXT LOC LFDC: INC ROF ;MARK OPEN HEX LDX #'[ ;SLASH CALL PRTSLC ;GO PRINT THE CONTENTS JMP SCAN LFDS: CALL PCADJ ;STEP OVER INSTR STA POINT ;SAVE NEW PC STY POINT+1 LFDS1: CALL PRTSLS ;GO PRINT LOCATION IN SYMBOLIC JMP SCAN ;BACK TO MAIN COMMAND DECODER ;^ OR TYPED - OPEN PREVIOUS BACK: BPL ERR1 ;IF MORE THAN ONE ARGUMENT IT IS AN ERROR CALL CLSE ;CLOSE OPEN REG CALL DECPT ;DECREMENT THE POINTER CALL CRLFS ;PUT OUT A CARRIAGE RETURN LINE FEED JMP LFDC ;COMMON CODE ;TAB GO TO ADDRESS IF IN SYMBOLIC MODE TAB: BPL ERR1 ;ERROR IF MORE THAN 1 ARG LDA ROF ;GET OUTPUT MODE FLAG BPL ERR1 ;ONLY GET EFFECTIVE ADDRESS IF SYMBOLIC LDX TABPT ;SAVE POINT LDA POINT STA TABRNG,X ;IN RING BUFFER LDA POINT+1 STA TABRNG+8,X INX ;STEP INDEX TXA AND #$07 ;MASK TO MOD 8 CNTR STA TABPT ;STORE IT BACK CALL CALCAD ;CALCULATE EFFECTIVE ADDRESS MOV2 INBUF,POINT ;GET JMP ADDRESS TAB1: CALL CRLFS ;PUT OUT CARRIAGE RETURN LINE FEED JMP LFDS1 ;GO TYPE OUT NEW ADDRESS ; UNTABIFY - POP RING THEN TAB UNTAB: BPL 5$ ;ERROR IF ANYTHING TYPED LDA ROF ;REGISTER OPEN FLAG 5$: BPL ERR2 ;ERROR IF NOT SYMBOLIC MODE LDA #$7 ;MASK FOR MOD 8 SUBTRACT DEC TABPT ;DECREMENT INDEX AND TABPT ;MASK IT STA TABPT ;STORE RESULT TAX ;XFER TO INDEX LDA TABRNG,X ;FETCH SAVED VALUE STA POINT ;RESTORE TO POINT LDA TABRNG+8,X STA POINT+1 JMP TAB1 ;FINISH THRU COMMON CODE ;EQUAL SIGN - TYPE IN OCTAL TOC: BPL ERR2 ;IF MORE THAN ONE ARGUMENT IT IS AN ERROR LDA STARTA ;GET CHARACTER IN A STA PFRMT ;SAVE BYTE LDX #3 ;TYPE 3 DIGITS LDY #3 ; OF 3 BITS EACH CLC ;INIT CARRY BIT BCC 15$ ;SKIP FIRST SHIFT 10$: ASL PFRMT ;SHIFT LEFT 15$: ROL A ;GET BIT INTO AC DEY ;COUNT BITS BNE 10$ ;CONTINUE FOR 3 BITS AND #@7 ;GRNTEE OIT CALL HEXST1 ;TYPE OUT LDY #3 ;RELOAD BIT COUNTER DEX ;DECREMENT DIGIT COUNTER BNE 10$ ;LOOP TILL DONE TOCRET: CALL OUTSSP ;PRINT SPACE JMP SCAN ;BACK TO MAIN LOOP ;QUOTE - TYPE OUT ASCII QUOTE: BPL ERR2 ;IF MORE THAN ONE ARGUMENT IT IS AN ERROR LDA STARTA ;GET CHARACTER IN A CALL OUTSCH ;PRINT THE CHARACTER IN ASCII JMP TOCRET ;GO PRINT A SPACE AND RETURN ;$A - TYPE MEMORY OUT IN ASCII ASCII: CALL INTPT ;SET UP POINT FROM ADDRESS TYPED CALL GETSCH ;GET QUOTE CHARACTER STA CF ;SAVE IT FOR COMPARE 10$: CALL GETSCH ;GET ANOTHER CHARACTER CMP CF BEQ 20$ ;IF QUOTE RETURN LDY #0 ;SET UP FOR INDEXING STA (POINT),Y ;PUT THE CHARACTER IN MEMORY CALL INCPT ;INCREMENT THE POINTER JMP 10$ ;GO DO ANOTHER CHARACTER 20$: JMP DCD ;GO BACK TO MAIN SCANING LOOP ;$B - BREAKPOINT COMMAND BKPT: LDX #$FF ;SAY NO BREAKPOINT NUMBER GIVEN BKPT1: LDA CF ;GET ARGUMENT FLAG BMI CLRALL ;POSSIBLE CLEAR ALL $B OR $NB/ CPX #0 ;SPECIFIC BREAK POINT BPL BKPT2 ; IF QUANT AFTER $ LDX #MAXBP-1 ;LOOK FOR A FREE ONE 5$: LDA BPINS,X BEQ BKPT2 ;FOUND IF ZERO DEX ;STEP TO NEXT BPL 5$ ; AND TRY AGAIN ERR2: JMP ERR ;BRANCH TO HERE FOR ERROR ;X NOW CONTAINS AN INDEX INTO THE BP TABLES BKPT2: LDA STARTA ;CHECK FOR 0$NB BNE SETBP ;IF NOT ZERO CONTINUE LDA STARTA+1 ;GET HIGH BYTE BEQ CLRONE ;CLEAR JUST ONE ;NOW SET A BREAK POINT - ADDRS IN INTMP SETBP: MOV2 STARTA,INBUF ;NEED IN PAGE 0 LOC LDY #0 ;SET FOR INDIRECT LDA (INBUF),Y ;FETCH INSTR BEQ ERR2 ;ERROR IF 00 STA BPINS,X ;SAVE IN TABLE LDA INBUF ;SAVE ADDRS STA BPLOCL,X ; LOW LDA INBUF+1 ; AND HIGH STA BPLOCH,X ;... ; ... ; ... BPXIT: CALL PRBLNK ;PRINT SOME SPACES JMP SCAN ;BACK TO DECODER ;ROUTINE TO CLEAR ONE BREAKPOINT ;C(X) - INDEX INTO BP TABLES, C(AC) := 0 CLRONE: STA BPINS,X ;CLEAR BP STA BPCNT,X ; AND PROCEED COUNT BEQ BPXIT ;RETURN ;ROUTINE TO CLEAR ALL BREAK POINTS CLRALL: CPX #0 ;SPECIFIC BREAK POINT BPL SHONE ;SHOW ONE BP RALL: LDX #MAXBP-1 ;INIT COUNT LDA #0 ;GET A ZERO 5$: STA BPINS,X ;CLEAR BP STA BPCNT,X ;... DEX BPL 5$ ;LOOP TILL DONE JMP DCD ;RE-INIT THINGS ;ROUTINE TO SHOW LOC OF BP SHONE: CALL GETSCH ;LOOK AHEAD CHAR CMP #'/ ;GAURNTEE SLASH BNE ERR2 CALL OUTSSP ;SPACE OVER LDA BPINS,X ;SEE IF ACTIVE BEQ ERR2 ;NO - SORRY LDA BPLOCH,X ;GET LOC HIGH CALL PRTSBY ;PRINT IT LDA BPLOCL,X ;GET LOC LOW CALL PRTSBY ;PRINT IT JMP DCD ;CLOSE REG, ETC. ;$D - JUMP TO DOS TODOS: JMP (DOSVEC) ;$U - SELECT DISK UNIT SETU: LDA STARTA ;GET UNIT # BEQ ERR2 ;MUST BE 1-4 CMP #5 ;VALID? BCC ERR2 ;TOO LARGE STA DRVNO ;STORE UNIT # JMP BPXIT ;RETURN ;$W - WRITE DISK SECTORS FROM MEMORY WRSECT: CALL GETVAL ;BUFFER LDA #DSKW ;WRITE COMMAND BNE INIDSK ;DO IT ;$R - READ DISK SECTORS INTO MEMORY RDSECT: CALL GETVAL ;GET BUFFER ADDRS LDA #DSKR ;READ COMMAND INIDSK: STA DCOMND ;STORE MOV2 INBUF,DBUFLO ;SETUP BUFFER CALL INTPTC ;SET POINT := START SECTOR LDA #DSKCOD ;BUS I.D. FOR DISK STA DDEVIC LDA DRVNO ;SETUP DRIVE # STA DUNIT LDA #128 ;BYTE COUNT STA DBYTLO CLR DBYTHI DSKLUP: MOV2 POINT,DAUX1 ;SETUP SECTOR ADDRS CALL DSKINV ;INVOKE DISK HANDLER BMI IOCERR ;ERROR CODE IS .GE. $80 CALL ENDCHK ;CHECK END, INCR POINT CLC ;NOT END - STEP TO NEXT BUFFER LDA #128 ;128 BYTE/BUFFER ADC DBUFLO STA DBUFLO LDA #0 ;PROPAGATE CARRY ADC DBUFHI STA DBUFHI BNE DSKLUP ;LOOP TILL DONE IOCERR: CALL ERRFST ;OUT ? CALL OUTSSP LDA DSTATS ;GET STATUS CALL PRTSBY ;PRINT ERROR CODE CALL PRBLNK ;SOME BLANKS CALL PRTSPT ; THEN DISK ADDRS JMP DCD ;RETURN ;$F - FIND A BYTE IN MEMORY FIND: CALL GETVAL ;GET THE BYTE CALL INTPTC ;SET UP INDIRECT POINTER FROM START LDA #1 STA ROF ;SET THE MODE FLAG 10$: LDY #0 ;SET UP INDEX LDA (POINT),Y ;GET BYTE FROM MEMORY CMP INBUF ;DOES IT MATCH BNE 20$ ;NO LDX #'[ ;SLASH CALL PRTSLC ;GO PRINT THE CONTENTS CALL CRLFS ;PUT OUT CARRIAGE RETURN LINE FEED 20$: CALL ENDCHK ;ARE WE FINISHED JMP 10$ ;NO ;$G - START SOMEWHERE GO: CALL INTPTC ;GO SETUP ADDRESS CLR ;CLEAR CURRENT BP GO2: CALL INSB ;INSERT BP'S GO3: LDX SP ;RESTORE STACK TXS LDA POINT+1 ;SETUP RETURN ADDRS PHA ; ON STACK FOR RTI LDA POINT PHA ;... LDA PS ;PROCESSOR STATUS PHA LDX XREG ;RESTORE REGS LDY YREG LDA AC ;... RTI ;GO BACK ;HERE IF SINGLE STEP - SETUP FOR RE-ENTER AFTER XCT GO1: LDY IOPC ;CHECK FOR JUMPS CPY #$4C BEQ GOJMP ;VANILLA JUMP CPY #$6C ;MAYBE JUMP, INDIRECT BEQ GOJMPI ; A LITTLE MORE HAIRY CPY #$60 ;"RTS"? BEQ IRTS ; INTERPRET SUBROUTINE RETURN CPY #$40 ;"RTI" BEQ IRTI ; INTERPRET INTERRUPT RETURN BNE GO3 ; AND GO EXECUTE GOJMP: SET2 XCTBR,POINT ;EXECUTE HERE BNE GO3 GOJMPI: MOV2 XBTARG,POINT ;NEED TO PICK UP ACTUAL TARGET LDY #0 LDA (POINT),Y STA XBTARG ;AND SET UP FOR "BRANCH" SIMULATION INY ;SET TO NEXT LOC LDA (POINT),Y STA XBTARG+1 JMP GOJMP ;NO GO SIMULATE JMP (I) IRTS: LDX SP ;GET STACK POINTER TXS ;SETUP FOR "RTS" SIMULATION IRTS1: PLA ;PCL STA XBTARG PLA ;PCH STA XBTARG+1 CPY #$40 ;IS THIS SUBR OR INTERRUPT BEQ 10$ ;DON'T INCREMENT PC IF "RTI" INC XBTARG ;"RTS" NEED PC + 1 BNE 10$ INC XBTARG+1 10$: TSX ;SAVE MODIFIED STACK PNTR STX SP JMP GOJMP IRTI: LDX SP ;SETUP STACK POINTER TXS PLA ;GET PROCESSOR STATUS STA PS JMP IRTS1 ;GOIN COMMON CODE ;$H - HEX DUMP TO TTY HDUMP: CALL INTPT ;SET UP START AND END ADDRESS LDA POINT ;GET LOW PART OF ADDRESS AND #$F0 ;MAKE IT START ON A NICE BOUNDRY STA POINT 10$: CALL SETOUT ;SETUP OUTPUT DEVICE / GET LPP STA LENGTH ; SAVE IT AWAY 20$: CALL CRLFS ;PRINT OUT CARRAGE RETURN LINEFEED CALL PRTSPT ;PRINT OUT THE LOCATION LDA #$10 ;NUMBER OF BYTES PER LINE CALL DMPLIN ;PRINT A LINE OF DUMP CALL ENDCHK ;CHECK TO SEE IF WE ARE FINISHED DEC LENGTH ;COUNT LINE BNE 20$ ;GO DO ANOTHER LINE CALL PAGEWT ;GO WAIT FOR CONTINUE JMP 10$ ;GO DO ANOTHER PAGE ;$I - INITIALIZE MEMORY INIT: CALL GETVAL ;GET VALUE LDX INBUF ;GET BYTE INTO X INITM1: CALL INTPTC ;SET UP ADDRESSES 10$: TXA ;GET CHARACTER BACK LDY #0 ;SET UP FOR INDEXING STA (POINT),Y ;SET MEMORY TO SPECIFIED VALUE CALL ENDCHK ;CHECK TO SEE IF FINISHED JMP 10$ ;NO GO DO ANOTHER VALUE ;$Z - ZERO MEMORY ZERO: LDX #0 ;GET A ZERO BEQ INITM1 ;GO INITIALIZE MEMORY ;$M - MOVE A BLOCK OF STORE MOVE: LDA #$8D ;GET STORE OPCODE CALL INTIVB ;SET UP STORE AND RETURN IN VEB CALL GETVAL ;GET TO ADDRESS CALL INTPT ;SET UP POINT FROM START MOV2 INBUF,VEB+1 ;SET UP ADDRESS 10$: LDY #0 ;SET UP FOR INDEXING LDA (POINT),Y ;GET BYTE CALL VEB ;STORE IT AT NEW ADDRESS CALL INCVEB ;BUMP THE VEB POINTER CALL ENDCHK ;FINISHED? JMP 10$ ;NO ;$L - PRINTER SELECT TOGGLE PNTSEL: LDA STARTA ;COMPLIMENT PRINTER FLAG STA PNTF JMP BPXIT ;RETURN TO MAIN LOOP ;$O - CALCULATE BRANCH OFFSET OFFSET: CALL PRBLNK ;PUT OUT SOME BLANKS CLC ;MAKE FROM BE ONE MORE LDA ENDAD ;GET FIRST OF TO ADDRESS SBC STARTA ;SUBTRACT FROM ADDRESS TAX ;SAVE LOW ORDER PART OF ADDRESS LDA ENDAD+1 ;GET HIGH PART OF TO ADDRESS SBC STARTA+1 ;SUBTRACT FROM ADDRESS TAY ;SAVE HIGH ORDER BYTE BNE 10$ ;IF IT IS ZERO MAY BE LEGAL ADDRESS TXA ;GET LOW PART BACK BPL 30$ ;VALID ADDRESS BMI 20$ ;ELSE ILLEGAL ADDRESS 10$: CMP #$FF ;OR $FF IS LEGAL BNE 20$ TXA ;GET LOW PART BACK BMI 30$ ;VALID ADDRESS 20$: TYA ;GET HIGH ORDER BYTE CALL PRTSBY ;GO PRINT HIGH ORDER BYTE 30$: TXA ;GET LOW ORDER BYTE CALL PRTSBY ;PRINT LOW BYTE CALL CRLFS ;AND CARRIAGE RETURN LINE FEED JMP SCAN ;GO BACK TO MAIN LOOP ;$P - PROCEED FROM BREAKPOINT PROC: CALL CRLFS ;SIGNAL START CLR SNGLF ;NOT SINGLE STEP LDA CF ;QUANT TYPED BMI PROC1 ;NO - PROCEED ONCE LDA STARTA ;GET LOW BYTE OF COUNT BEQ PERR ;DON'T ALLOW 0$P BNE PROC2 ;PROCEED COUNT IN AC PROC1: LDA #1 ;PRELOAD A ONE PROC2: LDX BPN ;ACTUAL BP # BEQ IXCT ;COULD BE FROM PANIC INT STA BPCNT-1,X ;STORE COUNT BNE IXCT ;JOIN SS CODE PERR: JMP ERR ;HANDY BRANCH LOC ;$X - SINGLE STEP EXEC: CLR BPN ;NO BREAKS IN PROGRESS INC SNGLF ;SET FLAG IXCT: MOV2 PRPC,POINT ;SET START ADDRESS CALL CALCAD ;GET LENGHT, EA, FORMAT MOV2 INBUF,XBTARG ;SET EA TO BRANCH TARGET LDX #$EA ;GET NOP STX IOPC+1 ;INIT FOR 1 BYTE INSTR STX IOPC+2 LDA (POINT),Y ;GET OPCODE BNE 5$ ;CONVERT "BRK" INTO "NOP" TXA 5$: STA IOPC LDA LENGTH ;LENGTH OF INSTR BEQ IXCT1 ;1 BYTE - GO NOW CALL INCPT ;MOVE TO NEXT BYTE LDA PFRMT ;CHECK FOR BRANCH CMP #$1D ; INSTR BNE IXCT3 ;NOT BRANCH LDA #XCTBR-IOPC-2 ;BRANCH - SET UP DISPLACEMENT STA IOPC+1 ;STORE IN OFFSET BYTE BNE IXCT1 ;JOIN COMMON EXIT IXCT3: LDA (POINT),Y ;GET NEXT BYTE STA IOPC+1 ;STORE IN XCT BLOCK LDA LENGTH CMP #2 ;CHECK FOR 1 OR 2 EXTRA BYTES BNE IXCT1 ;ONLY 1 BYTE CALL INCPT ;MOVE TO NEXT LDA (POINT),Y ;GET 3RD AND LAST STA IOPC+2 LDA IOPC ;GET OPCODE BYTE CMP #$20 ;IS IT "JSR"? BNE IXCT1 ;BRANCH IF NOT LDX SP ;GET SAVED STACK POINTER TXS ;SET STACK LDA POINT+1 ;YES - SETUP RETURN PC PHA LDA POINT PHA TSX ;SAVE UPDATED POINTER STX SP ; FOR PROCEED LDA #$4C ;CHANGE INTO "JMP" STA IOPC IXCT1: CALL INCPT ;STEP TO INSTR AFTER THIS ONE MOV2 POINT,XNOBR ;SETUP NO BRANCH LOC SET2 IOPC,POINT ;SET START ADDR TO IOPC BLOCK JMP GO1 ;AND START UP ;EXECUTE BLOCK FOR INSTR XCT SIMULATOR IOPC: BEQ XCTBR .BYTE $EA ;NOP STY YREG ;SAVE NEW STATE AFTER $X STX XREG STA AC PHP PLA STA PS ;PROCESSOR STATUS TSX STX SP ;STACK POINTER XCTNB: MOV2 XNOBR,POINT ;NO BRANCH OCCURED JMP BRKY XCTBR: MOV2 XBTARG,POINT ;BRANCH OCCURED JMP BRKY XNOBR: .BLKW 1 ;SAVED POINTERS FOR SINGLE STEP XBTARG: .BLKW 1 ;$Q - DISASSEMBLE CODE DISASS: CALL INTPT ;SET UP POINT 10$: CALL SETOUT ;SET OUTPUT DEVICE STA CF ; RETURNS LINES/PAGE 20$: CALL CRLFS ;PUT OUT CARRIAGE RETURN LINE FEED CALL PRTSLS ;GO PRINT A LINE CALL ENDCHK ;CHECK TO SEE IF FINISHED LDA LENGTH ;GET LENGTH OF INSTRUCTION CLC ;ONE ALREADY ADDED AT ENDCHK CALL PCADJ3 ;POINT TO NEXT INSTRUCTION STA POINT ;SAVE UPDATED ADDRESS STY POINT+1 DEC CF ;ACCOUNT FOR LINE BNE 20$ ;GO DO ANOTHER INSTRUCTION CALL PAGEWT ;GO WAIT FOR GO AHEAD BNE 10$ ;GO DO ANOTHER PAGE ;ROUTINE TO SETUP FOR OUTPUT - CHECK PNTF FOR PRINTER SETOUT: LDA PNTF ;WANT PRINTER? BEQ 10$ CALL OPENP ;YES - OPEN IT IF NOT OPEN ALREADY LDA #LPP ;RETURN LINES/PAGE RET 10$: LDA #LNSCR ;LINE/SCREEN (EDITOR) RET ;$S - SEARCH FOR ADDRESS SEARCH: CALL GETVAL ;GET A WORD MOV2 INBUF,VEB ;SAVE VALUE SEARCHING FOR CALL INTPTC ;SET UP ADDRESSES CALL DECPT ;DECREMENT IT BY ONE 10$: LDY #0 ;SET UP INDEX LDA (POINT),Y ;GET FIRST BYTE CMP VEB ;DOES IT MATCH BNE 20$ ;NO INY ;BUMP POINTER LDA (POINT),Y ;GET SECOND BYTE CMP VEB+1 ;DOES IT MATCH BNE 20$ ;NO CALL PRTSPT ;PRINT THE ADDRESS LDA #'/ ;PRINT SEPERATOR CALL OUTSCH ;PRINT IT CALL OUTSSP ;PUT OUT A SPACE LDA VEB+1 ;GET HIGH BYTE CALL PRTSBY ;PRINT THE BYTE LDA VEB ;GET LOW BYTE CALL PRTSBY ;PRINT IT JMP 30$ ;GO DO CARRIAGE RETURN LINE FEED 20$: CALL CALCAD ;GET EFFECTIVE ADDRESS OF INSTRUCTION LDA INBUF ;GET LOW BYTE CMP VEB ;DOES IT MATCH BNE 40$ ;NO LDA INBUF+1 ;GET HIGH BYTE CMP VEB+1 ;DOES IT MATCH BNE 40$ ;NO CALL PRTSLS ;GO PRINT THE CONTENTS LDA PFRMT ; CMP #$1D ;CHECK TO SEE IF IT WAS A BRANCH BEQ 30$ ;YES. NO NEED TO BUMP TWO CALL INCPT ;BUMP POINTER SO WE DO NOT GET ADDRESS AGAIN 30$: CALL CRLFS ;PUT OUT CARRIAGE RETURN LINE FEED 40$: CALL ENDCHK ;ARE WE FINISHED JMP 10$ ;NO ;$T - TYPE OUT MEMORY IN ASCII TYPE: CALL INTPTC ;SET UP ADDRESSES 10$: LDY #0 ;SET UP FOR INDEXING LDA (POINT),Y ;GET A CHARACTER CALL OUTSCH ;PRINT THE CHARACTER CALL ENDCHK ;FINISHED? JMP 10$ ;NO ;ROUTINES DEALING WITH POINT ;REGISTER CLOSE ROUTINE ;CLOSE LOCATION AND UPDATE IF NECESSARY CLSE: LDY #0 ;PREPARE TO MODIFY LDA ROF ;GET FLAG BEQ CLSEX ;XFER IF NONE OPEN BMI CLSEX ; OR SYMBOLIC LDA CF ;ANYTHING TYPED? BMI CLSEX ;NO - DO NOTHING LDA STARTA ; CURRENT OPEN REG STA (POINT),Y ; WITH INPUT VALUE CLSEX: STY ROF ;SET REGISTER CLOSED RET ;RETURN ;SET UP POINT FROM THE STARTING ADDRESS INTPTC: CALL CRLFS ;PUT OUT CARRIAGE RETURN LINE FEED FIRST INTPT: MOV2 STARTA,POINT RET ;DECREMENT THE PC DECPT: SEC ;PREPARE TO DECREMENT POINT LDA POINT SBC #1 STA POINT BCS 10$ DEC POINT+1 ;HANDLE BORROW 10$: RET ;CHECK TO SEE IF POINT IS AT END YET ENDCHK: LDA POINT ;CHECK TO SEE IF FINISHED CMP ENDAD LDA POINT+1 SBC ENDAD+1 BCS 20$ ;IF GREATER THAN, FINISHED JMP INCPT ;INCREMENT THE POINTER 20$: JMP DCD ;FINISHED GO BACK TO MAIN LOOP ;ROUTINES TO PICK UP VALUES ; GET ADDITIONAL VALUE, PROMPT FOR INPUT, ERROR IF NOT ; TERMINATED BY GETVAL: CALL OUTSSP ;OUTPUT SPACE LDA #': ; AND PROMPT CALL OUTSCH CALL GETNUM CMP #.ATEOL ;TERMINATED PROPERLY? BEQ ABTRET ;YES - RETURN JMP ERR ;NOPE -ERROR ;GET A NUMBER RETURN WITH TERMINATOR IN A GETNUM: CLR2 INBUF ;CLEAR THE BUFFER CALL PACKCH ;GET A CHARACTER BNE ABTCHK ;IF NOT HEX RETURN WITH CHARACTER IN A INC CF ;SAY WE HAVE A NUMBER 10$: CALL PACKCH ;GO GET ANOTHER CHARACTER BEQ 10$ ;IF HEX GO GET ANOTHER CHARACTER ;;; ... ; FALL INTO ABTCHK ;CHECK FOR RUBOUT OR BREAK. IF FOUND RETURN TO COMMAND DECODER ABTCHK: CMP #.ATRUB ;RUBOUT BEQ ABORT ;ABORT COMMAND CMP #BRKABT ;BREAK TYPED BEQ ABORT ABTRET: RET ABORT: TYPE EXES ;PUT OUT XXX JMP DCD4 EXES: .ASCII " XXX"<.ATEOL> ;GET A CHARACTER AND PACK IT PACKCH: CALL GETSCH ;GET THE CHARACTER CMP #'9+1 ;CAN IT BE A NUMBER BMI PACK ;YES GO TRY TO PACK IT CMP #'A ;IS IT A CHARACTER BMI 10$ ;NO. INVALID CHARACTER RETURN CMP #.ATRUB ;RUBOUT BEQ 10$ ;YES. INVALID CHARACTER RETURN AND #@337 ;GET RID OF LOWERCASE BIT CMP #'F+1 ;IS IT G OR LARGER BMI PACK ;NO. GO PACK IT 10$: TAY ;SIGNAL ILLEGAL CHARACTER RET PACK: CMP #'0 ;CHECK FOR HEX BMI PACKX CMP #'A-1 ;ADJUST FOR A-F BMI 10$ CLC ;BY ADDING OFFSET ADC #$09 10$: ROL A ;SHIFT IN ROL A ROL A ROL A LDY #$04 ;4 MORE SHIFTS THRU CARRY 20$: ROL A ; TO MOVE INTO INBUF ROL INBUF ROL INBUF+1 ;RIPPLE BIT THROUGH DEY ;COUNT LOOP BNE 20$ LDA #$00 ;RETURN A = 0 IF OK NUMBER PACKX: RET ;WAIT FOR A CHARACTER TO BE TYPED IF IT IS A RUBOUT RETURN TO COMMAND ;DECODER PAGEWT: LDA PIOCB ;ARE WE PRINTING? BEQ 10$ LDA #@14 ;OUTPUT FF JMP OUTSCH 10$: LDA #.ATBEL ;GET BELL CALL OUTSCH ;RING IT CALL GETSCH ;WAIT FOR CHARACTER JMP ABTCHK ;CHECK FOR ABORT OR PROCEED ;ROUTINE TO GET A CARACTER ; RETURNS CHARACTER IN A ; USES Y GETSCH: STX TEMPX ;SAVE X STY TEMPY ; AND Y AROUND O/S LDA #0 STA ICAX1Z ;CLEAR FLAG CALL KGETCH ;RETURNS STATUS IN Y, CHAR IN A BMI 20$ ;DON'T ECHO SPECIAL CHARS CMP #.ATRUB ;CHECK BS/DEL KEY BEQ 30$ ; RUBOUT DOESN'T ECHO CMP #.CHSP ;CHECK FOR CONTROLS BCS OUTSCN ; ECHO IF NOT BCC 30$ ;RETURN CHAR - NO ECHO 20$: CPY #BRKABT ;BREAK KEY TYPED? BNE 30$ TYA ;YES - RETURN BREAK FLAG 30$: LDX TEMPX ;RESTORE LDY TEMPY RET ; ELSE RETURN ;ROUTINE TO GET TWO HEX CARACTERS INTO AC ; RETURNS CHARACTER IN A ; X PRESERVED Y RETURNED = 0 GETSBY: CALL PACKCH ;GET A CHARACTER CALL PACKCH ;GET ANOTHER CHARACTER LDA INBUF ;LOAD UP BYTE RET ;GENERAL PURPOSE PRINTING ROUTIMES ;PRINT LOCATION AND IT'S CONTENETS IF FORM SPECIFIED BY ROF PRTSLS: LDA #$FF ;SET THE TYPEOUT MODE BACK STA ROF LDX #'/ ;SLASH PRTSLC: CALL PRTSPT ;PRINT CONTENTS OF POINT TXA ;GET CHAR BACK CALL OUTSCH CALL OUTSSP ; AND A SPACE ;;; ... ; FALL INTO PRTSCN ;PRINT OUT CONTENTS OF CURRENT LOCATION IN FORM SPECIFIED BY ROF PRTSCN: LDY #0 ;SET FOR GLOBAL INDEX LDA (POINT),Y ;GET CURRENT LOCATION IN A STA STARTA ;SAVE FOR QUOTE OR EQUAL LDX ROF ;SEE WHAT KIND BMI 20$ ;BR IF SYMBOLIC CALL PRTSBY ;PRINT CONTENTS 10$: JMP OUTSSP ;AWAIT NEXT REQUEST 20$: CALL DSMBL ;PRINT SYMBOLIC JMP 10$ ; AND RETURN TO CMD LOOP ;DUMP NUMBER OF LOCATIONS IN A TO SCREEN DMPLIN: STA PFRMT ;SAVE IT CALL PRBLNK ;SPACE OVER 2 BEQ 20$ ;DO NOT INCREMENT POINTER FIRST TIME 10$: CALL INCPT ;INCREMENT THE POINTER CALL OUTSSP ;PRINT BLANK 20$: LDY #0 ;SET UP FOR INDEXING LDA (POINT),Y ;GET LOCATION CALL PRTSBY ;PRINT IT DEC PFRMT ;ACCOUNT FOR CHARACTER BNE 10$ ;NOT FINISHED GO DO MORE RET ;OUTPUT NUMBER OF BLANKS IN X PRBLNK: LDX #$2 PRBL2: CALL OUTSSP DEX BNE PRBL2 ;LOOP TILL COUNT = 0 RET ;ROUTINE TO OUTPUT CHARACTER TO OUTPUT PORT ; CHARACTER IN A ; USES Y AND RETURNS CHARACTER IN A OUTSSP: LDA #.CHSP ;LOAD UP A BLANK OUTSCH: STX TEMPX ;SAVE X & Y AROUND O/S CALLS STY TEMPY OUTSCN: PHA ;SAVE THE CHARACTER TAY ; AND MOVE TO Y LDX PIOCB ;GET IOCB INDEX LDA #PUTCHR ;1 CHAR OUTPUT CALL CIOC ;OUTPUT TO EDITOR/PRINTER LDX TEMPX ;RESTORE X LDY TEMPY ;RESTORE Y PLA RET ;ROUTINE TO WRITE OUT CARRIAGE RETURN LINE FEED ; USES A AND Y CRLFS: LDA #.ATEOL JMP OUTSCH ;WRITE IT OUT AND RETURN ;ROUTINE TO PRINT CURRENT LOCATION ; PRINTS POINT ; USES A AND Y PRTSPT: LDA POINT+1 ;GET HIGH ORDER BYTE CALL PRTSBY LDA POINT ;GET LOW ORDER BYTE ;;; ... ;FALL INTO PRTSBY ;ROUTINE TO PRINT BYTE AS TWO HEX DIGITS ; BYTE IS IN A PRTSBY: PHA ;SAVE THE BYTE LSR A ;GET HIGH ORDER FOUR BITS LSR A LSR A LSR A CALL HEXSTA ;GO CONVERT IT TO HEX PLA ;GET THE ORGINAL BYTE BACK ;;; ... ; FALL INTO HEXSTA ;ROUTINE TO CONVERT A HEX DIGIT TO ASCII ; DIGIT IS IN A HEXSTA: AND #$0F ;GET JUST ONE DIGIT CMP #$0A ;IS IT A DECIMAL DIGIT CLC ;CLEAR THE CARRY BMI HEXST1 ;IF NEGATIVE IT IS A DECIMAL DIGIT ADC #$07 ;ADD IN OFFSET TO GET A-F HEXST1: ADC #$30 ;CONVERT TO ASCII JMP OUTSCH ;GOT WRITE CHARACTER AND RETURN ; MISC ROUTINES INITS: CLD ;CLEAR DECIMAL MODE LDA #LEDGE ;SET DEFAULT MARGINS STA LMARGN LDA #REDGE STA RMARGN LDA #$94 ;SETUP BACKGROUND COLOR STA COLOR4 ;TO BE SAME AS FOREGROUND JMP CLOSEP ;CLOSE PRINTER IF OPEN ;SET UP VEB AREA INTSVB: LDA #$AD ;LDA OP CODE INTIVB: STA VEB INTVEB: LDA STARTA ;SET UP SUB STA VEB+1 LDA STARTA+1 STA VEB+2 LDA #$60 ;"RTS" STA VEB+3 RET ;ROUTINE TO INCRENT POINT INCPT: INC2 POINT RET ;ROUTINE TO INCREMENT ADDRS IN VEB INCVEB: INC2 VEB+1 INCRET: RET ;PRINTER ROUTINES OPENP: LDA PIOCB ;CHECK IF ALREADY OPEN BNE INCRET ;YES - DON'T REOPEN LDX #$10 ;START AT IOCB#1 5$: LDA ICHID,X ;GET ID CMP #$FF ;FREE? BEQ THSONE CPX #$70 ;LAST ONE? BEQ PNONE TXA ;STEP INDEX TO NEXT CLC ADC #$10 TAX ;BACK TO X BNE 5$ PNONE: JMP ERR ;NO FREE IOCB'S ;FOUND FREE IOCB (INDEX IN X) THSONE: STX PIOCB ;SAVE IOCB INDEX LDA #OPNOT ;OPEN FOR OUTPUT STA ICAX1,X SET2 PDEV,ICBAL,X ;POINT TO DEVICE TEXT LDA #OPEN ;OPEN COMMAND CIOC: STA ICCOM,X ;STORE COMMAND LDA #0 ;SET LENGTH TO ZERO STA ICBLL,X STA ICBLH,X TYA ;MIGHT HAVE CHARACTER CALL CIOV ;INVOKE O/S STY DSTATS ;PUT COMPLETION CODE HERE BPL INCRET ;RETURN IF NO ERROR CPY #BRKABT ;BREAK TYPED? BEQ 10$ JMP IOCERR ;COMMON ERROR HANDLER 10$: JMP ABORT ;ABORT I/O - RETURN TO TOP LEVEL ; CLOSE PRINTER IOCB CLOSEP: LDX PIOCB ;SETUP IOCB INDEX BEQ INCRET ;RETURN IF NONE CLR PIOCB ;FLAG NO PRINTER LDA #CLOSE ;CLOSE COMMAND BNE CIOC ; INVOKE CIO PDEV: .ASCII "P:"<.ATEOL> ;GENERAL BREAKPOINT ROUTINES ;ROUTINE TO REMOVE BREAKPOINTS REMB: LDX #MAXBP-1 ;COUNT OF THINGS TO DO 5$: LDA BPINS,X ;GET INSTR OR ZERO BEQ 10$ ;NO BP IF ZERO CALL SETA ;SET UP ADDRS STA (INBUF),Y ;STORE INSTR 10$: DEX BPL 5$ ;LOOP OVER ALL RET ;RETURN ;SETUP ADDRS OF GIVEN BREAKPOINT FOR INDIRECT ;RETURNS INBUF WITH BPLOC,X , Y := 0 ;PRESERVES AC SETA: LDY BPLOCL,X ;GET LOW ADDRS BYTE STY INBUF ;USE THIS AS TEMP LDY BPLOCH,X ;GET HIGH ADDRS BYTE STY INBUF+1 LDY #0 ;SET FOR GLOBAL INDIRECT RET ;RETURN ;ROUTINE TO INSERT BREAKPOINTS INSB: LDX #MAXBP-1 ;DO ALL 5$: LDA BPINS,X ;SEE IF ACTIVE BEQ 10$ ;SKIP IF NO BP CALL SETA ;SET UP ADDRS LDA (INBUF),Y ;GET OLD INSTR STA BPINS,X ;SAVE OLD INSTR LDA #0 ;PUT BREAK IN PLACE STA (INBUF),Y ;... 10$: DEX BPL 5$ ;LOOP TILL DONE RET ;RETURN ;INTERUPT SERVICES ;IRQ - INSTRUCTION OR ACTUAL APPLICATION INT. BREAK: PLA ;AC IS ON STACK STA AC ;SAVE ACCUM PLA ;PROCESSOR STATUS STA PS STY YREG ;SAVE INDEX REGS STX XREG PLA ;PC LOW SEC ;DECREMENT PC TO REAL LOC SBC #2 ;ADJUST PC FOR ACTUAL BP LOC 10$: STA PRPC ;SAVE HERE FOR $P STA POINT ;SAVE HERE FOR EXAMINE PLA ;PC HIGH BCS 20$ ;CHECK BORROW SBC #0 ;ADJUST BY 1 20$: STA PRPC+1 STA POINT+1 TSX ;GET STACK PNTR STX SP ; SAVE IT AWAY CALL REMB ;REMOVE BREAKPOINTS NOW LDX #MAXBP ;SEARCH FOR BPN 25$: LDA BPINS-1,X ;ACTIVE BP? BEQ 30$ ;NO - SKIP TO NEXT LDA PRPC+1 ;GET PC HIGH CMP BPLOCH-1,X ;MATCH? BEQ 35$ ;YES - TRY FOR LOW 30$: DEX ;STEP TO NEXT BNE 25$ ; MORE TO DO STX BPN ;SIGNAL NO B.P. BEQ BRKX ;NONE FOUND (MAYBE PANIC) ;.. ;.. 35$: LDA PRPC ;GET PC LOW CMP BPLOCL-1,X ;MATCH? BNE 30$ ;NO - KEEP LOOKING ;ACTUAL BPN IN X STX BPN ;SAVE BPN LDA BPCNT-1,X ;BREAT THIS TIME? (0) BEQ BRKX ;BREAK IF ZERO DEC BPCNT-1,X ;COUNT THIS TIME BEQ BRKX ; AND DO AUTO PROC (IF .NE. 0) CLR SNGLF ; NOT SINGLE STEP SETXA IXCT ;EXIT THROUGH HERE BRKRTI: PHA ;SAVE HIGH PC TXA ;GET LOW PHA ;SAVE IT TOO LDA PS PHA ;CURRENT PROCESSOR STATUS RTI ;DISMISS TO ROUTINE ;HERE TO ENTER BREAKPOINT - CLEAR SINGLE STEP FLAG BRKX: CLR SNGLF ; CLEAR SS FLAG SETXA DOBRK BNE BRKRTI ;EXIT INT TO DOBRK DOBRK: CALL CRLFS ;PUT OUT A CR/LF LDA #'B ;PRINT BN;ADDRS CALL OUTSCH LDA BPN ;MAYBE 0 CALL HEXSTA ;TYPE LOW 4 BITS LDA #'; CALL OUTSCH JMP LFDS1 ;GO PRINT OUT ADDRESS AND INSTR. BRKY: MOV2 POINT,PRPC ;SINGLE STEP ENTRY - POINT HAS PC LDA SNGLF ;WAS THIS SINGLE STEP? BNE DOBRK ; SIMULATE BREAK IF $X JMP GO2 ;ELSE - JUST PROCEED .SBTTL 6502 DISASSEMBLER DSMBL: CALL CALCAD ;CALCULATE EFFECTIVE ADDRESS PHA ;SAVE MNEMONIC TABLE INDEX PROP: LDA (POINT),Y ;GET OP AND PRINT IT CALL PRTSBY LDX #$1 ;ONE SPACE 10$: CALL PRBL2 CPY LENGTH ;PRINT INSTR (1 TO 3 BYTES) INY ; IN A 12-CHAR FIELD BCC PROP LDX #$3 ;CHAR COUNT FOR MNEMONIC PRINT CPY #$4 BCC 10$ PLA ;RECOVER MNEMONIC INDEX TAY LDA MNEML,Y STA LMNEM ;FETCH 3-CHAR MNEMONIC LDA MNEMR,Y ; (PACKED IN 2 BYTES) STA RMNEM PRMN1: LDA #$0 LDY #$5 PRMN2: ASL RMNEM ROL LMNEM ;SHIFT 5 BITS OF CHAR INTO A ROL A ; (CLEARS CARRY) DEY BNE PRMN2 ADC #$3F ;ADD '?' OFFSET CALL OUTSCH DEX BNE PRMN1 CALL PRBLNK ;PRINT 3 BLANKS LDX #$6 ;COUNT FOR 6 PRINT FORMAT BITS PRADR1: CPX #$3 BNE PRADR3 ;IF X=3 THEN PRINT ADDRESS VAL LDY LENGTH BEQ PRADR3 ;NO PRINT IF LENGTH=0 LDA PFRMT CMP #$E8 ;HANDLE REL ADDRESSING MODE BNE PRADR2 ;IF NOT DO NOT ADJUST NUMBER OF BYTES INY ;IF RELATIVE BRANCH PRINT 2 BYTES CLR PFRMT ;CLEAR PFRMT PRADR2: LDA INBUF-1,Y ;SPECIAL (PRINT TARGET ADDRS) CALL PRTSBY ;OUTPUT 1 OR 2 BYTE ADDRS DEY ; MSB FIRST BNE PRADR2 PRADR3: ASL PFRMT ;TEST NEXT PRINT FORMAT BIT BCC PRADR4 ;IF 0, DON'T PRINT LDA CHAR1-1,X ; CORRESPONDING CHARS CALL OUTSCH ;OUTPUT 1 OR 2 CHARS LDA CHAR2-1,X ; (IF CHAR FROM CHAR2 IS 0, BEQ PRADR4 ; DON'T OUTPUT IT) CALL OUTSCH PRADR4: DEX BNE PRADR1 RET ;SET UP LENGTH, PFRMT AND EFFECTIV ADDRESS ; RETURNS INDEX INTO MNEMONIC TABLES IN A AND 0 IN Y CALCAD: LDY #0 ;SET UP FOR INDEXING STY INBUF+1 ;ZERO HIGH BYTE OF ADDRESS IN CASE ONLY ONE BYTE LDA (POINT),Y ;GET OPCODE TAY ;SAVE IN Y LSR A ; EVEN/ODD TEST BCC IEVEN LSR A ; TEST B1 BCS IERR ; XXXXXX11 INSTR INVALID CMP #$22 BEQ IERR ; 10001001 INSTR INVALID AND #$7 ;MASK 3 BITS FOR ADDRS MODE ORA #$80 ; ADD INDEXING OFFSET. IEVEN: LSR A ;LSB INTO CARRY FOR TAX ; LEFT/RIGHT TEST BELOW. LDA MODE1,X ;INDEX INTO ADDRS MODE TABLE BCS RTMODE ;IF CARRY SET USE LSD FOR LSR A ; PRINT FORMAT INDEX. LSR A LSR A LSR A ; IF CARRY CLEAR, USE MSD RTMODE: AND #$F ;MASK FOR 4-BIT INDEX BNE GETFMT ; 0 FOR INVALID OPCODES IERR: LDY #$80 ;SUBSTITUTE $80 FOR INVALID OP. LDA #$0 ;SET PRINT FORMAT TO 0 GETFMT: TAX LDA MODE2,X ;INDEX INTO PRINT FORMAT TABLE STA PFRMT ;SAVE FOR ADDRESS FIELD FORMAT AND #$3 ;MASK 2-BIT LENGTH 0 = 1-BYTE, STA LENGTH ; 1 = 2-BYTE, 2 = 3-BYTE. TYA ;RESTORE OP CODE PHA ;SAVE OPCODE ON STACK LDY LENGTH ;GET LENGTH BEQ 10$ ;IF ZERO SET CURRENT ADDRESS IN INBUF FOR TAB LDA (POINT),Y ;GET FIRST BYTE OF ADDRESS CPY #1 ;IS IT A 2 BYTE INSTRUCTION BNE 20$ ;NO GO PRINT BOTH BYTES CPX #13 ;WAS INDEX TO MODE2 FOR RELATIVE BNE 30$ ;NO GO DO JUST ONE BYTE CALL RELADR ;GO CALCULATE RELATIVE ADDRESS STY INBUF+1 ;SAVE HIGH ORDER BYTE TXA ;GET LOW ORDER BYTE BACK JMP 30$ ;GO FINISH UP 10$: LDA POINT+1 ;GET HIGH ORDER BYTE OF ADDRESS STA INBUF+1 ;AND SAVE IT LDA POINT ;GET LOW BYTE JMP 30$ ;GO SAVE IT AND FINISH 20$: STA INBUF+1 ;SAVE HIGH BYTE OF ADDRESS DEY ;SET TO GET LOW ORDER BYTE LDA (POINT),Y ;GET LOW BYTE 30$: STA INBUF ;SAVE LOW BYTE OF ADDRESS PLA ;GET OPCODE BACK TAY ;AND SAVE IT IN Y AND #$8F ;MASK IT FOR 1XXX1010 TEST TAX ; AND SAVE IT. TYA ;OPCODE AGAIN LDY #$3 CPX #$8A BEQ 60$ 40$: LSR A BCC 60$ ;FORM INDEX INTO MNEMONIC TABLE LSR A 50$: LSR A ; 1XXX1010 -> 00101XXX ORA #$20 ; XXXYYY01 -> 00111XXX DEY ; XXXYYY10 -> 00110XXX BNE 50$ ; XXXYY100 -> 00100XXX INY ; XXXXX000 -> 000XXXXX 60$: DEY BNE 40$ RET ;HERE TO HANDLE RELATIVE BRANCH ADDRS RELADR: CALL PCADJ3 ;PCL,H + DISPL + 1 TO A,Y TAX INX BNE 10$ ; +1 TO X,Y INY 10$: RET ;ADD LENGTH TO POINT PCADJ: LDA LENGTH ;0=1-BYTE, 1=2-BYTE, 2=3-BYTE SEC PCADJ3: LDY POINT+1 TAX ;TEST DISPL SIGN (FOR REL BPL 10$ ; BRANCH). EXTEND NEG DEY ; BY DECREMENTING PCH. 10$: ADC POINT BCC 20$ ;PCL+LENGTH (OR DISPL) +1 TO A. INY ;CARRY INTO Y (PCH) 20$: RET ;TABLES MODE1: .BYTE $40 .BYTE $2 .BYTE $45 .BYTE $3 .BYTE $D0 .BYTE $8 .BYTE $40 .BYTE $9 .BYTE $30 ;XXXXXXZ0 INSTRS. .BYTE $22 .BYTE $45 ; Z=0, LEFT HALF-BYTE .BYTE $33 ; Z=1, RIGHT HALF-BYTE .BYTE $D0 .BYTE $8 .BYTE $40 .BYTE $9 .BYTE $40 .BYTE $2 .BYTE $45 .BYTE $33 .BYTE $D0 .BYTE $8 .BYTE $40 .BYTE $9 .BYTE $40 .BYTE $2 ;(WAS 0) .BYTE $45 ;(WAS 40) .BYTE $B3 ;(WAS B0) .BYTE $D0 .BYTE $8 ;(WAS 0) .BYTE $40 .BYTE $9 ;(WAS 0) .BYTE $0 .BYTE $22 .BYTE $44 .BYTE $33 .BYTE $D0 .BYTE $8C .BYTE $44 .BYTE $0 .BYTE $11 .BYTE $22 .BYTE $44 .BYTE $33 .BYTE $D0 .BYTE $8C .BYTE $44 .BYTE $9A .BYTE $10 .BYTE $22 .BYTE $44 .BYTE $33 .BYTE $D0 .BYTE $8 .BYTE $40 .BYTE $9 .BYTE $10 .BYTE $22 .BYTE $44 .BYTE $33 .BYTE $D0 .BYTE $8 .BYTE $40 .BYTE $9 .BYTE $62 .BYTE $13 ;YYXXXZ01 INSTRS. .BYTE $78 .BYTE $A9 MODE2: .BYTE $0 ;ERR .BYTE $21 ;IMM .BYTE $1 ;Z-PAG (WAS 81) .BYTE $2 ;ABS (WAS 82) .BYTE $0 ;IMPL .BYTE $80 ;ACC (WAS 0) .BYTE $59 ;(Z-PAG,X) .BYTE $4D ;(Z-PAG),Y .BYTE $11 ;Z-PAG,X (WAS 91) .BYTE $12 ;ABS,X (WAS 92) .BYTE $6 ;ABS,Y (WAS 86) .BYTE $4A ;(ABS) .BYTE $5 ;Z-PAG,Y (WAS 85) .BYTE $1D ;REL (WAS 9D) CHAR1: .BYTE ', ;COMMA .BYTE ') ;RPAREN .BYTE ', ;COMMA .BYTE '# ;SHARP .BYTE '( ;LPAREN .BYTE 'A ;(WAS '$) CHAR2: .BYTE 'Y .BYTE 0 ;NULL .BYTE 'X .BYTE 0 ;(WAS '$) .BYTE 0 ;(WAS '$) .BYTE 0 MNEML: .BYTE $1C ;XXXXX000 INSTRS. .BYTE $8A .BYTE $1C .BYTE $23 .BYTE $5D .BYTE $8B .BYTE $1B .BYTE $A1 .BYTE $9D .BYTE $8A .BYTE $1D .BYTE $23 .BYTE $9D .BYTE $8B .BYTE $1D .BYTE $A1 .BYTE $0 .BYTE $29 .BYTE $19 .BYTE $AE .BYTE $69 .BYTE $A8 .BYTE $19 .BYTE $23 .BYTE $24 .BYTE $53 .BYTE $1B .BYTE $23 .BYTE $24 .BYTE $53 .BYTE $19 .BYTE $A1 .BYTE $0 ;XXXYY100 INSTRS .BYTE $1A .BYTE $5B .BYTE $5B .BYTE $A5 .BYTE $69 .BYTE $24 .BYTE $24 .BYTE $AE ;1XXX1010 INSTRS. .BYTE $AE .BYTE $A8 .BYTE $AD .BYTE $29 .BYTE $0 .BYTE $7C .BYTE $0 .BYTE $15 ;XXXYYY10 INSTRS. .BYTE $9C .BYTE $6D .BYTE $9C ;(WAS 0) .BYTE $A5 .BYTE $69 .BYTE $29 .BYTE $53 .BYTE $84 ;XXXYYY01 INSTRS. .BYTE $13 .BYTE $34 .BYTE $11 .BYTE $A5 .BYTE $69 .BYTE $23 .BYTE $A0 MNEMR: .BYTE $D8 ;XXXXX000 INSTRS. .BYTE $62 .BYTE $5A .BYTE $48 .BYTE $26 .BYTE $62 .BYTE $94 .BYTE $88 .BYTE $54 .BYTE $44 .BYTE $C8 .BYTE $54 .BYTE $68 .BYTE $44 .BYTE $E8 .BYTE $94 .BYTE $0 .BYTE $B4 .BYTE $8 .BYTE $84 .BYTE $74 .BYTE $B4 .BYTE $28 .BYTE $6E .BYTE $74 .BYTE $F4 .BYTE $CC .BYTE $4A .BYTE $72 .BYTE $F2 .BYTE $A4 .BYTE $8A .BYTE $0 ;XXXYY100 INSTRS. .BYTE $AA .BYTE $A2 .BYTE $A2 .BYTE $74 .BYTE $74 .BYTE $74 .BYTE $72 .BYTE $44 ;1XXX1010 INSTRS. .BYTE $68 .BYTE $B2 .BYTE $32 .BYTE $B2 .BYTE $0 .BYTE $22 .BYTE $0 .BYTE $1A ;XXXYYY10 INSTRS. .BYTE $1A .BYTE $26 .BYTE $26 ;(WAS 0) .BYTE $72 .BYTE $72 .BYTE $88 .BYTE $C8 .BYTE $C4 .BYTE $CA .BYTE $26 .BYTE $48 .BYTE $44 .BYTE $44 .BYTE $A2 .BYTE $C8 ;SPECIAL SYMBOL TABLE LGCH: '/ ;SLASH '% ;PERCENT '= ;EQUAL SIGN '' ;QUOTE ', ;COMMA '. ;DOT .CHESC ;ESCAPE .ATEOL ;CARRIAGE RETURN '[ ;BRACKET .ATURW ;ATARI UP-ARROW .ATDRW ;ATARI DOWN-ARROW .ATLRW ;ATARI LEFT-ARROW .ATRRW ;ATARI RIGHT-ARROW MAXL=.-LGCH-1 ;DISPATCH FOR % CONTSTRUCTS LGPC: 'X ;X REGISTER 'Y ;Y REGISTER 'A ;ACCUMULATOR 'S ;STACK 'F ;PROCESSOR STATUS MAXS=.-LGPC-1 ;THE FOLLOWING ARE ALL PAGE 0 VARIABLES PERAD: XREG ;ADDRS OF X YREG ;ADDRS OF Y AC ;ADDRS OF ACCUM SP ;ADDRS OF STACK PNTR PS ;ADDRS OF STATUS ;SPECIAL SYMBOL DISPATCH TABLE LDISP: .ADDR SLSH-1 ;SLASH - OPEN SYMBOLIC .ADDR PERC-1 ;PERCENT - SPECIAL REG .ADDR TOC-1 ;EQUAL - TYPE OCTAL .ADDR QUOTE-1 ;QUOTE - TYPE OUT ASCII .ADDR COMMA-1 ;COMMA - SAVE STARTING ADDRESS .ADDR DOT-1 ;DOT - USE CURRENT LOC .ADDR ESC-1 ;ESCAPE - MORE FOLLOWS .ADDR CRET-1 ;CARRIAGE RETURN - CLOSE REG .ADDR BRAKET-1 ;BRACKET - OPEN REG (HEX) .ADDR BACK-1 ;ATARI ARROWS (PREV LOC) .ADDR LFD-1 ; (NEXT LOC) .ADDR UNTAB-1 ; POP PC STACK .ADDR TAB-1 ; PUSH PC - OPEN EA ;DISPATCH CHARACTER TABLES DISP: .ADDR ASCII-1 ;$A - ASSIGN ASCII TO MEMORY .ADDR BKPT-1 ;$B - SET BP .ADDR ERR-1 ;$C - .ADDR TODOS-1 ;$D - XFER TO DOS .ADDR ERR-1 ;$E - .ADDR FIND-1 ;$F - FIND BYTE .ADDR GO-1 ;$G - GO .ADDR HDUMP-1 ;$H - HEX DUMP TO TTY .ADDR INIT-1 ;$I - INITALIZE MEMORY .ADDR ERR-1 ;$J - .ADDR ERR-1 ;$K - .ADDR PNTSEL-1 ;$L - TOGGLE PRINTER .ADDR MOVE-1 ;$M - MOVE A BLOCK OF MEMORY .ADDR ERR-1 ;$N - .ADDR OFFSET-1 ;$O - CALCULATE BRANCH OFFSET .ADDR PROC-1 ;$P - PROCEED .ADDR DISASS-1 ;$Q - DISASSEMBLE .ADDR RDSECT-1 ;$R - READ DISK .ADDR SEARCH-1 ;$S - SEARCH FOR ADDRESS .ADDR TYPE-1 ;$T - TYPE OUT MEMORY IN ASCII .ADDR SETU-1 ;$U - SET DISK UNIT .ADDR ERR-1 ;$V - .ADDR WRSECT-1 ;$W - WRITE DISK .ADDR EXEC-1 ;$X - SINGLE STEP .ADDR ERR-1 ;$Y - .ADDR ZERO-1 ;$Z - ZERO MEMORY ;NUMBER OF ARGUMENTS TABLE $FF=NONE, $0=1, $1=2, $80=NONE OR ONE ARGNUM: .BYTE $00 ;$A - ASSIGN ASCII TO MEMORY .BYTE $80 ;$B - SET BP .BYTE $01 ;$C - .BYTE $FF ;$D - JUMP TO DOS .BYTE $FF ;$E - .BYTE $01 ;$F - FIND BYTE .BYTE $00 ;$G - GO .BYTE $01 ;$H - HEX DUMP TO TTY .BYTE $01 ;$I - INITALIZE MEMORY .BYTE $FF ;$J - .BYTE $FF ;$K - .BYTE $00 ;$L - TOGGLE PRINTER .BYTE $01 ;$M - MOVE A BLOCK OF MEMORY .BYTE $FF ;$N - .BYTE $01 ;$O - CALCULATE BRANCH OFFSET .BYTE $80 ;$P - PROCEED .BYTE $01 ;$Q - DISASSEMBLE .BYTE $01 ;$R - READ DISK .BYTE $01 ;$S - SEARCH FOR ADDRESS .BYTE $01 ;$T - TYPE OUT MEMORY IN ASCII .BYTE $00 ;$U - SELECT DISK UNIT .BYTE $FF ;$V - .BYTE $01 ;$W - WRITE DISK .BYTE $FF ;$X - SINGLE STEP .BYTE $FF ;$Y - .BYTE $01 ;$Z - ZERO MEMORY END START