[comp.sys.m68k] MON68K - 68000 Monitor program part 1/4

thomasw@vlsi1.CS.Concordia.CA (Thomas Wieland 1728423) (10/18/89)

As promised several days ago, here is the source code for the 68000 monitor
I wrote some time ago.  Sorry that it took so long, but I had to upload it
to my university account and then make it a bit more presentable.

Thanks to George Kyriazis (kyriazis@rdrc.rpi.edu), druks!jamesc@att.att.com,
and to Jeff Turner (jeff@uf.msc.umn.edu) who each provided me with a shar
script or program and to Daniel Berglund (FOPERATOR@tekno.chalmers.se) who
told me where I could get one.  And yes, I had it installed on our systems.

If you have any comments, feel free to drop me a line.

Enjoy,

Thomas


Thomas Wieland                       Email:  thomasw@jupiter.cs.concordia.ca
Dept. of Computer Science               or:  thomasw@concour.cs.concordia.ca
Concordia University
Montreal, PQ  Canada                 Phone:  (514) 848-3039

---------------------------------- clip here ----------------------------------

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	MANIFEST
#	mon68.main.s
#	mon68.cmds.s
# This archive created: Tue Oct 17 19:46:49 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(10093 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'

            MON68K - A monitor for Motorola M68000-based systems
            ====================================================


Written by Thomas Wieland, 1984
Donated to the public domain, 17th October 1989 


This file is is intended as a quick introduction to MON68K: what it is,
how it came into being, some notes on the files etc.


History
-------

In 1983, I purchased a 68000 processor board for my Apple II; this board was
called a DTACK (Grounded) board and was manufactured by a small company named
Digital Acoustics in Santa Ana, CA.  The board was designed as a single-board
computer which was attached to the Apple through a simple parallel port; the
board was simple, but fast: just the processor and some static memory running
at 12.5 MHz (DTACK was grounded, therefore no waitstates).  With the board came
some sample programs, a couple of floating point libraries, and little else.
Eventually, some programs were written by other owners, such as a Apple-based
monitor and a BASIC compiler, and distributed through a software exchange.
Probably the two most successful products used with the board were a 68000
crossassembler running on a basic Apple II (ie. without using the DTACK board,
see below) and a very nice adaption of the Apple/UCSD p-system which ran
completely on the 68000 side and used the Apple merely as an I/O processor.
A few years later, with the advent of the Atari ST, Digital Acoustics stopped
producing hardware, went into developping an incremental BASIC compiler
for the ST, and that was the last I ever heard of them.

The DTACK board was a bare-bones  design, and provided only a boot PROM which
supported commands to upload and download blocks of memory and to transfer
control from the boot PROM to an address in 68K memory.  Any program that was
to run on the board therefore had to include a part which was to run on the
Apple II which would upload and start the 68000 part and that had to support
(as a minimum) commands for reading from the Apple keyboard and writing to the
Apple screen as the DTACK board did not have any I/O connectors.

I started developing MON68K to get a 68K-based monitor going on the DTACK
board, and to familiarize myself with 68K assembly language.  As there was
no operating system on the 68K side of things, my design included two parts,
one which was running on the Apple and provided a file system interface, and
the other which was running on the DTACK board and was the monitor proper.
I am only posting the code for the 68K monitor here, as it is pretty much
self-contained and I don't think the Apple part is useful to anyone on this net.

I finished writing the monitor in the middle of 1984 and released it through
the software exchange, but after that I got too busy with moving to Canada and
then going to school, that I never went back to doing much more with the DTACK
board.  That is also part of the reason it took me as long as it did to get the
sources posted; not only did I first have to find them, I also had to then
tranfer them between different Apple operating systems, and upload them to
my account at university.


Some Notes on the Assembler
---------------------------

The assembler I was using to develop MON68K was called ASSEM68K from a company
called Phase0 in (I believe) Arizona, no doubt long since gone.  ASSEM68K was a
floppy disk-based assembler which uses Apple II DOS 3.3; it produced a binary
load image which could be transferred to the DTACK board by a utility program.

I believe the assembler syntax is pretty much standard; I noticed, however,
that the Sun-OS assembler (I don't know about other UNIX assemblers) combines
the opcode and the operand size into one word (eg. movel, addw etc) whereas
ASSEM68K separates the opcode and its size by a period (eg. MOVE.L, ADD.W);
this latter is also the format used by the disassembler.  In addition, ASSEM68K
makes no distinction between upper- and lowercase as early Apple II's didn't
have lowercase characters.

By default, ASSEM68K assumes that the operand size is word, so the operand size
for a word operand does not have to (but may be) specified; eg, ADD D0,D1 will
be treated like ADD.W D0,D1.  ASSEM68K also uses default settings for forward
references when assembling code; these can be changed using the three pseudo-ops
listed below.  Backward references always assemble in the shortest possible
address format.

    BRANCH  S|W   assemble forward branches with a byte (B) or word (W) offset  
    FWRD    W|L   assemble forward operand references using a word (W) or
                  longword (L) address.
    SHORT   7|F   use short addressing up to $7FFF (7) or up to $FFFF (F) (*)

Some of the assembler pseudo-ops provided by ASSEM68K are listed below to avoid
any interpretation problems that might arise from other assemblers' syntax.

       ORG    <expr>,<file> assemble object at address <expr> and save to <file>
<lbl>  EQU    <expr>        equate label <lbl> to the address given by <expr>
       DC.s   <expr>        define constant storage; reserves space for the
                            constant and intializes it to <expr>
       DS.s   <expr>        define storage; reserve <expr> bytes, words, or
                            longwords of unintialized storage
       CHAIN  <file>        chain to sourcefile <file>
       ASC    <string>      reserve string storage and initialize it to <string>
       ACZ    <string>      like ASC, but add a zero byte at the end of <string>
       LIST                 generate assembler listing and symbol table
       NOLIST               suppress assembler listing and symbol table

where:

  s=B|W|L   a size  specification: byte (B), word (W), longword (L)
  <lbl>     a label name
  <expr>    an expression
  <file>    a file name
  <string>  an ASCII string enclosed in single or double quotes


(*) Note:  the DTACK board includes some special address decoding hardware
           to fix the 68000's "zero page bug" (or feature), which results from
           sign-extending word-length addresses and which splits the 64K of
           memory which can be addressed using short (word) addresses into a
           low (0..$7FFF) and a high part ($FF8000..$FFFFFF).  This hardware
           maps the high part back down into the address range $8000..$FFFF,
           reducing the total addressable space by 32K but resulting in a
           contiguous 64K zero page.  The SHORT pseudo-op tells the assembler
           which zero page mapping is in effect; even though MON68K has been
           assembled with SHORT=F (64K zero page), it should not make a
           difference to the code as it doesn't extend past $3A00.
           


MON68K Files
------------

As mentioned above, I had not looked at the source files for MON68K for more
than five years at the time I offered posting them.  As I don't have the time
for it now, I have not edited them significantly and have not tried to improve
or change the code at all.  I would have done a few things differently now that
I have done them once, especially in the disassembler, but for the time being
I'm not going to change anything; at least I know for a fact that this version
works and is reasonably bug-free.  I did, however, split the source files up
into more manageable parts and added some comments in places I felt it was
necessary (ie. where I had trouble figuring out what was going on).  I also
commented out a selftest routine which was used by the Apple part of the code
to determine if the monitor code had been corrupted and moved some routines
into the hardware-specific file.

There are also some chapters of the original disk-based manual included with
this post (chapters dealing with the Apple part of the code were not included).
I have not edited these at all, except for deleting some of the Apple-specific
parts that I felt were not appropriate, so please excuse any spelling or
grammatical mistakes in them.

The following files were posted to the net:

File name      Contents
--------------------------------------------------------------------------------
README         this file
MANIFEST       list of files and file lengths
mon68.main.s   equates; cold/warm start, main command loop
mon68.cmds.s   subroutines implementing monitor commands
mon68.csub.s   aux. subroutines used by monitor command subroutines
mon68.exce.s   exception handlers 
mon68.dasm.s   disassembler & disasm support routines
mon68.spec.s   hardware-specific subroutines; these rely on/are
               used by support routines on the host (6502) side
mon68.io.s     line editor & I/O subroutines
mon68.tbl.s    data area: vector/jump tables, text/mask tables for
               disassembler, monitor texts, monitor data area
mon68.ch3.doc  documents the available monitor commands 
mon68.ch5.doc  documents some of the internals of the monitor routines
mon68.qref     quick reference to monitor commands and line editor control keys



Last Words
----------

I hope the code will be of help to those of you who are doing a 68K-based
project; I realize it will take some work to transfer it to other systems,
but I think it is a reasonable starting point.  I would appreciate any comments
you may have about the monitor and would like to hear about any bugs you find
and any uses that you put the code to.  Of course, I would also be interested
in seeing how others have solved the same problem.

If you wish to contact me, you can write to me at the address below or send
me e-mail (the account will be valid at least until April 90) at:

        thomasw@jupiter.cs.concordia.ca
    or: thomasw@concour.cs.concordia.ca

Home Address:  Thomas Wieland     
               4615 Walkley #21
               Montreal, PQ
               H4B 2K7
               Canada


===============================================================================
Thomas Wieland                       Email:  thomasw@jupiter.cs.concordia.ca
Dept. of Computer Science               or:  thomasw@concour.cs.concordia.ca
Concordia University
Montreal, PQ  Canada                 Phone:  (514) 848-3039
SHAR_EOF
if test 10093 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 10093 characters)'
fi
fi
echo shar: "extracting 'MANIFEST'" '(228 characters)'
if test -f 'MANIFEST'
then
	echo shar: "will not over-write existing file 'MANIFEST'"
