Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
01/01/04 12:52
Read: times


 
#61700 - RE: Boot loading code to FLASH via Serial
Responding to: ???'s previous message
Howard Heffer wrote:
-------------------------------
Can any one give me some info on boot loading via a serial port or give me links on where to find n e info like this on the net. cheers

Howard Heffer wrote:
-------------------------------
Can any one give me some info on boot loading via a serial port or give me links on where to find n e info like this on the net. cheers

Try this....
; NAME: LOAD/DUMP INTEL HEX FILE
; DATE: SEPTEMBER 1987
; FUNCTION: LOAD INTEL HEX FILES IN RANGE 0800H THROUGH FFFFH;
; DUMP INTEL HEX OF ANY RANGE
; VERIFY INTEL HEX FILES
; TRACE INCOMING DATA
; PROGRAM THE PARTITION NIBBLE OF THE MCON REG

; ASCII EQUATES
;
CTRLC EQU 003H ; CONTROL C
BS EQU 008H ; BACK SPACE
TAB EQU 009H ; HORIZONTAL TAB, ^I
LF EQU 00AH ; LINE FEED
CR EQU 00DH ; CARRIAGE RETURN
XON EQU 011H ; RS232 PROTOCOL ^Q
XOFF EQU 013H ; RS232 PROTOCOL ^S
SPA EQU 020H ; SPACE
COLON EQU 03AH ; ':'
DEL EQU 07FH ; DELETE CHARACTER


; REGISTER NAMES
; (BANK 0 AND 1)
; GETADR R0 ; * ADDRESS TO FETCH CHAR FROM
; PUTADR R1 ; * ADDRESS TO PUT CHAR TO
; NCHS R2 ; * NUMBER OF CHARS IN BUFFER
; BUFBASE R3 ; * BASE ADDRESS OF BUFFER
; TEMPCH R3 ; * TEMP RESTING PLACE FOR CMDLIN CH
; SEEN R3 ; * NUMBER OF CHARS SEEN WHEN DECODING NUMBER
; GETOFF R4 ; OFFSET INTO BUFFER TO FETCH FROM
; PUTOFF R5 ; OFFSET INTO BUFFER TO PUT TO
; CH R6 ; CHAR FROM INPUT INTERRUPT


; EQUIVALENCED TO REGISTER DATA
;
GETOFFD EQU 004H ; DIRECT BYTE TO R4 OF BANK 0
PUTOFFD EQU 005H ; DIRECT BYTE TO R5 OF BANK 0

CLBUF EQU 00BH ; BYTE BEFORE COMMAND LINE BUFFER
CLSIZ EQU 012H ; SIZE OF COMMAND LINE BUFFER
ENDCLB EQU CLBUF+CLSIZ ; LAST BYTE IN COMMAND LINE BUFFER


; BIT FLAGS
;
XMT EQU 1 ; SET WHEN XMITTING, CLEAR OTHERWISE
XMOFF EQU 2 ; SET WHEN XOFF IS RECEIVED--DON'T XMIT
LODVER EQU 3 ; LOAD/VERIFY FLAG 0/1
EOL EQU 4 ; SET WHEN AT COMMAND LINE TERMINATOR
ERRFLG EQU 5 ; SET WHEN ERROR CONDITON IF FOUND
HEXCH EQU 6 ; SET WHEN VALID HEX CHAR SEEN; ISHEXCH
TRACE EQU 7 ; SET WHEN ECHOING INCOMING HEX DATA
SLFLG EQU 8 ; SET IF SECURITY LOCK IS SET


; 2 BYTE VARIABLES
;
HERE EQU 0024H ; START AFTER FLAG BITS

LO EQU HERE+000H ; USED TO DECODE 16 BIT NUMBERS
HI EQU HERE+001H ; OVERLAYED ON DIFF
DIFF_L EQU HERE+000H ; CALCULATED WORD DIFFERENCE
DIFF_H EQU HERE+001H ;
START_L EQU HERE+002H ; ADDRESS TO START FROM
START_H EQU HERE+003H ;
STOP_L EQU HERE+004H ; ADDRESS TO STOP AT
STOP_H EQU HERE+005H ;
CMP_L EQU HERE+006H ; WORD TO COMPARE STOP TO
CMP_H EQU HERE+007H ;


; 1 BYTE VARIABLES
;
CKSUM EQU HERE+00AH ; SUM OF BYTES IN STOHEX AND LODHEX
CURCKSUM EQU HERE+00BH ; CURRENT CALCULATED CHECK SUM ON LINE
LEN EQU HERE+00CH ; NUMBER OF BYTES ON LINE
RECTYP EQU HERE+00DH ; INTEL HEX RECORD TYPE
VAL EQU HERE+00EH ; TEMP VALUE USED BY LODHEX
TMP EQU HERE+00FH ; TEMP VALUE USED BY GETBYT, GCLWRD, PUTBYT

BUF EQU 040H ; INPUT CHARACTER BUFFER BASE
BSIZ EQU 020H ; BUFFER SIZE OF 32 BYTES

STKBASE EQU 060H ; MOVE STACK BASE TO HERE

;*****************************************************************
; PROGRAM SPACE:
; ABSOULUTE AREA
;*****************************************************************
ORG RESET
AJMP SL_INIT ; SERIAL LOAD INITIALIZATION


;*****************************************************************
;
; NAME: SERIINT
;
; ABSTRACT: SERIAL INTERRUPT PROCESSING. IF WE ARE INTERRUPTED
; ON A TRANSMIT, CLEAR THE FLAG AND RETURN. IF WE GET
; A CHARACTER, GRAB IT UP AND PUT IT INTO THE RECEIVE
; BUFFER. IF THE BUFFER IS FULL, THROW THE DATA AWAY.
; REGISTER BANK 0 IS USED FOR THE RECEIVE BUFFER VARS.
; DO NOT ECHO HERE. THE FOLLOWING CHARACTERS ARE READ:
; ^C: PUSH INIT; SET BIT RESET; RETI
; XON: CLEAR BIT XMOFF; RETI
; XOFF: SET BIT XMOFF; RETI
; ^I: TABS ARE CONVERTED TO SPACES
; DEL: CONVERTED TO BACKSPACES
; a-z: LOWER CASE ALPHA CONVERTED TO UPPER
; BS,CR,SPA,:,0-9,A-Z: INSERTED INTO BUFFER
; EVERYTHING ELSE IS THROWN AWAY.
;
; INPUTS: AN INTERRUPT
;
; OUTPUTS: NONE.
;
; VARIABLES MODIFIED: REGISTER BANK 0
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: NONE
;
;*****************************************************************
ORG SINT

