Commit 4d2d5f6d061af0ce244ae54496a434f15f59733f
receivedSun, 4. Dec 2022, 15:19:32 (by user sx)
Sun, 4 Dec 2022 14:19:32 +0000 (15:19 +0100)
authorManfred Steiner <sx@htl-kaindorf.at>
Sun, 4 Dec 2022 14:19:28 +0000 (15:19 +0100)
committerManfred Steiner <sx@htl-kaindorf.at>
Sun, 4 Dec 2022 14:19:28 +0000 (15:19 +0100)
7 files changed:
simavr/cores/sim_core_declare.h
simavr/cores/sim_mega16.c
simavr/cores/sim_mega324.c
simavr/cores/sim_mega328.c
simavr/sim/sim_avr.c
simavr/sim/sim_avr.h
simavr/sim/sim_elf.c

index 7e7677122c349bd764384fe3df5228ac833ac9b3..eeae701efd97303134f43e2cb229b4214d92f69b 100644 (file)
@@ -83,6 +83,7 @@
        .ioend  = RAMSTART - 1, \
        .ramend = RAMEND, \
        .flashend = FLASHEND, \
+       .spm_pagesize = SPM_PAGESIZE, \
        .e2end = E2END, \
        .vector_size = _vector_size, \
        .fuse = _FUSE_HELPER, \
@@ -93,7 +94,9 @@
                .extrf = AVR_IO_REGBIT(MCU_STATUS_REG, EXTRF),\
                .borf = AVR_IO_REGBIT(MCU_STATUS_REG, BORF),\
                .wdrf = AVR_IO_REGBIT(MCU_STATUS_REG, WDRF)\
-       }
+       }, \
+       .fuse_value = DEFAULT_avr_fuse_value, \
+       .lock_value = DEFAULT_avr_lock_value
 #else
 // Disable signature when using an old avr toolchain
 #define DEFAULT_CORE(_vector_size) \
index aa3563d3a1c389cdb0d06014695da14ed2a59d1e..3c0fbb0965833737ff8afebb96822f6a08df2245 100644 (file)
@@ -22,6 +22,7 @@
 // atmega32 has different name for Watchdog Turn-off Enable register 
 #define WDCE WDTOE
 #include "sim_avr.h"
+#include <string.h>
 
 #define SIM_VECTOR_SIZE        4
 #define SIM_MMCU               "atmega16"
 // instantiate the new core
 #include "sim_megax.h"
 
