blob: eca0d328bd969c9c87a7cfb968cedbf45f30ca23 [file] [log] [blame]
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <libgen.h>
#include <simavr/sim_avr.h>
#include <simavr/sim_gdb.h>
#include <simavr/avr_ioport.h>
#include <simavr/sim_elf.h>
#include <simavr/avr_uart.h>
static avr_t *g_avr;
static avr_irq_t *g_uart_irq;
static struct {
uint8_t argc;
char args[3][16];
} g_args;
static int g_args_idx;
static bool g_uart_xon;
static bool g_status_ok;
static void uart_tx_hook(struct avr_irq_t * irq, uint32_t value, void * param)
{
fputc(value, stdout);
fflush(stdout);
}
static bool stdin_can_read()
{
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return (FD_ISSET(0, &fds));
}
static void avr_logger(avr_t * avr, const int level, const char * format, va_list ap)
{
if ((!avr && level <= LOG_WARNING) || (avr && avr->log >= level)) {
vfprintf(stderr , format, ap);
}
}
static void uart_xon_hook(struct avr_irq_t * irq, uint32_t value, void * param)
{
g_uart_xon = true;
int v;
if (feof(stdin))
{
avr_raise_irq(&g_uart_irq[1], UART_INPUT_FE);
return;
}
while (g_uart_xon)
{
if (g_args_idx < sizeof(g_args))
{
v = ((char*)&g_args)[g_args_idx++];
}
else if (stdin_can_read())
{
v = fgetc(stdin);
}
else
{
break;
}
if (v != EOF)
{
avr_raise_irq(&g_uart_irq[1], v);
}
else
{
avr_raise_irq(&g_uart_irq[1], UART_INPUT_FE);
break;
}
}
}
static void uart_xoff_hook(struct avr_irq_t * irq, uint32_t value, void * param)
{
g_uart_xon = false;
}
void init_uart()
{
const char *irq_names[2] = {"8<uart_in", "8>uart_out"};
g_uart_irq = avr_alloc_irq(&g_avr->irq_pool, 0, 2, irq_names);
avr_irq_register_notify(&g_uart_irq[0], &uart_tx_hook, NULL);
uint32_t flags = 0;
avr_ioctl(g_avr, AVR_IOCTL_UART_GET_FLAGS('0'), &flags);
flags &= ~AVR_UART_FLAG_STDIO;
flags &= ~AVR_UART_FLAG_POLL_SLEEP;
avr_ioctl(g_avr, AVR_IOCTL_UART_SET_FLAGS('0'), &flags);
avr_irq_t *src = avr_io_getirq(g_avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUTPUT);
avr_irq_t *dst = avr_io_getirq(g_avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_INPUT);
avr_connect_irq(src, &g_uart_irq[0]);
avr_connect_irq(&g_uart_irq[1], dst);
avr_irq_t *xon = avr_io_getirq(g_avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUT_XON);
avr_irq_t *xoff = avr_io_getirq(g_avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUT_XOFF);
avr_irq_register_notify(xon, uart_xon_hook, NULL);
avr_irq_register_notify(xoff, uart_xoff_hook, NULL);
}
static void status_ok_hook(struct avr_irq_t * irq, uint32_t value, void * param)
{
g_status_ok = value;
}
int main(int argc, char *argv[])
{
avr_global_logger_set(&avr_logger);
g_avr = avr_make_mcu_by_name("atmega1284");
if (!g_avr)
{
fprintf(stderr, "avr_make_mcu_by_name failed\n");
return 1;
}
if (argc < 2)
{
fprintf(stderr, "Usage: %s [-g] binary [args ...]\n", argv[0]);
return 2;
}
const char *filename = argv[1];
bool enable_gdb = false;
int argc_offset = 2;
if (strcmp(filename, "-g") == 0)
{
enable_gdb = true;
argc_offset = 3;
filename = argv[2];
}
elf_firmware_t firmware = {};
elf_read_firmware(filename, &firmware);
avr_init(g_avr);
avr_load_firmware(g_avr, &firmware);
g_avr->frequency = 8000000;
if (enable_gdb)
{
g_avr->state = cpu_Stopped;
g_avr->gdb_port = 1234;
avr_gdb_init(g_avr);
}
init_uart();
avr_irq_register_notify(avr_io_getirq(g_avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 1), status_ok_hook, NULL);
// Pass the rest of arguments to application inside simulator
g_args.argc = argc - argc_offset;
if (g_args.argc > 3) g_args.argc = 3;
for (int i = 0; i < g_args.argc; i++)
{
strncpy(g_args.args[i], argv[i + argc_offset], 15);
}
while (1)
{
int state = avr_run(g_avr);
if (state == cpu_Done)
break;
if (state == cpu_Crashed)
{
fprintf(stderr, "CPU Crashed\n");
return 3;
}
}
if (g_status_ok)
{
return 0;
}
else
{
fprintf(stderr, "Received error status from simulation\n");
return 5;
}
}