forked from Miroirs/x49gp
445 lines
7.7 KiB
C
445 lines
7.7 KiB
C
/* $Id: main.c,v 1.30 2008/12/11 12:18:17 ecd Exp $
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <glib.h>
|
|
|
|
#include <x49gp.h>
|
|
#include <x49gp_ui.h>
|
|
#include <memory.h>
|
|
#include <s3c2410.h>
|
|
#include <s3c2410_power.h>
|
|
#include <s3c2410_timer.h>
|
|
#include <x49gp_timer.h>
|
|
|
|
#include "gdbstub.h"
|
|
|
|
static void *oom_check(void *ptr)
|
|
{
|
|
if (ptr == NULL) {
|
|
abort();
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
static x49gp_t *x49gp;
|
|
|
|
#ifdef QEMU_OLD // LD TEMPO HACK
|
|
extern
|
|
#endif
|
|
CPUState *__GLOBAL_env;
|
|
|
|
int semihosting_enabled = 1;
|
|
|
|
/* LD TEMPO HACK */
|
|
#ifndef QEMU_OLD
|
|
uint8_t *phys_ram_base;
|
|
int phys_ram_size;
|
|
ram_addr_t ram_size = 0x80000; // LD ???
|
|
|
|
/* vl.c */
|
|
int singlestep;
|
|
|
|
void *qemu_memalign(size_t alignment, size_t size)
|
|
{
|
|
#if defined(__APPLE__) || defined(_POSIX_C_SOURCE) && !defined(__sun__)
|
|
int ret;
|
|
void *ptr;
|
|
ret = posix_memalign(&ptr, alignment, size);
|
|
if (ret != 0)
|
|
abort();
|
|
return ptr;
|
|
#elif defined(CONFIG_BSD)
|
|
return oom_check(valloc(size));
|
|
#else
|
|
return oom_check(memalign(alignment, size));
|
|
#endif
|
|
}
|
|
|
|
|
|
void qemu_init_vcpu(void *_env)
|
|
{
|
|
CPUState *env = _env;
|
|
|
|
env->nr_cores = 1;
|
|
env->nr_threads = 1;
|
|
}
|
|
|
|
int qemu_cpu_self(void *env)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void qemu_cpu_kick(void *env)
|
|
{
|
|
}
|
|
|
|
void armv7m_nvic_set_pending(void *opaque, int irq)
|
|
{
|
|
abort();
|
|
}
|
|
int armv7m_nvic_acknowledge_irq(void *opaque)
|
|
{
|
|
abort();
|
|
}
|
|
void armv7m_nvic_complete_irq(void *opaque, int irq)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
void gdb_register_coprocessor(CPUState * env,
|
|
void * get_reg, void * set_reg,
|
|
int num_regs, const char *xml, int g_pos)
|
|
{
|
|
fprintf(stderr, "TODO: %s\n", __FUNCTION__);
|
|
}
|
|
|
|
#endif /* !QEMU_OLD */
|
|
|
|
void *
|
|
qemu_malloc(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
void *
|
|
qemu_mallocz(size_t size)
|
|
{
|
|
void *ptr;
|
|
|
|
ptr = qemu_malloc(size);
|
|
if (NULL == ptr)
|
|
return NULL;
|
|
memset(ptr, 0, size);
|
|
return ptr;
|
|
}
|
|
|
|
void
|
|
qemu_free(void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
void *
|
|
qemu_vmalloc(size_t size)
|
|
{
|
|
#if defined(__linux__)
|
|
void *mem;
|
|
if (0 == posix_memalign(&mem, sysconf(_SC_PAGE_SIZE), size))
|
|
return mem;
|
|
return NULL;
|
|
#else
|
|
return valloc(size);
|
|
#endif
|
|
}
|
|
|
|
#ifdef QEMU_OLD
|
|
int
|
|
term_vprintf(const char *fmt, va_list ap)
|
|
{
|
|
return vprintf(fmt, ap);
|
|
}
|
|
|
|
int
|
|
term_printf(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int n;
|
|
|
|
va_start(ap, fmt);
|
|
n = vprintf(fmt, ap);
|
|
va_end(ap);
|
|
|
|
return n;
|
|
}
|
|
#endif
|
|
|
|
#define SWI_Breakpoint 0x180000
|
|
|
|
#ifdef QEMU_OLD
|
|
int
|
|
do_arm_semihosting(CPUState *env, uint32_t number)
|
|
#else
|
|
uint32_t
|
|
do_arm_semihosting(CPUState *env)
|
|
#endif
|
|
{
|
|
#ifndef QEMU_OLD
|
|
uint32_t number;
|
|
if (env->thumb) {
|
|
number = lduw_code(env->regs[15] - 2) & 0xff;
|
|
} else {
|
|
number = ldl_code(env->regs[15] - 4) & 0xffffff;
|
|
}
|
|
#endif
|
|
switch (number) {
|
|
case SWI_Breakpoint:
|
|
break;
|
|
|
|
case 0:
|
|
#ifdef DEBUG_X49GP_SYSCALL
|
|
printf("%s: SWI LR %08x: syscall %u: args %08x %08x %08x %08x %08x %08x %08x\n",
|
|
__FUNCTION__, env->regs[14], env->regs[0],
|
|
env->regs[1], env->regs[2], env->regs[3],
|
|
env->regs[4], env->regs[5], env->regs[6],
|
|
env->regs[7]);
|
|
#endif
|
|
|
|
#if 1
|
|
switch (env->regs[0]) {
|
|
case 305: /* Beep */
|
|
printf("%s: BEEP: frequency %u, time %u, override %u\n",
|
|
__FUNCTION__, env->regs[1], env->regs[2], env->regs[3]);
|
|
|
|
gdk_beep();
|
|
env->regs[0] = 0;
|
|
return 1;
|
|
|
|
case 28: /* CheckBeepEnd */
|
|
env->regs[0] = 0;
|
|
return 1;
|
|
|
|
case 29: /* StopBeep */
|
|
env->regs[0] = 0;
|
|
return 1;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
x49gp_set_idle(x49gp_t *x49gp, x49gp_arm_idle_t idle)
|
|
{
|
|
#ifdef DEBUG_X49GP_ARM_IDLE
|
|
if (idle != x49gp->arm_idle) {
|
|
printf("%s: arm_idle %u, idle %u\n", __FUNCTION__, x49gp->arm_idle, idle);
|
|
}
|
|
#endif
|
|
|
|
x49gp->arm_idle = idle;
|
|
|
|
if (x49gp->arm_idle == X49GP_ARM_RUN) {
|
|
x49gp->env->halted = 0;
|
|
} else {
|
|
x49gp->env->halted = 1;
|
|
#ifdef QEMU_OLD
|
|
cpu_interrupt(x49gp->env, CPU_INTERRUPT_EXIT);
|
|
#else
|
|
cpu_exit(x49gp->env);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
arm_sighnd(int sig)
|
|
{
|
|
switch (sig) {
|
|
case SIGUSR1:
|
|
// stop_simulator = 1;
|
|
// x49gp->arm->CallDebug ^= 1;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "%s: sig %u\n", __FUNCTION__, sig);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
x49gp_gtk_timer(void *data)
|
|
{
|
|
while (gtk_events_pending()) {
|
|
// printf("%s: gtk_main_iteration_do()\n", __FUNCTION__);
|
|
gtk_main_iteration_do(FALSE);
|
|
}
|
|
|
|
x49gp_mod_timer(x49gp->gtk_timer,
|
|
x49gp_get_clock() + X49GP_GTK_REFRESH_INTERVAL);
|
|
}
|
|
|
|
void
|
|
x49gp_lcd_timer(void *data)
|
|
{
|
|
x49gp_t *x49gp = data;
|
|
int64_t now, expires;
|
|
|
|
// printf("%s: lcd_update\n", __FUNCTION__);
|
|
x49gp_lcd_update(x49gp);
|
|
gdk_flush();
|
|
|
|
now = x49gp_get_clock();
|
|
expires = now + X49GP_LCD_REFRESH_INTERVAL;
|
|
|
|
// printf("%s: now: %lld, next update: %lld\n", __FUNCTION__, now, expires);
|
|
x49gp_mod_timer(x49gp->lcd_timer, expires);
|
|
}
|
|
|
|
static void
|
|
usage(const char *progname)
|
|
{
|
|
fprintf(stderr, "usage: %s <config-file>\n",
|
|
progname);
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
ui_sighnd(int sig)
|
|
{
|
|
switch (sig) {
|
|
case SIGINT:
|
|
case SIGQUIT:
|
|
case SIGTERM:
|
|
x49gp->arm_exit = 1;
|
|
#ifdef QEMU_OLD
|
|
cpu_interrupt(x49gp->env, CPU_INTERRUPT_EXIT);
|
|
#else
|
|
cpu_exit(x49gp->env);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
char *progname;
|
|
int error;
|
|
|
|
|
|
progname = strrchr(argv[0], '/');
|
|
if (progname)
|
|
progname++;
|
|
else
|
|
progname = argv[0];
|
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
if (argc < 2)
|
|
usage(progname);
|
|
|
|
x49gp = malloc(sizeof(x49gp_t));
|
|
if (NULL == x49gp) {
|
|
fprintf(stderr, "%s: %s:%u: Out of memory\n",
|
|
progname, __FUNCTION__, __LINE__);
|
|
exit(1);
|
|
}
|
|
memset(x49gp, 0, sizeof(x49gp_t));
|
|
|
|
fprintf(stderr, "_SC_PAGE_SIZE: %08lx\n", sysconf(_SC_PAGE_SIZE));
|
|
|
|
printf("%s:%u: x49gp: %p\n", __FUNCTION__, __LINE__, x49gp);
|
|
|
|
INIT_LIST_HEAD(&x49gp->modules);
|
|
|
|
|
|
x49gp->progname = progname;
|
|
x49gp->clk_tck = sysconf(_SC_CLK_TCK);
|
|
|
|
x49gp->emulator_fclk = 75000000;
|
|
x49gp->PCLK_ratio = 4;
|
|
x49gp->PCLK = 75000000 / 4;
|
|
|
|
#ifdef QEMU_OLD
|
|
x49gp->env = cpu_init();
|
|
#else
|
|
//cpu_set_log(0xffffffff);
|
|
cpu_exec_init_all(0);
|
|
x49gp->env = cpu_init("arm926");
|
|
#endif
|
|
__GLOBAL_env = x49gp->env;
|
|
|
|
// cpu_set_log(cpu_str_to_log_mask("all"));
|
|
|
|
x49gp_timer_init(x49gp);
|
|
|
|
x49gp->gtk_timer = x49gp_new_timer(X49GP_TIMER_REALTIME,
|
|
x49gp_gtk_timer, x49gp);
|
|
x49gp->lcd_timer = x49gp_new_timer(X49GP_TIMER_VIRTUAL,
|
|
x49gp_lcd_timer, x49gp);
|
|
|
|
x49gp_ui_init(x49gp);
|
|
|
|
x49gp_s3c2410_arm_init(x49gp);
|
|
|
|
x49gp_flash_init(x49gp);
|
|
x49gp_sram_init(x49gp);
|
|
|
|
x49gp_s3c2410_init(x49gp);
|
|
|
|
if (x49gp_modules_init(x49gp)) {
|
|
exit(1);
|
|
}
|
|
|
|
error = x49gp_modules_load(x49gp, argv[argc-1]);
|
|
if (error) {
|
|
if (error != -EAGAIN) {
|
|
exit(1);
|
|
}
|
|
x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON);
|
|
}
|
|
// x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON);
|
|
|
|
signal(SIGINT, ui_sighnd);
|
|
signal(SIGTERM, ui_sighnd);
|
|
signal(SIGQUIT, ui_sighnd);
|
|
|
|
signal(SIGUSR1, arm_sighnd);
|
|
|
|
|
|
x49gp_set_idle(x49gp, 0);
|
|
|
|
// stl_phys(0x08000a1c, 0x55555555);
|
|
|
|
|
|
x49gp_mod_timer(x49gp->gtk_timer, x49gp_get_clock());
|
|
x49gp_mod_timer(x49gp->lcd_timer, x49gp_get_clock());
|
|
|
|
|
|
if(argc>=3) {
|
|
if((argv[1][0]=='-')&&(argv[1][1]=='d')&&(argv[1][2]==0)) {
|
|
gdbserver_start(1234);
|
|
gdb_handlesig(x49gp->env, 0);
|
|
}
|
|
}
|
|
|
|
x49gp_main_loop(x49gp);
|
|
|
|
|
|
x49gp_modules_save(x49gp, argv[argc-1]);
|
|
x49gp_modules_exit(x49gp);
|
|
|
|
|
|
#if 0
|
|
printf("ClkTicks: %lu\n", ARMul_Time(x49gp->arm));
|
|
printf("D TLB: hit0 %lu, hit1 %lu, search %lu (%lu), walk %lu\n",
|
|
x49gp->mmu->dTLB.hit0, x49gp->mmu->dTLB.hit1,
|
|
x49gp->mmu->dTLB.search, x49gp->mmu->dTLB.nsearch,
|
|
x49gp->mmu->dTLB.walk);
|
|
printf("I TLB: hit0 %lu, hit1 %lu, search %lu (%lu), walk %lu\n",
|
|
x49gp->mmu->iTLB.hit0, x49gp->mmu->iTLB.hit1,
|
|
x49gp->mmu->iTLB.search, x49gp->mmu->iTLB.nsearch,
|
|
x49gp->mmu->iTLB.walk);
|
|
#endif
|
|
return 0;
|
|
}
|