SL_SINT: PUSH PSW ; SAVE SOME STUFF
PUSH ACC ;
CLR ES ; DISABLE SERIAL INTERRUPTS
JNB TI,SER_A ; IF TI=0 GOTO SER_A
CLR TI ; MUST HAVE FINISHED A TRANSMIT
CLR XMT ; CLEAR OUR BIT
AJMP SER_X ; AND RETURN

SER_A: JNB RI,SER_X ; IF RI=0 GOTO SER_X
CLR RI ; CLEAR THE RECEIVE BIT

MOV A,SBUF ; GET THE CHARACTER
CLR ACC.7 ; MAKE THIS 0-127

CJNE A,#XON,SER_B ; IF A <> XON THEN GOTO SER_B
CLR XMOFF ; CLEAR THE BIT
AJMP SER_X ; AND EXIT THIS INTERRUPT

SER_B: CJNE A,#XOFF,SER_C ; IF A <> XOFF THEN GOTO SER_C
SETB XMOFF ; LET PUTCH KNOW NOT TO XMIT
AJMP SER_X ; ANY MORE CHARS AND EXIT

SER_C: CJNE A,#CTRLC,SER_D ; IF A <> CTRLC THEN GOTO SER_D
JNB XMT,SER_C0 ; IF A CHAR IS NOT BEING XMTED, JMP
JNB TI,$ ; WAIT TILL XMIT IS DONE TO CNTRL C
SER_C0: MOV DPTR,#SL_INIT ; GET INIT ADDRESS
PUSH DPL ; PUSH LOW BYTE OF ADDRESS
PUSH DPH ; AND THE HIGH BYTE
MOV (0C7H),#0AAH ; START TIMED ACCESS
MOV (0C7H),#055H ; CONTINUED
ANL (0C6H),#0FDH ; CLEAR THE PAA ANYWAY
RETI ; THEN RETURN THRU INIT

SER_D: CJNE A,#DEL,SER_E ; IF A <> DEL THEN GOTO SER_E
MOV A,#BS ; ELSE A = BS
AJMP SER_O ; GOTO INSERT [BS]

SER_E: CJNE A,#'a',SER_F ; IF A < 'a'
SER_F: JC SER_G ; THEN GOTO SER_G
CLR ACC.5 ; ELSE FOLD TO UPPERCASE

SER_G: CJNE A,#('Z'+1),SER_H ; IF A >= 'Z'+1
SER_H: JNC SER_X ; THEN EXIT

CJNE A,#'A',SER_I ; IF A >= 'A'
SER_I JNC SER_O ; THEN INSERT IT [A-Z]

CJNE A,#(':'+1),SER_J ; IF A >= ':'+1
SER_J: JNC SER_X ; THEN EXIT

CJNE A,#'0',SER_K ; IF A >= '0'
SER_K: JNC SER_O ; THEN INSERT IT [0-9,:]

CJNE A,#TAB,SER_L ; IF A <> TAB
MOV A,#SPA ; THEN A = SPA

SER_L: CJNE A,#SPA,SER_M ; IF A <> SPACE THEN GOTO SER_M
AJMP SER_O ; THEN INSERT IT [SPA]

SER_M: CJNE A,#CR,SER_N ; IF A <> CR THEN GOTO SER_N
AJMP SER_O ; THEN INSERT IT [CR]

SER_N: CJNE A,#BS,SER_X ; IF A <> BS THEN EXIT

SER_O: CLR RS0 ; USE BANK 0 REGISTERS (ASSUME RS1=0)
CJNE R2,#BSIZ,SER_P ; IS THE BUFFER FULL?
AJMP SER_X ; NO SPACE LEFT, THROW CHAR AWAY

SER_P: MOV R6,A ; SAVE THE CHARACTER
MOV A,R3 ; PUT BASE IN ACCUMULATOR
ADD A,R5 ; EA = BASE + PUT-OFFSET
MOV R1,A ; SAVE THE PUT ADDRESS
INC R5 ; POINT TO THE NEXT PUT PLACE
ANL PUTOFFD,#01FH ; MOD (PUTOFF, 32) USING DIRECT BYTE
MOV A,R6 ; RESTORE CHARACTER
MOV @R1,A ; PUT THE CHARACTER INTO BUFF
INC R2 ; ++N; CHARACTERS IS ONE MORE

SER_X: POP ACC ; GET THE ACCUMULATOR BACK
POP PSW ; RESTORE PROGRAM STATUS
SETB ES ; START UP SERIAL INTERRUPTS AGAIN
RETI ; RETURN FROM INTERRUPT

;*****************************************************************
;
; NAME: SL_INIT
;
; ABSTRACT: THIS IS THE ENTRY POINT INTO THE SERIAL LOADER.
; DIRECT MEMORY IS CLEARED, STACK AND BUFFER IS
; RESET. SERIAL INTERRUPTS ARE ENABLED. INTERRUPTS
; ARE ENABLED.
;
; INPUTS: NONE
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: EVERYTHING IS INITIALIZED
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY:
;
;*****************************************************************
SL_INIT: MOV IE,#0 ; DISABLE ALL INTERRUPTS
CLR A ; CLEAR ALL OF DIRECT MEMORY
MOV PSW,A ; USE REGISTER BANK 0
MOV R0,#07FH ; END OF DIRECT MEMORY (127.)
SL_0: MOV @R0,A ; CLEAR DIRECT MEMORY
DJNZ R0,SL_0 ; CLEAR TO BOTTOM OF MEMORY
; SET UP DATA STRUCTURES
MOV R3,#BUF ; BUFFER STARTS HERE
MOV SP,#STKBASE ; RESET STACK

