	CHIP 68332
   ORG $XXXXX000     ; link monitor on 4k boundary

********************************************************************************
*
* Customizable Emulation Monitor for HP64751 Motorola 68340 Emulator
*
********************************************************************************
* MKT:@(#) 64751-18003 A.00.00 68340 EMULATION FOREGROUND MONITOR       23Apr92                                   

* @(SUBID) MP: M64751FM   0.04  23Apr92 14:24:51                   
********************************************************************************
*  The emulation monitor is the vehicle by which the following emulator
*  functions are performed:
*
*      read/write emulation/target memory space
*      display/modify 68340 registers
*      execute user program
*      break away from user program
*
*  The 64751 foreground monitor must start on a 4K byte boundary (address
*  ends in $000).  The desired 4K byte boundary should be specified in the
*  "ORG" statement at the start of the monitor.  The same 32 bit address must
*  be specified in the emulator configuration question "cf monaddr=XXXXX000".
*  In this manner, communication between the foreground monitor and the
*  emulator operating software can be established.
*
*  The first few sections of the foreground monitor should not be modified
*  and their location with respect to the start of the foreground monitor
*  must not be altered.  These include the following:
*
*      Monitor Vector Table
*      Monitor Variables
*      Monitor Transfer Buffer
*      Monitor Interrupt Stack
*      Key Monitor Entry Routines
*
*  The Monitor Vector Table is primarily used by the emulator to transition
*  into the foreground monitor from reset, from software breakpoints, or from
*  emulator generated breaks (e.g.  write-to-ROM).  The initialized entries
*  in this table are used to program special circuitry on the emulator
*  and are not used for exception processing.  Under no circumstances can the
*  Monitor Vector Table be altered in size or location with respect to the
*  start of the foreground monitor.
*
*  If the monitor is located at address 0, the Monitor Vector Table can also
*  be used as the 68340 exception table.  If this is done, the user is free
*  to use any vector entries except 1 (reset pc), 4 (illegal instruction),
*  and 31 (level 7 autovector).  These entries are reserved by the emulator
*  and extreme care must be taken to ensure these these entries are not
*  corruptted.  The user is expected to change Vector 0 (reset stack) since
*  the monitor's stack only provides 256 bytes.
*
*  The Monitor Variables section contains a group of variables that act as
*  the communications path between the monitor and the emulator controller,
*  and contains a copy of the 68340 registers which are saved on entry to
*  the monitor and restored on exit.  The Monitor Transfer Buffer is used
*  to hold data which is transfered between the emulator controller and the
*  target system memory.  The Monitor Interrupt Stack is a minimal stack
*  area used when entering the monitor from reset.
*
*  The Key Monitor Entry routines are RESET_ENTRY, INTERRUPT_ENTRY,
*  BREAKPOINT_ENTRY, BACKGROUND_ENTRY, BACKGROUND_RESET_ENTRY and TRACE_ENTRY.
*  These routines cannot be modified or moved with respect to the start 
*  of the foreground monitor.
*
*  To perform single stepping with the foreground monitor, the Trace Vector in
*  the 68340 exception table must point to the TRACE_ENTRY in the foreground
*  monitor.
********************************************************************************

********************************************************************************
* Monitor Vector Table - 256 bytes
*   If the monitor is loaded at address zero, the following data section can
*   be used as the 68340 exception vector table.  If the monitor is relocated,
*   all entries in the following table will be adjusted by the base address of
*   the monitor.
*   UNDER NO CIRCUMSTANCES CAN THIS SECTION BE REMOVED!!
********************************************************************************
MONSTART
      DC.L    MON_STACK         ; Reset: Initial Interrupt Stack Pointer
      DC.L    RESET_ENTRY       ; Reset: Initial Program Counter
      DC.L    BUSERROR_ENTRY    ; Bus Error
		DS.L    1                 ; Address Error
      DC.L    BREAKPOINT_ENTRY  ; Illegal Instruction
		DS.L    1                 ; Zero Divide
		DS.L    1                 ; CHK,CHK2 Instruction
		DS.L    1                 ; cpTRAPcc, TRAPcc, TRAPV Instructions
		DS.L    1                 ; Privilege violation
		DC.L    TRACE_ENTRY       ; Trace
		DS.L    1                 ; Line 1010 Emulator
		DS.L    1                 ; Line 1111 Emulator
		DS.L    1                 ; Unassigned, Reserved
		DS.L    1                 ; Coprocessor Protocol Violation
		DS.L    1                 ; Format Error
		DS.L    1                 ; Uninitialized Interrupt
		DS.L    8                 ; Unassigned, Reserved
		DS.L    1                 ; Spurious Interrupt
		DS.L    1                 ; Level 1 Interrupt Auto Vector
		DS.L    1                 ; Level 2 Interrupt Auto Vector
		DS.L    1                 ; Level 3 Interrupt Auto Vector
		DS.L    1                 ; Level 4 Interrupt Auto Vector
		DS.L    1                 ; Level 5 Interrupt Auto Vector
		DS.L    1                 ; Level 6 Interrupt Auto Vector
		DC.L    INTERRUPT_ENTRY   ; Level 7 Interrupt Auto Vector
		DS.L    32                ; remaining vector locations

********************************************************************************
* Monitor Variables - 256 bytes
********************************************************************************
MON_RANGE                    ; Monitor Code Address Range for CMP2
MON_STARTADDR   DC.L MONSTART
MON_ENDADDR     DC.L MONSTART+$0FFF

* Monitor Control Registers 
CMD_CONTROL     DC.W 0       ; command to be executed
CMD_RESULT      DC.B 0       ; result of executed command
MON_INTRLEVEL   DC.B 0       ; minimum interrupt level (forgound only)
MON_CONTROL     DC.W 0       ; miscellaneous flags
MON_LASTENTRY   DC.W 0       ; last entry into the monitor
MEM_SRCADDR     DC.L 0       ; source address for read/write
MEM_DSTADDR     DC.L 0       ; destination address for read/write
MEM_FCS         DC.W 0       ; function codes to use for read/write
MEM_SIZE        DC.W 0       ; access size to use for read/write
MEM_BYTES       DC.W 0       ; number of bytes to transfer
                DC.W 0       ; padding
                DS.L 20      ; spares

* 68340 Registers
MPC             DC.L 0
RSVD_1          DC.W 0       ; padding 
MSR             DC.W $2700
MREGS
MD0             DC.L 0
MD1             DC.L 0
MD2             DC.L 0
MD3             DC.L 0
MD4             DC.L 0
MD5             DC.L 0
MD6             DC.L 0
MD7             DC.L 0
MA0             DC.L 0
MA1             DC.L 0
MA2             DC.L 0
MA3             DC.L 0
MA4             DC.L 0
MA5             DC.L 0
MA6             DC.L 0
MA7             DC.L 0
MUSP            DC.L 0
MSSP            DC.L 0
MVBR            DC.L 0
MSFC            DC.L 0
MDFC            DC.L 0
RSVD_2          DC.W 0       ; padding
MVO             DC.W 0       ; stack frame format word
		          DS.L 8       ; spares
MCMBABORT       DC.L 0
MCMBEXIT        DC.L 0
		          DS.L 2       ; spares

********************************************************************************
* Monitor Transfer Buffer - 1024 bytes
********************************************************************************
MONTRANS        DS.B $400
 
********************************************************************************
* Monitor Interrupt Stack - 512 bytes
********************************************************************************
      DS.B $200
MON_STACK

********************************************************************************
* Miscellaneous  Equates
********************************************************************************
* Equates for CMD_CONTROL
CC_SWINMON      EQU     1     ; are you there?
CC_EXITMON      EQU     2     ; exit monitor
CC_MEMREAD      EQU     3     ; read memory
CC_MEMWRITE     EQU     4     ; write memory

* Equates for CMD_RESULT (set by monitor/read by driver)
CR_SUCCESS      EQU     0     ;success
CR_RESET        EQU     1     ;failed due to reset
CR_BUSERROR     EQU     2     ;failed due to bus error

* Equates for MON_CONTROL
MC_TRACEMODE    EQU     0     ; single step being performed
MC_TRACEFLAG    EQU     4     ; trace exception frame exists (background only)
MC_CMBWAIT      EQU     12    ; monitor in CMB wait loop (background only)

* Equates for MON_LASTENTRY (set by monitor/cleared by driver)
ML_UNDEFINED    EQU     0    
ML_RESET        EQU     1     ; emulation/target reset
ML_BREAKPOINT   EQU     2     ; breakpoint exception
ML_INTERRUPT    EQU     3     ; interrupt exception
ML_TRACE        EQU     4     ; trace exception
ML_BGND         EQU     5     ; background exception

* Equates for MEM_FCS
FCODE_UD        EQU     1     ; user data space
FCODE_UP        EQU     2     ; user program space
FCODE_SD        EQU     5     ; supervisor data space
FCODE_SP        EQU     6     ; supervisor program space
FCODE_CPU       EQU     7     ; cpu space

* Equates for MEM_SIZE
MS_BYTES        EQU     0
MS_WORDS        EQU     1
MS_LONGS        EQU     2


********************************************************************************
* Key Monitor Entry Routines
********************************************************************************
TRACE_ENTRY
   * entry point for single stepping; in order for single stepping to
   * work correctly, the trace vector must point to this address
	MOVE.W  #ML_TRACE,-(A7)              ;save entry point on stack
	BRA     CHECK_REENTRY

RESET_ENTRY
   * entry point when entering the monitor from emulation reset;  the
   * emulator automatically jams this address onto the data bus when
   * the processor reads the reset PC from the exception table during
   * transition from emulation reset to monitor;  this entry point can
   * also be used for transition from target reset if the reset PC in
   * the exception table points here
	MOVE.W  #ML_RESET,MON_LASTENTRY      ;save entry point
	MOVE.B  #CR_RESET,CMD_RESULT         ;abort any command
	CLR.W   MVO                          ;clear for exit
	BRA     MON_MAIN

********************************************************************************
* BUSERROR_ENTRY is used when ...
********************************************************************************
BUSERROR_ENTRY           
	MOVE.B  #CR_BUSERROR,CMD_RESULT    ;abort any command
   MOVE.B  6(A7),D0         ;get stack frame format (format $A or $B)
   ANDI.B  #$0F,D0
	CMPI.B  #$B,D0
	BEQ.B   LONG_BERR
SHORT_BERR
	ADDA.L  #32,A7           ;pop and discard short bus cycle stack frame
	BRA     MON_MAIN
LONG_BERR
	ADDA.L  #92,A7           ;pop and discard long bus cycle stack frame 
	BRA  	MON_MAIN

   NOP                      ;Do not remove NOP's
   NOP
********************************************************************************
* BREAKPOINT_ENTRY is used when ...
********************************************************************************
BREAKPOINT_ENTRY
	MOVE.W   #ML_BREAKPOINT,-(A7)         ;save entry point on stack
	BRA      CHECK_REENTRY

********************************************************************************
* INTERRUPT_ENTRY is used when ...
********************************************************************************
INTERRUPT_ENTRY
	MOVE.W   #ML_INTERRUPT,-(A7)          ;save entry point on stack
	BRA      CHECK_REENTRY

********************************************************************************
* BACKGROUND_ENTRY$ is used by the BGND for breakpoint entry.
*   WARNING:   do not move this entry point.
********************************************************************************
BACKGROUND_ENTRY
	MOVE.W   MVO,-(A7)            ;make up an entry stack frame
	MOVE.L   MPC,-(A7)  
	MOVE.W   MSR,-(A7)      
	MOVE.W   #ML_BGND,-(A7)            ;save entry point on stack
	BRA      CHECK_REENTRY             ;and continue

   NOP                           ;Do not remove these NOP's
   NOP
   NOP
   NOP
   NOP
   NOP

********************************************************************************
* BACKGROUND_RESET_ENTRY$ is used byt the BGND for reset entry.
*   WARNING:  tdo not move this entry point. 
********************************************************************************
BACKGROUND_RESET_ENTRY
   MOVE.L   MSSP,A7
	BRA      RESET_ENTRY                 ; and continue reset_entry

********************************************************************************
CHECK_REENTRY
   ORI.W    #$0700,SR                   ;block interrupts during startup
   
	MOVE.L   A5,-(A7)                    ;save user's A5 on stack
	MOVE.L   8(A7),A5                    ;copy stacked PC into A5
	CMP2.L   MON_RANGE,A5
	BCS.B    ENTRY_OK                    ;okay if outside monitor range
	BTST.B   #5,6(A7)                 
	BEQ.B    ENTRY_OK                    ;okay if not supervisor mode
	MOVEA.L (A7)+,A5                     ;restore stacked A5
	TST.W   (A7)+                        ;discard stacked entry point
	RTE                                  

ENTRY_OK
	* block all interrupts during startup
	ORI.W    #$0700,SR

	* save all registers except SSP and USP
  	MOVEM.L  D0-D7/A0-A6,MREGS
	MOVE.L   (A7)+,MA5                   ;save stacked A5
	MOVE.W   (A7)+,MON_LASTENTRY         ;save stacked entry point
	MOVE.L   USP,A0
	MOVE.L   A0,MUSP
	MOVEC    VBR,A0
	MOVE.L   A0,MVBR
	MOVEC    SFC,A0
	MOVE.L   A0,MSFC
	MOVEC    DFC,A0 
	MOVE.L   A0,MDFC
	* check for format $1 (4-word throwaway) stack frame on user's
	* active (interrupt) stack; if found, pop and discard this stack
	* frame and switch over to user's master stack
   MOVE.B    6(A7),D0         ;get stack frame format 
   ASR.B     #4,D0             
   ANDI.B    #$0F,D0
	CMPI.B    #1,D0
	BNE.B     NOT_THROWAWAY
	ADDA.L    #8,A7            ;adjust user's ASP
	ORI.W     #$1000,SR        ;switch to system stack 
   MOVE.B    6(A7),D0         ;get stack frame format 
   ANDI.B    #$0F,D0

NOT_THROWAWAY
	* pop format $0 (4-word) or first 4 words format $2 (6-word) or
	* format $9 (10-word coprocessor-mid) stack frame placed on user's
	* active stack for monitor entry
	MOVE.W    (A7)+,MSR
	MOVE.L    (A7)+,MPC
	MOVE.W    (A7)+,MVO

	* if format $2 stack frame (trace), pop and discard additional 2
	* words and clear MVO to prevent exit routine from restoring the
	* format $2 stack frame
	CMPI.B    #2,D0
	BNE.B     SAVE_SSP_USP
	ADDA.L    #4,A7                 ;adjust user's ASP
	CLR.W     MVO                   ;clear for exit

   * if an instruction forced an exception as part of its normal execution
   * (ie: TRAP or CHK), the forced exception processing occurs before the
   * trace exception is processed;  in this case, the T0/T1 bits in the
   * status register are saved in the forced exception stack frame instead
   * of our trace exception stack frame
   MOVE.W    MSR,D1
   ANDI      #$07,D1
   BNE.B     SAVE_SSP_USP          ;trace bits in our stack frame
   CMPA.L    MA7,A7
   BGE.B     SAVE_SSP_USP          ;no forced stack frame
   MOVE.W    (A7),D1               ;clear trace bits in forced stack frame
   ANDI.W    #$0fff8,D1
   MOVE.W    D1,(A7)

SAVE_SSP_USP
	* now that A7 is stable, save SSP and USP registers
	MOVE.L    A7,MSSP
	MOVEC     USP,A0
	MOVE.L    A0,MUSP

	* if format $9 (10-word coprocessor mid) stack frame, modify copy
	* of user's ASP to effectively pop additional 6 words;  however,
	* this data remains on the stack in case we want to restore the
	* coprocessor mid stack frame on exit.
	CMPI.B   #9,D0
	BNE.B    LOWER_INTR_PRIORITY
	MOVE.W   SR,D0
	BTST     #12,D0
	BNE.B    MASTER_MODE
INTERRUPT_MODE
	ADD.L    #12,MUSP
	BRA      LOWER_INTR_PRIORITY
MASTER_MODE
	ADD.L    #12,MSSP
	
LOWER_INTR_PRIORITY
	* At this point it is safe to lower the interrupt priority level;
	* set the interrupt level to the greater of MON_INTRLEVEL variable
	* and the interrupt level in effect prior to monitor entry
   MOVE.B   MSR,D0        
   ANDI.B   #$07,D0
	CMP.B    MON_INTRLEVEL,D0
	BGE.B    USE_PRIOR
	MOVE.B   MON_INTRLEVEL,D0
USE_PRIOR
   ASL.W    #8,D0    ;needs to be in bit positions 12:10 
   ASL.W    #2,D0    
	MOVE.W   SR,D1
	OR.W     D1,D0
	MOVE.W   D0,SR

   * send special clear to emulator
   MOVE.L   MON_STARTADDR,A5
   MOVE.W   #0,($00FFC,A5) 
   
	* FALL THROUGH TO MON_MAIN *

***********************************************************************
* Main Monitor Loop
*
* Note:  the TST.B in the monitor loop is required to give the drivers
* a chance to access CMD_CONTROL if the instruction cache is enabled
* (not for 68340).
***********************************************************************
MON_MAIN
	CLR.W    CMD_CONTROL

MON_LOOP
	TST.B    MA0                        ;don't remove!
	MOVE.W   CMD_CONTROL,D0
	BPL.B    MON_LOOP                    ;wait for handshake bit

	EXT.W    D0                          ;clear handshake bit
	CMPI.W   #(CMD_TABLE_END-CMD_TABLE)/2,D0
	BPL.B    MON_MAIN                    ;ignore illegal requests
	MOVE.B   #CR_SUCCESS,CMD_RESULT
	LEA      (MON_MAIN,PC),A6            ;A6=return address
	MOVE.W   (CMD_TABLE,PC,D0.W*2),D1
	JMP      (CMD_TABLE,PC,D1.W)

CMD_TABLE
	DC.W     YO_MONITOR-CMD_TABLE        ;command 0 (dummy)
	DC.W     YO_MONITOR-CMD_TABLE        ;command 1 - are you there?
	DC.W     EXIT_MONITOR-CMD_TABLE      ;command 2 - exit monitor
	DC.W     READ_MEMORY-CMD_TABLE       ;command 3 - read memory
	DC.W     WRITE_MEMORY-CMD_TABLE      ;command 4 - write memory
CMD_TABLE_END

********************************************************************************
* YO_MONITOR subroutine - are you there?
********************************************************************************
YO_MONITOR
	* nothing to do - just return to complete handshake
	JMP      (A6)

********************************************************************************
* EXIT_MONITOR Subroutine - does not return
********************************************************************************
EXIT_MONITOR
	CLR.W    CMD_CONTROL
	* restore control registers 
  	MOVEA.L  MSSP,A7
   MOVEA.L  MUSP,A0
   MOVEC    A0,USP
   MOVEA.L  MVBR,A0
   MOVEC    A0,VBR
   MOVEA.L  MSFC,A0                            
   MOVEC    A0,SFC
   MOVEA.L  MDFC,A0
   MOVEC    A0,DFC

   * save stack pointer for entry validation when single stepping
   MOVE.L    A7,MA7

   * wait for cmb exit  and continue exit 
   * or wait for cmb abort and return to monitor loop
WAIT_FOR_CMB
   MOVE.L   MCMBEXIT,D0    ;cmb exit ?
   BNE      CONTINUE_EXIT       ; yes, continue to complete exit.
   MOVE.L   MCMBABORT,D0   ; no. then cmb abort ?
   BEQ WAIT_FOR_CMB             ; no, then wait for cmb.
	JMP      (A6)                ; yes, return main loop.
   
CONTINUE_EXIT
   MOVE.W   MVO,-(A7)      
   MOVE.L   MPC,-(A7)
   MOVE.W   MSR,-(A7)

	* set command complete, restore remaining registers and exit
	CLR.W    CMD_CONTROL
   MOVEM.L  MREGS,D0-D7/A0-A6
   RTE

********************************************************************************
* READ_MEMORY Subroutine
********************************************************************************
READ_MEMORY
	MOVE.W    MEM_SIZE,D0          ;D0=access size
   MOVE.W    MEM_BYTES,D1         ;D1=byte count
   MOVEA.L   MEM_SRCADDR,A0       ;A0=source address
	MOVEA.L   MEM_DSTADDR,A1       ;A1=destination address
   MOVEA.W   MEM_FCS,A2           ;SFC=function code
	MOVEC     A2,SFC        

	* adjust loop count for access size and DBF
        LSR.W     D0,D1
	SUBQ.W    #1,D1
	MOVE.W    (RD_JUMPTABLE,PC,D0.W*2),D2
	JMP       (RD_JUMPTABLE,PC,D2.W)

RD_BYTE_LOOP
   MOVES.B   (A0)+,D0
   MOVE.B    D0,(A1)+
	DBF       D1,RD_BYTE_LOOP
	JMP       (A6)

RD_WORD_LOOP
   MOVES.W   (A0)+,D0
   MOVE.W    D0,(A1)+
	DBF       D1,RD_WORD_LOOP
	JMP       (A6)

RD_LONG_LOOP
   MOVES.L   (A0)+,D0
   MOVE.L    D0,(A1)+
	DBF       D1,RD_LONG_LOOP
	JMP       (A6)

* function jump table for READ_MEMORY
RD_JUMPTABLE
	DC.W      RD_BYTE_LOOP-RD_JUMPTABLE
	DC.W      RD_WORD_LOOP-RD_JUMPTABLE
	DC.W      RD_LONG_LOOP-RD_JUMPTABLE
	DC.W      0 ; reserved

********************************************************************************
* WRITE_MEMORY Subroutine
********************************************************************************
WRITE_MEMORY
	MOVE.W    MEM_SIZE,D0          ;D0=access size
   MOVE.W    MEM_BYTES,D1         ;D1=bytes count
   MOVEA.L   MEM_SRCADDR,A0       ;A0=source address
	MOVEA.L   MEM_DSTADDR,A1       ;A1=destination address
   MOVEA.W   MEM_FCS,A2           ;DFC=function code
   MOVEC     A2,DFC        

	* adjust loop count for access size and DBF
   LSR.W     D0,D1
	SUBQ.W    #1,D1
	MOVE.W    (WR_JUMPTABLE,PC,D0.W*2),D2
	JMP       (WR_JUMPTABLE,PC,D2.W)

WR_BYTE_LOOP
   MOVE.B    (A0)+,D0
   MOVES.B   D0,(A1)+
	DBF       D1,WR_BYTE_LOOP
	JMP       (A6)

WR_WORD_LOOP
   MOVE.W    (A0)+,D0
   MOVES.W   D0,(A1)+
	DBF       D1,WR_WORD_LOOP
	JMP       (A6)

WR_LONG_LOOP
   MOVE.L    (A0)+,D0
   MOVES.L   D0,(A1)+
	DBF       D1,WR_LONG_LOOP
	JMP       (A6)

* function jump table for WRITE_MEMORY
WR_JUMPTABLE
	DC.W      WR_BYTE_LOOP-WR_JUMPTABLE
	DC.W      WR_WORD_LOOP-WR_JUMPTABLE
	DC.W      WR_LONG_LOOP-WR_JUMPTABLE
	DC.W      0 ; reserved for future optimize mode
