********************************************************************************
*
* Customizable Emulation Monitor for HP64751 Motorola 68340 Emulator
* This is also the default foreground monitor.
*
********************************************************************************
* MKT:@(#) 64751A      A.00.15 68340 EMULATION FIRMWARE       64751     09Oct95                                   

* @(SUBID) MP:                                                     
********************************************************************************
*  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 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 next section defines the $800 byte data section for HP64751 68340
*  monitors and should be included at the beginning of the monitor source
*  files to ensure consistent data definitions.
*
********************************************************************************

********************************************************************************
* Monitor Vector Table - $100 bytes
********************************************************************************
      CHIP    68332
      ORG     0      ;Do NOT change. The host will relocate code to address
                     ; specified by cf monaddr=XXXXX000 

MON_DATA
      DC.L    MON_STACK         ; Reset: Initial Interrupt Stack Pointer
      DC.L    RESET_ENTRY       ; Reset: Initial Program Counter
      DC.L    BUSERROR_ENTRY    ; Bus Error
      DC.L    ERROR_ENTRY       ; Address Error
      DC.L    BREAKPOINT_ENTRY  ; Illegal Instruction
      DC.L    ERROR_ENTRY       ; Zero Divide
      DC.L    ERROR_ENTRY       ; CHK,CHK2 Instruction
      DC.L    ERROR_ENTRY       ; TRAPcc, TRAPV Instructions
      DC.L    ERROR_ENTRY       ; Privilege violation
      DC.L    TRACE_ENTRY       ; Trace
      DC.L    ERROR_ENTRY       ; Line 1010 Emulator
      DC.L    ERROR_ENTRY       ; Line 1111 Emulator
      DC.L    ERROR_ENTRY       ; Hardware Breakpoint
      DC.L    ERROR_ENTRY       ; (Reserved for Coprocessor Protocol Violation)
      DC.L    ERROR_ENTRY       ; Format Error and Unitialized Interrupt
      DC.L    ERROR_ENTRY       ; Format Error and Unitialized Interrupt
      DCB.L   8,ERROR_ENTRY     ; Unassigned, Reserved
      DC.L    ERROR_ENTRY       ; Spurious Interrupt
      DC.L    ERROR_ENTRY       ; Level 1 Interrupt Auto Vector
      DC.L    ERROR_ENTRY       ; Level 2 Interrupt Auto Vector
      DC.L    ERROR_ENTRY       ; Level 3 Interrupt Auto Vector
      DC.L    ERROR_ENTRY       ; Level 4 Interrupt Auto Vector
      DC.L    ERROR_ENTRY       ; Level 5 Interrupt Auto Vector
      DC.L    ERROR_ENTRY       ; Level 6 Interrupt Auto Vector
      DC.L    ERROR_ENTRY       ; Level 7 Interrupt Auto Vector
      DCB.L   16,ERROR_ENTRY    ; Trap #0-15 Instruction Vectors
      DCB.L   8,ERROR_ENTRY     ; FP Exceptions
      DCB.L   8,ERROR_ENTRY     ; Unassigned/Reserved (vector 56-63)

********************************************************************************
* Monitor Variables - $600 bytes
********************************************************************************
MON_RANGE                    ; Monitor Code Address Range for CMP2
MON_STARTADDR   DC.L MONPROG
MON_ENDADDR     DC.L MONPROGEND

* 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
MON_VECTOR      DC.W 0       ; monitor vector offset
                DS.L 20      ; spares

* User 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       ; boolean
MCMBEXIT        DC.L 0       ; boolean
                DS.L 2       ; spares

********************************************************************************
* Monitor Transfer Buffer
* Transfer buffer for read/write (1K bytes)
********************************************************************************
MONTRANS        DS.B $400

********************************************************************************
* Monitor Stack
* Interrupt Stack when monitor entered from reset (256 bytes)
********************************************************************************
      DS.B $100
MON_STACK

      DS.B $100

********************************************************************************
* Monitor 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_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

*
* This file contains the foreground monitor for the HP64751 68340 emulator.
* The monitor requires a 4K byte block of memory.  The monitor data space
* consumes the first $800 bytes, leaving $800 bytes for monitor code.
*

********************************************************************************
***************  M O N I T O R   E N T R Y   R O U T I N E S  ******************
********************************************************************************

MONPROG
********************************************************************************
* BACKGROUND_RESET_ENTRY  is used by the 68340 BDM for reset entry.
*   WARNING:  this entry point is fixed at offset 0x800.
********************************************************************************
BACKGROUND_RESET_ENTRY
   LEA     (MON_DATA,PC),A2             ;set for A2-relative data
   MOVE.L   (MSSP,A2),A7
   BRA      RESET_ENTRY                 ; and continue reset_entry

********************************************************************************
* BACKGROUND_ENTRY  is used by the 68340 BDM for BGND entry.
*   WARNING:  this entry point is fixed at offset 0x80C. 
********************************************************************************
BACKGROUND_ENTRY
   MOVE.L   A2,-12(A7)                ;save users A2
   LEA      (MON_DATA,PC),A2          ;set for A2-relative data
   MOVE.W   (MVO,A2),-(A7)            ;make up an entry stack frame
   MOVE.L   (MPC,A2),-(A7)  
   MOVE.W   (MSR,A2),-(A7)      
   MOVE.L   -4(A7),A2                 ;restore users A2
   MOVE.W   #ML_BGND,-(A7)            ;save entry point on stack
   BRA      CHECK_REENTRY             ;and continue

********************************************************************************
* TRACE_ENTRY is used for single-stepping.  For single-stepping to operate, the 
*   trace exception vector in the target system must point to this address.
*
********************************************************************************
TRACE_ENTRY
   MOVE.W  #ML_TRACE,-(A7)              ;save entry point on stack
   BRA     CHECK_REENTRY

********************************************************************************
* RESET_ENTRY is used when the monitor is entered from reset.
********************************************************************************
RESET_ENTRY
   LEA     (MON_DATA,PC),A2             ;set for A2-relative data
   MOVE.W  #ML_RESET,(MON_LASTENTRY,A2) ;save entry point
   MOVE.B  #CR_RESET,(CMD_RESULT,A2)    ;abort any command
   CLR.W   (MVO,A2)                     ;clear for exit
   BRA     MON_MAIN_ENTRY

********************************************************************************
* BUSERROR_ENTRY ...  not used with BDM mode enabled
********************************************************************************
BUSERROR_ENTRY           
   LEA     (MON_DATA,PC),A2             ;set for A2-relative data
   MOVE.B  #CR_BUSERROR,(CMD_RESULT,A2) ;abort any command
   ADDA.L  #32,A7                  ;pop and discard short bus cycle stack frame
   BRA     MON_MAIN

********************************************************************************
* BREAKPOINT_ENTRY ...  not used with BDM mode enabled
********************************************************************************
BREAKPOINT_ENTRY
   MOVE.W   #ML_BREAKPOINT,-(A7)         ;save entry point on stack
   BRA      CHECK_REENTRY

********************************************************************************
* ERROR_ENTRY is used for unexpected exceptions
********************************************************************************
ERROR_ENTRY
   MOVE.W   #ML_INTERRUPT,-(A7)          ;save entry point on stack
   BRA      CHECK_REENTRY

********************************************************************************
CHECK_REENTRY
   MOVE.L   A2,-(A7)                    ;save user's A2 on stack
   MOVE.L   8(A7),A2                    ;copy stacked PC into A2
   CMP2.L   (MON_RANGE,PC),A2
   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)+,A2                     ;restore stacked A2
   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
   LEA      (MON_DATA,PC),A2            ;set for A2-relative data
   MOVEM.L  D0-D7/A0-A6,(MREGS,A2)
   MOVE.L   (A7)+,(MA2,A2)              ;save stacked A2
   MOVE.W   (A7)+,(MON_LASTENTRY,A2)    ;save stacked entry point
   MOVE.L   USP,A0
   MOVE.L   A0,(MUSP,A2)
   MOVEC    VBR,A0
   MOVE.L   A0,(MVBR,A2)
   MOVEC    SFC,A0
   MOVE.L   A0,(MSFC,A2)
   MOVEC    DFC,A0 
   MOVE.L   A0,(MDFC,A2)


   * pop format $0 (4-word) or first 4 words format $2 (6-word) 
   * stack frame placed on user's active stack for monitor entry
   MOVE.W    6(A7),(MON_VECTOR,A2) ;save format and vector offset
   MOVE.B    6(A7),D0         ;get stack frame format 
   ASR.B     #4,D0             
   ANDI.B    #$0F,D0

   MOVE.W    (A7)+,(MSR,A2)
   MOVE.L    (A7)+,(MPC,A2)
   MOVE.W    (A7)+,(MVO,A2)

   * 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,A2)              ;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,A2),D1
   ANDI      #$07,D1
   BNE.B     SAVE_SSP_USP          ;trace bits in our stack frame
   CMPA.L    (MA7,A2),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,A2)
   MOVEC     USP,A0
   MOVE.L    A0,(MUSP,A2)