MOV TMOD,#20H ; 8 BIT AUTO RELOAD TIMER 1
MOV TH1,#0FDH ; 9600 BAUD
MOV TCON,#040H ; TURN TIMER 1 ON.
ANL (087H),#07FH ; CLEAR SMOD BIT (IN PCON REGISTER)
MOV SCON,#050H ; 8 BIT UART, ENABLE SERIAL INTERRUPTS

MOV IP,A ; CLEAR THE INTERRUPT PRIORITY TABLE
MOV IE,#090H ; ENABLE SERIAL INTERRUPTS AND INTERRUPTS

;*****************************************************************
;
; NAME:
;
; ABSTRACT: COMMAND LINE PROCESSING TAKES PLACE HERE. A PROMPT
; IS DISPLAYED. A COMMAND LINE IS ASSEMBLED AND ECHOED,
; AND THEN IT IS PROCESSED.
;
; INPUTS: NONE
;
; OUTPUTS:
;
; VARIABLES MODIFIED:
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: PUTSTR, PUTCH, GETCH, DOCMD
;
;*****************************************************************
MOV DPTR,#SLMSG ; GET THE BANNER STRING
ACALL PUTSTR ; PRINT THE STRING

SETB RS0 ; USE REGISTER BANK 1

CL_C: MOV DPTR,#PROMPT ; PRINT OUT PROMPT STRING
ACALL PUTSTR ;
CLR A ; INIT THE COMMAND LINE
MOV R2,A ; NO CHARS YET IN COMMAND LINE
CLR LODVER ; CLEAR ALL OF THE EDIT FLAGS
CLR EOL ;
CLR ERRFLG ;
CLR HEXCH ;
; FILL UP THE COMMAND LINE BUFFER
; REPEAT
CL_D: ACALL GETCH ; GETCH
CJNE A,#BS,CL_E ; IF CH <> BS THEN GOTO CL_E
MOV A,R2 ; A := NCHS
JZ CL_D ; IF NCHS = 0 THEN GOTO CL_D
; /* PROCESS BACKSPACE CHAR */
DEC R2 ; --NCHS
MOV DPTR,#BACKUP ; DO A DESTRUCTIVE
ACALL PUTSTR ; BACKSPACE
AJMP CL_D ; GOTO CL_D

CL_E: MOV R3,A ; SAVE A
INC R2 ; ++NCHS
MOV A,#CLBUF ; A := CLBASE
ADD A,R2 ; A := CLBASE + NCHS
MOV R1,A ; BUFFER ADDRESS TO PUTADR
MOV A,R3 ; GET INPUT CHAR BACK
MOV @R1,A ; SAVE IT TO THE COMMAND LINE BUFFER
ACALL PUTCH ; ECHO IT (CR'S ARE MADE LF'S)
CJNE A,#LF,CL_F ; UNTIL (CH = LF) OR ...
; (PUTCH CONVERTS CR'S TO LF'S)
ACALL DOCMD ; EXECUTE THE COMMAND LINE
JB ERRFLG,CL_I ; IF ERROR, DISPLAY IT
AJMP CL_C ; GO GET ANOTHER COMMAND LINE

CL_F: CJNE R2,#CLSIZ,CL_D ; ... OR (NCHS <> CLSIZ) THEN GETCH

CL_H: ACALL GETCH ; START GETTING CHARS
ACALL PUTCH ; AND ECHOING THEM
CJNE A,#LF,CL_H ; UNTIL A CR IS FOUND (MOD BY PUTCH)

MOV DPTR,#EM_BADCMD ; LINE IS TOO LONG
CL_I: ACALL PUTSTR ; PRINT THE ERROR MESSAGE
AJMP CL_C ; GO GET ANOTHER COMMAND LINE


;*****************************************************************
;
; NAME: DOCMD
;
; ABSTRACT: PARSE THE COMMAND LINE AND EXECUTE THE COMMAND IF
; POSSIBLE.
;
; INPUTS: COMMAND LINE TO BE PROCESSED
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: BANK 1 REGISTERS
;
; ERROR EXITS: DEPENDS ON COMMAND
;
; SUBROUTINES ACCESSED DIRECTLY: MANY.
;
;*****************************************************************
DOCMD: MOV ENDCLB,#LF ; MAKE SURE WE HAVE A LF SOMEWHERE IN BUF
MOV R0,#(CLBUF+1) ; GET ADDRESS OF COMMAND LINE BUFFER
ACALL SKIPSPA ; SKIP THE WHITE SPACE
JNB EOL,DO_A ; IF AT EOL THEN
RET ; RETURN HOME FOR ANOTHER CL

DO_A: MOV DPTR,#EM_EXTARG ; ASSUME ERROR
SETB ERRFLG ;
ACALL GCLCH ; GET A COMMAND LINE CHARACTER
ACALL SKIPSPA ; SKIP THE WHITE SPACE

;-------------------------------------------------------
; L - LOAD INTEL HEX DATA TO DATA MEMORY
;-------------------------------------------------------
CMD_L: CJNE A,#'L',CMD_V ; IF CMD <> L GOTO CMD_V
ACALL CHKEOL ; CHECK FOR END OF LINE
ACALL LODHEX ; LOAD THE HEX DATA BY DEFAULT
RET ; RETURN

;-------------------------------------------------------
; V - VERIFY MEMORY AGAINST INTEL HEX DATA
;-------------------------------------------------------
CMD_V: CJNE A,#'V',CMD_T ; IF CMD <> T GOTO CMD_T
ACALL CHKEOL ; CHECK FOR END OF LINE
SETB LODVER ; SET THE LOAD VERIFY FLAG
ACALL LODHEX ; LOAD THE HEX DATA
RET ; RETURN

;-------------------------------------------------------
; T - TOGGLE THE TRACE FLAG FOR ECHOING INTEL HEX DATA
;-------------------------------------------------------
CMD_T: CJNE A,#'T',CMD_P ; IF CMD <> T GOTO CMD_P
ACALL CHKEOL ; CHECK FOR END OF LINE
CPL TRACE ; TOGGLE THE TRACE BIT
MOV DPTR,#ONMSG ; GET ON MESSAGE BY DEFAULT
JB TRACE,CMD_T0 ; IF CARRY IS ON BRANCH
MOV DPTR,#OFFMSG ; ADDRESS OF OFF MESSAGE
CMD_T0: ACALL PUTSTR ; PRINT OUT ON OFF
RET ; RETURN

