;******************************************************************************* ;* Program : TBOOT.ASM ;* Programmer: Tony Papadimitriou <tonyp@acm.org> ;* Purpose : Always-present Tiny Bootloader ;* Language : Motorola/Freescale/NXP HC08/9S08 Assembly Language (aspisys.com/ASM8) ;* Status : Copyright (c) 2022 by Tony Papadimitriou <tonyp@acm.org> ;* Segments : RAM : Variables ;* : ROM : Code ;* Note(s) : User vectors are automatically redirected. ;******************************************************************************* #ifdef ? #Hint **************************************************** #Hint * Available conditionals (for use with -Dx option) * #Hint **************************************************** #Hint *--------------------------------------------------- #Hint * S U P P O R T E D T A R G E T S #Hint *--------------------------------------------------- #Hint * QG8..............: Target is 9S08QG8 #Hint * QE8..............: Target is 9S08QE8 #Hint * QE32.............: Target is 9S08QE32 #Hint * QE128............: Target is 9S08QE128 #Hint * DZ32.............: Target is 9S08DZ32 #Hint * DZ60.............: Target is 9S08DZ60 #Hint * FL16.............: Target is 9S08FL16 #Hint * SH8..............: Target is 9S08SH8 #Hint * QD2..............: Target is 9S08QD2 #Hint * QD4..............: Target is 9S08QD4 #Hint * AC32.............: Target is 9S08AC32 #Hint * AC96.............: Target is 9S08AC96 #Hint *--------------------------------------------------- #Hint * O P T I O N S #Hint *--------------------------------------------------- #Hint * HZ...............: MCU effective clock as Hz #Hint * KHZ..............: MCU effective clock as KHz #Hint * MHZ..............: MCU effective clock as MHz #Hint * BDIV.............: Bus divisor (where available) #Hint * FLASH_DATA_SIZE..: Flash size for user data #Hint * ALLOW_EEPROM.....: Allow EEPROM address range #Hint * NVOPT_VALUE......: Use a specific NVOPT value #Hint * HARD_FLOW_CONTROL: For RTS/CTS control #Hint * RXINV............: SCI RX line inverted #Hint * TXINV............: SCI TX line inverted #Hint * BPS..............: BPS = 3/12/24/48/96/192/384/576(00) #Hint * SCI..............: SCI = (SCI)1 or (SCI)2 or SoftSCI (-1) #Hint * ENABLE_RUN.......: Enable [R]un command #Hint * NO_IRQ...........: Disable IRQ pin test #Hint * DISABLE_SURE.....: Disable 'Sure?' message #Hint * DEBUG............: For debugging only #Hint **************************************************** #Fatal Run ASM8 -Dx (where x is any of the above) #endif BOOTROM_VERSION def 120 ;version as x.xx ;------------------------------------------------------------------------------- SCI def 1 ;SCI to use (1 or 2, -1=Software) ;------------------------------------------------------------------------------- ? macro #ifdef ~1~ FLASH_DATA_SIZE def ~2~ #endif endm @? QE128||AC96,1024 @? DZ32||DZ60,0 ; config storage in EEPROM, not Flash @? GB60,1920 FLASH_DATA_SIZE def 512 ; all others have 512 default ;------------------------------------------------------------------------------- #ifdef QE128||AC96 BOOTROM def $F800 ;These MMU versions are a bit larger #else ifdef DZ32||DZ60 BOOTROM def $FA00 ;DZ has different Flash protection #endif BOOTROM def $FC00 #ifnz BOOTROM\512 #Error BOOTROM is not on a 512-byte page boundary #endif ;------------------------------------------------------------------------------- #ifdef PRIVATE NVOPT_VALUE def %10000000 ; NVOPT transfers to FOPT on reset #endif ; |||||||| NVOPT_VALUE def %00000010 ; NVOPT transfers to FOPT on reset #ifdef DZ32||DZ60 ; |||||||| NVOPT_VALUE set NVOPT_VALUE|%00100000 ; EPGMOD = 1 (8-byte mode) #endif ; |||||||| ; ||||||++---------- SEC00 \ 00:secure 10:unsecure ; ||||||++---------- SEC01 / 01:secure 11:secure ; |||+++------------ Not Used (Always 0) ; ||+--------------- EPGMOD - EEPROM Sector Mode (DZ only) 1=8-byte mode ; |+---------------- FNORED - No Vector Redirection ; ++---------------- KEYEN - Backdoor key mechanism enable #ifndef MAP #MapOff #endif ;------------------------------------------------------------------------------- #ifndef ROM ROM equ BOOTROM ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- #ifdef QE128 HZ def 32768*512 ;MCU & Cyclone's default BDIV def 1 #ListOff #Uses qe128.inc #ListOn #endif ;------------------------------------------------------------------------------- #ifdef QE8||QE32 HZ def 32768*512 ;MCU & Cyclone's default BDIV def 1 #ListOff #ifdef QE8 #Uses qe8.inc #else #Uses qe32.inc #endif #ListOn #endif ;------------------------------------------------------------------------------- #ifdef FL16 HZ def 16777216 ;Cyclone default 32768*512 BDIV def 1 #ListOff #Uses fl16.inc #ListOn #endif ;------------------------------------------------------------------------------- #ifdef GB60 HZ def 243000*64 ;MCU's default BDIV equ 1 ;(actually, no BDIV in GB60) #ListOff #Uses gb60.inc #ListOn #endif ;------------------------------------------------------------------------------- #ifdef AC32||AC96 HZ def 32768*512 ;MCU & Cyclone's default BDIV def 1 #ListOff #ifdef AC32 #Uses ac32.inc #else #Uses ac96.inc #endif #ListOn #endif ;------------------------------------------------------------------------------- #ifdef QD2||QD4 HZ def 32768*512 ;MCU & Cyclone's default BDIV def 1 SCI set -1 #ListOff #ifdef QD2 #Uses qd2.inc #else #Uses qd4.inc #endif #ListOn #endif ;------------------------------------------------------------------------------- #ifdef DZ32||DZ60 HZ def 32000000 ;MCU & Cyclone's default BDIV def 1 #ListOff #ifdef DZ32 #Uses dz32.inc #else #Uses dz60.inc #endif #ListOn #temp NVOPT_VALUE>5&1 ;isolate EPGMOD #Message EPGMOD = {:temp} ({:temp*4+4}-byte mode) #endif ;------------------------------------------------------------------------------- #ifdef SH8 HZ def 33554432 ;MCU & Cyclone's default BDIV def 1 #ListOff #Uses sh8.inc #ListOn #endif ;------------------------------------------------------------------------------- #ifdef QG8 HZ def 16000000 ;MCU & Cyclone's default BDIV def 1 #ListOff #Uses qg8.inc #ListOn #endif ;------------------------------------------------------------------------------- #ifndef RAM #Fatal Define one of the supported MCUs (see help with -d?) #endif ;------------------------------------------------------------------------------- #ListOn #MapOn ;------------------------------------------------------------------------------- #endif ;------------------------------------------------------------------------------- RVECTORS def BOOTROM-1&VECTORS APP_CODE_START def TRUE_ROM+FLASH_DATA_SIZE APP_CODE_END def BOOTROM-1 #Message AppSpace: {APP_CODE_START(h)}-{APP_CODE_END(h)} ({APP_CODE_END-APP_CODE_START+1} bytes) RVECTORS: {RVECTORS(h)} ;------------------------------------------------------------------------------- #XRAM RAM ;used only for boot #ROM BOOTROM ;******************************************************************************* #if SCI < 0 SCI_TX_PIN def SCI_RX_PIN def #ifdef BPS BPS_RATE equ BPS #endif #Uses lib/soft_sci/sci_rx.sub #Uses lib/soft_sci/sci_tx.sub ?GetChar equ SCI_GetChar ?PutChar equ SCI_PutChar #endif ;******************************************************************************* ; Macros ;******************************************************************************* #ifnomdef ?print ?print macro mset # #if :pc-?Print < 128 bsr ?Print #else jsr ?Print #endif fcs ~1~ endm #endif ;------------------------------------------------------------------------------- Page macro mset # #Message +------------------------------------------------- #Message | ~1~ #Message +------------------------------------------------- endm ;******************************************************************************* #ifndef MAP #MapOff #endif LF2CRLF def * #ifndef ?GetChar||?PutChar ;******************************************************************************* @Page SCI module starts here ;******************************************************************************* @ConstMinMax SCI,1,2 #ifdef HARD_FLOW_CONTROL #ifndef CTS_LINE #ifdef QE128 CTS_LINE pin PORTE,6 ;/CTS is output from MCU #else ifdef QE8||QE32 CTS_LINE pin PORTC,7 ;/CTS is output from MCU #endif #endif @CheckPin CTS_LINE #endif ? macro #ifndef SCI~1~BDH ;if required SCI does not exist mset 1 ;remove number (assuming SCI1) ?MY_SCI equ 1 ;assume SCI1 #endif ?MY_SCI def ~1~ ;assume user's SCI #Message Using SCI~1~ ?SCIBDH equ SCI~1~BDH,1 ?SCIBDL equ SCI~1~BDL,1 ?SCIC1 equ SCI~1~C1,1 ?SCIC2 equ SCI~1~C2,1 ?SCIC3 equ SCI~1~C3,1 ?SCIS1 equ SCI~1~S1,1 ?SCIS2 equ SCI~1~S2,1 ?SCID equ SCI~1~D,1 endm @? {SCI} @StandardBaudRates ; Attempt to define all standard bps rates #ifdef BPS ? macro #if BPS = ~{:loop}.~ ?MY_BPS_RATE def bps_~{:loop}.~ #endif mtop :n endm @? 300,1200,2400,4800,9600,19200,38400,57600,115200 #endif ?MY_BPS_RATE def bps_max #Hint ================================================== #Hint >>> Actual SCI{?MY_SCI} speed: {BUS_HZ/16/?MY_BPS_RATE} bps <<< #Hint ================================================== ;******************************************************************************* #ROM ;******************************************************************************* @cop #SAVE# ;******************************************************************************* ; Purpose: Set SCI BAUD rate to the specified value ; Input : HX = Needed baud rate (must have taken care of BUSCLK as shown below) ; Note(s): BUSCLK HZ ; : Baud is calculated using this formula: SBR12:SBR0 = ------- = ------- ; : 16*BAUD 32*BAUD ; : Example: 9600 baud @ 20MHz bus speed, use value: 130 ?SetBAUD proc sthx ?SCIBDH #ifz ]?SCIC2 mov #TE_|RE_,?SCIC2 ;Polled RX and TX mode #ifdef RXINV #Message SCI RX inverted mov #RXINV_,?SCIS2 ;RX inverted #else clr ?SCIS2 #endif #ifdef TXINV #Message SCI TX inverted mov #TXINV_,?SCIC3 ;TX inverted #else clr ?SCIC3 #endif #else lda #TE_|RE_ ;Polled RX and TX mode sta ?SCIC2 #ifdef RXINV #Message SCI RX inverted lda #RXINV_ ;RX inverted #else clra #endif sta ?SCIS2 #ifdef TXINV #Message SCI TX inverted lda #TXINV_ ;TX inverted #else clra #endif sta ?SCIC3 #endif #ifdef HARD_FLOW_CONTROL #Message HARD_FLOW_CONTROL (CTS) enabled @Off CTS_LINE ;start with enabled RX (output) #endif rts ;******************************************************************************* ; Purpose: Read SCI char into RegA ; Input : None ; Output : A = received character ; Note(s): #spauto ?GetChar proc Loop@@ #ifdef HARD_FLOW_CONTROL bclr CTS_LINE #endif @cop lda ?SCIS1 ;wait for a character bit #RDRF_ beq Loop@@ lda ?SCID ;get received character beq Loop@@ ;ignore Nulls cbeqa #LF,Loop@@ ;ignore LineFeeds clc ;never an error from here rts ;******************************************************************************* ; Purpose: Write RegA character to the SCI ; Input : A = character to send to the SCI ; Output : None ; Note(s): #spauto ?PutChar proc #ifdef LF2CRLF cmpa #LF ;is it LF? bne Print@@ ;no, continue as usual lda #CR ;yes, first print a CR bsr Print@@ lda #LF ;next, print a LF #endif Print@@ @cop #ifz ]?SCIS1 tst ?SCIS1 #else psha lda ?SCIS1 pula #endif bpl Print@@ sta ?SCID rts ;Carry Clear when exiting #endif ;#ifndef ?GetChar||?PutChar ;******************************************************************************* ;@Page Common print I/O routines ;******************************************************************************* ;******************************************************************************* ; Purpose: Print constant ASCIZ string following caller instruction (with FCS) ; Input : None ; Output : None ; Note(s): #spauto ?Print proc pc@@ equ ::,2 ;SP offset to return address pshhx ldhx pc@@,sp ;get return address bsr ?PrintString sthx pc@@,sp ;new return is past the ASCIZ string pulhx rts ;back to updated return address ;******************************************************************************* ; Purpose: Write (send) a string to the SCI ; Input : HX -> ASCIZ string, ie., Char1,Char2,...,0 ; Output : None ; Note(s): #spauto ?WriteZ proc pshhx bsr ?PrintString pulhx rts ;******************************************************************************* ; Purpose: (LOCAL) Write (send) a string to the SCI ; Input : HX -> ASCIZ string, ie., Char1,Char2,...,0 ; Output : HX -> past ASCIZ string ; Note(s): #spauto ?PrintString proc psha Loop@@ lda ,x ;get char to print aix #1 ;bump up pointer beq Done@@ ;on terminator, done bsr ?PutChar ;print character bra Loop@@ ;repeat for all chars Done@@ pula rts ;******************************************************************************* ; Purpose: Display the copyright message on the SCI terminal ; Input : None ; Output : None ; Note(s): #spauto ?ShowCopyright proc ldhx #?CopyrightMsgCls bsr ?WriteZ ; bra ?ShowSerial ;******************************************************************************* #spauto ?ShowSerial proc #ifdef SERIAL_NUMBER ldhx #SERIAL_NUMBER lda ,x cbeqa #[ERASED_STATE,Done@@ ;All S/N should not have erased first byte ($FF) @?print 'S/N: ' bsr ?WriteZ Done@@ #endif ; bra ?NewLine ;******************************************************************************* ; Purpose: Advance a line by sending a CR,LF pair (or equivalent) to the SCI ; Input : None ; Output : None ; Note(s): #spauto ?NewLine proc psha #ifndef LF2CRLF lda #CR ;send a CR bsr ?PutChar #endif lda #LF ;send a LF bsr ?PutChar pula rts ;******************************************************************************* ;@Page S19 module starts here ;******************************************************************************* ;******************************************************************************* #XRAM ;******************************************************************************* ?line_crc rmb 1 ;S-record CRC ?address rmb 2 ;S-record address field ?length rmb 1 ;S-record length field ?rec_type rmb 1 ;S-record type field ;******************************************************************************* #ROM ;******************************************************************************* ;******************************************************************************* ; Routine: LoadS19 ; Purpose: Load an S19 file through the primary SCI port ; Input : None ; Output : None ; Note(s): Only addresses within APP_CODE_START and APP_CODE_END and VECTORS ; : are processed. ; : ESC aborts #spauto ?LoadS19 proc MainLoop@@ clr ?line_crc ;Initialize CRC to zero SkipBlanks@@ jsr ?GetCharLocal ;Get first/next character beq SkipBlanks@@ ;if EOL, skip blank lines bcs ??Error ;abort on ESC cbeqa #'S',S@@ ;Probable S record SkipLine@@ jsr ?SkipToEOL ;ignore rest of line beq MainLoop@@ ??Error jmp ?Error ;abort on ESC S@@ jsr ?GetCharLocal ;Get next character bcs ??Error ;if ESC, get out with error cbeqa #'9',S9@@ ;Terminator record cbeqa #'1',S1@@ ;Code/data record #ifdef PPAGE cbeqa #'8',S8@@ ;Extended terminator record cbeqa #'2',S2@@ ;Extended address code/data record #endif bra SkipLine@@ ;skip S0 (header) or other lines ;******************************************************************************* ; Purpose: (LOCAL) Adjust the running CRC for the current record ; Input : A = current byte ; Output : None ; Note(s): #spauto ?UpdateCRC proc psha add ?line_crc sta ?line_crc pula rts endp ;******************************************************************************* S8@@ S9@@ @?print '!' bra OK@@ S2@@ S1@@ @?print '.' OK@@ sta ?rec_type ;Save the record type ;-------------------------------------- ; Get length of Record Bytes (including 16-bit address and 8-bit CRC) ;-------------------------------------- jsr ?ReadHex ;Get next 2 characters in binary bcs ??Error ;if something wrong, get out with error bsr ?UpdateCRC sub #3 ;adjust for 2-byte address and 1-byte CRC sta ?length ;save Length of record (without address & CRC) ;-------------------------------------- ;get optional PPAGE of load address #ifdef PPAGE mov #2,PPAGE ;assume default PPAGE for every new S record lda ?rec_type cmpa #'2' ;S2 type record? bne GetAddress@@ ;if not, continue as usual dec ?length ;adjust for 3rd address byte jsr ?ReadHex ;get extended address byte (ppage) bcs ??Error bsr ?UpdateCRC sta PPAGE ;update PPAGE for this record #endif ;-------------------------------------- ;now, get the load address GetAddress@@ jsr ?ReadHex ;Get MSB of address bcs ??Error sta ?address ;Save MSB of address bsr ?UpdateCRC jsr ?ReadHex ;Get LSB of address bcs ?Error sta ?address+1 ;Save LSB of address bsr ?UpdateCRC ;-------------------------------------- ;now, get the code/data bytes tst ?length ;Check Length of zero beq DoCRC@@ ;Empty code/data section of record Loop@@ jsr ?ReadHex ;get first/next data byte bcs ?Error ;if something wrong, get out with error bsr ?UpdateCRC ;-------------------------------------- ; Add load-time CRC calculation here, if required ;-------------------------------------- ;save byte and advance pointer ldhx ?address ;Get address in HX bsr ?CheckAddr ;Check address to be bcs RangeError@@ ; within valid Flash limits cphx #VECTORS blo Save@@ #ifz RVECTORS-VECTORS&$FF psha tha add #RVECTORS-VECTORS>8&$FF tah pula #else @aix #RVECTORS-VECTORS ;redirector to user vectors #endif Save@@ jsr ?FlashWrite ;Save to Flash beq NextByte@@ @?print BS,'F' ;Flash error indicator NextByte@@ ldhx ?address aix #1 ;Adjust the PC value by 1 sthx ?address dbnz ?length,Loop@@ ;One less byte to read ;------------------------------------------------------------------------------- DoCRC@@ bsr ?ReadHex ;Get CRC byte bcs ?Error ;if something wrong, get out with error com ?line_crc ;Get one's complement of final CRC value cbeq ?line_crc,GoNext@@ ;Is it the same as the one calculated. Yes, continue @?print BS,'C' ;CRC error indicator ;See if we're done (i.e., if we just processed an S9 record) GoNext@@ bsr ?SkipToEOL ;Clean up to the end of line lda ?rec_type ;Check record type cbeqa #'9',?Success ;Done, get out without errors #ifdef PPAGE cbeqa #'8',?Success ;Done, get out without errors #endif jmp MainLoop@@ ;Go back to read another line ;------------------------------------------------------------------------------- RangeError@@ @?print BS,'R' ;Address Range error indicator bra NextByte@@ ;skip error byte ;******************************************************************************* ?SkipToEOL proc Loop@@ bsr ?GetCharLocal bcc Loop@@ ?Error sec rts ;******************************************************************************* ; Purpose: Check address to be within range ; Input : HX = address ; Output : Carry Clear if within valid ranges ; : Carry Set if outside valid ranges ; Note(s): ?CheckAddr proc #ifdef PPAGE ;-------------------------------------- ; PPAGE 2 (startup default) has a different allowable range ;-------------------------------------- @cmp.s PPAGE #2 ;for all but the default page beq CheckAddr@@ ;-------------------------------------- ; Do a single PPAGE address range check and exit ;-------------------------------------- cphx #:PAGE_START blo ?Error cphx #:PAGE_END bhi ?Error clc rts CheckAddr@@ #endif #ifdef ALLOW_EEPROM #Message EEPROM is allowed cphx #EEPROM blo Go@@ cphx #EEPROM_END bls Done@@ #endif Go@@ cphx #APP_CODE_START ;Check address to be blo ?Error ; within valid Flash cphx #VECTORS ; limits. bhs Done@@ ;Vectors are passed cphx #APP_CODE_END ; as is, and redirected bhi ?Error ; automatically by loader. #if HighRegs > APP_CODE_START cphx #HighRegs ;Check address for hole blo Done@@ ; in Flash created by cphx #HighRegs_End ; HighRegs (certain MCUs only) bls ?Error #endif Done@@ clc ;no errors from here rts ?Success equ Done@@ ;******************************************************************************* ; Purpose: Read next character from S19 file ; Input : None ; Output : A = next S19 file character converted to uppercase ; : CCR[C] = 1 and CCR[Z] = 1 if CR received (normal end-of-line) ; : CCR[C] = 1 and CCR[Z] = 0 if ESC received (abort) ; : CCR[C] = 0 and CCR[Z] = 0 for any other character ; Note(s): #spauto ?GetCharLocal proc jsr ?GetChar ;Get a character cmpa #CR ;Z=1 if CR found, Z=0 anything else beq ?Error ;(do NOT change to CBEQA) clc ;assume no error cbeqa #ESC,?Error ;ESC cancels ; bra ?Upcase ;******************************************************************************* ; Purpose: Convert one character to uppercase ; Input : A = character ; Output : A = CHARACTER ; Note(s): Protects caller's CCR #spauto ?Upcase proc pshx tpx ;(transfer CCR to X) cmpa #'a' blo Done@@ cmpa #'z' bhi Done@@ add #'A'-'a' Done@@ txp ;(transfer X to CCR) pulx rts ;******************************************************************************* ; Purpose: Read two-digit ASCII hex from SCI and convert to binary value in A ; Input : None ; Output : A = binary value ; Note(s): Destroys HX #spauto ?ReadHex proc bsr ?GetCharLocal ;Get next character bcs Done@@ ;if EOL, get out with error jsr ?HexByte ;Convert from Hex to Binary bcs Done@@ ;if not hex, get out with error nsa ;Move to high nibble tax ;save temporarily in X bsr ?GetCharLocal ;Get next character bcs Done@@ ;if EOL, get out with error jsr ?HexByte ;Convert from Hex to Binary bcs Done@@ ;Invalid character, ignore rest of line pshx tmp@@ tsx ;20131006 addition ora tmp@@,spx ;combine LSN with MSN pulx ; clc ;indicate "no error" (valid since BCS fall thru) Done@@ rts ;******************************************************************************* ;@Page Flash module starts here ;******************************************************************************* ;******************************************************************************* ; Flash programming command codes mBlank def $05 ;Blank check mByteProg def $20 ;Byte programming mBurstProg def $25 ;Burst programming mPageErase def $40 ;Page erase mMassErase def $41 ;Mase erase ;******************************************************************************* ; Purpose: RAM routine to do the job we can't do from Flash ; Input : A = value to program ; Output : None ; Note(s): This routine is modified in RAM at zero-based offsets ; : @1, @2 (address) and @4 (Flash command) ; : RAM needed: 20 bytes #spauto ?RAM_Code proc sta $FFFF ;Step 1 - Latch data/address ?ADDR_OFFSET equ :pc-?RAM_Code-2,2 ;$FFFF (@1,@2) replaced with actual address during RAM copying lda #mByteProg ;mByteProg (@4) replaced with actual command during RAM copying ?CMD_OFFSET equ :pc-?RAM_Code-1,1 sta FCMD ;Step 2 - Write command to FCMD lda #FCBEF_ ;Step 3 - Write FCBEF_ in FSTAT sta FSTAT lsra ;min delay before checking FSTAT (four bus cycles) ;instead of NOP (moves FCBEF -> FCCF for later BIT) Loop@@ bit FSTAT ;Step 4 - Wait for completion beq Loop@@ ;check FCCF_ for completion rts ;after exit, check FSTAT for FPVIOL and FACCERR #size ?RAM_Code ;******************************************************************************* #XRAM ;******************************************************************************* ?burn_routine rmb ::?RAM_Code ?burn_address equ ?burn_routine+?ADDR_OFFSET,2 ?burn_command equ ?burn_routine+?CMD_OFFSET,1 ;******************************************************************************* #ROM ;******************************************************************************* ;******************************************************************************* ; Purpose: Program an internal Flash location ; Input : HX -> Flash memory location to program ; : A = value to write ; Output : CCR[Z] on success ; Note(s): Does not program (skips) non-erased locations #spauto ?FlashWrite proc cmpa ,x ;(do NOT replace with CBEQ) beq Done@@ ;value already there, no need to update #ifz ERASED_STATE tst ,x ;test if erased, and if not #else psha lda ,x ;if not erased already coma pula #endif bne Done@@ ;skip (and report as failure, CCR[Z]=0) bsr ?PrepareFlash mov #mByteProg,?burn_command ;save command within LDA #?? instruction ; bra ?FlashIt Done@@ equ :AnRTS ;******************************************************************************* ; Purpose: Call RAM routine ; Input : HX = address to Flash ; : BurnCommand already set with Flash command ; : A = value to program ; Output : A = FSTAT ; : CCR[Z] = 1 on success ; Note(s): Destroys all registers #spauto ?FlashIt proc sthx ?burn_address ;save HX within STA $FFFF instruction ; pshcc ; sei ;disable interrupts (never enabled in this app) @cop ;reset COP (for maximum tolerance) jsr ?burn_routine ;execute RAM routine to perform Flash command ; pulcc lda FSTAT bit #FPVIOL_|FACCERR_ rts ;******************************************************************************* ; Purpose: Erase an internal Flash page by address ; Input : HX -> location within page to erase ; Output : CCR[Z] on success ; Note(s): Forces address past HighRegs (if any). #spauto ?FlashErase proc #ifdef HighRegs cphx #HighRegs blo Cont@@ cphx #HighRegs_End bhi Cont@@ ldhx #HighRegs_End+1 #endif Cont@@ bsr ?PrepareFlash mov #mPageErase,?burn_command ;save command within LDA #?? instruction bra ?FlashIt ;******************************************************************************* ;* Supporting routines ;******************************************************************************* ;******************************************************************************* ; Purpose: Prepare Flash for programming ; Input : None ; Output : None ; Note(s): Makes FCLK fall between 150-200KHz [FCLK=FBUS/(DIV+1)] and DIV=0..63 #spauto ?PrepareFlash proc psha lda FCDIV bmi Done@@ lda #FLASH_CLK_VALUE ;required to allow further sta FCDIV ;access to Flash programming Done@@ lda #FPVIOL_|FACCERR_ sta FSTAT ;clear possible errors pula rts ;******************************************************************************* ?mcu macro MCU[,MCU]* #ifdef _~{:loop}.~_ fcc \@ ~{:loop}.~\@ mexit #endif mtop :n endm ;******************************************************************************* #MapOn ?CopyrightMsgCls fcc ASCII_FF,CR ;a Form Feed and CR (for CLS) ?CopyrightMsg fcc 'TBoot v{BOOTROM_VERSION(2)} (c) {:year} ASPiSYS' #ifexists checkout.inc fcc ' [' #ifndef _FL_ fcc 'Build ' #endif #Include checkout.inc ;(Fossil, Git, ...) checkout hash (optional) fcc ']' #endif @?mcu QE128,QE8,QE32,GB60,AC32,AC96,QD2,QD4,DZ32,DZ60,SH8,QG8,FL16 fcc ' {HZ/1000(3)} MHz' #ifmmu fcc ' MMU' #endif fcb 0 ;ASCIZ terminator ;******************************************************************************* ; Purpose: Initialize the MCU with MCU-specific settings for TBoot monitor ; Input : None ; Output : None ; Note(s): You can affect one-time writable settings as exit is always via reset #spauto ?Initialize proc #ifdef NVICSTRM lda NVICSTRM sta ICSTRM #ifdef FTRIM_ lda NVFTRIM and #FTRIM_ #ifdef DRS1_&&DRS0_ #if MHZ >= 48 ora #DRS1_ ;high DCO range (%01) x1536 #else if MHZ >= 32 ora #DRS0_ ;middle DCO range (%01) x1024 #endif #endif sta ICSSC #endif #else ifdef NVICGTRM lda NVICGTRM sta ICGTRM #endif ;-------------------------------------- #ifdef _AC_ brclr DCOS.,ICGS2,* ;wait for stabilization mov #%00001100,ICGC1 ; |||||||| ; |||||||+--------- Not Used ; ||||||+---------- LOCD (1=Loss of clock disabled) ; |||||+----------- OSCSTEN (1=Enable in off mode) ; |||++------------ CLKS (01 FLL engaged, internal reference) ; ||+-------------- REFS ; |+--------------- RANGE (0=Low, 1=High) reference ; +---------------- HGO (1=High Gain Oscillator) mov #%01110000,ICGC2 ;Example: 40MHz -> 243KHz/7*64*MFD/RFD ; |||||||| ; |||||+++--------- RFD (1) ; ||||+------------ LOCRE ; |+++------------- MFD (18) ; +---------------- LOLRE brclr LOCK.,ICGS1,* ;wait for FLL lock #endif ;-------------------------------------- #ifdef _AC_ SOPT_VALUE def %00110011 #else ; |||xxxxx SOPT_VALUE def %00100010 #endif ; |||||||| ; |||||||| ; |||||||+--------- RSTPE - RST pin enable ; ||||||+---------- BKGDPE - BKGD/MS pin for debugging only ; |||||+----------- RSTOPE - RTSO pin enable ; |||++------------ Not Used ; ||+-------------- STOPE - Stop Mode Enable ; |+--------------- COPT - COP Timeout (0=Short [32msec], 1=Long [256msec]) ; +---------------- COPE - COP Enable #ifdef QE128 #ifnz SOPT_VALUE&COPE_ #Warning COPE does not work well with buggy (QE128) chips #endif #endif lda #SOPT_VALUE sta SOPT ;write-once register ;-------------------------------------- ; #!ifz ]ICSC1 ; mov #%00000111|RDIV_,ICSC1 ; ; |||||||+--------- IREFSTEN ; ; ||||||+---------- IRCLKEN ; ; |||||+----------- IREFS ; ; ||+++------------ RDIV ; ; ++--------------- CLKS ; #else ifdef ICSC1 ; lda #%00000111|RDIV_ ; sta ICSC1 ; #endif #!ifz ]ICSC2 mov #%00000000|BDIV_|RANGE_,ICSC2 ; |||||||+--------- EREFSTEN ; ||||||+---------- ERCLKEN ; |||||+----------- EREFS ; ||||+------------ LP ; |||+------------- HGO ; ||+-------------- RANGE ; ++--------------- BDIV #else ifdef ICSC2 lda #%00000000|BDIV_|RANGE_ sta ICSC2 #endif ; bra ?CopyRamCode ;******************************************************************************* ; Purpose: Copy programming routine from Flash to RAM as you can't program where code runs ; Input : None ; Output : None ; Note(s): #spauto ?CopyRamCode proc #if ::?RAM_Code <= 256 ;(most likely scenario) ldhx #::?RAM_Code ;(do NOT use CLRH, LDX) Loop@@ lda ?RAM_Code-1,x ;A = next code byte sta ?burn_routine-1,x ;save to RAM mirror dbnzx Loop@@ ;repeat for all bytes #else clrhx Loop@@ lda ?RAM_Code,x ;A = next code byte sta ?burn_routine,x ;save to RAM mirror aix #1 ;point to next byte to process cphx #::?RAM_Code ;are we done? blo Loop@@ #endif rts ;******************************************************************************* ; Fixed vectors are always negative offsets in multiples of 2 from Reset Vector ; From your app, you can access this way: ; ldhx Vreset ; ldhx -2,x ; (where -2 is the appropriate object offset) ;******************************************************************************* dw 0 ;indicates end of backward list since v1.20 dw ?CopyrightMsg ;@-2 Copyright ASCIZ string ;******************************************************************************* ; PROGRAM EXECUTION STARTS HERE ;******************************************************************************* #spauto ?Start proc @rsp @cop ;-------------------------------------- ;for keeping pins in fail-safe state during TBoot #ifexists shutdown.tmp #Include shutdown.tmp ;include shutdown instructions (optional) #endif ;-------------------------------------- bmc ?Monitor ;in user code entry ints are enabled mov #IRQPE_,IRQSC ; |||||||+--------- IRQMOD (0=edge, 1=level) ; ||||||+---------- IRQIE (1=Interrupts Enabled) ; |||||+----------- IRQACK ; ||||+------------ IRQF ; |||+------------- IRQPE (1=Pin Enabled) ; ||+-------------- IRQEDG (0=Falling Edge) ; |+--------------- IRQPDD (1=Pulls Disabled) ; +---------------- Always zero jsr ?cmdRun ; bra ?Monitor ;******************************************************************************* ?Monitor proc sei ;just in case we entered from user code bsr ?Initialize ;-------------------------------------- ; Initialize the RS232 communications channel ;-------------------------------------- #ifdef ?SetBAUD ldhx #?MY_BPS_RATE jsr ?SetBAUD #endif jsr ?ShowCopyright ;display copyright message for boot loader ; bra ?MainLoop ;******************************************************************************* ; Main loop accepts three commands (E-rase, L-oad, or ESC-ape) ;******************************************************************************* #spauto ?MainLoop proc Loop@@ #ifdef ENABLE_RUN @?print LF,'[E]rase [L]oad [R]un [ESC]ape:' #else @?print LF,'[E]rase [L]oad [ESC]ape:' #endif jsr ?GetChar jsr ?Upcase cbeqa #ESC,?ForceReset ;(does not return) cbeqa #'E',Erase@@ cbeqa #'L',Load@@ #ifdef ENABLE_RUN cbeqa #'R',Run@@ ;(useful mostly for debugging) #endif bra Fail@@ ;print ERROR on wrong cmd #ifdef ENABLE_RUN Run@@ jsr ?RunNow ;we need JSR in case no code is found bra Fail@@ #endif Erase@@ #ifdef DISABLE_SURE ;(limited Flash MCUs but not good for general use) @?print LF,'Erasing' #else @?print LF,'Sure?' jsr ?GetChar cmpa #'Y' ;(explictly uppercase to minimize accidents) bne Fail@@ @?print CR,'Erasing' #endif jsr ?EraseFlash bra Cont@@ Load@@ @?print LF,'Loading' jsr ?LoadS19 Cont@@ bcc Loop@@ Fail@@ @?print ' Error' bra Loop@@ ;******************************************************************************* ?ForceReset reset ; force a reset ;******************************************************************************* ; Purpose: Check if app firmware is available (based on relocated reset vector) ; Input : None ; Output : HX = execution address ; : Carry Clear = BOOTMODE enabled ; Note(s): #spauto ?IsAppPresent proc ldhx Vreset&$FF|RVECTORS cphx #APP_CODE_START blo Fail@@ cphx #BOOTROM bhs Fail@@ clc rts ?No Fail@@ sec rts ;******************************************************************************* ; M O N I T O R C O M M A N D S ;******************************************************************************* #spauto ?cmdRun proc #ifdef NO_IRQ #ifdef TIBBO_DTR @Pullup TIBBO_DTR,,-1 brset TIBBO_DTR,Done@@ ;force entry to Monitor mode with high Tibbo DTR pin #else brn * ;keep image size the same as when BIL is used #endif #else bil Done@@ ;force entry to Monitor mode with low IRQ pin #endif ; bra ?RunNow Done@@ equ :AnRTS ;******************************************************************************* ?RunNow proc bsr ?IsAppPresent bcs Done@@ ;erased vector never executes clra sta IRQSC ;restore IRQ to reset default #ifdef ?SCIC1 sta ?SCIC1 ;restore all SCI registers sta ?SCIC2 ;... to their default status sta ?SCIBDH lda #4 sta ?SCIBDL #endif sthx $FE ;address at top of page zero @lds #$FE ;set default out-of-reset SP clra clrhx Done@@ RTS ;return OR execute user code ;******************************************************************************* ; Purpose: Convert an ASCII hex byte '0' to 'F' to binary value ; Input : A = hex ASCII ; Output : A = binary equivalent, Carry Clear ; : Carry Set if digits not in 0-9, A-F/a-f character set ; Note(s): #spauto ?HexByte proc jsr ?Upcase cmpa #'0' blo Done@@ ;Fail@@ really (but CCR[C]=1 already) cmpa #'F' bhi Fail@@ cmpa #'9' bls Number@@ cmpa #'A' blo Done@@ ;Fail@@ really (but CCR[C]=1 already) sub #'A'-10-'0' Number@@ sub #'0' ; clc ;(redundant due to positive SUB result) Done@@ rts Fail@@ equ ?No ;******************************************************************************* #spauto ?EraseFlash proc #ifdef PPAGE clr PPAGE ;start from first page NewPage@@ ldhx #:PAGE_START ;lower MMU page boundary Loop@@ pshhx jsr ?FlashErase ;erase this page pulhx ;;;;;;;;;;;;;;;;;;; bne Fail@@ @aix #FLASH_PAGE_SIZE ;HX -> next page cphx #:PAGE_END ;end of MMU page window? blo Loop@@ ;repeat for all Flash pages inc PPAGE ;go to next page #if PPAGES = 8 tst PPAGE ;required, INC result CCR[Z] is invalid #else if PPAGES < 8 lda PPAGE cmpa #PPAGES #else #Fatal Unexpected PPAGES ({PPAGES}) #endif bne NewPage@@ ;repeat for all PPAGEs ; clc ;indicate "no error" (valid since BLO fall thru) rts #else ;--------------------------------------------------------------- ldhx #FLASH_START ;user firmware's first page Loop@@ pshhx jsr ?FlashErase ;erase this page pulhx bne Fail@@ @aix #FLASH_PAGE_SIZE ;HX -> next page cphx #BOOTROM ;user firmware's last page blo Loop@@ ;repeat for all Flash pages ; clc ;indicate "no error" (implied by BLO fall thru) rts Fail@@ equ ?No #endif ;******************************************************************************* ? macro RealVector mset 2,VECTORS-RVECTORS ;offset for moving vectors #push #ROM ?~1.2~ proc #Cycles @@ReVector ~1~-{~2~} #pull @@vector ~1~,?~1.2~ #if :mindex = 1 #Message Vector redirection overhead: {:cycles} cycles #endif endm #ifdef QE128 @? Vtpm3ovf ;TPM3 overflow vector @? Vtpm3ch5 ;TPM3 channel 5 vector @? Vtpm3ch4 ;TPM3 channel 4 vector @? Vtpm3ch3 ;TPM3 channel 3 vector @? Vtpm3ch2 ;TPM3 channel 2 vector @? Vtpm3ch1 ;TPM3 channel 1 vector @? Vtpm3ch0 ;TPM3 channel 0 vector @? Vrtc ;RTC vector @? Vsci2tx ;SCI2 TX vector @? Vsci2rx ;SCI2 RX vector @? Vsci2err ;SCI2 Error vector @? Vacmpx ;ACMP - Analog Comparator @? Vadc ;Analog-to-Digital conversion @? Vkeyboard ;Keyboard vector @? Viicx ;IIC vector @? Vsci1tx ;SCI1 TX vector @? Vsci1rx ;SCI1 RX vector @? Vsci1err ;SCI1 Error vector @? Vspi1 ;SPI1 vector @? Vspi2 ;SPI2 vector @? Vtpm2ovf ;TPM2 overflow vector @? Vtpm2ch2 ;TPM2 channel 2 vector @? Vtpm2ch1 ;TPM2 channel 1 vector @? Vtpm2ch0 ;TPM2 channel 0 vector @? Vtpm1ovf ;TPM1 overflow vector @? Vtpm1ch2 ;TPM1 channel 2 vector @? Vtpm1ch1 ;TPM1 channel 1 vector @? Vtpm1ch0 ;TPM1 channel 0 vector @? Vlvd ;low voltage detect vector @? Virq ;IRQ pin vector @? Vswi ;SWI vector #else ifdef AC96 @? Vspi2 ;SPI2 vector @? Vtpm3ovf ;TPM3 overflow vector @? Vtpm3ch1 ;TPM3 channel 1 vector @? Vtpm3ch0 ;TPM3 channel 0 vector @? Vrti ;Real Time Interrupt vector @? Viic ;IIC vector @? Vadc ;Analog-to-Digital conversion @? Vkeyboard ;Keyboard vector @? Vsci2tx ;SCI2 TX vector @? Vsci2rx ;SCI2 RX vector @? Vsci2err ;SCI2 Error vector @? Vsci1tx ;SCI1 TX vector @? Vsci1rx ;SCI1 RX vector @? Vsci1err ;SCI1 Error vector @? Vspi ;SPI vector @? Vtpm2ovf ;TPM2 overflow vector @? Vtpm2ch5 ;TPM2 channel 5 vector @? Vtpm2ch4 ;TPM2 channel 4 vector @? Vtpm2ch3 ;TPM2 channel 3 vector @? Vtpm2ch2 ;TPM2 channel 2 vector @? Vtpm2ch1 ;TPM2 channel 1 vector @? Vtpm2ch0 ;TPM2 channel 0 vector @? Vtpm1ovf ;TPM1 overflow vector @? Vtpm1ch5 ;TPM1 channel 5 vector @? Vtpm1ch4 ;TPM1 channel 4 vector @? Vtpm1ch3 ;TPM1 channel 3 vector @? Vtpm1ch2 ;TPM1 channel 2 vector @? Vtpm1ch1 ;TPM1 channel 1 vector @? Vtpm1ch0 ;TPM1 channel 0 vector @? Vicg ;ICG vector @? Vlvd ;low voltage detect vector @? Virq ;IRQ pin vector @? Vswi ;SWI vector #endif @vector Vreset,?Start ;/RESET vector end :s19crc ;******************************************************************************* #Export APP_CODE_START,APP_CODE_END #Export APP_CODE_START ROM,APP_CODE_END ROM_END #Export BOOTROM,BOOTROM_VERSION #Export FLASH_DATA_SIZE #ifnz FLASH_DATA_SIZE #Export EEPROM,EEPROM_END #endif #Export RVECTORS ;******************************************************************************* @EndStats