From 84ee69b450f354818f1399e680b2c8e36a6c05bf Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Wed, 13 Nov 2013 09:32:40 +0100 Subject: [PATCH 01/21] automake: don't treat warnings as errors. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4cd85cb..068ecf7 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ # common initialisation of autotools #### AC_INIT([SimulAVR], [1.1dev], [simulavr-devel@nongnu.org]) -AM_INIT_AUTOMAKE([1.10 -Wall -Werror foreign subdir-objects]) +AM_INIT_AUTOMAKE([1.10 -Wall foreign subdir-objects]) AC_PREREQ([2.61]) AC_CONFIG_MACRO_DIR([m4]) AM_MAINTAINER_MODE From ec8cf93cc84cd84ca6b1aca1beb29886ca0cab6c Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sat, 14 Jun 2014 12:46:06 +0200 Subject: [PATCH 02/21] src/avrreadelf.cpp: fix three formatting warnings. --- src/avrreadelf.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 2fe7dc5..e36a6fb 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -205,7 +205,7 @@ void ELFLoad(const AvrDevice * core) { } else if(value >= 0x840000 && value < 0x840400) { /* signature space starting from 0x840000, do nothing */; } else - avr_warning("Unknown symbol address range found! (symbol='%s', address=0x%llx)", + avr_warning("Unknown symbol address range found! (symbol='%s', address=0x%lx)", name.c_str(), value); @@ -248,7 +248,7 @@ void ELFLoad(const AvrDevice * core) { } else if(vma >= 0x840000 && vma < 0x840400) { // read and check signature, if available, space from 0x840000 to 0x840400 if(filesize != 3) - avr_error("wrong device signature size in elf file, expected=3, given=%llu", + avr_error("wrong device signature size in elf file, expected=3, given=%lu", filesize); else { unsigned int sig = (((data[2] << 8) + data[1]) << 8) + data[0]; @@ -290,7 +290,7 @@ unsigned int ELFGetSignature(const char *filename) { if(vma >= 0x840000 && vma < 0x840400) { // read and check signature, if available, space from 0x840000 to 0x840400 if(filesize != 3) - avr_error("wrong device signature size in elf file, expected=3, given=%llu", + avr_error("wrong device signature size in elf file, expected=3, given=%lu", filesize); else { const unsigned char* data = (const unsigned char*)pseg->get_data(); From 341cd1a82b67e830d31012a5dadccafccd8c0455 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Fri, 15 Nov 2013 22:44:07 +0100 Subject: [PATCH 03/21] Allow to store simulation parameters inside the ELF file. For now this is a proof of concept. Storing parameters works fine, reading them back, too, but instead of being used, they're simple written to the console. For now the parameters are device type and cpu frequency, but the concept can be extended easily to all other command line parameters. The proof is applied to the simple_serial example. The point of this strategy is to avoid the neccessity to run simulavr with more command line parameters than just the name of the ELF file. At compilation time we know best for which device we compile, after all. --- examples/simple_serial/Makefile.am | 1 + examples/simple_serial/main.c | 20 ++++++ src/avrreadelf.cpp | 35 +++++++++ src/simulavr_info.h | 112 +++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+) create mode 100644 src/simulavr_info.h diff --git a/examples/simple_serial/Makefile.am b/examples/simple_serial/Makefile.am index bebf7a7..75158dc 100644 --- a/examples/simple_serial/Makefile.am +++ b/examples/simple_serial/Makefile.am @@ -10,6 +10,7 @@ AVR_GCC = @AVR_GCC@ AVR_CPU = atmega644 AVR_FREQUENCY = 20000000 AVR_CFLAGS = -g -O2 -mmcu=$(AVR_CPU) -DF_CPU=$(AVR_FREQUENCY) +AVR_CFLAGS += -Wl,--section-start=.siminfo=0x900000 AVR_OBJS = main.o serial.o SIMULAVR_ARGS = -d $(AVR_CPU) -f $(EXAMPLE).elf diff --git a/examples/simple_serial/main.c b/examples/simple_serial/main.c index fd6ec66..608bb80 100644 --- a/examples/simple_serial/main.c +++ b/examples/simple_serial/main.c @@ -36,6 +36,26 @@ #include +/* + * Here we tell SimulAVR for which device and which frequency we build this + * code. The nice thing is, these macros add a section to the ELF file, so + * they can be read by SimulAVR, but they're also ignored when converted to + * an ihex file for hardware upload. Accordingly, the executed binary for + * SimulAVR and real hardware is the same, no need to recompile for one or + * another. The more important result of this is, behaviour is also exactly + * the same, no extra cycles for serving simulator matters. + * + * One small caveat: To stop the linker from stripping this section, avr-gcc + * needs an extra parameter when linking the binary (see Makefile.am): + * + * -Wl,--section-start=.siminfo=0x900000 + * + * For details on these macros, see the comments in simulavr_info.h. + */ +#include "../../src/simulavr_info.h" +SIMINFO_DEVICE("atmega644"); +SIMINFO_CPUFREQUENCY(F_CPU); + // This is all we need: int main (void) { diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index e36a6fb..2f197b4 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -31,10 +31,12 @@ #include "elfio/elfio.hpp" #include +#include #include #include #include "avrdevice_impl.h" +#include "simulavr_info.h" #include "avrreadelf.h" @@ -204,6 +206,8 @@ void ELFLoad(const AvrDevice * core) { /* lock bits starting from 0x830000, do nothing */; } else if(value >= 0x840000 && value < 0x840400) { /* signature space starting from 0x840000, do nothing */; + } else if(!strncmp("siminfo" , name.c_str(), 7)) { + /* SIMINFO symbol, do nothing */ } else avr_warning("Unknown symbol address range found! (symbol='%s', address=0x%lx)", name.c_str(), @@ -211,6 +215,37 @@ void ELFLoad(const AvrDevice * core) { } } + if(psec->get_name() == ".siminfo") { + /* + * You wonder why SIMINFO is read here, ignoring symbols? + * Well, doing things this way is pretty independent from ELF + * internals, other than finding the .siminfo section start pointer. + * Accordingly, we can add pretty much anything, as long as the + * interpretation here matches what's given in simulavr_info.h. + */ + ELFIO::Elf_Xword filesize = psec->get_size(); + const char *data = psec->get_data(); + const char *data_ptr = data, *data_end = data + filesize; + + while(data_ptr < data_end) { + char tag = *data_ptr++; + switch(tag) { + case SIMINFO_TAG_DEVICE: + avr_warning("device is %s", data_ptr); + while(*data_ptr != '\0') + data_ptr++; + data_ptr++; // the '\0' its self + break; + case SIMINFO_TAG_CPUFREQUENCY: + avr_warning("frequency is %u", *(uint32_t *)data_ptr); + data_ptr += sizeof(uint32_t); + break; + default: + avr_warning("Unknown tag in ELF .siminfo section: %hu", tag); + data_ptr++; + } + } + } } // load program, data and - if available - eeprom, fuses and signature diff --git a/src/simulavr_info.h b/src/simulavr_info.h new file mode 100644 index 0000000..51def63 --- /dev/null +++ b/src/simulavr_info.h @@ -0,0 +1,112 @@ +/* + **************************************************************************** + * + * simulavr - A simulator for the Atmel AVR family of microcontrollers. + * Copyright (C) 2013 Markus Hitter + * ELF storage strategy inspired by simavr by Michel Pollet. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + **************************************************************************** + * + * $Id$ + * + * This header provides macros to embed simulator setup information into + * a compiled ELF binary. + * + * Example: + * + * Add this somewhere at the root level of your AVR code: + * + * #include "simulavr_info.h" + * SIMINFO_DEVICE("atmega644"); + * SIMINFO_CPUFREQUENCY(F_CPU); + * + * Then link as usual, but add these linker flags to avr-gcc to prohibit + * the linker from removing the info sections at the link stage: + * + * -Wl,--section-start=.siminfo=0x900000 + * + * The value choosen here to be 0x900000 can be choosen freely, but must + * be above 0x840400, else it can conflict with program / eeprom / fuses / + * lockbits / signature data, see ELFLoad() in src/avrreadelf.cpp, line 215ff. + * + * You also have to avoid the -Wl,--gc-sections flag, which unfortunately + * increases binary size if you have unused functions. + * + * Having this done, running the ELF binary in the simulator will + * automatically inform simulavr for which AVR variant and CPU frequency + * the binary was built, making the corresponding command line parameters + * obsolete. In case you give both, in-binary and CLI parameters, CLI + * parameters take precedence. + * + * The really nice thing about this mechanism is, it doesn't alter the + * executed binary at all. You can upload and run this on real hardware, + * not a single byte of Flash memory or a single CPU cycle at runtime wasted. + */ + +#ifndef __SIMULAVR_INFO_H__ +#define __SIMULAVR_INFO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SIMINFO_SECTION __attribute__((section(".siminfo"))) + +enum { + SIMINFO_TAG_NOTAG = 0, // keep this unused as a protection against empty data + SIMINFO_TAG_DEVICE, + SIMINFO_TAG_CPUFREQUENCY, +}; + +struct siminfo_long_t { + uint8_t tag; + uint32_t value; +} __attribute__((__packed__)); + +struct siminfo_string_t { + uint8_t tag; + char string[]; +} __attribute__((__packed__)); + + +/* + * This gives the device type, like "attiny45", "atmega128", "atmega644", etc. + */ +#define SIMINFO_DEVICE(name) \ + const struct siminfo_string_t siminfo_device SIMINFO_SECTION = { \ + SIMINFO_TAG_DEVICE, \ + name \ + } + +/* + * This gives the cpu frequency, like 8000000UL or 16000000UL. + */ +#define SIMINFO_CPUFREQUENCY(value) \ + const struct siminfo_long_t siminfo_cpufrequency SIMINFO_SECTION = { \ + SIMINFO_TAG_CPUFREQUENCY, \ + value \ + } + + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIMULAVR_INFO_H__ */ From ba900e082c9993ecd5a98e1efa998091325ad991 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sat, 16 Nov 2013 17:03:27 +0100 Subject: [PATCH 04/21] ELF simulation info storage: bring SIMINFO_DEVICE() into action. --- src/avrfactory.cpp | 4 +- src/avrreadelf.cpp | 119 +++++++++++++++++++++++++++++++++++++-------- src/avrreadelf.h | 2 +- src/cmd/main.cpp | 36 ++++---------- 4 files changed, 112 insertions(+), 49 deletions(-) diff --git a/src/avrfactory.cpp b/src/avrfactory.cpp index 785a1e9..b6592fd 100644 --- a/src/avrfactory.cpp +++ b/src/avrfactory.cpp @@ -52,7 +52,9 @@ AvrDevice* AvrFactory::makeDevice(const char *in) { for(unsigned int i = 0; i < devname.size(); i++) devname[i] = tolower(devname[i]); if(devname == "unknown") - avr_error("Device type not specified, use -d | --device TYPE or insert '#insert ' into your source to specify device signature"); + avr_error("Device type not specified, use -d | --device TYPE or " + "insert a SIMINFO_DEVICE(name) macro into your source to " + "specify the device name"); AVRDeviceMap::iterator i = devmap.find(devname); if(i == devmap.end()) avr_error("Invalid device specification: %s", in); diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 2f197b4..6d2f62f 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -36,6 +36,7 @@ #include #include "avrdevice_impl.h" +#include "avrsignature.h" #include "simulavr_info.h" #include "avrreadelf.h" @@ -129,7 +130,7 @@ void ELFLoad(const AvrDevice * core) { fclose(f); } -unsigned int ELFGetSignature(const char *filename) { +unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename) { return std::numeric_limits::max(); } @@ -231,7 +232,7 @@ void ELFLoad(const AvrDevice * core) { char tag = *data_ptr++; switch(tag) { case SIMINFO_TAG_DEVICE: - avr_warning("device is %s", data_ptr); + // Device name. Handled in ELFGetDeviceNameAndSignature(). while(*data_ptr != '\0') data_ptr++; data_ptr++; // the '\0' its self @@ -298,8 +299,9 @@ void ELFLoad(const AvrDevice * core) { } } -unsigned int ELFGetSignature(const char *filename) { +unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename) { unsigned int signature = std::numeric_limits::max(); + unsigned int new_sig = 0; ELFIO::elfio reader; if(!reader.load(filename)) @@ -310,33 +312,110 @@ unsigned int ELFGetSignature(const char *filename) { filename, reader.get_machine()); - ELFIO::Elf_Half seg_num = reader.segments.size(); + // Command line takes precedence. + if(!strcmp(devicename, "unknown")) { + ELFIO::Elf_Half seg_num = reader.segments.size(); - for(ELFIO::Elf_Half i = 0; i < seg_num; i++) { - ELFIO::segment* pseg = reader.segments[i]; + for(ELFIO::Elf_Half i = 0; i < seg_num; i++) { + ELFIO::segment* pseg = reader.segments[i]; - if(pseg->get_type() == PT_LOAD) { - ELFIO::Elf_Xword filesize = pseg->get_file_size(); - ELFIO::Elf64_Addr vma = pseg->get_virtual_address(); + if(pseg->get_type() == PT_LOAD) { + ELFIO::Elf_Xword filesize = pseg->get_file_size(); + ELFIO::Elf64_Addr vma = pseg->get_virtual_address(); - if(filesize == 0) - continue; + if(filesize == 0) + continue; - if(vma >= 0x840000 && vma < 0x840400) { - // read and check signature, if available, space from 0x840000 to 0x840400 - if(filesize != 3) - avr_error("wrong device signature size in elf file, expected=3, given=%lu", - filesize); - else { - const unsigned char* data = (const unsigned char*)pseg->get_data(); + if(vma >= 0x840000 && vma < 0x840400) { + // read and check signature, if available, space from 0x840000 to 0x840400 + if(filesize != 3) + avr_error("wrong device signature size in elf file, " + "expected=3, given=%lu", filesize); + else { + const unsigned char* data = (const unsigned char*)pseg->get_data(); + + signature = (((data[2] << 8) + data[1]) << 8) + data[0]; + break; + } + } + } + } - signature = (((data[2] << 8) + data[1]) << 8) + data[0]; - break; + ELFIO::Elf_Half sec_num = reader.sections.size(); + + for(ELFIO::Elf_Half i = 0; i < sec_num; i++) { + ELFIO::section* psec = reader.sections[i]; + + if(psec->get_name() == ".siminfo") { + ELFIO::Elf_Xword filesize = psec->get_size(); + const char *data = psec->get_data(); + const char *data_ptr = data, *data_end = data + filesize; + + while(data_ptr < data_end) { + char tag = *data_ptr++; + switch(tag) { + case SIMINFO_TAG_DEVICE: + strncpy(devicename, data_ptr, 1024); + devicename[1023] = '\0'; // safety + while(*data_ptr != '\0') + data_ptr++; + data_ptr++; // the '\0' its self + break; + case SIMINFO_TAG_CPUFREQUENCY: + // Handled in ELF_Load(). + data_ptr += sizeof(uint32_t); + break; + default: + // Unknown tag, warning given in ELFLoad(). + data_ptr++; + } } } } + + if(strcmp(devicename, "unknown")) { + // We found a device name, find the signature of _this_ one. + std::map::iterator cur = + AvrNameToSignatureMap.find(devicename); + if(cur != AvrNameToSignatureMap.end()) { + new_sig = cur->second; + } else { + avr_warning("signature for device '%s' not found", devicename); + } + } + if(signature != 0) { + if(new_sig != 0 && signature != new_sig) { + avr_warning("ELF signature 0x%x taking precedence over " + "ELF siminfo device name %s", + signature, devicename); + } + } else + signature = new_sig; + } + else { + // We have a device name from the command line. + std::map::iterator cur = + AvrNameToSignatureMap.find(devicename); + if(cur != AvrNameToSignatureMap.end()) { + signature = cur->second; + } else { + avr_warning("signature for device '%s' not found", devicename); + } + } + + // If we've found _anything_, we've a signature now. + if(signature != 0) { + std::map::iterator cur = + AvrSignatureToNameMap.find(signature); + if(cur != AvrSignatureToNameMap.end()) { + strncpy(devicename, cur->second.c_str(), 1024); + } else { + // Assume signatures found by device name never get here. + avr_warning("unknown signature in ELF file: 0x%x", signature); + } } + avr_message("Device name is %s", devicename); return signature; } diff --git a/src/avrreadelf.h b/src/avrreadelf.h index ef09c2c..bf9b85e 100644 --- a/src/avrreadelf.h +++ b/src/avrreadelf.h @@ -28,7 +28,7 @@ #include "avrdevice.h" -unsigned int ELFGetSignature(const char *filename); +unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename); void ELFLoad(const AvrDevice * core); #endif diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp index c866714..eaf5eac 100644 --- a/src/cmd/main.cpp +++ b/src/cmd/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include using namespace std; @@ -275,7 +276,6 @@ int main(int argc, char *argv[]) { break; case 'd': - avr_message("Device to simulate: %s", optarg); devicename = optarg; break; @@ -350,35 +350,17 @@ int main(int argc, char *argv[]) { /* check, if devicename is given or get it out from elf file, if given */ unsigned int sig; - if(devicename == "unknown") { - // option -d | --device not given - if(filename != "unknown") { - // filename given, try to get signature - sig = ELFGetSignature(filename.c_str()); - if(sig != numeric_limits::max()) { - // signature in elf found, try to get devicename - std::map::iterator cur = AvrSignatureToNameMap.find(sig); - if(cur != AvrSignatureToNameMap.end()) { - // devicename found - devicename = cur->second; - } else { - avr_warning("unknown signature in elf file '%s': 0x%x", filename.c_str(), sig); - } - } - } + char *new_devicename = (char *)malloc(1024); // can't be static + + strncpy(new_devicename, devicename.c_str(), 1024); + if(filename != "unknown") { + sig = ELFGetDeviceNameAndSignature(filename.c_str(), new_devicename); } /* now we create the device and set device name and signature */ - AvrDevice *dev1 = AvrFactory::instance().makeDevice(devicename.c_str()); - std::map::iterator cur = AvrNameToSignatureMap.find(devicename); - if(cur != AvrNameToSignatureMap.end()) { - // signature found - sig = cur->second; - } else { - avr_warning("signature for device '%s' not found", devicename.c_str()); - sig = -1; - } - dev1->SetDeviceNameAndSignature(devicename, sig); + AvrDevice *dev1 = AvrFactory::instance().makeDevice(new_devicename); + dev1->SetDeviceNameAndSignature(new_devicename, sig); + free(new_devicename); /* We had to wait with dumping the available tracing values until the device has been created! */ From acf7bf3884084c7ab36ad5112da4358db0f8ea67 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sat, 16 Nov 2013 22:28:42 +0100 Subject: [PATCH 05/21] ELF simulation info storage: bring SIMINFO_CPUFREQUENCY() into action. Substantial part of this patch is a move from accessing protected properties of class AvrDevice directly to using their Getters. --- src/avrreadelf.cpp | 26 +++++++++++++------------- src/avrreadelf.h | 2 +- src/cmd/main.cpp | 21 +++++++++++++++------ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 6d2f62f..2c7955f 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -91,18 +91,18 @@ typedef struct { } Elf32_Phdr; void ELFLoad(const AvrDevice * core) { - FILE * f = fopen(core->actualFilename.c_str(), "rb"); + FILE * f = fopen(core->GetFname().c_str(), "rb"); if(f == NULL) - avr_error("Could not open file: %s", core->actualFilename.c_str()); + avr_error("Could not open file: %s", core->GetFname().c_str()); Elf32_Ehdr header; fread(&header, sizeof(header), 1, f); if(header.e_ident[0] != 0x7F || header.e_ident[1] != 'E' || header.e_ident[2] != 'L' || header.e_ident[3] != 'F') - avr_error("File '%s' is not an ELF file", core->actualFilename.c_str()); + avr_error("File '%s' is not an ELF file", core->GetFname().c_str()); // TODO: fix endianity in header if(header.e_machine != 83) - avr_error("ELF file '%s' is not for Atmel AVR architecture (%d)", core->actualFilename.c_str(), header.e_machine); + avr_error("ELF file '%s' is not for Atmel AVR architecture (%d)", core->GetFname().c_str(), header.e_machine); for(int i = 0; i < header.e_phnum; i++) { fseek(f, header.e_phoff + i * header.e_phentsize, SEEK_SET); @@ -117,7 +117,7 @@ void ELFLoad(const AvrDevice * core) { continue; // not into a Flash if(progHeader.p_filesz != progHeader.p_memsz) { avr_error("Segment sizes 0x%x and 0x%x in ELF file '%s' must be the same", - progHeader.p_filesz, progHeader.p_memsz, core->actualFilename.c_str()); + progHeader.p_filesz, progHeader.p_memsz, core->GetFname().c_str()); } unsigned char * tmp = new unsigned char[progHeader.p_filesz]; fseek(f, progHeader.p_offset, SEEK_SET); @@ -137,17 +137,16 @@ unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename #endif #ifndef _MSC_VER - -void ELFLoad(const AvrDevice * core) { +void ELFLoad(AvrDevice * core) { ELFIO::elfio reader; - if(!reader.load(core->actualFilename)) + if(!reader.load(core->GetFname())) avr_error("File '%s' not found or isn't a elf object", - core->actualFilename.c_str()); + core->GetFname().c_str()); if(reader.get_machine() != EM_AVR) avr_error("ELF file '%s' is not for Atmel AVR architecture (%d)", - core->actualFilename.c_str(), + core->GetFname().c_str(), reader.get_machine()); // over all symbols ... @@ -238,7 +237,7 @@ void ELFLoad(const AvrDevice * core) { data_ptr++; // the '\0' its self break; case SIMINFO_TAG_CPUFREQUENCY: - avr_warning("frequency is %u", *(uint32_t *)data_ptr); + core->SetClockFreq((SystemClockOffset)1000000000 / *(uint32_t *)data_ptr); data_ptr += sizeof(uint32_t); break; default: @@ -289,9 +288,10 @@ void ELFLoad(const AvrDevice * core) { else { unsigned int sig = (((data[2] << 8) + data[1]) << 8) + data[0]; - if(core->devSignature != std::numeric_limits::max() && sig != core->devSignature) + if(core->GetDeviceSignature() != std::numeric_limits::max() && + sig != core->GetDeviceSignature()) avr_error("wrong device signature, expected=0x%x, given=0x%x", - core->devSignature, + core->GetDeviceSignature(), sig); } } diff --git a/src/avrreadelf.h b/src/avrreadelf.h index bf9b85e..e42f070 100644 --- a/src/avrreadelf.h +++ b/src/avrreadelf.h @@ -29,6 +29,6 @@ #include "avrdevice.h" unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename); -void ELFLoad(const AvrDevice * core); +void ELFLoad(AvrDevice * core); #endif diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp index eaf5eac..4ac26e1 100644 --- a/src/cmd/main.cpp +++ b/src/cmd/main.cpp @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { int global_gdb_debug = 0; bool globalWaitForGdbConnection = true; //please wait for gdb connection int userinterface_flag = 0; - unsigned long long fcpu = 4000000; + unsigned long long fcpu = 0; unsigned long long maxRunTime = 0; unsigned long long linestotrace = 1000000; UserInterface *ui; @@ -241,9 +241,6 @@ int main(int argc, char *argv[]) { cerr << "frequency is zero" << endl; exit(1); } - if(global_verbose_on) - printf("Running with CPU frequency: %1.4f MHz (%lld Hz)\n", - fcpu/1000000.0, fcpu); break; case 'l': @@ -417,8 +414,20 @@ int main(int argc, char *argv[]) { //if not gdb, the ui will be master controller :-) ui = (userinterface_flag == 1) ? new UserInterface(7777) : NULL; - dev1->SetClockFreq(1000000000 / fcpu); // time base is 1ns! - + if(fcpu != 0) + dev1->SetClockFreq((SystemClockOffset)1000000000 / fcpu); // time base is 1ns! + + if(dev1->GetClockFreq() == 0) { + avr_warning("Clock frequency not given, defaulting to 4000000. " + "Use -F | --cpufrequency FREQ or insert a " + "SIMINFO_CPUFREQUENCY(freq) macro into your source %s", + "to specify it."); + dev1->SetClockFreq((SystemClockOffset)1000000000 / 4000000); + } + avr_message("Running with CPU frequency: %1.3lf MHz (%lld Hz)\n", + (double)1000 / dev1->GetClockFreq(), + (unsigned long long)1000000000 / dev1->GetClockFreq()); + if(sysConHandler.GetTraceState()) dev1->trace_on = 1; From a313903b52159b2c63161a498c41420b95dfd65b Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sat, 16 Nov 2013 23:57:59 +0100 Subject: [PATCH 06/21] ELF simulation info storage: introduce a length variable. This makes the ELf file slightly bigger, but reading it more simple and failure-proof. --- src/avrreadelf.cpp | 33 ++++++++++++--------------------- src/simulavr_info.h | 6 ++++++ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 2c7955f..9feb232 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -228,22 +228,20 @@ void ELFLoad(AvrDevice * core) { const char *data_ptr = data, *data_end = data + filesize; while(data_ptr < data_end) { - char tag = *data_ptr++; + char tag = *data_ptr; + char length = *(data_ptr + 1); switch(tag) { case SIMINFO_TAG_DEVICE: // Device name. Handled in ELFGetDeviceNameAndSignature(). - while(*data_ptr != '\0') - data_ptr++; - data_ptr++; // the '\0' its self break; case SIMINFO_TAG_CPUFREQUENCY: - core->SetClockFreq((SystemClockOffset)1000000000 / *(uint32_t *)data_ptr); - data_ptr += sizeof(uint32_t); + core->SetClockFreq((SystemClockOffset)1000000000 / + ((siminfo_long_t *)data_ptr)->value); break; default: avr_warning("Unknown tag in ELF .siminfo section: %hu", tag); - data_ptr++; } + data_ptr += length; } } } @@ -352,23 +350,16 @@ unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename const char *data_ptr = data, *data_end = data + filesize; while(data_ptr < data_end) { - char tag = *data_ptr++; - switch(tag) { - case SIMINFO_TAG_DEVICE: - strncpy(devicename, data_ptr, 1024); + char tag = *data_ptr; + char length = *(data_ptr + 1); + if(tag == SIMINFO_TAG_DEVICE) { + strncpy(devicename, + ((siminfo_string_t *)data_ptr)->string, 1024); devicename[1023] = '\0'; // safety - while(*data_ptr != '\0') - data_ptr++; - data_ptr++; // the '\0' its self break; - case SIMINFO_TAG_CPUFREQUENCY: - // Handled in ELF_Load(). - data_ptr += sizeof(uint32_t); - break; - default: - // Unknown tag, warning given in ELFLoad(). - data_ptr++; } + // Everything else handled in ELFLoad(). + data_ptr += length; } } } diff --git a/src/simulavr_info.h b/src/simulavr_info.h index 51def63..a1a5514 100644 --- a/src/simulavr_info.h +++ b/src/simulavr_info.h @@ -77,11 +77,13 @@ enum { struct siminfo_long_t { uint8_t tag; + uint8_t length; uint32_t value; } __attribute__((__packed__)); struct siminfo_string_t { uint8_t tag; + uint8_t length; char string[]; } __attribute__((__packed__)); @@ -92,6 +94,9 @@ struct siminfo_string_t { #define SIMINFO_DEVICE(name) \ const struct siminfo_string_t siminfo_device SIMINFO_SECTION = { \ SIMINFO_TAG_DEVICE, \ + /* We could use sizeof(siminfo_device) here, but avr-gcc has \ + been seen to set length to 0 (zero), then. */ \ + sizeof(name) + 2, \ name \ } @@ -101,6 +106,7 @@ struct siminfo_string_t { #define SIMINFO_CPUFREQUENCY(value) \ const struct siminfo_long_t siminfo_cpufrequency SIMINFO_SECTION = { \ SIMINFO_TAG_CPUFREQUENCY, \ + sizeof(uint32_t) + 2, \ value \ } From f50960bb2ec1c4ce1d5639139cd20d1ac8ea9ad7 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Mon, 18 Nov 2013 14:47:01 +0100 Subject: [PATCH 07/21] ELF simulation info storage: bail out on malformed .siminfo sections. avr-gcc has been seen to set the length field to zero. Clearly a bug, but ignoring bugs doesn't help. --- src/avrreadelf.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 9feb232..d741a76 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -230,6 +230,8 @@ void ELFLoad(AvrDevice * core) { while(data_ptr < data_end) { char tag = *data_ptr; char length = *(data_ptr + 1); + // Length check already done in ELFGetDeviceNameAndSignature(). + switch(tag) { case SIMINFO_TAG_DEVICE: // Device name. Handled in ELFGetDeviceNameAndSignature(). @@ -352,6 +354,9 @@ unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename while(data_ptr < data_end) { char tag = *data_ptr; char length = *(data_ptr + 1); + if(length == 0) + avr_error("Field of zero length in .siminfo" + "section in ELF file found."); if(tag == SIMINFO_TAG_DEVICE) { strncpy(devicename, ((siminfo_string_t *)data_ptr)->string, 1024); From d70b1ffb59621aca2c052442e69bebabb552f709 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Mon, 18 Nov 2013 13:45:19 +0100 Subject: [PATCH 08/21] ELF simulation info storage: introduce SIMINFO_SERIAL_OUT(). Applied to the simple_serial example, but no action yet, just the info transport. --- examples/simple_serial/main.c | 1 + src/avrreadelf.cpp | 6 ++++++ src/simulavr_info.h | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/examples/simple_serial/main.c b/examples/simple_serial/main.c index 608bb80..8f2756f 100644 --- a/examples/simple_serial/main.c +++ b/examples/simple_serial/main.c @@ -55,6 +55,7 @@ #include "../../src/simulavr_info.h" SIMINFO_DEVICE("atmega644"); SIMINFO_CPUFREQUENCY(F_CPU); +SIMINFO_SERIAL_OUT("D1", "-", 19200); // This is all we need: diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index d741a76..3ab0729 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -240,6 +240,12 @@ void ELFLoad(AvrDevice * core) { core->SetClockFreq((SystemClockOffset)1000000000 / ((siminfo_long_t *)data_ptr)->value); break; + case SIMINFO_TAG_SERIAL_OUT: + avr_warning("Want to connect pin %s to file %s at %d baud.", + ((siminfo_serial_t *)data_ptr)->pin, + ((siminfo_serial_t *)data_ptr)->filename, + ((siminfo_serial_t *)data_ptr)->baudrate); + break; default: avr_warning("Unknown tag in ELF .siminfo section: %hu", tag); } diff --git a/src/simulavr_info.h b/src/simulavr_info.h index a1a5514..a79eea6 100644 --- a/src/simulavr_info.h +++ b/src/simulavr_info.h @@ -73,6 +73,7 @@ enum { SIMINFO_TAG_NOTAG = 0, // keep this unused as a protection against empty data SIMINFO_TAG_DEVICE, SIMINFO_TAG_CPUFREQUENCY, + SIMINFO_TAG_SERIAL_OUT, }; struct siminfo_long_t { @@ -87,6 +88,14 @@ struct siminfo_string_t { char string[]; } __attribute__((__packed__)); +struct siminfo_serial_t { + uint8_t tag; + uint8_t length; + char pin[3]; + uint32_t baudrate; + char filename[]; +} __attribute__((__packed__)); + /* * This gives the device type, like "attiny45", "atmega128", "atmega644", etc. @@ -110,6 +119,34 @@ struct siminfo_string_t { value \ } +/* + * Create a serial out (Tx, from AVR) component. The given file will receive + * the characters/bytes. This can be connected to the same file as a serial in, + * if it's a special file like a real serial device or a pipe. Connecting both + * to the same regular file will mess things up. + * + * Using "-" as file name means connecting to the console (stdin/stdout). + * + * The pin to connect is named by a 2-character string, where "E2" means + * pin 2 on port E. + * + * Why a baud rate? Well, the component doesn't just fetch what's written + * to the UART send register, but interprets the signal on the pin. If your + * code sets a baud rate not matching the one given here, serial communications + * won't work. Just like a real serial device configured to work at 19200 baud + * won't work on a real serial port set to something else. + * + * Other parameters are fixed to 8N1, which means 8 bits, no parity, 1 stop bit. + */ +#define SIMINFO_SERIAL_OUT(pin, filename, baudrate) \ + const struct siminfo_serial_t siminfo_serial_out SIMINFO_SECTION = { \ + SIMINFO_TAG_SERIAL_OUT, \ + sizeof(char[3]) + sizeof(uint32_t) + sizeof(filename) + 2, \ + pin, \ + baudrate, \ + filename \ + } + #ifdef __cplusplus }; From 0552bc635e6a1766b61faa3aff67c2ee83016cf7 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Mon, 18 Nov 2013 19:04:23 +0100 Subject: [PATCH 09/21] ui/serialrx: implement SerialRxFile. This class moves serial output to a file, to a special file or to stdout. While there's special_output_port already, using an UI device neither changes the AVR code nor does it influence AVR behaviour. --- src/ui/serialrx.cpp | 30 ++++++++++++++++++++++++++++++ src/ui/serialrx.h | 13 +++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/ui/serialrx.cpp b/src/ui/serialrx.cpp index c24f6c1..1af84bb 100644 --- a/src/ui/serialrx.cpp +++ b/src/ui/serialrx.cpp @@ -26,6 +26,7 @@ #include "serialrx.h" #include "systemclock.h" #include "systemclocktypes.h" +#include using namespace std; @@ -150,6 +151,35 @@ long SerialRxBuffered::Size(){ // =========================================================================== +SerialRxFile::SerialRxFile(const char *filename) { + if (std::string(filename) == "-") + stream.std::ostream::rdbuf(std::cout.rdbuf()); + else + stream.open(filename); + // Enable automatic flushing, hitting ctrl-c to + // end a simulation doesn't call destructors. + stream << std::unitbuf; +} + +SerialRxFile::~SerialRxFile() { + if (stream.std::ostream::rdbuf() != std::cout.rdbuf()) + stream.close(); +} + +void SerialRxFile::CharReceived(unsigned char c){ + if (sendInHex) { + stream << "0x" << std::hex << (unsigned int)c << " "; + } else { + stream << c; + } +} + + +// =========================================================================== +// =========================================================================== +// =========================================================================== + + SerialRx::SerialRx(UserInterface *_ui, const char *_name, const char *baseWindow): ui(_ui), name(_name) { rx.RegisterCallback(this); diff --git a/src/ui/serialrx.h b/src/ui/serialrx.h index 0cb4253..f91ddb3 100644 --- a/src/ui/serialrx.h +++ b/src/ui/serialrx.h @@ -26,6 +26,7 @@ #ifndef SERIALRX_H_INCLUDED #define SERIALRX_H_INCLUDED +#include #include "systemclocktypes.h" #include "ui.h" #include "pinnotify.h" @@ -81,6 +82,18 @@ class SerialRxBuffered: public SerialRxBasic{ }; +/** Reads bits from device pins, reconstructs UART bytes and sends them to + * a file, a special file/com port or the console. */ +class SerialRxFile: public SerialRxBasic { + private: + std::ofstream stream; + protected: + virtual void CharReceived(unsigned char c); + public: + SerialRxFile(const char *filename); + ~SerialRxFile(); + }; + /** Reads bits from device pins, reconstructs UART bytes and sends them to UI. */ class SerialRx: public SerialRxBasic, public ExternalType{ protected: From 3c5224009e7da864faef1ad4657ee13d62fa31d0 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Mon, 18 Nov 2013 16:25:20 +0100 Subject: [PATCH 10/21] ELF simulation info storage: bring SIMINFO_SERIAL_OUT() into action. Once I found out on how it's done, it was surprisingly simple. Even better for the user: No need for TCL, no need for Python, no need for Swig, just add a single, simple macro to your AVR source code. --- src/avrreadelf.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 3ab0729..17c31c3 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -37,6 +37,7 @@ #include "avrdevice_impl.h" #include "avrsignature.h" +#include "serialrx.h" #include "simulavr_info.h" #include "avrreadelf.h" @@ -241,10 +242,18 @@ void ELFLoad(AvrDevice * core) { ((siminfo_long_t *)data_ptr)->value); break; case SIMINFO_TAG_SERIAL_OUT: - avr_warning("Want to connect pin %s to file %s at %d baud.", + avr_message("Connecting pin %s as serial out to file %s at %d baud.", ((siminfo_serial_t *)data_ptr)->pin, ((siminfo_serial_t *)data_ptr)->filename, ((siminfo_serial_t *)data_ptr)->baudrate); + { + Net *net = new Net(); + SerialRxFile *serial = + new SerialRxFile(((siminfo_serial_t *)data_ptr)->filename); + serial->SetBaudRate(((siminfo_serial_t *)data_ptr)->baudrate); + net->Add(core->GetPin(((siminfo_serial_t *)data_ptr)->pin)); + net->Add(serial->GetPin("rx")); + } break; default: avr_warning("Unknown tag in ELF .siminfo section: %hu", tag); From 5ac7b69494364cebb413ba413c2631eb067706a5 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Tue, 19 Nov 2013 15:59:57 +0100 Subject: [PATCH 11/21] ELF simulation info storage: introduce SIMINFO_SERIAL_IN(): Almost the same as SIMINFO_SERIAL_IN(), but the other direction. --- examples/simple_serial/main.c | 1 + src/avrreadelf.cpp | 6 ++++++ src/simulavr_info.h | 33 ++++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/examples/simple_serial/main.c b/examples/simple_serial/main.c index 8f2756f..a62ca84 100644 --- a/examples/simple_serial/main.c +++ b/examples/simple_serial/main.c @@ -55,6 +55,7 @@ #include "../../src/simulavr_info.h" SIMINFO_DEVICE("atmega644"); SIMINFO_CPUFREQUENCY(F_CPU); +SIMINFO_SERIAL_IN("D0", "-", 19200); SIMINFO_SERIAL_OUT("D1", "-", 19200); diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 17c31c3..9c70262 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -241,6 +241,12 @@ void ELFLoad(AvrDevice * core) { core->SetClockFreq((SystemClockOffset)1000000000 / ((siminfo_long_t *)data_ptr)->value); break; + case SIMINFO_TAG_SERIAL_IN: + avr_warning("Want to connect pin %s to file %s at %d baud.", + ((siminfo_serial_t *)data_ptr)->pin, + ((siminfo_serial_t *)data_ptr)->filename, + ((siminfo_serial_t *)data_ptr)->baudrate); + break; case SIMINFO_TAG_SERIAL_OUT: avr_message("Connecting pin %s as serial out to file %s at %d baud.", ((siminfo_serial_t *)data_ptr)->pin, diff --git a/src/simulavr_info.h b/src/simulavr_info.h index a79eea6..52e392e 100644 --- a/src/simulavr_info.h +++ b/src/simulavr_info.h @@ -74,6 +74,7 @@ enum { SIMINFO_TAG_DEVICE, SIMINFO_TAG_CPUFREQUENCY, SIMINFO_TAG_SERIAL_OUT, + SIMINFO_TAG_SERIAL_IN, }; struct siminfo_long_t { @@ -120,24 +121,38 @@ struct siminfo_serial_t { } /* - * Create a serial out (Tx, from AVR) component. The given file will receive - * the characters/bytes. This can be connected to the same file as a serial in, - * if it's a special file like a real serial device or a pipe. Connecting both - * to the same regular file will mess things up. + * Create a serial in (Rx, to AVR) component. The the sent characters/bytes + * will be taken from the given file. This component can be connected to the + * same file as a serial out, if it's a special file like a real serial device + * or a pipe. Connecting both to the same regular file will mess things up. * * Using "-" as file name means connecting to the console (stdin/stdout). * * The pin to connect is named by a 2-character string, where "E2" means * pin 2 on port E. * - * Why a baud rate? Well, the component doesn't just fetch what's written - * to the UART send register, but interprets the signal on the pin. If your - * code sets a baud rate not matching the one given here, serial communications - * won't work. Just like a real serial device configured to work at 19200 baud - * won't work on a real serial port set to something else. + * Why a baud rate? Well, the component doesn't just write to the UART receive + * register, but synthesizes actual serial signals on the pin, which in turn + * should be interpreted by your AVR code. If your code sets a baud rate not + * matching the one given here, serial communications won't work. Just like a + * real serial device configured to work at 19200 baud won't work on a real + * serial port set to something else. * * Other parameters are fixed to 8N1, which means 8 bits, no parity, 1 stop bit. */ +#define SIMINFO_SERIAL_IN(pin, filename, baudrate) \ + const struct siminfo_serial_t siminfo_serial_in SIMINFO_SECTION = { \ + SIMINFO_TAG_SERIAL_IN, \ + sizeof(char[3]) + sizeof(uint32_t) + sizeof(filename) + 2, \ + pin, \ + baudrate, \ + filename \ + } + +/* + * Create a serial out (Tx, from AVR) component. Same as above, but the + * other direction. The serial port pin is continuously read and interpreted. + */ #define SIMINFO_SERIAL_OUT(pin, filename, baudrate) \ const struct siminfo_serial_t siminfo_serial_out SIMINFO_SECTION = { \ SIMINFO_TAG_SERIAL_OUT, \ From 1d1046af3a5f6996f50464cf8bcba186e5c47094 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Tue, 19 Nov 2013 21:07:50 +0100 Subject: [PATCH 12/21] ui/serialtx: implement SerialTxFile. Just like the Rx counterpart, this is for communications between a file/special file/console and the actually simulated UART. Works beautifully. --- src/ui/serialtx.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++- src/ui/serialtx.h | 17 +++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/ui/serialtx.cpp b/src/ui/serialtx.cpp index a987578..4663526 100644 --- a/src/ui/serialtx.cpp +++ b/src/ui/serialtx.cpp @@ -107,7 +107,7 @@ void SerialTxBuffered::Send(unsigned char data) { inputBuffer.push_back(data); //write new char to input buffer - cerr << "TX: " << hex << data << " "; + // cerr << "TX: " << hex << data << endl; //if we not active, activate tx machine now if (txState==TX_DISABLED) { txState=TX_SEND_STARTBIT; @@ -115,6 +115,10 @@ void SerialTxBuffered::Send(unsigned char data) } } +bool SerialTxBuffered::Sending(void) { + return (txState != TX_DISABLED); +} + void SerialTxBuffered::SetBaudRate(SystemClockOffset baud){ baudrate = baud; } @@ -124,6 +128,60 @@ void SerialTxBuffered::SetHexInput(bool newValue){ } +// =========================================================================== +// =========================================================================== +// =========================================================================== + +#include +#include +#include +#include + +SerialTxFile::SerialTxFile(const char *filename) { + if (std::string(filename) == "-") + fd = fileno(stdin); + else + fd = open(filename, O_RDONLY, O_CREAT); + if (fd < 0) + avr_error("open input file failed"); + Reset(); + + SystemClock::Instance().Add(this); +} + +SerialTxFile::~SerialTxFile() { + if (fd != fileno(stdin)) + close(fd); +} + +int SerialTxFile::Step(bool &trueHwStep, + SystemClockOffset *timeToNextStepIn_ns) { + + if (Sending()) { + SerialTxBuffered::Step(trueHwStep, timeToNextStepIn_ns); + } + +#ifndef WIN32 + pollfd cinfd[1]; + cinfd[0].fd = fd; + cinfd[0].events = POLLIN; + if (poll(cinfd, 1, 0) > 0) { +#else + HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + if (WaitForSingleObject(h, 0) == WAIT_OBJECT_0) { +#endif + unsigned char c; + if (read(fd, &c, 1)) { + Send((unsigned char)c); + } + } + + if ( ! Sending()) // may have changed with Step() or Send() + // Polling for new data every millisecond should be enough. If there's + // more than one byte waiting, they're accepted at every serial clock + // tick, which means, ten times faster than they can be sent. + *timeToNextStepIn_ns = (SystemClockOffset)1000000; +} // =========================================================================== // =========================================================================== diff --git a/src/ui/serialtx.h b/src/ui/serialtx.h index de40a74..4565892 100644 --- a/src/ui/serialtx.h +++ b/src/ui/serialtx.h @@ -61,10 +61,27 @@ class SerialTxBuffered: public SimulationMember { virtual int Step(bool &trueHwStep, SystemClockOffset *timeToNextStepIn_ns=0); /// Add byte from UI to be sent to device's UART. virtual void Send(unsigned char data); + bool Sending(void); virtual void SetBaudRate(SystemClockOffset baud); virtual Pin* GetPin(const char *name); }; +#include +#include + +/** Reads bytes from a file, a special file/com port or the console + * and sends them to the device's UART. */ +class SerialTxFile: public SerialTxBuffered { + private: + // Use a classic file descriptor to have better + // control over buffers (and their avoidance). + int fd; + public: + SerialTxFile(const char *filename); + ~SerialTxFile(); + virtual int Step(bool &trueHwStep, SystemClockOffset *timeToNextStepIn_ns=0); +}; + /** Buffers byte from UI to be sent to device's UART. */ class SerialTx: public SerialTxBuffered, public ExternalType { From 6ee8cb86d76fb1952dacea9ff4adb3c441ad661d Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Tue, 19 Nov 2013 15:39:53 +0100 Subject: [PATCH 13/21] ELF simulation info storage: bring SIMINFO_SERIAL_IN() into action. Just as the Rx counterpart, you can now connect to the console, a pipe file or even a serial device file of the host. All without additional scripting and languages, just a macro in the AVR source code. --- src/avrreadelf.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 9c70262..9311f3b 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -38,6 +38,7 @@ #include "avrdevice_impl.h" #include "avrsignature.h" #include "serialrx.h" +#include "serialtx.h" #include "simulavr_info.h" #include "avrreadelf.h" @@ -242,10 +243,18 @@ void ELFLoad(AvrDevice * core) { ((siminfo_long_t *)data_ptr)->value); break; case SIMINFO_TAG_SERIAL_IN: - avr_warning("Want to connect pin %s to file %s at %d baud.", - ((siminfo_serial_t *)data_ptr)->pin, + avr_message("Connecting file %s as serial in to pin %s at %d baud.", ((siminfo_serial_t *)data_ptr)->filename, + ((siminfo_serial_t *)data_ptr)->pin, ((siminfo_serial_t *)data_ptr)->baudrate); + { + Net *net = new Net(); + SerialTxFile *serial = + new SerialTxFile(((siminfo_serial_t *)data_ptr)->filename); + serial->SetBaudRate(((siminfo_serial_t *)data_ptr)->baudrate); + net->Add(core->GetPin(((siminfo_serial_t *)data_ptr)->pin)); + net->Add(serial->GetPin("tx")); + } break; case SIMINFO_TAG_SERIAL_OUT: avr_message("Connecting pin %s as serial out to file %s at %d baud.", From f5c049f57aaf4903cf11f1885737a6416c31f1b9 Mon Sep 17 00:00:00 2001 From: miso Date: Thu, 8 May 2014 01:15:50 +0200 Subject: [PATCH 14/21] src/traceval.[h,cpp]: fix string indexing types. --- src/traceval.cpp | 29 ++++++++++++++--------------- src/traceval.h | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/traceval.cpp b/src/traceval.cpp index be2e136..133cfd0 100644 --- a/src/traceval.cpp +++ b/src/traceval.cpp @@ -202,7 +202,7 @@ void TraceValueRegister::_tvr_insertTraceValuesToSet(TraceSet &t) { void TraceValueRegister::RegisterTraceValue(TraceValue *t) { // check for duplicate names and the right prefix string p = t->name(); - unsigned int idx = _tvr_scopeprefix.length(); + size_t idx = _tvr_scopeprefix.length(); if((p.length() <= idx) || (p.substr(0, idx) != _tvr_scopeprefix)) avr_error("add TraceValue denied: wrong prefix: '%s', scope is '%s'", p.c_str(), _tvr_scopeprefix.c_str()); @@ -220,7 +220,7 @@ void TraceValueRegister::RegisterTraceValue(TraceValue *t) { } void TraceValueRegister::UnregisterTraceValue(TraceValue *t) { - int idx = _tvr_scopeprefix.length(); + size_t idx = _tvr_scopeprefix.length(); string n = t->name().substr(idx); for (valmap_t::iterator i = _tvr_values.begin(); i != _tvr_values.end(); i++) { if(n == *(i->first)) { @@ -247,8 +247,8 @@ TraceValue* TraceValueRegister::GetTraceValueByName(const std::string &name) { } TraceValueRegister* TraceValueRegister::FindScopeGroupByName(const std::string &name) { - int idx = name.find('.'); - if(idx > 0) { + size_t idx = name.find('.'); + if(idx != 0 && idx != string::npos) { TraceValueRegister *r = GetScopeGroupByName(name.substr(0, idx)); if(r == NULL) return NULL; @@ -259,8 +259,8 @@ TraceValueRegister* TraceValueRegister::FindScopeGroupByName(const std::string & } TraceValue* TraceValueRegister::FindTraceValueByName(const std::string &name) { - int idx = name.find('.'); - if(idx > 0) { + size_t idx = name.find('.'); + if(idx != 0 && idx != string::npos) { TraceValueRegister *r = GetScopeGroupByName(name.substr(0, idx)); if(r == NULL) return NULL; @@ -311,8 +311,8 @@ void TraceValueCoreRegister::RegisterTraceSetValue(TraceValue *t, const std::str TraceValue* TraceValueCoreRegister::GetTraceValueByName(const std::string &name) { TraceValue *res = TraceValueRegister::GetTraceValueByName(name); if(res == NULL) { - int idx = _tvr_numberindex(name); - if(idx != -1) { + size_t idx = _tvr_numberindex(name); + if(idx != string::npos) { // name + number found, check name and index value string n = name.substr(0, idx); int v = atoi(name.substr(idx).c_str()); @@ -352,11 +352,10 @@ void TraceValueCoreRegister::_tvr_insertTraceValuesToSet(TraceSet &t) { } } -int TraceValueCoreRegister::_tvr_numberindex(const std::string &str) { - int l = str.size(); - int i = l - 1; +size_t TraceValueCoreRegister::_tvr_numberindex(const std::string &str) { + size_t l = str.size(), i; // start from end of string to the beginning ... - for(; i >= 0; i--) { + for(i = l - 1; i >= 0; i--) { char c = str[i]; // check, if number sign if(c < '0' || c > '9') { @@ -365,7 +364,7 @@ int TraceValueCoreRegister::_tvr_numberindex(const std::string &str) { } } if(i == l) - i = -1; + i = string::npos; return i; } @@ -598,8 +597,8 @@ TraceValue* DumpManager::seekValueByName(const std::string &name) { return NULL; return devices[0]->FindTraceValueByName(name); } else { - int idx = name.find('.'); - if(idx <= 0) + size_t idx = name.find('.'); + if(idx == 0 || idx == string::npos) return NULL; for(vector::iterator i = devices.begin(); i != devices.end(); i++) { if((*i)->GetScopeName() == name.substr(0, idx)) { diff --git a/src/traceval.h b/src/traceval.h index d7356b9..81745bd 100644 --- a/src/traceval.h +++ b/src/traceval.h @@ -510,7 +510,7 @@ class TraceValueCoreRegister: public TraceValueRegister { setmap_t _tvr_valset; //!< the registered TraceValue's //! helper function to split up into name an number tail - int _tvr_numberindex(const std::string &str); + size_t _tvr_numberindex(const std::string &str); protected: //! Get the count of all TraceValues, that are registered here and descending From 5c0ab6ce67f4577012adde284a92d9de2bd8d6fe Mon Sep 17 00:00:00 2001 From: miso Date: Wed, 14 May 2014 17:48:39 +0200 Subject: [PATCH 15/21] src/avrdevice.h: sync ELFLoad declaration with src/avrreadelf.h. --- src/avrdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avrdevice.h b/src/avrdevice.h index 73e7d45..7586cd6 100644 --- a/src/avrdevice.h +++ b/src/avrdevice.h @@ -222,7 +222,7 @@ class AvrDevice: public SimulationMember, public TraceValueRegister { //! When a call/jump/cond-jump instruction was executed. For debugging. void DebugOnJump(); - friend void ELFLoad(const AvrDevice * core); + friend void ELFLoad(AvrDevice * core); }; From 1d2cc6b5305c45456d57dd54214bcf1833f22f92 Mon Sep 17 00:00:00 2001 From: miso Date: Wed, 14 May 2014 17:54:27 +0200 Subject: [PATCH 16/21] src/avrreadelf.cpp: sync "#ifdef _MSC_VER" ELFLoad definition. Sync "#ifdef _MSC_VER" ELFLoad definition with src/avrreadelf.h declaration. --- src/avrreadelf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index 9311f3b..ed7227a 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -92,7 +92,7 @@ typedef struct { Elf32_Word p_align; /* memory/file alignment */ } Elf32_Phdr; -void ELFLoad(const AvrDevice * core) { +void ELFLoad(AvrDevice * core) { FILE * f = fopen(core->GetFname().c_str(), "rb"); if(f == NULL) avr_error("Could not open file: %s", core->GetFname().c_str()); From 9d0eaa286cecd0fabd4976fa2dfdf2b077a06cf7 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Fri, 20 Feb 2015 22:57:57 +0100 Subject: [PATCH 17/21] src/avrreadelf.cpp: fix warning about wrong ELF signature. There were errors like this: WARNING: file avrreadelf.cpp: line 417: ELF signature 0xffffffff taking precedence over ELF siminfo device name atmega644 WARNING: file avrreadelf.cpp: line 441: unknown signature in ELF file: 0xffffffff Problem was variable "signature" being initialised to max(), but checked against zero. To avoid more such confusions the whole function was rewritten in a more sorted order. Functionality should be still the same. --- src/avrreadelf.cpp | 178 +++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 80 deletions(-) diff --git a/src/avrreadelf.cpp b/src/avrreadelf.cpp index ed7227a..a411473 100644 --- a/src/avrreadelf.cpp +++ b/src/avrreadelf.cpp @@ -330,8 +330,8 @@ void ELFLoad(AvrDevice * core) { } unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename) { - unsigned int signature = std::numeric_limits::max(); - unsigned int new_sig = 0; + unsigned int signature = 0, sig_cli = 0, sig_elf = 0, sig_siminfo = 0; + char siminfo_name[128]; ELFIO::elfio reader; if(!reader.load(filename)) @@ -342,106 +342,124 @@ unsigned int ELFGetDeviceNameAndSignature(const char *filename, char *devicename filename, reader.get_machine()); - // Command line takes precedence. - if(!strcmp(devicename, "unknown")) { - ELFIO::Elf_Half seg_num = reader.segments.size(); + // Search command line for signature. + if(strcmp(devicename, "unknown")) { + std::map::iterator cur = + AvrNameToSignatureMap.find(devicename); + if(cur != AvrNameToSignatureMap.end()) { + sig_cli = cur->second; + } else { + avr_warning("signature for device '%s' not found", devicename); + } + } - for(ELFIO::Elf_Half i = 0; i < seg_num; i++) { - ELFIO::segment* pseg = reader.segments[i]; + // Search ELF binary for signature. + ELFIO::Elf_Half seg_num = reader.segments.size(); - if(pseg->get_type() == PT_LOAD) { - ELFIO::Elf_Xword filesize = pseg->get_file_size(); - ELFIO::Elf64_Addr vma = pseg->get_virtual_address(); + for(ELFIO::Elf_Half i = 0; i < seg_num; i++) { + ELFIO::segment* pseg = reader.segments[i]; - if(filesize == 0) - continue; + if(pseg->get_type() == PT_LOAD) { + ELFIO::Elf_Xword filesize = pseg->get_file_size(); + ELFIO::Elf64_Addr vma = pseg->get_virtual_address(); - if(vma >= 0x840000 && vma < 0x840400) { - // read and check signature, if available, space from 0x840000 to 0x840400 - if(filesize != 3) - avr_error("wrong device signature size in elf file, " - "expected=3, given=%lu", filesize); - else { - const unsigned char* data = (const unsigned char*)pseg->get_data(); + if(filesize == 0) + continue; - signature = (((data[2] << 8) + data[1]) << 8) + data[0]; - break; + if(vma >= 0x840000 && vma < 0x840400) { + // read and check signature, if available, space from 0x840000 to 0x840400 + if(filesize != 3) + avr_error("wrong device signature size in elf file, " + "expected=3, given=%lu", filesize); + else { + const unsigned char* data = (const unsigned char*)pseg->get_data(); + + sig_elf = (((data[2] << 8) + data[1]) << 8) + data[0]; + + std::map::iterator cur = + AvrSignatureToNameMap.find(sig_elf); + if(cur == AvrSignatureToNameMap.end()) { + avr_warning("unknown signature in ELF file: 0x%x", + sig_elf); + sig_elf = 0; } + break; } } } + } - ELFIO::Elf_Half sec_num = reader.sections.size(); - - for(ELFIO::Elf_Half i = 0; i < sec_num; i++) { - ELFIO::section* psec = reader.sections[i]; - - if(psec->get_name() == ".siminfo") { - ELFIO::Elf_Xword filesize = psec->get_size(); - const char *data = psec->get_data(); - const char *data_ptr = data, *data_end = data + filesize; - - while(data_ptr < data_end) { - char tag = *data_ptr; - char length = *(data_ptr + 1); - if(length == 0) - avr_error("Field of zero length in .siminfo" - "section in ELF file found."); - if(tag == SIMINFO_TAG_DEVICE) { - strncpy(devicename, - ((siminfo_string_t *)data_ptr)->string, 1024); - devicename[1023] = '\0'; // safety - break; + // Search SIMINFO for device name. + for(ELFIO::Elf_Half i = 0; i < seg_num; i++) { + ELFIO::section* psec = reader.sections[i]; + + if(psec->get_name() == ".siminfo") { + ELFIO::Elf_Xword filesize = psec->get_size(); + const char *data = psec->get_data(); + const char *data_ptr = data, *data_end = data + filesize; + + while(data_ptr < data_end) { + char tag = *data_ptr; + char length = *(data_ptr + 1); + if(length == 0) + avr_error("Field of zero length in .siminfo" + "section in ELF file found."); + if(tag == SIMINFO_TAG_DEVICE) { + strncpy(siminfo_name, + ((siminfo_string_t *)data_ptr)->string, 128); + siminfo_name[127] = '\0'; // safety + + std::map::iterator cur = + AvrNameToSignatureMap.find(siminfo_name); + if(cur != AvrNameToSignatureMap.end()) { + sig_siminfo = cur->second; + } + else { + avr_warning("signature for device '%s' not found", + siminfo_name); } - // Everything else handled in ELFLoad(). - data_ptr += length; + break; } + // Everything else handled in ELFLoad(). + data_ptr += length; } } + } - if(strcmp(devicename, "unknown")) { - // We found a device name, find the signature of _this_ one. - std::map::iterator cur = - AvrNameToSignatureMap.find(devicename); - if(cur != AvrNameToSignatureMap.end()) { - new_sig = cur->second; - } else { - avr_warning("signature for device '%s' not found", devicename); - } + // Now we have searched all possible sources, take the one with the highest + // precedence: command line over ELF over SIMINFO. + if(sig_cli) { + signature = sig_cli; + if(sig_elf && sig_elf != sig_cli) { + avr_warning("Command line device name '%s' taking precedence over " + "device signature 0x%x in ELF file.", + devicename, sig_elf); + } + if(sig_siminfo && sig_siminfo != sig_cli) { + avr_warning("Command line device name '%s' taking precedence over " + "SIMINFO device name '%s'.", devicename, siminfo_name); } - if(signature != 0) { - if(new_sig != 0 && signature != new_sig) { - avr_warning("ELF signature 0x%x taking precedence over " - "ELF siminfo device name %s", - signature, devicename); - } - } else - signature = new_sig; } - else { - // We have a device name from the command line. - std::map::iterator cur = - AvrNameToSignatureMap.find(devicename); - if(cur != AvrNameToSignatureMap.end()) { - signature = cur->second; - } else { - avr_warning("signature for device '%s' not found", devicename); + else if(sig_elf) { + signature = sig_elf; + if(sig_siminfo && sig_siminfo != sig_elf) { + avr_warning("Device signature 0x%x in ELF file taking precedence " + "over SIMINFO device name '%s'.", + sig_elf, siminfo_name); } } + else if(sig_siminfo) { + signature = sig_siminfo; + } - // If we've found _anything_, we've a signature now. - if(signature != 0) { - std::map::iterator cur = - AvrSignatureToNameMap.find(signature); - if(cur != AvrSignatureToNameMap.end()) { - strncpy(devicename, cur->second.c_str(), 1024); - } else { - // Assume signatures found by device name never get here. - avr_warning("unknown signature in ELF file: 0x%x", signature); - } + // Done. + std::map::iterator cur = + AvrSignatureToNameMap.find(signature); + if(cur != AvrSignatureToNameMap.end()) { + strncpy(devicename, cur->second.c_str(), 1024); } + avr_message("Device name is %s, signature 0x%x.", devicename, signature); - avr_message("Device name is %s", devicename); return signature; } From 69d944dd83e3103b80772b532f6b6ad94f740df0 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Tue, 24 Feb 2015 21:41:42 +0100 Subject: [PATCH 18/21] src/atmega1284abase.cpp: also accept p variants. Simply make them the same as their non-p counterparts, even is this isn't entirley correct; e.g. 644 has only one UART, 644p has two. No need to also change src/avrsignature.cpp, these variants are already known there. --- src/atmega1284abase.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/atmega1284abase.cpp b/src/atmega1284abase.cpp index aa8611c..6db193d 100644 --- a/src/atmega1284abase.cpp +++ b/src/atmega1284abase.cpp @@ -40,6 +40,11 @@ AVR_REGISTER(atmega324, AvrDevice_atmega324A) AVR_REGISTER(atmega644, AvrDevice_atmega644A) AVR_REGISTER(atmega1284, AvrDevice_atmega1284A) +AVR_REGISTER(atmega164p, AvrDevice_atmega164A) +AVR_REGISTER(atmega324p, AvrDevice_atmega324A) +AVR_REGISTER(atmega644p, AvrDevice_atmega644A) +AVR_REGISTER(atmega1284p, AvrDevice_atmega1284A) + AvrDevice_atmega1284Abase::~AvrDevice_atmega1284Abase() { delete usart1; delete usart0; @@ -203,6 +208,7 @@ AvrDevice_atmega1284Abase::AvrDevice_atmega1284Abase(unsigned ram_bytes, 21, // (22) UDRE vector 22); // (23) TX complete vector + // TODO: ATmega644P has USART1, but ATmega644 (maybe others) has not. usart1 = new HWUsart(this, irqSystem, PinAtPort(&portd, 3), // TXD1 From 0e4d36228327393314039284a01df0094d0943b4 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Tue, 24 Feb 2015 23:47:31 +0100 Subject: [PATCH 19/21] Partially revert breaking commit d6e3b58358cce6aa35eaf5fcc62 For unknown reasons, AvrDevice::Step() of an ATmega644 occasionally returns 1. This was ignored up until the breaking patch came along. Return to ignoring this flag again. --- src/systemclock.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/systemclock.cpp b/src/systemclock.cpp index ecd69b0..960f5ce 100644 --- a/src/systemclock.cpp +++ b/src/systemclock.cpp @@ -241,8 +241,18 @@ long SystemClock::Run(SystemClockOffset maxRunTime) { (SystemClock::Instance().GetCurrentTime() < maxRunTime)) { steps++; bool untilCoreStepFinished = false; - if (Step(untilCoreStepFinished)) - break; + // This breaks at least ATemga644, core->Step() in SystemClock::Step() + // occasionally returns 1 in normal program flow even without the use + // of Sleep, Break or whatever causes AvrDevice to return 1. + // + //if (Step(untilCoreStepFinished)) + // break; + // + // Breaking commit was d6e3b58358cce6aa35eaf5fcc62c1ff1e139bf06, + // "patch #7766 Make Step stoppable, print less when used as a library" + // + // Let's take the old code (this one line): + Step(untilCoreStepFinished); } return steps; From 076ca5c3767dd8d5a43bae5347929af36b287d72 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Wed, 25 Feb 2015 00:36:40 +0100 Subject: [PATCH 20/21] src/cmd/main.cpp: fix termination message. The message combined the expected runtime with the actual number of cycles simulated. These two don't fit in case the simulation was aborted prematurely by some means. --- src/cmd/main.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp index 4ac26e1..1b4bb94 100644 --- a/src/cmd/main.cpp +++ b/src/cmd/main.cpp @@ -442,9 +442,8 @@ int main(int argc, char *argv[]) { << "number of cpu cycles simulated: " << dec << steps << endl; } else { // limited steps = SystemClock::Instance().Run(maxRunTime); - cout << "Ran too long. Terminated after " << dec << maxRunTime - << " ns (simulated) and " << endl - << dec << steps << " cpu cycles" << endl; + cout << "Ran too long. Terminated after " + << dec << steps << " cpu cycles simulated." << endl; } Application::GetInstance()->PrintResults(); } else { // gdb should be activated From 66d3108523cee83525d7f3ccac68e1fa017f9e36 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Fri, 28 Aug 2015 14:58:04 -0400 Subject: [PATCH 21/21] Print port as an unsigned number It changes something like Connection opened by host 127.0.0.1, port -31795. to something like Connection opened by host 127.0.0.1, port 35990. --- src/cmd/gdbserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/gdbserver.cpp b/src/cmd/gdbserver.cpp index 438dfb9..417537a 100644 --- a/src/cmd/gdbserver.cpp +++ b/src/cmd/gdbserver.cpp @@ -270,7 +270,7 @@ bool GdbServerSocketUnix::Connect(void) { /* If we got this far, we now have a client connected and can start processing. */ - fprintf(stderr, "Connection opened by host %s, port %hd.\n", + fprintf(stderr, "Connection opened by host %s, port %hu.\n", inet_ntoa(address->sin_addr), ntohs(address->sin_port)); return true;