;-------------------------------------------------------
; P NIBBLE - PROGRAM THE PARTITION REGISTER WITH THIS NIBBLE
;-------------------------------------------------------
CMD_P: MOV DPTR,#EM_ARGREQ ; ARGUMENTS ARE REQUIRED
CJNE A,#'P',CMD_D ; IF CMD <> P GOTO CMD_D
JB EOL,CMD_PX ; ARG THAT IS NEEDED IS MISSING
ACALL GCLWRD ; GO GET A HEXADECIMAL NUMBER
JB ERRFLG,CMD_PX ; EXIT ON ERROR
ACALL SKIPSPA ; MOVE PAST THE WHITE SPACE
SETB ERRFLG ; SET THE ERROR FLAG
MOV DPTR,#EM_EXTARG ; ASSUME WE HAVE EXTRA CHARS
JNB EOL,CMD_PX ; WE BETTER BE AT END OF LINE
MOV A,LO ; GET THE LOW BYTE
ANL A,#0FH ; MASK BOTTOM NIBBLE
SWAP A ; SWAP THE NIBBLES
MOV (0C7H),#0AAH ; TIMED ACCESS
MOV (0C7H),#055H ; CONTINUED
MOV (0C6H),#02H ; SET THE PARTITION ADDRESS ACCESS

MOV (0C7H),#0AAH ; TIMED ACCESS
MOV (0C7H),#055H ; CONTINUED
MOV (0C6H),A ; CLEAR THE PAA AND SET PARTITION
CLR ERRFLG ; NO ERROR
CMD_PX: RET ;
;-------------------------------------------------------
; D [START-ADDR [END-ADDR]] - DUMP MEMORY IN INTEL HEX FORMAT
;-------------------------------------------------------
CMD_D: CJNE A,#'D',CMD_BAD ; IF CMD <> D GOTO CMD_BAD
ACALL OPTIONAL ; SEE IF WE GOT SOME ARGUMENTS
ACALL DMPHEX ; DUMP MEMORY
RET ;

;-------------------------------------------------------
; NO LEGAL COMMAND FOUND.
;-------------------------------------------------------
CMD_BAD: MOV DPTR,#EM_BADCMD ; ILLEGAL COMMAND WAS ENTERED
RET


;*****************************************************************
;
; NAME: CHKEOL
;
; ABSTRACT: CHECK THE EOL FLAG. IF IT IS SET, POP THE IMMEDIATE
; RETURN VALUE, AND RETURN TO THE NEXT, OTHERWISE JUST
; CLEAR THE FLAG AND RETURN
;
; INPUTS: ERRFLG
;
; OUTPUTS: ERRFLG
;
; VARIABLES MODIFIED: ERRFLG
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: NONE
;
;*****************************************************************
CHKEOL: JB EOL,CHK_0 ; IF EOL=SET THEN GOTO CHK_0
POP ACC ; NOT AT EOL, STUFF STILL ON
POP ACC ; THE LINE. RETURN THROUGH
RET ; PREVIOUS CALL
CHK_0: CLR ERRFLG ; NO ERROR, YET
RET ; CONTINUE.


;*****************************************************************
;
; NAME: OPTIONAL
;
; ABSTRACT: LOOK ON THE COMMAND LINE FOR TWO OPTIONAL ARGUMENTS.
; THESE VALUES WILL BE THE START AND STOP ADDRESS OF
; MEMORY. BY DEFAULT USE 0 TO MEMORY MAX. MEMORY MAX
; IS DETERMINED BY THE RANGE BIT IN MCON. DPTR IS SET
; WITH THE VALUE OF START. CLEAR THE ERROR FLAG AND
; SET THE ERROR FLAG IF WE STILL HAVE STUFF ON THE
; COMMAND LINE. NOTE THAT GCLWRD MAY RETURN AN ERROR.
; REPORT AN ERROR IF START > STOP.
; ---- IMPORTANT NOTE ----
; WHENEVER THE ERROR FLAG IS SET, RETURN TO THE CALLERS
; CALLER. THAT IS, POP THE STACK TWICE BEFORE RETURNING.
;
; INPUTS: NONE
;
; OUTPUTS: START, STOP, CMP, DPTR
;
; VARIABLES MODIFIED:
;
; ERROR EXITS: RETURN TO THE CALLERS CALLER
;
; SUBROUTINES ACCESSED DIRECTLY: GCLWRD, SKIPSPA
;
;*****************************************************************
OPTIONAL:
CLR ERRFLG ; ASSUME NO ERRORS
CLR A ; INIT START, STOP AND CMP
MOV START_L,A ;
MOV START_H,A ; START = 0;
MOV STOP_L,#0FFH ;
MOV STOP_H,#01FH ; STOP = 01FFF BY DEFAULT, 8K
MOV CMP_L,A ;
MOV CMP_H,#020H ; CMP = 2000H BY DEFAULT
MOV A,(0C6H) ; MCON REGISTER
JNB ACC.3,OPT_B ; IF 8K THEN GOTO OPT_B
MOV STOP_H,#07FH ; STOP = 07FFF, 32K
MOV CMP_H,#080H ; STOP ONE PAST

OPT_B: JB EOL,OPT_D ; IF AT EOL THEN USE DEFAULTS
ACALL GCLWRD ; GET A NUMBER, START ADDRESS
JB ERRFLG,OPT_R ; GOT AN ERROR
MOV START_L,LO ;
MOV START_H,HI ; GOT A NEW START VALUE
ACALL SKIPSPA ;
JB EOL,OPT_D ; ONLY HAVE A START VALUE, RETURN
ACALL GCLWRD ; GET THE STOP ADDRESS
JB ERRFLG,OPT_R ; GOT AN ERROR, RETURN

