********************************************************************************
* A Hewlett-Packard Software Product
* Copyright Hewlett-Packard Co. 1994
*
* All Rights Reserved. Reproduction, adaptation, or translation without prior
* written  permission  is prohibited, except as allowed under copyright laws.
********************************************************************************
* Customizable Foreground Monitor for HP64782 Motorola 6833x Emulator
*
* The emulation monitor is the vehicle by which the following emulator
* functions are performed:
*
*      read/write emulation/target memory space
*      display/modify 6833x CPU registers
*      execute user program
*      break away from user program
*      service the swsr register (user may disable this routine)
*
* The monitor consists of $800 bytes of data space followed by $800 bytes of
* code space.  The emulator operating software communicates with the monitor
* through the data space and no changes should be made to this portion of the
* monitor.  See areas marked as "USER MODIFIABLE" for specific customizations
* typically required by target systems.
********************************************************************************
* Use the following type of instructions to assemble and link for an 
* executable program;
* 
*   as68k -L fm64782.s >fm64782.lst
*   ld68k -L -ho fm64782 fm64782.o >fm64782.map      creates fm64782.X
*
************* WARNING, DO NOT USE ORG STATEMENT *******************************
* Note. Do not use an ORG statement 
*       The emulator will load the foreground monitor as set up by
*       the emulator configuration selection for monitor address.
********************************************************************************

   CHIP  CPU32 

********************************************************************************
* Monitor Vector Table - 256 bytes 
********************************************************************************
MONDATA
        DC.L    MON_STACK         Reset: Initial Interrupt Stack Pointer
MON_RST_PC
		DC.L    RESET_ENTRY       Reset: Initial Program Counter
		DC.L    ERROR_ENTRY       Bus Error
		DC.L    ERROR_ENTRY       Address Error
		DC.L    ERROR_ENTRY       Illegal Instruction
		DC.L    ERROR_ENTRY       Zero Divide
		DC.L    ERROR_ENTRY       CHK,CHK2 Instruction
		DC.L    ERROR_ENTRY       cpTRAPcc, TRAPcc, TRAPV Instructions
		DC.L    ERROR_ENTRY       Privilege violation
		DC.L    ERROR_ENTRY       Trace
		DC.L    ERROR_ENTRY       Line 1010 Emulator
		DC.L    ERROR_ENTRY       Line 1111 Emulator
		DC.L    ERROR_ENTRY       Unassigned, Reserved
		DC.L    ERROR_ENTRY       Coprocessor Protocol Violation
		DC.L    ERROR_ENTRY       Format Error
		DC.L    ERROR_ENTRY       Uninitialized Interrupt
		DCB.L   8,ERROR_ENTRY     Unassigned, Reserved
		DC.L    ERROR_ENTRY       Spurious Interrupt
		DCB.L   6,ERROR_ENTRY     Level 1-6 Interrupt Auto Vector
		DC.L    INTERRUPT_ENTRY   Level 7 Interrupt Auto Vector
		DCB.L   32,ERROR_ENTRY    remaining vector locations

********************************************************************************
* Monitor Variables - 256 bytes
********************************************************************************
* Monitor Control Registers 
MON_RANGE       DC.L MONPROG,MONPROGEND    code range for CMP2
CMD_HANDSHAKE   DC.W 0            nonzero if command being executed
CMD_CONTROL     DC.W 0            command to be executed
CMD_RESULT      DC.W 0            result of executed command
MON_INTRLEVEL   DC.W 0            minimum interrupt level (foreground only)
MON_CONTROL     DC.W 0            miscellaneous flags
MON_LASTENTRY   DC.W 0            last entry into the monitor

