Mercurial > hg > Members > kono > os9 > sbc09
diff mon2.asm @ 0:9a224bd9b45f
os9 emulation
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 02 Jul 2018 02:12:31 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mon2.asm Mon Jul 02 02:12:31 2018 +0900 @@ -0,0 +1,3080 @@ + ;Buggy machine language monitor and rudimentary O.S. version 1.0 + +* Memory map of SBC +* $0-$40 Zero page variables reserved by monitor and O.S. +* $40-$FF Zero page portion for user programs. +* $100-$17F Xmodem buffer 0, terminal input buffer, +* $180-$1FF Xmodem buffer 1, terminal output buffer. +* $200-$27F Terminal input line. +* $280-$2FF Variables reserved by monitor and O.S. +* $300-$400 System stack. +* $400-$7FFF RAM for user programs and data. +* $8000-$DFFF PROM for user programs. +* $E000-$E1FF I/O addresses. +* $E200-$E3FF Reserved. +* $E400-$FFFF Monitor ROM + +* Reserved Zero page addresses + org $0000 +* First the I/O routine vectors. +getchar rmb 3 ;Jump to getchar routine. +putchar rmb 3 ;Jump to putchar routine. +getline rmb 3 ;Jump to getline routine. +putline rmb 3 ;Jump to putline routine. +putcr rmb 3 ;Jump to putcr routine. +getpoll rmb 3 ;Jump to getpoll routine. +xopenin rmb 3 ;Jump to xopenin routine. +xopenout rmb 3 ;Jump to xopenout routine. +xabortin rmb 3 ;Jump to xabortin routine. +xclosein rmb 3 ;Jump to xclosein routine. +xcloseout rmb 3 ;Jump to xcloseout routine. +delay rmb 3 ;Jump to delay routine. + +*Next the system variables in the zero page. +temp rmb 2 ;hex scanning/disasm +temp2 rmb 2 ;Hex scanning/disasm +temp3 rmb 2 ;Used in Srecords, H command +timer rmb 3 ;3 byte timer, incremented every 20ms +xpacknum rmb 1 ;Packet number for XMODEM block, +xsum rmb 1 ;XMODEM checksum +lastok rmb 1 ;flag to indicate last block was OK +xcount rmb 1 ;Count of characters in buffer. +xmode rmb 1 ;XMODEM mode, 0 none, 1 out, 2 in. +disflg rmb 1 + +* I/O buffers. +buflen equ 128 ;Length of input line buffer. + org $100 +buf0 rmb 128 ;Xmodem buffer 0, serial input buffer. +buf1 rmb 128 ;Xmodem buffer 1, serial output buffer. +linebuf rmb buflen ;Input line buffer. + + +* Interrupt vectors (start at $280) +* All interrupts except RESET are vectored through jumps. +* FIRQ is timer interrupt, IRQ is ACIA interrupt. +swi3vec rmb 3 +swi2vec rmb 3 +firqvec rmb 3 +irqvec rmb 3 +swivec rmb 3 +nmivec rmb 3 +xerrvec rmb 3 ;Error handler for XMODEM error. +exprvec rmb 3 ;Expression evaluator in assembler. +asmerrvec rmb 3 ;Error handler for assembler errors. +pseudovec rmb 3 ;Vector for asm pseudo instructions. + +* Next the non zero page system variables. +oldpc rmb 2 ;Saved pc value for J command. +addr rmb 2 ;Address parameter. +length rmb 2 ;Length parameter. + +brkpoints equ 8 ;Number of settable breakpoints. +bpaddr rmb brkpoints*3 ;Address and byte for each break point. +stepbp rmb 3 ;Address of P command break point. + +sorg rmb 2 ;Origin address of S record entry. +soffs rmb 2 ;Offset load adrr-addr in record + +oldgetc rmb 2 ;Old getchar address. +oldputc rmb 2 ;Old putchar address. +oldputcr rmb 2 ;Old putcr address. +lastterm rmb 1 ;Last terminating character. +filler rmb 1 ;Filler at end of XMODEM file. +xmcr rmb 1 ;end-of-line characters for XMODEM send. +savesp rmb 2 ;Save sp to restore it on error. +nxtadd rmb 2 + +* Following variables are used by assembler/disassembler. +prebyte rmb 1 +opc1 rmb 1 +opcode rmb 1 +postbyte rmb 1 +amode rmb 1 +operand rmb 2 +mnembuf rmb 5 ;Buffer to store capitalized mnemonic. +opsize rmb 1 ;SIze (in bytes) of extra oeprand (0--2) +uncert rmb 1 ;Flag to indicate that op is unknown. +dpsetting rmb 2 + +endvars equ * + +ramstart equ $400 ;first free RAM address. + +ramtop equ $8000 ;top of RAM. + +* I/O port addresses +aciactl equ $e000 ;Control port of ACIA +aciasta equ $e000 ;Status port of ACIA +aciadat equ $e001 ;Data port of ACIA + +* ASCII control characters. +SOH equ 1 +EOT equ 4 +ACK equ 6 +BS equ 8 +TAB equ 9 +LF equ 10 +CR equ 13 +NAK equ 21 +CAN equ 24 +DEL equ 127 + +CASEMASK equ $DF ;Mask to make lowercase into uppercase. + +* Monitor ROM starts here. + org $E400 + +reset orcc #$FF ;Disable interrupts. + clra + tfr a,dp ;Set direct page register to 0. + clr disflg + lds #ramstart + ldx #intvectbl + ldu #swi3vec + ldb #osvectbl-intvectbl + bsr blockmove ;Initialize interrupt vectors from ROM. + ldx #osvectbl + ldu #0 + ldb #endvecs-osvectbl + bsr blockmove ;Initialize I/O vectors from ROM. + bsr initacia ;Initialize serial port. + andcc #$0 ;Enable interrupts +* Put the 'saved' registers of the program being monitored on top of the +* stack. There are 12 bytes on the stack for cc,b,a,dp,x,y,u and pc +* pc is initialized to $400, the rest to zero. + ldx #0 + tfr x,y + ldu #ramstart + pshs x,u + pshs x,y + pshs x,y + ldx #oldpc + ldb #endvars-oldpc +clvar clr ,x+ + decb + bne clvar ;Clear the variable area. + ldd #$1A03 + std filler ;Set XMODEM filler and end-of-line. + ldx #welcome + jsr outcount + jsr putcr ;Print a welcome message. + jmp cmdline +* Block move routine, from X to U length B. Modifies them all and A. +blockmove lda ,x+ + sta ,u+ + decb + bne blockmove + rts + +* Initialize serial communications port, buffers, interrupts. +initacia ldb #$03 + stb aciactl + ldb #%00110101 + rts + +* O.S. routine to read a character into B register. +osgetc ldb aciasta + bitb #$01 + beq osgetc + ldb aciadat + rts + +;O.S. rotuine to check if there is a character ready to be read. +osgetpoll ldb aciasta + bitb #$01 + bne poltrue + clrb + rts +poltrue ldb #$ff + rts + +* O.S. routine to write the character in the B register. +osputc pshs a +putcloop lda aciasta + bita #$02 + beq putcloop + stb aciadat + puls a + rts + +* O.S. routine to read a line into memory at address X, at most B chars +* long, return actual length in B. Permit backspace editing. +osgetl pshs a,x + stb temp + clra +osgetl1 jsr getchar + andb #$7F + cmpb #BS + beq backsp + cmpb #DEL + bne osgetl2 +backsp tsta ;Recognize BS and DEL as backspace key. + beq osgetl1 ;ignore if line already zero length. + ldb #BS + jsr putchar + ldb #' ' + jsr putchar + ldb #BS ;Send BS,space,BS. This erases last + jsr putchar ;character on most terminals. + leax -1,x ;Decrement address. + deca + bra osgetl1 +osgetl2 cmpb #CR + beq newline + cmpb #LF + bne osgetl3 ;CR or LF character ends line. + ldb lastterm + cmpb #CR + beq osgetl1 ;Ignore LF if it comes after CR + ldb #LF +newline stb lastterm + jsr putcr + tfr a,b ;Move length to B + puls a,x ;restore registers. + rts ;<--- Here is the exit point. +osgetl3 cmpb #TAB + beq dotab + cmpb #' ' + blo osgetl1 ;Ignore control characters. + cmpa temp + beq osgetl1 ;Ignore char if line full. + jsr putchar ;Echo the character. + stb ,x+ ;Store it in memory. + inca + bra osgetl1 +dotab ldb #' ' + cmpa temp + beq osgetl1 + jsr putchar + stb ,x+ + inca + bita #7 ;Insert spaces until length mod 8=0 + bne dotab + bra osgetl1 + +* O.S. routine to write a line starting at address X, B chars long. +osputl pshs a,b,x + tfr b,a + tsta + beq osputl1 +osputl2 ldb ,x+ + jsr putchar + deca + bne osputl2 +osputl1 puls a,b,x + rts + +* O.S. routine to terminate a line. +oscr pshs b + ldb #CR + jsr putchar + ldb #LF + jsr putchar ;Send the CR and LF characters. + puls b + rts + +* Output a counted string at addr X +outcount pshs x,b + ldb ,x+ + jsr putline + puls x,b + rts + +timerirq inc timer+2 + bne endirq + inc timer+1 + bne endirq + inc timer + rti +aciairq nop +endirq rti + +* Wait D times 20ms. +osdly addd timer+1 +dlyloop cmpd timer+1 + bne dlyloop + rts + +* This table will be copied to the interrupt vector area in RAM. +intvectbl jmp endirq + jmp endirq + jmp timerirq + jmp aciairq + jmp unlaunch + jmp endirq + jmp xerrhand + jmp expr + jmp asmerrvec + jmp pseudo +* And this one to the I/O vector table. +osvectbl jmp osgetc + jmp osputc + jmp osgetl + jmp osputl + jmp oscr + jmp osgetpoll + jmp xopin + jmp xopout + jmp xabtin + jmp xclsin + jmp xclsout + jmp osdly +endvecs equ * + +* The J command returns here. +stakregs pshs x ;Stack something where the pc comes + pshs ccr,b,a,dp,x,y,u ;Stack the normal registers. + ldx oldpc + stx 10,s ;Stack the old pc value. + bra unlaunch1 +* The G and P commands return here through a breakpoint. +* Registers are already stacked. +unlaunch ldd 10,s + subd #1 + std 10,s ;Decrement pc before breakpoint +unlaunch1 andcc #$0 ;reenable the interrupts. + jsr disarm ;Disarm the breakpoints. + jsr dispregs +cmdline jsr xcloseout + sts savesp + ldb #'.' + jsr putchar + ldx #linebuf + ldb #buflen + jsr getline + tstb + beq cmdline ;Ignore line if it is empty + abx + clr ,x ;Make location after line zero. + ldx #linebuf + ldb ,x+ + andb #CASEMASK ;Make 1st char uppercase. + subb #'A' + bcs unk + cmpb #26 + bcc unk ;Unknown cmd if it is not a letter. + ldx #cmdtab + aslb ;Index into command table. + jmp [b,x] + +cmdtab fdb asm,break,calc,dump + fdb enter,find,go,help + fdb inp,jump,unk,unk + fdb move,unk,unk,prog + fdb unk,regs,srec,trace + fdb unasm,unk,unk,xmodem + fdb unk,unk + +* Unknown command handling routine. +unk jsr xabortin + ldx #unknown + jsr outcount + jsr putcr + jmp cmdline + +help ldx #mhelp ;Print a help message. +help1 ldb ,x+ + beq endhlp + lbsr osputc + bra help1 +endhlp jmp cmdline +mhelp fcb CR,LF + fcc 'Commands list' + fcb CR,LF + + fcc '-------------' + fcb CR,LF + + fcc 'Asm ' + fcc '{Aaddr}' + fcb CR,LF + + fcc 'Unasm ' + fcc '{U or Uaddr or Uaddr,length}' + fcb CR,LF + + fcc 'Dump ' + fcc '{D or D<addr> or D<addr>,<length>}' + fcb CR,LF + + fcc 'Enter ' + fcc '{E or E<addr> or E<addr> <bytes> or E<addr>string}' + fcb CR,LF + + fcc 'Break ' + fcc '{B or B<addr>. B displays, B<addr> sets or clears breakpoint}' + fcb CR,LF + + fcc 'Find ' + fcb "{Faddr bytes or Faddr",34,"ascii",34,"}" + fcb CR,LF + + fcc 'Go ' + fcc '{G or G<addr>}' + fcb CR,LF + + fcc 'Calc ' + fcc '{Chexnum{+|-hexnum}}' + fcb CR,LF + + fcc 'Inp ' + fcc '{Iaddr}' + fcb CR,LF + + fcc 'Jump ' + fcc '{J<addr>}' + fcb CR,LF + + fcc 'Move ' + fcc '{M<addr1>,<addr2>,<lenght>}' + fcb CR,LF + + fcc 'Prog ' + fcc '{P}' + fcb CR,LF + + fcc 'Regs ' + fcc '{R or R<letter><hex>}' + fcb CR,LF + + fcc 'Srec ' + fcc '{SO<addr> or SS<addr>,<len> or S1<bytes> or S9<bytes>}' + fcb CR,LF + + fcc 'Trace ' + fcc '{T}' + fcb CR,LF + + fcc 'Xmodem ' + fcc '{XSaddr,len XLaddr,len XX XOcrlf,filler, XSSaddr,len}' + fcb CR,LF + + fcc 'Help ' + fcc '{H}' + fcb CR,LF,0 + + + +* Here are some useful messages. +welcome fcb unknown-welcome-1 + fcc "Welcome to BUGGY version 1.0" +unknown fcb brkmsg-unknown-1 + fcc "Unknown command" +brkmsg fcb clrmsg-brkmsg-1 + fcc "Breakpoint set" +clrmsg fcb fullmsg-clrmsg-1 + fcc "Breakpoint cleared" +fullmsg fcb smsg-fullmsg-1 + fcc "Breakpoints full" +smsg fcb lastrec-smsg-1 + fcc "Error in S record" +lastrec fcb xsmsg-lastrec-1 + fcc "S9030000FC" +xsmsg fcb xrmsg-xsmsg-1 + fcc "Start XMODEM Send" +xrmsg fcb xamsg-xrmsg-1 + fcc "Start XMODEM Receive" +xamsg fcb invmmsg-xamsg-1 + fcc "XMODEM transfer aborted" +invmmsg fcb exprmsg-invmmsg-1 + fcc "Invalid mnemonic" +exprmsg fcb modemsg-exprmsg-1 + fcc "Expression error" +modemsg fcb brmsg-modemsg-1 + fcc "Addressing mode error" +brmsg fcb endmsg-brmsg-1 + fcc "Branch too long" +endmsg equ * + +* Output hex digit contained in A +hexdigit adda #$90 + daa + adca #$40 + daa ;It's the standard conversion trick ascii + tfr a,b ;to hex without branching. + jsr putchar + rts + +* Output contents of A as two hex digits +outbyte pshs a + lsra + lsra + lsra + lsra + bsr hexdigit + puls a + anda #$0f + bra hexdigit + +* Output contents of d as four hex digits +outd pshs b + bsr outbyte + puls a + bsr outbyte + rts + +* Skip X past spaces, B is first non-space character. +skipspace ldb ,x+ + cmpb #' ' + beq skipspace + rts + +* Convert ascii hex digit in B register to binary Z flag set if no hex digit. +convb subb #'0' + blo convexit + cmpb #9 + bls cb2 + andb #CASEMASK ;Make uppercase. + subb #7 ;If higher than digit 9 it must be a letter. + cmpb #9 + bls convexit + cmpb #15 + bhi convexit +cb2 andcc #$FB ;clear zero + rts +convexit orcc #$04 + rts + +scanexit ldd temp + leax -1,x + tst temp2 + rts <-- exit point of scanhex + +* Scan for hexadecimal number at address X return in D, Z flag is set it no +* number found. +scanhex clr temp + clr temp+1 + clr temp2 + bsr skipspace +scloop jsr convb + beq scanexit + pshs b + ldd temp + aslb + rola + aslb + rola + aslb + rola + aslb + rola + addb ,s+ + std temp + inc temp2 + ldb ,x+ + bra scloop + +scan2parms std length + bsr scanhex + beq sp2 + std addr + bsr skipspace + cmpb #',' + bne sp2 + bsr scanhex + beq sp2 + std length +sp2 rts + +* Scan two hexdigits at in and convert to byte into A, Z flag if error. +scanbyte bsr skipspace + bsr convb + beq sb1 + tfr b,a + ldb ,x+ + bsr convb + beq sb1 + asla + asla + asla + asla + stb temp + adda temp + andcc #$fb ;Clear zero flag +sb1 rts + + +* This is the code for the D command, hex/ascii dump of memory +* Syntax: D or D<addr> or D<addr>,<length> +dump ldx #linebuf+1 + ldd #$40 + jsr scan2parms ;Scan address and length, default length=64 + ldy addr +dh1 lda #16 + sta temp+1 + tfr y,d + jsr outd + ldb #' ' + jsr putchar +dh2 lda ,y+ ;display row of 16 mem locations as hex + jsr outbyte + ldb #' ' + lda temp+1 + cmpa #9 + bne dh6 + ldb #'-' ;Do a - after the eighth byte. +dh6 jsr putchar + dec temp+1 + bne dh2 + leay -16,y ;And now for the ascii dump. + lda #16 +dh3 ldb ,y+ + cmpb #' ' + bhs dh4 + ldb #'.' +dh4 cmpb #DEL + blo dh5 + ldb #'.' ;Convert all nonprintables to . +dh5 jsr putchar + deca + bne dh3 + jsr putcr + ldd length + subd #16 + std length + bhi dh1 + sty addr + jmp cmdline + +* This is the code for the E command, enter hex bytes or ascii string. +* Syntax E or E<addr> or E<addr> <bytes> or E<addr>"string" +enter ldx #linebuf+1 + jsr scanhex + beq ent1 + std addr +ent1 bsr entline + lbne cmdline ;No bytes, then enter interactively. +ent2 ldb #'E' + jsr putchar + ldd addr + jsr outd + ldb #' ' + jsr putchar ;Display Eaddr + space + lda [addr] + jsr outbyte + ldb #' ' + jsr putchar + ldx #linebuf + ldb #buflen + jsr getline ;Get the line. + tstb + beq skipbyte + abx + clr ,x + ldx #linebuf + bsr entline + bne ent2 + jmp cmdline +skipbyte ldd addr + addd #1 + std addr + bra ent2 + +* Enter a line of hex bytes or ascci string at address X, Z if empty. +entline jsr skipspace + tstb + beq entexit + cmpb #'.' + beq entexit + cmpb #'"' + beq entasc + leax -1,x + ldy addr +entl2 jsr scanbyte ;Enter hex digits. + beq entdone + sta ,y+ + bra entl2 +entasc ldy addr +entl3 lda ,x+ + tsta + beq entdone + cmpa #'"' + beq entdone + sta ,y+ + bra entl3 +entdone sty addr + andcc #$fb + rts +entexit orcc #$04 + rts + +*This is the code for the I command, display the contents of an address +* Syntax: Iaddr +inp ldx #linebuf+1 + jsr scanhex + tfr d,x + lda ,x ;Read the byte from memory. + jsr outbyte ;Display itin hex. + jsr putcr + jmp cmdline + +*This is the code for the H command, display result of simple hex expression +*Syntax Hhexnum{+|-hexnum} +calc ldx #linebuf+1 + jsr scanhex + std temp3 +hexloop jsr skipspace + cmpb #'+' + bne hex1 + jsr scanhex + addd temp3 + std temp3 + bra hexloop +hex1 cmpb #'-' + bne hexend + jsr scanhex + comb + coma + addd #1 + addd temp3 + std temp3 + bra hexloop +hexend ldd temp3 + jsr outd + jsr putcr + jmp cmdline + +* This is the code for the G command, jump to the program +* Syntax G or G<addr> +go ldx #linebuf+1 + jsr scanhex + beq launch + std 10,s ;Store parameter in pc location. +launch jsr arm ;Arm the breakpoints. + puls ccr,b,a,dp,x,y,u,pc + +* This is the code for the J command, run a subroutine. +* Syntax J<addr> +jump ldx #linebuf+1 + ldd 10,s + std oldpc ;Save old pc + jsr scanhex + std 10,s ;Store parameter in PC location + tfr s,x + leas -2,s + tfr s,u + ldb #12 ;Move the saved register set 2 addresses + jsr blockmove ;down on the stack. + ldd #stakregs + std 12,s ;Prepare subroutine return address. + bra launch ;Jump to the routine. + + +* This is the code for the P command, run instruction followed by breakpoint +* Syntax P +prog ldy 10,s ;Get program counter value. + jsr disdecode ;Find out location past current insn. + sty stepbp + bra launch + +* This is the code for the T command, single step trace an instruction. +* Syntax T +trace jsr traceone + jsr dispregs + jmp cmdline + +traceone orcc #$50 ;Disable the interrupts. + ldd ,s++ + std oldpc ;Remove saved pc from stack. + ldd #traceret + std firqvec+1 ;Adjust timer IRQ vector. + sync ;Synchronize on the next timer interrupt. + ;1 cycle + ldx #4441 ;3 cycles +traceloop leax -1,x ;6 cycles\x4441= 39969 cycles. + bne traceloop ;3 cycles/ + nop ;2 cycles. + nop ;2 cycles. + nop ;2 cycles. + brn traceret ;3 cycles. + puls x,y,u,a,b,dp,cc,pc ;17 cycles, total=39999 20ms @ 2MHz + ;Pull all registers and execute. + ;Is timed such that next timer IRQ + ;occurs right after it. +traceret puls cc + pshs x,y,u,a,b,dp,cc;Store full register set instead of cc. + ldd #timerirq + std firqvec+1 ;Restore timer IRQ vector. + jmp [oldpc] + + +* Display the contents of 8 bit register, name in B, contents in A +disp8 jsr putchar + ldb #'=' + jsr putchar + jsr outbyte + ldb #' ' + jsr putchar + rts + +* Display the contents of 16 bit register, name in B, contents in Y +disp16 jsr putchar + ldb #'=' + jsr putchar + tfr y,d + jsr outd + ldb #' ' + jsr putchar + rts + +* Display the contents of the registers and disassemble instruction at +* PC location. +dispregs ldb #'X' + ldy 6,s ;Note that there's one return address on + bsr disp16 ;stack so saved register offsets are + ldb #'Y' ;inremented by 2. + ldy 8,s + bsr disp16 + ldb #'U' + ldy 10,s + bsr disp16 + ldb #'S' + tfr s,y + leay 14,y ;S of the running program is 12 higher, + ;because regs are not stacked when running. + bsr disp16 + ldb #'A' + lda 3,s + bsr disp8 + ldb #'B' + lda 4,s + bsr disp8 + ldb #'D' + lda 5,s + bsr disp8 + ldb #'C' + lda 2,s + bsr disp8 + jsr putcr + ldb #'P' + ldy 12,s + bsr disp16 + jsr disdecode + jsr disdisp ;Disassemble instruction at PC + jsr putcr + rts + + +* This is the code for the R command, display or alter the registers. +* Syntax R or R<letter><hex> +regs ldx #linebuf+1 + jsr skipspace + tstb + bne setreg + bsr dispregs ;Display regs ifnothing follows. + jmp cmdline +setreg ldy #regtab + clra + andb #CASEMASK ;Make letter uppercase. +sr1 tst ,y + lbeq unk ;At end of register tab, unknown reg + cmpb ,y+ + beq sr2 ;Found the register? + inca + bra sr1 +sr2 pshs a + jsr scanhex ;Convert the hex argument. + pshs d + lda 2,s ;Get register number. + cmpa #4 + bcc sr3 + ldb 1,s ;It's 8 bit. + leas 3,s ;Remove temp stuff from stack. + stb a,s ;Store it in the reg on stack. + jmp cmdline +sr3 cmpa #8 + bcc sr4 + puls x ;It's 16 bit. + leas 1,s + lsla + suba #4 ;Convert reg no to stack offset. + stx a,s + jmp cmdline +sr4 puls u ;It's the stack pointer. + leas 1,s + leau -12,u + tfr s,x + tfr u,s ;Set new stack pointer. + ldb #12 + jsr blockmove ;Move register set to new stack location. + jmp cmdline + +regtab FCC "CABDXYUPS " + +* Disarm the breakpoints, this is replace the SWI instructions with the +* original byte. +disarm ldx #bpaddr + lda #brkpoints+1 +disarm1 ldu ,x++ + ldb ,x+ ;Get address in u, byte in b + cmpu #0 + beq disarm2 + stb ,u +disarm2 deca + bne disarm1 + ldu #0 + stu -3,x ;Clear the step breakpoint. + rts + +* Arm the breakponts, this is replace the byte at the breakpoint address +* with an SWI instruction. +arm ldx #bpaddr+brkpoints*3 + lda #brkpoints+1 ;Arm them in reverse order of disarming. +arm1 ldu ,x ;Get address in u. + beq arm2 + ldb ,u + stb 2,x + cmpu 12,s ;Compare to program counter location + beq arm2 + ldb #$3F + stb ,u ;Store SWI instruction if not equal. +arm2 leax -3,x + deca + bne arm1 + rts + +* This is the code for the break command, set, clear display breakpoints. +* Syntax B or B<addr>. B displays, B<addr> sets or clears breakpoint. +break lda #brkpoints + sta temp2+1 ;Store number of breakpoints to visit. + ldx #linebuf+1 + jsr scanhex + beq dispbp ;No number then display breakpoints + ldx #bpaddr + ldu #0 + tfr u,y +bp1 cmpd ,x + beq clearit ;Found the breakpoint, so clear it, + cmpu ,x ;Is location zero + bne bp2 + tfr x,y ;Set free address to y +bp2 leax 3,x + dec temp2+1 + bne bp1 + cmpy #0 ;Address not found in list of breakpoints + beq bpfull ;Was free address found. + std ,y ;If so, store breakpoint there. + ldx #brkmsg +bpexit jsr outcount + jsr putcr + jmp cmdline +clearit clra + clrb + std ,x + ldx #clrmsg + bra bpexit +bpfull ldx #fullmsg + bra bpexit + +dispbp ldx #bpaddr +dbp1 ldd ,x + beq dbp2 + jsr outd + ldb #' ' + jsr putchar +dbp2 leax 3,x + dec temp2+1 + bne dbp1 + jsr putcr + jmp cmdline + +* Scan hex byte into a and add it to check sum in temp2+1 +addchk jsr scanbyte + lbeq srecerr + tfr a,b + addb temp2+1 + stb temp2+1 + rts + +* This tis the code for the S command, the Motorola S records entry. +* Syntax SO<addr> or SS<addr>,<len> or S1<bytes> or S9<bytes> +srec ldx #linebuf+1 + ldb ,x+ + andb #CASEMASK + cmpb #'O' + beq setsorg + cmpb #'S' + beq sendrec + ldb -1,x + clr temp3 + cmpb #'1' + beq readrec + cmpb #'9' + bne srecerr + inc temp3 +readrec clr temp2+1 ;clear checksum. + bsr addchk + suba #2 ;discount the address bytes from the count. + sta temp3+1 ;Read length byte. + bsr addchk + pshs a + bsr addchk + puls b + exg a,b ;Read address into d. + ldu sorg + beq rr1 + ldu soffs + bne rr1 + pshs d ;Sorg is nonzero and soffs is zero, now + subd sorg ;set soffs + std soffs + puls d +rr1 subd soffs ;Subtract the address offset. + tfr d,y +rr2 bsr addchk + dec temp3+1 + beq endrec + sta ,y+ + bra rr2 +endrec inc temp2+1 ;Check checksum. + bne srecerr + tst temp3 + lbeq cmdline ;Was it no S9 record? + cmpy #0 + beq endrec1 + sty 10,s ;Store address into program counter. +endrec1 clra + clrb + std sorg ;Reset sorg, next S loads will be normal. + std soffs + jmp cmdline +srecerr jsr xabortin + ldx #smsg ;Error in srecord, display message. + jsr outcount + jsr putcr + jmp cmdline +setsorg jsr scanhex ;Set S record origin. + std sorg + clra + clrb + std soffs + jmp cmdline +* Send a memory region as S-records. +sendrec ldd #$100 ;Scan address and length parameter. + jsr scan2parms + ldd sorg + beq ss1 + ldd addr + subd sorg + std soffs ;Compute offset for origin. +ss1 ldd length + beq endss ;All bytes sent? + cmpd #16 + blo ss2 + ldb #16 ;If more than 16 left, then send 16. +ss2 stb temp + negb + ldu length + leau b,u + stu length ;Discount line length from length. + ldb #'S' + jsr putchar + ldb #'1' + jsr putchar + clr temp+1 ;Clear check sum + ldb temp + addb #3 + bsr checkout ;Output byte b as hex and add to check sum. + ldd addr + tfr d,y + subd soffs + exg a,b + bsr checkout + exg a,b + bsr checkout ;Output address (add into check sum) +ss3 ldb ,y+ + bsr checkout + dec temp + bne ss3 + sty addr + ldb temp+1 + comb + bsr checkout ;Output checksum byte. + jsr putcr + bra ss1 +endss ldx #lastrec + jsr outcount + jsr putcr + jmp cmdline +* Output byte in register B and add it into check sum at temp+1 +checkout pshs a + tfr b,a + addb temp+1 + stb temp+1 + jsr outbyte + puls a + rts + +* This is the code for the M command, move memory region. +* Syntax: Maddr1,addr2,length +move ldx #linebuf+1 + jsr scanhex + lbeq unk + std temp3 + jsr skipspace + cmpb #',' + lbne unk + jsr scanhex + lbeq unk + tfr d,u + jsr skipspace + cmpb #',' + lbne unk + jsr scanhex + lbeq unk + tfr d,y ;Read the argument separated by commas + ldx temp3 ;src addr to x, dest addr to u, length to y + ;Don't tolerate syntax deviations. +mvloop lda ,x+ + sta ,u+ + leay -1,y + bne mvloop ;Perform the block move. + jmp cmdline + + +* This is the code for the F command, find byte/ascii string in memory. +* Syntax: Faddr bytes or Faddr "ascii" +find ldx #linebuf+1 + jsr scanhex + tfr d,y ;Scan the start address. + jsr skipspace + cmpb #'"' + bne findhex + ldu #linebuf ;Quote found, so scan for quoted string. + clra +fstrloop ldb ,x+ + beq startsrch ;End of line without final quote. + cmpb #'"' + beq startsrch ;End quote found + stb ,u+ + inca + bra fstrloop +findhex ldu #linebuf ;Convert string of hex bytes. + leax -1,x ;String will be stored at start of line + clra ;buffer and may overwrite part of the +fhexloop pshs a ;already converted string. + jsr scanbyte + tfr a,b + puls a + beq startsrch + stb ,u+ + inca + bra fhexloop +startsrch tsta ;Start searching, start addr in Y, + ;string starts at linebuf, length A + lbeq cmdline ;Quit with zero length string. + clr temp3 + sta temp3+1 +srchloop tfr y,x + lda temp3+1 + cmpx #$e100 + bcc srch1 + leax a,x + cmpx #$e000 ;Stop at I/O addresses. + lbcc cmdline +srch1 tfr y,x + ldu #linebuf +srch2 ldb ,x+ + cmpb ,u+ + bne srch3 ;Not equal, try next address. + deca + bne srch2 + tfr y,d + jsr outd ;String found + jsr putcr + inc temp3 + lda temp3 + cmpa #$10 + lbeq cmdline ;If 10 matches found, just stop. +srch3 leay 1,y + bra srchloop + +* Send the contents of the xmodem buffer and get it acknowledged, zero flag +* is set if transfer aborted. +xsendbuf ldb #SOH + jsr osputc ;Send SOH + ldb xpacknum + jsr osputc ;Send block number. + comb + jsr osputc ;and its complement. + clr xsum + lda #128 + ldx #buf0 +xsloop ldb ,x + addb xsum + stb xsum + ldb ,x+ + jsr osputc + deca + bne xsloop ;Send the buffer contents. + ldb xsum + jsr osputc ;Send the check sum +waitack jsr osgetc + cmpb #CAN + beq xsabt ;^X for abort. + cmpb #NAK + beq xsendbuf ;Send again if NAK + cmpb #ACK + bne waitack + inc xpacknum +xsok andcc #$fb ;Clear zero flag after ACK +xsabt rts + +* Start an XMODEM send session. +xsendinit ldb #1 + stb xpacknum ;Initialize block number. +waitnak jsr osgetc + cmpb #CAN + beq xsabt ;If ^X exit with zero flag. + cmpb #NAK + beq xsok + bra waitnak ;Wait until NAK received. + +* Send ETX and wait for ack. +xsendeot ldb #EOT + jsr osputc +waitack2 jsr osgetc + cmpb #CAN + beq xsabt + cmpb #NAK + beq xsendeot + cmpb #ACK + beq xsok + bra waitack2 + +* Read character into B with a timeout of A seconds, Carry set if timeout. +gettimeout asla + ldb #50 + mul + tfr b,a + adda timer+2 +gt1 jsr osgetpoll + tstb + bne gtexit + cmpa timer+2 + bne gt1 + orcc #$1 + rts +gtexit jsr osgetc + andcc #$fe + rts + +* Wait until line becomes quiet. +purge lda #3 + jsr gettimeout + bcc purge + rts + +* Receive an XMODEM block and wait till it is OK, Z set if etx. +xrcvbuf lda #3 + tst lastok + beq sendnak + ldb #ACK + jsr osputc ;Send an ack. + lda #5 + bra startblock +sendnak ldb #NAK + jsr osputc ;Send a NAK +startblock clr lastok + bsr gettimeout + lda #3 + bcs sendnak ;Keep sending NAKs when timed out. + cmpb #EOT + beq xrcveot ;End of file reached, acknowledge EOT. + cmpb #SOH + bne purgeit ;Not, SOH, bad block. + lda #1 + bsr gettimeout + bcs purgeit + cmpb xpacknum ;Is it the right block? + beq xr1 + incb + cmpb xpacknum ;Was it the previous block. + bne purgeit + inc lastok +xr1 stb xsum + lda #1 + bsr gettimeout + bcs purgeit + comb + cmpb xsum ;Is the complement of the block number OK + bne purgeit + ldx #buf0 + clr xsum +xrloop lda #1 + bsr gettimeout + bcs purgeit + stb ,x+ + addb xsum + stb xsum + cmpx #buf0+128 + bne xrloop ;Get the data bytes. + lda #1 + bsr gettimeout + bcs purgeit + cmpb xsum + bne purgeit ;Check the check sum. + tst lastok + bne xrcvbuf ;Block was the previous block, get next one + inc lastok + inc xpacknum + andcc #$fb + rts +purgeit jsr purge + bra sendnak +xrcveot lda #3 ;EOT was received. + ldb #ACK +ackloop jsr osputc + deca + bne ackloop ;Send 3 acks in a row. + rts + + +savevecs ldx getchar+1 + stx oldgetc + ldx putchar+1 + stx oldputc + ldx putcr+1 + stx oldputcr + clr lastterm + rts + +rstvecs ldx oldgetc + stx getchar+1 + ldx oldputc + stx putchar+1 + ldx oldputcr + stx putcr+1 + clr lastterm + rts + +* O.S. routine to open input through XMODEM transfer. +xopin pshs x,a,b + ldx #xsmsg + jsr outcount + jsr putcr ;Display message to start XMODEM send. + bsr savevecs + ldx #noop + stx putchar+1 ;Disable character output. + ldx #xgetc + stx getchar+1 ; + clr lastok + clr xcount + lda #1 + sta xpacknum + inca + sta xmode ;set xmode to 2. + puls x,a,b,pc + +* O.S. routine to open output through XMODEM transfer. +xopout pshs x,a,b + bsr savevecs + ldx #xrmsg + jsr outcount ;Display message to start XMODEM receive + jsr putcr + ldx #xputc + stx putchar+1 + ldx #xputcr + stx putcr+1 + jsr xsendinit + lbeq xerror + clr xcount + lda #1 + sta xmode + puls x,a,b,pc + + +* O.S. routine to abort input through XMODEM transfer. +xabtin lda xmode + cmpa #2 + bne xclsend + jsr purge + ldb #CAN + lda #8 +xabtloop jsr osputc + deca + bne xabtloop ;Send 8 CAN characters to kill transfer. + bsr rstvecs + clr xmode + ldx #xamsg + jsr outcount + jsr putcr ;Send diagnostic message. + rts + +* O.S. routine to close output through XMODEM transfer. +xclsout lda xmode + cmpa #1 + bne xclsend + tst xcount + beq xclsdone + lda #128 + suba xcount +xclsloop ldb filler + bsr xputc + deca + bne xclsloop ;Transfer filler chars to force block out. +xclsdone jsr xsendeot ;Send EOT + lbeq xerror + jsr rstvecs + clr xmode +xclsend rts + +* O.S. routine to close input through XMODEM, by gobbling up the remaining +* bytes. +xclsin ldb xmode + cmpb #2 + bne xclsend + jsr putchar + bra xclsin + +* putchar routine for XMODEM +xputc pshs x,a,b + lda xcount + inc xcount + ldx #buf0 + stb a,x ;Store character in XMODEM buffer. + cmpa #127 + bne xputc1 ;is buffer full? + clr xcount + pshs y,u + jsr xsendbuf + lbeq xerror + puls y,u +xputc1 puls x,a,b,pc + +* putcr routine for XMODEM +xputcr pshs b + ldb xmcr + bitb #2 + beq xputcr1 + ldb #CR + bsr xputc +xputcr1 ldb xmcr + bitb #1 + beq xputcr2 + ldb #LF + bsr xputc +xputcr2 puls b + rts + +* getchar routine for XMODEM +xgetc pshs x,a + tst xcount ;No characters left? + bne xgetc1 + pshs y,u + jsr xrcvbuf ;Receive new block. + puls y,u + beq xgetcterm ;End of input? + lda #128 + sta xcount +xgetc1 lda xcount + nega + ldx #buf0+128 + ldb a,x ;Get character from buffer + dec xcount + puls x,a,pc +xgetcterm jsr rstvecs + clr xmode + ldb filler + puls x,a,pc + +xerror jsr rstvecs ;Restore I/O vectors + clr xmode + ldx #xamsg + jsr outcount + jsr putcr + jmp xerrvec + +xerrhand lds savesp + jmp cmdline + +* This is the code for the X command, various XMODEM related commands. +* Syntax: XSaddr,len XLaddr,len XX XOcrlf,filler, XSSaddr,len +xmodem ldx #linebuf+1 + lda ,x+ + anda #CASEMASK ;Convert to uppercase. + cmpa #'X' + beq xeq + cmpa #'L' + beq xload + cmpa #'O' + beq xopts + cmpa #'S' + lbne unk + lda ,x + anda #CASEMASK + cmpa #'S' + beq xss + ldd #$100 ;XSaddr,len command. + jsr scan2parms ;Send binary through XMODEM + jsr xopenout + ldu addr + ldy length +xsbinloop ldb ,u+ + jsr putchar + leay -1,y + bne xsbinloop ;Send all the bytes through XMODEM. + jmp cmdline +xss leax 1,x ;XSSaddr,len command. + jsr xopenout ;Send Srecords through XMODEM + jmp sendrec +xload jsr scanhex ;XLaddr command + tfr d,y ;Load binary through XMODEM + jsr xopenin +xlodloop jsr getchar + tst xmode ;File ended? then done + lbeq cmdline + stb ,y+ + bra xlodloop +xeq jsr xopenin ;XX command + jmp cmdline ;Execute commands received from XMODEM +xopts ldd #$1a + jsr scan2parms + lda addr+1 + sta xmcr + lda length+1 + sta filler + jmp cmdline + +* mnemonics table, ordered alphabetically. +* 5 bytes name, 1 byte category, 2 bytes opcode, 8 bytes total. +mnemtab fcc "ABX " + fcb 0 + fdb $3a + fcc "ADCA " + fcb 7 + fdb $89 + fcc "ADCB " + fcb 7 + fdb $c9 + fcc "ADDA " + fcb 7 + fdb $8b + fcc "ADDB " + fcb 7 + fdb $cb + fcc "ADDD " + fcb 8 + fdb $c3 + fcc "ANDA " + fcb 7 + fdb $84 + fcc "ANDB " + fcb 7 + fdb $c4 + fcc "ANDCC" + fcb 2 + fdb $1c + fcc "ASL " + fcb 10 + fdb $08 + fcc "ASLA " + fcb 0 + fdb $48 + fcc "ASLB " + fcb 0 + fdb $58 + fcc "ASR " + fcb 10 + fdb $07 + fcc "ASRA " + fcb 0 + fdb $47 + fcc "ASRB " + fcb 0 + fdb $57 + fcc "BCC " + fcb 4 + fdb $24 + fcc "BCS " + fcb 4 + fdb $25 + fcc "BEQ " + fcb 4 + fdb $27 + fcc "BGE " + fcb 4 + fdb $2c + fcc "BGT " + fcb 4 + fdb $2e + fcc "BHI " + fcb 4 + fdb $22 + fcc "BHS " + fcb 4 + fdb $24 + fcc "BITA " + fcb 7 + fdb $85 + fcc "BITB " + fcb 7 + fdb $c5 + fcc "BLE " + fcb 4 + fdb $2f + fcc "BLO " + fcb 4 + fdb $25 + fcc "BLS " + fcb 4 + fdb $23 + fcc "BLT " + fcb 4 + fdb $2d + fcc "BMI " + fcb 4 + fdb $2b + fcc "BNE " + fcb 4 + fdb $26 + fcc "BPL " + fcb 4 + fdb $2a + fcc "BRA " + fcb 4 + fdb $20 + fcc "BRN " + fcb 4 + fdb $21 +mnembsr fcc "BSR " + fcb 4 + fdb $8d + fcc "BVC " + fcb 4 + fdb $28 + fcc "BVS " + fcb 4 + fdb $29 + fcc "CLR " + fcb 10 + fdb $0f + fcc "CLRA " + fcb 0 + fdb $4f + fcc "CLRB " + fcb 0 + fdb $5f + fcc "CMPA " + fcb 7 + fdb $81 + fcc "CMPB " + fcb 7 + fdb $c1 + fcc "CMPD " + fcb 9 + fdb $1083 + fcc "CMPS " + fcb 9 + fdb $118c + fcc "CMPU " + fcb 9 + fdb $1183 + fcc "CMPX " + fcb 8 + fdb $8c + fcc "CMPY " + fcb 9 + fdb $108c + fcc "COM " + fcb 10 + fdb $03 + fcc "COMA " + fcb 0 + fdb $43 + fcc "COMB " + fcb 0 + fdb $53 + fcc "CWAI " + fcb 2 + fdb $3c + fcc "DAA " + fcb 0 + fdb $19 + fcc "DEC " + fcb 10 + fdb $0a + fcc "DECA " + fcb 0 + fdb $4a + fcc "DECB " + fcb 0 + fdb $5a + fcc "EORA " + fcb 7 + fdb $88 + fcc "EORB " + fcb 7 + fdb $c8 + fcc "EQU " + fcb 13 + fdb 0 + fcc "EXG " + fcb 11 + fdb $1e +mnemfcb fcc "FCB " + fcb 13 + fdb 1 + fcc "FCC " + fcb 13 + fdb 2 + fcc "FDB " + fcb 13 + fdb 3 + fcc "INC " + fcb 10 + fdb $0c + fcc "INCA " + fcb 0 + fdb $4c + fcc "INCB " + fcb 0 + fdb $5c + fcc "JMP " + fcb 10 + fdb $0e +mnemjsr fcc "JSR " + fcb 8 + fdb $8d + fcc "LBCC " + fcb 5 + fdb $1024 + fcc "LBCS " + fcb 5 + fdb $1025 + fcc "LBEQ " + fcb 5 + fdb $1027 + fcc "LBGE " + fcb 5 + fdb $102c + fcc "LBGT " + fcb 5 + fdb $102e + fcc "LBHI " + fcb 5 + fdb $1022 + fcc "LBHS " + fcb 5 + fdb $1024 + fcc "LBLE " + fcb 5 + fdb $102f + fcc "LBLO " + fcb 5 + fdb $1025 + fcc "LBLS " + fcb 5 + fdb $1023 + fcc "LBLT " + fcb 5 + fdb $102d + fcc "LBMI " + fcb 5 + fdb $102b + fcc "LBNE " + fcb 5 + fdb $1026 + fcc "LBPL " + fcb 5 + fdb $102a + fcc "LBRA " + fcb 6 + fdb $16 + fcc "LBRN " + fcb 5 + fdb $1021 + fcc "LBSR " + fcb 6 + fdb $17 + fcc "LBVC " + fcb 5 + fdb $1028 + fcc "LBVS " + fcb 5 + fdb $1029 + fcc "LDA " + fcb 7 + fdb $86 + fcc "LDB " + fcb 7 + fdb $c6 + fcc "LDD " + fcb 8 + fdb $cc + fcc "LDS " + fcb 9 + fdb $10ce + fcc "LDU " + fcb 8 + fdb $ce + fcc "LDX " + fcb 8 + fdb $8e + fcc "LDY " + fcb 9 + fdb $108e + fcc "LEAS " + fcb 3 + fdb $32 + fcc "LEAU " + fcb 3 + fdb $33 + fcc "LEAX " + fcb 3 + fdb $30 + fcc "LEAY " + fcb 3 + fdb $31 + fcc "LSL " + fcb 10 + fdb $08 + fcc "LSLA " + fcb 0 + fdb $48 + fcc "LSLB " + fcb 0 + fdb $58 + fcc "LSR " + fcb 10 + fdb $04 + fcc "LSRA " + fcb 0 + fdb $44 + fcc "LSRB " + fcb 0 + fdb $54 + fcc "MUL " + fcb 0 + fdb $3d + fcc "NEG " + fcb 10 + fdb $00 + fcc "NEGA " + fcb 0 + fdb $40 + fcc "NEGB " + fcb 0 + fdb $50 + fcc "NOP " + fcb 0 + fdb $12 + fcc "ORA " + fcb 7 + fdb $8a + fcc "ORB " + fcb 7 + fdb $ca + fcc "ORCC " + fcb 2 + fdb $1a + fcc "ORG " + fcb 13 + fdb 4 + fcc "PSHS " + fcb 12 + fdb $34 + fcc "PSHU " + fcb 12 + fdb $36 + fcc "PULS " + fcb 12 + fdb $35 + fcc "PULU " + fcb 12 + fdb $37 + fcc "RMB " + fcb 13 + fdb 5 + fcc "ROL " + fcb 10 + fdb $09 + fcc "ROLA " + fcb 0 + fdb $49 + fcc "ROLB " + fcb 0 + fdb $59 + fcc "ROR " + fcb 10 + fdb $06 + fcc "RORA " + fcb 0 + fdb $46 + fcc "RORB " + fcb 0 + fdb $56 + fcc "RTI " + fcb 0 + fdb $3b + fcc "RTS " + fcb 0 + fdb $39 + fcc "SBCA " + fcb 7 + fdb $82 + fcc "SBCB " + fcb 7 + fdb $c2 + fcc "SET " + fcb 13 + fdb 6 + fcc "SETDP" + fcb 13 + fdb 7 + fcc "SEX " + fcb 0 + fdb $1d + fcc "STA " + fcb 7 + fdb $87 + fcc "STB " + fcb 7 + fdb $c7 + fcc "STD " + fcb 8 + fdb $cd + fcc "STS " + fcb 9 + fdb $10cf + fcc "STU " + fcb 8 + fdb $cf + fcc "STX " + fcb 8 + fdb $8f + fcc "STY " + fcb 9 + fdb $108f + fcc "SUBA " + fcb 7 + fdb $80 + fcc "SUBB " + fcb 7 + fdb $c0 + fcc "SUBD " + fcb 8 + fdb $83 + fcc "SWI " + fcb 0 + fdb $3f + fcb "SWI2 " + fcb 1 + fdb $103f + fcb "SWI3 " + fcb 1 + fdb $113f + fcc "SYNC " + fcb 0 + fdb $13 + fcc "TFR " + fcb 11 + fdb $1f + fcc "TST " + fcb 10 + fdb $0d + fcc "TSTA " + fcb 0 + fdb $4d + fcc "TSTB " + fcb 0 + fdb $5d + +mnemsize equ (*-mnemtab)/8 + +* Register table for PUSH/PULL and TFR/EXG instructions. +* 3 bytes for name, 1 for tfr/exg, 1 for push/pull, 5 total +asmregtab fcc "X " + fcb $01,$10 + fcc "Y " + fcb $02,$20 +aregu fcc "U " + fcb $03,$40 +aregs fcc "S " + fcb $04,$40 + fcc "PC " + fcb $05,$80 + fcc "A " + fcb $08,$02 + fcc "B " + fcb $09,$04 + fcc "D " + fcb $00,$06 + fcc "CC " + fcb $0a,$01 + fcc "CCR" + fcb $0a,$01 + fcc "DP " + fcb $0b,$08 + fcc "DPR" + fcb $0b,$08 +reginval fcc "? " + +ixregs fcc "XYUS" + +* opcode offsets to basic opcode, depends on first nibble. +opcoffs fcb 0,0,0,0,0,0,-$60,-$70 + fcb 0,-$10,-$20,-$30,0,-$10,-$20,-$30 +* mode depending on first nibble of opcode. +modetab fcb 3,0,0,0,0,0,5,4,1,3,5,4,1,3,5,4 +* mode depending on category code stored in mnemtab +modetab2 fcb 0,0,1,5,6,7,7,1,2,2,0,8,9 +* modes in this context: 0 no operands, 1 8-bit immediate, 2 16 bit imm, +* 3, 8-bit address, 4 16 bit address, 5 indexed with postbyte, 6 short +* relative, 7 long relative, 8 pushpul, 9 tftetx + +* Decode instruction pointed to by Y for disassembly (and to find out +* how long it is). On return, U points to appropriate mnemonic table entry, +* Y points past instruction. +* It's rather clumsy code, but we do want to reuse the same table +* as used with assembling. +disdecode clr prebyte + clr amode + lda ,y+ + cmpa #$10 + beq ddec1 + cmpa #$11 + bne ddec2 +ddec1 sta prebyte ;Store $10 or $11 prebyte. + lda ,y+ ;Get new opcode. +ddec2 sta opcode + lsra + lsra + lsra + lsra ;Get high nibble. + ldx #modetab + ldb a,x + stb amode + ldx #opcoffs + lda a,x + adda opcode ;Add opcode offset to opcode. +ddec4 sta opc1 ;Store the 'basis' opcode. + ldu #mnemtab + ldx #mnemsize +ddecloop ldb #13 + cmpb 5,u ;Compare category code with 13 + beq ddec3 ;13=pseudo op, no valid opcode + ldd prebyte + cmpd 6,u + beq ddecfound ;Opcode&prebyte agree, operation found. +ddec3 leau 8,u ;point to next mnemonic + leax -1,x + bne ddecloop + ldu #mnemfcb ;mnemonic not found, use FCB byte. + lda #3 + sta amode ;Store mode 3, 8 bit address. + lda opcode + tst prebyte + beq ddec5 + lda prebyte ;if it was the combination prebyte + clr prebyte ;and opcode that was not found, + leay -1,y ;FCB just the prebyte +ddec5 sta operand+1 ;The byte must be stored as operand. + rts +ddecfound cmpu #mnembsr + bne ddec6 + lda #$8d ;Is it really the BSR opcode? + cmpa opcode + beq ddec6 + ldu #mnemjsr ;We mistakenly found BSR instead of JSR +ddec6 lda amode + anda #$FE + bne ddec7 + lda 5,u ;nibble-dependent mode was 0 or 1, + ldx #modetab2 ;use category dependent mode instead. + lda a,x + sta amode +ddec7 lda amode + asla + ldx #disdectab + jmp [a,x] ;jump dependent on definitive mode. +disdectab fdb noop,opdec1,opdec2,opdec1,opdec2,opdecidx + fdb opdec1,opdec2,opdecpb,opdecpb +disdectab1 fdb noop,noop,noop,noop,noop,noop,noop,noop + fdb opdec1,opdec2,noop,noop,opdec1,opdec2,noop,opdec2 +opdec1 ldb ,y+ + sex +od1a std operand +noop rts +opdec2 ldd ,y++ + bra od1a +opdecpb ldb ,y+ +odpa stb postbyte + rts +opdecidx ldb ,y+ + bpl odpa ;postbytes <$80 have no extra operands. + stb postbyte + andb #$0f + aslb + ldx #disdectab1 + jmp [b,x] + +* Display disassembled instruction after the invocation of disdecode. +* U points to mnemonic table entry. +disdisp tfr u,x + ldb #5 + jsr putline ;Display the mnemonic. + ldb #' ' + jsr putchar + lda amode + asla + ldx #disdisptab + jmp [a,x] ;Perform action dependent on mode. +disdisptab fdb noop,disim8,disim16,disadr8,disadr16 + fdb disidx,disrel8,disrel16,distfr,dispush +disim8 bsr puthash + bra disadr8 +disim16 bsr puthash +disadr16 bsr putdol + ldd operand + jmp outd +disadr8 bsr putdol + lda operand+1 + jmp outbyte +disrel8 bsr putdol + ldb operand+1 + sex +dr8a sty temp + addd temp + jmp outd +disrel16 bsr putdol + ldd operand + bra dr8a + +puthash ldb #'#' + jmp putchar +putdol ldb #'$' + jmp putchar +putcomma ldb #',' + jmp putchar +putspace ldb #' ' + jmp putchar + +dispush ldb #12 + ldx #asmregtab ;Walk through the register table. + clr temp +regloop lda postbyte + anda 4,x + beq dispush1 ;Is bit corresponding to reg set in postbyte + cmpx #aregu + bne dispush3 + sta temp+1 + lda opcode + anda #2 + bne dispush1 ;no u register in pshu pulu. + lda temp+1 +dispush3 cmpx #aregs + bne dispush4 + sta temp+1 + lda opcode + anda #2 + beq dispush1 ;no s register in pshs puls. + lda temp+1 +dispush4 coma + anda postbyte ;remove the bits from postbyte. + sta postbyte + pshs b + tst temp + beq dispush2 + bsr putcomma ;print comma after first register. +dispush2 bsr disregname + inc temp + puls b +dispush1 leax 5,x + decb + bne regloop + rts + +distfr lda postbyte + lsra + lsra + lsra + lsra + bsr distfrsub + bsr putcomma + lda postbyte + anda #$0f +distfrsub ldb #12 + ldx #asmregtab +distfrloop cmpa 3,x + beq distfrend + leax 5,x + decb + bne distfrloop +distfrend bsr disregname + rts + +disregname lda #3 + tfr x,u +drnloop ldb ,u+ + cmpb #' ' + beq drnend + jsr putchar + deca + bne drnloop +drnend rts + +disidxreg lda postbyte + lsra + lsra + lsra + lsra + lsra + anda #3 + ldx #ixregs + ldb a,x + jmp putchar + +disidx clr temp + lda postbyte + bmi disidx1 + anda #$1f + bita #$10 + bne negoffs + jsr outdecbyte + bra discomma +negoffs ldb #'-' + jsr putchar + ora #$f0 + nega + jsr outdecbyte +discomma jsr putcomma ;Display ,Xreg and terminating ] +disindex bsr disidxreg +disindir tst temp ;Display ] if indirect. + beq disidxend + ldb #']' + jsr putchar +disidxend rts +disidx1 bita #$10 + beq disidx2 + ldb #'[' + jsr putchar + inc temp +disidx2 lda postbyte + anda #$0f + asla + ldx #disidxtab + jmp [a,x] ;Jump to routine for indexed mode +disadec2 lda #2 + bra disadeca +disadec1 lda #1 +disadeca jsr putcomma +disadloop ldb #'-' + jsr putchar + deca + bne disadloop + bra disindex +disainc2 lda #2 + bra disainca +disainc1 lda #1 +disainca sta temp+1 + jsr putcomma + jsr disidxreg + lda temp+1 +disailoop ldb #'+' + jsr putchar + deca + bne disailoop + jmp disindir +disax ldb #'A' + jsr putchar + jmp discomma +disbx ldb #'B' + jsr putchar + jmp discomma +disdx ldb #'D' + jsr putchar + jmp discomma +disinval ldb #'?' + jsr putchar + jmp disindir +disnx lda operand+1 + bmi disnxneg +disnx1 jsr putdol + jsr outbyte + jmp discomma +disnxneg ldb #'-' + jsr putchar + nega + bra disnx1 +disnnx jsr putdol + ldd operand + jsr outd + jmp discomma +disnpc jsr putdol + ldb operand+1 + sex +disnpca sty temp2 + addd temp2 + jsr outd + ldx #commapc + ldb #4 + jsr putline + jmp disindir +disnnpc jsr putdol + ldd operand + bra disnpca +disdirect jsr putdol + ldd operand + jsr outd + jmp disindir + +commapc fcc ",PCR" + +disidxtab fdb disainc1,disainc2,disadec1,disadec2 + fdb discomma,disbx,disax,disinval + fdb disnx,disnnx,disinval,disdx + fdb disnpc,disnnpc,disinval,disdirect + +* Display byte A in decimal (0<=A<20) +outdecbyte cmpa #10 + blo odb1 + suba #10 + ldb #'1' + jsr putchar +odb1 adda #'0' + tfr a,b + jmp putchar + +* This is the code for the U command, unassemble instructions in memory. +* Syntax: U or Uaddr or Uaddr,length +unasm bsr disasm + jmp cmdline +disasm ldx #linebuf+1 + ldd #20 + jsr scan2parms ;Scan address,length parameters. +dis1 ldd addr + addd length + std length + ldy addr +unasmloop tfr y,d + jsr outd ;Display instruction address + jsr putspace + pshs y + jsr disdecode + puls x + sty temp + clr temp2 +unadishex lda ,x+ + jsr outbyte + inc temp2 + inc temp2 + cmpx temp + bne unadishex ;Display instruction bytes as hex. +unadisspc ldb #' ' + jsr putchar + inc temp2 + lda #11 + cmpa temp2 ;Fill out with spaces to width 11. + bne unadisspc + bne unadishex + jsr disdisp ;Display disassembled instruction. + tst disflg + bne skipcr + jsr putcr +skipcr cmpy length + bls unasmloop + sty addr + rts + +* Simple 'expression evaluator' for assembler. +expr ldb ,x + cmpb #'-' + bne pos + clrb + leax 1,x +pos pshs b + bsr scanfact + beq exprend1 + tst ,s+ + bne exprend ;Was the minus sign there. + coma + comb + addd #1 + andcc #$fb ;Clear Z flag for valid result. +exprend rts +exprend1 puls b + rts + +scanfact ldb ,x+ + cmpb #'$' + lbeq scanhex ;Hex number if starting with dollar. + cmpb #''' + bne scandec ;char if starting with ' else decimal + ldb ,x+ + lda ,x + cmpa #''' + bne scanchar2 + leax 1,x ;Increment past final quote if it's there. +scanchar2 clra + andcc #$fb ;Clear zero flag. + rts +scandec cmpb #'0' + blo noexpr + cmpb #'9' + bhi noexpr + clr temp + clr temp+1 +scandloop subb #'0' + bcs sdexit + cmpb #10 + bcc sdexit + pshs b + ldd temp + aslb + rola + pshs d + aslb + rola + aslb + rola + addd ,s++ ;Multiply number by 10. + addb ,s+ + adca #0 ;Add digit to 10. + std temp + ldb ,x+ ;Get next character. + bra scandloop +sdexit ldd temp + leax -1,x + andcc #$fb + rts +noexpr orcc #$04 + rts + +* Assemble the instruction pointed to by X. +* Fisrt stage: copy mnemonic to mnemonic buffer. +asminstr lda #5 + ldu #mnembuf +mncploop ldb ,x+ + beq mncpexit + cmpb #' ' + beq mncpexit ;Mnemonic ends at first space or null + andb #CASEMASK + cmpb #'A' + blo nolet + cmpb #'Z' + bls mnemcp1 ;Capitalize letters, but only letters. +nolet ldb -1,x +mnemcp1 stb ,u+ ;Copy to mnemonic buffer. + deca + bne mncploop +mncpexit tsta + beq mncpdone + ldb #' ' +mnfilloop stb ,u+ + deca + bne mnfilloop ;Fill the rest of mnem buffer with spaces. +* Second stage: look mnemonic up using binary search. +mncpdone stx temp3 + clr temp ;Low index=0 + lda #mnemsize + sta temp+1 ;High index=mnemsize. +bsrchloop ldb temp+1 + cmpb #$ff + beq invmnem ;lower limit -1? + cmpb temp + blo invmnem ;hi index lower than low index? + clra + addb temp ;Add indexes. + adca #0 + lsra + rorb ;Divide by 2 to get average + stb temp2 + aslb + rola + aslb + rola + aslb + rola ;Multiply by 8 to get offset. + ldu #mnemtab + leau d,u ;Add offset to table base + tfr u,y + lda #5 + ldx #mnembuf +bscmploop ldb ,x+ + cmpb ,y+ + bne bscmpexit ;Characters don't match? + deca + bne bscmploop + jmp mnemfound ;We found the mnemonic. +bscmpexit ldb temp2 + bcc bscmplower + decb + stb temp+1 ;mnembuf<table, adjust high limit. + bra bsrchloop +bscmplower incb + stb temp ;mnembuf>table, adjust low limit. + bra bsrchloop +invmnem ldx #invmmsg + jmp asmerrvec +* Stage 3: Perform routine depending on category code. +mnemfound clr uncert + ldy addr + lda 5,u + asla + ldx #asmtab + jsr [a,x] + sty addr + rts +asmtab fdb onebyte,twobyte,immbyte,lea + fdb sbranch,lbranch,lbra,acc8 + fdb dreg1,dreg2,oneaddr,tfrexg + fdb pushpul,pseudovec + +putbyte stb ,y+ + rts +putword std ,y++ + rts + +onebyte ldb 7,u ;Cat 0, one byte opcode w/o operands RTS + bra putbyte +twobyte ldd 6,u ;Cat 1, two byte opcode w/o operands SWI2 + bra putword +immbyte ldb 7,u ;Cat 2, opcode w/ immdiate operand ANDCC + bsr putbyte + jsr scanops + ldb amode + cmpb #1 + lbne moderr + ldb operand+1 + bra putbyte +lea ldb 7,u ;Cat 3, LEA + bsr putbyte + jsr scanops + lda amode + cmpa #1 + lbeq moderr ;No immediate w/ lea + cmpa #3 + lbhs doaddr + jsr set3 + lda #$8f + sta postbyte + lda #2 + sta opsize ;Use 8F nn nn for direct mode. + jmp doaddr +sbranch ldb 7,u ;Cat 4, short branch instructions + bsr putbyte + jsr startop + leax -1,x + jsr exprvec + lbeq exprerr + jmp shortrel +lbranch ldd 6,u ;Cat 5, long brach w/ two byte opcode + bsr putword +lbra1 jsr startop + leax -1,x + jsr exprvec + lbeq exprerr + jmp longrel +lbra ldb 7,u ;Cat 6, long branch w/ one byte opcode. + jsr putbyte + bra lbra1 +acc8 lda #1 ;Cat 7, 8-bit two operand instructions ADDA + sta opsize + jsr scanops + jsr adjopc + jsr putbyte + jmp doaddr +dreg1 lda #2 ;Cat 8, 16-bit 2operand insns 1byte opc LDX + sta opsize + jsr scanops + jsr adjopc + jsr putbyte + jmp doaddr +dreg2 lda #2 ;Cat 9, 16-bit 2operand insns 2byte opc LDY + sta opsize + jsr scanops + jsr adjopc + lda 6,u + jsr putword + jmp doaddr +oneaddr jsr scanops ;Cat 10, one-operand insns NEG..CLR + ldb 7,u + lda amode + cmpa #1 + lbeq moderr ;No immediate mode + cmpa #3 + bhs oaind ;indexed etc + lda opsize + deca + beq oadir + addb #$10 ;Add $70 for extended direct. +oaind addb #$60 ;And $60 for indexed etc. +oadir jsr putbyte ;And nothing for direct8. + jmp doaddr +tfrexg jsr startop ;Cat 11, TFR and EXG + leax -1,x + ldb 7,u + jsr putbyte + jsr findreg + ldb ,u + aslb + aslb + aslb + aslb + stb postbyte + ldb ,x+ + cmpb #',' + lbne moderr + jsr findreg + ldb ,u + orb postbyte + jmp putbyte +pushpul jsr startop ;Cat 12, PSH and PUL + leax -1,x + ldb 7,u + jsr putbyte + clr postbyte +pploop jsr findreg + ldb 1,u + orb postbyte + stb postbyte + ldb ,x+ + cmpb #',' + beq pploop + leax -1,x + ldb postbyte + jmp putbyte +pseudo ldb 7,u ;Cat 13, pseudo oeprations + aslb + ldx #pseudotab + jmp [b,x] +pseudotab fdb pseudoend,dofcb,dofcc,dofdb + fdb doorg,dormb,pseudoend,pseudoend +dofcb jsr startop + leax -1,x +fcbloop jsr exprvec + lbeq exprerr + jsr putbyte + ldb ,x+ + cmpb #',' + beq fcbloop +pseudoend rts +dofcc jsr startop + tfr b,a ;Save delimiter. +fccloop ldb ,x+ + beq pseudoend + pshs a + cmpb ,s+ + beq pseudoend + jsr putbyte + bra fccloop +dofdb jsr startop + leax -1,x +fdbloop jsr exprvec + lbeq exprerr + jsr putword + ldb ,x+ + cmpb #',' + beq fdbloop + rts +doorg jsr startop + leax -1,x + jsr exprvec + lbeq exprerr + tfr d,y + rts +dormb jsr startop + leax -1,x + jsr exprvec + lbeq exprerr + leay d,y + rts + + +* Adjust opcdoe depending on mode (in $80-$FF range) +adjopc ldb 7,u + lda amode + cmpa #2 + beq adjdir ;Is it direct? + cmpa #3 + bhs adjind ;Indexed etc? + rts ;Not, then immediate, no adjust. +adjind addb #$20 ;Add $20 to opcode for indexed etc modes. + rts +adjdir addb #$10 ;Add $10 to opcode for direct8 + lda opsize + deca + bne adjind ;If opsize=2, add another $20 for extended16 + rts + +* Start scanning of operands. +startop ldx temp3 + clr amode + jmp skipspace + +* amode settings in assembler: 1=immediate, 2=direct/extended, 3=indexed +* etc. 4=pc relative, 5=indirect, 6=pcrelative and indirect. + +* This subroutine scans the assembler operands. +scanops bsr startop + cmpb #'[' + bne noindir + lda #5 ;operand starts with [, then indirect. + sta amode + ldb ,x+ +noindir cmpb #'#' + lbeq doimm + cmpb #',' + lbeq dospecial + andb #CASEMASK ;Convert to uppercase. + lda #$86 + cmpb #'A' + beq scanacidx + lda #$85 + cmpb #'B' + beq scanacidx + lda #$8B + cmpb #'D' + bne scanlab +scanacidx ldb ,x+ ;Could it be A,X B,X or D,X + cmpb #',' + bne nocomma + sta postbyte + clr opsize + jsr set3 + jsr scanixreg + bra scanend +nocomma leax -1,x +scanlab leax -1,x ;Point to the start of the operand + jsr exprvec + lbeq exprerr + std operand + tst uncert + bne opsz2 ;Go for extended if operand unknown. + subd dpsetting + tsta ;Can we use 8-bit operand? + bne opsz2 + inca + bra opsz1 +opsz2 lda #2 +opsz1 sta opsize ;Set opsize depending on magnitude of op. + lda amode + cmpa #5 + bne opsz3 ;Or was it indirect. + lda #2 ;Then we have postbyte and opsize=2 + sta opsize + lda #$8F + sta postbyte + bra opsz4 +opsz3 lda #2 + sta amode ;Assume direct or absolute addressing +opsz4 ldb ,x+ + cmpb #',' + lbeq doindex ;If followed by, then indexed. +scanend lda amode + cmpa #5 + blo scanend2 ;Was it an indirect mode? + lda postbyte + ora #$10 ;Set indirect bit. + sta postbyte + ldb ,x+ + cmpb #']' ;Check for the other ] + lbeq moderr +scanend2 rts +doimm jsr exprvec ;Immediate addressing. + lbeq exprerr + std operand + lda amode + cmpa #5 + lbeq moderr ;Inirect mode w/ imm is illegal. + lda #$01 + sta amode + rts +dospecial jsr set3 + clr opsize + clra +adecloop ldb ,x+ + cmpb #'-' + bne adecend + inca ;Count the - signs for autodecrement. + bra adecloop +adecend leax -1,x + cmpa #2 + lbhi moderr + tsta + bne autodec + clr postbyte + jsr scanixreg + clra +aincloop ldb ,x+ + cmpb #'+' + bne aincend + inca + bra aincloop ;Count the + signs for autoincrement. +aincend leax -1,x + cmpa #2 + lbhi moderr + tsta + bne autoinc + lda #$84 + ora postbyte + sta postbyte + bra scanend +autoinc adda #$7f + ora postbyte + sta postbyte + bra scanend +autodec adda #$81 + sta postbyte + jsr scanixreg + lbra scanend +doindex clr postbyte + jsr set3 + ldb ,x+ + andb #CASEMASK ;Convert to uppercase. + cmpb #'P' + lbeq dopcrel ;Check for PC relative. + leax -1,x + clr opsize + bsr scanixreg + ldd operand + tst uncert + bne longindex ;Go for long index if operand unknown. + cmpd #-16 + blt shortindex + cmpd #15 + bgt shortindex + lda amode + cmpa #5 + beq shortind1 ;Indirect may not be 5-bit index + ;It's a five-bit index. + andb #$1f + orb postbyte + stb postbyte + lbra scanend +shortindex cmpd #-128 + blt longindex + cmpd #127 + bgt longindex +shortind1 inc opsize + ldb #$88 + orb postbyte + stb postbyte + lbra scanend +longindex lda #$2 + sta opsize + ldb #$89 + orb postbyte + stb postbyte + lbra scanend +dopcrel ldb ,x+ + andb #CASEMASK ;Convert to uppercase + cmpb #'C' + blo pcrelend + cmpb #'R' + bhi pcrelend + bra dopcrel ;Scan past the ,PCR +pcrelend leax -1,x + ldb #$8C + orb postbyte ;Set postbyte + stb postbyte + inc amode ;Set addr mode to PCR + lbra scanend + +* Scan for one of the 4 index registers and adjust postbyte. +scanixreg ldb ,x+ + andb #CASEMASK ;Convert to uppercase. + pshs x + ldx #ixregs + clra +scidxloop cmpb ,x+ + beq ixfound + adda #$20 + bpl scidxloop + jmp moderr ;Index register not found where expected. +ixfound ora postbyte + sta postbyte ;Set index reg bits in postbyte. + puls x + rts + +* This routine sets amode to 3, if it was less. +set3 lda amode + cmpa #3 + bhs set3a + lda #3 + sta amode +set3a rts + +* This subroutine lays down the address. +doaddr lda amode + cmpa #3 + blo doa1 + ldb postbyte + jsr putbyte + lda amode + anda #1 + beq doapcrel ;pc rel modes. +doa1 lda opsize + tsta + beq set3a + deca + beq doa2 + ldd operand + jmp putword +doa2 ldb operand+1 + jmp putbyte +doapcrel sty addr + ldd operand + subd addr + subd #1 + tst uncert + bne pcrlong + cmpd #-128 + blt pcrlong + cmpd #-127 + bgt pcrlong + lda #1 + sta opsize + jmp putbyte +pcrlong subd #1 + leay -1,y + inc postbyte + pshs d + ldb postbyte + jsr putbyte + lda #2 + sta opsize + puls d + jmp putword + +* This routine checks and lays down short relative address. +shortrel sty addr + subd addr + subd #1 + cmpd #-128 + blt brerr + cmpd #127 + bgt brerr + jsr putbyte + lda #4 + sta amode + lda #1 + sta opsize + rts +* This routine lays down long relative address. +longrel sty addr + subd addr + subd #2 + jsr putword + lda #4 + sta amode + lda #2 + sta opsize + rts + +brerr ldx #brmsg + jmp asmerrvec +exprerr ldx #exprmsg + jmp asmerrvec +moderr ldx #modemsg + jmp asmerrvec +asmerr pshs x + jsr xabortin + puls x + jsr outcount + jsr putcr + lds savesp + jmp cmdline + +* Find register for TFR and PSH instruction +findreg ldb #12 + pshs y,b + ldu #asmregtab +findregloop tfr x,y + lda #3 +frcmps ldb ,u + cmpb #' ' + bne frcmps1 + ldb ,y + cmpb #'A' + blt frfound +frcmps1 ldb ,y+ + andb #CASEMASK + cmpb ,u+ + bne frnextreg + deca + bne frcmps + inca + bra frfound +frnextreg inca + leau a,u + dec ,s + bne findregloop + lbra moderr +frfound leau a,u + tfr y,x + puls y,b + rts + +* This is the code for the A command, assemble instructions. +* Syntax: Aaddr +asm ldx #linebuf+1 + jsr scanhex + std addr + inc disflg + + +asmloop ldy #0 + sty length + ldd addr + pshs d + jsr dis1 ;display unassembled line + ldd addr + std nxtadd + + puls d + std addr + +* ldd addr +* jsr outd + + ldb #TAB + jsr putchar ;Print TAB + ldx #linebuf + ldb #128 + jsr getline ;Get new line + tstb + beq next + +*** beq asmend ;Exit on empty line. + abx + clr ,x ;Make line zero terminated. + ldx #linebuf + lda ,x + cmpa #'.' + beq asmend + jsr asminstr + bra asmloop + +next ldd nxtadd + std addr + bra asmloop + +asmend clr disflg + jmp cmdline + + +* Jump table for monitor routines that are usable by other programs. + org $ffc0 + jmp outbyte + jmp outd + jmp scanbyte + jmp scanhex + jmp scanfact + jmp asminstr + + +* Interrupt vector addresses at top of ROM. Most are vectored through jumps +* in RAM. + org $fff2 + fdb swi3vec + fdb swi2vec + fdb firqvec + fdb irqvec + fdb swivec + fdb nmivec + fdb reset + + end