MOV A,LO ; GOT THE STOP VALUE
MOV STOP_L,A ;
ADD A,#01H ; AND BEGIN CALC OF CMP VALUE
MOV CMP_L,A ; GOT THE LOW PART OF CMP
MOV STOP_H,HI ; STOP IS DONE
CLR A ; NEED THE CARRY FROM THE PREVIOUS ADD
ADDC A,HI ; NOW I HAVE THE TOP OF CMP
MOV CMP_H,A ; AND WE ARE DONE

ACALL SKIPSPA ; ANY MORE ON THE LINE?
JB EOL,OPT_D ; IF AT END OF LINE THEN RETURN
MOV DPTR,#EM_EXTARG ; ERROR - EXTRA STUFF ON LINE
AJMP OPT_R ; GOT TO RETURN ROUTINE
OPT_D: MOV DPL,START_L ; NO ERROR IF THIS IS EXECUTED.
MOV DPH,START_H ; DPTR = START

MOV A,START_H ; IS START > STOP? LETS FIND OUT
CJNE A,STOP_H,OPT_F ; IF HIGH BYTES ARE DIFFERENT, THEN GOTO OPT_F


MOV A,STOP_L ; START AND STOP HIGH ARE EQUAL AT THIS POINT
CJNE A,START_L,OPT_E ; STOP MUST BE LESS THAN START TO BE IN ERROR
OPT_E: JC OPT_G ; JUMP IF STOP_L < START_L
RET ; RETURN, EVERYTHING IS FINE
OPT_F: JNC OPT_G ; IF START_H >= STOP_H THEN GOTO OPT_G
RET ; START <= STOP, SO RETURN
OPT_G: MOV DPTR,#EM_ILLOPT ; START > STOP
OPT_R: SETB ERRFLG ; GOT AN ERROR
POP ACC ; GET RID OF THE RETURN ADDRESS AND
POP ACC ; RETURN TO THE CALLERS CALLER.
OPT_X: RET ;


;*****************************************************************
;
; NAME: GCLCH - GET COMMAND LINE CHARACTER
;
; ABSTRACT: GET THE NEXT CHAR FROM THE COMMAND LINE,
; POINT TO THE NEXT CHAR. IF IT IS A CR THEN
; SET EOL.
;
; INPUTS: REGISTER BANK 1 IS ASSUMED
;
; OUTPUTS: A:CHAR, R0:POINT TO NEXT CHAR, EOL:SET IF AT EOL
;
; VARIABLES MODIFIED: REGISTER BANK 1
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: NONE, BUT FALL THROUGH
; TO THE ROUTINE SKIPSPA
;
;*****************************************************************
GCLCH: MOV A,@R0 ; GET THE CHAR
INC R0 ; POINT TO NEXT CHAR
AJMP SKIP_A ; GO DOWN AND TEST FOR EOL

;*****************************************************************
;
; NAME: SKIPSPA
;
; ABSTRACT: MOVE R0 ACROSS THE SPACES. IF THE CHAR WE
; LAND ON IS A CR, SET THE FLAG EOL. NOTE THAT R0
; IS CHANGED ONLY IF THE CURRENT CHARACTER IT IS POINTING
; TO IS A BLANK.
;
; INPUTS: REGISTER BANK 1 IS ASSUMED
;
; OUTPUTS: R0:POINTS TO NEXT NON BLANK CHAR
;
; VARIABLES MODIFIED: REGISTER BANK 1
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: NONE
;
;*****************************************************************
SKIPSPA: CJNE @R0,#SPA,SKIP_A ; DO WHILE CH = SPA
INC R0 ; ++GETADR
AJMP SKIPSPA ; CONTINUE SKIPPING WHITE SPACE
SKIP_A: CJNE @R0,#CR,SKIP_B ; IF CH = CR THEN
SETB EOL ; SET EOL
SKIP_B: RET ;


;*****************************************************************
;
; NAME: GCLWRD - GET COMMAND LINE HEXADECMIAL WORD
;
; ABSTRACT: READ IN A STRING OF HEX DIGITS AND DECODE THEM TO
; BINARY. ONLY THE LAST 4 DIGITS COUNT. SET ERRFLG
; AND ERROR MESSAGE IF WE CAN'T GET NUMBER. CLEAR IT
; OTHERWISE.
;
; INPUTS: THE COMMAND LINE
;
; OUTPUTS: LO, HI
;
; VARIABLES MODIFIED: A, B, R3, TMP, ERRFLG
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: GCLCH, ISHEXCH
;
;*****************************************************************
GCLWRD: CLR A ;
MOV LO,A ; N = 0
MOV HI,A ;
MOV R3,A ; SEEN = 0
CLR ERRFLG ;

GCLW_A: ACALL GCLCH ; GET A CHARACTER
ACALL ISHEXCH ; CONVERT IT IF POSSIBLE
JNB HEXCH,GCLW_B ; CONVERT UNTIL NO MORE HEX CHARS
MOV TMP,A ; SAVE OUR NIBBLE

MOV A,LO ; N = N*16 + HEXNIBBLE
MOV B,#010H ;
MUL AB ;
ADD A,TMP ;
MOV LO,A ;
MOV A,HI ;
ANL A,#0FH ;
SWAP A ;
ADD A,B ;
MOV HI,A ; ALL DONE

INC R3 ; WE HAVE SEEN ONE MORE HEX CHAR
AJMP GCLW_A ;

GCLW_B: DEC R0 ; PUT THE CHARACTER BACK
CJNE R3,#0,GCLW_D ; WE DECODED AT LEAST ONE CHAR
GCLW_C: SETB ERRFLG ; MAKE SURE THEY SEE UP ABOVE
MOV DPTR,#EM_NOTHEX ; THE STRING TO PROVE IT
RET
GCLW_D: MOV A,@R0 ; WHAT CHAR DID WE STOP ON?
CJNE A,#SPA,GCLW_E ; IF CH <> SPA THEN GOTO GCL_W
RET ; OKAY DELIMITER
GCLW_E: CJNE A,#CR,GCLW_C ; IF CH <> CR THEN GOTO GCLW_C
RET ; EVERYTHING IS OKAY