MEM_SRCADDR     DC.L 0            address for read/write
MEM_DSTADDR     DC.L 0            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
USER_INTR       DC.W 0            user interrupt 
USER_VECTOR     DC.W 0            user interrupt vector
MON_INTR        DC.W 0            monitor interrupt 
MON_VECTOR      DC.W 0            monitor interrupt vector
ODD_ACCESS      DC.W 0            =0 do not allow odd address access
*                                  1 allow odd address access
SIM_BASE        DC.L $0FFF000
FGMON_VERSION   DC.L $64782000    HP64780, version 000

                DS.W 22           spares

* Table of exception stack frame sizes
FRAMESIZE	    DC.W 8            format $0 - four word stack frame
                DC.W 0            format $1 - not used
                DC.W 12           format $2 - six word stack frame
                DC.W 0,0,0,0,0,0  format $3 thru $8 - not used
                DC.W 0            format $9 - not used
                DC.W 0            format $A - not used
                DC.W 0            format $B - not used
                DC.W 24           format $C - BERR stack frame
                DC.W 0,0,0        format $D thru $F - not used

* User Registers
MPC  	        DC.L 0            program counter
                DC.W 0            padding (reserved)
MSR             DC.W $2700        status register
MREGS
MD0             DC.L 0            data registers D0-D7
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            address registers A0-A7
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            user stack pointer
MSSP            DC.L 0            supervisor stack pointer
MVBR            DC.L 0            vector base register
MSFC            DC.L 0            source function code register
MDFC            DC.L 0            destination function code register

TMP             DS.W 18

********************************************************************************
* Monitor Transfer Buffer - 1024 bytes
********************************************************************************
MON_TRANS       DS.W $200

********************************************************************************
* Monitor Interrupt Stack - 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
CC_SERVSWSR     EQU     5     ; service the swsr register 