else
cat << \SHAR_EOF > 'MANIFEST'
README		10093
MANIFEST	228
mon68.main.s	7708
mon68.cmds.s	20768
mon68.csub.s	11276
mon68.exce.s	8040
mon68.dasm.s	17308
mon68.spec.s	3606
mon68.io.s	16417
mon68.tbl.s	7821
mon68.ch3.doc	39010
mon68.ch5.doc	30933
mon68.qref	5665
SHAR_EOF
if test 228 -ne "`wc -c < 'MANIFEST'`"
then
	echo shar: "error transmitting 'MANIFEST'" '(should have been 228 characters)'
fi
fi
echo shar: "extracting 'mon68.main.s'" '(7708 characters)'
if test -f 'mon68.main.s'
then
	echo shar: "will not over-write existing file 'mon68.main.s'"
else
cat << \SHAR_EOF > 'mon68.main.s'
****************************
*                          *
*           MON68K         *
*                          *
*  A 68000 Monitor Program *
*                          *
*  VERSION 2.2  15-JUL-84  *
*                          *
****************************
*
*
*  mon68.main.s: equates; cold/warm start, main command loop
*
*
*  Source code donated to the public domain, 17 Oct 1989
*
*  You may use this code in any way you see fit, including
*  incorporating some or all of it into a project of your own,
*  commercial or otherwise.  I would appreciate receiving some
*  credit if you decide to use some of my code, but as this is
*  quite unenforceable it remains a wish, not a condition.
*
*  Naturally, I can make no guarantees as to the code's correctness
*  or suitability for any purpose, although I would hope that it is
*  both reasonably correct and suitable for something, and I know
*  that it works on my equipment.
*
*  If you wish to contact me, you can write to me at the address
*  below or send me e-mail (until April 90) at:
*
*        thomasw@jupiter.cs.concordia.ca
*    or: thomasw@concour.cs.concordia.ca
*
*  Written by:  Thomas Wieland     
*               4615 Walkley #21
*               Montreal, PQ
*               H4B 2K7
*               Canada
*
*
*
*
* SET ASSEMBLER SWITCHES
*
 BRANCH S
 FWRD W
 SHORT F
*
*
 ORG $10F4,MON68K
*
*
* ASCII CONSTANTS
*
NUL EQU $00 ;ASCII NUL
BEL EQU $07
BS EQU $08 ;BACKSPACE
CR EQU $0D ;CARRIAGE RETURN
SPC EQU $20 ;BLANK
DQT EQU $22 ;DOUBLE QUOTE
SQT EQU $27 ;SINGLE QUOTE
*
* FLAG DEFINITIONS FOR FLAGREGISTER (D7)
*
CURSOR EQU 0 ;CURSOR CHAR. VALID
INSMOD EQU 1 ;INSERT MODE
DELIM EQU 0 ;BLANKS ARE DELIMITERS
ASCTYP EQU 1 ;0/1=LOW/HIGH ASCII
ASCLST EQU 2 ;INSIDE OF ASCII LIST
NUMFND EQU 3 ;GETNUM FOUND NUMBER
SADR EQU 4 ;STARTADR. SPECIFIED
EADR EQU 5 ;ENDADR. SPECIFIED
TBLERR EQU 6 ;ERROR COND IN TABLE S/R
EXTTBL EQU 7 ;EXTENDED TABLE
*
* DTACK BOARD EQUATES
*
IDLE EQU $122 ;BOOT PROM IDLE ROUTINE
*
DATIN EQU $FF8 ;DATA INPUT PORT
* NOTE: R/W DECODES TO DIFFERENT PORTS
DATOUT EQU $FFA ;DATA OUTPUT PORT (W)
STATUS EQU $FFA ;I/O STATUS PORT (R)
*
VECTOR EQU $1000 ;EXCEPTION VECTOR TABLE
PRIVVI EQU $1024 ;PRIV. VIOLATION VECTOR
DISASMSP EQU $10AE ;TEMP. SP FOR DISASSEMBLER
SYSREG EQU $10B2 ;SAVE AREA FOR PROC.REGS
SYSSP EQU SYSREG+60 ;STACK POINTER
SYSSTAT EQU SYSREG+64 ;SAVE AREA FOR STAT.REG
*
* MONITOR EQUATES
*
NTBL EQU 8 ;Number of ENTRIES IN monitor TABLES (1..NTBL)
*
* Note: $37E0 is no "magic number", it's just an address that
*       leaves a reasonable amount of stack space after the
*       end of the code as determined by assembling the code
*       and looking at where it ends.  This could be done more
*       elegantly using symbols, but the assembler I was using
*       at the time couldn't handle all the forward references.
*
INBUF EQU $37E0 ;also top of monitor stack area
LSTBUF EQU INBUF+$100 ;for byte lists
* PROGRAM FLAGS (LAST THREE BYTES OF LSTBUF ARE NEVER USED)
TRCFLAG EQU LSTBUF+$FE ;GO/TRACE/SINGLE STEP FLAG
PROMPT EQU LSTBUF+$FF ;CURRENT PROMPT CHARACTER
BITBUF EQU LSTBUF+$100 ;flags wildcards in byte list
BUFTOP EQU BITBUF+$20 ;last byte+1 of buffers
*
*
*
*********************************
* BOOT PROM COMMAND VECTORTABLE *
*********************************
*
CMD10 DC.W CLDSTRT ;COLDSTART ENTRY POINT
CMD11 DC.W WRMSTRT ;WARMSTART ENTRY POINT
CMD12 DC.W STEST68 ;TEST 68000 CODE (FROM 6502)
CMD13 DC.W MEMSIZE ;DETERMINE MEMORY SIZE
CMD14 DC.W MONENTP ;GET MONITOR ENTRY POINTS
*
* UNUSED VECTORS GO BACK TO IDLE
*
CMD15 DC.W IDLE
CMD16 DC.W IDLE
CMD17 DC.W IDLE
CMD18 DC.W IDLE
CMD19 DC.W IDLE
CMD1A DC.W IDLE
CMD1B DC.W IDLE
CMD1C DC.W IDLE
CMD1D DC.W IDLE
CMD1E DC.W IDLE
CMD1F DC.W IDLE
CMD20 DC.W IDLE
*
*
*********************************
* MONITOR COLDSTART ENTRY POINT *
*********************************
*
*
CLDSTRT MOVEA #INBUF,SP ;SET SSP
 JSR MEMSIZE ;DETERMINE MEMORY SIZE
 MOVE.L A0,RAMHIGH ;SAVE HIGHEST RAM ADDRESS
 MOVE.L A0,CMDHIGH ;SET UPPER LIMIT FOR COMMANDS
 MOVE.L A0,HILIM ;SET UPPER LIMIT FOR EXECUTION
 JSR PRTCLSC ;CLEAR SCREEN
 MOVE #HEADTXT,A0
 JSR PRTTEXT ;SEND HEADER
 MOVE.L RAMLOW,D2
 JSR PRTLHEX ;DISPLAY LOW RAM ADDRESS
 JSR PRTTEXT ;SECOND PART OF TEXT
 MOVE.L RAMHIGH,D2
 JSR PRTLHEX ;DISPLAY HIGH RAM ADDRESS
 JSR PRTTEXT ;THIRD PART OF TEXT
