"8051"

*	MKT:@(#) 64788-11001 A.00.01 8051 FAMILY EMUL FOREGROUND MONITOR      09Aug89                            
*
*	8051 Monitor Program 
*
* This version of the monitor is assembled with the HP 8051 ASSEMBLER
*
* Users can link this code anywhere they like.  The space must be mapped as
* don't care function code and must be in emulation memory
* The foreground monitor is used via the cf fgmon configuration item.
* The foreground monitor must be loaded by the user.

               ORG 2000H

* Users should not modify the section below here
               NOWARN
WDK            EQU    0AAH
WDS            EQU    0A9H
DPS            EQU    086H
DPL1           EQU    084H
DPH1           EQU    085H

;Equates used by the monitor loops
MAIN_LOOP      EQU    55H
WAIT_CMB_LOOP  EQU    0AAH

* Defines for the jump table
EXIT_MON       EQU    02H
MON_NOP        EQU    04H
WRITE_PC       EQU    06H
ADJUST_PC      EQU    08H
INDIR_MEM_RD   EQU    0AH
INDIR_MEM_WR   EQU    0CH
WR_PSW         EQU    0EH
RD_MEM_DIR     EQU    10H
WR_MEM_DIR     EQU    12H
RD_TAR_PG      EQU    14H
WR_TAR_DATA    EQU    16H
RD_TAR_DATA    EQU    18H
WR_REG         EQU    1AH
RD_REG         EQU    1CH
WRITE_TIME     EQU    1EH
SET_BIT        EQU    20H
CLR_BIT        EQU    22H
WR_P3          EQU    24H




OP_ADDRESS     DW 0
OP_COUNT       DB 0
BUFFER         DS 256

MON_STATUS     DB 0 
MON_COMMAND    DB 0

SAVE_A         DB 0
SAVE_BREG      DB 0
SAVE_DPS       DB 0
SAVE_DP0       DW 0  ;DPL0 followed by DPH0
SAVE_DP1       DW 0  ;DPL1 followed by DPH1
SAVE_PSW       DB 0
SAVE_PC        DW 0
SAVE_REG_TEMP  DB 0
HOST_WATCHDOG  DB 0
SAVE_WATCHDOG  DB 0

REG_BUFFER     DS 8



BACKGROUND_ENTRY
               JB F0,REENABLE        ;Check interrupts
               SJMP MON_ENTRY+2      ;No interrupts, don't stack PSW

REENABLE       SETB EA               ;Reenable interrupts
               SJMP MON_ENTRY+2      ;don't stack PSW

* Above here don't modify the monitor

MON_ENTRY      PUSH PSW              ;Save PSW on stack
               PUSH DPH              ;Save DPH0 on stack
               PUSH DPL              ;Save DPL0 on stack
               PUSH DPH1             ;Save DPH1 on stack
               PUSH DPL1             ;Save DPL1 on stack
               MOV DPTR,#SAVE_A  
               MOVX @DPTR,A          ;Save A in special place
               INC DPTR
               MOV A,B
               MOVX @DPTR,A          ;Save B register in special place
               INC DPTR
               MOV A,DPS             
               MOVX @DPTR,A          ;Save Data Pointer Selection reg 
               MOV DPTR,#SAVE_DP1    ;Address of DP1 save space
               POP ACC               ;Get DPL1 off stack
               MOVX @DPTR,A          ;Save DPL1
               INC DPTR              ;Address of DPH1
               POP ACC               ;Get DPH1 off stack
               MOVX @DPTR,A          ;Save DPH1
               MOV DPTR,#SAVE_DP0    ;Address of DP0 save space
               POP ACC               ;Get DPL0 off stack
               MOVX @DPTR,A          ;Save DPL0
               INC DPTR              ;Address of DPH0
               POP ACC               ;Get DPH0 off stack
               MOVX @DPTR,A          ;Save DPH0
               MOV DPTR,#SAVE_PSW    ;Address of PSW save space
               POP ACC               ;Get PSW off stack
               INC SP                ;Put SP back
               MOVX @DPTR,A          ;Save PSW
               MOV DPTR,#SAVE_PC     ;Address of PC save space
               MOV A,#0
               MOVX @DPTR,A          
               INC DPTR  
               MOVX @DPTR,A          

               MOV A,WDS             ;Read WDS register
               INC A                 ;Increment for new value
               ANL A,#0FH            ;Lower 4 bits are value
               MOV B,A               ;Save a copy of the new value
               MOV WDS,A             ;Writing to WDS, if can change not running
               MOV A,WDS             ;Read new value
               CJNE A,B,RST_WD       ;Not running!

NO_RST_WD      MOV DPTR,#SAVE_WATCHDOG
               MOV A,#0              ;Zero is the no rst value
               MOVX @DPTR,A          ;Write the value
               DEC WDS
               SJMP CLR_MON_CMD

RST_WD         MOV DPTR,#HOST_WATCHDOG ;Host address for flag
               MOVX A,@DPTR          ;Read host flag
               JZ NO_RST_WD          ;Host has it turned off
               INC DPTR              ;Point at SAVE_WATCHDOG
               MOV A,#0A5H           ;Running value
               MOVX @DPTR,A          ;Write reset value
               ACALL WATCHDOG        ;Take care of WD timer


CLR_MON_CMD    CLR A                 ;Clear the last monitor command
               MOV DPTR,#MON_COMMAND
               MOVX @DPTR,A



MAIN_MON_LOOP  MOV A,#MAIN_LOOP      ;Put main mon loop value in A
               MOV DPTR,#MON_STATUS  ;Load address of mon status in DPTR
               MOVX @DPTR,A          ;Write Main mon loop status for host
               ACALL WATCHDOG        ;Take care of WD timer
               MOV DPTR,#MON_COMMAND ;Put address on MON_COMMAND in DPTR
               MOVX A,@DPTR          ;Put the current monitor command in A
               JZ MAIN_MON_LOOP      ;0 is no command do main mon loop again


               MOV DPTR,#JMP_TABLE
               JMP @A+DPTR
JMP_TABLE      AJMP CLR_MON_CMD
               AJMP RET_TO_USER
               AJMP CLR_MON_CMD
               AJMP WRITE_PROG_COUNTER
               AJMP ADJUST_PROG_COUNTER
               AJMP READ_INDIR_MEM
               AJMP WR_INDIR_MEM
               AJMP WR_STACK_PSW
               AJMP RD_MEM_DIRECT
               AJMP WR_MEM_DIRECT
               AJMP RD_TAR_PROGRAM
               AJMP WR_TARGET_DATA
               AJMP RD_TARGET_DATA
               AJMP WR_REG_VALUE
               AJMP STORE_REG
               AJMP WRITE_TIMER
               AJMP DO_SET_BIT
               AJMP DO_CLR_BIT
               AJMP WRITE_P3


RET_TO_USER    
					MOV DPS,#0
               MOV DPTR,#SAVE_BREG   ;Address of B
               MOVX A,@DPTR          ;Fetch B data
               MOV B,A               ;Restore the users B value
               MOV DPTR,#SAVE_DP1    ;Load DPTR1 store address
               MOVX A,@DPTR          ;Fetch DPL1
               MOV DPL1,A            ;Put value in DPL1
               INC DPTR              ;Get at DPH1 with DPTR0
               MOVX A,@DPTR          ;Fetch DPH1
               MOV DPH1,A            ;Put value in DPH1A
               MOV DPTR,#SAVE_A      ;Address of A
               MOVX A,@DPTR          ;Fetch users A value
               PUSH ACC              ;Put on the stack
               MOV DPTR,#SAVE_DPS    ;Point at DPS
               MOVX A,@DPTR          ;Fetch users DPS value
               PUSH ACC              ;Put on the stack
               MOV DPTR,#SAVE_DP0    ;Address of DPL0
               MOVX A,@DPTR          ;Fetch users DPL0 value
               PUSH ACC              ;Put on the stack
               INC DPTR              ;Point at DPH0
               MOVX A,@DPTR          ;Fetch users DPH0 value
               PUSH ACC              ;Put on the stack
               POP DPH               ;Now put the stuff -
               POP DPL               ;in -
               POP DPS               ;the -
               POP ACC               ;correct spot.

               POP PSW               ;Restore the stacked PSW
               RET                   ;Return to the user

               

WR_TARGET_DATA
               MOV DPS,#01           ;Select DPTR1
               MOV DPTR,#OP_ADDRESS  ;Get base address of buffer in DPTR1.
               MOVX A,@DPTR          ;Get upper byte of address
               MOV DPH,A             ;Move upper byte to DPH
               INC DPTR              ;Point at DPL
               MOVX A,@DPTR          ;Get lower byte of address
               INC DPTR              
               MOV DPL,A
               MOVX A,@DPTR          ;Get count for transfer
               MOV B,A               ;Move count byte to B
               MOV DPTR,#BUFFER      ;Where to get write data

WR_TAR_LOOP_DATA
               MOV DPS,#01           ;Select DPTR0, target address
               MOVX A,@DPTR          ;Get the data to write
               INC DPTR
               MOV DPS,#00           ;Select DPTR1
               MOVX @DPTR,A          ;write target data
               INC DPTR
               DJNZ B,WR_TAR_LOOP_DATA
               AJMP CLR_MON_CMD      ;Notify host we are finished


RD_TARGET_DATA
               MOV DPS,#01           ;Select DPTR1
               MOV DPTR,#OP_ADDRESS  ;Get base address of buffer in DPTR1.
               MOVX A,@DPTR          ;Get upper byte of address
               MOV DPH,A             ;Move upper byte to DPH
               INC DPTR              
               MOVX A,@DPTR          ;Get lower byte of address
               INC DPTR              
               MOV DPL,A
               MOVX A,@DPTR          ;Get count for transfer
               MOV B,A               ;Move count byte to B
               MOV DPTR,#BUFFER      ;Where to write read data

RD_TAR_LOOP_DATA
               MOV DPS,#00           ;Select DPTR0, target address
               MOVX A,@DPTR          ;read target data 
               INC DPTR
               MOV DPS,#01           ;Select DPTR1
               MOVX @DPTR,A          ;Write the program data to the buffer
               INC DPTR
               DJNZ B,RD_TAR_LOOP_DATA
               AJMP CLR_MON_CMD      ;Notify host we are finished



RD_TAR_PROGRAM
               MOV DPS,#01           ;Select DPTR1
               MOV DPTR,#OP_ADDRESS  ;Get base address of buffer in DPTR1.
               MOVX A,@DPTR          ;Get upper byte of address
               MOV DPH,A             ;Move upper byte to DPH
               INC DPTR              
               MOVX A,@DPTR          ;Get lower byte of address
               INC DPTR              
               MOV DPL,A
               MOVX A,@DPTR          ;Get count for transfer
               MOV B,A               ;Move count byte to B
               MOV DPTR,#BUFFER      ;Where to write read data

RD_TAR_LOOP_PROG
               MOV DPS,#00           ;Select DPTR0, target address
               CLR A
               MOVC A,@A+DPTR        ;Read target
               INC DPTR              
               MOV DPS,#01           ;Select DPTR1
               MOVX @DPTR,A          ;Write the program data to the buffer
               INC DPTR
               DJNZ B,RD_TAR_LOOP_PROG
               AJMP CLR_MON_CMD      ;Notify host we are finished


WR_MEM_DIRECT
               MOV DPS,#01
               MOV DPTR,#BUFFER      ;Get base address of buffer in DPTR1.
               MOV DPS,#00
               MOV DPTR,#OP_ADDRESS+2 ;Get count
               MOVX A,@DPTR
               MOV B,A               ;B contains count

WR_DIR_LOOP    MOV DPS,#00
               MOV DPTR,#OP_ADDRESS  ;Put operation address in DPTR0
               MOVX A,@DPTR          ;Get the operation address
               INC A                 ;Increment for next address
               MOVX @DPTR,A          ;Store next addr to read
               DEC A                 ;Get back to initial read address
               MOV DPTR,#WR_MOV_DIR+1 ;Where to change opcode
               MOVX @DPTR,A          ;Change direct address
               MOV DPS,#01           ;Select other DPTR1
               MOVX A,@DPTR          ;Fetch the write data
               INC DPTR              ;Increment for next addr

WR_MOV_DIR     MOV 00H,A             ;Do the write
               DJNZ B,WR_DIR_LOOP
               AJMP CLR_MON_CMD      ;Notify host we are finished



RD_MEM_DIRECT
               MOV DPS,#01
               MOV DPTR,#BUFFER      ;Get base address of buffer in DPTR1.
               MOV DPS,#00
               MOV DPTR,#OP_ADDRESS+2 ;Get count
               MOVX A,@DPTR
               MOV B,A               ;B contains count

RD_DIR_LOOP    MOV DPS,#00
               MOV DPTR,#OP_ADDRESS  ;Put operation address in DPTR0
               MOVX A,@DPTR          ;Get the operation address
               INC A                 ;Increment for next address
               MOVX @DPTR,A          ;Store next addr to read
               DEC A                 ;Get back to initial read address
               MOV DPTR,#RD_MOV_DIR+1 ;Where to change opcode
               MOVX @DPTR,A          ;Change direct address

RD_MOV_DIR     MOV A,00H             ;Do the read
               MOV DPS,#01           ;Select other DPTR1
               MOVX @DPTR,A          ;Save read data
               INC DPTR              ;Increment for next addr
               DJNZ B,RD_DIR_LOOP
               AJMP CLR_MON_CMD      ;Notify host we are finished

STORE_REG      
               PUSH PSW              ;Store monitor PSW
               DEC SP                ;Get at user PSW
               POP PSW               ;Restore user PSW
               INC SP                ;Put SP back to correct spot
               INC SP                ;Put SP back to correct spot
               MOV DPTR,#REG_BUFFER  ;
               MOV A,R0
               MOVX @DPTR,A
               INC DPTR
               MOV A,R1
               MOVX @DPTR,A
               INC DPTR
               MOV A,R2
               MOVX @DPTR,A
               INC DPTR
               MOV A,R3
               MOVX @DPTR,A
               INC DPTR
               MOV A,R4
               MOVX @DPTR,A
               INC DPTR
               MOV A,R5
               MOVX @DPTR,A
               INC DPTR
               MOV A,R6
               MOVX @DPTR,A
               INC DPTR
               MOV A,R7
               MOVX @DPTR,A
               POP PSW               ;Restore monitor PSW
               AJMP CLR_MON_CMD      ;Notify host we are finished

WR_STACK_PSW
               MOV DPTR,#SAVE_PSW    ;Load buffer address
               MOVX A,@DPTR          ;Load new PSW into A
               DEC SP                ;Decrement past old PSW
               PUSH ACC              ;Push new PSW
               AJMP CLR_MON_CMD      ;Notify host we are finished

WR_INDIR_MEM                         ;Internal memory 80 - 0ff
               MOV DPTR,#SAVE_REG_TEMP
               MOV A,R0              ;Save the most recent copy of R0 -
               MOVX @DPTR,A          ;since we are going to use it now.

               MOV DPTR,#OP_ADDRESS  ;Put operation address in DPTR
               MOVX A,@DPTR          ;Get the operation address
               MOV R0,A
               INC DPTR              ;Prepare to get OP_COUNT
               INC DPTR              ;Prepare to get OP_COUNT
               MOVX A,@DPTR
               MOV B,A               ;Move count to B register
               INC DPTR              ;Point DPTR to BUFFER
INDIR_LOOP_WR
               MOVX A,@DPTR          ;Read the new data
               INC DPTR              ;Point to next location in buffer
               MOV @R0,A             ;Write the indirect location
               INC R0                ;Point to next location
               DJNZ B,INDIR_LOOP_WR
               MOV DPTR,#SAVE_REG_TEMP  ;Yes finished, restore R0
               MOVX A,@DPTR          ;Fetch from temp spot
               MOV R0,A              ;Copy into R0
               AJMP CLR_MON_CMD      ;Notify host we are finished


READ_INDIR_MEM                       ;Internal memory 80 - 0ff
               MOV DPTR,#SAVE_REG_TEMP
               MOV A,R0              ;Save the most recent copy of R0 -
               MOVX @DPTR,A          ;since we are going to use it now.

               MOV DPTR,#OP_ADDRESS  ;Put operation address in DPTR
               MOVX A,@DPTR          ;Get the operation address
               MOV R0,A
               INC DPTR              ;Prepare to get OP_COUNT
               INC DPTR              ;Prepare to get OP_COUNT
               MOVX A,@DPTR
               MOV B,A               ;Move count to B register
               INC DPTR              ;Point DPTR to BUFFER
INDIR_LOOP_RD
               MOV A,@R0             ;Read the indirect location
               INC R0                ;Point to next location
               MOVX @DPTR,A          ;Write data to buffer
               INC DPTR              ;Point to next location in buffer
               DJNZ B,INDIR_LOOP_RD
               MOV DPTR,#SAVE_REG_TEMP  ;Yes finished, restore R0
               MOVX A,@DPTR          ;Fetch from temp spot
               MOV R0,A              ;Copy into R0
               AJMP CLR_MON_CMD      ;Notify host we are finished





ADJUST_PROG_COUNTER
               DEC SP                ;Decrement stack past the PSW
               POP B                 ;Fetch the PCH
               POP ACC               ;Fetch the PCL
               CLR C                 ;Clear the carry for the SUB below
               JB F0,SEVEN           ;If interrupts were enabled we 
                                     ;need to subtract
                                     ;seven from the address on the stack.
               SUBB A,#6             ;No interrupts were enabled just subtract
                                     ;six from the address on the stack. The six
                                     ;or seven is because the Jammed JBC 
                                     ;instruction
                                     ;may or may not have jumped!
               SJMP TEST_CARRY       ;check the barrow
SEVEN          SUBB A,#7             ;Subtract 7 here
TEST_CARRY     JNC NO_CARRY          ;Need to subtract 1 from the upper byte?
               DEC B                 ;Yes, dec the upper byte
NO_CARRY       PUSH ACC              ;Put back on the stack
               PUSH B
               INC SP                ;Put the SP back to PSW
               MOV DPS,#0            ;Clear the DPS
               MOV DPTR,#SAVE_PC+1   ;Address of PC save spot
               MOVX @DPTR,A          ;Write the PC
               MOV DPTR,#SAVE_PC     ;save spot 
               MOV A,B               ;Now write
               MOVX @DPTR,A          ;the other part of PC
               AJMP CLR_MON_CMD      ;Notify host we are finished

WRITE_PROG_COUNTER
               DEC SP                ;Get past the PSW
               DEC SP                ;Get past the PCH
               MOV DPS,#00           ;Clear the DPS
               MOV DPTR,#SAVE_PC     ;Load the address of saved PC
               MOVX A,@DPTR          ;Get the PC Low
               PUSH ACC              ;Write the PCL
               DEC SP                ;Get past the PCH
               DEC SP                ;Get past the PCL
               INC DPTR              ;Now point to PC high
               MOVX A,@DPTR          ;Get the PC low
               PUSH ACC              ;Write PC low
               INC SP                ;Point SP at PCH
               INC SP                ;Point SP at PSW
               AJMP CLR_MON_CMD      ;Notify host we are finished


               
WR_REG_VALUE
               PUSH PSW              ;Store monitor PSW
               DEC SP                ;Get at user PSW
               POP PSW               ;Restore user PSW
               INC SP                ;Put SP back to correct spot
               INC SP                ;Put SP back to correct spot
               MOV DPTR,#OP_ADDRESS  ;Get register number to modify
               MOVX A,@DPTR          
               ADD A,#0F8H           ;Value F8 is MOV R0,A instruction
               MOV DPTR,#MOV_RN      ;Location of opcode
               MOVX @DPTR,A          ;Alter instruction
               MOV DPTR,#BUFFER      ;Now get the data -
               MOVX A,@DPTR          ;from the buffer
MOV_RN         MOV R0,A              ;Alter register
               POP PSW               ;Restore monitor PSW
               AJMP CLR_MON_CMD      ;Notify host we are finished

WRITE_TIMER    MOV DPTR,#OP_ADDRESS  ;Load address of which timer
               MOVX A,@DPTR          ;Get which timer to write
               MOV DPTR,#BUFFER      ;Load location of timer data
               JZ WRITE_TIMER_0      ;Mess with timer 0
               MOVX A,@DPTR          ;Low byte of timer data
               INC DPTR              ;Increment for high byte
               MOV TL1,A             ;Load timer value
               MOVX A,@DPTR          ;Get high byte
               MOV TH1,A             ;Load high byte of timer 1
               AJMP CLR_MON_CMD      ;Notify host we are finished

WRITE_TIMER_0  
               MOVX A,@DPTR          ;Low byte of timer data
               INC DPTR              ;Increment for high byte
               MOV TL0,A             ;Load timer value
               MOVX A,@DPTR          ;Get high byte
               MOV TH0,A             ;Load high byte of timer 1
               AJMP CLR_MON_CMD      ;Notify host we are finished

DO_SET_BIT     MOV DPTR,#OP_ADDRESS
               MOVX A,@DPTR          ;Load the bit address
               MOV DPTR,#SET_A_BIT+1 ;Where to put address
               MOVX @DPTR,A

SET_A_BIT      SETB 0                ;Set the address
               AJMP CLR_MON_CMD      ;Notify host we are finished

DO_CLR_BIT     MOV DPTR,#OP_ADDRESS
               MOVX A,@DPTR          ;Load the bit address
               MOV DPTR,#CLR_A_BIT+1 ;Where to put address
               MOVX @DPTR,A

CLR_A_BIT      CLR 0                 ;Set the address
               AJMP CLR_MON_CMD      ;Notify host we are finished

WRITE_P3       
               MOV DPTR,#BUFFER      ;Prepare to read new P3 data
               MOVX A,@DPTR          ;Fetch new P3 value
               ORL A,#0C0H           ;Read and Write stay high
               MOV P3,A              ;Write data to port.
               AJMP CLR_MON_CMD      ;Notify host we are finished


WATCHDOG       MOV DPTR,#SAVE_WATCHDOG
               MOVX A,@DPTR       ;Read WD value
               JZ WD_RET
               MOV WDK,A
               SWAP A
               MOV WDK,A
WD_RET         RET


END
