diff --git a/oracle/README.md b/oracle/README.md new file mode 100644 index 0000000..1935cac --- /dev/null +++ b/oracle/README.md @@ -0,0 +1,47 @@ +# Oracle — the hand-written TinySafeBoot assembly + +`tsb-fixedbaud.asm` is the reference implementation this port is measured +against: the **native-UART, fixed-baud** TinySafeBoot bootloader, hand-written +in AVR assembly. It is the size-and-feature bar for the port's `tsb_asm` tier. + +- **Source**: + (`firmware_ASM/latest_stable_release/20200727-fixedbaud/main.asm`), the Seed + Robotics fixed-baud fork of Julien Thomas' TinySafeBoot. +- **License**: GPLv3 (see the header in the file). It is vendored here **only as + a reference oracle** — it is not compiled, linked, or distributed as part of + the MIT-licensed port. Mere aggregation. + +## Why this variant + +The user chose the fixed-baud, hardware-UART variant deliberately: it is the one +whose feature set the port must match. It fits the **complete** TSB feature set +into the 512-byte ATmega boot section: + +| Feature | Oracle routine | +|---|---| +| Watchdog-reset bail straight to the app | `RESET` (WDRF check) | +| One-wire half-duplex (RX/TX shorted): RXEN/TXEN toggled per direction, TX turnaround guard | `SetRX` / `SetTX` / `TransmitByte` | +| Activation timeout read from the config page, with a lockout-proof minimum | `WRX1To` (uses `utimeoutH`) | +| 3×`@` activation knock | `ActCharRcvd` | +| Password gate; wrong byte hangs (still draining the UART) | `CheckPassword` | +| Emergency erase on password `\0` + double-confirm — wipes flash, EEPROM and the config page | `EmergencyErase` | +| Device-info block (16 bytes) | `SendDeviceInfo` / `DEVICEINFO` | +| App-flash read/write (`f`/`F`), EEPROM read/write (`e`/`E`), config read/write (`c`/`C`) | `CheckCommands` | + +## Assembled size (the bar) + +Assembled for the ATmega328P with `avra`: + +``` +avra -I /usr/share/avra tsb-fixedbaud.asm # after uncommenting .include "m328Pdef.inc" +# Code : 250 words (500 bytes) — the whole loader, all features, in the 512 B section +``` + +**500 bytes with every feature** — the proof that ≤512 B and full feature parity +are simultaneously reachable. The port's `tsb_asm` tier matches this bar; `tsb_pure` +and `tsb_tricks` implement the same protocol at larger sizes in the 1 KB section, +trading bytes for readability. + +The oracle targets 20 MHz / 33333 baud; the port targets 16 MHz / 115200 baud +(what the simavr protocol test drives). Baud and geometry differ, code size and +feature set do not. diff --git a/oracle/tsb-fixedbaud.asm b/oracle/tsb-fixedbaud.asm new file mode 100644 index 0000000..7e271fc --- /dev/null +++ b/oracle/tsb-fixedbaud.asm @@ -0,0 +1,776 @@ +;*********************************************************************** +;*********************************************************************** +;*********************************************************************** +; TinySafeBoot - The Universal Bootloader for AVR ATmegas +;*********************************************************************** +;*********************************************************************** +;*********************************************************************** +; +;----------------------------------------------------------------------- +; 2020 - Version using native UART, Fixed Baud by Seed Robotics in 2020 +;----------------------------------------------------------------------- +; meant for use on ATMEGA devices only (with native UART - UART0) +; +; Main differences to Regular TSB Bootloader: +; - Uses a native UART (UART0); therefore not compatible with ATTINY +; - Baud rate is fixed (set by a macro in the code). No auto bauding. +; - Disables TX while not transmitting to allow for one wire flashing +; (where RX and TX are shorted, for a multi drop bus) +; - Also works with separate RX and TX; however an external pull up +; on TX _may_ be required; alternatively you can modify the code +; in the ReceiveByte routine so that it won't disable TX. +; - FIXES: +; - situations where booting onto a bus with active communication could +; lock the autobauding feature +; - times out and boots to application code if the host stops interacting +; with the bootloader +; +;----------------------------------------------------------------------- +; Extended by Seed Robotics from 2017 +;----------------------------------------------------------------------- +; Seed Robotics contributions are available from the Github +; repository github.com/seedrobotics +; The License and conditions remain as stated below, in the +; original notice. +; +; +;----------------------------------------------------------------------- +; Written in 2011-2015 by Julien Thomas +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation; either version 3 +; of the License, or (at your option) any later version. +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty +; of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +; See the GNU General Public License for more details. +; You should have received a copy of the GNU General Public License +; along with this program; if not, see: +; http://www.gnu.org/licenses/ +;----------------------------------------------------------------------- +; +; +; +;*********************************************************************** +; OVERVIEW +;*********************************************************************** +; +; TSB assembly source is organized in 4 segments (approx. line numbers) +; +; ~ 50 ... Global definitions +; ~ ... TSB for ATmegas +; +;*********************************************************************** +; ADJUSTMENTS FOR INDIVIDUAL ASSEMBLY +;*********************************************************************** +; +; This Sourcecode is directly compatible to: AVRASM2, GAVRASM +; +.nolist +; +;----------------------------------------------------------------------- +; SPECIFY TARGET AVR +;----------------------------------------------------------------------- +; +; Comment in and provide def.inc file for target device +; +; [Examples] +; +;.include "tn2313def.inc" +;.include "tn85def.inc" +;.include "m8515def.inc" +;.include "m168def.inc" +;.include "m161def.inc" +;.include "m324Adef.inc" +;.include "m328Pdef.inc" +;.include "tn441def.inc" +;.include "tn167def.inc" +;.include "tn861def.inc" +;.include "tn841def.inc" +;.include "tn84def.inc" +;.include "m8def.inc" +;.include "m644PAdef.inc" +;.include "m644def.inc" +;.include "tn167def.inc" +;.include "tn25def.inc" +; +; [...] +; +; +.list +; +;----------------------------------------------------------------------- +; BUILD INFO +;----------------------------------------------------------------------- +; YY = Year - MM = Month - DD = Day +.set YY = 21 +.set MM = 12 +.set DD = 21 +; +.set BUILDSTATE = $F3 ; F1 fixed baud, pull up, derived from original (modified for fixed baud) + ; F2 fixed baud, pull up, guaranteed minimum activation timeout in case of userpage data corruption + ; F3 adds a CONSTANT with clock speed (Mhz) as word in the last page of memory (clock speed our defined CONSTANT) + +; +;----------------------------------------------------------------------- +; TSB / TSB-INSTALLER SWITCH +;----------------------------------------------------------------------- +; 0 = Regular assembly to target address +; Other value = NOT SUPPORTED +; +.set TSBINSTALLER = 0 +; +;----------------------------------------------------------------------- +; F_CPU and Baud rate setting +;----------------------------------------------------------------------- +.equ F_CPU = 20000000 +.equ BAUD = 33333 ; baudrate (notice some possible wrong cals: example for 56K, it is actually 55,555, so for BAUD_PRESC give an INT result of 8, we must set BAUD to 55500) + +.equ BAUD_PRESCx10 = (F_CPU * 10/16/BAUD) - 10 ; baud prescale (regular formula = F_CPU * 10/16/BAUD - 1 but we do it x10 to check the rounding) + +; arredondar acima se necesssario +.if BAUD_PRESCx10 - ( (BAUD_PRESCx10 / 10) * 10 ) >= 5 ; calculate the remainder: we rely on the fact these are integer divisions. Therefore, dividing by 10, rounds DOWN in integer division + .equ BAUD_PRESC = (F_CPU/16/BAUD) + .warning "Incrementing default BAUD_PRESC formula by 1 due to rounding." + +.else + .equ BAUD_PRESC = (F_CPU/16/BAUD) - 1 + .warning "Using default BAUD_PRESC formula (no rounding up)" +.endif + +.if BAUD_PRESC > 255 +.error "ERROR: BAUD RATE TOO LOW. WE ONLY WRITE THE UBRRL REGISTER, SO UBRR MUST BE <255 FOR THIS CLOCK FREQ AND BAUD" +.endif + + +;*********************************************************************** +; AUTO-ADJUST FOR DIFFERENT ASSEMBLY OPTIONS +;*********************************************************************** +; +; Always set TINYMEGA=1 bc this code only supports ATMEGA + +.equ TINYMEGA=1 + +.if FLASHEND > ($7fff) + .error "SORRY! DEVICES OVER 64 KB NOT SUPPORTED YET." + .exit +.endif + +;----------------------------------------------------------------------- +; Workarounds for devices with renamed or missing definitions +;----------------------------------------------------------------------- +; +.ifndef SPMCSR ; SPMEN / PGERS / ... + .equ SPMCSR = SPMCR +.endif + +.ifndef MCUSR ; PORF / EXTRF / BORF / WDRF + .equ MCUSR = MCUCSR +.endif + +; Detect Attiny441/841 to amend missing pagesize and apply 4-page mode + +.set FOURPAGES = 0 + +.if ((SIGNATURE_000 == $1E) && (SIGNATURE_002 == $15) && (SIGNATURE_001 == $92)) + .equ PAGESIZE = 32 + .set FOURPAGES = 1 + .message "ATTINY441: 4-PAGE-ERASE MODE" +.endif + +.if ((SIGNATURE_000 == $1E) && (SIGNATURE_002 == $15) && (SIGNATURE_001 == $93)) + .equ PAGESIZE = 32 + .set FOURPAGES = 1 + .message "ATTINY841: 4-PAGE-ERASE MODE" +.endif + +;----------------------------------------------------------------------- +; Universal Constants and Registers +;----------------------------------------------------------------------- + +.equ REQUEST = '?' ; request / answer / go on +.equ CONFIRM = '!' ; confirm / attention + +; Current bootloader date coded into 16-bit number +.equ BUILDDATE = YY * 512 + MM * 32 + DD + +; Other +.equ INFOLEN = 8 ; *Words* of Device Info +.equ BUFFER = SRAM_START + +; Registers (in use by TSB-Firmware and TSB-Installer for ATtinys) +.def avecl = r4 ; application vector temp low +.def avech = r5 ; application vector temp high +.def tmp1 = r16 ; these are +.def tmp2 = r17 ; universal +.def tmp3 = r18 ; temporary +.def tmp4 = r19 ; registers +.def bcnt = r20 ; page bytecounter +.def cntr1 = r21 ; timeout counter +.def rxen = r22 ; check if RX enabled (meaning TX disabled) +.def utimeoutH = r23 ; user timeout High byte + ; special purpose registers start at R26 +; +; +;*********************************************************************** +;*********************************************************************** +;*********************************************************************** +; START OF TSB FOR ATMEGAS +;*********************************************************************** +;*********************************************************************** +;*********************************************************************** +; +; TSB for ATmegas is always coded directly to target address. + +.if TINYMEGA == 1 + +.message "ASSEMBLY OF TSB FOR ATMEGA" + +.equ BOOTSTART = (FLASHEND+1)-256 ; = 512 Bytes +.equ LASTPAGE = BOOTSTART - PAGESIZE ; = 1 page below TSB! + +.org BOOTSTART + +RESET: + cli + + in tmp4, MCUSR ; check reset condition + sbrc tmp4, WDRF ; in case of a Watchdog reset + rjmp APPJUMP ; immediately leave TSB + + ldi tmp1, low (RAMEND) ; write ramend low + out SPL, tmp1 ; into SPL (stackpointer low) +.ifdef SPH + ldi tmp1, high(RAMEND) ; write ramend high for ATtinys + out SPH, tmp1 ; with SRAM > 256 bytes + .message "PROVIDING FOR STACK BIGGER THAN 256 BYTES" +.endif + +.ifndef DDRD2 + .equ DDRD2 = DDD2 +.endif + +;----------------------------------------------------------------------- +; ACTIVATION CHECK +;----------------------------------------------------------------------- + ; Configure UART; no autobauding in this version + + ldi tmp1,BAUD_PRESC ; load baud prescale + sts UBRR0L,tmp1 ; set baud prescale + ; ldi tmp2,HIGH(bpsc) ; save code by not loading UBBRH + ;sts UBRRH,tmp2 ; to UBRR0 + ;ldi tmp2,( (1< 0 we're attempting to activate bootloader; + ; if not, if X=0 we timedout and go to app start + rcall ReceiveByte + brcs WRX2To ; if X got to 0 (i.e. carry set), assume we timed out + cpi tmp1, '@' ; did we get an activation char = "@" + breq ActCharRcvd +WRX2To: + rjmp APPJUMP ; not an activation char goto APPJUMP in LASTPAGE + + +ActCharRcvd: + inc tmp2 + cpi tmp2, 3 + brne WRX1To ; branch if not yet at 3; + ; otherwise fall through to password check + +;----------------------------------------------------------------------- +; CHECK PASSWORD / EMERGENCY ERASE +;----------------------------------------------------------------------- + ; we use the user timeout (utimeoutH) register for COMM timeout + ; when we don't get valid data + ; increase this value to a fixed one now, to cope + ; with cases where the user timeout is set so low that we don't have time to + ; do anything + ldi utimeoutH, (F_CPU / 78500) ; this should result in 255 for 20Mhz and proportionally + ; less for lower Clocks, so that we get the same time approx. 2.4sec + +CheckPassword: + +chpw0: ser tmp4 ; tmp4 = 255 enables comparison +chpw1: lpm tmp3, z+ ; load pw character from Z + and tmp3, tmp4 ; if tmp4 = 0 disables comparison, for wrong password scenarios + cpi tmp3, 255 ; byte value 255 indicates + breq chpwx ; end of password -> success +chpw2: rcall Receivebyte ; else receive next character + cpi tmp1, 0 ; rxbyte = 0 will branch + breq chpwee ; to confirm emergency erase + cp tmp1, tmp3 ; compare password with rxbyte + breq chpw0 ; if equal check next character + clr tmp4 ; tmp4 = 0 to loop forever + rjmp chpw1 ; and smoothen power profile +chpwee: + ; Fix for ISSUE #1: only check for Emergency Erase if we haven't + ; gotten a wrong password; if we got a wrong password + ; then we should stay in loop and not escape to Emergency + ; Erase + cpi tmp4, 0 ; if tmp4=0 we are set to loop forever + breq chpw1 + rcall RequestConfirm ; request confirm + brts chpa ; not confirmed, leave + rcall RequestConfirm ; request 2nd confirm + brts chpa ; can't be mistake now + rcall EmergencyErase ; go, emergency erase! + rjmp Mainloop +chpa: + rjmp APPJUMP ; start application +chpwx: +; rjmp SendDeviceInfo ; go on to SendDeviceInfo + +;----------------------------------------------------------------------- +; SEND DEVICEINFO +;----------------------------------------------------------------------- + +SendDeviceInfo: + ldi zl, low (DEVICEINFO*2) ; load address of deviceinfo + ldi zh, high(DEVICEINFO*2) ; low and highbyte + ldi bcnt, INFOLEN*2 + rcall SendFromFlash + +;----------------------------------------------------------------------- +; MAIN LOOP TO RECEIVE AND EXECUTE COMMANDS +;----------------------------------------------------------------------- + +Mainloop: + clr zl ; clear Z pointer + clr zh ; which is frequently used + rcall SendConfirm ; send CONFIRM via RS232 + rcall Receivebyte ; receive command via RS232 + rcall CheckCommands ; check command letter + rjmp Mainloop ; and loop on + +;----------------------------------------------------------------------- +; CHANGE USER DATA IN LASTPAGE +;----------------------------------------------------------------------- + +ChangeSettings: + rcall GetNewPage ; get new LASTPAGE contents + brtc ChangeS0 ; from Host (if confirmed) + ret +ChangeS0: + rcall ZtoLASTPAGE ; re-write LASTPAGE + rcall EraseFlashPage + rcall WritePage ; erase and write LASTPAGE + +;----------------------------------------------------------------------- +; SEND USER DATA FROM LASTPAGE +;----------------------------------------------------------------------- + +ControlSettings: + rcall ZtoLASTPAGE ; point to LASTPAGE +; rcall SendPageFromFlash + +;----------------------------------------------------------------------- +; SEND DATA FROM FLASH MEMORY +;----------------------------------------------------------------------- + +SendPageFromFlash: + ldi bcnt, low (PAGESIZE*2) ; whole Page to send +SendFromFlash: + rcall SPMwait ; (re)enable RWW read access + lpm tmp1, z+ ; read directly from flash + rcall Transmitbyte ; and send out to RS232 + dec bcnt ; bcnt is number of bytes + brne SendFromFlash + ret + +;----------------------------------------------------------------------- +; READ APPLICATION FLASH +;----------------------------------------------------------------------- +; read and transmit application flash area (pagewise) + +ReadAppFlash: +RAF0: + rcall RwaitConfirm + brts RAFx + rcall SendPageFromFlash +RAF1: + cpi zl, low (LASTPAGE*2) ; count up to last byte + brne RAF0 ; below LASTPAGE + cpi zh, high(LASTPAGE*2) + brne RAF0 +RAFx: + ret + +;----------------------------------------------------------------------- +; WRITE APPLICATION FLASH +;----------------------------------------------------------------------- +; Write Appflash pagewise, don't modify anything for ATmegas + +WriteAppFlash: + rcall EraseAppFlash ; Erase whole app flash +Flash2: + rcall GetNewPage ; get next page from host + brts FlashX ; stop on user's behalf +Flash3: + rcall WritePage ; write page data into flash +Flash4: + cpi zh, high(LASTPAGE*2-1) ; end of available Appflash? + brne Flash2 ; if Z reached last location + cpi zl, low (LASTPAGE*2-1) ; then we are finished + brne Flash2 ; else go on +FlashX: + ret ; we're already finished! + +;----------------------------------------------------------------------- +; WRITE FLASH PAGE FROM BUFFER, VERIFYING AND VERIFY-ERROR-HANDLING +;----------------------------------------------------------------------- + +WritePage: + rcall YtoBUFFER ; Y=BUFFER, bcnt=PAGESIZE*2 +WrPa1: + ld r0, y+ ; fill R0/R1 with word + ld r1, y+ ; from buffer position Y / Y+1 + ldi tmp1, 0b00000001 ; set only SPMEN in SPMCSR + out SPMCSR, tmp1 ; to activate page buffering + spm ; store word in page buffer + adiw zl, 2 ; and forward to next word + subi bcnt, 2 + brne WrPa1 + ; Z = start of next page now + subi zl, low (PAGESIZE*2) ; point back Z to + sbci zh, high(PAGESIZE*2) ; start of current page + ; Z = back on current page's start +WrPa2: + ldi tmp1, 0b00000101 ; enable PRWRT + SPMEN + out SPMCSR, tmp1 ; in SPMCSR + spm ; write whole page to flash +WrPa3: + in tmp1, SPMCSR ; wait for flash write finished + sbrc tmp1, 0 ; skip if SPMEN (bit0) cleared + rjmp WrPa3 ; ITS BEEN WRITTEN + subi zl, low (-PAGESIZE*2) ; same effect as + sbci zh, high(-PAGESIZE*2) ; Z = Z + PAGESIZE*2 + ret + +;----------------------------------------------------------------------- +; CHECK COMMANDS +;----------------------------------------------------------------------- + +CheckCommands: + cpi tmp1, 'c' ; read LASTPAGE + breq ControlSettings + cpi tmp1, 'C' ; write LASTPAGE + breq ChangeSettings + cpi tmp1, 'f' ; read Appflash + breq ReadAppFlash + cpi tmp1, 'F' ; write Appflash + breq WriteAppFlash + cpi tmp1, 'e' ; read EEPROM + breq EepromRead + cpi tmp1, 'E' ; write EEPROM + breq EEpromWrite + rjmp APPJUMP ; else start application + +;----------------------------------------------------------------------- +; EEPROM READ/WRITE ACCESS +;----------------------------------------------------------------------- + +EepromWrite: +EEWr0: + rcall GetNewPage ; get EEPROM datablock + brts EERWFx ; or abort on host's demand +EEWr1: + rcall YtoBUFFER ; Y = Buffer and Bcnt = blocksize +EEWr2: + ld tmp1, y+ ; read EEPROM byte from buffer + rcall EEWriteByte + dec bcnt ; count down block byte counter + brne EEWr2 ; loop on if block not finished + rjmp EeWr0 + +;----------------------------------------------------------------------- + +EEpromRead: +EeRe1: + rcall RwaitConfirm ; wait to confirm + brts EERWFx ; else we are finished + ldi bcnt, low(PAGESIZE*2) ; again PAGESIZE*2 is blocksize +EERe2: + out EEARL, zl ; current EEPROM address low + .ifdef EEARH + out EEARH, zh ; current EEPROM address high + .endif + sbi EECR, 0 ; set EERE - EEPROM read enable + in tmp1, EEDR ; read byte from current address + rcall Transmitbyte ; send out to RS232 + adiw zl,1 ; count up EEPROM address + dec bcnt ; count down block byte counter + brne EERe2 ; loop on if block not finished + rjmp EERe1 +EERWFx: + ret + +;----------------------------------------------------------------------- + +EEWriteByte: + out EEDR, tmp1 ; write to EEPROM data register + out EEARL, zl ; current EEPROM address low + .ifdef EEARH + out EEARH, zh ; high EEARH for some attinys + .endif + sbi EECR, 2 ; EEPROM master prog enable + sbi EECR, 1 ; EEPE initiate prog cycle +EeWB: + sbic EECR, 1 ; wait write cycle to complete + rjmp EeWB ; before we can go on + adiw zl,1 ; count up EEPROM address + ret + +;----------------------------------------------------------------------- +; GET NEW PAGE +;----------------------------------------------------------------------- + +GetNewPage: + rcall RequestConfirm ; check for Confirm + brts GNPx ; abort if not confirmed +GNP0: + rcall YtoBUFFER ; Y = BUFFER, bcnt = PAGESIZE*2 +GNP1: + rcall ReceiveByte ; receive serial byte + st y+, tmp1 ; and store in buffer + dec bcnt ; until full page loaded + brne GNP1 ; loop on +GNPx: + ret ; finished +;----------------------------------------------------------------------- +; REQUEST TO CONFIRM / AWAIT CONFIRM COMMAND +;----------------------------------------------------------------------- + +RequestConfirm: + ldi tmp1, REQUEST ; send request character + rcall Transmitbyte ; prompt to confirm (or not) + +RwaitConfirm: + rcall ReceiveByte ; get host's reply + clt ; set T=0 for confirmation + cpi tmp1, CONFIRM ; if host HAS sent CONFIRM + breq RCx ; return with the T=0 + set ; else set T=1 (NOT CONFIRMED) +RCx: + ret ; whether confirmed or not + +;----------------------------------------------------------------------- +; FLASH ERASE TOP-TO-BOTTOM ( (BOOTSTART-1) ... $0000) +;----------------------------------------------------------------------- + +EraseAppFlash: + rcall ZtoLASTPAGE ; point Z to LASTPAGE, directly +EAF0: + subi zl, low (PAGESIZE*2) + sbci zh, high(PAGESIZE*2) + rcall EraseFlashPage + brne EAF0 ; until first page reached +EAFx: ret ; and leave with Z = $0000 + +;----------------------------------------------------------------------- +; EMERGENCY ERASE OF FLASH / EEPROM / USERDATA +;----------------------------------------------------------------------- + +EmergencyErase: + rcall EraseAppFlash ; erase Application Flash + ser tmp1 ; byte value for EEPROM writes +EEE0: + rcall EEWriteByte ; write EEPROM byte, Z = Z + 1 + cpi zh, high(EEPROMEND+1)+2 ; EEPROMEND + brne EEE0 ; and loop on until finished + + rcall ZtoLASTPAGE ; LASTPAGE is to be erased +; rcall EraseFlashPage + +;----------------------------------------------------------------------- +; ERASE ONE FLASH PAGE +;----------------------------------------------------------------------- + +EraseFlashPage: + ldi tmp1, 0b00000011 ; enable PGERS + SPMEN + out SPMCSR, tmp1 ; in SPMCSR and erase current + spm ; page by SPM (MCU halted) + +; Waiting for SPM to be finished is *obligatory* on ATmegas! +SPMwait: + in tmp1, SPMCSR + sbrc tmp1, 0 ; wait previous SPMEN + rjmp SPMwait + ldi tmp1, 0b00010001 ; set RWWSRE and SPMEN + out SPMCSR, tmp1 + spm + ret + +;----------------------------------------------------------------------- +; OTHER SUBROUTINES +;----------------------------------------------------------------------- + +YtoBUFFER: + ldi yl, low (BUFFER) ; reset pointer + ldi yh, high(BUFFER) ; to programming buffer + ldi bcnt, low(PAGESIZE*2) ; and often needed + ret + +;----------------------------------------------------------------------- + +ZtoLASTPAGE: + ldi zl, low (LASTPAGE*2) ; reset Z to LASTPAGE start + ldi zh, high(LASTPAGE*2) + ret + +;----------------------------------------------------------------------- +; RS232 RECEIVE BYTE +;----------------------------------------------------------------------- + +; uses: tmp1 (received data byte), cntr1 (for timeout) +; also uses utimeoutH which holds the default timeout defined by the user +; and X which is actually used to count down +SetRX: + ldi tmp1,(1<= ($1fff) + jmp $0000 ; absolute jump +.else + rjmp $0000 ; relative jump +.endif + + +DEVICEINFO: +.message "DEVICE INFO BLOCK FOR ATMEGA" +.db "TSB", low (BUILDDATE), high (BUILDDATE), BUILDSTATE +.db SIGNATURE_000, SIGNATURE_001, SIGNATURE_002, low (PAGESIZE) +.dw BOOTSTART-PAGESIZE +.dw EEPROMEND +.db $AA, $AA + + +;----------------------------------------------------------------------- +; DEVICE INFO BLOCK = PERMANENT DATA +;----------------------------------------------------------------------- + +; set last word with the clock speed +.org FLASHEND +.dw (F_CPU/1000000) + +//.message "SAVING CLOCK SPEED IN LAST BYTE AS " (F_CPU/1000000) " Mhz" + +.message "ASSEMBLY OF TSB FOR ATMEGA SUCCESSFULLY FINISHED!" + +.endif ; closing TSB for ATmega sourcecode; + +;*********************************************************************** +; END OF TSB FOR ATMEGAS +;*********************************************************************** + +.exit + +;*********************************************************************** +;*********************************************************************** +;*********************************************************************** +; END OF CONDITIONAL ASSEMBLY SOURCE OF TSB FOR ATTINYS AND ATMEGAS +;*********************************************************************** +;*********************************************************************** +;*********************************************************************** + +