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
This commit is contained in:
Peter Rutenbar 2014-05-10 19:25:31 -04:00
parent 2800cc3c7e
commit d19c17812c
27 changed files with 2451 additions and 2230 deletions

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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;
}

View File

@ -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;
}

View File

@ -98,6 +98,8 @@ typedef struct {
pthread_t cpu_thread_pid, via_thread_pid;
_Bool debug_mode;
char error_msg[8192];
} shoebill_control_t;

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}
}

View File

@ -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 () {

View File

@ -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
};

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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
View 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

Binary file not shown.

923
debugger/debugger.c Normal file
View 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;
}

View File

@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB