	.title "ODYSSEY NS32532 FOREGROUND MONITOR"

#
#	MKT:@(#) 64772-18000 A.00.04 NS32532 EMUL FOREGROUND MONITOR          20Jun90                 
#
# This foreground monitor is used by the 64772A NS32532 emulator 
# to access processor and target resources.  It is also used to
# implement processor run control.  The foreground monitor is 
# entered in one of three ways.  An emulation controller generated 
# reset into the monitor will begin execution at relative address
# 0 in the monitor.  This is the RESETENTRY.  An emulation 
# controller generated NMI will force execution into the monitor
# at the BREAKENTRY.  In this case the exception processing will
# have its stack reads and writes forced to particular monitor memory
# locations.  The third entry method is through normal exception
# processing such as when processing software breakpoints and 
# single-stepping.  This results in entry at EXCEPTIONENTRY.  The 
# configuration item "cf excp" can be used to set up other user 
# induced exceptions to result in entry into the foreground monitor.

# If the monitor is entered through the BREAKENTRY or RESETENTRY
# then it has entered through the background mode.  In these cases
# once the monitor has saved its state, it will exit the background
# portion and enter the foreground mode of the foreground monitor.
# Once in this mode the foreground monitor will accept target 
# generated interrupts.  The monitor is exited by executing a return
# from trap (rett) instruction.  Prior to execution of this instruction
# the stack is modifed to contain the desired values for the PC and
# PSR registers.  If the stack cannot be modified then the exit from
# monitor will fail.

# This forground monitor has been coded to be PC relative and 
# therefore can be loaded anywhere in the 32 bit address space.
# However, in order to communicate effectively, the emulation
# controller expects certain variables to be at known address
# offsets.  In addition several hardware communication functions
# which are at the begining of the monitor must not be moved.  

# The monitor start address must always be aligned to a 4K byte
# boundary.  The monitor is always assembled and linked  such 
# that the text space starts at 0 and the data space starts 
# at 0xc00.  The entire size of the monitor cannot exceed 4096 
# bytes.  Since this monitor has currently hit that limit, 
# customization will require removal of unused code.  Suggested
# functions to remove are the target memory access and the FPU
# register read and write.  By default this monitor will be 
# loaded from firmware when the foreground monitor is being used.

# A user supplied forground monitor can be used by loading using
# the load command with the -f option.  This will change the 
# default foreground monitor until the emulator is reinitialized.
# User supplied monitors must be assembled and linked using the
# same restrictions as described above.


#**********************************************************************#
# MONITOR OFFSET VALUES 
# The controller will access certain values within the monitor.  This
# is accomplished by reading and writing monitor memory at predetermined
# monitor offsets.  The following monitor offsets are defined.
#
#   Location          Monitor Offset
#   --------          --------------
#   resetentry            0x000
#   breakentry            0x020
#   exception_table       0x0dc
#   CMD_BLOCK             0xd80
#     cmd_num             0xd80
#     count               0xd84
#     start_addr          0xd88
#     hw_config           0xd8c
#     accessmode          0xd90
#     functioncode        0xd94
#     regnumber           0xd98
#     loadaddress         0xd9c
#     defaultregisters    0xda0
#     psrmask             0xda4
#   STATUS_BLOCK          0xdb0
#     semaphore           0xdb0
#     are_you_there       0xdb1
#     running             0xdb2
#     mon_entry           0xdb4
#   DATA_BUF              0xdc0
#     data_buf            0xdc0
#   REGISTERS             0xec8
#   JAMIN_STACK           0xf80
#   JAMOUT_STACK          0xfc0
#**********************************************************************#

#**********************************************************************#
# MONITOR CONSTANTS

# Monitor Command Values - Controller will request one of these commands
	.set	CMDEXIT,   1
	.set	CMDRDMEM,  2
	.set	CMDWRMEM,  3
	.set	CMDRDREG,  4
	.set	CMDWRREG,  5
	.set	CMDWAITRST,6
	.set	CMDEXITNR, 7

#  Monitor entry values - Indicates Entry Method
#  Jam Entry
	.set	CHECKED_ENTRY,31
	.set	RESET_ENTRY,24
	.set	CMB_REENTRY,25
	.set	BREAK_ENTRY,26

#  Exception Entry
	.set    NVI_ENTRY,0
	.set    NMI_ENTRY,1
	.set    ABT_ENTRY,2
	.set    SLAVE_ENTRY,3
	.set    ILL_ENTRY,4
	.set    SVC_ENTRY,5
	.set    DVZ_ENTRY,6
	.set    FLG_ENTRY,7
	.set    BPT_ENTRY,8
	.set    TRC_ENTRY,9
	.set    UND_ENTRY,10
	.set    RBE_ENTRY,11
	.set    NBE_ENTRY,12
	.set    OVF_ENTRY,13
	.set    DBG_ENTRY,14
	.set    RESERVED_ENTRY,15
	.set    VI16_ENTRY,16

#  Semaphore values - For Monitor / Controller Synchronization
	.set	NO_CMD,       0
	.set	NEW_CMD,      1
	.set	CMD_STARTED,  2
	.set	MON_FINISHED, 3

#  Monitor status - are_you_there values
	.set    RESPOND,     0
	.set    MON_LOOP,    h'12
	.set    WAIT_CMB,    h'34
	.set    WAIT_RST,    h'56

#  Access Modes - For Target Memory
	.set    BYTEACCESS,  1
	.set    WORDACCESS,  2
	.set    DOUBLEACCESS,4

#  Function Codes  
	.set    ILLEGAL_FC,  0
	.set    DONTCARE_FC, 1
	.set    SUPER_FC,    2
	.set    USER_FC,     3

#  IOB Signals Bit Positions
	.set	OKTORUN, 4
	.set	ANYBRK,  0

#  CFG Register Number and Bit Positions
	.set    CFG_MASK,       h'0ffffe1ff  # Caches are disabled
	.set	FPU_CFG,        1   # Bit position of FPU in CFG register
	.set    MMU_CFG,        2   # Bit position of MMU in CFG register
	.set    DE_CFG,         8   # Bit position of DE in CFG register
	.set    DC_CFG,         9   # Bit position of DC in CFG register
	.set    IC_CFG,         11  # Bit position of IC in CFG register
	.set    PSR_T,          1   # Bit position of T in PSR register
	.set    PSR_U,          8   # Bit position of U in PSR register
	.set    PSR_S,          9   # Bit position of S in PSR register
	.set    PSR_P,          10  # Bit position of P in PSR register

	.set    REG_R0_NUM,     0   # Assigned number for R0 register
	.set    REG_R1_NUM,     1   # Assigned number for R1 register
	.set    REG_R2_NUM,     2   # Assigned number for R2 register
	.set    REG_R3_NUM,     3   # Assigned number for R3 register
	.set    REG_R4_NUM,     4   # Assigned number for R4 register
	.set    REG_R5_NUM,     5   # Assigned number for R5 register
	.set    REG_R6_NUM,     6   # Assigned number for R6 register
	.set    REG_R7_NUM,     7   # Assigned number for R7 register

	.set    REG_PC_NUM,     8   # Assigned number for PC register
	.set    REG_SP_NUM,     9   # Assigned number for SP register
	.set    REG_SP0_NUM,   10   # Assigned number for SP0 register
	.set    REG_SP1_NUM,   11   # Assigned number for SP1 register
	.set    REG_PSR_NUM,   12   # Assigned number for PSR register
	.set    REG_CFG_NUM,   13   # Assigned number for CFG register
	.set    REG_FP_NUM,    14   # Assigned number for FP register
	.set    REG_SB_NUM,    15   # Assigned number for SB register
	.set    REG_INTBASE_NUM, 16   # Assigned number for INTBASE register
	.set    REG_MOD_NUM,   17   # Assigned number for MOD register
   
	.set    REG_DCR_NUM,   18   # Assigned number for DCR register
	.set    REG_DSR_NUM,   19   # Assigned number for DSR register
	.set    REG_CAR_NUM,   20   # Assigned number for CAR register
	.set    REG_BPC_NUM,   21   # Assigned number for BPC register

	.set    REG_PTB0_NUM,  22   # Assigned number for PTB0 register
	.set    REG_PTB1_NUM,  23   # Assigned number for PTB1 register
	.set    REG_IVAR0_NUM, 24   # Assigned number for IVAR0 register
	.set    REG_IVAR1_NUM, 25   # Assigned number for IVAR1 register
	.set    REG_TEAR_NUM,  26   # Assigned number for TEAR register
	.set    REG_MCR_NUM,   27   # Assigned number for MCR register
	.set    REG_MSR_NUM,   28   # Assigned number for MSR register

	.set    REG_FSR_NUM,   29   # Assigned number for FSR register
	.set    REG_F0_NUM,    30   # Assigned number for F0 register
	.set    REG_F1_NUM,    31   # Assigned number for F2 register
	.set    REG_F2_NUM,    32   # Assigned number for F3 register
	.set    REG_F3_NUM,    33   # Assigned number for F3 register
	.set    REG_F4_NUM,    34   # Assigned number for F4 register
	.set    REG_F5_NUM,    35   # Assigned number for F5 register
	.set    REG_F6_NUM,    36   # Assigned number for F6 register
	.set    REG_F7_NUM,    37   # Assigned number for F7 register
	.set    REG_L0_NUM,    38   # Assigned number for L0 register
	.set    REG_L1_NUM,    39   # Assigned number for L2 register
	.set    REG_L2_NUM,    40   # Assigned number for L3 register
	.set    REG_L3_NUM,    41   # Assigned number for L3 register
	.set    REG_L4_NUM,    42   # Assigned number for L4 register
	.set    REG_L5_NUM,    43   # Assigned number for L5 register
	.set    REG_L6_NUM,    44   # Assigned number for L6 register
	.set    REG_L7_NUM,    45   # Assigned number for L7 register


