shoebill/debugger/debugger.c
Peter Rutenbar 476a8bb570 Major speed improvements (25-50%)
There may be bugs lurking in it. On my Core i7 macbook pro,
shoebill now runs so fast that SetUpTimeK() on A/UX 3 hangs.
(SetUpTimeK tries to time a dbra loop, and refuses to accept any
speed faster than a certain threshold, which shoebill is now
surpassing. If you see A/UX hanging early in boot, it's probably
that.)

- Added a new specialized cache for instruction stream reads
-- This also lets us distinguish between data and instruction
   reads, which the 68020 does. Instruction reads are now done
   with the correct function code (2 or 6), although that
   doesn't currently fix or improve anything currently
- Added an obvious condition code optimization, dunno how I missed
  it earlier
- Other little changes
2015-01-29 00:19:57 -05:00

891 lines
22 KiB
C

/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <GLUT/glut.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <histedit.h>
#include "../core/shoebill.h"
rb_tree *keymap;
struct dbg_state_t {
EditLine *el;
uint8_t running;
uint64_t breakpoint_counter;
dbg_breakpoint_t *breakpoints;
_Bool trace;
char *ring;
uint32_t ring_i, ring_len;
uint64_t op_count[0x10000];
};
struct dbg_state_t dbg_state;
void print_mmu_rp(uint64_t rp)
{
printf("lu=%u limit=0x%x sg=%u dt=%u addr=0x%08x\n", rp_lu(rp), rp_limit(rp), rp_sg(rp), rp_dt(rp), rp_addr(rp));
}
void printregs()
{
printf("[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]);
printf("[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]);
printf("[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]);
printf("[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]);
printf("[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc,
sr_s()?'S':'s',
sr_m()?'M':'m',
sr_x()?'X':'x',
sr_n()?'N':'n',
sr_z()?'Z':'z',
sr_v()?'V':'v',
sr_c()?'C':'c',
shoe.tc
);
printf("[vbr]%08x\n", shoe.vbr);
printf("srp: ");
print_mmu_rp(shoe.srp);
printf("crp: ");
print_mmu_rp(shoe.crp);
printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n",
_tc_enable(), _tc_sre(), tc_fcl(), _tc_ps(), _tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid());
printf("\n");
}
void print_pc()
{
char str[1024];
uint8_t binary[32];
uint32_t i;
uint32_t len;
const char *name = NULL;
if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) {
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
for (i=0; macii_rom_symbols[i].name; i++) {
if (macii_rom_symbols[i].addr > addr) {
break;
}
name = macii_rom_symbols[i].name;
}
}
else if (sr_s()) { // these symbols are only meaningful in supervisor mode
coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc);
if (symb && strlen(symb->name))
name = symb->name;
}
else {
if ((shoe.pc >= 0x10000000) && (shoe.pc < 0x20000000)) {
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
for (i=0; macii_rom_symbols[i].name; i++) {
if (macii_rom_symbols[i].addr > addr) {
break;
}
name = macii_rom_symbols[i].name;
}
}
else {
name = "";
}
}
const uint16_t old_abort = shoe.abort;
shoe.suppress_exceptions = 1;
for (i=0; i<32; i++) {
binary[i] = (uint8_t) lget(shoe.pc+i, 1);
}
disassemble_inst(binary, shoe.pc, str, &len);
printf("*0x%08x %s [ ", shoe.pc, name ? name : "");
for (i=0; i<len; i+=2) {
printf("%02x%02x ", binary[i], binary[i+1]);
}
printf("] %s\n", str);
shoe.abort = old_abort;
shoe.suppress_exceptions = 0;
}
static void dump_proc(uint32_t procnum)
{
uint32_t u_proc_p;
uint16_t pid;
uint8_t do_print = 0, cpuflag;
// Only dump this process state if we're in user mode
if (sr_s())
return ;
shoe.suppress_exceptions = 1;
cpuflag = lget(0x0000012f, 1);
set_sr_s(1); // set supervisor mode so we can access the proc structure
u_proc_p = lget(0x1ff01000, 4);
if (shoe.abort)
goto done;
pid = lget(u_proc_p + 0x26, 2);
if (shoe.abort)
goto done;
do_print = 1;
done:
set_sr_s(0);
shoe.abort = 0;
shoe.suppress_exceptions = 0;
if (do_print) {
printf("pid = %u, cpuflag=0x%02x\n", pid, cpuflag);
// print_pc();
// printregs();
}
}
void verb_backtrace_handler (const char *line)
{
const uint32_t old_abort = shoe.abort;
shoe.suppress_exceptions = 1;
shoe.abort = 0;
// link
// push a6 to a7
// set a6 = a7
// set a7 = a7 - (some stack space)
// jsr
// push return pointer to a7
// call
// set a7 = a7 - (some stack space)
// push arguments to a7
// push return pointer to a7
// (jump to function)
// push
// bt algorithm
// set a7 = a6
// pop a7 -> a6
// pop a7 -> return pointer
uint32_t i, j, a7, a6 = shoe.a[6];
coff_symbol *symb;
if (sr_s()) {
symb = coff_find_func(shoe.coff, shoe.pc);
printf("%u: *0x%08x %s+%u\n", 0, shoe.pc, (symb && strlen(symb->name))?symb->name:"?", shoe.pc - symb->value);
}
else
printf("%u: *0x%08x\n", 0, shoe.pc);
for (i=1; 1; i++) {
a7 = a6;
const uint32_t last_a6 = lget(a7, 4);
const uint32_t last_pc = lget(a7+4, 4);
if ((last_a6 - a6) <= 1000) {
printf(" {");
for (j = a6+8; j < last_a6; j+=4) {
uint32_t data = lget(j, 4);
printf("%x, ", data);
}
printf("}\n");
}
if (sr_s()) {
symb = coff_find_func(shoe.coff, last_pc);
printf("%u: *0x%08x %s+%u\n", i, last_pc, (symb && strlen(symb->name))?symb->name:"?", last_pc - symb->value);
}
else
printf("%u: *0x%08x\n", i, last_pc);
if ((last_a6 - a6) > 1000) {
break;
}
a6 = last_a6;
}
shoe.suppress_exceptions = 0;
shoe.abort = old_abort;
}
void verb_break_handler (const char *line)
{
errno = 0;
const uint32_t addr = (uint32_t) strtoul(line, NULL, 0);
if (errno) {
printf("errno: %d\n", errno);
return ;
}
dbg_breakpoint_t *brk = calloc(sizeof(dbg_breakpoint_t), 1);
brk->next = NULL;
brk->addr = addr;
brk->num = dbg_state.breakpoint_counter++;
dbg_breakpoint_t **cur = &dbg_state.breakpoints;
while (*cur)
cur = &(*cur)->next;
*cur = brk;
printf("Set breakpoint %llu = *0x%08x\n", brk->num, brk->addr);
}
void verb_delete_handler (const char *line)
{
errno = 0;
uint64_t num = strtoull(line, NULL, 0);
if (errno) {
printf("errno: %d\n", errno);
return ;
}
dbg_breakpoint_t **cur = &dbg_state.breakpoints;
while (*cur) {
if ((*cur)->num == num) {
dbg_breakpoint_t *victim = *cur;
*cur = (*cur)->next;
free(victim);
return ;
}
cur = &(*cur)->next;
}
printf("No such breakpoint (#%llu)\n", num);
}
void verb_help_handler (const char *line)
{
printf("Help help help\n");
}
void verb_stepi_handler (const char *line)
{
dbg_state.running = 1;
cpu_step();
dbg_state.running = 0;
print_pc();
}
void verb_registers_handler (const char *line)
{
printregs();
}
void verb_trace_toggle_handler (const char *line)
{
dbg_state.trace = !dbg_state.trace;
}
void verb_examine_handler (const char *line)
{
uint32_t addr = (uint32_t)strtoul(line, NULL, 0);
uint32_t old_suppress = shoe.suppress_exceptions;
shoe.suppress_exceptions = 1;
printf("(uint32_t)*0x%08x = 0x%08x\n", addr, (uint32_t)lget(addr, 4));
shoe.suppress_exceptions = old_suppress;
}
void verb_lookup_handler (const char *line)
{
char *sym_name = malloc(strlen(line)+1);
sscanf(line, "%s", sym_name);
coff_symbol *symb = coff_find_symbol(shoe.coff, sym_name);
free(sym_name);
if (symb == NULL) {
printf("Couldn't find \"%s\"\n", sym_name);
return ;
}
printf("%s = *0x%08x\n", symb->name, symb->value);
}
void stepper()
{
dbg_breakpoint_t *cur;
if (shoe.cpu_thread_notifications) {
// If there's an interrupt pending
if (shoe.cpu_thread_notifications & 0xff) {
// process_pending_interrupt() may clear SHOEBILL_STATE_STOPPED
process_pending_interrupt();
}
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
// I think it's safe to ignore STOP instructions...
}
}
cpu_step();
if (dbg_state.trace) {
print_pc();
printregs();
}
for (cur = dbg_state.breakpoints; cur != NULL; cur = cur->next) {
if (shoe.pc == cur->addr) {
printf("Hit breakpoint %llu *0x%08x\n", cur->num, shoe.pc);
dbg_state.running = 0;
return ;
}
}
}
void verb_continue_handler (const char *line)
{
dbg_state.running = 1;
while (dbg_state.running) {
stepper();
}
print_pc();
}
void verb_quit_handler (const char *line)
{
printf("Quitting\n");
fflush(stdout);
exit(0);
}
void verb_reset_handler (const char *line)
{
p_free_pool(shoe.pool);
shoe.pool = NULL;
}
struct verb_handler_table_t {
const char *name;
void (*func)(const char *);
} verb_handler_table[] =
{
{"quit", verb_quit_handler},
{"continue", verb_continue_handler},
{"help", verb_help_handler},
{"registers", verb_registers_handler},
{"stepi", verb_stepi_handler},
{"backtrace", verb_backtrace_handler},
{"bt", verb_backtrace_handler},
{"break", verb_break_handler},
{"delete", verb_delete_handler},
{"lookup", verb_lookup_handler},
{"trace", verb_trace_toggle_handler},
{"x", verb_examine_handler},
{"reset", verb_reset_handler},
};
void execute_verb (const char *line)
{
char verb[128];
uint32_t max_len=0, max_i=0;
const char *remainder;
uint32_t i, matches = 0, match_i;
if (sscanf(line, "%127s", verb) != 1)
return ;
// Skip past the verb
for (remainder = line; *remainder && !isspace(*remainder); remainder++)
;
// Skip past the space between the verb and the arguments
for (; *remainder && isspace(*remainder); remainder++)
;
const uint32_t verb_len = strlen(verb);
for (i=0; i < (sizeof(verb_handler_table) / sizeof(struct verb_handler_table_t)); i++) {
const uint32_t i_len = strlen(verb_handler_table[i].name);
// If it's a perfect match,
if (strcasecmp(verb, verb_handler_table[i].name)==0) {
verb_handler_table[i].func(remainder);
return ;
}
// Otherwise, see if it's a partial match
if ((i_len >= verb_len) && strncasecmp(verb, verb_handler_table[i].name, verb_len)==0) {
matches++;
match_i = i;
}
}
// Only execute the verb if it's an unambiguous match (matches == 1)
if (matches == 1) {
verb_handler_table[match_i].func(remainder);
return ;
}
printf(" %s?\n", verb);
}
char *cli_prompt_callback(EditLine *el)
{
return "~ ";
}
// Hack to clear line after ^C. el_reset() screws up tty when called from the signal handler.
void ch_reset(EditLine *el, int mclear);
void signal_callback(int sig)
{
EditLine *el = dbg_state.el;
(void) signal(SIGINT, signal_callback);
(void) signal(SIGWINCH, signal_callback);
switch (sig) {
case SIGWINCH:
el_resize(el);
break ;
case SIGINT:
if (dbg_state.running) {
dbg_state.running = 0;
}
else {
printf("\n");
ch_reset(el, 0);
el_set(el, EL_REFRESH);
}
break ;
}
return ;
}
void *ui_thread (void *arg)
{
EditLine *el;
History *hist;
HistEvent histev;
const char *buf;
int num;
hist = history_init();
history(hist, &histev, H_SETSIZE, 10000); // Remember 10000 previous user inputs
el = el_init("Shoebill", stdin, stdout, stderr);
dbg_state.el = el;
el_set(el, EL_SIGNAL, 0);
el_set(el, EL_PROMPT, cli_prompt_callback);
el_set(el, EL_EDITOR, "emacs");
el_set(el, EL_HIST, history, hist);
(void) signal(SIGINT, signal_callback);
(void) signal(SIGWINCH, signal_callback);
while ((buf = el_gets(el, &num)) != NULL) {
if (strcmp(buf, "\n")!=0) {
execute_verb(buf);
history(hist, &histev, H_ENTER, buf);
}
}
el_end(el);
history_end(hist);
return NULL;
}
static uint8_t lookup_special(int special)
{
switch (special) {
case GLUT_KEY_UP: return 0x3e;
case GLUT_KEY_DOWN: return 0x3d;
case GLUT_KEY_LEFT: return 0x3b;
case GLUT_KEY_RIGHT: return 0x3c;
default: return 0xff;
}
}
static uint32_t _get_modifiers (void)
{
int glut_modifiers = glutGetModifiers();
uint32_t result = 0;
result |= (glut_modifiers & GLUT_ACTIVE_SHIFT) ? (1 << 17) : 0;
result |= (glut_modifiers & GLUT_ACTIVE_CTRL) ? (1 << 18) : 0;
result |= (glut_modifiers & GLUT_ACTIVE_ALT) ? (1 << 19) : 0;
return result;
}
void global_mouse_func (int button, int state, int x, int y)
{
shoebill_mouse_click(state == GLUT_DOWN);
shoebill_mouse_move(x, y);
}
void global_motion_func (int x, int y)
{
shoebill_mouse_click(1);
shoebill_mouse_move(x, y);
}
void global_passive_motion_func (int x, int y)
{
shoebill_mouse_click(0);
shoebill_mouse_move(x, y);
}
void global_keyboard_up_func (unsigned char c, int x, int y)
{
uint16_t value;
if (rb_find(keymap, c, &value)) {
shoebill_key_modifier((value >> 8) | (_get_modifiers() >> 16));
shoebill_key(0, value & 0xff);
}
}
void global_keyboard_down_func (unsigned char c, int x, int y)
{
uint16_t value;
if (rb_find(keymap, c, &value)) {
shoebill_key_modifier((value >> 8) | (_get_modifiers() >> 16));
shoebill_key(1, value & 0xff);
}
}
void global_special_up_func (int special, int x, int y)
{
const uint8_t code = lookup_special(special);
if (code != 0xff) {
shoebill_key_modifier(_get_modifiers() >> 16);
shoebill_key(0, code);
}
}
void global_special_down_func (int special, int x, int y)
{
const uint8_t code = lookup_special(special);
if (code != 0xff) {
shoebill_key_modifier(_get_modifiers() >> 16);
shoebill_key(1, code);
}
}
void timer_func (int arg)
{
glutTimerFunc(15, timer_func, 0); // 15ms = 66.67hz
glutPostRedisplay();
}
void _display_func (void)
{
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 0);
shoebill_send_vbl_interrupt(9);
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glViewport(0, 0, frame.width, frame.height);
glRasterPos2i(0, frame.height);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(frame.width,
frame.height,
GL_RGBA,
GL_UNSIGNED_BYTE,
frame.buf);
glutSwapBuffers();
}
static void _init_keyboard_map (void)
{
#define mapkeymod(u, a, m) do { \
assert((a >> 7) == 0); \
uint16_t value = ((m) << 8)| (a); \
rb_insert(keymap, u, &value, NULL); \
} while (0)
#define mapkey(_u, a) mapkeymod(_u, a, 0)
keymap = rb_new(p_new_pool(NULL), sizeof(uint16_t));
// Letters
mapkey('a', 0x00);
mapkey('b', 0x0b);
mapkey('c', 0x08);
mapkey('d', 0x02);
mapkey('e', 0x0e);
mapkey('f', 0x03);
mapkey('g', 0x05);
mapkey('h', 0x04);
mapkey('i', 0x22);
mapkey('j', 0x26);
mapkey('k', 0x28);
mapkey('l', 0x25);
mapkey('m', 0x2e);
mapkey('n', 0x2d);
mapkey('o', 0x1f);
mapkey('p', 0x23);
mapkey('q', 0x0c);
mapkey('r', 0x0f);
mapkey('s', 0x01);
mapkey('t', 0x11);
mapkey('u', 0x20);
mapkey('v', 0x09);
mapkey('w', 0x0d);
mapkey('x', 0x07);
mapkey('y', 0x10);
mapkey('z', 0x06);
// Numbers
mapkey('0', 0x1d);
mapkey('1', 0x12);
mapkey('2', 0x13);
mapkey('3', 0x14);
mapkey('4', 0x15);
mapkey('5', 0x17);
mapkey('6', 0x16);
mapkey('7', 0x1a);
mapkey('8', 0x1c);
mapkey('9', 0x19);
// Top row symbols
mapkeymod(')', 0x1d, modShift);
mapkeymod('!', 0x12, modShift);
mapkeymod('@', 0x13, modShift);
mapkeymod('#', 0x14, modShift);
mapkeymod('$', 0x15, modShift);
mapkeymod('%', 0x17, modShift);
mapkeymod('^', 0x16, modShift);
mapkeymod('&', 0x1a, modShift);
mapkeymod('*', 0x1c, modShift);
mapkeymod('(', 0x19, modShift);
// Other symbols (no shift)
mapkeymod('`', 0x32, 0);
mapkeymod('-', 0x1b, 0);
mapkeymod('=', 0x18, 0);
mapkeymod('[', 0x21, 0);
mapkeymod(']', 0x1e, 0);
mapkeymod('\\', 0x2a, 0);
mapkeymod(';', 0x29, 0);
mapkeymod('\'', 0x27, 0);
mapkeymod(',', 0x2b, 0);
mapkeymod('.', 0x2f, 0);
mapkeymod('/', 0x2c, 0);
// Other symbols (with shift)
mapkeymod('~', 0x32, modShift);
mapkeymod('_', 0x1b, modShift);
mapkeymod('+', 0x18, modShift);
mapkeymod('{', 0x21, modShift);
mapkeymod('}', 0x1e, modShift);
mapkeymod('|', 0x2a, modShift);
mapkeymod(':', 0x29, modShift);
mapkeymod('"', 0x27, modShift);
mapkeymod('<', 0x2b, modShift);
mapkeymod('>', 0x2f, modShift);
mapkeymod('?', 0x2c, modShift);
// Function keys
/*mapkey(NSF1FunctionKey, 0x7a);
mapkey(NSF2FunctionKey, 0x78);
mapkey(NSF3FunctionKey, 0x63);
mapkey(NSF4FunctionKey, 0x76);
mapkey(NSF5FunctionKey, 0x60);
mapkey(NSF6FunctionKey, 0x61);
mapkey(NSF7FunctionKey, 0x62);
mapkey(NSF8FunctionKey, 0x64);
mapkey(NSF9FunctionKey, 0x65);
mapkey(NSF10FunctionKey, 0x6d);
mapkey(NSF11FunctionKey, 0x67);
mapkey(NSF12FunctionKey, 0x6f);
mapkey(NSF13FunctionKey, 0x69);
mapkey(NSF14FunctionKey, 0x6b);
mapkey(NSF15FunctionKey, 0x71);*/
// Arrows
/*mapkey(NSUpArrowFunctionKey, 0x3e);
mapkey(NSDownArrowFunctionKey, 0x3d);
mapkey(NSRightArrowFunctionKey, 0x3c);
mapkey(NSLeftArrowFunctionKey, 0x3b);*/
// Delete
//mapkey(NSDeleteFunctionKey, 0x75);
mapkey(0x08, 0x33);
mapkey(0x7f, 0x33);
// Enter, NL, CR
mapkey('\r', 0x24);
mapkey('\n', 0x24);
mapkey(0x03, 0x24);
// Other keys
mapkey(0x1b, 0x35); // escape
mapkey(' ', 0x31); // space
mapkey('\t', 0x30); // tab
}
static void _init_glut_video (void)
{
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 1);
glutInitWindowSize(frame.width, frame.height);
glutCreateWindow("Shoebill");
glutDisplayFunc(_display_func);
glutIgnoreKeyRepeat(1);
glutKeyboardFunc(global_keyboard_down_func);
glutKeyboardUpFunc(global_keyboard_up_func);
glutSpecialFunc(global_special_down_func);
glutSpecialUpFunc(global_special_up_func);
glutMouseFunc(global_mouse_func);
glutMotionFunc(global_motion_func);
glutPassiveMotionFunc(global_passive_motion_func);
glutInitDisplayMode (GLUT_DOUBLE);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.1, 1.0, 0.1, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, frame.width, 0, frame.height, -1.0, 1.0);
glViewport(0, 0, frame.width, frame.height);
}
int main (int argc, char **argv)
{
shoebill_config_t config;
pthread_t pid;
bzero(&config, sizeof(shoebill_config_t));
/*
* A variety of hacky things happen in debug mode.
* shoebill_start() will not create a new thread to run
* the CPU loop. We'll create a CPU thread here, bypass
* core_api, and directly manipulate the emulator guts.
*
* This is not a great example of how to write a GUI
* for shoebill...
*/
config.debug_mode = 1;
config.aux_verbose = 1;
config.ram_size = 32 * 1024 * 1024;
config.aux_kernel_path = "/unix";
config.rom_path = "../priv/macii.rom";
config.scsi_devices[0].path = "../priv/root3.img";
//config.scsi_devices[1].path = "../priv/marathon.img";
/*dbg_state.ring_len = 256 * 1024 * 1024;
dbg_state.ring = malloc(dbg_state.ring_len);
dbg_state.ring_i = 0;*/
if (!shoebill_initialize(&config)) {
printf("%s\n", config.error_msg);
return 0;
}
_init_keyboard_map();
shoebill_install_video_card(&config,
9, // slotnum
640, // 1024,
480); // 768,
// uint8_t ethernet_addr[6] = {0x22, 0x33, 0x55, 0x77, 0xbb, 0xdd};
// shoebill_install_ethernet_card(&config, 13, ethernet_addr);
// Start the VIA timer thread
shoebill_start();
// Create a new thread to drive the CPU & debugger UI
pthread_create(&pid, NULL, ui_thread, NULL);
int dummyargc = 1;
glutInit(&dummyargc, argv);
// Create/configure the screen
_init_glut_video();
// Set a GLUT timer to update the screen
glutTimerFunc(15, timer_func, 0);
glutMainLoop();
return 0;
}