; RD2MON.ASM ; ; ************************************************* ; * * ; * MINMON - The Minimal 8051 Monitor Program * ; * * ; * Portions of this program are courtesy of * ; * Rigel Corporation, of Gainesville, Florida * ; * * ; * Modified for 6.115 * ; * Massachusetts Institute of Technology * ; * January, 2001 Steven B. Leeb * ; * * ; * Modified for Microcontroller HSSP Class * ; * June, 2001 Douglas Ricket * ; * * ; ************************************************* ; constant: OSCFREQ equ 0Bh PGM_MTP equ 0FFF0h ; address of In-Application-Programmer MON_ADDRESS equ 07000h ; Starting address for this monitor code MON_GETCHR equ MON_ADDRESS+02 MON_SNDCHR equ MON_ADDRESS+04h ; These routines can be called MON_GETBYT equ MON_ADDRESS+06h ; by a user program MON_PRTHEX equ MON_ADDRESS+08h MON_PRINT equ MON_ADDRESS+0Ah MON_CRLF equ MON_ADDRESS+0Ch MON_SERIALINIT equ MON_ADDRESS+0Eh MON_ASCBIN equ MON_ADDRESS+10h MON_BINASC equ MON_ADDRESS+12h stack equ 2fh ; bottom of stack ; - stack starts at 30h - errorf equ 0 ; bit 0 is error status ;================================================================= ; 8032 hardware vectors ;================================================================= ; org 00h ; power up and reset vector ; ljmp start ; org 03h ; interrupt 0 vector ; ljmp start ; org 0bh ; timer 0 interrupt vector ; ljmp start ; org 13h ; interrupt 1 vector ; ljmp start ; org 1bh ; timer 1 interrupt vector ; ljmp start ; org 23h ; serial port interrupt vector ; ljmp start ; org 2bh ; 8052 extra interrupt vector ; ljmp start ;================================================================= ; jump table for general-purpose utility routines ;================================================================= org MON_ADDRESS ajmp start ; 00h ajmp getchr ; 02h ajmp sndchr ; 04h ajmp getbyt ; 06h ajmp prthex ; 08h ajmp print ; 0ah ajmp crlf ; 0ch ajmp serialinit ; 0eh ajmp ascbin ; 10h ajmp binasc ; 12h ;================================================================= ; begin main program ;================================================================= start: mov 0A2h, #20h ; SFR: Use IAP Boot Room Code in last 1k (FC00) clr ea ; disable interrupts acall serialinit ; initialize hardware acall print ; print welcome message db 0ah, 0dh, "Welcome to Microcontroller Project Laboratory 2001!", 0ah, 0dh db "Commands: [E]rase [D]ownload [B]oot Vector [G]oto#### [R]ead#### [W]rite####=##", 0ah, 0dh db 0ah, 0dh, 0h monloop: mov sp,#stack ; reinitialize stack pointer clr ea ; disable all interrupts clr errorf ; clear the error flag acall print ; print prompt db 0dh, 0ah,"RD2MON> ", 0h clr ri ; flush the serial input buffer acall getcmd ; read the single-letter command mov r2, a ; put the command number in R2 ajmp nway ; branch to a monitor routine endloop: ; come here after command has finished sjmp monloop ; loop forever in monitor loop ;================================================================= ; subroutine init ; this routine initializes the hardware ;================================================================= serialinit: ; set up serial port with a 11.0592 MHz crystal, ; use timer 1 for 9600 baud serial communications (19200 for RD2) mov tmod, #20h ; set timer 1 for auto reload - mode 2 mov tcon, #41h ; run counter 1 and set edge trig ints mov th1, #0fdh ; set 9600 baud with xtal=11.059mhz mov scon, #50h ; set serial control reg for 8 bit data ; and mode 1 ret ;================================================================= ; monitor jump table ;================================================================= jumtab: dw badcmd ; command '@' 00 dw badcmd ; command 'a' 01 dw bootvec ; command 'b' 02 used dw badcmd ; command 'c' 03 dw downld ; command 'd' 04 used dw erase ; command 'e' 05 used dw badcmd ; command 'f' 06 dw goaddr ; command 'g' 07 used dw badcmd ; command 'h' 08 dw badcmd ; command 'i' 09 dw badcmd ; command 'j' 0a dw badcmd ; command 'k' 0b dw badcmd ; command 'l' 0c dw badcmd ; command 'm' 0d dw badcmd ; command 'n' 0e dw badcmd ; command 'o' 0f dw badcmd ; command 'p' 10 dw badcmd ; command 'q' 11 dw read ; command 'r' 12 used dw badcmd ; command 's' 13 dw badcmd ; command 't' 14 dw badcmd ; command 'u' 15 dw badcmd ; command 'v' 16 dw write ; command 'w' 17 used dw badcmd ; command 'x' 18 dw badcmd ; command 'y' 19 dw badcmd ; command 'z' 1a ;***************************************************************** ; monitor command routines ;***************************************************************** ;=============================================================== ; Command read 'r' ; Syntax: R9001 ; Prints the value of memory at location 9001 ;=============================================================== read: acall getbyt ; get address high byte mov dph, a ; save in dptr high byte acall prthex acall getbyt ; get address low byte mov dpl, a ; save in dptr low byte acall prthex acall crlf ;;;movx a, @dptr ; READ FROM EXTERNAL MEMORY mov r0, #OSCFREQ mov r1, #03h lcall PGM_MTP ; READ FROM FLASH acall prthex ; print it acall crlf ajmp endloop ; return ;=============================================================== ; Command write 'w' ; Syntax: W9001=FF ; Sets the value of memory at location 9001 to FF ;=============================================================== write: acall getbyt ; get address high byte mov dph, a ; save in dptr high byte acall prthex acall getbyt ; get address low byte mov dpl, a ; save in dptr low byte acall prthex acall getchr cjne a, #61, noequals ; demand an = sign here acall sndchr acall getbyt acall prthex ;;;movx @dptr, a ; WRITE TO EXTERNAL MEMORY mov r0, #OSCFREQ mov r1, #02h lcall PGM_MTP ; WRITE TO FLASH jnz writefail ajmp endloop ; return writefail: acall print db "Programming Failed", 0ah, 0dh, 0h ajmp endloop ; return noequals: acall print ; print welcome message db 0ah, 0dh, "Syntax error. Usage: W####=##", 0ah, 0dh, 0h ajmp endloop ; return ;=============================================================== ; Command write 't' ; Sets a range of memory addresses ; ; Syntax: T94 ; 9400 01 ; 9401 02 ... ; (Prompts user for up to 256 bytes of data, non-number is end) ;=============================================================== writevector: ;mov a, r1 ; save registers ;push acc acall getbyt ; load high byte mov dph, a acall prthex mov dpl, #0 ; assume 00 for low byte acall crlf writevectorloop: ; print the address and a space mov a, dph acall prthex mov a, dpl acall prthex mov a, #' ' acall sndchr acall getbyt ; get the data byte acall prthex acall crlf ;;;movx @dptr, a ; write data to memory mov r0, #OSCFREQ mov r1, #02h lcall PGM_MTP jnz writefail inc dpl ; move to next memory location mov a, dpl jnz writevectorloop ; zero means rolled-around, so done ;pop acc ; restore registers ;mov r1, a ajmp endloop ; return ;=============================================================== ; command goaddr 'g' ; this routine branches to the 4 hex digit address which follows ;=============================================================== goaddr: acall getbyt ; get address high byte mov r7, a ; save in R7 acall prthex acall getbyt ; get address low byte push acc ; push lsb of jump address acall prthex acall crlf mov a, r7 ; recall address high byte push acc ; push msb of jump address mov 0A2h, #00h ; Disable accidental IAP Programming ret ; do jump by doing a ret ;=============================================================== ; command downld 'd' ; this command reads in an Intel hex file from the serial port ; and stores it in external memory. ;=============================================================== downld: acall crlf mov a, #'>' ; acknowledge by a '>' acall sndchr dl: acall getchr ; read in ':' cjne a, #':', dl acall getbytx ; get hex length byte jz enddl ; if length=0 then return mov r2, a ; save length in r2 acall getbytx ; get msb of address ;;;no more: ;;;setb acc.7 ; make sure it is in RAM mov dph, a ; save in dph acall getbytx ; get lsb of address mov dpl, a ; save in dpl acall getbytx ; read in special purpose byte (ignore) dloop: acall getbytx ; read in data byte ;;;no more: ;;;movx @dptr, a ; save in ext mem mov r0, #OSCFREQ mov r1, #02h lcall PGM_MTP jnz prog_error inc dptr ; bump mem pointer djnz r2, dloop ; repeat for all data bytes in record acall getbytx ; read in checksum mov a, #'.' acall sndchr ; handshake '.' sjmp dl ; read in next record enddl: acall getbytx ; read in remainder of the acall getbytx ; termination record acall getbytx acall getbytx mov a, #'.' acall sndchr ; handshake '.' acall print db 0ah, 0dh, "Programming Sucessful!", 0ah, 0dh, 0h ajmp endloop ; return getbytx: acall getbyt jb errorf, gb_err ret gb_err: ajmp badpar prog_error: acall print db "Programming Failed!", 0ah, 0dh, 0h acall waitforq ajmp endloop ; return waitforq: acall print db "Hit q to quit", 0h qloop: acall getchr cjne a, #'q', qloop acall crlf ret ;=============================================================== ; command erase 'e' ; this command erases one of the 5 blocks of flash memory ;=============================================================== erase: acall print db 0ah, 0dh, "Erase Block" db 0ah, 0dh, "Enter Block # (0-4): ", 0h acall getchr ; get msb ascii chr acall sndchr acall crlf push acc acall print db "Erasing...", 0h pop acc acall ascbin ; conv it to binary cjne a, #05h, dummy ; Test if a < 5 dummy: ; here, C is set if A < 5 jnc badblocknumber acall blocktoaddress ; convert index to address mov r0, #OSCFREQ mov r1, #01h ; erase block mov dph, a mov dpl, #00h lcall PGM_MTP acall print db 0ah, 0dh, "Erase Complete", 0ah, 0dh, 0h ajmp endloop ; return badblocknumber: push acc acall print db "Bad Block Number: ", 0h pop acc acall prthex acall crlf ajmp endloop ; return blocktoaddress: ; converts a block index to address inc a movc a, @a+pc ; translate code to ascii ret db 00h, 20h, 40h, 80h, 0C0h ; translation table ;=============================================================== ; command erase 'b' ; this command sets the boot vector ;=============================================================== bootvec: acall print db 0ah, 0dh, "Reprogram Boot Vector: Are you sure? ", 0h acall getchr acall sndchr acall crlf cjne a, #'y', bootquit mov r0, #OSCFREQ mov r1, #04h mov dph, #00h lcall PGM_MTP ; ERASE Boot Vec & Status Byte mov r0, #OSCFREQ mov r1, #06h mov dph, #00h mov dpl, #00h mov a, #00h lcall PGM_MTP ; Program Status Byte to 00h acall print db "Enter new boot vector (ROM is FC):", 0h acall getbytx acall prthex mov r0, #OSCFREQ mov r1, #06h mov dph, #00h mov dpl, #01h ; a contains new status byte lcall PGM_MTP ; Program status byte acall print db 0ah, 0dh, "Boot Vector Programmed", 0ah, 0dh, 0h ajmp endloop ; return bootquit: acall print db "Boot Programming Aborted", 0ah, 0dh, 0h ajmp endloop ; return ; --------------------- END USER COMMANDS -------------------- ; ------------------------------------------------------------ ;***************************************************************** ; monitor support routines ;***************************************************************** badcmd: acall print db 0dh, 0ah," bad command ", 0h ajmp endloop badpar: acall print db 0dh, 0ah," bad parameter ", 0h ajmp endloop ;=============================================================== ; subroutine getbyt ; this routine reads in an 2 digit ascii hex number from the ; serial port. the result is returned in the acc. ;=============================================================== getbyt: acall getchr ; get msb ascii chr acall ascbin ; conv it to binary swap a ; move to most sig half of acc mov b, a ; save in b acall getchr ; get lsb ascii chr acall ascbin ; conv it to binary orl a, b ; combine two halves ret ;=============================================================== ; subroutine getcmd ; this routine gets the command line. currently only a ; single-letter command is read - all command line parameters ; must be parsed by the individual routines. ; ;=============================================================== getcmd: acall getchr ; get the single-letter command clr acc.5 ; make lower case acall sndchr ; echo command clr C ; clear the carry flag subb a, #'@' ; convert to command number jnc cmdok1 ; letter command must be above '@' acall badpar cmdok1: push acc ; save command number subb a, #1Bh ; command number must be 1Ah or less jc cmdok2 acall badpar ; no need to pop acc since badpar ; initializes the system cmdok2: pop acc ; recall command number ret ;=============================================================== ; subroutine nway ; this routine branches (jumps) to the appropriate monitor ; routine. the routine number is in r2 ;================================================================ nway: mov dptr, #jumtab ;point dptr at beginning of jump table mov a, r2 ;load acc with monitor routine number rl a ;multiply by two. inc a ;load first vector onto stack movc a, @a+dptr ; " " push acc ; " " mov a, r2 ;load acc with monitor routine number rl a ;multiply by two movc a, @a+dptr ;load second vector onto stack push acc ; " " ret ;jump to start of monitor routine ;***************************************************************** ; general purpose routines ;***************************************************************** ;=============================================================== ; subroutine sndchr ; this routine takes the chr in the acc and sends it out the ; serial port. ;=============================================================== sndchr: clr scon.1 ; clear the tx buffer full flag. mov sbuf,a ; put chr in sbuf txloop: jnb scon.1, txloop ; wait till chr is sent ret ;=============================================================== ; subroutine getchr ; this routine reads in a chr from the serial port and saves it ; in the accumulator. ;=============================================================== getchr: jnb ri, getchr ; wait till character received mov a, sbuf ; get character anl a, #7fh ; mask off 8th bit clr ri ; clear serial status bit ret ;=============================================================== ; subroutine print ; print takes the string immediately following the call and ; sends it out the serial port. the string must be terminated ; with a null. this routine will ret to the instruction ; immediately following the string. ;=============================================================== print: pop dph ; put return address in dptr pop dpl prtstr: clr a ; set offset = 0 movc a, @a+dptr ; get chr from code memory cjne a, #0h, mchrok ; if termination chr, then return sjmp prtdone mchrok: acall sndchr ; send character inc dptr ; point at next character sjmp prtstr ; loop till end of string prtdone: mov a, #1h ; point to instruction after string jmp @a+dptr ; return ;=============================================================== ; subroutine crlf ; crlf sends a carriage return line feed out the serial port ;=============================================================== crlf: push acc mov a, #0ah ; print lf acall sndchr pop acc cret: push acc mov a, #0dh ; print cr acall sndchr pop acc ret ;=============================================================== ; subroutine prthex ; this routine takes the contents of the acc and prints it out ; as a 2 digit ascii hex number. ;=============================================================== prthex: push acc acall binasc ; convert acc to ascii acall sndchr ; print first ascii hex digit mov a, r2 ; get second ascii hex digit acall sndchr ; print it pop acc ret ;=============================================================== ; subroutine binasc ; binasc takes the contents of the accumulator and converts it ; into two ascii hex numbers. the result is returned in the ; accumulator and r2. ;=============================================================== binasc: mov r2, a ; save in r2 anl a, #0fh ; convert least sig digit. add a, #0f6h ; adjust it jnc noadj1 ; if a-f then readjust add a, #07h noadj1: add a, #3ah ; make ascii xch a, r2 ; put result in reg 2 swap a ; convert most sig digit anl a, #0fh ; look at least sig half of acc add a, #0f6h ; adjust it jnc noadj2 ; if a-f then re-adjust add a, #07h noadj2: add a, #3ah ; make ascii ret ;=============================================================== ; subroutine ascbin ; this routine takes the ascii character passed to it in the ; acc and converts it to a 4 bit binary number which is returned ; in the acc. ;=============================================================== ascbin: clr errorf add a, #0d0h ; if chr < 30 then error jnc notnum clr c ; check if chr is 0-9 add a, #0f6h ; adjust it jc hextry ; jmp if chr not 0-9 add a, #0ah ; if it is then adjust it ret hextry: clr acc.5 ; convert to upper clr c ; check if chr is a-f add a, #0f9h ; adjust it jnc notnum ; if not a-f then error clr c ; see if char is 46 or less. add a, #0fah ; adjust acc jc notnum ; if carry then not hex anl a, #0fh ; clear unused bits ret notnum: setb errorf ; if not a valid digit ljmp endloop ; end of MINMON