*
*
*********************************
* MONITOR WARMSTART ENTRY POINT *
*********************************
*
*
WRMSTRT MOVEA #INBUF,SP ;SET SSP TO BOTTOM OF BUFFERS
 MOVEA #EVECTBL,A0
 MOVEA #VECTOR+4,A1
 MOVEQ #26-1,D0 ;26 EXCEPTION VECTORS
SETEVECT MOVE (A0)+,(A1)+ ;SET JUMPS TO EXCEPTION HANDLERS
 ADDQ #4,A1
 DBF D0,SETEVECT
WRMSTRT1 MOVE.B #'M',PROMPT ;SET MONITOR PROMPT
 JSR GETLIN ;GET LINE OF INPUT
*
**************************
* MAIN COMMAND PROCESSOR *
**************************
*
CMDPROC MOVEQ #0,D7 ;CLEAR FLAGS
 MOVE A5,-(SP) ;SAVE TXTPTR
 JSR GETCHRNS
 BVC CMDPROC1
 ADDQ #2,SP ;DROP TXTPTR
 BRA WRMSTRT1 ;INPUT LINE WAS EMPTY OR ALL BLANKS
CMDPROC1 CMPI.B #'A',D0
 BCS CMDPROC3 ;CHAR < 'A'
 CMPI.B #'B',D0
 BHI CMDPROC3 ;CHAR > 'B'
 JSR GETCHRNS ;GET SECOND CHAR.
 BVS CMDPROC2 ;'A' OR 'B' SUBMODE
 CMPI.B #';',D0
 BNE CMDPROC3 ;CAN'T BE 'A' OR 'B' SUBMODE
CMDPROC2 MOVEA (SP)+,A5
 JSR GETCHRNS ;GET COMMAND LETTER
 SUBQ #1,A5 ;POINT A5 TO CMD CHAR.
 BRA CMDPROC7 ;EXECUTE COMMAND
CMDPROC3 MOVE (SP)+,A5 ;RESTORE TXTPTR
 JSR GETNUM ;GET FIRST ADDRESS
 BTST #NUMFND,D7
 BEQ CMDPROC4 ;NO NUMBER WAS FOUND
 BSET #SADR,D7 ;SIGNAL &
 MOVEA.L D1,A1 ;SAVE START ADDRESS (CCR UNAFFECTED)
CMDPROC4 BVS CMDPROC6 ;SINGLE ADDRESS => EXAMINE
 CMPI.B #'.',D0
 BNE CMDPROC7 ;D0 MUST BE CMDLETTER NOW
 ADDQ #1,A5 ;ADVANCE TO NEXT CHAR.
 JSR GETNUM ;GET SECOND ADDRESS
 BTST #NUMFND,D7
 BNE CMDPROC5
 BSR ERROR2 ;'.' MUST BE FOLLOWED BY ADDRESS
 BRA CMDPROC
CMDPROC5 BSET #EADR,D7 ;SIGNAL &
 MOVEA.L D1,A2 ;SAVE END ADDRESS (CCR UNAFFECTED)
 BVC CMDPROC7 ;TWO ADDRESSES MUST BE FOLLOWED BY A CMD LETTER
CMDPROC6 MOVEQ #'X',D0 ;SET X(AMINE AS DEFAULT
CMDPROC7 MOVE #CMDTEND-CMDTBL,D1 ;COUNT= NO. OF CMDLETTERS-1
 MOVEA #CMDTEND+1,A0 ;+1 FOR PREDECR.
CMDPROC8 CMP.B -(A0),D0
 BEQ CMDPROC9 ;COMMAND LETTER FOUND
 DBF D1,CMDPROC8 ;LOOP THROUGH ALL CMD LETTERS
 BSR ERROR1 ;NO COMMAND LETTER FOUND
 BRA CMDPROC
CMDPROC9 ADD D1,D1 ;DOUBLE TO USE AS INDEX
 MOVEA D1,A0
 MOVE JMPTBL(A0),A0 ;GET SUBROUTINE ADDRESS
 JSR (A0) ;EXECUTE COMMAND SUBROUTINE
 BRA CMDPROC ;GET NEXT COMMAND
*
* ERROR #n
*
ERROR1 MOVEQ #1,D0
 BRA ERRHDL
ERROR2 MOVEQ #2,D0
 BRA ERRHDL
ERROR3 MOVEQ #3,D0
 BRA ERRHDL
ERROR4 MOVEQ #4,D0
 BRA ERRHDL
ERROR5 MOVEQ #5,D0
*
* ERROR HANDLER
* D0.B : ERROR CODE
* (SP) : RETURN ADDRESS FOR CONT'D EXECUTION
*
ERRHDL CMPA A5,A6 ;AT END OF BUFFER ?
 BNE ERRHDL1
 SUBQ #1,A5 ;DON'T PRINT CR
ERRHDL1 ADDQ #1,A5 ;CHAR. AFTER ERROR
 MOVE.B (A5),D1 ;SAVE BUFFER CONTENTS
 MOVE D1,-(SP)
 MOVE D0,-(SP) ;SAVE ERROR CODE
 CLR.B (A5) ;MARK END OF TEXT
 MOVEA #INBUF,A0 ;SET TO START OF BUFFER
 JSR PRTCR
 JSR PRTTEXT ;PRINT CONTENTS OF BUFFER
 JSR PRTEOP ;CLEAR TO EOP
 JSR PRTLF
 JSR PRTBS
 MOVEQ #'^',D0
 JSR SENDBYTE ;MARK ERROR POSITION
 JSR PRTCR
 JSR PRTBEL
 MOVE #ERRTXT,A0 ;SET TO START OF ERROR TABLE
 MOVE (SP)+,D0 ;GET ERROR CODE BACK
 BRA ERRHDL3
ERRHDL2 MOVE.B (A0)+,D1 ;SET A0 TO START
 BNE ERRHDL2 ;OF ERROR MESSAGE
ERRHDL3 DBF D0,ERRHDL2
 JSR PRTTEXT ;PRINT ERROR MESSAGE
 MOVE #ERRTXT1,A0
 JSR PRTTEXT
 MOVE (SP)+,D0 ;RESTORE BUFFER
 MOVE.B D0,(A5)
 SUBQ #1,A5
 MOVEQ #6,D0
 JSR PRTSFCT ;6=GET 'Y' OR 'N'
 JSR GETBYTE ;GET ANSWER
 MOVE D0,D1 ;SAVE ANSWER
 JSR PRTCR
 CMPI.B #'Y',D1
 BEQ ERRHDL5 ;YES, CONTINUE
ERRHDL4 ADDQ #4,SP ;DROP RETURN ADDRESS
 BRA WRMSTRT1 ;GET NEW LINE
*
ERRHDL5 JSR SKIPNXT ;SKIP UNTIL ';'
 BVS ERRHDL4
 RTS  ;CONTINUE WITH NEXT CMD
*
*
 CHAIN MON68.CMDS.S
SHAR_EOF
if test 7708 -ne "`wc -c < 'mon68.main.s'`"
then
	echo shar: "error transmitting 'mon68.main.s'" '(should have been 7708 characters)'
fi
fi
echo shar: "extracting 'mon68.cmds.s'" '(20768 characters)'
if test -f 'mon68.cmds.s'
then
	echo shar: "will not over-write existing file 'mon68.cmds.s'"