* Equates for CMD_RESULT vector numbers (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
CR_ACCERROR     EQU    12     ;failed due to memory access violation
CR_FMTERROR     EQU    14     ;failed due to format error
CR_MMUERROR     EQU    56     ;failed due to format error

* Equates for MON_CONTROL
MC_TRACEMODE    EQU     0     ;single step being performed
MC_IDLE         EQU     3     ;monitor in idle wait
MC_CMBWAIT      EQU    12     ;monitor in CMB wait loop (background only)

* Equates for MON_LASTENTRY (vector offsets)
ML_BDMENTRY     EQU     0     ;BDM entry
ML_RESET        EQU     1     ;emulation/target reset
ML_BREAKPOINT   EQU  $010     ;breakpoint exception
ML_TRACE        EQU  $024     ;trace exception
ML_INTERRUPT    EQU  $07C     ;interrupt 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

* Equates for SIM register locations
REG_SWSR        EQU     $0000A27

* This monitor must be relocatable and uses A5 and PC relative addressing to
* reference data.  Vector table entries are adjusted by the drivers when the
* monitor is loaded.
*

MONPROG
********************************************************************************
* Monitor entry point for BDM into monitor.  
* Register A5 has already been save by BDM 
********************************************************************************
BDM_ENTRY
   LEA     (MONDATA,PC),A5         set up for A5-relative data
   MOVE.W  #ML_BDMENTRY,(TMP,A5)   save entry point
   MOVEM.L D0-D7/A0-A4,(MREGS,A5)  save some registers
   MOVE.L  A6,(MA6,A5)
   BRA     SAVE_RESTOF_REGS

********************************************************************************
* Monitor entry point for BDM into monitor idle loop.  
********************************************************************************
BDM_ENTRY_IDLE
   BRA     MON_MAIN

********************************************************************************
* Monitor entry point for reset into monitor.
********************************************************************************
RESET_ENTRY
   MOVE.L  A5,-(A7)              save user's A5 on stack
   LEA     (TMP,PC),A5
   MOVE.W  #ML_RESET,(A5)        save entry point
   BRA     USER_ENTRY

********************************************************************************
* Monitor entry point for software breakpoints.  When the emulator detects the
* interrupt acknowledge cycle after generating a level 7 NMI, it terminates the
* bus cycle with autovector and "jams" this address on the data bus when the
* processor fetches the level 7 autovector vector.
********************************************************************************
INTERRUPT_ENTRY
   MOVE.L  A5,-(A7)               save user's A5 on stack
   LEA     (TMP,PC),A5
   MOVE.W  #ML_INTERRUPT,(A5)     save entry point
   BRA     CHECK_REENTRY

********************************************************************************
* Exception handler for exceptions generated during monitor commands.  During
* monitor command execution, all target interrupts are blocked and VBR points
* to the monitor's vector table.  This entry point can also be used to trap
* exceptions generated during target execution if VBR points to the base
* address of the monitor or individual vectors point to this address.
********************************************************************************
ERROR_ENTRY
   MOVE.L  A5,-(A7)               save user's A5 on stack
   LEA     (TMP,PC),A5
   MOVE.W  10(A7),(A5)            save entry point and set lsb to 
   ORI.W   #1,(A5)                prevent removal of stack frame

   * fall through to CHECK_REENTRY *

********************************************************************************
* Check for monitor reentry.  Compare the PC and SR in the exception stack
* frame with the address range of the monitor to determine if this is a 
* transition from user program or exception during monitor command execution.  
********************************************************************************
CHECK_REENTRY
   ORI.W   #$0700,SR               block interrupts
   MOVE.L  6(A7),A5
   CMP2.L  (MON_RANGE,PC),A5       check PC
   BCS.B   USER_ENTRY
   BTST.B  #5,4(A7)                check SR supervisor bit
   BEQ.B   USER_ENTRY

********************************************************************************
***********************  M O N I T O R   E X C E P T I O N  ********************
********************************************************************************

********************************************************************************
* Exception handler for exceptions generated during monitor command execution.
* The monitor copies the exception stack frame into the transfer buffer then
* terminates the command with an error.
********************************************************************************
MON_EXCEPTION
   LEA     (MONDATA,PC),A5         set up for A5-relative data
   MOVE.L  (A7)+,D0                  remove copy of A5 off of stack
   MOVE.W  6(A7),D0                    use vector number as error code
   ANDI.W  #$00FF,D0
   MOVE.W  D0,(MON_VECTOR,A5)
   ASR.W   #2,D0
   ANDI.W  #$0FF,D0
   MOVE.W  D0,(CMD_RESULT,A5)
   
   LEA     (MON_TRANS,PC),A0          copy exception stack frame to the
                                      ;start of the monitor transfer buffer
   MOVE.W  6(A7),D0                    use vector number as error code
   ASR.W   #8,D0
   ASR.W   #4,D0
   ANDI.W  #$00F,D0
   MOVE.W  D0,(CMD_RESULT,A5)
   MOVE.W  (FRAMESIZE,PC,D0*2),D0     for processing by the drivers
   LSR.W   #2,D0
   SUBQ    #1,D0
ME_LOOP    MOVE.L  (A7)+,(A0)+
   DBF     D0,ME_LOOP

   MOVE.W  #1,D0
   MOVE.W  D0,(MON_INTR,A5)

   BRA     MON_MAIN

********************************************************************************
**************  E N T R Y   F R O M   U  S E R   P R O G R A M   ***************
********************************************************************************

********************************************************************************
* Save all user registers and process and remove the exception stack frame.
********************************************************************************
USER_ENTRY
   LEA     (MONDATA,PC),A5         set up for A5-relative data

   MOVEM.L D0-D7/A0-A6,(MREGS,A5)  save all registers
   MOVE.L  (A7)+,(MA5,A5)

SAVE_RESTOF_REGS
   MOVE.L  USP,A0
   MOVE.L  A0,(MUSP,A5)
   MOVEC   VBR,A0
   MOVE.L  A0,(MVBR,A5)
   MOVEC   SFC,A0
   MOVE.L  A0,(MSFC,A5)
   MOVEC   DFC,A0 
   MOVE.L  A0,(MDFC,A5)

   MOVE.W  (TMP,PC),D0             store vector offset as entry point
   CMPI.W  #ML_RESET,D0
   BEQ     USER_RST_ENTRY
   ANDI.W  #$0FFC,D0
   MOVE.W  D0,(MON_LASTENTRY,A5)
   BNE     UNWIND_STACK

   MOVE.L  A7,(MSSP,A5)
   BRA     MON_MAIN                if entry point is BDM then MON_MAIN

*******************************************************************************
*   Do something with other entries
*******************************************************************************
UNWIND_STACK
   MOVE.W  D0,(USER_VECTOR,A5)
   MOVE.W  (A7)+,D0
   MOVE.W  D0,(MSR,A5)
   MOVE.L  (A7)+,D0
   MOVE.L  D0,(MPC,A5)
   MOVE.W  (A7)+,D0
   ASR.W   #8,D0
   ASR.W   #4,D0
   BEQ     USER_ENTRY1   
   CMP.W   #2,D0
   BEQ     SIX_WORD
   ADD.L   #16,A7
   BRA     USER_ENTRY1
SIX_WORD
   ADD.L   #4,A7

USER_ENTRY1
   MOVE.L  A7,(MSSP,A5)
   MOVEQ   #1,D0
   MOVE.W  D0,(USER_INTR,A5)
   MOVE.L  (MD0,A5),D0
   MOVE.L  (MA5,A5),A5
   BGND                            go to BDM

USER_RST_ENTRY                     ;we have user entry via fg monitor reset
   MOVE.W  D0,(USER_VECTOR,A5)
   MOVE.L  MON_RST_PC,D0
   MOVE.L  D0,(MPC,A5)       
   MOVE.W  #$2700,D0
   MOVE.W  D0,(MSR,A5)
   BRA     USER_ENTRY1


********************************************************************************
********************   M O N I T O R   I D L E   L O O P   *********************
********************************************************************************

********************************************************************************
* During the monitor idle loop, the monitor can be interrupted by the target
* system.  The interrupt priority level (IPL) is set to the value defined in
* configuration or the user's IPL in effect upon monitor entry, whichever is
* greater.  Most user registers are restored while running in the idle loop.
* When a command is requested, the monitor blocks all interrupts and uses its
* own vector table and stack to trap any exceptions generated during command
* execution.
*
* Note:  the first TST.B in the monitor loop is required to give the drivers
* a chance to access CMD_CONTROL when the instruction cache is enabled.
********************************************************************************
MON_MAIN
   CLR.W   (CMD_HANDSHAKE,A5)   flag command completion
   CLR.W   (CMD_CONTROL,A5)     flag command control
   CLR.W   (ODD_ACCESS,A5)

MON_MAIN1
   MOVE.L  (MVBR,PC),D0           restore all user registers during idle
   MOVEC   D0,VBR                 loop in case they are needed by target
   MOVE.L  (MSFC,PC),D0                            
   MOVEC   D0,SFC
   MOVE.L  (MDFC,PC),D0
   MOVEC   D0,DFC
   MOVE.L  (MUSP,PC),D0
   MOVEC   D0,USP
   MOVE.L  (MSSP,PC),D0
   MOVE.L  D0,A7             

   MOVE.W  (MSR,PC),D0            select user's interrupt mask and set
   ASR.W   #8,D0
   ANDI.W  #$007,D0
   CMP.W   (MON_INTRLEVEL,PC),D0  priority mask to the configured value
   BGE.B   USE_PRIOR              or the value in effect on monitor 
   MOVE.W  (MON_INTRLEVEL,PC),D0  entry, whichever is higher
USE_PRIOR
   MOVE.W  SR,D1
   ANDI.W  #$F8FF,D1
   ASL.W   #8,D0                  
   OR.W    D0,D1
   MOVE.W  D1,SR
   MOVEM.L (MREGS,PC),D0-D7/A0-A6  

MON_LOOP
   NOP                            don't remove!

   ORI.W   #$0700,SR              block interrupts, select monitor's
   LEA     (MONDATA,PC),A5        vector table and interrupt stack
   LEA     (MON_STACK,PC),A7
   MOVEC   A5,VBR

   MOVEQ   #0,D0                  execute command
   MOVE.W  (CMD_CONTROL,PC),D0

   TST.W   (CMD_HANDSHAKE,PC)
   BNE     MON_LOOP1            
   MOVE.W  #CC_SERVSWSR,D0        no handshake, then service the swsr reg.  
MON_LOOP1

   CMPI.W  #(CMD_TABLE_END-CMD_TABLE)/2,D0
   BPL     MON_MAIN
   MOVE.W  #CR_SUCCESS,(CMD_RESULT,A5)
   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
   DC.W    SERV_SWSR-CMD_TABLE         ;command 5 - service the swsr register
CMD_TABLE_END

********************************************************************************
*****************   S O F T W A R E   H A N D S H A K E   **********************
********************************************************************************
YO_MONITOR
   BRA     MON_MAIN   

********************************************************************************
***********************   E X I T   M O N I T O R   ****************************
********************************************************************************

********************************************************************************
* The monitor restores all registers and then waits for CMB go command
* When the monitor receives a CMB go command the processor executes BGND
* instruction going to BDM. The BDM knows that this is a special BGND
* exits BDM with desired PC.
********************************************************************************
EXIT_MONITOR
   CLR.W   (CMD_HANDSHAKE,A5)      flag command completion
   CLR.W   (CMD_CONTROL,A5)        flag command control

   MOVEA.L (MVBR,PC),A0            restore registers
   MOVEC   A0,VBR
   MOVEA.L (MSFC,PC),A0                            
   MOVEC   A0,SFC
   MOVEA.L (MDFC,PC),A0
   MOVEC   A0,DFC
   MOVEA.L (MUSP,PC),A0
   MOVE.L  A0,USP

   MOVE.L  (MSSP,PC),A0    
   MOVE.L  A0,A7

   MOVEM.L (MREGS,PC),D0-D7/A0-A6

   BGND                            exit through BDM

********************************************************************************
************************   R E A D   M E M O R Y   *****************************
********************************************************************************
READ_MEMORY
  MOVEA.L (MEM_SRCADDR,PC),A0    A0=source address
  MOVEA.L (MEM_DSTADDR,PC),A1    A1=destination address
  LEA     (RD_JUMPTABLE,PC),A2   A2=address of jump table
  BRA     RDWR_MEMORY         

RD_JUMPTABLE
   DC.W    RD_BYTES-RD_JUMPTABLE
   DC.W    RD_WORDS-RD_JUMPTABLE
   DC.W    RD_LONGS-RD_JUMPTABLE

RD_BYTES
   MOVES.B (A0)+,D0
   MOVE.B  D0,(A1)+
   DBF     D1,RD_BYTES
   RTS
RD_WORDS
   MOVES.W (A0)+,D0
   MOVE.W  D0,(A1)+
   DBF     D1,RD_WORDS
   RTS
RD_LONGS
   MOVES.L (A0)+,D0
   MOVE.L  D0,(A1)+
   DBF     D1,RD_LONGS
   RTS

********************************************************************************
***********************   W R I T E   M E M O R Y   ****************************
********************************************************************************
WRITE_MEMORY
   MOVEA.L (MEM_DSTADDR,PC),A0     A0=destination address
   MOVEA.L (MEM_SRCADDR,PC),A1     A1=source address
   LEA     (WR_JUMPTABLE,PC),A2    A2=address of jump table
   BRA     RDWR_MEMORY           

WR_JUMPTABLE
   DC.W    WR_BYTES-WR_JUMPTABLE
   DC.W    WR_WORDS-WR_JUMPTABLE
   DC.W    WR_LONGS-WR_JUMPTABLE

WR_BYTES
   MOVE.B  (A1)+,D0
   MOVES.B D0,(A0)+
   DBF     D1,WR_BYTES
   RTS
WR_WORDS
   MOVE.W  (A1)+,D0
   MOVES.W D0,(A0)+
   DBF     D1,WR_WORDS
   RTS
WR_LONGS
   MOVE.L  (A1)+,D0
   MOVES.L D0,(A0)+
   DBF     D1,WR_LONGS
   RTS

********************************************************************************
RDWR_MEMORY
   MOVE.W  (MEM_BYTES,PC),D2       D2=number of bytes
   MOVE.W  (MEM_SIZE,PC),D3        D3=access size
   MOVE.W  (MEM_FCS,PC),D4         D4=function code
   MOVEC   D4,SFC                  SFC=function code
   MOVEC   D4,DFC                  DFC=function code

   TST.W   (ODD_ACCESS,PC)         Allow odd address access
   BNE     DO_ODD_ACCESS           Yes, then DO_ODD_ACCESS

REALIGN
   MOVE.W  D3,D4
CHECKALIGN
   MOVE.L  A0,D5
   LSR.L   D4,D5
   LSL.L   D4,D5
   CMP.L   A0,D5
   BEQ.B   ALIGNED
MISALIGNED
   SUBQ    #1,D4                  ;use next smaller access size
   BRA.B   CHECKALIGN
ALIGNED
   MOVE.W  D2,D1                  ;convert byte count into loop count
   LSR.W   D4,D1                  ;  based on current access size
   BEQ.B   MISALIGNED             ;insufficient bytes for access size
   CMP.W   D3,D4                  ;force loop count to 1 if access size
   BEQ.B   RDWR_ACCESS            ;  was reduced for misaligned address
   MOVEQ   #1,D1
RDWR_ACCESS
   MOVE    D1,D5                  ;save loop count
   SUBQ    #1,D1                  ;adjust loop count for DBF
   MOVE.W  (0,A2,D4.W*2),D6
   JSR     (0,A2,D6.W)
   LSL.W   D4,D5                  ;adjust byte count
   SUB.W   D5,D2
   BNE.B   REALIGN
   BRA     MON_MAIN

DO_ODD_ACCESS
   MOVE.W  D3,D4
   MOVE.W  D2,D1                  ;convert byte count into loop count
   LSR.W   D4,D1                  ;  based on current access size
   BRA     RDWR_ACCESS

************************************************************************
* The following routine services the swsr while in the foreground monitor.
* If an interrupt service routine services the swsr register, then this
* routine may be modified to return to the monitor main loop. 
************************************************************************
********************************************************************************
***********************   SERVICE SWSR  REGISTER  ******************************
********************************************************************************
SERV_SWSR

***********************************************************************
* USER MODIFIABLE CODE -
* If an interrupt service routine services the swsr register, then this
* routine may be modified to return to the monitor main loop. Remove the
* "*" from column 1 in following line.
*  BRA      MON_MAIN1
***********************************************************************
 
   MOVE.L   (SIM_BASE,PC),A0
   ADD.L    #REG_SWSR,A0   # Address of Software Service Register

   MOVE.B   #$55,(A0)
   MOVE.B   #$AA,(A0)
   BRA      MON_MAIN1  
 
MONPROGEND

;****************************************************************************
; Identification strings to indicate revision level and origin of this file
;
; MKT:@(#) 64782A      A.00.07 6833X EMULATION FIRMWARE       64782     14Nov96                      
; CPR:@(#)                                                                      
; @(SUBID) MP:                                  
; @(SUBID) MAIN: /lsd/zodiac/inst/m6833x/drivers 0.38  13Nov96 16:00:36         
;****************************************************************************