#  Other Constants
	.set	FALSE,0
	.set	TRUE,1
#**********************************************************************#

	.text
# CODE space is linked at 0;  All memory references are PC relative

#**********************************************************************#
#
MONITOR_ENTRY_POINTS:

# From reset, monitor will be entered at location 0

# From break, monitor will be entered at location 0x10 or 0x20.
# Address 0x10 or 0x20 are determined from the dispatch table
# during NMI processing.  The dispatch table has been set up
# to work regardless of the intbase register contents and mode 
# of exception processing.  Every location in the dispatch table
# contains 0x10, and therefore the new address to run from will
# always be 0x10101010 for direct execpetion mode and 0x10102020
# for module exception mode.  Since jamming will force the
# upper 20 bits to 0, the final effective new addresses are 0x010
# and 0x020.

# All page table reads and writes will be forced to address 0xffc
# during monitor entry and exit. If the MMU is enabled during
# execution of the monitor then page table reads and writes will
# be forced to address 0.

# A reset entry is handled differently from a break entry.


# RESET_ENTRY
# ADDRESS 0
	# Reset entry point - processor starts excuting at 0 from reset
	# When the MMU is turned on and translating supervisor space
	# address 0 will be read for both pte1 and pte2.  This is because
	# while in the monitor only the lower 12 bits are valid.
	# In order to satisfy the MMU bits 0, 7, 8  must be 1.
	# The cmpd and addb instructions form a map which maps the monitor
	# back onto itself in addition to forming non-volatile code.

procreset:
	cmpd	r0,r6
	addb    r0,r0
	br	resetentry
	.space 9
# ADDRESS 0x10
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
# ADDRESS 0x20
	# Perform jump to absolute addresses to make monitor addresses match
	# jamming address.  Jamming will always force upper 20 bits to 0
        jump	 @breakentry


#**********************************************************************#
# Hardware access functions are placed here to assure that they stay
# at the same position.  The monitor control bits within the emulation
# hardware has been set up for the following key locations so as to trigger
# hardware state machines when certain monitor locations are accessed.
#
# These functions are procedurized and include many nop's to ensure that
# bus cycles will be deterministic, behaving in exactly the same way
# every time.
#**********************************************************************#

#**********************************************************************#
# This function reads the IOB signals.  This function is at a special
# location to trigger the circuitry required to read these signals.
# Instruction will cause two read - write pairs.  We want to trigger
# a jam on the second read.  The write from the first pair will occur
# immediately prior to the second read.  The trigger point is set to
# on the second write address location.
#
# READ_IOB

	.align 4
read_iob:
	movmb    %dummy2,%dummy1,2
	ret      $(0)
#**********************************************************************#

	.space	16

#**********************************************************************#
# This function sets the signal setemulrdy low.  This function is at a
# special location to trigger the circuitry required to do this.
#
# SETEMULRDY_LOW

	.align 4
setemulrdy_low:
	# Monitor bit trigger - address of following instruction
	ret	 $(0)
#**********************************************************************#

	.space	16

#**********************************************************************#
# This function located at a special location so as to trigger 
# the exit from background monitor circuitry.
#
# BACKGROUND_EXIT

	.align 4
background_exit:
	# Monitor bit trigger - address of following instruction
 	reti
#**********************************************************************#

#**********************************************************************#
# This function transfers the data pointed to by register r7 to the
# location pointed to by the register r6.  This function is at a 
# special location to trigger the target system access circuitry.
# It must trigger the hardware for read from target system.
# Trigger location is set to the location one bus cycle before the read
# Size of data transfer may be byte, word, or double.  The code is
# modified to the correct size for the current transfer operation.
#
# SUPERREADMOP

	.align 4
  	.double   0
	.double   h'00007b94   # movb
	.double   h'00007b95   # movw
	.double   h'00007b97   # movd

superreadmop:
 	movb	0(r7),0(r6)
	nop
	nop
	nop
	nop
	ret $(0)
#**********************************************************************#

#**********************************************************************#
# This function transfers the data pointed to by register r7 to the
# location pointed to by the register r6.  This function is at a 
# special location to trigger the target system access circuitry.
# It must trigger the hardware for read from target system.
# Trigger location is set to the location one bus cycle before the read
# Size of data transfer may be byte, word, or double.  The code is
# modified to the correct size for the current transfer operation.
#
# USERREADMOP

	.align 4
	.double	  0
	.double   h'007b9cae   # movusb
	.double   h'007b9dae   # movusw
	.double   h'007b9fae   # movusd

userreadmop:
 	movusb	0(r7),0(r6)
	nop
	nop
	nop
	ret $(0)
#**********************************************************************#

	.space 16

#**********************************************************************#
# This function located at a special location so as to trigger 
# the exit from monitor circuitry.
#
# MONITOR_EXIT

	.align 4
monitor_exit:
	# Monitor bit trigger - address of following instruction
 	rett  $(0)
#**********************************************************************#

#**********************************************************************#
# This function transfers the data pointed to by register r6 to the
# location pointed to by the register r7.  This function is at a 
# special location to trigger the target system access circuitry.
# It must trigger the hardware for writes to the target system.
# Trigger location is set to the location one bus cycle before the write.
# Size of data transfer may be byte, word, or double.  The code is
# modified to the correct size for the current transfer operation.
#
# SUPERWRITEMOP

	.align 4
	.double   h'000073d4   # movb
	.double   h'000073d5   # movw
	.double   h'000073d7   # movd

superwritemop:
  	movb	0(r6),0(r7)
	ret $(0)
#**********************************************************************#

#**********************************************************************#
# This function transfers the data pointed to by register r6 to the
# location pointed to by the register r7.  This function is at a 
# special location to trigger the target system access circuitry.
# It must trigger the hardware for writes to the target system.
# Trigger location is set to the location one bus cycle before the write.
# Size of data transfer may be byte, word, or double.  The code is
# modified to the correct size for the current transfer operation.
#
# USERWRITEMOP

	.align 4
	.double   h'0073ccae   # movsub
	.double   h'0073cdae   # movsuw
	.double   h'0073cfae   # movsud

userwritemop:
  	movsub	0(r6),0(r7)
	ret $(0)
#**********************************************************************#

#**********************************************************************#
# This table provides a mechanism of entry into the exception processing
# functions.  This table is at a known offset in the foreground monitor
# and cannot be changed.  This table is used so the the actual exception
# functions do not have to be position dependent.
#
# EXCEPTION_TABLE

	.align 4
exception_table:
        br	nvientry
	.align 4
        br	nmientry
	.align 4
        br	abtentry
	.align 4
        br	slaveentry
	.align 4
        br	illentry
	.align 4
        br	svcentry
	.align 4
        br	dvzentry
	.align 4
        br	flgentry
	.align 4
        br	bptentry
	.align 4
        br	trcentry
	.align 4
        br	undentry
	.align 4
        br	rbeentry
	.align 4
        br	nbeentry
	.align 4
        br	ovfentry
	.align 4
        br	dbgentry
	.align 4
        br	reservedentry
	.align 4
        br	vi16entry


#**********************************************************************#

# END OF POSITION DEPENDENT FUNCTIONS
#**********************************************************************#

#**********************************************************************#
# Non-Vectored Interrupt entry point 
# Monitor entry here as the result of a non-vectored interrupt
#
# NVIENTRY - exception vector 0

	.align 4
