New debugger + inital PRAM/real-time clock + fixes
- Refactored VIA rega/b implementation - Timers don't "work" yet, but they work a little better - Split rega/b into input and output versions - Fixed a bug that would mistake VIA1 accesses for VIA2 - Added basic support for PRAM and the RTC, although they're not wired into the GUI yet - Replaced every *alloc() call with an alloc_pool call, which is a start toward supporting clean restarts - Replaced ea_addr, ea_read, ea_write, and ea_read_commit with jump tables - Got rid of ~inst() macro in cpu.c - added a GLUT-based debugger
8
Makefile
@ -1,11 +1,17 @@
|
||||
|
||||
CC = clang
|
||||
CFLAGS = -O3 -flto -Wno-deprecated-declarations
|
||||
|
||||
all: shoebill
|
||||
|
||||
shoebill: make_gui
|
||||
shoebill: make_gui debugger
|
||||
|
||||
make_gui: make_core
|
||||
xcodebuild -project gui/Shoebill.xcodeproj SYMROOT=build
|
||||
|
||||
debugger: make_core
|
||||
$(MAKE) -C debugger
|
||||
|
||||
make_core:
|
||||
$(MAKE) -C core -j 4
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
CC = clang
|
||||
CFLAGS = -O3 -flto -ggdb -Wno-deprecated-declarations
|
||||
CFLAGS = -O3 -ggdb -flto -Wno-deprecated-declarations
|
||||
# CFLAGS = -O0 -ggdb -Wno-deprecated-declarations
|
||||
|
||||
|
||||
DEPS = core_api.h coff.h mc68851.h redblack.h shoebill.h Makefile macro.pl
|
||||
NEED_DECODER = cpu dis
|
||||
NEED_PREPROCESSING = adb fpu mc68851 mem via
|
||||
NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi toby_frame_buffer video core_api filesystem debug_server alloc_pool
|
||||
NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi video core_api filesystem alloc_pool
|
||||
|
||||
# Object files that can be compiled directly from the source
|
||||
OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING))
|
||||
@ -73,7 +73,7 @@ $(TEMP)/dis_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS)
|
||||
|
||||
# Compile the decoder generator
|
||||
$(TEMP)/decoder_gen: decoder_gen.c $(DEPS)
|
||||
$(CC) $(CFLAGS) decoder_gen.c -o $(TEMP)/decoder_gen
|
||||
$(CC) decoder_gen.c -o $(TEMP)/decoder_gen
|
||||
|
||||
|
||||
$(TEMP):
|
||||
|
14
core/adb.c
@ -81,7 +81,7 @@
|
||||
|
||||
void adb_start_service_request()
|
||||
{
|
||||
printf("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
|
||||
//printf("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
|
||||
if (shoe.adb.pending_service_requests) {
|
||||
shoe.adb.service_request = 1;
|
||||
|
||||
@ -245,7 +245,7 @@ static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Com
|
||||
|
||||
shoe.adb.poll = 0;
|
||||
|
||||
via->regb |= VIA_REGB_ADB_STATUS;
|
||||
via->regb_input |= VIA_REGB_ADB_STATUS;
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ static void adb_handle_state_one (void) // "Even" state
|
||||
printf("adb_talk: ");
|
||||
if (shoe.adb.timeout) {
|
||||
shoe.adb.timeout = 0;
|
||||
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
printf("timeout\n");
|
||||
return ;
|
||||
@ -288,7 +288,7 @@ static void adb_handle_state_one (void) // "Even" state
|
||||
printf("adb_listen: ");
|
||||
if (shoe.adb.timeout) {
|
||||
shoe.adb.timeout = 0;
|
||||
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
printf("timeout\n");
|
||||
return ;
|
||||
@ -304,7 +304,7 @@ static void adb_handle_state_one (void) // "Even" state
|
||||
break;
|
||||
}
|
||||
|
||||
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
|
||||
via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
}
|
||||
|
||||
@ -317,11 +317,11 @@ static void adb_handle_state_two (void) // "Odd" state
|
||||
// If this transaction was part of a service request, clear the service_request flag now
|
||||
if (shoe.adb.service_request) {
|
||||
shoe.adb.service_request = 0;
|
||||
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
|
||||
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
|
||||
printf("(service request) ");
|
||||
}
|
||||
else
|
||||
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
|
||||
via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
|
||||
|
||||
switch (shoe.adb.command_type) {
|
||||
case adb_flush:
|
||||
|
30
core/coff.c
@ -76,7 +76,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
}
|
||||
|
||||
// Allocate a coff_file and copy in the header
|
||||
cf = (coff_file*)calloc(1, sizeof(coff_file));
|
||||
cf = (coff_file*)p_alloc(shoe.pool, sizeof(coff_file));
|
||||
ptr = rawhead;
|
||||
cf->magic = be2native(&ptr, 2);
|
||||
cf->num_sections = be2native(&ptr, 2);
|
||||
@ -98,17 +98,17 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
|
||||
// pull out cf->opt_header bytes (a.out-format header, I guess?)
|
||||
if (cf->opt_header_len > 0) {
|
||||
uint8_t *opt = malloc(cf->opt_header_len);
|
||||
uint8_t *opt = p_alloc(shoe.pool, cf->opt_header_len);
|
||||
if (!_coff_buf_read(opt, cf->opt_header_len)) {
|
||||
printf("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len);
|
||||
free(opt);
|
||||
p_free(opt);
|
||||
goto fail;
|
||||
}
|
||||
cf->opt_header = opt;
|
||||
}
|
||||
|
||||
// start pulling out sections
|
||||
cf->sections = calloc(cf->num_sections, sizeof(coff_section));
|
||||
cf->sections = p_alloc(shoe.pool, cf->num_sections * sizeof(coff_section));
|
||||
for (i=0; i<cf->num_sections; i++) {
|
||||
// read the header
|
||||
uint8_t rawsec[40];
|
||||
@ -158,10 +158,10 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
}
|
||||
|
||||
// load the data and attach it to the section struct
|
||||
data = malloc(cf->sections[i].sz); // FIXME: sz might not be a sane value
|
||||
data = p_alloc(shoe.pool, cf->sections[i].sz); // FIXME: sz might not be a sane value
|
||||
if (!_coff_buf_read(data, cf->sections[i].sz)) {
|
||||
printf("coff_parse: I couldn't fread section %u (%s)'s data (%u bytes)\n", i+1, cf->sections[i].name, cf->sections[i].sz);
|
||||
free(data);
|
||||
p_free(data);
|
||||
goto fail;
|
||||
}
|
||||
cf->sections[i].data = data;
|
||||
@ -174,7 +174,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
|
||||
cf->func_tree = rb_new();
|
||||
//printf("func_tree = %llx, *func_tree = %llx\n", cf->func_tree, *cf->func_tree);
|
||||
cf->symbols = (coff_symbol*)calloc(sizeof(coff_symbol), cf->num_symbols);
|
||||
cf->symbols = (coff_symbol*)p_alloc(shoe.pool, sizeof(coff_symbol) *cf->num_symbols);
|
||||
|
||||
// Seek to the symbol table
|
||||
if (!_coff_buf_seek(cf->symtab_offset)) {
|
||||
@ -208,7 +208,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
cf->symbols[i].name = malloc(j+1);
|
||||
cf->symbols[i].name = p_alloc(shoe.pool, j+1);
|
||||
memcpy(cf->symbols[i].name, tmp_name, j);
|
||||
cf->symbols[i].name[j] = 0;
|
||||
_coff_buf_seek(cf->symtab_offset + (i+1)*18);
|
||||
@ -252,17 +252,17 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
fail:
|
||||
if (cf) {
|
||||
if (cf->opt_header) {
|
||||
free(cf->opt_header);
|
||||
p_free(cf->opt_header);
|
||||
}
|
||||
if (cf->sections) {
|
||||
for (i=0; i<cf->num_sections; i++) {
|
||||
if (cf->sections[i].data) {
|
||||
free(cf->sections[i].data);
|
||||
p_free(cf->sections[i].data);
|
||||
}
|
||||
}
|
||||
free(cf->sections);
|
||||
p_free(cf->sections);
|
||||
}
|
||||
free(cf);
|
||||
p_free(cf);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -270,12 +270,12 @@ fail:
|
||||
coff_file* coff_parse_from_path(const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
uint8_t *buf = malloc(1);
|
||||
uint8_t *buf = p_alloc(shoe.pool, 1);
|
||||
uint32_t i=0, tmp;
|
||||
coff_file *coff;
|
||||
|
||||
do {
|
||||
buf = realloc(buf, i + 128*1024);
|
||||
buf = p_realloc(buf, i + 128*1024);
|
||||
assert(buf);
|
||||
tmp = fread(buf+i, 1, 128*1024, f);
|
||||
i += tmp;
|
||||
@ -285,7 +285,7 @@ coff_file* coff_parse_from_path(const char *path)
|
||||
|
||||
|
||||
coff = coff_parse(buf, i);
|
||||
free(buf);
|
||||
p_free(buf);
|
||||
return coff;
|
||||
}
|
||||
|
||||
|
199
core/core_api.c
@ -34,136 +34,17 @@
|
||||
#include "coff.h"
|
||||
#include "core_api.h"
|
||||
|
||||
/*
|
||||
char *ring, *ring_tmp;
|
||||
const uint32_t ring_len = 64 * 1024 * 1024;
|
||||
uint32_t ring_i = 0;
|
||||
|
||||
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()
|
||||
{
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[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
|
||||
);
|
||||
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[vbr]%08x\n", shoe.vbr);
|
||||
|
||||
//printf("srp: ");
|
||||
//print_mmu_rp(shoe.srp);
|
||||
|
||||
//printf("crp: ");
|
||||
//print_mmu_rp(shoe.crp);
|
||||
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n\n",
|
||||
tc_enable(), tc_sre(), tc_fcl(), tc_ps(), tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid());
|
||||
|
||||
}
|
||||
|
||||
void dump_ring()
|
||||
{
|
||||
uint32_t i = ring_i+1;
|
||||
|
||||
while (i != ring_i) {
|
||||
fwrite(&ring[i], 1, 1, stdout);
|
||||
i = (i+1) % ring_len;
|
||||
}
|
||||
}
|
||||
|
||||
void ring_print(const char *str)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i=0; str[i]; i++) {
|
||||
ring[ring_i] = str[i];
|
||||
ring_i = (ring_i+1) % ring_len;
|
||||
}
|
||||
}
|
||||
|
||||
void print_pc()
|
||||
{
|
||||
char str[1024];
|
||||
uint8_t binary[64];
|
||||
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
|
||||
name = "";
|
||||
|
||||
if ((name == NULL) || (name[0] == 0))
|
||||
return;
|
||||
if (strncmp("scsi", name, 4) != 0)
|
||||
return ;
|
||||
|
||||
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);
|
||||
|
||||
sprintf(ring_tmp, "*0x%08x %s [ ", shoe.pc, name ? name : "");
|
||||
for (i=0; i<len; i+=2) {
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "%02x%02x ", binary[i], binary[i+1]);
|
||||
}
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "] %s\n", str);
|
||||
|
||||
printregs();
|
||||
|
||||
for (i=0; ring_tmp[i]; i++) {
|
||||
ring[ring_i] = ring_tmp[i];
|
||||
ring_i = (ring_i+1) % ring_len;
|
||||
}
|
||||
|
||||
shoe.abort = old_abort;
|
||||
shoe.suppress_exceptions = 0;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void shoebill_start()
|
||||
{
|
||||
pthread_mutex_unlock(&shoe.cpu_thread_lock);
|
||||
pthread_mutex_unlock(&shoe.via_clock_thread_lock);
|
||||
pthread_mutex_unlock(&shoe.cpu_thread_lock);
|
||||
}
|
||||
|
||||
void *_cpu_thread (void *arg) {
|
||||
|
||||
void *_cpu_thread (void *arg)
|
||||
{
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
|
||||
// ring = calloc(ring_len, 1);
|
||||
// ring_tmp = malloc(128 * 1024);
|
||||
|
||||
while (1) {
|
||||
if (shoe.cpu_thread_notifications) {
|
||||
|
||||
@ -177,13 +58,14 @@ void *_cpu_thread (void *arg) {
|
||||
continue; // FIXME: yield or block on a condition variable here
|
||||
}
|
||||
}
|
||||
// print_pc();
|
||||
cpu_step();
|
||||
}
|
||||
}
|
||||
|
||||
/*static void _cpu_loop_debug()
|
||||
static void _cpu_loop_debug()
|
||||
{
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
|
||||
while (1) {
|
||||
if (shoe.cpu_thread_notifications) {
|
||||
// I think we can safely ignore "stop" instructions for A/UX in debug mode
|
||||
@ -193,9 +75,14 @@ void *_cpu_thread (void *arg) {
|
||||
process_pending_interrupt();
|
||||
}
|
||||
|
||||
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
|
||||
continue; // FIXME: yield or block on a condition variable here
|
||||
}
|
||||
}
|
||||
|
||||
cpu_step();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/*void shoebill_cpu_stepi (void)
|
||||
{
|
||||
@ -319,16 +206,7 @@ static void _init_macintosh_lomem_globals (const uint32_t offset)
|
||||
pset(offset+0xdd8, 4, 0);
|
||||
pset(offset+0x1d4, 4, 0x50000000); // VIA (via1 ptr)
|
||||
pset(offset+0x1d8, 4, 0x50004000); // SCC
|
||||
|
||||
#define hwCbSCSI (1<<15)
|
||||
#define hwCbClock (1<<14)
|
||||
#define hwCbExPRAM (1<<13)
|
||||
#define hwCbFPU (1<<12)
|
||||
#define hwCbMMU (1<<11)
|
||||
#define hwCbADB (1<<10)
|
||||
#define hwCbAUX (1<<9) /* not sure if I need to set this one */
|
||||
const uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB;
|
||||
pset(offset+0xb22, 2, HWCfgFlags); // HWCfgFlags
|
||||
pset(offset+0xb22, 2, 0xfc00); // HWCfgFlags
|
||||
}
|
||||
|
||||
|
||||
@ -482,7 +360,7 @@ static uint32_t _compute_rom_checksum (const uint8_t *rom, const uint32_t len)
|
||||
static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uint32_t *_rom_size)
|
||||
{
|
||||
uint32_t i, rom_size;
|
||||
uint8_t *rom_data = (uint8_t*)malloc(64 * 1024);
|
||||
uint8_t *rom_data = (uint8_t*)p_alloc(shoe.pool, 64 * 1024);
|
||||
FILE *f = fopen(control->rom_path, "r");
|
||||
|
||||
if (f == NULL) {
|
||||
@ -491,7 +369,7 @@ static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uin
|
||||
}
|
||||
|
||||
for (rom_size = 0; rom_size < (2*1024*1024); rom_size += (64*1024)) {
|
||||
rom_data = (uint8_t*)realloc(rom_data, rom_size + (64*1024));
|
||||
rom_data = (uint8_t*)p_realloc(rom_data, rom_size + (64*1024));
|
||||
if (fread(rom_data + rom_size, 64*1024, 1, f) != 1)
|
||||
break;
|
||||
}
|
||||
@ -514,7 +392,7 @@ static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uin
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rom_data = realloc(rom_data, rom_size);
|
||||
// rom_data = p_realloc(rom_data, rom_size);
|
||||
assert(rom_data);
|
||||
|
||||
*_rom_size = rom_size;
|
||||
@ -524,7 +402,7 @@ static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uin
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (rom_data) free(rom_data);
|
||||
if (rom_data) p_free(rom_data);
|
||||
if (f) fclose(f);
|
||||
return 0;
|
||||
}
|
||||
@ -697,7 +575,7 @@ uint32_t shoebill_initialize(shoebill_control_t *control)
|
||||
goto fail;
|
||||
|
||||
coff = coff_parse(kernel_data, kernel_size);
|
||||
free(kernel_data);
|
||||
free(kernel_data); // kernel_data was allocated with malloc()
|
||||
|
||||
if (coff == NULL) {
|
||||
sprintf(control->error_msg, "Can't open that A/UX kernel [%s]\n",
|
||||
@ -718,13 +596,13 @@ uint32_t shoebill_initialize(shoebill_control_t *control)
|
||||
}
|
||||
|
||||
shoe.physical_rom_size = rom_size;
|
||||
shoe.physical_rom_base = valloc(rom_size+8); // +8 because of physical_get hack
|
||||
shoe.physical_rom_base = p_alloc(shoe.pool, rom_size+8); // +8 because of physical_get hack
|
||||
memcpy(shoe.physical_rom_base, rom_data, rom_size);
|
||||
free(rom_data);
|
||||
p_free(rom_data);
|
||||
rom_data = NULL;
|
||||
|
||||
shoe.physical_mem_size = control->ram_size;
|
||||
shoe.physical_mem_base = valloc(control->ram_size+8); // +8 because of physical_get hack
|
||||
shoe.physical_mem_base = p_alloc(shoe.pool, control->ram_size+8); // +8 because of physical_get hack
|
||||
memset(shoe.physical_mem_base, 0, shoe.physical_mem_size);
|
||||
|
||||
// Initialize Macintosh lomem variables that A/UX actually cares about
|
||||
@ -746,40 +624,49 @@ uint32_t shoebill_initialize(shoebill_control_t *control)
|
||||
* (Can't fail after this point)
|
||||
*/
|
||||
|
||||
// FIXME: Don't do this! Rewrite the via timers!
|
||||
gettimeofday(&shoe.start_time, NULL);
|
||||
shoe.total_ticks = 0;
|
||||
/*
|
||||
* FIXME: to implement clean resetting, everything with a global structure needs
|
||||
* an initialization function. Starting here with via/pram...
|
||||
*/
|
||||
init_via_state();
|
||||
|
||||
|
||||
// Put the adb chip in state 3 (idle)
|
||||
// FIXME: put this in a "init_adb_state()"-type function
|
||||
shoe.adb.state = 3;
|
||||
pthread_mutex_init(&shoe.adb.lock, NULL);
|
||||
|
||||
|
||||
set_sr(0x2000);
|
||||
shoe.pc = pc;
|
||||
memcpy(shoe.scsi_devices, disks, 8 * sizeof(scsi_device_t));
|
||||
|
||||
pthread_mutex_init(&shoe.cpu_thread_lock, NULL);
|
||||
pthread_mutex_init(&shoe.via_clock_thread_lock, NULL);
|
||||
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
pthread_mutex_lock(&shoe.via_clock_thread_lock);
|
||||
|
||||
pthread_create(&control->cpu_thread_pid, NULL, _cpu_thread, NULL);
|
||||
// pthread_create(&control->cpu_thread_pid, NULL, debug_cpu_thread, NULL);
|
||||
pthread_create(&control->via_thread_pid, NULL, via_clock_thread, NULL);
|
||||
|
||||
/*
|
||||
* control->debug_mode is a hack - the debugger implements its own CPU thread
|
||||
*/
|
||||
pthread_mutex_init(&shoe.cpu_thread_lock, NULL);
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
if (!control->debug_mode)
|
||||
pthread_create(&control->cpu_thread_pid, NULL, _cpu_thread, NULL);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (rom_data) free(rom_data);
|
||||
if (rom_data) p_free(rom_data);
|
||||
|
||||
for (i=0; i<7; i++)
|
||||
if (disks[i].f) fclose(disks[i].f);
|
||||
|
||||
if (shoe.physical_rom_base) free(shoe.physical_rom_base);
|
||||
if (shoe.physical_mem_base) free(shoe.physical_mem_base);
|
||||
if (shoe.physical_rom_base) p_free(shoe.physical_rom_base);
|
||||
if (shoe.physical_mem_base) p_free(shoe.physical_mem_base);
|
||||
|
||||
p_free_pool(shoe.pool);
|
||||
memset(&shoe, 0, sizeof(global_shoebill_context_t));
|
||||
|
||||
// No way to free *coff yet
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,8 @@ typedef struct {
|
||||
|
||||
pthread_t cpu_thread_pid, via_thread_pid;
|
||||
|
||||
_Bool debug_mode;
|
||||
|
||||
char error_msg[8192];
|
||||
} shoebill_control_t;
|
||||
|
||||
|
511
core/cpu.c
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include "../core/shoebill.h"
|
||||
#include "../core/coff.h"
|
||||
|
||||
#define DEBUG_MODE_STOPPED 0
|
||||
#define DEBUG_MODE_RUNNING 1
|
||||
#define DEBUG_MODE_STEP 2
|
||||
|
||||
#define SHOEBILL_DEBUG_PORT 0xfded
|
||||
static int _start_debug_server(void)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_len = sizeof(struct sockaddr_in);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(SHOEBILL_DEBUG_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (sock == -1) {
|
||||
assert(!"can't socket");
|
||||
}
|
||||
else if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) != 0) {
|
||||
assert(!"can't bind");
|
||||
// return -1;
|
||||
}
|
||||
else if (listen(sock, 1) != 0) {
|
||||
assert(!"can't listen");
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
void *debug_server_thread (void *arg)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t sin_size = sizeof(struct sockaddr_in);
|
||||
uint8_t *inbuf = calloc(0x10000, 1);
|
||||
uint8_t *outbuf = calloc(0x10000, 1);
|
||||
int sock = _start_debug_server();
|
||||
int clientfd = accept(sock, (struct sockaddr*)&addr, &sin_size);
|
||||
|
||||
shoe.dbg.connected = 1;
|
||||
shoe.dbg.mode = DEBUG_MODE_RUNNING;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *debug_cpu_thread (void *arg)
|
||||
{
|
||||
memset(&shoe.dbg, 0, sizeof(shoe.dbg));
|
||||
shoe.dbg.mode = DEBUG_MODE_STOPPED;
|
||||
|
||||
pthread_t server_thread_pid;
|
||||
pthread_create(&server_thread_pid,
|
||||
NULL,
|
||||
debug_server_thread,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* The CPU only runs once the debugger is connected, and the
|
||||
* emulator has started
|
||||
*/
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
while (!shoe.dbg.connected)
|
||||
usleep(1000);
|
||||
|
||||
while (1) {
|
||||
if (shoe.dbg.mode == DEBUG_MODE_RUNNING) {
|
||||
if (!shoe.dbg.ignore_interrupts &&
|
||||
(shoe.cpu_thread_notifications & 0xff)) {
|
||||
process_pending_interrupt();
|
||||
}
|
||||
|
||||
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu_step();
|
||||
}
|
||||
else if (shoe.dbg.mode == DEBUG_MODE_STOPPED)
|
||||
pthread_yield_np();
|
||||
else if (shoe.dbg.mode == DEBUG_MODE_STEP) {
|
||||
cpu_step();
|
||||
shoe.dbg.mode = DEBUG_MODE_STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
32
core/dis.c
@ -794,24 +794,40 @@ void dis_movea () {
|
||||
}
|
||||
|
||||
void dis_move () {
|
||||
~decompose(dis_op, 00 ss RRR MMM oooooo)
|
||||
~decompose(dis_op, 00 ss RRR MMM oooooo);
|
||||
// (oooooo = source EA), (MMMRRR = dest EA)
|
||||
const uint8_t sizes[3] = {1, 4, 2};
|
||||
const char *sourceStr = decode_ea_rw(o, sizes[s-1]);
|
||||
const char *destStr = decode_ea_rw((M<<3)|R, sizes[s-1]);
|
||||
sprintf(dis.str, "move.%c %s,%s", "blw"[s-1], sourceStr, destStr);
|
||||
const uint8_t sizes[4] = {0, 1, 4, 2};
|
||||
const char *sourceStr = decode_ea_rw(o, sizes[s]);
|
||||
const char *destStr = decode_ea_rw((M<<3)|R, sizes[s]);
|
||||
sprintf(dis.str, "move.%c %s,%s", "?blw"[s], sourceStr, destStr);
|
||||
}
|
||||
|
||||
void dis_move_d_to_d () {
|
||||
sprintf(dis.str, "move_d_to_d ???");
|
||||
~decompose(dis_op, 00 ss DDD 000 000 SSS);
|
||||
sprintf(dis.str, "move.%c d%u,d%u", "?blw"[s], S, D);
|
||||
}
|
||||
|
||||
void dis_move_to_d () {
|
||||
sprintf(dis.str, "move_to_d ???");
|
||||
~decompose(dis_op, 00 ss rrr 000 MMMMMM);
|
||||
const uint8_t sizes[4] = {0, 1, 4, 2};
|
||||
|
||||
sprintf(dis.str,
|
||||
"move.%c %s,d%u",
|
||||
"?blw"[s],
|
||||
decode_ea_rw(M, sizes[s]),
|
||||
r);
|
||||
}
|
||||
|
||||
void dis_move_from_d () {
|
||||
sprintf(dis.str, "move_from_d ???");
|
||||
~decompose(dis_op, 00 ss RRR MMM 000 rrr);
|
||||
const uint8_t sizes[4] = {0, 1, 4, 2};
|
||||
|
||||
sprintf(dis.str,
|
||||
"move.%c d%u,%s",
|
||||
"?blw"[s],
|
||||
r,
|
||||
decode_ea_rw((M<<3) | R, sizes[s]));
|
||||
|
||||
}
|
||||
|
||||
void dis_scc () {
|
||||
|
873
core/mem.c
@ -46,8 +46,26 @@ void _physical_get_ram (void)
|
||||
else
|
||||
addr = (uint64_t*)&shoe.physical_mem_base[shoe.physical_addr % shoe.physical_mem_size];
|
||||
|
||||
/*if ((shoe.physical_addr >= 0x100) && (shoe.physical_addr < (0x4000+256))) {
|
||||
uint32_t i, val = 0;
|
||||
_Bool uninit = 0;
|
||||
for (i=0; i<shoe.physical_size; i++) {
|
||||
const uint8_t byte = shoe.physical_mem_base[shoe.physical_addr+i];
|
||||
val = val << 8;
|
||||
val |= byte;
|
||||
if (byte == 0xbc) uninit = 1;
|
||||
}
|
||||
if (uninit) {
|
||||
printf("LOMEM: *0x%08x = 0x%x UNSET\n", shoe.physical_addr, val);
|
||||
}
|
||||
}*/
|
||||
|
||||
const uint8_t bits = (8 - shoe.physical_size) * 8;
|
||||
shoe.physical_dat = ntohll(*addr) >> bits;
|
||||
|
||||
if ((shoe.physical_addr >= 256) && (shoe.physical_addr < 0x4000)) {
|
||||
printf("LOMEM get: *0x%08x = 0x%x\n", shoe.physical_addr, (uint32_t)shoe.physical_dat);
|
||||
}
|
||||
}
|
||||
|
||||
void _physical_get_rom (void)
|
||||
@ -61,13 +79,8 @@ void _physical_get_rom (void)
|
||||
void _physical_get_io (void)
|
||||
{
|
||||
switch (shoe.physical_addr & 0x5003ffff) {
|
||||
case 0x50000000 ... 0x50001fff: // VIA1
|
||||
via_reg_read();
|
||||
// printf("physical_get: got read to VIA1 (%x & 0x5003ffff = %x)\n", shoe.physical_addr, shoe.physical_addr & 0x5003ffff);
|
||||
return ;
|
||||
case 0x50002000 ... 0x50003fff: // VIA2
|
||||
via_reg_read();
|
||||
// printf("physical_get: got read to VIA2\n");
|
||||
case 0x50000000 ... 0x50003fff: // VIA1 + VIA2
|
||||
via_read_raw();
|
||||
return ;
|
||||
case 0x50004000 ... 0x50005fff: {// SCC
|
||||
//printf("physical_get: got read to SCC\n");
|
||||
@ -77,8 +90,6 @@ void _physical_get_io (void)
|
||||
return ;
|
||||
}
|
||||
case 0x50006000 ... 0x50007fff: // SCSI (pseudo-DMA with DRQ?)
|
||||
//printf("physical_get: got read to SCSI low\n");
|
||||
//assert(!"physical_get: got read to SCSI low");
|
||||
assert(shoe.logical_size == 4);
|
||||
shoe.physical_dat = scsi_dma_read_long();
|
||||
return ;
|
||||
@ -88,11 +99,12 @@ void _physical_get_io (void)
|
||||
case 0x50012000 ... 0x50013fff: // SCSI (pseudo-DMA with no DRQ?)
|
||||
assert(shoe.logical_size == 1);
|
||||
shoe.physical_dat = scsi_dma_read();
|
||||
// printf("physical_get: got read to SCSI hi\n");
|
||||
// assert(!"physical_get: got read to SCSI hi\n");
|
||||
return ;
|
||||
case 0x50014000 ... 0x50015fff: // Sound
|
||||
//printf("physical_get: got read to sound\n");
|
||||
printf("soundsound read : register 0x%04x sz=%u\n",
|
||||
shoe.physical_addr - 0x50014000, shoe.physical_size);
|
||||
shoe.physical_dat = 0;
|
||||
return ;
|
||||
case 0x50016000 ... 0x50017fff: // SWIM (IWM?)
|
||||
// printf("physical_get: got read to IWM\n");
|
||||
@ -157,6 +169,10 @@ void _physical_set_ram (void)
|
||||
else
|
||||
addr = &shoe.physical_mem_base[shoe.physical_addr];
|
||||
|
||||
if ((shoe.physical_addr >= 0x100) && (shoe.physical_addr < (0x8000))) {
|
||||
printf("LOMEM set: *0x%08x = 0x%x\n", shoe.physical_addr, (uint32_t)chop(shoe.physical_dat, shoe.physical_size));
|
||||
}
|
||||
|
||||
const uint32_t sz = shoe.physical_size;
|
||||
switch (sz) {
|
||||
case 1:
|
||||
@ -195,13 +211,8 @@ void _physical_set_rom (void)
|
||||
void _physical_set_io (void)
|
||||
{
|
||||
switch (shoe.physical_addr & 0x5003ffff) {
|
||||
case 0x50000000 ... 0x50001fff: // VIA1
|
||||
via_reg_write();
|
||||
// printf("physical_set: got write to VIA1\n");
|
||||
return ;
|
||||
case 0x50002000 ... 0x50003fff: // VIA2
|
||||
via_reg_write();
|
||||
// printf("physical_set: got write to VIA2\n");
|
||||
case 0x50000000 ... 0x50003fff: // VIA1 + VIA2
|
||||
via_write_raw();
|
||||
return ;
|
||||
case 0x50004000 ... 0x50005fff: // SCC
|
||||
//printf("physical_set: got write to SCC\n");
|
||||
@ -216,11 +227,11 @@ void _physical_set_io (void)
|
||||
case 0x50012000 ... 0x50013fff: // SCSI (pseudo-DMA with no DRQ?)
|
||||
assert(shoe.physical_size == 1);
|
||||
scsi_dma_write(shoe.physical_dat);
|
||||
//printf("physical_set: got write to SCSI hi\n");
|
||||
//assert(!"physical_set: got write to SCSI hi\n");
|
||||
return ;
|
||||
case 0x50014000 ... 0x50015fff: // Sound
|
||||
printf("physical_set: got write to sound\n");
|
||||
printf("soundsound write: register 0x%04x sz=%u dat=0x%x\n",
|
||||
shoe.physical_addr - 0x50014000, shoe.physical_size, (uint32_t)shoe.physical_dat);
|
||||
// printf("physical_set: got write to sound\n");
|
||||
return ;
|
||||
case 0x50016000 ... 0x50017fff: // SWIM (IWM?)
|
||||
//printf("physical_set: got write to IWM\n");
|
||||
@ -339,7 +350,7 @@ static void translate_logical_addr()
|
||||
uint8_t desc_size = 1; // And the root pointer descriptor is always 8 bytes (1==8 bytes, 0==4 bytes)
|
||||
uint8_t used_bits = tc_is(); // Keep track of how many bits will be the effective "page size"
|
||||
// (If the table search terminates early (before used_bits == ts_ps()),
|
||||
// then this will be the effective page size. That is, the number of bits
|
||||
// then (32 - used_bits) will be the effective page size. That is, the number of bits
|
||||
// we or into the physical addr from the virtual addr)
|
||||
|
||||
desc_addr = -1; // address of the descriptor (-1 -> register)
|
||||
@ -801,275 +812,581 @@ static void ea_decode_extended()
|
||||
}
|
||||
|
||||
|
||||
void ea_read()
|
||||
// Data register direct mode
|
||||
void _ea_000_read (void)
|
||||
{
|
||||
shoe.dat = get_d(shoe.mr & 7, shoe.sz);
|
||||
}
|
||||
void _ea_000_write (void)
|
||||
{
|
||||
set_d(shoe.mr & 7, shoe.dat, shoe.sz);
|
||||
}
|
||||
|
||||
|
||||
// address register direct mode
|
||||
void _ea_001_read (void)
|
||||
{
|
||||
shoe.dat = get_a(shoe.mr & 7, shoe.sz);
|
||||
}
|
||||
void _ea_001_write (void)
|
||||
{
|
||||
assert(shoe.sz==4);
|
||||
shoe.a[shoe.mr & 7] = shoe.dat;
|
||||
}
|
||||
|
||||
|
||||
// address register indirect mode
|
||||
void _ea_010_read (void)
|
||||
{
|
||||
shoe.dat = lget(shoe.a[shoe.mr & 7], shoe.sz);
|
||||
}
|
||||
void _ea_010_write (void)
|
||||
{
|
||||
lset(shoe.a[shoe.mr & 7], shoe.sz, shoe.dat);
|
||||
}
|
||||
void _ea_010_addr (void)
|
||||
{
|
||||
shoe.dat = shoe.a[shoe.mr & 7];
|
||||
}
|
||||
|
||||
|
||||
// address register indirect with postincrement mode
|
||||
void _ea_011_read (void)
|
||||
{
|
||||
shoe.dat = lget(shoe.a[shoe.mr & 7], shoe.sz);
|
||||
}
|
||||
void _ea_011_read_commit (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
shoe.a[reg] += (((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz);
|
||||
}
|
||||
void _ea_011_write (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz;
|
||||
|
||||
lset(shoe.a[reg], shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] += delta;
|
||||
}
|
||||
|
||||
|
||||
// address register indirect with predecrement mode
|
||||
void _ea_100_read (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.dat = lget(shoe.a[reg]-delta, shoe.sz);
|
||||
}
|
||||
void _ea_100_read_commit (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
shoe.a[reg] -= (((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz);
|
||||
}
|
||||
void _ea_100_write (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz;
|
||||
|
||||
lset(shoe.a[reg] - delta, shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] -= delta;
|
||||
}
|
||||
|
||||
|
||||
// address register indirect with displacement mode
|
||||
void _ea_101_read (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc;
|
||||
switch (mode) {
|
||||
case 0: { // Data register direct mode
|
||||
shoe.dat = get_d(reg, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 1: { // address register direct mode
|
||||
shoe.dat = get_a(reg, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 2: { // address register indirect mode
|
||||
shoe.dat = lget(shoe.a[reg], shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 3: { // address register indirect with postincrement mode
|
||||
shoe.dat = lget(shoe.a[reg], shoe.sz);
|
||||
// printf("ea_read(): %u %u not implemented\n", mode, reg);
|
||||
return ;
|
||||
}
|
||||
case 4: { // address register indirect with predecrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.dat = lget(shoe.a[reg]-delta, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
const int16_t disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(shoe.a[reg]+disp, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
const int32_t addr = (int16_t)nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget((uint32_t)addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
const uint32_t addr = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 2: { // program counter indirect with displacement mode
|
||||
const uint32_t base_pc = shoe.uncommitted_ea_read_pc;
|
||||
const uint16_t u_disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
const int16_t disp = (int16_t)u_disp;
|
||||
|
||||
shoe.dat = lget(base_pc + disp, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 3: { // (program counter ...)
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 4: { // immediate data
|
||||
if (shoe.sz==1) {
|
||||
shoe.dat = nextword(shoe.uncommitted_ea_read_pc) & 0xff;
|
||||
} else if (shoe.sz == 2) {
|
||||
shoe.dat = nextword(shoe.uncommitted_ea_read_pc);
|
||||
} else if (shoe.sz == 4) {
|
||||
shoe.dat = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
} else if (shoe.sz == 8) {
|
||||
const uint64_t q = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = (q<<32) | nextlong(shoe.uncommitted_ea_read_pc);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
const int16_t disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(shoe.a[shoe.mr & 7] + disp, shoe.sz);
|
||||
}
|
||||
|
||||
void ea_read_commit()
|
||||
void _ea_101_read_commit (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
switch (mode) {
|
||||
case 0: // Data register direct mode
|
||||
case 1: // address register direct mode
|
||||
case 2: // address register indirect mode
|
||||
return ; // nothing to do
|
||||
|
||||
case 3: { // address register indirect with postincrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.a[reg] += delta;
|
||||
return ;
|
||||
}
|
||||
case 4: { // address register indirect with predecrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.a[reg] -= delta;
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
shoe.pc += 2; // this mode fetches one word
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
// shoe.extended_len was set in the previous ea_read() call.
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
shoe.pc+=2;
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
shoe.pc+=4;
|
||||
return ;
|
||||
}
|
||||
case 2: { // program counter indirect with displacement mode
|
||||
shoe.pc+=2;
|
||||
return ;
|
||||
}
|
||||
case 3: { // (program counter ...)
|
||||
// shoe.extended_len was set in the previous ea_read() call.
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 4: { // immediate data
|
||||
if (shoe.sz==1) shoe.pc += 2;
|
||||
else shoe.pc += shoe.sz;
|
||||
return ;
|
||||
}
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
shoe.pc += 2;
|
||||
}
|
||||
|
||||
void ea_write()
|
||||
void _ea_101_write (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
switch (mode) {
|
||||
case 0: { // Data register direct mode
|
||||
set_d(reg, shoe.dat, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 1: { // address register direct mode
|
||||
assert(shoe.sz==4);
|
||||
shoe.a[reg] = shoe.dat;
|
||||
return ;
|
||||
}
|
||||
case 2: { // address register indirect mode
|
||||
lset(shoe.a[reg], shoe.sz, shoe.dat);
|
||||
return ;
|
||||
}
|
||||
case 3: { // address register indirect with postincrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
|
||||
lset(shoe.a[reg], shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] += delta;
|
||||
return ;
|
||||
}
|
||||
case 4: { // address register indirect with predecrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
lset(shoe.a[reg]-delta, shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] -= delta;
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
const uint16_t u_disp = nextword(shoe.pc);
|
||||
const int16_t disp = (int16_t)u_disp; // sign-extend word to long
|
||||
lset(shoe.a[reg]+disp, shoe.sz, shoe.dat);
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
|
||||
lset(shoe.extended_addr, shoe.sz, shoe.dat);
|
||||
if (shoe.abort) return ;
|
||||
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
const int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
lset((uint32_t)addr, shoe.sz, shoe.dat);
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
lset(addr, shoe.sz, shoe.dat);
|
||||
// printf("ea_write(): %u %u not implemented\n", mode, reg);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
const int16_t disp = nextword(shoe.pc);
|
||||
lset(shoe.a[shoe.mr & 7] + disp, shoe.sz, shoe.dat);
|
||||
}
|
||||
|
||||
void ea_addr()
|
||||
void _ea_101_addr (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
switch (mode) {
|
||||
case 2: { // address register indirect mode
|
||||
shoe.dat = shoe.a[reg];
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
int16_t disp = nextword(shoe.pc);
|
||||
shoe.dat = shoe.a[reg] + disp;
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = shoe.extended_addr;
|
||||
const int16_t disp = nextword(shoe.pc);
|
||||
shoe.dat = shoe.a[shoe.mr & 7] + disp;
|
||||
}
|
||||
|
||||
|
||||
// memory/address register indirect with index
|
||||
void _ea_110_read (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort)
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + shoe.extended_len;
|
||||
}
|
||||
void _ea_110_read_commit (void)
|
||||
{
|
||||
shoe.pc = shoe.uncommitted_ea_read_pc;
|
||||
}
|
||||
void _ea_110_write (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort) {
|
||||
lset(shoe.extended_addr, shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
shoe.dat = (uint32_t)addr;
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
shoe.dat = addr;
|
||||
return ;
|
||||
}
|
||||
case 2: { // program counter indirect with displacement mode
|
||||
const uint32_t oldpc = shoe.pc;
|
||||
const uint16_t displacement = nextword(shoe.pc);
|
||||
shoe.dat = oldpc + (int16_t)displacement;
|
||||
return ;
|
||||
}
|
||||
case 3: { // (program counter ...)
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = shoe.extended_addr;
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
void _ea_110_addr (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort) {
|
||||
shoe.dat = shoe.extended_addr;
|
||||
shoe.pc += shoe.extended_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// absolute short addressing mode
|
||||
void _ea_111_000_read (void)
|
||||
{
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc;
|
||||
const int32_t addr = (int16_t)nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget((uint32_t)addr, shoe.sz);
|
||||
}
|
||||
void _ea_111_000_read_commit (void)
|
||||
{
|
||||
shoe.pc += 2;
|
||||
}
|
||||
void _ea_111_000_write (void)
|
||||
{
|
||||
const int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
lset((uint32_t)addr, shoe.sz, shoe.dat);
|
||||
}
|
||||
void _ea_111_000_addr (void)
|
||||
{
|
||||
const int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
shoe.dat = (uint32_t)addr;
|
||||
}
|
||||
|
||||
|
||||
// absolute long addressing mode
|
||||
void _ea_111_001_read (void)
|
||||
{
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc;
|
||||
const uint32_t addr = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(addr, shoe.sz);
|
||||
}
|
||||
void _ea_111_001_read_commit (void)
|
||||
{
|
||||
shoe.pc += 4;
|
||||
}
|
||||
void _ea_111_001_write (void)
|
||||
{
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
lset(addr, shoe.sz, shoe.dat);
|
||||
}
|
||||
void _ea_111_001_addr (void)
|
||||
{
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
shoe.dat = addr;
|
||||
}
|
||||
|
||||
// program counter indirect with displacement mode
|
||||
void _ea_111_010_read (void)
|
||||
{
|
||||
const uint32_t base_pc = shoe.pc;
|
||||
shoe.uncommitted_ea_read_pc = base_pc;
|
||||
const int16_t disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(base_pc + disp, shoe.sz);
|
||||
}
|
||||
void _ea_111_010_read_commit (void)
|
||||
{
|
||||
shoe.pc += 2;
|
||||
}
|
||||
void _ea_111_010_addr (void)
|
||||
{
|
||||
const uint32_t oldpc = shoe.pc;
|
||||
const int16_t displacement = nextword(shoe.pc);
|
||||
shoe.dat = oldpc + displacement;
|
||||
}
|
||||
|
||||
|
||||
// (program counter ...)
|
||||
void _ea_111_011_read (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort)
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + shoe.extended_len;
|
||||
}
|
||||
void _ea_111_011_read_commit (void)
|
||||
{
|
||||
shoe.pc = shoe.uncommitted_ea_read_pc;
|
||||
}
|
||||
void _ea_111_011_addr (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort) {
|
||||
shoe.dat = shoe.extended_addr;
|
||||
shoe.pc += shoe.extended_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// immediate data
|
||||
void _ea_111_100_read (void)
|
||||
{
|
||||
if (shoe.sz == 1) {
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + 2;
|
||||
shoe.dat = lget(shoe.pc, 2) & 0xff;
|
||||
}
|
||||
else {
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + shoe.sz;
|
||||
shoe.dat = lget(shoe.pc, shoe.sz);
|
||||
}
|
||||
}
|
||||
void _ea_111_100_read_commit (void)
|
||||
{
|
||||
shoe.pc = shoe.uncommitted_ea_read_pc;
|
||||
}
|
||||
|
||||
|
||||
// illegal EA mode
|
||||
void _ea_illegal (void)
|
||||
{
|
||||
throw_illegal_instruction();
|
||||
}
|
||||
|
||||
// nothing to do
|
||||
void _ea_nop (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const _ea_func ea_read_jump_table[64] = {
|
||||
// Data register direct mode
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
_ea_000_read,
|
||||
// address register direct mode
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
_ea_001_read,
|
||||
// address register indirect mode
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
_ea_010_read,
|
||||
// address register indirect with postincrement mode
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
_ea_011_read,
|
||||
// address register indirect with predecrement mode
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
_ea_100_read,
|
||||
// address register indirect with displacement mode
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
_ea_101_read,
|
||||
// memory/address register indirect with index
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
_ea_110_read,
|
||||
// absolute short addressing mode
|
||||
_ea_111_000_read,
|
||||
// absolute long addressing mode
|
||||
_ea_111_001_read,
|
||||
// program counter indirect with displacement mode
|
||||
_ea_111_010_read,
|
||||
// program counter indirect with index
|
||||
_ea_111_011_read,
|
||||
// immediate
|
||||
_ea_111_100_read,
|
||||
// The rest are illegal EA modes
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal
|
||||
};
|
||||
|
||||
const _ea_func ea_read_commit_jump_table[64] = {
|
||||
// Data register direct mode
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
// address register direct mode
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
// address register indirect mode
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
_ea_nop,
|
||||
// address register indirect with postincrement mode
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
_ea_011_read_commit,
|
||||
// address register indirect with predecrement mode
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
_ea_100_read_commit,
|
||||
// address register indirect with displacement mode
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
_ea_101_read_commit,
|
||||
// memory/address register indirect with index
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
_ea_110_read_commit,
|
||||
// absolute short addressing mode
|
||||
_ea_111_000_read_commit,
|
||||
// absolute long addressing mode
|
||||
_ea_111_001_read_commit,
|
||||
// program counter indirect with displacement mode
|
||||
_ea_111_010_read_commit,
|
||||
// program counter indirect with index
|
||||
_ea_111_011_read_commit,
|
||||
// immediate
|
||||
_ea_111_100_read_commit,
|
||||
// The rest are illegal EA modes
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
const _ea_func ea_write_jump_table[64] = {
|
||||
// Data register direct mode
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
_ea_000_write,
|
||||
// address register direct mode
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
_ea_001_write,
|
||||
// address register indirect mode
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
_ea_010_write,
|
||||
// address register indirect with postincrement mode
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
_ea_011_write,
|
||||
// address register indirect with predecrement mode
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
_ea_100_write,
|
||||
// address register indirect with displacement mode
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
_ea_101_write,
|
||||
// memory/address register indirect with index
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
_ea_110_write,
|
||||
// absolute short addressing mode
|
||||
_ea_111_000_write,
|
||||
// absolute long addressing mode
|
||||
_ea_111_001_write,
|
||||
// program counter indirect with displacement mode
|
||||
_ea_illegal,
|
||||
// program counter indirect with index
|
||||
_ea_illegal,
|
||||
// immediate
|
||||
_ea_illegal,
|
||||
// The rest are illegal EA modes
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal
|
||||
};
|
||||
|
||||
|
||||
const _ea_func ea_addr_jump_table[64] = {
|
||||
// Data register direct mode
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
// address register direct mode
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
// address register indirect mode
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
_ea_010_addr,
|
||||
// address register indirect with postincrement mode
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
// address register indirect with predecrement mode
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
// address register indirect with displacement mode
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
_ea_101_addr,
|
||||
// memory/address register indirect with index
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
_ea_110_addr,
|
||||
// absolute short addressing mode
|
||||
_ea_111_000_addr,
|
||||
// absolute long addressing mode
|
||||
_ea_111_001_addr,
|
||||
// program counter indirect with displacement mode
|
||||
_ea_111_010_addr,
|
||||
// program counter indirect with index
|
||||
_ea_111_011_addr,
|
||||
// immediate
|
||||
_ea_illegal,
|
||||
// The rest are illegal EA modes
|
||||
_ea_illegal,
|
||||
_ea_illegal,
|
||||
_ea_illegal
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1240
core/old_debugger.c
@ -33,7 +33,7 @@
|
||||
// (just return an empty black leaf pointer)
|
||||
rb_tree* rb_new()
|
||||
{
|
||||
return calloc(sizeof(rb_tree), 1);
|
||||
return p_alloc(shoe.pool, sizeof(rb_tree));
|
||||
}
|
||||
|
||||
// Insert a new key/value into the tree
|
||||
@ -43,7 +43,7 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
|
||||
{
|
||||
// Special edge case: insert the root node if tree's empty
|
||||
if (*root == NULL) {
|
||||
*root = calloc(sizeof(rb_node), 1);
|
||||
*root = p_alloc(shoe.pool, sizeof(rb_node));
|
||||
(*root)->key = key;
|
||||
(*root)->value = value;
|
||||
return 0;
|
||||
@ -66,7 +66,7 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
|
||||
}
|
||||
|
||||
// insert
|
||||
*cur = calloc(sizeof(rb_node), 1);
|
||||
*cur = p_alloc(shoe.pool, sizeof(rb_node));
|
||||
(*cur)->parent = parent;
|
||||
(*cur)->key = key;
|
||||
(*cur)->value = value;
|
||||
@ -252,16 +252,16 @@ void _rb_free (rb_node *node)
|
||||
{
|
||||
if (!node) return ;
|
||||
_rb_free(node->right);
|
||||
if (node->right) free(node->right);
|
||||
if (node->right) p_free(node->right);
|
||||
_rb_free(node->left);
|
||||
if (node->left) free(node->left);
|
||||
if (node->left) p_free(node->left);
|
||||
}
|
||||
|
||||
// Free all the nodes (and the rb_tree ptr itself)
|
||||
void rb_free (rb_tree *tree)
|
||||
{
|
||||
_rb_free(*tree);
|
||||
free(*tree);
|
||||
free(tree);
|
||||
p_free(*tree);
|
||||
p_free(tree);
|
||||
}
|
||||
|
||||
|
100
core/shoebill.h
@ -100,7 +100,7 @@
|
||||
// set the status register, swapping a7 if necessary
|
||||
#define set_sr(newsr) { \
|
||||
make_stack_pointers_valid(); \
|
||||
shoe.sr = newsr & 0xf71f; \
|
||||
shoe.sr = (newsr) & 0xf71f; \
|
||||
load_stack_pointer(); \
|
||||
}
|
||||
|
||||
@ -196,9 +196,27 @@ typedef struct {
|
||||
} adb_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ifr, ier, rega, regb, ddrb, ddra, sr;
|
||||
uint8_t ifr, ier, ddrb, ddra, sr, acr, pcr;
|
||||
// uint8_t rega, regb;
|
||||
uint16_t t1c, t2c, t1l;
|
||||
uint8_t rega_input, regb_input;
|
||||
uint8_t rega_output, regb_output;
|
||||
long double t1_last_set, t2_last_set;
|
||||
} via_state_t;
|
||||
|
||||
#define PRAM_READ 1
|
||||
#define PRAM_WRITE 2
|
||||
typedef struct {
|
||||
uint8_t data[256];
|
||||
uint8_t last_bits;
|
||||
|
||||
// FSM
|
||||
uint8_t command[8];
|
||||
uint8_t byte, mode, command_i, bit_i;
|
||||
} pram_state_t;
|
||||
|
||||
void init_via_state();
|
||||
|
||||
typedef struct {
|
||||
uint8_t scsi_id;
|
||||
uint32_t num_blocks, block_size;
|
||||
@ -254,7 +272,6 @@ typedef struct {
|
||||
void (*write_func)(uint32_t, uint32_t, uint32_t, uint8_t);
|
||||
void *ctx;
|
||||
uint8_t slotnum, connected, interrupts_enabled;
|
||||
int32_t glut_window_id;
|
||||
long double interrupt_rate, last_fired;
|
||||
} nubus_card_t;
|
||||
|
||||
@ -276,7 +293,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
|
||||
#define SHOEBILL_STATE_STOPPED (1<<9)
|
||||
#define SHOEBILL_STATE_STOPPED (1<<8)
|
||||
|
||||
// bits 0-6 are CPU interrupt priorities
|
||||
// bit 8 indicates that STOP was called
|
||||
@ -286,14 +303,6 @@ typedef struct {
|
||||
pthread_mutex_t via_clock_thread_lock;
|
||||
pthread_mutex_t cpu_freeze_lock;
|
||||
|
||||
// -- PMMU caching structures ---
|
||||
#define PMMU_CACHE_KEY_BITS 10
|
||||
#define PMMU_CACHE_SIZE (1<<PMMU_CACHE_KEY_BITS)
|
||||
struct {
|
||||
pmmu_cache_entry_t entry[PMMU_CACHE_SIZE];
|
||||
uint8_t valid_map[PMMU_CACHE_SIZE / 8];
|
||||
} pmmu_cache[2];
|
||||
|
||||
// -- Assorted CPU state variables --
|
||||
uint16_t op; // the first word of the instruction we're currently running
|
||||
uint16_t orig_sr; // the sr before we began executing the instruction
|
||||
@ -318,18 +327,21 @@ typedef struct {
|
||||
_Bool logical_is_write; // <- boolean: true iff the operation is logical_set()
|
||||
uint8_t logical_fc; // logical function code
|
||||
|
||||
// -- Interrupts/VIA chips --
|
||||
// -- PMMU caching structures ---
|
||||
#define PMMU_CACHE_KEY_BITS 10
|
||||
#define PMMU_CACHE_SIZE (1<<PMMU_CACHE_KEY_BITS)
|
||||
struct {
|
||||
pmmu_cache_entry_t entry[PMMU_CACHE_SIZE];
|
||||
uint8_t valid_map[PMMU_CACHE_SIZE / 8];
|
||||
} pmmu_cache[2];
|
||||
|
||||
// uint8_t stopped; // whether STOP was called
|
||||
// uint8_t pending_interrupt; // (0 -> no pending interrupt, >0 -> interrupt priority (autovector))
|
||||
via_state_t via[2];
|
||||
adb_state_t adb;
|
||||
keyboard_state_t key;
|
||||
mouse_state_t mouse;
|
||||
iwm_state_t iwm;
|
||||
|
||||
nubus_card_t slots[16];
|
||||
// video_state_t video;
|
||||
// -- EA state --
|
||||
uint32_t uncommitted_ea_read_pc; // set by ea_read(). It's the PC that ea_read_commit will set.
|
||||
uint64_t dat; // the raw input/output for the transaction
|
||||
uint32_t extended_addr; // EA returned by ea_decode_extended()
|
||||
uint32_t extended_len; // number of instruction bytes used by ea_decode_extended()
|
||||
uint8_t sz; // the size of the EA transaction
|
||||
uint8_t mr; // a 6-bit mode/reg pair
|
||||
|
||||
// -- Registers --
|
||||
uint32_t d[8];
|
||||
@ -430,27 +442,27 @@ typedef struct {
|
||||
|
||||
long double fp[8]; // 80 bit floating point general registers
|
||||
|
||||
// -- Interrupts/VIA chips --
|
||||
|
||||
// -- EA state --
|
||||
uint32_t uncommitted_ea_read_pc; // set by ea_read(). It's the PC that ea_read_commit will set.
|
||||
uint64_t dat; // the raw input/output for the transaction
|
||||
uint32_t extended_addr; // EA returned by ea_decode_extended()
|
||||
uint32_t extended_len; // number of instruction bytes used by ea_decode_extended()
|
||||
uint8_t sz; // the size of the EA transaction
|
||||
uint8_t mr; // a 6-bit mode/reg pair
|
||||
via_state_t via[2];
|
||||
adb_state_t adb;
|
||||
keyboard_state_t key;
|
||||
mouse_state_t mouse;
|
||||
iwm_state_t iwm;
|
||||
|
||||
nubus_card_t slots[16];
|
||||
|
||||
via_clock_t via_clocks;
|
||||
|
||||
|
||||
struct timeval start_time; // when the emulator started (for computing timer interrupts)
|
||||
uint64_t total_ticks; // how many 60hz ticks have been generated
|
||||
|
||||
coff_file *coff; // Data/symbols from the unix kernel
|
||||
|
||||
coff_file *launch; // FIXME: delete me: coff symbols from aux 1.1.1 launch binary
|
||||
|
||||
scsi_device_t scsi_devices[8]; // SCSI devices
|
||||
|
||||
pram_state_t pram;
|
||||
|
||||
debugger_state_t dbg;
|
||||
alloc_pool_t *pool;
|
||||
} global_shoebill_context_t;
|
||||
@ -520,11 +532,17 @@ void logical_set (void);
|
||||
lset_fc((addr), (s), (val), sr_s() ? 5 : 1) \
|
||||
}
|
||||
|
||||
typedef void (*_ea_func) (void);
|
||||
extern const _ea_func ea_read_jump_table[64];
|
||||
extern const _ea_func ea_read_commit_jump_table[64];
|
||||
extern const _ea_func ea_write_jump_table[64];
|
||||
extern const _ea_func ea_addr_jump_table[64];
|
||||
|
||||
#define ea_read() ea_read_jump_table[shoe.mr]()
|
||||
#define ea_read_commit() ea_read_commit_jump_table[shoe.mr]()
|
||||
#define ea_write() ea_write_jump_table[shoe.mr]()
|
||||
#define ea_addr() ea_addr_jump_table[shoe.mr]()
|
||||
|
||||
void ea_read();
|
||||
void ea_read_commit();
|
||||
void ea_write();
|
||||
void ea_addr();
|
||||
|
||||
#define call_ea_read(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read();if (shoe.abort) return;}
|
||||
#define call_ea_write(M, s) {shoe.mr=(M);shoe.sz=(s);ea_write();if (shoe.abort) return;}
|
||||
@ -549,9 +567,6 @@ void ea_addr();
|
||||
desc_addr = (_addr); \
|
||||
desc_level++; \
|
||||
}
|
||||
// if (shoe.dbg) \
|
||||
// printf("desc_addr *0x%08x = 0x%llx\n", (uint32_t)(_addr), desc); \
|
||||
// }
|
||||
|
||||
|
||||
// dis.c functions
|
||||
@ -589,11 +604,10 @@ void scsi_dma_write(uint8_t byte);
|
||||
void scsi_dma_write_long(uint32_t dat);
|
||||
|
||||
// via1 & via2 (+ CPU interrupts)
|
||||
void check_time();
|
||||
void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit);
|
||||
void process_pending_interrupt();
|
||||
void via_reg_read();
|
||||
void via_reg_write();
|
||||
void via_read_raw();
|
||||
void via_write_raw();
|
||||
void *via_clock_thread(void *arg);
|
||||
|
||||
// VIA registers
|
||||
|
579
core/via.c
@ -29,6 +29,7 @@
|
||||
#include <pthread.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "../core/shoebill.h"
|
||||
|
||||
char *via_reg_str[16] = {
|
||||
@ -66,8 +67,8 @@ void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit)
|
||||
// Only if the bit is enabled in IER do we raise a cpu interrupt
|
||||
if (via->ier & (1 << ifr_bit))
|
||||
set_pending_interrupt(vianum);
|
||||
else
|
||||
printf("didn't set pending interrupt\n");
|
||||
//else
|
||||
// printf("didn't set pending interrupt\n");
|
||||
}
|
||||
|
||||
|
||||
@ -184,6 +185,7 @@ void process_pending_interrupt ()
|
||||
|
||||
#define VIA_REGB_DONE 8
|
||||
|
||||
|
||||
// VIA registers
|
||||
#define VIA_ORB 0
|
||||
#define VIA_ORA 1
|
||||
@ -202,75 +204,413 @@ void process_pending_interrupt ()
|
||||
#define VIA_IER 14
|
||||
#define VIA_ORA_AUX 15
|
||||
|
||||
uint16_t counter;
|
||||
// Interrupt flag register bits
|
||||
#define VIA_IFR_CA2 (1<<0)
|
||||
#define VIA_IFR_CA1 (1<<1)
|
||||
#define VIA_IFR_SHIFT_REG (1<<2)
|
||||
#define VIA_IFR_CB2 (1<<3)
|
||||
#define VIA_IFR_CB1 (1<<4)
|
||||
#define VIA_IFR_T2 (1<<5)
|
||||
#define VIA_IFR_T1 (1<<6)
|
||||
#define VIA_IFR_IRQ (1<<7)
|
||||
|
||||
void via_reg_read ()
|
||||
static long double _now (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
long double secs = tv.tv_sec;
|
||||
long double usecs = tv.tv_usec;
|
||||
|
||||
return secs + (usecs / 1000000.0);
|
||||
}
|
||||
|
||||
static void handle_pram_write_byte (void)
|
||||
{
|
||||
pram_state_t *pram = &shoe.pram;
|
||||
|
||||
printf("PRAMPRAM: wrote_byte 0x%02x\n", pram->byte);
|
||||
|
||||
pram->mode = PRAM_READ;
|
||||
pram->byte = 0;
|
||||
}
|
||||
|
||||
static void handle_pram_read_byte (void)
|
||||
{
|
||||
pram_state_t *pram = &shoe.pram;
|
||||
|
||||
assert(pram->command_i < 8);
|
||||
pram->command[pram->command_i++] = pram->byte;
|
||||
|
||||
printf("PRAMPRAM: read_byte: 0x%02x\n", pram->byte);
|
||||
|
||||
// If this is a pram-read/write...
|
||||
if ((pram->command[0] & 0x78) == 0x38) {
|
||||
const _Bool isget = pram->command[0] >> 7;
|
||||
const uint8_t addr = (pram->command[0] << 5) | ((pram->command[1] >> 2) & 0x1f);
|
||||
|
||||
if ((pram->command_i == 3) && !isget) { // complete set command
|
||||
pram->mode = PRAM_READ; // stay in read-mode
|
||||
pram->data[addr] = pram->command[2];
|
||||
|
||||
FILE *f = fopen("pram.dump", "w");
|
||||
if (f) {
|
||||
fwrite(pram->data, 256, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
printf("PRAMPRAM: setting pram addr 0x%02x = 0x%02x\n", addr, pram->command[2]);
|
||||
|
||||
pram->byte = 0;
|
||||
pram->command_i = 0;
|
||||
|
||||
return ;
|
||||
}
|
||||
else if ((pram->command_i == 2) && isget) { // complete get command
|
||||
pram->mode = PRAM_WRITE; // switch to write-mode
|
||||
pram->byte = pram->data[addr];
|
||||
pram->command_i = 0;
|
||||
|
||||
printf("PRAMPRAM: fetching pram addr 0x%02x (= 0x%02x)\n", addr, pram->byte);
|
||||
|
||||
return ;
|
||||
}
|
||||
else { // incomplete command, keep reading
|
||||
assert(pram->command_i < 4);
|
||||
pram->mode = PRAM_READ; // keep reading
|
||||
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is clock-read/write
|
||||
else if (~bmatch(pram->command[0], x 00x xx 01)) {
|
||||
const _Bool isget = pram->command[0] >> 7;
|
||||
const uint8_t addr = (pram->command[0] >> 2) & 3;
|
||||
const _Bool mysterybit = (pram->command[0] >> 4) & 1; // FIXME: What does this do?
|
||||
|
||||
if ((pram->command_i == 2) && !isget) { // complete set command
|
||||
pram->mode = PRAM_READ; // stay in read-mode
|
||||
|
||||
printf("PRAMPRAM: setting time byte %u to 0x%02x (mysterybit=%u)\n", addr, pram->command[1], mysterybit);
|
||||
|
||||
pram->byte = 0;
|
||||
pram->command_i = 0;
|
||||
return ;
|
||||
}
|
||||
else if ((pram->command_i == 1) && isget) { // complete get command
|
||||
const uint32_t now = time(NULL) + 0x7c25b080;
|
||||
//uint32_t now = 0xafd56d80; // Tue, 24 Jun 1997 12:26:40 GMT
|
||||
const uint8_t now_byte = now >> (8*addr);
|
||||
|
||||
pram->mode = PRAM_WRITE;
|
||||
pram->byte = now_byte;
|
||||
pram->command_i = 0;
|
||||
|
||||
printf("PRAMPRAM: fetching time byte %u of 0x%08x (mysterybit=%u)\n", addr, now, mysterybit);
|
||||
return ;
|
||||
}
|
||||
else { // incomplete command, keep reading
|
||||
assert(pram->command_i < 3);
|
||||
pram->mode = PRAM_READ;
|
||||
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
// This is mystery command # 2
|
||||
else if (pram->command[0] == 0x35) {
|
||||
// Arrives in pairs of two bytes
|
||||
if (pram->command_i == 2) {
|
||||
printf("PRAMPRAM: mystery command 2 0x%02x 0x%02x (?))\n", pram->command[0], pram->command[1]);
|
||||
|
||||
pram->mode = PRAM_READ;
|
||||
pram->command_i = 0;
|
||||
return ;
|
||||
}
|
||||
else { // keep reading
|
||||
assert(pram->command_i < 3);
|
||||
pram->mode = PRAM_READ;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
printf("PRAMPRAM: don't understand this command\n");
|
||||
pram->command_i = 0;
|
||||
pram->mode = PRAM_READ;
|
||||
}
|
||||
|
||||
static void handle_pram_state_change (void)
|
||||
{
|
||||
pram_state_t *pram = &shoe.pram;
|
||||
|
||||
// If rtcClock or rtcEnable changed, then the state machine needs updating
|
||||
if (pram->last_bits == (shoe.via[0].regb_output & shoe.via[0].ddrb & 6))
|
||||
return ;
|
||||
|
||||
printf("PRAMPRAM: pram->last_bits = %u, (shoe.via[0].regb & 6) = %u\n", pram->last_bits, (shoe.via[0].regb_output & shoe.via[0].ddrb & 6));
|
||||
|
||||
// it doesn't matter what the last rtcData value was
|
||||
const _Bool last_rtcClock = (pram->last_bits >> 1) & 1;
|
||||
const _Bool last_rtcEnable = (pram->last_bits >> 2) & 1;
|
||||
|
||||
const _Bool rtcData = shoe.via[0].regb_output & 1;
|
||||
const _Bool rtcClock = (shoe.via[0].regb_output >> 1) & 1;
|
||||
const _Bool rtcEnable = (shoe.via[0].regb_output >> 2) & 1;
|
||||
|
||||
printf("PRAMPRAM: bits changed %u%ux -> %u%u%u\n", last_rtcEnable, last_rtcClock, rtcEnable, rtcClock, rtcData);
|
||||
|
||||
if (rtcEnable) {
|
||||
// rtcEnable==true => the RTC chip is enabled and we are talking to it
|
||||
// Not sure what happens when you toggle data/clock bits while rtcEnable is asserted...
|
||||
if (last_rtcEnable)
|
||||
printf("PRAMPRAM: toggled bits while rtcEnable was asserted!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!rtcEnable && last_rtcEnable) {
|
||||
// if rtcEnable went from hi to low, then reset all the state stuff
|
||||
pram->mode = PRAM_READ;
|
||||
pram->command_i = 0; // the current command byte we're working on
|
||||
pram->bit_i = 0; // the current bit num we're reading/writing
|
||||
pram->byte = 0; // the current byte we're reading/writing
|
||||
memset(pram->command, 0, 8);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
switch (pram->mode) {
|
||||
case PRAM_READ: {
|
||||
// if rtcClock goes from low to hi, then rtcData represents a new bit
|
||||
if (rtcClock && !last_rtcClock) {
|
||||
pram->byte <<= 1;
|
||||
pram->byte |= rtcData;
|
||||
pram->bit_i++;
|
||||
}
|
||||
|
||||
if ((shoe.via[0].ddrb & 1) == 0) {
|
||||
// This is input-mode -- should be output-mode
|
||||
printf("PRAMPRAM: BOGUS MODE ddrb&1 == 0\n");
|
||||
}
|
||||
|
||||
|
||||
if (pram->bit_i >= 8) {
|
||||
pram->bit_i = 0;
|
||||
handle_pram_read_byte();
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
case PRAM_WRITE: {
|
||||
// if rtcClock goes from hi to low, load in the new rtcData bit
|
||||
if (!rtcClock && last_rtcClock) {
|
||||
const uint8_t newData = (pram->byte >> (7 - pram->bit_i)) & 1;
|
||||
shoe.via[0].regb_input &= 0xfe;
|
||||
shoe.via[0].regb_input |= newData;
|
||||
}
|
||||
|
||||
// if B goes from low to hi, skip to the next bit
|
||||
if (rtcClock && !last_rtcClock)
|
||||
pram->bit_i++;
|
||||
|
||||
assert((shoe.via[0].ddrb & 1) == 0);
|
||||
|
||||
if (pram->bit_i >= 8) {
|
||||
pram->bit_i = 0;
|
||||
handle_pram_write_byte();
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(!"can't get here");
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
// Remember the last state of the bits
|
||||
pram->last_bits = (shoe.via[0].regb_output & shoe.via[0].ddrb & 6);
|
||||
}
|
||||
|
||||
void init_via_state (void)
|
||||
{
|
||||
/* -- Zero everything -- */
|
||||
|
||||
memset(&shoe.pram, 0, sizeof(pram_state_t));
|
||||
memset(&shoe.via, 0, 2 * sizeof(via_state_t));
|
||||
|
||||
// Jeez, keep this straight!
|
||||
// DDR 0 -> input (from pins to OS)
|
||||
// 1 -> output (from OS to pins)
|
||||
|
||||
/* -- Initialize VIA1 -- */
|
||||
|
||||
/* VIA 1 reg A
|
||||
* Bit 7 - input - vSCCWrReq
|
||||
* Bit 6 - input - CPU.ID1
|
||||
* Bit 5 - output - vHeadSel
|
||||
* Bit 4 - output - vOverlay
|
||||
* Bit 3 - output - vSync
|
||||
* Bit 2-0 unused
|
||||
*/
|
||||
shoe.via[0].ddra = 0b00111000;
|
||||
|
||||
/* VIA 1 reg B
|
||||
* Bit 7 - output - vSndEnb
|
||||
* Bit 6 - unused
|
||||
* Bit 5 - output - vFDesk2
|
||||
* Bit 4 - output - vFDesk1
|
||||
* Bit 3 - input - vFDBInt
|
||||
* Bit 2 - output - rTCEnb
|
||||
* Bit 1 - output - rtcClk
|
||||
* Bit 0 - in/out - rtcData (initialize to output)
|
||||
*/
|
||||
shoe.via[0].ddrb = 0b10110111; // A/UX apparently neglects to initialize ddra/b
|
||||
|
||||
/* -- Initialize VIA2 -- */
|
||||
|
||||
/* VIA 2 reg A
|
||||
* Bit 7 - unused
|
||||
* Bit 6 - unused
|
||||
* Bit 5 - Interrupt for slot 15
|
||||
* ...
|
||||
* Bit 0 - Interrupt for slot 9
|
||||
*/
|
||||
shoe.via[1].ddra = 0x00; // via2/rega consists of input pins for nubus interrupts
|
||||
shoe.via[1].rega_input = 0b00111111; // no nubus interrupts currently asserted
|
||||
|
||||
/* VIA 2 reg B
|
||||
* Bit 7 - output - v2VBL
|
||||
* Bit 6 - input - v2SNDEXT
|
||||
* Bit 5 - input - v2TM0A (nubus transfer what??)
|
||||
* Bit 4 - input - v2TM1A
|
||||
* Bit 3 - output - AMU/PMMU control
|
||||
* Bit 2 - output - v2PowerOff
|
||||
* Bit 1 - output - v2BusLk
|
||||
* Bit 0 - output - v2cdis
|
||||
*/
|
||||
shoe.via[1].ddrb = 0b10001111;
|
||||
// FIXME: apparently via2/regb bit 7 is tied to VIA1, and driven by timer T1, to
|
||||
// generate 60.15hz interrupts on VIA1
|
||||
// emulate this more accurately!
|
||||
|
||||
/* -- Initialize PRAM -- */
|
||||
|
||||
pram_state_t *pram = &shoe.pram;
|
||||
pram->mode = PRAM_READ;
|
||||
|
||||
FILE *f = fopen("pram.dump", "r");
|
||||
if (f) {
|
||||
fread(pram->data, 256, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
#define E_CLOCK 783360
|
||||
#define HALF_E_CLOCK (E_CLOCK / 2)
|
||||
|
||||
#define _via_get_delta_counter(last_set) ({ \
|
||||
const long double delta_t = now - (last_set); \
|
||||
const long double delta_ticks = fmodl((delta_t * (long double)E_CLOCK), 0x10000); \
|
||||
/* The VIA timers decrement by 2 for every E_CLOCK tick */ \
|
||||
const uint16_t delta_counter = ((uint16_t)delta_ticks) << 1; \
|
||||
printf("_via_get_delta_counter: now = %Lf delta_t = %Lf delta_ticks = %Lf delta_counter = %u\n", now, delta_t, delta_ticks, delta_counter); \
|
||||
delta_counter; \
|
||||
})
|
||||
|
||||
// from the pins' perspective
|
||||
#define VIA_REGA_PINS(n) ((shoe.via[(n)-1].rega_output & shoe.via[(n)-1].ddra) | \
|
||||
(shoe.via[(n)-1].rega_input & (~~shoe.via[(n)-1].ddra)))
|
||||
|
||||
#define VIA_REGB_PINS(n) ((shoe.via[(n)-1].regb_output & shoe.via[(n)-1].ddrb) | \
|
||||
(shoe.via[(n)-1].regb_input & (~~shoe.via[(n)-1].ddrb)))
|
||||
|
||||
static uint8_t via_read_reg(const uint8_t vianum, const uint8_t reg, const long double now)
|
||||
{
|
||||
const uint8_t vianum = (shoe.physical_addr >= 0x50002000) ? 2 : 1;
|
||||
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
|
||||
via_state_t *via = &shoe.via[vianum - 1];
|
||||
|
||||
printf("via_reg_read: reading from via%u reg %s (%u)\n", vianum, via_reg_str[reg], reg);
|
||||
|
||||
switch (reg) {
|
||||
case VIA_ACR:
|
||||
return via->acr;
|
||||
|
||||
case VIA_PCR:
|
||||
return via->pcr;
|
||||
|
||||
case VIA_IER:
|
||||
// According to the eratta, bit 7 is always set during a read
|
||||
shoe.physical_dat = via->ier | 0x80;
|
||||
break ;
|
||||
return via->ier | 0x80;
|
||||
|
||||
case VIA_IFR: {
|
||||
// Figure out whether any enabled interrupts are set, and set IRQ accordingly
|
||||
const uint8_t irq = (via->ifr & via->ier & 0x7f) ? 0x80 : 0x0;
|
||||
shoe.physical_dat = (via->ifr & 0x7f) | irq;
|
||||
break ;
|
||||
return (via->ifr & 0x7f) | irq;
|
||||
}
|
||||
|
||||
case VIA_SR:
|
||||
shoe.physical_dat = via->sr;
|
||||
break;
|
||||
|
||||
case VIA_ORB:
|
||||
shoe.physical_dat = via->regb;
|
||||
break;
|
||||
return via->sr;
|
||||
|
||||
case VIA_ORB: {
|
||||
/*
|
||||
* FIXME: this is not exactly correct.
|
||||
* if input latching is enabled, then the value of input pins
|
||||
* is held in escrow until a CB1 transition occurs. I'm not doing that.
|
||||
*/
|
||||
printf("via_reg_read: FYI: regb_output=0x%02x regb_input=0x%02x ddrb=0x%02x combined=0x%02x\n",
|
||||
shoe.via[vianum-1].regb_output, shoe.via[vianum-1].regb_input, via->ddrb, VIA_REGB_PINS(vianum));
|
||||
return VIA_REGB_PINS(vianum);
|
||||
}
|
||||
|
||||
case VIA_ORA_AUX:
|
||||
case VIA_ORA:
|
||||
//if ((vianum==2) && !(via->ifr & (1<<IFR_CA1)))
|
||||
//via->rega = 0x3f;
|
||||
shoe.physical_dat = via->rega;
|
||||
break;
|
||||
case VIA_ORA: {
|
||||
/*
|
||||
* FIXME: This is not exactly correct either, and it behaves differently from regb
|
||||
* Reading regA never returns the contents of the output register directly,
|
||||
* it returns the the value of the pins - unless input latching is enabled,
|
||||
* then it holds the pin values in escrow until a CA1 transition occurs.
|
||||
* I'm just returning the value of the "pins"
|
||||
*/
|
||||
return VIA_REGA_PINS(vianum);
|
||||
}
|
||||
|
||||
case VIA_DDRB:
|
||||
shoe.physical_dat = via->ddrb;
|
||||
break;
|
||||
return via->ddrb;
|
||||
|
||||
case VIA_DDRA:
|
||||
shoe.physical_dat = via->ddra;
|
||||
break;
|
||||
return via->ddra;
|
||||
|
||||
case VIA_T2C_HI: {
|
||||
const uint16_t counter = via->t2c - _via_get_delta_counter(via->t2_last_set);
|
||||
return counter >> 8;
|
||||
}
|
||||
case VIA_T2C_LO: {
|
||||
const uint16_t counter = via->t2c - _via_get_delta_counter(via->t2_last_set);
|
||||
via->ifr &= ~~VIA_IFR_T2; // Read from T2C_LOW clears TIMER 2 interrupt
|
||||
return (uint8_t)counter;
|
||||
}
|
||||
|
||||
case VIA_T2C_LO:
|
||||
// XXX: A/UX 3.0.1 tries to precisely time a huge dbra loop
|
||||
// using via timer2. It won't accept any result shorter than
|
||||
// 0x492, and hypothetically, this emulator could execute the
|
||||
// loop faster than that (although not currently). So this is
|
||||
// a super dumb hack that always returns a delta-t of 0x492
|
||||
// between sequential reads from t2c.
|
||||
// (oh, also, a/ux 3.0.1 cleverly reads from both t2c_lo and _hi
|
||||
// simultaneously by doing a word-size read at VIA+0x11ff)
|
||||
counter -= 0x492;
|
||||
shoe.physical_dat = 0xffff & ((counter >> 8) | (counter << 8));
|
||||
break;
|
||||
case VIA_T1C_LO:
|
||||
via->ifr &= ~~VIA_IFR_T1; // Read from T1C_LOW clears TIMER 1 interrupt
|
||||
return 0; // FIXME
|
||||
|
||||
default:
|
||||
printf("via_reg_read: (unhandled!)\n");
|
||||
break;
|
||||
case VIA_T1C_HI:
|
||||
return 0; // FIXME
|
||||
|
||||
case VIA_T1L_LO:
|
||||
return 0; // FIXME
|
||||
|
||||
case VIA_T1L_HI:
|
||||
return 0; // FIXME
|
||||
}
|
||||
assert(!"never get here");
|
||||
}
|
||||
|
||||
void via_reg_write()
|
||||
static void via_write_reg(const uint8_t vianum, const uint8_t reg, const uint8_t data, const long double now)
|
||||
{
|
||||
const uint8_t vianum = (shoe.physical_addr >= 0x50002000) ? 2 : 1;
|
||||
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
|
||||
const uint8_t data = (uint8_t)shoe.physical_dat;
|
||||
via_state_t *via = &shoe.via[vianum - 1];
|
||||
|
||||
printf("via_reg_write: writing 0x%02x to via%u reg %s (%u)\n", (uint8_t)shoe.physical_dat, vianum, via_reg_str[reg], reg);
|
||||
@ -300,25 +640,49 @@ void via_reg_write()
|
||||
break;
|
||||
|
||||
case VIA_ORB: {
|
||||
via->regb = data;
|
||||
|
||||
// The OS should only be able to "set" the bits that are marked as "output" in ddra/b
|
||||
|
||||
// FIXME: we need separate ORA/ORB and IRA/IRB registers
|
||||
|
||||
/*const uint8_t ddr_mask = via->ddrb;
|
||||
const uint8_t data_sans_input = data & ddr_mask;
|
||||
const uint8_t reg_sans_output = via->regb & (~~ddr_mask);
|
||||
via->regb = data_sans_input | reg_sans_output;
|
||||
// via->regb = data;*/
|
||||
via->regb_output = data;
|
||||
|
||||
if (vianum == 1) {
|
||||
const uint8_t adb_state = (data >> 4) & 3;
|
||||
const uint8_t adb_state = (data >> 4) & 3; // just assume that the corresponding ddrb bits are marked "output"
|
||||
if (shoe.adb.state != adb_state) {
|
||||
const uint8_t old_state = shoe.adb.state;
|
||||
shoe.adb.state = adb_state;
|
||||
|
||||
adb_handle_state_change(old_state, adb_state);
|
||||
}
|
||||
|
||||
handle_pram_state_change();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case VIA_ORA_AUX:
|
||||
case VIA_ORA:
|
||||
via->rega = data;
|
||||
case VIA_ORA: {
|
||||
// The OS should only be able to "set" the bits that are marked as "output" in ddra/b
|
||||
|
||||
// FIXME: we need separate ORA/ORB and IRA/IRB registers
|
||||
|
||||
/*const uint8_t ddr_mask = via->ddra;
|
||||
const uint8_t data_sans_input = data & ddr_mask;
|
||||
const uint8_t reg_sans_output = via->rega & (~~ddr_mask);
|
||||
via->rega = data_sans_input | reg_sans_output;
|
||||
// via->rega = data;*/
|
||||
|
||||
via->rega_output = data;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case VIA_DDRB:
|
||||
via->ddrb = data;
|
||||
@ -328,55 +692,90 @@ void via_reg_write()
|
||||
via->ddra = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("via_reg_read: (unhandled!)\n");
|
||||
case VIA_ACR:
|
||||
via->acr = data;
|
||||
break;
|
||||
|
||||
case VIA_PCR:
|
||||
via->pcr = data;
|
||||
break;
|
||||
|
||||
case VIA_T2C_LO:
|
||||
break;
|
||||
|
||||
case VIA_T2C_HI:
|
||||
via->ifr &= ~~VIA_IFR_T2; // Write to T2C_HI clears TIMER 2 interrupt
|
||||
break;
|
||||
|
||||
case VIA_T1C_LO:
|
||||
break;
|
||||
|
||||
case VIA_T1C_HI:
|
||||
via->ifr &= ~~VIA_IFR_T1; // Write to T1C_HI clears TIMER 1 interrupt
|
||||
break;
|
||||
|
||||
case VIA_T1L_LO:
|
||||
break;
|
||||
|
||||
case VIA_T1L_HI:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: check_time() is bad and needs rewritten
|
||||
void check_time()
|
||||
void via_write_raw (void)
|
||||
{
|
||||
struct timeval now, delta_tv;
|
||||
const uint32_t hz = 10;
|
||||
const uint8_t vianum = ((shoe.physical_addr >> 13) & 1) + 1;
|
||||
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
|
||||
|
||||
// return ;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
delta_tv.tv_sec = now.tv_sec - shoe.start_time.tv_sec;
|
||||
if (now.tv_usec < shoe.start_time.tv_usec) {
|
||||
delta_tv.tv_sec--;
|
||||
delta_tv.tv_usec = (now.tv_usec + 1000000) - shoe.start_time.tv_usec;
|
||||
if (shoe.physical_size == 1) {
|
||||
const long double now = ((reg >= VIA_T1C_LO) && (reg <= VIA_T2C_HI)) ? _now() : 0.0;
|
||||
// Common case: writing to only one register
|
||||
|
||||
via_write_reg(vianum, reg, (uint8_t)shoe.physical_dat, now);
|
||||
}
|
||||
else if ((shoe.physical_size == 2) && ((shoe.physical_addr & 0x1ff) == 0x1ff)) {
|
||||
const long double now = ((reg >= VIA_T1C_LO) && ((reg+1) <= VIA_T2C_HI)) ? _now() : 0.0;
|
||||
// Uncommon case: writing to two registers simultaneously
|
||||
|
||||
printf("via_write_raw: writing to two registers simultaneously %u and %u\n", reg, reg+1);
|
||||
|
||||
assert(reg != 15); // If A/UX is trying to write to two VIA chips simultanously, that's not cool
|
||||
|
||||
via_write_reg(vianum, reg, (uint8_t)(shoe.physical_dat >> 8), now);
|
||||
via_write_reg(vianum, reg+1, (uint8_t)shoe.physical_dat, now);
|
||||
}
|
||||
else
|
||||
delta_tv.tv_usec = now.tv_usec - shoe.start_time.tv_usec;
|
||||
|
||||
uint64_t delta = delta_tv.tv_sec * 1000;
|
||||
delta += delta_tv.tv_usec / 1000;
|
||||
|
||||
uint64_t ticks = delta / hz;
|
||||
if (ticks <= shoe.total_ticks)
|
||||
return ;
|
||||
|
||||
shoe.total_ticks = ticks;
|
||||
//printf("ticks = %llu\n", ticks);
|
||||
|
||||
via_raise_interrupt(1, IFR_CA1);
|
||||
//
|
||||
shoe.via[1].rega = 0b00111101;
|
||||
via_raise_interrupt(2, IFR_CA1);
|
||||
assert("Writing multiple bytes to the same VIA register!");
|
||||
|
||||
}
|
||||
|
||||
static long double _now (void)
|
||||
void via_read_raw (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
const uint8_t vianum = ((shoe.physical_addr >> 13) & 1) + 1;
|
||||
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
|
||||
|
||||
long double secs = tv.tv_sec;
|
||||
long double usecs = tv.tv_usec;
|
||||
|
||||
return secs + (usecs / 1000000.0);
|
||||
if (shoe.physical_size == 1) {
|
||||
const long double now = ((reg >= VIA_T1C_LO) && (reg <= VIA_T2C_HI)) ? _now() : 0.0;
|
||||
|
||||
// Common case: reading only one register
|
||||
shoe.physical_dat = via_read_reg(vianum, reg, now);
|
||||
}
|
||||
else if ((shoe.physical_size == 2) && ((shoe.physical_addr & 0x1ff) == 0x1ff)) {
|
||||
const long double now = ((reg >= VIA_T1C_LO) && ((reg+1) <= VIA_T2C_HI)) ? _now() : 0.0;
|
||||
|
||||
// Uncommon case: reading from two registers simultaneously
|
||||
|
||||
printf("via_read_raw: reading from two registers simultaneously %u and %u\n", reg, reg+1);
|
||||
|
||||
assert(reg != 15); // If A/UX is trying to read from two VIA chips simultaneously, that's not cool
|
||||
|
||||
uint16_t result = via_read_reg(vianum, reg, now);
|
||||
result = (result << 8) | via_read_reg(vianum, reg+1, now);
|
||||
shoe.physical_dat = result;
|
||||
|
||||
}
|
||||
else
|
||||
assert(!"Reading multiple bytes from the same VIA register!");
|
||||
}
|
||||
|
||||
#define fire(s) ({assert((s) >= 0); if (earliest_next_timer > (s)) earliest_next_timer = (s);})
|
||||
@ -416,14 +815,14 @@ void *via_clock_thread(void *arg)
|
||||
|
||||
via_raise_interrupt(1, IFR_CA2);
|
||||
|
||||
/*via_raise_interrupt(1, IFR_TIMER1);
|
||||
via_raise_interrupt(1, IFR_TIMER1);
|
||||
via_raise_interrupt(1, IFR_TIMER2);
|
||||
via_raise_interrupt(2, IFR_TIMER1);
|
||||
via_raise_interrupt(2, IFR_TIMER2);*/
|
||||
via_raise_interrupt(2, IFR_TIMER2);
|
||||
}
|
||||
|
||||
// Check if any nubus cards have interrupt timers
|
||||
shoe.via[1].rega = 0b00111111;
|
||||
shoe.via[1].rega_input = 0b00111111;
|
||||
for (i=9; i<15; i++) {
|
||||
if (!shoe.slots[i].connected)
|
||||
continue;
|
||||
@ -435,9 +834,9 @@ void *via_clock_thread(void *arg)
|
||||
|
||||
if (shoe.slots[i].interrupts_enabled) {
|
||||
// shoe.via[1].rega = 0b00111111 & ~~(1<<(i-9));
|
||||
shoe.via[1].rega &= 0b00111111 & ~~(1<<(i-9));
|
||||
shoe.via[1].rega_input &= 0b00111111 & ~~(1<<(i-9));
|
||||
via_raise_interrupt(2, IFR_CA1);
|
||||
printf("Fired nubus interrupt %u\n", i);
|
||||
// printf("Fired nubus interrupt %u\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
core/video.c
@ -95,10 +95,11 @@ void nubus_video_init(void *_ctx, uint8_t slotnum,
|
||||
ctx->scanline_width = scanline_width;
|
||||
ctx->pixels = scanline_width * height;
|
||||
|
||||
ctx->direct_buf = valloc(ctx->pixels * sizeof(video_ctx_color_t));
|
||||
ctx->indexed_buf = valloc(ctx->pixels);
|
||||
ctx->clut = malloc(256 * sizeof(video_ctx_color_t));
|
||||
ctx->rom = malloc(4096);
|
||||
ctx->direct_buf = p_alloc(shoe.pool, ctx->pixels * sizeof(video_ctx_color_t));
|
||||
ctx->indexed_buf = p_alloc(shoe.pool, ctx->pixels);
|
||||
|
||||
ctx->clut = p_alloc(shoe.pool, 256 * sizeof(video_ctx_color_t));
|
||||
ctx->rom = p_alloc(shoe.pool, 4096);
|
||||
|
||||
// Set the depth and clut for B&W
|
||||
_switch_depth(ctx, 1);
|
||||
@ -207,7 +208,7 @@ void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
|
||||
if ((addr >> 16) == 0xf0) {
|
||||
switch ((addr & 0x0000ffff) >> 2) {
|
||||
case 0: {// Clear interrupt flag
|
||||
shoe.via[1].rega |= (1 << (slotnum - 9));
|
||||
shoe.via[1].rega_input |= (1 << (slotnum - 9));
|
||||
break;
|
||||
}
|
||||
case 1: { // Set depth
|
||||
|
12
debugger/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
CC = clang
|
||||
CFLAGS = -O0 -ggdb -flto -Wno-deprecated-declarations
|
||||
LFLAGS = -L ../intermediates -lshoebill_core -framework GLUT -framework OpenGL -ledit
|
||||
|
||||
all: debugger
|
||||
|
||||
debugger: Makefile debugger.c ../intermediates/libshoebill_core.a
|
||||
$(CC) $(CFLAGS) $(LFLAGS) debugger.c -o debugger
|
||||
|
||||
clean:
|
||||
rm -rf debugger
|
BIN
debugger/debugger
Executable file
923
debugger/debugger.c
Normal file
@ -0,0 +1,923 @@
|
||||
/*
|
||||
* 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/core_api.h"
|
||||
#include "../core/shoebill.h"
|
||||
#include "../core/coff.h"
|
||||
|
||||
rb_tree *keymap;
|
||||
|
||||
struct dbg_state_t {
|
||||
EditLine *el;
|
||||
uint8_t running;
|
||||
uint64_t breakpoint_counter;
|
||||
dbg_breakpoint_t *breakpoints;
|
||||
_Bool trace;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
void *_value;
|
||||
if (rb_find(keymap, c, &_value)) {
|
||||
const uint16_t value = (uint16_t)_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)
|
||||
{
|
||||
void *_value;
|
||||
if (rb_find(keymap, c, &_value)) {
|
||||
const uint16_t value = (uint16_t)_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();
|
||||
}
|
||||
|
||||
static void _do_clut_translation(shoebill_card_video_t *ctx)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
switch (ctx->depth) {
|
||||
case 1: {
|
||||
for (i=0; i < ctx->pixels/8; i++) {
|
||||
const uint8_t byte = ctx->indexed_buf[i];
|
||||
ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1];
|
||||
ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1];
|
||||
ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1];
|
||||
ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1];
|
||||
ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1];
|
||||
ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1];
|
||||
ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1];
|
||||
ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
for (i=0; i < ctx->pixels/4; i++) {
|
||||
const uint8_t byte = ctx->indexed_buf[i];
|
||||
ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3];
|
||||
ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3];
|
||||
ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3];
|
||||
ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
for (i=0; i < ctx->pixels/2; i++) {
|
||||
const uint8_t byte = ctx->indexed_buf[i];
|
||||
ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf];
|
||||
ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
for (i=0; i < ctx->pixels; i++)
|
||||
ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]];
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"unknown depth");
|
||||
}
|
||||
}
|
||||
|
||||
void _display_func (void)
|
||||
{
|
||||
shoebill_card_video_t *video = (shoebill_card_video_t*)shoe.slots[9].ctx;
|
||||
|
||||
_do_clut_translation(video);
|
||||
|
||||
glDrawBuffer(GL_BACK);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
glViewport(0, 0, video->width, video->height);
|
||||
glRasterPos2i(0, video->height);
|
||||
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
glPixelZoom(1.0, -1.0);
|
||||
|
||||
glDrawPixels(video->width,
|
||||
video->height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
video->direct_buf);
|
||||
|
||||
glutSwapBuffers();
|
||||
}
|
||||
|
||||
static void _init_keyboard_map (void)
|
||||
{
|
||||
#define mapkeymod(u, a, m) do { \
|
||||
assert((a >> 7) == 0); \
|
||||
void *value = (void*)(((m) << 8)| (a)); \
|
||||
rb_insert(keymap, u, value, NULL); \
|
||||
} while (0)
|
||||
|
||||
#define mapkey(_u, a) mapkeymod(_u, a, 0)
|
||||
|
||||
keymap = rb_new();
|
||||
|
||||
// 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_card_video_t *ctx = (shoebill_card_video_t*)shoe.slots[9].ctx;
|
||||
|
||||
glutInitWindowSize(ctx->width, ctx->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, ctx->width, 0, ctx->height, -1.0, 1.0);
|
||||
|
||||
glViewport(0, 0, ctx->width, ctx->height);
|
||||
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
shoebill_control_t control;
|
||||
pthread_t pid;
|
||||
|
||||
|
||||
bzero(&control, sizeof(shoebill_control_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...
|
||||
*/
|
||||
control.debug_mode = 1;
|
||||
|
||||
control.aux_verbose = 1;
|
||||
control.ram_size = 16 * 1024 * 1024;
|
||||
control.aux_kernel_path = "/unix";
|
||||
control.rom_path = "/Users/pruten/checkouts/shoebill/priv/macii.rom";
|
||||
|
||||
control.scsi_devices[0].path = "/Users/pruten/checkouts/shoebill/priv/Apple_UNIX_3.iso";
|
||||
|
||||
if (!shoebill_initialize(&control)) {
|
||||
printf("%s\n", control.error_msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_init_keyboard_map();
|
||||
|
||||
shoebill_install_video_card(&control,
|
||||
9, // slotnum
|
||||
1024,
|
||||
768,
|
||||
60.0);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -265,6 +265,7 @@
|
||||
control.ram_size = (uint32_t)memsize * 1024 * 1024;
|
||||
control.aux_kernel_path = rootKernelPathCString;
|
||||
control.rom_path = romPathCString;
|
||||
control.debug_mode = 0;
|
||||
|
||||
*width = screenWidthValue;
|
||||
*height = screenHeightValue;
|
||||
|
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 151 KiB |