else
cat << \SHAR_EOF > 'mon68.cmds.s'
****************************
*                          *
*           MON68K         *
*                          *
*  A 68000 Monitor Program *
*                          *
*  VERSION 2.2  15-JUL-84  *
*                          *
****************************
*
*
*  mon68.cmds.s: subroutines implementing monitor commands
*
*
*  Source code donated to the public domain, 17 Oct 1989
*
*  You may use this code in any way you see fit, including
*  incorporating some or all of it into a project of your own,
*  commercial or otherwise.  I would appreciate receiving some
*  credit if you decide to use some of my code, but as this is
*  quite unenforceable it remains a wish, not a condition.
*
*  Naturally, I can make no guarantees as to the code's correctness
*  or suitability for any purpose, although I would hope that it is
*  both reasonably correct and suitable for something, and I know
*  that it works on my equipment.
*
*  If you wish to contact me, you can write to me at the address
*  below or send me e-mail (until April 90) at:
*
*        thomasw@jupiter.cs.concordia.ca
*    or: thomasw@concour.cs.concordia.ca
*
*  Written by:  Thomas Wieland     
*               4615 Walkley #21
*               Montreal, PQ
*               H4B 2K7
*               Canada
*
*
*
*
* ';'  SEPARATES COMMANDS
*
COLON ADDQ #1,A5 ;ADVANCE TO NEXT CHAR.
 RTS
*
* TEST FOR FIRST, GET SECOND OPERAND
*
TSTOP BTST #SADR,D7
 BNE TSTOP1 ;1.OPERAND GIVEN
 MOVEA.L LASTRES,A1 ;DEFAULT: LAST RESULT
TSTOP1 BTST #EADR,D7
 BNE TSTOP3 ;2.OPERAND NOT ALLOWED
 ADDQ #1,A5 ;ADVANCE TO CHAR. AFTER OPERATOR
 JSR GETNUM ;2.OPERAND IN D1.L
 BTST #NUMFND,D7
 BEQ TSTOP2 ;2.OPERAND NOT GIVEN
 MOVE.L A1,D2 ;1.OPERAND IN D2.L
 RTS
TSTOP2 ADDQ #4,SP ;DROP RETURN ADR.
 BRA ERROR3 ;RETURNS TO CMDPROC
TSTOP3 ADDQ #4,SP
 BRA ERROR4
*
* SIGNAL ARITHMETIC OVERFLOW
*
OVL MOVEQ #'C',D0
OVL0 JSR SENDBYTE
 MOVEQ #'=',D0
 JSR SENDBYTE
 MOVEQ #'1',D0
 JSR SENDBYTE ;SEND 'C=1' OR 'V=1'
 JSR PRTBEL
 JMP PRTCR ;EXIT
*
* ADD TWO OPERANDS
*
PLUS BSR TSTOP
 ADD.L D1,D2
 BCC.L SAVERES
 BCS MINUS1 ;SIGNAL CARRY
*
* SUBTRACT TWO OPERANDS
*
MINUS BSR TSTOP
 SUB.L D1,D2
 BCC SAVERES
MINUS1 BSR OVL ;SIGNAL BORROW
 BRA SAVERES
*
* MULTIPLY TWO 16 BIT OPERANDS
*
MULT BSR TSTOP
 TST D1
 BEQ MULT0 ;2.OP=0
 TST D2
 BEQ MULT0 ;1.OP=0
 MULU D1,D2
 BRA SAVERES
MULT0 MOVEQ #0,D2 ;RESULT=0
 BRA SAVERES
*
* DIVIDE A 32 BIT BY A 16 BIT OPERAND
*
DIVID BSR TSTOP
 TST D1
 BEQ ERROR5 ;DIVIDE BY 0
 TST.L D2
 BEQ MULT0 ;1.OPERAND=0
 DIVU D1,D2 ;HIGH/LOW WORD=D2 MOD D1/D2 DIV D1
 BVC DIVID1
 MOVEQ #'V',D0
 BSR OVL0 ;OPERAND OR RESULT OVERFLOW
 SWAP D2
 CLR.W D2 ;CLEAR 'MODULO'
 SWAP D2
DIVID1 SWAP D2
 MOVE D2,-(SP) ;SAVE D2 MOD D1
 CLR.W D2
 SWAP D2
 BSR SAVERES ;DISPLAY & SAVE D2 DIV D1
 MOVEQ #0,D2
 MOVE (SP)+,D2
 BRA CONVERT0 ;DISPLAY D2 MOD D1 & EXIT
*
* SHIFT OPERAND LEFT  BY COUNT
*
SHFTL BSR TSTOP
 LSL.L D1,D2
 BRA SAVERES
*
* SHIFT OPERAND RIGHT BY COUNT
*
SHFTR BSR TSTOP
 LSR.L D1,D2
 BRA SAVERES
*
* ROTATE OPERAND LEFT  BY COUNT
*
ROL BSR TSTOP
 ROL.L D1,D2
 BRA SAVERES
*
* ROTATE OPERAND RIGHT BY COUNT
*
ROR BSR TSTOP
 ROR.L D1,D2
 BRA SAVERES
*
* LOGICAL AND TWO OPERANDS
*
AND BSR TSTOP
 AND.L D1,D2
 BRA SAVERES
*
* LOGICAL OR  TWO OPERANDS
*
OR BSR TSTOP
 OR.L D1,D2
 BRA SAVERES
*
* LOGICAL EOR TWO OPERANDS
*
EOR BSR TSTOP
 EOR.L D1,D2
*
* SAVE RESULT OF OPERATION & PRINT IT
*
SAVERES MOVE.L D2,LASTRES
 BRA CONVERT0
*
* CONVERT 32-BIT DATA
*
CONVERT BTST #SADR,D7
 BEQ ERROR3 ;NO DATA
 BTST #EADR,D7
 BNE ERROR4 ;2.OPERAND NOT ALLOWED
 ADDQ #1,A5 ;ADVANCE TO CHAR. AFTER "="
 MOVE.L A1,D2 ;GET DATA
CONVERT0 JSR PRTEOL ;CLEAR LINE
 JSR PRTDOL
 JSR PRTLHEX ;DISPLAY AS HEX
 MOVEQ #16,D0
 BSR HTABN ;POS. FOR DECIMAL
 JSR PRTPND
 JSR PRTLDEC ;DISPLAY AS DECIMAL
 MOVEQ #32,D0
 BSR HTABN ;POS. FOR ASCII
 JSR PRTLASC ;DISPLAY AS ASCII
 JSR PRTCR
 JSR PRTEOL
 JSR PRTPCT
 JSR PRTLBIN ;DISPLAY AS BINARY
 JMP PRTCR ;NEW LINE & RETURN
*
HTABN MOVE D0,-(SP) ;SAVE HTAB
 MOVEQ #3,D0
 JSR PRTSFCT ;3=HTAB n
 MOVE (SP)+,D0 ;GET HTAB
 JMP SENDBYTE ;SEND COUNT & RETURN
*
* ASSEMBLER SUBMODE
*
ASMSUB MOVE.B #'A',PROMPT
 ADDQ #1,A5
 MOVEQ #0,D0
 BRA ERRHDL ;NOT IMPLEMENTED
*
* BREAKPOINT SUBMODE
*
BRKSUB MOVE.B #'B',PROMPT
 ADDQ #1,A5
BRKSUB1 JSR GETCHRNS ;GET FIRST CHAR
 BVC BRKSUB2
 JSR GETLIN
 BRA BRKSUB1
BRKSUB2 CMPI.B #';',D0
 BEQ BRKSUB1 ;SKIP COLONS
 CMPI.B #'Q',D0
 BEQ.L BRKSUB8 ;EXIT BREAKPOINT SUBMODE
 CMPI.B #'K',D0
 BEQ.L CLRBRK ;KILL BREAKPOINT TABLES
 CMPI.B #'P',D0
 BEQ.L DSPBRK ;SHOW ALL BREAKPOINTS
 CMPI.B #'L',D0
 BEQ.L SETLLIM ;SET LOW  LIMIT
 CMPI.B #'H',D0
 BEQ.L SETHLIM ;SET HIGH LIMIT
 CMPI.B #'M',D0
 BEQ.L SETMBRK ;SET MEMORY BREAKPOINT
 CMPI.B #'X',D0
 BEQ.L DELBRK ;DELETE (MEM) BREAKPOINT
BRKSUB3 SUBQ #1,A5
 BSR GETBRK ;GET ADDRESS OF BREAKPOINT
 CMPI.B #',',D0 ;GETNUM RETURNS NEXT CHAR. <> ' '
 BNE BRKSUB4 ;NO COUNT GIVEN
 MOVE.L D1,D3 ;SAVE ADDRESS
 ADDQ #1,A5
 BSR GETBRK ;COUNT MUST FOLLOW NOW
 MOVE D1,D2 ;SET COUNT
 MOVE.L D3,D1 ;RESTORE ADDRESS
 BRA BRKSUB5
