📄 monplus.asm
字号:
; A low-level monitor for the 8051 family for the A51 assembler
; Copyright 1989 by Steve Kemplin
; This program is provided for personal, private use only.
; Commercial use in whole or in part without express written permission of
; the author is prohibited.
; No warranty is made as to the suitability of the program for any
; particular use.
;
; Based on a monitor written and copyrighted by Ron Stubbers
; [Ver 900626]
.ORG 0x40FC ;SET UP LABEL ADDRESS FOR PATCH
.EQU PATCH,* ;MUST BE RAM, BOTH PROG & DATA SPACE
.EQU CR,0x0D ;CHARACTER EQUATES
.EQU LF,0x0A
.EQU ESC,0x1B
.EQU VECTAB,0x2000 ;ADDRESS OF BASIC VECTORS
.EQU RSTVEC,VECTAB ;JUMPS HERE AT POWER UP
.EQU SERINVEC,VECTAB+3 ;JUMPS HERE TO READ A CHARACTER
.EQU SEROUTVEC,VECTAB+6 ;JUMPS HERE TO SEND A CHARACTER
.EQU INT1VEC,VECTAB+0x10 ;JUMPS HERE ON INT1
.EQU SERVEC,VECTAB+0x18 ;JUMPS HERE ON SERIAL INTERRUPT
.EQU TMR0VEC,VECTAB+0x20 ;JUMPS HERE ON TIMER 0 INTERRUPT
.EQU TMR1VEC,VECTAB+0x28 ;JUMPS HERE ON TIMER 1 INTERRUPT
.EQU TMR2VEC,VECTAB+0x30 ;JUMPS HERE ON TIMER 2 INTERRUPT
.EQU BUFFER,0x50 ;BUFFER AREA FOR PROM LOAD
.EQU CNTLO,0x70 ;LOW BYTE OF COUNT
.EQU CNTHI,CNTLO+1 ;HIGH BYTE OF COUNT
.EQU ADHI,CNTLO+2 ;HIGH ADDRESS
.EQU ADLO,CNTLO+3 ;LOW ADDRESS
.EQU DATA,CNTLO+4 ;TEMPORARY BYTE STORAGE LOCATION
.EQU CKSUM,CNTLO+5 ;CHECKSUM FOR PROM LOAD
.EQU TEMP1,CNTLO+6 ;TEMPORARY STORAGE LOCATIONS
.EQU TEMP2,CNTLO+7
.EQU TEMP3,CNTLO+8
.EQU ASAVE,0x7A ;REGISTER IMAGES
.EQU BSAVE,ASAVE+1
.EQU PSWSAVE,ASAVE+2
.EQU DPHSAVE,ASAVE+3
.EQU DPLSAVE,ASAVE+4
.EQU BRKPT1,0x50 ;OVERLAYS LOAD BUFFER AREA
.EQU BRKPT2,BRKPT1+5
.EQU BRKPT3,BRKPT1+10
.EQU BRKPT4,BRKPT1+15
.EQU BKFLAG,0x7F
.EQU BK1MASK,0x01
.EQU BK2MASK,0x02
.EQU BK3MASK,0x04
.EQU BK4MASK,0x08
.EQU ALLMASK,BK1MASK|BK2MASK|BK3MASK|BK4MASK
.EQU BPHLR_HI,((BPHLR>>8)&0xFF)
.EQU BPHLR_LO,(BPHLR&0xFF)
.eject
.ORG 0
LJMP INIT ;GO TO INIT AT POWER UP
.ORG 0x03
.EQU INT0,* ;VECTOR FOR EXTERNAL INTERRUPT 0
LJMP MONENT
.ORG 0x0B
.EQU TMR0,* ;VECTOR FOR TIMER 0
LJMP TMR0VEC
.ORG 0x13
.EQU INT1,* ;VECTOR FOR EXTERNAL INTERRUPT 1
LJMP INT1VEC
.ORG 0x1B
.EQU TMR1,* ;VECTOR FOR TIMER 1
LJMP TMR1VEC
.ORG 0x23
.EQU SERINT,* ;VECTOR FOR SERIAL I/O INTERRUPT
LJMP SERVEC
.ORG 0x2B
.EQU TMR2,* ;VECTOR FOR TIMER 2
.EQU INT2,* ;ALSO FOR EXTERNAL INTERRUPT 2
LJMP TMR2VEC
.eject
;START OF MONITOR PROGRAM
;
.ORG 0x30 ;START OF MONITOR CODE
ENTLST: LJMP INIT ;Entry point to the monitor
;
LJMP DELAY ;Pause for 1 msec times value in ACC
;
LJMP SERIN ;Serial Input Primitive
;
LJMP GETC ;Read char from serial port,
;Echo char back to serial port
;
LJMP PUTC ;Send char in ACC to serial port
;
LJMP PUTS ;Sends text string to serial port,
;DPTR points to start, null ends
;
LJMP CRLF ;Sends CR,LF to serial port
;
LJMP ASC2HEX ;Converts ASCII char in ACC to HEX equivalent,
;Returns value in lower nibble, upper nibble zeroes
;
LJMP HEX2ASC ;Convert lower nibble in ACC to ASCII char,
;returned in ACC
;
LJMP RDHEX ;Reads 2 char from serial port,
;converts to byte returned in ACC
;
LJMP WRBYTE ;Writes byte in ACC to serial port,
;as 2 ASCII char
;
.eject
.ORG 0x0080
INIT: MOV SP,#0x30 ;SET THE STACK POINTER SOMEWHERE SAFE
MOV SCON,#0x52
MOV TMOD,#0x20
MOV PCON,#0X80 ;SET FOR DOUBLE BAUD RATE
MOV A, #0xCC ;1200 BAUD, #0xF3=>1200 BAUD (12 MHz)
MOV TH1,A
SETB TR1 ;START TIMER FOR SERIAL PORT
SETB P3.2 ;THIS TURNS OFF INT0
MOV A,#10 ;SHORT DELAY TO MAKE SURE IT GOT DONE
DJNZ ACC,*
ORL IE,#0x81 ;ENABLE INT0
ORL IP,#0x01 ;AND MAKE IT HIGH PRIORITY
MOV BKFLAG,#0 ;CLEAR ALL BREAKPOINTS
JB P1.6,GETCMD ;IF PIN P1.6 NOT GROUNDED,CONTINUE
LJMP RSTVEC ;ELSE JUMP TO USER PROGRAM
SAVEREG: MOV PSWSAVE,PSW ;SAVE EVERYTHING
MOV ASAVE,ACC
MOV BSAVE,B
MOV DPHSAVE,DPH
MOV DPLSAVE,DPL
ACALL RSTALL ;FIX UP THE CODE FROM BREAKPOINTS
RET
CALLRET: ACALL SAVEREG ;SAVE THE REGISTERS,FIXUP THE CODE
SJMP GETCMD ;AND GO GET A COMMAND
RESTORE: MOV PSW,PSWSAVE ;RESTORE EVERYTHING EXCEPT PC
MOV ACC,ASAVE
MOV B,BSAVE
MOV DPH,DPHSAVE
MOV DPL,DPLSAVE
RET
MONENT: CLR EX0 ;DISABLE THE INTERRUPT
ACALL SAVEREG ;SAVE THE REGISTERS,FIXUP THE CODE
POP ADHI ;GET THE PROGRAM COUNTER
POP ADLO
PUSH ADLO
PUSH ADHI
MOV A,ADHI ;DISPLAY THE ADDRESS
ACALL WRBYTE
MOV A,ADLO
ACALL WRBYTE ;FALL THROUGH INTO GETCMD
.eject
GETCMD: ACALL CRLF ;START OFF ON A NEW LINE
MOV A,#'#' ;PROMPT FOR A COMMAND
ACALL PUTC
ACALL GETC ;GET THE COMMAND
I_TEST: CJNE A,#'I',M_TEST ;IF NOT I, THEN CHECK M
ACALL INTRAM ;I, SO RUN INTERNAL
M_TEST: CJNE A,#'M',L_TEST ;IF NOT M, THEN CHECK L
ACALL MEMORY ;M, SO RUN MEMORY MODIFY
L_TEST: CJNE A,#'L',G_TEST ;IF NOT L, THEN CHECK G
ACALL LOAD ;L, SO LOAD HEX FILE
G_TEST: CJNE A,#'G',S_TEST ;IF NOT G, THEN CHECK S
AJMP GO ;G, SO GO TO ADDRESS
S_TEST: CJNE A,#'S',C_TEST ;IF NOT S, THEN CHECK C
AJMP STEP ;S, SO SINGLE STEP
C_TEST: CJNE A,#'C',D_TEST ;IF NOT C, THEN CHECK D
AJMP UCALL ;C, SO CALL
D_TEST: CJNE A,#'D',P_TEST ;IF NOT D, THEN CHECK P
ACALL DUMP ;D, SO DUMP RAM
P_TEST: CJNE A,#'P',F_TEST ;IF NOT P, THEN CHECK F
ACALL PRMLD
F_TEST: CJNE A,#'F',V_TEST ;IF NOT F, THEN CHECK V
ACALL FILL ;F, SO FILL RAM
V_TEST: CJNE A,#'V',B_TEST ;IF NOT V THEN NO MATCH SO TRY AGAIN
ACALL MOVE
B_TEST: CJNE A,#'B',R_TEST ;IF NOT B THEN CHECK R
ACALL BPDISP ;CALL BREAKPOINT DISPATCHER
R_TEST: CJNE A,#'R',NOMATCH ;IF NOT R THEN NO MATCH SO TRY AGAIN
ACALL REGSTR ;CALL REGISTER HANDLING ROUTINE
NOMATCH: MOV A,#0xFF ;WAIT A WHILE
ACALL DELAY
SJMP GETCMD ;NOT FOUND, SO BACK TO GETCMD
.eject
INTRAM: PUSH DPH ;SAVE DPTR
PUSH DPL
ACALL SPACE ;OUTPUT A SPACE
ACALL RDHEX ;GET ADDRESS OF DIRECT BYTE TO READ
RAMENT: PUSH ACC ;SAVE IT
MOV DPTR,#PATCH ;MOV INSTRUCTION WILL BE ASSEMBLED AT PATCH
MOV A,#0xE5 ;0xE5 IS A MOV A,DIRECT
MOVX @DPTR,A ;PUT THE INSTRUCTION AT PATCH
POP ACC ;RETRIEVE THE ADDRESS OF THE DIRECT BYTE
INC DPTR ;STORE IT TO THE NEXT LOCATION
MOVX @DPTR,A
MOV A,#0x22 ;0x22 IS RETURN INSTRUCTION
INC DPTR ;PUT RET INSTRUCTION IN PATCH
MOVX @DPTR,A
LCALL PATCH ;EXECUTE PATCH
ACALL SPACE ;OUTPUT A SPACE
ACALL WRBYTE ;SHOW BYTE RETRIEVED BY PATCH
ACALL SPACE ;OUTPUT A SPACE
INTRAM1: ACALL GETC ;GET THE NEXT CHARACTER
CJNE A,#' ',INTRAM2 ;ITS NOT A SPACE, SO KEEP CHECKING
SJMP INTRAM1 ;A SPACE DOESN'T MEAN ANYTHING, SO LOOP
INTRAM2: CJNE A,#CR,NEWINT ;ITS NOT A RETURN EITHER
SJMP INTRAMX ;ITS A RETURN SO WE'RE DONE
NEWINT: ACALL RDHX1 ;PRESUME ITS A NEW VALUE
PUSH ACC ;SAVE THE NEW VALUE
MOV DPTR,#PATCH ;MOV INSTRUCTION WILL BE ASSEMBLED AT PATCH
MOV A,#0xF5 ;0xF5 IS A MOV DIRECT,A
MOVX @DPTR,A ;PUT THE INSTRUCTION AT PATCH
POP ACC ;RECOVER THE NEW VALUE
LCALL PATCH ;DATA IN A, INSTRs AT PATCH, SO EXECUTE
INTRAMX: ACALL CRLF ;WE'RE DONE
POP DPL ;RESTORE DPTR
POP DPH
RET ;BACK FOR NEXT COMMAND
.eject
MEMORY: PUSH ACC ;SAVE THE ACCUMULATOR
PUSH DPH ;AND DPTR
PUSH DPL
ACALL RDHEX ;GET THE UPPER ADDRESS BYTE
MOV DPH,A
ACALL RDHEX ;GET THE LOWER ADDRESS BYTE
MOV DPL,A
MEM1: ACALL CRLF ;GO TO A NEW LINE
MOV A,DPH ;SHOW THE ADDRESS
ACALL WRBYTE
MOV A,DPL
ACALL WRBYTE
ACALL SPACE ;SPACE BETWEEN ADDRESS AND DATA
MOVX A,@DPTR ;SHOW THE CURRENT DATA
ACALL WRBYTE
ACALL SPACE ;OUTPUT A SPACE
ACALL GETC ;GET THE NEXT CHARACTER
CJNE A,#' ',MEM2 ;ITS NOT A SPACE SO KEEP CHECKING
INC DPTR ;SPACE, SO SHOW NEXT LOCATION
SJMP MEM1
MEM2: CJNE A,#'^',MEM4 ;ITS NOT A ^ SO KEEP CHECKING
XCH A,DPL ;THIS ROUTINE DECREMENTS DPTR
JNZ MEM3 ;DPL NOT ZERO, SO DON'T CHANGE DPH
DEC DPH
MEM3: DEC A
XCH A,DPL
SJMP MEM1 ;SO WE CAN DISPLAY PREVIOUS
MEM4: CJNE A,#CR,NEWMEM ;PRESUME ITS A NEW VALUE
SJMP MEMX ;ITS A RETURN SO EXIT
NEWMEM: ACALL RDHX1 ;GET THE NEW VALUE
MOVX @DPTR,A ;MOVE THE NEW VALUE TO MEMORY
INC DPTR ;POINT TO NEXT LOCATION
SJMP MEM1 ;AND CONTINUE
MEMX: POP DPL ;RESTORE DPTR
POP DPH
POP ACC ;AND THE ACCUMULATOR
RET ;BACK FOR NEXT COMMAND
.eject
LOAD: PUSH DPH ;SAVE DPTR
PUSH DPL
PUSH CNTLO ;SAVE CNTLO
PUSH ADHI ;SAVE ADHI AND ADLO
PUSH ADLO
MOV ADHI,#0 ;INITIALIZE ADHI AND ADLO TO 0
MOV ADLO,#0
LOADX: ACALL GETC ;GET THE NEXT CHARACTER
CJNE A,#' ',LOAD1 ;NOT A SPACE SO KEEP CHECKING
SJMP LOADX ;SPACE DOESN'T MEAN ANYTHING SO LOOP
LOAD1: CJNE A,#CR,LOAD2 ;NOT A RETURN SO PRESUME A NEW ADDRESS
SJMP LOAD3 ;RETURN, SO LOAD FROM OLD ADDRESS
LOAD2: ACALL RDHX1 ;PRESUME A NEW ADDRESS
MOV ADHI,A
ACALL RDHEX
MOV ADLO,A
LOAD3: ACALL CRLF
ACALL CRLF
WAITBGN: ACALL GETC ;WAIT UNTIL ':' IS RECEIVED (START OF LINE)
CJNE A,#':',WAITBGN
ACALL RDHEX ;GET THE BYTE COUNT
JZ ALLRD ;LAST RECORD HAS 0 BYTE COUNT
MOV CNTLO,A ;LOAD BYTE COUNT FOR LINE INTO CNTLO
ACALL RDHEX ;READ HIGH BYTE OF START ADDRESS
MOV DPH,A
ACALL RDHEX ;READ LOW BYTE OF START ADDRESS
ADD A,ADLO ;ADD OFFSET ADDRESS
MOV DPL,A
MOV A,DPH
ADDC A,ADHI
MOV DPH,A
ACALL RDHEX ;READ RECORD TYPE 00 = DATA, 01 = END
RDLP: ACALL RDHEX ;GET DATA BYTE
MOVX @DPTR,A ;STORE IT
INC DPTR ;POINT TO NEXT BYTE ADDRESS
DJNZ CNTLO,RDLP ;DECR BYTE COUNTER, LOOP IF NOT FINISHED
ACALL RDHEX ;SKIP THE CHECKSUM
ACALL CRLF ;GO TO A NEW LINE
SJMP WAITBGN ;IGNORE CHECKSUM, LINE FEED, CARRIAGE RETURN
ALLRD: ACALL RDHEX ;READ ADDRESS
ACALL RDHEX ;READ ADDRESS
ACALL RDHEX ;READ RECORD TYPE
ACALL RDHEX ;READ LAST CHECKSUM
ACALL GETC ;READ LAST CR
ACALL CRLF ;GO TO A NEW LINE
POP ADLO ;RESTORE ADHI AND ADLO
POP ADHI
POP CNTLO ;RESTORE CNTLO
POP DPL ;RESTORE DPTR
POP DPH
RET ;DONE, BACK FOR NEXT COMMAND
.eject
GO: POP DPH ;GET THE OLD PROGRAM COUNTER
POP DPL ;USE DPTR SINCE IT WILL BE RESTORED
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -