From dd33d43225031b6108d0914ca5764dea32fcad4c Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sun, 4 Dec 2022 15:26:08 +0100 Subject: [PATCH] simuc V0.0.4 (merge from 1841259, simavr bugfix, simavr can parse fuses) --- examples/simuc/.vscode/settings.json | 9 ++- examples/simuc/src/main.cpp | 44 ++++++++++---- examples/simuc/src/sim/sim.cpp | 6 +- examples/simuc/src/simavr/simavr.cpp | 66 +++++++++++++++------ examples/simuc/src/simavr/simavr.h | 1 + simavr/cores/sim_core_declare.h | 10 +++- simavr/cores/sim_mega16.c | 72 ++++++++++++++++++++++- simavr/cores/sim_mega324.c | 85 +++++++++++++++++++++++++++- simavr/cores/sim_mega328.c | 77 ++++++++++++++++++++++++- simavr/sim/sim_avr.c | 7 ++- simavr/sim/sim_avr.h | 52 +++++++++++++++++ simavr/sim/sim_elf.c | 71 +++++++++++++++++------ simavr/sim/sim_gdb.c | 2 +- 13 files changed, 442 insertions(+), 60 deletions(-) diff --git a/examples/simuc/.vscode/settings.json b/examples/simuc/.vscode/settings.json index cb0d49d..4c1291f 100644 --- a/examples/simuc/.vscode/settings.json +++ b/examples/simuc/.vscode/settings.json @@ -58,7 +58,13 @@ "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", diff --git a/examples/simuc/src/main.cpp b/examples/simuc/src/main.cpp index 2da3f34..fe2fe31 100644 --- a/examples/simuc/src/main.cpp +++ b/examples/simuc/src/main.cpp @@ -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 *)¶ms, 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", ¶ms.gdbPort); - } else if (strcmp(argv[i], "--frequency") == 0) { + } else if (strcmp(argv[i], "--frequency") == 0 && argc >= (i + 1)) { sscanf(argv[++i], "%" PRIu64, ¶ms.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", ¶ms.pc); } else { sscanf(argv[++i], "%d", ¶ms.pc); } - } else if (strcmp(argv[i], "--vcc") == 0) { + } else if (strcmp(argv[i], "--vcc") == 0 && argc >= (i + 1)) { sscanf(argv[++i], "%d", ¶ms.vcc); - } else if (strcmp(argv[i], "--avcc") == 0) { + } else if (strcmp(argv[i], "--avcc") == 0 && argc >= (i + 1)) { sscanf(argv[++i], "%d", ¶ms.avcc); - } else if (strcmp(argv[i], "--aref") == 0) { + } else if (strcmp(argv[i], "--aref") == 0 && argc >= (i + 1)) { sscanf(argv[++i], "%d", ¶ms.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; diff --git a/examples/simuc/src/sim/sim.cpp b/examples/simuc/src/sim/sim.cpp index 7f0e3e3..4ba1da0 100644 --- a/examples/simuc/src/sim/sim.cpp +++ b/examples/simuc/src/sim/sim.cpp @@ -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); diff --git a/examples/simuc/src/simavr/simavr.cpp b/examples/simuc/src/simavr/simavr.cpp index ec59848..ac15d1f 100644 --- a/examples/simuc/src/simavr/simavr.cpp +++ b/examples/simuc/src/simavr/simavr.cpp @@ -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); diff --git a/examples/simuc/src/simavr/simavr.h b/examples/simuc/src/simavr/simavr.h index 38c84f4..1f2090b 100644 --- a/examples/simuc/src/simavr/simavr.h +++ b/examples/simuc/src/simavr/simavr.h @@ -31,6 +31,7 @@ struct StartParameters { int32_t avcc; int32_t aref; int nosync; + int log; }; enum SimAvrState { diff --git a/simavr/cores/sim_core_declare.h b/simavr/cores/sim_core_declare.h index 7d6dac7..eeae701 100644 --- a/simavr/cores/sim_core_declare.h +++ b/simavr/cores/sim_core_declare.h @@ -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) /* @@ -82,9 +83,10 @@ .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) \ diff --git a/simavr/cores/sim_mega16.c b/simavr/cores/sim_mega16.c index aa3563d..3c0fbb0 100644 --- a/simavr/cores/sim_mega16.c +++ b/simavr/cores/sim_mega16.c @@ -22,6 +22,7 @@ // atmega32 has different name for Watchdog Turn-off Enable register #define WDCE WDTOE #include "sim_avr.h" +#include #define SIM_VECTOR_SIZE 4 #define SIM_MMCU "atmega16" @@ -54,9 +55,78 @@ // 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 = { diff --git a/simavr/cores/sim_mega324.c b/simavr/cores/sim_mega324.c index 0697b76..15001e6 100644 --- a/simavr/cores/sim_mega324.c +++ b/simavr/cores/sim_mega324.c @@ -20,6 +20,7 @@ */ #include "sim_avr.h" +#include #define SIM_MMCU "atmega324" #define SIM_CORENAME mcu_mega324 @@ -37,12 +38,93 @@ #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 }; + diff --git a/simavr/cores/sim_mega328.c b/simavr/cores/sim_mega328.c index 3466939..ae7e891 100644 --- a/simavr/cores/sim_mega328.c +++ b/simavr/cores/sim_mega328.c @@ -20,6 +20,7 @@ */ #include "sim_avr.h" +#include #define SIM_VECTOR_SIZE 4 #define SIM_MMCU "atmega328" @@ -31,9 +32,83 @@ // 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 = { diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 24cb244..4b01ed0 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -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; diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index e9a97cd..1ba9786 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -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; diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 246af57..04b9180 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -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, §ion) || 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); } } diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c index 3989fc6..2291ceb 100644 --- a/simavr/sim/sim_gdb.c +++ b/simavr/sim/sim_gdb.c @@ -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)) { -- 2.39.5