BRKSUB4 MOVEQ #0,D2 ;SET COUNT=0
BRKSUB5 BSR MAKEEVEN
 MOVEA #BRKTBL,A3 ;SET TABLE ADDRESS
 BCLR #EXTTBL,D7
 JSR ADDTBL ;ADD BREAKPOINT
 MOVEA #BTBLTXT,A0
BRKSUB6 BTST #TBLERR,D7
 BEQ BRKSUB7
 JSR PRTTEXT ;ERROR: TABLE FULL
 ADDQ #6,A0
 JSR PRTTEXT
BRKSUB7 JSR SKIPNXT
 BRA BRKSUB1
BRKSUB8 RTS
BRKERR JSR PRTBEL ;ERROR IN COMMAND
 BRA BRKSUB7
* CLEAR BREAKPOINT TABLES
CLRBRK MOVEA #LWLIM,A3
 MOVEA #MBRKXTBL,A4
 MOVE.L #BUFTOP,(A3)+ ;RESET LOW  LIMIT
 MOVE.L RAMHIGH,(A3)+ ;RESET HIGH LIMIT
 BCLR #EXTTBL,D7
 JSR CLRTBL ;CLEAR BRK TABLE
 BSET #EXTTBL,D7
 JSR CLRTBL ;CLEAR MEMBRK & EXTENDED TABLES
 BRA BRKSUB7
*
GETBRK JSR GETNUM ;GET ADDRESS
 BRA GETBRKS1
*
GETBRKS JSR GETADRS ;GET ADDRESS + SIZE
GETBRKS1 BTST #NUMFND,D7
 BEQ GETBRKS2 ;NO ADDRESS GIVEN
 RTS
GETBRKS2 ADDQ #4,SP ;DROP RETURN ADDRESS
 BRA BRKERR ;ERROR & NEXT COMMAND
* SET LOW LIMIT
SETLLIM BSR GETBRK
 BSR MAKEEVEN
 MOVE.L D1,LWLIM ;SET LOW  LIMIT FOR EXECUTION
 BRA BRKSUB7
* SET HIGH LIMIT
SETHLIM BSR GETBRK
 BSR MAKEEVEN
 MOVE.L D1,HILIM ;SET HIGH LIMIT FOR EXECUTION
 BRA BRKSUB7
* MAKE ADDRESS IN D1 EVEN
MAKEEVEN BCLR #0,D1
 RTS
* SET MEMORY BREAKPOINT
SETMBRK BSR GETBRKS ;GET ADR & SIZE
 JSR GETCHRNS
 CMPI.B #',',D0
 BNE BRKERR ;',' MUST FOLLOW
 MOVE.L D1,-(SP) ;SAVE ADR FIELD
 MOVE D2,-(SP) ;SAVE TAG FIELD
 JSR GETNUM ;GET CONTENTS FIELD
 MOVE.L D1,D3
 MOVE (SP)+,D2 ;RESTORE TAG FIELD
 MOVE.L (SP)+,D1 ;RESTORE ADR FIELD
 BTST #NUMFND,D7
 BEQ BRKERR ;CONTENTS FIELD MUST FOLLOW
 CMPI.B #2,D2
 BHI SETMBRK2 ;SIZE = LONG
 BEQ SETMBRK1 ;SIZE = WORD
 ANDI.W #$00FF,D3 ;SIZE = BYTE
SETMBRK1 SWAP D3
 CLR.W D3 ;CLEAR UPPER WORD
 SWAP D3
SETMBRK2 CMPI.B #1,D2
 BEQ SETMBRK3
 BSR MAKEEVEN
SETMBRK3 MOVEA #MBRKTBL,A3 ;SET TABLE ADDRESSES
 MOVEA #MBRKXTBL,A4
 BSET #EXTTBL,D7
 JSR ADDTBL ;ADD MEM BRKPNT TO TABLES
 MOVEA #MBTBLTXT,A0 ;SET ERROR MESSAGE
 BRA BRKSUB6 ;TEST FOR ERROR & CONTINUE
* DELETE A BREAKPOINT
DELBRK BSR GETBRK ;GET ADDRESS TO DELETE
 MOVEA #BRKTBL,A3
 BCLR #EXTTBL,D7
 JSR DELTBL ;TRY TO DELETE IN BRK TABLE
 BTST #TBLERR,D7
 BEQ BRKSUB7 ;ENTRY FOUND
 MOVEA #MBRKXTBL,A4
 BSET #EXTTBL,D7
 JSR DELTBL ;TRY TO DELETE IN MEMBRK TABLE
 BRA BRKSUB7
* DISPLAY ALL TABLES
DSPBRK JSR PRTCR
 MOVEA #BRKTXT,A0
 JSR PRTTEXT
 MOVEA #BRKTBL,A3
 BSR.L DBRKTST ;TEST FOR ENTRIES
 MOVEQ #NTBL-1,D5
DSPBRK1 MOVE.L (A3)+,D2 ;GET TABLE ENTRY
 MOVE.W (A3)+,D4
 BMI DSPBRK2 ;EMPTY ENTRY, FINISHED
 BSR.L DBRKADR
 MOVEQ #SPC,D0
 MOVEQ #4,D3
 JSR PRTNCHR ;PRINT 4 SPACES
 MOVE.B D4,D1
 JSR PRTDOL ;PRINT COUNT
 JSR PRTHEX ;IN HEX
 JSR PRT2SPC
 JSR PRTPND
 JSR PRTDEC ;AND DECIMAL
 JSR PRTCR
 DBF D5,DSPBRK1
DSPBRK2 JSR PRTCR
 MOVEA #MBRKTXT,A0
 JSR PRTTEXT
 MOVEA #MBRKTBL,A3
 MOVEA #MBRKXTBL,A4
 BSR DBRKTST
 MOVEQ #NTBL-1,D5
DSPBRK3 MOVE.L (A3)+,D2 ;GET ADDRESS
 MOVE.W (A3)+,D3 ;GET SIZE
 BMI DSPBRK7 ;EMPTY ENTRY, FINISHED
 MOVE.L (A4)+,D4 ;GET CONTENTS
 BSR DBRKADR
 MOVEQ #'.',D0
 JSR SENDBYTE
 MOVE.L D4,D2 ;GET CONTENTS
 SUBQ.B #2,D3 ;TEST SIZE
 BHI DSPBRK5 ;SIZE = LONG
 BEQ DSPBRK4 ;SIZE = WORD
 MOVEQ #'B',D0
 BSR DBRKSIZE
 MOVE.B D2,D1 ;GET BYTE TO DISPLAY
 JSR PRTHEX ;PRINT DATA BYTE
 BRA DSPBRK6
DSPBRK4 MOVEQ #'W',D0
 BSR DBRKSIZE
 JSR PRTWHEX ;PRINT DATA WORD
 BRA DSPBRK6
DSPBRK5 MOVEQ #'L',D0
 BSR DBRKSIZE
 JSR PRTLHEX ;PRINT DATA LONGWORD
DSPBRK6 JSR PRTCR
 DBF D5,DSPBRK3
DSPBRK7 JSR PRTCR
 MOVEA #LADRTXT,A0
 JSR PRTTEXT
 ADDQ #4,A0
 MOVE.L LWLIM,D2
 BSR DBRKLIM ;PRINT LOW  LIMIT
 MOVEA #HADRTXT,A0
 MOVE.L HILIM,D2
 BSR DBRKLIM ;PRINT HIGH LIMIT
 BRA BRKSUB7
* TEST IF >=1 ENTRY IN TABLE
DBRKTST TST.B 4(A3)
 BMI DBRKTST1 ;NO ENTRY
 JMP PRTCR
DBRKTST1 JMP PRTTEXT
* DISPLAY ENTRY NUMBER & ADDRESS
DBRKADR MOVEQ #NTBL,D1
 SUB.B D5,D1 ;CALC. ENTRY NO., 1..NTBL
 JSR PRTPND
 JSR PRTDEC ;ENTRY # (3 CHAR.S)
 JSR PRTSPC
 JSR PRTDOL
 JMP PRTLHEX ;ADDRESS
* DISPLAY SIZE
DBRKSIZE JSR SENDBYTE
 JSR PRT2SPC
 JMP PRTDOL