;*****************************************************************
;
; NAME: ISHEXCH (A)
;
; ABSTRACT: IF A IS A VALID HEXADECIMAL CHARACTER (0-9,A-F)
; THEN SET BIT HEXCH, AND CONVERT IT TO ITS BINARY
; VALUE LEAVING IT IN A. OTHERWISE CLEAR HEXCH
; AND RETURN.
;
; INPUTS: A, AND ASCII CHAR
;
; OUTPUTS: A
;
; VARIABLES MODIFIED:
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY:
;
;*****************************************************************
ISHEXCH: CLR HEXCH ; ASSUME THAT IT ISN'T A HEX CHAR
CJNE A,#'G',HEX_A ;
HEX_A: JNC HEX_X ; IF CH >= G THEN EXIT
CJNE A,#'0',HEX_B ;
HEX_B: JC HEX_X ; IF CH < 0 THEN EXIT
CJNE A,#':',HEX_C ; IF CH <> : THEN GOTO HEX_C
RET ; THEN EXIT
HEX_C: SETB HEXCH ; YEP, IT IS A HEX CHAR
JNB ACC.6,HEX_D ; JUMP IF 0-9
ADD A,#09H ;
HEX_D: ANL A,#0FH ; GET BOTTOM 4 BITS.
HEX_X: RET ; RETURN WITH NIBBLE IN A


;*****************************************************************
;
; NAME: GETCH
;
; ABSTRACT: RETURN A CHARACTER FROM THE INPUT QUEUE. WAIT IF
; NOTHING IS AVAILABLE YET. AN ASYNC RECEIVE ROUTINE
; FILLS THIS BUFFER. REGISTER BANK 0 IS USED FOR THE
; RECEIVE BUFFER VARIABLES.
;
; INPUTS: NONE
;
; OUTPUTS: A HAS THE INPUT CHARACTER
;
; VARIABLES MODIFIED: REGISTER BANK 0
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: NONE
;
;*****************************************************************
GETCH: PUSH PSW ; SAVE THE PSW
CLR RS0 ; USE BANK 0 REGISTERS (ASSUME RS1 = 0)
GET_A: CJNE R2,#0,GET_B ; REPEAT
AJMP GET_A ; UNTIL (NCHS > 0)
GET_B: MOV A,R3 ; PUT BASE IN ACCUMULATOR
ADD A,R4 ; EA = BASE + GET-OFFSET
MOV R0,A ; PUT ADDRESS OF CH IN R5
INC R4 ; POINT TO THE NEXT CHAR
ANL GETOFFD,#01FH ; MOD (GETOFF, 32) USING DIRECT BYTE
MOV A,@R0 ; PUT THE CHARACTER INTO A
DEC R2 ; --N; CHARACTERS IS ONE LESS
POP PSW ; RESTORE IT
RET ; RETURN WITH CHARACTER IN A


;*****************************************************************
;
; NAME: PUTCH
;
; ABSTRACT:
;
; INPUTS: A
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: A IS CONVERTED TO A LF WHENEVER
; A = CR ON ENTRY.
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: NONE
;
;*****************************************************************
PUTCH: JB XMOFF,$ ; REPEAT UNITL (XMOFF = 0)
MOV SBUF,A ; COPY A TO SBUF
SETB XMT ; SET THE BIT TO SHOW WE ARE XMITTING
JB XMT,$ ; WAIT TILL IT CLEARS

CJNE A,#CR,PUT_A ; IF A <> CR THEN GOTO PUT_A
MOV A,#LF ;
AJMP PUTCH ; NOW PUT OUT A LINE FEED

PUT_A: RET ; XMT IS CLEARED BY SERIAL INT ROUTINE


;*****************************************************************
;
; NAME: PUTBYT
;
; ABSTRACT: TAKE THE HEX NUMBER IN A AND PUT OUT TWO HEX DIGITS.
; ADD THE BYTE IN A TO THE RUNNING TOTAL IN CHECK SUM.
;
; INPUTS: A
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: A, CKSUM, TMP
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: PUTCH
;
;*****************************************************************
PUTBYT: MOV TMP,A ; SAVE THE BYTE TO BE PRINTED (PUSH)
SWAP A ; SHIFT HIGH NIBBLE OVER
ANL A,#0FH ; NOW WE REALLY HAVE JUST A NIBBLE
ADD A,#90H ; 90H-99H,9AH-9FH
DA A ; 90H-99H,00H-05H
ADDC A,#40H ; D0H-D9H,41H-46H
DA A ; 30H-39H,41H-46H WHICH IS 0-9,A-F ASCII!
ACALL PUTCH ; AND NOW ITS ON ITS WAY.

MOV A,TMP ; GET THE LOW NIBBLE NOW
ANL A,#0FH ; NOW WE REALLY HAVE JUST A NIBBLE
ADD A,#90H ; 90H-99H,9AH-9FH
DA A ; 90H-99H,00H-05H
ADDC A,#40H ; D0H-D9H,41H-46H
DA A ; 30H-39H,41H-46H WHICH IS 0-9,A-F ASCII!
ACALL PUTCH ; AND NOW ITS ON ITS TOO.

MOV A,TMP ; SAVE OUR BYTE
ADD A,CKSUM ; ADD CHECK SUM TO THIS BYTE
MOV CKSUM,A ; AND SAVE IT BACK TO CKSUM
RET ;


;*****************************************************************
;
; NAME: PUTSTR
;
; ABSTRACT: TAKE THE STRING POINTED TO BY DPTR AND PRINTS IT OUT.
; THE STRING MUST BE TERMINATED BY A NULL.
;
; INPUTS: DPTR
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: A, DPTR
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: PUTCH
;
;*****************************************************************
PUTSTR: CLR A ; MAKE ADDRESS OFFSET ZERO
MOVC A,@A+DPTR ; GET NEXT CHAR TO PRINT
JZ PUTS_A ; WHEN ZERO WE ARE AT END OF STRING
ACALL PUTCH ; WRITE IT OUT
INC DPTR ; POINT TO NEXT CHAR
AJMP PUTSTR ; DO IT AGAIN
PUTS_A: RET ;


