diff --git a/Makefile b/Makefile index 0eb6dd8..2154a21 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ all: shoebill -shoebill: make_core +shoebill: make_gui + +make_gui: make_core + xcodebuild -project gui/Shoebill.xcodeproj SYMROOT=build make_core: $(MAKE) -C core -j 4 clean: - rm -rf intermediates + rm -rf intermediates gui/build diff --git a/README.md b/README.md index de370e2..07eff57 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,17 @@ A Macintosh II emulator that runs A/UX (and A/UX only). Shoebill is an all-new, BSD-licensed Macintosh II emulator designed from the ground up with the singular goal of running A/UX. -A/UX 1.x.x through 2.0.0 are supported currently, and 3.x.x support is in progress. - -Shoebill requires a OS X, a Macintosh II or IIx ROM, a disk image with A/UX installed, and an A/UX kernel. +Shoebill requires a OS X, a Macintosh II, IIx or IIcx ROM, and a disk image with A/UX installed. [Download the latest release], and then see the [getting started] wiki. Also check out [screenshots]. +__Update (April 26, 2014): Shoebill 0.0.2 is available, and it supports A/UX 3.0.0! And you no longer need to supply your own kernel.__ + + +####Supports +* A/UX 1.1.1 through 3.0.0 (but not 3.0.1 or higher, yet) + ####Currently Implements * 68020 CPU (mostly) * 68881 FPU (a little) diff --git a/README.txt b/README.txt index 8d14f39..0fd377f 100644 --- a/README.txt +++ b/README.txt @@ -1,17 +1,13 @@ Shoebill - a Macintosh II emulator that runs A/UX - (except A/UX 3.x.x currently) - See the wiki on https://github.com/pruten/shoebill for better documentation on building and running Shoebill. *** KEEP IN MIND *** -* Shoebill v.first-terrible-code-drop (a.k.a. version 0.0.1) +* Shoebill v.0.0.2 * ONLY RUNS A/UX - * BUT NOT 3.x.x (I’m working on it) - * Only 1.x.x and 2.x.x * Shoebill has broken, ultra-minimalist support for * 68020 (CPU) + 68851 (MMU) + 68881 (FPU) * Some instructions for ‘020 and most for the MMU and FPU are unimplemented @@ -26,14 +22,11 @@ documentation on building and running Shoebill. *** RUNNING *** You will need -* OS X and a 64-bit Intel Macintosh - (32-bit builds are possible by twiddling the makefiles) -* A Macintosh II or IIx ROM -* A disk image with A/UX 1.x.x or 2.x.x installed +* OS X 10.8 or 10.9 +* A Macintosh II, IIx, or IIcx ROM +* A disk image with A/UX 1.x.x or 2.x.x, or 3.0.0 installed + * Note: 3.0.1 and 3.1.x do not work! * If you happen to have an installation CD image for A/UX, that will work -* The kernel on that image (/unix). Shoebill can’t read - SVFS or UFS file sytems yet to load the kernel directly - from the disk image. To boot A/UX @@ -42,15 +35,21 @@ To boot A/UX will very likely be corrupted - sometimes so severely that A/UX can’t even boot enough to run fsck. * Open Shoebill.app and select Preferences menu item - * Set the paths for your ROM, kernel, and disk image(s). + * Set the paths for your ROM and disk image(s). * Do use SCSI ID #0 for your A/UX boot image. - * Press “Apply and Run” + * Press “Apply and Run” +* Note: As of 0.0.2, you no longer need to provide your own kernel file *** BUILDING *** 1) cd to shoebill/ -2) make # to build shoebill_core -3) xcodebuild -project gui/Shoebill.xcodeproj # to build the Cocoa GUI +2) make +3) The resulting app will be in gui/build + + + +*** ETC. *** +Props to Jared Falter for technical and emotional support! diff --git a/core/Makefile b/core/Makefile index fec5999..45c21d1 100644 --- a/core/Makefile +++ b/core/Makefile @@ -1,12 +1,13 @@ CC = clang CFLAGS = -O3 -flto -ggdb -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 +NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi toby_frame_buffer video core_api filesystem debug_server alloc_pool # Object files that can be compiled directly from the source OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING)) diff --git a/core/alloc_pool.c b/core/alloc_pool.c new file mode 100644 index 0000000..a82d489 --- /dev/null +++ b/core/alloc_pool.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, Peter Rutenbar + * 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 +#include +#include +#include "../core/shoebill.h" + +/*typedef struct _alloc_pool_t { + struct _alloc_pool_t *prev, *next; + uint32_t size, magic; +} alloc_pool_t;*/ + +void* p_alloc(alloc_pool_t *pool, uint64_t size) +{ + alloc_pool_t *buf = calloc(sizeof(alloc_pool_t) + size, 1); + buf->size = size; + buf->magic = 'moof'; + + buf->next = pool->next; + buf->prev = pool; + + if (pool->next) + pool->next->prev = buf; + pool->next = buf; + + return &buf[1]; +} + +void* p_realloc(void *ptr, uint64_t size) +{ + alloc_pool_t *header = &((alloc_pool_t*)ptr)[-1]; + alloc_pool_t *new_header = realloc(header, size + sizeof(alloc_pool_t)); + + if (new_header) + return &new_header[1]; + + return NULL; +} + +void p_free(void *ptr) +{ + alloc_pool_t *header = &((alloc_pool_t*)ptr)[-1]; + assert(header->magic == 'moof'); + + if (header->next) + header->next->prev = header->prev; + + if (header->prev) + header->prev->next = header->next; + + free(header); +} + +void p_free_pool(alloc_pool_t *pool) +{ + while (pool->prev) + pool = pool->prev; + + while (pool) { + alloc_pool_t *cur = pool; + pool = cur->next; + assert(cur->magic == 'moof'); + free(cur); + } +} + +alloc_pool_t* p_new_pool(void) +{ + alloc_pool_t *pool = calloc(sizeof(alloc_pool_t), 1); + pool->magic = 'moof'; + return pool; +} \ No newline at end of file diff --git a/core/core_api.c b/core/core_api.c index 8ea2886..64734af 100644 --- a/core/core_api.c +++ b/core/core_api.c @@ -34,12 +34,10 @@ #include "coff.h" #include "core_api.h" -static uint64_t sub_tv (const struct timeval a, const struct timeval b) -{ - - return 0; -} - +/* +char *ring, *ring_tmp; +const uint32_t ring_len = 64 * 1024 * 1024; +uint32_t ring_i = 0; void print_mmu_rp(uint64_t rp) { @@ -48,11 +46,11 @@ void print_mmu_rp(uint64_t 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, + 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', @@ -63,24 +61,42 @@ void printregs() shoe.tc ); - printf("[vbr]%08x\n", shoe.vbr); - - printf("srp: "); - print_mmu_rp(shoe.srp); + sprintf(ring_tmp+strlen(ring_tmp), "[vbr]%08x\n", shoe.vbr); - printf("crp: "); - print_mmu_rp(shoe.crp); + //printf("srp: "); + //print_mmu_rp(shoe.srp); - printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n", + //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()); - printf("\n"); +} + +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[32]; + uint8_t binary[64]; uint32_t i; uint32_t len; const char *name = NULL; @@ -99,22 +115,13 @@ void print_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 { - coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc); - if (symb) - 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; @@ -125,30 +132,38 @@ void print_pc() disassemble_inst(binary, shoe.pc, str, &len); - printf("*0x%08x %s [ ", shoe.pc, name ? name : ""); + sprintf(ring_tmp, "*0x%08x %s [ ", shoe.pc, name ? name : ""); for (i=0; iram_size; - shoe.physical_mem_base = valloc(control->ram_size); + shoe.physical_mem_base = valloc(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 diff --git a/core/cpu.c b/core/cpu.c index 3854557..24a30be 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -31,9 +31,32 @@ #include "../core/mc68851.h" global_shoebill_context_t shoe; -//struct dbg_state_t dbg_state; + +static _Bool _cc_t() {return 1;} +static _Bool _cc_f() {return 0;} +static _Bool _cc_hi() {return !sr_c() && !sr_z();} +static _Bool _cc_ls() {return sr_c() || sr_z();} +static _Bool _cc_cc() {return !sr_c();} +static _Bool _cc_cs() {return sr_c();} +static _Bool _cc_ne() {return !sr_z();} +static _Bool _cc_eq() {return sr_z();} +static _Bool _cc_vc() {return !sr_v();} +static _Bool _cc_vs() {return sr_v();} +static _Bool _cc_pl() {return !sr_n();} +static _Bool _cc_mi() {return sr_n();} +static _Bool _cc_ge() {return (sr_n() && sr_v()) || (!sr_n() && !sr_v());} +static _Bool _cc_lt() {return (sr_n() && !sr_v()) || (!sr_n() && sr_v());} +static _Bool _cc_gt() {return (sr_n() && sr_v() && !sr_z()) || (!sr_n() && !sr_v() && !sr_z());} +static _Bool _cc_le() {return sr_z() || (sr_n() && !sr_v()) || (!sr_n() && sr_v());} +typedef _Bool (*_cc_func)(); +static const _cc_func evaluate_cc[16] = { + _cc_t, _cc_f, _cc_hi, _cc_ls, _cc_cc, _cc_cs, _cc_ne, _cc_eq, + _cc_vc, _cc_vs, _cc_pl, _cc_mi, _cc_ge, _cc_lt, _cc_gt, _cc_le +}; + #define nextword() ({const uint16_t w=lget(shoe.pc,2); if (shoe.abort) {return;}; shoe.pc+=2; w;}) +#define nextlong() ({const uint32_t L=lget(shoe.pc,4); if (shoe.abort) {return;}; shoe.pc+=4; L;}) #define verify_supervisor() {if (!sr_s()) {throw_privilege_violation(); return;}} ~newmacro(inst, 2, { @@ -75,67 +98,9 @@ global_shoebill_context_t shoe; // (xyz) == (010) -> sz=2 // (xyz) == (011) -> sz=4 const uint32_t sz = y << (z+1); // too clever - const uint32_t next_pc = shoe.orig_pc + 2 + sz; - - const uint8_t C = sr_c(); - const uint8_t Z = sr_z(); - const uint8_t V = sr_v(); - const uint8_t N = sr_n(); - - uint8_t set = 0; - - switch (c) { - case 0: // trapt - set = 1; // FIXME: do-trap unconditionally? - break; - case 1: // trapf - set = 0; // FIXME: do-not-trap unconditionally? - break; - case 2: - if (!C && !Z) set = 1; // traphi - break; - case 3: - if (C || Z) set = 1; // trapls - break; - case 4: - if (!C) set = 1; // trapcc - break; - case 5: - if (C) set = 1; // trapcs - break; - case 6: - if (!Z) set = 1; // trapne - break; - case 7: - if (Z) set = 1; // trapeq - break; - case 8: - if (!V) set = 1; // trapvc - break; - case 9: - if (V) set = 1; // trapvs - break; - case 10: - if (!N) set = 1; // trappl - break; - case 11: - if (N) set = 1; // trapmi - break; - case 12: - if ( (N && V) || (!N && !V) ) set = 1; // trapge - break; - case 13: - if ( (N && !V) || (!N && V) ) set = 1; // traplt - break; - case 14: - if ( (N && V && !Z) || (!N && !V && !Z) ) set = 1; // trapgt - break; - case 15: - if ( (Z || (N && !V) || (!N && V) ) ) set = 1; // traple - break; - } + const uint32_t next_pc = shoe.pc + sz; - if (set) + if (evaluate_cc[c]()) throw_frame_two(shoe.sr, next_pc, 7, shoe.orig_pc); else shoe.pc = next_pc; @@ -638,7 +603,7 @@ global_shoebill_context_t shoe; const uint16_t format_word = lget(shoe.a[7]+6, 2); if (shoe.abort) return ; - printf("rte: sr=0x%04x pc=0x%08x format=0x%04x, post-pop a7=0x%08x\n", sr, pc, format_word, shoe.a[7]+8); + // printf("rte: sr=0x%04x pc=0x%08x format=0x%04x, post-pop a7=0x%08x\n", sr, pc, format_word, shoe.a[7]+8); switch (format_word >> 12) { case 0: @@ -900,8 +865,7 @@ global_shoebill_context_t shoe; if (s < 2) { immed = chop(nextword(), sz); } else { - immed = nextword(); - immed = (immed << 16) | nextword(); + immed = nextlong(); } call_ea_read(M, sz); @@ -1155,25 +1119,64 @@ global_shoebill_context_t shoe; ~inst(movea, { ~decompose(shoe.op, 00 ab rrr 001 MMMMMM); - if (a == 0) { // only word and long sizes are supported for movea - throw_illegal_instruction(); - return ; - } - const uint8_t sz = b ? 2 : 4; // 1<<(1+(!b)); // (3=word, 2=long) + + const uint8_t sz = b ? 2 : 4; call_ea_read(M, sz); call_ea_read_commit(M, sz); if (b) { // word-size, sign extend shoe.dat - int16_t dat = shoe.dat; + const int16_t dat = shoe.dat; shoe.a[r] = (int32_t)dat; } else { - // printf("r = %u, dat=0x%llx\n", r, shoe.dat); shoe.a[r] = shoe.dat; } }) +~inst(move_d_to_d, { + ~decompose(shoe.op, 00 ab RRR 000 000 rrr); // r=source, R=dest + + const uint8_t sz = 1<<(a+(!b)); // (1=byte, 3=word, 2=long) + const uint32_t val = chop(shoe.d[r], sz); + + set_d(R, val, sz); + + set_sr_v(0); + set_sr_c(0); + set_sr_n(mib(val, sz)); + set_sr_z(val == 0); +}) + +~inst(move_from_d, { + ~decompose(shoe.op, 00 ab RRR MMM 000 rrr); // r=source, MR=dest + + const uint8_t sz = 1<<(a+(!b)); // (1=byte, 3=word, 2=long) + const uint32_t val = chop(shoe.d[r], sz); + + set_sr_v(0); + set_sr_c(0); + set_sr_n(mib(val, sz)); + set_sr_z(val == 0); + + shoe.dat = val; + call_ea_write((M << 3) | R, sz); +}) + +~inst(move_to_d, { + ~decompose(shoe.op, 00 ab rrr 000 mmmmmm); // m=source, r=dest + const uint8_t sz = 1<<(a+(!b)); // (1=byte, 3=word, 2=long) + + call_ea_read(m, sz); + call_ea_read_commit(m, sz); + + set_sr_v(0); + set_sr_c(0); + set_sr_n(ea_n(sz)); + set_sr_z(ea_z(sz)); + set_d(r, shoe.dat, sz); +}) + ~inst(move, { - ~decompose(shoe.op, 00 ab RRR MMM mmm rrr); // o=source, MR=dest + ~decompose(shoe.op, 00 ab RRR MMM mmm rrr); // mr=source, MR=dest const uint8_t sz = 1<<(a+(!b)); // (1=byte, 3=word, 2=long) call_ea_read((m<<3) | r, sz); @@ -1567,12 +1570,12 @@ global_shoebill_context_t shoe; } else if (s==1) { immed = (int16_t)nextword(); } else { - immed = nextword(); - immed = (immed << 16) | nextword(); + immed = nextlong(); } // fetch the destination operand call_ea_read(M, sz); + // do the subtraction const uint32_t result = shoe.dat - immed; // find the MIBs for source, dest, and result @@ -1602,8 +1605,7 @@ global_shoebill_context_t shoe; } else if (s==1) { immed = (int16_t)nextword(); } else { - immed = nextword(); - immed = (immed << 16) | nextword(); + immed = nextlong(); } call_ea_read(M, sz); @@ -1633,8 +1635,7 @@ global_shoebill_context_t shoe; } else if (s==1) { immed = (int16_t)nextword(); } else { - immed = nextword(); - immed = (immed << 16) | nextword(); + immed = nextlong(); } call_ea_read(M, sz); @@ -1660,8 +1661,7 @@ global_shoebill_context_t shoe; } else if (s==1) { immed = (int16_t)nextword(); } else { - immed = nextword(); - immed = (immed << 16) | nextword(); + immed = nextlong(); } // fetch the destination operand @@ -1689,8 +1689,7 @@ global_shoebill_context_t shoe; } else if (s==1) { immed = (int16_t)nextword(); } else { - immed = nextword(); - immed = (immed << 16) | nextword(); + immed = nextlong(); } // fetch the destination operand @@ -1813,33 +1812,15 @@ global_shoebill_context_t shoe; ~inst(dbcc, { ~decompose(shoe.op, 0101 cccc 11001 rrr); - const uint32_t orig_pc = shoe.pc; - const int16_t disp = nextword(); - const uint8_t C = sr_c(); - const uint8_t Z = sr_z(); - const uint8_t V = sr_v(); - const uint8_t N = sr_n(); - switch (c) { - case 0: return ; // dbt (what a useless instruction: c==0 => condition=true => return without doing anything) - case 1: break ; // dbf (or dbra) - case 2: if (!C && !Z) return; break; // dbhi - case 3: if (C || Z) return; break; // dbls - case 4: if (!C) return; break; // dbcc - case 5: if (C) return; break; // dbcs - case 6: if (!Z) return; break; // dbne - case 7: if (Z) return; break; // dbeq - case 8: if (!V) return; break; // dbvc - case 9: if (V) return; break; // dbvs - case 10: if (!N) return; break; // dbpl - case 11: if (N) return; break; // dbmi - case 12: if ( (N && V) || (!N && !V) ) return; break; // dbge - case 13: if ( (N && !V) || (!N && V) ) return; break; // dblt - case 14: if ( (N && V && !Z) || (!N && !V && !Z) ) return; break; // dbgt - case 15: if ( (Z || (N && !V) || (!N && V) ) ) return; break; // dble - } - set_d(r, get_d(r, 2)-1, 2); - if (get_d(r, 2) != 0xffff) { - shoe.pc = orig_pc + disp; + if (evaluate_cc[c]()) { + shoe.pc += 2; + } + else { + const int16_t disp = nextword(); + const uint16_t newd = get_d(r, 2) - 1; + set_d(r, newd, 2); + if (newd != 0xffff) + shoe.pc = shoe.pc + disp - 2; } }) @@ -1849,14 +1830,11 @@ global_shoebill_context_t shoe; // find the new PC if ((d==0) || (d==0xff)) { - const uint16_t ext = nextword(); if (d==0xff) { - uint32_t mylong = ((uint32_t)ext)<<16; - mylong |= nextword(); - new_pc += mylong; + new_pc += nextlong(); } else - new_pc += ((int16_t)ext); + new_pc += ((int16_t)nextword()); } else { uint8_t tmp = d; @@ -1870,137 +1848,43 @@ global_shoebill_context_t shoe; }) ~inst(bcc, { - uint32_t new_pc = shoe.pc; + const uint32_t orig_pc = shoe.pc; ~decompose(shoe.op, 0110 cccc dddddddd); - // find the new PC - if ((d==0) || (d==0xff)) { - const uint16_t ext = nextword(); - if (d==0xff) { - uint32_t mylong = ((uint32_t)ext)<<16; - mylong |= nextword(); - new_pc += mylong; - } - else - new_pc += ((int16_t)ext); - } - else { - uint8_t tmp = d; - new_pc += ((int8_t)d); - } - // we'll use these control codes - const uint8_t C = sr_c(); - const uint8_t Z = sr_z(); - const uint8_t V = sr_v(); - const uint8_t N = sr_n(); - - // branch conditionally - switch (c) { - case 0: { // BRA - shoe.pc = new_pc; return; // branch unconditionally + if (evaluate_cc[c]()) { + if (d == 0) { + const int16_t ext = (int16_t)nextword(); + shoe.pc = orig_pc + ext; } - case 1: { - assert(!"How did we get here?"); // decoder should have called inst_bsr() + else if (d == 0xff) { + shoe.pc = orig_pc + nextlong(); + } + else { + const int8_t tmp = (int8_t)d; + shoe.pc = orig_pc + tmp; } - case 2: if (!C && !Z) shoe.pc = new_pc; return; // bhi - case 3: if (C || Z) shoe.pc = new_pc; return; // bls - case 4: if (!C) shoe.pc = new_pc; return; // bcc - case 5: if (C) shoe.pc = new_pc; return; // bcs - case 6: if (!Z) shoe.pc = new_pc; return; // bne - case 7: if (Z) shoe.pc = new_pc; return; // beq - case 8: if (!V) shoe.pc = new_pc; return; // bvc - case 9: if (V) shoe.pc = new_pc ; return; // bvs - case 10: if (!N) shoe.pc = new_pc; return; // bpl - case 11: if (N) shoe.pc = new_pc; return; // bmi - case 12: if ( (N && V) || (!N && !V) ) shoe.pc = new_pc; return; // bge - case 13: if ( (N && !V) || (!N && V) ) shoe.pc = new_pc; return; // blt - case 14: if ( (N && V && !Z) || (!N && !V && !Z) ) shoe.pc = new_pc; return; // bgt - case 15: if ( (Z || (N && !V) || (!N && V) ) ) shoe.pc = new_pc; return; // ble + } + else { + if (d == 0) shoe.pc += 2; + else if (d == 0xff) shoe.pc += 4; } }) ~inst(scc, { ~decompose(shoe.op, 0101 cccc 11 MMMMMM); - const uint8_t C = sr_c(); - const uint8_t Z = sr_z(); - const uint8_t V = sr_v(); - const uint8_t N = sr_n(); - uint8_t byte = 0; - switch (c) { - case 0: // st (set unconditionally? FIXME: TEST ME!) - byte = 0xff; - break; - case 1: // sf - byte = 0x0; // (FIXME: do-not-set unconditionally? This can possibly be right) - break; - case 2: - if (!C && !Z) byte = 0xff; // shi - break; - case 3: - if (C || Z) byte = 0xff; // sls - break; - case 4: - if (!C) byte = 0xff; // scc - break; - case 5: - if (C) byte = 0xff; // scs - break; - case 6: - if (!Z) byte = 0xff; // sne - break; - case 7: - if (Z) byte = 0xff; // seq - break; - case 8: - if (!V) byte = 0xff; // svc - break; - case 9: - if (V) byte = 0xff; // svs - break; - case 10: - if (!N) byte = 0xff; // spl - break; - case 11: - if (N) byte = 0xff; // smi - break; - case 12: - if ( (N && V) || (!N && !V) ) byte = 0xff; // sge - break; - case 13: - if ( (N && !V) || (!N && V) ) byte = 0xff; // slt - break; - case 14: - if ( (N && V && !Z) || (!N && !V && !Z) ) byte = 0xff; // sgt - break; - case 15: - if ( (Z || (N && !V) || (!N && V) ) ) byte = 0xff; // sle - break; - } - shoe.dat = byte; + shoe.dat = evaluate_cc[c]() ? 0xff : 0; call_ea_write(M, 1); }) ~inst(nop, {}) -/* - // Illegal on 68040 -~inst(cinv, { - // Caches aren't implemented, so do nothing -}) - -~inst(cpush, { - // Caches aren't implemented, so do nothing -}) -*/ - ~inst(chk, { ~decompose(shoe.op, 0100 rrr 1s 0 MMMMMM); const uint8_t sz = s ? 2 : 4; call_ea_read(M, sz); - call_ea_read_commit(M, sz); int32_t reg, ea; @@ -2019,6 +1903,8 @@ global_shoebill_context_t shoe; set_sr_n((reg < 0)); throw_frame_two(shoe.sr, shoe.pc, 6, shoe.orig_pc); } + + call_ea_read_commit(M, sz); return ; }) @@ -2036,39 +1922,22 @@ global_shoebill_context_t shoe; shoe.a[7] -= 4; shoe.pc = shoe.dat; - if (sr_s()&&0) { + /* + if (sr_s()) { //return ; coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); + if (symb) { - uint32_t i; - - printf("CALL %s+%u 0x%08x\n", symb->name, shoe.pc-symb->value, shoe.pc); - if (strcmp(symb->name, "tracescsi") == 0) { - uint32_t addr = lget(shoe.a[7]+4, 4); - - printf("tracescsi: ["); - char c; - do { - c = lget(addr++, 1); - printf("%c", c); - } while ((c != 0) && (!shoe.abort)); - printf("]\n"); - } + sprintf(ring_tmp, "CALL (s) %s+%u 0x%08x\n", symb->name, shoe.pc-symb->value, shoe.pc); + ring_print(ring_tmp); } - - if (shoe.pc == 0x1002ba94) { - uint32_t addr = lget(shoe.a[7]+4, 4); - printf("panic: ["); - char c; - do { - c = lget(addr++, 1); - printf("%c", c); - } while ((c != 0) && (!shoe.abort)); - printf("]\n"); + else { + sprintf(ring_tmp, "CALL (s) unknown+ 0x%08x\n", shoe.pc); + ring_print(ring_tmp); } } - else if (0) { + else { char *name = (char*)"unknown"; uint32_t value = 0; if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) { @@ -2081,16 +1950,12 @@ global_shoebill_context_t shoe; value = macii_rom_symbols[i].addr; } } - /*else { - coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc); - if (symb) { - value = symb->value; - name = symb->name; - } - }*/ - printf("CALL %s+%u 0x%08x\n", name, shoe.pc-value, shoe.pc); + + sprintf(ring_tmp, "CALL (u) %s+%u 0x%08x\n", name, shoe.pc-value, shoe.pc); + ring_print(ring_tmp); } + */ }) @@ -2136,6 +2001,7 @@ global_shoebill_context_t shoe; shoe.a[7] += 4; shoe.pc = pop; + /* if (sr_s() && 0) { // return ; coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); @@ -2155,23 +2021,15 @@ global_shoebill_context_t shoe; value = macii_rom_symbols[i].addr; } } - /*else { - coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc); - if (symb) { - value = symb->value; - name = symb->name; - } - }*/ printf("RETURN TO %s+%u 0x%08x\n", name, shoe.pc-value, shoe.pc); - } + }*/ }) ~inst(link_long, { ~decompose(shoe.op, 0100 1000 0000 1 rrr); - const uint16_t ext_hi = nextword(); - const uint32_t disp = (ext_hi<<16) | nextword(); + const uint32_t disp = nextlong(); // push the contents of the address register onto the stack lset(shoe.a[7]-4, 4, shoe.a[r]); @@ -2926,14 +2784,19 @@ uint32_t extract_bitfield(const uint32_t width, const uint32_t offset, const uin assert(!"never get here"); }) +void dump_ring(); ~inst(unknown, { printf("Unknown instruction (0x%04x)!\n", shoe.op); + /*if (shoe.op == 0x33fe) { + dump_ring(); + assert(!"dumped"); + }*/ throw_illegal_instruction(); }) ~inst(a_line, { - if (shoe.op == 0xA9EB || shoe.op == 0xA9EC) { + /*if (shoe.op == 0xA9EB || shoe.op == 0xA9EC) { shoe.suppress_exceptions = 1; uint32_t fp_op = lget(shoe.a[7]+0, 2); @@ -2961,7 +2824,7 @@ uint32_t extract_bitfield(const uint32_t width, const uint32_t offset, const uin shoe.abort = 0; shoe.suppress_exceptions = 0; - } + }*/ throw_illegal_instruction(); }) @@ -3058,36 +2921,35 @@ void trap_debug() void cpu_step() { - while (1) { - // remember the PC and SR (so we can throw exceptions later) - shoe.orig_pc = shoe.pc; - shoe.orig_sr = shoe.sr; - - // Is this an odd address? Throw an address exception! - if (shoe.pc & 1) { - // throw_address_error(shoe.pc, 0); - assert(!"What do I do here?"); - continue; - } - - // Fetch the next instruction word - shoe.op = lget(shoe.pc, 2); - - // If there was an exception, then the pc changed. Restart execution from the beginning. - if (shoe.abort) { - shoe.abort = 0; - continue; - } - shoe.pc+=2; - - inst_instruction_to_pointer[inst_opcode_map[shoe.op]](); - - /* The abort flag indicates that a routine should stop trying to execute the - instruction and return immediately to cpu_step(), usually to begin - exception processing */ - - shoe.abort = 0; // clear the abort flag + // remember the PC and SR (so we can throw exceptions later) + shoe.orig_pc = shoe.pc; + shoe.orig_sr = shoe.sr; + + // Is this an odd address? Throw an address exception! + if (shoe.pc & 1) { + // throw_address_error(shoe.pc, 0); + // I'm leaving this assert in here for now because it almost always indicates a bug in the emulator when it fires + assert(!"What do I do here?"); + return ; + } + + // Fetch the next instruction word + shoe.op = lget(shoe.pc, 2); + + // If there was an exception, then the pc changed. Restart execution from the beginning. + if (shoe.abort) { + shoe.abort = 0; return ; } + shoe.pc+=2; + + inst_instruction_to_pointer[inst_opcode_map[shoe.op]](); + + /* The abort flag indicates that a routine should stop trying to execute the + instruction and return immediately to cpu_step(), usually to begin + exception processing */ + + shoe.abort = 0; // clear the abort flag + return ; } diff --git a/core/decoder_gen.c b/core/decoder_gen.c index fba40d6..71a1e0b 100644 --- a/core/decoder_gen.c +++ b/core/decoder_gen.c @@ -929,6 +929,65 @@ void begin_definitions() // subtract illegal size (00) sub_range(inst, "00 00 xxxxxx xxxxxx"); + + // subtract move_from_d + sub_range(inst, "00 xx xxxxxx 000xxx"); + + // subtract move_to_d + sub_range(inst, "00 xx xxx000 xxxxxx"); + } + + { // move_d_to_d + inst_t *inst = new_inst("move_d_to_d", "all", 1); + no_ea(inst); + + add_range(inst, "00 xx xxx 000 000 xxx"); + sub_range(inst, "00 00 xxx 000 000 xxx"); + } + + { // move_to_d + inst_t *inst = new_inst("move_to_d", "all", 2); + { // EA mode == addr register (byte-size not allowed) + set_range_group(inst, 0); + add_range(inst, "00 11 xxx000 MMMMMM"); + add_range(inst, "00 10 xxx000 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { // all other EA modes + set_range_group(inst, 1); + add_range(inst, "00 xx xxx000 MMMMMM"); + sub_range(inst, "00 00 xxx000 MMMMMM"); + ea_all(inst); + ea_sub_mode(inst, EA_001); + ea_sub_mode(inst, EA_000); // EA_000 is handled by move_d_to_d + } + } + + { // move_from_d + inst_t *inst = new_inst("move_from_d", "all", 1); + + // I'm manually specifying this entire thing, since the EA description is too complicated + no_ea(inst); + + // Add in all modes, all sizes + add_range(inst, "00 xx xxxxxx 000xxx"); + + // subtract the invalid destination modes (001, 111_010, 111_011, 111_100) + sub_range(inst, "00 xx xxx 001 xxxxxx"); + sub_range(inst, "00 xx 010 111 xxxxxx"); + sub_range(inst, "00 xx 011 111 xxxxxx"); + sub_range(inst, "00 xx 100 111 xxxxxx"); + + // subtract the illegal destination modes (111_101, 111_110, 111_111) + sub_range(inst, "00 xx 101 111 xxxxxx"); + sub_range(inst, "00 xx 110 111 xxxxxx"); + sub_range(inst, "00 xx 111 111 xxxxxx"); + + // subtract illegal size (00) + sub_range(inst, "00 00 xxxxxx xxxxxx"); + + // subtract move_d_to_d + sub_range(inst, "00 xx xxx 000 000xxx"); } { // movea diff --git a/core/dis.c b/core/dis.c index 616d80d..8a50570 100644 --- a/core/dis.c +++ b/core/dis.c @@ -802,6 +802,18 @@ void dis_move () { sprintf(dis.str, "move.%c %s,%s", "blw"[s-1], sourceStr, destStr); } +void dis_move_d_to_d () { + sprintf(dis.str, "move_d_to_d ???"); +} + +void dis_move_to_d () { + sprintf(dis.str, "move_to_d ???"); +} + +void dis_move_from_d () { + sprintf(dis.str, "move_from_d ???"); +} + void dis_scc () { const char *condition_names[16] = { "t", "ra", "hi", "ls", "cc", "cs", "ne", "eq", diff --git a/core/filesystem.c b/core/filesystem.c index 220bfb4..1d5ccf6 100644 --- a/core/filesystem.c +++ b/core/filesystem.c @@ -28,15 +28,7 @@ #include #include #include - -#pragma mark Alloc pool stuff - -/* --- alloc pool --- */ - -typedef struct _alloc_pool_t{ - struct _alloc_pool_t *prev, *next; - uint32_t size, magic; -} alloc_pool_t; +#include "../core/shoebill.h" #define fix_endian(x) do { \ if (ntohs(1) == 1) \ @@ -45,76 +37,9 @@ typedef struct _alloc_pool_t{ case 1: break; \ case 2: (x) = ntohs(x); break; \ case 4: (x) = ntohl(x); break; \ - case 8: { \ - const uint64_t n = ntohl((x) & 0xffffffff); \ - (x) = (n<<32) | ntohl((x)>>32); \ - break; \ - } \ default: assert(!"bogus size"); \ }} while (0) -static void* p_alloc(alloc_pool_t *pool, uint64_t size) -{ - alloc_pool_t *buf = calloc(sizeof(alloc_pool_t) + size, 1); - buf->size = size; - buf->magic = 'moof'; - - buf->next = pool->next; - buf->prev = pool; - - if (pool->next) - pool->next->prev = buf; - pool->next = buf; - - return &buf[1]; -} - -static void* p_realloc(void *ptr, uint64_t size) -{ - alloc_pool_t *header = &((alloc_pool_t*)ptr)[-1]; - alloc_pool_t *new_header = realloc(header, size + sizeof(alloc_pool_t)); - - if (new_header) - return &new_header[1]; - - return NULL; -} - -static void p_free(void *ptr) -{ - alloc_pool_t *header = &((alloc_pool_t*)ptr)[-1]; - assert(header->magic == 'moof'); - - if (header->next) - header->next->prev = header->prev; - - if (header->prev) - header->prev->next = header->next; - - free(header); -} - -static void p_free_pool(alloc_pool_t *pool) -{ - while (pool->prev) - pool = pool->prev; - - while (pool) { - alloc_pool_t *cur = pool; - pool = cur->next; - assert(cur->magic == 'moof'); - free(cur); - } -} - -static alloc_pool_t* p_new_pool(void) -{ - alloc_pool_t *pool = calloc(sizeof(alloc_pool_t), 1); - pool->magic = 'moof'; - return pool; -} - - /* --- Disk/partition management stuff --- */ #pragma mark Disk/partition management stuff @@ -344,8 +269,8 @@ static disk_t* open_disk (const char *disk_path, char *error_str) memcpy(disk->partitions[i].name, disk->partition_maps[i].pmPartName, 32); memcpy(disk->partitions[i].type, disk->partition_maps[i].pmPartType, 32); - // printf("%u type:%s name:%s\n", i, disk->partitions[i].type, disk->partitions[i].name); - // printf("bz_magic=0x%08x slice=%u\n", disk->partition_maps[i].bz.magic, disk->partition_maps[i].bz.slice); + printf("%u type:%s name:%s\n", i, disk->partitions[i].type, disk->partitions[i].name); + printf("bz_magic=0x%08x slice=%u\n", disk->partition_maps[i].bz.magic, disk->partition_maps[i].bz.slice); } return disk; @@ -855,7 +780,8 @@ typedef struct __attribute__ ((__packed__)) { uint16_t nlink; uint16_t uid; uint16_t gid; - uint64_t size; + uint32_t size_hi; // UFS stores size as a uint64_t, but A/UX apparently only reads/writes + uint32_t size; // to the low bits, so sometimes the hi bits contain garbage uint32_t atime; uint32_t dummy; uint32_t mtime; @@ -986,6 +912,7 @@ static uint8_t ufs_load_inode(ufs_t *mount, ufs_inode_t *inode, uint32_t inum) fix_endian(inode->nlink); fix_endian(inode->uid); fix_endian(inode->gid); + fix_endian(inode->size_hi); fix_endian(inode->size); fix_endian(inode->atime); fix_endian(inode->mtime); @@ -1043,7 +970,7 @@ static uint8_t ufs_read_level(ufs_t *mount, const uint32_t block_addr = (blockno / mount->frag_per_block) * mount->frag_per_block; const uint32_t block_offset = (blockno - block_addr) * mount->frag_size; - //printf("L%u: raw_blkno=0x%08x len=0x%08x blockno:0x%08x chunk_size=0x%08x\n", level-1, blockno, (uint32_t)*len, block_addr, (uint32_t)chunk_size); + printf("L%u: raw_blkno=0x%08x len=0x%08x blockno:0x%08x chunk_size=0x%08x\n", level-1, blockno, (uint32_t)*len, block_addr, (uint32_t)chunk_size); // If the chunk_size is a whole block, then we better be reading in a whole block if (chunk_size == mount->block_size) { @@ -1325,6 +1252,7 @@ uint8_t* shoebill_extract_kernel(const char *disk_path, const char *kernel_path, sprintf(error_str, "Couldn't find root partition"); goto done; } + printf("apm_part_num = %u\n", apm_part_num); svfs_mount_obj = svfs_mount(&disk->partitions[apm_part_num]); if (svfs_mount_obj) { diff --git a/core/mc68851.c b/core/mc68851.c index 338e8d2..937dc2d 100644 --- a/core/mc68851.c +++ b/core/mc68851.c @@ -81,15 +81,15 @@ void inst_mc68851_pflushr(uint16_t ext){ verify_supervisor(); printf("pflushr!"); // Just nuke the entire cache - bzero(shoe.pmmu_cache[0].valid_map, 512/8); - bzero(shoe.pmmu_cache[1].valid_map, 512/8); + bzero(shoe.pmmu_cache[0].valid_map, PMMU_CACHE_SIZE/8); + bzero(shoe.pmmu_cache[1].valid_map, PMMU_CACHE_SIZE/8); } void inst_mc68851_pflush(uint16_t ext){ verify_supervisor(); printf("pflush!"); - bzero(shoe.pmmu_cache[0].valid_map, 512/8); - bzero(shoe.pmmu_cache[1].valid_map, 512/8); + bzero(shoe.pmmu_cache[0].valid_map, PMMU_CACHE_SIZE/8); + bzero(shoe.pmmu_cache[1].valid_map, PMMU_CACHE_SIZE/8); // printf("%s: Error, not implemented!\n", __func__); } diff --git a/core/mem.c b/core/mem.c index 6c69d81..df2a870 100644 --- a/core/mem.c +++ b/core/mem.c @@ -30,410 +30,250 @@ #include #include "../core/shoebill.h" -static void translate_logical_addr(); +#ifdef __APPLE__ +#include +#define ntohll(x) OSSwapBigToHostInt64(x) +#endif -void physical_get (void) { +/* --- Physical_get jump table --- */ +#pragma mark Physical_get jump table + +void _physical_get_ram (void) +{ + uint64_t *addr; + if (shoe.physical_addr < shoe.physical_mem_size) + addr = (uint64_t*)&shoe.physical_mem_base[shoe.physical_addr]; + else + addr = (uint64_t*)&shoe.physical_mem_base[shoe.physical_addr % shoe.physical_mem_size]; - switch (shoe.physical_addr >> 28) { - case 0: - case 1: - case 2: - case 3: { // RAM - void *addr; - if (shoe.physical_addr >= shoe.physical_mem_size) - addr = &shoe.physical_mem_base[shoe.physical_addr % shoe.physical_mem_size]; - else - addr = &shoe.physical_mem_base[shoe.physical_addr]; - - switch (shoe.physical_size) { - case 4: - shoe.physical_dat = ntohl(*(uint32_t*)addr); - return ; - case 2: - shoe.physical_dat = ntohs(*(uint16_t*)addr); - return ; - case 1: - shoe.physical_dat = *(uint8_t*)addr; - return ; - default: { - const uint32_t s = shoe.physical_size; - uint64_t q = 0; - uint32_t i; - for (i=0; i> 24) & 0xf; - if (shoe.slots[slot].connected) - shoe.physical_dat = shoe.slots[slot].read_func(shoe.physical_addr, - shoe.physical_size, - slot); - else - shoe.abort = 1; // throw a bus error for reads to disconnected slots + const uint8_t bits = (8 - shoe.physical_size) * 8; + shoe.physical_dat = ntohll(*addr) >> bits; +} + +void _physical_get_rom (void) +{ + uint64_t *addr = (uint64_t*)&shoe.physical_rom_base[shoe.physical_addr & (shoe.physical_rom_size-1)]; + + const uint8_t bits = (8 - shoe.physical_size) * 8; + shoe.physical_dat = ntohll(*addr) >> bits; +} + +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 ; - } - default: { // Nubus super slot space - const uint32_t slot = shoe.physical_addr >> 28; - if (shoe.slots[slot].connected) - shoe.physical_dat = shoe.slots[slot].read_func(shoe.physical_addr, - shoe.physical_size, - slot); - else - shoe.abort = 1; // throw a bus error for reads to disconnected slots - // XXX: Do super slot accesses raise bus errors? + case 0x50002000 ... 0x50003fff: // VIA2 + via_reg_read(); + // printf("physical_get: got read to VIA2\n"); + return ; + case 0x50004000 ... 0x50005fff: {// SCC + //printf("physical_get: got read to SCC\n"); + const uint32_t a = shoe.physical_addr & 0x1fff; + if (a == 2 && shoe.physical_size==1) + shoe.physical_dat = 0x4; // R0TXRDY 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 ; + case 0x50010000 ... 0x50011fff: // SCSI (normal mode?) + scsi_reg_read(); + return ; + 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"); + return ; + case 0x50016000 ... 0x50017fff: // SWIM (IWM?) + // printf("physical_get: got read to IWM\n"); + shoe.physical_dat = iwm_dma_read(); + return ; + default: + //printf("physical_get: got read to UNKNOWN IO ADDR %x\n", shoe.physical_addr); + return ; } } -void physical_set (void) +void _physical_get_super_slot (void) { - switch (shoe.physical_addr >> 28) { - case 0: + const uint32_t slot = shoe.physical_addr >> 28; + if (shoe.slots[slot].connected) + shoe.physical_dat = shoe.slots[slot].read_func(shoe.physical_addr, + shoe.physical_size, + slot); + else + shoe.abort = 1; // throw a bus error for reads to disconnected slots + // XXX: Do super slot accesses raise bus errors? +} + +void _physical_get_standard_slot (void) +{ + const uint32_t slot = (shoe.physical_addr >> 24) & 0xf; + if (shoe.slots[slot].connected) + shoe.physical_dat = shoe.slots[slot].read_func(shoe.physical_addr, + shoe.physical_size, + slot); + else + shoe.abort = 1; // throw a bus error for reads to disconnected slots +} + +const physical_get_ptr physical_get_jump_table[16] = { + _physical_get_ram, // 0x0 + _physical_get_ram, // 0x1 + _physical_get_ram, // 0x2 + _physical_get_ram, // 0x3 + _physical_get_rom, // 0x4 + _physical_get_io, // 0x5 + _physical_get_super_slot, // 0x6 + _physical_get_super_slot, // 0x7 + _physical_get_super_slot, // 0x8 + _physical_get_super_slot, // 0x9 + _physical_get_super_slot, // 0xa + _physical_get_super_slot, // 0xb + _physical_get_super_slot, // 0xc + _physical_get_super_slot, // 0xd + _physical_get_super_slot, // 0xe + _physical_get_standard_slot // 0xf +}; + +/* --- Physical_set jump table --- */ +#pragma mark Physical_set jump table + +void _physical_set_ram (void) +{ + uint8_t *addr; + if (shoe.physical_addr >= shoe.physical_mem_size) + addr = &shoe.physical_mem_base[shoe.physical_addr % shoe.physical_mem_size]; + else + addr = &shoe.physical_mem_base[shoe.physical_addr]; + + const uint32_t sz = shoe.physical_size; + switch (sz) { case 1: + *addr = (uint8_t)shoe.physical_dat; + return ; + case 2: - case 3: { // RAM - const uint32_t dat = htonl(shoe.physical_dat) >> ((4-shoe.physical_size)*8); - void *addr; - if (shoe.physical_addr >= shoe.physical_mem_size) - addr = &shoe.physical_mem_base[shoe.physical_addr % shoe.physical_mem_size]; - else - addr = &shoe.physical_mem_base[shoe.physical_addr]; - switch (shoe.physical_size) { - case 4: - *((uint32_t*)addr) = dat; - return ; - case 2: - *((uint16_t*)addr) = (uint16_t)dat; - return ; - case 1: - *((uint8_t*)addr) = (uint8_t)dat; - return ; - // case 8: { } // I should do something fast for case 8 here - default: { - const uint32_t s = shoe.physical_size; - uint64_t q = shoe.physical_dat; - uint32_t i; - for (i=0; i>= 8; - } - return ; - } - } - assert(!"never get here"); - } - case 4: { // ROM - // Nothing happens when you try to modify ROM + *((uint16_t*)addr) = htons((uint16_t)shoe.physical_dat); return ; - } - case 5: { // IO - 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"); - return ; - case 0x50004000 ... 0x50005fff: // SCC - //printf("physical_set: got write to SCC\n"); - return ; - case 0x50006000 ... 0x50007fff: // SCSI (pseudo-DMA with DRQ?) - assert(shoe.physical_size == 4); - scsi_dma_write_long(shoe.physical_dat); - return ; - case 0x50010000 ... 0x50011fff: // SCSI (normal mode?) - scsi_reg_write(); - return ; - 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"); - return ; - case 0x50016000 ... 0x50017fff: // SWIM (IWM?) - //printf("physical_set: got write to IWM\n"); - iwm_dma_write(); - return ; - default: - //printf("physical_set: got write to UNKNOWN IO ADDR %x\n", shoe.physical_addr); - return ; - } - } - case 0xf: { // Nubus standard slot space - const uint32_t slot = (shoe.physical_addr >> 24) & 0xf; - if (shoe.slots[slot].connected) - shoe.slots[slot].write_func(shoe.physical_addr, - shoe.physical_size, - shoe.physical_dat, - slot); + + case 4: + *((uint32_t*)addr) = htonl((uint32_t)shoe.physical_dat); return ; - // Writing to a disconnected slot won't cause a bus error on macii - } - default: { // Nubus super slot space - const uint32_t slot = shoe.physical_addr >> 28; - if (shoe.slots[slot].connected) - shoe.slots[slot].write_func(shoe.physical_addr, - shoe.physical_size, - shoe.physical_dat, - slot); + + case 8: + *(uint64_t*)addr = ntohll(shoe.physical_dat); + return ; + + default: { + uint64_t q = shoe.physical_dat; + uint8_t i; + for (i=1; i<=sz; i++) { + addr[sz-i] = (uint8_t)q; + q >>= 8; + } return ; } } } -void logical_get (void) +void _physical_set_rom (void) { - - // If address translation isn't enabled, this is a physical address - if (!tc_enable()) { - shoe.physical_addr = shoe.logical_addr; - shoe.physical_size = shoe.logical_size; - physical_get(); - if (shoe.abort) { - shoe.abort = 0; - throw_long_bus_error(shoe.logical_addr, 0); + // nothing happens when you try to modify ROM +} + +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 ; - } - shoe.logical_dat = shoe.physical_dat; - return ; - } - - const uint32_t logical_size = shoe.logical_size; - const uint32_t logical_addr = shoe.logical_addr; - - const uint16_t ps = tc_ps(); // log2 of the page size - const uint32_t pagesize = 1 << ps; // the page size - const uint32_t pagemask = pagesize-1; // a mask of the page bits - const uint32_t pageoffset = logical_addr & pagemask; - - shoe.logical_is_write = 0; - - // This read crosses a page boundary - if ((pageoffset + logical_size - 1) >> ps) { - const uint32_t addr_a = shoe.logical_addr; - const uint32_t size_b = (pageoffset + logical_size) & pagemask; - const uint32_t size_a = shoe.logical_size - size_b; - const uint32_t addr_b = addr_a + size_a; - - // printf("ps = %u, pagesize=%u, pagemask=%x, pageoffset=%x\n", ps, pagesize, pagemask, pageoffset); - // printf("multiple page get: addr_a=0x%08x size_a=%u addr_b=0x%08x size_b=%u\n", addr_a, size_a, addr_b, size_b); - shoe.logical_addr = addr_a; - shoe.logical_size = size_a; - translate_logical_addr(); - if (shoe.abort) + case 0x50002000 ... 0x50003fff: // VIA2 + via_reg_write(); + // printf("physical_set: got write to VIA2\n"); return ; - - const uint32_t p_addr_a = shoe.physical_addr; - shoe.physical_size = size_a; - physical_get(); - if (shoe.abort) { - shoe.abort = 0; - throw_long_bus_error(shoe.logical_addr, 0); + case 0x50004000 ... 0x50005fff: // SCC + //printf("physical_set: got write to SCC\n"); return ; - } - const uint64_t fetch_a = shoe.physical_dat; - - shoe.logical_addr = addr_b; - shoe.logical_size = size_b; - translate_logical_addr(); - if (shoe.abort) + case 0x50006000 ... 0x50007fff: // SCSI (pseudo-DMA with DRQ?) + assert(shoe.physical_size == 4); + scsi_dma_write_long(shoe.physical_dat); return ; - - const uint32_t p_addr_b = shoe.physical_addr; - shoe.physical_size = size_b; - physical_get(); - if (shoe.abort) { - shoe.abort = 0; - throw_long_bus_error(shoe.logical_addr, 0); + case 0x50010000 ... 0x50011fff: // SCSI (normal mode?) + scsi_reg_write(); + return ; + 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"); + return ; + case 0x50016000 ... 0x50017fff: // SWIM (IWM?) + //printf("physical_set: got write to IWM\n"); + iwm_dma_write(); + return ; + default: + //printf("physical_set: got write to UNKNOWN IO ADDR %x\n", shoe.physical_addr); return ; - } - - // printf("multiple_page_get: p_addr_a = 0x%08x, p_addr_b = 0x%08x\n", p_addr_a, p_addr_b); - - shoe.logical_dat = (fetch_a << (size_b*8)) | shoe.physical_dat; - - // printf("multiple_page_get: logical_dat = (%llx | %llx) = %llx\n", fetch_a, shoe.physical_dat, shoe.logical_dat); - - return ; - } - - // Common case: the read is contained entirely within a page - translate_logical_addr(); - if (shoe.abort) - return ; - - shoe.physical_size = shoe.logical_size; - physical_get(); - if (shoe.abort) { - shoe.abort = 0; - throw_long_bus_error(shoe.logical_addr, 0); - return ; } - shoe.logical_dat = shoe.physical_dat; - } -void logical_set (void) +void _physical_set_super_slot (void) { - // If address translation isn't enabled, this is a physical address - if (!tc_enable()) { - shoe.physical_addr = shoe.logical_addr; - shoe.physical_size = shoe.logical_size; - shoe.physical_dat = shoe.logical_dat; - physical_set(); - return ; - } - - const uint32_t logical_size = shoe.logical_size; - const uint32_t logical_addr = shoe.logical_addr; - - const uint16_t ps = tc_ps(); // log2 of the page size - const uint32_t pagesize = 1 << ps; // the page size - const uint32_t pagemask = pagesize-1; // a mask of the page bits - const uint32_t pageoffset = logical_addr & pagemask; - - // Make the translate function fail if the page is write-protected - shoe.logical_is_write = 1; - - // This write crosses a page boundary - if ((pageoffset + logical_size - 1) >> ps) { - const uint32_t addr_a = shoe.logical_addr; - const uint32_t size_b = (pageoffset + logical_size) & pagemask; - const uint32_t size_a = shoe.logical_size - size_b; - const uint32_t addr_b = addr_a + size_a; - const uint64_t data_a = shoe.logical_dat >> (size_b*8); - const uint64_t data_b = bitchop_64(shoe.logical_dat, size_b*8); - - // printf("ps = %u, pagesize=%u, pagemask=%x, pageoffset=%x\n", ps, pagesize, pagemask, pageoffset); - // printf("multiple page set: addr_a=0x%08x size_a=%u addr_b=0x%08x size_b=%u\n", addr_a, size_a, addr_b, size_b); - - shoe.logical_addr = addr_a; - shoe.logical_size = size_a; - translate_logical_addr(); - if (shoe.abort) - return ; - const uint32_t p_addr_a = shoe.physical_addr; - - shoe.logical_addr = addr_b; - shoe.logical_size = size_b; - translate_logical_addr(); - if (shoe.abort) - return ; - const uint32_t p_addr_b = shoe.physical_addr; - - // printf("multiple page set: paddr_a=0x%08x (data_a=0x%llx) paddr_b=0x%08x (data_b=0x%llx) (orig_dat=0x%llx)\n", p_addr_a, data_a, p_addr_b, data_b, shoe.logical_dat); - - shoe.physical_addr = p_addr_a; - shoe.physical_size = size_a; - shoe.physical_dat = data_a; - physical_set(); - - shoe.physical_addr = p_addr_b; - shoe.physical_size = size_b; - shoe.physical_dat = data_b; - physical_set(); - - return ; - } - - // Common case: the write is contained entirely within a page - translate_logical_addr(); - if (shoe.abort) - return ; - - // printf("L(0x%08x) = P(0x%08x)\n", shoe.logical_addr, shoe.physical_addr); - - shoe.physical_size = shoe.logical_size; - shoe.physical_dat = shoe.logical_dat; - physical_set(); - /*if (!((tc_sre() && sr_s()))) - printf("set *0x%08x (phys 0x%08x) = %llx\n", shoe.logical_addr, shoe.physical_addr, shoe.physical_dat); - - if ((shoe.logical_addr >> 24) == 0x3f) - printf("set *0x%08x (phys 0x%08x) = %llx\n", shoe.logical_addr, shoe.physical_addr, shoe.physical_dat); - */ + const uint32_t slot = shoe.physical_addr >> 28; + if (shoe.slots[slot].connected) + shoe.slots[slot].write_func(shoe.physical_addr, + shoe.physical_size, + shoe.physical_dat, + slot); +} + +void _physical_set_standard_slot (void) +{ + const uint32_t slot = (shoe.physical_addr >> 24) & 0xf; + if (shoe.slots[slot].connected) + shoe.slots[slot].write_func(shoe.physical_addr, + shoe.physical_size, + shoe.physical_dat, + slot); } +const physical_set_ptr physical_set_jump_table[16] = { + _physical_set_ram, // 0x0 + _physical_set_ram, // 0x1 + _physical_set_ram, // 0x2 + _physical_set_ram, // 0x3 + _physical_set_rom, // 0x4 + _physical_set_io, // 0x5 + _physical_set_super_slot, // 0x6 + _physical_set_super_slot, // 0x7 + _physical_set_super_slot, // 0x8 + _physical_set_super_slot, // 0x9 + _physical_set_super_slot, // 0xa + _physical_set_super_slot, // 0xb + _physical_set_super_slot, // 0xc + _physical_set_super_slot, // 0xd + _physical_set_super_slot, // 0xe + _physical_set_standard_slot // 0xf +}; + +/* --- PMMU logical address translation --- */ +#pragma mark PMMU logical address translation + #define PMMU_CACHE_CRP 0 #define PMMU_CACHE_SRP 1 @@ -445,12 +285,12 @@ void logical_set (void) uint32_t unused1 : 1; uint32_t unused2 : 8; uint32_t physical_addr : 24; -} pmmu_cache_entry; - -struct { + } pmmu_cache_entry; + + struct { pmmu_cache_entry entry[512]; uint8_t valid_map[512 / 8]; -} pmmu_cache[2];*/ + } pmmu_cache[2];*/ #define write_back_desc() { \ if (desc_addr < 0) { \ @@ -460,43 +300,34 @@ struct { } \ } -static void translate_logical_addr() -{ - const uint8_t use_srp = (tc_sre() && (shoe.logical_fc >= 4)); -/* --- First check for an entry in pmmu_cache --- */ +static _Bool check_pmmu_cache(void) +{ + const _Bool use_srp = (tc_sre() && (shoe.logical_fc >= 4)); // logical addr [is]xxxxxxxxxxxx[ps] -> value xxxxxxxxxxxx const uint32_t value = (shoe.logical_addr << tc_is()) >> (tc_is() + tc_ps()); // value xxx[xxxxxxxxx] -> key xxxxxxxxx - const uint32_t key = value & 511; // low 9 bits + const uint32_t key = value & (PMMU_CACHE_SIZE-1); // low PMMU_CACHE_KEY_BITS bits - // Has this cache entry been set yet? - if ((shoe.pmmu_cache[use_srp].valid_map[key/8] >> (key & 7)) & 1) { - const pmmu_cache_entry_t entry = shoe.pmmu_cache[use_srp].entry[key]; - - // Do the values match? - if (entry.logical_value == value) { - - // Is this a write, but the page isn't marked "modified"? - if (!(shoe.logical_is_write && !entry.modified)) { - - // Is this a write, and the page is write-protected? - if (!(shoe.logical_is_write && entry.wp)) { - const uint32_t ps_mask = 0xffffffff >> entry.used_bits; - const uint32_t v_mask = ~~ps_mask; - shoe.physical_addr = ((entry.physical_addr<<8) & v_mask) + (shoe.logical_addr & ps_mask); - return ; - } - // This should be rare, just let the lookup handle it - } - // The page descriptor needs to be marked "modified" - } - // Values don't match, this is a different address - } + const pmmu_cache_entry_t entry = shoe.pmmu_cache[use_srp].entry[key]; + + const _Bool is_set = (shoe.pmmu_cache[use_srp].valid_map[key/8] >> (key & 7)) & 1; + const _Bool values_match = (entry.logical_value == value); + const _Bool first_modify = !(shoe.logical_is_write && !entry.modified); + const _Bool not_write_protected = !(shoe.logical_is_write && entry.wp); + + const uint32_t ps_mask = 0xffffffff >> entry.used_bits; + const uint32_t v_mask = ~~ps_mask; + + shoe.physical_addr = ((entry.physical_addr<<8) & v_mask) | (shoe.logical_addr & ps_mask); + return is_set && values_match && first_modify && not_write_protected; +} -/* --- pmmu_cache miss, manually traverse the page tables to do the translation */ - + +static void translate_logical_addr() +{ + const uint8_t use_srp = (tc_sre() && (shoe.logical_fc >= 4)); uint64_t *rootp_ptr = (use_srp ? (&shoe.srp) : (&shoe.crp)); const uint64_t rootp = *rootp_ptr; uint8_t desc_did_change = 0; @@ -507,9 +338,9 @@ static void translate_logical_addr() uint64_t desc = rootp; // Initial descriptor is the root pointer descriptor 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 - // we or into the physical addr from the virtual addr) + // (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 + // we or into the physical addr from the virtual addr) desc_addr = -1; // address of the descriptor (-1 -> register) @@ -617,16 +448,16 @@ static void translate_logical_addr() const uint32_t ps_mask = 0xffffffff >> used_bits; const uint32_t v_mask = ~~ps_mask; - const uint32_t paddr = (desc_page_addr(desc) & v_mask) + (shoe.logical_addr & ps_mask); + const uint32_t paddr = (desc_page_addr(desc) & v_mask) | (shoe.logical_addr & ps_mask); shoe.physical_addr = paddr; - /*if (shoe.logical_addr == 0) { - printf("Success! desc = 0x%llx sz=%u bytes\n", desc, 4< value xxxxxxxxxxxx + const uint32_t value = (shoe.logical_addr << tc_is()) >> (tc_is() + tc_ps()); + // value xxx[xxxxxxxxx] -> key xxxxxxxxx + const uint32_t key = value & (PMMU_CACHE_SIZE-1); // low PMMU_CACHE_KEY_BITS bits pmmu_cache_entry_t entry; shoe.pmmu_cache[use_srp].valid_map[key/8] |= (1 << (key & 7)); @@ -637,17 +468,187 @@ static void translate_logical_addr() entry.used_bits = used_bits; shoe.pmmu_cache[use_srp].entry[key] = entry; - // if (debug_predicted) - // assert(debug_predicted == shoe.physical_addr); } +void logical_get (void) +{ + + // If address translation isn't enabled, this is a physical address + if (!tc_enable()) { + shoe.physical_addr = shoe.logical_addr; + shoe.physical_size = shoe.logical_size; + physical_get(); + if (shoe.abort) { + shoe.abort = 0; + throw_long_bus_error(shoe.logical_addr, 0); + return ; + } + shoe.logical_dat = shoe.physical_dat; + return ; + } + + const uint32_t logical_size = shoe.logical_size; + const uint32_t logical_addr = shoe.logical_addr; + + const uint16_t ps = tc_ps(); // log2 of the page size + const uint32_t pagesize = 1 << ps; // the page size + const uint32_t pagemask = pagesize-1; // a mask of the page bits + const uint32_t pageoffset = logical_addr & pagemask; + + shoe.logical_is_write = 0; + + // Common case: the read is contained entirely within a page + if (!((pageoffset + logical_size - 1) >> ps)) { + if (!check_pmmu_cache()) { + translate_logical_addr(); + if (shoe.abort) + return ; + } + + if (shoe.physical_addr < shoe.physical_mem_size) { + // Fast path + shoe.logical_dat = ntohll(*(uint64_t*)&shoe.physical_mem_base[shoe.physical_addr]) >> ((8-logical_size)*8); + } + else { + shoe.physical_size = logical_size; + physical_get(); + if (shoe.abort) { + shoe.abort = 0; + throw_long_bus_error(logical_addr, 0); + return ; + } + shoe.logical_dat = shoe.physical_dat; + } + } + else { // This read crosses a page boundary + const uint32_t addr_a = logical_addr; + const uint32_t size_b = (pageoffset + logical_size) & pagemask; + const uint32_t size_a = logical_size - size_b; + const uint32_t addr_b = addr_a + size_a; + + shoe.logical_addr = addr_a; + shoe.logical_size = size_a; + if (!check_pmmu_cache()) { + translate_logical_addr(); + if (shoe.abort) + return ; + } + + const uint32_t p_addr_a = shoe.physical_addr; + + shoe.logical_addr = addr_b; + shoe.logical_size = size_b; + if (!check_pmmu_cache()) { + translate_logical_addr(); + if (shoe.abort) + return ; + } + + const uint32_t p_addr_b = shoe.physical_addr; + shoe.physical_size = size_b; + physical_get(); + if (shoe.abort) { + shoe.abort = 0; + throw_long_bus_error(shoe.logical_addr, 0); + return ; + } + const uint64_t fetch_b = shoe.physical_dat; + + shoe.physical_addr = p_addr_a; + shoe.physical_size = size_a; + physical_get(); + if (shoe.abort) { + shoe.abort = 0; + throw_long_bus_error(shoe.logical_addr, 0); + return ; + } + + shoe.logical_dat = (shoe.physical_dat << (size_b*8)) | fetch_b; + } +} + +void logical_set (void) +{ + // If address translation isn't enabled, this is a physical address + if (!tc_enable()) { + shoe.physical_addr = shoe.logical_addr; + shoe.physical_size = shoe.logical_size; + shoe.physical_dat = shoe.logical_dat; + physical_set(); + return ; + } + + const uint32_t logical_size = shoe.logical_size; + const uint32_t logical_addr = shoe.logical_addr; + + const uint16_t ps = tc_ps(); // log2 of the page size + const uint32_t pagesize = 1 << ps; // the page size + const uint32_t pagemask = pagesize-1; // a mask of the page bits + const uint32_t pageoffset = logical_addr & pagemask; + + // Make the translate function fail if the page is write-protected + shoe.logical_is_write = 1; + + // Common case: this write is contained entirely in one page + if (!((pageoffset + logical_size - 1) >> ps)) { + // Common case: the write is contained entirely within a page + if (!check_pmmu_cache()) { + translate_logical_addr(); + if (shoe.abort) + return ; + } + + shoe.physical_size = shoe.logical_size; + shoe.physical_dat = shoe.logical_dat; + physical_set(); + } + else { // This write crosses a page boundary + const uint32_t addr_a = shoe.logical_addr; + const uint32_t size_b = (pageoffset + logical_size) & pagemask; + const uint32_t size_a = shoe.logical_size - size_b; + const uint32_t addr_b = addr_a + size_a; + const uint64_t data_a = shoe.logical_dat >> (size_b*8); + const uint64_t data_b = bitchop_64(shoe.logical_dat, size_b*8); + + shoe.logical_addr = addr_a; + shoe.logical_size = size_a; + if (!check_pmmu_cache()) { + translate_logical_addr(); + if (shoe.abort) + return ; + } + const uint32_t p_addr_a = shoe.physical_addr; + + shoe.logical_addr = addr_b; + shoe.logical_size = size_b; + if (!check_pmmu_cache()) { + translate_logical_addr(); + if (shoe.abort) + return ; + } + const uint32_t p_addr_b = shoe.physical_addr; + + shoe.physical_addr = p_addr_a; + shoe.physical_size = size_a; + shoe.physical_dat = data_a; + physical_set(); + + shoe.physical_addr = p_addr_b; + shoe.physical_size = size_b; + shoe.physical_dat = data_b; + physical_set(); + + return ; + } +} + -// -// EA routines begin here: -// +/* --- EA routines --- */ +#pragma mark EA routines #define nextword(pc) ({const uint16_t w=lget((pc),2);if (shoe.abort){return;}(pc)+=2; w;}) +#define nextlong(pc) ({const uint32_t L=lget((pc),4);if (shoe.abort){return;}(pc)+=4; L;}) // ea_decode_extended() - find the EA for those hiddeous 68020 addr modes static void ea_decode_extended() @@ -737,8 +738,7 @@ static void ea_decode_extended() if (z == 2) { // if word-length, fetch nextword() and sign-extend base_disp = (int16_t)(nextword(mypc)); } else { // otherwise, it's a longword - base_disp = nextword(mypc); - base_disp = (base_disp<<16) | nextword(mypc); + base_disp = nextlong(mypc); } } @@ -752,8 +752,7 @@ static void ea_decode_extended() break; case 0b0011: case 0b0111: case 0b1011: { // long word outer displacement - outer_disp = nextword(mypc); - outer_disp = (outer_disp<<16) | nextword(mypc); + outer_disp = nextlong(mypc); break ; } } @@ -830,17 +829,14 @@ void ea_read() return ; } case 5: { // address register indirect with displacement mode - const uint16_t u_disp = nextword(shoe.uncommitted_ea_read_pc); - const int16_t disp = (int16_t)u_disp; // sign-extend word to long + const int16_t disp = nextword(shoe.uncommitted_ea_read_pc); shoe.dat = lget(shoe.a[reg]+disp, shoe.sz); return ; } case 6: { - // printf("ea_read(): %u %u not implemented\n", mode, reg); ea_decode_extended(); if (shoe.abort) return ; shoe.dat = lget(shoe.extended_addr, shoe.sz); - //eaprintf("read(0x%x) = 0x%x\n", shoe.extended_addr, shoe.dat); return ; } case 7: { @@ -851,12 +847,8 @@ void ea_read() return ; } case 1: { // absolute long addressing mode - //printf("ea_read(): %u %u not implemented\n", mode, reg); - uint32_t addr = nextword(shoe.uncommitted_ea_read_pc); - addr = (addr << 16) | nextword(shoe.uncommitted_ea_read_pc); - // printf("addr = 0x%x\n", addr); + const uint32_t addr = nextlong(shoe.uncommitted_ea_read_pc); shoe.dat = lget(addr, shoe.sz); - // printf("ea_write(): %u %u not implemented\n", mode, reg); return ; } case 2: { // program counter indirect with displacement mode @@ -865,7 +857,6 @@ void ea_read() const int16_t disp = (int16_t)u_disp; shoe.dat = lget(base_pc + disp, shoe.sz); - return ; } case 3: { // (program counter ...) @@ -875,21 +866,15 @@ void ea_read() return ; } case 4: { // immediate data - const uint16_t ext = nextword(shoe.uncommitted_ea_read_pc); if (shoe.sz==1) { - shoe.dat = ext & 0xff; + shoe.dat = nextword(shoe.uncommitted_ea_read_pc) & 0xff; } else if (shoe.sz == 2) { - shoe.dat = ext; + shoe.dat = nextword(shoe.uncommitted_ea_read_pc); } else if (shoe.sz == 4) { - const uint16_t ext2 = nextword(shoe.uncommitted_ea_read_pc); - shoe.dat = ((uint32_t)ext)<<16; - shoe.dat |= ext2; + shoe.dat = nextlong(shoe.uncommitted_ea_read_pc); } else if (shoe.sz == 8) { - uint64_t q; - q = (ext << 16) | nextword(shoe.uncommitted_ea_read_pc); - q = (ext << 16) | nextword(shoe.uncommitted_ea_read_pc); - q = (ext << 16) | nextword(shoe.uncommitted_ea_read_pc); - shoe.dat = q; + const uint64_t q = nextlong(shoe.uncommitted_ea_read_pc); + shoe.dat = (q<<32) | nextlong(shoe.uncommitted_ea_read_pc); } return ; } @@ -913,7 +898,6 @@ void ea_read_commit() case 3: { // address register indirect with postincrement mode const uint8_t delta = ((reg==7) && (shoe.sz==1))?2:shoe.sz; shoe.a[reg] += delta; - //printf("ea_read_commit(): %u %u not implemented\n", mode, reg); return ; } case 4: { // address register indirect with predecrement mode @@ -945,8 +929,7 @@ void ea_read_commit() return ; } case 3: { // (program counter ...) - ea_decode_extended(); - if (shoe.abort) return ; + // shoe.extended_len was set in the previous ea_read() call. shoe.pc += shoe.extended_len; return ; } @@ -1019,8 +1002,7 @@ void ea_write() return ; } case 1: { // absolute long addressing mode - uint32_t addr = nextword(shoe.pc); - addr = (addr << 16) | nextword(shoe.pc); + const uint32_t addr = nextlong(shoe.pc); lset(addr, shoe.sz, shoe.dat); // printf("ea_write(): %u %u not implemented\n", mode, reg); return ; @@ -1062,8 +1044,7 @@ void ea_addr() return ; } case 1: { // absolute long addressing mode - uint32_t addr = (nextword(shoe.pc)) << 16; - addr |= (nextword(shoe.pc)); + const uint32_t addr = nextlong(shoe.pc); shoe.dat = addr; return ; } diff --git a/core/scsi.c b/core/scsi.c index 1b40b03..f1f8a3a 100644 --- a/core/scsi.c +++ b/core/scsi.c @@ -150,7 +150,7 @@ typedef struct { uint8_t target_id; // target ID (as an int [0, 7]) // transfer buffers - uint8_t buf[512 * 64]; + uint8_t buf[512 * 256]; uint32_t bufi; uint32_t in_len, in_i; uint32_t out_len, out_i; @@ -412,13 +412,19 @@ static void scsi_buf_set (uint8_t byte) printf("scsi_buf_set: Responding to read at off=%u len=%u\n", offset, len); - assert(len <= 64); + //assert(len <= 64); assert(dev->num_blocks > offset); + if (len == 0) { + switch_status_phase(0); + break; + } + assert(0 == fseeko(dev->f, 512 * offset, SEEK_SET)); assert(fread(scsi.buf, len * 512, 1, dev->f) == 1); + scsi.in_len = len * 512; scsi.in_i = 0; @@ -435,7 +441,7 @@ static void scsi_buf_set (uint8_t byte) printf("scsi_buf_set: Responding to write at off=%u len=%u\n", offset, len); - assert(len <= 64); + //assert(len <= 64); scsi.write_offset = offset; scsi.out_len = len * 512; @@ -466,7 +472,7 @@ void scsi_reg_read () { const uint32_t reg = ((shoe.physical_addr & 0xffff) >> 4) & 0xf; - printf("\nscsi_reg_read: reading from register %s(%u) ", scsi_read_reg_str[reg], reg); + //printf("\nscsi_reg_read: reading from register %s(%u) ", scsi_read_reg_str[reg], reg); switch (reg) { case 0: // Current scsi data bus register @@ -555,7 +561,7 @@ void scsi_reg_read () break; } - printf("(set to 0x%02x)\n\n", (uint32_t)shoe.physical_dat); + //printf("(set to 0x%02x)\n\n", (uint32_t)shoe.physical_dat); } void scsi_reg_write () diff --git a/core/shoebill.h b/core/shoebill.h index 6bede22..9243c49 100644 --- a/core/shoebill.h +++ b/core/shoebill.h @@ -33,6 +33,9 @@ #include //#include +// void ring_print(const char *str); +// extern char *ring_tmp; + #include "coff.h" // -- Global constants -- @@ -59,7 +62,7 @@ #define get_d(n,s) get_reg__(shoe.d[n], s) #define get_a(n,s) get_reg__(shoe.a[n], s) #define set_d(n,val,s) set_reg__(shoe.d[n], val, s) - // #define set_a(n,val,s) set_reg__(shoe.a[n], val, s) // address registers should always be set with sz==4 + // sr masks #define sr_c() (shoe.sr&1) @@ -100,12 +103,13 @@ shoe.sr = newsr & 0xf71f; \ load_stack_pointer(); \ } - + #define set_sr_c(b) {shoe.sr &= (~(1<<0)); shoe.sr |= (((b)!=0)<<0);} #define set_sr_v(b) {shoe.sr &= (~(1<<1)); shoe.sr |= (((b)!=0)<<1);} #define set_sr_z(b) {shoe.sr &= (~(1<<2)); shoe.sr |= (((b)!=0)<<2);} #define set_sr_n(b) {shoe.sr &= (~(1<<3)); shoe.sr |= (((b)!=0)<<3);} #define set_sr_x(b) {shoe.sr &= (~(1<<4)); shoe.sr |= (((b)!=0)<<4);} + #define set_sr_mask(m) {shoe.sr &= (~(7<<8)); shoe.sr |= ((((uint16_t)(m))&7) << 8);} // Be careful when setting these bits #define set_sr_m(b) {make_stack_pointers_valid(); shoe.sr &= (~(1<<12)); shoe.sr |= (((b)!=0)<<12); load_stack_pointer();} #define set_sr_s(b) {make_stack_pointers_valid(); shoe.sr &= (~(1<<13)); shoe.sr |= (((b)!=0)<<13); load_stack_pointer();} @@ -132,7 +136,21 @@ // misc #define ea_n(s) ((shoe.dat>>((s)*8-1))&1) - #define ea_z(s) ((shoe.dat&((0xffffffff)>>(8*(4-(s)))))==0) + #define ea_z(s) (chop(shoe.dat, (s))==0) + +// alloc_pool.c +typedef struct _alloc_pool_t { + struct _alloc_pool_t *prev, *next; + uint32_t size, magic; +} alloc_pool_t; + +void* p_alloc(alloc_pool_t *pool, uint64_t size); +void* p_realloc(void *ptr, uint64_t size); +void p_free(void *ptr); +void p_free_pool(alloc_pool_t *pool); +alloc_pool_t* p_new_pool(void); + + typedef struct dbg_breakpoint_t { struct dbg_breakpoint_t *next; @@ -231,7 +249,6 @@ typedef struct { } iwm_state_t; - typedef struct { uint32_t (*read_func)(uint32_t, uint32_t, uint8_t); void (*write_func)(uint32_t, uint32_t, uint32_t, uint8_t); @@ -270,9 +287,11 @@ typedef struct { pthread_mutex_t cpu_freeze_lock; // -- PMMU caching structures --- +#define PMMU_CACHE_KEY_BITS 10 +#define PMMU_CACHE_SIZE (1<> 28]() +#define pset(addr, s, val) {shoe.physical_addr=(addr); shoe.physical_size=(s); shoe.physical_dat=(val); physical_set();} + +#define physical_get() physical_get_jump_table[shoe.physical_addr >> 28]() #define pget(addr, s) ({shoe.physical_addr=(addr); shoe.physical_size=(s); physical_get(); shoe.physical_dat;}) void logical_get (void); @@ -479,9 +508,6 @@ void logical_get (void); shoe.logical_dat; \ }) -void physical_set (void); -#define pset(addr, s, val) {shoe.physical_addr=(addr); shoe.physical_size=(s); shoe.physical_dat=(val); physical_set();} - void logical_set (void); #define lset_fc(addr, s, val, fc) {\ shoe.logical_addr=(addr); \ diff --git a/core/via.c b/core/via.c index 44ceed3..e8cd979 100644 --- a/core/via.c +++ b/core/via.c @@ -99,10 +99,10 @@ void process_pending_interrupt () // If the CPU was stopped, unstop it shoe.cpu_thread_notifications &= ~~SHOEBILL_STATE_STOPPED; - printf("Interrupt pri %u! mask=%u\n", priority, sr_mask()); - const uint16_t vector_offset = (priority + 24) * 4; + printf("Interrupt pri %u! mask=%u vector_offset=0x%08x\n", priority, sr_mask(), vector_offset); + // Save the old SR, and switch to supervisor mode const uint16_t old_sr = shoe.sr; set_sr_s(1); @@ -119,7 +119,6 @@ void process_pending_interrupt () push_a7(old_sr, 2); printf("interrupt: pushed sr 0x%04x to 0x%08x\n", old_sr, shoe.a[7]); assert(!shoe.abort); - if (sr_m()) { // clear sr_m, and write a format 1 exception to the ISP @@ -137,8 +136,18 @@ void process_pending_interrupt () assert(!shoe.abort); } + /* + * "When processing an interrupt exception, the MC68020/EC020 first makes an internal copy of the SR, + * sets the privilege level to supervisor, suppresses tracing, and sets the processor interrupt mask + * level to the level of the interrupt being serviced." + */ + set_sr_mask(priority); + set_sr_t0(0); + set_sr_t1(0); + // Fetch the autovector handler address const uint32_t newpc = lget(shoe.vbr + vector_offset, 4); + printf("autovector handler = *0x%08x = 0x%08x\n", shoe.vbr + vector_offset, newpc); assert(!shoe.abort); shoe.pc = newpc; diff --git a/web/0.0.2_prefs_general.png b/web/0.0.2_prefs_general.png new file mode 100644 index 0000000..4618678 Binary files /dev/null and b/web/0.0.2_prefs_general.png differ