* DISPLAY TEXT & LOW/HIGH ADDRESS
DBRKLIM JSR PRTTEXT
 JSR PRTLHEX
 JMP PRTCR
*
* CHANGE MEMORY FROM SADR TO BYTES IN LIST
*
CHANGE JSR SADRNXT
 ADDQ #1,A5 ;ADVANCE TO START OF LIST
 JSR GETLIST
 TST.B D2
 BEQ CHANGE5 ;EMPTY LIST, EXIT
CHANGE0 SUBQ #1,D2 ;ADJUST INDEX
CHANGE1 CMPA A3,A4
 BHI CHANGE2
 MOVEA D3,A3 ;RESET TO START OF LSTBUF
CHANGE2 MOVE.B (A3)+,D1 ;GET BYTE
 BNE CHANGE3
 JSR TSTWCD ;IS IT ZERO OR WILDCARD ?
 BNE CHANGE6
CHANGE3 MOVE.B D1,(A1)+ ;CHANGE MEMORY
CHANGE4 DBF D2,CHANGE1
 MOVE.L A1,NXTADR ;SAVE DEFAULT ADDRESS
CHANGE5 RTS
CHANGE6 ADDQ #1,A1 ;WILDCARD, LEAVE MEMORY ALONE
 BRA CHANGE4
*
* EXECUTE USER PROGRAM
*
GOUSER JSR SADRPC ;GET SADR
 ADDQ #1,A5 ;ADVANCE TO NEXT CHAR
 JSR GETCHRNS
 BVS GOUSER2 ;ONLY ONE 'G'
 CMPI.B #'G',D0
 BNE GOUSER1
 BSET #5,USRSTAT ;SET SUPERVISOR MODE
 BCLR #7,USRSTAT ;NO TRACE
 BSR GETSP
 MOVE.L #RTNSUP,-(A0) ;SET SUPERVISOR RETURN ADDRESS
 SUBQ.L #4,A0 ;SET TO DUMMY RETURN ADR
 MOVE.L A0,SP ;SET SSP
 BRA GOUSER4
GOUSER1 SUBQ #1,A5 ;ADJUST TXTPTR
GOUSER2 CLR.B TRCFLAG ;0 <=> GO
GOUSER3 BCLR #5,USRSTAT ;SET USER MODE
 BSET #7,USRSTAT ;INVISIBLE TRACE
 BSR GETSP
 MOVE.L #RTNUSR,-(A0) ;SET USER RETURN ADDRESS
 SUBQ.L #4,A0 ;SET TO DUMMY RETURN ADR
 MOVE A0,USP
GOUSER4 MOVE.L A1,(A0) ;SET START ADDRESS
 MOVEM.L USRREG,D0-A6 ;SET UP USRREGS
 MOVE USRSTAT,SR
 RTS  ;START TRACE AT (A1)
* SAVE PROCESSOR REGISTERS,
* GET & CHECK USER STACKPOINTER
GETSP MOVEM.L D0-A6,SYSREG ;SAVE SYSTEM REGS
 MOVE SR,SYSSTAT
 MOVE.L SP,A0
 ADDQ.L #4,A0 ;ADJUST FOR RETURN ADDRESS
 MOVE.L A0,SYSSP
 MOVE.L USRSP,D0 ;GET USER STACKPOINTER
 MOVE.L RAMHIGH,D1
 ADDQ.L #1,D1 ;SET TO HIGHEST POSSIBLE SP
 CMPI.L #BITBUF,D0
 BCS GETSP1 ;USP < BITBUF
 CMP.L D1,D0
 BLS GETSP2 ;USP <= RAMHIGH+1
GETSP1 MOVE.L D1,D0 ;SET USP TO TOP OF RAM
GETSP2 BCLR #0,D0 ;WORD-ALIGN USP
 MOVE.L D0,A0
 RTS
*
* HELP FACILITY
*
HELP MOVEQ #8,D0
 JSR PRTSFCT ;8=HELP
 ADDQ #1,A5
 JSR GETCHRNS
 BVS HELPALL
 CMPI.B #';',D0
 BEQ HELPALL
HELP1 JMP SENDBYTE ;SEND (OPTIONAL) PARAMETER
HELPALL MOVEQ #SPC,D0 ;ALL COMMANDS
 BRA HELP1
*
* INSERT BYTELIST AT START ADDRESS, MOVE MEMORY
*
INSERT JSR EADRLST
 EXT.L D2 ;CLEAR HIGH WORD
 MOVE.L A1,-(SP) ;SAVE SADR (DESTROYED BY MOVE)
 MOVE.L A1,A3
 ADDA.L D2,A3 ;DADR=SADR+NO. OF BYTES
 CMPA A3,A2
 BCS INSERT1 ;DON'T MOVE IF DADR>EADR
 SUBA.L D2,A2 ;EADR=EADR-NO. OF BYTES
 JSR MOVE0 ;MOVE RANGE UP
INSERT1 MOVE.L (SP)+,A1
 MOVE D3,A3 ;RESTORE POINTER TO LSTBUF
 BRA CHANGE0 ;NOW INSERT BYTELIST
*
* FILL MEMORY FROM SADR THROUGH EADR WITH PATTERN IN LIST
*
FILL JSR EADRLST
 SUBQ.B #1,D2
 BEQ FILLB ;ONLY ONE BYTE IN LIST
FILL1 CMPA.L A1,A2
 BCS FILL5 ;END OF RANGE
 CMPA A3,A4
 BHI FILL2
 MOVE D3,A3 ;RESET LIST POINTER TO START
FILL2 MOVE.B (A3)+,D1 ;GET BYTE FROM LIST
 BNE FILL3 ;CAN'T BE WILDCARD
 JSR TSTWCD
 BNE FILL4 ;CHAR. IS WILDCARD
FILL3 MOVE.B D1,(A1)+ ;FILL MEMORY
 BRA FILL1
FILL4 ADDQ.L #1,A1 ;ADVANCE TO NEXT BYTE
 BRA FILL1
FILL5 MOVE.L A1,NXTADR ;SAVE DEFAULT ADDRESS
FILL6 RTS
* LIST IS ONLY ONE BYTE
FILLB MOVEA D4,A4 ;SET TO BITBUF
 BTST D2,(A4) ;D2=0, TEST BIT 0 FOR ONLY BYTE
 BNE FILL6 ;THE ONLY BYTE IS A WILDCARD
 MOVE.B (A3)+,D1 ;GET BYTE
FILLB1 CMPA.L A1,A2
 BCS FILL5 ;END OF RANGE
 MOVE.B D1,(A1)+ ;FILL MEMORY
 BRA FILLB1
*
* DISASSEMBLE RANGE OF INSTRUCTIONS
*
LIST JSR SADRPC ;GET START ADDRESS
 JSR EADRCNT ;GET END ADDRESS
 BTST #EADR,D7
 BEQ LIST2 ;NO EADR => COUNT=# INSTRUCTIONS
LIST1 JSR DISASM ;DISPLAY, DISASSEMBLE & ADVANCE A1
 CMPA.L A1,A2
 BCC LIST1
 BRA LIST3
LIST2 JSR DISASM
 DBF D1,LIST2
LIST3 MOVE.L A1,PCADR ;SAVE NEXT PC
 RTS
*
* MOVE MEMORY FROM STARTADR THROUGH ENDADR TO DESTADR
*
MOVE JSR DESTADR
MOVE0 CMPA.L A1,A3
 BEQ MOVE3 ;IGNORE IF SADR=DADR
 BCS MOVE2 ;DADR<SADR
 CMPA.L A2,A3
 BHI MOVE2 ;SADR<DADR & EADR<DADR
* RANGES OVERLAP (SADR<DADR<=EADR), MOVE FROM END
 ADDA.L A2,A3
 SUBA.L A1,A3 ;DADR=DADR+(EADR-SADR)
 ADDQ.L #1,A3 ;ADJUST FOR PREDECR
 ADDQ.L #1,A2 ;ADJUST FOR PREDECR
MOVE1 CMPA.L A2,A1
 BCC MOVE3 ;ALL DONE IF EADR<=SADR
 MOVE.B -(A2),-(A3)
 BRA MOVE1 ;NEXT BYTE
* RANGES DON'T OVERLAP, MOVE FORWARD
MOVE2 CMPA.L A1,A2
 BCS MOVE3 ;ALL DONE IF SADR>EADR
 MOVE.B (A1)+,(A3)+
 BRA MOVE2
