-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathoptiboot.c
executable file
·688 lines (632 loc) · 26.1 KB
/
optiboot.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
#define FUNC_READ 1
#define FUNC_WRITE 1
/**********************************************************/
/* Optiboot bootloader for Arduino */
/* */
/* http://optiboot.googlecode.com */
/* */
/* Arduino-maintained version : See README.TXT */
/* http://code.google.com/p/arduino/ */
/* It is the intent that changes not relevant to the */
/* Arduino production envionment get moved from the */
/* optiboot project to the arduino project in "lumps." */
/* */
/* Heavily optimised bootloader that is faster and */
/* smaller than the Arduino standard bootloader */
/* */
/* Enhancements: */
/* Fits in 512 bytes, saving 1.5K of code space */
/* Higher baud rate speeds up programming */
/* Written almost entirely in C */
/* Customisable timeout with accurate timeconstant */
/* Optional virtual UART. No hardware UART required. */
/* Optional virtual boot partition for devices without. */
/* */
/* What you lose: */
/* Implements a skeleton STK500 protocol which is */
/* missing several features including EEPROM */
/* programming and non-page-aligned writes */
/* High baud rate breaks compatibility with standard */
/* Arduino flash settings */
/* */
/* Fully supported: */
/* ATmega168 based devices (Diecimila etc) */
/* ATmega328P based devices (Duemilanove etc) */
/* */
/* Beta test (believed working.) */
/* ATmega8 based devices (Arduino legacy) */
/* ATmega328 non-picopower devices */
/* ATmega644P based devices (Sanguino) */
/* ATmega1284P based devices */
/* ATmega1280 based devices (Arduino Mega) */
/* */
/* Alpha test */
/* ATmega32 */
/* */
/* Work in progress: */
/* ATtiny84 based devices (Luminet) */
/* */
/* Does not support: */
/* USB based devices (eg. Teensy, Leonardo) */
/* */
/* Assumptions: */
/* The code makes several assumptions that reduce the */
/* code size. They are all true after a hardware reset, */
/* but may not be true if the bootloader is called by */
/* other means or on other hardware. */
/* No interrupts can occur */
/* UART and Timer 1 are set to their reset state */
/* SP points to RAMEND */
/* */
/* Code builds on code, libraries and optimisations from: */
/* stk500boot.c by Jason P. Kyle */
/* Arduino bootloader http://arduino.cc */
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
/* avr-libc project http://nongnu.org/avr-libc */
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
/* AVR305 Atmel Application Note */
/* */
/* Copyright 2013-2015 by Bill Westfield. */
/* Copyright 2010 by Peter Knight. */
/* */
/* 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 2 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, write */
/* to the Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Licence can be viewed at */
/* http://www.fsf.org/licenses/gpl.txt */
/* */
/**********************************************************/
/**********************************************************/
/* */
/* Optional defines: */
/* */
/**********************************************************/
/* */
/* BIGBOOT: */
/* Build a 1k bootloader, not 512 bytes. This turns on */
/* extra functionality. */
/* */
/* BAUD_RATE: */
/* Set bootloader baud rate. */
/* */
/* SOFT_UART: */
/* Use AVR305 soft-UART instead of hardware UART. */
/* */
/* LED_START_FLASHES: */
/* Number of LED flashes on bootup. */
/* */
/* LED_DATA_FLASH: */
/* Flash LED when transferring data. For boards without */
/* TX or RX LEDs, or for people who like blinky lights. */
/* */
/* SUPPORT_EEPROM: */
/* Support reading and writing from EEPROM. This is not */
/* used by Arduino, so off by default. */
/* */
/* TIMEOUT_MS: */
/* Bootloader timeout period, in milliseconds. */
/* 500,1000,2000,4000,8000 supported. */
/* */
/* UART: */
/* UART number (0..n) for devices with more than */
/* one hardware uart (644P, 1284P, etc) */
/* */
/**********************************************************/
/**********************************************************/
/* Version Numbers! */
/* */
/* Arduino Optiboot now includes this Version number in */
/* the source and object code. */
/* */
/* Version 3 was released as zip from the optiboot */
/* repository and was distributed with Arduino 0022. */
/* Version 4 starts with the arduino repository commit */
/* that brought the arduino repository up-to-date with */
/* the optiboot source tree changes since v3. */
/* Version 5 was created at the time of the new Makefile */
/* structure (Mar, 2013), even though no binaries changed*/
/* It would be good if versions implemented outside the */
/* official repository used an out-of-seqeunce version */
/* number (like 104.6 if based on based on 4.5) to */
/* prevent collisions. */
/* */
/**********************************************************/
/**********************************************************/
/* Edit History: */
/* */
/* Aug 2014 */
/* 6.2 WestfW: make size of length variables dependent */
/* on the SPM_PAGESIZE. This saves space */
/* on the chips where it's most important. */
/* 6.1 WestfW: Fix OPTIBOOT_CUSTOMVER (send it!) */
/* Make no-wait mod less picky about */
/* skipping the bootloader. */
/* Remove some dead code */
/* Jun 2014 */
/* 6.0 WestfW: Modularize memory read/write functions */
/* Remove serial/flash overlap */
/* (and all references to NRWWSTART/etc) */
/* Correctly handle pagesize > 255bytes */
/* Add EEPROM support in BIGBOOT (1284) */
/* EEPROM write on small chips now causes err */
/* Split Makefile into smaller pieces */
/* Add Wicked devices Wildfire */
/* Move UART=n conditionals into pin_defs.h */
/* Remove LUDICOUS_SPEED option */
/* Replace inline assembler for .version */
/* and add OPTIBOOT_CUSTOMVER for user code */
/* Fix LED value for Bobuino (Makefile) */
/* Make all functions explicitly inline or */
/* noinline, so we fit when using gcc4.8 */
/* Change optimization options for gcc4.8 */
/* Make ENV=arduino work in 1.5.x trees. */
/* May 2014 */
/* 5.0 WestfW: Add support for 1Mbps UART */
/* Mar 2013 */
/* 5.0 WestfW: Major Makefile restructuring. */
/* See Makefile and pin_defs.h */
/* (no binary changes) */
/* */
/* 4.6 WestfW/Pito: Add ATmega32 support */
/* 4.6 WestfW/radoni: Don't set LED_PIN as an output if */
/* not used. (LED_START_FLASHES = 0) */
/* Jan 2013 */
/* 4.6 WestfW/dkinzer: use autoincrement lpm for read */
/* 4.6 WestfW/dkinzer: pass reset cause to app in R2 */
/* Mar 2012 */
/* 4.5 WestfW: add infrastructure for non-zero UARTS. */
/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */
/* Jan 2012: */
/* 4.5 WestfW: fix NRWW value for m1284. */
/* 4.4 WestfW: use attribute OS_main instead of naked for */
/* main(). This allows optimizations that we */
/* count on, which are prohibited in naked */
/* functions due to PR42240. (keeps us less */
/* than 512 bytes when compiler is gcc4.5 */
/* (code from 4.3.2 remains the same.) */
/* 4.4 WestfW and Maniacbug: Add m1284 support. This */
/* does not change the 328 binary, so the */
/* version number didn't change either. (?) */
/* June 2011: */
/* 4.4 WestfW: remove automatic soft_uart detect (didn't */
/* know what it was doing or why.) Added a */
/* check of the calculated BRG value instead. */
/* Version stays 4.4; existing binaries are */
/* not changed. */
/* 4.4 WestfW: add initialization of address to keep */
/* the compiler happy. Change SC'ed targets. */
/* Return the SW version via READ PARAM */
/* 4.3 WestfW: catch framing errors in getch(), so that */
/* AVRISP works without HW kludges. */
/* http://code.google.com/p/arduino/issues/detail?id=368n*/
/* 4.2 WestfW: reduce code size, fix timeouts, change */
/* verifySpace to use WDT instead of appstart */
/* 4.1 WestfW: put version number in binary. */
/**********************************************************/
#define OPTIBOOT_MAJVER 6
#define OPTIBOOT_MINVER 2
/*
* OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits
* of optiboot. That way you don't wind up with very different code that
* matches the version number of a "released" optiboot.
*/
#if !defined(OPTIBOOT_CUSTOMVER)
#define OPTIBOOT_CUSTOMVER 0
#endif
unsigned const int __attribute__((section(".version")))
optiboot_version = 256*(OPTIBOOT_MAJVER + OPTIBOOT_CUSTOMVER) + OPTIBOOT_MINVER;
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
/*
* Note that we use our own version of "boot.h"
* <avr/boot.h> uses sts instructions, but this version uses out instructions
* This saves cycles and program memory. Sorry for the name overlap.
*/
#include "boot.h"
#include "uart.h"
#include "watchdog.h"
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
/*
* pin_defs.h
* This contains most of the rather ugly defines that implement our
* ability to use UART=n and LED=D3, and some avr family bit name differences.
*/
#include "pin_defs.h"
/*
* stk500.h contains the constant definitions for the stk500v1 comm protocol
*/
#include "optiboot_stk500.h"
#ifndef LED_START_FLASHES
#define LED_START_FLASHES 0
#endif
/*
* We can never load flash with more than 1 page at a time, so we can save
* some code space on parts with smaller pagesize by using a smaller int.
*/
#if SPM_PAGESIZE > 255
typedef uint16_t pagelen_t ;
#define GETLENGTH(len) len = getch()<<8; len |= getch()
#else
typedef uint8_t pagelen_t;
#define GETLENGTH(len) (void) getch() /* skip high byte */; len = getch()
#endif
/* Function Prototypes
* The main() function is in init9, which removes the interrupt vector table
* we don't need. It is also 'OS_main', which means the compiler does not
* generate any entry or exit code itself (but unlike 'naked', it doesn't
* supress some compile-time options we want.)
*/
void __attribute__((noinline)) verifySpace();
void __attribute__((noinline)) watchdogConfig(uint8_t x);
static inline void getNch(uint8_t);
void getNch(uint8_t count) {
do getch(); while (--count);
verifySpace();
}
#if LED_START_FLASHES > 0
static inline void flash_led(uint8_t);
#endif
static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
uint16_t address, pagelen_t len);
static inline void read_mem(uint8_t memtype,
uint16_t address, pagelen_t len);
/*
* RAMSTART should be self-explanatory. It's bigger on parts with a
* lot of peripheral registers. Let 0x100 be the default
* Note that RAMSTART (for optiboot) need not be exactly at the start of RAM.
*/
#if !defined(RAMSTART) // newer versions of gcc avr-libc define RAMSTART
#define RAMSTART 0x100
#if defined (__AVR_ATmega644P__)
// correct for a bug in avr-libc
#undef SIGNATURE_2
#define SIGNATURE_2 0x0A
#elif defined(__AVR_ATmega1280__)
#undef RAMSTART
#define RAMSTART (0x200)
#endif
#endif
/* C zero initialises all global variables. However, that requires */
/* These definitions are NOT zero initialised, but that doesn't matter */
/* This allows us to drop the zero init code, saving us memory */
#define buff ((uint8_t*)(RAMSTART))
/* Virtual boot partition support */
#ifdef VIRTUAL_BOOT_PARTITION
#define rstVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+4))
#define rstVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+5))
#define saveVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+6))
#define saveVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+7))
// Vector to save original reset jump:
// SPM Ready is least probably used, so it's default
// if not, use old way WDT_vect_num,
// or simply set custom save_vect_num in Makefile using vector name
// or even raw number.
#if !defined (save_vect_num)
#if defined (SPM_RDY_vect_num)
#define save_vect_num (SPM_RDY_vect_num)
#elif defined (SPM_READY_vect_num)
#define save_vect_num (SPM_READY_vect_num)
#elif defined (WDT_vect_num)
#define save_vect_num (WDT_vect_num)
#else
#error Cant find SPM or WDT interrupt vector for this CPU
#endif
#endif //save_vect_num
// check if it's on the same page (code assumes that)
#if (SPM_PAGESIZE <= save_vect_num)
#error Save vector not in the same page as reset!
#endif
#if FLASHEND > 8192
// AVRs with more than 8k of flash have 4-byte vectors, and use jmp.
// We save only 16 bits of address, so devices with more than 128KB
// may behave wrong for upper part of address space.
#define rstVect0 2
#define rstVect1 3
#define saveVect0 (save_vect_num*4+2)
#define saveVect1 (save_vect_num*4+3)
#define appstart_vec (save_vect_num*2)
#else
// AVRs with up to 8k of flash have 2-byte vectors, and use rjmp.
#define rstVect0 0
#define rstVect1 1
#define saveVect0 (save_vect_num*2)
#define saveVect1 (save_vect_num*2+1)
#define appstart_vec (save_vect_num)
#endif
#else
#define appstart_vec (0)
#endif // VIRTUAL_BOOT_PARTITION
/* main program starts here */
int optiboot(void) {
uint8_t ch;
/*
* Making these local and in registers prevents the need for initializing
* them, and also saves space because code no longer stores to memory.
* (initializing address keeps the compiler happy, but isn't really
* necessary, and uses 4 bytes of flash.)
*/
register uint16_t address = 0;
register pagelen_t length;
/* Forever loop: exits by causing WDT reset */
for (;;) {
/* get character from UART */
ch = getch();
if(ch == STK_GET_PARAMETER) {
unsigned char which = getch();
verifySpace();
/*
* Send optiboot version as "SW version"
* Note that the references to memory are optimized away.
*/
if (which == STK_SW_MINOR) {
putch(optiboot_version & 0xFF);
} else if (which == STK_SW_MAJOR) {
putch(optiboot_version >> 8);
} else {
/*
* GET PARAMETER returns a generic 0x03 reply for
* other parameters - enough to keep Avrdude happy
*/
putch(0x03);
}
}
else if(ch == STK_SET_DEVICE) {
// SET DEVICE is ignored
getNch(20);
}
else if(ch == STK_SET_DEVICE_EXT) {
// SET DEVICE EXT is ignored
getNch(5);
}
else if(ch == STK_LOAD_ADDRESS) {
// LOAD ADDRESS
uint16_t newAddress;
newAddress = getch();
newAddress = (newAddress & 0xff) | (getch() << 8);
#ifdef RAMPZ
// Transfer top bit to RAMPZ
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
#endif
newAddress += newAddress; // Convert from word address to byte address
address = newAddress;
verifySpace();
}
else if(ch == STK_UNIVERSAL) {
// UNIVERSAL command is ignored
getNch(4);
putch(0x00);
}
/* Write memory, length is big endian and is in bytes */
else if(ch == STK_PROG_PAGE) {
// PROGRAM PAGE - we support flash programming only, not EEPROM
uint8_t desttype;
uint8_t *bufPtr;
pagelen_t savelength;
GETLENGTH(length);
savelength = length;
desttype = getch();
// read a page worth of contents
bufPtr = buff;
do *bufPtr++ = getch();
while (--length);
// Read command terminator, start reply
verifySpace();
#ifdef VIRTUAL_BOOT_PARTITION
#if FLASHEND > 8192
/*
* AVR with 4-byte ISR Vectors and "jmp"
* WARNING: this works only up to 128KB flash!
*/
if (address == 0) {
// This is the reset vector page. We need to live-patch the
// code so the bootloader runs first.
//
// Save jmp targets (for "Verify")
rstVect0_sav = buff[rstVect0];
rstVect1_sav = buff[rstVect1];
saveVect0_sav = buff[saveVect0];
saveVect1_sav = buff[saveVect1];
// Move RESET jmp target to 'save' vector
buff[saveVect0] = rstVect0_sav;
buff[saveVect1] = rstVect1_sav;
// Add jump to bootloader at RESET vector
// WARNING: this works as long as 'main' is in first section
buff[rstVect0] = ((uint16_t)main) & 0xFF;
buff[rstVect1] = ((uint16_t)main) >> 8;
}
#else
/*
* AVR with 2-byte ISR Vectors and rjmp
*/
if ((uint16_t)(void*)address == rstVect0) {
// This is the reset vector page. We need to live-patch
// the code so the bootloader runs first.
//
// Move RESET vector to 'save' vector
// Save jmp targets (for "Verify")
rstVect0_sav = buff[rstVect0];
rstVect1_sav = buff[rstVect1];
saveVect0_sav = buff[saveVect0];
saveVect1_sav = buff[saveVect1];
// Instruction is a relative jump (rjmp), so recalculate.
uint16_t vect=(rstVect0_sav & 0xff) | ((rstVect1_sav & 0x0f)<<8); //calculate 12b displacement
vect = (vect-save_vect_num) & 0x0fff; //substract 'save' interrupt position and wrap around 4096
// Move RESET jmp target to 'save' vector
buff[saveVect0] = vect & 0xff;
buff[saveVect1] = (vect >> 8) | 0xc0; //
// Add rjump to bootloader at RESET vector
vect = ((uint16_t)main) &0x0fff; //WARNIG: this works as long as 'main' is in first section
buff[0] = vect & 0xFF; // rjmp 0x1c00 instruction
buff[1] = (vect >> 8) | 0xC0;
}
#endif // FLASHEND
#endif // VBP
writebuffer(desttype, buff, address, savelength);
}
/* Read memory block mode, length is big endian. */
else if(ch == STK_READ_PAGE) {
uint8_t desttype;
GETLENGTH(length);
desttype = getch();
verifySpace();
read_mem(desttype, address, length);
}
/* Get device signature bytes */
else if(ch == STK_READ_SIGN) {
// READ SIGN - return what Avrdude wants to hear
verifySpace();
putch(SIGNATURE_0);
putch(SIGNATURE_1);
putch(SIGNATURE_2);
}
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
// Adaboot no-wait mod
watchdogConfig(WATCHDOG_16MS);
verifySpace();
}
else {
// This covers the response to commands like STK_ENTER_PROGMODE
verifySpace();
}
putch(STK_OK);
}
}
void verifySpace() {
if (getch() != CRC_EOP) {
// watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
// while (1) // and busy-loop so that WD causes
// ; // a reset and app start.
}
putch(STK_INSYNC);
}
#if LED_START_FLASHES > 0
void flash_led(uint8_t count) {
do {
TCNT1 = -(F_CPU/(1024*16));
TIFR1 = _BV(TOV1);
while(!(TIFR1 & _BV(TOV1)));
#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega16__)
LED_PORT ^= _BV(LED);
#else
LED_PIN |= _BV(LED);
#endif
watchdogReset();
} while (--count);
}
#endif
/*
* void writebuffer(memtype, buffer, address, length)
*/
static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
uint16_t address, pagelen_t len)
{
switch (memtype) {
case 'E': // EEPROM
#if defined(SUPPORT_EEPROM) || defined(BIGBOOT)
while(len--) {
eeprom_write_byte((uint8_t *)(address++), *mybuff++);
}
#else
/*
* On systems where EEPROM write is not supported, just busy-loop
* until the WDT expires, which will eventually cause an error on
* host system (which is what it should do.)
*/
while (1)
; // Error: wait for WDT
#endif
break;
default: // FLASH
/*
* Default to writing to Flash program memory. By making this
* the default rather than checking for the correct code, we save
* space on chips that don't support any other memory types.
*/
{
// Copy buffer into programming buffer
uint8_t *bufPtr = mybuff;
uint16_t addrPtr = (uint16_t)(void*)address;
/*
* Start the page erase and wait for it to finish. There
* used to be code to do this while receiving the data over
* the serial link, but the performance improvement was slight,
* and we needed the space back.
*/
__boot_page_erase_short((uint16_t)(void*)address);
boot_spm_busy_wait();
/*
* Copy data from the buffer into the flash write buffer.
*/
do {
uint16_t a;
a = *bufPtr++;
a |= (*bufPtr++) << 8;
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
addrPtr += 2;
} while (len -= 2);
/*
* Actually Write the buffer to flash (and wait for it to finish.)
*/
__boot_page_write_short((uint16_t)(void*)address);
boot_spm_busy_wait();
#if defined(RWWSRE)
// Reenable read access to flash
boot_rww_enable();
#endif
} // default block
break;
} // switch
}
static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length)
{
uint8_t ch;
switch (memtype) {
#if defined(SUPPORT_EEPROM) || defined(BIGBOOT)
case 'E': // EEPROM
do {
putch(eeprom_read_byte((uint8_t *)(address++)));
} while (--length);
break;
#endif
default:
do {
#ifdef VIRTUAL_BOOT_PARTITION
// Undo vector patch in bottom page so verify passes
if (address == rstVect0) ch = rstVect0_sav;
else if (address == rstVect1) ch = rstVect1_sav;
else if (address == saveVect0) ch = saveVect0_sav;
else if (address == saveVect1) ch = saveVect1_sav;
else ch = pgm_read_byte_near(address);
address++;
#elif defined(RAMPZ)
// Since RAMPZ should already be set, we need to use EPLM directly.
// Also, we can use the autoincrement version of lpm to update "address"
// do putch(pgm_read_byte_near(address++));
// while (--length);
// read a Flash and increment the address (may increment RAMPZ)
__asm__ ("elpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address));
#else
// read a Flash byte and increment the address
__asm__ ("lpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address));
#endif
putch(ch);
} while (--length);
break;
} // switch
}