MON_MAIN_ENTRY
   * This write will cause the ERY line to go false if it isn't already
   * This is a way to notify host that we are in monitor. This is a special
   * location in dual port ram($00FFC) and used by the host.
   MOVE.W   #0,($00FFC,A2) 
   
***********************************************************************
* Main Monitor Loop
*
***********************************************************************

MON_MAIN
   CLR.W    (CMD_CONTROL,A2)

   * 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,PC),D0        
   ANDI.B   #$07,D0
   CMP.B    (MON_INTRLEVEL,PC),D0
   BGE.B    USE_PRIOR
   MOVE.B   (MON_INTRLEVEL,PC),D0
USE_PRIOR
   LSL.W    #8,D0    ;needs to be in bit positions 10:8
   MOVE.W   SR,D1
   ANDI.W   #$f8ff,D1
   OR.W     D1,D0    ;D0 now has desired intr. level

   * restore all user registers before entering idle loop because
   * they may be needed by the target interrupt exception handler(s)

   MOVE.L  (MSSP,PC),A7    * restore control registers
   MOVE.L  (MUSP,PC),D1
   MOVEC    D1,USP
   MOVE.L  (MVBR,PC),D1
   MOVEC    D1,VBR
   MOVE.L  (MSFC,PC),D1
   MOVEC    D1,SFC
   MOVE.L  (MDFC,PC),D1
   MOVEC    D1,DFC
   MOVEM.L  (MD1,PC),D1-D7/A0-A6  *basic except D0 and A7
   MOVE.W   D0,SR                 *the desired intr. level
   MOVE     (MD0,PC),D0           *and finally D0

