| ??? 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 |
| Topic | Author | Date |
| 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 |



