# simavr
-This repository is mirrored from [https://github.com/buserror/simavr.git](https://github.com/buserror/simavr.git), commit 7003af0 (Mon Jul 18 10:29:17 2022)
+This repository is forked from [https://github.com/buserror/simavr.git](https://github.com/buserror/simavr.git), commit 7003af0 (Mon Jul 18 10:29:17 2022)
* **simuc**: see [examples/](examples/simuc/README.md)
* Original `README.md`: see [README-simavr.md](README-simavr.md)
DEBARCH="armhf"
endif
-DEBVERSION := 0.0.5~1
+DEBBASE := dpkg
DEBNAME := dpkg/htl-simuc_version_arch
DEBSRC := dpkg/htl-simuc_version_arch
DEBARCH := $(shell dpkg --print-architecture)
-DEB := $(DEBNAME:%version=%$(DEBVERSION),%arch=%$(DEBARCH).deb)
+DEB := $(DEBBASE:%version=%$(DEBVERSION),%arch=%$(DEBARCH).deb)
LIBC_NAME := libc6
LIBC_VERSION := $(shell dpkg --list | grep ${LIBC_NAME}:${DEBARCH} | tr -s ' ' | cut -d" " -f 3 | cut -d"-" -f 1)
LIBCXX_NAME := libstdc++6
deb: dpkg $(DEBSRC)/DEBIAN/control $(DEBSRC)/usr/share/doc/htl-simuc/readme
@dpkg-deb -Z xz --root-owner-group --build $(DEBSRC) ${DEB}
- @mv $(DEBSRC)/*.deb dpkg/
@chmod 644 dpkg/*.deb
.PHONY: $(DEBSRC)/DEBIAN/control $(DEBSRC)/usr/share/doc/htl-simuc/readme
**simuc** is used to simulate a megaAvr microcontroller.
-If the cpu is stopped by command or `avr-gdb`, some information is printed on standard output:
+The git repository for this program can be found on the git repository [https://git.htl-mechatronik.at/public/?p=sx/simavr.git;a=home](https://git.htl-mechatronik.at/public/?p=sx/simavr.git;a=home).
+The software `simuc` itself is located in the subfolder [examples/simuc](https://git.htl-mechatronik.at/public/?p=sx/simavr.git;a=tree;f=examples/simuc;hb=HEAD)
+
+----------------------------------------------------
+
+## Installation
+
+If the Debian/Ubuntu htl package is included the software is already installed.
+
+In any other case "ready to use" debian packages are located on [http://www.htl-mechatronik.at/ubuntu-new/pool/partner/](http://www.htl-mechatronik.at/ubuntu-new/pool/partner/) and can be installed after download with `apt install ...`.
+
+The package is available for 4 supported architectures:
+
+* **[amd64](http://www.htl-mechatronik.at/ubuntu-new/pool/partner/htl-simuc_0.0.6~1_amd64.deb)** Linux (Debian, Ubuntu, ...) PC 64 bit
+* **[i386](http://www.htl-mechatronik.at/ubuntu-new/pool/partner/htl-simuc_0.0.6~1_arm64.deb)** Linux (Debian, Ubuntu, ...) PC 32 bit
+* **[arm64](http://www.htl-mechatronik.at/ubuntu-new/pool/partner/htl-simuc_0.0.6~1_arm64.deb)** ARM 64 Bit (Respberry Pi 3,4 ... with RaspbianOs 64 Bit)
+* **[armhf](http://www.htl-mechatronik.at/ubuntu-new/pool/partner/htl-simuc_0.0.6~1_armhf.deb)** ARM 32 Bit (Raspberry Pi 2,3,4 ... with RaspbianOs 32 Bit)
+
+----------------------------------------------------
+
+## Overview
+
+If the microcontroller CPU is stopped by command or `avr-gdb`, some information is printed on standard output:
* Number of cycles and elapsed time
* Status Flags
* General Purpose registers r0..r31
* address registers X, Y and Z
* Stack pointer SP and stack content
-
-Commands available via standard input (keyboard):
-* *Enter* print current cycles, elapsed time and LED status
-* `interrupt`: stop cpu
-* `continue`: continue cpu run
-* `stack`: print complete stack content on standard output
+* LED status for some type boards (Arduino, Sure Electronics, ...)
+
+**Commands** available via standard input (keyboard):
+* ***Enter*** print current cycles, elapsed time and LED status
+* `break` + *Enter*:
+ ... stop microcontroller CPU (breakpoint)
+* `continue` + *Enter*:
+ ... continue microcontroller CPU
+* `reset` + *Enter*:
+ ... simulate external reset (registers will be cleared, SRAM contents remain unchanged)
+* `power` + *Enter*:
+ ... simulate power on reset (registers and SRAM will be cleared)
+* `stack` + *Enter*:
+ ... print complete stack content on standard output
+
+It is sufficient to enter only as many characters of the command until the command is unique.
+`b` for *break*, `c` for *continue*, `r` for *reset*, `p` for *power* and `s` for *stack*
Microcontrollers UART interface(s) is/are connected to local devices and can be used with terminal programs (like `picocom`).
-After start of `simuc` the program waits for an keyboard action to start simulation. So you are able to connect with avr-gdb before the simulation is executing some machine code.
+After start of `simuc` the program waits for a command (via keyboard) to start simulation. So you are able to connect with *avr-gdb* before the simulation is executing some machine code.
1) start `simuc` with proper options and arguments
2) start new shell and execute `avr-gdb`
3) inside (gdb) connect to simuc with the gdb shell command `target remote :1234`
4) load symbols with gdb command `file ...`
5) optionally set source directory with `directory ...`
-6) press enter in the shell of simuc
-7) now debug avr program step by step with gdb commands `stepi`, `step`, `nexti`, `next` or continue execution with `continue`
+6) press `b` and enter in the shell of simuc (break on first machine command)
+7) now debug avr program step by step with gdb commands `stepi` (`si`), `step` (`s`), `nexti` (`ni`), `next` (`n`) or continue execution with `continue` (`c`)
+
+Don't forget to compile your program with the option **`-g`** (include gdb debugging information in elf-file)!
-------------------------------------------------------------
```sh
$ sudo apt install gcc make gcc-avr avr-libc
$ sudo apt install libelf-dev
-$ sudo apt install freeglut3 freeglut3-dev
+$ sudo apt install freeglut3-dev
$ sudo apt install libncurses5 libncurses5-dev
```
user@host:~ $ git clone https://git.htl-mechatronik.at/public/sx/simavr.git
```
+The main branch is named `master-sx` because the branch `master` remains unchanged with the original simavr repository on [https://github.com/buserror/simavr](https://github.com/buserror/simavr) (commit [7003af0](https://github.com/buserror/simavr/commit/7003af0)).
+
+
### Make complete simavr
```sh
```sh
user@host:~ $ cd ~/simavr/examples/simuc
-user@host:~/simavr/examples/simuc $ make deb
+user@host:~/simavr/examples/simuc $ export DEBVERSION="0.0.6~1"; make deb
```
Debian packet available in folder `dpkg`
+
+Find "ready to use" debian packages on [http://www.htl-mechatronik.at/ubuntu-new/pool/partner/](http://www.htl-mechatronik.at/ubuntu-new/pool/partner/).
#include "sim/sim.h"
#include "simavr/simavr.h"
+void printVersion () {
+ printf("simuc V0.0.6 (%s,%s)\n", __DATE__, __TIME__);
+}
+
void printHelp () {
- printf("simuc V0.0.5 (%s,%s)\n", __DATE__, __TIME__);
+ printVersion();
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");
}
if (params.filenames == NULL || params.filenames[0] == NULL) {
+ printVersion();
printf("ERROR: missing target elf file, use --help to show usage\n\n");
return 1;
}
- printf("--------------------------------------------------------------------\n");
+ printf("----------------------------------------------------------------------\n");
init(¶ms);
if (errno == 1) {
return 1;
}
- printf("--------------------------------------------------------------------\n");
- printf("available commands: i (interrupt), c (continue), s (stack), r (reset), q (quit)\n");
- printf("--------------------------------------------------------------------\n");
+ printf("----------------------------------------------------------------------\n");
+ printf("available commands:\n");
+ printf(" b (break), c (continue), s (stack), r (reset), p (power), q (quit)\n");
+ printf("----------------------------------------------------------------------\n");
printf("init done - press key to start\n");
- getchar();
- printf("--------------------------------------------------------------------\n");
- start();
+ char c = getchar();
+ if (c != '\n') {
+ getchar(); // remove line feed from stdin
+ }
+ printf("----------------------------------------------------------------------\n");
+
+ switch (c) {
+ case 'b': start(CommandBreak, NULL); break;
+ case 's': start(CommandStack, NULL); break;
+ case 'r': start(CommandReset, NULL); break;
+ case 'p': start(CommandPower, NULL); break;
+ case 'q': return 0;
+ default: start(ReadyForNewCommand, NULL); break;
+ }
// int cnt = 0;
char *line = NULL;
// shutdown();
// break;
// }
-
+
if (getline(&line, &size, stdin) > 0) {
- const char *commands[] = { "quit", "interrupt", "continue", "stack", "reset" };
+ const char *commands[] = { "quit", "break", "continue", "stack", "reset", "power" };
try {
int foundIndex = -1;
int foundCnt = 0;
}
}
}
- // printf("foundCnt=%d foundIndex=%d command=%s\n", foundCnt, foundIndex, foundIndex >= 0 ? commands[foundIndex] : "");
+ printf("foundCnt=%d foundIndex=%d command=%s\n", foundCnt, foundIndex, foundIndex >= 0 ? commands[foundIndex] : "");
if (foundCnt == 1 || length == 0) {
EnumSimAvrCommand cmd = (EnumSimAvrCommand)(foundCnt > 0 ? foundIndex + 2 : 1);
setCommand(cmd, NULL);
usleep(10000);
return 0;
-}
\ No newline at end of file
+}
}
simavr.load(param);
- printf("--------------------------------------------------------------------\n");
+ printf("----------------------------------------------------------------------\n");
simavr.setUartDumpEnabled(false);
// simavr.registerIoWrite(PORTB, handleWritePortB);
simavr.setUartPtyEnabled(0, true);
}
}
-void start () {
+void start (EnumSimAvrCommand cmd, void *param) {
try {
- simavr.start();
+ simavr.start(cmd, param);
} catch (std::exception& e) {
lastErrorMessage = "start() fails, caused by " + std::string(e.what());
extern void init (struct StartParameters *param);
extern void shutdown ();
extern const char * lastError ();
-extern void start ();
+extern void start (EnumSimAvrCommand cmd, void *param);
extern void stop ();
extern void setCommand (EnumSimAvrCommand cmd, void *param);
extern void addEvent (EnumSimEvent event);
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");
+ printf("----------------------------------------------------------------------\n");
}
if (params->mmcu != NULL) {
strncpy(firmware->mmcu, params->mmcu, sizeof(firmware->mmcu));
printf("EEPROM: ");
if (firmware->eesize == 0) {
- printf("not defined (no section .eeprom found)");
+ printf("not defined (no section .eeprom found)\n");
} else {
printf("%d bytes defined (", firmware->eesize);
for (uint32_t i = 0; i < firmware->eesize; i++) {
if (avr_init(avr) != 0) {
throw std::logic_error(error(AT, "avr_init() fails"));
}
-
+
// now we can chang log level to desired value
avr->log = params->log;
printf("simavr log level: ");
}
}
-void SimAvr::start () {
+void SimAvr::start (EnumSimAvrCommand cmd, void *param) {
if (pthread_mutex_lock(&lock)) {
throw std::logic_error(error(AT, "start() fails caused by mutex error"));
}
if (avr == NULL) {
throw std::logic_error("avr not ready (check if load done)");
}
+ command = cmd;
syncTime[0] = !syncTime[1];
avrRunThread = new std::thread(&SimAvr::avrRun, this);
pthread_mutex_unlock(&lock);
}
if (!onlyOnChange || nextLedL != ledL) {
ledL = nextLedL;
- snprintf(s, size, "LED L = %c", ledL ? 'X' : '.');
+ snprintf(s, size, "LED L = %c", ledL == 1 ? 'X' : '.');
rv = true;
}
break;
if (!onlyOnChange || change) {
int n = snprintf(s, size, "LED PA[3210] =");
for (int i = 3; i >= 0; i--) {
- n += snprintf(s + n, size - n, " %c", led[i] ? 'X' : '.');
+ n += snprintf(s + n, size - n, " %c", led[i] == 1 ? 'X' : '.');
}
rv = true;
}
}
if (!onlyOnChange || nextLed != led) {
led = nextLed;
- snprintf(s, size, "LED1 (PB0) = %c", led ? 'X' : '.');
+ snprintf(s, size, "LED1 (PB0) = %c", led == 1 ? 'X' : '.');
rv = true;
}
break;
return rv;
}
+void SimAvr::reset (ResetType type) {
+ avr_reset(avr);
+
+ switch (type) {
+ case powerOn: avr_regbit_set(avr, avr->reset_flags.porf); break;
+ case external: avr_regbit_set(avr, avr->reset_flags.extrf); break;
+ case brownout: avr_regbit_set(avr, avr->reset_flags.borf); break;
+ case watchdog: avr_regbit_set(avr, avr->reset_flags.wdrf); break;
+ }
+
+ // bugfix, also clear r0..r31, and set SP to 0
+ for (int i = 0; i < 0x20; i++) {
+ avr->data[i] = 0;
+ }
+ _avr_sp_set(avr, 0);
+}
+
void SimAvr::avrRun () {
long cnt = 0;
printf(" %s\n", s);
break;
}
- case CommandInterrupt: {
+ case CommandBreak: {
if (avr->state == cpu_Running) {
avr->state = cpu_Stopped;
}
}
case CommandReset: {
- avr_reset(avr);
- printf("RESET done -> PC=0x%04x, use command 'continue' to start!\n", avr->pc);
- avr->state = cpu_Stopped;
- break;
+ reset(external);
+ printf("\n\n----------------------------------------------------------------\n");
+ printf("RESET done (registers set to init value, SRAM remains unchanged)\n");
+ command = CommandBreak;
+ continue;
+ }
+
+ case CommandPower: {
+ reset(powerOn);
+ printf("\n\n-----------------------------------------------\n");
+ printf("Power-On done (SRAM cleared and power-on reset)\n");
+ command = CommandBreak;
+ continue;
}
default: break;
ReadyForNewCommand = 0,
CommandStatus,
CommandQuit,
- CommandInterrupt,
+ CommandBreak,
CommandContinue,
CommandStack,
- CommandReset
+ CommandReset,
+ CommandPower
} EnumSimAvrCommand;
struct SimAvrStatus {
class SimAvr;
typedef void (*avrsim_io_write_callback_t)(avr_t *avr, avr_io_addr_t addr, uint8_t value, SimAvr *simavr);
+typedef enum { powerOn = 1, external = 2, brownout = 4, watchdog = 8 } ResetType;
class SimAvr {
struct SimAvrEvent waitForEvent ();
const char *eventText (EnumSimAvrEvent event);
-public:
+public:
void load (struct StartParameters *params);
void shutdown ();
- void start ();
+ void start (EnumSimAvrCommand cmd, void *param);
void stop ();
void addEvent (int event);
void setUartDumpEnabled (bool enabled);
uint64_t timeMicrosOnSyncStart = 0;
Semaphore eventCount;
uart_pty_t *uartPty[2] = { NULL, NULL };
+ void reset (ResetType type);
void printCyclesAndElapsedTime ();
bool sprintfLedStatus (char *s, size_t size, bool onlyOnChange);
};
-#endif // SIMAVR_H
\ No newline at end of file
+#endif // SIMAVR_H