MON_LOOP
   TST.W    (CMD_CONTROL,PC)            
   BEQ.W    MON_LOOP                    ;wait for command 

   LEA      (MON_DATA,PC),A2            ;set for A2-relative data
   MOVE.W   (CMD_CONTROL,PC),D0         ;get comand request(bits 7:0)   
   ANDI.W   #$00FF,D0
   CMPI.W   #(CMD_TABLE_END-CMD_TABLE)/2,D0
   BPL.B    MON_MAIN                    ;ignore illegal requests

   MOVE.B   #CR_SUCCESS,(CMD_RESULT,A2)
   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
   BRA      MON_MAIN

********************************************************************************
* EXIT_MONITOR Subroutine - does not return
********************************************************************************
EXIT_MONITOR
   CLR.W    (CMD_CONTROL,A2)

   * wait for cmb exit  and continue exit 
   * or wait for cmb abort and return to monitor loop
WAIT_FOR_CMB
   MOVE.L   (MCMBEXIT,PC),D0    ;cmb exit ?
   BNE      CONTINUE_EXIT       ; yes, continue to complete exit.
   MOVE.L   (MCMBABORT,PC),D0   ; no. then cmb abort ?
   BEQ      WAIT_FOR_CMB        ; no, then wait for cmb.
   BRA      MON_MAIN            ; yes, return main loop.
   
CONTINUE_EXIT
   * restore control registers 
   MOVEA.L  (MSSP,PC),A7
   MOVEA.L  (MUSP,PC),A0
   MOVEC    A0,USP
   MOVEA.L  (MVBR,PC),A0
   MOVEC    A0,VBR
   MOVEA.L  (MSFC,PC),A0                            
   MOVEC    A0,SFC
   MOVEA.L  (MDFC,PC),A0
   MOVEC    A0,DFC

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

   MOVE.W   (MVO,A2),-(A7)      
   MOVE.L   (MPC,A2),-(A7)
   MOVE.W   (MSR,A2),-(A7)

   * set command complete, restore remaining registers and exit
   MOVEM.L  (MREGS,PC),D0-D7/A0-A6
   RTE

********************************************************************************
* READ_MEMORY Subroutine
********************************************************************************
READ_MEMORY
   MOVE.W    (MEM_SIZE,PC),D0          ;D0=access size
   MOVE.W    (MEM_BYTES,PC),D1         ;D1=byte count
   MOVEA.L   (MEM_SRCADDR,PC),A0       ;A0=source address
   MOVEA.L   (MEM_DSTADDR,PC),A1       ;A1=destination address
   MOVE.W    (MEM_FCS,PC),D2           ;SFC=function code
   MOVEC     D2,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
   BRA       MON_MAIN

RD_WORD_LOOP
   MOVES.W   (A0)+,D0
   MOVE.W    D0,(A1)+
   DBF       D1,RD_WORD_LOOP
   BRA       MON_MAIN

RD_LONG_LOOP
   MOVES.L   (A0)+,D0
   MOVE.L    D0,(A1)+
   DBF       D1,RD_LONG_LOOP
   BRA       MON_MAIN

* 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,PC),D0          ;D0=access size
   MOVE.W    (MEM_BYTES,PC),D1         ;D1=bytes count
   MOVEA.L   (MEM_SRCADDR,PC),A0       ;A0=source address
   MOVEA.L   (MEM_DSTADDR,PC),A1       ;A1=destination address
   MOVE.W    (MEM_FCS,PC),D2           ;DFC=function code
   MOVEC     D2,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
   BRA       MON_MAIN

WR_WORD_LOOP
   MOVE.W    (A0)+,D0
   MOVES.W   D0,(A1)+
   DBF       D1,WR_WORD_LOOP
   BRA       MON_MAIN

WR_LONG_LOOP
   MOVE.L    (A0)+,D0
   MOVES.L   D0,(A1)+
   DBF       D1,WR_LONG_LOOP
   BRA       MON_MAIN

* 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

MONPROGEND

;****************************************************************************
; Identification strings to indicate revision level and origin of this file
;
; MKT:@(#)                                                                                           
; CPR:@(#)                                                                      
; @(SUBID) MP:                                  
; @(SUBID) MAIN: /lsd/zodiac/inst/m68340/drivers 0.13  09Oct95 11:18:13         
;****************************************************************************