;*****************************************************************
;
; NAME: LODHEX
;
; ABSTRACT: READ AN INTEL HEX FORMAT FILE AND MOVE THE DATA TO
; MEMORY IF THIS IS FROM A LOAD COMMAND AND VERIFY
; THAT THE INTEL AND MEMORY ARE THE SAME VALUE.
;
; INPUTS: LODVER(BIT)
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: CKSUM, CURCKSUM, LEN, RECTYP, VAL
; A, DPTR
;
; ERROR EXITS: ERRREC, ERRVER, ERRCKS
;
; SUBROUTINES ACCESSED DIRECTLY: GETCH, GETBYT
;
;*****************************************************************
LODHEX: MOV (0C7H),#0AAH ; START TIMED ACCESS
MOV (0C7H),#055H ; CONTINUED
ORL (0C6H),#02H ; SET THE PAA BIT
ACALL GETCH ; REPEAT GETCH
JNB TRACE,LOD_A ; IF NOECHO THEN GOTO LOD_A
ACALL PUTCH ; PUTCH
LOD_A: CJNE A,#COLON,LODHEX ; UNTIL (CH = ':')

MOV CKSUM,#0 ; CKSUM := 0

ACALL GETBYT ;
MOV LEN,A ; LEN := GETBYT

ACALL GETBYT ;
ADD A,#20H ;Endereco deslocado,para 2000h
MOV DPH,A ;
ACALL GETBYT ;
MOV DPL,A ; ADDRESS := GETBYT*256 + GETBYT

ACALL GETBYT ;
MOV RECTYP,A ; RECTYP := GETBYT

MOV A,RECTYP ;
JZ LOD_B ; IF RECTYP = 0 THEN GOTO LOD_B
CJNE A,#01H,LOD_BR ; IF RECTYP <> 1 THEN GOTO LOD_BR

LOD_B: MOV A,LEN ;
JZ LOD_E ; IF LEN = 0 THEN GOTO LOD_E

LOD_C: MOV A,DPH ; REPEAT IF ADDRESS < 0800H THEN ERROR
CJNE A,#08,LOD_C0 ; GET DPH FOR COMPARISON
LOD_C0: JC LOD_OR ; YEP, DATA IN IN BOTTOM 2K
ACALL GETBYT ; GET NEXT BYTE
MOV VAL,A ; VAL := GETBYT
JB LODVER,LOD_D ; IF (VERIFY) THEN GOTO LOD_C
MOVX @DPTR,A ; MEM[ADDRESS] := VAL
LOD_D: MOVX A,@DPTR ; A = MEM[ADDRESS]
CJNE A,VAL,LOD_VER ; IF (VAL<>MEM) THEN GOTO LOD_VER
INC DPTR ; INCREMENT MEMORY ADDRESS
DJNZ LEN,LOD_C ; UNTIL (LEN = 0)

