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