MOVE3 RTS
*
* OUTPUT CONTROL SUBMODE
*
OUTSUB MOVE.B #'O',PROMPT
 BCLR #EXTTBL,D7 ;ONLY REGULAR TABLES
 ADDQ #1,A5
OUTSUB1 JSR GETCHRNS ;GET FIRST CHAR
 BVC OUTSUB2
 JSR GETLIN
 BRA OUTSUB1
OUTSUB2 CMPI.B #';',D0
 BEQ OUTSUB1 ;SKIP COLONS
 CMPI.B #'Q',D0
 BEQ OUTSUB4 ;EXIT OUTPUT SUBMODE
 CMPI.B #'K',D0
 BEQ CLROUT ;KILL OUTPUT TABLE
 CMPI.B #'P',D0
 BEQ DSPOUT ;GIVE SAMPLE OUTPUT
 CMPI.B #'H',D0
 BEQ.L SETCMDH ;SET HIGHEST MEM.ADR FOR COMMANDS
 CMPI.B #'M',D0
 BEQ SETMOUT ;SET MEMORY ADDRESS
 CMPI.B #'X',D0
 BEQ DELOUT ;CLEAR MEM ADR OR REGS
 SUBQ #1,A5 ;RESET TO FIRST CHAR.
 JSR GETRLST ;SET REGISTERS
 TST.L D6
 BEQ OUTSUB3 ;INVALID LIST
 OR.L D6,REGMASK ;SET REGISTER MASK
OUTSUB3 JSR SKIPNXT
 BRA OUTSUB1
OUTSUB4 RTS
OUTERR JSR PRTBEL ;SIGNAL ERROR
 BRA OUTSUB3
* CLEAR OUTPUT TABLE
CLROUT MOVEA #REGMASK,A3
 CLR.L (A3)+ ;CLEAR REGISTER MASK
 JSR CLRTBL ;CLEAR OUTPUT TABLE
 MOVE.L RAMHIGH,CMDHIGH ;RESET HIGHEST MEM. ADDRESS
 BRA OUTSUB3
* SHOW SAMPLE OUTPUT
DSPOUT MOVEA #REGMASK,A3
 MOVEA #USRREG,A4
 JSR PRTMREG ;DISPLAY REG & MEM
 BRA OUTSUB3
* SET MEMORY ADDRESS TO DISPLAY
SETMOUT JSR GETADRS ;GET ADDRESS & SIZE
 BTST #NUMFND,D7
 BEQ OUTERR ;NO ADDRESS GIVEN
 CMPI.B #1,D2
 BEQ SETMOUT1
 JSR MAKEEVEN ;DISPLAY W/L ONLY AT EVEN ADDRESS
SETMOUT1 MOVEA #OUTTBL,A3
 JSR ADDTBL
 BTST #TBLERR,D7
 BEQ OUTSUB3
 MOVEA #OTBLTXT,A0
 JSR PRTTEXT ;ERROR: TABLE FULL
 BRA OUTSUB3
* DELETE REGISTERS OR ADDRESS
DELOUT JSR GETRLST ;GET REG LIST
 TST.L D6
 BEQ DELOUT1 ;NO REGISTER LIST
 AND.L REGMASK,D6 ;CLEAR REGS NOT YET SET
 EOR.L D6,REGMASK ;CLEAR REGISTERS
 BRA OUTSUB3
DELOUT1 JSR GETNUM ;TRY FOR ADDRESS
 BTST #NUMFND,D7
 BEQ OUTERR ;ADDRESS OR REGLIST MUST FOLLOW
 MOVEA #OUTTBL,A3
 JSR DELTBL ;DELETE ENTRY
 BRA OUTSUB3
* SET HIGHEST DEFAULT MEMORY ADDRESS
SETCMDH JSR GETNUM ;TRY TO GET ADDRESS
 BTST #NUMFND,D7
 BEQ SETCMDH1
 MOVE.L D1,CMDHIGH
SETCMDH1 MOVEA #CMDHTXT,A0
 JSR PRTTEXT
 MOVE.L CMDHIGH,D2
 JSR PRTLHEX
 JSR PRTCR
 BRA OUTSUB3
*
* PRINTER CONTROL
*
PRINTER ADDQ #1,A5 ;ADVANCE TO NEXT CHAR.
 MOVEQ #7,D0
 JMP PRTSFCT ;TOGGLE 6502 PRTFLAG & RETURN
*
* QUIT : RETURN TO EXEC MODE
*
QUIT MOVEQ #0,D0
 JSR PRTSFCT ;0=RETURN TO E-MODE
 JMP IDLE ;BACK TO DTACK MONITOR
*
* REGISTER SUBMODE: DISPLAY & SET REGISTERS
*
REGSUB MOVE.B #'R',PROMPT
 ADDQ #1,A5 ;ADVANCE TO FIRST CHAR
REGSUB1 MOVEA #USRREG,A4 ;DISPLAY USER REGS
REGSUB2 MOVEQ #$FF,D6 ;DISPLAY ALL REGS
 JSR PRTREG
REGSUB3 JSR GETCHRNS ;GET FIRST CHAR.
 BVC REGSUB4
 JSR GETLIN ;GET NEW INPUT LINE
 BRA REGSUB3
REGSUB4 CMPI.B #';',D0
 BEQ REGSUB3 ;SKIP ';'
 CMPI.B #'Q',D0
 BEQ REGSUB8 ;EXIT SUBMODE
 CMPI.B #'K',D0
 BEQ CLRREG ;CLEAR USER REGS
 CMPI.B #'P',D0
 BEQ PROCREG ;DISPLAY PROCESSOR REGS
 CMPI.B #'I',D0
 BEQ SETINT
 SUBQ #1,A5 ;RESET TO FIRST CHAR.
 JSR GETRLST ;TRY FOR REGISTER LIST OR 'SR'
 TST.L D6
 BMI SETSTAT ;SET STATUS REG
 BNE SETREG ;SET REGISTERS
 MOVEA #FLGLST,A0
 MOVEQ #7-1,D1 ;7 FLAGS LEFT
REGSUB5 CMP.B (A0)+,D0
 BEQ.L SETFLAG ;SET A SINGLE FLAG
 DBF D1,REGSUB5
REGSUB6 JSR PRTBEL ;SIGNAL ERROR
 JSR SKIPNXT ;SKIP TO NEXT COMMAND
 BRA REGSUB3
REGSUB7 JSR SKIPNXT ;SKIP TO NEXT COMMAND (NO ERROR)
 BRA REGSUB1
REGSUB8 RTS
* CLEAR USER REGISTERS
CLRREG MOVEQ #0,D0
 MOVEQ #33-1,D1 ;33 WORDS= D0-SR
 MOVEA #USRREG,A0
CLRREG1 MOVE D0,(A0)+
 DBF D1,CLRREG1
 MOVE.L RAMHIGH,D0
 ADDQ.L #1,D0
 MOVE.L D0,USRSP ;SET SP = TOP OF RAM +1
 BRA REGSUB7
* DISPLAY PROCESSOR REGISTERS
PROCREG MOVEM.L D0-D7/A0-A7,SYSREG
 MOVE SR,SYSSTAT ;SAVE PROCESSOR REGS
 MOVEA #SYSREG,A4 ;DISPLAY PROCESSOR REGS
 JSR SKIPNXT
 BRA REGSUB2 ;DISPLAY REGISTERS
* SET INTERRUPT MASK
SETINT JSR GETNUM07 ;GET I-MASK
 BTST #NUMFND,D7
 BEQ REGSUB6
 MOVE.B USRSTAT,D1 ;GET SYSTEM BYTE
 ANDI.B #%11111000,D1 ;CLEAR I-MASK
 OR.B D0,D1 ;SET I-MASK
 MOVE.B D1,USRSTAT ;SAVE SYSTEM BYTE
 BRA REGSUB7
* SET STATUS REGISTER
SETSTAT JSR GETNUM ;GET DATA FOR SR
 BTST #NUMFND,D7
 BEQ REGSUB6 ;NO DATA GIVEN
 MOVE D1,USRSTAT ;SET STATUS REGISTER
 BRA REGSUB7
