RegBase: equ $0000 ; include "..\DP256Reg\SCI.Asm" include "..\DP256Reg\CRG.Asm" include "..\DP256Reg\MEBI.Asm" include "..\DP256Reg\Flash.Asm" include "..\DP256Reg\MMC.Asm" ; OscClk: equ 8000000 Eclock: equ 24000000 ; final E-clock frequency (PLL) RefClock: equ 8000000 ; REFDVVal: equ (OscClk/RefClock)-1 SYNRVal: equ (Eclock/RefClock)-1 if OscClk>12800000 FCLKDIVVal: equ (OscClk/200000/8)+FDIV8 else FCLKDIVVal: equ (OscClk/200000) endif ; Baud115200: equ Eclock/16/115200 Baud57600: equ Eclock/16/57600 ; value for baud register, based on clock frequency. Baud38400: equ Eclock/16/38400 Baud9600: equ Eclock/16/9600 ; value for baud register, based on clock frequency. ; ATDDIEN0 equ $008d PortAD0: equ $008f ATDDIEN1 equ $012d PortAD1 equ $012f PARTID: equ $001a ; Dx128ID: equ $01 FlashStart: equ $8000 ; start address of the flash window. EEStart: equ $400 BootBlkSize: equ 4096 ; Erase protected bootblock size. StackTop: equ $ff80 ; stack location after RAM is moved. RAMBoot256: equ $3000 RAMBoot128: equ $1000 SectorSize: equ 512 ; size of a Flash Sector. PPAGESize: equ 16384 ; mSDlyCnt: equ Eclock/4000 ; SRecLow256: equ $c0000 SRecLow128: equ $0e SRecHi: equ $ff000 ; S0RecType: equ '0' S1RecType: equ '1' S2RecType: equ '2' S8RecType: equ '8' S9RecType: equ '9' ; FEraseError: equ 1 ; Flash failed to erase. SRecRngErr: equ 2 ; S-Record out of range FlashPrgErr: equ 3 ; Flash programming error. EEraseError: equ 4 ; EEPROM Failed to erase. BadHexError: equ 5 ; Bad Hex Data. CheckSumError: equ 6 ; S-Record checksum error SRecDataErr: equ 7 ; Received S-Record contained an odd number of data bytes. SRecAddrErr: equ 8 ; S-Record Address is odd. SRecLenErr: equ 9 ; S-Record is too long. ; ;************************************************************************************************************* ; ; org $f000 ; ; BootStart: bra OverGlobals ; SRecLow: dc.b SRecLow256 NumFBlocks: dc.b 3 ; number of Flash blocks to perform a mass erase on. PPAGEBase: dc.b $30 ; OverGlobals: ldaa #$03 ; enable the digital input buffer for bit 0 & 1 of staa ATDDIEN0 ; A2D #0 port. nop nop ldaa PortAD0 ; get PortAD0 value. anda #$03 ; mask off all but bit 0. cmpa #$01 ; jump to internal EEPROM? beq JumpEE ; yes. ; cmpa #$03 ; should we execute the bootloader? beq Boot ; yes. DEBUG12: jmp [Reset-BootBlkSize,pcr] ; no. jump to the users program pointed to by the the secondary ; reset vector. JumpEE: ldab PARTID cmpb #Dx128ID beq JumpEE128 jmp EEStart JumpEE128: ldab #$20 ; move the RAM to $2000 (so the EEPROM becomes visible). stab INITRM jmp EEStart ; then jump to the start of internal EEPROM (above the I/O registers). ; Boot: clr COPCTL ; disable watchdog ; BootCopy: lds #StackTop ; initialize the stack pointer ldx #BootStart ; point to the start of the Flash bootloader in Flash. ldy #RAMBoot256 ; point to the start of on-chip RAM. ldab PARTID cmpb #Dx128ID bne On256KPart ldy #RAMBoot128 ; point to the start of on-chip RAM. On256KPart: ldd #BootLoadEnd ; calculate the size of the bootloader code. subd #BootStart MoveMore: movb 1,x+,1,y+ ; move a byte of the bootloader into RAM. dbne d,MoveMore ; dec byte count, move till done. ; ldab #$e0+RAMHAL ; write to the INITRM register to overlay the Flash bootblock with RAM. ; if *&$0001<>0 nop endif ; stab >INITRM ; this instruction MUST use extended addressing an be aligned to an even byte boundary. ; ldab PARTID cmpb #Dx128ID bne On256KPart2 ldab #SRecLow128 stab SRecLow,pcr ldab #1 stab NumFBlocks,pcr ldab #$38 stab PPAGEBase ; On256KPart2: ldab #REFDVVal ; set the REFDV register to give us an 8.0 MHz reference. stab REFDV ldab #SYNRVal ; set the SYNR register to give us a 24.0 MHz E-clock. stab SYNR nop ; nops required for bug in initial silicon. nop nop nop brclr CRGFLG,#LOCK,* ; wait here till the PLL is locked. bset CLKSEL,#PLLSEL ; switch the bus clock to the PLL. ; ldab #FCLKDIVVal ; value for the Flash & EEPROM clock divider register. stab FCLKDIV stab ECLKDIV ; ldd #Baud9600 ; set SCI to 9600 baud @ 24.0 MHz jsr SCIInit,pcr ; go initialize the SCI. cli ; leax SignOn,pcr ; get the bootloader signon message jsr OutStr,pcr ; send it to the terminal. CmdLoop: clr ErrorFlag,pcr ; clear the global error flag. leax BLPrompt,pcr ; get the bootloader prompt bsr PromptResp ; go display the prompt & get a 1 character response. cmpb #$61 ; do a range check. less than 'a'? blo CmdLoop ; yes. just re-display the prompt. cmpb #$64 ; greater than 'd'? bhi CmdLoop ; yes. just re-display the prompt. andb #$0f ; no. mask off the upper nybble. decb ; reduce by 1 for indexing into the command offset table. lslb ; mult by 2 as each cmd table entry is a 2 byte address. leax CmdTable,pcr ; point to the command table. ldd b,x ; get the offset from the beginning of the table to the command. jsr d,x ; execute the command. ldab ErrorFlag,pcr ; error executing the command? beq CmdLoop ; no. go display the prompt, wait for entered command. decb ; subtract 1 from the error number for indexing. lslb ; multiply by 2 because each address in the table is 2 bytes. leax ErrorTable,pcr ; yes. point to the error table. ldd b,x ; get the offset from the start of the table to the string. leax d,x ; calculate the address of the error string from the table. jsr OutStr,pcr ; send error message to the terminal. bsr CmdAbort bra CmdLoop ; go display the prompt. ; ;************************************************************************************************************* ; mSCount: ds.w 1 ; CmdAbort: bra ClrmSCount ; begin by clearing the mS counter. CmdAbort1: jsr SCIGetBuf,pcr ; any characters in the Rx buffer? beq CmdAbort2 ; no. go delay for 1 mS, check the mS count. jsr getchar,pcr ; yes. get a character. ClrmSCount: clra ; zero to acc d. clrb std mSCount,pcr ; init the mS counter bra CmdAbort1 ; go see if there are any more. ; CmdAbort2: bsr mSDelay ; delay 1 mS. ldd mSCount,pcr ; get the mS count. addd #1 ; add 1 to the count. std mSCount,pcr ; save result. cpd #500 ; delayed 500 mS w/o receiving a character? bls CmdAbort1 ; no. go see if we received any characters during the 1 mS delay. rts ; yes. return. ; mSDelay: ldx #mSDlyCnt ; load 1mS delay count into x mSDelayLoop: nop ; decrement count dbne x,mSDelayLoop ; loop till done. rts ; return. ; ;************************************************************************************************************* ; PromptResp: jsr OutStr,pcr ; send prompt to the terminal. jsr getchar,pcr ; go get the user's choice. jsr putchar,pcr ; echo it. pshb ; save it. leax CrLfStr,pcr ; go to the next line. jsr OutStr,pcr pulb ; restore the entered character. rts ; ;************************************************************************************************************* ; CmdTable: dc.w EraseFlash-CmdTable ; cmd table entry for 'Erase Flash' command. dc.w ProgFlash-CmdTable ; cmd table entry for 'Program Flash' command. dc.w SetBaud-CmdTable ; cmd table entry for 'Set Baud Rate' command. dc.w EraseEE-CmdTable ; cmd table entry for 'Erase EEPROM' command. ; SignOn: dc.b $0d,$0a,"D-Bug12 Bootloader v1.0.0",$0d,$0a,0 ; BLPrompt: dc.b $0d,$0a,"a) Erase Flash",$0d,$0a dc.b "b) Program Flash",$0d,$0a dc.b "c) Set Baud Rate",$0d,$0a dc.b "d) Erase EEPROM",$0d,$0a dc.b "? ",0 ; CrLfStr: dc.b $0d,$0a,0 ; BaudPrompt: dc.b $0d,$0a,"1) 9600",$0d,$0a dc.b "2) 38400",$0d,$0a dc.b "3) 57600",$0d,$0a dc.b "4) 115200",$0d,$0a dc.b "? ",0 ; BaudChgPrompt: dc.b "Change Terminal BR, Press Return",0 ; ErrorTable: dc.w FNotErasedStr-ErrorTable dc.w SRecRngStr-ErrorTable dc.w FlashPrgErrStr-ErrorTable dc.w ENotErasedStr-ErrorTable dc.w BadHexErrorStr-ErrorTable dc.w ChkSumErrorStr-ErrorTable dc.w SRecDataErrStr-ErrorTable dc.w SRecAddrErrStr-ErrorTable dc.w SRecLenErrStr-ErrorTable ; FNotErasedStr: dc.b $0d,$0a,"Flash Not Erased",$0d,$0a,0 SRecRngStr: dc.b $0d,$0a,"S-Record out of Range",$0d,$0a,0 FlashPrgErrStr: dc.b $0d,$0a,"Flash Programming Error",$0d,$0a,0 ENotErasedStr: dc.b $0d,$0a,"EEPROM Not Erased",$0d,$0a,0 BadHexErrorStr: dc.b $0d,$0a,"Bad Hex Data",$0d,$0a,0 ChkSumErrorStr: dc.b $0d,$0a,"S-Record Checksum Error",$0d,$0a,0 SRecDataErrStr: dc.b $0d,$0a,"S-Record Code/Data Length Is Odd",$0d,$0a,0 SRecAddrErrStr: dc.b $0d,$0a,"S-Record Address Is Odd",$0d,$0a,0 SRecLenErrStr: dc.b $0d,$0a,"S-Record Code/Data Field Too Long",$0d,$0a,0 ; ;************************************************************************************************************* ; EraseEE: ldab #ERASE+MASS ; perform a bulk erase. std EEStart ; latch address for erase command. stab ECMD ldab #CBEIF stab ESTAT ; initiate the erase command. brclr ESTAT,#PVIOL+ACCERR,EEErCmdOK ; continue if the privliage violation & Access error flags are clear. ldaa #EEraseError bra SaveEEError EEErCmdOK: brclr ESTAT,#CCIF,* ; wait until the command has completed. ldab #ERVER+MASS ; perform an erase verify. std EEStart ; latch address for erase verify command. stab ECMD ldab #CBEIF stab ESTAT ; initiate the erase command. brclr ESTAT,#PVIOL+ACCERR,EEVerfCmdOK ; indicate failure if the privliage violation or Access error flags are set. EENotErased: ldaa #EEraseError bra SaveEEError EEVerfCmdOK: brclr ESTAT,#CCIF,* ; wait until the command has completed. brclr ESTAT,#BLANK,EENotErased ; flag a not erased error if the BLANK bit did not set. ldab #BLANK ; clear the BLANK status bit. stab ESTAT clra SaveEEError: staa ErrorFlag,pcr ; put error code where pod can access it. rts ; if we fall through, we automatically return a non-zero condition. ; ;************************************************************************************************************* ; SetBaud: leax BaudPrompt,pcr ; get the bootloader prompt jsr PromptResp,pcr ; go display the prompt & get a 1 character response. cmpb #$31 ; do a range check. less than '1'? blo SetBaud ; yes. just re-display the prompt. cmpb #$34 ; greater than '4'? bhi SetBaud ; yes. just re-display the prompt. andb #$0f ; no. mask off the upper nybble. decb lslb leax BaudTable,pcr ldd b,x pshd leax BaudChgPrompt,pcr jsr OutStr,pcr ; send it to the terminal. brclr SCI0SR1,#TC,* ; wait until the last character is sent until we change the baud rate. puld std SCI0BD jsr getchar,pcr ; go get the user's choice. leax CrLfStr,pcr ; go to the next line. jsr OutStr,pcr rts ; BaudTable: dc.w Baud9600 dc.w Baud38400 dc.w Baud57600 dc.w Baud115200 ; ;************************************************************************************************************* ; ProgFlash: ldab #PVIOL+ACCERR ; if either the PVIOL or ACCERR bit is set from a previous error, stab FSTAT ; reset them so we can program the Flash. bra FSkipFirst ; don't send the progress character the first time. FSendPace: ldab #'*' ; the ascii asterisk is the progress character. jsr putchar,pcr ; let the user know we've processed an S-Record. FSkipFirst: jsr GetSRecord,pcr ; go get an S-Record. lbne ProgRtn ; non-zero condition means there was an error brclr DataBytes,pcr,#$01,DataLOK ; is the received S-Record length even? ldaa #SRecDataErr ; no. report the error. bra ProgDone ; stop programming. DataLOK: brclr LoadAddr+2,pcr,#$01,SRecOK ; is the received S-Record address even? ldaa #SRecAddrErr ; no. report the error. bra ProgDone ; stop programming. ; SRecOK: ldab RecType,pcr ; check the record type. cmpb #S1RecType ; S1 record received? bne ChckNext ; no. check for S0, S2, S8 & S9 records. ldaa #SRecRngErr ; yes. only S2 records w/ load addresses $C0000 - $FEFFF allowed. bra ProgDone ; save error & return. ; ChckNext: cmpb #S9RecType ; was it an S9 record? beq ProgRtn ; yes. we're done. cmpb #S8RecType ; was it an S8 record? beq ProgRtn ; yes. we're done. cmpb #S0RecType ; no. was it an S0 record? beq FSendPace ; yes. just ignore it. ; ldab LoadAddr,pcr ; it was an S2 record. Get the high byte of the 24-bit address. cmpb SRecLow,pcr ; less than $c0000 or $e0000? bhs ChkHiLimit ; no. check the upper limit. BadSRecRng: ldaa #SRecRngErr ; yes. S-Record out of range. bra ProgDone ; save the error code & return. ; ChkHiLimit: ldab DataBytes,pcr ; get the number of bytes in the S-Record. clra ; zero extend it. addd LoadAddr+1,pcr ; add in the lower 16-bits of the 24-bit address. tfr d,x ; save rthe result in X. ldab LoadAddr,pcr ; get the upper 8-bits of the 24-bit address. adcb #$00 ; add in possible carry from lower 16-bits. cmpb #SRecHi>>16 ; greater than $0fxxxx? blo AddrOK ; no. S-Record within range. cpx #SRecHi&$ffff ; yes. check the lower 16- bits. Out of range? bhi BadSRecRng ; yes. S-Record out of range. ; AddrOK: ldab LoadAddr,pcr ; get upper 8-bits of 24-bit load address. exg b,y ; zero extend b into y for the 32-bit divide ldd LoadAddr+1,pcr ; get the lower 16-bits of 24-bit load address. ldx #PPAGESize ; divide the load address by the PPAGE window size. ediv addd #FlashStart ; add the PPAGE window start address to the remainder (this gives the PPAGE window load address). exg d,y ; lower byte of the quotent is the PPAGE value. stab PPAGE lsrb ; calculate the value of the block select bits based lsrb ; on bits 3:2 of the PPAGE register value. comb andb #$03 ; mask off all but the lower 2 bits. stab FCNFG ; select the block to erase. sty PPAGEWAddr,pcr ; save the PPAGE window address. jsr ProgFBlock,pcr ; no. that means it was an S1 record. go program the data into Flash. lbeq FSendPace ; zero condition means all went ok. ldaa #FlashPrgErr ProgDone: staa ErrorFlag,pcr ; put error code where pod can access it. ProgRtn: rts ; if we fall through, we automatically return a non-zero condition. ; ;************************************************************************************************************* ; offset 0 ; NumWords: ds 1 ;LocalSize: set * ; ProgFBlock: ldab DataBytes,pcr ; get the block size. lsrb ; divide the byte count by 2 since we program a word at a time. pshb ; allocate the local. ldx PPAGEWAddr,pcr ; get the S-Record (Flash) load address. leay SRecData,pcr ; point to the received S-Record data. ProgLoop: ldd 2,y+ ; get a word from the buffer. std 2,x+ ; latch the address & data into the Flash program/erase buffers. ldab #PROG ; get the program command. stab FCMD ; write it to the command register. ldab #CBEIF ; start the command by writing a 1 to CBEIF. stab FSTAT ldab FSTAT ; check to see if there was a problem executing the command. bitb #PVIOL+ACCERR ; if either the PVIOL or ACCERR bit is set, bne Return ; return. brclr FSTAT,#CBEIF,* ; wait here till the command buffer is empty. dec NumWords,sp ; any more words to program? bne ProgLoop ; yes. continue until done. brclr FSTAT,#CCIF,* ; no. wait until all commands complete. ; ldab DataBytes,pcr ; get the block size. lsrb ; divide the byte count by 2 since we verify a word at a time. stab NumWords,sp ldx PPAGEWAddr,pcr ; get the S-Record (Flash) load address. leay SRecData,pcr ; point to the received S-Record data. VerfLoop: ldd 2,y+ ; get a word from the buffer. cpd 2,x+ ; same as the word in Flash? bne Return ; no. return w/ an error (!= condition). dec NumWords,sp ; yes. done comparing all words? bne VerfLoop ; no. compare some more. ; Return: pulb ; deallocate the local. rts ; return. ; ; ;************************************************************************************************************* ; offset 0 ; BlockCnt: ds.b 1 ; number of 64K blocks to erase. ; ;LocalSize: set * ; EraseFlash: ldab NumFBlocks,pcr pshb ldab PPAGEBase,pcr EraseLoop: stab PPAGE ; write the PPAGE register to allow writes to the proper Flash block. lsrb ; calculate the value of the block select bits based lsrb ; on bits 3:2 of the PPAGE register. comb andb #$03 stab FCNFG ; select the block to erase. ldx #FlashStart ; latch address for erase command ldab #ERASE+MASS ; perform a bulk erase. bsr EraseCmd bne SaveEFError ldab #ERVER+MASS ; perform an erase verify. std 0,x ; latch address for erase verify command. stab FCMD ; put command in the command buffer. ldab #CBEIF stab FSTAT ; initiate the erase command. brclr FSTAT,#PVIOL+ACCERR,VerfCmdOK ; indicate failure if the privliage violation or Access error flags are set. NotErased: ldaa #FEraseError bra SaveEFError VerfCmdOK: brclr FSTAT,#CCIF,* ; wait until the command has completed. brclr FSTAT,#BLANK,NotErased ; flag a not erased error if the BLANK bit did not set. ldab #BLANK ; clear the BLANK status bit. stab FSTAT ldab PPAGE ; get the current PPAGE value. addb #$04 ; add 4 to select the next 64K Flash block. dec BlockCnt,sp ; done with 3 of the 64K blocks? bne EraseLoop ; no. bsr EraseBlk0 ; block 0 must be erased seperately because it contains the bootblock. SaveEFError: staa ErrorFlag,pcr ; put error code where pod can access it. FEEDone: pulb rts ; return. ; ; EraseBlk0 erases Flash block 0 a sector (512 bytes) at a time because the bootblock is protected. ; offset 0 ; PPAGECnt: ds.b 1 ; number of 16K PPAGE windows that will be completely erased. ; ;LocalSize: set * ; EraseBlk0: movb #3,1,-sp ; 3 16K PPAGE windows will be completely erased. stab PPAGE ; PPAGE for first 16K page of block 0. clr FCNFG ; set block select bits to 0. EraseBlk0Loop: ldx #FlashStart ; point to the start of the PPAGE window. ldab #PPAGESize/SectorSize ; number of sectors in a PPAGE window. bsr EraseSectors ; go erase the PPAGE window a sector at a time. bne BadBlk0 ; non-zero value returned in A indiciates a sector didn't erase. inc PPAGE ; go to the next PPAGE. dec PPAGECnt,sp ; done with all full PPAGE blocks? bne EraseBlk0Loop ; no. erase more blocks. ldx #FlashStart ; yes. point to the start of the PPAGE window. ldab #(PPAGESize-BootBlkSize)/SectorSize ; number of sectors in PPAGE $3F minus the bootblock. bsr EraseSectors ; erase all sectors outside the bootblock. BadBlk0: pulb ; remove the page count from the stack. rts ; ; Erases 'b' (accumulator) sectors beginning at address 'x' (index register) ; EraseSectors: exg b,y ; put the sector count in y. EraseSectLoop: ldab #ERASE ; perform a sector erase. bsr EraseCmd beq DoEraseVerf ; if no problem with the erase command, do a verify. Rtn: rts ; if problem, return with an error code in a. DoEraseVerf: bsr VerfSector bne Rtn ; if problem, return with an error code in a. leax SectorSize,x ; point to the next sector. dbne y,EraseSectLoop ; continue to erase remaining sectors. rts ; done. return. ; ; Erases a block or sector of Flash ; EraseCmd: std 0,x ; latch address for erase command. stab FCMD ldab #CBEIF stab FSTAT ; initiate the erase command. brclr FSTAT,#PVIOL+ACCERR,EraseCmdOK ; continue if the privliage violation & Access error flags are clear. ldaa #FEraseError rts EraseCmdOK: brclr FSTAT,#CCIF,* ; wait until the command has completed. clra rts ; ; Verify that a sector was properly erased ; Must verify a word at a time because the built in verify command only works on a block (64K) ; VerfSector: pshx ; save the base address of the sector. pshy ; save the sector count. ldy #SectorSize/2 ; we'll check 2 bytes at a time. VerfSectLoop: ldd 2,x+ ; get a byte from the sector. ibeq d,WordOK ldaa #FEraseError bra SectRtn WordOK: dbne y,VerfSectLoop ; yes. dec the sector word count. clra SectRtn: puly ; restore the sector count. pulx ; restore the base address of the sector. rts ; return. ; ;************************************************************************************************************* ; offset 0 ; SRecBytes: ds.b 1 ; number of bytes in the address, data & checksum fields. CheckSum: ds.b 1 ; used for calculated checksum. ; ;LocalSize: set * ; GetSRecord: equ * leas -2,sp ; allocate stack space for variables. leax LoadAddr,pcr ; point to the code/data buffer. clr 0,x ; clear the upper byte of the 24 bit address (in case we receive a 16-bit address). LookForSOR: jsr getchar,pcr ; get a character from the receiver. cmpb #'S' ; start-of-record character? bne LookForSOR ; no. go back & get another character. jsr getchar,pcr ; yes. we found the start-of-record character (ASCII 'S') cmpb #S0RecType ; found an S0 (header) record? bne CheckForS9 ; no. go check for an S9 record. stab RecType,pcr ; yes. set the record type to '0' ldaa #3 staa DataBytes,pcr bra RcvSRec ; go receive the S0 record. ; CheckForS9: cmpb #S9RecType ; found an S9 (end) record? bne ChkForS1 ; no. go check for an S1 record. bra Addr16 ; go receive the S9 record. ; ChkForS1: cmpb #S1RecType ; found an S1 (code/data) record? bne ChkForS2 ; no. false start-of-record character received. go check for another. Addr16: inx ldaa #3 staa DataBytes,pcr bra SaveRecType ; go receive the S9 record. ; ChkForS2: cmpb #S2RecType ; S2 record? (24-bit load address) bne ChkForS8 bra Addr24 ; go receive the S9 record. ; ChkForS8: cmpb #S8RecType ; no. s8 record? (24-bit transfer address) bne LookForSOR ; no. go look for next Start of Record. Addr24: ldaa #4 staa DataBytes,pcr SaveRecType: stab RecType,pcr ; yes. save the record type. ; RcvSRec: jsr GetHexByte,pcr ; get the S-Record length byte. beq HexOK ; return if there was an error. BadHex: ldab #BadHexError bra SaveError HexOK: stab SRecBytes,sp ; save the total number of S-Record bytes we are to receive. stab CheckSum,sp ; initialize the checksum calculation with the data byte count subb DataBytes,pcr ; subtract the load address & checksum field from the data field count. stab DataBytes,pcr ; save the code/data field size. cmpb #64 ; is the code/data field <= 64? bls RcvData ; yes. it can be received. ldaa #SRecLenErr ; no. the code/data field is limited to 64 bytes. bra SaveError ; return with the error code in a. RcvData: jsr GetHexByte,pcr ; get an S-Record data byte. bne BadHex ; return if there was an error. stab 1,x+ ; save the byte in the data buffer. addb CheckSum,sp ; add the byte into the checksum. stab CheckSum,sp ; save the result. dec SRecBytes,sp ; received all the S-Record bytes? bne RcvData ; no. go get some more. inc CheckSum,sp ; if checksum was ok, the result will be zero. beq SRecRtn ldab #CheckSumError SaveError: stab ErrorFlag,pcr SRecRtn: leas 2,sp rts ; ;************************************************************************************************************* ; IsHex: equ * cmpb #'0' ; less than ascii hex zero? blo NotHex ; yes. character is not hex. return a non-zero ccr indication. cmpb #'9' ; less than or equal to ascii hex nine? bls IsHex1 ; yes. character is hex. return a zero ccr indication. cmpb #'A' ; less than ascii hex 'A'? blo NotHex ; yes. character is not hex. return a non-zero ccr indication. cmpb #'F' ; less than or equal to ascii hex 'F'? bhi NotHex ; yes. character is hex. return a non-zero ccr indication. IsHex1: orcc #$04 ; no. return a zero ccr indication. NotHex: rts ; ;************************************************************************************************************* ; GetHexByte: equ * jsr getchar,pcr ; get the upper nybble from the SCI. bsr IsHex ; valid hex character? beq OK1 ; yes. go convert it to binary. rts ; no. return with a non-zero ccr indication. OK1: bsr CvtHex ; convert the ascii-hex character to binary. ldaa #16 ; shift it to the upper 4-bits. mul pshb ; save it on the stack. jsr getchar,pcr ; get the lower nybble from the SCI. bsr IsHex ; valid hex character? beq OK2 ; yes. go convert it to binary. pulb ; remove saved upper byte from the stack. rts ; no. return with a non-zero ccr indication. OK2: bsr CvtHex ; convert the ascii-hex character to binary. addb 1,sp+ ; add it to the upper nybble. clra ; simple way to set the Z ccr bit. rts ; return. ; ;************************************************************************************************************* ; CvtHex: subb #'0' ; subtract ascii '0' from the hex character. cmpb #$09 ; was it a decimal digit? bls CvtHexRtn ; yes. ok as is. subb #$07 ; no. it was an ascii hex letter ('A' - 'F'). CvtHexRtn: rts ; ;************************************************************************************************************* ; OutStr: equ * ; send a null terminated string to the display. ldab 1,x+ ; get a character, advance pointer, null? beq OutStrDone ; yes. return. jsr putchar,pcr ; no. send it out the SCI. bra OutStr ; go get the next character. OutStrDone: rts ; ; ;************************************************************************************************************* ; RxBufSize: equ 64 TxBufSize: equ 32 ; XOnCount: equ RxBufSize-8 ; number of bytes avail. in the Rx queue before an XOn can be sent. XOffCount: equ (RxBufSize-16)+2 ; number of bytes remaining in the Rx queue when an XOff is sent. ; XOn: equ $11 ; ASCII DC1 XOff: equ $13 ; ASCII DC3 ; RxBuff: dcb RxBufSize,0 ; receive queue size. TxBuff: dcb TxBufSize,0 ; transmit queue size. RxIn: dc.b 0 ; next available location in the Rx queue. RxOut: dc.b 0 ; next character to be removed from the Rx queue. TxIn: dc.b 0 ; next available location in the Tx queue TxOut: dc.b 0 ; next character to be sent from the Tx queue. RxBAvail: dc.b 0 ; number of bytes left in the Rx queue. TxBAvail: dc.b 0 ; number of bytes left in the Tx queue. XOffSent: dc.b 0 ; if != 0, an XOff has been sent. SendXOff: dc.b 0 ; flag to TXISR to send an XOff to the host. ; ; ;************************************************************************************************************* ; SCIInit: std SCI0BD ; initialize the baud rate register. ldab #RxBufSize ; init number of available Rx stab RxBAvail,pcr ; queue bytes to RxBuffSize. ldab #TxBufSize ; init number of available Tx stab TxBAvail,pcr ; queue bytes to TxBuffSize. ldab #TE+RE+RIE ; get bit mask for Tx, Rx & Rx interrupt. stab SCI0CR2 ; enable Tx & Rx & Rx interrupts. leax SCIISR,pcr ; setup SCI interrupt vector to point to the stx SCI0 ; bootloader's SCI interrupt service routine. rts ; done. ; ;************************************************************************************************************* ; SCIISR: brclr SCI0CR2,#RIE,ChkRxInts ; Rx interrupts enabled? brset SCI0SR1,#RDRF,RxIRQ ; yes. if RDRF flag set, service Rx interrupt. brset SCI0SR1,#OR,RxIRQ ; yes. if OR flag set, service Rx interrupt. ChkRxInts: brclr SCI0CR2,#TIE,NoSCIInt ; Tx interrupts enabled? brset SCI0SR1,#TDRE,TxIRQ ; Yes. if TDRE is set, service Tx interrupt NoSCIInt: rti ; return w/o any action. ; ;************************************************************************************************************* ; RxIRQ: tst XOffSent,pcr ; was an XOff previously sent to the host? bne AlreadySent ; yes. go place the received character in the Rx queue. ldaa RxBAvail,pcr ; no. get the number of bytes available in the Rx queue. cmpa #XOffCount ; more than enough space to receive a FIFO full of data from the host? bhi AlreadySent ; yes. go place the received byte in the Rx queue. inc XOffSent,pcr ; set the 'XOff Sent' flag inc SendXOff,pcr ; set flag indicating to TxISR to send an XOff to the host. bset SCI0CR2,#TIE ; enable Tx interrupts. ; AlreadySent: tst RxBAvail,pcr ; any room left in the Rx queue? beq Buffull ; no. just throw the character away. dec RxBAvail,pcr ; yes. there'll be one less now. leax RxBuff,pcr ; point to the physical start of the Rx queue. ldaa RxIn,pcr ; get the index for the next available queue location. ldab SCI0DRL ; get the received character. stab a,x ; place it in the queue. inca ; next available queue location. cmpa #RxBufSize ; wrap around to start of queue? blo NoRxWrap ; no. just update the index. clra ; yes. start at begining of queue. NoRxWrap: staa RxIn,pcr ; update the next available queue location index. rti ; return from the SCI Rx interrupt. ; Buffull: ldab SCI0DRL ; the queue was full. get character & throw it away. rti ; return. ; ;************************************************************************************************************* ; TxIRQ: tst SendXOff,pcr ; send an XOff to the host? beq NoXOff ; no. just xmit the next ldab #XOff ; get the XOff character stab SCI0DRL ; send it. clr SendXOff,pcr ; clear the XOff send flag. bra ChckTxBuff ; go check to see if we need to disable Tx interrupts ; NoXOff: leax TxBuff,pcr ; point to the physical start of the Tx queue. ldaa TxOut,pcr ; get the index for the next character to send. ldab a,x ; get the data. stab SCI0DRL ; send it. inca ; advance to next character to send. cmpa #TxBufSize ; reached the end of the queue? blo NoTxWrap ; no. clra ; yes. wrap to the start. NoTxWrap: staa TxOut,pcr ; update the queue index. inc TxBAvail,pcr ; one more byte available in the queue. ChckTxBuff: ldab TxBAvail,pcr ; get the count of avail bytes in the Tx queue. cmpb #TxBufSize ; any more characters to send? bne TxRTI ; yes. more characters to send, don't disable Tx interrupts. bclr SCI0CR2,#TIE ; yes. queue is empty turn off TDRE interrupts. TxRTI: rti ; return. ; ;************************************************************************************************************* ; SCIGetBuf: ldab #RxBufSize ; are there any characters in the Rx queue? subb RxBAvail,pcr rts ; return number available. ; ;************************************************************************************************************* ; getchar: pshx ; save the registers we'll use. psha RxChk: ldab #RxBufSize ; any characters available? subb RxBAvail,pcr beq RxChk ; no. just wait until some are. leax RxBuff,pcr ; point to the physical start of the Rx queue. ldaa RxOut,pcr ; get the index to the next available character in the Rx queue. ldab a,x ; get the character. inca ; point to the next location in the queue. cmpa #RxBufSize ; reached the end of the queue? blo NogcWrap ; no. clra ; yes. wrap to the start. NogcWrap: staa RxOut,pcr ; update the queue index. inc RxBAvail,pcr ; we removed a character from the queue, there's 1 more available. tst XOffSent,pcr ; was an XOff character previously sent by the RX ISR? beq gcReturn ; no. just return. ldaa RxBAvail,pcr ; yes. get the number of bytes available in the Rx queue. cmpa #XOnCount ; enough space available to receive more? bhs gcReturn ; no. just return. pshb ; yes. save the character we retrieved from the Rx queue. ldab #XOn ; send an XOn character to the host. bsr putchar clr XOffSent,pcr ; clear the XOff flag. pulb ; restore the character we retrieved from the Rx queue. gcReturn: pula ; restore what we saved. pulx rts ; return. ; ;************************************************************************************************************* ; putchar: pshx ; save the registers we'll use. psha TxChk: tst TxBAvail,pcr ; Any room left in the Tx queue? beq TxChk ; no. just wait here till it is. leax TxBuff,pcr ; point to the physical start of the Tx queue. ldaa TxIn,pcr ; get the index to the next available spot. stab a,x ; put the character in. inca ; point to the next available spot. cmpa #TxBufSize ; go past the end of the queue? blo NopcWrap ; no. clra ; yes. wrap around to the start. NopcWrap: staa TxIn,pcr ; update the queue index dec TxBAvail,pcr ; one less byte available in the Tx queue. bset SCI0CR2,#TIE ; enable transmitter interrupts. pula ; restore what we saved. pulx rts ; return ; ; ; BootLoadEnd: equ * ; ; ; ; Global Variable declarations ; ; ErrorFlag: ds.b 1 ; error code stored by various routines. RecType: ds.b 1 ; received record type. '0' = S0; '1' = S1; '2' = S2; '8' = S8; '9' = S9 DataBytes: ds.b 1 ; number of data bytes in the S-Record. PPAGEWAddr: ds.b 2 LoadAddr: ds.b 3 ; load address of the S-Record. SRecData: ds.b 65 ; S-Record data storage. (handle 64-byte S-Records + received checksum) ; ; ;************************************************************************************************************* ; ; This is the jump table that is used to access the secondary interrupt vector table. Each one ; of the actual interrupt vectors, begining at $ff8c, points to an entry in this table. Each jmp ; instruction uses indexed indirect program counter relative (pcr) addressing to access the ; secondary interrupt vector table that is located just below the bootblock. ; ;************************************************************************************************************* ; JPWMEShutdown: jmp [PWMEShutdown-BootBlkSize,pcr] JPortPInt: jmp [PortPInt-BootBlkSize,pcr] JMSCAN4Tx: jmp [MSCAN4Tx-BootBlkSize,pcr] JMSCAN4Rx: jmp [MSCAN4Rx-BootBlkSize,pcr] JMSCAN4Errs: jmp [MSCAN4Errs-BootBlkSize,pcr] JMSCAN4WakeUp: jmp [MSCAN4WakeUp-BootBlkSize,pcr] JMSCAN3Tx: jmp [MSCAN3Tx-BootBlkSize,pcr] JMSCAN3Rx: jmp [MSCAN3Rx-BootBlkSize,pcr] JMSCAN3Errs: jmp [MSCAN3Errs-BootBlkSize,pcr] JMSCAN3WakeUp: jmp [MSCAN3WakeUp-BootBlkSize,pcr] JMSCAN2Tx: jmp [MSCAN2Tx-BootBlkSize,pcr] JMSCAN2Rx: jmp [MSCAN2Rx-BootBlkSize,pcr] JMSCAN2Errs: jmp [MSCAN2Errs-BootBlkSize,pcr] JMSCAN2WakeUp: jmp [MSCAN2WakeUp-BootBlkSize,pcr] JMSCAN1Tx: jmp [MSCAN1Tx-BootBlkSize,pcr] JMSCAN1Rx: jmp [MSCAN1Rx-BootBlkSize,pcr] JMSCAN1Errs: jmp [MSCAN1Errs-BootBlkSize,pcr] JMSCAN1WakeUp: jmp [MSCAN1WakeUp-BootBlkSize,pcr] JMSCAN0Tx: jmp [MSCAN0Tx-BootBlkSize,pcr] JMSCAN0Rx: jmp [MSCAN0Rx-BootBlkSize,pcr] JMSCAN0Errs: jmp [MSCAN0Errs-BootBlkSize,pcr] JMSCAN0WakeUp: jmp [MSCAN0WakeUp-BootBlkSize,pcr] JFlash: jmp [Flash-BootBlkSize,pcr] JEEPROM: jmp [EEPROM-BootBlkSize,pcr] JSPI2: jmp [SPI2-BootBlkSize,pcr] JSPI1: jmp [SPI1-BootBlkSize,pcr] JIICBus: jmp [IICBus-BootBlkSize,pcr] JDLC: jmp [DLC-BootBlkSize,pcr] JSCME: jmp [SCMEVect-BootBlkSize,pcr] JCRGLock: jmp [CRGLock-BootBlkSize,pcr] JPACCBOv: jmp [PACCBOv-BootBlkSize,pcr] JModDnCtr: jmp [ModDnCtr-BootBlkSize,pcr] JPortHInt: jmp [PortHInt-BootBlkSize,pcr] JPortJInt: jmp [PortJInt-BootBlkSize,pcr] JATD1: jmp [ATD1-BootBlkSize,pcr] JATD0: jmp [ATD0-BootBlkSize,pcr] JSCI1: jmp [SCI1-BootBlkSize,pcr] JSCI0: jmp [SCI0-BootBlkSize,pcr] JSPI0: jmp [SPI0-BootBlkSize,pcr] JPACCAEdge: jmp [PACCAEdge-BootBlkSize,pcr] JPACCAOv: jmp [PACCAOv-BootBlkSize,pcr] JTimerOv: jmp [TimerOv-BootBlkSize,pcr] JTimerCh7: jmp [TimerCh7-BootBlkSize,pcr] JTimerCh6: jmp [TimerCh6-BootBlkSize,pcr] JTimerCh5: jmp [TimerCh5-BootBlkSize,pcr] JTimerCh4: jmp [TimerCh4-BootBlkSize,pcr] JTimerCh3: jmp [TimerCh3-BootBlkSize,pcr] JTimerCh2: jmp [TimerCh2-BootBlkSize,pcr] JTimerCh1: jmp [TimerCh1-BootBlkSize,pcr] JTimerCh0: jmp [TimerCh0-BootBlkSize,pcr] JRTI: jmp [RTI-BootBlkSize,pcr] JIRQ: jmp [IRQ-BootBlkSize,pcr] JXIRQ jmp [XIRQ-BootBlkSize,pcr] JSWI: jmp [SWI-BootBlkSize,pcr] JIllop: jmp [Illop-BootBlkSize,pcr] JCOPFail: jmp [COPFail-BootBlkSize,pcr] JClockFail: jmp [ClockFail-BootBlkSize,pcr] ; org $ff0d ; dc.b $cf ; setup a 4K booblock in Flash block 0. ; org $ff0f ; dc.b $fe ; org $ff8c ; PWMEShutdown: dc.w JPWMEShutdown PortPInt: dc.w JPortPInt MSCAN4Tx: dc.w JMSCAN4Tx MSCAN4Rx: dc.w JMSCAN4Rx MSCAN4Errs: dc.w JMSCAN4Errs MSCAN4WakeUp: dc.w JMSCAN4WakeUp MSCAN3Tx: dc.w JMSCAN3Tx MSCAN3Rx: dc.w JMSCAN3Rx MSCAN3Errs: dc.w JMSCAN3Errs MSCAN3WakeUp: dc.w JMSCAN3WakeUp MSCAN2Tx: dc.w JMSCAN2Tx MSCAN2Rx: dc.w JMSCAN2Rx MSCAN2Errs: dc.w JMSCAN2Errs MSCAN2WakeUp: dc.w JMSCAN2WakeUp MSCAN1Tx: dc.w JMSCAN1Tx MSCAN1Rx: dc.w JMSCAN1Rx MSCAN1Errs: dc.w JMSCAN1Errs MSCAN1WakeUp: dc.w JMSCAN1WakeUp MSCAN0Tx: dc.w JMSCAN0Tx MSCAN0Rx: dc.w JMSCAN0Rx MSCAN0Errs: dc.w JMSCAN0Errs MSCAN0WakeUp: dc.w JMSCAN0WakeUp Flash: dc.w JFlash EEPROM: dc.w JEEPROM SPI2: dc.w JSPI2 SPI1: dc.w JSPI1 IICBus: dc.w JIICBus DLC: dc.w JDLC SCMEVect: dc.w JSCME CRGLock: dc.w JCRGLock PACCBOv: dc.w JPACCBOv ModDnCtr: dc.w JModDnCtr PortHInt: dc.w JPortHInt PortJInt: dc.w JPortJInt ATD1: dc.w JATD1 ATD0: dc.w JATD0 SCI1: dc.w JSCI1 SCI0: dc.w JSCI0 SPI0: dc.w JSPI0 PACCAEdge: dc.w JPACCAEdge PACCAOv: dc.w JPACCAOv TimerOv: dc.w JTimerOv TimerCh7: dc.w JTimerCh7 TimerCh6: dc.w JTimerCh6 TimerCh5: dc.w JTimerCh5 TimerCh4: dc.w JTimerCh4 TimerCh3: dc.w JTimerCh3 TimerCh2: dc.w JTimerCh2 TimerCh1: dc.w JTimerCh1 TimerCh0: dc.w JTimerCh0 RTI: dc.w JRTI IRQ: dc.w JIRQ XIRQ: dc.w JXIRQ SWI: dc.w JSWI Illop: dc.w JIllop COPFail: dc.w JCOPFail ClockFail: dc.w JClockFail Reset: dc.w BootStart