$MOD552 VERSION EQU '1' REVISION EQU '2' RAMBASE EQU 2000H ;beginning of RAM area STKBASE EQU 40H ;bottom of STACK area ESC EQU 1BH ;escape character CR EQU 0DH ;carriage return LF EQU 0AH ;line feed ORG 0 ;THEN SET REST OF PROG AT 00H ;0000 is the processor's reset vector ajmp INIT ;Jump to initialisation routine ; ;Interrupt Service Routines ;0003 external INT0 (p3.2) ORG 3 ljmp RAMBASE+3 ; ;000B timer 0 ORG 000BH ljmp RAMBASE+000BH ; ;0013 external INT1 (p3.3) ORG 0013H ljmp RAMBASE+0013H ; ;001b timer 1 ORG 001BH ljmp RAMBASE+001BH ; ;0023 internal serial interface RI and TI ORG 0023H ljmp RAMBASE+0023H ; ;002BH Serial I2C interface ORG 002BH ljmp RAMBASE+002BH ; ;0033H T2 capture 0 ORG 0033H ljmp RAMBASE+0033H ; ;003BH T2 capture 1 ORG 003BH ljmp RAMBASE+003BH ; ;0043H T2 capture 2 ORG 0043H ljmp RAMBASE+0043H ; ;004BH T2 capture 3 ORG 004BH ljmp RAMBASE+004BH ; ;0053H ADC completion ORG 0053H ljmp RAMBASE+0053H ; ;005BH T2 compare 0 ORG 005BH ljmp RAMBASE+005BH ; ;0063H T2 compare 1 ORG 0063H ljmp RAMBASE+0063H ; ;005BH T2 compare 2 ORG 006BH ljmp RAMBASE+006BH ; ;0073H T2 overflow ORG 0073H ljmp RAMBASE+0073H ; ; ; ;------------------------------------------------------------------------ ; ***** MAINLINE CODE STARTS HERE ***** ;------------------------------------------------------------------------ INIT: mov a,#STKBASE ;set stack pointer mov sp,a CLR P1.5 ;*** SHUT OFF BELL FOR WYSE 50 clr a mov psw,a ;set register bank zero ; ;initalize interrupt vectors in RAM mov a,#0032H ;"RETI" instruction mov dptr,#RAMBASE+03H ;INT0 vector in RAM movx @dptr,a mov dptr,#RAMBASE+0BH ;timer 0 vector in RAM movx @dptr,a mov dptr,#RAMBASE+013H ;INT1 vector in RAM movx @dptr,a mov dptr,#RAMBASE+01BH ;timer 1 vector in RAM movx @dptr,a mov dptr,#RAMBASE+023H ;serial RI/TI vector in RAM movx @dptr,a mov dptr,#RAMBASE+02BH ;serial I2C vector in RAM movx @dptr,a mov dptr,#RAMBASE+033H ;CT0 movx @dptr,a mov dptr,#RAMBASE+03BH ;CT1 movx @dptr,a mov dptr,#RAMBASE+043H ;CT2 movx @dptr,a mov dptr,#RAMBASE+04BH ;CT3 movx @dptr,a mov dptr,#RAMBASE+053H ;ADC movx @dptr,a mov dptr,#RAMBASE+05BH ;CM0 movx @dptr,a mov dptr,#RAMBASE+063H ;CM1 movx @dptr,a mov dptr,#RAMBASE+06BH ;CM2 movx @dptr,a mov dptr,#RAMBASE+073H ;T2 movx @dptr,a ; ;initialize CPU's serial port mov pcon, #080h mov tcon, #040h mov ien0, #010h MOV S0CON, #052H ;original was #52H MOV TMOD, #020H mov p3, #00h MOV TH1, #0F7H ;#0E8H=1200 BAUD #0FDH=9600 BAUD ;#0FAH=4800 BAUD #0F4H=2400 BAUD mov p3, #00000011b SETB TR1 ;START TIMER FOR SERIAL PORT ; MENU: LCALL XSTRING DB CR,LF DB 'MONITR552 RTC-552 System Monitor VERSION ' DB VERSION,'.',REVISION,CR,LF DB 'ENTER THE LETTER FOR YOUR SELECTION',CR,LF,LF DB 'D - DUMP External RAM',CR,LF DB 'R - READ Internal RAM (indirect)',CR,LF DB 'L - LOAD External RAM WITH BYTE',CR,LF DB 'J - JUMP to Address',CR,LF DB 'P - DOWNLOAD Hex File to RAM',CR,LF DB 'I - DIRECT READ Internal RAM (0-7F & SFR''s)',CR,LF DB 'O - DIRECT WRITE Internal RAM (0-7F & SFR''s)',CR,LF DB 'X - Display REGISTER banks & internal ram',CR,LF DB CR,LF,LF,LF,LF,LF,LF,LF,LF,LF DB esc getsel: lcall xstring DB CR,LF,':' ;prompt DB ESC LCALL CHR_IN anl a,#05FH ;upcase, strip parity D_TEST: CJNE A,#'D',R_TEST ;IF NOT D, THEN CHECK R AJMP D_RUN ;D, SO RUN DUMP MEMORY R_TEST: CJNE A,#'R',L_TEST ;IF NOT R, THEN CHECK L AJMP R_RUN ;R, SO RUN REGISTER SET/READ L_TEST: CJNE A,#'L',J_TEST ;IF NOT L, THEN CHECK J AJMP L_RUN ;L, SO RUN LOAD RAM W/ BYTE J_TEST: CJNE A,#'J',P_TEST ;IF NOT J, THEN CHECK P AJMP J_RUN ;J, SO RUN JUMP TO ADDRESS P_TEST: CJNE A,#'P',I_TEST ;IF NOT P, THEN CHECK I AJMP P_RUN ;P, SO RUN DOWNLOAD PROGRAM I_TEST: CJNE A,#'I',O_TEST ;IF NOT I, THEN NO DIRECT READ AJMP I_RUN ;I, SO DIRECT READ O_TEST: CJNE A,#'O',X_test ;IF NOT O, THEN CHECK for X AJMP O_RUN ;O, SO DIRECT WRITE X_test: cjne a,#'X',j_menu ;go if no match ajmp disp_reg ;yep - go dump registers J_MENU: ACALL WAIT ;default - wait, then show menu LJMP MENU ;------------------------------------------------------------------------ ;Display external data memory (hex and ASCII) D_RUN: LCALL XSTRING ;ASK FOR START ADDRESS DB CR,LF,'ENTER 2-BYTE START ADDRESS: ',CR,LF,CR,LF DB ESC ACALL READHEX ;READ START ADDRESS MOV DPH,A ;PUT START ADDR IN DPTR ACALL READHEX ;READ SECOND NIBBLE OF START ADDRESS ANL A,#0F0H ;START ON 16-BYTE BOUNDARY MOV DPL,A ;HAVE START ADDRESS IN DPTR PUSH DPH ;save start address onto stack PUSH DPL LCALL XSTRING DB CR,LF,'HOW MANY 16-BYTE ROWS (00 TO FF): ',CR,LF,CR,LF DB ESC POP DPL ;restore start address to DPTR POP DPH ; = = = = = ACALL READHEX ;READ NUMBER OF 16-BYTE ROWS MOV R1,#00 ;CLEAR R1 (AI) MOV R1,A ;SET UP ROW COUNTER ACALL LFCR ;START DISPLAY ON NEXT LINE INC R1 ;INCREMENT ROW COUNTER LOUTLOOP: MOV R0,#16 ;SET UP BYTE COUNTER MOV A,DPH ;AT START OF LINE OUTPUT ADDR ACALL WRBYTE ; MOV A,DPL ; ACALL WRBYTE ; MOV A,#' ' ;AND SPACE TO MAKE IT TIDY ACALL CHR_OUT ; push dpl push dph ;save line start address on stack BOUTLOOP: MOVX A,@DPTR ;OUTPUT ROW ONE BYTE AT A TIME ACALL WRBYTE MOV A,#' ' ACALL CHR_OUT INC DPTR DJNZ R0,BOUTLOOP ;END OF BYTE LOOP pop dph pop dpl ;restore line start address acall dascii ;display ascii equivalents ACALL LFCR ;GO TO NEXT LINE DJNZ R1,LOUTLOOP ;LOOP THROUGH NEXT LINE IF REQ'D acall lfcr ;drop down a line LJMP getsel ;and return to command mode ; dascii: mov r0,#16 ;initalize loop count mov a,#' ' acall chr_out ;put out couple of spaces acall chr_out dasci1: movx a,@dptr ;get the byte anl a,#07fH ;mask parity bit clr c ;clear carry subb a,#' ' ;subtract ascii space jnc dasci2 ;jump if displayable mov a,#('.'-' ') ;load "." minus space if not displayable dasci2: add a,#' ' ;make it ascii again acall chr_out ;print it inc dptr ;bump data pointer djnz r0,dasci1 ;and loop 'till done ret ;return and do next line ; ;------------------------------------------------------------------------ R_RUN: ACALL XSTRING DB CR,LF,'ENTER MEMORY BYTE ADDRESS (IN HEX, BOTH NIBBLES) ' DB CR,LF,'(Note that SFRs cannot' DB ' be read as an indirect register move is used.)',CR,LF DB ESC ACALL READHEX ;GET ADDRESS BYTE MOV R0,A ;PUT THE ADDRESS INTO A REGISTER MOV A,#' ' ;PUT A SPACE BETWEEN REG ADDR AND DATA ACALL CHR_OUT MOV A,@R0 ;USE REGISTER INDIRECT TO GET DATA ACALL WRBYTE ;AND SEND IT TO THE CONSOLE ACALL LFCR LJMP getsel ; ;------------------------------------------------------------------------ L_RUN: ACALL XSTRING DB CR,LF,'ENTER THE 2-BYTE STARTING ADDRESS YOU WISH TO CHANGE' DB CR,LF,'NOTE THAT WRITING TO ROM WILL NOT CAUSE AN ERROR',CR,LF DB ESC ACALL READHEX ;FIRST GET THE TWO ADDRESS BYTESº MOV DPH,A ACALL READHEX MOV DPL,A PUSH DPH ;SAVE THE ADDRESS PUSH DPL MOV A,#' ' ;SPACE BETWEEN ADDRESS AND DATA ACALL CHR_OUT MOVX A,@DPTR ;SHOW THE CURRENT DATA ACALL WRBYTE ACALL XSTRING DB CR,LF,'ENTER THE BYTE TO BE WRITTEN (IN HEX, BOTH NIBBLES) ',CR,LF DB ESC ACALL READHEX ;GET THE NEW VALUE POP DPL POP DPH MOVX @DPTR,A ;MOVE THE NEW VALUE TO MEMORY LJMP getsel ;return to command mode ; ;------------------------------------------------------------------------ ;Jump to address J_RUN: ACALL XSTRING DB CR,LF,'ENTER THE 2-BYTE JUMP DESTINATION ADDRESS',CR,LF DB ESC ACALL READHEX ;FIRST GET THE JUMP ADDRESS MOV DPH,A ACALL READHEX MOV DPL,A clr a ; MOV A,#00H JMP @A+DPTR ;JUMP TO THE ADDRESS ; ;------------------------------------------------------------------------ ;Load hex file into memory P_RUN: ACALL LFCR ACALL LFCR ACALL CHR_IN ;GET RID OF : AT START OF LINE ACALL READHEX JZ ALLREAD ;LAST RECORD HAS 01 IN RECORD TYPE MOV R5,A ;LOAD BYTE COUNT FOR LINE INTO R5 ACALL READHEX ;READ HIGH BYTE OF START ADDRESS MOV DPH,A ACALL READHEX ;READ LOW BYTE OF START ADDRESS MOV DPL,A ACALL READHEX ;READ RECORD TYPE 00 = DATA, 01 = END READLOOP: ACALL READHEX MOVX @DPTR,A INC DPTR ;MOVE DPTR TO NEXT BYTE ADDRESS DJNZ R5,READLOOP ;DECR BYTE COUNTER, JNZ ACALL READHEX ;GET RID OF CHECKSUM, NO CHECKING ACALL CHR_IN ;GET RID OF LINE FEED ACALL CHR_IN ;GET RID OF CARRIAGE RETURN AJMP P_RUN ;GET NEXT LINE ALLREAD: ACALL READHEX ;READ ADDRESS ACALL READHEX ;READ ADDRESS ACALL READHEX ;READ RECORD TYPE ACALL READHEX ;READ LAST CHECKSUM ACALL CHR_IN ;READ LAST CR ACALL CHR_IN ;READ LAST LF LJMP getsel ;DONE, GO BACK TO MENU ; ;------------------------------------------------------------------------ ;Read internal RAM using direct addressing I_RUN: acall sfrlist ;display SFR crib sheet MOV dptr,#PATCH ;MOV INSTRUCTION WILL BE ASSEMBLED MOV A,#0E5H ;E5 IS A MOV A,DIRECT MOVX @DPTR,A ;PUT THE INSTRUCTION PATCH INC DPTR ;SET DPTR TO NEXT LOCATION (PATCH+1) PUSH DPH ;SAVE DPTR PUSH DPL ACALL XSTRING ;GET REGISTER ADDR TO READ DB CR,LF,'ENTER HEX ADDRESS OF DIRECT BYTE TO READ',CR,LF DB ESC ACALL READHEX POP DPL ;GET PATCH DPTR VALUE BACK AFTER XSTRNG POP DPH MOVX @DPTR,A ;SEND ADDR OF BYTE TO COMPLETE INSTR. INC DPTR ; MOV A,#022H ;PUT RET INSTRUCTION IN PATCH+2. MOVX @DPTR,A ; LCALL PATCH ;EXECUTE PATCH ACALL WRBYTE ;SHOW BYTE RETRIEVED BY PATCH ACALL LFCR LJMP getsel ; ;------------------------------------------------------------------------ ;Write internal RAM using direct addressing O_RUN: acall sfrlist MOV DPtr,#PATCH ;MOV INSTRUCTION WILL BE ASSEMBLED MOV A,#0F5H ;F5 IS A MOV DIRECT,A MOVX @DPTR,A ;PUT THE INSTRUCTION AT PATCH INC DPTR ;SET DPTR TO NEXT LOCATION (PATCH+1) PUSH DPH ;SAVE DPTR PUSH DPL ACALL XSTRING ;GET REGISTER ADDR TO WRITE DB CR,LF,'ENTER HEX ADDRESS OF DIRECT BYTE TO WRITE',CR,LF DB ESC ACALL READHEX POP DPL ;GET PATCH DPTR VALUE BACK AFTER XSTRNG POP DPH MOVX @DPTR,A ;SEND ADDR OF BYTE TO COMPLETE INSTR. INC DPTR ;DPTR TO PATCH+2 FOR RET INSTR. MOV A,#022H MOVX @DPTR,A ;PUT RET INSTRUCTION IN PATCH ACALL XSTRING ;GET BYTE TO WRITE DB CR,LF,'ENTER BYTE (IN HEX, BOTH NIBBLES) TO WRITE ' DB 'TO DIRECT MEMORY: ',CR,LF DB ESC ACALL READHEX ;get value from user LCALL PATCH ;DATA IN A, INSTRs AT PATCH, SO EXECUTE LJMP getsel ; ;------------------------------------------------------------------------ ;display registers disp_reg: acall xstring DB CR,LF,'Registers:' DB CR,LF,'Bank r0 r1 r2 r3 r4 r5 r6 r7',CR,LF DB esc clr a mov r0,a ;data pointer dr1: mov a,r0 rr a rr a rr a ;make value a bank address acall wrbyte ;display bank number mov a,#' ' acall chr_out acall chr_out acall chr_out acall chr_out ;output four spaces dr2: mov a,@r0 acall wrbyte ;display the value mov a,#' ' acall chr_out ;space between each one inc r0 ;bump pointer mov a,r0 ;get address anl a,#007H cjne a,#0,dr2 ;continue till bits 2-0 = zero ; acall lfcr ;bump display to next line cjne r0,#020H,dr1 ;continue 'till all four banks displayed ; acall xstring DB CR,LF,'Internal data ram:',CR,LF DB esc dr3: mov a,r0 acall wrbyte ;display the address mov a,#' ' acall chr_out acall chr_out acall chr_out acall chr_out ;output four spaces dr4: mov a,@r0 inc r0 acall wrbyte ;display the data mov a,#' ' acall chr_out ;keep it pretty mov a,r0 anl a,#0fH cjne a,#0,dr4 ;16 bytes at a time ; acall lfcr ;bump down to next line cjne r0,#0,dr3 ;loop 'till r3 overflows ajmp getsel ;and return to command mode ;------------------------------------------------------------------------ ;display SFR crib sheet sfrlist: acall xstring DB CR,LF,'Special Function Register Addresses:',CR,LF DB CR,LF,'P0 80 P1 90 P2 A0 P3 B0' DB CR,LF,'ACC E0 PSW D0 B F0 DPL 82 DPH 83 SP 81' DB CR,LF,'TCON 88 TMOD 89 TL0 8A TH0 8C TL1 8B TH1 8D' DB CR,LF,'SCON 98 SBUF 99 IE A8 PCON 87',CR,LF DB esc ret ;------------------------------------------------------------------------ ; LFCR SENDS A LINE FEED AND CARRIAGE RETURN OUT THE SERIAL PORT ; NOTHING IS PASSED IN, AND THE CONTENTS OF A ARE DESTROYED ; LFCR: MOV A,LF ACALL CHR_OUT MOV A,CR ACALL CHR_OUT RET ; ; WAIT PAUSES FOR A FRACTION OF A SECOND. FREQUENCY UNKNOWN ; WAIT: MOV A,#-1 WAIT1: MOV B,#-1 DJNZ B,$ DEC A JNZ WAIT1 RET ; ; XSTRING IS FROM THE AMD 8051 DATA BOOK AND SENDS THE TEXT STRING ; THAT FOLLOWS THE CALL TO THE SERIAL PORT. IT MESSES UP THE ; DPTR AND ACC, AND ALTHOUGH IS NOT ENDED WITH A RET, MUST BE ; CALLED. THE TEXT STRING MUST END WITH AN ESC CHARACTER ; XSTRING: POP DPH ;LOAD DPTR WITH FIRST CHAR POP DPL XSTR_1: CLR A ;(ZERO OFFSET) MOVC A,@A+DPTR ;FETCH FIRST CHAR IN STRING XSTR_2: JNB TI,$ ;WAIT UNTIL TRANSMITTER READY CLR TI ;MARK AS NOT READY MOV S0BUF,A ;OUTPUT NEXT CHARACTER INC DPTR ;BUMP POINTER CLR A MOVC A,@A+DPTR ;GET NEXT CHARACTER CJNE A,#ESC,XSTR_2 ;LOOP UNTIL ESCAPE READ MOV A,#1 JMP @A+DPTR ;RETURN TO CODE AFTER ESCAPE ; ; READS A CHARACTER INTO A FROM THE SERIAL PORT AND ; ECHOS THE CHARACTER BACK TO THE SERIAL PORT ; CHR_IN: JNB RI,$ CLR RI MOV A,S0BUF ANL A,#07FH ACALL CHR_OUT RET ; ; SENDS A CHARACTER IN A OUT THE SERIAL PORT. MUST BE AN ASCII CHARACTER ; CHR_OUT: JNB TI,$ CLR TI MOV S0BUF,A RET ; ; CONVERTS AN ASCII CHARACTER IN A TO ITS HEX EQUIVALENT. ; RETURNS VALUE IN LOWER NIBBLE, UPPER NIBBLE ZEROS ; ASC2HEX: CLR CY SUBB A,#'0' MOV B,A SUBB A,#10 ;subtract 10 decimal JB CY,A2LT10 MOV A,B SUBB A,#7 MOV B,A A2LT10: MOV A,B RET ; ; CONVERTS THE LOWER NIBBLE IN A TO AN ASCII CHARACTER RETURNED IN A ; HEX2ASC: ANL A,#0FH CLR CY MOV B,A SUBB A,#10 MOV A,B JB CY,H2LT10 ADD A,#7 H2LT10: ADD A,#'0' RET ; ; READS TWO ASCII CHARACTERS FROM THE SERIAL PORT AND ; CONVERTS THEM INTO A BYTE RETURNED IN A. USES ; REGISTER 2 IN THE FIRST BANK ; READHEX: ACALL CHR_IN ;GET THE FIRST CHARACTER ACALL ASC2HEX ;CONVERT TO HEX NIBBLE SWAP A ;HIGH ORDER NIBBLE IS FIRST ONE MOV R2,A ;SAVE THE HIGH ORDER NIBBLE ACALL CHR_IN ;GET LOW ORDER CHARACTER ACALL ASC2HEX ;CHANGE TO HEX NIBBLE ORL A,R2 ;PUT NIBBLES TOGETHER IN A RET ; ; WRITES BYTE IN A TO THE SERIAL PORT AS TWO ASCII ; CHARACTERS. USES REGISTER 2 IN THE FIRST BANK. ; WRBYTE: MOV R2,A SWAP A ACALL HEX2ASC ACALL CHR_OUT MOV A,R2 ACALL HEX2ASC ACALL CHR_OUT RET ; ORG RAMBASE PATCH: DB ' ',' ',' ' ;reserve 3 bytes ;SET UP LABEL ADDRESS FOR PATCH JUMP END