+static void init_fuse_lock(struct avr_t * avr)
+{
+       avr->fuse_value.lfuse = avr->fuse[0];
+       avr->fuse_value.hfuse = avr->fuse[1];
+
+       // 0= programmed (function active), 1=not programmed (function not active)
+       uint8_t lfuse = avr->fuse_value.lfuse;
+       avr->fuse_value.cksel =
+               (((lfuse & ~FUSE_CKSEL3) != 0) << 3) | (((lfuse & ~FUSE_CKSEL2) != 0) << 2) |
+               (((lfuse & ~FUSE_CKSEL1) != 0) << 1) | (((lfuse & ~FUSE_CKSEL0) != 0) << 0);
+       avr->fuse_value.sut = (((lfuse & ~FUSE_SUT1) != 0) << 1) | (((lfuse & ~FUSE_SUT0) != 0) << 0);
+       avr->fuse_value.boden_disabled = (lfuse & ~FUSE_BODEN) != 0;
+       avr->fuse_value.bodlevel = (lfuse & ~FUSE_BODLEVEL) != 0;
+
+       // 0= programmed (function active), 1=not programmed (function not active)
+       uint8_t hfuse = avr->fuse_value.hfuse;
+       avr->fuse_value.bootrst_disabled = (hfuse & ~FUSE_BOOTRST) != 0;
+       avr->fuse_value.bootsz = (((hfuse & ~FUSE_BOOTSZ0) != 0) << 1) | ((hfuse & ~FUSE_BOOTSZ1) != 0);
+       avr->fuse_value.eesave_disabled = (hfuse & ~FUSE_EESAVE) != 0;
+       avr->fuse_value.ckopt_disabled = (hfuse & ~FUSE_CKOPT) != 0;
+       avr->fuse_value.spien_disabled = (hfuse & ~FUSE_SPIEN) != 0;
+       avr->fuse_value.jtagen_disabled = (hfuse & ~FUSE_JTAGEN) != 0;
+       avr->fuse_value.ocden_disabled = (hfuse & ~FUSE_OCDEN) != 0;
+
+       memset(&avr->lock_value, 0x00, sizeof(avr_lock_value_t));
+       uint8_t lock = avr->lockbits;
+       avr->lock_value.lock = lock;
+       switch (lock & 0x03) {
+               case 0: avr->lock_value.mode3_dis_prg_ver = 1; break;
+               case 1: break;
+               case 2: avr->lock_value.mode2_dis_prg = 1; break;
+               case 3: avr->lock_value.mode1_nolock = 1; break;
+       }
+       switch ((lock >> 2)& 0x03) {
+               case 0: avr->lock_value.app_mode4_nolpm = 1; break;
+               case 1: avr->lock_value.app_mode3_nospmlpm = 1; break;
+               case 2: avr->lock_value.app_mode2_nospm = 1; break;
+               case 3: avr->lock_value.app_mode1_nolock = 1; break;
+       }
+       switch ((lock >> 4)& 0x03) {
+               case 0: avr->lock_value.boot_mode4_nolpm = 1; break;
+               case 1: avr->lock_value.boot_mode3_nospmlpm = 1; break;
+               case 2: avr->lock_value.boot_mode2_nospm = 1; break;
+               case 3: avr->lock_value.boot_mode1_nolock = 1; break;
+       }
+
+       if (FLASHEND == 0x3fff) {
+               switch (avr->fuse_value.bootsz) {
+                       case 0: avr->fuse_value.bootloader_pages = 16; break;
+                       case 1: avr->fuse_value.bootloader_pages =  8; break;
+                       case 2: avr->fuse_value.bootloader_pages =  4; break;
+                       case 3: avr->fuse_value.bootloader_pages =  2; break;
+               }
+               uint32_t appEnd = avr->flashend  - avr->fuse_value.bootloader_pages * avr->spm_pagesize;
+               AVR_LOG(avr, LOG_DEBUG, "HFUSE=0x%02x -> application 0..0x%04x, bootloader: 0x%04x..0x%04x\n", hfuse, appEnd, appEnd + 1, avr->flashend);
+               if (!avr->fuse_value.bootrst_disabled) {
+                       avr->reset_pc = appEnd + 1;
+                       avr->pc = avr->reset_pc;
+                       AVR_LOG(avr, LOG_OUTPUT, "HFUSE=0x%02x -> bootloader reset at 0x%04x\n", hfuse, avr->reset_pc);
+               }
+               
+       } else {
+               AVR_LOG(avr, LOG_WARNING, "init_fuse_bit() fails, invalid flash size\n");
+       }
+}
+
 static avr_t * make()
 {
-       return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
+       avr_t *avr = avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
+       avr->init_fuse_lock = init_fuse_lock;
+       avr->init_fuse_lock(avr);
+       return avr;
 }
 
 avr_kind_t mega16 = {
index 0697b76545158c600d353e72a27c7adf8559eea8..15001e6ab16f15439398b75b3cc5c9c10d274619 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "sim_avr.h"
+#include <string.h>
 
 #define SIM_MMCU               "atmega324"
 #define SIM_CORENAME   mcu_mega324
 #define EFUSE_DEFAULT (0xFF)
 #endif
 
+// #define HFUSE_DEFAULT 0
+
 // instantiate the new core
 #include "sim_megax4.h"
 
+#define _BVX(v) (1 << v) 
+#define BIT6 (unsigned char)~_BVX(6)
+#define BIT7 (unsigned char)~_BVX(7)
+#define VALUE_DEFAULT (BIT6 & BIT7)
+
+static void init_fuse_lock(struct avr_t * avr)
+{
+       avr->fuse_value.lfuse = avr->fuse[0];
+       avr->fuse_value.hfuse = avr->fuse[1];
+       avr->fuse_value.efuse = avr->fuse[2];
+
+       // 0= programmed (function active), 1=not programmed (function not active)
+       uint8_t lfuse = avr->fuse_value.lfuse;
+       avr->fuse_value.cksel =
+               (((lfuse & ~FUSE_CKSEL3) != 0) << 3) | (((lfuse & ~FUSE_CKSEL2) != 0) << 2) |
+               (((lfuse & ~FUSE_CKSEL1) != 0) << 1) | (((lfuse & ~FUSE_CKSEL0) != 0) << 0);
+       avr->fuse_value.sut = (((lfuse & ~FUSE_SUT1) != 0) << 1) | (((lfuse & ~FUSE_SUT0) != 0) << 0);
+       avr->fuse_value.ckout_disabled = (lfuse & ~FUSE_CKOUT) != 0;
+       avr->fuse_value.ckdiv8_disabled = (lfuse & ~FUSE_CKDIV8) != 0;
+
+       // 0= programmed (function active), 1=not programmed (function not active)
+       uint8_t hfuse = avr->fuse_value.hfuse;
+       avr->fuse_value.bootrst_disabled = (hfuse & ~FUSE_BOOTRST) != 0;
+       avr->fuse_value.bootsz = (((hfuse & ~FUSE_BOOTSZ0) != 0) << 1) | ((hfuse & ~FUSE_BOOTSZ1) != 0);
+       avr->fuse_value.eesave_disabled = (hfuse & ~FUSE_EESAVE) != 0;
+       avr->fuse_value.wdton_disabled = (hfuse & ~FUSE_WDTON) != 0;
+       avr->fuse_value.spien_disabled = (hfuse & ~FUSE_SPIEN) != 0;
+       avr->fuse_value.jtagen_disabled = (hfuse & ~FUSE_JTAGEN) != 0;
+       avr->fuse_value.ocden_disabled = (hfuse & ~FUSE_OCDEN) != 0;
+
+       uint8_t efuse = avr->fuse_value.efuse;
+       avr->fuse_value.bodlevel = (((efuse & ~FUSE_BODLEVEL2) != 0) << 2) |
+               (((efuse & ~FUSE_BODLEVEL1) != 0) << 1) | (((efuse & ~FUSE_BODLEVEL0) != 0) << 0);
+
+       memset(&avr->lock_value, 0x00, sizeof(avr_lock_value_t));
+       uint8_t lock = avr->lockbits;
+       avr->lock_value.lock = lock;
+       switch (lock & 0x03) {
+               case 0: avr->lock_value.mode3_dis_prg_ver = 1; break;
+               case 1: break;
+               case 2: avr->lock_value.mode2_dis_prg = 1; break;
+               case 3: avr->lock_value.mode1_nolock = 1; break;
+       }
+       switch ((lock >> 2)& 0x03) {
+               case 0: avr->lock_value.app_mode4_nolpm = 1; break;
+               case 1: avr->lock_value.app_mode3_nospmlpm = 1; break;
+               case 2: avr->lock_value.app_mode2_nospm = 1; break;
+               case 3: avr->lock_value.app_mode1_nolock = 1; break;
+       }
+       switch ((lock >> 4)& 0x03) {
+               case 0: avr->lock_value.boot_mode4_nolpm = 1; break;
+               case 1: avr->lock_value.boot_mode3_nospmlpm = 1; break;
+               case 2: avr->lock_value.boot_mode2_nospm = 1; break;
+               case 3: avr->lock_value.boot_mode1_nolock = 1; break;
+       }
+
+       if (FLASHEND == 0x7fff) {
+               switch (avr->fuse_value.bootsz) {
+                       case 0: avr->fuse_value.bootloader_pages = 32; break;
+                       case 1: avr->fuse_value.bootloader_pages = 16; break;
+                       case 2: avr->fuse_value.bootloader_pages =  8; break;
+                       case 3: avr->fuse_value.bootloader_pages =  4; break;
+               }
+               uint32_t appEnd = avr->flashend  - avr->fuse_value.bootloader_pages * avr->spm_pagesize;
+               AVR_LOG(avr, LOG_DEBUG, "HFUSE=0x%02x -> application 0..0x%04x, bootloader: 0x%04x..0x%04x\n", hfuse, appEnd, appEnd + 1, avr->flashend);
+               if (!avr->fuse_value.bootrst_disabled) {
+                       avr->reset_pc = appEnd + 1;
+                       avr->pc = avr->reset_pc;
+                       AVR_LOG(avr, LOG_OUTPUT, "HFUSE=0x%02x -> bootloader reset at 0x%04x\n", hfuse, avr->reset_pc);
+               }
+               
+       } else {
+               AVR_LOG(avr, LOG_WARNING, "init_fuse_bit() fails, invalid flash size\n");
+       }
+}
+
 static avr_t * make()
 {
-       return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
+       avr_t *avr = avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
+       avr->init_fuse_lock = init_fuse_lock;
+       avr->init_fuse_lock(avr);
+       return avr;
 }
 
 avr_kind_t mega324 = {
@@ -50,3 +132,4 @@ avr_kind_t mega324 = {
        .make = make
 };
 
+
index 346693928ed01a50b215ad1565eefc6d8c98548b..ae7e891ac295f2e38a39ac6dc43632a4ed83da0b 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "sim_avr.h"
+#include <string.h>
 
 #define SIM_VECTOR_SIZE        4
 #define SIM_MMCU               "atmega328"
 // instantiate the new core
 #include "sim_megax8.h"
 
+static void init_fuse_lock(struct avr_t * avr)
+{
+       avr->fuse_value.lfuse = avr->fuse[0];
+       avr->fuse_value.hfuse = avr->fuse[1];
+       avr->fuse_value.efuse = avr->fuse[2];
+
+       // 0= programmed (function active), 1=not programmed (function not active)
+       uint8_t lfuse = avr->fuse_value.lfuse;
+       avr->fuse_value.cksel =
+               (((lfuse & ~FUSE_CKSEL3) != 0) << 3) | (((lfuse & ~FUSE_CKSEL2) != 0) << 2) |
+               (((lfuse & ~FUSE_CKSEL1) != 0) << 1) | (((lfuse & ~FUSE_CKSEL0) != 0) << 0);
+       avr->fuse_value.sut = (((lfuse & ~FUSE_SUT1) != 0) << 1) | (((lfuse & ~FUSE_SUT0) != 0) << 0);
+       avr->fuse_value.ckout_disabled = (lfuse & ~FUSE_CKOUT) != 0;
+       avr->fuse_value.ckdiv8_disabled = (lfuse & ~FUSE_CKDIV8) != 0;
+
+       // 0= programmed (function active), 1=not programmed (function not active)
+       uint8_t hfuse = avr->fuse_value.hfuse;
+       avr->fuse_value.bootrst_disabled = (hfuse & ~FUSE_BOOTRST) != 0;
+       avr->fuse_value.bootsz = (((hfuse & ~FUSE_BOOTSZ0) != 0) << 1) | ((hfuse & ~FUSE_BOOTSZ1) != 0);
+       avr->fuse_value.eesave_disabled = (hfuse & ~FUSE_EESAVE) != 0;
+       avr->fuse_value.wdton_disabled = (hfuse & ~FUSE_WDTON) != 0;
+       avr->fuse_value.spien_disabled = (hfuse & ~FUSE_SPIEN) != 0;
+       avr->fuse_value.dwen_disabled = (hfuse & ~FUSE_DWEN) != 0;
+       avr->fuse_value.rstdisbl_disabled = (hfuse & ~FUSE_RSTDISBL) != 0;
+
+       uint8_t efuse = avr->fuse_value.efuse;
+       avr->fuse_value.bodlevel = (((efuse & ~FUSE_BODLEVEL2) != 0) << 2) |
+               (((efuse & ~FUSE_BODLEVEL1) != 0) << 1) | (((efuse & ~FUSE_BODLEVEL0) != 0) << 0);
+
+       memset(&avr->lock_value, 0x00, sizeof(avr_lock_value_t));
+       uint8_t lock = avr->lockbits;
+       avr->lock_value.lock = lock;
+       switch (lock & 0x03) {
+               case 0: avr->lock_value.mode3_dis_prg_ver = 1; break;
+               case 1: break;
+               case 2: avr->lock_value.mode2_dis_prg = 1; break;
+               case 3: avr->lock_value.mode1_nolock = 1; break;
+       }
+       switch ((lock >> 2)& 0x03) {
+               case 0: avr->lock_value.app_mode4_nolpm = 1; break;
+               case 1: avr->lock_value.app_mode3_nospmlpm = 1; break;
+               case 2: avr->lock_value.app_mode2_nospm = 1; break;
+               case 3: avr->lock_value.app_mode1_nolock = 1; break;
+       }
+       switch ((lock >> 4)& 0x03) {
+               case 0: avr->lock_value.boot_mode4_nolpm = 1; break;
+               case 1: avr->lock_value.boot_mode3_nospmlpm = 1; break;
+               case 2: avr->lock_value.boot_mode2_nospm = 1; break;
+               case 3: avr->lock_value.boot_mode1_nolock = 1; break;
+       }
+
+       if (FLASHEND == 0x7fff) {
+               switch (avr->fuse_value.bootsz) {
+                       case 0: avr->fuse_value.bootloader_pages = 32; break;
+                       case 1: avr->fuse_value.bootloader_pages = 16; break;
+                       case 2: avr->fuse_value.bootloader_pages =  8; break;
+                       case 3: avr->fuse_value.bootloader_pages =  4; break;
+               }
+               uint32_t appEnd = avr->flashend  - avr->fuse_value.bootloader_pages * avr->spm_pagesize;
+               AVR_LOG(avr, LOG_DEBUG, "HFUSE=0x%02x -> application 0..0x%04x, bootloader: 0x%04x..0x%04x\n", hfuse, appEnd, appEnd + 1, avr->flashend);
+               if (!avr->fuse_value.bootrst_disabled) {
+                       avr->reset_pc = appEnd + 1;
+                       avr->pc = avr->reset_pc;
+                       AVR_LOG(avr, LOG_OUTPUT, "HFUSE=0x%02x -> bootloader reset at 0x%04x\n", hfuse, avr->reset_pc);
+               }
+               
+       } else {
+               AVR_LOG(avr, LOG_WARNING, "init_fuse_bit() fails, invalid flash size\n");
+       }
+}
+
 static avr_t * make()
 {
-       return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
+       avr_t *avr = avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
+       avr->init_fuse_lock = init_fuse_lock;
+       avr->init_fuse_lock(avr);
+       return avr;
 }
 
 avr_kind_t mega328 = {
index 24cb2442857ff817a04310571a2104b2df095b6a..4b01ed08ff5e1169f64c0e92faa5118b6aa7396f 100644 (file)
@@ -123,7 +123,7 @@ avr_init(
        avr->sleep = avr_callback_sleep_raw;
        // number of address bytes to push/pull on/off the stack
        avr->address_size = avr->eind ? 3 : 2;
-       avr->log = 1;
+       avr->log = LOG_WARNING;
        avr_reset(avr);
        avr_regbit_set(avr, avr->reset_flags.porf);             // by  default set to power-on reset
        return 0;
@@ -160,8 +160,9 @@ void
 avr_reset(
                avr_t * avr)
 {
-       AVR_LOG(avr, LOG_TRACE, "%s reset\n", avr->mmcu);
-
+       if (avr->cycle > 0) {
+               AVR_LOG(avr, LOG_OUTPUT, "%s reset (PC set to 0x%04x)\n", avr->mmcu, avr->reset_pc);
+       }
        avr->state = cpu_Running;
        for(int i = 0x20; i <= avr->ioend; i++)
                avr->data[i] = 0;
index e9a97cde20e03f5f234e392d294e2b2e3d736057..1ba9786c32e0949f3de713721d5538817d79b609 100644 (file)
@@ -43,6 +43,51 @@ extern "C" {
 
 typedef uint32_t avr_flashaddr_t;
 
+// fuse values are initialized with -1 and set by device specific init_fuse_lock()
+// Attention: fuse unprogrammed -> bit=1 (function disabled) 
+//            fuse programmed   -> bit=0 (function enabled)
+#define DEFAULT_avr_fuse_value { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+typedef struct avr_fuse_value_t {
+       int lfuse;             // LFUSE
+       int hfuse;             // HFUSE
+       int efuse;             // EFUSE
+       int cksel;             // FUSE_CKSEL3, FUSE_CKSEL2, FUSE_CKSEL1, FUSE_CKSEL0
+       int sut;               // FUSE_SUT1, FUSE_SUT0
+       int ckout_disabled;    // FUSE_CKOUT
+       int ckdiv8_disabled;   // FUSE_CKDIV8
+       int     bootrst_disabled;  // FUSE_BOOTRST
+       int bootsz;            // FUSE_BOOTSZ1, FUSE_BOOTSZ0
+       int bootloader_pages;  // bootloader size in number of flash pages
+       int eesave_disabled;   // FUSE_EESAVE
+       int wdton_disabled;    // FUSE_WDTON
+       int ckopt_disabled;    // FUSE_CKOPT
+       int spien_disabled;    // FUSE_SPIEN
+       int jtagen_disabled;   // FUSE_JTAGEN
+       int ocden_disabled;    // FUSE_OCDEN
+       int dwen_disabled;     // FUSE FUSE_DWEN
+       int rstdisbl_disabled; // FUSE_RSTDISBL
+       int boden_disabled;    // FUSE BODEN
+       int bodlevel;          // FUSE_BODLEVEL2, FUSE_BODLEVEL1, FUSE_BODLEVEL0
+} avr_fuse_value_t;
+
+// lock values are initialized with -1 and set by device specific init_fuse_lock()
+#define DEFAULT_avr_lock_value { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+typedef struct avr_lock_value_t {
+       int lock;               // LOCK value
+       int mode1_nolock;        // Mode 1: No memory lock features enabled
+       int mode2_dis_prg;       // Mode 2: Further programming disabled
+       int mode3_dis_prg_ver;   // Mode 3: Further programming and verification disabled
+       int app_mode1_nolock;    // Application Mode 1, no lock on SPM and LPM
+       int app_mode2_nospm;     // Application Mode 2, SPM prohibited
+       int app_mode3_nospmlpm;  // Application Mode 3, SPM and LPM prohibited
+       int app_mode4_nolpm;     // Application Mode 4, LPM prohibited
+       int boot_mode1_nolock;   // Bootloader Mode 1, no lock on SPM and LPM
+       int boot_mode2_nospm;    // Bootloader Mode 2, SPM prohibited
+       int boot_mode3_nospmlpm; // Bootloader Mode 3, SPM and LPM prohibited
+       int boot_mode4_nolpm;    // Bootloader Mode 4, LPM prohibited
+} avr_lock_value_t;
+
+
 struct avr_t;
 typedef uint8_t (*avr_io_read_t)(
                struct avr_t * avr,
@@ -164,6 +209,7 @@ typedef struct avr_t {
        uint16_t                        ioend;
        uint16_t                        ramend;
        uint32_t                        flashend;
+       uint16_t            spm_pagesize;
        uint32_t                        e2end;
        uint8_t                         vector_size;
        uint8_t                         signature[3];
@@ -348,6 +394,12 @@ typedef struct avr_t {
                uint32_t size;
                uint32_t len;
        } io_console_buffer;
+
+       // fuse and lock bits (function called in avr_load_firmware())
+       void (*init_fuse_lock)(struct avr_t * avr);
+       struct avr_fuse_value_t fuse_value;
+       struct avr_lock_value_t lock_value;
+
 } avr_t;
 
 
index 246af5772cecf87b0a936e0eda3f61d6d1856cde..04b91805c36ef36dd5ef483ceda9c97c2166fc11 100644 (file)
@@ -86,8 +86,15 @@ avr_load_firmware(
                };
                avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
        }
-       if (firmware->fuse)
+       if (firmware->fuse) {
                memcpy(avr->fuse, firmware->fuse, firmware->fusesize);
+               AVR_LOG(avr, LOG_DEBUG, "fuses available, checking bootloader settings\n");
+               if (avr->init_fuse_lock) {
+                       avr->init_fuse_lock(avr);
+               } else {
+                       AVR_LOG(avr, LOG_WARNING, "WARNING: fuse and lock values ignored (no init_fuse_lock() found)\n");
+               }
+       }
        if (firmware->lockbits)
                avr->lockbits = firmware->lockbits[0];
        // load the default pull up/down values for ports
@@ -308,8 +315,6 @@ elf_handle_segment(int fd, Elf32_Phdr *php, uint8_t **dest, const char *name)
                                name, php->p_filesz, php->p_vaddr);
                return -1;
        }
-       AVR_LOG(NULL, LOG_DEBUG, "  Loaded %d (0x%0x) bytes (section offset 0x%04x)\n",
-               php->p_filesz, php->p_filesz, php->p_vaddr);
        return 0;
 }
 
@@ -380,19 +385,25 @@ elf_read_firmware(
                if (php->p_vaddr < 0x810000) {  // .text or .data section
                        if (firmware->flash == NULL) {
                                avr_t *avr = avr_make_mcu_by_name(firmware->mmcu);
+                               if (avr == NULL) {
+                                       AVR_LOG(NULL, LOG_ERROR, "  ERROR: cannot initialize flash, unknown mmcu name %s!\n", firmware->mmcu);
+                                       return -1;
+                               }
                                firmware->flashbase = 0;
                                firmware->flashsize = avr->flashend + 1;
+                               free(avr);
+                               avr = NULL;
                                if (firmware->flashsize <= 0) {
-                                       AVR_LOG(NULL, LOG_ERROR, "cannot initialize flash, unknown size!\n");
+                                       AVR_LOG(NULL, LOG_ERROR, "  ERROR: cannot initialize flash, unknown size!\n");
                                        return -1;
                                }
                                firmware->flash = (uint8_t *)malloc(firmware->flashsize);
                                if (firmware->flash == NULL) {
-                                       AVR_LOG(NULL, LOG_ERROR, "malloc flash memory fails!\n");
+                                       AVR_LOG(NULL, LOG_ERROR, "  ERROR: malloc flash memory fails!\n");
                                        return -1;
                                }
                                memset(firmware->flash, 0xff, firmware->flashsize);
-                               AVR_LOG(NULL, LOG_DEBUG, "flash initialization with 0xff (%d bytes)\n", firmware->flashsize);
+                               AVR_LOG(NULL, LOG_DEBUG, "  Flash (%d bytes = %dKiB) initialized with 0xff\n", firmware->flashsize, firmware->flashsize / 1024);
                        }
 
                        if (php->p_vaddr < 0x800000) {
@@ -407,14 +418,14 @@ elf_read_firmware(
                                isTextSectionLoaded = 0;
                        } else if (!isTextSectionLoaded) {
                                AVR_LOG(NULL, LOG_ERROR,
-                                               "Initialialised data but no flash (%d bytes at %x in file \"%s\")!\n",
+                                               "  ERROR: .data without .text (%d bytes at %x in file \"%s\")!\n",
                                                php->p_filesz, php->p_vaddr, file);
                                return -1;
                        }
                        uint8_t *section = NULL;
                        if (elf_copy_segment(fd, php, &section) || section == NULL) {
                                AVR_LOG(NULL, LOG_ERROR,
-                                       "cannot read section (%d bytes at %x in file \"%s\")!\n",
+                                       "  ERROR: cannot read section (%d bytes at %x in file \"%s\")!\n",
                                        php->p_filesz, php->p_vaddr, file);
                                if (section != NULL) {
                                        free(section);
@@ -422,8 +433,8 @@ elf_read_firmware(
                                }
                                return -1;
                        } else {
-                               AVR_LOG(NULL, LOG_DEBUG, "  Loading %d (0x%0x) bytes (section offset 0x%04x) to flash address 0x%04x\n",
-                                       php->p_filesz, php->p_filesz, php->p_vaddr, offset);
+                               AVR_LOG(NULL, LOG_OUTPUT, "  Loading section %s (%d=0x%0x bytes at 0x%04x) to flash 0x%04x\n",
+                                       isTextSectionLoaded ? ".text" : ".data", php->p_filesz, php->p_filesz, php->p_vaddr, offset);
                        }
 
                        uint32_t overlapping_start = UINT32_MAX;
@@ -432,7 +443,7 @@ elf_read_firmware(
                        for (uint32_t addr = offset; addr < (offset + php->p_filesz); addr++) {
                                if (addr >= firmware->flashsize) {
                                        AVR_LOG(NULL, LOG_ERROR,
-                                               "section out of flash address range (%d bytes at %x in file \"%s\")!\n",
+                                               "  ERROR: section out of flash address range (%d bytes at %x in file \"%s\")!\n",
                                                php->p_filesz, php->p_vaddr, file);
                                        return -1;
                                }
@@ -449,11 +460,11 @@ elf_read_firmware(
                        if (overlapping_start <= overlapping_end) {
                                if (overlapping_error) {
                                        AVR_LOG(NULL, LOG_OUTPUT,
-                                               "WARNING: overlapping section with different content (0x%04x..0x%04x)!\n",
+                                               "  WARNING: overlapping section with different content (0x%04x..0x%04x)!\n",
                                                overlapping_start, overlapping_end);
                                } else {
                                        AVR_LOG(NULL, LOG_OUTPUT,
-                                               "overlapping section with same content (0x%04x..0x%04x)!\n",
+                                               "  overlapping section with same content (0x%04x..0x%04x)!\n",
                                                overlapping_start, overlapping_end);
                                }
                        }
@@ -463,19 +474,45 @@ elf_read_firmware(
                } else if (php->p_vaddr < 0x820000) {
                        /* EEPROM. */
 
-                       if (elf_handle_segment(fd, php, &firmware->eeprom, "EEPROM"))
+                       if (elf_handle_segment(fd, php, &firmware->eeprom, "EEPROM")) {
+                               AVR_LOG(NULL, LOG_WARNING,
+                                       "  WARNING: Loading section .eeprom (%d bytes at 0x%04x) fails!\n",
+                                       php->p_filesz, php->p_vaddr);
                                continue;
+                       }
                        firmware->eesize = php->p_filesz;
+                       AVR_LOG(NULL, LOG_OUTPUT,
+                               "  Loading eeprom data from section .eeprom (%d bytes at 0x%04x)\n",
+                               php->p_filesz, php->p_vaddr);
+
                } else if (php->p_vaddr < 0x830000) {
                        /* Fuses. */
 
-                       if (elf_handle_segment(fd, php, &firmware->fuse, "Fuses"))
+                       if (elf_handle_segment(fd, php, &firmware->fuse, "Fuses")) {
+                               AVR_LOG(NULL, LOG_WARNING,
+                                       "WARNING: Loading section .fuse (%d bytes at 0x%04x) fails!\n",
+                                       php->p_filesz, php->p_vaddr);
                                continue;
+                       }
                        firmware->fusesize = php->p_filesz;
+                       char lfuse[16], hfuse[16], efuse[16];
+                       snprintf(lfuse, firmware->fusesize >= 1 ? sizeof(lfuse) : 1, " LFUSE=0x%02x", firmware->fusesize >= 1 ? firmware->fuse[0] : 0);
+                       snprintf(hfuse, firmware->fusesize >= 2 ? sizeof(lfuse) : 1, " HFUSE=0x%02x", firmware->fusesize >= 2 ? firmware->fuse[1] : 0);
+                       snprintf(efuse, firmware->fusesize >= 3 ? sizeof(lfuse) : 1, " EFUSE=0x%02x", firmware->fusesize >= 3 ? firmware->fuse[2] : 0);
+                       AVR_LOG(NULL, LOG_OUTPUT, "  Loading%s%s%s from section .fuse (%d bytes at 0x%04x)\n",
+                               lfuse, hfuse, efuse, php->p_filesz, php->p_vaddr);
+
                } else if (php->p_vaddr < 0x840000) {
                        /* Lock bits. */
-
-                       elf_handle_segment(fd, php, &firmware->lockbits, "Lock bits");
+                       if (elf_handle_segment(fd, php, &firmware->lockbits, "Lock bits")) {
+                               AVR_LOG(NULL, LOG_WARNING,
+                                       "  WARNING: Loading section .lock (%d bytes at 0x%04x) fails!\n",
+                                       php->p_filesz, php->p_vaddr);
+                               continue;
+                       }
+                       AVR_LOG(NULL, LOG_OUTPUT,
+                               "  Loading LOCK=0x%02x from section .lock (%d bytes at 0x%04x)\n",
+                               *firmware->lockbits, php->p_filesz, php->p_vaddr);
                }
        }