mirror of
https://github.com/pruten/shoebill.git
synced 2025-02-09 13:30:31 +00:00
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:
parent
2800cc3c7e
commit
d19c17812c
8
Makefile
8
Makefile
@ -1,11 +1,17 @@
|
||||
|
||||
CC = clang
|
||||
CFLAGS = -O3 -flto -Wno-deprecated-declarations
|
||||
|
||||
all: shoebill
|
||||
|
||||
shoebill: make_gui
|
||||
shoebill: make_gui debugger
|
||||
|
||||
make_gui: make_core
|
||||
xcodebuild -project gui/Shoebill.xcodeproj SYMROOT=build
|
||||
|
||||
debugger: make_core
|
||||
$(MAKE) -C debugger
|
||||
|
||||
make_core:
|
||||
$(MAKE) -C core -j 4
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
CC = clang
|
||||
CFLAGS = -O3 -flto -ggdb -Wno-deprecated-declarations
|
||||
CFLAGS = -O3 -ggdb -flto -Wno-deprecated-declarations
|
||||
# CFLAGS = -O0 -ggdb -Wno-deprecated-declarations
|
||||
|
||||
|
||||
DEPS = core_api.h coff.h mc68851.h redblack.h shoebill.h Makefile macro.pl
|
||||
NEED_DECODER = cpu dis
|
||||
NEED_PREPROCESSING = adb fpu mc68851 mem via
|
||||
NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi toby_frame_buffer video core_api filesystem debug_server alloc_pool
|
||||
NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi video core_api filesystem alloc_pool
|
||||
|
||||
# Object files that can be compiled directly from the source
|
||||
OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING))
|
||||
@ -73,7 +73,7 @@ $(TEMP)/dis_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS)
|
||||
|
||||
# Compile the decoder generator
|
||||
$(TEMP)/decoder_gen: decoder_gen.c $(DEPS)
|
||||
$(CC) $(CFLAGS) decoder_gen.c -o $(TEMP)/decoder_gen
|
||||
$(CC) decoder_gen.c -o $(TEMP)/decoder_gen
|
||||
|
||||
|
||||
$(TEMP):
|
||||
|
14
core/adb.c
14
core/adb.c
@ -81,7 +81,7 @@
|
||||
|
||||
void adb_start_service_request()
|
||||
{
|
||||
printf("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
|
||||
//printf("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
|
||||
if (shoe.adb.pending_service_requests) {
|
||||
shoe.adb.service_request = 1;
|
||||
|
||||
@ -245,7 +245,7 @@ static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Com
|
||||
|
||||
shoe.adb.poll = 0;
|
||||
|
||||
via->regb |= VIA_REGB_ADB_STATUS;
|
||||
via->regb_input |= VIA_REGB_ADB_STATUS;
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ static void adb_handle_state_one (void) // "Even" state
|
||||
printf("adb_talk: ");
|
||||
if (shoe.adb.timeout) {
|
||||
shoe.adb.timeout = 0;
|
||||
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
printf("timeout\n");
|
||||
return ;
|
||||
@ -288,7 +288,7 @@ static void adb_handle_state_one (void) // "Even" state
|
||||
printf("adb_listen: ");
|
||||
if (shoe.adb.timeout) {
|
||||
shoe.adb.timeout = 0;
|
||||
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
printf("timeout\n");
|
||||
return ;
|
||||
@ -304,7 +304,7 @@ static void adb_handle_state_one (void) // "Even" state
|
||||
break;
|
||||
}
|
||||
|
||||
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
|
||||
via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
|
||||
via_raise_interrupt(1, IFR_SHIFT_REG);
|
||||
}
|
||||
|
||||
@ -317,11 +317,11 @@ static void adb_handle_state_two (void) // "Odd" state
|
||||
// If this transaction was part of a service request, clear the service_request flag now
|
||||
if (shoe.adb.service_request) {
|
||||
shoe.adb.service_request = 0;
|
||||
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
|
||||
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
|
||||
printf("(service request) ");
|
||||
}
|
||||
else
|
||||
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
|
||||
via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
|
||||
|
||||
switch (shoe.adb.command_type) {
|
||||
case adb_flush:
|
||||
|
30
core/coff.c
30
core/coff.c
@ -76,7 +76,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
}
|
||||
|
||||
// Allocate a coff_file and copy in the header
|
||||
cf = (coff_file*)calloc(1, sizeof(coff_file));
|
||||
cf = (coff_file*)p_alloc(shoe.pool, sizeof(coff_file));
|
||||
ptr = rawhead;
|
||||
cf->magic = be2native(&ptr, 2);
|
||||
cf->num_sections = be2native(&ptr, 2);
|
||||
@ -98,17 +98,17 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
|
||||
// pull out cf->opt_header bytes (a.out-format header, I guess?)
|
||||
if (cf->opt_header_len > 0) {
|
||||
uint8_t *opt = malloc(cf->opt_header_len);
|
||||
uint8_t *opt = p_alloc(shoe.pool, cf->opt_header_len);
|
||||
if (!_coff_buf_read(opt, cf->opt_header_len)) {
|
||||
printf("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len);
|
||||
free(opt);
|
||||
p_free(opt);
|
||||
goto fail;
|
||||
}
|
||||
cf->opt_header = opt;
|
||||
}
|
||||
|
||||
// start pulling out sections
|
||||
cf->sections = calloc(cf->num_sections, sizeof(coff_section));
|
||||
cf->sections = p_alloc(shoe.pool, cf->num_sections * sizeof(coff_section));
|
||||
for (i=0; i<cf->num_sections; i++) {
|
||||
// read the header
|
||||
uint8_t rawsec[40];
|
||||
@ -158,10 +158,10 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
}
|
||||
|
||||
// load the data and attach it to the section struct
|
||||
data = malloc(cf->sections[i].sz); // FIXME: sz might not be a sane value
|
||||
data = p_alloc(shoe.pool, cf->sections[i].sz); // FIXME: sz might not be a sane value
|
||||
if (!_coff_buf_read(data, cf->sections[i].sz)) {
|
||||
printf("coff_parse: I couldn't fread section %u (%s)'s data (%u bytes)\n", i+1, cf->sections[i].name, cf->sections[i].sz);
|
||||
free(data);
|
||||
p_free(data);
|
||||
goto fail;
|
||||
}
|
||||
cf->sections[i].data = data;
|
||||
@ -174,7 +174,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
|
||||
cf->func_tree = rb_new();
|
||||
//printf("func_tree = %llx, *func_tree = %llx\n", cf->func_tree, *cf->func_tree);
|
||||
cf->symbols = (coff_symbol*)calloc(sizeof(coff_symbol), cf->num_symbols);
|
||||
cf->symbols = (coff_symbol*)p_alloc(shoe.pool, sizeof(coff_symbol) *cf->num_symbols);
|
||||
|
||||
// Seek to the symbol table
|
||||
if (!_coff_buf_seek(cf->symtab_offset)) {
|
||||
@ -208,7 +208,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
cf->symbols[i].name = malloc(j+1);
|
||||
cf->symbols[i].name = p_alloc(shoe.pool, j+1);
|
||||
memcpy(cf->symbols[i].name, tmp_name, j);
|
||||
cf->symbols[i].name[j] = 0;
|
||||
_coff_buf_seek(cf->symtab_offset + (i+1)*18);
|
||||
@ -252,17 +252,17 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
fail:
|
||||
if (cf) {
|
||||
if (cf->opt_header) {
|
||||
free(cf->opt_header);
|
||||
p_free(cf->opt_header);
|
||||
}
|
||||
if (cf->sections) {
|
||||
for (i=0; i<cf->num_sections; i++) {
|
||||
if (cf->sections[i].data) {
|
||||
free(cf->sections[i].data);
|
||||
p_free(cf->sections[i].data);
|
||||
}
|
||||
}
|
||||
free(cf->sections);
|
||||
p_free(cf->sections);
|
||||
}
|
||||
free(cf);
|
||||
p_free(cf);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -270,12 +270,12 @@ fail:
|
||||
coff_file* coff_parse_from_path(const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
uint8_t *buf = malloc(1);
|
||||
uint8_t *buf = p_alloc(shoe.pool, 1);
|
||||
uint32_t i=0, tmp;
|
||||
coff_file *coff;
|
||||
|
||||
do {
|
||||
buf = realloc(buf, i + 128*1024);
|
||||
buf = p_realloc(buf, i + 128*1024);
|
||||
assert(buf);
|
||||
tmp = fread(buf+i, 1, 128*1024, f);
|
||||
i += tmp;
|
||||
@ -285,7 +285,7 @@ coff_file* coff_parse_from_path(const char *path)
|
||||
|
||||
|
||||
coff = coff_parse(buf, i);
|
||||
free(buf);
|
||||
p_free(buf);
|
||||
return coff;
|
||||
}
|
||||
|
||||
|
199
core/core_api.c
199
core/core_api.c
@ -34,136 +34,17 @@
|
||||
#include "coff.h"
|
||||
#include "core_api.h"
|
||||
|
||||
/*
|
||||
char *ring, *ring_tmp;
|
||||
const uint32_t ring_len = 64 * 1024 * 1024;
|
||||
uint32_t ring_i = 0;
|
||||
|
||||
void print_mmu_rp(uint64_t rp)
|
||||
{
|
||||
printf("lu=%u limit=0x%x sg=%u dt=%u addr=0x%08x\n", rp_lu(rp), rp_limit(rp), rp_sg(rp), rp_dt(rp), rp_addr(rp));
|
||||
}
|
||||
|
||||
void printregs()
|
||||
{
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]);
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc,
|
||||
sr_s()?'S':'s',
|
||||
sr_m()?'M':'m',
|
||||
sr_x()?'X':'x',
|
||||
sr_n()?'N':'n',
|
||||
sr_z()?'Z':'z',
|
||||
sr_v()?'V':'v',
|
||||
sr_c()?'C':'c',
|
||||
shoe.tc
|
||||
);
|
||||
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "[vbr]%08x\n", shoe.vbr);
|
||||
|
||||
//printf("srp: ");
|
||||
//print_mmu_rp(shoe.srp);
|
||||
|
||||
//printf("crp: ");
|
||||
//print_mmu_rp(shoe.crp);
|
||||
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n\n",
|
||||
tc_enable(), tc_sre(), tc_fcl(), tc_ps(), tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid());
|
||||
|
||||
}
|
||||
|
||||
void dump_ring()
|
||||
{
|
||||
uint32_t i = ring_i+1;
|
||||
|
||||
while (i != ring_i) {
|
||||
fwrite(&ring[i], 1, 1, stdout);
|
||||
i = (i+1) % ring_len;
|
||||
}
|
||||
}
|
||||
|
||||
void ring_print(const char *str)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i=0; str[i]; i++) {
|
||||
ring[ring_i] = str[i];
|
||||
ring_i = (ring_i+1) % ring_len;
|
||||
}
|
||||
}
|
||||
|
||||
void print_pc()
|
||||
{
|
||||
char str[1024];
|
||||
uint8_t binary[64];
|
||||
uint32_t i;
|
||||
uint32_t len;
|
||||
const char *name = NULL;
|
||||
|
||||
if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) {
|
||||
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
|
||||
for (i=0; macii_rom_symbols[i].name; i++) {
|
||||
if (macii_rom_symbols[i].addr > addr) {
|
||||
break;
|
||||
}
|
||||
name = macii_rom_symbols[i].name;
|
||||
}
|
||||
}
|
||||
else if (sr_s()) { // these symbols are only meaningful in supervisor mode
|
||||
coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc);
|
||||
if (symb && strlen(symb->name))
|
||||
name = symb->name;
|
||||
}
|
||||
else
|
||||
name = "";
|
||||
|
||||
if ((name == NULL) || (name[0] == 0))
|
||||
return;
|
||||
if (strncmp("scsi", name, 4) != 0)
|
||||
return ;
|
||||
|
||||
const uint16_t old_abort = shoe.abort;
|
||||
shoe.suppress_exceptions = 1;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
binary[i] = (uint8_t) lget(shoe.pc+i, 1);
|
||||
}
|
||||
|
||||
disassemble_inst(binary, shoe.pc, str, &len);
|
||||
|
||||
sprintf(ring_tmp, "*0x%08x %s [ ", shoe.pc, name ? name : "");
|
||||
for (i=0; i<len; i+=2) {
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "%02x%02x ", binary[i], binary[i+1]);
|
||||
}
|
||||
sprintf(ring_tmp+strlen(ring_tmp), "] %s\n", str);
|
||||
|
||||
printregs();
|
||||
|
||||
for (i=0; ring_tmp[i]; i++) {
|
||||
ring[ring_i] = ring_tmp[i];
|
||||
ring_i = (ring_i+1) % ring_len;
|
||||
}
|
||||
|
||||
shoe.abort = old_abort;
|
||||
shoe.suppress_exceptions = 0;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void shoebill_start()
|
||||
{
|
||||
pthread_mutex_unlock(&shoe.cpu_thread_lock);
|
||||
pthread_mutex_unlock(&shoe.via_clock_thread_lock);
|
||||
pthread_mutex_unlock(&shoe.cpu_thread_lock);
|
||||
}
|
||||
|
||||
void *_cpu_thread (void *arg) {
|
||||
|
||||
void *_cpu_thread (void *arg)
|
||||
{
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
|
||||
// ring = calloc(ring_len, 1);
|
||||
// ring_tmp = malloc(128 * 1024);
|
||||
|
||||
while (1) {
|
||||
if (shoe.cpu_thread_notifications) {
|
||||
|
||||
@ -177,13 +58,14 @@ void *_cpu_thread (void *arg) {
|
||||
continue; // FIXME: yield or block on a condition variable here
|
||||
}
|
||||
}
|
||||
// print_pc();
|
||||
cpu_step();
|
||||
}
|
||||
}
|
||||
|
||||
/*static void _cpu_loop_debug()
|
||||
static void _cpu_loop_debug()
|
||||
{
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
|
||||
while (1) {
|
||||
if (shoe.cpu_thread_notifications) {
|
||||
// I think we can safely ignore "stop" instructions for A/UX in debug mode
|
||||
@ -193,9 +75,14 @@ void *_cpu_thread (void *arg) {
|
||||
process_pending_interrupt();
|
||||
}
|
||||
|
||||
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
|
||||
continue; // FIXME: yield or block on a condition variable here
|
||||
}
|
||||
}
|
||||
|
||||
cpu_step();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/*void shoebill_cpu_stepi (void)
|
||||
{
|
||||
@ -319,16 +206,7 @@ static void _init_macintosh_lomem_globals (const uint32_t offset)
|
||||
pset(offset+0xdd8, 4, 0);
|
||||
pset(offset+0x1d4, 4, 0x50000000); // VIA (via1 ptr)
|
||||
pset(offset+0x1d8, 4, 0x50004000); // SCC
|
||||
|
||||
#define hwCbSCSI (1<<15)
|
||||
#define hwCbClock (1<<14)
|
||||
#define hwCbExPRAM (1<<13)
|
||||
#define hwCbFPU (1<<12)
|
||||
#define hwCbMMU (1<<11)
|
||||
#define hwCbADB (1<<10)
|
||||
#define hwCbAUX (1<<9) /* not sure if I need to set this one */
|
||||
const uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB;
|
||||
pset(offset+0xb22, 2, HWCfgFlags); // HWCfgFlags
|
||||
pset(offset+0xb22, 2, 0xfc00); // HWCfgFlags
|
||||
}
|
||||
|
||||
|
||||
@ -482,7 +360,7 @@ static uint32_t _compute_rom_checksum (const uint8_t *rom, const uint32_t len)
|
||||
static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uint32_t *_rom_size)
|
||||
{
|
||||
uint32_t i, rom_size;
|
||||
uint8_t *rom_data = (uint8_t*)malloc(64 * 1024);
|
||||
uint8_t *rom_data = (uint8_t*)p_alloc(shoe.pool, 64 * 1024);
|
||||
FILE *f = fopen(control->rom_path, "r");
|
||||
|
||||
if (f == NULL) {
|
||||
@ -491,7 +369,7 @@ static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uin
|
||||
}
|
||||
|
||||
for (rom_size = 0; rom_size < (2*1024*1024); rom_size += (64*1024)) {
|
||||
rom_data = (uint8_t*)realloc(rom_data, rom_size + (64*1024));
|
||||
rom_data = (uint8_t*)p_realloc(rom_data, rom_size + (64*1024));
|
||||
if (fread(rom_data + rom_size, 64*1024, 1, f) != 1)
|
||||
break;
|
||||
}
|
||||
@ -514,7 +392,7 @@ static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uin
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rom_data = realloc(rom_data, rom_size);
|
||||
// rom_data = p_realloc(rom_data, rom_size);
|
||||
assert(rom_data);
|
||||
|
||||
*_rom_size = rom_size;
|
||||
@ -524,7 +402,7 @@ static uint32_t _load_rom (shoebill_control_t *control, uint8_t **_rom_data, uin
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (rom_data) free(rom_data);
|
||||
if (rom_data) p_free(rom_data);
|
||||
if (f) fclose(f);
|
||||
return 0;
|
||||
}
|
||||
@ -697,7 +575,7 @@ uint32_t shoebill_initialize(shoebill_control_t *control)
|
||||
goto fail;
|
||||
|
||||
coff = coff_parse(kernel_data, kernel_size);
|
||||
free(kernel_data);
|
||||
free(kernel_data); // kernel_data was allocated with malloc()
|
||||
|
||||
if (coff == NULL) {
|
||||
sprintf(control->error_msg, "Can't open that A/UX kernel [%s]\n",
|
||||
@ -718,13 +596,13 @@ uint32_t shoebill_initialize(shoebill_control_t *control)
|
||||
}
|
||||
|
||||
shoe.physical_rom_size = rom_size;
|
||||
shoe.physical_rom_base = valloc(rom_size+8); // +8 because of physical_get hack
|
||||
shoe.physical_rom_base = p_alloc(shoe.pool, rom_size+8); // +8 because of physical_get hack
|
||||
memcpy(shoe.physical_rom_base, rom_data, rom_size);
|
||||
free(rom_data);
|
||||
p_free(rom_data);
|
||||
rom_data = NULL;
|
||||
|
||||
shoe.physical_mem_size = control->ram_size;
|
||||
shoe.physical_mem_base = valloc(control->ram_size+8); // +8 because of physical_get hack
|
||||
shoe.physical_mem_base = p_alloc(shoe.pool, control->ram_size+8); // +8 because of physical_get hack
|
||||
memset(shoe.physical_mem_base, 0, shoe.physical_mem_size);
|
||||
|
||||
// Initialize Macintosh lomem variables that A/UX actually cares about
|
||||
@ -746,40 +624,49 @@ uint32_t shoebill_initialize(shoebill_control_t *control)
|
||||
* (Can't fail after this point)
|
||||
*/
|
||||
|
||||
// FIXME: Don't do this! Rewrite the via timers!
|
||||
gettimeofday(&shoe.start_time, NULL);
|
||||
shoe.total_ticks = 0;
|
||||
/*
|
||||
* FIXME: to implement clean resetting, everything with a global structure needs
|
||||
* an initialization function. Starting here with via/pram...
|
||||
*/
|
||||
init_via_state();
|
||||
|
||||
|
||||
// Put the adb chip in state 3 (idle)
|
||||
// FIXME: put this in a "init_adb_state()"-type function
|
||||
shoe.adb.state = 3;
|
||||
pthread_mutex_init(&shoe.adb.lock, NULL);
|
||||
|
||||
|
||||
set_sr(0x2000);
|
||||
shoe.pc = pc;
|
||||
memcpy(shoe.scsi_devices, disks, 8 * sizeof(scsi_device_t));
|
||||
|
||||
pthread_mutex_init(&shoe.cpu_thread_lock, NULL);
|
||||
pthread_mutex_init(&shoe.via_clock_thread_lock, NULL);
|
||||
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
pthread_mutex_lock(&shoe.via_clock_thread_lock);
|
||||
|
||||
pthread_create(&control->cpu_thread_pid, NULL, _cpu_thread, NULL);
|
||||
// pthread_create(&control->cpu_thread_pid, NULL, debug_cpu_thread, NULL);
|
||||
pthread_create(&control->via_thread_pid, NULL, via_clock_thread, NULL);
|
||||
|
||||
/*
|
||||
* control->debug_mode is a hack - the debugger implements its own CPU thread
|
||||
*/
|
||||
pthread_mutex_init(&shoe.cpu_thread_lock, NULL);
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
if (!control->debug_mode)
|
||||
pthread_create(&control->cpu_thread_pid, NULL, _cpu_thread, NULL);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (rom_data) free(rom_data);
|
||||
if (rom_data) p_free(rom_data);
|
||||
|
||||
for (i=0; i<7; i++)
|
||||
if (disks[i].f) fclose(disks[i].f);
|
||||
|
||||
if (shoe.physical_rom_base) free(shoe.physical_rom_base);
|
||||
if (shoe.physical_mem_base) free(shoe.physical_mem_base);
|
||||
if (shoe.physical_rom_base) p_free(shoe.physical_rom_base);
|
||||
if (shoe.physical_mem_base) p_free(shoe.physical_mem_base);
|
||||
|
||||
p_free_pool(shoe.pool);
|
||||
memset(&shoe, 0, sizeof(global_shoebill_context_t));
|
||||
|
||||
// No way to free *coff yet
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,8 @@ typedef struct {
|
||||
|
||||
pthread_t cpu_thread_pid, via_thread_pid;
|
||||
|
||||
_Bool debug_mode;
|
||||
|
||||
char error_msg[8192];
|
||||
} shoebill_control_t;
|
||||
|
||||
|
511
core/cpu.c
511
core/cpu.c
File diff suppressed because it is too large
Load Diff
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include "../core/shoebill.h"
|
||||
#include "../core/coff.h"
|
||||
|
||||
#define DEBUG_MODE_STOPPED 0
|
||||
#define DEBUG_MODE_RUNNING 1
|
||||
#define DEBUG_MODE_STEP 2
|
||||
|
||||
#define SHOEBILL_DEBUG_PORT 0xfded
|
||||
static int _start_debug_server(void)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_len = sizeof(struct sockaddr_in);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(SHOEBILL_DEBUG_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (sock == -1) {
|
||||
assert(!"can't socket");
|
||||
}
|
||||
else if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) != 0) {
|
||||
assert(!"can't bind");
|
||||
// return -1;
|
||||
}
|
||||
else if (listen(sock, 1) != 0) {
|
||||
assert(!"can't listen");
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
void *debug_server_thread (void *arg)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t sin_size = sizeof(struct sockaddr_in);
|
||||
uint8_t *inbuf = calloc(0x10000, 1);
|
||||
uint8_t *outbuf = calloc(0x10000, 1);
|
||||
int sock = _start_debug_server();
|
||||
int clientfd = accept(sock, (struct sockaddr*)&addr, &sin_size);
|
||||
|
||||
shoe.dbg.connected = 1;
|
||||
shoe.dbg.mode = DEBUG_MODE_RUNNING;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *debug_cpu_thread (void *arg)
|
||||
{
|
||||
memset(&shoe.dbg, 0, sizeof(shoe.dbg));
|
||||
shoe.dbg.mode = DEBUG_MODE_STOPPED;
|
||||
|
||||
pthread_t server_thread_pid;
|
||||
pthread_create(&server_thread_pid,
|
||||
NULL,
|
||||
debug_server_thread,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* The CPU only runs once the debugger is connected, and the
|
||||
* emulator has started
|
||||
*/
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
while (!shoe.dbg.connected)
|
||||
usleep(1000);
|
||||
|
||||
while (1) {
|
||||
if (shoe.dbg.mode == DEBUG_MODE_RUNNING) {
|
||||
if (!shoe.dbg.ignore_interrupts &&
|
||||
(shoe.cpu_thread_notifications & 0xff)) {
|
||||
process_pending_interrupt();
|
||||
}
|
||||
|
||||
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu_step();
|
||||
}
|
||||
else if (shoe.dbg.mode == DEBUG_MODE_STOPPED)
|
||||
pthread_yield_np();
|
||||
else if (shoe.dbg.mode == DEBUG_MODE_STEP) {
|
||||
cpu_step();
|
||||
shoe.dbg.mode = DEBUG_MODE_STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
32
core/dis.c
32
core/dis.c
@ -794,24 +794,40 @@ void dis_movea () {
|
||||
}
|
||||
|
||||
void dis_move () {
|
||||
~decompose(dis_op, 00 ss RRR MMM oooooo)
|
||||
~decompose(dis_op, 00 ss RRR MMM oooooo);
|
||||
// (oooooo = source EA), (MMMRRR = dest EA)
|
||||
const uint8_t sizes[3] = {1, 4, 2};
|
||||
const char *sourceStr = decode_ea_rw(o, sizes[s-1]);
|
||||
const char *destStr = decode_ea_rw((M<<3)|R, sizes[s-1]);
|
||||
sprintf(dis.str, "move.%c %s,%s", "blw"[s-1], sourceStr, destStr);
|
||||
const uint8_t sizes[4] = {0, 1, 4, 2};
|
||||
const char *sourceStr = decode_ea_rw(o, sizes[s]);
|
||||
const char *destStr = decode_ea_rw((M<<3)|R, sizes[s]);
|
||||
sprintf(dis.str, "move.%c %s,%s", "?blw"[s], sourceStr, destStr);
|
||||
}
|
||||
|
||||
void dis_move_d_to_d () {
|
||||
sprintf(dis.str, "move_d_to_d ???");
|
||||
~decompose(dis_op, 00 ss DDD 000 000 SSS);
|
||||
sprintf(dis.str, "move.%c d%u,d%u", "?blw"[s], S, D);
|
||||
}
|
||||
|
||||
void dis_move_to_d () {
|
||||
sprintf(dis.str, "move_to_d ???");
|
||||
~decompose(dis_op, 00 ss rrr 000 MMMMMM);
|
||||
const uint8_t sizes[4] = {0, 1, 4, 2};
|
||||
|
||||
sprintf(dis.str,
|
||||
"move.%c %s,d%u",
|
||||
"?blw"[s],
|
||||
decode_ea_rw(M, sizes[s]),
|
||||
r);
|
||||
}
|
||||
|
||||
void dis_move_from_d () {
|
||||
sprintf(dis.str, "move_from_d ???");
|
||||
~decompose(dis_op, 00 ss RRR MMM 000 rrr);
|
||||
const uint8_t sizes[4] = {0, 1, 4, 2};
|
||||
|
||||
sprintf(dis.str,
|
||||
"move.%c d%u,%s",
|
||||
"?blw"[s],
|
||||
r,
|
||||
decode_ea_rw((M<<3) | R, sizes[s]));
|
||||
|
||||
}
|
||||
|
||||
void dis_scc () {
|
||||
|
873
core/mem.c
873
core/mem.c
@ -46,8 +46,26 @@ void _physical_get_ram (void)
|
||||
else
|
||||
addr = (uint64_t*)&shoe.physical_mem_base[shoe.physical_addr % shoe.physical_mem_size];
|
||||
|
||||
/*if ((shoe.physical_addr >= 0x100) && (shoe.physical_addr < (0x4000+256))) {
|
||||
uint32_t i, val = 0;
|
||||
_Bool uninit = 0;
|
||||
for (i=0; i<shoe.physical_size; i++) {
|
||||
const uint8_t byte = shoe.physical_mem_base[shoe.physical_addr+i];
|
||||
val = val << 8;
|
||||
val |= byte;
|
||||
if (byte == 0xbc) uninit = 1;
|
||||
}
|
||||
if (uninit) {
|
||||
printf("LOMEM: *0x%08x = 0x%x UNSET\n", shoe.physical_addr, val);
|
||||
}
|
||||
}*/
|
||||
|
||||
const uint8_t bits = (8 - shoe.physical_size) * 8;
|
||||
shoe.physical_dat = ntohll(*addr) >> bits;
|
||||
|
||||
if ((shoe.physical_addr >= 256) && (shoe.physical_addr < 0x4000)) {
|
||||
printf("LOMEM get: *0x%08x = 0x%x\n", shoe.physical_addr, (uint32_t)shoe.physical_dat);
|
||||
}
|
||||
}
|
||||
|
||||
void _physical_get_rom (void)
|
||||
@ -61,13 +79,8 @@ void _physical_get_rom (void)
|
||||
void _physical_get_io (void)
|
||||
{
|
||||
switch (shoe.physical_addr & 0x5003ffff) {
|
||||
case 0x50000000 ... 0x50001fff: // VIA1
|
||||
via_reg_read();
|
||||
// printf("physical_get: got read to VIA1 (%x & 0x5003ffff = %x)\n", shoe.physical_addr, shoe.physical_addr & 0x5003ffff);
|
||||
return ;
|
||||
case 0x50002000 ... 0x50003fff: // VIA2
|
||||
via_reg_read();
|
||||
// printf("physical_get: got read to VIA2\n");
|
||||
case 0x50000000 ... 0x50003fff: // VIA1 + VIA2
|
||||
via_read_raw();
|
||||
return ;
|
||||
case 0x50004000 ... 0x50005fff: {// SCC
|
||||
//printf("physical_get: got read to SCC\n");
|
||||
@ -77,8 +90,6 @@ void _physical_get_io (void)
|
||||
return ;
|
||||
}
|
||||
case 0x50006000 ... 0x50007fff: // SCSI (pseudo-DMA with DRQ?)
|
||||
//printf("physical_get: got read to SCSI low\n");
|
||||
//assert(!"physical_get: got read to SCSI low");
|
||||
assert(shoe.logical_size == 4);
|
||||
shoe.physical_dat = scsi_dma_read_long();
|
||||
return ;
|
||||
@ -88,11 +99,12 @@ void _physical_get_io (void)
|
||||
case 0x50012000 ... 0x50013fff: // SCSI (pseudo-DMA with no DRQ?)
|
||||
assert(shoe.logical_size == 1);
|
||||
shoe.physical_dat = scsi_dma_read();
|
||||
// printf("physical_get: got read to SCSI hi\n");
|
||||
// assert(!"physical_get: got read to SCSI hi\n");
|
||||
return ;
|
||||
case 0x50014000 ... 0x50015fff: // Sound
|
||||
//printf("physical_get: got read to sound\n");
|
||||
printf("soundsound read : register 0x%04x sz=%u\n",
|
||||
shoe.physical_addr - 0x50014000, shoe.physical_size);
|
||||
shoe.physical_dat = 0;
|
||||
return ;
|
||||
case 0x50016000 ... 0x50017fff: // SWIM (IWM?)
|
||||
// printf("physical_get: got read to IWM\n");
|
||||
@ -157,6 +169,10 @@ void _physical_set_ram (void)
|
||||
else
|
||||
addr = &shoe.physical_mem_base[shoe.physical_addr];
|
||||
|
||||
if ((shoe.physical_addr >= 0x100) && (shoe.physical_addr < (0x8000))) {
|
||||
printf("LOMEM set: *0x%08x = 0x%x\n", shoe.physical_addr, (uint32_t)chop(shoe.physical_dat, shoe.physical_size));
|
||||
}
|
||||
|
||||
const uint32_t sz = shoe.physical_size;
|
||||
switch (sz) {
|
||||
case 1:
|
||||
@ -195,13 +211,8 @@ void _physical_set_rom (void)
|
||||
void _physical_set_io (void)
|
||||
{
|
||||
switch (shoe.physical_addr & 0x5003ffff) {
|
||||
case 0x50000000 ... 0x50001fff: // VIA1
|
||||
via_reg_write();
|
||||
// printf("physical_set: got write to VIA1\n");
|
||||
return ;
|
||||
case 0x50002000 ... 0x50003fff: // VIA2
|
||||
via_reg_write();
|
||||
// printf("physical_set: got write to VIA2\n");
|
||||
case 0x50000000 ... 0x50003fff: // VIA1 + VIA2
|
||||
via_write_raw();
|
||||
return ;
|
||||
case 0x50004000 ... 0x50005fff: // SCC
|
||||
//printf("physical_set: got write to SCC\n");
|
||||
@ -216,11 +227,11 @@ void _physical_set_io (void)
|
||||
case 0x50012000 ... 0x50013fff: // SCSI (pseudo-DMA with no DRQ?)
|
||||
assert(shoe.physical_size == 1);
|
||||
scsi_dma_write(shoe.physical_dat);
|
||||
//printf("physical_set: got write to SCSI hi\n");
|
||||
//assert(!"physical_set: got write to SCSI hi\n");
|
||||
return ;
|
||||
case 0x50014000 ... 0x50015fff: // Sound
|
||||
printf("physical_set: got write to sound\n");
|
||||
printf("soundsound write: register 0x%04x sz=%u dat=0x%x\n",
|
||||
shoe.physical_addr - 0x50014000, shoe.physical_size, (uint32_t)shoe.physical_dat);
|
||||
// printf("physical_set: got write to sound\n");
|
||||
return ;
|
||||
case 0x50016000 ... 0x50017fff: // SWIM (IWM?)
|
||||
//printf("physical_set: got write to IWM\n");
|
||||
@ -339,7 +350,7 @@ static void translate_logical_addr()
|
||||
uint8_t desc_size = 1; // And the root pointer descriptor is always 8 bytes (1==8 bytes, 0==4 bytes)
|
||||
uint8_t used_bits = tc_is(); // Keep track of how many bits will be the effective "page size"
|
||||
// (If the table search terminates early (before used_bits == ts_ps()),
|
||||
// then this will be the effective page size. That is, the number of bits
|
||||
// then (32 - used_bits) will be the effective page size. That is, the number of bits
|
||||
// we or into the physical addr from the virtual addr)
|
||||
|
||||
desc_addr = -1; // address of the descriptor (-1 -> register)
|
||||
@ -801,275 +812,581 @@ static void ea_decode_extended()
|
||||
}
|
||||
|
||||
|
||||
void ea_read()
|
||||
// Data register direct mode
|
||||
void _ea_000_read (void)
|
||||
{
|
||||
shoe.dat = get_d(shoe.mr & 7, shoe.sz);
|
||||
}
|
||||
void _ea_000_write (void)
|
||||
{
|
||||
set_d(shoe.mr & 7, shoe.dat, shoe.sz);
|
||||
}
|
||||
|
||||
|
||||
// address register direct mode
|
||||
void _ea_001_read (void)
|
||||
{
|
||||
shoe.dat = get_a(shoe.mr & 7, shoe.sz);
|
||||
}
|
||||
void _ea_001_write (void)
|
||||
{
|
||||
assert(shoe.sz==4);
|
||||
shoe.a[shoe.mr & 7] = shoe.dat;
|
||||
}
|
||||
|
||||
|
||||
// address register indirect mode
|
||||
void _ea_010_read (void)
|
||||
{
|
||||
shoe.dat = lget(shoe.a[shoe.mr & 7], shoe.sz);
|
||||
}
|
||||
void _ea_010_write (void)
|
||||
{
|
||||
lset(shoe.a[shoe.mr & 7], shoe.sz, shoe.dat);
|
||||
}
|
||||
void _ea_010_addr (void)
|
||||
{
|
||||
shoe.dat = shoe.a[shoe.mr & 7];
|
||||
}
|
||||
|
||||
|
||||
// address register indirect with postincrement mode
|
||||
void _ea_011_read (void)
|
||||
{
|
||||
shoe.dat = lget(shoe.a[shoe.mr & 7], shoe.sz);
|
||||
}
|
||||
void _ea_011_read_commit (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
shoe.a[reg] += (((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz);
|
||||
}
|
||||
void _ea_011_write (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz;
|
||||
|
||||
lset(shoe.a[reg], shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] += delta;
|
||||
}
|
||||
|
||||
|
||||
// address register indirect with predecrement mode
|
||||
void _ea_100_read (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.dat = lget(shoe.a[reg]-delta, shoe.sz);
|
||||
}
|
||||
void _ea_100_read_commit (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
shoe.a[reg] -= (((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz);
|
||||
}
|
||||
void _ea_100_write (void)
|
||||
{
|
||||
const uint8_t reg = shoe.mr & 7;
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1)) ? 2 : shoe.sz;
|
||||
|
||||
lset(shoe.a[reg] - delta, shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] -= delta;
|
||||
}
|
||||
|
||||
|
||||
// address register indirect with displacement mode
|
||||
void _ea_101_read (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc;
|
||||
switch (mode) {
|
||||
case 0: { // Data register direct mode
|
||||
shoe.dat = get_d(reg, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 1: { // address register direct mode
|
||||
shoe.dat = get_a(reg, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 2: { // address register indirect mode
|
||||
shoe.dat = lget(shoe.a[reg], shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 3: { // address register indirect with postincrement mode
|
||||
shoe.dat = lget(shoe.a[reg], shoe.sz);
|
||||
// printf("ea_read(): %u %u not implemented\n", mode, reg);
|
||||
return ;
|
||||
}
|
||||
case 4: { // address register indirect with predecrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.dat = lget(shoe.a[reg]-delta, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
const int16_t disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(shoe.a[reg]+disp, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
const int32_t addr = (int16_t)nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget((uint32_t)addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
const uint32_t addr = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 2: { // program counter indirect with displacement mode
|
||||
const uint32_t base_pc = shoe.uncommitted_ea_read_pc;
|
||||
const uint16_t u_disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
const int16_t disp = (int16_t)u_disp;
|
||||
|
||||
shoe.dat = lget(base_pc + disp, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 3: { // (program counter ...)
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 4: { // immediate data
|
||||
if (shoe.sz==1) {
|
||||
shoe.dat = nextword(shoe.uncommitted_ea_read_pc) & 0xff;
|
||||
} else if (shoe.sz == 2) {
|
||||
shoe.dat = nextword(shoe.uncommitted_ea_read_pc);
|
||||
} else if (shoe.sz == 4) {
|
||||
shoe.dat = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
} else if (shoe.sz == 8) {
|
||||
const uint64_t q = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = (q<<32) | nextlong(shoe.uncommitted_ea_read_pc);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
const int16_t disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(shoe.a[shoe.mr & 7] + disp, shoe.sz);
|
||||
}
|
||||
|
||||
void ea_read_commit()
|
||||
void _ea_101_read_commit (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
switch (mode) {
|
||||
case 0: // Data register direct mode
|
||||
case 1: // address register direct mode
|
||||
case 2: // address register indirect mode
|
||||
return ; // nothing to do
|
||||
|
||||
case 3: { // address register indirect with postincrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.a[reg] += delta;
|
||||
return ;
|
||||
}
|
||||
case 4: { // address register indirect with predecrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
shoe.a[reg] -= delta;
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
shoe.pc += 2; // this mode fetches one word
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
// shoe.extended_len was set in the previous ea_read() call.
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
shoe.pc+=2;
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
shoe.pc+=4;
|
||||
return ;
|
||||
}
|
||||
case 2: { // program counter indirect with displacement mode
|
||||
shoe.pc+=2;
|
||||
return ;
|
||||
}
|
||||
case 3: { // (program counter ...)
|
||||
// shoe.extended_len was set in the previous ea_read() call.
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 4: { // immediate data
|
||||
if (shoe.sz==1) shoe.pc += 2;
|
||||
else shoe.pc += shoe.sz;
|
||||
return ;
|
||||
}
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
shoe.pc += 2;
|
||||
}
|
||||
|
||||
void ea_write()
|
||||
void _ea_101_write (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
switch (mode) {
|
||||
case 0: { // Data register direct mode
|
||||
set_d(reg, shoe.dat, shoe.sz);
|
||||
return ;
|
||||
}
|
||||
case 1: { // address register direct mode
|
||||
assert(shoe.sz==4);
|
||||
shoe.a[reg] = shoe.dat;
|
||||
return ;
|
||||
}
|
||||
case 2: { // address register indirect mode
|
||||
lset(shoe.a[reg], shoe.sz, shoe.dat);
|
||||
return ;
|
||||
}
|
||||
case 3: { // address register indirect with postincrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
|
||||
lset(shoe.a[reg], shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] += delta;
|
||||
return ;
|
||||
}
|
||||
case 4: { // address register indirect with predecrement mode
|
||||
const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz;
|
||||
lset(shoe.a[reg]-delta, shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.a[reg] -= delta;
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
const uint16_t u_disp = nextword(shoe.pc);
|
||||
const int16_t disp = (int16_t)u_disp; // sign-extend word to long
|
||||
lset(shoe.a[reg]+disp, shoe.sz, shoe.dat);
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
|
||||
lset(shoe.extended_addr, shoe.sz, shoe.dat);
|
||||
if (shoe.abort) return ;
|
||||
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
const int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
lset((uint32_t)addr, shoe.sz, shoe.dat);
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
lset(addr, shoe.sz, shoe.dat);
|
||||
// printf("ea_write(): %u %u not implemented\n", mode, reg);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
const int16_t disp = nextword(shoe.pc);
|
||||
lset(shoe.a[shoe.mr & 7] + disp, shoe.sz, shoe.dat);
|
||||
}
|
||||
|
||||
void ea_addr()
|
||||
void _ea_101_addr (void)
|
||||
{
|
||||
const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7);
|
||||
switch (mode) {
|
||||
case 2: { // address register indirect mode
|
||||
shoe.dat = shoe.a[reg];
|
||||
return ;
|
||||
}
|
||||
case 5: { // address register indirect with displacement mode
|
||||
int16_t disp = nextword(shoe.pc);
|
||||
shoe.dat = shoe.a[reg] + disp;
|
||||
return ;
|
||||
}
|
||||
case 6: {
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = shoe.extended_addr;
|
||||
const int16_t disp = nextword(shoe.pc);
|
||||
shoe.dat = shoe.a[shoe.mr & 7] + disp;
|
||||
}
|
||||
|
||||
|
||||
// memory/address register indirect with index
|
||||
void _ea_110_read (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort)
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + shoe.extended_len;
|
||||
}
|
||||
void _ea_110_read_commit (void)
|
||||
{
|
||||
shoe.pc = shoe.uncommitted_ea_read_pc;
|
||||
}
|
||||
void _ea_110_write (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort) {
|
||||
lset(shoe.extended_addr, shoe.sz, shoe.dat);
|
||||
if (!shoe.abort)
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
case 7: {
|
||||
switch (reg) {
|
||||
case 0: { // absolute short addressing mode
|
||||
int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
shoe.dat = (uint32_t)addr;
|
||||
return ;
|
||||
}
|
||||
case 1: { // absolute long addressing mode
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
shoe.dat = addr;
|
||||
return ;
|
||||
}
|
||||
case 2: { // program counter indirect with displacement mode
|
||||
const uint32_t oldpc = shoe.pc;
|
||||
const uint16_t displacement = nextword(shoe.pc);
|
||||
shoe.dat = oldpc + (int16_t)displacement;
|
||||
return ;
|
||||
}
|
||||
case 3: { // (program counter ...)
|
||||
ea_decode_extended();
|
||||
if (shoe.abort) return ;
|
||||
shoe.dat = shoe.extended_addr;
|
||||
shoe.pc += shoe.extended_len;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw_illegal_instruction();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
void _ea_110_addr (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort) {
|
||||
shoe.dat = shoe.extended_addr;
|
||||
shoe.pc += shoe.extended_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// absolute short addressing mode
|
||||
void _ea_111_000_read (void)
|
||||
{
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc;
|
||||
const int32_t addr = (int16_t)nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget((uint32_t)addr, shoe.sz);
|
||||
}
|
||||
void _ea_111_000_read_commit (void)
|
||||
{
|
||||
shoe.pc += 2;
|
||||
}
|
||||
void _ea_111_000_write (void)
|
||||
{
|
||||
const int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
lset((uint32_t)addr, shoe.sz, shoe.dat);
|
||||
}
|
||||
void _ea_111_000_addr (void)
|
||||
{
|
||||
const int32_t addr = (int16_t)nextword(shoe.pc);
|
||||
shoe.dat = (uint32_t)addr;
|
||||
}
|
||||
|
||||
|
||||
// absolute long addressing mode
|
||||
void _ea_111_001_read (void)
|
||||
{
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc;
|
||||
const uint32_t addr = nextlong(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(addr, shoe.sz);
|
||||
}
|
||||
void _ea_111_001_read_commit (void)
|
||||
{
|
||||
shoe.pc += 4;
|
||||
}
|
||||
void _ea_111_001_write (void)
|
||||
{
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
lset(addr, shoe.sz, shoe.dat);
|
||||
}
|
||||
void _ea_111_001_addr (void)
|
||||
{
|
||||
const uint32_t addr = nextlong(shoe.pc);
|
||||
shoe.dat = addr;
|
||||
}
|
||||
|
||||
// program counter indirect with displacement mode
|
||||
void _ea_111_010_read (void)
|
||||
{
|
||||
const uint32_t base_pc = shoe.pc;
|
||||
shoe.uncommitted_ea_read_pc = base_pc;
|
||||
const int16_t disp = nextword(shoe.uncommitted_ea_read_pc);
|
||||
shoe.dat = lget(base_pc + disp, shoe.sz);
|
||||
}
|
||||
void _ea_111_010_read_commit (void)
|
||||
{
|
||||
shoe.pc += 2;
|
||||
}
|
||||
void _ea_111_010_addr (void)
|
||||
{
|
||||
const uint32_t oldpc = shoe.pc;
|
||||
const int16_t displacement = nextword(shoe.pc);
|
||||
shoe.dat = oldpc + displacement;
|
||||
}
|
||||
|
||||
|
||||
// (program counter ...)
|
||||
void _ea_111_011_read (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort)
|
||||
shoe.dat = lget(shoe.extended_addr, shoe.sz);
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + shoe.extended_len;
|
||||
}
|
||||
void _ea_111_011_read_commit (void)
|
||||
{
|
||||
shoe.pc = shoe.uncommitted_ea_read_pc;
|
||||
}
|
||||
void _ea_111_011_addr (void)
|
||||
{
|
||||
ea_decode_extended();
|
||||
if (!shoe.abort) {
|
||||
shoe.dat = shoe.extended_addr;
|
||||
shoe.pc += shoe.extended_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// immediate data
|
||||
void _ea_111_100_read (void)
|
||||
{
|
||||
if (shoe.sz == 1) {
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + 2;
|
||||
shoe.dat = lget(shoe.pc, 2) & 0xff;
|
||||
}
|
||||
else {
|
||||
shoe.uncommitted_ea_read_pc = shoe.pc + shoe.sz;
|
||||
shoe.dat = lget(shoe.pc, shoe.sz);
|
||||
}
|
||||
}
|
||||
void _ea_111_100_read_commit (void)
|
||||
{
|
||||
|