Commit dd33d43225031b6108d0914ca5764dea32fcad4c
receivedSun, 4. Dec 2022, 15:26:12 (by user sx)
Sun, 4 Dec 2022 14:26:12 +0000 (15:26 +0100)
authorManfred Steiner <sx@htl-kaindorf.at>
Sun, 4 Dec 2022 14:26:08 +0000 (15:26 +0100)
committerManfred Steiner <sx@htl-kaindorf.at>
Sun, 4 Dec 2022 14:26:08 +0000 (15:26 +0100)
13 files changed:
examples/simuc/.vscode/settings.json
examples/simuc/src/main.cpp
examples/simuc/src/sim/sim.cpp
examples/simuc/src/simavr/simavr.cpp
examples/simuc/src/simavr/simavr.h
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
simavr/sim/sim_gdb.c

index cb0d49d32ce110ef793e205aa46020a9d6ee7aa4..4c1291f55dec43d8e2ffc89de9d93aecbbd05565 100644 (file)
         "thread": "cpp",
         "cinttypes": "cpp",
         "typeinfo": "cpp",
-        "variant": "cpp"
+        "variant": "cpp",
+        "iom324.h": "c",
+        "sim_megax4.h": "c",
+        "sim_core_declare.h": "c",
+        "iom328p.h": "c",
+        "iom16.h": "c",
+        "sim_avr.h": "c"
     },
     "cSpell.words": [
         "aref",
@@ -70,6 +76,7 @@
         "eeprom",
         "eesize",
         "evws",
+        "fusesize",
         "ioend",
         "lfcrlf",
         "lockbits",
index 2da3f340902ca18b0ca36bf0e0097d62f6a3cac3..fe2fe313fa8cc54c64aa16b61e6b343a68f9b590 100644 (file)
@@ -8,7 +8,7 @@
 #include "simavr/simavr.h"
 
 void printHelp () {
-    printf("simuc V0.0.3 (%s,%s)\n", __DATE__, __TIME__);
+    printf("simuc V0.0.4 (%s,%s)\n", __DATE__, __TIME__);
     printf("usage: simuc [options] elf-file [elf-file ...]\n\n");
     printf("  available options (you can use file .simucinit instead):\n");
     printf("    --port ...         listining port for gdb (default 1234)\n");
@@ -20,6 +20,8 @@ void printHelp () {
     printf("    --vcc ...          set voltage VCC in Volt\n");
     printf("    --avcc ...         set voltage AVCC in Volt\n");
     printf("    --aref ...         set voltage AREF in Volt\n\n");
+    printf("    --log ...          set simavr log level\n");
+    printf("                       (none, output, error, warning, trace or debug)\n");
     printf("  example:\n");
     printf("    simuc --mmcu atmega328p --frequency 16000000 --pc 0x7000 a.out\n");
     printf("    simuc --board arduino a.out\n\n");
@@ -32,6 +34,7 @@ struct SimUcInit {
 
 
 int main (int argc, char **argv) {
+    struct SimUcInit *simUcInit = NULL;
     struct StartParameters params;
     memset((void *)&params, 0, sizeof(params));
     params.filenames = NULL;
@@ -39,11 +42,12 @@ int main (int argc, char **argv) {
     params.frequency = -1;
     params.mmcu = NULL;
     params.board = BoardUnknown;
+    params.pc = -1;
     params.vcc = -1;
     params.avcc = -1;
     params.aref = -1;
     params.nosync = 0;
-    struct SimUcInit *simUcInit = NULL;
+    params.log = LOG_WARNING;
 
     if (argc <= 1) {
         const char *fileName = ".simucinit";
@@ -133,27 +137,47 @@ int main (int argc, char **argv) {
             if (strcmp(argv[i], "--board") == 0 && argc >= (i + 1)) {
                 i++;
                 continue;
-            } else if (strcmp(argv[i], "--mmcu") == 0) {
+            } else if (strcmp(argv[i], "--mmcu") == 0 && argc >= (i + 1)) {
                 params.mmcu = argv[++i];
-            } else if (strcmp(argv[i], "--port") == 0) {
+            } else if (strcmp(argv[i], "--port") == 0 && argc >= (i + 1)) {
                 sscanf(argv[++i], "%d", &params.gdbPort);
-            } else if (strcmp(argv[i], "--frequency") == 0) {
+            } else if (strcmp(argv[i], "--frequency") == 0 && argc >= (i + 1)) {
                 sscanf(argv[++i], "%" PRIu64, &params.frequency);
-            } else if (strcmp(argv[i], "--pc") == 0) {
+            } else if (strcmp(argv[i], "--pc") == 0 && argc >= (i + 1)) {
                 i++;
                 if (argv[i][0] == '0' && argv[i][1] == 'x') {
                     sscanf(&argv[i][2], "%x", &params.pc);
                 } else {
                     sscanf(argv[++i], "%d", &params.pc);
                 }
-            } else if (strcmp(argv[i], "--vcc") == 0) {
+            } else if (strcmp(argv[i], "--vcc") == 0 && argc >= (i + 1)) {
                 sscanf(argv[++i], "%d", &params.vcc);
-            } else if (strcmp(argv[i], "--avcc") == 0) {
+            } else if (strcmp(argv[i], "--avcc") == 0 && argc >= (i + 1)) {
                 sscanf(argv[++i], "%d", &params.avcc);
-            } else if (strcmp(argv[i], "--aref") == 0) {
+            } else if (strcmp(argv[i], "--aref") == 0 && argc >= (i + 1)) {
                 sscanf(argv[++i], "%d", &params.aref);
-            } else if (strcmp(argv[i], "--nosync") == 0) {
+            } else if (strcmp(argv[i], "--nosync") == 0 && argc >= (i + 1)) {
                 params.nosync = 1;
+            } else if (strcmp(argv[i], "--log") == 0 && argc >= (i + 1)) {
+                params.nosync = 1;
+                i++;
+                if (strcmp("none", argv[i]) == 0) {
+                    params.log = LOG_NONE;
+                } else if (strcmp("output", argv[i]) == 0) {
+                    params.log = LOG_OUTPUT;
+                } else if (strcmp("error", argv[i]) == 0) {
+                    params.log = LOG_ERROR;
+                } else if (strcmp("warning", argv[i]) == 0) {
+                    params.log = LOG_WARNING;
+                } else if (strcmp("trace", argv[i]) == 0) {
+                    params.log = LOG_TRACE;
+                } else if (strcmp("debug", argv[i]) == 0) {
+                    params.log = LOG_DEBUG;
+                } else {
+                    fprintf(stderr, "ERROR: invalid option %s, use --help to show usage\n\n", argv[i - 1]);
+                    return 1;
+                }
+
             } else {
                 fprintf(stderr, "ERROR: invalid option %s, use --help to show usage\n\n", argv[i]);
                 return 1;
index 7f0e3e3b9ce52c49faeeebe7feec8efc25d685b8..4ba1da09719a0a673e0e283ed59fe521d125e80d 100644 (file)
@@ -153,10 +153,8 @@ void init (struct StartParameters *param) {
                        std::logic_error(error(AT, "missing elf filename"));
                }
                simavr.load(param);
-               if (strcmp(simavr.getTargetDeviceName(), "atmega324p") != 0) {
-                       std::logic_error(error(AT, "invalid target device %s", simavr.getTargetDeviceName()));
-               }
-               
+
+               printf("--------------------------------------------------------------------\n");
                simavr.setUartDumpEnabled(false);
                // simavr.registerIoWrite(PORTB, handleWritePortB);
                simavr.setUartPtyEnabled(0, true);
index ec59848312dba0c83cb2e652c0637458981d89eb..ac15d1fc4f13249db4ddda9abfd8103d24fb787b 100644 (file)
@@ -67,10 +67,10 @@ void SimAvr::load (struct StartParameters *params) {
                for (int i = 0; params->filenames[i] != NULL; i++) {
                        std::string filename = std::string(params->filenames[i]);
                        printf("firmware file \"%s\"\n", params->filenames[i]);
-
                        if (firmware == NULL || elf_read_firmware(filename.c_str(), firmware) != 0) {
                                throw std::logic_error(error(AT, "elf_read_firmware() from %s fails", filename.c_str()));
                        }
+                       printf("--------------------------------------------------------------------\n");
                }
                if (params->mmcu != NULL) {
                        strncpy(firmware->mmcu, params->mmcu, sizeof(firmware->mmcu));
@@ -115,35 +115,65 @@ void SimAvr::load (struct StartParameters *params) {
                } else {
                        avr->gdb_port = 1234;
                }
-               printf("init with gdb-port=%d, mmcu=%s, f=%u, vcc=%d, avcc=%d, aref=%d, pc=0x%04x\n",
-                       avr->gdb_port, firmware->mmcu, firmware->frequency, firmware->vcc, firmware->avcc, firmware->aref, params->pc < 0 ? 0 : params->pc);
+
+               if (params->log >= LOG_TRACE) {
+                       printf("init with gdb-port=%d, mmcu=%s, f=%u, vcc=%d, avcc=%d, aref=%d, pc=0x%04x\n",
+                               avr->gdb_port, firmware->mmcu, firmware->frequency, firmware->vcc, firmware->avcc, firmware->aref, params->pc < 0 ? 0 : params->pc);
+               }
                status.freqHz = firmware->frequency;
 
+               // firmware->eeprom = (uint8_t *)malloc(1024);
+               // for (int i = 0; i < 1024; i++) {
+               //      firmware->eeprom[i] = 0xff;
+               // }
+               // firmware->eeprom[0] = 0x01;
+               // firmware->eesize = 1024;
+
+               printf("EEPROM: ");
+               if (firmware->eesize == 0) {
+                       printf("not defined (no section .eeprom found)");
+               } else {
+                       printf("%d bytes defined (", firmware->eesize);
+                       for (uint32_t i = 0; i < firmware->eesize; i++) {
+                               if (i > 6) {
+                                       printf(" ...");
+                                       break;
+                               } else if (i > 0) {
+                                       printf(" ");
+                               }
+                               printf("0x%02x", firmware->eeprom[i]);
+                       }
+                       printf(")\n");
+               }
+
+               if (params->pc >= 0) {
+                       avr->reset_pc = params->pc;
+                       printf("reset on 0x%04x (option --pc)\n", avr->reset_pc);
+               }
+
+               // avr_init() sets log level to LOG_WARNING
                if (avr_init(avr) != 0) {
                        throw std::logic_error(error(AT, "avr_init() fails"));
                }
 
-               
-               firmware->eeprom = (uint8_t *)malloc(1024);
-               for (int i = 0; i < 1024; i++) {
-                       firmware->eeprom[i] = 0xff;
+               // now we can chang log level to desired value
+               avr->log = params->log;
+               printf("simavr log level: ");
+               switch (avr->log) {
+                       case LOG_NONE: printf("NONE\n"); break;
+                       case LOG_OUTPUT: printf("OUTPUT\n"); break;
+                       case LOG_ERROR: printf("ERROR\n"); break;
+                       case LOG_WARNING: printf("WARNING\n"); break;
+                       case LOG_TRACE: printf("TRACE\n"); break;
+                       case LOG_DEBUG: printf("DEBUG\n"); break;
+                       default: printf(" ? (=%d)\n", avr->log); break;
                }
-               firmware->eeprom[0] = 0xf0;
-               firmware->eesize = 1024;
 
                avr_load_firmware(avr, firmware);
                status.state = StateLoaded;
 
-               avr->fuse[AVR_FUSE_LOW] = 0xe7;
-               avr->fuse[AVR_FUSE_HIGH] = 0xd8;
-               avr->fuse[AVR_FUSE_EXT] = 0xff;
-               avr->lockbits = 0xff;
-
-               avr->gdb_port = 1234;
+               avr->gdb_port = params->gdbPort > 0 ? params->gdbPort : 1234;
                avr_gdb_init(avr);
-               if (params->pc >= 0) {
-                       avr->pc = params->pc;
-               }
 
                pthread_mutex_unlock(&lock);
 
index 38c84f4670f2265a20b038ffe4e40ec3a61f4cfd..1f2090b3dfd931dfdc742d8c054f67eaa831da5e 100644 (file)
@@ -31,6 +31,7 @@ struct StartParameters {
     int32_t avcc;
     int32_t aref;
        int nosync;
+       int log;
 };
 
 enum SimAvrState {
index 7d6dac7bc41cd8549c1b97d5550f1f6b22f2e013..eeae701efd97303134f43e2cb229b4214d92f69b 100644 (file)
@@ -32,7 +32,8 @@
 #define _SFR_IO8(v) ((v)+32)
 #define _SFR_IO16(v) ((v)+32)
 #define _SFR_MEM8(v) (v)
-#define _BV(v) (v)
+// #define _BV(v) (1 << v)
+#define _BV(v) ( 1 << v >= 128 ? -128 : 1 << v )
 #define _VECTOR(v) (v)
 
 /*
        .ioend  = RAMSTART - 1, \
        .ramend = RAMEND, \
        .flashend = FLASHEND, \
+       .spm_pagesize = SPM_PAGESIZE, \
        .e2end = E2END, \
        .vector_size = _vector_size, \
-       .fuse = _FUSE_HELPER, \
+       .fuse = _FUSE_HELPER, \
        .signature = { SIGNATURE_0,SIGNATURE_1,SIGNATURE_2 }, \
        .lockbits = 0xFF, \
        .reset_flags = {\
@@ -92,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);
                }
        }
 
index 3989fc61a4fb8793361a79cba350cd57d92d3296..2291ceb9c03fc95b9c42a69ef5729527b08235fa 100644 (file)
@@ -980,7 +980,7 @@ avr_gdb_init(
        address.sin_port = htons (avr->gdb_port);
 
        if (bind(g->listen, (struct sockaddr *) &address, sizeof(address))) {
-               AVR_LOG(avr, LOG_ERROR, "GDB: Can not bind socket: %s", strerror(errno));
+               AVR_LOG(avr, LOG_ERROR, "GDB: Can not bind socket: %s\n", strerror(errno));
                goto error;
        }
        if (listen(g->listen, 1)) {