LOD_E: MOV DPTR,#EM_BADCKS ; ASSUME WE WILL GET A BAD CHECKSUM
MOV A,CKSUM ; GET THE REAL CHECK SUM
CPL A ; WHICH REQUIRES THAT THE SUM BE COMPLEMENTED
INC A ; AND ONE ADDED (TWO'S COMPLEMENT)
MOV CURCKSUM,A ; AND PUT IT SOMEPLACE SAFE
ACALL GETBYT ; GET LINE CHECK SUM
CJNE A,CURCKSUM,LODERR; IF THE CALC <> LINE_CKSUM THEN JUMP ERRCKS

LOD_F: MOV A,RECTYP ; CHECK IF RECTYP = 1
CJNE A,#01H,LOD_A ; KEEP DOING IT UNTIL RECTYPE = 1.

MOV (0C7H),#0AAH ; START TIMED ACCESS
MOV (0C7H),#055H ; CONTINUED
ANL (0C6H),#0FDH ; CLEAR THE PAA
RET ; DONE WITH LOAD.

LOD_BR: MOV DPTR,#EM_BADREC ; BAD RECORD TYPE
AJMP LODERR ; PRINT IT OUT

LOD_OR: MOV DPTR,#EM_RANGE ; DATA OUT OF RANGE MESSAGE
AJMP LODERR ; PRINT IT OUT

LOD_VER: MOV DPTR,#EM_MEMVER ; MEMORY VERIFY ERROR

LODERR: MOV A,#CR ;
ACALL PUTCH ; PUT MESSAGE ON A NEW LINE
ACALL PUTSTR ;
AJMP LODHEX ; START WORK ON A NEW LINE


;*****************************************************************
;
; NAME: GETBYT
;
; ABSTRACT: GET TWO CHARACTERS FROM GETCH. THEY SHOULD BOTH
; BE HEX CHARACTERS. CONVERT THEM TO BINARY.
; ADD THE VALUE TO A RUNNING TOTAL IN CKSUM.
; --------------------------------------------------
; --- VERY IMPORTANT NOTE: -------------------------
; --------------------------------------------------
; IF EITHER OF THE TWO CHARACTERS IS NOT A HEX CHAR,
; DO SOMETHING STRANGE: POP THE STACK OF THE RETURN
; ADDRESS AND JUMP INTO THE LOAD HEX ERROR REPORTING
; CODE. THIS SIMPLIFIES ERROR CHECKING.
; --------------------------------------------------
;
; INPUTS: NONE
;
; OUTPUTS: A
;
; VARIABLES MODIFIED: A, TMP, CKSUM
;
; ERROR EXITS: DIRECT JUMP TO LOD_ERR
;
; SUBROUTINES ACCESSED DIRECTLY: GETCH, ISHEXCH, PUTCH
;
;*****************************************************************
GETBYT: ACALL GETCH ; GET A BYTE INTO A
JNB TRACE,GETB_A ; IF TRACE IS ON
ACALL PUTCH ; THEN ECHO IT.
GETB_A: ACALL ISHEXCH ; CONVERT CHAR TO HEX IF POSSIBLE
JNB HEXCH,GETB_E ; GOT AN ERROR, SO GO DO IT
SWAP A ; SHIFT LEFT INTO HIGH NIBBLE
MOV TMP,A ; AND SAVE IT IN TEMPORARY SPACE

ACALL GETCH ; GET A THE SECOND BYTE INTO A
JNB TRACE,GETB_B ; IF TRACE IS ON
ACALL PUTCH ; THEN ECHO IT.
GETB_B: ACALL ISHEXCH ; CONVERT CHAR TO HEX IF POSSIBLE
JNB HEXCH,GETB_E ; GOT AN ERROR, SO GO DO IT

ORL A,TMP ; GET HIGH NIBBLE AND RETURN
MOV TMP,A ; SAVE OUR BYTE (PUSH IS BETTER)
ADD A,CKSUM ; ADD CKSUM TO THIS BYTE
MOV CKSUM,A ; AND SAVE IT BACK TO CKSUM
MOV A,TMP ; AND RECOVER OUR BYTE (PUSH THEN POP)
RET ;
;------------------------------------------------------------------
; THIS IS VERY UNUSUAL CODE. POP THE RETURN STACK AND JUMP TO
; THE ERROR REPORTING CODE IN LODHEX. BE SURE TO NOTICE THERE IS
; NO RETURN, BUT A JUMP INSTEAD.
;------------------------------------------------------------------
GETB_E: POP ACC ; CLEAR HIGH BYTE OF RETURN ADDRESS
POP ACC ; CLEAR LOW BYTE OF RETURN ADDRESS
MOV DPTR,#EM_NOTHEX ; FOUND A NON HEX CHARACTER
AJMP LODERR ; HANDLE ERROR STUFF HERE.


;*****************************************************************
;
; NAME: DMPHEX (START, STOP, CMP)
;
; ABSTRACT: WRITE AN INTEL HEX FORMAT FILE.
;
; INPUTS: START_L, START_H, STOP_L, STOP_H, CMD_L, CMP_H
;
; OUTPUTS: NONE
;
; VARIABLES MODIFIED: CKSUM, LEN, VAL
; CMP_L, CMP_H, DIFF_L, DIFF_H
; A, DPTR
;
; ERROR EXITS: NONE
;
; SUBROUTINES ACCESSED DIRECTLY: PUTCH, PUTBYT, PUTSTR
;
;*****************************************************************
DMPHEX: CLR C ;
MOV A,STOP_L ;
SUBB A,DPL ;
MOV DIFF_L,A ;
MOV A,STOP_H ;
SUBB A,DPH ;
MOV DIFF_H,A ; DIFF := STOP - INDEX

JNZ DMP_B ; DIFF > 255
MOV A,DIFF_L ;
ANL A,#0E0H ;
JNZ DMP_B ; DIFF > 31
MOV LEN,DIFF_L ; LEN := DIFF (0 <= DIFF < 32)
INC LEN ; WE WANT TO MOVE ONE MORE BYTE THAN LEN
AJMP DMP_C ;

DMP_B: MOV LEN,#020H ; LEN := 32
DMP_C: MOV CKSUM,#0 ; CKSUM := 0
MOV A,#CR ;
ACALL PUTCH ; START RECORD ON A NEW LINE
MOV A,#COLON ;
ACALL PUTCH ; HEADER CHARACTER
MOV A,LEN ;
ACALL PUTBYT ; LENGTH
MOV A,DPH ;
ACALL PUTBYT ; ADDRESS (HI BYTE)
MOV A,DPL ;
ACALL PUTBYT ; ADDRESS (LOW BYTE)
CLR A ;
ACALL PUTBYT ; RECORD TYPE

DMP_D: MOVX A,@DPTR ; REPEAT A := MEM[DPTR]
ACALL PUTBYT ; WRITE IT OUT
INC DPTR ; ++INDEX
DJNZ LEN,DMP_D ; UNTIL (LEN = 0);

MOV A,CKSUM ; DO A TWO'S COMPLEMENT OF CKSUM BY
CPL A ; COMPLEMENTING
INC A ; AND ADDING ONE
ACALL PUTBYT ; CKSUM
;
MOV A,CMP_H ; LOOK AND SEE IF WE HAVE MORE TO WRITE
CJNE A,DPH,DMPHEX ; STILL MORE BYTES TO READ.
MOV A,CMP_L ;
CJNE A,DPL,DMPHEX ; YEP, STILL HAVE SOME MORE.

MOV A,#CR ;
ACALL PUTCH ; START ON A NEW LINE
MOV DPTR,#ENDREC ; ADDRESS OF INTEL HEX END RECORD
ACALL PUTSTR ; PUT OUT THE STRING

RET ;


;*****************************************************************
; DATA DEFINITIONS
;*****************************************************************
ENDREC DB ':00000001FF', CR, 0
BACKUP DB BS, ' ', BS, 0
PROMPT DB CR, '> ', 0
SLMSG DB CR, 'HEX LOADER/DUMPER VER 1.0', 0
ONMSG DB 'ON', 0
OFFMSG DB 'OFF', 0

EM_BADCMD DB '<ILLEGAL_COMMAND>', 0
EM_EXTARG DB '<EXTRA_ARGUMENTS_FOUND>', 0
EM_ARGREQ DB '<ARGUMENT_REQUIRED>', 0
EM_ILLOPT DB '<ILLEGAL_OPTION>', 0
EM_BADREC DB '<BAD_RECORD>', 0
EM_BADCKS DB '<BAD_CHECK_SUM>', 0
EM_MEMVER DB '<VERIFY>', 0
EM_NOTHEX DB '<NON_HEX_CHARACTER>', 0
EM_RANGE DB '<OUT_OF_RANGE>', 0
END

List of 7 messages in thread
TopicAuthorDate
Boot loading code to FLASH via Serial            01/01/70 00:00      
   RE: Boot loading code to FLASH via Serial            01/01/70 00:00      
      RE: Boot loading code to FLASH via Serial            01/01/70 00:00      
   RE: Boot loading code to FLASH via Serial            01/01/70 00:00      
      RE: Boot loading code to FLASH via Serial            01/01/70 00:00      
         RE: Boot loading code to FLASH via Serial            01/01/70 00:00      
            RE: Boot loading code to FLASH via Serial            01/01/70 00:00      

Back to Subject List