nvientry:
	sbitd	 $(NVI_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Non-Maskable Interrupt entry point 
# Monitor entry here as the result of a non-maskable interrupt
#
# NMIENTRY - exception vector 1

	.align 4
nmientry:
	sbitd	 $(NMI_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Abort Trap entry point    
# Monitor entry here as the result of an abort trap
#
# ABTENTRY - exception vector 2

	.align 4
abtentry:
	sbitd	 $(ABT_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Slave Request Trap entry point    
# Monitor entry here as the result of a slave induced trap
#
# SLAVEENTRY - exception vector 3

	.align 4
slaveentry:
	sbitd	 $(SLAVE_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Illegal Operation Trap entry point    
# Monitor entry here as the result of an illegal operation
#
# ILLENTRY - exception vector 4

	.align 4
illentry:
	sbitd	 $(ILL_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Supervisor Call Trap entry point    
# Monitor entry here as the result of a supervisor call instruction
#
# SVCENTRY - exception vector 5

	.align 4
svcentry:
	sbitd	 $(SVC_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Divide by 0 Trap entry point    
# Monitor entry here as the result of a divide by 0 operation
#
# DVZENTRY - exception vector 6

	.align 4
dvzentry:
	sbitd	 $(DVZ_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Flag Trap entry point    
# Monitor entry here as the result of a flag instruction
#
# FLGENTRY - exception vector 7

	.align 4
flgentry:
	sbitd	 $(FLG_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Software Breakpoint Trap entry point    
# Monitor entry here as the result of a breakpoint instruction
#
# BPTENTRY - exception vector 8

	.align 4
bptentry:
	sbitd	 $(BPT_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Trace Trap entry point    
# Monitor entry here as the result of instruction tracing
#
# TRCENTRY - exception vector 9

	.align 4
trcentry:
	sbitd	 $(TRC_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Undefined Operation Trap Breakpoint entry point    
# Monitor entry here as the result of an undefined instruction or operation
#
# UNDENTRY - exception vector 10

	.align 4
undentry:
	sbitd	 $(UND_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Restartable bus error execption entry point
# Monitor entry here as the result of a restartable bus error
#
# RBEENTRY - exception vector 11

	.align 4
rbeentry:
	sbitd	 $(RBE_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Non-Restartable bus error execption entry point
# Monitor entry here as the result of a non-restartable bus error
#
# NBEENTRY - exception vector 12

	.align 4
nbeentry:
	sbitd	 $(NBE_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Overflow Trap entry point    
# Monitor entry here as the result of an overflow result
#
# OVFENTRY - exception vector 13

	.align 4
ovfentry:
	sbitd	 $(OVF_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Debug Trap entry point    
# Monitor entry here as the result of processor debug conditions being true
#
# DBGENTRY - exception vector 14

	.align 4
dbgentry:
	sbitd	 $(DBG_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Reserved Exception entry point    
#
# RESERVEDENTRY - exception vector 15

	.align 4
reservedentry:
	sbitd	 $(RESERVED_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# Vectored Interrupt entry point    
#
# VI16ENTRY  - exception vector 16

	.align 4
vi16entry:
	sbitd	 $(VI16_ENTRY),%mon_entry

	br	 exceptionentry
#**********************************************************************#

#**********************************************************************#
# NORMAL EXCEPTION PROCESSING
# Monitor is executing in foreground
#  
# EXCEPTIONENTRY

	.align 4
exceptionentry:
        # This entry point is due to a normal processor exception

	# At this point the processor is in supervisor mode
	# The exceptions NMI, INT, DBG, ABT, and bus errors will
	# disable maskable interrupts.  The other exceptions will
	# not disturb the I bit in the PSR.  The original contents
	# of the PSR I bit is reloaded into the PSR in the 
	# MONITOR_LOOP so that interrupts may be enabled during
	# the duration of monitor execution.  Upon exit from the
	# monitor the PSR will be restored to its value prior to 
	# entry of the monitor.  For those traps which do not affect
	# the PSR interrupts are disabled here and turned on later.

	lprw	 psr,$(0)

	# Save general purpose registers used in monitor
	movd     r4,%REG_R4
	movd     r5,%REG_R5
	movd     r6,%REG_R6
	movd     r7,%REG_R7

	# Save cfg register,  Turn off caching
	sprd	 cfg,r7
	movd     r7,%REG_CFG
	andd     $(CFG_MASK),r7
	lprd 	 cfg,r7

	# Turn off the MMU if it is currently enabled
	movqd    $(0),%REG_MCR
	tbitd    $(MMU_CFG),%REG_CFG
	bfc      .EE4
	smr      mcr,%REG_MCR
	lmr      mcr,$(0)
.EE4:

	# Do special things with PC, SP, and PSR registers
        # Save the stack values before and after the break
	sprd	 sp,%return_stack

        # Save the PC and PSR; These are the correct values prior to break
	movd     0(sp),%REG_PC
	movw     6(sp),%REG_PSR
	# Save MOD because of possible module exception mode
	movw     4(sp),%REG_MOD

	# If exception was caused by system controlled single step,
	# then T bit in PSR will be set.  Clear it to 0
	cmpqb    $(TRUE),%singlestep
	bne      .EE3
	cbitw    $(PSR_T),%REG_PSR
	movqb    $(FALSE),%singlestep

	# If pending bit is set, then wanted to single-step, but a higher
	# priority caused the exception.  Clear pending bit and indicate
	# single-step entry in addition to real cause of monitor entry
	tbitw    $(PSR_P),%REG_PSR
	bfc      .EE3
	cbitw    $(PSR_P),%REG_PSR
	sbitd    $(TRC_ENTRY),%mon_entry
.EE3:

        # Save interrupt stack pointer prior to the exception
        movd     %return_stack,r7
        addd     $(8),r7
        movd     r7,%REG_SP0

        # MOD and SB registers are special handled according to 
	# type of exeception mode.  Controller will handle SB
	# for module exception mode.

        tbitd    $(DE_CFG),%REG_CFG
	bfc      .EE0
	# If direct exception mode, then 
	# MOD and SB registers were not affected by break
	sprw 	 mod,%REG_MOD
.EE0:

	# If module exception mode then mod register will be in 
	# monitor stack.  Controller will read memory to get SB.
	# Load mod with prior break value to keep current
	# At exit value in mod register will be used to restore
	# This value was saved earlier
	# Store in register to handle any changes to CFG register
	lprw 	 mod,%REG_MOD

	# Go to main monitor loop
	br	 monitor_loop
#**********************************************************************#

#**********************************************************************#
# Reset into the monitor will force execution from monitor offset 0
# Monitor will execute in background until exit to monitor_loop
#
# RESETENTRY

	.align 4
resetentry:
        # Setup of the default power-up conditions
	sbitd	 $(RESET_ENTRY),%mon_entry

	# Processor is in reset configuration
	# Execution from address 0
	# Implemented bits in PSR, MSR, MCR, and CFG registers are 0

	# Save general purpose registers used in monitor
	movd     r4,%REG_R4
	movd     r5,%REG_R5
	movd     r6,%REG_R6
	movd     r7,%REG_R7

        # Configure the registers for a reset configuration
	# Specifically set the CFG register for correct state of
	# MMU and FPU existence.  The variable hw_config will 
	# contain the default CFG register setting.  The variable
	# default_registers bit 0 will be a 1 if the CFG register
	# is to be set to a particular value.
	sprd     cfg,%REG_CFG
	# if defaultregisters bit 0 is 1 then initialize CFG register
        tbitd    $(0),%defaultregisters
	bfc      .DFCF
	movd     %hw_config,%REG_CFG
.DFCF:
	movd     %REG_CFG,r7
	andd     $(CFG_MASK),r7
	lprd 	 cfg,r7

	# Setup default stack pointer
	addr     %TOP_OF_STACK,r6
	addd     %loadaddress,r6
	movd     r6,%REG_SP0

	# Calculate stack value prior to return from monitor
	sprd     sp,%return_stack

        # Initialize PC and PSR to reset values; reset to 0
	movqd    $(0),%REG_PC
	movqw    $(0),%REG_PSR

        # Initialize MCR to reset value
	movqd	 $(0),%REG_MCR

	# Save MOD register; don't care what it is
	sprw 	 mod,%REG_MOD

	# Go to main monitor loop
        # To exit from background portion of monitor to foreground must
	# set up stack to point to monitor_loop.  A stack value is set
	# up to guarantee that a stack exists for this transfer from 
	# the background portion of the monitor to the foreground portion.

	# Set stack pointer so that it is double word aligned 
	# This makes the jamout easy - just set up PC, PSR, and
	# MOD at aligned spots - make PSR and MOD 0
	addr     %TOP_OF_MONSTACK,r6
	addd     %loadaddress,r6
	lprd     sp,r6
	adjspd   $(8)

	addr     %JAMOUT_STACK,r7
	addr     %monitor_loop,r6
	addd     %loadaddress,r6
	movd     r6,0(r7)          # PC value - address of monitor_loop
	movw     $(0),6(r7)        # PSR value
	movw     %REG_MOD,4(r7)    # MOD value
	movd     $(0),8(r7)        # SB values
	movb     $(0),12(r7)       # EOI vector

	br       %background_exit
#**********************************************************************#

#**********************************************************************#
# Break from foreground will cause execution in monitor 
# based on dispatch table.  Entry should always specify
# this entry, breakentry.
# Monitor will execute in background until exit to monitor_loop
#
# BREAKENTRY

	.align 4
breakentry:
        # Controller induced break
	sbitd	 $(BREAK_ENTRY),%mon_entry

        # This entry point is due to a break from user code to monitor -NMI
	# At this point the processor is in supervisor mode
	# PSR U is 0 - all instructions may be executed
	# PSR S is 0 - use supervisor stack pointer SP0
	# PSR I is 0 - maskable interrupts are disabled
	#              If interrupts were enabled, then they are reenabled

	# At this point the processor is in supervisor mode
	# NMI was used to reach this entry point and therefore maskable
	# interrupts were disabled.  The original contents of the PSR I
	# bit is reloaded in the MONITOR_LOOP so that interrupts may be
	# enabled during the duration of monitor execution.  Upon exit
	# from the monitor the PSR will be restored to its value prior
	# to entry of the monitor.

	# Save general purpose registers used in monitor
	movd     r4,%REG_R4
	movd     r5,%REG_R5
	movd     r6,%REG_R6
	movd     r7,%REG_R7

	# Save cfg register,  Turn off caching
	sprd	 cfg,r7
	movd     r7,%REG_CFG
	andd     $(CFG_MASK),r7
	lprd 	 cfg,r7

	# Turn off the MMU if it is currently enabled
	movqd    $(0),%REG_MCR
	tbitd    $(MMU_CFG),%REG_CFG
	bfc      .BE1
	smr      mcr,%REG_MCR
	lmr      mcr,$(0)
.BE1:

	# Do special things with PC, SP, and PSR registers
        # Save the stack values before and after the break
	sprd	 sp,%return_stack
        movd     %return_stack,r7
        addd     $(8),r7
        movd     r7,%REG_SP0

	# Save the INTBASE register, to be used my get_jam
	sprd 	 intbase,%REG_INTBASE

        # Read PC, MOD, and PSR from JAMIN STACK
        # Before using the following registers must be current
        # REG_SP0
        # REG_CFG
        # REG_INTBASE
        # 
        # GET_JAM
	movqd	$(3),r5        # calculate rotate left bits
	andd	%REG_SP0,r5    # rotate_left = 32 - (REG_SP0 & 3) * 8
	lshd	$(3),r5

        # r5 contains the number of bits to shift
	# r6 contains the number of bits to rotate
	# register r6 = 32 - (8 * (lower two bits of SP0))
	movd	$(32),r4
	movd    r5,r6
	subd	r6,r4
	movd    r4,r6

	# Set up masks for PSR MOD
	# bits 1..0 of SP0
	#  00   mask_1=0xffff0000   mask_2=0x0000ffff   mask_3=0x00000000
	#  01   mask_1=0xff000000   mask_2=0x000000ff   mask_3=0x00ffff00
	#  10   mask_1=0x0000ffff   mask_2=0xffff0000   mask_3=0x00000000
	#  11   mask_1=0x00ffff00   mask_2=0xff000000   mask_3=0x000000ff
	# register r5 = 8 * (lower two bits of SP0)

	# case 00
	movd    $(h'0ffff0000),%mask_1
	comd    %mask_1,%mask_2

	movqd	$(3),r4
	andd	%REG_SP0,r4
	cmpqd	$(1),r4
	bne	.GJ7
	# case 01
	movd    $(h'0ff000000),%mask_1
	movd    $(h'0000000ff),%mask_2
	br	.GJ9
.GJ7:
	cmpqd	$(2),r4
	bne	.GJ8
	# case 10
	movd    $(h'00000ffff),%mask_1
	comd    %mask_1,%mask_2
	br	.GJ9
.GJ8:
	cmpqd	$(3),r4
	bne	.GJ9
	# case 11
	movd    $(h'000ffff00),%mask_1
	movd    $(h'0ff000000),%mask_2
.GJ9:

	# Calculate mask_3
	movd    %mask_1,r4
	ord     %mask_2,r4
	comd    r4,%mask_3

        addr    %JAMIN_STACK,r7

	# Get PSR and MOD
	andd    %mask_1,0(r7)
	movd	0(r7),%jam_value   # Always get first double of jam
	addqd	$(4),r7

	# Check for exception mode type
	tbitb	$(DE_CFG),%REG_CFG
	bfs	.GJ1

	# Module exception mode
	# For module exception mode always get a second double
	andd    %mask_2,0(r7)
	ord	0(r7),%jam_value
	addqd	$(4),r7
	# If SP0 is odd then get a third double
	tbitb	$(0),%REG_SP0
	bfc	.GJ2
	andd    %mask_3,0(r7)
	ord	0(r7),%jam_value
	addqd	$(4),r7
.GJ2:
        # Since module exception mode, need to skip reads
	# If REG_INTBASE is double aligned - three double reads
	addd	$(12),r7
	movqd	$(3),r4
	andd	%REG_INTBASE,r4
	cmpqd	$(0),r4
	beq	.GJ3
	# If not double aligned - then four double reads
	addqd	$(4),r7
.GJ3:
	br	.GJ4
.GJ1:
        # Direct exception mode
	# If bits 1..0 of REG_SP0 are 01 then need second word
	movqd	$(3),r4
	andd	%REG_SP0,r4
	cmpqd	$(1),r4
	bne	.GJ5
	andd    %mask_2,0(r7)
	ord	0(r7),%jam_value
	addqd	$(4),r7
.GJ5:
.GJ4:
        # REG_PSR is in upper 16 bits, REG_MOD is in lower 16 bits
	rotd	r6,%jam_value
	movd	%jam_value,r4
	lshd	$(-16),r4
	movw	r4,%REG_PSR
	movqw	$(-1),r4
	andw	%jam_value,r4
	movw	r4,%REG_MOD

	# Get PC
	# If REG_SP0 is double aligned need only one double
	# Set up masks for PC 
	# PC masks
	# bits 1..0 of SP0
	#  00   mask_1=0xffffffff   mask_2=0x00000000
	#  01   mask_1=0xffffff00   mask_2=0x000000ff
	#  10   mask_1=0xffff0000   mask_2=0x0000ffff
	#  11   mask_1=0xff000000   mask_2=0x00ffffff
	# register r5 = 8 * (lower two bits of SP0)

	movd    $(h'0ffffffff),%mask_1
	lshd    r5,%mask_1
	movd    %mask_1,r4
	comd    r4,mask_2

	andd    %mask_1,0(r7)
	movd	0(r7),%jam_value
	addqd	$(4),r7
	movqd	$(3),r4
	andd	%REG_SP0,r4
	cmpqd	$(0),r4
	beq	.GJ6
	# If REG_SP0 is not double aligned need two doubles
	andd    %mask_2,0(r7)
	ord	0(r7),%jam_value
.GJ6:
	movd	%jam_value,r4
	rotd	r6,r4
	movd	r4,%REG_PC

        # Clear JAMIN Stack
        addr    %JAMIN_STACK,r7
	movqd   $(0),r6 
.CJ1:
	movd    $(h'10101010),0(r7)
	addqd   $(4),r7
	addqd   $(1),r6
	cmpd    $(16),r6
	bne     .CJ1
.CJ2:

        # If direct exception mode, then MOD was not on stack
        tbitd    $(DE_CFG),%REG_CFG
	bfc      .MON0
	# If direct exception mode, then 
	# MOD and SB registers were not affected by break
	sprw 	 mod,%REG_MOD

.MON0:
	# If module exception mode then mod register will be in 
	# JAMIN Stack.  Controller will read memory to get SB.
	# Load mod with prior break value to keep current
	# At exit value in mod register will be used to restore
	lprw 	 mod,%REG_MOD

	# Go to main monitor loop
        # To exit from background portion of monitor to foreground must
	# set up stack to point to monitor_loop.  A stack value is set
	# up to guarantee that a stack exists for this transfer from 
	# the background portion of the monitor to the foreground portion.

	# Set stack pointer so that it is double word aligned 
	# This makes the jamout easy - just set up PC, PSR, and
	# MOD at aligned spots - make PSR and MOD 0
	addr     %TOP_OF_MONSTACK,r6
	addd     %loadaddress,r6
	lprd     sp,r6
	adjspd   $(8)

	addr     %JAMOUT_STACK,r7
	addr     %monitor_loop,r6
	addd     %loadaddress,r6
	movd     r6,0(r7)          # PC value - address of monitor_loop
	movw     $(0),6(r7)        # PSR value
	movw     %REG_MOD,4(r7)    # MOD value
	movd     $(0),8(r7)        # SB values
	movb     $(0),12(r7)       # EOI vector

	br       %background_exit
#**********************************************************************#

#**********************************************************************#
# Reenter monitor from monitor itself
# This will occur while waiting for CMB a pending break is detected
#
# REENTRY

	.align 4
reentry:
        # This entry point is due to a break while running in monitor
	sbitd	 $(CMB_REENTRY),%mon_entry

	# Turn off MMU
	tbitd	 $(MMU_CFG),%REG_CFG
	bfc      .RE1
	lmr      mcr,$(0)
.RE1:

	# All registers are already saved

	# Go to main monitor loop
	br	 monitor_loop
#**********************************************************************#

#**********************************************************************#
# This is the main command loop
#
# MONITOR_LOOP

	.align 4
monitor_loop:
	cbitd    $(CHECKED_ENTRY),%mon_entry

        # Load the stack pointer to the monitor stack area
	# Monitor will call procedures, therefore needs a valid stack
	# If jammed monitor entry then stack was set up
	# If exception entry then use the existing stack
#	addr     %TOP_OF_MONSTACK,r7
#	lprd     sp,r7

        # Now enable maskable interrupts, if they were enabled
	# User can select whether or not interrupts should be
	# enabled while in the monitor.  If the user wants them
	# enabled, then they are only enabled if enabled prior
	# to the monitor entry.
	movzwd   %REG_PSR,r7
	andd     %psrmask,r7       # Load orignal PSR I bit
	lprw     psr,r7

.LL2:
        # Check for a new command
	cmpqb	 $(NEW_CMD),%semaphore
	beq	 .LL3
	movb	 %are_you_there,r7
	br	 .LL4
.LL3:
	# A new command has been issued - do it
	# Signal acceptance of command
	movqb	 $(CMD_STARTED),%semaphore

        # Initialize the functioncode for target accesses
	cmpqd 	 $(DONTCARE_FC),%functioncode
	bne      .FC1
	tbitw    $(PSR_U),%REG_PSR
	bfc      .FC2
	movqd    $(USER_FC),%functioncode
	br       .FC1
.FC2:
        movqd    $(SUPER_FC),%functioncode
.FC1:

	br	 .LL6
.LL7:
        # cmd_num == CMDEXIT
	# Check CMB and return to foreground
	br	 foreground
.LL8:
        # cmd_num == CMDRDMEM
	# Read from target memory to data_buf
	bsr	 readtarget
	movqb	 $(MON_FINISHED),%semaphore
	br	 .LL5
.LL9:
        # cmd_num == CMDWRMEM
	# Write from data_buf to target memory
	bsr	 writetarget
	movqb	 $(MON_FINISHED),%semaphore
	br	 .LL5
.LL10:
        # cmd_num == CMDRDREG
	# Ensure that register copies are in monitor register area
	bsr	 readregister
	movqb	 $(MON_FINISHED),%semaphore
	br	 .LL5
.LL11:
        # cmd_num == CMDWRREG
	# Modify registers
	bsr	 writeregister
	movqb	 $(MON_FINISHED),%semaphore
	br	 .LL5
.LL12:
        # cmd_num == CMDWAITRST
	# Wait for target system reset
	br       wait_for_rst
.NR16:
        # cmd_num == CMDEXITNR
	# Return to foreground without checking CMB
	# and setting EMULRDY
	# This command is used to handle multiple 
	# exceptions, such as when stepping through
	# a hardware breakpoint.
	br	 foreground_ready
.LL14:
        # default:
	br	 .LL5
.LL6:
.LL15:
	movd  	 %cmd_num,r6
	cmpqd	 $(CMDEXIT),r6
	bgt	 .LL14
	cmpqd	 $(CMDEXITNR),r6
	blt	 .LL14
.LP6:
	casew	 .LP5+(-2)[r6:w]

.LL5:
.LL4:
        # Indicate that the monitor is in the main monitor loop
	movb	 $(MON_LOOP),%are_you_there
	br	 .LL2


	# monitor loop branch table
	.align 4
.LP5:
	.word	.LL7 - .LP6
	.word	.LL8 - .LP6
	.word	.LL9 - .LP6
	.word	.LL10 - .LP6
	.word	.LL11 - .LP6
	.word	.LL12 - .LP6
	.word	.NR16 - .LP6
#**********************************************************************#

#**********************************************************************#
# Just stay here waiting for reset- there is no other way out
#
# WAIT_FOR_RST

	.align 4
wait_for_rst:
        # Indicate that the monitor is in the waiting for reset loop
	movqb	 $(MON_FINISHED),%semaphore
	movb	 $(TRUE),%running
	movb	 $(WAIT_RST),%are_you_there

        br       wait_for_rst
#**********************************************************************#

#**********************************************************************#
# Return from monitor to user code 
# This involves :
#   Restoring registers
#   Signalling ready on the CMB
#   Checking for CMB for OK To RUN
#     If not ready then check for pending break
#     If pending break, then reenter monitor
#
# FOREGROUND

	.align 4
foreground:
        # Indicate that this emulator is ready to go
	bsr	 setemulrdy_low

.LL17:
	# Indicate run has started
	movb	 $(TRUE),%running

        # Indicate that the monitor is in the waiting for CMB loop
	movb	 $(WAIT_CMB),%are_you_there

	# Read IOB signals
	bsr	 read_iob
	# If OK TO RUN
	tbitb	 $(OKTORUN),%iob_signals
	# signal is active high
	bfc	 .LL18

	# System is ready - Return to foreground
	# Check count flag for new specification of PC
	# New PC value will be in start_addr if count bit 0 is 1
	tbitd	 $(0),%count
	bfc	 .LL19
	# New PC value, stuff into stack
	movd     %start_addr,%REG_PC
.LL19:

foreground_ready:

 	# Restore registers CFG, PC, SP0, MOD, and R0-R7
	# Do special things with PC, SP, and PSR registers
	# Calculate the new address for the PC and PSR on stack
	# Stack pointer may have been changed, so have to rebuild
	# stack for correct return.
	movd     %REG_SP0,r7
	subd     $(8),r7
	movd     r7,%return_stack

	# Set the user bit in PSR to match function code
	sbitw    $(PSR_U),%REG_PSR
	cmpqd 	 $(USER_FC),%functioncode
	beq      .FC3
	cbitw    $(PSR_U),%REG_PSR
.FC3:

        # Restore the PC and PSR; These are the correct values prior to break
	# Also put MOD into stack for possible module exception mode.  If not
	# module exeption mode it doesn't matter
	sprw 	 mod,%REG_MOD
	movw     %REG_PSR,6(r7)
	movd     %REG_PC,0(r7)
	movw     %REG_MOD,4(r7)

        # Restore MOD register for possible direct execption mode
	# If module exception mode then it doesn't matter
	# SB is handled completely by the controller
	lprw 	 mod,%REG_MOD

	# Restore cfg register
	lprd 	 cfg,%REG_CFG

	# Check count flag for single step specification
	# Single step indication if count bit 1 is 1
	tbitd	 $(1),%count
	bfc	 .LL21
	# Modify return PSR to have the TRC bit set (bit 1)
	orw      $(2),6(r7)
	movqb    $(TRUE),%singlestep
.LL21:

        # Restore the interrupt stack value after the break
	lprd	 sp,%return_stack

	# Restore r4-r7 registers used in monitor prior to break
	movd     %REG_R7,r7
	movd     %REG_R6,r6
	movd     %REG_R5,r5
	movd     %REG_R4,r4

	# Tell controller that the monitor is finished
	movqb	 $(MON_FINISHED),%semaphore

        # Turn on the MMU if it is currently enabled
	tbitd    $(MMU_CFG),%REG_CFG
	bfc      .FG22
	# Invalidate TLB by reloading PTB0
	smr      ptb0,%REG_PTB0
	lmr      ptb0,%REG_PTB0
	lmr      mcr,%REG_MCR
	# Address translation starts at this point

.FG22:

	# This will stop execution of monitor at this point
	br	 %monitor_exit

.LL18:
        # CMB not ready, check for pending break
	# signal is active low
	tbitb	 $(ANYBRK),%iob_signals
	bfs	 .LL20

	# If pending break, then reenter monitor
	br	 %reentry
.LL20:
	br	 .LL17
#**********************************************************************#

#**********************************************************************#
#
# READREGISTER

	.align 4
readregister:
        # CPU registers 0..21   REG_R0_NUM..REG_BPC_NUM
	# MMU registers 22..28  REG_PTB0_NUM..REG_MSR_NUM
	# FPU registers 29..45  REG_FSR_NUM..REG_L7_NUM
    
	# Save CPU registers into monitor buffer area
	# Registers CFG, PC, SP0, PSR, MOD, and R5-R7 are handled special
	# These registers are saved upon monitor entry and will be 
	# restored upon monitor exit.  Changes made in between are lost.
	# There is an attempt to keep all registers loaded with their
	# latest user value.

	# Save R0-R4,SP1,FP,SB,INTBASE,MOD,DCR,DSR,CAR,BPC
	movd     r0,%REG_R0
	movd     r1,%REG_R1
	movd     r2,%REG_R2
	movd     r3,%REG_R3
	bispsrw  $(b'0000001000000000)
	sprd 	 sp,%REG_SP1
	bicpsrw	 $(b'0000001000000000)
	sprd 	 fp,%REG_FP
	sprd 	 sb,%REG_SB
	sprd 	 intbase,%REG_INTBASE
	sprw 	 mod,%REG_MOD
	sprd 	 dcr,%REG_DCR
	sprd 	 dsr,%REG_DSR
	sprd 	 car,%REG_CAR
	sprd 	 bpc,%REG_BPC

	# Update REG_SP to be either REG_SP0 or REG_SP1
        tbitw    $(PSR_S),%REG_PSR
	bfc      .RER0 
	movd     %REG_SP1,%REG_SP
	br       .RER1
.RER0:
	movd     %REG_SP0,%REG_SP
.RER1:
	# Save MMU registers into monitor buffer area
	# Get MMU registers if M bit in CFG register is set
        tbitd    $(MMU_CFG),%REG_CFG
	bfc      .RLL4 
	smr	 ptb0,%REG_PTB0
	smr      ptb1,%REG_PTB1
	# Cannot read registers IVAR0 and IVAR1
	smr      tear,%REG_TEAR
	# MCR register saved earlier in order to turn off translation
	# smr      mcr,%REG_MCR
	smr      msr,%REG_MSR

.RLL4:
	# Save FPU registers into monitor buffer area
	# Get FPU registers if FPU present and F bit in CFG register is set
        tbitd    $(FPU_CFG),%hw_config
	bfc      .RLL7 
        tbitd    $(FPU_CFG),%REG_CFG
	bfc      .RLL7 
	sfsr	 %REG_FSR
	movl	 l0,%REG_L0
	movl	 l1,%REG_L1
	movl	 l2,%REG_L2
	movl	 l3,%REG_L3
	movl	 l4,%REG_L4
	movl	 l5,%REG_L5
	movl	 l6,%REG_L6
	movl	 l7,%REG_L7
	# Reload fsr since reads from other registers are destructive
	lfsr	 %REG_FSR

.RLL7:
	ret	 $(0)
#**********************************************************************#

#**********************************************************************#
#
# WRITEREGISTER

	.align 4
writeregister:
	# New register value has been loaded into data_buf
	# Transfer value from buffer to either monitor register area or register

	# Registers CFG, PC, SP0, PSR, MOD, and R0-R7 are handled special
	# These registers are saved upon monitor entry and will be 
	# restored upon monitor exit.  All references to these resiters are
	# made through the monitor register area.

	# The registers SP1,FP,SB,INTBASE,DCR,DSR,CAR,BPC, along with MMU and
	# FPU registers are kept upto date since they don't change while in
	# the monitor.

	# This function uses register r6 and r7
	# Check if the write register is either an MMU or FPU
	# These units may not be on, therefore they can't be written to

	# Check for MMU register to be written to
	movd	%regnumber,r6
	cmpd	$(REG_PTB0_NUM),r6
	bgt	.WLL55
	cmpd	$(REG_MSR_NUM),r6
	blt	.WLL55

	# Check to see if MMU is enabled
        tbitd    $(MMU_CFG),%REG_CFG
	bfc      .WLL6 
	br       .WLL56

.WLL55:
	# Not an MMU register, check for FPU register
	# Check for FPU register to be written to
	movd	%regnumber,r6
	cmpd	$(REG_FSR_NUM),r6
	bgt	.WLL56
	cmpd	$(REG_L7_NUM),r6
	blt	.WLL56

	# Check to see if FPU is present
        tbitd    $(FPU_CFG),%hw_config
	bfc      .WLL6 
	# Check to see of FPU is enabled
        tbitd    $(FPU_CFG),%REG_CFG
	bfc      .WLL6 

	# Write to FPU register, save and restore FSR
	sfsr	 %REG_FSR


.WLL56:

	# Not an invalid MMU or FPU write, so continue with write to register

	addr     %data_buf,r7   # address of new register value
	br	.WLL7           # branch based on register number

.WLL8:
        # Write Register R0
        movd     0(r7),%REG_R0
	movd     %REG_R0,r0
	br	.WLL6
.WLL9:
        # Write Register R1
        movd     0(r7),%REG_R1
	movd     %REG_R1,r1
	br	.WLL6
.WLL10:
        # Write Register R2
        movd     0(r7),%REG_R2
	movd     %REG_R2,r2
	br	.WLL6
.WLL11:
        # Write Register R3
        movd     0(r7),%REG_R3
	movd     %REG_R3,r3
	br	.WLL6
.WLL12:
        # Write Register R4 - used in monitor restored at exit
        movd     0(r7),%REG_R4
	br	.WLL6
.WLL13:
        # Write Register R5 - used in monitor restored at exit
        movd     0(r7),%REG_R5
	br	.WLL6
.WLL14:
        # Write Register R6 - used in monitor restored at exit
        movd     0(r7),%REG_R6
.WLL15:
        # Write Register R7 - used in monitor restored at exit
        movd     0(r7),%REG_R7
	br	.WLL6
.WLL16:
        # Write Register PC
        movd     0(r7),%REG_PC
	br	.WLL6
.WLL17:
        # Write Register SP
        movd     0(r7),%REG_SP
	# Update either SP0 or SP1
        tbitw    $(PSR_S),%REG_PSR
	bfc      .WLL18   # Update SP0
	br       .WLL19   # Update SP1
.WLL18:
        # Write Register SP0
        movd     0(r7),%REG_SP0
	br	.WLL6
.WLL19:
        # Write Register SP1
        movd     0(r7),%REG_SP1
	# Switch to user stack pointer
	bispsrw  $(b'0000001000000000)
	lprd 	 sp,%REG_SP1
	# Switch back to supervisor stack pointer
	bicpsrw	 $(b'0000001000000000)
	br	.WLL6
.WLL20:
        # Write Register PSR
        movw     0(r7),%REG_PSR
	br	.WLL6
.WLL21:
        # Write Register CFG
	# Ensure that CFG register bits 4..7 are 1
        movd     0(r7),%REG_CFG
	ord      $(h'f0),%REG_CFG
	andd     $(CFG_MASK),0(r7)
	lprd 	 cfg,0(r7)
	br	.WLL6
.WLL22:
        # Write Register FP
        movd     0(r7),%REG_FP
	lprd     fp,%REG_FP
	br	.WLL6
.WLL23:
        # Write Register SB
        movd     0(r7),%REG_SB
	lprd     sb,%REG_SB
	br	.WLL6
.WLL24:
        # Write Register INTBASE
        movd     0(r7),%REG_INTBASE
	lprd     intbase,%REG_INTBASE
	br	.WLL6
.WLL25:
        # Write Register MOD
        movw     0(r7),%REG_MOD
	lprw     mod,%REG_MOD
	br	.WLL6
.WLL26:
        # Write Register DCR
        movd     0(r7),%REG_DCR
	lprd     dcr,%REG_DCR
	br	.WLL6
.WLL27:
        # Write Register DSR
        movd     0(r7),%REG_DSR
	lprd     dsr,%REG_DSR
	br	.WLL6
.WLL28:
        # Write Register CAR
        movd     0(r7),%REG_CAR
	lprd     car,%REG_CAR
	br	.WLL6
.WLL29:
        # Write Register BPC
        movd     0(r7),%REG_BPC
	lprd     bpc,%REG_BPC
	br	.WLL6
.WLL30:
        # Write Register PTB0
        movd     0(r7),%REG_PTB0
	lmr      ptb0,%REG_PTB0
	br	.WLL6
.WLL31:
        # Write Register PTB1
        movd     0(r7),%REG_PTB1
	lmr      ptb1,%REG_PTB1
	br	.WLL6
.WLL32:
        # Write Register IVAR0
        movd     0(r7),%REG_IVAR0
	lmr      ivar0,%REG_IVAR0
	br	.WLL6
.WLL33:
        # Write Register IVAR1
        movd     0(r7),%REG_IVAR1
	lmr      ivar1,%REG_IVAR1
	br	.WLL6
.WLL34:
        # Write Register TEAR
        movd     0(r7),%REG_TEAR
	lmr      tear,%REG_TEAR
	br	.WLL6
.WLL35:
        # Write Register MCR
        movd     0(r7),%REG_MCR   # Register restored at monitor exit
	br	.WLL6
.WLL36:
        # Write Register MSR
        movd     0(r7),%REG_MSR
	lmr      msr,%REG_MSR
	br	.WLL6
.WLL37:
        # Write Register FSR
        movd     0(r7),%REG_FSR
	br	.WLL57
.WLL38:
        # Write Register F0
        movf     0(r7),f0
	br	.WLL57
.WLL39:
        # Write Register F1
        movf     0(r7),f1
	br	.WLL57
.WLL40:
        # Write Register F2
        movf     0(r7),f2
	br	.WLL57
.WLL41:
        # Write Register F3
        movf     0(r7),f3
	br	.WLL57
.WLL42:
        # Write Register F4
        movf     0(r7),f4
	br	.WLL57
.WLL43:
        # Write Register F5
        movf     0(r7),f5
	br	.WLL57
.WLL44:
        # Write Register F6
        movf     0(r7),f6
	br	.WLL57
.WLL45:
        # Write Register F7
        movf     0(r7),f7
	br	.WLL57
.WLL46:
        # Write Register L0
        movd     0(r7),%REG_L0
        movd     4(r7),%REG_L0+4
	movl	 %REG_L0,l0
	br	.WLL57
.WLL47:
        # Write Register L1
        movd     0(r7),%REG_L1
        movd     4(r7),%REG_L1+4
	movl	 %REG_L1,l1
	br	.WLL57
.WLL48:
        # Write Register L2
        movd     0(r7),%REG_L2
        movd     4(r7),%REG_L2+4
	movl	 %REG_L2,l2
	br	.WLL57
.WLL49:
        # Write Register L3
        movd     0(r7),%REG_L3
        movd     4(r7),%REG_L3+4
	movl	 %REG_L3,l3
	br	.WLL57
.WLL50:
        # Write Register L4
        movd     0(r7),%REG_L4
        movd     4(r7),%REG_L4+4
	movl	 %REG_L4,l4
	br	.WLL57
.WLL51:
        # Write Register L5
        movd     0(r7),%REG_L5
        movd     4(r7),%REG_L5+4
	movl	 %REG_L5,l5
	br	.WLL57
.WLL52:
        # Write Register L6
        movd     0(r7),%REG_L6
        movd     4(r7),%REG_L6+4
	movl	 %REG_L6,l6
	br	.WLL57
.WLL53:
        # Write Register L7
        movd     0(r7),%REG_L7
        movd     4(r7),%REG_L7+4
	movl	 %REG_L7,l7
	br	.WLL57

.WLL7:
	movd	%regnumber,r6
	cmpd	$(REG_R0_NUM),r6
	bgt	.WLL54
	cmpd	$(REG_L7_NUM),r6
	blt	.WLL54
.WLP4:
	casew	.WLP3[r6:w]

.WLL57:
        # FPU register was modified reload fsr register
	lfsr	 %REG_FSR
 
.WLL54:
.WLL6:
	ret	 $(0)


	# writeregister branch table 
	.align 4
.WLP3:
	.word	.WLL8  - .WLP4
	.word	.WLL9  - .WLP4
	.word	.WLL10 - .WLP4
	.word	.WLL11 - .WLP4
	.word	.WLL12 - .WLP4
	.word	.WLL13 - .WLP4
	.word	.WLL14 - .WLP4
	.word	.WLL15 - .WLP4
	.word	.WLL16 - .WLP4
	.word	.WLL17 - .WLP4
	.word	.WLL18 - .WLP4
	.word	.WLL19 - .WLP4
	.word	.WLL20 - .WLP4
	.word	.WLL21 - .WLP4
	.word	.WLL22 - .WLP4
	.word	.WLL23 - .WLP4
	.word	.WLL24 - .WLP4
	.word	.WLL25 - .WLP4
	.word	.WLL26 - .WLP4
	.word	.WLL27 - .WLP4
	.word	.WLL28 - .WLP4
	.word	.WLL29 - .WLP4
	.word	.WLL30 - .WLP4
	.word	.WLL31 - .WLP4
	.word	.WLL32 - .WLP4
	.word	.WLL33 - .WLP4
	.word	.WLL34 - .WLP4
	.word	.WLL35 - .WLP4
	.word	.WLL36 - .WLP4
	.word	.WLL37 - .WLP4
	.word	.WLL38 - .WLP4
	.word	.WLL39 - .WLP4
	.word	.WLL40 - .WLP4
	.word	.WLL41 - .WLP4
	.word	.WLL42 - .WLP4
	.word	.WLL43 - .WLP4
	.word	.WLL44 - .WLP4
	.word	.WLL45 - .WLP4
	.word	.WLL46 - .WLP4
	.word	.WLL47 - .WLP4
	.word	.WLL48 - .WLP4
	.word	.WLL49 - .WLP4
	.word	.WLL50 - .WLP4
	.word	.WLL51 - .WLP4
	.word	.WLL52 - .WLP4
	.word	.WLL53 - .WLP4
#**********************************************************************#

#**********************************************************************#
# Alter the read and write target functions for correct integer size and
# function code.  The mov or movsu instruction is set up so that the
# target bus cycle will trigger the hardware for access to the target.
#
# PREPAREMOP
	.align 4
preparemop:
	addr 	 %superreadmop,r7
	addr 	 %userreadmop,r6
	addr 	 %superwritemop,r5
	addr 	 %userwritemop,r4

	cmpqd	 $(DOUBLEACCESS),%accessmode
	bne	 .PM1
        # superreadmop double = 977b0000
	movd     -4(r7),0(r7)
        # userreadmop double = ae9f7b00
	movd     -4(r6),0(r6)
        # superwritemop double = d7730000
	movd     -4(r5),0(r5)
        # userwritemop double = aecf7300
	movd     -4(r4),0(r4)
	br	 .PM3

.PM1:
	cmpqd	 $(WORDACCESS),%accessmode
	bne	 .PM2
        # superreadmop word   = 957b0000
	movd     -8(r7),0(r7)
        # userreadmop word   = ae9d7b00
	movd     -8(r6),0(r6)
        # superwritemop word   = d5730000
	movd     -8(r5),0(r5)
        # userwritemop word   = aecd7300
	movd     -8(r4),0(r4)
	br	 .PM3

.PM2:
        # superreadmop byte   = 947b0000
	movd     -12(r7),0(r7)
        # userreadmop byte   = ae9c7b00
	movd     -12(r6),0(r6)
        # superwritemop byte   = d4730000
	movd     -12(r5),0(r5)
        # userwritemop byte   = aecc7300
	movd     -12(r4),0(r4)

.PM3:
	ret	 $(0)
#**********************************************************************#

#**********************************************************************#
#
# READMOP    

	.align 4
readmop:

        # Jump to either superreadmop or userreadmop
	cmpqd 	 $(USER_FC),%functioncode
	beq      userreadmop
	br       superreadmop
	# return to readmop caller
#**********************************************************************#

#**********************************************************************#
#
# WRITEMOP    

	.align 4
writemop:

        # Jump to either superwritemop or userwritemop
	cmpqd 	 $(USER_FC),%functioncode
	beq      userwritemop
	br       superwritemop
	# return to writemop caller
#**********************************************************************#

#**********************************************************************#
#
# READLOOP 

	.align 4
readloop:
	# read target memory, write to monitor data_buf
	movd	 %start_addr,r7
	addr	 %data_buf,r6
	movqd	 $(0),r5
.LL26:
        # read count number of bytes using selected access mode
	bsr	 readmop
	addd	 r4,r7
	addd	 r4,r6
	addd	 r4,r5
	cmpd	 r5,%count
	blo	 .LL26
.LL25:
	ret	 $(0)
#**********************************************************************#

#**********************************************************************#
# Transfer count number of bytes from target memory to monitor data_buf
# Target memory is always accessed using the user specified mode
#
# READTARGET

	.align 4
readtarget:

        bsr preparemop

	cmpqd	 $(BYTEACCESS),%accessmode
	bne	 .LL22

	# BYTE Accessmode
	# Exactly count number of bytes will be read
	movqd    $(1),r4
	bsr	 readloop 
.LL22:
	cmpqd	 $(WORDACCESS),%accessmode
	bne	 .LL23

	# WORD Accessmode
	# In addition to count number of bytes, 1 additional byte may be read
	# Round count up to word alignment
	movd	 %count,r7
	modd     $(2),r7
	addd     r7,%count
	movqd    $(2),r4
	bsr	 readloop 
.LL23:
	cmpqd	 $(DOUBLEACCESS),%accessmode
	bne	 .LL24

	# DOUBLE Accessmode
	# In addition to count number of bytes, 
	# 1, 2, or 3 additional bytes may be read
	# Round count up to double word alignment
	movd	 %count,r7
	modd     $(4),r7
	subd     r7,%count
	addqd    $(4),%count
	movqd    $(4),r4
	bsr	 readloop 
.LL24:
	ret	 $(0)
#**********************************************************************#

#**********************************************************************#
#
# WRITELOOP

	.align 4
writeloop:
	# read from monitor data_buf, write to target memory
	addr	 %data_buf,r6
	movd	 %start_addr,r7
	movqd	 $(0),r5
.LL35:
        # write count number of bytes using specified access mode
	bsr	 writemop
	addd	 r4,r7
	addd	 r4,r6
	addd	 r4,r5
	cmpd	 r5,%count
	blo	 .LL35
.LL34:
	ret	 $(0)
#**********************************************************************#

#**********************************************************************#
#
# WRITETARGET

	.align 4
writetarget:
# Transfer count number of bytes from monitor data_buf to target memory
# Target memory is always accessed using the user specified mode

        bsr preparemop

	cmpqd	 $(BYTEACCESS),%accessmode
	bne	 .LL31

	# BYTE Accessmode
	# Exactly count number of bytes will be written
	movqd    $(1),r4
	bsr      writeloop

.LL31:
	cmpqd	 $(WORDACCESS),%accessmode
	bne	 .LL32

	# WORD Accessmode
	# If count is odd than last word will be read first to 
	# form correct last word to be written out.
	# Round count down to word alignment
	movd	 %count,r7
	modd     $(2),r7
	movw	 r7,%excesscount
	subd     r7,%count
	movqd    $(2),r4
	bsr      writeloop
	# If excesscount != 0, then have to special case last word
	cmpqw	 $(0),%excesscount
	beq	 .LL38
	movzwd	 0(r6),%lastitem
	# Read last word from target memory
	bsr	 readmop
	movqd	 $(-1),%mask

	# Calculate new word and place in the last word of the data_buf
	# mask <<= excesscount * 8
	lshd     $(3),%excesscount
	lshd	 %excesscount,%mask

	# last word = (last word & (u_int16) mask) |
        #	      ((u_int16) lastitem & (u_int16) ~mask)
	movw	 0(r6),r5
	andd	 %mask,r5
	bicw	 %mask,%lastitem
	orw	 %lastitem,r5
	movw	 r5,0(r6)

	# Write modified last word to target memory
	bsr	 writemop
.LL38:

.LL32:
	cmpqd	 $(DOUBLEACCESS),%accessmode
	bne	 .LL33

	# DOUBLE Accessmode
	# If count is not a multiple of 4 then last double word will be
	# read first to form correct last double word to be written out.
	# Round count down to double word alignment
	movd	 %count,r7
	modd     $(4),r7
	movw	 r7,%excesscount
	subd     r7,%count
	movqd    $(4),r4
	bsr      writeloop
	# If excesscount != 0, then have to special case last double word
	cmpqw	 $(0),%excesscount
	beq	 .LL41
	movd	 0(r6),%lastitem
	# Read last double word from target memory
	bsr	 readmop
	movqd	 $(-1),%mask

	# Calculate new double word and place in the
	# last double word of the data_buf
	# mask <<= excesscount
	lshd     $(3),%excesscount
	lshd	 %excesscount,%mask

	# last word = (last word & (u_int16) mask) |
        #	      ((u_int16) lastitem & (u_int16) ~mask)
	movd	 0(r6),r5
	andd	 %mask,r5
	bicd	 %mask,%lastitem
	ord	 %lastitem,r5
	movd	 r5,0(r6)

	# Write modified last double word to target memory
	bsr	 writemop
.LL41:

.LL33:
	ret	 $(0)
#**********************************************************************#
#**********************************************************************#
# Variables used internally and can be anywhere are in the text space
			.align 4
return_stack:           .double 0  # u_int32
jam_value:              .double 0  # u_int32
lastitem: 		.double 0  # u_int32
mask: 			.double 0  # u_int32
mask_1:	  		.double 0  # u_int32
mask_2:	  		.double 0  # u_int32
mask_3:  		.double 0  # u_int32
excesscount:		.word   0  # u_int16
singlestep:             .byte FALSE  # u_int8

# Variables which are communicated with externally are predefined addresses
# monitor data space is linked at 0xc00

		.data

#**********************************************************************#
# The bottom 128 bytes (0c00..0c7f) are used for a default dispatch table  
# The middle 128 bytes (0c80..0cff) are used for monitor stack space
# The upper 128 bytes (0d00..0d7f) are used for default stack space

# ADDRESS = 0xc00
INTBASE_TABLE:
		.space 256
TOP_OF_MONSTACK:
		.space 128
TOP_OF_STACK:
#**********************************************************************#

#**********************************************************************#
# This area contains all monitor variables.  All must remain at a known
# offset to be accessible by the controller.
# ADDRESS = 0xd80

CMD_BLOCK:
cmd_num: 	.double NO_CMD     # 0xd80  u_int32  
count:	 	.double 0   	   # 0xd84  u_int32
start_addr: 	.double h'fff      # 0xd88  u_int32 *
hw_config:      .double h'1f0      # 0xd8c  u_int32  CFG Register Default
accessmode:	.double BYTEACCESS # 0xd90  u_int32
functioncode:   .double SUPER_FC   # 0xd94  u_int32
regnumber: 	.double 0          # 0xd98  u_int32
loadaddress: 	.double procreset  # 0xd9c  u_int32
defaultregisters: .double 0        # 0xda0  u_int32
psrmask:        .double h'0800     # 0xda4  u_int32

		.space  3          # 0xda8
dummy1:         .byte   0          # 0xdab
iob_signals:    .byte   0          # 0xdac  u_int8
		.byte   0
		.byte   0
dummy2:		.byte   0          # 0xdaf

# ADDRESS = 0xdb0

STATUS_BLOCK:
semaphore:	.byte NO_CMD       # 0xdb0  u_int8 
are_you_there:  .byte RESPOND      # 0xdb1  u_int8
running:        .byte FALSE        # 0xdb2  u_int8

		.align 4
mon_entry:	.double h'80000000 # 0xdb4  u_int32
		.double 0          # space saver
		.double 0          # space saver

# ADDRESS = 0xdc0

		.align 4
DATA_BUF:
data_buf: 	.space 264         # 0xdc0  u_int8 [260]

# ADDRESS = 0xec8
		.align 4
REGISTERS:
REG_R0:		.double 0 
REG_R1: 	.double 0
REG_R2: 	.double 0
REG_R3: 	.double 0
REG_R4: 	.double 0
REG_R5: 	.double 0
REG_R6: 	.double 0
REG_R7: 	.double 0
REG_PC: 	.double 0
REG_SP: 	.double 0
REG_SP0: 	.double 0
REG_SP1: 	.double 0
REG_PSR: 	.word   0
REG_CFG: 	.double 0
REG_FP: 	.double 0
REG_SB: 	.double 0
REG_INTBASE: 	.double 0
REG_MOD: 	.word   0
REG_DCR: 	.double 0
REG_DSR: 	.double 0
REG_CAR:	.double 0
REG_BPC: 	.double 0
REG_PTB0: 	.double 0
REG_PTB1: 	.double 0
REG_IVAR0: 	.double 0
REG_IVAR1: 	.double 0
REG_TEAR:	.double 0
REG_MCR: 	.double 0
REG_MSR: 	.double 0
REG_FSR: 	.double 0
REG_L0: 	.long l'0000000000000000
REG_L1: 	.long l'0000000000000000
REG_L2: 	.long l'0000000000000000
REG_L3: 	.long l'0000000000000000
REG_L4: 	.long l'0000000000000000
REG_L5: 	.long l'0000000000000000
REG_L6: 	.long l'0000000000000000
REG_L7: 	.long l'0000000000000000
		.double 0          # space saver

JAMIN_STACK:
# This 128 byte area is used as the stack for saving PC, PSR, and MOD
# during exception processing of break induced NMI
# During the jam into the monitor this area will be the interrupt
# stack used for saving the PC, PSR, and MOD depending on the
# exception mode.  This area will also be used during exit from
# the monitor, again as the interrupt stack area.  The return PC,
# PSR, and optionally the MOD will be read from this area.

# ADDRESS = 0xf80
		.byte [64] h'10


JAMOUT_STACK:
# This 128 byte area is used as the dispatch vector table
# during exception processing of break induced NMI
# During the jam into the monitor this area will be read to 
# determine the address of the monitor breakentry entry point.
# During this time only the least significant 7 bits of the  
# address bus are used.

# ADDRESS = 0xfc0
		.byte [60] 0
		.double h'00000187