* SET USER REGISTERS
SETREG JSR GETNUM ;GET DATA FOR REGS
 BTST #NUMFND,D7
 BEQ REGSUB6 ;NO DATA GIVEN
 MOVEA #USRREG,A0
 MOVEQ #16-1,D0
SETREG1 LSR #1,D6
 BCC SETREG3 ;REG NOT SPECIFIED
 MOVE.L D1,(A0)+ ;SET REGISTER
SETREG2 DBF D0,SETREG1
 BRA REGSUB7
SETREG3 ADDQ #4,A0 ;SKIP REGISTER
 BRA SETREG2
* SET A STATUS FLAG
SETFLAG CMPI.B #'T',D0
 BNE SETFLAG1
 MOVEQ #15,D1 ;SET FOR TRACE FLAG
 BRA SETFLAG2
SETFLAG1 CMPI.B #'S',D0
 BNE SETFLAG2
 MOVEQ #13,D1 ;SET FOR SUPERVISOR FLAG
SETFLAG2 ADDQ #1,A5 ;ADVANCE TO CHAR AFTER FLAGNAME
 JSR GETNUM01 ;GET STATE OF FLAG IN D0
 BTST #NUMFND,D7
 BEQ REGSUB6
 MOVE USRSTAT,D2 ;GET STATUS REGISTER
 LSR #1,D0
 BCS SETFLAG3
 BCLR D1,D2 ;CLEAR FLAG
 BRA SETFLAG4
SETFLAG3 BSET D1,D2 ;SET FLAG
SETFLAG4 MOVE D2,USRSTAT ;SAVE STATUS REGISTER
 BRA REGSUB7
*
* SEARCH RANGE FROM SADR THROUGH EADR FOR BYTELIST
*
SEARCH JSR EADRLST
 SUBQ.B #1,D2
 BEQ SEARCHB ;ONLY ONE BYTE TO LOOK FOR
SEARCH1 CMPA.L A1,A2
 BCS SEARCH10 ;END OF RANGE
 MOVE.B (A1)+,D2 ;GET MEM. BYTE
 MOVE.B (A3)+,D1 ;LIST BYTE
 BNE SEARCH2 ;NO WILDCARD
 JSR TSTWCD
 BNE SEARCH3 ;WCD
SEARCH2 CMP.B D1,D2
 BEQ SEARCH5 ;FIRST BYTES MATCH
 MOVEA D3,A3 ;RESET TO START OF LSTBUF
 BRA SEARCH1 ;TRY NEXT BYTE
SEARCH3 CMPA A3,A4
 BHI SEARCH1 ;STILL MORE CHAR. IN LIST
SEARCH4 RTS  ;EXIT, LIST IS ALL WILDCARDS
SEARCH5 MOVE.L A1,-(SP) ;SAVE ADR. OF NEXT BYTE
SEARCH6 CMPA.L A1,A2
 BCS SEARCH9 ;NO MATCH POSSIBLE
 CMPA A3,A4
 BLS SEARCH8 ;END OF LIST, MATCH FOUND
 MOVE.B (A1)+,D2 ;MEM. BYTE
 MOVE.B (A3)+,D1 ;LIST BYTE
 BNE SEARCH7 ;NO WILDCARD
 JSR TSTWCD
 BNE SEARCH6 ;WCD, MEM. BYTE IRRELEVANT
SEARCH7 CMP.B D1,D2
 BEQ SEARCH6 ;MATCH STILL POSSIBLE
 MOVEA D3,A3 ;RESET LIST POINTER
 MOVEA.L (SP)+,A1 ;SET MEM. PTR TO NEXT BYTE
 BRA SEARCH1 ;START OVER
SEARCH8 MOVEA.L (SP)+,A1 ;GET ADDRESS OF MATCH
 MOVE.L A1,D2
 BSR VFYPRT1 ;PRINT MATCH ADDRESS
 BRA SEARCH1
SEARCH9 ADDQ #4,SP ;DROP MEM.PTR
SEARCH10 MOVE.L A1,NXTADR ;SAVE DEFAULT ADDRESS
 JMP PRTCR
* LIST IS ONLY ONE BYTE
SEARCHB MOVEA D4,A4 ;SET TO BITBUF
 BTST D2,(A4) ;D2=0, TEST BIT 0 FOR ONLY BYTE
 BNE SEARCH4 ;THE ONLY BYTE IS WILDCARD
 MOVE.B (A3)+,D3 ;GET SEARCH BYTE
SEARCHB1 CMPA.L A1,A2
 BCS SEARCH10 ;END OF RANGE
 CMP.B (A1)+,D3
 BNE SEARCHB1 ;NO MATCH
 MOVE.L A1,D2
 BSR VFYPRT1 ;PRINT MATCH ADDRESS
 BRA SEARCHB1
*
* TRACE USER PROGRAM
*
TRACE JSR SADRPC ;GET SADR
 JSR EADRCNT ;GET EADR
 CMPA.L A2,A1
 BHI TRACE1 ;NOTHING TO TRACE
 ST TRCFLAG ;$FF <=> SINGLE STEP
 BRA GOUSER3
TRACE1 JMP PRTBEL
*
* COMPARE TWO MEMORY RANGES
* Output FORMAT: AAAAAA: HH C  -  AAAAAA: HH C
*   AAAAAA - 3-byte address (hex); HH - hex, C - ASCII
*
VERIFY JSR DESTADR
VERIFY1 CMPA.L A1,A2
 BCS VERIFY2 ;END OF RANGE
 MOVE.B (A1)+,D3 ;GET ORIGINAL BYTE
 CMP.B (A3)+,D3 ;COMPARE WITH BYTE AT DEST ADR
 BEQ VERIFY1 ;NEXT BYTE
 MOVE.L A1,D2
 BSR VFYPRT1 ;PRINT ORIG ADR
 MOVE.B D3,D1
 JSR VFYPRT2 ;PRINT ORIG BYTE
 JSR PRT2SPC
 JSR PRTMIN
 JSR PRT2SPC
 MOVE.L A3,D2
 BSR VFYPRT1 ;PRINT COMP ADR
 MOVE.B -1(A3),D1
 JSR VFYPRT2 ;PRINT COMP BYTE
 JSR PRTCR ;NEW LINE
 BRA VERIFY1
VERIFY2 RTS
*
VFYPRT1 SUBQ.L #1,D2 ;ADJUST POSTINCR
 JSR PRTADR
 JMP PRTSPC
*
VFYPRT2 JSR PRTHEX
 JSR PRTSPC
 JMP PRTASC
*
* EXAMINE MEMORY
* Output FORMAT: AAAAAA:HH HH HH HH HH HH HH HH CCCCCCCC
*   AAAAAA - 3-byte address (hex); HH - hex, C - ASCII
*
XAMINE JSR SADRNXT ;GET START ADDRESS
 JSR EADRCNT ;GET END ADDRESS
XAMINE1 MOVE.L A1,D2
 JSR PRTADR ;SEND ADDRESS & ':'
 MOVEQ #7,D3 ;HTAB HEX AREA
 MOVEQ #31,D4 ;HTAB ASCII AREA
XAMINE2 MOVE.B (A1)+,D1 ;GET BYTE
 JSR PRTHEX
 MOVE.B D4,D0
 JSR HTABN ;HTAB TO ASCII AREA
 JSR PRTASC ;PRINT AS ASCII
 CMPA.L A1,A2
 BCS XAMINE4 ;A1>A2, END OF RANGE
 MOVE.L A1,D2
 ANDI #%00000111,D2
 BEQ XAMINE3 ;END OF LINE
 ADDQ #3,D3 ;UPDATE HTABS
 ADDQ #1,D4
 MOVE.B D3,D0
 JSR HTABN ;HTAB TO HEX AREA
 BRA XAMINE2 ;NEXT BYTE
XAMINE3 JSR PRTCR
 BRA XAMINE1 ;NEXT LINE
XAMINE4 MOVE.L A1,NXTADR ;SAVE NEXT MEMORY ADDRESS
 JMP PRTCR ;NEW LINE & EXIT
*
*
 CHAIN MON68.CSUB.S
SHAR_EOF
if test 20768 -ne "`wc -c < 'mon68.cmds.s'`"
then
	echo shar: "error transmitting 'mon68.cmds.s'" '(should have been 20768 characters)'
fi
fi
exit 0
#	End of shell archive