"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",
"eeprom",
"eesize",
"evws",
+ "fusesize",
"ioend",
"lfcrlf",
"lockbits",
#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");
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");
int main (int argc, char **argv) {
+ struct SimUcInit *simUcInit = NULL;
struct StartParameters params;
memset((void *)¶ms, 0, sizeof(params));
params.filenames = NULL;
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";
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;
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);
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));
} 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);
int32_t avcc;
int32_t aref;
int nosync;
+ int log;
};
enum SimAvrState {
#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 = {\
.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) \
// 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 = {
*/
#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 = {
.make = make
};
+
*/
#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 = {
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;
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;
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,
uint16_t ioend;
uint16_t ramend;
uint32_t flashend;
+ uint16_t spm_pagesize;
uint32_t e2end;
uint8_t vector_size;
uint8_t signature[3];
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;
};
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
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;
}
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) {
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);
}
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;
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;
}
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);
}
}
} 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);
}
}
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)) {