VUBug: AN M68000 MONITOR PROGRAM I. Introduction. VUBug is a primitive single user monitor program designed to interface the user to the "Raymatic" M68000 development board designed by Raymond Carr at Vanderbilt University in 1988. The monitor program itself was originally written by Edward M. Carter also while at Vanderbilt in 1983. This documentation relates to the 1988 version of the program, about two thirds of which is new. The new stuff was added by Russell G. Brown, then of Vanderbilt, but lately of Cornell Computer Science. It allows the user to perform such operations as are necessary to develop and debug M68000 assembly programs in conjunction with a host computer running an M68000 assembler which is capable of generating object code in the Motorola S-record format. Some functions provided by VUBUG are load from host, dump memory, disassemble memory, and run at address. Feel free to distribute this source and documentation, but make sure that the copyright and like information stays on it. Also, please make sure that any modified version of this program which you may distribute is obviously marked as being modified. II. Running VUBug VUbug comes up running as soon as power is applied to the system. It asserts its presence by printing the following message: M68000 Monitor VUBug Version 4.0 27 April, 1988 !_ If there is anything wrong with the system RAM, it will instead respond RAM Error!!!! Assuming that a RAM error doesn't happen, you can now begin entering commands. III. Getting Started The first thing that you will want to do is to load and execute an assembly language program using VUBug. The following is an example interactive execution session: 1. Turn on the system. The VUBug boot message prints at the terminal. 2. Type 'e'. VUBug responds "Terminal Mode:". 3. Log into the host system. Enter vi and type in the following program: org $4400 move.l #$00000004,d0 movea.l #$000019ca,a3 adda.w d0,a3 move.l a3,d0 trap #$06 trap #$0 end 4. Write and quit from vi. Assemble the program by typing mas68k -l . where progname is the name of your sample program. 5. Examine the listing file produced by mas68k to see the source and object code together. The listing file is called . 6. Type 'cat ' but DO NOT! type a carriage return. 7. type ctrl-L. VUBug will exit terminal mode, feed a carriage return to the host, and accept an Srec format object file. 8. You are now back in VUBug. Type 'a 4400'. You will see an assembly listing which is equivalent to your source code, except that it has values substituted for all labels. There will be a number of garbage lines following the program. disregard these. 9. Type 'g 4400'. This is the command meaning "go at $4400". VUBug responds with the following: Program: 000019ce ! This is approximately how all debugging sessions should begin. Once you have become more familiar with VUBug, you will learn shortcuts and enhancements, but the commands already used will serve for a start. IV. VUBug Commands This section contains the full, alphabetic listing of the commands provided in VUBug. For information on how to get help for commands while in VUBug, see the section on 'h'. A - Assembly Listing A provides a source code listing of memory locations specified in one of the following ways: A List 20 instructions from last examined address. A xxxx List 20 instructions from address xxxx. A xxxx,yyyy List from xxxx to yyyy. B - Set/Remove Breakpoints B permits the setting and removing of breakpoints in a user program. B is invoked as follows: B List all breakpoints. B+xxxx Add a breakpoint at address xxxx. B-xxxx Remove a breakpoint at xxxx. B# Remove all breakpoints. C - Copy Memory C allows the copying of a data block from one location to another. It is called using: C xxxx=yyyy,zzzz. This copies memory from a block which starts at yyyy and ends at zzzz to a block starting at xxxx. NOTE: the copy routine works from bottom to top. Therefore care must be taken when copying between blocks that share address space. D - Dump Memory D is used to provide a hex dump of memory. Memory is printed out in lines consisting of an address, 16 hex values, and the ascii representation of such of those values as have printable characters. The format for calling D is as follows: D Dump 64 bytes from last examined location. D xxxx Dump 64 bytes from xxxx. D xxxx,yyyy Dump bytes from xxxx to yyyy. E - Enter terminal emulator mode When E is entered, VUBug enters a passthrough mode in which any key entered at the keyboard is passed through to the host, and vice versa. This is true for all characters except for ctrl-X, which causes VUBug to exit terminal emulator mode, and ctrl-L, which is the same as ctrl-X, except that it causes VUBug to enter load mode. E is invoked as follows: E G - Start user program G is the VUBug command to start a user program running. A user program which is properly designed to end will have as its last executed line trap #$00 G is called in one of the following ways: G Go from start address in the last executed L command. Same as G. G xxxx Go from address xxxx. H - Print help messages. H is used to print a simple message (consisting mostly of instruction syntax) to the terminal. It is called with: H Prints a list of commands for which help is available. Hx Prints the long help message for command x. If x is nonexistant, Hx acts like H. L - Load user program from host L causes VUBug to accept an S-record format object file from the host. It is called in one of the following ways: L Load from host with no offset. ctrl-L Same as L but invoked from emulator mode. L xxxx Load from host with offset xxxx. M - Enter memory update mode M invokes a submode of VUBug in which modifications to memory locations can be made. M is invoked as follows: M Start memory mode. M xxxx Start memory mode at xxxx. Memory mode subcommands are the following: .xxxx Set pointer to location xxxx. =xx Update current location to xx. ,xx Increment pointer, then update. + Increment pointer. - Decrement pointer Print current pointer and value. Typing any other character in memory update mode causes an exit back into VUBug proper. P - Prototype commands in RAM P allows the user to create new command subroutines in RAM and call them without having to burn new ROMs. This is significant in that ordinarily user programs cannot make use of the interrupt routines and other subroutines provided in VUBug. P is set up to allow a user routine to make use of these subroutines. It is invoked as follows: Px xxxx Load address xxxx for prototype command x. Px Execute prototype command x. Note that x must be a 1, 2, or 3. R - Enter register examine/update mode R invokes a submode of VUBug in which registers may be examined and changed. It is called in the following way: R Start register mode. R xx Start mode at register xx, where xx is one of: SR/_sr - status register, PC/_pc - program counter, dx - data register 0 - 7, ax - address reg. 0 - 7. Register examine/update commands are as follows: .xx Set pointer to register xx. =xxxxxxxx Set current register to xxxxxxxx. Print all registers. Any other character entered in register submode causes an exit to VUBug. S - Single step mode In single step mode, a Go command causes VUBug to execute a single instruction and then return to the prompt, allowing registers to be examined and changed between instructions. S is called in one of two ways: S+ Turn on single step mode. S- Turn off single step mode. T - Trace mode In trace mode, a Go command causes VUBug to execute a program, printing out the PC after each instruction. This permits tracing of a program's path. It is called as follows: T+ Turn on trace mode. T- Turn off trace mode. V. U - Upload user program from terminal U allows VUBug to upload an S-record format object file from the terminal. This allows the user to connect the 68000 board to a microcomputer, using it as both terminal and host. Upload is invoked with one of the following commands: U Upload from terminal with no offset. U xxxx Upload from terminal with offset xxxx. V. Troubleshooting There is not a whole lot that can go wrong with VUBug. Most of the possible difficulties actually have their roots in hardware. If a RAM error is indicated at boot-up time, then one of the system RAM chips needs replacing. If no boot-up message is printed, then something is wrong with one of the following: the terminal, the terminal cable, the ACIAs on the development board, the system RAM, or the VUBug ROM. If an error is found in VUBug's performance, the thing to do is to document carefully when and where the bug appears, and report the problem to the nearest digital electronics professor. VI. Caveats A number of things should be taken into account when using VUBug. Most of these have to do with the memory map. Number one is that hitting the reset button invokes the RAM test program which CLEARS THE RAM! For this reason, ctrl-C should be used to recover control from a lost program. The memory map for the board looks like this: 0000 - 3FFF System ROM 4000 - 43FF System RAM 4400 - 7FFF User RAM 8000 - 803E PI/T (68230) registers EVEN ONLY! A000 Load Port Status Register A002 Load Port Data Register C000 Terminal Port Status Register C002 Terminal Port Data Register Note that the PI/T and ACIA registers are on even only locations. Attempting to write to a peripheral chip on an odd location will lock up the system. Similarly, writing to system RAM can cause unexpected results, up to and including locking up the system. VII. Conclusion VUBug 4.0, mas68k, and the Raymatic development board form an effective development environment for M68000 assembly language programs. While they cannot substitute for professional development/analysis systems, it is nevertheless possible to complete considerable software endeavors with a reasonable minimum of difficulty. ----------------------------CUT HERE------------------------------------------- ; NOTES : PORTED TO PC BY DAVE GOODMAN ; : PORTED TO RAYMATIC 68K BOARD BY RUSSELL G. BROWN ; ASSEMBLE: mas68k -l vubug.68k ; : ASSEMBLER WILL TAKE FILE vubug.68k AND ; : WILL CREATE vubug.o, vubug.l ; VER 3.0 : VUBUG VER 3.0 PORTEd TO PC FOR ASSEMBLE USING a68K 9/84 ; VER 3.1 : VUBUG VER 3.1 FIXED FOR VU68K BOARD 10/86 ; VER 4.0 : VUBUG VER 4.0 PORTED TO RAYMATIC 68K BOARD 4/88 ;******************************************* ;* * ;******** V U B U G ******** ;* * ;* Copyright (C) 1983, 1988 * ;* Vanderbilt Univ. * ;* Comp. Sci. dept. * ;* PO Box 1679 * ;* Station B * ;* Nashville, Tenn. * ;* 37235 * ;* * ;* author: * ;* Edward M. Carter * ;* * ;******************************************* ;* * ;* This software was prepared for distri- * ;* bution by Russell G. Brown. Please * ;* note that it is being distributed at * ;* the request of several readers of the * ;* usenet newsgroup comp.sys.m68k. It has * ;* no warranty of any sort, at all. I * ;* think that the code is fairly self * ;* explanatory. Good luck in modifying * ;* it to work on whatever application you * ;* may have. * ;******************************************* ;* * ;* although the information contained here-* ;* in, as well as any information provided * ;* relative thereto, has been carefully re-* ;* viewed and is believed correct, Vander- * ;* bilt University assumes no liability * ;* arising out of its application or use, * ;* neither does it convey any license under* ;* its patent rights nor the rights of * ;* others. * ;* * ;******************************************* ;* * ;* The commands supported are as follows: * ;* * ;* m - examine/update memory * ;* l - load program from host * ;* u - load program from terminal * ;* d - display blocks of memory * ;* t - single-step a program * ;* s - single-step * ;* g - start a user mode program * ;* - short g command * ;* b - set/remove breakpoints * ;* r - examine/update registers * ;* p - prototype commands * ;* e - terminal emulator mode * ;* c - copy memory blocks * ;* x - print help messages * ;* * ;* Sub-command under each of these commands* ;* are shown in the source code for each * ;* command. * ;* * ;******************************************* ; ; Queue structure ; org $0 head = $0000 tail = $0002 count = $0004 queue = $0006 ; ; Breakpoint structure ; org $0 instr = $0000 iloc = $0002 ; ; The following is the exception vector ; table for the monitor. There should be ; no further "org"s to address contained ; herein as this will destroy the vector ; for iterrupts, breakpoints... ; org $0 ;Reset Vector dc.l stack ;system stack dc.l start ;initial pc dc.l abhlr ;bus error dc.l abhlr ;address error dc.l bhlr ;illegal instruction vector dc.l ghlr ;zero divide dc.l ghlr ;chk dc.l ghlr ;trapv dc.l phlr ;privileged instruction trap dc.l thlr ;trace handler dc.l bhlr ;emulator trap 1010 dc.l bhlr ;emulator trap 1111 org $3c dc.l ghlr ;uninitialized iterrupt org $60 dc.l ghlr ;spurious iterrupt dc.l lpint ;download-line vector dc.l inint ;terminal vector dc.l uav3 ;user auto-vectors dc.l uav4 dc.l uav5 dc.l uav6 dc.l uav7 dc.l texit ;exit dc.l tgetb ;getb dc.l tgetw ;getw dc.l tgetl ;getl dc.l twrtb ;wrtb dc.l twrtw ;wrtw dc.l twrtl ;wrtl dc.l tgetc ;getc dc.l twrts ;wrts dc.l twrtc ;wrtc dc.l tcrlf ;crlf utrpb: dc.l utrapb ;user trap vectors utrpc: dc.l utrapc utrpd: dc.l utrapd utrpe: dc.l utrape utrpf: dc.l utrapf ; ;************************************ ;* * ;* Monitor data area * ;* * ;************************************ ; org $4000 utrapb: dc.l $00000000 utrapc: dc.l $00000000 utrapd: dc.l $00000000 utrape: dc.l $00000000 utrapf: dc.l $00000000 userv1: dc.l $00000000 userv2: dc.l $00000000 userv3: dc.l $00000000 userv4: dc.l $00000000 userv5: dc.l $00000000 uav3: dc.l $00000000 uav4: dc.l $00000000 uav5: dc.l $00000000 uav6: dc.l $00000000 uav7: dc.l $00000000 sarea: dcb.w $80,$0000 ;system stack stack = . bktab: dcb.w $0a,$0000 ;breakpoint table _sr: dc.w $0000 ;register save area _pc: dc.l $00000000 dr0: dc.l $00000000 dr1: dc.l $00000000 dr2: dc.l $00000000 dr3: dc.l $00000000 dr4: dc.l $00000000 dr5: dc.l $00000000 dr6: dc.l $00000000 dr7: dc.l $00000000 ar0: dc.l $00000000 ar1: dc.l $00000000 ar2: dc.l $00000000 ar3: dc.l $00000000 ar4: dc.l $00000000 ar5: dc.l $00000000 ar6: dc.l $00000000 ar7: dc.l $00000000 ptab: dcb.w $3,0000 ;prototype table rexam: dc.w $0000 ;register examination pointer exam: dc.w $0000 ;memory examination pointer t1: dc.w $0000 ;temporary work area t2: dc.w $0000 t3: dc.w $0000 t4: dc.w $0000 t5: dc.w $0000 ctrls: dc.w $0000 ;ctrl-s,ctrl-q flag bkptf = .-1 ;breakpoint flag lbuff: dcb.w $0b,0000 ;load buffer ibuff: dcb.w $0b,0000 ;terminal buffer users: dcb.w $80,0000 ;users stack area ustck = . aend: dc.w $0000 siz: dc.w $0000 writm: dc.w $0000 echo: dc.w $0000 ;terminal port echo flag ; ;Terminal port ; ttyst = $0000c000 ttyd = $0000c002 ; ;Load port ; lpst = $0000a000 lpd = $0000a002 ;+++++++++++++++++++++++++++++++++++++++++ ; + ; Start of monitor + ; + ;+++++++++++++++++++++++++++++++++++++++++ org $C0 csc = $1b45 ;clear screen (h-19) cr = $0d lf = $0a nul = $00 howdy: dc.w csc .ascii "M68000 Monitor VUBUG " .ascii "Version 4.0 11 August, 1988" rnn0: dc.b cr,lf,lf,nul bcomm: .ascii ": Bad Command" dc.b cr,lf,nul ; ; These are seven user interrupt vectors ; which must remain at address $0100. ; Please ensure that they do ; vect1: dc.l $userv1 vect2: dc.l $userv2 vect3: dc.l $userv3 vect4: dc.l $userv4 vect5: dc.l $userv5 ssri: dc.w $2000 ;supervisor SR ssrn: dc.w $2700 ;same w/o interrupts prmp: dc.b cr,lf dc.b '!' ; command promdt dc.b nul start: move.b #$03,ttyst ;setup ports move.b #$03,lpst move.b #$15,ttyst move.b #$15,lpst move.w #$ffff,d0 ;load $ffff for first memory test movea.w #$4000,a0 ;start at $4000 move.w #$1fff,d2 ;$2000 words of ram mt1: move.w d0,(a0) ;store value move.w (a0)+,d1 ;load it back cmp.w d0,d1 bne memerr ;if not the same, memory error. dbf d2,mt1 move.w #$0000,d0 ;load $0000 for second mem test movea.w #$4000,a0 move.w #$1fff,d2 mt2: move.w d0,(a0) move.w (a0)+,d1 bne memerr ;if not zero, memory error. dbf d2,mt2 bra gwan memerr: lea memnot,a0 ;RAM doesn't work right. bsr writs bra gwan memnot: .ascii "RAM ERROR!!!!" dc.b cr,lf,nul gwan: lea ibuff,a1 ;setup buffers move.w #$0000,head(a1) move.w #$ffff,tail(a1) move.w #$0000,count(a1) lea lbuff,a1 move.w #$0,head(a1) ;set queue for lp move.w #$ffff,tail(a1) move.w #0,count(a1) move.w #0,exam ;initialize control variables move.b #0,ctrls move.b #0,bkptf moveq #$4,d0 ;clear breakpoint table lea bktab,a1 slp: move.l #0,(a1)+ dbf d0,slp move.w #0,_sr ;clear register save area move.l #$10,d0 lea _pc,a0 slp1: move.l #0,(a0)+ dbf d0,slp1 lea ustck,a0 ;set user stack pointer move.l a0,ar7 lea sarea,a0 ;clear system stack moveq #$3f,d0 slp2: move.l #0,(a0)+ dbf d0,slp2 done: move.w ssri,sr ;enable interrupts at CPU lea howdy,a0 ;say hello bsr writs move.b #$95,ttyst ;enable interrupts from ports move.b #$95,lpst bset #$00,echo ;turn on terminal echo bra comm ;enter command loop ; ; Generalized write facility writes 1 byte ; passed in d0 to tty. ; writ: btst #0,ctrls ;Is ctrl-s active beq cwrit ;no, so write it stop #$2000 ;yes, so wait on next character bra writ ;when awakened try to echo cwrit: move.b d0,ttyd ;write the character to port writa: move.b ttyst,d0 ;sample control register till done btst #$1,d0 beq writa rts ; ; Generalized write facility writes 1 byte ; passed in d0 to serial port. ; writu: move.b d0,lpd ;write it writp: move.b lpst,d0 ;wait for completion btst #$1,d0 beq writp rts ; ; Generalized routine to write a string which ; must terminate in a null ; writs: move.b (a0)+,d0 ;a0 is address of string beq dwrts bsr writ bra writs dwrts: rts ; ;Generalized routine to write ;a word, byte or long word. ; writb: move.w #$1,t1 ;t1 is the number of bytes bra wr writw: move.w #$3,t1 bra wr writl: move.w #$7,t1 wr: movem.l #$6082,-(a7) ;save registers d1,d2,a0,a6 move.w t1,d2 ;set count move.b #$00,t5+1 ;set a null at end lea t5+1,a6 ;use temps as a stack alp: move.b d0,d1 ;make each hex digit a and.b #$0f,d1 ;writable ascii byte cmp.b #$0a,d1 ;check for abcdef blt or3 or.b #$40,d1 sub.b #$09,d1 bra m1 or3: or.b #$30,d1 ;set high-order bits m1: move.b d1,-(a6) ;put on stack lsr.l #$4,d0 ;get next hex digit dbf d2,alp movea.w a6,a0 ;write the stack with writs bsr writs movem.l (a7)+,#$4106 ;restore registers d1,d2,a0,a6 rts ; ; Interrupt handler for the keyboard ; interrupt. It simply stashes the input ; character in a buffer pointed to by a1. ; inint: move.w ssrn,sr ;disable interrupts movem.l #$e060,-(a7) ;save registers d0,d1,d2,a1,a2 move.b ttyd,d1 ;get the character andi.b #$7f,d1 ;mask out the parity, if any btst #$3,bkptf ;In emulator mode ? beq incmp ;No, so continue cmp.b #$0c,d1 ;ctrl-l ? beq inld ;yes, so load cmp.b #$18,d1 ;No, is it a ctrl-x ? bne inwru ;No, so write it inld: bclr #$3,bkptf ;Exit emulator mode lea emudn,a1 ;set up return move.l a1,$16(a7) ;put return deep in stack cmp.b #$0c,d1 ;ctrl-l ? bne out ;No bra incmp ;check for ctrl-s or q inwru: move.b d1,d0 ;write to host bsr writu bra out incmp: cmp.b #$03,d1 ;check for ctrl-c beq rstrt cmp.b #$13,d1 ;check for ctrl-s bne ctrlq move.b #$1,ctrls bra out ctrlq: cmp.b #$11,d1 ;check for ctrl-q bne c1 move.b #$0,ctrls bra out c1: lea ibuff,a1 ;get buffer address cmpi.b #$10,count(a1) ;overflow ? blt cont ;No bra out ;Yes, so ignore character cont: addq.b #$1,tail(a1) ;add chacter to buffer addq.b #$1,count(a1) ;add 1 to count andi.b #$0f,tail(a1) ;modulo-16 move.w tail(a1),d2 ;get offset of new entry ror.w #$08,d2 ;in lower 8 bits of d2 andi.w #$ff,d2 ;mask off what's left lea queue(a1),a1 ;get address of queue move.b d1,$0(a1,d2:w) ;move byte into buffer btst #$00,echo ;is the echo turned on? beq out ;if not, skip the echo, move.b d1,d0 ;else setup for echo bsr writ out: movem.l (a7)+,#$0607 ;reset registers d0,d1,a1,a2 rte ; ; Interrupt handler for the load port. ; It stashes the character in the buffer ; pointed to by a1. ; lpint: move.w ssrn,sr ;same as above but less complex movem.l #$e060,-(a7) ;registers d0,d1,d2,a1,a2 move.b lpd,d1 andi.b #$7f,d1 btst #$3,bkptf beq lplea move.b d1,d0 ;echo for emulator mode bsr writ bra lout lplea: lea lbuff,a1 ;queue a character cmpi.b #$10,count(a1) blt lcont bra out lcont: addq.b #$1,tail(a1) addq.b #$1,count(a1) andi.b #$0f,tail(a1) move.w tail(a1),d2 ror.w #$08,d2 andi.w #$ff,d2 lea queue(a1),a1 move.b d1,$0(a1,d2:w) lout: movem.l (a7)+,#$0607 ;regs d0,d1,d2,a1,a2 rte ; ; Lgch - get a character from the serial port ; queue. If none available then wait for one ; ; lgch: movem.l #$2060,-(a7) ;save registers d2,a1,a2 lagn: ori.w #$0700,sr ;diable interrupts lea lbuff,a1 ;point at buffer move.w count(a1),t1 ;see if there is a cahracter beq lwait ;No, so wait move.w head(a1),d2 ;Yes, find it and update ror.w #$08,d2 andi.w #$00ff,d2 addq.b #$1,head(a1) subq.b #$1,count(a1) andi.b #$0f,head(a1) lea queue(a1),a1 ;Return character move.b $0(a1,d2:w),d0 andi.w #$f8ff,sr ;enable interrupts and movem.l (a7)+,#$0604 ;regs d2,a1/a2 rts lwait: stop #$2000 bra lagn ; ; Rstrt - restart from control c ; rstrt: movem.l (a7)+,#$0603 ;rest regs d0,d1,a1,a2 frm intrpt hndlr movem.l #$ffff,dr0 ;save registers d0-a7 move.l usp,a0 ;save user stack pointer move.l a0,ar7 move.w (a7)+,_sr ;save status register from stack move.l (a7)+,_pc ;save program counter from stack pea comm ;fake a return to command loop move.w ssri,-(a7) ;fake a new status register rte ; ; Getch - get a character from the input ; queue. If none available then wait for it ; getch: movem.l #$2060,-(a7) ;same as lgch above d2,a1,a2 tryag: ori.w #$0700,sr lea ibuff,a1 move.w count(a1),t1 beq wait moveq #$0,d0 movea.w head(a1),d2 ror.w #$08,d2 andi.w #$00ff,d2 addq.b #$1,head(a1) subq.b #$1,count(a1) andi.b #$0f,head(a1) lea queue(a1),a1 move.b $0(a1,d2:w),d0 andi.w #$f8ff,sr movem.l (a7)+,#$0604 ;regs d2,a1,a2 rts wait: stop #$2000 bra tryag ; ; CRLF - write a carriage return and ; line feed. ; cf: dc.b cr,lf,nul,nul crlf: lea cf,a0 bsr writs rts ; ; Generalized number fetcher ; getb: move.w #$1,t1 ;t1 is byte count bra gb getw: move.w #$3,t1 bra gb getl: move.w #$7,t1 gb: movem.l #$6000,-(a7) ;save registers d1,d2 move.w t1,d2 moveq #$0,d1 blp: jsr (a0) ;a0 is address of which.. ;routine to use for getting, i.e. ;serial or terminal port cmp.b #$3a,d0 ;check for abcdef blt n1 add.b #$09,d0 n1: and.b #$0f,d0 asl.l #$4,d1 ;place in next hex didgit or.b d0,d1 dbf d2,blp move.l d1,d0 ;setup return in d0 movem.l (a7)+,#$0006 ;restore registers d1,d2 rts ; ; command interpreter ; ctab: dc.w $4d00 ;m - memory update dc.w mem dc.w $4c00 ;l - load from host (S-format) dc.w load dc.w $0c00 ;ctrl-l - load from host (S-format) dc.w lnoof dc.w $5500 ;u - upload program from terminal port dc.w uload dc.w $4400 ;d - dump contents of memory dc.w dump dc.w $5300 ;s - single step dc.w singl dc.w $5400 ;t - trace a program's path dc.w trace dc.w $4700 ;g - start user program dc.w go dc.w $0d00 ; - short g command dc.w ggo dc.w $4500 ;e - enter terminal emulator mode dc.w emul dc.w $4200 ;b - set/remove breakpoints dc.w bkpt dc.w $4300 ;c - copy memory blocks dc.w copy dc.w $5200 ;r - display/modify registers dc.w regs dc.w $5000 ;p - prototype commands dc.w proto dc.w $4800 ;h - display help messages dc.w help dc.w $4100 ;a - assembly listing dc.w assem ; ; Structure of each entry is command ; (com) and address of servicing routine ; (code) ; com = $0 code = $2 comm: lea prmp,a0 ;write prompt bsr writs bsr getch ;get command from buffer and.b #$5f,d0 ;make upper-case lea ctab-4,a2 ;set-up search of ctab moveq #$0f,d2 ;count is one less clp: addq.w #4,a2 cmp.b com(a2),d0 dbeq d2,clp bne bad ;search fails movea.w code(a2),a2 ;get address for success jsr (a2) ;go to it bra comm ;loop back for next command bad: lea bcomm,a0 ;say it's bad and return bsr writs bra comm ; ; Copy - Copy memory blocks ; ;*************************************** ;* * ;* Copy is invoked as follows: * ;* * ;* c xxxx=yyyy,zzzz * ;* * ;* Copy locations yyyy thru zzzz to * ;* locations xxxx and upward. * ;* * ;*************************************** ; cdmes: dc.b lf,cr .asciz "Copied" ctom: .asciz " to " cform: .asciz " for " cbyt: .asciz " bytes" dc.b nul copy: bsr getch ;get past blank lea getch,a0 ;setup for terminal input bsr getw ;get target address move.l d0,d2 ;save it movea.w d0,a2 bsr getch ;get past = bsr getw ;get start address move.l d0,d3 ;save it movea.w d0,a3 ;again bsr getch ;get past , bsr getw ;get ending address sub.l d3,d0 ;calculate byte count move.l d0,d4 ;save it addq.b #$1,d4 colp: move.b (a3)+,(a2)+ ;start moving dbf d0,colp lea cdmes,a0 ;say we're done bsr writs move.l d3,d0 bsr writw lea ctom,a0 bsr writs move.l d2,d0 bsr writw lea cform,a0 bsr writs move.l d4,d0 bsr writw lea cbyt,a0 bsr writs rts ; ; Mem - memory update ; ;******************************************* ;* * ;* Memory sub-commands are as follows: * ;* * ;* m - start memory mode * ;* m xxxx - start m mode at loca- * ;* tion xxxx * ;* .xxxx - set pointer to location* ;* xxxx * ;* =xx - update current location * ;* to xx * ;* ,xx - increment location and * ;* update it to xx * ;* + - increment location * ;* - - decrement location * ;* - print current location * ;* and value * ;* * ;******************************************* ; mtab: dc.w $2e00 ;. dc.w mdot dc.w $3d00 ;= dc.w mequ dc.w $2c00 ;, dc.w mcom dc.w $2b00 ;+ dc.w mplu dc.w $2d00 ;- dc.w mmin dc.w $0d00 ; dc.w mloc mmes: dc.b lf,lf,cr .asciz "Memory Mode" mprmp: dc.b lf,cr,':',nul meqm: .asciz " == " mem: bsr getch ;get delimiter cmp.b #$0d,d0 ;if then enter m beq mnoad lea getch,a0 ;else get the address bsr getw bra mplp ;set the address mnoad: moveq #$0,d0 ;start with no address mplp: move.w d0,exam ;set the address lea mmes,a0 ;load message bsr writs mlp: lea mprmp,a0 ;write memory prompt bsr writs bsr getch ;enter memory command loop moveq #$5,d2 ;set for search lea mtab-4,a0 mmlp: addq.w #$4,a0 ;search loop like comm cmp.b (a0),d0 dbeq d2,mmlp bne mexit ;exit if not found movea.w $2(a0),a0 ;get routine address jsr (a0) ;go to it bra mlp ;stay in memory loop mexit: rts mdot: lea getch,a0 ;handle setting of address bsr getw ;get address move.w d0,exam ;set in p[ointer bsr mloc ;print address and value rts mequ: lea getch,a0 ;handle new value at pointer bsr getb ;get new value movea.w exam,a0 ;set address move.b d0,(a0) ;move new value bsr mloc ;write new value rts mcom: addq.w #$1,exam ;handle pointer increment by , bsr mequ ;write new address and value rts mplu: addq.w #$1,exam ;increment pointer bsr mloc ;write val rts mmin: subq.w #$1,exam ;decrement pointer bsr mloc rts mloc: bsr crlf ;write address and value move.w exam,d0 ;write address bsr writw lea meqm,a0 bsr writs movea.w exam,a0 move.b (a0),d0 ;write value bsr writb rts ; ; Regs - Modify/examine registers ; ;*************************************** ;* * ;* Register subcommands are as follows:* ;* * ;* r - start register mode * ;* r xx - start r mode at register* ;* xx. Where xx : * ;* SR/_sr - status register * ;* PC/_pc - program counter * ;* d0 - d7 - data registers * ;* a0 - a7 - address regs. * ;* .xx - set pointer to regsister * ;* =xxxxxxxx - update current reg- * ;* ister to xxxxxxxx * ;* - print all registers * ;* * ;*************************************** ; rtab: dc.w $2e00 ;. dc.w rdot dc.w $3d00 ;= dc.w requ dc.w $0d00 ; dc.w rall rtab1: dc.w $cb00 ;internal name/offset .ascii "SR" ;print name dc.w $9c02 .ascii "PC" dc.w $d006 .ascii "d0" dc.w $d10a .ascii "d1" dc.w $d20e .ascii "d2" dc.w $d312 .ascii "d3" dc.w $d416 .ascii "d4" dc.w $d51a .ascii "d5" dc.w $d61e .ascii "d6" dc.w $d722 .ascii "d7" dc.w $a026 .ascii "a0" dc.w $a12a .ascii "a1" dc.w $a22e .ascii "a2" dc.w $a332 .ascii "a3" dc.w $a436 .ascii "a4" dc.w $a53a .ascii "a5" dc.w $a63e .ascii "a6" dc.w $a742 .ascii "a7" rmes: dc.b lf,lf,cr .asciz "Register Mode" rprmp: dc.b lf,cr,':',nul reqm: .asciz " == " regs: bsr getch ;get delimiter cmp.b #$0d,d0 ;if then start at sr beq rnoad lea getch,a0 ;else set for terminal input bsr getb ;get register name bsr raddr ;set address bra rplp ;set register pointer rnoad: lea rtab1,a3 ;set default pointer value move.w a3,rexam rplp: lea rmes,a0 ;say hello bsr writs bsr rloc ;write starting loc value rlp: lea rprmp,a0 ;write register prompt bsr writs bsr getch ;get command moveq #$2,d2 ;set for search lea rtab-4,a0 rmlp: addq.w #$4,a0 ;search cmp.b (a0),d0 dbeq d2,rmlp bne rexit ;exit if not found movea.w $2(a0),a0 ;found it so go to it jsr (a0) bra rlp ;go again rexit: rts rdot: lea getch,a0 ;set register pointer bsr getb bsr raddr ;set input address bsr rloc ;write register and value rts requ: lea getch,a0 ;set new value movea.w rexam,a3 moveq #$0,d1 ;clear d1 move.b $1(a3),d1 ;get offset beq requs ;branch if sr is reg bsr getl ;get new value lea _sr,a4 ;find save area offset adda.l d1,a4 ;add offset move.l d0,(a4) ;move in new value bra requr ;print it requs: bsr getw ;same as above but for sr (word vs. long move.w d0,_sr requr: bsr rloc ;write new value rts rall: lea rtab1-4,a3 ;write all registers moveq #$11,d2 ;set count ralp: addq.w #$4,a3 ;loop move.w a3,rexam bsr rloc dbf d2,ralp rts raddr: move.w #$11,d4 ;find offset in save area lea rtab1-4,a3 radlp: addq.w #$4,a3 cmp.b (a3),d0 dbeq d4,radlp bne rexit move.w a3,rexam ;set register pointer rts rloc: bsr crlf ;print register name and value movea.w rexam,a4 move.b $2(a4),d0 ;write name bsr writ move.b $3(a4),d0 bsr writ lea reqm,a0 bsr writs moveq #$0,d0 move.b $1(a4),d0 ;write value beq rpsr ;branch if sr lea _sr,a0 ;find offset adda.l d0,a0 ;add offset move.l (a0),d0 ;move in new value bsr writl bra rrts rpsr: move.w _sr,d0 ;write sr value bsr writw rrts: rts ; ; Load - Load data from host ; ;**************************************** ;* * ;* Load is invoked as follows: * ;* * ;* l - load from host with no * ;* offset * ;* - same as l but used * ;* only exiting emulator * ;* l xxxx - load with offset xxxx * ;* * ;**************************************** ; lmes: dc.b lf,cr .asciz "Load..." slmes: dc.b lf,cr .asciz "User PC == " elmes: dc.b lf,cr .asciz "Load done..." dc.b nul load: bsr getch ;get delimiter cmp.b #$0d,d0 ;if then no offset beq lnoof lea getch,a0 ;get offset bsr getw move.l d0,_pc ;save load point for go command bra ld1 lnoof: move.l #$0,_pc ld1: lea lbuff,a1 ;point at lpbuff move.w #$0,head(a1) ;set queue for lp move.w #$ffff,tail(a1) move.w #$0,count(a1) lea lmes,a0 ;print starting message bsr writs move.b #$0d,d0 ;load a bsr writu ;send it to the host lea lgch,a0 ;set up for host load routine llp: jsr (a0) ;get S cmp.b #$53,d0 bne llp ;No - start over jsr (a0) ;get 1 or 9 cmp.b #$39,d0 ;9 - then done beq ldone cmp.b #$31,d0 ;1 - then another record bne llp bsr getb ;get byte count move.l d0,d1 subq.b #$4,d1 ;remove count for check bsr getw add.l _pc,d0 ;add offset movea.w d0,a1 ;save starting address lblp: bsr getb ;get actual data byte move.b d0,(a1)+ ;move to memory dbf d1,lblp ;loop for count bsr getw ;gobble up check and crlf bra llp ;try another record ldone: jsr (a0) ;gobble up byte count jsr (a0) bsr getw ;get address from end macro add.l _pc,d0 ;add offset move.l d0,d1 ;save it move.l d0,_pc ;set starting address for go move.w #$0,_sr ;set status register move.l #$10,d0 lea dr0,a1 lreg: move.l #$0,(a1)+ dbf d0,lreg movea.l a0,a2 ;save the port location in a2 lea ustck,a0 move.l a0,ar7 ;set user stack lea slmes,a0 ;write message bsr writs move.l d1,d0 bsr writw ;write starting address move.l #$03,d1 ;gobble up last four bytes movea.l a2,a0 ;restore the port location to a0 ll2: jsr (a0) dbf d1,ll2 lea elmes,a0 ;send last message bsr writs bset #$00,echo ;turn terminal echo back on rts ; ; Upload - upload program from terminal port ; ;**************************************** ;* * ;* Upload is invoked as follows: * ;* * ;* u - load from terminal * ;* with no offset * ;* u xxxx - load with offset xxxx * ;* * ;**************************************** ; uload: bsr getch ;same as above, except that it cmp.b #$0d,d0 ;uses the terminal port for the beq ulnoof ;load. lea getch,a0 bsr getw move.l d0,_pc bra uld1 ulnoof: move.l #$0,_pc uld1: lea ibuff,a1 move.w #$0,head(a1) move.w #$ffff,tail(a1) move.w #$0,count(a1) lea lmes,a0 bsr writs move.b #$0d,d0 bsr writu lea getch,a0 bclr #$00,echo bra llp ;goes to the load routine above ; ; e - Enter terminal emulator mode * ; ;******************************************** ;* * ;* Invoke emulator mode as follows * ;* * ;* e * ;* * ;* NOTE: That in this mode any char- * ;* except a ctrl-x may be sent to the * ;* host. Ctrl-x is the escape sequence * ;* for getting out of terminal emulator * ;* mode. Ctrl-l does the same thing * ;* except a load (l) command is put * ;* in the command buffer. * ;* * ;******************************************** ; emmes: dc.b lf,cr .asciz "Exit terminal mode" enmes: dc.b lf,cr .ascii "Terminal mode:" dc.b lf,cr,nul emul: lea enmes,a0 ;write message bsr writs bset #$3,bkptf ;set emulator mode emu1: stop #$2000 ;wait for interrupt ;if interrupted the handlers ;will buffer and echo input bra emu1 emudn: lea emmes,a0 ;entered from interrupt handler bsr writs rts ; ; Proto - Prototype command in ram ; ;****************************************** ;* * ;* Prototype commands are invoked: * ;* * ;* px xxxx - load address xxxx for * ;* prototype command x. * ;* px - execute prototype com- * ;* mand x. * ;* * ;* NOTE: x must be a 1, 2, or 3 * ;* * ;****************************************** ; pmess: dc.b lf,cr .asciz "Prototype " pm1: .ascii "running:" dc.b lf,cr,nul pm2: .ascii "installed" dc.b cr,nul,nul proto: bsr getch ;get prototype number move.l d0,d1 ;save number andi.b #$0f,d1 ;strip leading hex digit subq.b #$1,d1 ;normalize to 0 lsl.l #$1,d1 ;multiply by 2 lea ptab,a1 ;set starting address adda.l d1,a1 ;add offset bsr getch ;get delimiter cmp.b #$0d,d0 ;if then do command beq prun lea getch,a0 ;else install in table bsr getw ;get address move.w d0,(a1) ;move in address lea pmess,a0 bsr writs lea pm2,a0 bsr writs bra prts prun: movea.w (a1),a1 ;run prototype command lea pmess,a0 bsr writs lea pm1,a0 bsr writs jsr (a1) ;go do it prts: rts ; ; Bkpt - Set/Remove breakpoints ; ; ;********************************************** ;* * ;* Breakpoint is invoked as follows: * ;* * ;* b - display breakpoints * ;* b+xxxx - add a breakpoint at xxxx * ;* b-xxxx - delete breakpoint at xxxx * ;* b# - delete all breakpoints * ;* * ;********************************************** ; brmes: dc.b lf,cr .asciz "Bkpts removed" bdmes: dc.b lf,cr .ascii "Bkpts at:" dc.b lf,cr,nul bpmes: dc.b lf,cr .asciz "Bkpt added at " bmmes: dc.b lf,cr .asciz "Bkpt deleted at " bbmes: dc.b lf,cr .asciz "Bkpt error" dc.b nul bkin: dc.w $FFFF ;instruction constant bkpt: bsr getch ;get delimiter cmp.b #$0d,d0 ;if then print all bkpts beq bdis cmp.b #$2b,d0 ;if + then add a bkpt beq bpls cmp.b #$2d,d0 ;if - then delete a bkpt beq bmin cmp.b #$23,d0 ;if # then delete all bkpts bne bbad ;else its a bad message brem: moveq #$4,d1 ;remove all bkpts lea bktab-4,a1 ;set for loop blp1: adda.w #$4,a1 movea.w iloc(a1),a0 ;get address from table cmpa.w #$00,a0 ;if 0 then not an entry beq bno move.w instr(a1),(a0) ;else move instr back move.l #$0,instr(a1) ;clear table entry bno: dbf d1,blp1 ;loop bclr #$0,bkptf ;clear bkpt if in one btst #$2,bkptf ;In trace ? bne brno ;Yes. andi.w #$7fff,_sr ;else clear trace bit brno: lea brmes,a0 ;say done bsr writs bra brts bdis: lea bdmes,a0 ;handle display all bkpts bsr writs lea bktab-4,a1 ;set loop moveq #$4,d1 bdlp: adda.w #$4,a1 ;loop move.w iloc(a1),d0 ;get bkpt beq belp ;if 0 then not an entry bsr writw bsr crlf belp: dbf d1,bdlp ;loop bra brts bpls: lea bktab-4,a1 ;add a bkpt moveq #$4,d1 ;set for loop lea getch,a0 ;setup to get address bsr getw bl2: adda.w #$4,a1 ;loop cmp.w iloc(a1),d0 ;found entry already in table ? bne bmo ;yes movea.w d0,a2 ;reset it for insurance move.w bkin,(a2) ;set instruction bra bfnd ;exit for found bmo: move.w iloc(a1),d2 ;move to set condition codes dbeq d1,bl2 ;exit if 0 entry found bne bbad ;if exit is on count and not 0 then error move.w d0,iloc(a1) ;move in address movea.w d0,a2 ;point at location move.w (a2),instr(a1) ;get instruction into table move.w bkin,(a2) ;set bkpt instruction bfnd: lea bpmes,a0 ;load message bsr writs move.l a2,d0 bsr writw bclr #$1,bkptf ;clear in-single flag btst #$2,bkptf ;In trace ? bne brts ;Yes andi.w #$7fff,_sr ;clear trace bit bra brts bmin: lea bktab-4,a1 ;delete a breakpoint entry moveq #$4,d1 ;setup for search lea getch,a0 ;setup for terminal input bsr getw bl3: adda.w #$4,a1 ;loop cmp.w iloc(a1),d0 ;Is this the one ? dbeq d1,bl3 ;if yes then exit else loop bne bbad ;Exit on count ? movea.w d0,a2 ;no, so get address move.w instr(a1),(a2) ;return instruction move.l #$0,instr(a1) ;clear table entry btst #$0,bkptf ;In breakpoint ? beq bok ;No cmp.l _pc,d0 ;Yes, This breakpoint ? bne bok ;No bclr #$0,bkptf ;Yes, so clear handling it btst #$2,bkptf ;In trace ? bne bok ;Yes andi.w #$7fff,_sr ;else clear trace flag bok: lea bmmes,a0 ;load message bsr writs move.l a2,d0 ;print address bsr writw bra brts bbad: lea bbmes,a0 ;error handler bsr writs brts: rts ; ; dump - dump memory ; ;***************************************** ;* * ;* dump is invoked as follows: * ;* * ;* d - dump the next 64 bytes from* ;* last examined location * ;* d xxxx - dump the next 64 bytes* ;* from address xxxx * ;* d xxxx,yyyy - dump the bytes bet- * ;* ween xxxx and yyyy * ;* * ;***************************************** ; dmes: dc.b lf,lf,cr .ascii "Memory dump" dc.b lf,cr,nul dhed: dc.b lf,cr .ascii " 0 1 2 3" .ascii " 4 5 6 7 8 9 a" .ascii " B C d E F" dcr: dc.b lf,cr,nul dump: lea getch,a0 ;set for terminal input bsr getch ;get delimiter cmp.b #$0d,d0 ;if then dump from pointer bne dexam ;else get address movea.w exam,a1 ;get exam movea.w a1,a2 ;save it for ending address adda.w #$40,a2 ;add 64 for length of dump bra dgo ;go do it dexam: bsr getw ;get starting address movea.w d0,a1 bsr getch ;get delimiter cmp.b #$2c,d0 ;if , the get ending address bne dcom bsr getw ;get address movea.w d0,a2 ;save it bra dgo ;go dump dcom: movea.w a1,a2 ;default to 64 byte dump adda.w #$40,a2 dgo: lea dmes,a0 ;do the dump bsr writs lea dhed,a0 ;print header bsr writs move.l a1,d0 ;set starting address at 16 byte boundary and.b #$f0,d0 movea.w d0,a1 move.l a2,d0 ;round ending address to boundary or.b #$0f,d0 movea.w d0,a2 moveq #$0f,d1 ;move byte count to register dl1: move.l a1,d0 ;write starting address bsr writw movea.w a1,a3 ;save starting address dflp: moveq #$20,d0 ;write a space bsr writ move.b (a1)+,d0 ;get next byte bsr writb ;write it dbf d1,dflp ;loop moveq #$0f,d1 ;reset byte count movea.w a3,a1 ;refetch starting address moveq #$20,d0 ;write a space bsr writ dslp: move.b (a1)+,d0 ;write the byte representation cmp.b #$20,d0 ;if not printable then a dot bge dok move.b #$2e,d0 ;move in the dot bra dwrt dok: cmp.b #$7f,d0 ;printable again ? blt dwrt ;yes move.b #$2e,d0 ;no, move in a dot dwrt: bsr writ ;write it dbf d1,dslp ;line done ? lea dcr,a0 ;yes, so cr-lf bsr writs moveq #$10,d1 ;reset byte count cmpa.l a1,a2 ;done ? dblt d1,dl1 ;NO, so loop move.w a1,exam ;yes, so update exam rts ; ; Trace - Set trace mode ; ;***************************************** ;* * ;* Invoke trace as follows: * ;* * ;* t+ - trace a program's path * ;* t- - turn off trace * ;* * ;***************************************** ; tmes: dc.b lf,cr .asciz "Trace " tonm: .asciz "on" toffm: .asciz "off" trace: bsr getch ;get command move.l d0,d1 ;save it lea tmes,a0 ;write message bsr writs cmp.b #$2b,d1 ;Is it a + ? beq ton ;yes btst #$0,bkptf ;In breakpoint ? bne tclr ;Yes, so don't clear trace andi.w #$7fff,_sr ;clear trace tclr: bclr #$2,bkptf ;turn-off in-trace flag lea toffm,a0 ;load off message bra tdone ;exit ton: ori.w #$8000,_sr ;set trace bit bclr #$1,bkptf ;clear single step bset #$2,bkptf ;set in-trace flag lea tonm,a0 ;write message tdone: bsr writs rts ; ; Single - set single step ; ;***************************************** ;* * ;* Invoke single step as follows: * ;* * ;* s+ - turn on single step * ;* s- - turn off single step * ;* * ;***************************************** ; smes: dc.b lf,cr .asciz "Single step" sonm: .asciz " on " soffm: .asciz " off " dc.b nul singl: bsr getch ;get command move.l d0,d1 ;save it lea smes,a0 ;write message bsr writs cmp.b #$2b,d1 ;+ ? beq son ;yes btst #$0,bkptf ;In breakpoint ? bne sclr ;Yes, so don't clear trace andi.w #$7fff,_sr ;clear trace bit sclr: bclr #$1,bkptf ;turn-off in-single flag lea soffm,a0 ;write off message bsr writs bra sdone ;exit son: bclr #$0,bkptf ;clear in-bkpt flag bset #$1,bkptf ;set in-single flag bclr #$2,bkptf ;clear in-trace flag lea sonm,a0 ;write message bsr writs bsr brem ;remove all breakpoints for single ori.w #$8000,_sr ;set trace bit sdone: rts ; ; Go - Start user program ; ;***************************************** ;* * ;* Invoke go as follows: * ;* * ;* g - go from start address in * ;* last load * ;* - same as g * ;* g xxxx - go from address xxxx * ;* * ;***************************************** ; gmes: dc.w csc .ascii "Program:" dc.b lf,lf,cr,nul go: bsr getch ;get seperator cmp.b #$0d,d0 ;if CR then beq ggo ;start from default gget: lea getch,a0 ;else get start addr bsr getw ;as given in comm. move.l d0,_pc ;set for return ggo: btst #$1,bkptf ;single set ? bne gnom ;Yes so no message lea gmes,a0 ;write message bsr writs gnom: addq.w #$4,a7 ;pop the stack movem.l dr0,#$7fff ;get saved values d0-a6 move.l a7,t1 ;save system stack pointer movea.l ar7,a7 ;get saved user stack pointer move.l a7,usp ;reset the user stack movea.l t1,a7 ;reset system stack gbmov: move.l _pc,-(a7) ;set up return pc andi.w #$f8ff,_sr ;enable interrupts move.w _sr,-(a7) ;set up return sr rte ;++++++++++++++++++++++++++++++++++++++++ ;+ + ;+ End of commands, Start Handlers + ;+ + ;++++++++++++++++++++++++++++++++++++++++ ; ; Generic trap handler ; ghmes: dc.b lf,cr .asciz "Trap at " dc.b nul ghlr: movem.l #$ffff,dr0 ;save all registers d0-a7 move.l usp,a6 ;get user stack pointer move.l a6,ar7 ;and save it move.w (a7)+,_sr ;save current SR move.l (a7)+,_pc ;save current return value pea comm ;set for return to comm move.w ssri,-(a7) ;enable interrupts on return ghpr: lea ghmes,a0 ;wx message ghpr1: bsr writs move.l _pc,d0 bsr writl rte ; ; Breakpoint handler ; bhmes: dc.b lf,cr .asciz "Breakpoint at " binin: dc.b lf,cr .asciz "Bad Instruction at " dc.b nul bhlr: move.w ssrn,sr ;disable interrupts movem.l #$ffff,dr0 ;save registers d0-a7 move.l usp,a6 ;get and save user stack pointer move.l a6,ar7 move.w (a7)+,_sr ;save status register move.l (a7)+,_pc ;save program counter pea comm ;set for return to comm move.w ssri,-(a7) ;enable interrupts on return movea.l _pc,a0 ;get pc on interrupt cmpi.w #$ffff,(a0) ;was interrupt caused by bkpt instruction ? beq bsnd ;Yes lea binin,a0 ;No, invalid instruction bra ghpr1 ;go wx message bsnd: lea bhmes,a0 ;wx bkpt message bsr writs move.l _pc,d0 bsr writw bsr crlf lea bktab-4,a1 ;find the breakpoint entry move.l #$4,d1 ;maximum of 5 move.l _pc,d0 ;this is where it happened bhl: adda.w #$4,a1 cmp.w iloc(a1),d0 ;is this the entry ? dbeq d1,bhl ;loop if not bne bhrte ;not found so quit movea.w d0,a2 ;point at it move.w instr(a1),(a2) ;move instruction back in ori.w #$8000,_sr ;set trace mode on bset #$0,bkptf ;set in-bkpt flag bhrte: rte ; ; Trace handler ; tlocm: dc.b lf,cr .asciz "PC == " dc.b nul thlr: move.w ssrn,sr ;disable interrupts move.l a0,ar0 ;save used registers move.l d0,dr0 move.l a1,ar1 move.l d1,dr1 move.l a2,ar2 move.l d2,dr2 btst #$0,bkptf ;Handling a breakpoint ? beq treal ;No, so its a real trace movea.l _pc,a0 ;Yes, find where it occurred move.w bkin,(a0) ;reset the bkpt instruction bclr #$0,bkptf ;clear in progress bkpt btst #$2,bkptf ;In trace mode bne treal ;yes, go trace it thma0: andi.w #$7fff,(a7) ;No, so clear the trace bit bra trte treal: move.l $2(a7),_pc ;Not (just) a bkpt but trace or single btst #$1,bkptf ;Trace ? beq trpr ;Yes movem.l #$ffff,dr0 ;No,single-step d0-a7 move.l usp,a6 ;save registers and stack pointer move.l a6,ar7 move.w (a7)+,_sr ;save status register move.l (a7)+,_pc ;save pc pea comm ;fake return to comm move.w ssri,-(a7) ;enable interrupts on return trpr: lea tlocm,a0 ;wx message bsr writs move.l _pc,d0 bsr writl bsr crlf move.l _pc,a1 ;load the current address bsr ass1 ;wx the disassembled instruction trte: movea.l ar0,a0 ;restore used registers move.l dr0,d0 movea.l ar1,a1 move.l dr1,d1 movea.l ar2,a2 move.l dr2,d2 tr: rte ; ; Privilege Violation Handler ; ; See generic handler for details ; prmes: dc.b lf,cr .asciz "Privilege Error at " phlr: movem.l #$ffff,dr0 ;regs d0-a7 move.l usp,a6 move.l a6,ar7 move.w (a7)+,_sr move.l (a7)+,_pc pea comm move.w ssri,-(a7) prpr: lea prmes,a0 bra ghpr1 ; ; address error/bus error trap ; abmes: dc.b lf,cr .asciz "address error at " abhlr: movem.l #$ffff,dr0 ;regs d0-a7 move.l usp,a6 move.l a6,ar7 ;same as above but... move.w $8(a7),_sr ;status register is deeper in stack move.l $a(a7),_pc ;also pc pea comm move.w ssri,-(a7) abpr: lea abmes,a0 bra ghpr1 ; ; Macro instruction handlers ; ; ; Exit ; texit: movem.l #$ffff,dr0 ;save register values d0-a7 move.l usp,a6 ;save user stack pointer move.l a6,ar7 move.w (a7)+,_sr ;save status register move.l (a7)+,_pc ;save pc lea stack,a7 ;reset system mode stack pea comm ;fake return to comm move.w ssri,-(a7) ;ditto for status rte ; ; Getb ; tgetb: lea getch,a0 bsr getb rte ; ; Getw ; tgetw: lea getch,a0 bsr getw rte ; ; Getl ; tgetl: lea getch,a0 bsr getl rte ; ; Wrtb ; twrtb: bsr writb rte ; ; Wrtw ; twrtw: bsr writw rte ; ; Wrtl ; twrtl: bsr writl rte ; ; Getc ; tgetc: bsr getch rte ; ; Wrts ; twrts: bsr writs rte ; ; Wrtc ; twrtc: bsr writ rte ; ; Crlf ; tcrlf: bsr crlf rte ; ; Help - display help messages ; ;***************************************** ;* * ;* Invoke help as follows: * ;* * ;* h - print list of available * ;* help * ;* hx - print help message for x * ;* * ;***************************************** hlph: .ascii " H - display help messages" dc.b cr,lf,nul hlph1: .ascii " Invoke help as follows:" dc.b cr,lf .ascii " h - print list of available help" dc.b cr,lf .ascii " hx - print help message for x" dc.b cr,lf,nul hlpc: .ascii " C - Copy memory blocks" dc.b cr,lf,nul hlpc1: .ascii " Copy is invoked as follows:" dc.b cr,lf .ascii " c xxxx=yyyy,zzzz" dc.b cr,lf .ascii " Copy locations yyyy thru zzzz to" dc.b cr,lf .ascii " locations xxxx and upward." dc.b cr,lf,nul hlpm: .ascii " M - memory update" dc.b cr,lf,nul hlpm1: .ascii " Memory sub-commands are as follows:" dc.b cr,lf dc.b cr,lf .ascii " m - start memory mode" dc.b cr,lf .ascii " m xxxx - start m mode at location xxxx" dc.b cr,lf .ascii " .xxxx - set pointer to location xxxx" dc.b cr,lf .ascii " =xx - update current location to xx" dc.b cr,lf .ascii " ,xx - increment location and update it to xx" dc.b cr,lf .ascii " + - increment location" dc.b cr,lf .ascii " - - decrement location" dc.b cr,lf .ascii " - print current location and value" dc.b cr,lf,nul hlpr: .ascii " R - Modify/examine registers" dc.b cr,lf,nul hlpr1: .ascii " Register subcommands are as follows:" dc.b cr,lf dc.b cr,lf .ascii " r - start register mode" dc.b cr,lf .ascii " r xx - start r mode at register xx. Where xx :" dc.b cr,lf .ascii " SR/_sr - status register" dc.b cr,lf .ascii " PC/_pc - program counter" dc.b cr,lf .ascii " d0 - d7 - data registers" dc.b cr,lf .ascii " a0 - a7 - address regs." dc.b cr,lf .ascii " .xx - set pointer to register" dc.b cr,lf .ascii " =xxxxxxxx - update current register to xxxxxxxx" dc.b cr,lf .ascii " - print all registers" dc.b cr,lf,nul hlpl: .ascii " L - Load data from host" dc.b cr,lf,nul hlpu: .ascii " U - Load data from terminal port" dc.b cr,lf,nul hlpl1: .ascii " Load is invoked as follows:" dc.b cr,lf .ascii " l - load from host with no offset" dc.b cr,lf .ascii " - same as l but used from emulator mode" dc.b cr,lf .ascii " l xxxx - load with offset xxxx" dc.b cr,lf,cr,lf .ascii " Upload is invoked as follows:" dc.b cr,lf .ascii " u - load from terminal with no offset" dc.b cr,lf .ascii " u xxxx - load from terminal with offset xxxx" dc.b cr,lf,nul hlpe: .ascii " E - Enter terminal emulator mode" dc.b cr,lf,nul hlpe1: .ascii " Invoke emulator mode as follows" dc.b cr,lf dc.b cr,lf .ascii " e" dc.b cr,lf .ascii " NOTE: That in this mode any character except" dc.b cr,lf .ascii " a ctrl-x may be sent to the host. Ctrl-x is the" dc.b cr,lf .ascii " escape sequence for getting out of terminal emulator" dc.b cr,lf .ascii " mode. Ctrl-l does the same thing except a load (l)" dc.b cr,lf .ascii " command is put in the command buffer." dc.b cr,lf,nul hlpp: .ascii " P - Prototype commands in RAM" dc.b cr,lf,nul hlpp1: .ascii " Prototype commands are invoked:" dc.b cr,lf .ascii " px xxxx - load address xxxx for prototype command x." dc.b cr,lf .ascii " px - execute prototype command x." dc.b cr,lf dc.b cr,lf .ascii " NOTE: x must be a 1, 2, or 3" dc.b cr,lf,nul hlpb: .ascii " B - Set/Remove breakpoints" dc.b cr,lf,nul hlpb1: .ascii " Breakpoint is invoked as follows:" dc.b cr,lf .ascii " b - display breakpoints" dc.b cr,lf .ascii " b+xxxx - add a breakpoint at xxxx" dc.b cr,lf .ascii " b-xxxx - delete breakpoint at xxxx" dc.b cr,lf .ascii " b# - delete all breakpoints" dc.b cr,lf,nul hlpd: .ascii " D - dump memory" dc.b cr,lf,nul hlpd1: .ascii " dump is invoked as follows:" dc.b cr,lf dc.b cr,lf .ascii " d - dump the next 64 bytes from last examined location" dc.b cr,lf .ascii " d xxxx - dump the next 64 bytes from address xxxx" dc.b cr,lf .ascii " d xxxx,yyyy - dump the bytes between xxxx and yyyy" dc.b cr,lf,nul hlpa: .ascii " A - Assembly listing" dc.b cr,lf,nul hlpa1: .ascii " disassembly is invoked as follows:" dc.b cr,lf dc.b cr,lf .ascii " a - list the next 20 instructions from last location" dc.b cr,lf .ascii " a xxxx - list the next 20 instructions from address xxxx" dc.b cr,lf .ascii " a xxxx,yyyy - list the instructions between xxxx and yyyy" dc.b cr,lf,nul hlpt: .ascii " T - Set trace mode" dc.b cr,lf,nul hlpt1: .ascii " Invoke trace as follows:" dc.b cr,lf dc.b cr,lf .ascii " t+ - trace a program's path" dc.b cr,lf .ascii " t- - turn off trace" dc.b cr,lf,nul hlps: .ascii " S - set single step" dc.b cr,lf,nul hlps1: .ascii " Invoke single step as follows:" dc.b cr,lf dc.b cr,lf .ascii " s+ - turn on single step" dc.b cr,lf .ascii " s- - turn off single step" dc.b cr,lf,nul hlpg: .ascii " G - Start user program" dc.b cr,lf,nul hlpg1: .ascii " Invoke go as follows:" dc.b cr,lf dc.b cr,lf .ascii " g - go from start address in last load" dc.b cr,lf .ascii " - same as g" dc.b cr,lf .ascii " g xxxx - go from address xxxx " dc.b cr,lf,nul htab: dc.w $4800 ;h - help dc.w hlph,hlph1 dc.w $4d00 ;m - memory dc.w hlpm,hlpm1 dc.w $4c00 ;l - load dc.w hlpl,hlpl1 dc.w $5500 ;u - upload dc.w hlpu,hlpl1 dc.w $4400 ;d - dump dc.w hlpd,hlpd1 dc.w $5300 ;s - single step dc.w hlps,hlps1 dc.w $5400 ;t - trace program dc.w hlpt,hlpt1 dc.w $4700 ;g - start user program dc.w hlpg,hlpg1 dc.w $4500 ;e - emulate mode dc.w hlpe,hlpe1 dc.w $4200 ;b - breakpoints dc.w hlpb,hlpb1 dc.w $4300 ;c - copy dc.w hlpc,hlpc1 dc.w $5200 ;r - register modify dc.w hlpr,hlpr1 dc.w $5000 ;p - prototype commands dc.w hlpp,hlpp1 dc.w $4100 ;a - assembly listing dc.w hlpa,hlpa1 ; ; Structure of entry is topic (top), ; address of short message (hshort), ; and address of long message (hlong). ; help: bsr getch ;get argument andi.b #$5f,d0 ;make it uppercase cmpi.b #$0d,d0 ;is it a carriage return? bne htopic ;no, so decode topic hall: bsr crlf bsr crlf moveq #$0d,d1 ;load total # topics - 1 lea htab+2,a1 ;load location of short help shlp: movea.w (a1),a0 ;copy help location to a0 bsr writs ;write a short help message addq.w #$06,a1 ;increment to next help message dbf d1,shlp ;if not last message, print another one rts htopic: lea htab,a1 ;set up search of ctab moveq #$0d,d1 ;load total # topics - 1 lhlp: cmp.b (a1),d0 ;is the topic equal to the table value? beq hprn ;if so, print the short and long helps addq.w #$06,a1 ;else go to the next table location dbf d1,lhlp ;if not finished, try again bra hall ;if not one of these, print all shorts hprn: bsr crlf bsr crlf addq.w #$02,a1 ;increment a2 to short help location movea.w (a1)+,a0 ;transfer address to a0 bsr writs ;write the short message bsr crlf ;feed an extra line movea.w (a1),a0 ;transfer long help address to a0 bsr writs ;write the long message rts ; ; assem - assembly listing ; ;**************************************** ;* * ;* assem is invoked as follows: * ;* * ;* a - disassemble the next * ;* 20 instructions from * ;* last examined location * ;* a xxxx - disassemble 20 * ;* instructions from xxxx * ;* a xxxx,yyyy - disassemble all * ;* instructions from xxxx * ;* to yyyy * ;* * ;**************************************** ames: dc.b lf,lf,cr .ascii "assembly listing:" dc.b lf,cr,nul,nul assem: lea getch,a0 ;set for terminal input bsr getch ;get delimiter cmp.b #$0d,d0 ;if then list from pointer bne aexam ;else get address movea.w exam,a1 ;get exam lea ames,a0 ;write message bsr writs move.b #$13,d2 ;load 19 into d2 ass20: bsr ass1 ;list a single instruction dbf d2,ass20 ;if not finished, decrement and go again move.w a1,exam ;save new examination pointer rts aexam: bsr getw ;get starting address movea.w d0,a1 bsr getch ;get delimiter cmpi.b #$2c,d0 ;if , then get ending address bne acom bsr getw ;get address move.w d0,aend ;save it lea ames,a0 ;write message bsr writs assxy: bsr ass1 ;list a single instruction cmpa.w aend,a1 ;reached the end of the range yet? ble assxy ;if not, do it again move.w a1,exam ;save new examination pointer rts acom: lea ames,a0 ;write message bsr writs move.b #$13,d2 ;load 19 into d2 bra ass20 ;jump to dump 20 routine ass1: move.w a1,d0 ;load the address bsr writw ;print it out bsr spc bsr spc move.w (a1)+,d0 ;load the instruction word move.w d0,d1 ;make a copy rol.w #$06,d0 ;get a longword offset for and.w #$003c,d0 ;the instruction group (most sig. 4 bits) lea grtab,a2 ;load the address of the group table adda.w d0,a2 ;add the group offset movea.l (a2),a2 ;get the actual address jsr (a2) ;jump to the appropriate subroutine rts ;exit disend: bra crlf ;send crlf after instruction rts ;return from instruction subroutine grtab: dc.l gr0 dc.l gr1 dc.l gr2 dc.l gr3 dc.l gr4 dc.l gr5 dc.l gr6 dc.l gr7 dc.l gr8 dc.l gr9 dc.l gra dc.l grb dc.l grc dc.l grd dc.l gre dc.l grf gr0: move.w d1,d0 cmpi.w #$023c,d0 ;is it ANDIccr? bne ANDIsr ;no. lea mANDI,a0 ;yes, print bsr writs ;write it bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load the operand bsr writb ;write it bsr comma lea mccr,a0 ;load "ccr" bsr writs bra disend ANDIsr: cmpi.w #$027c,d0 ;is it ANDIsr? bne EORIcr ;no. lea mANDI,a0 ;yes, print bsr writs ;write it bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load the operand bsr writw ;write it bsr comma lea msr,a0 ;load "sr" bsr writs bra disend EORIcr: cmpi.w #$0a3c,d0 ;is it EORIccr? bne EORIsr ;no. lea mEORI,a0 ;yes, print bsr writs ;write it bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load the operand bsr writb ;write it bsr comma lea mccr,a0 ;load "ccr" bsr writs bra disend EORIsr: cmpi.w #$0a7c,d0 ;is it EORIsr? bne ORIccr ;no. lea mEORI,a0 ;yes, print bsr writs bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load the operand bsr writw ;write it bsr comma lea msr,a0 ;load "sr" bsr writs ;write it bra disend ORIccr: cmpi.w #$003c,d0 ;is it ORIccr? bne ORIsr ;no. lea mORI,a0 ;yes, print bsr writs ;write it bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load the operand bsr writb ;write it bsr comma lea mccr,a0 ;load "ccr" bsr writs bra disend ORIsr: cmpi.w #$007c,d0 ;is it ORIsr? bne ADDI ;no. lea mORI,a0 ;yes, print bsr writs ;write it bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load the operand bsr writw ;write it bsr comma lea msr,a0 ;load "sr" bsr writs bra disend ADDI: andi.w #$0f00,d0 ;mask operation bits cmpi.w #$0600,d0 ;is it ADDI? bne ANDI ;no. lea mADDI,a0 ;yes, print bsr writs ;write it bra iops ;go print operands ANDI: cmpi.w #$0200,d0 ;is it ANDI? bne CMPI ;no. lea mANDI,a0 ;yes, print bsr writs ;write it bra iops ;go print operands CMPI: cmpi.w #$0c00,d0 ;is it CMPI? bne EORI ;no. lea mCMPI,a0 ;yes, print bsr writs ;write it bra iops ;go print operands EORI: cmpi.w #$0a00,d0 ;is it EORI? bne ORI ;no. lea mEORI,a0 ;yes, print bsr writs ;write it bra iops ;go print operands ORI: cmpi.w #$0000,d0 ;is it ORI? bne SUBI ;no. lea mORI,a0 ;yes, print bsr writs ;write it bra iops ;go print operands SUBI: cmpi.w #$0400,d0 ;is it SUBI? bne MOVEP ;no. lea mSUBI,a0 ;yes, print bsr writs ;write it iops: move.w d1,d0 andi.w #$00c0,d0 ;check the size to see if it is legal cmpi.w #$00c0,d0 ;is it size 11? bne lops ;if not, it is legal bsr spc ;if so, it is not legal bsr spc bra ILLEG lops: bsr dot move.w d1,d0 bsr findsiz ;print the operand size bsr spc bsr pound bsr dollar cmpi.b #$62,siz ;is byte? bne iopsw ;no move.w (a1)+,d0 ;yes bsr writb bra iopsc iopsw: cmpi.b #$77,siz ;is word? bne iopsl ;no move.w (a1)+,d0 ;yes bsr writw bra iopsc iopsl: move.l (a1)+,d0 ;size long bsr writl iopsc: bsr comma move.w d1,d0 bsr writea ;write the operand bra disend MOVEP: move.w d1,d0 andi.w #$0138,d0 ;mask MOVEP bits cmpi.w #$0108,d0 ;is it a MOVEP? bne bitop ;if not, it's a bit operation lea mMOVEP,a0 ;load "MOVEP" bsr writs ;write it bsr dot move.w d1,d0 andi.w #$0040,d0 ;word or longword bne movepl ;longword move.b #$77,d0 ;load a 'W' bsr writ ;write it bra moveps ;go write operands movepl: move.b #$6C,d0 ;load an 'L' bsr writ ;write it moveps: bsr spc move.w d1,d0 andi.w #$0080,d0 ;mask direction bit beq movepr ;if zero, move to reg move.w d1,d0 andi.w #$0e00,d0 ;mask data reg rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bsr comma bsr lparen move.w (a1)+,d0 bsr writw ;write the address bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask address reg bsr wareg ;write it bsr rparen bra disend movepr: move.w d1,d0 bsr lparen move.w (a1)+,d0 bsr writw ;write the address bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask address reg bsr wareg ;write it bsr rparen bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask data reg rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bra disend bitop: move.w d1,d0 andi.w #$0f00,d0 ;mask the subgroup bits cmpi.w #$0e00,d0 ;and make sure this is not illegal, since beq ILLEG ;a non-MOVEP 00001110xxxxxxxx is invalid move.w d1,d0 andi.w #$00c0,d0 ;mask bitop select bits bne BCHG ;it's not BTST lea mBTST,a0 ;load "BTST" bsr writs ;write it bra bitop2 ;go print operands BCHG: cmpi.w #$0040,d0 bne BCLR ;it's not BCHG lea mBCHG,a0 ;load "BCHG" bsr writs ;write it bra bitop2 ;go print operands BCLR: cmpi.w #$0080,d0 bne BSET ;it's not BCLR lea mBCLR,a0 ;load "BCLR" bsr writs ;write it bra bitop2 ;go print operands BSET: lea mBSET,a0 ;load "BSET" bsr writs ;write it bitop2: bsr spc move.w d1,d0 andi.w #$0100,d0 ;is it reg or immediate operand? bne bitopr ;if nonzero, it's a reg operand bsr pound move.w (a1)+,d0 ;get the bit number andi.b #$07,d0 ;modulo 8 bsr writb ;write it bsr comma move.w d1,d0 bsr writea ;write the destination operand bra disend bitopr: move.w d1,d0 andi.w #$0e00,d0 ;mask off the reg number rol.w #$07,d0 ;get it into rightmost bits bsr wdreg ;write it bsr comma move.w d1,d0 bsr writea ;write the destination operand bra disend gr1: move.b #$62,siz ;make MOVE a byte operation bra MOVE ;go parse the command type gr2: move.b #$6c,siz ;make MOVE a word operation bra MOVE ;go parse the command type gr3: move.b #$77,siz ;make MOVE a long operation MOVE: move.w d1,d0 andi.w #$01c0,d0 ;mask the destination opmode cmpi.w #$0040,d0 ;is it MOVEA? beq MOVEA ;if so, go do MOVEA lea mMOVE,a0 ;load "MOVE" bsr writs ;write it bsr dot bsr findend ;write the size bsr spc move.w d1,d0 bsr writea ;write source operand bsr comma move.w d1,d0 ror.w #$01,d0 ;these rols and rors make dest. op. std. rol.b #$03,d0 ror.w #$08,d0 ror.b #$03,d0 ror.w #$05,d0 ;dest. op. now looks like source op. bsr writea ;write it bra disend MOVEA: move.b siz,d0 ;load the size. cmpi.b #$42,d0 ;is it a byte? beq ILLEG ;if so, this is not a valid instruction lea mMOVEA,a0 ;load "MOVEA" bsr writs ;write it bsr dot bsr findend ;write the size bsr spc move.w d1,d0 bsr writea ;write source operand bsr comma move.w d1,d0 rol.w #$07,d0 ;get destination into rightmost andi.w #$07,d0 ;mask off the destination bits bsr wareg ;write it bra disend gr4: move.w d1,d0 NOP: cmpi.w #$4e71,d0 ;is it a NOP? bne RESET ;no lea mNOP,a0 ;yes, print bsr writs ;write it bra disend RESET: cmpi.w #$4e70,d0 ;is it RESET? bne RTE ;no lea mRESET,a0 ;yes, print bsr writs ;write it bra disend RTE: cmpi.w #$4e73,d0 ;is it RTE? bne RTR ;no lea mRTE,a0 ;yes, print bsr writs ;write it bra disend RTR: cmpi.w #$4e77,d0 ;is it RTR? bne RTS ;no lea mRTR,a0 ;yes, print bsr writs ;write it bra disend RTS: cmpi.w #$4e75,d0 ;is it RTS? bne STOP ;no lea mRTS,a0 ;yes, print bsr writs ;write it bra disend STOP: cmpi.w #$4e72,d0 ;is it STOP? bne TRAPV ;no lea mSTOP,a0 ;yes, print bsr writs ;write it bsr spc bsr pound bsr dollar move.w (a1)+,d0 ;load data word bsr writw ;write it bra disend TRAPV: cmpi.w #$4e76,d0 ;is it TRAPV? bne JMP ;no lea mTRAPV,a0 ;yes, print bsr writs ;write it bra disend JMP: andi.w #$0fc0,d0 ;mask bits for one operations cmpi.w #$0ec0,d0 ;is it JMP? bne JSR ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode beq ILLEG cmpi.w #$0008,d0 ;these are not beq ILLEG cmpi.w #$0018,d0 ;valid modes with beq ILLEG cmpi.w #$0020,d0 ;this instruction beq ILLEG lea mJMP,a0 ;yes, print bsr writs bra gtea0 ;go write operand JSR: cmpi.w #$0e80,d0 ;is it JSR? bne MOVtc ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode beq ILLEG cmpi.w #$0008,d0 ;these are not beq ILLEG cmpi.w #$0018,d0 ;valid modes with beq ILLEG cmpi.w #$0020,d0 ;this instruction beq ILLEG lea mJSR,a0 ;yes, print bsr writs bra gtea0 ;go write operand MOVtc: cmpi.w #$04c0,d0 ;is it MOVEtoccr? bne MOVfc ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mMOVE,a0 ;yes, print bsr writs bsr spc move.w d1,d0 bsr writea ;write the source operand bsr comma lea mccr,a0 ;load "ccr" bsr writs bra disend MOVfc: cmpi.w #$02c0,d0 ;is it MOVEfromccr? bne MOVts ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mMOVE,a0 ;yes, print bsr writs bsr spc lea mccr,a0 ;load "ccr" bsr writs ;write it bsr comma move.w d1,d0 bsr writea ;write the operand bra disend MOVts: cmpi.w #$06c0,d0 ;is it MOVEtosr? bne MOVfs ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mMOVE,a0 ;yes, print bsr writs bsr spc move.w d1,d0 bsr writea ;write the source operand bsr comma lea msr,a0 ;load "sr" bsr writs bra disend MOVfs: cmpi.w #$00c0,d0 ;is it MOVEfromsr? bne NBCD ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mMOVE,a0 ;yes, print bsr writs bsr spc lea msr,a0 ;load "sr" bsr writs bsr comma move.w d1,d0 bsr writea ;write the operand bra disend NBCD: cmpi.w #$0800,d0 ;is it NBCD? bne PEA ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mNBCD,a0 ;yes, print bsr writs bra gtea0 ;go write operand PEA: cmpi.w #$0840,d0 ;is it PEA? bne TAS ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode beq SWAP cmpi.w #$0008,d0 ;these are not beq ILLEG cmpi.w #$0018,d0 ;valid modes with beq ILLEG cmpi.w #$0020,d0 ;this instruction beq ILLEG lea mPEA,a0 ;yes, print bsr writs bra gtea0 ;go write operand TAS: cmpi.w #$0AC0,d0 ;is it TAS? bne CLR ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG cmpi.w #$0038,d0 ;special modes bne tasok move.w d1,d0 andi.w #$0006,d0 bne ILLEG ;certain of them are bad tasok: lea mTAS,a0 ;yes, print bsr writs gtea0: bsr spc move.w d1,d0 bsr writea ;write the operand bra disend CLR: andi.w #$0f00,d0 ;mask + operations cmpi.w #$0200,d0 ;is it clr? bne NEG ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mCLR,a0 ;yes, print bsr writs bra gtea1 ;go write operand NEG: cmpi.w #$0400,d0 ;is it NEG? bne NEGX ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mNEG,a0 ;yes, print bsr writs bra gtea1 ;go write operand NEGX: cmpi.w #$0000,d0 ;is it NEGX? bne NOT ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mNEGX,a0 ;yes, print bsr writs bra gtea1 ;go write operand NOT: cmpi.w #$0600,d0 ;is it NOT? bne TST ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mNOT,a0 ;yes, print bsr writs bra gtea1 ;go write operand TST: cmpi.w #$0A00,d0 ;is it TST? bne BKPT ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mTST,a0 ;yes, print bsr writs gtea1: bsr dot move.w d1,d0 bsr findsiz ;print the operand length bsr spc move.w d1,d0 bsr writea ;print the operand bra disend BKPT: move.w d1,d0 andi.w #$fff8,d0 ;mask out the operand cmpi.w #$4848,d0 ;is it BKPT? bne LINK ;no lea mBKPT,a0 ;yes, print bsr writs ;write it bsr spc move.w d1,d0 andi.w #$0007,d0 ;mask BKPT number addi.b #$30,d0 ;make it an ascii numeral bsr writ ;write it bra disend LINK: move.w d1,d0 andi.w #$0f00,d0 ;look at bits 8-11 cmpi.w #$0e00,d0 ;is it an E? bne SWAP ;no move.w d1,d0 andi.w #$fff8,d0 ;mask off reg number cmpi.w #$4e50,d0 ;is it a LINK? bne MOVEsp ;no lea mLINK,a0 ;load "LINK" bsr writs ;write it bsr spc move.w d1,d0 andi.w #$0007,d0 ;mask reg bits bsr wareg ;write it bsr comma bsr pound bsr dollar move.w (a1)+,d0 ;load displacement bsr writw ;write it bra disend MOVEsp: move.w d1,d0 andi.w #$fff0,d0 ;mask off operand bits cmpi.w #$4e60,d0 ;is it MOVEusp? bne TRAP ;no lea mMOVE,a0 ;yes, so load "MOVE" bsr writs ;write it bsr spc move.w d1,d0 andi.w #$0008,d0 ;mask direction bit bne MOVEts ;if zero, move to usp move.w d1,d0 andi.w #$0007,d0 ;mask reg bits bsr wareg ;write it bsr comma lea musp,a0 ;load "usp" bsr writs ;write it bra disend MOVEts: lea musp,a0 ;load "usp" bsr writs ;write it bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask reg bits bsr wareg ;write it bra disend TRAP: move.w d1,d0 andi.w #$fff0,d0 ;mask operand if TRAP cmpi.w #$4e40,d0 ;is it TRAP? bne SWAP ;no lea mTRAP,a0 ;yes bsr writs bsr spc bsr pound bsr dollar move.b d1,d0 andi.b #$0f,d0 ;mask off trap number bsr writb ;write it bra disend SWAP: move.w d1,d0 andi.w #$fff8,d0 ;mask off operand if SWAP cmpi.w #$4840,d0 ;is it SWAP? bne UNLK ;no lea mSWAP,a0 ;load "swap" bsr writs ;write it bsr spc move.w d1,d0 andi.w #$0007,d0 ;mask off the reg bits bsr wdreg ;write the reg bra disend UNLK: cmpi.w #$4e58,d0 ;is it UNLK? bne LEA ;no lea mUNLK,a0 ;load "UNLK" bsr writs ;write it bsr spc move.w d1,d0 andi.w #$0007,d0 ;mask off reg number bsr wareg ;write it bra disend LEA: move.w d1,d0 andi.w #$f1c0,d0 ;mask for lea cmpi.w #$41c0,d0 ;is it LEA? bne CHK ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode beq ILLEG cmpi.w #$0008,d0 ;these are not beq ILLEG cmpi.w #$0018,d0 ;valid modes with beq ILLEG cmpi.w #$0020,d0 ;this instruction beq ILLEG lea mLEA,a0 ;load "LEA" bsr writs ;write it bsr spc move.w d1,d0 bsr writea ;write source op bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask reg number rol.w #$07,d0 ;get reg in rightmost bits bsr wareg ;write it bra disend CHK: cmpi.w #$4180,d0 ;is it CHK? bne EXT ;no move.w d1,d0 andi.w #$0038,d0 ;check to see if it's a valid mode cmpi.w #$0008,d0 ;these are not beq ILLEG lea mCHK,a0 ;load "CHK" bsr writs ;write it move.b #$77,siz ;size is word bsr spc move.w d1,d0 bsr writea ;write source operand bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask reg number rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bra disend EXT: move.w d1,d0 andi.w #$ffb8,d0 ;mask all pertinent bits cmpi.w #$4880,d0 ;is it EXT? bne MOVEC ;no lea mEXT,a0 ;yes, load "EXT" bsr writs ;write it bsr dot move.w d1,d0 andi.w #$0040,d0 ;mask the size bit bne lext ;size long move.b #$77,d0 ;size word, load 'W' bsr writ ;write it bra ext1 lext: move.b #$6c,d0 ;load 'L' bsr writ ;write it ext1: bsr spc move.w d1,d0 andi.w #$0007,d0 ;mask the reg number bsr wdreg ;write it bra disend MOVEC: move.w d1,d0 andi.w #$fffe,d0 ;mask in appropriate bits cmpi.w #$4e7b,d0 ;is it a MOVEC? bne MOVEM ;no lea mCOPOUT,a0 ;yes, so load "COPOUT" bsr writs ;write it move.w (a1)+,d0 ;compensate for the operand word bra disend MOVEM: move.w d1,d0 andi.w #$fb80,d0 ;mask bits cmpi.w #$4880,d0 ;is it MOVEM? bne ILLEG ;no lea mMOVEM,a0 ;yes, load "MOVEM" bsr writs bsr dot move.w d1,d0 andi.w #$0040,d0 ;mask MOVEM size bit bne MOVEMl ;if nonzero, longword operand move.b #$77,d0 ;load 'W' move.b d0,siz ;save size as 'W' bsr writ ;write it bsr spc bra MOVEMo ;go write operands MOVEMl: move.b #$6c,d0 ;load 'L' move.b d0,siz ;save size as 'L' bsr writ ;write it bsr spc MOVEMo: move.w d1,d0 andi.w #$0400,d0 ;which direction? bne MOVEMr ;to reg bsr dollar move.w (a1)+,d0 ;load the reg list bsr writw ;write it bsr comma move.w d1,d0 bsr writea ;write the address bra disend MOVEMr: move.w (a1)+,t1 ;save the reg list move.w d1,d0 bsr writea ;write the address bsr comma bsr dollar move.w t1,d0 ;reload the reg list bsr writw ;write it bra disend ILLEG: lea mILLEG,a0 ;yes, print bsr writs ;write it bra disend gr5: move.w d1,d0 ;refresh the instruction word and.w #$00c0,d0 ;mask bits 6-7 cmp.w #$00c0,d0 ;DBcc/Scc? bne addq ;no move.w d1,d0 ;yes andi.w #$0038,d0 ;mask DB/S bit cmpi.w #$0008,d0 ;DBcc? bne Scc ;no move.b #$64,d0 ;load D into d0 bsr writ ;write it move.b #$62,d0 ;load B into d0 bsr writ ;write it move.w d1,d0 ;refresh bsr findcon ;print condition bsr spc move.w d1,d0 ;refresh andi.w #$0007,d0 ;mask out reg bsr wdreg ;write reg bsr comma clr.w d0 ;zero d0 so wdis looks for word disp. bsr wdis ;print the address bra disend Scc: move.b #$72,d0 ;load S into d0 bsr writ ;write it move.w d1,d0 ;refresh bsr findcon ;print condition bsr spc move.w d1,d0 bsr writea ;write operand bra disend findcon:lea contab,a0 ;load location of beginning of table andi.w #$0f00,d0 ;mask off the condition ror.w #$07,d0 ;make condition a word offset adda.w d0,a0 ;add to table location to get ascii move.b (a0)+,d0 ;load the first byte bsr writ ;write it move.b (a0)+,d0 ;load the second byte bsr writ ;write it rts contab: .ascii "t " .ascii "f " .ascii "hi" .ascii "ls" .ascii "cc" .ascii "cs" .ascii "ne" .ascii "eq" .ascii "vc" .ascii "vs" .ascii "pl" .ascii "mi" .ascii "ge" .ascii "lt" .ascii "gt" .ascii "le" addq: move.w d1,d0 andi.w #$0100,d0 ;addq/subq bne subq lea mADDQ,a0 ;load "addq" bra qwrit subq: lea mSUBQ,a0 ;load "subq" qwrit: bsr writs ;write it bsr dot move.w d1,d0 bsr findsiz ;write size of operand bsr spc bsr pound bsr dollar move.w d1,d0 andi.w #$0e00,d0 ;mask data rol.w #$07,d0 ;get into rightmost bits bne q8 ;if nonzero, range is 1-7 move.b #$08,d0 ;if zero, range is 8 q8: bsr writb ;write byte bsr comma move.w d1,d0 bsr writea ;write dest bra disend gr6: move.w d1,d0 andi.w #$0f00,d0 ;mask the cond bit bne BSR ;not BRA lea mBRA,a0 ;load "bra" bsr writs ;write it bra Bccw ;go write operand BSR: cmp.w #$0100,d0 ;BSR? bne Bcc ;no lea mBSR,a0 ;load "bsr" bsr writs ;write it bra Bccw ;go write operand Bcc: move.b #$62,d0 ;load a B bsr writ ;write it move.w d1,d0 bsr findcon ;print the condition Bccw: bsr spc move.w d1,d0 bsr wdis ;write the address bra disend gr7: move.w d1,d0 andi.w #$0100,d0 ;check to make sure bne ILLEG lea mMOVEQ,a0 ;load "MOVEQ" bsr writs ;write it bsr spc bsr pound bsr dollar move.b d1,d0 ;load data bsr writb ;write it bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask off the reg bits rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bra disend gr8: move.w d1,d0 andi.w #$01f0,d0 ;mask for SBCD. cmpi.w #$0100,d0 ;is it SBCD? bne DIVS lea mSBCD,a0 ;load "SBCD" xBCD: bsr writs ;write it move.w d1,d0 andi.w #$0008,d0 ;mask reg/memory bit beq sbcdrg ;reg to reg op bsr spc bsr minus bsr lparen move.w d1,d0 andi.w #$0007,d0 ;mask source reg bsr wareg ;print it bsr rparen bsr comma bsr minus bsr lparen move.w d1,d0 andi.w #$0e00,d0 ;mask destination reg rol.w #$07,d0 ;get into rightmost bits bsr wareg ;print it bsr rparen bra disend sbcdrg: bsr spc move.w d1,d0 andi.w #$0007,d0 ;mask source reg bsr wdreg bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask destination reg rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;print it bra disend DIVS: move.w d1,d0 andi.w #$00c0,d0 ;mask mode bits cmpi.w #$00c0,d0 ;is this a DIV operation bne OR ;no. move.w d1,d0 ;yes. andi.w #$0100,d0 ;mask the sign bit beq DIVU ;it's unsigned divide lea mDIVS,a0 ;load "DIVS" bsr writs ;write it bra divprt ;go decode the rest of the command DIVU: lea mDIVU,a0 ;load "DIVU" bsr writs ;write it divprt: bsr spc move.w d1,d0 bsr writea bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask data reg rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;print it bra disend OR: lea mOR,a0 ;load "OR" ANDent: bsr writs ;write it bsr dot move.w d1,d0 bsr findsiz ;print operand size bsr spc move.w d1,d0 andi.w #$0100,d0 ;find destination beq ordreg ;if zero, data reg move.w d1,d0 andi.w #$0e00,d0 ;mask the reg bits rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;and print it bsr comma move.w d1,d0 bsr writea ;write the destination bra disend ordreg: move.w d1,d0 bsr writea ;write the source bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask the reg bits rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;and print it bra disend gr9: lea mSUB,a0 ;load "SUB" bsr writs ;write it ax: move.w d1,d0 andi.w #$00c0,d0 ;mask the size bits cmpi.w #$00c0,d0 ;is it ADDA or SUBA? bne SUB ;no move.b #$61,d0 ;yes, so load an 'A' bsr writ ;write it bsr dot move.w d1,d0 andi.w #$0100,d0 ;mask size bit bne SUBAl ;if set, longword operand move.b #$77,d0 ;load 'W' bsr writ ;write it bra axa ;go print operands SUBAl: move.b #$6c,d0 ;load 'L' bsr writ ;write it bra axa ;go print operands SUB: move.w d1,d0 andi.w #$0130,d0 ;mask appropriate bits cmpi.w #$0100,d0 ;is it ADDX or SUBX? beq SUBX ;yes bsr dot ;no, so continue move.w d1,d0 bsr findsiz ;print the size of the operand axa: bsr spc move.w d1,d0 andi.w #$00c0,d0 ;mask the size bits cmpi.w #$00c0,d0 ;is it ADDA or SUBA beq subea1 ;if so, is first operand move.w d1,d0 andi.w #$0100,d0 ;mask direction bit bne subea2 ;if bit is set, is last operand move.w d1,d0 bsr writea ;write the first operand bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask the reg bits rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;print it bra disend subea1: move.w d1,d0 bsr writea ;write the first operand bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask the reg bits rol.w #$07,d0 ;get into rightmost bits bsr wareg ;print it bra disend subea2: move.w d1,d0 andi.w #$0e00,d0 ;mask the reg bits rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;print it bsr comma move.w d1,d0 bsr writea ;write second operand bra disend SUBX: move.b #$78,d0 ;load an 'X' bsr writ ;write it bsr dot move.w d1,d0 bsr findsiz ;write the operand length bsr spc move.w d1,d0 andi.w #$0008,d0 ;mask reg/memory bit beq SUBXdr ;reg to reg op bsr minus bsr lparen move.w d1,d0 andi.w #$0007,d0 ;mask source reg bsr wareg ;print it bsr rparen bsr comma bsr minus bsr lparen move.w d1,d0 andi.w #$0e00,d0 ;mask destination reg rol.w #$07,d0 ;get into rightmost bits bsr wareg ;print it bsr rparen bra disend SUBXdr: move.w d1,d0 andi.w #$0007,d0 ;mask source reg bsr wdreg bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask destination reg rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;print it bra disend gra: bra ILLEG ;not a valid instruction grb: move.w d1,d0 andi.w #$00c0,d0 ;mask size bits cmpi.w #$00c0,d0 ;size = 11 ? bne CMP ;no. lea mCMPA,a0 ;yes, so load "CMPA" bsr writs ;write it bsr dot move.w d1,d0 andi.w #$0100,d0 ;mask CMPA size bit bne CMPAl ;if nonzero, longword operand move.b #$77,d0 ;load 'W' move.b d0,siz ;save size as 'W' bsr writ ;write it bra CMPAop ;go write operands CMPAl: move.b #$6c,d0 ;load 'L' move.b d0,siz ;save size as 'L' bsr writ ;write it CMPAop: bsr spc move.w d1,d0 bsr writea ;go write source operand bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask reg number rol.w #$07,d0 ;get into rightmost bits bsr wareg ;write it bra disend CMP: move.w d1,d0 andi.w #$0100,d0 ;mask CMP/CMPM bit bne CMPM ;if nonzero, it's CMPM lea mCMP,a0 ;load "CMP" bsr writs ;write it bsr dot move.w d1,d0 bsr findsiz ;write size of operand bsr spc move.w d1,d0 bsr writea ;write source operand bsr comma move.w d1,d0 andi.w #$0e00,d0 ;mask reg number rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bra disend CMPM: move.w d1,d0 andi.w #$0038,d0 ;mask mode bits cmpi.w #$0008,d0 ;is it address reg mode? bne EOR ;if not, it's an EOR lea mCMPM,a0 ;load "CMPM" bsr writs ;write it bsr dot move.w d1,d0 bsr findsiz ;write the operand size bsr spc bsr lparen move.w d1,d0 andi.w #$0007,d0 ;mask source reg bits bsr wareg ;write it bsr rparen bsr plus bsr comma bsr lparen move.w d1,d0 andi.w #$0e00,d0 ;mask destination reg bits rol.w #$07,d0 ;get into rightmost bits bsr wareg ;write it bsr rparen bsr plus bra disend EOR: lea mEOR,a0 ;load "EOR" bsr writs ;write it bsr dot move.w d1,d0 bsr findsiz ;write operand size bsr spc move.w d1,d0 andi.w #$0e00,d0 ;mask reg number rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bsr comma move.w d1,d0 bsr writea ;write destination bra disend grc: move.w d1,d0 andi.w #$01f0,d0 ;mask for ABCD cmpi.w #$0100,d0 ;is it ABCD? bne MULS ;no. lea mABCD,a0 ;load "ABCD" bra xBCD ;go print everything MULS: move.w d1,d0 andi.w #$00c0,d0 ;mask mode bits cmpi.w #$00c0,d0 ;is this a MUL operation? bne EXG ;no. move.w d1,d0 ;yes. andi.w #$0100,d0 ;mask the sign bit beq MULU ;it's unsigned multiply lea mMULS,a0 ;load "MULS" bsr writs ;write it bra divprt ;go decode the rest of the command MULU: lea mMULU,a0 ;load "MULU" bsr writs ;write it bra divprt ;go decode the rest of the command EXG: move.w d1,d0 andi.w #$0130,d0 ;mask for EXG cmpi.w #$0100,d0 ;is it EXG? bne AND ;no. lea mEXG,a0 ;yes, print bsr writs ;write it bsr spc move.w d1,d0 andi.w #$00f8,d0 ;mask op-mode bits cmpi.w #$0040,d0 ;is it Di,Dj? bne EXGaa ;no move.w d1,d0 andi.w #$0e00,d0 ;mask source reg number rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask destination reg number bsr wdreg ;write it bra disend EXGaa: cmpi.w #$0048,d0 ;is it Ai,Aj? bne EXGda ;no move.w d1,d0 andi.w #$0e00,d0 ;mask source reg number rol.w #$07,d0 ;get into rightmost bits bsr wareg ;write it bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask destination reg number bsr wareg ;write it bra disend EXGda: cmpi.w #$0088,d0 ;is it Di,Aj? bne ILLEG move.w d1,d0 andi.w #$0e00,d0 ;mask source reg number rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write it bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask destination reg number bsr wareg ;write it bra disend AND: lea mAND,a0 ;load "AND" bra ANDent ;go write the operation grd: lea mADD,a0 ;load "ADD" bsr writs ;write it, then find out which ADD bra ax ;go find out which ADD it is gre: move.w d1,d0 move.w d1,t1 ;save an extra copy of opcode andi.w #$00c0,d0 ;is this an instruction? cmpi.w #$00c0,d0 bne fshf ;if not, find out which shift move.w d1,d0 ;else adjust the saved opcode ror.w #$06,d0 ;rightward by six bits to allow proper move.w d0,t1 ;decoding of the shift type fshf: move.w t1,d0 ;load the properly adjusted opcode andi.w #$0018,d0 ;mask operation bits of adjusted opcode bne LS ;not AS lea mAS,a0 ;load "AS" bra lr ;find the direction LS: cmpi.w #$0008,d0 ;is it LS? bne ROX ;no lea mLS,a0 ;yes, so load "LS" bra lr ;find the direction ROX: cmpi.w #$0010,d0 ;is it ROX? bne RO ;no lea mROX,a0 ;yes, so load "ROX" bra lr RO: lea mRO,a0 ;load "RO" lr: bsr writs ;write the operation move.w d1,d0 andi.w #$0100,d0 ;mask the direction bit bne lsh ;left shift if bit set move.b #$72,d0 ;load 'r' bra shtyp ;go find the shift type lsh: move.b #$6c,d0 ;load 'l' shtyp: bsr writ ;write the direction move.w d1,d0 andi.w #$00c0,d0 ;mask the size bits cmpi.w #$00c0,d0 ;is the size 11? bne regsh ;if not, it's a reg shift bsr spc move.w d1,d0 bsr writea ;write the operand bra disend regsh: bsr dot move.w d1,d0 bsr findsiz ;print the operand length bsr spc move.w d1,d0 andi.w #$0020,d0 ;mask the immediate/reg bit beq immsh ;if bit clear, it's an immediate shift move.w d1,d0 andi.w #$0e00,d0 ;mask the count reg rol.w #$07,d0 ;get into rightmost bits bsr wdreg ;write count reg bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask destination reg bsr wdreg ;write destination reg bra disend immsh: bsr spc bsr pound bsr dollar move.w d1,d0 andi.w #$0e00,d0 ;mask the count bits rol.w #$07,d0 ;get into rightmost bits bne sh17 ;if not zero, 1-7 bit shift move.b #$08,d0 ;if zero, 8 bit shift sh17: bsr writb ;write it bsr comma move.w d1,d0 andi.w #$0007,d0 ;mask the reg bits bsr wdreg ;write the destination reg bra disend grf: bra ILLEG ;not a valid instruction ; ; message table -- the ascii strings for the instructions ; mCOPOUT:.asciz "COPOUT" mABCD: .asciz "abcd" mADD: .asciz "add" mADDA: .asciz "adda" mADDI: .asciz "addi" mADDQ: .asciz "addq" mADDX: .asciz "addx" mAND: .asciz "and" mANDI: .asciz "andi" mAS: .asciz "as" mBCHG: .asciz "bchg" mBCLR: .asciz "bclr" mBKPT: .asciz "bkpt" mBRA: .asciz "bra" mBSET: .asciz "bset" mBSR: .asciz "bsr" mBTST: .asciz "btst" mCHK: .asciz "chk" mCLR: .asciz "clr" mCMP: .asciz "cmp" mCMPA: .asciz "cmpa" mCMPI: .asciz "cmpi" mCMPM: .asciz "cmpm" mDIVS: .asciz "divs" mDIVU: .asciz "divu" mEOR: .asciz "eor" mEORI: .asciz "eori" mEORIcr:.asciz "eoriccr" mEXG: .asciz "exg" mEXT: .asciz "ext" mILLEG: .asciz "ILLEGAL" mJMP: .asciz "jmp" mJSR: .asciz "jsr" mLEA: .asciz "lea" mLINK: .asciz "link" mLS: .asciz "ls" mMOVE: .asciz "move" mMOVEA: .asciz "movea" mMOVEC: .asciz "movec" mMOVEM: .asciz "movem" mMOVEP: .asciz "movep" mMOVEQ: .asciz "moveq" mMULS: .asciz "muls" mMULU: .asciz "mulu" mNBCD: .asciz "nbcd" mNEG: .asciz "neg" mNEGX: .asciz "negx" mNOP: .asciz "nop" mNOT: .asciz "not" mOR: .asciz "or" mORI: .asciz "ori" mPEA: .asciz "pea" mRESET: .asciz "reset" mRO: .asciz "ro" mROX: .asciz "rox" mRTE: .asciz "rte" mRTR: .asciz "rtr" mRTS: .asciz "rts" mSBCD: .asciz "sbcd" mSTOP: .asciz "stop" mSUB: .asciz "sub" mSUBA: .asciz "suba" mSUBI: .asciz "subi" mSUBQ: .asciz "subq" mSUBX: .asciz "subx" mSWAP: .asciz "swap" mTAS: .asciz "tas" mTRAP: .asciz "trap" mTRAPV: .asciz "trapv" mTST: .asciz "tst" mUNLK: .asciz "unlk" mccr: .asciz "ccr" msr: .asciz "sr" musp: .asciz "usp" spc: move.b #$20,d0 ;load a spc bsr writ ;write it rts comma: move.b #$2c,d0 ;load a comma bsr writ ;write it rts lparen: move.b #$28,d0 ;load a left parenthesis bsr writ ;write it rts rparen: move.b #$29,d0 ;load a right parenthesis bsr writ ;write it rts pound: move.b #$23,d0 ;load a pound sign bsr writ ;write it rts dot: move.b #$2e,d0 ;load a period bsr writ ;write it rts plus: move.b #$2b,d0 ;load a plus bsr writ ;write it rts minus: move.b #$2d,d0 ;load a minus bsr writ ;write it rts dollar: move.b #$24,d0 ;load a dollar sign bsr writ ;write it rts findsiz:andi.w #$00c0,d0 ;mask out the size bits bne wsize ;if nonzero, it's not a byte move.b #$62,siz ;set size to byte bra findend wsize: cmpi.w #$0040,d0 ;is it a word operand? bne lsize ;no. move.b #$77,siz ;set size to word bra findend lsize: move.b #$6c,siz ;set size to longword findend:move.b siz,d0 bsr writ ;write the size rts wareg: swap d0 ;save the reg number in upper 16 bits move.b #$61,d0 ;load 'a' bsr writ ;write it swap d0 ;restore the reg number ori.b #$30,d0 ;add offset to get digit bsr writ ;write it rts wdreg: swap d0 ;save the reg number in upper 16 bits move.b #$64,d0 ;load 'a' bsr writ ;write it swap d0 ;restore the reg number ori.b #$30,d0 ;add offset to get digit bsr writ ;write it rts mPC: .asciz "pc" mIAM: .asciz "ILLEGAL ADDRESS MODE" writea: move.b d0,writm ;save the important part of the opcode andi.b #$38,d0 ;mask off all but the mode bits bne mode1 ;if zero, it's data reg direct move.b writm,d0 andi.b #$07,d0 ;mask the reg number bsr wdreg ;write the data reg bra eaout mode1: cmpi.b #$08,d0 ;is it address reg direct? bne mode2 ;no move.b writm,d0 ;yes andi.b #$07,d0 ;mask reg number bsr wareg ;write address reg bra eaout mode2: cmpi.b #$10,d0 ;is it address reg indirect? bne mode3 ;no bsr lparen ;yes move.b writm,d0 andi.b #$07,d0 ;mask reg number bsr wareg ;write address reg bsr rparen bra eaout mode3: cmpi.b #$18,d0 ;is it postincrement? bne mode4 ;no bsr lparen ;yes move.b writm,d0 andi.b #$07,d0 ;mask reg number bsr wareg ;write address reg bsr rparen bsr plus bra eaout mode4: cmpi.b #$20,d0 ;is it predecrement? bne mode5 ;no bsr minus ;yes bsr lparen move.b writm,d0 andi.b #$07,d0 ;mask reg number bsr wareg ;write address reg bsr rparen bra eaout mode5: cmpi.b #$28,d0 ;is it reg indirect w/ displacement? bne mode6 ;no bsr dollar move.w (a1)+,d0 ;yes, so load 16 bit displacement bsr writw ;write it bsr lparen move.b writm,d0 andi.b #$07,d0 ;mask reg number bsr wareg ;write address reg bsr rparen bra eaout mode6: cmpi.b #$30,d0 ;is it reg indirect w/ index? bne mode7 ;no bsr dollar move.w (a1),d0 ;load the index word bsr writb ;write the 8 bit displacement bsr lparen move.b writm,d0 andi.b #$07,d0 ;mask reg number bsr wareg ;write address reg bsr comma m6ad: move.w (a1),d0 ;load index word again bpl m6d ;if MSB of index word is 0, data reg rol.w #$04,d0 ;rotate reg number into rightmost bits andi.w #$0007,d0 ;mask reg number bsr wareg ;write address reg bra m6no m6d: rol.w #$04,d0 ;rotate reg number into rightmost bits andi.w #$0007,d0 ;mask reg number bsr wdreg ;write data reg m6no: bsr dot move.w (a1)+,d0 ;load the index reg a final time andi.w #$0800,d0 ;mask the length bit bne m6l ;if nonzero, long reg index move.b #$77,d0 ;load 'w' bsr writ ;write it bsr rparen bra eaout m6l: move.b #$6c,d0 ;load 'l' bsr writ ;write it bsr rparen bra eaout mode7: move.b writm,d0 ;mode seven, so decode reg number andi.w #$07,d0 ;mask reg number bne m71 ;if zero, absolute.w bsr dollar move.w (a1)+,d0 ;move the address into d0 bsr writw ;write it bra eaout m71: cmpi.b #$01,d0 ;is it absolute.l? bne m72 ;no bsr dollar move.l (a1)+,d0 ;yes, so move the address into d0 bsr writl ;write it bra eaout m72: cmpi.b #$02,d0 ;is it relative w/ displacement? bne m73 ;no bsr dollar move.w (a1)+,d0 ;yes, so load displacement into d0 bsr writw ;write it bsr lparen lea mPC,a0 ;load "PC" bsr writs ;write it bsr rparen bra eaout m73: cmpi.b #$03,d0 ;is it relative w/ index? bne m74 ;no bsr dollar move.w (a1),d0 ;load the index word bsr writb ;write the 8 bit displacement bsr lparen lea mPC,a0 ;load "PC" bsr writs ;write it bsr comma bra m6ad ;go to reg. indir. routine to finish m74: cmpi.b #$04,d0 ;is it immediate? bne m75 ;no bsr pound bsr dollar move.b siz,d0 ;load the size byte cmpi.b #$62,d0 ;is it byte data? bne m74w ;no move.w (a1)+,d0 ;yes, so load immediate data bsr writb ;write byte data bra eaout m74w: cmpi.b #$77,d0 ;is it word data? bne m74l ;no move.w (a1)+,d0 ;yes, so load immediate data bsr writw ;write word data bra eaout m74l: move.l (a1)+,d0 ;load long immediate data bsr writl ;write long data bra eaout m75: lea mIAM,a0 ;load illegal mode message bsr writs ;write it eaout: rts wdis: swap d0 ;save opcode in upper 16 so we can bsr dollar ;hexidecimalize the displacement swap d0 ;get it back in lower 16 move.l a1,d1 ;copy current address to d1 tst.b d0 ;is displacement zero? beq wdisw ;if so, word displacement andi.l #$00ff,d0 ;mask off the displacement ext.w d0 ;sign extend the displacement ext.l d0 ;to word size add.l d0,d1 ;add 8-bit displacement to address move.l d1,d0 ;copy into d0 bsr writl ;write address bra wdiso wdisw: move.w (a1)+,d0 ;load the displacement word ext.l d0 ;sign extend it add.l d0,d1 ;add displacement move.l d1,d0 ;copy to d0 bsr writl wdiso: rts