From 93cefd94519abd7022a2d04f233ee0f3b26b9ad6 Mon Sep 17 00:00:00 2001 From: Peter Rutenbar Date: Mon, 24 Feb 2014 17:14:52 -0500 Subject: [PATCH] First big barely-functional code drop --- .gitignore | 5 + LICENSE | 26 +- Makefile | 16 + README | 42 + core/Makefile | 58 + core/adb.c | 393 ++ core/atrap_tab.c | 4102 +++++++++++++++++ core/coff.c | 329 ++ core/coff.h | 84 + core/core_api.c | 908 ++++ core/core_api.h | 129 + core/cpu.c | 3019 ++++++++++++ core/debugger.c | 1240 +++++ core/decoder_gen.c | 1484 ++++++ core/dis.c | 1478 ++++++ core/exception.c | 251 + core/floppy.c | 130 + core/fpu.c | 1484 ++++++ core/macii_symbols.c | 1520 ++++++ core/macro.pl | 562 +++ core/mc68851.c | 446 ++ core/mc68851.h | 64 + core/mem.c | 1172 +++++ core/redblack.c | 267 ++ core/redblack.h | 50 + core/scsi.c | 763 +++ core/shoebill.h | 634 +++ core/toby_frame_buffer.c | 321 ++ core/via.c | 441 ++ core/video.c | 331 ++ core/video_rom/rom.bin | Bin 0 -> 4096 bytes core/video_rom/rom.c | 513 +++ core/video_rom/rom_to_c.c | 33 + core/video_rom/shoebill_video.make | 1 + core/video_rom/shoebill_video_driver.a | 1 + core/video_rom/shoebill_video_primary_init.a | 1 + core/video_rom/shoebill_video_rom.a | 1 + gui/Shoebill.xcodeproj/project.pbxproj | 381 ++ gui/Shoebill/Base.lproj/MainMenu.xib | 188 + .../AppIcon.appiconset/Contents.json | 58 + gui/Shoebill/Shoebill-Info.plist | 34 + gui/Shoebill/Shoebill-Prefix.pch | 9 + gui/Shoebill/en.lproj/Credits.rtf | 29 + gui/Shoebill/en.lproj/InfoPlist.strings | 2 + gui/Shoebill/main.m | 6 + gui/Shoebill/shoeAppDelegate.h | 36 + gui/Shoebill/shoeAppDelegate.m | 40 + gui/Shoebill/shoeApplication.h | 42 + gui/Shoebill/shoeApplication.m | 317 ++ .../shoePreferencesWindowController.h | 42 + .../shoePreferencesWindowController.m | 190 + .../shoePreferencesWindowController.xib | 438 ++ gui/Shoebill/shoeScreenView.h | 41 + gui/Shoebill/shoeScreenView.m | 291 ++ gui/Shoebill/shoeScreenView.xib | 26 + gui/Shoebill/shoeScreenWindow.h | 36 + gui/Shoebill/shoeScreenWindow.m | 83 + test.c | 407 ++ 58 files changed, 24982 insertions(+), 13 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README create mode 100644 core/Makefile create mode 100644 core/adb.c create mode 100644 core/atrap_tab.c create mode 100644 core/coff.c create mode 100644 core/coff.h create mode 100644 core/core_api.c create mode 100644 core/core_api.h create mode 100644 core/cpu.c create mode 100644 core/debugger.c create mode 100644 core/decoder_gen.c create mode 100644 core/dis.c create mode 100644 core/exception.c create mode 100644 core/floppy.c create mode 100644 core/fpu.c create mode 100644 core/macii_symbols.c create mode 100755 core/macro.pl create mode 100644 core/mc68851.c create mode 100644 core/mc68851.h create mode 100644 core/mem.c create mode 100644 core/redblack.c create mode 100644 core/redblack.h create mode 100644 core/scsi.c create mode 100644 core/shoebill.h create mode 100644 core/toby_frame_buffer.c create mode 100644 core/via.c create mode 100644 core/video.c create mode 100644 core/video_rom/rom.bin create mode 100644 core/video_rom/rom.c create mode 100644 core/video_rom/rom_to_c.c create mode 100644 core/video_rom/shoebill_video.make create mode 100644 core/video_rom/shoebill_video_driver.a create mode 100644 core/video_rom/shoebill_video_primary_init.a create mode 100644 core/video_rom/shoebill_video_rom.a create mode 100644 gui/Shoebill.xcodeproj/project.pbxproj create mode 100644 gui/Shoebill/Base.lproj/MainMenu.xib create mode 100644 gui/Shoebill/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 gui/Shoebill/Shoebill-Info.plist create mode 100644 gui/Shoebill/Shoebill-Prefix.pch create mode 100644 gui/Shoebill/en.lproj/Credits.rtf create mode 100644 gui/Shoebill/en.lproj/InfoPlist.strings create mode 100644 gui/Shoebill/main.m create mode 100644 gui/Shoebill/shoeAppDelegate.h create mode 100644 gui/Shoebill/shoeAppDelegate.m create mode 100644 gui/Shoebill/shoeApplication.h create mode 100644 gui/Shoebill/shoeApplication.m create mode 100644 gui/Shoebill/shoePreferencesWindowController.h create mode 100644 gui/Shoebill/shoePreferencesWindowController.m create mode 100644 gui/Shoebill/shoePreferencesWindowController.xib create mode 100644 gui/Shoebill/shoeScreenView.h create mode 100644 gui/Shoebill/shoeScreenView.m create mode 100644 gui/Shoebill/shoeScreenView.xib create mode 100644 gui/Shoebill/shoeScreenWindow.h create mode 100644 gui/Shoebill/shoeScreenWindow.m create mode 100644 test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae42782 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/intermediates +/shoebill +.DS_Store +*.xcworkspace +xcuserdata diff --git a/LICENSE b/LICENSE index be1bc02..63805f2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,23 +1,23 @@ -Copyright (c) 2014, pruten +Copyright (c) 2013, 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: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* 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. +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 HOLDER OR CONTRIBUTORS BE LIABLE FOR +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 + 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. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..35f1e8f --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ + +CC = clang +CFLAGS = -O4 -arch x86_64 -Wno-deprecated-declarations +LFLAGS = -framework OpenGL -framework GLUT + +all: shoebill + +shoebill: make_core test.c + $(CC) $(LFLAGS) $(CFLAGS) -L intermediates -l shoebill_core test.c -o shoebill + +make_core: + $(MAKE) -C core -j 4 + +clean: + rm -rf intermediates + rm -f shoebill diff --git a/README b/README new file mode 100644 index 0000000..a365fbc --- /dev/null +++ b/README @@ -0,0 +1,42 @@ + +Shoebill - a Macintosh II emulator that can only run A/UX + + +See the wiki on https://code.google.com/p/shoebill for better +documentation on building and running Shoebill. + +*** RUNNING *** + +You will need +* OS X and a 64-bit Intel Macintosh + (32-bit builds may be possible in the future) +* A Macintosh II or IIx ROM +* A disk image with A/UX 1.x.x or 2.x.x installed +* 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 +* Backup your disk images!! + When Shoebill inevitably crashes, your A/UX boot image + 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). + * Do use SCSI ID #0 for your A/UX boot image. + * Give A/UX a reasonable amount of RAM - say, 32MB + * Press “Apply and Run” + + +*** BUILDING *** + +1) cd to shoebill/ +2) make # to build shoebill_core +3) xcodebuild -project gui/Shoebill.xcodeproj # to build the Cocoa GUI + + + + + + diff --git a/core/Makefile b/core/Makefile new file mode 100644 index 0000000..83f3596 --- /dev/null +++ b/core/Makefile @@ -0,0 +1,58 @@ + +CC = clang +CFLAGS = -O4 -ggdb -arch x86_64 -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 + +OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING)) +OBJ_NEED_PREPROCESSING = $(patsubst %,$(TEMP)/%.o,$(NEED_PREPROCESSING)) +OBJ_NEED_DECODER = $(patsubst %,$(TEMP)/%.o,$(NEED_DECODER)) + +# Files that NEED_DECODER also NEED_PREPROCESSING +POST_PREPROCESSING = $(patsubst %,$(TEMP)/%.post.c,$(NEED_PREPROCESSING)) $(patsubst %,$(TEMP)/%.post.c,$(NEED_DECODER)) + +MACRO = perl macro.pl + +TEMP = ../intermediates + + +all: $(TEMP)/libshoebill_core.a + +$(TEMP)/libshoebill_core.a: $(TEMP) $(DEPS) $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER) + libtool -static -o $(TEMP)/libshoebill_core.a $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER) + +# Build object files +$(OBJ_NEED_NOTHING): $(TEMP)/%.o: %.c $(DEPS) + $(CC) -c $(CFLAGS) $< -o $@ + +$(OBJ_NEED_PREPROCESSING): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS) + $(CC) -c $(CFLAGS) $< -o $@ + +$(OBJ_NEED_DECODER): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS) $(TEMP)/dis_decoder_guts.c $(TEMP)/inst_decoder_guts.c + $(CC) -c $(CFLAGS) $< -o $@ + +# Preprocess C files +$(POST_PREPROCESSING): $(TEMP)/%.post.c: %.c $(DEPS) + $(MACRO) $< $@ + +# Generate instruction decoders +$(TEMP)/inst_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS) + $(TEMP)/decoder_gen inst $(TEMP)/ +$(TEMP)/dis_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS) + $(TEMP)/decoder_gen dis $(TEMP)/ + +# Compile the decoder generator +$(TEMP)/decoder_gen: decoder_gen.c $(DEPS) + $(CC) $(CFLAGS) decoder_gen.c -o $(TEMP)/decoder_gen + + +$(TEMP): + mkdir -p $(TEMP) + +clean: + rm -rf $(TEMP) + diff --git a/core/adb.c b/core/adb.c new file mode 100644 index 0000000..0bfbf1e --- /dev/null +++ b/core/adb.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2013, 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" +#include + +// via1 ORB bits abcd efgh +// cd -> adb FSM state +// e -> adb timeout occurred / service request (?) +// f/g/h nvram stuff + +#define VIA_REGB_ADB_STATUS 8 + +/* + Reset: + + -> OS writes reset command to sr, sets state 0 + <- chip sets ADB status line, raises interrupt + -> OS dummy-reads sr, sets state 2 + <- chip sets ADB status line, raises interrupt + -> OS dummy-reads sr, sets state 3 + + + Talk: + -> OS writes talk command to sr, sets state 0 + <- chip responds with an interrupt. Status=0 -> poll(unsolicited?), status=1 -> response? + -> OS sets state=1 + <- chip responds with an interrupt. Status=0 -> timeout, status=1 -> not-timedout? + -> OS reads first byte from sr, sets state=2 + <- chip responds with interrupt. Status=0 -> service request, service=1 no-service-reques + -> OS reads second byte from sr, sets state=3 + + + Listen: + -> OS writes listen command to sr, sets state 0 + <- chip + ??? + + Keyboard: + -> OS sends EXISTS (TALK) for id 2, reg 3 + <- (if no keyboard: timeout. If keyboard: respond with some data) + + -> OS sends FLUSH + <- Keyboard responds + + -> OS sends LISTEN for id 2, reg 3 (data: 0x2201 - sets the service request enable bit) + <- Keyboard respnods + + -> OS sends TALK for id 2 reg 2 + <- Keyboard responds with some keyboard setup data + + -> OS sends TALK for id 2 reg 0 + <- if there's a key, keyboard returns key data. Otherwise, response times out. + +*/ + +void adb_start_service_request() +{ + 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; + + shoe.adb.poll = shoe.adb.pending_poll; + shoe.adb.pending_poll = 0; + + via_raise_interrupt(1, IFR_SHIFT_REG); + } +} + +void adb_request_service_request(uint8_t id) +{ + shoe.adb.pending_service_requests |= (1 << id); + shoe.adb.pending_poll = 1; + + if (shoe.adb.state == 3) { + adb_start_service_request(); + } +} + +static void keyboard_talk(uint8_t reg) +{ + shoe.adb.timeout = 0; + + switch (reg) { + case 0: + if (shoe.key.key_i > 0) { + shoe.adb.data[0] = shoe.key.keys[0].code_b; + shoe.adb.data[1] = shoe.key.keys[0].code_a; + shoe.adb.data_len = 2; + shoe.key.key_i--; + memmove(&shoe.key.keys[0], &shoe.key.keys[1], shoe.key.key_i * sizeof(shoe.key.keys[0])); + } + else + shoe.adb.timeout = 1; + + return ; + + case 2: + // All the modifier keys are up + shoe.adb.data[0] = 0b01111111; + shoe.adb.data[1] = 0b11100111; + shoe.adb.data_len = 2; + return ; + + case 1: + shoe.adb.timeout = 1; + return ; + + case 3: + shoe.adb.data[0] = 0; + shoe.adb.data[1] = 0; + shoe.adb.data_len = 2; + return ; + } +} + +static void mouse_talk(uint8_t reg) +{ + shoe.adb.timeout = 0; + + printf("mouse_talk: reg=%u\n", reg); + switch (reg) { + + case 0: + if (shoe.mouse.changed) { + + printf("mouse_talk: x=%d, y=%d button=%u\n", shoe.mouse.delta_x, shoe.mouse.delta_y, shoe.mouse.button_down); + + shoe.adb.data[1] = shoe.mouse.delta_x & 0x7f; + shoe.adb.data[0] = shoe.mouse.delta_y & 0x7f; + if (!shoe.mouse.button_down) { + //shoe.adb.data[1] |= 0x80; + shoe.adb.data[0] |= 0x80; + } + // printf("mouse_talk: ") + + + shoe.adb.data_len = 2; + + shoe.mouse.delta_x = 0; + shoe.mouse.delta_y = 0; + // shoe.mouse.button_down = 0; + shoe.mouse.changed = 0; + } + else + shoe.adb.timeout = 1; + + return ; + + case 1: + assert(!"Can't handle reg 1"); + + case 2: + assert(!"Can't handle reg 2"); + + case 3: + shoe.adb.data[0] = 3; // device address: 3 + shoe.adb.data[1] = 1; // handler ID: 1 + shoe.adb.data_len = 2; + return ; + + } +} + +static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Command" state +{ + via_state_t *via = &shoe.via[0]; + const uint8_t id = command_byte >> 4; // the target device ID + const uint8_t reg = command_byte & 3; + + // Figure out the command type (reset/flush/talk/listen) + + if ((command_byte & 0xf) == 0) // reset + shoe.adb.command_type = adb_reset; + else if ((command_byte & 0xf) == 1) // flush + shoe.adb.command_type = adb_flush; + else if (~bmatch(command_byte, xxxx 11 xx)) // talk + shoe.adb.command_type = adb_talk; + else if (~bmatch(command_byte, xxxx 10 xx)) // listen + shoe.adb.command_type = adb_listen; + else + assert(!"What is this adb state-0 command? xxxx 01xx"); + + printf("adb_handle_state_zero: command_byte=0x%02x, id=%u, reg=%u\n", command_byte, id, reg); + + shoe.adb.command_device_id = id; + shoe.adb.command_reg = reg; + + // Flush/reset/listen and talk-with-timeout need data_i initialized to 0 + shoe.adb.data_i = 0; + shoe.adb.data_len = 0; + + // If talk, go ask they keyboard/mouse if they have anything to say + if (shoe.adb.command_type == adb_talk) { + + if (id == 2) { + keyboard_talk(reg); + } + else if (id == 3) { + mouse_talk(reg); + } + else { // timeout + shoe.adb.timeout = 1; + } + + // If there was a service request pending for this device, it is now handled. + shoe.adb.pending_service_requests &= ~~(1 << id); + } + + shoe.adb.poll = 0; + + via->regb |= VIA_REGB_ADB_STATUS; + via_raise_interrupt(1, IFR_SHIFT_REG); +} + +static void adb_handle_state_one (void) // "Even" state +{ + via_state_t *via = &shoe.via[0]; + + printf("adb_handle_state_one: "); + if (shoe.adb.poll) { + // Upon receiving a service request, the adb controller sends a TALK/reg=0 to the last accessed device + adb_handle_state_zero((shoe.adb.command_device_id << 4) | 0x0c, 1); + } + + switch (shoe.adb.command_type) { + case adb_flush: + case adb_reset: + assert(!"adb_handle_state_one: unexpected command type"); + break; + + case adb_talk: + printf("adb_talk: "); + if (shoe.adb.timeout) { + shoe.adb.timeout = 0; + via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout + via_raise_interrupt(1, IFR_SHIFT_REG); + printf("timeout\n"); + return ; + } + + if (shoe.adb.data_i < shoe.adb.data_len) + via->sr = shoe.adb.data[shoe.adb.data_i++]; + else + via->sr = 0; + + printf("set sr = 0x%02x\n", via->sr); + + break; + + case adb_listen: + printf("adb_listen: "); + if (shoe.adb.timeout) { + shoe.adb.timeout = 0; + via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout + via_raise_interrupt(1, IFR_SHIFT_REG); + printf("timeout\n"); + return ; + } + + if (shoe.adb.data_i < 8) + shoe.adb.data[shoe.adb.data_i++] = via->sr; + else + assert(!"OS made us listen to > 8 bytes"); + + printf("loaded sr = 0x%02x\n", via->sr); + + break; + } + + via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout + via_raise_interrupt(1, IFR_SHIFT_REG); +} + +static void adb_handle_state_two (void) // "Odd" state +{ + via_state_t *via = &shoe.via[0]; + + printf("adb_handle_state_two: "); + + // 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 + printf("(service request) "); + } + else + via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request + + switch (shoe.adb.command_type) { + case adb_flush: + case adb_reset: + printf("adb_flush/reset\n"); + break; + + case adb_talk: + printf("adb_talk: "); + if (shoe.adb.data_i < shoe.adb.data_len) + via->sr = shoe.adb.data[shoe.adb.data_i++]; + else + via->sr = 0; + printf("set sr = 0x%02x\n", via->sr); + break; + + case adb_listen: + printf("adb_listen: "); + if (shoe.adb.data_i < 8) + shoe.adb.data[shoe.adb.data_i++] = via->sr; + else + assert(!"OS made us listen to > 8 bytes"); + printf("read sr = 0x%02x\n", via->sr); + break; + } + + via_raise_interrupt(1, IFR_SHIFT_REG); +} + +static void adb_handle_state_three (void) // "idle" state +{ + printf("adb_handle_state_three: completed for id %u\n", shoe.adb.command_device_id); + + switch (shoe.adb.command_type) { + case adb_reset: + case adb_flush: + case adb_talk: + break; + + case adb_listen: + printf("adb_handle_state_three: listen completed for id %u, reg %u, data_len = %u {%02x %02x}\n", + shoe.adb.command_device_id, shoe.adb.command_reg, shoe.adb.data_i, shoe.adb.data[0], shoe.adb.data[1]); + break; + } + + adb_start_service_request(); +} + +void adb_handle_state_change(uint8_t old_state, uint8_t new_state) +{ + via_state_t *via = &shoe.via[0]; + + printf("%s: lock\n", __func__); fflush(stdout); + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + shoe.adb.state = new_state; + + switch (new_state) { + case 0: + shoe.adb.command_byte = via->sr; + adb_handle_state_zero(shoe.adb.command_byte, 0); + break ; + + case 1: + adb_handle_state_one(); + break ; + + case 2: + adb_handle_state_two(); + break ; + + case 3: + adb_handle_state_three(); + break ; + } + + printf("%s: unlock\n", __func__); fflush(stdout); + pthread_mutex_unlock(&shoe.adb.lock); +} + diff --git a/core/atrap_tab.c b/core/atrap_tab.c new file mode 100644 index 0000000..2ff3b86 --- /dev/null +++ b/core/atrap_tab.c @@ -0,0 +1,4102 @@ +#include + +/* Ganked from Traps.h in MPW 3.2.3. */ + +const char *atrap_names[4096] = { +/* a000 */ "_Open", +/* a001 */ "_Close", +/* a002 */ "_Read", +/* a003 */ "_Write", +/* a004 */ "_Control", +/* a005 */ "_Status", +/* a006 */ "_KillIO", +/* a007 */ "_GetVolInfo", +/* a008 */ "_Create", +/* a009 */ "_Delete", +/* a00a */ "_OpenRF", +/* a00b */ "_Rename", +/* a00c */ "_GetFileInfo", +/* a00d */ "_SetFileInfo", +/* a00e */ "_UnmountVol", +/* a00f */ "_MountVol", +/* a010 */ "_Allocate", +/* a011 */ "_GetEOF", +/* a012 */ "_SetEOF", +/* a013 */ "_FlushVol", +/* a014 */ "_GetVol", +/* a015 */ "_SetVol", +/* a016 */ "_FInitQueue", +/* a017 */ "_Eject", +/* a018 */ "_GetFPos", +/* a019 */ "_InitZone", +/* a01a */ NULL, +/* a01b */ "_SetZone", +/* a01c */ "_FreeMem", +/* a01d */ NULL, +/* a01e */ NULL, +/* a01f */ "_DisposePtr", +/* a020 */ "_SetPtrSize", +/* a021 */ "_GetPtrSize", +/* a022 */ NULL, +/* a023 */ "_DisposeHandle", +/* a024 */ "_SetHandleSize", +/* a025 */ "_GetHandleSize", +/* a026 */ NULL, +/* a027 */ "_ReallocHandle", +/* a028 */ NULL, +/* a029 */ "_HLock", +/* a02a */ "_HUnlock", +/* a02b */ "_EmptyHandle", +/* a02c */ "_InitApplZone", +/* a02d */ "_SetApplLimit", +/* a02e */ "_BlockMove", +/* a02f */ "_PostEvent", +/* a030 */ "_OSEventAvail", +/* a031 */ "_GetOSEvent", +/* a032 */ "_FlushEvents", +/* a033 */ "_VInstall", +/* a034 */ "_VRemove", +/* a035 */ "_OffLine", +/* a036 */ "_MoreMasters", +/* a037 */ NULL, +/* a038 */ "_WriteParam", +/* a039 */ "_ReadDateTime", +/* a03a */ "_SetDateTime", +/* a03b */ "_Delay", +/* a03c */ "_CmpString", +/* a03d */ "_DrvrInstall", +/* a03e */ "_DrvrRemove", +/* a03f */ "_InitUtil", +/* a040 */ "_ResrvMem", +/* a041 */ "_SetFilLock", +/* a042 */ "_RstFilLock", +/* a043 */ "_SetFilType", +/* a044 */ "_SetFPos", +/* a045 */ "_FlushFile", +/* a046 */ NULL, +/* a047 */ "_SetTrapAddress", +/* a048 */ NULL, +/* a049 */ "_HPurge", +/* a04a */ "_HNoPurge", +/* a04b */ "_SetGrowZone", +/* a04c */ "_CompactMem", +/* a04d */ "_PurgeMem", +/* a04e */ "_AddDrive", +/* a04f */ "_RDrvrInstall", +/* a050 */ "_RelString", +/* a051 */ "_ReadXPRam", +/* a052 */ "_WriteXPRam", +/* a053 */ NULL, +/* a054 */ "_UprString", +/* a055 */ "_StripAddress", +/* a056 */ "_LowerText", +/* a057 */ "_SetAppBase", +/* a058 */ "_InsTime", +/* a059 */ "_RmvTime", +/* a05a */ "_PrimeTime", +/* a05b */ "_PowerOff", +/* a05c */ "_MemoryDispatch", +/* a05d */ "_SwapMMUMode", +/* a05e */ "_NMInstall", +/* a05f */ "_NMRemove", +/* a060 */ "_FSDispatch", +/* a061 */ "_MaxBlock", +/* a062 */ NULL, +/* a063 */ "_MaxApplZone", +/* a064 */ "_MoveHHi", +/* a065 */ "_StackSpace", +/* a066 */ NULL, +/* a067 */ "_HSetRBit", +/* a068 */ "_HClrRBit", +/* a069 */ "_HGetState", +/* a06a */ "_HSetState", +/* a06b */ NULL, +/* a06c */ "_InitFS", +/* a06d */ "_InitEvents", +/* a06e */ "_SlotManager", +/* a06f */ "_SlotVInstall", +/* a070 */ "_SlotVRemove", +/* a071 */ "_AttachVBL", +/* a072 */ "_DoVBLTask", +/* a073 */ NULL, +/* a074 */ NULL, +/* a075 */ "_SIntInstall", +/* a076 */ "_SIntRemove", +/* a077 */ "_CountADBs", +/* a078 */ "_GetIndADB", +/* a079 */ "_GetADBInfo", +/* a07a */ "_SetADBInfo", +/* a07b */ "_ADBReInit", +/* a07c */ "_ADBOp", +/* a07d */ "_GetDefaultStartup", +/* a07e */ "_SetDefaultStartup", +/* a07f */ "_InternalWait", +/* a080 */ "_GetVideoDefault", +/* a081 */ "_SetVideoDefault", +/* a082 */ "_DTInstall", +/* a083 */ "_SetOSDefault", +/* a084 */ "_GetOSDefault", +/* a085 */ "_PMgrOp", +/* a086 */ "_IOPInfoAccess", +/* a087 */ "_IOPMsgRequest", +/* a088 */ "_IOPMoveData", +/* a089 */ NULL, +/* a08a */ "_Sleep", +/* a08b */ "_CommToolboxDispatch", +/* a08c */ NULL, +/* a08d */ "_DebugUtil", +/* a08e */ NULL, +/* a08f */ "_DeferUserFn", +/* a090 */ "_SysEnvirons", +/* a091 */ "_Translate24To32", +/* a092 */ "_EgretDispatch", +/* a093 */ NULL, +/* a094 */ NULL, +/* a095 */ NULL, +/* a096 */ NULL, +/* a097 */ NULL, +/* a098 */ NULL, +/* a099 */ NULL, +/* a09a */ NULL, +/* a09b */ NULL, +/* a09c */ NULL, +/* a09d */ NULL, +/* a09e */ NULL, +/* a09f */ NULL, +/* a0a0 */ NULL, +/* a0a1 */ NULL, +/* a0a2 */ NULL, +/* a0a3 */ NULL, +/* a0a4 */ NULL, +/* a0a5 */ NULL, +/* a0a6 */ NULL, +/* a0a7 */ NULL, +/* a0a8 */ NULL, +/* a0a9 */ NULL, +/* a0aa */ NULL, +/* a0ab */ NULL, +/* a0ac */ NULL, +/* a0ad */ NULL, +/* a0ae */ NULL, +/* a0af */ NULL, +/* a0b0 */ NULL, +/* a0b1 */ NULL, +/* a0b2 */ NULL, +/* a0b3 */ NULL, +/* a0b4 */ NULL, +/* a0b5 */ NULL, +/* a0b6 */ NULL, +/* a0b7 */ NULL, +/* a0b8 */ NULL, +/* a0b9 */ NULL, +/* a0ba */ NULL, +/* a0bb */ NULL, +/* a0bc */ NULL, +/* a0bd */ NULL, +/* a0be */ NULL, +/* a0bf */ NULL, +/* a0c0 */ NULL, +/* a0c1 */ NULL, +/* a0c2 */ NULL, +/* a0c3 */ NULL, +/* a0c4 */ NULL, +/* a0c5 */ NULL, +/* a0c6 */ NULL, +/* a0c7 */ NULL, +/* a0c8 */ NULL, +/* a0c9 */ NULL, +/* a0ca */ NULL, +/* a0cb */ NULL, +/* a0cc */ NULL, +/* a0cd */ NULL, +/* a0ce */ NULL, +/* a0cf */ NULL, +/* a0d0 */ NULL, +/* a0d1 */ NULL, +/* a0d2 */ NULL, +/* a0d3 */ NULL, +/* a0d4 */ NULL, +/* a0d5 */ NULL, +/* a0d6 */ NULL, +/* a0d7 */ NULL, +/* a0d8 */ NULL, +/* a0d9 */ NULL, +/* a0da */ NULL, +/* a0db */ NULL, +/* a0dc */ NULL, +/* a0dd */ "_PPC", +/* a0de */ NULL, +/* a0df */ NULL, +/* a0e0 */ NULL, +/* a0e1 */ NULL, +/* a0e2 */ NULL, +/* a0e3 */ NULL, +/* a0e4 */ NULL, +/* a0e5 */ NULL, +/* a0e6 */ NULL, +/* a0e7 */ NULL, +/* a0e8 */ NULL, +/* a0e9 */ NULL, +/* a0ea */ NULL, +/* a0eb */ NULL, +/* a0ec */ NULL, +/* a0ed */ NULL, +/* a0ee */ NULL, +/* a0ef */ NULL, +/* a0f0 */ NULL, +/* a0f1 */ NULL, +/* a0f2 */ NULL, +/* a0f3 */ NULL, +/* a0f4 */ NULL, +/* a0f5 */ NULL, +/* a0f6 */ NULL, +/* a0f7 */ NULL, +/* a0f8 */ NULL, +/* a0f9 */ NULL, +/* a0fa */ NULL, +/* a0fb */ NULL, +/* a0fc */ NULL, +/* a0fd */ NULL, +/* a0fe */ NULL, +/* a0ff */ NULL, +/* a100 */ NULL, +/* a101 */ NULL, +/* a102 */ NULL, +/* a103 */ NULL, +/* a104 */ NULL, +/* a105 */ NULL, +/* a106 */ NULL, +/* a107 */ NULL, +/* a108 */ NULL, +/* a109 */ NULL, +/* a10a */ NULL, +/* a10b */ NULL, +/* a10c */ NULL, +/* a10d */ NULL, +/* a10e */ NULL, +/* a10f */ NULL, +/* a110 */ NULL, +/* a111 */ NULL, +/* a112 */ NULL, +/* a113 */ NULL, +/* a114 */ NULL, +/* a115 */ NULL, +/* a116 */ NULL, +/* a117 */ NULL, +/* a118 */ NULL, +/* a119 */ NULL, +/* a11a */ "_GetZone", +/* a11b */ NULL, +/* a11c */ NULL, +/* a11d */ "_MaxMem", +/* a11e */ "_NewPtr", +/* a11f */ NULL, +/* a120 */ NULL, +/* a121 */ NULL, +/* a122 */ "_NewHandle", +/* a123 */ NULL, +/* a124 */ NULL, +/* a125 */ NULL, +/* a126 */ "_HandleZone", +/* a127 */ NULL, +/* a128 */ "_RecoverHandle", +/* a129 */ NULL, +/* a12a */ NULL, +/* a12b */ NULL, +/* a12c */ NULL, +/* a12d */ NULL, +/* a12e */ NULL, +/* a12f */ "_PPostEvent", +/* a130 */ NULL, +/* a131 */ NULL, +/* a132 */ NULL, +/* a133 */ NULL, +/* a134 */ NULL, +/* a135 */ NULL, +/* a136 */ NULL, +/* a137 */ NULL, +/* a138 */ NULL, +/* a139 */ NULL, +/* a13a */ NULL, +/* a13b */ NULL, +/* a13c */ NULL, +/* a13d */ NULL, +/* a13e */ NULL, +/* a13f */ NULL, +/* a140 */ NULL, +/* a141 */ NULL, +/* a142 */ NULL, +/* a143 */ NULL, +/* a144 */ NULL, +/* a145 */ NULL, +/* a146 */ "_GetTrapAddress", +/* a147 */ NULL, +/* a148 */ "_PtrZone", +/* a149 */ NULL, +/* a14a */ NULL, +/* a14b */ NULL, +/* a14c */ NULL, +/* a14d */ NULL, +/* a14e */ NULL, +/* a14f */ NULL, +/* a150 */ NULL, +/* a151 */ NULL, +/* a152 */ NULL, +/* a153 */ NULL, +/* a154 */ NULL, +/* a155 */ NULL, +/* a156 */ NULL, +/* a157 */ NULL, +/* a158 */ NULL, +/* a159 */ NULL, +/* a15a */ NULL, +/* a15b */ NULL, +/* a15c */ "_MemoryDispatchA0Result", +/* a15d */ NULL, +/* a15e */ NULL, +/* a15f */ NULL, +/* a160 */ NULL, +/* a161 */ NULL, +/* a162 */ "_PurgeSpace", +/* a163 */ NULL, +/* a164 */ NULL, +/* a165 */ NULL, +/* a166 */ "_NewEmptyHandle", +/* a167 */ NULL, +/* a168 */ NULL, +/* a169 */ NULL, +/* a16a */ NULL, +/* a16b */ NULL, +/* a16c */ NULL, +/* a16d */ NULL, +/* a16e */ NULL, +/* a16f */ NULL, +/* a170 */ NULL, +/* a171 */ NULL, +/* a172 */ NULL, +/* a173 */ NULL, +/* a174 */ NULL, +/* a175 */ NULL, +/* a176 */ NULL, +/* a177 */ NULL, +/* a178 */ NULL, +/* a179 */ NULL, +/* a17a */ NULL, +/* a17b */ NULL, +/* a17c */ NULL, +/* a17d */ NULL, +/* a17e */ NULL, +/* a17f */ NULL, +/* a180 */ NULL, +/* a181 */ NULL, +/* a182 */ NULL, +/* a183 */ NULL, +/* a184 */ NULL, +/* a185 */ NULL, +/* a186 */ NULL, +/* a187 */ NULL, +/* a188 */ NULL, +/* a189 */ NULL, +/* a18a */ NULL, +/* a18b */ NULL, +/* a18c */ NULL, +/* a18d */ NULL, +/* a18e */ NULL, +/* a18f */ NULL, +/* a190 */ NULL, +/* a191 */ NULL, +/* a192 */ NULL, +/* a193 */ NULL, +/* a194 */ NULL, +/* a195 */ NULL, +/* a196 */ NULL, +/* a197 */ NULL, +/* a198 */ "_HWPriv", +/* a199 */ NULL, +/* a19a */ NULL, +/* a19b */ NULL, +/* a19c */ NULL, +/* a19d */ NULL, +/* a19e */ NULL, +/* a19f */ NULL, +/* a1a0 */ NULL, +/* a1a1 */ NULL, +/* a1a2 */ NULL, +/* a1a3 */ NULL, +/* a1a4 */ NULL, +/* a1a5 */ NULL, +/* a1a6 */ NULL, +/* a1a7 */ NULL, +/* a1a8 */ NULL, +/* a1a9 */ NULL, +/* a1aa */ NULL, +/* a1ab */ NULL, +/* a1ac */ NULL, +/* a1ad */ "_Gestalt", +/* a1ae */ NULL, +/* a1af */ NULL, +/* a1b0 */ NULL, +/* a1b1 */ NULL, +/* a1b2 */ NULL, +/* a1b3 */ NULL, +/* a1b4 */ NULL, +/* a1b5 */ NULL, +/* a1b6 */ NULL, +/* a1b7 */ NULL, +/* a1b8 */ NULL, +/* a1b9 */ NULL, +/* a1ba */ NULL, +/* a1bb */ NULL, +/* a1bc */ NULL, +/* a1bd */ NULL, +/* a1be */ NULL, +/* a1bf */ NULL, +/* a1c0 */ NULL, +/* a1c1 */ NULL, +/* a1c2 */ NULL, +/* a1c3 */ NULL, +/* a1c4 */ NULL, +/* a1c5 */ NULL, +/* a1c6 */ NULL, +/* a1c7 */ NULL, +/* a1c8 */ NULL, +/* a1c9 */ NULL, +/* a1ca */ NULL, +/* a1cb */ NULL, +/* a1cc */ NULL, +/* a1cd */ NULL, +/* a1ce */ NULL, +/* a1cf */ NULL, +/* a1d0 */ NULL, +/* a1d1 */ NULL, +/* a1d2 */ NULL, +/* a1d3 */ NULL, +/* a1d4 */ NULL, +/* a1d5 */ NULL, +/* a1d6 */ NULL, +/* a1d7 */ NULL, +/* a1d8 */ NULL, +/* a1d9 */ NULL, +/* a1da */ NULL, +/* a1db */ NULL, +/* a1dc */ NULL, +/* a1dd */ NULL, +/* a1de */ NULL, +/* a1df */ NULL, +/* a1e0 */ NULL, +/* a1e1 */ NULL, +/* a1e2 */ NULL, +/* a1e3 */ NULL, +/* a1e4 */ NULL, +/* a1e5 */ NULL, +/* a1e6 */ NULL, +/* a1e7 */ NULL, +/* a1e8 */ NULL, +/* a1e9 */ NULL, +/* a1ea */ NULL, +/* a1eb */ NULL, +/* a1ec */ NULL, +/* a1ed */ NULL, +/* a1ee */ NULL, +/* a1ef */ NULL, +/* a1f0 */ NULL, +/* a1f1 */ NULL, +/* a1f2 */ NULL, +/* a1f3 */ NULL, +/* a1f4 */ NULL, +/* a1f5 */ NULL, +/* a1f6 */ NULL, +/* a1f7 */ NULL, +/* a1f8 */ NULL, +/* a1f9 */ NULL, +/* a1fa */ NULL, +/* a1fb */ NULL, +/* a1fc */ NULL, +/* a1fd */ NULL, +/* a1fe */ NULL, +/* a1ff */ NULL, +/* a200 */ "_HOpen", +/* a201 */ NULL, +/* a202 */ NULL, +/* a203 */ NULL, +/* a204 */ NULL, +/* a205 */ NULL, +/* a206 */ NULL, +/* a207 */ "_HGetVInfo", +/* a208 */ "_HCreate", +/* a209 */ "_HDelete", +/* a20a */ "_HOpenRF", +/* a20b */ "_HRename", +/* a20c */ "_HGetFileInfo", +/* a20d */ "_HSetFileInfo", +/* a20e */ "_HUnmountVol", +/* a20f */ NULL, +/* a210 */ "_AllocContig", +/* a211 */ NULL, +/* a212 */ NULL, +/* a213 */ NULL, +/* a214 */ "_HGetVol", +/* a215 */ "_HSetVol", +/* a216 */ NULL, +/* a217 */ NULL, +/* a218 */ NULL, +/* a219 */ NULL, +/* a21a */ NULL, +/* a21b */ NULL, +/* a21c */ NULL, +/* a21d */ NULL, +/* a21e */ NULL, +/* a21f */ NULL, +/* a220 */ NULL, +/* a221 */ NULL, +/* a222 */ NULL, +/* a223 */ NULL, +/* a224 */ NULL, +/* a225 */ NULL, +/* a226 */ NULL, +/* a227 */ NULL, +/* a228 */ NULL, +/* a229 */ NULL, +/* a22a */ NULL, +/* a22b */ NULL, +/* a22c */ NULL, +/* a22d */ NULL, +/* a22e */ NULL, +/* a22f */ NULL, +/* a230 */ NULL, +/* a231 */ NULL, +/* a232 */ NULL, +/* a233 */ NULL, +/* a234 */ NULL, +/* a235 */ NULL, +/* a236 */ NULL, +/* a237 */ NULL, +/* a238 */ NULL, +/* a239 */ NULL, +/* a23a */ NULL, +/* a23b */ NULL, +/* a23c */ NULL, +/* a23d */ NULL, +/* a23e */ NULL, +/* a23f */ NULL, +/* a240 */ NULL, +/* a241 */ "_HSetFLock", +/* a242 */ "_HRstFLock", +/* a243 */ NULL, +/* a244 */ NULL, +/* a245 */ NULL, +/* a246 */ NULL, +/* a247 */ "_SetOSTrapAddress", +/* a248 */ NULL, +/* a249 */ NULL, +/* a24a */ NULL, +/* a24b */ NULL, +/* a24c */ NULL, +/* a24d */ NULL, +/* a24e */ NULL, +/* a24f */ NULL, +/* a250 */ NULL, +/* a251 */ NULL, +/* a252 */ NULL, +/* a253 */ NULL, +/* a254 */ NULL, +/* a255 */ NULL, +/* a256 */ "_StripText", +/* a257 */ NULL, +/* a258 */ NULL, +/* a259 */ NULL, +/* a25a */ NULL, +/* a25b */ NULL, +/* a25c */ NULL, +/* a25d */ NULL, +/* a25e */ NULL, +/* a25f */ NULL, +/* a260 */ "_HFSDispatch", +/* a261 */ NULL, +/* a262 */ NULL, +/* a263 */ NULL, +/* a264 */ NULL, +/* a265 */ NULL, +/* a266 */ NULL, +/* a267 */ NULL, +/* a268 */ NULL, +/* a269 */ NULL, +/* a26a */ NULL, +/* a26b */ NULL, +/* a26c */ NULL, +/* a26d */ NULL, +/* a26e */ NULL, +/* a26f */ NULL, +/* a270 */ NULL, +/* a271 */ NULL, +/* a272 */ NULL, +/* a273 */ NULL, +/* a274 */ NULL, +/* a275 */ NULL, +/* a276 */ NULL, +/* a277 */ NULL, +/* a278 */ NULL, +/* a279 */ NULL, +/* a27a */ NULL, +/* a27b */ NULL, +/* a27c */ NULL, +/* a27d */ NULL, +/* a27e */ NULL, +/* a27f */ NULL, +/* a280 */ NULL, +/* a281 */ NULL, +/* a282 */ NULL, +/* a283 */ NULL, +/* a284 */ NULL, +/* a285 */ "_IdleUpdate", +/* a286 */ NULL, +/* a287 */ NULL, +/* a288 */ NULL, +/* a289 */ NULL, +/* a28a */ "_SleepQInstall", +/* a28b */ NULL, +/* a28c */ NULL, +/* a28d */ NULL, +/* a28e */ NULL, +/* a28f */ NULL, +/* a290 */ NULL, +/* a291 */ NULL, +/* a292 */ NULL, +/* a293 */ NULL, +/* a294 */ NULL, +/* a295 */ NULL, +/* a296 */ NULL, +/* a297 */ NULL, +/* a298 */ NULL, +/* a299 */ NULL, +/* a29a */ NULL, +/* a29b */ NULL, +/* a29c */ NULL, +/* a29d */ NULL, +/* a29e */ NULL, +/* a29f */ NULL, +/* a2a0 */ NULL, +/* a2a1 */ NULL, +/* a2a2 */ NULL, +/* a2a3 */ NULL, +/* a2a4 */ NULL, +/* a2a5 */ NULL, +/* a2a6 */ NULL, +/* a2a7 */ NULL, +/* a2a8 */ NULL, +/* a2a9 */ NULL, +/* a2aa */ NULL, +/* a2ab */ NULL, +/* a2ac */ NULL, +/* a2ad */ NULL, +/* a2ae */ NULL, +/* a2af */ NULL, +/* a2b0 */ NULL, +/* a2b1 */ NULL, +/* a2b2 */ NULL, +/* a2b3 */ NULL, +/* a2b4 */ NULL, +/* a2b5 */ NULL, +/* a2b6 */ NULL, +/* a2b7 */ NULL, +/* a2b8 */ NULL, +/* a2b9 */ NULL, +/* a2ba */ NULL, +/* a2bb */ NULL, +/* a2bc */ NULL, +/* a2bd */ NULL, +/* a2be */ NULL, +/* a2bf */ NULL, +/* a2c0 */ NULL, +/* a2c1 */ NULL, +/* a2c2 */ NULL, +/* a2c3 */ NULL, +/* a2c4 */ NULL, +/* a2c5 */ NULL, +/* a2c6 */ NULL, +/* a2c7 */ NULL, +/* a2c8 */ NULL, +/* a2c9 */ NULL, +/* a2ca */ NULL, +/* a2cb */ NULL, +/* a2cc */ NULL, +/* a2cd */ NULL, +/* a2ce */ NULL, +/* a2cf */ NULL, +/* a2d0 */ NULL, +/* a2d1 */ NULL, +/* a2d2 */ NULL, +/* a2d3 */ NULL, +/* a2d4 */ NULL, +/* a2d5 */ NULL, +/* a2d6 */ NULL, +/* a2d7 */ NULL, +/* a2d8 */ NULL, +/* a2d9 */ NULL, +/* a2da */ NULL, +/* a2db */ NULL, +/* a2dc */ NULL, +/* a2dd */ NULL, +/* a2de */ NULL, +/* a2df */ NULL, +/* a2e0 */ NULL, +/* a2e1 */ NULL, +/* a2e2 */ NULL, +/* a2e3 */ NULL, +/* a2e4 */ NULL, +/* a2e5 */ NULL, +/* a2e6 */ NULL, +/* a2e7 */ NULL, +/* a2e8 */ NULL, +/* a2e9 */ NULL, +/* a2ea */ NULL, +/* a2eb */ NULL, +/* a2ec */ NULL, +/* a2ed */ NULL, +/* a2ee */ NULL, +/* a2ef */ NULL, +/* a2f0 */ NULL, +/* a2f1 */ NULL, +/* a2f2 */ NULL, +/* a2f3 */ NULL, +/* a2f4 */ NULL, +/* a2f5 */ NULL, +/* a2f6 */ NULL, +/* a2f7 */ NULL, +/* a2f8 */ NULL, +/* a2f9 */ NULL, +/* a2fa */ NULL, +/* a2fb */ NULL, +/* a2fc */ NULL, +/* a2fd */ NULL, +/* a2fe */ NULL, +/* a2ff */ NULL, +/* a300 */ NULL, +/* a301 */ NULL, +/* a302 */ NULL, +/* a303 */ NULL, +/* a304 */ NULL, +/* a305 */ NULL, +/* a306 */ NULL, +/* a307 */ NULL, +/* a308 */ NULL, +/* a309 */ NULL, +/* a30a */ NULL, +/* a30b */ NULL, +/* a30c */ NULL, +/* a30d */ NULL, +/* a30e */ NULL, +/* a30f */ NULL, +/* a310 */ NULL, +/* a311 */ NULL, +/* a312 */ NULL, +/* a313 */ NULL, +/* a314 */ NULL, +/* a315 */ NULL, +/* a316 */ NULL, +/* a317 */ NULL, +/* a318 */ NULL, +/* a319 */ NULL, +/* a31a */ NULL, +/* a31b */ NULL, +/* a31c */ NULL, +/* a31d */ NULL, +/* a31e */ "_NewPtrClear", +/* a31f */ NULL, +/* a320 */ NULL, +/* a321 */ NULL, +/* a322 */ "_NewHandleClear", +/* a323 */ NULL, +/* a324 */ NULL, +/* a325 */ NULL, +/* a326 */ NULL, +/* a327 */ NULL, +/* a328 */ NULL, +/* a329 */ NULL, +/* a32a */ NULL, +/* a32b */ NULL, +/* a32c */ NULL, +/* a32d */ NULL, +/* a32e */ NULL, +/* a32f */ NULL, +/* a330 */ NULL, +/* a331 */ NULL, +/* a332 */ NULL, +/* a333 */ NULL, +/* a334 */ NULL, +/* a335 */ NULL, +/* a336 */ NULL, +/* a337 */ NULL, +/* a338 */ NULL, +/* a339 */ NULL, +/* a33a */ NULL, +/* a33b */ NULL, +/* a33c */ NULL, +/* a33d */ NULL, +/* a33e */ NULL, +/* a33f */ NULL, +/* a340 */ NULL, +/* a341 */ NULL, +/* a342 */ NULL, +/* a343 */ NULL, +/* a344 */ NULL, +/* a345 */ NULL, +/* a346 */ "_GetOSTrapAddress", +/* a347 */ NULL, +/* a348 */ NULL, +/* a349 */ NULL, +/* a34a */ NULL, +/* a34b */ NULL, +/* a34c */ NULL, +/* a34d */ NULL, +/* a34e */ NULL, +/* a34f */ NULL, +/* a350 */ NULL, +/* a351 */ NULL, +/* a352 */ NULL, +/* a353 */ NULL, +/* a354 */ NULL, +/* a355 */ NULL, +/* a356 */ NULL, +/* a357 */ NULL, +/* a358 */ NULL, +/* a359 */ NULL, +/* a35a */ NULL, +/* a35b */ NULL, +/* a35c */ NULL, +/* a35d */ NULL, +/* a35e */ NULL, +/* a35f */ NULL, +/* a360 */ NULL, +/* a361 */ NULL, +/* a362 */ NULL, +/* a363 */ NULL, +/* a364 */ NULL, +/* a365 */ NULL, +/* a366 */ NULL, +/* a367 */ NULL, +/* a368 */ NULL, +/* a369 */ NULL, +/* a36a */ NULL, +/* a36b */ NULL, +/* a36c */ NULL, +/* a36d */ NULL, +/* a36e */ NULL, +/* a36f */ NULL, +/* a370 */ NULL, +/* a371 */ NULL, +/* a372 */ NULL, +/* a373 */ NULL, +/* a374 */ NULL, +/* a375 */ NULL, +/* a376 */ NULL, +/* a377 */ NULL, +/* a378 */ NULL, +/* a379 */ NULL, +/* a37a */ NULL, +/* a37b */ NULL, +/* a37c */ NULL, +/* a37d */ NULL, +/* a37e */ NULL, +/* a37f */ NULL, +/* a380 */ NULL, +/* a381 */ NULL, +/* a382 */ NULL, +/* a383 */ NULL, +/* a384 */ NULL, +/* a385 */ NULL, +/* a386 */ NULL, +/* a387 */ NULL, +/* a388 */ NULL, +/* a389 */ NULL, +/* a38a */ NULL, +/* a38b */ NULL, +/* a38c */ NULL, +/* a38d */ NULL, +/* a38e */ NULL, +/* a38f */ NULL, +/* a390 */ NULL, +/* a391 */ NULL, +/* a392 */ NULL, +/* a393 */ NULL, +/* a394 */ NULL, +/* a395 */ NULL, +/* a396 */ NULL, +/* a397 */ NULL, +/* a398 */ NULL, +/* a399 */ NULL, +/* a39a */ NULL, +/* a39b */ NULL, +/* a39c */ NULL, +/* a39d */ NULL, +/* a39e */ NULL, +/* a39f */ NULL, +/* a3a0 */ NULL, +/* a3a1 */ NULL, +/* a3a2 */ NULL, +/* a3a3 */ NULL, +/* a3a4 */ NULL, +/* a3a5 */ NULL, +/* a3a6 */ NULL, +/* a3a7 */ NULL, +/* a3a8 */ NULL, +/* a3a9 */ NULL, +/* a3aa */ NULL, +/* a3ab */ NULL, +/* a3ac */ NULL, +/* a3ad */ "_NewGestalt", +/* a3ae */ NULL, +/* a3af */ NULL, +/* a3b0 */ NULL, +/* a3b1 */ NULL, +/* a3b2 */ NULL, +/* a3b3 */ NULL, +/* a3b4 */ NULL, +/* a3b5 */ NULL, +/* a3b6 */ NULL, +/* a3b7 */ NULL, +/* a3b8 */ NULL, +/* a3b9 */ NULL, +/* a3ba */ NULL, +/* a3bb */ NULL, +/* a3bc */ NULL, +/* a3bd */ NULL, +/* a3be */ NULL, +/* a3bf */ NULL, +/* a3c0 */ NULL, +/* a3c1 */ NULL, +/* a3c2 */ NULL, +/* a3c3 */ NULL, +/* a3c4 */ NULL, +/* a3c5 */ NULL, +/* a3c6 */ NULL, +/* a3c7 */ NULL, +/* a3c8 */ NULL, +/* a3c9 */ NULL, +/* a3ca */ NULL, +/* a3cb */ NULL, +/* a3cc */ NULL, +/* a3cd */ NULL, +/* a3ce */ NULL, +/* a3cf */ NULL, +/* a3d0 */ NULL, +/* a3d1 */ NULL, +/* a3d2 */ NULL, +/* a3d3 */ NULL, +/* a3d4 */ NULL, +/* a3d5 */ NULL, +/* a3d6 */ NULL, +/* a3d7 */ NULL, +/* a3d8 */ NULL, +/* a3d9 */ NULL, +/* a3da */ NULL, +/* a3db */ NULL, +/* a3dc */ NULL, +/* a3dd */ NULL, +/* a3de */ NULL, +/* a3df */ NULL, +/* a3e0 */ NULL, +/* a3e1 */ NULL, +/* a3e2 */ NULL, +/* a3e3 */ NULL, +/* a3e4 */ NULL, +/* a3e5 */ NULL, +/* a3e6 */ NULL, +/* a3e7 */ NULL, +/* a3e8 */ NULL, +/* a3e9 */ NULL, +/* a3ea */ NULL, +/* a3eb */ NULL, +/* a3ec */ NULL, +/* a3ed */ NULL, +/* a3ee */ NULL, +/* a3ef */ NULL, +/* a3f0 */ NULL, +/* a3f1 */ NULL, +/* a3f2 */ NULL, +/* a3f3 */ NULL, +/* a3f4 */ NULL, +/* a3f5 */ NULL, +/* a3f6 */ NULL, +/* a3f7 */ NULL, +/* a3f8 */ NULL, +/* a3f9 */ NULL, +/* a3fa */ NULL, +/* a3fb */ NULL, +/* a3fc */ NULL, +/* a3fd */ NULL, +/* a3fe */ NULL, +/* a3ff */ NULL, +/* a400 */ NULL, +/* a401 */ NULL, +/* a402 */ NULL, +/* a403 */ NULL, +/* a404 */ NULL, +/* a405 */ NULL, +/* a406 */ NULL, +/* a407 */ NULL, +/* a408 */ NULL, +/* a409 */ NULL, +/* a40a */ NULL, +/* a40b */ NULL, +/* a40c */ NULL, +/* a40d */ NULL, +/* a40e */ NULL, +/* a40f */ NULL, +/* a410 */ NULL, +/* a411 */ NULL, +/* a412 */ NULL, +/* a413 */ NULL, +/* a414 */ NULL, +/* a415 */ NULL, +/* a416 */ NULL, +/* a417 */ NULL, +/* a418 */ NULL, +/* a419 */ NULL, +/* a41a */ NULL, +/* a41b */ NULL, +/* a41c */ NULL, +/* a41d */ NULL, +/* a41e */ NULL, +/* a41f */ NULL, +/* a420 */ NULL, +/* a421 */ NULL, +/* a422 */ NULL, +/* a423 */ NULL, +/* a424 */ NULL, +/* a425 */ NULL, +/* a426 */ NULL, +/* a427 */ NULL, +/* a428 */ NULL, +/* a429 */ NULL, +/* a42a */ NULL, +/* a42b */ NULL, +/* a42c */ NULL, +/* a42d */ NULL, +/* a42e */ NULL, +/* a42f */ NULL, +/* a430 */ NULL, +/* a431 */ NULL, +/* a432 */ NULL, +/* a433 */ NULL, +/* a434 */ NULL, +/* a435 */ NULL, +/* a436 */ NULL, +/* a437 */ NULL, +/* a438 */ NULL, +/* a439 */ NULL, +/* a43a */ NULL, +/* a43b */ NULL, +/* a43c */ NULL, +/* a43d */ NULL, +/* a43e */ NULL, +/* a43f */ NULL, +/* a440 */ NULL, +/* a441 */ NULL, +/* a442 */ NULL, +/* a443 */ NULL, +/* a444 */ NULL, +/* a445 */ NULL, +/* a446 */ NULL, +/* a447 */ NULL, +/* a448 */ NULL, +/* a449 */ NULL, +/* a44a */ NULL, +/* a44b */ NULL, +/* a44c */ NULL, +/* a44d */ NULL, +/* a44e */ NULL, +/* a44f */ NULL, +/* a450 */ NULL, +/* a451 */ NULL, +/* a452 */ NULL, +/* a453 */ NULL, +/* a454 */ NULL, +/* a455 */ NULL, +/* a456 */ "_UpperText", +/* a457 */ NULL, +/* a458 */ "_InsXTime", +/* a459 */ NULL, +/* a45a */ NULL, +/* a45b */ NULL, +/* a45c */ NULL, +/* a45d */ NULL, +/* a45e */ NULL, +/* a45f */ NULL, +/* a460 */ NULL, +/* a461 */ NULL, +/* a462 */ NULL, +/* a463 */ NULL, +/* a464 */ NULL, +/* a465 */ NULL, +/* a466 */ NULL, +/* a467 */ NULL, +/* a468 */ NULL, +/* a469 */ NULL, +/* a46a */ NULL, +/* a46b */ NULL, +/* a46c */ NULL, +/* a46d */ NULL, +/* a46e */ NULL, +/* a46f */ NULL, +/* a470 */ NULL, +/* a471 */ NULL, +/* a472 */ NULL, +/* a473 */ NULL, +/* a474 */ NULL, +/* a475 */ NULL, +/* a476 */ NULL, +/* a477 */ NULL, +/* a478 */ NULL, +/* a479 */ NULL, +/* a47a */ NULL, +/* a47b */ NULL, +/* a47c */ NULL, +/* a47d */ NULL, +/* a47e */ NULL, +/* a47f */ NULL, +/* a480 */ NULL, +/* a481 */ NULL, +/* a482 */ NULL, +/* a483 */ NULL, +/* a484 */ NULL, +/* a485 */ "_IdleState", +/* a486 */ NULL, +/* a487 */ NULL, +/* a488 */ NULL, +/* a489 */ NULL, +/* a48a */ "_SleepQRemove", +/* a48b */ NULL, +/* a48c */ NULL, +/* a48d */ NULL, +/* a48e */ NULL, +/* a48f */ NULL, +/* a490 */ NULL, +/* a491 */ NULL, +/* a492 */ NULL, +/* a493 */ NULL, +/* a494 */ NULL, +/* a495 */ NULL, +/* a496 */ NULL, +/* a497 */ NULL, +/* a498 */ NULL, +/* a499 */ NULL, +/* a49a */ NULL, +/* a49b */ NULL, +/* a49c */ NULL, +/* a49d */ NULL, +/* a49e */ NULL, +/* a49f */ NULL, +/* a4a0 */ NULL, +/* a4a1 */ NULL, +/* a4a2 */ NULL, +/* a4a3 */ NULL, +/* a4a4 */ NULL, +/* a4a5 */ NULL, +/* a4a6 */ NULL, +/* a4a7 */ NULL, +/* a4a8 */ NULL, +/* a4a9 */ NULL, +/* a4aa */ NULL, +/* a4ab */ NULL, +/* a4ac */ NULL, +/* a4ad */ NULL, +/* a4ae */ NULL, +/* a4af */ NULL, +/* a4b0 */ NULL, +/* a4b1 */ NULL, +/* a4b2 */ NULL, +/* a4b3 */ NULL, +/* a4b4 */ NULL, +/* a4b5 */ NULL, +/* a4b6 */ NULL, +/* a4b7 */ NULL, +/* a4b8 */ NULL, +/* a4b9 */ NULL, +/* a4ba */ NULL, +/* a4bb */ NULL, +/* a4bc */ NULL, +/* a4bd */ NULL, +/* a4be */ NULL, +/* a4bf */ NULL, +/* a4c0 */ NULL, +/* a4c1 */ NULL, +/* a4c2 */ NULL, +/* a4c3 */ NULL, +/* a4c4 */ NULL, +/* a4c5 */ NULL, +/* a4c6 */ NULL, +/* a4c7 */ NULL, +/* a4c8 */ NULL, +/* a4c9 */ NULL, +/* a4ca */ NULL, +/* a4cb */ NULL, +/* a4cc */ NULL, +/* a4cd */ NULL, +/* a4ce */ NULL, +/* a4cf */ NULL, +/* a4d0 */ NULL, +/* a4d1 */ NULL, +/* a4d2 */ NULL, +/* a4d3 */ NULL, +/* a4d4 */ NULL, +/* a4d5 */ NULL, +/* a4d6 */ NULL, +/* a4d7 */ NULL, +/* a4d8 */ NULL, +/* a4d9 */ NULL, +/* a4da */ NULL, +/* a4db */ NULL, +/* a4dc */ NULL, +/* a4dd */ NULL, +/* a4de */ NULL, +/* a4df */ NULL, +/* a4e0 */ NULL, +/* a4e1 */ NULL, +/* a4e2 */ NULL, +/* a4e3 */ NULL, +/* a4e4 */ NULL, +/* a4e5 */ NULL, +/* a4e6 */ NULL, +/* a4e7 */ NULL, +/* a4e8 */ NULL, +/* a4e9 */ NULL, +/* a4ea */ NULL, +/* a4eb */ NULL, +/* a4ec */ NULL, +/* a4ed */ NULL, +/* a4ee */ NULL, +/* a4ef */ NULL, +/* a4f0 */ NULL, +/* a4f1 */ NULL, +/* a4f2 */ NULL, +/* a4f3 */ NULL, +/* a4f4 */ NULL, +/* a4f5 */ NULL, +/* a4f6 */ NULL, +/* a4f7 */ NULL, +/* a4f8 */ NULL, +/* a4f9 */ NULL, +/* a4fa */ NULL, +/* a4fb */ NULL, +/* a4fc */ NULL, +/* a4fd */ NULL, +/* a4fe */ NULL, +/* a4ff */ NULL, +/* a500 */ NULL, +/* a501 */ NULL, +/* a502 */ NULL, +/* a503 */ NULL, +/* a504 */ NULL, +/* a505 */ NULL, +/* a506 */ NULL, +/* a507 */ NULL, +/* a508 */ NULL, +/* a509 */ NULL, +/* a50a */ NULL, +/* a50b */ NULL, +/* a50c */ NULL, +/* a50d */ NULL, +/* a50e */ NULL, +/* a50f */ NULL, +/* a510 */ NULL, +/* a511 */ NULL, +/* a512 */ NULL, +/* a513 */ NULL, +/* a514 */ NULL, +/* a515 */ NULL, +/* a516 */ NULL, +/* a517 */ NULL, +/* a518 */ NULL, +/* a519 */ NULL, +/* a51a */ NULL, +/* a51b */ NULL, +/* a51c */ NULL, +/* a51d */ NULL, +/* a51e */ "_NewPtrSys", +/* a51f */ NULL, +/* a520 */ NULL, +/* a521 */ NULL, +/* a522 */ NULL, +/* a523 */ NULL, +/* a524 */ NULL, +/* a525 */ NULL, +/* a526 */ NULL, +/* a527 */ NULL, +/* a528 */ NULL, +/* a529 */ NULL, +/* a52a */ NULL, +/* a52b */ NULL, +/* a52c */ NULL, +/* a52d */ NULL, +/* a52e */ NULL, +/* a52f */ NULL, +/* a530 */ NULL, +/* a531 */ NULL, +/* a532 */ NULL, +/* a533 */ NULL, +/* a534 */ NULL, +/* a535 */ NULL, +/* a536 */ NULL, +/* a537 */ NULL, +/* a538 */ NULL, +/* a539 */ NULL, +/* a53a */ NULL, +/* a53b */ NULL, +/* a53c */ NULL, +/* a53d */ NULL, +/* a53e */ NULL, +/* a53f */ NULL, +/* a540 */ NULL, +/* a541 */ NULL, +/* a542 */ NULL, +/* a543 */ NULL, +/* a544 */ NULL, +/* a545 */ NULL, +/* a546 */ NULL, +/* a547 */ NULL, +/* a548 */ NULL, +/* a549 */ NULL, +/* a54a */ NULL, +/* a54b */ NULL, +/* a54c */ NULL, +/* a54d */ NULL, +/* a54e */ NULL, +/* a54f */ NULL, +/* a550 */ NULL, +/* a551 */ NULL, +/* a552 */ NULL, +/* a553 */ NULL, +/* a554 */ NULL, +/* a555 */ NULL, +/* a556 */ NULL, +/* a557 */ NULL, +/* a558 */ NULL, +/* a559 */ NULL, +/* a55a */ NULL, +/* a55b */ NULL, +/* a55c */ NULL, +/* a55d */ NULL, +/* a55e */ NULL, +/* a55f */ NULL, +/* a560 */ NULL, +/* a561 */ NULL, +/* a562 */ NULL, +/* a563 */ NULL, +/* a564 */ NULL, +/* a565 */ NULL, +/* a566 */ NULL, +/* a567 */ NULL, +/* a568 */ NULL, +/* a569 */ NULL, +/* a56a */ NULL, +/* a56b */ NULL, +/* a56c */ NULL, +/* a56d */ NULL, +/* a56e */ NULL, +/* a56f */ NULL, +/* a570 */ NULL, +/* a571 */ NULL, +/* a572 */ NULL, +/* a573 */ NULL, +/* a574 */ NULL, +/* a575 */ NULL, +/* a576 */ NULL, +/* a577 */ NULL, +/* a578 */ NULL, +/* a579 */ NULL, +/* a57a */ NULL, +/* a57b */ NULL, +/* a57c */ NULL, +/* a57d */ NULL, +/* a57e */ NULL, +/* a57f */ NULL, +/* a580 */ NULL, +/* a581 */ NULL, +/* a582 */ NULL, +/* a583 */ NULL, +/* a584 */ NULL, +/* a585 */ NULL, +/* a586 */ NULL, +/* a587 */ NULL, +/* a588 */ NULL, +/* a589 */ NULL, +/* a58a */ NULL, +/* a58b */ NULL, +/* a58c */ NULL, +/* a58d */ NULL, +/* a58e */ NULL, +/* a58f */ NULL, +/* a590 */ NULL, +/* a591 */ NULL, +/* a592 */ NULL, +/* a593 */ NULL, +/* a594 */ NULL, +/* a595 */ NULL, +/* a596 */ NULL, +/* a597 */ NULL, +/* a598 */ NULL, +/* a599 */ NULL, +/* a59a */ NULL, +/* a59b */ NULL, +/* a59c */ NULL, +/* a59d */ NULL, +/* a59e */ NULL, +/* a59f */ NULL, +/* a5a0 */ NULL, +/* a5a1 */ NULL, +/* a5a2 */ NULL, +/* a5a3 */ NULL, +/* a5a4 */ NULL, +/* a5a5 */ NULL, +/* a5a6 */ NULL, +/* a5a7 */ NULL, +/* a5a8 */ NULL, +/* a5a9 */ NULL, +/* a5aa */ NULL, +/* a5ab */ NULL, +/* a5ac */ NULL, +/* a5ad */ "_ReplaceGestalt", +/* a5ae */ NULL, +/* a5af */ NULL, +/* a5b0 */ NULL, +/* a5b1 */ NULL, +/* a5b2 */ NULL, +/* a5b3 */ NULL, +/* a5b4 */ NULL, +/* a5b5 */ NULL, +/* a5b6 */ NULL, +/* a5b7 */ NULL, +/* a5b8 */ NULL, +/* a5b9 */ NULL, +/* a5ba */ NULL, +/* a5bb */ NULL, +/* a5bc */ NULL, +/* a5bd */ NULL, +/* a5be */ NULL, +/* a5bf */ NULL, +/* a5c0 */ NULL, +/* a5c1 */ NULL, +/* a5c2 */ NULL, +/* a5c3 */ NULL, +/* a5c4 */ NULL, +/* a5c5 */ NULL, +/* a5c6 */ NULL, +/* a5c7 */ NULL, +/* a5c8 */ NULL, +/* a5c9 */ NULL, +/* a5ca */ NULL, +/* a5cb */ NULL, +/* a5cc */ NULL, +/* a5cd */ NULL, +/* a5ce */ NULL, +/* a5cf */ NULL, +/* a5d0 */ NULL, +/* a5d1 */ NULL, +/* a5d2 */ NULL, +/* a5d3 */ NULL, +/* a5d4 */ NULL, +/* a5d5 */ NULL, +/* a5d6 */ NULL, +/* a5d7 */ NULL, +/* a5d8 */ NULL, +/* a5d9 */ NULL, +/* a5da */ NULL, +/* a5db */ NULL, +/* a5dc */ NULL, +/* a5dd */ NULL, +/* a5de */ NULL, +/* a5df */ NULL, +/* a5e0 */ NULL, +/* a5e1 */ NULL, +/* a5e2 */ NULL, +/* a5e3 */ NULL, +/* a5e4 */ NULL, +/* a5e5 */ NULL, +/* a5e6 */ NULL, +/* a5e7 */ NULL, +/* a5e8 */ NULL, +/* a5e9 */ NULL, +/* a5ea */ NULL, +/* a5eb */ NULL, +/* a5ec */ NULL, +/* a5ed */ NULL, +/* a5ee */ NULL, +/* a5ef */ NULL, +/* a5f0 */ NULL, +/* a5f1 */ NULL, +/* a5f2 */ NULL, +/* a5f3 */ NULL, +/* a5f4 */ NULL, +/* a5f5 */ NULL, +/* a5f6 */ NULL, +/* a5f7 */ NULL, +/* a5f8 */ NULL, +/* a5f9 */ NULL, +/* a5fa */ NULL, +/* a5fb */ NULL, +/* a5fc */ NULL, +/* a5fd */ NULL, +/* a5fe */ NULL, +/* a5ff */ NULL, +/* a600 */ NULL, +/* a601 */ NULL, +/* a602 */ NULL, +/* a603 */ NULL, +/* a604 */ NULL, +/* a605 */ NULL, +/* a606 */ NULL, +/* a607 */ NULL, +/* a608 */ NULL, +/* a609 */ NULL, +/* a60a */ NULL, +/* a60b */ NULL, +/* a60c */ NULL, +/* a60d */ NULL, +/* a60e */ NULL, +/* a60f */ NULL, +/* a610 */ NULL, +/* a611 */ NULL, +/* a612 */ NULL, +/* a613 */ NULL, +/* a614 */ NULL, +/* a615 */ NULL, +/* a616 */ NULL, +/* a617 */ NULL, +/* a618 */ NULL, +/* a619 */ NULL, +/* a61a */ NULL, +/* a61b */ NULL, +/* a61c */ NULL, +/* a61d */ NULL, +/* a61e */ NULL, +/* a61f */ NULL, +/* a620 */ NULL, +/* a621 */ NULL, +/* a622 */ NULL, +/* a623 */ NULL, +/* a624 */ NULL, +/* a625 */ NULL, +/* a626 */ NULL, +/* a627 */ NULL, +/* a628 */ NULL, +/* a629 */ NULL, +/* a62a */ NULL, +/* a62b */ NULL, +/* a62c */ NULL, +/* a62d */ NULL, +/* a62e */ NULL, +/* a62f */ NULL, +/* a630 */ NULL, +/* a631 */ NULL, +/* a632 */ NULL, +/* a633 */ NULL, +/* a634 */ NULL, +/* a635 */ NULL, +/* a636 */ NULL, +/* a637 */ NULL, +/* a638 */ NULL, +/* a639 */ NULL, +/* a63a */ NULL, +/* a63b */ NULL, +/* a63c */ NULL, +/* a63d */ NULL, +/* a63e */ NULL, +/* a63f */ NULL, +/* a640 */ NULL, +/* a641 */ NULL, +/* a642 */ NULL, +/* a643 */ NULL, +/* a644 */ NULL, +/* a645 */ NULL, +/* a646 */ NULL, +/* a647 */ "_SetToolBoxTrapAddress", +/* a648 */ NULL, +/* a649 */ NULL, +/* a64a */ NULL, +/* a64b */ NULL, +/* a64c */ NULL, +/* a64d */ NULL, +/* a64e */ NULL, +/* a64f */ NULL, +/* a650 */ NULL, +/* a651 */ NULL, +/* a652 */ NULL, +/* a653 */ NULL, +/* a654 */ NULL, +/* a655 */ NULL, +/* a656 */ "_StripUpperText", +/* a657 */ NULL, +/* a658 */ NULL, +/* a659 */ NULL, +/* a65a */ NULL, +/* a65b */ NULL, +/* a65c */ NULL, +/* a65d */ NULL, +/* a65e */ NULL, +/* a65f */ NULL, +/* a660 */ NULL, +/* a661 */ NULL, +/* a662 */ NULL, +/* a663 */ NULL, +/* a664 */ NULL, +/* a665 */ NULL, +/* a666 */ NULL, +/* a667 */ NULL, +/* a668 */ NULL, +/* a669 */ NULL, +/* a66a */ NULL, +/* a66b */ NULL, +/* a66c */ NULL, +/* a66d */ NULL, +/* a66e */ NULL, +/* a66f */ NULL, +/* a670 */ NULL, +/* a671 */ NULL, +/* a672 */ NULL, +/* a673 */ NULL, +/* a674 */ NULL, +/* a675 */ NULL, +/* a676 */ NULL, +/* a677 */ NULL, +/* a678 */ NULL, +/* a679 */ NULL, +/* a67a */ NULL, +/* a67b */ NULL, +/* a67c */ NULL, +/* a67d */ NULL, +/* a67e */ NULL, +/* a67f */ NULL, +/* a680 */ NULL, +/* a681 */ NULL, +/* a682 */ NULL, +/* a683 */ NULL, +/* a684 */ NULL, +/* a685 */ "_SerialPower", +/* a686 */ NULL, +/* a687 */ NULL, +/* a688 */ NULL, +/* a689 */ NULL, +/* a68a */ NULL, +/* a68b */ NULL, +/* a68c */ NULL, +/* a68d */ NULL, +/* a68e */ NULL, +/* a68f */ NULL, +/* a690 */ NULL, +/* a691 */ NULL, +/* a692 */ NULL, +/* a693 */ NULL, +/* a694 */ NULL, +/* a695 */ NULL, +/* a696 */ NULL, +/* a697 */ NULL, +/* a698 */ NULL, +/* a699 */ NULL, +/* a69a */ NULL, +/* a69b */ NULL, +/* a69c */ NULL, +/* a69d */ NULL, +/* a69e */ NULL, +/* a69f */ NULL, +/* a6a0 */ NULL, +/* a6a1 */ NULL, +/* a6a2 */ NULL, +/* a6a3 */ NULL, +/* a6a4 */ NULL, +/* a6a5 */ NULL, +/* a6a6 */ NULL, +/* a6a7 */ NULL, +/* a6a8 */ NULL, +/* a6a9 */ NULL, +/* a6aa */ NULL, +/* a6ab */ NULL, +/* a6ac */ NULL, +/* a6ad */ NULL, +/* a6ae */ NULL, +/* a6af */ NULL, +/* a6b0 */ NULL, +/* a6b1 */ NULL, +/* a6b2 */ NULL, +/* a6b3 */ NULL, +/* a6b4 */ NULL, +/* a6b5 */ NULL, +/* a6b6 */ NULL, +/* a6b7 */ NULL, +/* a6b8 */ NULL, +/* a6b9 */ NULL, +/* a6ba */ NULL, +/* a6bb */ NULL, +/* a6bc */ NULL, +/* a6bd */ NULL, +/* a6be */ NULL, +/* a6bf */ NULL, +/* a6c0 */ NULL, +/* a6c1 */ NULL, +/* a6c2 */ NULL, +/* a6c3 */ NULL, +/* a6c4 */ NULL, +/* a6c5 */ NULL, +/* a6c6 */ NULL, +/* a6c7 */ NULL, +/* a6c8 */ NULL, +/* a6c9 */ NULL, +/* a6ca */ NULL, +/* a6cb */ NULL, +/* a6cc */ NULL, +/* a6cd */ NULL, +/* a6ce */ NULL, +/* a6cf */ NULL, +/* a6d0 */ NULL, +/* a6d1 */ NULL, +/* a6d2 */ NULL, +/* a6d3 */ NULL, +/* a6d4 */ NULL, +/* a6d5 */ NULL, +/* a6d6 */ NULL, +/* a6d7 */ NULL, +/* a6d8 */ NULL, +/* a6d9 */ NULL, +/* a6da */ NULL, +/* a6db */ NULL, +/* a6dc */ NULL, +/* a6dd */ NULL, +/* a6de */ NULL, +/* a6df */ NULL, +/* a6e0 */ NULL, +/* a6e1 */ NULL, +/* a6e2 */ NULL, +/* a6e3 */ NULL, +/* a6e4 */ NULL, +/* a6e5 */ NULL, +/* a6e6 */ NULL, +/* a6e7 */ NULL, +/* a6e8 */ NULL, +/* a6e9 */ NULL, +/* a6ea */ NULL, +/* a6eb */ NULL, +/* a6ec */ NULL, +/* a6ed */ NULL, +/* a6ee */ NULL, +/* a6ef */ NULL, +/* a6f0 */ NULL, +/* a6f1 */ NULL, +/* a6f2 */ NULL, +/* a6f3 */ NULL, +/* a6f4 */ NULL, +/* a6f5 */ NULL, +/* a6f6 */ NULL, +/* a6f7 */ NULL, +/* a6f8 */ NULL, +/* a6f9 */ NULL, +/* a6fa */ NULL, +/* a6fb */ NULL, +/* a6fc */ NULL, +/* a6fd */ NULL, +/* a6fe */ NULL, +/* a6ff */ NULL, +/* a700 */ NULL, +/* a701 */ NULL, +/* a702 */ NULL, +/* a703 */ NULL, +/* a704 */ NULL, +/* a705 */ NULL, +/* a706 */ NULL, +/* a707 */ NULL, +/* a708 */ NULL, +/* a709 */ NULL, +/* a70a */ NULL, +/* a70b */ NULL, +/* a70c */ NULL, +/* a70d */ NULL, +/* a70e */ NULL, +/* a70f */ NULL, +/* a710 */ NULL, +/* a711 */ NULL, +/* a712 */ NULL, +/* a713 */ NULL, +/* a714 */ NULL, +/* a715 */ NULL, +/* a716 */ NULL, +/* a717 */ NULL, +/* a718 */ NULL, +/* a719 */ NULL, +/* a71a */ NULL, +/* a71b */ NULL, +/* a71c */ NULL, +/* a71d */ NULL, +/* a71e */ "_NewPtrSysClear", +/* a71f */ NULL, +/* a720 */ NULL, +/* a721 */ NULL, +/* a722 */ NULL, +/* a723 */ NULL, +/* a724 */ NULL, +/* a725 */ NULL, +/* a726 */ NULL, +/* a727 */ NULL, +/* a728 */ NULL, +/* a729 */ NULL, +/* a72a */ NULL, +/* a72b */ NULL, +/* a72c */ NULL, +/* a72d */ NULL, +/* a72e */ NULL, +/* a72f */ NULL, +/* a730 */ NULL, +/* a731 */ NULL, +/* a732 */ NULL, +/* a733 */ NULL, +/* a734 */ NULL, +/* a735 */ NULL, +/* a736 */ NULL, +/* a737 */ NULL, +/* a738 */ NULL, +/* a739 */ NULL, +/* a73a */ NULL, +/* a73b */ NULL, +/* a73c */ NULL, +/* a73d */ NULL, +/* a73e */ NULL, +/* a73f */ NULL, +/* a740 */ NULL, +/* a741 */ NULL, +/* a742 */ NULL, +/* a743 */ NULL, +/* a744 */ NULL, +/* a745 */ NULL, +/* a746 */ "_GetToolBoxTrapAddress", +/* a747 */ NULL, +/* a748 */ NULL, +/* a749 */ NULL, +/* a74a */ NULL, +/* a74b */ NULL, +/* a74c */ NULL, +/* a74d */ NULL, +/* a74e */ NULL, +/* a74f */ NULL, +/* a750 */ NULL, +/* a751 */ NULL, +/* a752 */ NULL, +/* a753 */ NULL, +/* a754 */ NULL, +/* a755 */ NULL, +/* a756 */ NULL, +/* a757 */ NULL, +/* a758 */ NULL, +/* a759 */ NULL, +/* a75a */ NULL, +/* a75b */ NULL, +/* a75c */ NULL, +/* a75d */ NULL, +/* a75e */ NULL, +/* a75f */ NULL, +/* a760 */ NULL, +/* a761 */ NULL, +/* a762 */ NULL, +/* a763 */ NULL, +/* a764 */ NULL, +/* a765 */ NULL, +/* a766 */ NULL, +/* a767 */ NULL, +/* a768 */ NULL, +/* a769 */ NULL, +/* a76a */ NULL, +/* a76b */ NULL, +/* a76c */ NULL, +/* a76d */ NULL, +/* a76e */ NULL, +/* a76f */ NULL, +/* a770 */ NULL, +/* a771 */ NULL, +/* a772 */ NULL, +/* a773 */ NULL, +/* a774 */ NULL, +/* a775 */ NULL, +/* a776 */ NULL, +/* a777 */ NULL, +/* a778 */ NULL, +/* a779 */ NULL, +/* a77a */ NULL, +/* a77b */ NULL, +/* a77c */ NULL, +/* a77d */ NULL, +/* a77e */ NULL, +/* a77f */ NULL, +/* a780 */ NULL, +/* a781 */ NULL, +/* a782 */ NULL, +/* a783 */ NULL, +/* a784 */ NULL, +/* a785 */ NULL, +/* a786 */ NULL, +/* a787 */ NULL, +/* a788 */ NULL, +/* a789 */ NULL, +/* a78a */ NULL, +/* a78b */ NULL, +/* a78c */ NULL, +/* a78d */ NULL, +/* a78e */ NULL, +/* a78f */ NULL, +/* a790 */ NULL, +/* a791 */ NULL, +/* a792 */ NULL, +/* a793 */ NULL, +/* a794 */ NULL, +/* a795 */ NULL, +/* a796 */ NULL, +/* a797 */ NULL, +/* a798 */ NULL, +/* a799 */ NULL, +/* a79a */ NULL, +/* a79b */ NULL, +/* a79c */ NULL, +/* a79d */ NULL, +/* a79e */ NULL, +/* a79f */ NULL, +/* a7a0 */ NULL, +/* a7a1 */ NULL, +/* a7a2 */ NULL, +/* a7a3 */ NULL, +/* a7a4 */ NULL, +/* a7a5 */ NULL, +/* a7a6 */ NULL, +/* a7a7 */ NULL, +/* a7a8 */ NULL, +/* a7a9 */ NULL, +/* a7aa */ NULL, +/* a7ab */ NULL, +/* a7ac */ NULL, +/* a7ad */ "_GetGestaltProcPtr", +/* a7ae */ NULL, +/* a7af */ NULL, +/* a7b0 */ NULL, +/* a7b1 */ NULL, +/* a7b2 */ NULL, +/* a7b3 */ NULL, +/* a7b4 */ NULL, +/* a7b5 */ NULL, +/* a7b6 */ NULL, +/* a7b7 */ NULL, +/* a7b8 */ NULL, +/* a7b9 */ NULL, +/* a7ba */ NULL, +/* a7bb */ NULL, +/* a7bc */ NULL, +/* a7bd */ NULL, +/* a7be */ NULL, +/* a7bf */ NULL, +/* a7c0 */ NULL, +/* a7c1 */ NULL, +/* a7c2 */ NULL, +/* a7c3 */ NULL, +/* a7c4 */ NULL, +/* a7c5 */ NULL, +/* a7c6 */ NULL, +/* a7c7 */ NULL, +/* a7c8 */ NULL, +/* a7c9 */ NULL, +/* a7ca */ NULL, +/* a7cb */ NULL, +/* a7cc */ NULL, +/* a7cd */ NULL, +/* a7ce */ NULL, +/* a7cf */ NULL, +/* a7d0 */ NULL, +/* a7d1 */ NULL, +/* a7d2 */ NULL, +/* a7d3 */ NULL, +/* a7d4 */ NULL, +/* a7d5 */ NULL, +/* a7d6 */ NULL, +/* a7d7 */ NULL, +/* a7d8 */ NULL, +/* a7d9 */ NULL, +/* a7da */ NULL, +/* a7db */ NULL, +/* a7dc */ NULL, +/* a7dd */ NULL, +/* a7de */ NULL, +/* a7df */ NULL, +/* a7e0 */ NULL, +/* a7e1 */ NULL, +/* a7e2 */ NULL, +/* a7e3 */ NULL, +/* a7e4 */ NULL, +/* a7e5 */ NULL, +/* a7e6 */ NULL, +/* a7e7 */ NULL, +/* a7e8 */ NULL, +/* a7e9 */ NULL, +/* a7ea */ NULL, +/* a7eb */ NULL, +/* a7ec */ NULL, +/* a7ed */ NULL, +/* a7ee */ NULL, +/* a7ef */ NULL, +/* a7f0 */ NULL, +/* a7f1 */ NULL, +/* a7f2 */ NULL, +/* a7f3 */ NULL, +/* a7f4 */ NULL, +/* a7f5 */ NULL, +/* a7f6 */ NULL, +/* a7f7 */ NULL, +/* a7f8 */ NULL, +/* a7f9 */ NULL, +/* a7fa */ NULL, +/* a7fb */ NULL, +/* a7fc */ NULL, +/* a7fd */ NULL, +/* a7fe */ NULL, +/* a7ff */ NULL, +/* a800 */ "_SoundDispatch", +/* a801 */ "_SndDisposeChannel", +/* a802 */ "_SndAddModifier", +/* a803 */ "_SndDoCommand", +/* a804 */ "_SndDoImmediate", +/* a805 */ "_SndPlay", +/* a806 */ "_SndControl", +/* a807 */ "_SndNewChannel", +/* a808 */ "_InitProcMenu", +/* a809 */ "_GetCVariant", +/* a80a */ "_GetWVariant", +/* a80b */ "_PopUpMenuSelect", +/* a80c */ "_RGetResource", +/* a80d */ "_Count1Resources", +/* a80e */ "_Get1IxResource", +/* a80f */ "_Get1IxType", +/* a810 */ "_Unique1ID", +/* a811 */ "_TESelView", +/* a812 */ "_TEPinScroll", +/* a813 */ "_TEAutoView", +/* a814 */ "_SetFractEnable", +/* a815 */ "_SCSIDispatch", +/* a816 */ "_Pack8", +/* a817 */ "_CopyMask", +/* a818 */ "_FixATan2", +/* a819 */ "_XMunger", +/* a81a */ "_HOpenResFile", +/* a81b */ "_HCreateResFile", +/* a81c */ "_Count1Types", +/* a81d */ "_InvalMenuBar", +/* a81e */ NULL, +/* a81f */ "_Get1Resource", +/* a820 */ "_Get1NamedResource", +/* a821 */ "_MaxSizeRsrc", +/* a822 */ "_ResourceDispatch", +/* a823 */ "_AliasDispatch", +/* a824 */ NULL, +/* a825 */ NULL, +/* a826 */ "_InsMenuItem", +/* a827 */ "_HideDItem", +/* a828 */ "_ShowDItem", +/* a829 */ "_LayerDispatch", +/* a82a */ "_ComponentDispatch", +/* a82b */ "_Pack9", +/* a82c */ "_Pack10", +/* a82d */ "_Pack11", +/* a82e */ "_Pack12", +/* a82f */ "_Pack13", +/* a830 */ "_Pack14", +/* a831 */ "_Pack15", +/* a832 */ NULL, +/* a833 */ "_ScrnBitMap", +/* a834 */ "_SetFScaleDisable", +/* a835 */ "_FontMetrics", +/* a836 */ "_GetMaskTable", +/* a837 */ "_MeasureText", +/* a838 */ "_CalcMask", +/* a839 */ "_SeedFill", +/* a83a */ "_ZoomWindow", +/* a83b */ "_TrackBox", +/* a83c */ "_TEGetOffset", +/* a83d */ "_TEDispatch", +/* a83e */ "_TEStyleNew", +/* a83f */ "_Long2Fix", +/* a840 */ "_Fix2Long", +/* a841 */ "_Fix2Frac", +/* a842 */ "_Frac2Fix", +/* a843 */ "_Fix2X", +/* a844 */ "_X2Fix", +/* a845 */ "_Frac2X", +/* a846 */ "_X2Frac", +/* a847 */ "_FracCos", +/* a848 */ "_FracSin", +/* a849 */ "_FracSqrt", +/* a84a */ "_FracMul", +/* a84b */ "_FracDiv", +/* a84c */ "_UserDelay", +/* a84d */ "_FixDiv", +/* a84e */ "_GetItemCmd", +/* a84f */ "_SetItemCmd", +/* a850 */ "_InitCursor", +/* a851 */ "_SetCursor", +/* a852 */ "_HideCursor", +/* a853 */ "_ShowCursor", +/* a854 */ "_FontDispatch", +/* a855 */ "_ShieldCursor", +/* a856 */ "_ObscureCursor", +/* a857 */ NULL, +/* a858 */ "_BitAnd", +/* a859 */ "_BitXOr", +/* a85a */ "_BitNot", +/* a85b */ "_BitOr", +/* a85c */ "_BitShift", +/* a85d */ "_BitTst", +/* a85e */ "_BitSet", +/* a85f */ "_BitClr", +/* a860 */ "_WaitNextEvent", +/* a861 */ "_Random", +/* a862 */ "_ForeColor", +/* a863 */ "_BackColor", +/* a864 */ "_ColorBit", +/* a865 */ "_GetPixel", +/* a866 */ "_StuffHex", +/* a867 */ "_LongMul", +/* a868 */ "_FixMul", +/* a869 */ "_FixRatio", +/* a86a */ "_HiWord", +/* a86b */ "_LoWord", +/* a86c */ "_FixRound", +/* a86d */ "_InitPort", +/* a86e */ "_InitGraf", +/* a86f */ "_OpenPort", +/* a870 */ "_LocalToGlobal", +/* a871 */ "_GlobalToLocal", +/* a872 */ "_GrafDevice", +/* a873 */ "_SetPort", +/* a874 */ "_GetPort", +/* a875 */ "_SetPBits", +/* a876 */ "_PortSize", +/* a877 */ "_MovePortTo", +/* a878 */ "_SetOrigin", +/* a879 */ "_SetClip", +/* a87a */ "_GetClip", +/* a87b */ "_ClipRect", +/* a87c */ "_BackPat", +/* a87d */ "_CloseCPort", +/* a87e */ "_AddPt", +/* a87f */ "_SubPt", +/* a880 */ "_SetPt", +/* a881 */ "_EqualPt", +/* a882 */ "_StdText", +/* a883 */ "_DrawChar", +/* a884 */ "_DrawString", +/* a885 */ "_DrawText", +/* a886 */ "_TextWidth", +/* a887 */ "_TextFont", +/* a888 */ "_TextFace", +/* a889 */ "_TextMode", +/* a88a */ "_TextSize", +/* a88b */ "_GetFontInfo", +/* a88c */ "_StringWidth", +/* a88d */ "_CharWidth", +/* a88e */ "_SpaceExtra", +/* a88f */ "_OSDispatch", +/* a890 */ "_StdLine", +/* a891 */ "_LineTo", +/* a892 */ "_Line", +/* a893 */ "_MoveTo", +/* a894 */ "_Move", +/* a895 */ "_ShutDown", +/* a896 */ "_HidePen", +/* a897 */ "_ShowPen", +/* a898 */ "_GetPenState", +/* a899 */ "_SetPenState", +/* a89a */ "_GetPen", +/* a89b */ "_PenSize", +/* a89c */ "_PenMode", +/* a89d */ "_PenPat", +/* a89e */ "_PenNormal", +/* a89f */ "_Unimplemented", +/* a8a0 */ "_StdRect", +/* a8a1 */ "_FrameRect", +/* a8a2 */ "_PaintRect", +/* a8a3 */ "_EraseRect", +/* a8a4 */ "_InverRect", +/* a8a5 */ "_FillRect", +/* a8a6 */ "_EqualRect", +/* a8a7 */ "_SetRect", +/* a8a8 */ "_OffsetRect", +/* a8a9 */ "_InsetRect", +/* a8aa */ "_SectRect", +/* a8ab */ "_UnionRect", +/* a8ac */ "_Pt2Rect", +/* a8ad */ "_PtInRect", +/* a8ae */ "_EmptyRect", +/* a8af */ "_StdRRect", +/* a8b0 */ "_FrameRoundRect", +/* a8b1 */ "_PaintRoundRect", +/* a8b2 */ "_EraseRoundRect", +/* a8b3 */ "_InverRoundRect", +/* a8b4 */ "_FillRoundRect", +/* a8b5 */ "_ScriptUtil", +/* a8b6 */ "_StdOval", +/* a8b7 */ "_FrameOval", +/* a8b8 */ "_PaintOval", +/* a8b9 */ "_EraseOval", +/* a8ba */ "_InvertOval", +/* a8bb */ "_FillOval", +/* a8bc */ "_SlopeFromAngle", +/* a8bd */ "_StdArc", +/* a8be */ "_FrameArc", +/* a8bf */ "_PaintArc", +/* a8c0 */ "_EraseArc", +/* a8c1 */ "_InvertArc", +/* a8c2 */ "_FillArc", +/* a8c3 */ "_PtToAngle", +/* a8c4 */ "_AngleFromSlope", +/* a8c5 */ "_StdPoly", +/* a8c6 */ "_FramePoly", +/* a8c7 */ "_PaintPoly", +/* a8c8 */ "_ErasePoly", +/* a8c9 */ "_InvertPoly", +/* a8ca */ "_FillPoly", +/* a8cb */ "_OpenPoly", +/* a8cc */ "_ClosePoly", +/* a8cd */ "_KillPoly", +/* a8ce */ "_OffsetPoly", +/* a8cf */ "_PackBits", +/* a8d0 */ "_UnpackBits", +/* a8d1 */ "_StdRgn", +/* a8d2 */ "_FrameRgn", +/* a8d3 */ "_PaintRgn", +/* a8d4 */ "_EraseRgn", +/* a8d5 */ "_InverRgn", +/* a8d6 */ "_FillRgn", +/* a8d7 */ "_BitMapToRegion", +/* a8d8 */ "_NewRgn", +/* a8d9 */ "_DisposeRgn", +/* a8da */ "_OpenRgn", +/* a8db */ "_CloseRgn", +/* a8dc */ "_CopyRgn", +/* a8dd */ "_SetEmptyRgn", +/* a8de */ "_SetRecRgn", +/* a8df */ "_RectRgn", +/* a8e0 */ "_OffsetRgn", +/* a8e1 */ "_InsetRgn", +/* a8e2 */ "_EmptyRgn", +/* a8e3 */ "_EqualRgn", +/* a8e4 */ "_SectRgn", +/* a8e5 */ "_UnionRgn", +/* a8e6 */ "_DiffRgn", +/* a8e7 */ "_XOrRgn", +/* a8e8 */ "_PtInRgn", +/* a8e9 */ "_RectInRgn", +/* a8ea */ "_SetStdProcs", +/* a8eb */ "_StdBits", +/* a8ec */ "_CopyBits", +/* a8ed */ "_StdTxMeas", +/* a8ee */ "_StdGetPic", +/* a8ef */ "_ScrollRect", +/* a8f0 */ "_StdPutPic", +/* a8f1 */ "_StdComment", +/* a8f2 */ "_PicComment", +/* a8f3 */ "_OpenPicture", +/* a8f4 */ "_ClosePicture", +/* a8f5 */ "_KillPicture", +/* a8f6 */ "_DrawPicture", +/* a8f7 */ "_Layout", +/* a8f8 */ "_ScalePt", +/* a8f9 */ "_MapPt", +/* a8fa */ "_MapRect", +/* a8fb */ "_MapRgn", +/* a8fc */ "_MapPoly", +/* a8fd */ "_PrGlue", +/* a8fe */ "_InitFonts", +/* a8ff */ "_GetFName", +/* a900 */ "_GetFNum", +/* a901 */ "_FMSwapFont", +/* a902 */ "_RealFont", +/* a903 */ "_SetFontLock", +/* a904 */ "_DrawGrowIcon", +/* a905 */ "_DragGrayRgn", +/* a906 */ "_NewString", +/* a907 */ "_SetString", +/* a908 */ "_ShowHide", +/* a909 */ "_CalcVis", +/* a90a */ "_CalcVBehind", +/* a90b */ "_ClipAbove", +/* a90c */ "_PaintOne", +/* a90d */ "_PaintBehind", +/* a90e */ "_SaveOld", +/* a90f */ "_DrawNew", +/* a910 */ "_GetWMgrPort", +/* a911 */ "_CheckUpDate", +/* a912 */ "_InitWindows", +/* a913 */ "_NewWindow", +/* a914 */ "_DisposeWindow", +/* a915 */ "_ShowWindow", +/* a916 */ "_HideWindow", +/* a917 */ "_GetWRefCon", +/* a918 */ "_SetWRefCon", +/* a919 */ "_GetWTitle", +/* a91a */ "_SetWTitle", +/* a91b */ "_MoveWindow", +/* a91c */ "_HiliteWindow", +/* a91d */ "_SizeWindow", +/* a91e */ "_TrackGoAway", +/* a91f */ "_SelectWindow", +/* a920 */ "_BringToFront", +/* a921 */ "_SendBehind", +/* a922 */ "_BeginUpDate", +/* a923 */ "_EndUpDate", +/* a924 */ "_FrontWindow", +/* a925 */ "_DragWindow", +/* a926 */ "_DragTheRgn", +/* a927 */ "_InvalRgn", +/* a928 */ "_InvalRect", +/* a929 */ "_ValidRgn", +/* a92a */ "_ValidRect", +/* a92b */ "_GrowWindow", +/* a92c */ "_FindWindow", +/* a92d */ "_CloseWindow", +/* a92e */ "_SetWindowPic", +/* a92f */ "_GetWindowPic", +/* a930 */ "_InitMenus", +/* a931 */ "_NewMenu", +/* a932 */ "_DisposeMenu", +/* a933 */ "_AppendMenu", +/* a934 */ "_ClearMenuBar", +/* a935 */ "_InsertMenu", +/* a936 */ "_DeleteMenu", +/* a937 */ "_DrawMenuBar", +/* a938 */ "_HiliteMenu", +/* a939 */ "_EnableItem", +/* a93a */ "_DisableItem", +/* a93b */ "_GetMenuBar", +/* a93c */ "_SetMenuBar", +/* a93d */ "_MenuSelect", +/* a93e */ "_MenuKey", +/* a93f */ "_GetItmIcon", +/* a940 */ "_SetItmIcon", +/* a941 */ "_GetItmStyle", +/* a942 */ "_SetItmStyle", +/* a943 */ "_GetItmMark", +/* a944 */ "_SetItmMark", +/* a945 */ "_CheckItem", +/* a946 */ "_GetItem", +/* a947 */ "_SetItem", +/* a948 */ "_CalcMenuSize", +/* a949 */ "_GetMHandle", +/* a94a */ "_SetMFlash", +/* a94b */ "_PlotIcon", +/* a94c */ "_FlashMenuBar", +/* a94d */ "_AddResMenu", +/* a94e */ "_PinRect", +/* a94f */ "_DeltaPoint", +/* a950 */ "_CountMItems", +/* a951 */ "_InsertResMenu", +/* a952 */ "_DelMenuItem", +/* a953 */ "_UpdtControl", +/* a954 */ "_NewControl", +/* a955 */ "_DisposeControl", +/* a956 */ "_KillControls", +/* a957 */ "_ShowControl", +/* a958 */ "_HideControl", +/* a959 */ "_MoveControl", +/* a95a */ "_GetCRefCon", +/* a95b */ "_SetCRefCon", +/* a95c */ "_SizeControl", +/* a95d */ "_HiliteControl", +/* a95e */ "_GetCTitle", +/* a95f */ "_SetCTitle", +/* a960 */ "_GetCtlValue", +/* a961 */ "_GetMinCtl", +/* a962 */ "_GetMaxCtl", +/* a963 */ "_SetCtlValue", +/* a964 */ "_SetMinCtl", +/* a965 */ "_SetMaxCtl", +/* a966 */ "_TestControl", +/* a967 */ "_DragControl", +/* a968 */ "_TrackControl", +/* a969 */ "_DrawControls", +/* a96a */ "_GetCtlAction", +/* a96b */ "_SetCtlAction", +/* a96c */ "_FindControl", +/* a96d */ "_Draw1Control", +/* a96e */ "_Dequeue", +/* a96f */ "_Enqueue", +/* a970 */ "_GetNextEvent", +/* a971 */ "_EventAvail", +/* a972 */ "_GetMouse", +/* a973 */ "_StillDown", +/* a974 */ "_Button", +/* a975 */ "_TickCount", +/* a976 */ "_GetKeys", +/* a977 */ "_WaitMouseUp", +/* a978 */ "_UpdtDialog", +/* a979 */ "_CouldDialog", +/* a97a */ "_FreeDialog", +/* a97b */ "_InitDialogs", +/* a97c */ "_GetNewDialog", +/* a97d */ "_NewDialog", +/* a97e */ "_SelIText", +/* a97f */ "_IsDialogEvent", +/* a980 */ "_DialogSelect", +/* a981 */ "_DrawDialog", +/* a982 */ "_CloseDialog", +/* a983 */ "_DisposeDialog", +/* a984 */ "_FindDItem", +/* a985 */ "_Alert", +/* a986 */ "_StopAlert", +/* a987 */ "_NoteAlert", +/* a988 */ "_CautionAlert", +/* a989 */ "_CouldAlert", +/* a98a */ "_FreeAlert", +/* a98b */ "_ParamText", +/* a98c */ "_ErrorSound", +/* a98d */ "_GetDItem", +/* a98e */ "_SetDItem", +/* a98f */ "_SetIText", +/* a990 */ "_GetIText", +/* a991 */ "_ModalDialog", +/* a992 */ "_DetachResource", +/* a993 */ "_SetResPurge", +/* a994 */ "_CurResFile", +/* a995 */ "_InitResources", +/* a996 */ "_RsrcZoneInit", +/* a997 */ "_OpenResFile", +/* a998 */ "_UseResFile", +/* a999 */ "_UpdateResFile", +/* a99a */ "_CloseResFile", +/* a99b */ "_SetResLoad", +/* a99c */ "_CountResources", +/* a99d */ "_GetIndResource", +/* a99e */ "_CountTypes", +/* a99f */ "_GetIndType", +/* a9a0 */ "_GetResource", +/* a9a1 */ "_GetNamedResource", +/* a9a2 */ "_LoadResource", +/* a9a3 */ "_ReleaseResource", +/* a9a4 */ "_HomeResFile", +/* a9a5 */ "_SizeRsrc", +/* a9a6 */ "_GetResAttrs", +/* a9a7 */ "_SetResAttrs", +/* a9a8 */ "_GetResInfo", +/* a9a9 */ "_SetResInfo", +/* a9aa */ "_ChangedResource", +/* a9ab */ "_AddResource", +/* a9ac */ "_AddReference", +/* a9ad */ "_RmveResource", +/* a9ae */ "_RmveReference", +/* a9af */ "_ResError", +/* a9b0 */ "_WriteResource", +/* a9b1 */ "_CreateResFile", +/* a9b2 */ "_SystemEvent", +/* a9b3 */ "_SystemClick", +/* a9b4 */ "_SystemTask", +/* a9b5 */ "_SystemMenu", +/* a9b6 */ "_OpenDeskAcc", +/* a9b7 */ "_CloseDeskAcc", +/* a9b8 */ "_GetPattern", +/* a9b9 */ "_GetCursor", +/* a9ba */ "_GetString", +/* a9bb */ "_GetIcon", +/* a9bc */ "_GetPicture", +/* a9bd */ "_GetNewWindow", +/* a9be */ "_GetNewControl", +/* a9bf */ "_GetRMenu", +/* a9c0 */ "_GetNewMBar", +/* a9c1 */ "_UniqueID", +/* a9c2 */ "_SysEdit", +/* a9c3 */ "_KeyTrans", +/* a9c4 */ "_OpenRFPerm", +/* a9c5 */ "_RsrcMapEntry", +/* a9c6 */ "_Secs2Date", +/* a9c7 */ "_Date2Secs", +/* a9c8 */ "_SysBeep", +/* a9c9 */ "_SysError", +/* a9ca */ "_PutIcon", +/* a9cb */ "_TEGetText", +/* a9cc */ "_TEInit", +/* a9cd */ "_TEDispose", +/* a9ce */ "_TextBox", +/* a9cf */ "_TESetText", +/* a9d0 */ "_TECalText", +/* a9d1 */ "_TESetSelect", +/* a9d2 */ "_TENew", +/* a9d3 */ "_TEUpdate", +/* a9d4 */ "_TEClick", +/* a9d5 */ "_TECopy", +/* a9d6 */ "_TECut", +/* a9d7 */ "_TEDelete", +/* a9d8 */ "_TEActivate", +/* a9d9 */ "_TEDeactivate", +/* a9da */ "_TEIdle", +/* a9db */ "_TEPaste", +/* a9dc */ "_TEKey", +/* a9dd */ "_TEScroll", +/* a9de */ "_TEInsert", +/* a9df */ "_TESetJust", +/* a9e0 */ "_Munger", +/* a9e1 */ "_HandToHand", +/* a9e2 */ "_PtrToXHand", +/* a9e3 */ "_PtrToHand", +/* a9e4 */ "_HandAndHand", +/* a9e5 */ "_InitPack", +/* a9e6 */ "_InitAllPacks", +/* a9e7 */ "_Pack0", +/* a9e8 */ "_Pack1", +/* a9e9 */ "_Pack2", +/* a9ea */ "_Pack3", +/* a9eb */ "_Pack4", +/* a9ec */ "_Pack5", +/* a9ed */ "_Pack6", +/* a9ee */ "_Pack7", +/* a9ef */ "_PtrAndHand", +/* a9f0 */ "_LoadSeg", +/* a9f1 */ "_UnLoadSeg", +/* a9f2 */ "_Launch", +/* a9f3 */ "_Chain", +/* a9f4 */ "_ExitToShell", +/* a9f5 */ "_GetAppParms", +/* a9f6 */ "_GetResFileAttrs", +/* a9f7 */ "_SetResFileAttrs", +/* a9f8 */ "_MethodDispatch", +/* a9f9 */ "_InfoScrap", +/* a9fa */ "_UnloadScrap", +/* a9fb */ "_LoadScrap", +/* a9fc */ "_ZeroScrap", +/* a9fd */ "_GetScrap", +/* a9fe */ "_PutScrap", +/* a9ff */ "_Debugger", +/* aa00 */ "_OpenCPort", +/* aa01 */ "_InitCPort", +/* aa02 */ NULL, +/* aa03 */ "_NewPixMap", +/* aa04 */ "_DisposePixMap", +/* aa05 */ "_CopyPixMap", +/* aa06 */ "_SetPortPix", +/* aa07 */ "_NewPixPat", +/* aa08 */ "_DisposePixPat", +/* aa09 */ "_CopyPixPat", +/* aa0a */ "_PenPixPat", +/* aa0b */ "_BackPixPat", +/* aa0c */ "_GetPixPat", +/* aa0d */ "_MakeRGBPat", +/* aa0e */ "_FillCRect", +/* aa0f */ "_FillCOval", +/* aa10 */ "_FillCRoundRect", +/* aa11 */ "_FillCArc", +/* aa12 */ "_FillCRgn", +/* aa13 */ "_FillCPoly", +/* aa14 */ "_RGBForeColor", +/* aa15 */ "_RGBBackColor", +/* aa16 */ "_SetCPixel", +/* aa17 */ "_GetCPixel", +/* aa18 */ "_GetCTable", +/* aa19 */ "_GetForeColor", +/* aa1a */ "_GetBackColor", +/* aa1b */ "_GetCCursor", +/* aa1c */ "_SetCCursor", +/* aa1d */ "_AllocCursor", +/* aa1e */ "_GetCIcon", +/* aa1f */ "_PlotCIcon", +/* aa20 */ "_OpenCPicture", +/* aa21 */ "_OpColor", +/* aa22 */ "_HiliteColor", +/* aa23 */ "_CharExtra", +/* aa24 */ "_DisposeCTable", +/* aa25 */ "_DisposeCIcon", +/* aa26 */ "_DisposeCCursor", +/* aa27 */ "_GetMaxDevice", +/* aa28 */ "_GetCTSeed", +/* aa29 */ "_GetDeviceList", +/* aa2a */ "_GetMainDevice", +/* aa2b */ "_GetNextDevice", +/* aa2c */ "_TestDeviceAttribute", +/* aa2d */ "_SetDeviceAttribute", +/* aa2e */ "_InitGDevice", +/* aa2f */ "_NewGDevice", +/* aa30 */ "_DisposeGDevice", +/* aa31 */ "_SetGDevice", +/* aa32 */ "_GetGDevice", +/* aa33 */ "_Color2Index", +/* aa34 */ "_Index2Color", +/* aa35 */ "_InvertColor", +/* aa36 */ "_RealColor", +/* aa37 */ "_GetSubTable", +/* aa38 */ "_UpdatePixMap", +/* aa39 */ "_MakeITable", +/* aa3a */ "_AddSearch", +/* aa3b */ "_AddComp", +/* aa3c */ "_SetClientID", +/* aa3d */ "_ProtectEntry", +/* aa3e */ "_ReserveEntry", +/* aa3f */ "_SetEntries", +/* aa40 */ "_QDError", +/* aa41 */ "_SetWinColor", +/* aa42 */ "_GetAuxWin", +/* aa43 */ "_SetCtlColor", +/* aa44 */ "_GetAuxCtl", +/* aa45 */ "_NewCWindow", +/* aa46 */ "_GetNewCWindow", +/* aa47 */ "_SetDeskCPat", +/* aa48 */ "_GetCWMgrPort", +/* aa49 */ "_SaveEntries", +/* aa4a */ "_RestoreEntries", +/* aa4b */ "_NewCDialog", +/* aa4c */ "_DelSearch", +/* aa4d */ "_DelComp", +/* aa4e */ "_SetStdCProcs", +/* aa4f */ "_CalcCMask", +/* aa50 */ "_SeedCFill", +/* aa51 */ "_CopyDeepMask", +/* aa52 */ "_HighLevelFSDispatch", +/* aa53 */ NULL, +/* aa54 */ NULL, +/* aa55 */ NULL, +/* aa56 */ NULL, +/* aa57 */ NULL, +/* aa58 */ NULL, +/* aa59 */ NULL, +/* aa5a */ NULL, +/* aa5b */ NULL, +/* aa5c */ NULL, +/* aa5d */ NULL, +/* aa5e */ NULL, +/* aa5f */ NULL, +/* aa60 */ "_DelMCEntries", +/* aa61 */ "_GetMCInfo", +/* aa62 */ "_SetMCInfo", +/* aa63 */ "_DispMCInfo", +/* aa64 */ "_GetMCEntry", +/* aa65 */ "_SetMCEntries", +/* aa66 */ "_MenuChoice", +/* aa67 */ "_ModalDialogMenuSetup", +/* aa68 */ "_DialogDispatch", +/* aa69 */ NULL, +/* aa6a */ NULL, +/* aa6b */ NULL, +/* aa6c */ NULL, +/* aa6d */ NULL, +/* aa6e */ NULL, +/* aa6f */ NULL, +/* aa70 */ NULL, +/* aa71 */ NULL, +/* aa72 */ NULL, +/* aa73 */ NULL, +/* aa74 */ NULL, +/* aa75 */ NULL, +/* aa76 */ NULL, +/* aa77 */ NULL, +/* aa78 */ NULL, +/* aa79 */ NULL, +/* aa7a */ NULL, +/* aa7b */ NULL, +/* aa7c */ NULL, +/* aa7d */ NULL, +/* aa7e */ NULL, +/* aa7f */ NULL, +/* aa80 */ NULL, +/* aa81 */ NULL, +/* aa82 */ NULL, +/* aa83 */ NULL, +/* aa84 */ NULL, +/* aa85 */ NULL, +/* aa86 */ NULL, +/* aa87 */ NULL, +/* aa88 */ NULL, +/* aa89 */ NULL, +/* aa8a */ NULL, +/* aa8b */ NULL, +/* aa8c */ NULL, +/* aa8d */ NULL, +/* aa8e */ NULL, +/* aa8f */ NULL, +/* aa90 */ "_InitPalettes", +/* aa91 */ "_NewPalette", +/* aa92 */ "_GetNewPalette", +/* aa93 */ "_DisposePalette", +/* aa94 */ "_ActivatePalette", +/* aa95 */ "_SetPalette", +/* aa96 */ "_GetPalette", +/* aa97 */ "_PmForeColor", +/* aa98 */ "_PmBackColor", +/* aa99 */ "_AnimateEntry", +/* aa9a */ "_AnimatePalette", +/* aa9b */ "_GetEntryColor", +/* aa9c */ "_SetEntryColor", +/* aa9d */ "_GetEntryUsage", +/* aa9e */ "_SetEntryUsage", +/* aa9f */ "_CTab2Palette", +/* aaa0 */ "_Palette2CTab", +/* aaa1 */ "_CopyPalette", +/* aaa2 */ "_PaletteDispatch", +/* aaa3 */ NULL, +/* aaa4 */ NULL, +/* aaa5 */ NULL, +/* aaa6 */ NULL, +/* aaa7 */ NULL, +/* aaa8 */ NULL, +/* aaa9 */ NULL, +/* aaaa */ NULL, +/* aaab */ NULL, +/* aaac */ NULL, +/* aaad */ NULL, +/* aaae */ NULL, +/* aaaf */ NULL, +/* aab0 */ NULL, +/* aab1 */ NULL, +/* aab2 */ NULL, +/* aab3 */ NULL, +/* aab4 */ NULL, +/* aab5 */ NULL, +/* aab6 */ NULL, +/* aab7 */ NULL, +/* aab8 */ NULL, +/* aab9 */ NULL, +/* aaba */ NULL, +/* aabb */ NULL, +/* aabc */ NULL, +/* aabd */ NULL, +/* aabe */ NULL, +/* aabf */ NULL, +/* aac0 */ NULL, +/* aac1 */ NULL, +/* aac2 */ NULL, +/* aac3 */ NULL, +/* aac4 */ NULL, +/* aac5 */ NULL, +/* aac6 */ NULL, +/* aac7 */ NULL, +/* aac8 */ NULL, +/* aac9 */ NULL, +/* aaca */ NULL, +/* aacb */ NULL, +/* aacc */ NULL, +/* aacd */ NULL, +/* aace */ NULL, +/* aacf */ NULL, +/* aad0 */ NULL, +/* aad1 */ NULL, +/* aad2 */ NULL, +/* aad3 */ NULL, +/* aad4 */ NULL, +/* aad5 */ NULL, +/* aad6 */ NULL, +/* aad7 */ NULL, +/* aad8 */ NULL, +/* aad9 */ NULL, +/* aada */ NULL, +/* aadb */ NULL, +/* aadc */ NULL, +/* aadd */ NULL, +/* aade */ NULL, +/* aadf */ NULL, +/* aae0 */ NULL, +/* aae1 */ NULL, +/* aae2 */ NULL, +/* aae3 */ NULL, +/* aae4 */ NULL, +/* aae5 */ NULL, +/* aae6 */ NULL, +/* aae7 */ NULL, +/* aae8 */ NULL, +/* aae9 */ NULL, +/* aaea */ NULL, +/* aaeb */ NULL, +/* aaec */ NULL, +/* aaed */ NULL, +/* aaee */ NULL, +/* aaef */ NULL, +/* aaf0 */ NULL, +/* aaf1 */ NULL, +/* aaf2 */ NULL, +/* aaf3 */ NULL, +/* aaf4 */ NULL, +/* aaf5 */ NULL, +/* aaf6 */ NULL, +/* aaf7 */ NULL, +/* aaf8 */ NULL, +/* aaf9 */ NULL, +/* aafa */ NULL, +/* aafb */ NULL, +/* aafc */ NULL, +/* aafd */ NULL, +/* aafe */ NULL, +/* aaff */ NULL, +/* ab00 */ NULL, +/* ab01 */ NULL, +/* ab02 */ NULL, +/* ab03 */ NULL, +/* ab04 */ NULL, +/* ab05 */ NULL, +/* ab06 */ NULL, +/* ab07 */ NULL, +/* ab08 */ NULL, +/* ab09 */ NULL, +/* ab0a */ NULL, +/* ab0b */ NULL, +/* ab0c */ NULL, +/* ab0d */ NULL, +/* ab0e */ NULL, +/* ab0f */ NULL, +/* ab10 */ NULL, +/* ab11 */ NULL, +/* ab12 */ NULL, +/* ab13 */ NULL, +/* ab14 */ NULL, +/* ab15 */ NULL, +/* ab16 */ NULL, +/* ab17 */ NULL, +/* ab18 */ NULL, +/* ab19 */ NULL, +/* ab1a */ NULL, +/* ab1b */ NULL, +/* ab1c */ NULL, +/* ab1d */ "_QDExtensions", +/* ab1e */ NULL, +/* ab1f */ NULL, +/* ab20 */ NULL, +/* ab21 */ NULL, +/* ab22 */ NULL, +/* ab23 */ NULL, +/* ab24 */ NULL, +/* ab25 */ NULL, +/* ab26 */ NULL, +/* ab27 */ NULL, +/* ab28 */ NULL, +/* ab29 */ NULL, +/* ab2a */ NULL, +/* ab2b */ NULL, +/* ab2c */ NULL, +/* ab2d */ NULL, +/* ab2e */ NULL, +/* ab2f */ NULL, +/* ab30 */ NULL, +/* ab31 */ NULL, +/* ab32 */ NULL, +/* ab33 */ NULL, +/* ab34 */ NULL, +/* ab35 */ NULL, +/* ab36 */ NULL, +/* ab37 */ NULL, +/* ab38 */ NULL, +/* ab39 */ NULL, +/* ab3a */ NULL, +/* ab3b */ NULL, +/* ab3c */ NULL, +/* ab3d */ NULL, +/* ab3e */ NULL, +/* ab3f */ NULL, +/* ab40 */ NULL, +/* ab41 */ NULL, +/* ab42 */ NULL, +/* ab43 */ NULL, +/* ab44 */ NULL, +/* ab45 */ NULL, +/* ab46 */ NULL, +/* ab47 */ NULL, +/* ab48 */ NULL, +/* ab49 */ NULL, +/* ab4a */ NULL, +/* ab4b */ NULL, +/* ab4c */ NULL, +/* ab4d */ NULL, +/* ab4e */ NULL, +/* ab4f */ NULL, +/* ab50 */ NULL, +/* ab51 */ NULL, +/* ab52 */ NULL, +/* ab53 */ NULL, +/* ab54 */ NULL, +/* ab55 */ NULL, +/* ab56 */ NULL, +/* ab57 */ NULL, +/* ab58 */ NULL, +/* ab59 */ NULL, +/* ab5a */ NULL, +/* ab5b */ NULL, +/* ab5c */ NULL, +/* ab5d */ NULL, +/* ab5e */ NULL, +/* ab5f */ NULL, +/* ab60 */ NULL, +/* ab61 */ NULL, +/* ab62 */ NULL, +/* ab63 */ NULL, +/* ab64 */ NULL, +/* ab65 */ NULL, +/* ab66 */ NULL, +/* ab67 */ NULL, +/* ab68 */ NULL, +/* ab69 */ NULL, +/* ab6a */ NULL, +/* ab6b */ NULL, +/* ab6c */ NULL, +/* ab6d */ NULL, +/* ab6e */ NULL, +/* ab6f */ NULL, +/* ab70 */ NULL, +/* ab71 */ NULL, +/* ab72 */ NULL, +/* ab73 */ NULL, +/* ab74 */ NULL, +/* ab75 */ NULL, +/* ab76 */ NULL, +/* ab77 */ NULL, +/* ab78 */ NULL, +/* ab79 */ NULL, +/* ab7a */ NULL, +/* ab7b */ NULL, +/* ab7c */ NULL, +/* ab7d */ NULL, +/* ab7e */ NULL, +/* ab7f */ NULL, +/* ab80 */ NULL, +/* ab81 */ NULL, +/* ab82 */ NULL, +/* ab83 */ NULL, +/* ab84 */ NULL, +/* ab85 */ NULL, +/* ab86 */ NULL, +/* ab87 */ NULL, +/* ab88 */ NULL, +/* ab89 */ NULL, +/* ab8a */ NULL, +/* ab8b */ NULL, +/* ab8c */ NULL, +/* ab8d */ NULL, +/* ab8e */ NULL, +/* ab8f */ NULL, +/* ab90 */ NULL, +/* ab91 */ NULL, +/* ab92 */ NULL, +/* ab93 */ NULL, +/* ab94 */ NULL, +/* ab95 */ NULL, +/* ab96 */ NULL, +/* ab97 */ NULL, +/* ab98 */ NULL, +/* ab99 */ NULL, +/* ab9a */ NULL, +/* ab9b */ NULL, +/* ab9c */ NULL, +/* ab9d */ NULL, +/* ab9e */ NULL, +/* ab9f */ NULL, +/* aba0 */ NULL, +/* aba1 */ NULL, +/* aba2 */ NULL, +/* aba3 */ NULL, +/* aba4 */ NULL, +/* aba5 */ NULL, +/* aba6 */ NULL, +/* aba7 */ NULL, +/* aba8 */ NULL, +/* aba9 */ NULL, +/* abaa */ NULL, +/* abab */ NULL, +/* abac */ NULL, +/* abad */ NULL, +/* abae */ NULL, +/* abaf */ NULL, +/* abb0 */ NULL, +/* abb1 */ NULL, +/* abb2 */ NULL, +/* abb3 */ NULL, +/* abb4 */ NULL, +/* abb5 */ NULL, +/* abb6 */ NULL, +/* abb7 */ NULL, +/* abb8 */ NULL, +/* abb9 */ NULL, +/* abba */ NULL, +/* abbb */ NULL, +/* abbc */ NULL, +/* abbd */ NULL, +/* abbe */ NULL, +/* abbf */ NULL, +/* abc0 */ NULL, +/* abc1 */ NULL, +/* abc2 */ NULL, +/* abc3 */ NULL, +/* abc4 */ NULL, +/* abc5 */ NULL, +/* abc6 */ NULL, +/* abc7 */ NULL, +/* abc8 */ NULL, +/* abc9 */ "_IconDispatch", +/* abca */ "_DeviceLoop", +/* abcb */ NULL, +/* abcc */ NULL, +/* abcd */ NULL, +/* abce */ NULL, +/* abcf */ NULL, +/* abd0 */ NULL, +/* abd1 */ NULL, +/* abd2 */ NULL, +/* abd3 */ NULL, +/* abd4 */ NULL, +/* abd5 */ NULL, +/* abd6 */ NULL, +/* abd7 */ NULL, +/* abd8 */ NULL, +/* abd9 */ NULL, +/* abda */ NULL, +/* abdb */ NULL, +/* abdc */ NULL, +/* abdd */ NULL, +/* abde */ NULL, +/* abdf */ NULL, +/* abe0 */ NULL, +/* abe1 */ NULL, +/* abe2 */ NULL, +/* abe3 */ NULL, +/* abe4 */ NULL, +/* abe5 */ NULL, +/* abe6 */ NULL, +/* abe7 */ NULL, +/* abe8 */ NULL, +/* abe9 */ NULL, +/* abea */ NULL, +/* abeb */ NULL, +/* abec */ NULL, +/* abed */ NULL, +/* abee */ NULL, +/* abef */ NULL, +/* abf0 */ NULL, +/* abf1 */ NULL, +/* abf2 */ NULL, +/* abf3 */ NULL, +/* abf4 */ NULL, +/* abf5 */ NULL, +/* abf6 */ NULL, +/* abf7 */ NULL, +/* abf8 */ "_StdOpcodeProc", +/* abf9 */ NULL, +/* abfa */ NULL, +/* abfb */ NULL, +/* abfc */ NULL, +/* abfd */ NULL, +/* abfe */ NULL, +/* abff */ "_DebugStr", +/* ac00 */ NULL, +/* ac01 */ NULL, +/* ac02 */ NULL, +/* ac03 */ NULL, +/* ac04 */ NULL, +/* ac05 */ NULL, +/* ac06 */ NULL, +/* ac07 */ NULL, +/* ac08 */ NULL, +/* ac09 */ NULL, +/* ac0a */ NULL, +/* ac0b */ NULL, +/* ac0c */ NULL, +/* ac0d */ NULL, +/* ac0e */ NULL, +/* ac0f */ NULL, +/* ac10 */ NULL, +/* ac11 */ NULL, +/* ac12 */ NULL, +/* ac13 */ NULL, +/* ac14 */ NULL, +/* ac15 */ NULL, +/* ac16 */ NULL, +/* ac17 */ NULL, +/* ac18 */ NULL, +/* ac19 */ NULL, +/* ac1a */ NULL, +/* ac1b */ NULL, +/* ac1c */ NULL, +/* ac1d */ NULL, +/* ac1e */ NULL, +/* ac1f */ NULL, +/* ac20 */ NULL, +/* ac21 */ NULL, +/* ac22 */ NULL, +/* ac23 */ NULL, +/* ac24 */ NULL, +/* ac25 */ NULL, +/* ac26 */ NULL, +/* ac27 */ NULL, +/* ac28 */ NULL, +/* ac29 */ NULL, +/* ac2a */ NULL, +/* ac2b */ NULL, +/* ac2c */ NULL, +/* ac2d */ NULL, +/* ac2e */ NULL, +/* ac2f */ NULL, +/* ac30 */ NULL, +/* ac31 */ NULL, +/* ac32 */ NULL, +/* ac33 */ NULL, +/* ac34 */ NULL, +/* ac35 */ NULL, +/* ac36 */ NULL, +/* ac37 */ NULL, +/* ac38 */ NULL, +/* ac39 */ NULL, +/* ac3a */ NULL, +/* ac3b */ NULL, +/* ac3c */ NULL, +/* ac3d */ NULL, +/* ac3e */ NULL, +/* ac3f */ NULL, +/* ac40 */ NULL, +/* ac41 */ NULL, +/* ac42 */ NULL, +/* ac43 */ NULL, +/* ac44 */ NULL, +/* ac45 */ NULL, +/* ac46 */ NULL, +/* ac47 */ NULL, +/* ac48 */ NULL, +/* ac49 */ NULL, +/* ac4a */ NULL, +/* ac4b */ NULL, +/* ac4c */ NULL, +/* ac4d */ NULL, +/* ac4e */ NULL, +/* ac4f */ NULL, +/* ac50 */ NULL, +/* ac51 */ NULL, +/* ac52 */ NULL, +/* ac53 */ NULL, +/* ac54 */ NULL, +/* ac55 */ NULL, +/* ac56 */ NULL, +/* ac57 */ NULL, +/* ac58 */ NULL, +/* ac59 */ NULL, +/* ac5a */ NULL, +/* ac5b */ NULL, +/* ac5c */ NULL, +/* ac5d */ NULL, +/* ac5e */ NULL, +/* ac5f */ NULL, +/* ac60 */ NULL, +/* ac61 */ NULL, +/* ac62 */ NULL, +/* ac63 */ NULL, +/* ac64 */ NULL, +/* ac65 */ NULL, +/* ac66 */ NULL, +/* ac67 */ NULL, +/* ac68 */ NULL, +/* ac69 */ NULL, +/* ac6a */ NULL, +/* ac6b */ NULL, +/* ac6c */ NULL, +/* ac6d */ NULL, +/* ac6e */ NULL, +/* ac6f */ NULL, +/* ac70 */ NULL, +/* ac71 */ NULL, +/* ac72 */ NULL, +/* ac73 */ NULL, +/* ac74 */ NULL, +/* ac75 */ NULL, +/* ac76 */ NULL, +/* ac77 */ NULL, +/* ac78 */ NULL, +/* ac79 */ NULL, +/* ac7a */ NULL, +/* ac7b */ NULL, +/* ac7c */ NULL, +/* ac7d */ NULL, +/* ac7e */ NULL, +/* ac7f */ NULL, +/* ac80 */ NULL, +/* ac81 */ NULL, +/* ac82 */ NULL, +/* ac83 */ NULL, +/* ac84 */ NULL, +/* ac85 */ NULL, +/* ac86 */ NULL, +/* ac87 */ NULL, +/* ac88 */ NULL, +/* ac89 */ NULL, +/* ac8a */ NULL, +/* ac8b */ NULL, +/* ac8c */ NULL, +/* ac8d */ NULL, +/* ac8e */ NULL, +/* ac8f */ NULL, +/* ac90 */ NULL, +/* ac91 */ NULL, +/* ac92 */ NULL, +/* ac93 */ NULL, +/* ac94 */ NULL, +/* ac95 */ NULL, +/* ac96 */ NULL, +/* ac97 */ NULL, +/* ac98 */ NULL, +/* ac99 */ NULL, +/* ac9a */ NULL, +/* ac9b */ NULL, +/* ac9c */ NULL, +/* ac9d */ NULL, +/* ac9e */ NULL, +/* ac9f */ NULL, +/* aca0 */ NULL, +/* aca1 */ NULL, +/* aca2 */ NULL, +/* aca3 */ NULL, +/* aca4 */ NULL, +/* aca5 */ NULL, +/* aca6 */ NULL, +/* aca7 */ NULL, +/* aca8 */ NULL, +/* aca9 */ NULL, +/* acaa */ NULL, +/* acab */ NULL, +/* acac */ NULL, +/* acad */ NULL, +/* acae */ NULL, +/* acaf */ NULL, +/* acb0 */ NULL, +/* acb1 */ NULL, +/* acb2 */ NULL, +/* acb3 */ NULL, +/* acb4 */ NULL, +/* acb5 */ NULL, +/* acb6 */ NULL, +/* acb7 */ NULL, +/* acb8 */ NULL, +/* acb9 */ NULL, +/* acba */ NULL, +/* acbb */ NULL, +/* acbc */ NULL, +/* acbd */ NULL, +/* acbe */ NULL, +/* acbf */ NULL, +/* acc0 */ NULL, +/* acc1 */ NULL, +/* acc2 */ NULL, +/* acc3 */ NULL, +/* acc4 */ NULL, +/* acc5 */ NULL, +/* acc6 */ NULL, +/* acc7 */ NULL, +/* acc8 */ NULL, +/* acc9 */ NULL, +/* acca */ NULL, +/* accb */ NULL, +/* accc */ NULL, +/* accd */ NULL, +/* acce */ NULL, +/* accf */ NULL, +/* acd0 */ NULL, +/* acd1 */ NULL, +/* acd2 */ NULL, +/* acd3 */ NULL, +/* acd4 */ NULL, +/* acd5 */ NULL, +/* acd6 */ NULL, +/* acd7 */ NULL, +/* acd8 */ NULL, +/* acd9 */ NULL, +/* acda */ NULL, +/* acdb */ NULL, +/* acdc */ NULL, +/* acdd */ NULL, +/* acde */ NULL, +/* acdf */ NULL, +/* ace0 */ NULL, +/* ace1 */ NULL, +/* ace2 */ NULL, +/* ace3 */ NULL, +/* ace4 */ NULL, +/* ace5 */ NULL, +/* ace6 */ NULL, +/* ace7 */ NULL, +/* ace8 */ NULL, +/* ace9 */ NULL, +/* acea */ NULL, +/* aceb */ NULL, +/* acec */ NULL, +/* aced */ NULL, +/* acee */ NULL, +/* acef */ NULL, +/* acf0 */ NULL, +/* acf1 */ NULL, +/* acf2 */ NULL, +/* acf3 */ NULL, +/* acf4 */ NULL, +/* acf5 */ NULL, +/* acf6 */ NULL, +/* acf7 */ NULL, +/* acf8 */ NULL, +/* acf9 */ NULL, +/* acfa */ NULL, +/* acfb */ NULL, +/* acfc */ NULL, +/* acfd */ NULL, +/* acfe */ NULL, +/* acff */ NULL, +/* ad00 */ NULL, +/* ad01 */ NULL, +/* ad02 */ NULL, +/* ad03 */ NULL, +/* ad04 */ NULL, +/* ad05 */ NULL, +/* ad06 */ NULL, +/* ad07 */ NULL, +/* ad08 */ NULL, +/* ad09 */ NULL, +/* ad0a */ NULL, +/* ad0b */ NULL, +/* ad0c */ NULL, +/* ad0d */ NULL, +/* ad0e */ NULL, +/* ad0f */ NULL, +/* ad10 */ NULL, +/* ad11 */ NULL, +/* ad12 */ NULL, +/* ad13 */ NULL, +/* ad14 */ NULL, +/* ad15 */ NULL, +/* ad16 */ NULL, +/* ad17 */ NULL, +/* ad18 */ NULL, +/* ad19 */ NULL, +/* ad1a */ NULL, +/* ad1b */ NULL, +/* ad1c */ NULL, +/* ad1d */ NULL, +/* ad1e */ NULL, +/* ad1f */ NULL, +/* ad20 */ NULL, +/* ad21 */ NULL, +/* ad22 */ NULL, +/* ad23 */ NULL, +/* ad24 */ NULL, +/* ad25 */ NULL, +/* ad26 */ NULL, +/* ad27 */ NULL, +/* ad28 */ NULL, +/* ad29 */ NULL, +/* ad2a */ NULL, +/* ad2b */ NULL, +/* ad2c */ NULL, +/* ad2d */ NULL, +/* ad2e */ NULL, +/* ad2f */ NULL, +/* ad30 */ NULL, +/* ad31 */ NULL, +/* ad32 */ NULL, +/* ad33 */ NULL, +/* ad34 */ NULL, +/* ad35 */ NULL, +/* ad36 */ NULL, +/* ad37 */ NULL, +/* ad38 */ NULL, +/* ad39 */ NULL, +/* ad3a */ NULL, +/* ad3b */ NULL, +/* ad3c */ NULL, +/* ad3d */ NULL, +/* ad3e */ NULL, +/* ad3f */ NULL, +/* ad40 */ NULL, +/* ad41 */ NULL, +/* ad42 */ NULL, +/* ad43 */ NULL, +/* ad44 */ NULL, +/* ad45 */ NULL, +/* ad46 */ NULL, +/* ad47 */ NULL, +/* ad48 */ NULL, +/* ad49 */ NULL, +/* ad4a */ NULL, +/* ad4b */ NULL, +/* ad4c */ NULL, +/* ad4d */ NULL, +/* ad4e */ NULL, +/* ad4f */ NULL, +/* ad50 */ NULL, +/* ad51 */ NULL, +/* ad52 */ NULL, +/* ad53 */ NULL, +/* ad54 */ NULL, +/* ad55 */ NULL, +/* ad56 */ NULL, +/* ad57 */ NULL, +/* ad58 */ NULL, +/* ad59 */ NULL, +/* ad5a */ NULL, +/* ad5b */ NULL, +/* ad5c */ NULL, +/* ad5d */ NULL, +/* ad5e */ NULL, +/* ad5f */ NULL, +/* ad60 */ NULL, +/* ad61 */ NULL, +/* ad62 */ NULL, +/* ad63 */ NULL, +/* ad64 */ NULL, +/* ad65 */ NULL, +/* ad66 */ NULL, +/* ad67 */ NULL, +/* ad68 */ NULL, +/* ad69 */ NULL, +/* ad6a */ NULL, +/* ad6b */ NULL, +/* ad6c */ NULL, +/* ad6d */ NULL, +/* ad6e */ NULL, +/* ad6f */ NULL, +/* ad70 */ NULL, +/* ad71 */ NULL, +/* ad72 */ NULL, +/* ad73 */ NULL, +/* ad74 */ NULL, +/* ad75 */ NULL, +/* ad76 */ NULL, +/* ad77 */ NULL, +/* ad78 */ NULL, +/* ad79 */ NULL, +/* ad7a */ NULL, +/* ad7b */ NULL, +/* ad7c */ NULL, +/* ad7d */ NULL, +/* ad7e */ NULL, +/* ad7f */ NULL, +/* ad80 */ NULL, +/* ad81 */ NULL, +/* ad82 */ NULL, +/* ad83 */ NULL, +/* ad84 */ NULL, +/* ad85 */ NULL, +/* ad86 */ NULL, +/* ad87 */ NULL, +/* ad88 */ NULL, +/* ad89 */ NULL, +/* ad8a */ NULL, +/* ad8b */ NULL, +/* ad8c */ NULL, +/* ad8d */ NULL, +/* ad8e */ NULL, +/* ad8f */ NULL, +/* ad90 */ NULL, +/* ad91 */ NULL, +/* ad92 */ NULL, +/* ad93 */ NULL, +/* ad94 */ NULL, +/* ad95 */ NULL, +/* ad96 */ NULL, +/* ad97 */ NULL, +/* ad98 */ NULL, +/* ad99 */ NULL, +/* ad9a */ NULL, +/* ad9b */ NULL, +/* ad9c */ NULL, +/* ad9d */ NULL, +/* ad9e */ NULL, +/* ad9f */ NULL, +/* ada0 */ NULL, +/* ada1 */ NULL, +/* ada2 */ NULL, +/* ada3 */ NULL, +/* ada4 */ NULL, +/* ada5 */ NULL, +/* ada6 */ NULL, +/* ada7 */ NULL, +/* ada8 */ NULL, +/* ada9 */ NULL, +/* adaa */ NULL, +/* adab */ NULL, +/* adac */ NULL, +/* adad */ NULL, +/* adae */ NULL, +/* adaf */ NULL, +/* adb0 */ NULL, +/* adb1 */ NULL, +/* adb2 */ NULL, +/* adb3 */ NULL, +/* adb4 */ NULL, +/* adb5 */ NULL, +/* adb6 */ NULL, +/* adb7 */ NULL, +/* adb8 */ NULL, +/* adb9 */ NULL, +/* adba */ NULL, +/* adbb */ NULL, +/* adbc */ NULL, +/* adbd */ NULL, +/* adbe */ NULL, +/* adbf */ NULL, +/* adc0 */ NULL, +/* adc1 */ NULL, +/* adc2 */ NULL, +/* adc3 */ NULL, +/* adc4 */ NULL, +/* adc5 */ NULL, +/* adc6 */ NULL, +/* adc7 */ NULL, +/* adc8 */ NULL, +/* adc9 */ NULL, +/* adca */ NULL, +/* adcb */ NULL, +/* adcc */ NULL, +/* adcd */ NULL, +/* adce */ NULL, +/* adcf */ NULL, +/* add0 */ NULL, +/* add1 */ NULL, +/* add2 */ NULL, +/* add3 */ NULL, +/* add4 */ NULL, +/* add5 */ NULL, +/* add6 */ NULL, +/* add7 */ NULL, +/* add8 */ NULL, +/* add9 */ NULL, +/* adda */ NULL, +/* addb */ NULL, +/* addc */ NULL, +/* addd */ NULL, +/* adde */ NULL, +/* addf */ NULL, +/* ade0 */ NULL, +/* ade1 */ NULL, +/* ade2 */ NULL, +/* ade3 */ NULL, +/* ade4 */ NULL, +/* ade5 */ NULL, +/* ade6 */ NULL, +/* ade7 */ NULL, +/* ade8 */ NULL, +/* ade9 */ NULL, +/* adea */ NULL, +/* adeb */ NULL, +/* adec */ NULL, +/* aded */ NULL, +/* adee */ NULL, +/* adef */ NULL, +/* adf0 */ NULL, +/* adf1 */ NULL, +/* adf2 */ NULL, +/* adf3 */ NULL, +/* adf4 */ NULL, +/* adf5 */ NULL, +/* adf6 */ NULL, +/* adf7 */ NULL, +/* adf8 */ NULL, +/* adf9 */ NULL, +/* adfa */ NULL, +/* adfb */ NULL, +/* adfc */ NULL, +/* adfd */ NULL, +/* adfe */ NULL, +/* adff */ NULL, +/* ae00 */ NULL, +/* ae01 */ NULL, +/* ae02 */ NULL, +/* ae03 */ NULL, +/* ae04 */ NULL, +/* ae05 */ NULL, +/* ae06 */ NULL, +/* ae07 */ NULL, +/* ae08 */ NULL, +/* ae09 */ NULL, +/* ae0a */ NULL, +/* ae0b */ NULL, +/* ae0c */ NULL, +/* ae0d */ NULL, +/* ae0e */ NULL, +/* ae0f */ NULL, +/* ae10 */ NULL, +/* ae11 */ NULL, +/* ae12 */ NULL, +/* ae13 */ NULL, +/* ae14 */ NULL, +/* ae15 */ NULL, +/* ae16 */ NULL, +/* ae17 */ NULL, +/* ae18 */ NULL, +/* ae19 */ NULL, +/* ae1a */ NULL, +/* ae1b */ NULL, +/* ae1c */ NULL, +/* ae1d */ NULL, +/* ae1e */ NULL, +/* ae1f */ NULL, +/* ae20 */ NULL, +/* ae21 */ NULL, +/* ae22 */ NULL, +/* ae23 */ NULL, +/* ae24 */ NULL, +/* ae25 */ NULL, +/* ae26 */ NULL, +/* ae27 */ NULL, +/* ae28 */ NULL, +/* ae29 */ NULL, +/* ae2a */ NULL, +/* ae2b */ NULL, +/* ae2c */ NULL, +/* ae2d */ NULL, +/* ae2e */ NULL, +/* ae2f */ NULL, +/* ae30 */ NULL, +/* ae31 */ NULL, +/* ae32 */ NULL, +/* ae33 */ NULL, +/* ae34 */ NULL, +/* ae35 */ NULL, +/* ae36 */ NULL, +/* ae37 */ NULL, +/* ae38 */ NULL, +/* ae39 */ NULL, +/* ae3a */ NULL, +/* ae3b */ NULL, +/* ae3c */ NULL, +/* ae3d */ NULL, +/* ae3e */ NULL, +/* ae3f */ NULL, +/* ae40 */ NULL, +/* ae41 */ NULL, +/* ae42 */ NULL, +/* ae43 */ NULL, +/* ae44 */ NULL, +/* ae45 */ NULL, +/* ae46 */ NULL, +/* ae47 */ NULL, +/* ae48 */ NULL, +/* ae49 */ NULL, +/* ae4a */ NULL, +/* ae4b */ NULL, +/* ae4c */ NULL, +/* ae4d */ NULL, +/* ae4e */ NULL, +/* ae4f */ NULL, +/* ae50 */ NULL, +/* ae51 */ NULL, +/* ae52 */ NULL, +/* ae53 */ NULL, +/* ae54 */ NULL, +/* ae55 */ NULL, +/* ae56 */ NULL, +/* ae57 */ NULL, +/* ae58 */ NULL, +/* ae59 */ NULL, +/* ae5a */ NULL, +/* ae5b */ NULL, +/* ae5c */ NULL, +/* ae5d */ NULL, +/* ae5e */ NULL, +/* ae5f */ NULL, +/* ae60 */ NULL, +/* ae61 */ NULL, +/* ae62 */ NULL, +/* ae63 */ NULL, +/* ae64 */ NULL, +/* ae65 */ NULL, +/* ae66 */ NULL, +/* ae67 */ NULL, +/* ae68 */ NULL, +/* ae69 */ NULL, +/* ae6a */ NULL, +/* ae6b */ NULL, +/* ae6c */ NULL, +/* ae6d */ NULL, +/* ae6e */ NULL, +/* ae6f */ NULL, +/* ae70 */ NULL, +/* ae71 */ NULL, +/* ae72 */ NULL, +/* ae73 */ NULL, +/* ae74 */ NULL, +/* ae75 */ NULL, +/* ae76 */ NULL, +/* ae77 */ NULL, +/* ae78 */ NULL, +/* ae79 */ NULL, +/* ae7a */ NULL, +/* ae7b */ NULL, +/* ae7c */ NULL, +/* ae7d */ NULL, +/* ae7e */ NULL, +/* ae7f */ NULL, +/* ae80 */ NULL, +/* ae81 */ NULL, +/* ae82 */ NULL, +/* ae83 */ NULL, +/* ae84 */ NULL, +/* ae85 */ NULL, +/* ae86 */ NULL, +/* ae87 */ NULL, +/* ae88 */ NULL, +/* ae89 */ NULL, +/* ae8a */ NULL, +/* ae8b */ NULL, +/* ae8c */ NULL, +/* ae8d */ NULL, +/* ae8e */ NULL, +/* ae8f */ NULL, +/* ae90 */ NULL, +/* ae91 */ NULL, +/* ae92 */ NULL, +/* ae93 */ NULL, +/* ae94 */ NULL, +/* ae95 */ NULL, +/* ae96 */ NULL, +/* ae97 */ NULL, +/* ae98 */ NULL, +/* ae99 */ NULL, +/* ae9a */ NULL, +/* ae9b */ NULL, +/* ae9c */ NULL, +/* ae9d */ NULL, +/* ae9e */ NULL, +/* ae9f */ NULL, +/* aea0 */ NULL, +/* aea1 */ NULL, +/* aea2 */ NULL, +/* aea3 */ NULL, +/* aea4 */ NULL, +/* aea5 */ NULL, +/* aea6 */ NULL, +/* aea7 */ NULL, +/* aea8 */ NULL, +/* aea9 */ NULL, +/* aeaa */ NULL, +/* aeab */ NULL, +/* aeac */ NULL, +/* aead */ NULL, +/* aeae */ NULL, +/* aeaf */ NULL, +/* aeb0 */ NULL, +/* aeb1 */ NULL, +/* aeb2 */ NULL, +/* aeb3 */ NULL, +/* aeb4 */ NULL, +/* aeb5 */ NULL, +/* aeb6 */ NULL, +/* aeb7 */ NULL, +/* aeb8 */ NULL, +/* aeb9 */ NULL, +/* aeba */ NULL, +/* aebb */ NULL, +/* aebc */ NULL, +/* aebd */ NULL, +/* aebe */ NULL, +/* aebf */ NULL, +/* aec0 */ NULL, +/* aec1 */ NULL, +/* aec2 */ NULL, +/* aec3 */ NULL, +/* aec4 */ NULL, +/* aec5 */ NULL, +/* aec6 */ NULL, +/* aec7 */ NULL, +/* aec8 */ NULL, +/* aec9 */ NULL, +/* aeca */ NULL, +/* aecb */ NULL, +/* aecc */ NULL, +/* aecd */ NULL, +/* aece */ NULL, +/* aecf */ NULL, +/* aed0 */ NULL, +/* aed1 */ NULL, +/* aed2 */ NULL, +/* aed3 */ NULL, +/* aed4 */ NULL, +/* aed5 */ NULL, +/* aed6 */ NULL, +/* aed7 */ NULL, +/* aed8 */ NULL, +/* aed9 */ NULL, +/* aeda */ NULL, +/* aedb */ NULL, +/* aedc */ NULL, +/* aedd */ NULL, +/* aede */ NULL, +/* aedf */ NULL, +/* aee0 */ NULL, +/* aee1 */ NULL, +/* aee2 */ NULL, +/* aee3 */ NULL, +/* aee4 */ NULL, +/* aee5 */ NULL, +/* aee6 */ NULL, +/* aee7 */ NULL, +/* aee8 */ NULL, +/* aee9 */ NULL, +/* aeea */ NULL, +/* aeeb */ NULL, +/* aeec */ NULL, +/* aeed */ NULL, +/* aeee */ NULL, +/* aeef */ NULL, +/* aef0 */ NULL, +/* aef1 */ NULL, +/* aef2 */ NULL, +/* aef3 */ NULL, +/* aef4 */ NULL, +/* aef5 */ NULL, +/* aef6 */ NULL, +/* aef7 */ NULL, +/* aef8 */ NULL, +/* aef9 */ NULL, +/* aefa */ NULL, +/* aefb */ NULL, +/* aefc */ NULL, +/* aefd */ NULL, +/* aefe */ NULL, +/* aeff */ NULL, +/* af00 */ NULL, +/* af01 */ NULL, +/* af02 */ NULL, +/* af03 */ NULL, +/* af04 */ NULL, +/* af05 */ NULL, +/* af06 */ NULL, +/* af07 */ NULL, +/* af08 */ NULL, +/* af09 */ NULL, +/* af0a */ NULL, +/* af0b */ NULL, +/* af0c */ NULL, +/* af0d */ NULL, +/* af0e */ NULL, +/* af0f */ NULL, +/* af10 */ NULL, +/* af11 */ NULL, +/* af12 */ NULL, +/* af13 */ NULL, +/* af14 */ NULL, +/* af15 */ NULL, +/* af16 */ NULL, +/* af17 */ NULL, +/* af18 */ NULL, +/* af19 */ NULL, +/* af1a */ NULL, +/* af1b */ NULL, +/* af1c */ NULL, +/* af1d */ NULL, +/* af1e */ NULL, +/* af1f */ NULL, +/* af20 */ NULL, +/* af21 */ NULL, +/* af22 */ NULL, +/* af23 */ NULL, +/* af24 */ NULL, +/* af25 */ NULL, +/* af26 */ NULL, +/* af27 */ NULL, +/* af28 */ NULL, +/* af29 */ NULL, +/* af2a */ NULL, +/* af2b */ NULL, +/* af2c */ NULL, +/* af2d */ NULL, +/* af2e */ NULL, +/* af2f */ NULL, +/* af30 */ NULL, +/* af31 */ NULL, +/* af32 */ NULL, +/* af33 */ NULL, +/* af34 */ NULL, +/* af35 */ NULL, +/* af36 */ NULL, +/* af37 */ NULL, +/* af38 */ NULL, +/* af39 */ NULL, +/* af3a */ NULL, +/* af3b */ NULL, +/* af3c */ NULL, +/* af3d */ NULL, +/* af3e */ NULL, +/* af3f */ NULL, +/* af40 */ NULL, +/* af41 */ NULL, +/* af42 */ NULL, +/* af43 */ NULL, +/* af44 */ NULL, +/* af45 */ NULL, +/* af46 */ NULL, +/* af47 */ NULL, +/* af48 */ NULL, +/* af49 */ NULL, +/* af4a */ NULL, +/* af4b */ NULL, +/* af4c */ NULL, +/* af4d */ NULL, +/* af4e */ NULL, +/* af4f */ NULL, +/* af50 */ NULL, +/* af51 */ NULL, +/* af52 */ NULL, +/* af53 */ NULL, +/* af54 */ NULL, +/* af55 */ NULL, +/* af56 */ NULL, +/* af57 */ NULL, +/* af58 */ NULL, +/* af59 */ NULL, +/* af5a */ NULL, +/* af5b */ NULL, +/* af5c */ NULL, +/* af5d */ NULL, +/* af5e */ NULL, +/* af5f */ NULL, +/* af60 */ NULL, +/* af61 */ NULL, +/* af62 */ NULL, +/* af63 */ NULL, +/* af64 */ NULL, +/* af65 */ NULL, +/* af66 */ NULL, +/* af67 */ NULL, +/* af68 */ NULL, +/* af69 */ NULL, +/* af6a */ NULL, +/* af6b */ NULL, +/* af6c */ NULL, +/* af6d */ NULL, +/* af6e */ NULL, +/* af6f */ NULL, +/* af70 */ NULL, +/* af71 */ NULL, +/* af72 */ NULL, +/* af73 */ NULL, +/* af74 */ NULL, +/* af75 */ NULL, +/* af76 */ NULL, +/* af77 */ NULL, +/* af78 */ NULL, +/* af79 */ NULL, +/* af7a */ NULL, +/* af7b */ NULL, +/* af7c */ NULL, +/* af7d */ NULL, +/* af7e */ NULL, +/* af7f */ NULL, +/* af80 */ NULL, +/* af81 */ NULL, +/* af82 */ NULL, +/* af83 */ NULL, +/* af84 */ NULL, +/* af85 */ NULL, +/* af86 */ NULL, +/* af87 */ NULL, +/* af88 */ NULL, +/* af89 */ NULL, +/* af8a */ NULL, +/* af8b */ NULL, +/* af8c */ NULL, +/* af8d */ NULL, +/* af8e */ NULL, +/* af8f */ NULL, +/* af90 */ NULL, +/* af91 */ NULL, +/* af92 */ NULL, +/* af93 */ NULL, +/* af94 */ NULL, +/* af95 */ NULL, +/* af96 */ NULL, +/* af97 */ NULL, +/* af98 */ NULL, +/* af99 */ NULL, +/* af9a */ NULL, +/* af9b */ NULL, +/* af9c */ NULL, +/* af9d */ NULL, +/* af9e */ NULL, +/* af9f */ NULL, +/* afa0 */ NULL, +/* afa1 */ NULL, +/* afa2 */ NULL, +/* afa3 */ NULL, +/* afa4 */ NULL, +/* afa5 */ NULL, +/* afa6 */ NULL, +/* afa7 */ NULL, +/* afa8 */ NULL, +/* afa9 */ NULL, +/* afaa */ NULL, +/* afab */ NULL, +/* afac */ NULL, +/* afad */ NULL, +/* afae */ NULL, +/* afaf */ NULL, +/* afb0 */ NULL, +/* afb1 */ NULL, +/* afb2 */ NULL, +/* afb3 */ NULL, +/* afb4 */ NULL, +/* afb5 */ NULL, +/* afb6 */ NULL, +/* afb7 */ NULL, +/* afb8 */ NULL, +/* afb9 */ NULL, +/* afba */ NULL, +/* afbb */ NULL, +/* afbc */ NULL, +/* afbd */ NULL, +/* afbe */ NULL, +/* afbf */ NULL, +/* afc0 */ NULL, +/* afc1 */ NULL, +/* afc2 */ NULL, +/* afc3 */ NULL, +/* afc4 */ NULL, +/* afc5 */ NULL, +/* afc6 */ NULL, +/* afc7 */ NULL, +/* afc8 */ NULL, +/* afc9 */ NULL, +/* afca */ NULL, +/* afcb */ NULL, +/* afcc */ NULL, +/* afcd */ NULL, +/* afce */ NULL, +/* afcf */ NULL, +/* afd0 */ NULL, +/* afd1 */ NULL, +/* afd2 */ NULL, +/* afd3 */ NULL, +/* afd4 */ NULL, +/* afd5 */ NULL, +/* afd6 */ NULL, +/* afd7 */ NULL, +/* afd8 */ NULL, +/* afd9 */ NULL, +/* afda */ NULL, +/* afdb */ NULL, +/* afdc */ NULL, +/* afdd */ NULL, +/* afde */ NULL, +/* afdf */ NULL, +/* afe0 */ NULL, +/* afe1 */ NULL, +/* afe2 */ NULL, +/* afe3 */ NULL, +/* afe4 */ NULL, +/* afe5 */ NULL, +/* afe6 */ NULL, +/* afe7 */ NULL, +/* afe8 */ NULL, +/* afe9 */ NULL, +/* afea */ NULL, +/* afeb */ NULL, +/* afec */ NULL, +/* afed */ NULL, +/* afee */ NULL, +/* afef */ NULL, +/* aff0 */ NULL, +/* aff1 */ NULL, +/* aff2 */ NULL, +/* aff3 */ NULL, +/* aff4 */ NULL, +/* aff5 */ NULL, +/* aff6 */ NULL, +/* aff7 */ NULL, +/* aff8 */ NULL, +/* aff9 */ NULL, +/* affa */ NULL, +/* affb */ NULL, +/* affc */ NULL, +/* affd */ NULL, +/* affe */ NULL, +/* afff */ NULL +}; diff --git a/core/coff.c b/core/coff.c new file mode 100644 index 0000000..7fbef60 --- /dev/null +++ b/core/coff.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2013, 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 +#include +#include "shoebill.h" +#include "coff.h" + +void symb_inorder(rb_node *cur) { + const coff_symbol *sym = (coff_symbol*)cur->value; + if (!sym) + return ; + symb_inorder(cur->left); + printf("0x%x %s\n", cur->key, sym->name); + symb_inorder(cur->right); +} + +// Given a path to a COFF binary, create a coff_file structure and return a pointer. +// God help you if you want to free it. +coff_file* coff_parser(const char *path) +{ + FILE *f; + uint8_t rawhead[20], *ptr; + uint32_t i; + coff_file *cf = NULL; + + // Open the file + f = fopen(path, "r"); + if (!f) { + printf("coff_parser: I couldn't open that binary for reading (%s)\n", path); + goto fail; + } + + // Pull out 20 bytes (the file header) + if (fread(rawhead, 20, 1, f) != 1) { + printf("coff_parser: error: this binary is missing its file header\n"); + goto fail; + } + + // Allocate a coff_file and copy in the header + cf = (coff_file*)calloc(1, sizeof(coff_file)); + ptr = rawhead; + cf->magic = be2native(&ptr, 2); + cf->num_sections = be2native(&ptr, 2); + cf->timestamp = be2native(&ptr, 4); + cf->symtab_offset = be2native(&ptr, 4); + cf->num_symbols = be2native(&ptr, 4); + cf->opt_header_len = be2native(&ptr, 2); + cf->flags = be2native(&ptr, 2); + + // A little sanity checking... + if (cf->magic != 0x150) { + printf("coff_parse: I don't recognize this magic number: 0x%04x\n", cf->magic); + goto fail; + } + else if (cf->num_sections != 3) { + //printf("coff_parse: warning: there are %u sections in this file (not 3, like I expect)\n", cf->num_sections); + // FIXME: investigate all the other possible section types + } + + // 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); + if (fread(opt, cf->opt_header_len, 1, f) != 1) { + printf("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len); + free(opt); + goto fail; + } + cf->opt_header = opt; + } + + // start pulling out sections + cf->sections = calloc(cf->num_sections, sizeof(coff_section)); + for (i=0; inum_sections; i++) { + // read the header + uint8_t rawsec[40]; + if (fread(rawsec, 40, 1, f) != 1) { + printf("coff_parse: I ran out of data pulling section #%u\n", i+1); + goto fail; + } + // and copy it into cf->sections[i] + memcpy(cf->sections[i].name, rawsec, 8); + ptr = &rawsec[8]; + cf->sections[i].p_addr = be2native(&ptr, 4); + cf->sections[i].v_addr = be2native(&ptr, 4); + cf->sections[i].sz = be2native(&ptr, 4); + cf->sections[i].data_ptr = be2native(&ptr, 4); + cf->sections[i].reloc_ptr = be2native(&ptr, 4); + cf->sections[i].line_ptr = be2native(&ptr, 4); + cf->sections[i].num_relocs = be2native(&ptr, 2); + cf->sections[i].num_lines = be2native(&ptr, 2); + cf->sections[i].flags = be2native(&ptr, 4); + + // a little bit of sanity checking: + if (cf->sections[i].v_addr != cf->sections[i].p_addr) { + //printf("coff_parse: warning: section %u's virtual_addr and physical_addr don't match: p=%x v=%x\n", + // i+1, cf->sections[i].p_addr, cf->sections[i].v_addr); + // This is okay for the unix kernel + } + } + + // pull out the corresponding raw data for each section + for (i=0; inum_sections; i++) { + uint8_t *data; + + // don't bother if there's no data + if (cf->sections[i].sz == 0) { + continue ; + } + + // don't bother if it's .bss + if (memcmp(cf->sections[i].name, ".bss\0\0\0\0", 8)==0) { + continue ; + } + + // seek to the position in the binary that holds this section's raw data + if (fseek(f, cf->sections[i].data_ptr, SEEK_SET) != 0) { + printf("coff_parse: I couldn't seek to 0x%x in section %u\n", cf->sections[i].data_ptr, i+1); + goto fail; + } + + // load the data and attach it to the section struct + data = malloc(cf->sections[i].sz); // FIXME: sz might not be a sane value + if (fread(data, cf->sections[i].sz, 1, f) != 1) { + 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); + goto fail; + } + cf->sections[i].data = data; + } + + // pull out the symbol table + + if (cf->num_symbols == 0) // if num_symbols==0, symtab_offset may be bogus + return cf; // just return + + 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); + + // Seek to the symbol table + if (fseek(f, cf->symtab_offset, SEEK_SET) != 0) { + printf("coff_parse: I couldn't seek to symtab_offset, 0x%x\n", cf->symtab_offset); + goto fail; + } + + for (i=0; i < cf->num_symbols; i++) { + uint8_t raw_symb[18]; + if (fread(raw_symb, 18, 1, f) != 1) { + printf("coff_parse: I ran out of data pulling symbol #%u\n", i+1); + goto fail; + } + + // load the name + if (*((uint32_t*)raw_symb) == 0) { + uint8_t tmp_name[256]; + uint32_t j, offset, idx = cf->symtab_offset + 18*cf->num_symbols; + for (j=4, offset=0; j<8; j++) offset = (offset<<8) | raw_symb[j]; + idx += offset; + + // printf("Loading from external: base idx=0x%x, offset=%u, addr=0x%x\n", idx-offset, offset, idx); + + if (fseek(f, idx, SEEK_SET) != 0) { + printf("coff_parse: I ran out of data pulling symbol %u's name (idx=0x%x)\n", i+1, idx); + goto fail; + } + for (j=0; (fread(&tmp_name[j], 1, 1, f)==1) && tmp_name[j]; j++) { + if (j >= 255) { + // printf("coff_parse: this symbol's name is too long: %u\n", i+1); + goto fail; + } + } + cf->symbols[i].name = malloc(j+1); + memcpy(cf->symbols[i].name, tmp_name, j); + cf->symbols[i].name[j] = 0; + fseek(f, cf->symtab_offset + (i+1)*18, SEEK_SET); + //printf("cf->symtab_offset = 0x%x, i=%u, (i+1)*18 = %u\n", + //cf->symtab_offset, i, (i+1)*18); + //printf("seeking back to 0x%x\n", cf->symtab_offset + (i+1)*18); + } + else { + uint8_t tmp_name[9]; + memcpy(tmp_name, raw_symb, 8); + tmp_name[8] = 0; + cf->symbols[i].name = strdup((char*)tmp_name); + } + + ptr = &raw_symb[8]; + cf->symbols[i].value = be2native(&ptr, 4); + cf->symbols[i].scnum = be2native(&ptr, 2); + cf->symbols[i].type = be2native(&ptr, 2); + cf->symbols[i].sclass = raw_symb[16]; + cf->symbols[i].numaux = raw_symb[17]; + + // FIXME: I need to handle numaux > 0. + + //if (cf->symbols[i].numaux > 0) { + printf("%s\n", cf->symbols[i].name); + printf("value=0x%08x scnum=0x%04x type=0x%04x sclass=0x%02x numaux=%u\n\n", + cf->symbols[i].value, cf->symbols[i].scnum, cf->symbols[i].type, cf->symbols[i].sclass, cf->symbols[i].numaux); + //} + + + if (cf->symbols[i].sclass == 2 || cf->symbols[i].sclass == 3) { + rb_insert(cf->func_tree, cf->symbols[i].value, &cf->symbols[i], NULL); + //printf("%s addr=0x%x\n", cf->symbols[i].name, cf->symbols[i].value); + } + // printf("%u: %s (class=%u)\n", i+1, cf->symbols[i].name, cf->symbols[i].sclass); + + } + + // symb_inorder(*cf->func_tree); + + // and we're done + return cf; + +fail: + if (cf) { + if (cf->opt_header) { + free(cf->opt_header); + } + if (cf->sections) { + for (i=0; inum_sections; i++) { + if (cf->sections[i].data) { + free(cf->sections[i].data); + } + } + free(cf->sections); + } + free(cf); + } + return NULL; +} + +// dump some data about a coff_file structure +void print_coff_info(coff_file *coff) +{ + char timebuf[32]; + time_t timestamp = coff->timestamp; + uint32_t i; + + printf("Magic = 0x%04x\n", coff->magic); + printf("Linked on %s", ctime_r(×tamp, timebuf)); + printf("Num sections = %u\n", coff->num_sections); + + printf("debug: num_symbols=%u, symtab_offset=0x%x\n", coff->num_symbols, coff->symtab_offset); + + for (i=0; inum_sections; i++) { + coff_section *s = &coff->sections[i]; + char name[9]; + memcpy(name, s->name, 8); + name[8] = 0; + printf("Section #%u: %s\n", i+1, name); + printf("\taddr=0x%08x, len=0x%x, (debug: paddr=0x%08x, flags=0x%08x)\n", s->v_addr, s->sz, s->p_addr, s->flags); + } +} + +coff_symbol* coff_find_symbol(coff_file *coff, const char *name) +{ + uint32_t i; + + for (i=0; i < coff->num_symbols; i++) { + if (strcmp(coff->symbols[i].name, name) == 0) + return &coff->symbols[i]; + } + return NULL; +} + +coff_symbol* coff_find_func(coff_file *coff, uint32_t addr) +{ + rb_node *cur; + coff_symbol *last = NULL; + + // printf("coff->num_symbols = %u\n", coff->num_symbols); + if (coff->num_symbols == 0) + return NULL; + cur = *coff->func_tree; + + while (cur) { + // printf("... iterating\n"); + if (addr < cur->key) + cur = cur->left; + else if (addr > cur->key) { + last = cur->value; + cur = cur->right; + } + else + return cur->value; + } + + return last; +} + + +// big endian -> native int +uint32_t be2native (uint8_t **dat, uint32_t bytes) +{ + uint32_t i, v = 0; + for (i=0; i < bytes; i++) + v = (v<<8) | (*dat)[i]; + (*dat) += bytes; + return v; +} + diff --git a/core/coff.h b/core/coff.h new file mode 100644 index 0000000..75ae594 --- /dev/null +++ b/core/coff.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef _COFF_H +#define _COFF_H + +#include +#include "redblack.h" + +typedef struct { + char *name; + uint32_t value; + uint16_t scnum, type; + uint8_t sclass, numaux; +} coff_symbol; + +// informed by http://www.delorie.com/djgpp/doc/coff/scnhdr.html +typedef struct { + char name[8]; + uint32_t p_addr; + uint32_t v_addr; + uint32_t sz; + uint32_t data_ptr; + uint32_t reloc_ptr; + uint32_t line_ptr; + uint16_t num_relocs; + uint16_t num_lines; + uint32_t flags; + + uint8_t *data; +} coff_section; + +// data for this segment appears in the file, but shouldn't be copied into memory +#define coff_copy 0x0010 +#define coff_text 0x0020 +#define coff_data 0x0040 +#define coff_bss 0x0080 + +typedef struct { + uint16_t magic; + uint16_t num_sections; + uint32_t timestamp; + uint32_t symtab_offset; + uint32_t num_symbols; + uint16_t opt_header_len; + uint16_t flags; + uint8_t *opt_header; + coff_section *sections; + rb_tree *func_tree; + coff_symbol *symbols; + +} coff_file; + +coff_symbol* coff_find_func(coff_file *coff, uint32_t addr); +coff_symbol* coff_find_symbol(coff_file *coff, const char *name); + +coff_file* coff_parser(const char *path); +uint32_t be2native (uint8_t **dat, uint32_t bytes); +void print_coff_info(coff_file *coff); + + +#endif // _COFF_H diff --git a/core/core_api.c b/core/core_api.c new file mode 100644 index 0000000..514a527 --- /dev/null +++ b/core/core_api.c @@ -0,0 +1,908 @@ +/* + * Copyright (c) 2013, 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 +#include +#include +#include +#include "shoebill.h" +#include "coff.h" +#include "core_api.h" + +static uint64_t sub_tv (const struct timeval a, const struct timeval b) +{ + + return 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() +{ + printf("[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]); + printf("[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]); + printf("[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]); + printf("[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]); + printf("[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc, + sr_s()?'S':'s', + sr_m()?'M':'m', + sr_x()?'X':'x', + sr_n()?'N':'n', + sr_z()?'Z':'z', + sr_v()?'V':'v', + sr_c()?'C':'c', + shoe.tc + ); + + printf("[vbr]%08x\n", shoe.vbr); + + printf("srp: "); + print_mmu_rp(shoe.srp); + + printf("crp: "); + print_mmu_rp(shoe.crp); + + printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n", + tc_enable(), tc_sre(), tc_fcl(), tc_ps(), tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid()); + + printf("\n"); +} + +void print_pc() +{ + char str[1024]; + uint8_t binary[32]; + uint32_t i; + uint32_t len; + const char *name = NULL; + + if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) { + uint32_t i, addr = shoe.pc % (shoe.physical_rom_size); + for (i=0; macii_rom_symbols[i].name; i++) { + if (macii_rom_symbols[i].addr > addr) { + break; + } + name = macii_rom_symbols[i].name; + } + } + else if (sr_s()) { // these symbols are only meaningful in supervisor mode + coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); + if (symb && strlen(symb->name)) + name = symb->name; + } + else { + if ((shoe.pc >= 0x10000000) && (shoe.pc < 0x20000000)) { + uint32_t i, addr = shoe.pc % (shoe.physical_rom_size); + for (i=0; macii_rom_symbols[i].name; i++) { + if (macii_rom_symbols[i].addr > addr) { + break; + } + name = macii_rom_symbols[i].name; + } + } + /*else { + coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc); + if (symb) + name = symb->name; + }*/ + } + + const uint16_t old_abort = shoe.abort; + shoe.suppress_exceptions = 1; + + for (i=0; i<32; i++) { + binary[i] = (uint8_t) lget(shoe.pc+i, 1); + } + + disassemble_inst(binary, shoe.pc, str, &len); + + printf("*0x%08x %s [ ", shoe.pc, name ? name : ""); + for (i=0; i unlocked + uint8_t is_in_drive; + uint8_t unknown_2; + uint8_t unknown_3 : 7; + uint8_t double_sided : 1; // 0 if single-sided, presumably 1 if HDD or double-sided + /* --- */ + + uint32_t next_offset; + int16_t qType; // 1 -> both dQDrvSz and dQDrvSz2 are used + int16_t dQDrive; // drive number (scsi target ID) + int16_t dQRefNum; // Driver reference number (I'm thinking -33 is the right value here) + int16_t dQFSID; // Filesystem identifier (0 is best, I think) + uint16_t dQDrvSz; // low 16 bits of numblocks + uint16_t dQDrvSz2; // high 16 bits of numblocks +}; + +/* + * Initialize the Macintosh lomem variables, or some of them anyways. + * Debugging weird errors revealed that A/UX actually cares about + * some of them. + */ +static void _init_macintosh_lomem_globals (const uint32_t offset) +{ + /* + * FIXME: explain what I'm doing here + */ + + uint32_t i; + + // Fill the entire lomem space with 0xBB to make debugging easier + // if somebody tries to read an uninitialized lomem value +// for (i=0; i<0x4000; i++) +// pset(offset + i, 1, 0xBB); + + // There are the lomem globals that matter, apparently + + pset(offset+0x12f, 1, 0x02); // CPUFlag = 0x02 (MC68020) + pset(offset+0x31a, 4, 0x00ffffff); // Lo3Bytes (always 0x00ffffff) + pset(offset+0x28e, 2, 0x3fff); // ROM85 (always 0x3fff, I think?) + // universal info ptr. is allowed to be null on Mac II, (I THINK) + 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(0xb22, 2, HWCfgFlags); // HWCfgFlags +} + + +/* + * Setup and blast the kernel_info structure into memory + * before booting A/UX. + * Side-effects: sets CPU registers d0 and a0 + */ +static void _init_kernel_info(shoebill_control_t *control, scsi_device_t *disks, uint32_t offset) +{ + struct kernel_info ki, *p; + uint32_t i, p_addr; + + p_addr = offset + 0x3c00; + p = (struct kernel_info*) (uint64_t)p_addr; + + /* + * On boot, the kernel looks for this magic constant in d0 to see whether + * the bootloader setup a kernel_info structure. + */ + shoe.d[0] = 0x536d7201; // "Smr\1"? Something version 1? + shoe.a[0] = (uint32_t)p; // Address of the kernel_info structure + + /* ----- Setup kernel info structure ------ */ + + ki.auto_magic = 0x50696773; // 'Pigs' (Pigs in space?) + + for (i=0; i<16; i++) { + ki.auto_id[i] = 0x0000ffff; + ki.auto_version[i] = 0; + } + + // FIXME: I need to stick the auto_id for each nubus card in here + // ki.auto_id[0xb] = 0x5; // Macintosh II video card has an auto_id of 5 (I guess?) + + ki.auto_command = control->aux_autoconfig; // AUTO_NONE/AUTO_CONFIG + + /* + * Note: ctrl -> SCSI controller chip + * drive -> SCSI Target ID + * partition -> partition + * cluster -> A set of partitions on a given drive + * (Used by escher/eschatology somehow) + */ + + ki.root_ctrl = control->root_ctrl; + ki.swap_ctrl = control->swap_ctrl; + + ki.root_drive = control->root_drive; + ki.swap_drive = control->swap_drive; + + ki.root_partition = control->root_partition; + ki.swap_partition = control->swap_partition; + + ki.root_cluster = control->root_cluster; + + // Find the text, data, and bss segments in the kernel + for (i = 0; i < shoe.coff->num_sections; i++) { + coff_section *s = &shoe.coff->sections[i]; + uint8_t sect; + + if (strcmp(s->name, ".text") == 0) + sect = 0; + else if (strcmp(s->name, ".data") == 0) + sect = 1; + else if (strcmp(s->name, ".bss") == 0) + sect = 2; + else + continue; + + ki.si[sect].vstart = s->v_addr; + ki.si[sect].pstart = s->p_addr; + ki.si[sect].size = s->sz; + } + + ki.machine_type = 4; // Macintosh II? + + // +4 because the DrvQEl structure has a hidden "flags" field 4 bytes below the pointer + ki.drive_queue_offset = sizeof(struct kernel_info) + 4; + + ki.ki_flags = control->aux_verbose; + ki.ki_version = 1; + + /* ----- Copy ki into memory ----- */ +#define ki_pset(_f) pset((uint32_t)&p->_f, sizeof(p->_f), ki._f) + ki_pset(auto_magic); + for (i=0; i<16; i++) { + ki_pset(auto_id[i]); + ki_pset(auto_version[i]); + } + ki_pset(auto_command); + + ki_pset(root_ctrl); + ki_pset(root_drive); + ki_pset(root_cluster); + + for (i=0; i<3; i++) { + ki_pset(si[i].vstart); + ki_pset(si[i].pstart); + ki_pset(si[i].size); + } + + ki_pset(machine_type); + ki_pset(drive_queue_offset); + ki_pset(ki_flags); + ki_pset(ki_version); + ki_pset(root_partition); + ki_pset(swap_ctrl); + ki_pset(swap_drive); + ki_pset(swap_partition); + + /* ---- Copy DrvQEl elements into memory ---- */ + // FIXME: btw, this is probably wrong. DrvQEl elements are supposed to be partitions, I think + + uint32_t addr = p_addr + sizeof(struct kernel_info); + uint32_t num_disks = 0; + for (i=0; i<7; i++) + if (disks[i].f) num_disks++; + + for (i=0; i<7; i++) { + if (disks[i].f == NULL) + continue; + + num_disks--; + + pset(addr, 4, 0x00080000); addr += 4; // magic internal flags (non-ejectable) + pset(addr, 4, num_disks ? 0x14 : 0); addr += 4; // offset to next drvqel + pset(addr, 2, 1); addr += 2; // Use both dQDrvSzs + pset(addr, 2, i | 8); addr += 2; // SCSI ID (with bit 3 always set?) + // pset(addr, 2, 0xffdf); addr += 2; // dQRefNum: not sure if this is right + pset(addr, 2, (i | 0x20) ^ 0xffff); addr += 2; // dQRefNum: not sure if this is right + pset(addr, 2, 0); addr += 2; // FSID + pset(addr, 2, disks[i].num_blocks & 0xffff); addr += 2; // low 16 bits of num_blocks + pset(addr, 2, disks[i].num_blocks >> 16); addr += 2; // high bits + } +} + +/* + * Compute the checksum for a Macintosh ROM file + */ +static uint32_t _compute_rom_checksum (const uint8_t *rom, const uint32_t len) +{ + uint32_t i, checksum; + for (i=4, checksum=0; i < len; i+=2) { + const uint16_t word = (rom[i]<<8) + rom[i+1]; + checksum += word; + } + return checksum; +} + +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); + FILE *f = fopen(control->rom_path, "r"); + + if (f == NULL) { + sprintf(control->error_msg, "Couldn't open rom path [%s]\n", control->rom_path); + goto fail; + } + + for (rom_size = 0; rom_size < (2*1024*1024); rom_size += (64*1024)) { + rom_data = (uint8_t*)realloc(rom_data, rom_size + (64*1024)); + if (fread(rom_data + rom_size, 64*1024, 1, f) != 1) + break; + } + + // Rom_size had better be a power of two + if ((rom_size & (rom_size - 1)) != 0) { + sprintf(control->error_msg, + "Rom is probably corrupt (size not a power of two %u)\n", + rom_size); + goto fail; + } + + // Check the checksum + const uint32_t computed_checksum = _compute_rom_checksum(rom_data, rom_size); + const uint32_t purported_checksum = ntohl(*(uint32_t*)rom_data); + if (computed_checksum != purported_checksum) { + sprintf(control->error_msg, + "Rom checksum doesn't match (computed=0x%08x, expected=0x%08x)\n", + computed_checksum, purported_checksum); + goto fail; + } + + *_rom_size = rom_size; + *_rom_data = rom_data; + + fclose(f); + return 1; + +fail: + if (rom_data) free(rom_data); + if (f) fclose(f); + return 0; +} + +static uint32_t _open_disk_images (shoebill_control_t *control, scsi_device_t *disks) +{ + uint32_t i; + + for (i=0; i<8; i++) { + shoe.scsi_devices[i].scsi_id = i; + shoe.scsi_devices[i].block_size = 0; + shoe.scsi_devices[i].num_blocks = 0; + shoe.scsi_devices[i].image_path = "dummy"; + shoe.scsi_devices[i].f = NULL; + } + + for (i=0; i<7; i++) { + struct stat stat_buf; + const char *path = control->scsi_devices[i].path; + + if (!path) continue; + + FILE *f = fopen(path, "r+"); + + if (f == NULL) { + sprintf(control->error_msg, "Couldn't open scsi id #%u disk [%s]\n", i, path); + goto fail; + } + + disks[i].scsi_id = i; + disks[i].f = f; + disks[i].image_path = path; + + if (fstat(fileno(f), &stat_buf)) { + sprintf(control->error_msg, "Couldn't fstat() scsi id #%u disk [%s]\n", i, path); + goto fail; + } + else if (stat_buf.st_size % 512) { + sprintf(control->error_msg, "Not aligned to 512 byte blocks: [%s]\n", path); + goto fail; + } + + disks[i].block_size = 512; + disks[i].num_blocks = stat_buf.st_size / 512; + } + + return 1; + +fail: + for (i=0; i<7; i++) + if (disks[i].f) fclose(disks[i].f); + memset(disks, 0, 7 * sizeof(scsi_device_t)); + return 0; +} + +/*static uint32_t _setup_nubus_cards(shoebill_control_t *control) +{ + uint32_t i; + + for (i=0; i<16; i++) { + switch (control->slots[i].card_type) { + case card_empty: + continue; + + case card_toby_frame_buffer: + case card_shoebill_ethernet: + assert(!"not implemented"); + + case card_shoebill_video: { + const uint16_t width = control->slots[i].card.video.width; + const uint16_t height = control->slots[i].card.video.height; + const uint16_t scanline_width = control->slots[i].card.video.scanline_width; + const double refresh_rate = control->slots[i].card.video.refresh_rate; + uint8_t *frame_buffer = control->slots[i].card.video.frame_buffer; + assert(scanline_width >= width); + + nubus_video_init(i, width, height, scanline_width, refresh_rate, frame_buffer); + + } + } + } + + return 1; + +fail: + + return 0; +}*/ + +static uint32_t _load_aux_kernel(shoebill_control_t *control, coff_file *coff, uint32_t *_pc) +{ + uint32_t j, i, pc = 0xffffffff; + for (i = 0; i < coff->num_sections; i++) { + coff_section *s = &coff->sections[i]; + + // Don't load a "copy" segment + if (s->flags & coff_copy) + continue; + + if ((s->flags & coff_text) || (s->flags & coff_data)) { + /* copy text or data section */ + + for (j = 0; j < s->sz; j++) + pset(s->p_addr+j, 1, s->data[j]); + + if (strcmp(s->name, "pstart") == 0) + pc = s->p_addr; + } + else if (s->flags & coff_bss) { + /* Create an empty .bss segment */ + + for (j = 0; j < s->sz; j++) + pset(s->p_addr+j, 1, 0); + } + } + + if (pc == 0xffffffff) { + sprintf(control->error_msg, "This unix kernel doesn't contain a pstart segment\n"); + return 0; + } + + *_pc = pc; // Entry point to the kernel + + return 1; + +fail: + return 0; +} + +uint32_t shoebill_install_video_card(shoebill_control_t *control, uint8_t slotnum, + uint16_t width, uint16_t height, + double refresh_rate) +{ + shoebill_card_video_t *ctx = &control->slots[slotnum].card.video; + + if (control->slots[slotnum].card_type != card_none) { + sprintf(control->error_msg, "This slot (%u) already has a card\n", slotnum); + return 0; + } + + // Make sure the scanline width is a multiple of 32 pixels, and is at least 32 pixels + // beyond the end of the display. If scanline_width==width, A/UX 2.0 will wrap the mouse around + // the edge of the screen. + uint32_t scanline_width = width + (32 - (width % 32)) + 32; + + scanline_width = width; // FIXME: undo this + + shoe.slots[slotnum].connected = 1; + shoe.slots[slotnum].read_func = nubus_video_read_func; + shoe.slots[slotnum].write_func = nubus_video_write_func; + shoe.slots[slotnum].interrupt_rate = refresh_rate; + shoe.slots[slotnum].last_fired = 0; + shoe.slots[slotnum].interrupts_enabled = 1; + nubus_video_init(ctx, slotnum, width, height, scanline_width, refresh_rate); + return 1; +} + +/* + * Given a config_control_t structure, configure and initialize + * the emulator. + * This is the first function you should call if you're writing an + * interface to Shoebill. + */ +uint32_t shoebill_initialize(shoebill_control_t *control) +{ + uint32_t i, j, pc = 0xffffffff; + coff_file *coff = NULL; + scsi_device_t disks[8]; + uint8_t *rom_data = NULL; + uint32_t rom_size = 0; + + memset(&disks[0], 0, 8 * sizeof(scsi_device_t)); + memset(&shoe, 0, sizeof(global_shoebill_context_t)); + + fpu_setup_jump_table(); + + // Try to load the ROM + if (control->rom_path == NULL) { + sprintf(control->error_msg, "No rom file specified\n"); + goto fail; + } + else if (!_load_rom(control, &rom_data, &rom_size)) + goto fail; + + // Try to open the disk images + if (!_open_disk_images(control, disks)) + goto fail; + + // Try to load the A/UX kernel + if (control->aux_kernel_path == NULL) { + sprintf(control->error_msg, "No A/UX kernel specified\n"); + goto fail; + } + coff = coff_parser(control->aux_kernel_path); + + if (coff == NULL) { + sprintf(control->error_msg, "Can't open that A/UX kernel [%s]\n", + control->aux_kernel_path); + goto fail; + } + shoe.coff = coff; + + + // Allocate and configure the rom and memory space + + /*if (control->ram_size > (256 * 1024 * 1024)) { + // I think A/UX will go insane if you give it >256MB of memory + sprintf(control->error_msg, "%u bytes is too much memory\n", control->ram_size); + goto fail; + } + else */if (control->ram_size < (1024*1024)) { + sprintf(control->error_msg, "%u bytes is too little ram\n", control->ram_size); + goto fail; + } + + shoe.physical_rom_size = rom_size; + shoe.physical_rom_base = valloc(rom_size); + memcpy(shoe.physical_rom_base, rom_data, rom_size); + free(rom_data); + rom_data = NULL; + + shoe.physical_mem_size = control->ram_size; + shoe.physical_mem_base = valloc(control->ram_size); + memset(shoe.physical_mem_base, 0, shoe.physical_mem_size); + + // Initialize Macintosh lomem variables that A/UX actually cares about + + #define AUX_LOMEM_OFFSET 0x50000 + _init_macintosh_lomem_globals(AUX_LOMEM_OFFSET); + + // Initialize A/UX's kernel_info structure + + _init_kernel_info(control, disks, AUX_LOMEM_OFFSET); + + // Load A/UX kernel COFF segments into memory (returns PC, the entry point into the kernel) + + if (!_load_aux_kernel(control, coff, &pc)) + goto fail; + + // HACK: +// for (i=0; i<0x4000; i++) { +// uint8_t c = pget(AUX_LOMEM_OFFSET + i, 1); +// pset(i, 1, c); +// } + + /* + * Load it all into the internal global shoebill state + * (Can't fail after this point) + */ + + // FIXME: Don't do this! Rewrite the via timers! + gettimeofday(&shoe.start_time, NULL); + shoe.total_ticks = 0; + + // Put the adb chip in state 3 (idle) + 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, via_clock_thread, NULL); + + return 1; + +fail: + if (rom_data) 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); + + // No way to free *coff yet + return 0; +} + +static void _send_key(uint8_t code) +{ + if ((shoe.key.key_i+1) < KEYBOARD_STATE_MAX_KEYS) { + shoe.key.keys[shoe.key.key_i].code_a = code; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } +} + +void shoebill_key(uint8_t down, uint8_t key) +{ + const uint8_t down_mask = down ? 0 : 0x80; + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + _send_key(key | down_mask); + + adb_request_service_request(3); + pthread_mutex_unlock(&shoe.adb.lock); +} + +void shoebill_key_modifier(uint8_t modifier_mask) +{ + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + const uint8_t changed_mask = shoe.key.last_modifier_mask ^ modifier_mask; + shoe.key.last_modifier_mask = modifier_mask; + + if (changed_mask & modShift) { + _send_key(((modifier_mask & modShift) ? 0 : 0x80) | 0x38); + } + if (changed_mask & modControl) { + _send_key(((modifier_mask & modControl) ? 0 : 0x80) | 0x36); + } + if (changed_mask & modOption) { + _send_key(((modifier_mask & modOption) ? 0 : 0x80) | 0x3a); + } + if (changed_mask & modCommand) { + _send_key(((modifier_mask & modCommand) ? 0 : 0x80) | 0x37); + } + + + adb_request_service_request(3); + pthread_mutex_unlock(&shoe.adb.lock); +} + +void shoebill_mouse_move(int32_t x, int32_t y) +{ + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + int32_t delta_x = x - shoe.mouse.old_x; + int32_t delta_y = y - shoe.mouse.old_y; + + shoe.mouse.old_x = x; + shoe.mouse.old_y = y; + + shoe.mouse.delta_x += delta_x; + shoe.mouse.delta_y += delta_y; + + shoe.mouse.changed = 1; + + adb_request_service_request(3); + pthread_mutex_unlock(&shoe.adb.lock); +} + +void shoebill_mouse_move_delta (int32_t x, int32_t y) +{ + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + shoe.mouse.delta_x += x; + shoe.mouse.delta_y += y; + + shoe.mouse.changed = 1; + + adb_request_service_request(3); + pthread_mutex_unlock(&shoe.adb.lock); +} + +void shoebill_mouse_click(uint8_t down) +{ + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + shoe.mouse.button_down = (down != 0); + shoe.mouse.changed = 1; + + adb_request_service_request(3); + + pthread_mutex_unlock(&shoe.adb.lock); +} + diff --git a/core/core_api.h b/core/core_api.h new file mode 100644 index 0000000..db08eea --- /dev/null +++ b/core/core_api.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef _CORE_API_H +#define _CORE_API_H + +#include + +typedef enum { + card_none = 0, // Empty slot + card_toby_frame_buffer, // Original Macintosh II video card + card_shoebill_video, // Fancy 21st-century Shoebill video card + card_shoebill_ethernet // FIXME: doesn't exist yet +} card_names_t; + +typedef struct { + uint8_t *frame_buffer; +} shoebill_card_tfb_t; + +typedef struct { + uint8_t r, g, b, a; +} video_ctx_color_t; + +typedef struct { + video_ctx_color_t *direct_buf, *clut; + uint8_t *indexed_buf, *rom; + + uint32_t pixels; + + uint16_t width, height, scanline_width; + + uint16_t depth, clut_idx; + + double refresh_rate; +} shoebill_card_video_t; + +typedef struct { + // Doesn't exist yet +} shoebill_card_ethernet_t; + +typedef struct { +/* + * Fill in this part of the struct + * before you call shoebill_initialize() + */ + uint32_t ram_size; + const char *rom_path; + const char *aux_kernel_path; + + uint8_t aux_verbose : 1; // Whether to boot A/UX in verbose mode + uint8_t aux_autoconfig : 1; // Whether to run A/UX autoconfig + + uint16_t root_ctrl, swap_ctrl; + uint8_t root_drive, swap_drive; + uint8_t root_partition, swap_partition; + uint8_t root_cluster; + + /* Devices at the 7 possible target SCSI ids */ + struct { + const char *path; + uint64_t size; // will be filled in later + } scsi_devices[7]; // scsi device #7 is the initiator (can't be a target) + +/* ^^^ You can stop now ^^^ */ + + /* Cards installed in the 16 (really, just 0x9 to 0xe) nubus slots */ + struct { + card_names_t card_type; + union { + shoebill_card_tfb_t tfb; + shoebill_card_video_t video; + shoebill_card_ethernet_t ethernet; + } card; + } slots[16]; + + pthread_t cpu_thread_pid, clock_pid; + + char error_msg[8192]; +} shoebill_control_t; + +uint32_t shoebill_initialize(shoebill_control_t *params); + +uint32_t shoebill_install_video_card(shoebill_control_t *control, uint8_t slotnum, + uint16_t width, uint16_t height, + double refresh_rate); + +/* + * These keyboard modifier constants match the ones used + * in NSEvent shifted right by 16 bits. + */ +enum { + modCapsLock = 1 << 0, + modShift = 1 << 1, + modControl = 1 << 2, + modOption = 1 << 3, + modCommand = 1 << 4 +}; + +void shoebill_key(uint8_t down, uint8_t key); +void shoebill_key_modifier(uint8_t modifier_mask); +void shoebill_mouse_move(int32_t x, int32_t y); +void shoebill_mouse_move_delta (int32_t x, int32_t y); +void shoebill_mouse_click(uint8_t down); + +void shoebill_start(); + +#endif diff --git a/core/cpu.c b/core/cpu.c new file mode 100644 index 0000000..8a75e11 --- /dev/null +++ b/core/cpu.c @@ -0,0 +1,3019 @@ +/* + * Copyright (c) 2013, 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 +#include "../core/shoebill.h" +#include "../core/mc68851.h" + +global_shoebill_context_t shoe; +struct dbg_state_t dbg_state; + +#define nextword() ({const uint16_t w=lget(shoe.pc,2); if (shoe.abort) {return;}; shoe.pc+=2; w;}) +#define verify_supervisor() {if (!sr_s()) {throw_privilege_violation(); return;}} + +~newmacro(inst, 2, { + # This macro encapsulates an instruction implementation + my ($name, $code) = @$args; + + my $out = "void inst_$name () {\n" . $code . "}"; + return $out; +}) + +~inst(callm, { + assert(!"callm: error, not implemented\n"); +}) + +~inst(chk2_cmp2, { + assert(!"chk2_cmp2: error: not implemented\n"); +}) + +~inst(illegal, { + assert(!"illegal: error: not implemented\n"); +}) + +~inst(move16, { + assert(!"move16: SHOULD NOT BE CALLED\n"); // shouldn't be called by 68020 decoder +}) + +~inst(rtm, { + assert(!"rtm: error: not implemented\n"); +}) + +~inst(tas, { + assert(!"tas: error: not implemented\n"); +}) + +~inst(trapcc, { + assert(!"trapcc: error: not implemented\n"); +}) + +~inst(trapv, { + assert(!"trapv: error: not implemented\n"); +}) + +~inst(asx_reg, { + ~decompose(shoe.op, 1110 ccc d ss i 00 rrr); + const uint8_t sz = 1<>= 1; + dat |= tmask; + } + set_d(r, dat, sz); + if (count) { + set_sr_x(lastb); + } + set_sr_n(mib(dat, sz)); + set_sr_z(get_d(r, sz) == 0); + set_sr_v(0); + set_sr_c(lastb); + + //printf(" result=%u\n", get_d(r, sz)); + } +}) + +~inst(asx_mem, { + ~decompose(shoe.op, 1110 000d 11 MMMMMM); + + call_ea_read(M, 2); + const uint16_t dat = shoe.dat; + if (d) { // left shift 1 bit + + const uint16_t R = dat << 1; + const uint16_t lost = (dat >> 15); + + shoe.dat = R; + call_ea_write(M, 2); + + set_sr_x(lost); + set_sr_c(lost); + set_sr_v((R >> 15) != (dat >> 15)); // set if the MSB changes (at anytime during the shift operation) + set_sr_n(R>>15); + set_sr_z(R==0); + } + else { // right shift 1 bit + const uint16_t R = (uint16_t)(((int16_t)dat) >> 1); + const uint16_t lost = dat & 1; + + printf("asr_mem: shifted 0x%04x to 0x%04x lost=%u\n", dat, R, lost); + + shoe.dat = R; + call_ea_write(M, 2); + + set_sr_x(lost); + set_sr_c(lost); + set_sr_v(0); + set_sr_n(R>>15); + set_sr_z(R==0); + } +}) + +// GCC returns garbage when you shift a value by >= its size: ((uint32_t)123)<<32) == garbage +// So we'll use macros for risky shifts +#define shiftl(_v, _b) ({const uint32_t v=(_v), b=(_b); const uint32_t r=(b>=32)?0:(v<=32)?0:(v>>b); r;}) +~inst(lsx_reg, { + ~decompose(shoe.op, 1110 ccc d ss i 01 rrr); + const uint8_t sz = 1< 1 bit + const uint16_t R = shoe.dat << 1; + const uint8_t lost = (shoe.dat >> 15); + + shoe.dat = R; + call_ea_write(M, 2); + + set_sr_x(lost); + set_sr_c(lost); + set_sr_v(0); + set_sr_n(R>>15); + set_sr_z(R==0); + } + else { // right shift 1 bit + const uint16_t R = shoe.dat>>1; + const uint8_t lost = shoe.dat & 1; + + shoe.dat = R; + call_ea_write(M, 2); + + set_sr_x(lost); + set_sr_c(lost); + set_sr_v(0); + set_sr_n(R>>15); + set_sr_z(R==0); + } +}) + +// FIXME: rox_reg and roxx_reg can be made O(1) + +~inst(roxx_reg, { + ~decompose(shoe.op, 1110 ccc d ss i 10 rrr); + + const uint8_t sz = 1<>= 1; + data |= (extend << hi_bit); + extend = carry; + } + } + else { // left + for (j=0; j>= 1; + data |= (carry << hi_bit); + } + } + else { // left + for (j=0; j>15)&1); + set_sr_z((quotient_32 & 0xffff) == 0); + set_sr_v(quotient_32 >> 16); +}) + +~inst(divs, { + ~decompose(shoe.op, 1000 rrr 111 MMMMMM); + + call_ea_read(M, 2); + + const int32_t dividend = (int32_t)shoe.d[r]; + const uint16_t u_divisor = (uint16_t)shoe.dat; + const int16_t s_divisor = (int16_t)shoe.dat; + + if (s_divisor == 0) { + throw_divide_by_zero(); + return ; + } + + call_ea_read_commit(M, 2); + + const int32_t s_quotient_32 = dividend / s_divisor; + const int32_t s_remainder_32 = dividend % s_divisor; + + const uint32_t u_quotient_32 = (uint32_t)s_quotient_32; + const uint32_t u_remainder_32 = (uint32_t)s_remainder_32; + + shoe.d[r] = (u_remainder_32 << 16) | (u_quotient_32 & 0xffff); + + set_sr_c(0); + set_sr_n((u_quotient_32>>15)&1); + set_sr_z((u_quotient_32 & 0xffff) == 0); + set_sr_v(u_quotient_32 >> 16); +}) + +~inst(bkpt, { + assert(!"Hey! inst_bkpt isn't implemented!\n"); +}) + +~inst(swap, { + ~decompose(shoe.op, 0100 1000 0100 0 rrr); + shoe.d[r] = (shoe.d[r]>>16) | (shoe.d[r]<<16); + set_sr_c(0); + set_sr_v(0); + set_sr_z(shoe.d[r]==0); + set_sr_n(mib(shoe.d[r], 4)); +}) + +~inst(abcd, { + ~decompose(shoe.op, 1100 xxx 10000 m yyy); + uint8_t packed_x, packed_y; + const uint8_t extend = sr_x() ? 1 : 0; + + // printf("abcd: pc=0x%08x extend=%u m=%u x=%u y=%u\n", shoe.orig_pc, extend, m, x, y); + + if (m) { + // predecrement mem to predecrement mem + // FIXME: these addresses aren't predecremented (check whether a7 is incremented 2 bytes) + assert(!"acbd is broken"); + packed_x = lget(shoe.a[x], 1); + if (shoe.abort) return ; + packed_y = lget(shoe.a[y], 1); + if (shoe.abort) return ; + } + else { + packed_x = shoe.d[x] & 0xff; + packed_y = shoe.d[y] & 0xff; + } + + if (((packed_x & 0xF) > 9) || (((packed_x>>4) & 0xF) > 9) || ((packed_y & 0xF) > 9) || (((packed_y>>4) & 0xF) > 9)) + assert(!"abcd: badly packed byte"); + + const uint8_t unpacked_x = (packed_x & 0xf) + ((packed_x >> 4) * 10); + const uint8_t unpacked_y = (packed_y & 0xf) + ((packed_y >> 4) * 10); + const uint8_t sum = unpacked_x + unpacked_y + extend; + const uint8_t unpacked_sum = sum % 100; + const uint8_t carry = (sum >= 100); + const uint8_t packed_sum = ((unpacked_sum / 10) << 4) | (unpacked_sum % 10); + + // printf("abcd: packed_x = 0x%02x(%u) packed_y = 0x%02x(%u) sum=0x%02x(%u) carry=%u\n", packed_x, unpacked_x, packed_y, unpacked_y, packed_sum, unpacked_sum, carry); + + if (unpacked_sum) + set_sr_z(0); + set_sr_c(carry); + set_sr_x(carry); + + if (m) { + lset(shoe.a[x]-1, 1, packed_sum); + if (shoe.abort) return ; + + shoe.a[x]--; + if (x != y) + shoe.a[y]--; + } + else { + set_d(x, packed_sum, 1); + } + +}) + +~inst(muls, { + ~decompose(shoe.op, 1100 rrr 011 MMMMMM); + + call_ea_read(M, 2); + call_ea_read_commit(M, 2); + + const uint16_t u_a = get_d(r, 2); + const uint16_t u_b = shoe.dat; + const int16_t s_a = (int16_t)u_a; + const int16_t s_b = (int16_t)u_b; + + const int32_t s_result = ((int32_t)s_a) * ((int32_t)s_b); + const uint32_t result = (uint32_t)s_result; + + //printf("muls: %d * %d = %d\n", s_a, s_b, s_result); + + shoe.d[r] = result; + + set_sr_c(0); + set_sr_v(0); + set_sr_z(result == 0); + set_sr_n(mib(result, 4)); +}) + +/* short form unsigned multiply */ +~inst(mulu, { + ~decompose(shoe.op, 1100 rrr 011 MMMMMM); + + call_ea_read(M, 2); + call_ea_read_commit(M, 2); + + const uint16_t a = (uint16_t) get_d(r, 2); + const uint16_t b = (uint16_t) shoe.dat; + const uint32_t result = ((uint32_t)a) * ((uint32_t)b); + + shoe.d[r] = result; + + set_sr_c(0); + set_sr_v(0); + set_sr_z(result == 0); + set_sr_n(mib(result, 4)); +}) + +~inst(exg, { + ~decompose(shoe.op, 1100 xxx 1 ppppp yyy); + + if (p == ~b(01000)) { // data reg mode + const uint32_t tmp = shoe.d[x]; + shoe.d[x] = shoe.d[y]; + shoe.d[y] = tmp; + } + else if (p == ~b(01001)) { // address reg mode + const uint32_t tmp = shoe.a[x]; + shoe.a[x] = shoe.a[y]; + shoe.a[y] = tmp; + } + else if (p == ~b(10001)) { // addr/reg mode + const uint32_t tmp = shoe.d[x]; + shoe.d[x] = shoe.a[y]; + shoe.a[y] = tmp; + } + else { + // I'm not sure whether decode.c will map opcodes with other modes here + assert(!"inst_exg: bad op mode"); + } +}) + +~inst(stop, { + verify_supervisor(); + + const uint16_t ext = nextword(); + set_sr(ext); + + shoe.cpu_thread_notifications |= SHOEBILL_STATE_STOPPED; +}) + +~inst(rtr, { + const uint16_t ccr = lget(shoe.a[7], 2); + if (shoe.abort) return ; + + const uint32_t pc = lget(shoe.a[7]+2, 4); + if (shoe.abort) return ; + + shoe.a[7] += 6; + + // We don't need to use sr_set() here because only changing the condition codes + shoe.sr = (shoe.sr & 0xff00) | (ccr & 0x00ff); + shoe.pc = pc; +}) + +~inst(rtd, { + const int16_t disp = nextword(); + const uint32_t new_pc = lget(shoe.a[7], 4); + if (shoe.abort) return ; + + shoe.pc = new_pc; + shoe.a[7] += 4; + shoe.a[7] += disp; +}) + +~inst(rte, { + verify_supervisor(); + + const uint16_t sr = lget(shoe.a[7], 2); + if (shoe.abort) return ; + + const uint32_t pc = lget(shoe.a[7]+2, 4); + if (shoe.abort) return ; + + 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); + + switch (format_word >> 12) { + case 0: + case 1: { + shoe.a[7] += 8; + shoe.pc = pc; + set_sr(sr); + return ; + } + case 0xa: { + // FIXME: I should probably check the special status word here + shoe.a[7] += 16 * 2; + shoe.pc = pc; + set_sr(sr); + return ; + } + case 0xb: { + //FIXME: Check the special status word + version + shoe.a[7] += 46 * 2; + shoe.pc = pc; + set_sr(sr); + return ; + } + default: + printf("rte?? I don't recognize this exception format! 0x%04x\n", format_word); + assert(!"rte?? Don't recognize this exception format!\n"); + break; + } + +}) + +~inst(move_usp, { + verify_supervisor(); + ~decompose(shoe.op, 0100 1110 0110 d rrr); + + if (d) { + make_stack_pointers_valid(); + shoe.a[r] = shoe.usp; + } + else { + make_stack_pointers_valid(); + shoe.usp = shoe.a[r]; + load_stack_pointer(); + } +}) + +~inst(and, { + ~decompose(shoe.op, 1100 rrr dss MMMMMM); + const uint8_t sz = 1< -> + // S D R + call_ea_read(M, sz); + const uint32_t R = chop(shoe.dat & shoe.d[r], sz); + shoe.dat = R; + call_ea_write(M, sz); + + set_sr_c(0); + set_sr_v(0); + set_sr_z(R==0); + set_sr_n(mib(R, sz)); + return ; + } + else { + // ^ Dn -> Dn + // S D R + call_ea_read(M, sz); + call_ea_read_commit(M, sz); + + const uint32_t R = chop(shoe.dat & shoe.d[r], sz); + set_d(r, R, sz); + + set_sr_c(0); + set_sr_v(0); + set_sr_z(R==0); + set_sr_n(mib(R, sz)); + return ; + } +}) + +~inst(or, { + ~decompose(shoe.op, 1000 rrr dss MMMMMM); + const uint8_t sz = 1< -> + // S D R + call_ea_read(M, sz); + const uint32_t R = chop(shoe.dat | shoe.d[r], sz); + shoe.dat = R; + call_ea_write(M, sz); + + set_sr_c(0); + set_sr_v(0); + set_sr_z(R==0); + set_sr_n(mib(R, sz)); + return ; + } + else { + // V Dn -> Dn + // S D R + call_ea_read(M, sz); + call_ea_read_commit(M, sz); + + const uint32_t R = chop(shoe.dat | shoe.d[r], sz); + set_d(r, R, sz); + + set_sr_c(0); + set_sr_v(0); + set_sr_z(R==0); + set_sr_n(mib(R, sz)); + return ; + } +}) + + +~inst(moveq, { + ~decompose(shoe.op, 0111 rrr 0 dddddddd); + const int32_t dat = ((int8_t)d); + shoe.d[r] = dat; + set_sr_c(0); + set_sr_v(0); + set_sr_z(d==0); + set_sr_n(d>>7); + // printf("dat = %x, shoe.d[%u] = %x\n", dat, r, shoe.d[r]); + // printf("I'm called, right?\n"); +}) + +~inst(add, { + ~decompose(shoe.op, 1101 rrr d ss MMMMMM); + const uint8_t sz = 1<, result is + Sm = mib(shoe.d[r], sz); + Dm = mib(shoe.dat, sz); + shoe.dat += get_d(r, sz); + set_sr_z(chop(shoe.dat, sz) == 0); + Rm = mib(shoe.dat, sz); + call_ea_write(M, sz); + } + else { // store the result in d[r] + // source is , dest in Dn, result is Dn + Sm = mib(shoe.dat, sz); + Dm = mib(shoe.d[r], sz); + const uint32_t R = shoe.dat + get_d(r, sz); + set_sr_z(chop(R, sz) == 0); + Rm = mib(R, sz); + set_d(r, R, sz); + call_ea_read_commit(M, sz); + } + set_sr_v((Sm && Dm && !Rm) || (!Sm && !Dm && Rm)); + set_sr_c((Sm && Dm) || (!Rm && Dm) || (Sm && !Rm)); + set_sr_x(sr_c()); + set_sr_n(Rm); +}) + +~inst(adda, { + ~decompose(shoe.op, 1101 rrr s11 MMMMMM) + const uint8_t sz = 2 + 2*s; + call_ea_read(M, sz); + call_ea_read_commit(M, sz); + if (s) { // long + shoe.a[r] += shoe.dat; + } else { // word + const int16_t ea = shoe.dat; + shoe.a[r] += ea; + } +}) + +~inst(addx, { + ~decompose(shoe.op, 1101 xxx 1 ss 00 r yyy); + const uint8_t sz = 1<, Dn + // -> source + // Dn -> dest + // (Dn-) -> result + ~decompose(shoe.op, 1011 rrr ooo MMMMMM); + const uint8_t sz = 1< cc + // Dn, ea + ~decompose(shoe.op, 1011 rrr o11 MMMMMM); + const uint8_t sz = 2<>32); + set_sr_n((uint8_t)(R>>63)); + set_sr_z(R==0); + set_sr_v(0); + set_sr_c(0); + } else { // 32-bit result + // FIXME: I'm not positive this behavior is right: + // Is sr_n set if the quad-word is negative? or if the long-word is? + // I'm presuming long-word, but I didn't actually check. + // Also check whether sr_z is set if R==0 + // (The documentation is vague) + // + // Update: I checked, and this seems to be right + set_sr_v((R>>32)!=0); + set_sr_n((R>>31)&1); + set_sr_z((R&0xffffffff)==0); + set_sr_c(0); + } +}) + +~inst(long_div, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 0100 1100 01 MMMMMM); + ~decompose(ext, 0 qqq u s 0000000 rrr); + call_ea_read(M, 4); + call_ea_read_commit(M, 4); + + const uint32_t divisor = shoe.dat; + if (divisor == 0) { + throw_divide_by_zero(); + return ; + } + + uint64_t dividend; + if (s) + dividend = (((uint64_t)shoe.d[r])<<32) | shoe.d[q]; + else { + if (u) // if signed-mode, we need to sign extend 32-bit dividends (This caused a quickdraw bug that took forever to debug!) + dividend = ((int32_t)shoe.d[q]); + else + dividend = shoe.d[q]; + } + + uint64_t Q; + uint32_t R; + if (u) { // if signed + Q = (uint64_t)((int64_t)(((int64_t)dividend) / ((int32_t)divisor))); + R = (uint32_t)((int32_t)(((int64_t)dividend) % ((int32_t)divisor))); + } else { // if unsigned + Q = ((uint64_t)dividend) / ((uint32_t)divisor); + R = ((uint64_t)dividend) % ((uint32_t)divisor); + } + + if (s) { // if 64 bit dividend, + const uint8_t overflow = ((Q>>32)!=0); + set_sr_z((Q & 0xffffffff) == 0); + set_sr_n((Q>>31)&1); + set_sr_v(overflow); + set_sr_c(0); + if (!overflow) { // only modify the registers if !overflow + shoe.d[r] = R; + shoe.d[q] = (uint32_t)Q; + } + } else { // if 32 bit dividend + set_sr_z((Q & 0xffffffff) == 0); + set_sr_n((Q>>31)&1); + set_sr_v(0); // can't overflow with 32 bit dividend + set_sr_c(0); + shoe.d[r] = R; + shoe.d[q] = (uint32_t)Q; // if r==q, then only set r[q]=Q + } +}) + +~inst(addq, { + ~decompose(shoe.op, 0101 ddd 0 ss MMMMMM); + const uint8_t dat = d + ((!d)<<3); + if ((s==0) && ((M>>3) == 1)) { + // There's a very subtle distinciton in the M68000 Family Programmer's Reference Manual, + // "Only word and long operations can be used with address registers" with subq, but + // "Word and long operations are also allowed on the address registers" with addq. + // Hmm... + // What it actually means is "If size==byte, illegal instruction. If size==word -> pretend size is long." + throw_illegal_instruction(); + return ; + } + else if ((M>>3) == 1) { // size is always long if using addr register, CCodes aren't set. + shoe.a[M&7] += dat; + return ; + } + + call_ea_read(M, 1<>3) == 1)) { // Reject byte-size for addr registers + throw_illegal_instruction(); + return ; + } + else if ((M>>3) == 1) { // Use long-size for addr registers + shoe.a[M&7] -= dat; + return ; + } + + call_ea_read(M, 1<'020 registers + case 0x003: { // TC + // TC is a 16 bit register, but movec is always a 32bit + if (x) shoe.tc = reg[r] & ~b(1100 0000 0000 0000); + else reg[r] = shoe.tc & ~b(1100 0000 0000 0000); + return ; + } + case 0x006: // DTT0 + if (x) shoe.dtt0 = reg[r] & ~b(11111111 11111111 11100011 01100100); + else reg[r] = shoe.dtt0 & ~b(11111111 11111111 11100011 01100100); + return ; + case 0x007: // DTT1 + if (x) shoe.dtt1 = reg[r] & ~b(11111111 11111111 11100011 01100100); + else reg[r] = shoe.dtt1 & ~b(11111111 11111111 11100011 01100100); + return ; */ + case 0x801: // VBR + if (x) shoe.vbr = reg[r]; + else reg[r] = shoe.vbr; + return ; + case 0x800: // USP + make_stack_pointers_valid(); + if (x) shoe.usp = reg[r]; + else reg[r] = shoe.usp; + load_stack_pointer(); + return ; + // (NO!) case 0x802: // CAAR (not supported on 68040) + case 0x000: // SFC + if (x) shoe.sfc = reg[r] & 7; + else reg[r] = shoe.sfc & 7; + return ; + case 0x001: // DFC + if (x) shoe.dfc = reg[r] & 7; + else reg[r] = shoe.dfc & 7; + return ; + case 0x803: // MSP + case 0x804: // ISP + case 0x004: // ITT0 + case 0x005: // ITT1 + case 0x805: // MMUSR + case 0x806: // URP + case 0x807: // SRP + printf("inst_movec: error! I don't support this condition code yet! (0x%03x)\n", c); + assert(!"inst_movec: error: unknown condition\n"); + return ; + + default: + return throw_illegal_instruction(); + } +}) + +~inst(moves, { + verify_supervisor(); + const uint16_t ext = nextword(); + + ~decompose(shoe.op, 0000 1110 ss MMMMMM); + ~decompose(ext, a rrr d 00000000000); + + if ((M>>3) < 2) { + // Dn and An addressing modes not supported + throw_illegal_instruction(); + return ; + } + + const uint8_t fc = d ? shoe.dfc : shoe.sfc; + const uint8_t sz = 1<>3) == 4) { + assert((M&7) != 7); + // Predecrement + addr = shoe.a[M & 7] - sz; + } + else if ((M>>3) < 4) { + if ((M>>3) == 3) assert((M&7) != 7); + // Post increment or addr indirect + addr = shoe.a[M & 7]; + } + else { + // all other EA modes + call_ea_addr(M); + addr = (uint32_t)shoe.dat; + } + + if (d) { + const uint32_t data = chop(a ? shoe.a[r] : shoe.d[r], sz); + + // Motorola's 68k documentation has a note that for moves An,(An)+ or -(An), + // the value of An written is incremented or decremented + // XXX: implement this + assert(! ((a && (M&7)==r) && (((M>>3) == 3) || ((M>>3) == 4))) ); + + lset_fc(addr, sz, data, fc); + if (shoe.abort) + return ; + } + else { + uint32_t data = lget_fc(addr, sz, fc); + if (shoe.abort) + return ; + + // if destination is address register, data is sign extended to 32 bits + if (a && (sz == 1)) { + int8_t d8 = data; + int32_t d32 = d8; + data = d32; + } + else if (a && (sz == 2)) { + int16_t d16 = data; + int32_t d32 = d16; + data = d32; + } + + if (a) + shoe.a[r] = data; + else + set_d(r, data, sz); + + } + + // commit predecrement/postincrement addr reg changes + if ((M>>3) == 4) + shoe.a[M & 7] -= sz; + else if ((M>>3) == 3) + shoe.a[M & 7] += sz; + +}) + +~inst(cas, { + assert(!"inst_cas: error: not implemented!"); +}) + +~inst(cas2, { + assert(!"inst_cas2: error: not implemented!"); +}) + +~inst(move_to_sr, { + verify_supervisor(); + ~decompose(shoe.op, 0100 0110 11 MMMMMM); + call_ea_read(M, 2); // sr is 2 bytes + call_ea_read_commit(M, 2); + + set_sr(shoe.dat); +}) + +~inst(move_from_sr, { + verify_supervisor(); + ~decompose(shoe.op, 0100 0000 11 MMMMMM); + shoe.dat = shoe.sr; + call_ea_write(M, 2); +}) + +~inst(neg, { + ~decompose(shoe.op, 0100 0100 ss MMMMMM); + const uint8_t sz = 1< - Dn -> + const uint32_t result = shoe.dat - get_d(r, sz); + { + const uint8_t Sm = mib(shoe.d[r], sz); + const uint8_t Dm = mib(shoe.dat, sz); + const uint8_t Rm = mib(result, sz); + set_sr_v((!Sm && Dm && !Rm) || (Sm && !Dm && Rm)); + set_sr_c((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm)); + set_sr_x(sr_c()); + set_sr_n(Rm); + set_sr_z(chop(result,sz)==0); + } + shoe.dat = result; + call_ea_write(M, sz); + } + else { // Dn - -> Dn + const uint32_t result = get_d(r, sz) - shoe.dat; + { + const uint8_t Sm = mib(shoe.dat, sz); + const uint8_t Dm = mib(shoe.d[r], sz); + const uint8_t Rm = mib(result, sz); + set_sr_v((!Sm && Dm && !Rm) || (Sm && !Dm && Rm)); + set_sr_c((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm)); + set_sr_x(sr_c()); + set_sr_n(Rm); + set_sr_z(chop(result,sz)==0); + } + set_d(r, result, sz); + call_ea_read_commit(M, sz); + } +}) + +~inst(subi, { + ~decompose(shoe.op, 0000 0100 ss MMMMMM); + const uint8_t sz = 1<> 3) == 0) { + set_sr_z(! ((shoe.d[M&7] >> (ext % 32)) & 1) ); + return ; + } + + const uint8_t n = b % 8; + call_ea_read(M, 1); + call_ea_read_commit(M, 1); + + set_sr_z(!((shoe.dat >> n)&1)); +}) + +~inst(pea, { + ~decompose(shoe.op, 0100 1000 01 MMMMMM); + // fetch the EA + call_ea_addr(M); + // push it onto the stack + lset(shoe.a[7]-4, 4, shoe.dat); + if (shoe.abort) return ; + // decrement the stack pointer if lset didn't abort + shoe.a[7] -= 4; +}) + +~inst(subx, { + ~decompose(shoe.op, 1001 yyy 1 ss 00 m xxx); + const uint8_t sz = 1<, An + // An - -> An + // D S R + + call_ea_read(M, sz); + call_ea_read_commit(M, sz); + // if sz==word, sign extend source to long + const uint32_t S = s ? shoe.dat : ((uint32_t) ((int16_t)shoe.dat)); + const uint32_t R = shoe.a[r] - S; + shoe.a[r] = R; + + // don't set any condition codes! +}) + +~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; + } +}) + +~inst(bsr, { + ~decompose(shoe.op, 0110 0001 dddddddd); + uint32_t new_pc = shoe.pc; + + // 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); + } + + lset(shoe.a[7]-4, 4, shoe.pc); + if (shoe.abort) return ; + shoe.a[7] -= 4; + shoe.pc = new_pc; +}) + +~inst(bcc, { + uint32_t new_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 + } + case 1: { + assert(!"How did we get here?"); // decoder should have called inst_bsr() + } + 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 + } +}) + +~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; + 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; + + if (s) { // word + int16_t tmp = shoe.d[r] & 0xffff; + reg = tmp; + tmp = shoe.dat & 0xffff; + ea = tmp; + } + else { // long word + reg = shoe.d[r]; + ea = shoe.dat & 0xffffffff; + } + + if ((reg < 0) || (reg > ea)) { + set_sr_n((reg < 0)); + throw_frame_two(shoe.sr, shoe.pc, 6, shoe.orig_pc); + } + + return ; +}) + +~inst(jsr, { + ~decompose(shoe.op, 0100 1110 10 MMMMMM); + call_ea_addr(M); + + // my quadra 800 doesn't object when a7 is odd... + // so, no extra error checking needed + lset(shoe.a[7]-4, 4, shoe.pc); + if (shoe.abort) return ; + + // printf("jsr: writing pc (0x%08x) to *0x%08x (phys=0x%08x)\n", shoe.pc, shoe.a[7]-4, shoe.physical_addr); + + shoe.a[7] -= 4; + shoe.pc = shoe.dat; + if (sr_s()&&0) { + //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"); + } + } + + 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 if (0) { + char *name = (char*)"unknown"; + uint32_t value = 0; + 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 = (char*)macii_rom_symbols[i].name; + 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); + } + +}) + +~inst(jmp, { + ~decompose(shoe.op, 0100 1110 11 MMMMMM); + call_ea_addr(M); + shoe.pc = shoe.dat; +}) + +~inst(link_word, { + ~decompose(shoe.op, 0100 1110 0101 0 rrr); + const int16_t ext = nextword(); + + // push the contents of the address register onto the stack + lset(shoe.a[7]-4, 4, shoe.a[r]); + if (shoe.abort) return ; + shoe.a[7] -= 4; + + // load the updated stack pointer into the address register + shoe.a[r] = shoe.a[7]; + + // add the (sign-extended) displacement value to the stack pointer + shoe.a[7] += ext; +}) + +~inst(unlk, { + ~decompose(shoe.op, 0100 1110 0101 1 rrr); + + const uint32_t pop = lget(shoe.a[r], 4); + if (shoe.abort) return ; + + // loads the stack pointer from the address register + shoe.a[7] = shoe.a[r]+4; + + // loads the address register with the long word popped from the stack + shoe.a[r] = pop; +}) + +~inst(rts, { + const uint32_t pop = lget(shoe.a[7], 4); + if (shoe.abort) return ; + + shoe.a[7] += 4; + shoe.pc = pop; + + if (sr_s() && 0) { + // return ; + coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); + if (symb) + printf("RETURN TO %s+%u 0x%08x\n", symb->name, shoe.pc-symb->value, shoe.pc); + } + else if (0){ + char *name = (char*)"unknown"; + uint32_t value = 0; + 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 = (char*)macii_rom_symbols[i].name; + 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(); + + // push the contents of the address register onto the stack + lset(shoe.a[7]-4, 4, shoe.a[r]); + if (shoe.abort) return ; + shoe.a[7] -= 4; + + // load the updated stack pointer into the address register + shoe.a[r] = shoe.a[7]; + + // add the displacement value to the stack pointer + shoe.a[7] += disp; +}) + +~inst(movem, { + const uint16_t mask = nextword(); + ~decompose(shoe.op, 0100 1d00 1s MMMMMM); + const uint8_t sz = 2< short, s==1 => long + uint32_t i; + + if (d) { // memory->register + if (~bmatch(M, xx100xxx)) { // predecrement isn't allowed for mem->reg + throw_illegal_instruction(); + return ; + } + if (~bmatch(M, xx011xxx)) // if postincrement, + shoe.dat = shoe.a[M&7]; // hand-parse this address mode + else + call_ea_addr(M); // otherwise, ea_addr() can handle it + + // extract the bitfields for a and d registers, + const uint8_t dfield = mask&0xff; + const uint8_t afield = (mask>>8)&0xff; + + // read in the data registers + for (i=0; i<8; i++) { + if ((dfield >> i) & 1) { + uint32_t tmp; + if (s) + tmp = lget(shoe.dat, 4); + else + tmp = (uint32_t)((int32_t)((int16_t)lget(shoe.dat, 2))); // sign-extend if short-mode + if (shoe.abort) goto abort; + shoe.d[i] = tmp; + shoe.dat += sz; + } + } + + // read in the address registers + for (i=0; i<8; i++) { + if ((afield >> i) & 1) { + uint32_t tmp; + if (s) + tmp = lget(shoe.dat, 4); + else + tmp = (uint32_t)((int32_t)((int16_t)lget(shoe.dat, 2))); // sign-extend if short-mode + if (shoe.abort) goto abort; + shoe.a[i] = tmp; + shoe.dat += sz; + } + } + + // update register if postincrement + if (~bmatch(M, xx011xxx)) + shoe.a[M&7] = shoe.dat; + } + else { // register->memory + if (~bmatch(M, xx011xxx)) { // postincrement isn't allowed for reg->mem + throw_illegal_instruction(); + return ; + } + uint32_t addr; + uint16_t newmask = mask; // if predecrement-mode, bit-reversed mask. Regular mask otherwise. + uint16_t numbits = 0; // the number of set bits in mask + + if (~bmatch(M, xx100xxx)) { // if predecrement, + uint16_t maskcopy; + + // printf("*0x%08x movem %02x\n", shoe.orig_pc, shoe.op); + + for (maskcopy=mask, i=0; i < 16; i++) { + newmask = (newmask<<1) | (maskcopy & 1); // build a flipped version of mask + numbits += (maskcopy & 1); // count the bits in mask, to pre-predecrement the addr + maskcopy >>= 1; + } + addr = shoe.a[M&7] - numbits * sz; // hand-parse and pre-predecrement the addr + + // XXX: This is broken - according to the documentation, 68020 will write (a7-sz) + // if it's written during pre-decrement mode. + // shoe.a[M&7] -= sz; // "pre-decrement" the address register itself (see abort:) + } + else { + call_ea_addr(M); // otherwise, ea_addr() can handle it + addr = shoe.dat; + } + + const uint32_t addr_copy = addr; + const uint8_t dfield = newmask&0xff; + const uint8_t afield = (newmask>>8)&0xff; + + // write the data registers + for (i=0; i<8; i++) { + // FIXME: determine what happens when the predecrementing address register is written + if ((dfield >> i) & 1) { + lset(addr, sz, shoe.d[i]); + if (shoe.abort) + goto abort; // FIXME: figure out how to abort cleanly + addr += sz; + } + } + + // write the address registers + for (i=0; i<8; i++) { + // FIXME: determine what happens when the predecrementing address register is written + if ((afield >> i) & 1) { + + // For the MC68020-40, for predecrement mode, if the address register + // is written to memory, it is "predecremented" by the size of the operation. + // (Literally the "size" of the operation, 2 or 4 bytes) + + uint32_t data = shoe.a[i]; + // if this is pre-dec mode, and we're pushing the address reg specified in the EA + if ( (M>>3) == 4 && (M&7)==i ) { + data -= sz; + printf("movem: For movem %u/%u, deciding to write 0x%08x for a%u\n", M>>3, M&7, data, M&7); + } + + lset(addr, sz, data); + if (shoe.abort) + goto abort; // FIXME: figure out how to abort cleanly + addr += sz; + } + } + + + // update register if predecrement + if (~bmatch(M, xx100xxx)) + shoe.a[M&7] = addr_copy; + } + + return ; + +abort: + // For the MC68020-40, for predecrement mode, if the address register is written to memory, it is "predecremented" by the size of the operation. (Literally, 2 or 4 bytes.) + // So undo that here: + + // XXX: This is broken. We should only undo the predecrement if we DID predecrement + + //if (~bmatch(M, xx100xxx)) + //shoe.a[M&7] += sz; + + return ; +}) + +~inst(nbcd, { + assert(!"inst_nbcd: fixme: I'm not implemented!\n"); +}) + +~inst(eori_to_ccr, { + const uint16_t val = 0xff & nextword(); + const uint16_t new_sr = shoe.sr ^ val; + + set_sr(new_sr); +}) + +~inst(eori_to_sr, { + verify_supervisor(); + + const uint16_t new_sr = shoe.sr ^ nextword(); + + set_sr(new_sr); +}) + +~inst(movep, { + assert(!"inst_movep: fixme: I'm not implemented!\n"); +}) + + +void write_bitfield(const uint32_t width, const uint32_t offset, const uint32_t M, const uint32_t ea, const uint32_t raw_field) +{ + const int32_t soffset = offset; + const uint32_t field = bitchop(raw_field, width); // make sure that field is all 0's beyond (width) + + // special case for EA-mode == data register + if ((M>>3) == 0) { + const uint32_t reg = shoe.d[M&7]; // the EA reg + const uint32_t ones = 0xffffffff >> (32-width); // unrotated mask + if (soffset >= 0) { + const uint32_t mask = ~~(rrot32(ones << (32-width), soffset&31)); + const uint32_t rotatedfield = rrot32(field << (32-width), soffset&31); + shoe.d[M&7] = (shoe.d[M&7] & mask) | rotatedfield; + } + else { + const uint32_t mask = ~~(lrot32(ones << (32-width), (-soffset)&31)); + const uint32_t rotatedfield = lrot32(field << (32-width), (-soffset)&31); + shoe.d[M&7] = (shoe.d[M&7] & mask) | rotatedfield; + } + } + else { + const uint32_t bit_offset = offset & 7; + // byte_offset = offset (arithmetic-right-shift) 3 + const uint32_t byte_offset = ((offset|(offset>>1)|(offset>>2)) & 0xe0000000) | (offset>>3); + + // call_ea_addr(M); + + const uint32_t first_byte_addr = ea + byte_offset; + //printf("debug: extract_bitfield: addr = 0x%08x, first_byte_addr = 0x%08x\n", ea, first_byte_addr); + + + // if the field is contained entirely within the first byte + if (width <= (8-bit_offset)) { + // yes this is convoluted, it simply creates a chopped/rotated mask that matches the bits in the first byte + const uint8_t byte_mask = bitchop(0xff, width) << (8-(bit_offset+width)); + const uint8_t field_mask = field << (8-(bit_offset+width)); + const uint8_t old_byte = lget(first_byte_addr, 1); + const uint8_t new_byte = (old_byte & (~~byte_mask)) | field_mask; + + lset(first_byte_addr, 1, new_byte); + //printf("write_bitfield: byte_mask = 0x%02x field_mask = 0x%02x bit_offset=%u byte_offset=%u\n", byte_mask, field_mask, bit_offset, byte_offset); + //printf("write_bitfield: changing byte at 0x%08x from 0x%02x to 0x%02x\n", + //first_byte_addr, old_byte, new_byte); + if (shoe.abort) return ; + } + else { + uint32_t boff = bit_offset; + uint32_t curwidth = 8-bit_offset; + uint32_t remaining_width = width; + uint32_t addr = first_byte_addr; + uint32_t remaining_field = field<<(32-width); // left-aligned + while (remaining_width > 0) { + const uint8_t byte = lget(addr, 1); + if (shoe.abort) return ; + + const uint8_t mask = ~~(((uint8_t)((0xff) << (8-curwidth))) >> boff); + const uint8_t field_chunk = remaining_field >> (32-curwidth); + const uint8_t rotated_chunk = (field_chunk << (8-curwidth)) >> boff; + + // printf("mask = 0x%02x\nfield = 0x%02x\n", mask, rotated_chunk); + + lset(addr, 1, (byte & mask) | rotated_chunk); + //printf("write_bitfield: changing byte at 0x%08x from 0x%02x to 0x%02x\n", + //addr, byte, (byte & mask) | rotated_chunk); + if (shoe.abort) return ; + + addr++; + remaining_field <<= curwidth; + remaining_width -= curwidth; + curwidth = (remaining_width>8)? 8 : remaining_width; + boff = 0; + } + } + } +} + +uint32_t extract_bitfield(const uint32_t width, const uint32_t offset, const uint32_t M, const uint32_t ea) +{ + const int32_t soffset = offset; + uint32_t field; + + // special case for EA-mode == data register + if ((M>>3) == 0) { + const uint32_t reg = shoe.d[M&7]; // the EA reg + + // OKAY: I think I have this figured out. It was laborious to discover, so don't forget it. + // When mode=datareg, the register is ROTATED by the offset, not shifted. + // This has nonintuitive consequences. + // {Offset=-27, length=32, data=1} will say a bit is set at the (-27+5)th position + + if (soffset >= 0) + field = lrot32(reg, soffset&31) >> (32-width); + else + field = rrot32(reg, (-soffset)&31) >> (32-width); + } + else { + const uint32_t bit_offset = offset & 7; + // byte_offset = offset (arithmetic-right-shift) 3 + const uint32_t byte_offset = ((offset|(offset>>1)|(offset>>2)) & 0xe0000000) | (offset>>3); + + // this is call_ea_addr(M); + // shoe.mr=M; + // ea_addr(); + // if (shoe.abort) return 0; + + //printf("debug: extract_bitfield: offset = 0x%08x, byte_offset = %d, bit_offset = %d\n", offset, byte_offset, bit_offset); + + const uint32_t first_byte_addr = ea + byte_offset; + //printf("debug: extract_bitfield: addr = 0x%08x, first_byte_addr = 0x%08x\n", ea, first_byte_addr); + + field = bitchop(lget(first_byte_addr, 1), 8-bit_offset); + //printf("debug: extract_bitfield: first byte field (low %u bits): 0x%02x\n", 8-bit_offset, field); + if (shoe.abort) return 0; + if (width > (8-bit_offset)) { // if the data isn't entirely contained in the first byte + uint32_t last_long = lget(first_byte_addr+1, 4); + if (shoe.abort) return 0; + field = (field<<(width - (8-bit_offset))) | // first_byte, left shifted + (last_long >> (32 - (width - (8-bit_offset)))); // last_long, right shifted + } + else // otherwise, right-align the first byte + field >>= (8-(bit_offset+width)); + } + + return field; +} + +~inst(bfextu, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1001 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + + shoe.d[r] = field; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); + set_sr_z(field == 0); +}) + +~inst(bfchg, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1011 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + write_bitfield(width, offset, M, ea, ~~field); + if (shoe.abort) return; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); + set_sr_z(field == 0); +}) + +~inst(bfexts, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1011 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + const uint32_t mib = (field >> (width-1))&1; + + const uint32_t maskA = (((uint32_t)0) - mib) << 1; + const uint32_t maskB = (maskA << (width-1)); + const uint32_t result = maskB | field; + shoe.d[r] = result; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(mib); + set_sr_z(field == 0); +}) + +~inst(bfclr, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1011 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + write_bitfield(width, offset, M, ea, 0); + if (shoe.abort) return; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); + set_sr_z(field == 0); +}) + +~inst(bfset, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1011 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + write_bitfield(width, offset, M, ea, 0xffffffff); + if (shoe.abort) return; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); + set_sr_z(field == 0); +}) + +~inst(bftst, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1000 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); + set_sr_z(field == 0); +}) + +~inst(bfffo, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1110 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + const uint32_t field = extract_bitfield(width, offset, M, ea); + if (shoe.abort) return; + + uint32_t i; + for (i=1; (i<=width) && ((field>>(width-i))&1)==0; i++) ; + shoe.d[r] = offset+i-1; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); + set_sr_z(field == 0); +}) + +~inst(bfins, { + const uint16_t ext = nextword(); + ~decompose(shoe.op, 1110 1011 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + const uint32_t width_ua = W ? (shoe.d[w]%32) : w; // unadjusted, [0, 31] + const uint32_t width = (width_ua==0)?32:width_ua; // width_ua==0 => width==32 [1, 32] + const uint32_t offset = F ? (shoe.d[f]) : f; // [0, 31] + + const uint32_t field = bitchop(shoe.d[r], width); + // printf("write_bitfield: writing %u at offset=%u width=%u\n", field, offset, width); + + uint32_t ea = 0; + if (M >> 3) { // If ea isn't data reg mode (handled separately in *_bitfield()) + call_ea_addr(M); + ea = shoe.dat; + } + + write_bitfield(width, offset, M, ea, field); + if (shoe.abort) return; + + set_sr_c(0); + set_sr_v(0); + set_sr_n(field >> (width-1)); // set according to the inserted value + set_sr_z(field == 0); +}) + +~inst(btst_reg, { + ~decompose(shoe.op, 0000 rrr 100 MMMMMM); + + if ((M>>3)==0) { // if the dest is a data reg, handle specially + set_sr_z(! ((shoe.d[M&7]>>(shoe.d[r]%32)) & 1) ); + return ; + } + + call_ea_read(M, 1); + call_ea_read_commit(M, 1); + set_sr_z(! ((shoe.dat >> (shoe.d[r] % 8)) & 1)); +}) + +~inst(bchg_reg, { + ~decompose(shoe.op, 0000 rrr 101 MMMMMM); + + // The LSB bit is idx:0, MSB is idx:7 or :31 + + if ((M>>3)==0) { // if the dest is a data reg, handle specially + set_sr_z((shoe.d[M&7] & (1 << (shoe.d[r]%32))) == 0); + + shoe.d[M&7] ^= (1 << (shoe.d[r]%32)); + + return ; + } + + call_ea_read(M, 1); + + const uint32_t z = ((shoe.d[r] & (1 << (shoe.d[r] % 8))) == 0); + + // shoe.dat ^= (0x80 >> (shoe.d[r] % 8)); // NO NO! BAD + shoe.dat ^= (1 << (shoe.d[r] % 8)); + + call_ea_write(M, 1); + + set_sr_z(z); +}) + +~inst(bclr_reg, { + ~decompose(shoe.op, 0000 rrr 111 MMMMMM); + + const uint8_t is_data_reg = (M>>3) == 0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = shoe.d[r] % (is_data_reg ? 32 : 8); + + call_ea_read(M, sz); + + set_sr_z(((shoe.dat >> shift) & 1) == 0); + + shoe.dat &= ~~(1 << shift); + call_ea_write(M, sz); +}) + +~inst(bclr_immediate, { + ~decompose(shoe.op, 0000 1000 11 MMMMMM); + const uint16_t ext = nextword(); + ~decompose(ext, 00000000 bbbbbbbb); + + const uint8_t is_data_reg = (M>>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = b % (is_data_reg ? 32 : 8); + + call_ea_read(M, sz); + + set_sr_z(((shoe.dat >> shift) & 1) == 0); + + shoe.dat &= ~~(1 << shift); + call_ea_write(M, sz); +}) + +~inst(bset_reg, { + ~decompose(shoe.op, 0000 rrr 111 MMMMMM); + + const uint8_t is_data_reg = (M>>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = shoe.d[r] % (is_data_reg ? 32 : 8); + + call_ea_read(M, sz); + + set_sr_z(((shoe.dat >> shift) & 1) == 0); + + shoe.dat |= (1 << shift); + call_ea_write(M, sz); +}) + +~inst(bset_immediate, { + ~decompose(shoe.op, 0000 1000 11 MMMMMM); + const uint16_t ext = nextword(); + ~decompose(ext, 00000000 bbbbbbbb); + + const uint8_t is_data_reg = (M>>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = b % (is_data_reg ? 32 : 8); + + call_ea_read(M, sz); + + set_sr_z(((shoe.dat >> shift) & 1) == 0); + + shoe.dat |= (1 << shift); + call_ea_write(M, sz); +}) + +~inst(bchg_immediate, { + ~decompose(shoe.op, 0000 1000 01 MMMMMM); + const uint16_t ext = nextword(); + ~decompose(ext, 00000000 bbbbbbbb); + + const uint8_t is_data_reg = (M>>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = b % (is_data_reg ? 32 : 8); + + call_ea_read(M, sz); + + set_sr_z(((shoe.dat >> shift) & 1) == 0); + + shoe.dat ^= (1 << shift); + call_ea_write(M, sz); +}) + +~inst(ext, { + ~decompose(shoe.op, 0100 100 ooo 000 rrr); + switch (o) { + case ~b(010): { // byte -> word + uint16_t val = (int8_t)get_d(r, 1); + set_d(r, val, 2); + break; + } case ~b(011): { // word -> long + uint32_t val = (int16_t)get_d(r, 2); + set_d(r, val, 4); + break; + } case ~b(111): { // byte -> long + uint32_t val = (int8_t)get_d(r, 1); + set_d(r, val, 4); + break; + } default: + throw_illegal_instruction(); + return ; + } + set_sr_v(0); + set_sr_c(0); + // if the LSb of o is 1, then result size == long + set_sr_z(get_d(r, 2+2*(o&1))==0); + set_sr_n(mib(shoe.d[r], 2+2*(o&1))); +}) + +~inst(andi_to_sr, { + verify_supervisor(); + const uint16_t ext = nextword(); + + set_sr(shoe.sr & ext); +}) + +~inst(andi_to_ccr, { + const uint16_t ext = nextword(); + + set_sr(shoe.sr & (ext & 0xff)); +}) + +~inst(ori_to_sr, { + verify_supervisor(); + const uint16_t ext = nextword(); + + set_sr(shoe.sr | ext); +}) + +~inst(ori_to_ccr, { + const uint16_t ext = nextword(); + + set_sr(shoe.sr | (ext & 0xff)); +}) + +~inst(mc68851_decode, { + ~decompose(shoe.op, 1111 000 a b c MMMMMM); + + // prestore or psave + if (a) { + if (~bmatch(shoe.op, 1111 000 101 xxxxxx)) + inst_mc68851_prestore(); + else if (~bmatch(shoe.op, 1111 000 100 xxxxxx)) + inst_mc68851_psave(); + else + throw_illegal_instruction(); + return ; + } + + // pbcc + if (~bmatch(shoe.op, 1111 000 01x 00xxxx)) { + inst_mc68851_pbcc(); + return ; + } + + const uint16_t ext = nextword(); + + // pdbcc, ptrapcc, pscc + if (~bmatch(shoe.op, 1111 000 001 xxxxxx)) { + ~decompose(shoe.op, 1111 000 001 mmm rrr); + // These all just store a condition code in the extension word + ~decompose(ext, 0000 0000 00 cccccc); + + if (m == 1) + inst_mc68851_pdbcc(c); + else if ((m == ~b(111)) && (r > 2)) + inst_mc68851_ptrapcc(c); + else + inst_mc68851_pscc(c); + return ; + } + + // shoe.op must have the form (1111 000 000 xxxxxx) now + ~decompose(ext, XXX YYY 00 0000 0000); + switch (X) { + case 1: // pflush, pload, pvalid + if (Y == ~b(000)) + inst_mc68851_pload(ext); + else if ((Y == ~b(010)) || (Y == ~b(011))) + inst_mc68851_pvalid(ext); + else + inst_mc68851_pflush(ext); + return ; + case 2: // pmove format 1 + inst_mc68851_pmove(ext); + return ; + case 3: // pmove formats 2 and 3, + inst_mc68851_pmove(ext); + return ; + case 4: // ptest + inst_mc68851_ptest(ext); + return ; + case 5: // pflushr + inst_mc68851_pflushr(ext); + return ; + default: + throw_illegal_instruction(); + return ; + } + assert(!"never get here"); +}) + +~inst(unknown, { + printf("Unknown instruction (0x%04x)!\n", shoe.op); + throw_illegal_instruction(); +}) + +~inst(a_line, { + + if (shoe.op == 0xA9EB || shoe.op == 0xA9EC) { + shoe.suppress_exceptions = 1; + + uint32_t fp_op = lget(shoe.a[7]+0, 2); + uint32_t fp_operand_addr = lget(shoe.a[7]+2, 4); + + printf("%s : op 0x%04x (", (shoe.op == 0xA9EB) ? "FP68K" : "Elems68K", fp_op); + + uint8_t buf[10]; + uint32_t i; + for (i=0; i<10; i++) { + buf[i] = lget(fp_operand_addr+i, 1); + printf("%02x ", buf[i]); + } + + { + uint8_t castable[12] = { + buf[9], buf[8], buf[7], buf[6], buf[5], + buf[4], buf[3], buf[2], buf[1], buf[0], + 0, 0 + }; + printf("%Lf)\n", *(long double*)&castable[0]); + } + + + + shoe.abort = 0; + shoe.suppress_exceptions = 0; + } + + throw_illegal_instruction(); +}) + +void trap_debug() +{ + shoe.suppress_exceptions = 1; + + const uint32_t syscall = lget(shoe.a[7]+4, 4); + printf("syscall = %u\n", shoe.d[0]); + + + switch (shoe.d[0]) { + case 4: { + uint32_t fd = lget(shoe.a[7]+4, 4); + uint32_t buf = lget(shoe.a[7]+8, 4); + uint32_t len = lget(shoe.a[7]+12, 4); + printf("write(%u, 0x%08x, %u) \"", fd, buf, len); + + uint32_t i; + for (i=0; i + * 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 +#include +#include +#include +#include +#include "../shoebill.h" +#include "../coff.h" + +struct dbg_state_t dbg_state; + +void print_mmu_rp(uint64_t rp) +{ + printf("lu=%u limit=0x%x sg=%u dt=%u addr=0x%08x\n", rp_lu(rp), rp_limit(rp), rp_sg(rp), rp_dt(rp), rp_addr(rp)); +} + +void printregs() +{ + printf("[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]); + printf("[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]); + printf("[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]); + printf("[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]); + printf("[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc, + sr_s()?'S':'s', + sr_m()?'M':'m', + sr_x()?'X':'x', + sr_n()?'N':'n', + sr_z()?'Z':'z', + sr_v()?'V':'v', + sr_c()?'C':'c', + shoe.tc + ); + + printf("[vbr]%08x\n", shoe.vbr); + + printf("srp: "); + print_mmu_rp(shoe.srp); + + printf("crp: "); + print_mmu_rp(shoe.crp); + + printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n", + tc_enable(), tc_sre(), tc_fcl(), tc_ps(), tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid()); + + printf("\n"); +} + +void print_pc() +{ + char str[1024]; + uint8_t binary[32]; + uint32_t i; + uint32_t len; + const char *name = NULL; + + if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) { + uint32_t i, addr = shoe.pc % (shoe.physical_rom_size); + for (i=0; macii_rom_symbols[i].name; i++) { + if (macii_rom_symbols[i].addr > addr) { + break; + } + name = macii_rom_symbols[i].name; + } + } + else if (sr_s()) { // these symbols are only meaningful in supervisor mode + coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); + if (symb && strlen(symb->name)) + name = symb->name; + } + else { + if ((shoe.pc >= 0x10000000) && (shoe.pc < 0x20000000)) { + uint32_t i, addr = shoe.pc % (shoe.physical_rom_size); + for (i=0; macii_rom_symbols[i].name; i++) { + if (macii_rom_symbols[i].addr > addr) { + break; + } + name = macii_rom_symbols[i].name; + } + } + else { + coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc); + if (symb) + name = symb->name; + } + } + + const uint16_t old_abort = shoe.abort; + shoe.suppress_exceptions = 1; + + for (i=0; i<32; i++) { + binary[i] = (uint8_t) lget(shoe.pc+i, 1); + } + + disassemble_inst(binary, shoe.pc, str, &len); + + printf("*0x%08x %s [ ", shoe.pc, name ? name : ""); + for (i=0; inext) { + if (shoe.pc == cur->addr) { + printf("Hit breakpoint %llu *0x%08x\n", cur->num, shoe.pc); + dbg_state.running = 0; + return ; + } + } + + if (shoe.dbg) { + // printf("*0x1ff01074 = %llx\n", lget(0x1ff01074, 4)); + print_pc(); + printregs(); + } + +// if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) { +// //print_pc(); +// //printregs(); +// } +// else { +// coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); +// if ((symb && (strcmp(symb->name, "scsitask")==0)) || +// /*(symb && (strcmp(symb->name, "scsiget")==0)) || +// (symb && (strcmp(symb->name, "scsi_out")==0)) || +// (symb && (strcmp(symb->name, "scsireq")==0)) || +// (symb && (strcmp(symb->name, "scsi_vio")==0)) || +// (symb && (strcmp(symb->name, "binit")==0)) ||*/ +// (symb && (strcmp(symb->name, "realvtopte")==0)) || +// (symb && (strcmp(symb->name, "realvtop")==0)) || +// (symb && (strcmp(symb->name, "realsvtop")==0)) || /* +// (symb && (strcmp(symb->name, "sdcmd")==0)) || +// (symb && (strcmp(symb->name, "sdread")==0)) || +// (symb && (strcmp(symb->name, "gdpartinit")==0)) || +// (symb && (strcmp(symb->name, "scsi_in")==0)) || +// (symb && (strcmp(symb->name, "gddriveinit")==0)) || +// (symb && (strcmp(symb->name, "vio_init")==0)) || +// (symb && (strcmp(symb->name, "get_psr")==0)) || +// (symb && (strcmp(symb->name, "scsisched")==0)) || +// (symb && (strcmp(symb->name, "choosetask")==0)) || */ +// (symb && (strcmp(symb->name, "scsiselect")==0))) { +// print_pc(); +// printregs(); +// } +// else if ((shoe.pc > (0x0014ea02-32)) && (shoe.pc < (0x0014ea02+32))) { +// print_pc(); +// printregs(); +// } +// } +} + + +char *cli_prompt_callback(EditLine *el) +{ + return "~ "; +} + +// Hack to clear line after ^C. el_reset() screws up tty when called from the signal handler. +void ch_reset(EditLine *el, int mclear); + +void signal_callback(int sig) +{ + EditLine *el = dbg_state.el; + (void) signal(SIGINT, signal_callback); + (void) signal(SIGWINCH, signal_callback); + + switch (sig) { + case SIGWINCH: + el_resize(el); + break ; + case SIGINT: + if (dbg_state.running) { + dbg_state.running = 0; + } + else { + printf("\n"); + ch_reset(el, 0); + el_set(el, EL_REFRESH); + } + break ; + } + + return ; +} + +void verb_backtrace_handler (const char *line) +{ + const uint32_t old_abort = shoe.abort; + shoe.suppress_exceptions = 1; + shoe.abort = 0; + + // link + // push a6 to a7 + // set a6 = a7 + // set a7 = a7 - (some stack space) + + // jsr + // push return pointer to a7 + + // call + // set a7 = a7 - (some stack space) + // push arguments to a7 + // push return pointer to a7 + // (jump to function) + // push + + // bt algorithm + // set a7 = a6 + // pop a7 -> a6 + // pop a7 -> return pointer + + + uint32_t i, j, a7, a6 = shoe.a[6]; + coff_symbol *symb; + + if (sr_s()) { + symb = coff_find_func(shoe.coff, shoe.pc); + printf("%u: *0x%08x %s+%u\n", 0, shoe.pc, (symb && strlen(symb->name))?symb->name:"?", shoe.pc - symb->value); + } + else + printf("%u: *0x%08x\n", 0, shoe.pc); + + for (i=1; 1; i++) { + a7 = a6; + const uint32_t last_a6 = lget(a7, 4); + const uint32_t last_pc = lget(a7+4, 4); + + if ((last_a6 - a6) <= 1000) { + printf(" {"); + for (j = a6+8; j < last_a6; j+=4) { + uint32_t data = lget(j, 4); + printf("%x, ", data); + } + printf("}\n"); + } + + if (sr_s()) { + symb = coff_find_func(shoe.coff, last_pc); + printf("%u: *0x%08x %s+%u\n", i, last_pc, (symb && strlen(symb->name))?symb->name:"?", last_pc - symb->value); + } + else + printf("%u: *0x%08x\n", i, last_pc); + + if ((last_a6 - a6) > 1000) { + break; + } + + a6 = last_a6; + } + + shoe.suppress_exceptions = 0; + shoe.abort = old_abort; +} + +void verb_break_handler (const char *line) +{ + errno = 0; + const uint32_t addr = (uint32_t) strtoul(line, NULL, 0); + + if (errno) { + printf("errno: %d\n", errno); + return ; + } + + dbg_breakpoint_t *brk = calloc(sizeof(dbg_breakpoint_t), 1); + brk->next = NULL; + brk->addr = addr; + brk->num = dbg_state.breakpoint_counter++; + + dbg_breakpoint_t **cur = &dbg_state.breakpoints; + while (*cur) + cur = &(*cur)->next; + *cur = brk; + + printf("Set breakpoint %llu = *0x%08x\n", brk->num, brk->addr); +} + +void verb_delete_handler (const char *line) +{ + errno = 0; + uint64_t num = strtoull(line, NULL, 0); + + if (errno) { + printf("errno: %d\n", errno); + return ; + } + + dbg_breakpoint_t **cur = &dbg_state.breakpoints; + while (*cur) { + if ((*cur)->num == num) { + dbg_breakpoint_t *victim = *cur; + *cur = (*cur)->next; + free(victim); + return ; + } + cur = &(*cur)->next; + } + + printf("No such breakpoint (#%llu)\n", num); +} + +void verb_help_handler (const char *line) +{ + printf("Help help help\n"); +} + +void verb_quit_handler (const char *line) +{ + printf("Quitting\n"); + fflush(stdout); + exit(0); +} + +void verb_continue_handler (const char *line) +{ + dbg_state.running = 1; + while (dbg_state.running) { + stepper(); + } + print_pc(); +} + +void verb_stepi_handler (const char *line) +{ + shoe.stopped = 0; + dbg_state.running = 1; + cpu_step(); + dbg_state.running = 0; + print_pc(); +} + +void verb_registers_handler (const char *line) +{ + printregs(); +} + +void verb_trace_toggle_handler (const char *line) +{ + shoe.dbg = !shoe.dbg; +} + +void verb_examine_handler (const char *line) +{ + uint32_t addr = (uint32_t)strtoul(line, NULL, 0); + uint32_t old_suppress = shoe.suppress_exceptions; + + shoe.suppress_exceptions = 1; + printf("(uint32_t)*0x%08x = 0x%08x\n", addr, (uint32_t)lget(addr, 4)); + shoe.suppress_exceptions = old_suppress; + +} + +void verb_lookup_handler (const char *line) +{ + char *sym_name = malloc(strlen(line)+1); + + sscanf(line, "%s", sym_name); + coff_symbol *symb = coff_find_symbol(shoe.coff, sym_name); + + free(sym_name); + + if (symb == NULL) { + printf("Couldn't find \"%s\"\n", sym_name); + return ; + } + + printf("%s = *0x%08x\n", symb->name, symb->value); +} + +struct verb_handler_table_t { + const char *name; + void (*func)(const char *); +} verb_handler_table[] = +{ + {"quit", verb_quit_handler}, + {"help", verb_help_handler}, + {"registers", verb_registers_handler}, + {"continue", verb_continue_handler}, + {"stepi", verb_stepi_handler}, + {"backtrace", verb_backtrace_handler}, + {"bt", verb_backtrace_handler}, + {"break", verb_break_handler}, + {"delete", verb_delete_handler}, + {"lookup", verb_lookup_handler}, + {"trace", verb_trace_toggle_handler}, + {"x", verb_examine_handler} +}; + +void execute_verb (const char *line) +{ + char verb[128]; + uint32_t max_len=0, max_i=0; + const char *remainder; + uint32_t i, matches = 0, match_i; + + if (sscanf(line, "%127s", verb) != 1) + return ; + + // Skip past the verb + for (remainder = line; *remainder && !isspace(*remainder); remainder++) ; + + // Skip past the space between the verb and the arguments + for (; *remainder && isspace(*remainder); remainder++) ; + + const uint32_t verb_len = strlen(verb); + for (i=0; i < (sizeof(verb_handler_table) / sizeof(struct verb_handler_table_t)); i++) { + const uint32_t i_len = strlen(verb_handler_table[i].name); + + // If it's a perfect match, + if (strcasecmp(verb, verb_handler_table[i].name)==0) { + verb_handler_table[i].func(remainder); + return ; + } + + // Otherwise, see if it's a partial match + if ((i_len >= verb_len) && strncasecmp(verb, verb_handler_table[i].name, verb_len)==0) { + matches++; + match_i = i; + } + } + + // Only execute the verb if it's an unambiguous match (matches == 1) + if (matches == 1) { + verb_handler_table[match_i].func(remainder); + return ; + } + + printf(" %s?\n", verb); +} + +void *ui_thread (void *arg) +{ + EditLine *el; + History *hist; + HistEvent histev; + + const char *buf; + int num; + + hist = history_init(); + history(hist, &histev, H_SETSIZE, 10000); // Remember 10000 previous user inputs + + el = el_init("Shoebill", stdin, stdout, stderr); + dbg_state.el = el; + + el_set(el, EL_SIGNAL, 0); + el_set(el, EL_PROMPT, cli_prompt_callback); + el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_HIST, history, hist); + + (void) signal(SIGINT, signal_callback); + (void) signal(SIGWINCH, signal_callback); + + while ((buf = el_gets(el, &num)) != NULL) { + if (strcmp(buf, "\n")!=0) { + execute_verb(buf); + history(hist, &histev, H_ENTER, buf); + } + } + + el_end(el); + history_end(hist); + return NULL; +} + +uint8_t *loadrom (char *path, uint32_t *len) +{ + FILE *f = fopen(path, "r"); + uint8_t *buf = calloc(1024, 1024); + uint32_t i, sz, expected, checksum; + + if (!f) { + printf("Couldn't open %s\n", path); + return NULL; + } + + for (sz=0; sz < (1024*1024); sz += (64*1024)) { + printf("sz = %u\n", sz); + if (fread(buf + sz, 64*1024, 1, f) != 1) { + break; + } + } + printf("sz = %u (done)\n", sz); + + fclose(f); + + if (sz == 0) { + printf("loadrom: empty rom file\n"); + free(buf); + return NULL; + } + + for (i=0, expected=0; i<4; i++) + expected = (expected << 8) + buf[i]; + + for (i=4, checksum=0; i < sz; i+=2) { + uint16_t word = (buf[i]<<8) + buf[i+1]; + checksum += word; + } + + if (checksum != expected) { + printf("Bad checksum (computed %08x, expected %08x)\n", checksum, expected); + free(buf); + return NULL; + } + + *len = sz; + return buf; +} + +struct __attribute__ ((__packed__)) kernel_info { + // Auto data + uint32_t auto_magic; + uint32_t auto_id[16]; + uint32_t auto_version[16]; + uint32_t auto_command; + + uint16_t root_ctrl; + uint8_t root_drive; + uint8_t root_cluster; + + struct __attribute__ ((__packed__)) sect_info { + uint32_t vstart; + uint32_t pstart; + uint32_t size; + } si[3]; + + uint16_t machine_type; // Gestalt, I think? The "machine_type" for a quadra 950 doesn't match its gestalt, though. + uint32_t drive_queue_offset; + uint16_t ki_flags; + uint8_t ki_version; // always 1 + uint8_t root_partition; + uint16_t swap_ctrl; + uint8_t swap_drive; + uint8_t swap_partition; +}; + +void init_kernel_info() +{ + struct kernel_info ki, *p; + uint32_t i; + + p = (struct kernel_info*)0x00003c00; + + shoe.d[0] = 0x536d7201; + shoe.a[0] = (uint32_t)p; + + /* ----- Setup kernel info structure ----- */ + + ki.auto_magic = 0x50696773; // 'Pigs' (Pigs in space?) + + for (i=0; i<16; i++) { + ki.auto_id[i] = 0x0000ffff; + ki.auto_version[i] = 0; + } + + ki.auto_id[0xa] = 0x50; // Macintosh II video card has an auto_id of 5 (I guess?) + ki.auto_id[0xb] = 0x5; // Macintosh II video card has an auto_id of 5 (I guess?) + + ki.auto_command = 0; // AUTO_RUN + + ki.root_ctrl = 0; + ki.root_drive = 0; + ki.root_cluster = 0; + + for (i = 0; i < shoe.coff->num_sections; i++) { + coff_section *s = &shoe.coff->sections[i]; + uint8_t sect; + + if (strcmp(s->name, ".text") == 0) + sect = 0; + else if (strcmp(s->name, ".data") == 0) + sect = 1; + else if (strcmp(s->name, ".bss") == 0) + sect = 2; + else + continue; + + ki.si[sect].vstart = s->v_addr; + ki.si[sect].pstart = s->p_addr; + ki.si[sect].size = s->sz; + } + + ki.machine_type = 4; // Macintosh II? + + // +4 because the DrvQEl structure has a hidden "flags" field 4 bytes below the pointer + ki.drive_queue_offset = sizeof(struct kernel_info) + 4; + + ki.ki_flags = 1; // KI_VERBOSE + ki.ki_version = 1; + ki.root_partition = 0; + ki.swap_ctrl = 0; + ki.swap_drive = 0; + ki.swap_partition = 1; + + /* ----- Copy ki into memory ----- */ +#define ki_pset(_f, _s) {pset((uint32_t)&p->_f, _s, ki._f); printf("Setting 0x%08x to %x\n", (uint32_t)&p->_f, ki._f);} + ki_pset(auto_magic, 4); + for (i=0; i<16; i++) { + ki_pset(auto_id[i], 4); + ki_pset(auto_version[i], 4); + } + ki_pset(auto_command, 4); + + ki_pset(root_ctrl, 2); + ki_pset(root_drive, 1); + ki_pset(root_cluster, 1); + + for (i=0; i<3; i++) { + ki_pset(si[i].vstart, 4); + ki_pset(si[i].pstart, 4); + ki_pset(si[i].size, 4); + } + + ki_pset(machine_type, 2); + ki_pset(drive_queue_offset, 4); + ki_pset(ki_flags, 2); + ki_pset(ki_version, 1); + ki_pset(root_partition, 1); + ki_pset(swap_ctrl, 2); + ki_pset(swap_drive, 1); + ki_pset(swap_partition, 1); + + // Fake drive queue + /*uint8_t dummy[0x14*2] = { + // 00 08 01 00 00 00 00 14 00 01 00 08 FF D9 00 00 CE AD 00 2C + 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x08, 0xFF, 0xD9, 0x00, 0x00, 0x0f, 0x71, 0x00, 0x01, + 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0xFF, 0xDF, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 + };*/ + + uint8_t dummy[0x14*2] = { + // 00 08 01 00 00 00 00 14 00 01 00 08 FF D9 00 00 CE AD 00 2C + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x08, 0xFF, 0xD9, 0x00, 0x00, 0, 0, 0, 0, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0xFF, 0xDF, 0x00, 0x00, 0, 0, 0, 0 + }; + + for (i=0; i<(0x14*2); i++) + pset(((uint32_t)p) + sizeof(struct kernel_info) + i, 1, dummy[i]); + + // FIXME: *really* implement drive queue +} + +void init_macintosh_globals() +{ + uint8_t buf[0x1000]; + + memset(buf, 0xBB, 0x1000); + + uint32_t i; + for (i=0; i<0x1000; i++) + pset(i, 1, buf[i]); + + + #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) + // uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB | hwCbAUX; + + uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB; + + pset(0xb22, 2, HWCfgFlags); // HWCfgFlags + + pset(0x12f, 1, 0x02); // CPUFlag = 0x02 (MC68020) + pset(0x31a, 4, 0x00ffffff); // Lo3Bytes (always 0x00ffffff) + + pset(0x28e, 2, 0x3fff); // ROM85 (always 0x3fff, I think?) + + + pset(0xdd8, 4, 0); // universal info ptr. is allowed to be null on Mac II, (I THINK) + pset(0x1d4, 4, 0x50000000); // VIA (via1 ptr) + pset(0x1d8, 4, 0x50004000); // SCC + + /*pset(0x8ce, 1, 1); // CrsrNew (set to 1?) + pset(0x8cd, 1, 0); // CrsrBusy (0 -> Not presently busy) + pset(0x8d0, 2, 0); // CrsrState + pset(0x8cf, 1, 0xff); // CrsrCouple ?? + pset(0x8d6, 4, 0xffffffff); // MouseMask + pset(0x8da, 4, 0); // MouseOffset + pset(0x8d3, 1, 6); // CrsrScale + */ + + // 21e -> KbdType + // dd8 -> UnivInfoPtr + // d00 -> TimeDBRA + // d02 -> TimeSCCDB + // FIXME: add 0x21e, 0xdd8, 0x28e, 0xd00, 0xd02 + + // Do this after setting lomem mac stuff, because this structure is more important. + init_kernel_info(); +} + +uint32_t init_state (coff_file *coff, uint8_t *rom, uint32_t romsize) +{ + uint32_t i, j, pc = 0xffffffff; + + fpu_setup_jump_table(); + + shoe.coff = coff; + shoe.launch = coff_parser("priv/launch"); + + shoe.physical_mem_size = 32 * 1024 * 1024; + shoe.physical_rom_size = romsize; + + shoe.physical_mem_base = valloc(shoe.physical_mem_size); + shoe.physical_rom_base = valloc(romsize); + + memset(shoe.physical_mem_base, 0, shoe.physical_mem_size); + memcpy(shoe.physical_rom_base, rom, romsize); + + for (i=0; i<16; i++) { + shoe.slots[i].slotnum = i; + shoe.slots[i].connected = 0; + shoe.slots[i].glut_window_id = -1; + } + + // Install TFB at slot B + /*{ + shoe.slots[0xb].connected = 1; + shoe.slots[0xb].read_func = nubus_tfb_read_func; + shoe.slots[0xb].write_func = nubus_tfb_write_func; + nubus_tfb_init(0xb); + }*/ + + { + shoe.slots[0xa].connected = 1; + shoe.slots[0xa].read_func = nubus_video_read_func; + shoe.slots[0xa].write_func = nubus_video_write_func; + // nubus_video_init(0xa, 1440, 900); + nubus_video_init(0xa, 800, 600); + } + + + // Initialize relevant Mac globals + // (Do this before copying COFF segments, in case they overwrite these globals) + init_macintosh_globals(); + + /* Copy COFF segments into memory */ + for (i = 0; i < coff->num_sections; i++) { + coff_section *s = &coff->sections[i]; + + // Don't load a "copy" segment + if (s->flags & coff_copy) + continue; + + if ((s->flags & coff_text) || (s->flags & coff_data)) { + /* copy text or data section */ + + for (j = 0; j < s->sz; j++) + pset(s->p_addr+j, 1, s->data[j]); + + if (strcmp(s->name, "pstart") == 0) + pc = s->p_addr; + } + else if (s->flags & coff_bss) { + /* Create an empty .bss segment */ + + for (j = 0; j < s->sz; j++) + pset(s->p_addr+j, 1, 0); + } + } + + if (pc == 0xffffffff) { + printf("init_state: this unix doesn't contain a pstart segment\n"); + return 0; + } + + set_sr(0x2000); + shoe.pc = pc; + + // Start the VIA clocks + gettimeofday(&shoe.start_time, NULL); + shoe.total_ticks = 0; + + // Put the adb chip in state 3 (idle) + shoe.adb.state = 3; + pthread_mutex_init(&shoe.adb.lock, NULL); + + for (i=0; i<8; i++) { + shoe.scsi_devices[i].scsi_id = i; + shoe.scsi_devices[i].block_size = 0; + shoe.scsi_devices[i].num_blocks = 0; + shoe.scsi_devices[i].image_path = "dummy"; + shoe.scsi_devices[i].f = NULL; + } + + // Hacky load scsi disk at id 0 + + /*shoe.scsi_devices[0].scsi_id = 0; + shoe.scsi_devices[0].block_size = 512; + shoe.scsi_devices[0].num_blocks = 656544; + shoe.scsi_devices[0].image_path = "priv/Apple_UNIX_3.iso"; + shoe.scsi_devices[0].f = fopen(shoe.scsi_devices[0].image_path, "r+"); + assert(shoe.scsi_devices[0].f);*/ + + shoe.scsi_devices[0].scsi_id = 0; + shoe.scsi_devices[0].block_size = 512; + shoe.scsi_devices[0].num_blocks = 195912; //205561; + shoe.scsi_devices[0].image_path = "priv/aux2.img"; + shoe.scsi_devices[0].f = fopen(shoe.scsi_devices[0].image_path, "r+"); + assert(shoe.scsi_devices[0].f); + + shoe.scsi_devices[1].scsi_id = 1; + shoe.scsi_devices[1].block_size = 512; + shoe.scsi_devices[1].num_blocks = 1048576; + shoe.scsi_devices[1].image_path = "priv/blank.img"; + shoe.scsi_devices[1].f = fopen(shoe.scsi_devices[1].image_path, "r+"); + assert(shoe.scsi_devices[1].f); + + /*shoe.scsi_devices[6].scsi_id = 6; + shoe.scsi_devices[6].block_size = 512; + shoe.scsi_devices[6].num_blocks = 1280032; //205561; + shoe.scsi_devices[6].image_path = "priv/macii_fs.img"; + shoe.scsi_devices[6].f = fopen(shoe.scsi_devices[6].image_path, "r+"); + assert(shoe.scsi_devices[6].f);*/ + + /* In the future, we'll need to setup that booter struct for A/UX. */ + + // HACK HACK HACK + // Not sure why, but it seems that on non-RBV systems, A/UX version >= 1.1.1 does memcpy(0x0, 0x50000, 0x4000), blowing away all the lomem stuff + // So copy lomem stuff to 0x50000 + + for (i=0; i<0x4000; i++) { + uint8_t c = pget(i, 1); + pset(0x50000 + i, 1, c); + } + + shoe.a[0] += 0x50000; // A/UX thinks kernel_info should live at 0x50000 + (normal kernel_info addr). + + return 1; +} + + +#define KEY_SHIFT 1 + +const struct { + uint8_t code; + char c; + uint8_t modifiers; +} key_codes[] = { + {0x0, 'A', 0}, + {0x1, 'S', 0}, + {2, 'D', 0}, + {3, 'F', 0}, + {4, 'H', 0}, + {5, 'G', 0}, + {6, 'Z', 0}, + {7, 'X', 0}, + {8, 'C', 0}, + {9, 'V', 0}, + // {0xa ?? + {0xb, 'B', 0}, + {0xc, 'Q', 0}, + {0xd, 'W', 0}, + {0xe, 'E', 0}, + {0xf, 'R', 0}, + {0x10, 'Y', 0}, + {0x11, 'T', 0}, + + {0x12, '1', 0}, + {0x12, '!', KEY_SHIFT}, + + + {0x13, '2', 0}, + {0x13, '@', KEY_SHIFT}, + + {0x14, '3', 0}, + {0x14, '#', KEY_SHIFT}, + + {0x15, '4', 0}, + {0x15, '$', KEY_SHIFT}, + + {0x16, '6', 0}, + {0x16, '^', KEY_SHIFT}, + + {0x17, '5', 0}, + {0x17, '%', KEY_SHIFT}, + + {0x18, '=', 0}, + {0x18, '+', KEY_SHIFT}, + + {0x19, '9', 0}, + {0x19, '(', KEY_SHIFT}, + + {0x1a, '7', 0}, + {0x1a, '&', KEY_SHIFT}, + + {0x1b, '-', 0}, + {0x1b, '_', KEY_SHIFT}, + + {0x1c, '8', 0}, + {0x1c, '*', KEY_SHIFT}, + + {0x1d, '0', 0}, + {0x1d, ')', KEY_SHIFT}, + + {0x1e, ']', 0}, + {0x1e, '}', KEY_SHIFT}, + + {0x1f, 'O', 0}, + {0x20, 'U', 0}, + + {0x21, '[', 0}, + {0x21, '{', KEY_SHIFT}, + + {0x22, 'I', 0}, + {0x23, 'P', 0}, + + {0x24, '\n', 0}, + {0x24, '\r', 0}, + + {0x25, 'L', 0}, + {0x26, 'J', 0}, + + {0x27, '"', KEY_SHIFT}, + {0x27, '\'', 0}, + + {0x28, 'K', 0}, + + {0x29, ';', 0}, + {0x29, ':', KEY_SHIFT}, + + {0x2a, '\\', 0}, + {0x2a, '|', KEY_SHIFT}, + + {0x2b, ',', 0}, + {0x2b, '<', KEY_SHIFT}, + + {0x2c, '/', 0}, + {0x2c, '?', 0}, + + {0x2d, 'N', 0}, + {0x2e, 'M', 0}, + + {0x2f, '.', 0}, + {0x2f, '>', KEY_SHIFT}, + + {0x30, '\t', 0}, + {0x31, ' ', 0}, + + {0x32, '`', 0}, + {0x32, '~', KEY_SHIFT}, + + {0x33, '\b', 0}, + {0x33, 0x7f, 0}, + // {0x34, ?? + // {0x35 // escape char + // 0x36 // ctrl + // 0x37 // command + // 0x38 // shift + // 0x39 // caps lock + // 0x3a // option + // 0x3b // left arrow + // 0x3c // right arrow + // 0x3d // down arrow + // 0x3e // up arrow + + {0, 0, 0}, +}; + +static uint8_t lookup_key(char c) +{ + uint32_t i; + uint8_t upper=toupper(c); + + for (i=0; key_codes[i].c; i++) { + if (key_codes[i].c == upper) + return key_codes[i].code; + + } + + return 0xff; +} + +static uint8_t lookup_special(int special) +{ + switch (special) { + case GLUT_KEY_UP: return 0x3e; + case GLUT_KEY_DOWN: return 0x3d; + case GLUT_KEY_LEFT: return 0x3b; + case GLUT_KEY_RIGHT: return 0x3c; + default: return 0xff; + } +} + +static void keyboard_add_entry(uint8_t code, uint8_t up) +{ + uint8_t up_mask = up ? 0x80 : 0; + uint32_t i; + int modifiers = glutGetModifiers(); + + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + if ((shoe.key.key_i+1) < KEYBOARD_STATE_MAX_KEYS) { + if (modifiers & GLUT_ACTIVE_SHIFT) { + shoe.key.keys[shoe.key.key_i].code_a = 0x38; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } + else if (shoe.key.down_modifiers & GLUT_ACTIVE_SHIFT) { + shoe.key.keys[shoe.key.key_i].code_a = 0x80 | 0x38; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } + shoe.key.keys[shoe.key.key_i].code_a = code | up_mask; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } + + shoe.key.down_modifiers = modifiers; + + adb_request_service_request(2); + + pthread_mutex_unlock(&shoe.adb.lock); +} + +void global_mouse_func (int button, int state, int x, int y) +{ + //if (button != GLUT_LEFT_BUTTON) + // return ; + + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + shoe.mouse.button_down = (state == GLUT_DOWN); + shoe.mouse.changed = 1; + + adb_request_service_request(3); + + pthread_mutex_unlock(&shoe.adb.lock); + + // printf("mouse_func: setting service request\n"); +} + +static void move_mouse (int x, int y, uint8_t button_down) +{ + printf("%s: lock\n", __func__); fflush(stdout); + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + int32_t delta_x = x - shoe.mouse.old_x; + int32_t delta_y = y - shoe.mouse.old_y; + + shoe.mouse.old_x = x; + shoe.mouse.old_y = y; + + shoe.mouse.delta_x += delta_x; + shoe.mouse.delta_y += delta_y; + shoe.mouse.button_down = button_down; + shoe.mouse.changed = 1; + + adb_request_service_request(3); + printf("%s: unlock\n", __func__); fflush(stdout); + pthread_mutex_unlock(&shoe.adb.lock); + + // printf("move_mouse: setting service request\n"); +} + +void global_motion_func (int x, int y) +{ + move_mouse(x, y, 1); +} + +void global_passive_motion_func (int x, int y) +{ + move_mouse(x, y, 0); +} + +void global_keyboard_up_func (unsigned char c, int x, int y) +{ + uint8_t code = lookup_key(c); + if (code != 0xff) + keyboard_add_entry(code, 1); +} + +void global_keyboard_down_func (unsigned char c, int x, int y) +{ + uint8_t code = lookup_key(c); + if (code != 0xff) + keyboard_add_entry(code, 0); +} + +void global_special_up_func (int special, int x, int y) +{ + const uint8_t code = lookup_special(special); + if (code != 0xff) + keyboard_add_entry(code, 1); +} + +void global_special_down_func (int special, int x, int y) +{ + const uint8_t code = lookup_special(special); + if (code != 0xff) + keyboard_add_entry(code, 0); +} + +void timer_func (int arg) +{ + glutTimerFunc(15, timer_func, 0); // 66.67hz is the usual refresh interval (right?) + + uint32_t slotnum; + for (slotnum = 0; slotnum < 16; slotnum++) { + if (shoe.slots[slotnum].glut_window_id == -1) + continue; + + glutSetWindow(shoe.slots[slotnum].glut_window_id); + glutPostRedisplay(); + } +} + +//void _macii_load_video_rom(const char *path); +int main (int argc, char **argv) +{ + coff_file *coff; + uint32_t romsize; + uint8_t *rom; + pthread_t pid; + + //_macii_load_video_rom("tfb_rom"); + + rom = loadrom("priv/macii.rom", &romsize); + if (rom == NULL) + return 0; + //printf(") + + /*if (romsize != (256 * 1024)) { + printf("Bogus rom size (%u bytes)\n", romsize); + return 0; + }*/ + + coff = coff_parser("priv/unix"); + if (coff == NULL) { + printf("main: coff_parser() failed to load \"unix\"\n"); + return 0; + } + + int dummyargc = 1; + glutInit(&dummyargc, argv); + + if (!init_state(coff, rom, romsize)) + return 0; + free(rom); + + pthread_create(&pid, NULL, ui_thread, NULL); + + glutTimerFunc(15, timer_func, 0); + glutMainLoop(); + while (1) sleep(1); + return 0; +} + diff --git a/core/decoder_gen.c b/core/decoder_gen.c new file mode 100644 index 0000000..fba40d6 --- /dev/null +++ b/core/decoder_gen.c @@ -0,0 +1,1484 @@ +/* + * Copyright (c) 2013, 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 +#include +#include + +typedef struct { + uint8_t add; + const char *descriptor; +} range_t; + +typedef struct { + range_t *ranges; + uint32_t numranges; + uint8_t use_ea; + uint8_t allowed_ea_modes[12]; +} range_group_t; + +typedef struct { + range_group_t *groups; + uint32_t numgroups, curgroup; + const char *name; + uint8_t supervisor_only; + uint8_t supported_architectures[5]; // 680x0 +} inst_t; + +typedef struct { + inst_t inst[256]; + uint32_t num_instructions; + uint32_t curinst; + + uint8_t inst_map[0x10000]; +} generator_ctx_t; + +generator_ctx_t ctx; + +/* --- generator API --- */ + +// All but addr reg allowed +const uint8_t _ea_data[12] = {1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +// All but registers allowed +const uint8_t _ea_memory[12] = {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +// No regs, pre/post-inc/dec, or immediate +const uint8_t _ea_control[12] = {0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1}; +// Erratum: 68kprm table 2-4 says that "program counter memory indirect" +// is alterable, but that can't be right. +// Also it says that (xxx).L/W aren't alterable, but it seems they are. +const uint8_t _ea_alterable[12] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}; + +enum ea_definitions { + EA_000 = 0, + EA_001, + EA_010, + EA_011, + EA_100, + EA_101, + EA_110, + EA_111_000, + EA_111_001, + EA_111_100, + EA_111_010, + EA_111_011 +}; + +// For each of the 12 EA modes, this is bitmap of the allowed lower 6 bits +const uint64_t ea_mode_masks[12] = { + 0x00000000000000ff, // 000 + 0x000000000000ff00, // 001 + 0x0000000000ff0000, // 010 + 0x00000000ff000000, // 011 + 0x000000ff00000000, // 100 + 0x0000ff0000000000, // 101 + 0x00ff000000000000, // 110 + 0x0100000000000000, // 111_000 + 0x0200000000000000, // 111_001 + 0x1000000000000000, // 111_100 + 0x0400000000000000, // 111_010 + 0x0800000000000000, // 111_011 +}; + +void ea_data(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + group->use_ea = 1; + memcpy(group->allowed_ea_modes, _ea_data, 12); +} +void ea_memory(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + group->use_ea = 1; + memcpy(group->allowed_ea_modes, _ea_memory, 12); +} +void ea_control(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + group->use_ea = 1; + memcpy(group->allowed_ea_modes, _ea_control, 12); +} +void ea_alterable(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + group->use_ea = 1; + memcpy(group->allowed_ea_modes, _ea_alterable, 12); +} +void ea_control_alterable(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + uint32_t i; + group->use_ea = 1; + for (i=0; i<12; i++) + group->allowed_ea_modes[i] = _ea_alterable[i] && _ea_control[i]; +} +void ea_memory_alterable(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + uint32_t i; + group->use_ea = 1; + for (i=0; i<12; i++) + group->allowed_ea_modes[i] = _ea_alterable[i] && _ea_memory[i]; +} +void ea_data_alterable(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + uint32_t i; + group->use_ea = 1; + for (i=0; i<12; i++) + group->allowed_ea_modes[i] = _ea_alterable[i] && _ea_data[i]; +} +void ea_all(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + uint32_t i; + group->use_ea = 1; + for (i=0; i<12; i++) group->allowed_ea_modes[i] = 1; +} + +void no_ea(inst_t *inst) { + range_group_t *group = &inst->groups[inst->curgroup]; + assert(group->use_ea == 0xff); + group->use_ea = 0; +} + +void ea_add_mode(inst_t *inst, enum ea_definitions mode) +{ + range_group_t *group = &inst->groups[inst->curgroup]; + group->use_ea = 1; + assert(!group->allowed_ea_modes[mode]); + group->allowed_ea_modes[mode] = 1; +} + +void ea_sub_mode(inst_t *inst, enum ea_definitions mode) +{ + range_group_t *group = &inst->groups[inst->curgroup]; + group->use_ea = 1; + assert(group->allowed_ea_modes[mode]); + group->allowed_ea_modes[mode] = 0; +} + +void add_range(inst_t *inst, const char *descriptor) +{ + range_group_t *group = &inst->groups[inst->curgroup]; + group->ranges = realloc(group->ranges, sizeof(range_t) * (group->numranges+1)); + range_t *range = &group->ranges[group->numranges]; + group->numranges++; + + range->add = 1; + range->descriptor = descriptor; +} + +void sub_range(inst_t *inst, const char *descriptor) +{ + range_group_t *group = &inst->groups[inst->curgroup]; + group->ranges = realloc(group->ranges, sizeof(range_t) * (group->numranges+1)); + range_t *range = &group->ranges[group->numranges]; + group->numranges++; + + range->add = 0; + range->descriptor = descriptor; +} + +void supervisor_only(inst_t *inst) +{ + assert(!inst->supervisor_only); + inst->supervisor_only = 1; +} + +void set_range_group(inst_t *inst, uint32_t curgroup) +{ + assert(curgroup < inst->numgroups); + inst->curgroup = curgroup; +} + +inst_t* new_inst (const char *name, const char *architectures, uint32_t numgroups) +{ + uint32_t i, curinst = ctx.num_instructions; + + ctx.num_instructions++; + ctx.curinst = curinst; + + inst_t *inst = &ctx.inst[curinst]; + + memset(inst, 0, sizeof(inst_t)); + + inst->name = name; + inst->supervisor_only = 0; + + char tmp[128]; + if ((sscanf(architectures, "%s", tmp) == 1) && (strcasecmp(tmp, "all") == 0)) { + for (i=0; i<5; i++) + inst->supported_architectures[i] = 1; + } + else { + char c; + for (i=0; (c=architectures[i]) != 0; i++) { + if (isspace(c)) continue; + if (isdigit(c)) { + c -= '0'; + assert(c <= 4); + assert(!inst->supported_architectures[c]); + inst->supported_architectures[c] = 1; + continue ; + } + printf("Extraneous characters in arch string for %s\n", name); + assert(!"extraneous characters in architecture string"); + } + } + + inst->numgroups = numgroups; + inst->groups = (range_group_t*) calloc(numgroups, sizeof(range_group_t)); + inst->curgroup = 0; + + for (i=0; igroups[i].ranges = malloc(sizeof(range_t)); + inst->groups[i].use_ea = 0xff; // invalid + } + + return inst; +} + +/* --- Generator guts --- */ + +typedef struct { + uint16_t fixed; + uint16_t mask; +} desc_t; + +static desc_t process_descriptor(uint32_t inst_num, range_group_t *group, uint32_t range_num) +{ + uint16_t fixed=0, mask=0, EA=0, bits=0; + uint32_t i; + desc_t result; + char c; + + range_t *range = &group->ranges[range_num]; + for (i=0; (c=range->descriptor[i]) != 0; i++) { + if (isspace(c)) continue; + + fixed <<= 1; + mask <<= 1; + EA <<= 1; + if (c == '1' || c == '0') { + fixed |= (c - '0'); + mask |= 1; + } + else if (c == 'M') + EA |= 1; // both x and M will be considered wild bits + // Later, we'll subtract the unused EA modes from the bitmask + else if (c != 'x') + goto bad; + + bits++; + } + if (bits != 16) + goto bad; + else if (group->use_ea && (EA != 0x3f)) + goto bad; + else if (!group->use_ea && (EA != 0)) + goto bad; + + result.fixed = fixed; + result.mask = mask; + + return result; + +bad: + printf("bad descriptor for instruction %s '%s'\n", + ctx.inst[inst_num].name, range->descriptor); + assert(!"bad desc"); +} + +// Build a map (uint64_t) of the allowable lower 6 bits +static uint64_t process_ea_modes(range_group_t *group) +{ + uint64_t result = 0; + uint32_t i; + + for (i=0; i<12; i++) + if (group->allowed_ea_modes[i]) + result |= ea_mode_masks[i]; + return result; +} + +static void process_group(uint32_t inst_num, uint32_t group_num) +{ + inst_t *inst = &ctx.inst[inst_num]; + range_group_t *group = &inst->groups[group_num]; + uint8_t bitmap[8192]; + uint32_t i; + + memset(bitmap, 0, 8192); + + if (group->use_ea == 0xff) { + printf("inst %s group %u needs EA specified\n", inst->name, group_num); + assert(!"blowup"); + } + + // add or subtract all the descriptors into the bitmap + for (i=0; inumranges; i++) { + desc_t desc = process_descriptor(inst_num, group, i); + uint32_t j; + if (group->ranges[i].add) { + for (j=0; j < 0x10000; j++) { + if ((j & desc.mask) == desc.fixed) + bitmap[j >> 3] |= (1 << (j & 7)); // add this opcode + } + } + else { + for (j=0; j < 0x10000; j++) { + if ((j & desc.mask) == desc.fixed) + bitmap[j >> 3] &= ~(1 << (j & 7)); // subtract this opcode + } + } + } + + // Now we need to subtract the impossible and invalid EA modes, if use_ea + if (group->use_ea) { + // Negate the allowable modes map (making a disallowed modes map) + const uint64_t disallowed_modes = ~process_ea_modes(group); + for (i=0; i<0x10000; i++) { + if (disallowed_modes & (1ULL << (i & 0x3f))) + bitmap[i >> 3] &= ~(1 << (i & 7)); + } + } + + // Now feed bitmap[] into the global instruction map + for (i=0; i<0x10000; i++) { + if (!(bitmap[i >> 3] & (1 << (i & 7)))) continue; + + if (ctx.inst_map[i] != 0) { + printf("Error! instructions %s(%u) and %s(%u) overlap at opcode 0x%04x\n", + ctx.inst[ctx.inst_map[i]].name, ctx.inst_map[i], + ctx.inst[inst_num].name, inst_num, i); + assert(!"blowup"); + } + + ctx.inst_map[i] = inst_num; + } + +} + +void digest_definitions(uint32_t arch) +{ + uint32_t i; + for (i=0; isupported_architectures[arch]) + continue; + + for (j=0; jnumgroups; j++) + process_group(i, j); + } + +} + +void write_decoder (const char *prefix, const char *path) +{ + uint32_t i; + char *file_path = malloc(strlen(path) + strlen(prefix) + 32); + sprintf(file_path, "%s/%s_decoder_guts.c", path, prefix); + + FILE *f = fopen(file_path, "w"); + + if (f == NULL) { + printf("write_decoder: can't open %s for writing\n", path); + assert(!"blowup"); + } + + fprintf(f, "const uint32_t %s_num_instructions = %u;\n\n", prefix, ctx.num_instructions); + + + /* --- write inst_num -> function_pointer table --- */ + + fprintf(f, "typedef void (*%s_func_ptr)();\n", prefix); + fprintf(f, "%s_func_ptr %s_instruction_to_pointer[%u] = {\n", prefix, prefix, ctx.num_instructions); + for (i=0; i inst_num table --- */ + + fprintf(f, "const uint8_t %s_opcode_map[0x10000] = {\n", prefix); + for (i=0; i < 0xffff; i++) { + if ((i % 8) == 0) + fprintf(f, "\t"); + fprintf(f, "0x%02x, ", ctx.inst_map[i]); + if (((i + 1) % 8) == 0) + fprintf(f, "\n"); + } + fprintf(f, "0x%02x\n};\n\n", ctx.inst_map[i]); + +} + + +void init() { + memset(ctx.inst_map, 0x00, 0x10000); // 0x00 -> unset + + ctx.num_instructions = 1; + ctx.inst[0].name = "unknown"; + ctx.inst[0].numgroups = 0; +} + +void begin_definitions(); +int main (int argc, char **argv) +{ + if (argc != 3) { + printf("arguments: ./decoder_gen inst|dis intermediates/"); + return 0; + } + + init(); + begin_definitions(); + digest_definitions(2); // build for 68020. Dunno if I'll ever support other architectures + write_decoder(argv[1], argv[2]); + + // printf("num_instructions = %u\n", ctx.num_instructions); + + return 0; +} + +/* --- Big list of definitions --- */ + +void begin_definitions() +{ + + /* --- Unprivileged integer instructions --- */ + + { // abcd + inst_t *inst = new_inst("abcd", "all", 1); + add_range(inst, "1100 xxx 10000 x xxx"); + no_ea(inst); + } + + { // add + inst_t *inst = new_inst("add", "all", 3); + { // to-register (EA mode == addr register) + set_range_group(inst, 0); + add_range(inst, "1101 xxx 001 MMMMMM"); + add_range(inst, "1101 xxx 010 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { // to-register (all other EA modes) + set_range_group(inst, 1); + add_range(inst, "1101 xxx 0xx MMMMMM"); + sub_range(inst, "1101 xxx 011 MMMMMM"); + ea_all(inst); + ea_sub_mode(inst, EA_001); + } + { // to-EA + set_range_group(inst, 2); + add_range(inst, "1101 xxx 1xx MMMMMM"); + sub_range(inst, "1101 xxx 111 MMMMMM"); + ea_memory_alterable(inst); + } + } + + { // adda + inst_t *inst = new_inst("adda", "all", 1); + add_range(inst, "1101 xxx x11 MMMMMM"); + ea_all(inst); + } + + { // addi + inst_t *inst = new_inst("addi", "all", 1); + add_range(inst, "0000 0110 xx MMMMMM"); + sub_range(inst, "0000 0110 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // addq + inst_t *inst = new_inst("addq", "all", 2); + { // ea mode == addr reg + set_range_group(inst, 0); + add_range(inst, "0101 xxx 0 01 MMMMMM"); + add_range(inst, "0101 xxx 0 10 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { + set_range_group(inst, 1); + add_range(inst, "0101 xxx 0 xx MMMMMM"); + sub_range(inst, "0101 xxx 0 11 MMMMMM"); + ea_alterable(inst); + ea_sub_mode(inst, EA_001); + } + } + + { // addx + inst_t *inst = new_inst("addx", "all", 1); + add_range(inst, "1101 xxx 1 xx 00 x xxx"); + sub_range(inst, "1101 xxx 1 11 00 x xxx"); + no_ea(inst); + } + + { // and + inst_t *inst = new_inst("and", "all", 2); + { // to register + set_range_group(inst, 0); + add_range(inst, "1100 xxx 0xx MMMMMM"); + sub_range(inst, "1100 xxx 011 MMMMMM"); + ea_data(inst); + } + { // to memory + set_range_group(inst, 1); + add_range(inst, "1100 xxx 1xx MMMMMM"); + sub_range(inst, "1100 xxx 111 MMMMMM"); + ea_memory_alterable(inst); + } + } + + { // andi + inst_t *inst = new_inst("andi", "all", 1); + add_range(inst, "0000 0010 xx MMMMMM"); + sub_range(inst, "0000 0010 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // andi_to_ccr + inst_t *inst = new_inst("andi_to_ccr", "all", 1); + add_range(inst, "0000 0010 00111100"); + no_ea(inst); + } + + { // asx_reg + inst_t *inst = new_inst("asx_reg", "all", 1); + add_range(inst, "1110 xxx x xx x 00 xxx"); + sub_range(inst, "1110 xxx x 11 x 00 xxx"); + no_ea(inst); + } + + { // asx_mem + inst_t *inst = new_inst("asx_mem", "all", 1); + add_range(inst, "1110 000 x 11 MMMMMM"); + ea_memory_alterable(inst); + } + + { // bcc + inst_t *inst = new_inst("bcc", "all", 1); + add_range(inst, "0110 xxxx xxxxxxxx"); + sub_range(inst, "0110 0001 xxxxxxxx"); // this is BSR + no_ea(inst); + } + + { + inst_t *inst = new_inst("bchg_reg", "all", 1); + add_range(inst, "0000 xxx 101 MMMMMM"); + ea_data_alterable(inst); + } + + { + inst_t *inst = new_inst("bchg_immediate", "all", 1); + add_range(inst, "0000 1000 01 MMMMMM"); + ea_data_alterable(inst); + } + + { + inst_t *inst = new_inst("bclr_reg", "all", 1); + add_range(inst, "0000 xxx 110 MMMMMM"); + ea_data_alterable(inst); + } + + { + inst_t *inst = new_inst("bclr_immediate", "all", 1); + add_range(inst, "0000 1000 10 MMMMMM"); + ea_data_alterable(inst); + } + + + { // bfchg + inst_t *inst = new_inst("bfchg", "234", 1); + add_range(inst, "1110 1010 11 MMMMMM"); + ea_control_alterable(inst); // Yes, control_alterable + ea_add_mode(inst, EA_000); + } + + { // bfclr + inst_t *inst = new_inst("bfclr", "234", 1); + add_range(inst, "1110 1100 11 MMMMMM"); + ea_control_alterable(inst); // Yes, control_alterable + ea_add_mode(inst, EA_000); + } + + { // bfexts + inst_t *inst = new_inst("bfexts", "234", 1); + add_range(inst, "1110 1011 11 MMMMMM"); + ea_control(inst); // Yes, control (doesn't alter) + ea_add_mode(inst, EA_000); + } + + { // bfextu + inst_t *inst = new_inst("bfextu", "234", 1); + add_range(inst, "1110 1001 11 MMMMMM"); + ea_control(inst); // Yes, control + ea_add_mode(inst, EA_000); + } + + { // bfffo + inst_t *inst = new_inst("bfffo", "234", 1); + add_range(inst, "1110 1101 11 MMMMMM"); // eratum: incorrect in 68kprm + ea_control(inst); // Yes, control + ea_add_mode(inst, EA_000); + } + + { // bfins + inst_t *inst = new_inst("bfins", "234", 1); + add_range(inst, "1110 1111 11 MMMMMM"); + ea_control_alterable(inst); // Yes, control_alterable + ea_add_mode(inst, EA_000); + } + + { // bfset + inst_t *inst = new_inst("bfset", "234", 1); + add_range(inst, "1110 1110 11 MMMMMM"); + ea_control_alterable(inst); // Yes, control_alterable + ea_add_mode(inst, EA_000); + } + + { // bftst + inst_t *inst = new_inst("bftst", "234", 1); + add_range(inst, "1110 1000 11 MMMMMM"); + ea_control(inst); // Yes, control + ea_add_mode(inst, EA_000); + } + + { // bkpt + inst_t *inst = new_inst("bkpt", "1234", 1); // MC68EC000 is also supported + add_range(inst, "0100 1000 0100 1 xxx"); + no_ea(inst); + } + + // This is just bcc with cc == 0 == TRUE + /*{ // bra + inst_t *inst = new_inst("bra", "all", 1); + add_range(inst, "0110 0000 xxxxxxxx"); + no_ea(inst); + }*/ + + { + inst_t *inst = new_inst("bset_reg", "all", 1); + add_range(inst, "0000 xxx 111 MMMMMM"); + ea_data_alterable(inst); + } + + { + inst_t *inst = new_inst("bset_immediate", "all", 1); + add_range(inst, "0000 1000 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // bsr + inst_t *inst = new_inst("bsr", "all", 1); // long-mode is 68020-040 only + add_range(inst, "0110 0001 xxxxxxxx"); + no_ea(inst); + } + + { // btst_reg + inst_t *inst = new_inst("btst_reg", "all", 1); + add_range(inst, "0000 xxx 100 MMMMMM"); + ea_data(inst); + } + + { // btst_immediate + inst_t *inst = new_inst("btst_immediate", "all", 1); + add_range(inst, "0000 1000 00 MMMMMM"); + ea_data(inst); + } + + { // callm + inst_t *inst = new_inst("callm", "2", 1); + add_range(inst, "0000 0110 11 MMMMMM"); + ea_control(inst); + } + + { // cas + inst_t *inst = new_inst("cas", "234", 1); + add_range(inst, "0000 1xx 011 MMMMMM"); + sub_range(inst, "0000 100 011 MMMMMM"); + ea_memory_alterable(inst); + } + + { // cas2 + inst_t *inst = new_inst("cas2", "234", 1); + add_range(inst, "0000 1 10 011111100"); + add_range(inst, "0000 1 11 011111100"); + no_ea(inst); + } + + { // chk + inst_t *inst = new_inst("chk", "all", 1); + add_range(inst, "0100 xxx 10 0 MMMMMM"); + add_range(inst, "0100 xxx 11 0 MMMMMM"); + ea_data(inst); + } + + { // chk2+cmp2 (These instructions are distinguished by the extension word) + inst_t *inst = new_inst("chk2_cmp2", "234", 1); + add_range(inst, "0000 0xx0 11 MMMMMM"); + sub_range(inst, "0000 0110 11 MMMMMM"); + ea_control(inst); + } + + { // clr + inst_t *inst = new_inst("clr", "all", 1); + add_range(inst, "0100 0010 xx MMMMMM"); + sub_range(inst, "0100 0010 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // cmp + inst_t *inst = new_inst("cmp", "all", 2); + { // address mode reg (byte-mode isn't supported for address registers) + set_range_group(inst, 0); + add_range(inst, "1011 xxx 001 MMMMMM"); + add_range(inst, "1011 xxx 010 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { // other modes + set_range_group(inst, 1); + add_range(inst, "1011 xxx 0xx MMMMMM"); + sub_range(inst, "1011 xxx 011 MMMMMM"); + ea_all(inst); + ea_sub_mode(inst, EA_001); + } + } + + { // cmpa + inst_t *inst = new_inst("cmpa", "all", 1); + add_range(inst, "1011 xxx x11 MMMMMM"); + ea_all(inst); + } + + { // cmpi + inst_t *inst = new_inst("cmpi", "all", 1); + add_range(inst, "0000 1100 xx MMMMMM"); + sub_range(inst, "0000 1100 11 MMMMMM"); + ea_data(inst); + /* + * Erratum: documentation says "data addressing modes", + * but the table doesn't list immediate mode + */ + ea_sub_mode(inst, EA_111_100); + } + + { // cmpm + inst_t *inst = new_inst("cmpm", "all", 1); + add_range(inst, "1011 xxx 1 xx 001 xxx"); + sub_range(inst, "1011 xxx 1 11 001 xxx"); + no_ea(inst); + } + + // cmp2 is handled by chk2_cmp2 + + { // DBcc + inst_t *inst = new_inst("dbcc", "all", 1); + add_range(inst, "0101 xxxx 11001 xxx"); + no_ea(inst); + } + + { // divs + inst_t *inst = new_inst("divs", "all", 1); + add_range(inst, "1000 xxx 111 MMMMMM"); + ea_data(inst); // Erratum: 68kprm says "data alterable", but means "data" + } + + { // divu + inst_t *inst = new_inst("divu", "all", 1); + add_range(inst, "1000 xxx 011 MMMMMM"); + ea_data(inst); // 68kprm gets it right here + } + + { // divl (both signed and unsigned) + inst_t *inst = new_inst("long_div", "234", 1); + add_range(inst, "0100 1100 01 MMMMMM"); + ea_data(inst); // Erratum: 68kprm means "data" here + } + + { // eor + inst_t *inst = new_inst("eor", "all", 1); + add_range(inst, "1011 xxx 1xx MMMMMM"); + sub_range(inst, "1011 xxx 111 MMMMMM"); + ea_data_alterable(inst); + } + + { // eori + inst_t *inst = new_inst("eori", "all", 1); + add_range(inst, "0000 1010 xx MMMMMM"); + sub_range(inst, "0000 1010 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // eori_to_ccr + inst_t *inst = new_inst("eori_to_ccr", "all", 1); + add_range(inst, "0000 1010 0011 1100"); + no_ea(inst); + } + + { // exg + inst_t *inst = new_inst("exg", "all", 1); + add_range(inst, "1100 xxx 1 01000 xxx"); + add_range(inst, "1100 xxx 1 01001 xxx"); + add_range(inst, "1100 xxx 1 10001 xxx"); + no_ea(inst); + } + + { // ext + inst_t *inst = new_inst("ext", "all", 1); + add_range(inst, "0100 100 010 000 xxx"); + add_range(inst, "0100 100 011 000 xxx"); + add_range(inst, "0100 100 111 000 xxx"); + no_ea(inst); + } + + { // illegal + inst_t *inst = new_inst("illegal", "all", 1); + add_range(inst, "0100 1010 1111 1100"); + no_ea(inst); + } + + { // jmp + inst_t *inst = new_inst("jmp", "all", 1); + add_range(inst, "0100 1110 11 MMMMMM"); + ea_control(inst); + } + + { // jsr + inst_t *inst = new_inst("jsr", "all", 1); + add_range(inst, "0100 1110 10 MMMMMM"); + ea_control(inst); + } + + { // lea + inst_t *inst = new_inst("lea", "all", 1); + add_range(inst, "0100 xxx 111 MMMMMM"); + ea_control(inst); + } + + { // link_word + inst_t *inst = new_inst("link_word", "all", 1); + add_range(inst, "0100 1110 0101 0 xxx"); // word + no_ea(inst); + } + + { // link_long + inst_t *inst = new_inst("link_long", "all", 1); + add_range(inst, "0100 1000 0000 1 xxx"); // long + no_ea(inst); + } + + { // lsx_reg + inst_t *inst = new_inst("lsx_reg", "all", 1); + add_range(inst, "1110 xxx x xx x 01 xxx"); + sub_range(inst, "1110 xxx x 11 x 01 xxx"); + no_ea(inst); + } + + { // lsx_mem + inst_t *inst = new_inst("lsx_mem", "all", 1); + add_range(inst, "1110 001 x 11 MMMMMM"); + ea_memory_alterable(inst); + } + + + { // move + inst_t *inst = new_inst("move", "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 xxxxxx"); + + // 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 the illegal source modes + sub_range(inst, "00 xx xxxxxx 111 101"); + sub_range(inst, "00 xx xxxxxx 111 110"); + sub_range(inst, "00 xx xxxxxx 111 111"); + + // Subtract address reg source mode for size==byte + sub_range(inst, "00 01 xxxxxx 001 xxx"); + + // subtract illegal size (00) + sub_range(inst, "00 00 xxxxxx xxxxxx"); + } + + { // movea + inst_t *inst = new_inst("movea", "all", 1); + add_range(inst, "00 10 xxx 001 MMMMMM"); + add_range(inst, "00 11 xxx 001 MMMMMM"); + ea_all(inst); + } + + { // move_from_ccr + inst_t *inst = new_inst("move_from_ccr", "1234", 1); + add_range(inst, "0100 0010 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // move_to_ccr + inst_t *inst = new_inst("move_to_ccr", "all", 1); + add_range(inst, "0100 0100 11 MMMMMM"); + ea_data(inst); + } + + { // move_from_sr + inst_t *inst = new_inst("move_from_sr", "all", 1); // NOTE: this is supervisor-only for 68010-68040 + add_range(inst, "0100 0000 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // move16 + inst_t *inst = new_inst("move16", "4", 1); + add_range(inst, "1111 0110 001 00 xxx"); // postincrement source and destination + add_range(inst, "1111 0110 000 xx xxx"); // absolute long address source or destination + no_ea(inst); + } + + { // movem + inst_t *inst = new_inst("movem", "all", 2); + { // to-mem + set_range_group(inst, 0); + add_range(inst, "0100 1000 1x MMMMMM"); + ea_control_alterable(inst); + ea_add_mode(inst, EA_100); + } + { // to-reg + set_range_group(inst, 1); + add_range(inst, "0100 1100 1x MMMMMM"); + ea_control(inst); + ea_add_mode(inst, EA_011); + } + } + + { // movep + inst_t *inst = new_inst("movep", "all", 1); + add_range(inst, "0000 xxx 1xx 001 xxx"); + no_ea(inst); + } + + { // moveq + inst_t *inst = new_inst("moveq", "all", 1); + add_range(inst, "0111 xxx 0 xxxxxxxx"); + no_ea(inst); + } + + { // muls + inst_t *inst = new_inst("muls", "all", 1); + add_range(inst, "1100 xxx 111 MMMMMM"); + ea_data(inst); // Erratum: 68kprm says "data alterable", but means "data" + } + + { // mulu + inst_t *inst = new_inst("mulu", "all", 1); + add_range(inst, "1100 xxx 011 MMMMMM"); + ea_data(inst); + } + + { // mulsl/mulul + inst_t *inst = new_inst("long_mul", "234", 1); + add_range(inst, "0100 1100 00 MMMMMM"); // Erratum: muls_long says "data alterable" + ea_data(inst); + } + + { // nbcd + inst_t *inst = new_inst("nbcd", "all", 1); + add_range(inst, "0100 1000 00 MMMMMM"); + ea_data_alterable(inst); + } + + { // neg + inst_t *inst = new_inst("neg", "all", 1); + add_range(inst, "0100 0100 xx MMMMMM"); + sub_range(inst, "0100 0100 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // negx + inst_t *inst = new_inst("negx", "all", 1); + add_range(inst, "0100 0000 xx MMMMMM"); + sub_range(inst, "0100 0000 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // nop + inst_t *inst = new_inst("nop", "all", 1); + add_range(inst, "0100 1110 0111 0001"); + no_ea(inst); + } + + { // not + inst_t *inst = new_inst("not", "all", 1); + add_range(inst, "0100 0110 xx MMMMMM"); + sub_range(inst, "0100 0110 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // or + inst_t *inst = new_inst("or", "all", 2); + { // to register + set_range_group(inst, 0); + add_range(inst, "1000 xxx 0xx MMMMMM"); + sub_range(inst, "1000 xxx 011 MMMMMM"); + ea_data(inst); + } + { // to memory + set_range_group(inst, 1); + add_range(inst, "1000 xxx 1xx MMMMMM"); + sub_range(inst, "1000 xxx 111 MMMMMM"); + ea_memory_alterable(inst); + } + } + + { // ori + inst_t *inst = new_inst("ori", "all", 1); + add_range(inst, "0000 0000 xx MMMMMM"); + sub_range(inst, "0000 0000 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // ori_to_ccr + inst_t *inst = new_inst("ori_to_ccr", "all", 1); + add_range(inst, "0000 0000 00 111100"); + no_ea(inst); + } + + { // pack + inst_t *inst = new_inst("pack", "234", 1); + add_range(inst, "1000 xxx 10100 x xxx"); + no_ea(inst); + } + + { // pea + inst_t *inst = new_inst("pea", "all", 1); + add_range(inst, "0100 1000 01 MMMMMM"); + ea_control(inst); + } + + /*{ // rox + inst_t *inst = new_inst("rox", "all", 2); + { // register rotate + set_range_group(inst, 0); + add_range(inst, "1110 xxx x xx x 11 xxx"); + sub_range(inst, "1110 xxx x 11 x 11 xxx"); + no_ea(inst); + } + { // memory rotate + set_range_group(inst, 1); + add_range(inst, "1110 011 x 11 MMMMMM"); + ea_memory_alterable(inst); + } + }*/ + + { // rox_reg + inst_t *inst = new_inst("rox_reg", "all", 1); + add_range(inst, "1110 xxx x xx x 11 xxx"); + sub_range(inst, "1110 xxx x 11 x 11 xxx"); + no_ea(inst); + } + + { // rox_mem + inst_t *inst = new_inst("rox_mem", "all", 1); + add_range(inst, "1110 011 x 11 MMMMMM"); + ea_memory_alterable(inst); + } + + + /*{ // roxx + inst_t *inst = new_inst("roxx", "all", 2); + { // register rotate + set_range_group(inst, 0); + add_range(inst, "1110 xxx x xx x 10 xxx"); + sub_range(inst, "1110 xxx x 11 x 10 xxx"); + no_ea(inst); + } + { // memory rotate + set_range_group(inst, 1); + add_range(inst, "1110 010 x 11 MMMMMM"); + ea_memory_alterable(inst); + } + }*/ + + { // roxx_reg + inst_t *inst = new_inst("roxx_reg", "all", 1); + add_range(inst, "1110 xxx x xx x 10 xxx"); + sub_range(inst, "1110 xxx x 11 x 10 xxx"); + no_ea(inst); + } + + { // roxx_mem + inst_t *inst = new_inst("roxx_mem", "all", 1); + add_range(inst, "1110 010 x 11 MMMMMM"); + ea_memory_alterable(inst); + } + + + { // rtd + inst_t *inst = new_inst("rtd", "1234", 1); + add_range(inst, "0100 1110 0111 0100"); + no_ea(inst); + } + + { // rtm + inst_t *inst = new_inst("rtm", "2", 1); + add_range(inst, "0000 0110 1100 x xxx"); + no_ea(inst); + } + + { // rtr + inst_t *inst = new_inst("rtr", "all", 1); + add_range(inst, "0100 1110 0111 0111"); + no_ea(inst); + } + + { // rts + inst_t *inst = new_inst("rts", "all", 1); + add_range(inst, "0100 1110 0111 0101"); + no_ea(inst); + } + + { // sbcd + inst_t *inst = new_inst("sbcd", "all", 1); + add_range(inst, "1000 xxx 10000 x xxx"); + no_ea(inst); + } + + { // scc + inst_t *inst = new_inst("scc", "all", 1); + add_range(inst, "0101 xxxx 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // sub + inst_t *inst = new_inst("sub", "all", 3); + { // to-register (EA mode == addr register) + set_range_group(inst, 0); + add_range(inst, "1001 xxx 001 MMMMMM"); + add_range(inst, "1001 xxx 010 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { // to-register (all other EA modes) + set_range_group(inst, 1); + add_range(inst, "1001 xxx 0xx MMMMMM"); + sub_range(inst, "1001 xxx 011 MMMMMM"); + ea_all(inst); + ea_sub_mode(inst, EA_001); + } + { // to-EA + set_range_group(inst, 2); + add_range(inst, "1001 xxx 1xx MMMMMM"); + sub_range(inst, "1001 xxx 111 MMMMMM"); + ea_memory_alterable(inst); + } + } + + { // suba + inst_t *inst = new_inst("suba", "all", 1); + add_range(inst, "1001 xxx x11 MMMMMM"); + ea_all(inst); + } + + { // subi + inst_t *inst = new_inst("subi", "all", 1); + add_range(inst, "0000 0100 xx MMMMMM"); + sub_range(inst, "0000 0100 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // subq + inst_t *inst = new_inst("subq", "all", 2); + { // ea mode == addr reg + set_range_group(inst, 0); + add_range(inst, "0101 xxx 1 01 MMMMMM"); + add_range(inst, "0101 xxx 1 10 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { + set_range_group(inst, 1); + add_range(inst, "0101 xxx 1 xx MMMMMM"); + sub_range(inst, "0101 xxx 1 11 MMMMMM"); + ea_alterable(inst); + ea_sub_mode(inst, EA_001); + } + } + + { // subx + inst_t *inst = new_inst("subx", "all", 1); + add_range(inst, "1001 xxx 1 xx 00 x xxx"); + sub_range(inst, "1001 xxx 1 11 00 x xxx"); + no_ea(inst); + } + + { // swap + inst_t *inst = new_inst("swap", "all", 1); + add_range(inst, "0100 1000 0100 0 xxx"); + no_ea(inst); + } + + { // tas + inst_t *inst = new_inst("tas", "all", 1); + add_range(inst, "0100 1010 11 MMMMMM"); + ea_data_alterable(inst); + } + + { // trap + inst_t *inst = new_inst("trap", "all", 1); + add_range(inst, "0100 1110 0100 xxxx"); + no_ea(inst); + } + + { // trapcc + inst_t *inst = new_inst("trapcc", "234", 1); + add_range(inst, "0101 xxxx 11111 010"); + add_range(inst, "0101 xxxx 11111 011"); + add_range(inst, "0101 xxxx 11111 100"); + no_ea(inst); + } + + { // trapv + inst_t *inst = new_inst("trapv", "all", 1); + add_range(inst, "0100 1110 0111 0110"); + no_ea(inst); + } + + { // tst + inst_t *inst = new_inst("tst", "all", 2); + { // addr mode + set_range_group(inst, 0); + add_range(inst, "0100 1010 01 MMMMMM"); + add_range(inst, "0100 1010 10 MMMMMM"); + ea_add_mode(inst, EA_001); + } + { // other modes + set_range_group(inst, 1); + add_range(inst, "0100 1010 xx MMMMMM"); + sub_range(inst, "0100 1010 11 MMMMMM"); + ea_all(inst); + ea_sub_mode(inst, EA_001); + } + } + + { // unlk + inst_t *inst = new_inst("unlk", "all", 1); + add_range(inst, "0100 1110 0101 1 xxx"); + no_ea(inst); + } + + { // unpk + inst_t *inst = new_inst("unpk", "234", 1); + add_range(inst, "1000 xxx 11000 x xxx"); + no_ea(inst); + } + + // --- supervisor instructions --- + + { // andi_to_sr + inst_t *inst = new_inst("andi_to_sr", "all", 1); + supervisor_only(inst); + add_range(inst, "0000 0010 0111 1100"); + no_ea(inst); + } + + { // eori_to_sr + inst_t *inst = new_inst("eori_to_sr", "all", 1); + supervisor_only(inst); + add_range(inst, "0000 1010 0111 1100"); + no_ea(inst); + } + + { // move_to_sr + inst_t *inst = new_inst("move_to_sr", "all", 1); + supervisor_only(inst); + add_range(inst, "0100 0110 11 MMMMMM"); + ea_data(inst); + } + + { // move_usp + inst_t *inst = new_inst("move_usp", "all", 1); + supervisor_only(inst); + add_range(inst, "0100 1110 0110 x xxx"); + no_ea(inst); + } + + { // movec + inst_t *inst = new_inst("movec", "1234", 1); + supervisor_only(inst); + add_range(inst, "0100 1110 0111 101x"); + no_ea(inst); + } + + { // moves + inst_t *inst = new_inst("moves", "1234", 1); + supervisor_only(inst); + add_range(inst, "0000 1110 xx MMMMMM"); + sub_range(inst, "0000 1110 11 MMMMMM"); + ea_memory_alterable(inst); + } + + { // ori_to_sr + inst_t *inst = new_inst("ori_to_sr", "all", 1); + supervisor_only(inst); + add_range(inst, "0000 0000 0111 1100"); + no_ea(inst); + } + + { // reset + inst_t *inst = new_inst("reset", "all", 1); + supervisor_only(inst); + add_range(inst, "0100 1110 0111 0000"); + no_ea(inst); + } + + { // rte + inst_t *inst = new_inst("rte", "all", 1); + supervisor_only(inst); + add_range(inst, "0100 1110 0111 0011"); + no_ea(inst); + } + + { // stop + inst_t *inst = new_inst("stop", "all", 1); + supervisor_only(inst); + add_range(inst, "0100 1110 0111 0010"); + no_ea(inst); + } + + /* --- F/A-lines --- */ + + { // a-line + inst_t *inst = new_inst("a_line", "all", 1); + add_range(inst, "1010 xxxx xxxx xxxx"); + no_ea(inst); + } + + /* --- MMU (68851) instructions --- */ + + { + inst_t *inst = new_inst("mc68851_decode", "2", 1); + add_range(inst, "1111 000 xxx xxxxxx"); + no_ea(inst); + } + + /*{ // All other 68851 instructions + inst_t *inst = new_inst("mc68851_op", "2", 1); + add_range(inst, "1111 000 000 MMMMMM"); + ea_all(inst); + } + + { // PScc + inst_t *inst = new_inst("mc68851_pscc", "2", 1); + add_range(inst, "1111 000 001 MMMMMM"); + ea_data_alterable(inst); + } + + { // PDBcc + inst_t *inst = new_inst("mc68851_pdbcc", "2", 1); + add_range(inst, "1111 000 001 001 xxx"); + no_ea(inst); + } + + { // PTRAPcc + inst_t *inst = new_inst("mc68851_ptrapcc", "2", 1); + add_range(inst, "1111 000 001 111 xxx"); + no_ea(inst); + } + + { // pbcc + inst_t *inst = new_inst("mc68851_pbcc", "2", 1); + add_range(inst, "1111 000 01x xxxxxx"); + no_ea(inst); + } + + { // psave + inst_t *inst = new_inst("mc68851_psave", "2", 1); + add_range(inst, "1111 000 100 MMMMMM"); + // Errata: 68kprm says "control" but means "control alterable" + ea_control_alterable(inst); + ea_add_mode(inst, EA_100); + } + + { // prestore + inst_t *inst = new_inst("mc68851_prestore", "2", 1); + add_range(inst, "1111 000 101 MMMMMM"); + ea_control(inst); + ea_add_mode(inst, EA_011); + }*/ + + /* --- FPU (68881) instructions --- */ + + { + inst_t *inst = new_inst("fpu_decode", "2", 1); + add_range(inst, "1111 001 xxx xxxxxx"); + no_ea(inst); + } + + /* { // all other fpu ops + inst_t *inst = new_inst("fpu_decode", "2", 1); + add_range(inst, "1111 001 000 MMMMMM"); + ea_all(inst); + } + + { // FScc + inst_t *inst = new_inst("fscc", "2", 1); + add_range(inst, "1111 001 001 MMMMMM"); + ea_data_alterable(inst); + } + + { // FBcc + inst_t *inst = new_inst("fbcc", "2", 1); + add_range(inst, "1111 001 01x xxxxxx"); + no_ea(inst); + } + + { // fsave + inst_t *inst = new_inst("fsave", "2", 1); + add_range(inst, "1111 001 100 MMMMMM"); + ea_control_alterable(inst); + ea_add_mode(inst, EA_100); + } + + { // frestore + inst_t *inst = new_inst("frestore", "2", 1); + add_range(inst, "1111 001 101 MMMMMM"); + ea_control(inst); + ea_add_mode(inst, EA_011); + }*/ + +} + + + + + + + + + diff --git a/core/dis.c b/core/dis.c new file mode 100644 index 0000000..616d80d --- /dev/null +++ b/core/dis.c @@ -0,0 +1,1478 @@ +/* + * Copyright (c) 2013, 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 +#include +#include "../core/shoebill.h" +#include "../core/mc68851.h" + +struct dis_t dis; +uint16_t dis_op; + +// +// Helper routines +// + +uint16_t dis_next_word (void) +{ + uint16_t next = dis.binary[dis.pos]; + next <<= 8; + next |= dis.binary[dis.pos+1]; + dis.pos+=2; + return next; +} + +// +// EA decoder routines +// + +void disass_ea_extended (char *buf, uint8_t mr) +{ + const uint32_t start_pc = dis.orig_pc + dis.pos; + const uint32_t ext_a = dis_next_word(); + ~decompose(ext_a, d rrr w ss F b i zz 0 III); + + // d == index register type + // r == index register + // w == word/long-word index size + // s == scale factor + // F == extension word format (0==brief, 1==full) + // b == base register suppress + // i == index suppress + // z == base displacement size + // I == index/indirect selection + + // printf("index_reg_type=%u, index_reg=%u, index_sz=%u, scale=%u, brief/ful=%u, supress_base=%u, suppress_index=%u, base_disp_sz=%u, I=%x\n", + // d, r, w, s, F, b, i, z, I); + + if (F == 0) { // If this is the brief extension word + char base_disp[32] = "0x0"; + char base_addr[32] = "0x0"; + char index[32] = ""; + + // use the sign extended least significant byte in the extension word + int8_t base_disp_addr = (int8_t)(ext_a & 0xff); + sprintf(base_disp, "%s0x%x", (base_disp_addr<0)?"-":"", abs(base_disp_addr)); + + // find the base address + if (~bmatch(mr, 00xx1xxx)) // consult the MR, use the PC? + sprintf(base_addr, "pc"); + else // otherwise, it's aX + sprintf(base_addr, "a%u", mr&7); + + // find the index value + sprintf(index, "%c%u.%c", "da"[d], r, "wl"[w]); + if (s > 0) // if there's an actual scale value + sprintf(index+strlen(index), "*%u", 1< 0) // if there's an actual scale value + sprintf(index+strlen(index), "*%u", 1< 1) { // but only if the size is > null + uint32_t base_disp_addr; + if (z == 2) // the base displacement is a sign-extended word + base_disp_addr = (int16_t)dis_next_word(); + else { // else, it's a long word + base_disp_addr = dis_next_word(); + base_disp_addr = (base_disp_addr<<16) | dis_next_word(); + } + sprintf(base_disp, "0x%x", base_disp_addr); + } + + // find the outer displacement + switch ((i<<3)|I) { // based on I/IS + case ~b(0010): case ~b(0110): case ~b(1010): { + // sign-extended word-length outer displacemnt + uint32_t addr = (int16_t)(dis_next_word()); + sprintf(outer_disp, "0x%x", addr); + break; + } + case ~b(0011): case ~b(0111): case ~b(1011): { + // long word outer displacement + uint32_t addr = dis_next_word(); + addr = (addr << 16) | dis_next_word(); + sprintf(outer_disp, "0x%x", addr); + break; + } + } + + // now generate a disassembled EA string + + // switch on the index/indirect selection + switch ((i<<3)|I) { + case ~b(1100) ... ~b(1111): case ~b(0100): { // invalid + sprintf(buf, "???"); + return ; + } + case ~b(0001): case ~b(0010): case ~b(0011): { + // indirect preindexed with * outer displacement + // ([bd,An,Xn.SIZE*SCALE],od) + if (strlen(outer_disp)) + sprintf(buf, "[%s,%s,%s],%s", base_disp, base_addr, index, outer_disp); + else + sprintf(buf, "[%s,%s,%s]", base_disp, base_addr, index); + return ; + } + case ~b(0101): case ~b(0110): case ~b(0111): { + // indirect postindexed with * outer displacement + // ([bd,An],Xn.SIZE*SCALE,od) + if (strlen(outer_disp)) + sprintf(buf, "[%s,%s],%s,%s", base_disp, base_addr, index, outer_disp); + else + sprintf(buf, "[%s,%s],%s", base_disp, base_addr, index); + return ; + } + case ~b(1001): case ~b(1010): case ~b(1011): { + // Memory indirect with * outer displacement + // ([bd,An],od) + if (strlen(outer_disp)) + sprintf(buf, "[%s,%s],%s", base_disp, base_addr, outer_disp); + else + sprintf(buf, "[%s,%s]", base_disp, base_addr); + return ; + } + case ~b(0000): { + // No memory indirect action (with index) + sprintf(buf, "%s,%s,%s", base_disp, base_addr, index); + return; + } + case ~b(1000): { + // No memory indirect action (without index) + sprintf(buf, "%s,%s", base_disp, base_addr); + return ; + } + } + } + // never get here + sprintf(buf, "NEVER GET HERE!"); + return ; +} + + + +char* decode_ea_rw (uint8_t mr, uint8_t sz) +{ + const uint8_t mode = (mr >> 3) & 7, reg = (mr & 7); + char *str = dis.ea_str_internal + dis.ea_last_pos_internal; + dis.ea_last_pos_internal = (dis.ea_last_pos_internal+256) % 1024; + switch (mode) { + case 0: { // Data register direct mode + sprintf(str, "d%u", reg); + return str; + } + case 1: { // address register direct mode + sprintf(str, "a%u", reg); + return str; + } + case 2: { // address register indirect mode + sprintf(str, "(a%u)", reg); + return str; + } + case 3: { // address register indirect with postincrement mode + sprintf(str, "(a%u)+", reg); + return str; + } + case 4: { // address register indirect with predecrement mode + sprintf(str, "-(a%u)", reg); + return str; + } + case 5: { // address register indirect with displacement mode + int16_t displacement = ((int16_t)dis_next_word()); + sprintf(str, "%s0x%x(a%u)", (displacement>=0)?"":"-", abs(displacement), reg); + return str; + } + case 6: { + str[0] = '('; + disass_ea_extended(str+1, mr); + sprintf(str + strlen(str), ")"); + return str; + } + case 7: { + switch (reg) { + case 0: { // absolute short addressing mode + const int32_t addr = (int16_t)(dis_next_word()); + sprintf(str, "(0x%08x)", addr); + return str; + } + case 1: { // absolute long addressing mode + uint32_t addr = dis_next_word(); + addr = (addr<<16) | dis_next_word(); + sprintf(str, "(0x%08x)", addr); + return str; + } + case 2: { // program counter indirect with displacement mode + const uint16_t ext = dis_next_word(); + sprintf(str, "(0x%08x)", dis.orig_pc + 2 + ((int16_t)ext)); + return str; + } + case 3: { // (program counter - evil 68020 addr modes) + str[0] = '('; + disass_ea_extended(str+1, mr); + sprintf(str + strlen(str), ")"); + return str; + } + case 4: { // immediate data + const uint16_t ext = dis_next_word(); + if (sz == 1) { + sprintf(str, "0x%02x", ext&0xff); + } else if (sz == 2) { + sprintf(str, "0x%04x", ext); + } else { + const uint16_t ext2 = dis_next_word(); + sprintf(str, "0x%04x%04x", ext, ext2); + } + return str; + } + case 5 ... 7: { + sprintf(str, "???"); + return str; + } + } + } + } + return "error: dis: Never get here!"; +} + +char* decode_ea_addr (uint8_t mr) +{ + const uint8_t mode = (mr >> 3) & 7, reg = (mr & 7); + char *str = dis.ea_str_internal + dis.ea_last_pos_internal; + dis.ea_last_pos_internal = (dis.ea_last_pos_internal+256) % 1024; + switch (mode) { + case 0 ... 1: { // Data/address register direct mode + sprintf(str, "???"); + return str; + } + case 2: { // address register indirect mode + sprintf(str, "(a%u)", reg); + return str; + } + case 3: { // address register indirect with postincrement mode + sprintf(str, "???"); + return str; + } + case 4: { // address register indirect with predecrement mode + sprintf(str, "???"); + return str; + } + case 5: { // address register indirect with displacement mode + int16_t displacement = ((int16_t)dis_next_word()); + sprintf(str, "%s0x%x(a%u)", (displacement>=0)?"":"-", abs(displacement), reg); + return str; + } + case 6: { + str[0] = '('; + disass_ea_extended(str+1, mr); + sprintf(str + strlen(str), ")"); + return str; + } + case 7: { + switch (reg) { + case 0: { // absolute short addressing mode + const int32_t addr = (int16_t)(dis_next_word()); + sprintf(str, "(0x%08x)", addr); + return str; + } + case 1: { // absolute long addressing mode + uint32_t addr = dis_next_word() << 16; + addr |= dis_next_word(); + sprintf(str, "(0x%08x)", addr); + return str; + } + case 2: { // program counter indirect with displacement mode + const uint16_t ext = dis_next_word(); + sprintf(str, "(0x%08x)", dis.orig_pc + 2 + ((int16_t)ext)); + return str; + } + case 3: { // (program counter - evil 68020 addr modes) + str[0] = '('; + disass_ea_extended(str+1, mr); + sprintf(str + strlen(str), ")"); + return str; + } + case 4: { // immediate data + sprintf(str, "???"); + return str; + } + case 5 ... 7: { + sprintf(str, "???"); + return str; + } + } + } + } + return "Error: decode_ea_addr: never get here!"; +} + +// +// Disassembler instruction implementations +// + +void dis_reset() { + sprintf(dis.str, "reset"); +} + +void dis_asx_reg () { + ~decompose(dis_op, 1110 ccc d ss i 00 rrr); + if (i) { + sprintf(dis.str, "as%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); + } else { + const uint8_t count = (c==0)?8:c; + sprintf(dis.str, "as%c.%c %u,d%u", "rl"[d], "bwl"[s], count, r); + } +} + +void dis_asx_mem () { + sprintf(dis.str, "asx_mem?"); +} + +void dis_lsx_reg () { + ~decompose(dis_op, 1110 ccc d ss i 01 rrr); + if (i) { + sprintf(dis.str, "ls%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); + } else { + const uint8_t count = (c==0)?8:c; + sprintf(dis.str, "ls%c.%c %u,d%u", "rl"[d], "bwl"[s], count, r); + } +} + +void dis_lsx_mem () { + ~decompose(dis_op, 1110 001d 11 MMMMMM); + sprintf(dis.str, "ls%c %s", "rl"[d], decode_ea_rw(M, 2)); +} + +void dis_roxx_reg () { + ~decompose(dis_op, 1110 ccc d ss i 10 rrr); + + if (i) + sprintf(dis.str, "rox%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); + else + sprintf(dis.str, "rox%c.%c %u,d%u", "rl"[d], "bwl"[s], c?c:8, r); +} + +void dis_roxx_mem () { + sprintf(dis.str, "roxx_mem?"); +} + +void dis_rox_reg () { + ~decompose(dis_op, 1110 ccc d ss i 11 rrr); + + if (i) + sprintf(dis.str, "ro%c.%c d%u,d%u", "rl"[d], "bwl"[s], c, r); + else + sprintf(dis.str, "ro%c.%c %u,d%u", "rl"[d], "bwl"[s], c?c:8, r); +} + +void dis_rox_mem () { + sprintf(dis.str, "rox_mem?"); +} + +void dis_moveq () { + ~decompose(dis_op, 0111 rrr 0 dddddddd); + const int32_t dat = ((int8_t)d); + sprintf(dis.str, "moveq.l 0x%x,d%u", dat, r); +} + +void dis_add () { + ~decompose(dis_op, 1101 rrr d ss MMMMMM); + if (d) { + sprintf(dis.str, "add.%c d%u,%s", "bwl"[s], r, decode_ea_rw(M, 1<>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfextu %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u", w&7); + else sprintf(dis.str + strlen(dis.str), "%u", (w==0)?32:w); + + sprintf(dis.str + strlen(dis.str), "},d%u", r); +} + +void dis_bfchg() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfchg %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); + else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); +} + +void dis_bfexts() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfexts %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u", w&7); + else sprintf(dis.str + strlen(dis.str), "%u", (w==0)?32:w); + + sprintf(dis.str + strlen(dis.str), "},d%u", r); +} + +void dis_bfclr() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfclr %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); + else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); +} + +void dis_bfset() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfset %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); + else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); +} + +void dis_bfffo() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfffo %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u", w&7); + else sprintf(dis.str + strlen(dis.str), "%u", (w==0)?32:w); + + sprintf(dis.str + strlen(dis.str), "},d%u", r); +} + +void dis_bftst() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 000 Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bftst %s{", ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); + else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); +} + +void dis_bfins() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 1110 1111 11 MMMMMM); + ~decompose(ext, 0 rrr Ffffff Wwwwww); + + char *ea = decode_ea_addr(M); + if ((M>>3)==0) // addr modes or data reg + sprintf(ea, "d%u", M&7); + sprintf(dis.str, "bfins d%u,%s{", r, ea); + + if (F) sprintf(dis.str + strlen(dis.str), "d%u:", f&7); + else sprintf(dis.str + strlen(dis.str), "%u:", f); + + if (W) sprintf(dis.str + strlen(dis.str), "d%u}", w&7); + else sprintf(dis.str + strlen(dis.str), "%u}", (w==0)?32:w); +} + +void dis_btst_reg() { + ~decompose(dis_op, 0000 rrr 100 MMMMMM); + // sz==4 if M==000xxx + if ((M >> 3) == 0) + sprintf(dis.str, "btst.l d%u,%s", r, decode_ea_rw(M, 4)); + else + sprintf(dis.str, "btst.b d%u,%s", r, decode_ea_rw(M, 1)); +} + +void dis_bchg_reg() { + ~decompose(dis_op, 0000 rrr 101 MMMMMM); + const uint32_t sz = (M >> 3) ? 4 : 1; + sprintf(dis.str, "bchg %du,%s", r%32, decode_ea_rw(M, sz)); +} + +void dis_bclr_reg() { + ~decompose(dis_op, 0000 rrr 110 MMMMMM); + const uint32_t sz = (M >> 3) ? 4 : 1; + sprintf(dis.str, "bclr d%u,%s", r%32, decode_ea_rw(M, sz)); +} + +void dis_bset_reg() { + ~decompose(dis_op, 0000 rrr 111 MMMMMM); + const uint32_t sz = (M >> 3) ? 4 : 1; + sprintf(dis.str, "bset %u,%s", r%32, decode_ea_rw(M, sz)); +} + +void dis_subi () { + ~decompose(dis_op, 0000 0100 ss MMMMMM); + const uint8_t sz = 1<> 1)) + sprintf(dis.str, "movea.b ???"); + else + sprintf(dis.str, "movea.%c %s,a%u", "lw"[s&1], decode_ea_rw(M, 1< relative address (?) + const char *condition_names[16] = { + "t", "ra", "hi", "ls", "cc", "cs", "ne", "eq", + "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" + }; + ~decompose(dis_op, 0101 cccc 11001 rrr); + uint32_t new_pc = dis.orig_pc+2; + new_pc += (int16_t)dis_next_word(); + sprintf(dis.str, "db%s d%u,*0x%08x", condition_names[c], r, new_pc); +} + +void dis_bcc () { + uint32_t new_pc = dis.orig_pc+2; + char size = 'b'; + ~decompose(dis_op, 0110 cccc dddddddd); + + // ra => relative address (?) + // sr => subroutine (?) + const char *condition_names[16] = { + "ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq", + "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" + }; + + // figure out the new PC + if ((d==0) || (d==0xff)) { + const uint16_t ext = dis_next_word(); + if (d==0xff) { + size = 'l'; + uint32_t mylong = ((uint32_t)ext)<<16; + mylong |= dis_next_word(); + new_pc += mylong; + } + else { + size = 'w'; + new_pc += ((int16_t)ext); + } + } + else { + uint8_t tmp = d; + new_pc += ((int8_t)d); + } + + sprintf(dis.str, "b%s.%c *0x%08x", condition_names[c], size, new_pc); +} + +void dis_bsr () { + dis_bcc(); // bsr is bcc where cc==F +} + +void dis_subx() { + ~decompose(dis_op, 1001 yyy 1 ss 00 m xxx); + if (m) + sprintf(dis.str, "subx.%c -(a%u),-(a%u)", "bwl"[s], x, y); + else + sprintf(dis.str, "subx.%c d%u,d%u", "bwl"[s], x, y); +} + +void dis_btst_immediate() { + ~decompose(dis_op, 0000 1000 11 MMMMMM); + ~decompose(dis_op, 0000 1000 11 mmmrrr); + const uint16_t ext = dis_next_word(); + ~decompose(ext, 00000000 bbbbbbbb); + + if ((M >> 3) == 0) + sprintf(dis.str, "btst.l %u,%s", b % 32, decode_ea_rw(M, 4)); + else + sprintf(dis.str, "btst.b %u,%s", b % 8, decode_ea_rw(M, 1)); +} + +void dis_move_from_ccr() { + ~decompose(dis_op, 0100 0010 11 MMMMMM); + sprintf(dis.str, "move.w ccr,%s", decode_ea_rw(M, 2)); +} + +void dis_move_to_ccr() { + ~decompose(dis_op, 0100 0100 11 MMMMMM); + sprintf(dis.str, "move.w %s,ccr", decode_ea_rw(M, 2)); +} + +void dis_neg() { + ~decompose(dis_op, 0100 0100 ss MMMMMM); + sprintf(dis.str, "neg.%c %s", "bwl"[s], decode_ea_rw(M, 1<>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = b % (is_data_reg ? 32 : 8); + + sprintf(dis.str, "bclr.%c %u,%s", (sz==1)?'b':'l', shift, decode_ea_rw(M, sz)); +} + +void dis_bchg_immediate() { + ~decompose(dis_op, 0000 1000 10 MMMMMM); + const uint16_t ext = dis_next_word(); + ~decompose(ext, 00000000 bbbbbbbb); + + const uint8_t is_data_reg = (M>>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = b % (is_data_reg ? 32 : 8); + + sprintf(dis.str, "bchg.%c %u,%s", (sz==1)?'b':'l', shift, decode_ea_rw(M, sz)); +} + +void dis_bset_immediate() { + ~decompose(dis_op, 0000 1000 11 MMMMMM); + const uint16_t ext = dis_next_word(); + ~decompose(ext, 00000000 bbbbbbbb); + + const uint8_t is_data_reg = (M>>3)==0; + const uint8_t sz = is_data_reg ? 4 : 1; + const uint8_t shift = b % (is_data_reg ? 32 : 8); + + sprintf(dis.str, "bset.%c %u,%s", (sz==1)?'b':'l', shift, decode_ea_rw(M, sz)); +} + +void dis_sub() { + ~decompose(dis_op, 1001 rrr dss MMMMMM); + const uint8_t sz = 1< - Dn -> + sprintf(dis.str, "sub.%c d%u,%s", "bwl"[s], r, decode_ea_rw(M, sz)); + } else { + sprintf(dis.str, "sub.%c %s,d%u", "bwl"[s], decode_ea_rw(M, sz), r); + } +} + +void dis_suba () { + ~decompose(dis_op, 1001 rrr s 11 MMMMMM); + sprintf(dis.str, "suba.%c %s,a%u", "wl"[s], decode_ea_rw(M, 2+2*s), r); +} + +void dis_move_to_sr() { + ~decompose(dis_op, 0100 0110 11 MMMMMM); + sprintf(dis.str, "move.w %s,sr", decode_ea_rw(M, 2)); +} + +void dis_move_from_sr() { + ~decompose(dis_op, 0100 0000 11 MMMMMM); + sprintf(dis.str, "move.w sr,%s", decode_ea_rw(M, 2)); +} + +void dis_negx() { + ~decompose(dis_op, 0100 0000 ss MMMMMM); + sprintf(dis.str, "negx.%c %s", "bwl"[s], decode_ea_rw(M, 1<word, 2->long word + sprintf(dis.str, "chk.%c %s,d%u", "lw"[s], decode_ea_rw(M, sz), r); +} +void dis_jmp () { + ~decompose(dis_op, 0100 1110 11 MMMMMM); + sprintf(dis.str, "jmp %s", decode_ea_addr(M)); +} + +void dis_unknown () { + sprintf(dis.str, "???"); +} + +void dis_link_word () { + ~decompose(dis_op, 0100 1110 0101 0 rrr); + const int16_t ext = dis_next_word(); + + sprintf(dis.str, "link.w a%u,%d", r, ext); +} + +void dis_unlk () { + ~decompose(dis_op, 0100 1110 0101 1 rrr); + sprintf(dis.str, "unlk a%u", r); +} + +void dis_rts () { + sprintf(dis.str, "rts"); +} + +void dis_cinv() { + ~decompose(dis_op, 1111 0100 cc 0 ss rrr); + switch (s) { + case 1: + sprintf(dis.str, "cinvl %cc,(a%u)", "ndib"[c], r); + break ; + case 2: + sprintf(dis.str, "cinvp %cc,(a%u)", "ndib"[c], r); + break ; + case 3: + sprintf(dis.str, "cinva %cc", "ndib"[c]); + } +} + +void dis_cpush() { + ~decompose(dis_op, 1111 0100 cc 1 ss rrr); + switch (s) { + case 1: + sprintf(dis.str, "cpushl %cc,(a%u)", "ndib"[c], r); + break ; + case 2: + sprintf(dis.str, "cpushp %cc,(a%u)", "ndib"[c], r); + break ; + case 3: + sprintf(dis.str, "cpusha %cc", "ndib"[c]); + } +} + +void dis_link_long() { + ~decompose(dis_op, 0100 1000 0000 1 rrr); + uint32_t disp = dis_next_word() << 16; + disp |= dis_next_word(); + sprintf(dis.str, "link.l a%u,%d", r, (int32_t)disp); +} + +void dis_pea() { + ~decompose(dis_op, 0100 1000 01 MMMMMM); + sprintf(dis.str, "pea %s", decode_ea_addr(M)); +} + +void dis_nbcd() { + sprintf(dis.str, "nbcd???"); +} + +void dis_sbcd() { + sprintf(dis.str, "sbcd???"); +} + +void dis_pack() { + sprintf(dis.str, "pack???"); +} + +void dis_unpk() { + sprintf(dis.str, "unpk???"); +} + +void dis_divu() { + ~decompose(dis_op, 1000 rrr 011 MMMMMM); + sprintf(dis.str, "divu.w %s,d%u", decode_ea_rw(M, 2), r); +} + +void dis_divs() { + ~decompose(dis_op, 1000 rrr 111 MMMMMM); + sprintf(dis.str, "divs.w %s,d%u", decode_ea_rw(M, 2), r); +} + +void dis_bkpt() { + sprintf(dis.str, "bkpt???"); +} + +void dis_swap() { + ~decompose(dis_op, 0100 1000 0100 0 rrr); + sprintf(dis.str, "swap d%u", r); +} + +void dis_abcd() { + ~decompose(dis_op, 1100 xxx 10000 m yyy); + + if (m) + sprintf(dis.str, "abcd.b -(a%u),-(a%u)", y, x); + else + sprintf(dis.str, "abcd.b d%u,d%u", y, x); +} + +void dis_muls() { + ~decompose(dis_op, 1100 rrr 011 MMMMMM); + sprintf(dis.str, "muls.w %s,d%u", decode_ea_rw(M, 2), r); +} + +void dis_mulu() { + ~decompose(dis_op, 1100 rrr 011 MMMMMM); + sprintf(dis.str, "mulu.w %s,d%u", decode_ea_rw(M, 2), r); +} + +void dis_exg() { + ~decompose(dis_op, 1100 xxx 1 ppppp yyy); + + if (p == ~b(01000)) // data reg mode + sprintf(dis.str, "exg d%u,d%u", x, y); + else if (p == ~b(01001)) // address reg mode + sprintf(dis.str, "exg a%u,a%u", x, y); + else if (p == ~b(10001)) // data/addr reg mode + sprintf(dis.str, "exg d%u,a%u", x, y); + else + sprintf(dis.str, "exg ???\n"); +} + +void dis_stop() { + uint16_t ext = dis_next_word(); + sprintf(dis.str, "stop 0x%04x", ext); +} + +void dis_rte() { + sprintf(dis.str, "rte"); +} + +void dis_rtr() { + sprintf(dis.str, "rtr"); +} + +void dis_rtd() { + const int16_t ext = dis_next_word(); + sprintf(dis.str, "rtd %d", ext); +} + +void dis_move_usp() { + ~decompose(dis_op, 0100 1110 0110 d rrr); + if (d) + sprintf(dis.str, "move.l usp,a%u", r); + else + sprintf(dis.str, "move.l a%u,usp", r); +} + +void dis_and() { + ~decompose(dis_op, 1100 rrr dss MMMMMM); + const uint8_t sz = 1<>3) == ~b(100)) + sprintf(ea_str, "-(a%u)", M&7); + else if ((M>>3) == ~b(011)) + sprintf(ea_str, "(a%u)+", M&7); + else + ea_str = decode_ea_addr(M); + + // For predecrement-mode, the mask is backwards, for nobody's convenience + const uint8_t is_mask_backwards = (((M>>3)==4) && (D==0)); + + + char regstr[50] = ""; + int8_t a[8], d[8], ai=0, di=0; + uint32_t i, j; + + // movem traditionally has a format like "movem (a7),d2-d5/a1" + // Also, this implementation is very, very ugly, and I am very embarrassed about it. + + uint8_t newmask[16]; + for (i=0; i<16; i++) + newmask[i] = is_mask_backwards ? (1&(mask>>(15-i))) : ((mask>>i)&1); + + if (mask) { + for (i=0; i<16; i++) { + if ((i/8) && newmask[i]) // addr reg + sprintf(regstr + strlen(regstr), "a%u/", i%8); + else if (newmask[i]) // data reg + sprintf(regstr + strlen(regstr), "d%u/", i%8); + } + regstr[strlen(regstr)-1] = 0; + } + else { + sprintf(regstr, "0"); + } + + if (D) { // memory - to - register + sprintf(dis.str, "movem.%c %s,%s", "wl"[s], ea_str, regstr); + } + else { // register - to - memory + sprintf(dis.str, "movem.%c %s,%s", "wl"[s], regstr, ea_str); + } +} + +void dis_movec() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 0100 1110 0111 101x); + ~decompose(ext, t rrr cccccccccccc); + char *c_reg; + switch (c) { + case 0x002: // CACR + c_reg = "cacr"; + break; + case 0x000: // SFC + c_reg = "sfc"; + break; + case 0x001: // DFC + c_reg = "dfc"; + break; + case 0x800: // USP + c_reg = "usp"; + break; + case 0x801: // VBR + c_reg = "vbr"; + break; + case 0x802: // CAAR (not supported on 68040) + c_reg = "caar"; + break; + case 0x803: // MSP + c_reg = "msp"; + break; + case 0x804: // ISP + c_reg = "isp"; + break; + case 0x003: // TC + c_reg = "tc"; + break; + case 0x004: // ITT0 + c_reg = "itt0"; + break; + case 0x005: // ITT1 + c_reg = "itt1"; + break; + case 0x006: // DTT0 + c_reg = "dtt0"; + break; + case 0x007: // DTT1 + c_reg = "dtt1"; + break; + case 0x805: // MMUSR + c_reg = "mmusr"; + break; + case 0x806: // URP + c_reg = "urp"; + break; + case 0x807: // SRP + c_reg = "srp"; + break; + default: + c_reg = "???"; + break; + } + if (x) sprintf(dis.str, "movec.l %s%u,%s", t?"a":"d", r, c_reg); + else sprintf(dis.str, "movec.l %s,%s%u", c_reg, t?"a":"d", r); +} + +void dis_moves() { + const uint16_t ext = dis_next_word(); + ~decompose(dis_op, 0000 1110 ss MMMMMM); + ~decompose(ext, a rrr d 00000000000); + const uint8_t sz = 1< 2)) + dis_mc68851_ptrapcc(c); + else + dis_mc68851_pscc(c); + return ; + } + + // dis_op must have the form (1111 000 000 xxxxxx) now + ~decompose(ext, XXX YYY 00 0000 0000); + switch (X) { + case 1: // pflush, pload, pvalid + if (Y == ~b(000)) + dis_mc68851_pload(ext); + else if ((Y == ~b(010)) || (Y == ~b(011))) + dis_mc68851_pvalid(ext); + else + dis_mc68851_pflush(ext); + return ; + case 2: // pmove format 1 + dis_mc68851_pmove(ext); + return ; + case 3: // pmove formats 2 and 3, + dis_mc68851_pmove(ext); + return ; + case 4: // ptest + dis_mc68851_ptest(ext); + return ; + case 5: // pflushr + dis_mc68851_pflushr(ext); + return ; + default: + sprintf(dis.str, "p_unknown"); + return ; + } + assert(!"never get here"); +} + +#include "dis_decoder_guts.c" + +/* + * Disassembler entry point + */ +void disassemble_inst(uint8_t binary[32], uint32_t orig_pc, char *str, uint32_t *instlen) +{ + dis.pos = 0; + memcpy(dis.binary, binary, 32); + dis.ea_last_pos_internal = 0; // start the ea decoder's ring buffer at 0 + dis.orig_pc = orig_pc; + dis.str = str; + + dis_op = dis_next_word(); // dis_decode() can only see dis_op + + dis_instruction_to_pointer[dis_opcode_map[dis_op]](); + + if (instlen) *instlen = dis.pos; +} + diff --git a/core/exception.c b/core/exception.c new file mode 100644 index 0000000..b0b4d81 --- /dev/null +++ b/core/exception.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2013, 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 "shoebill.h" + + +#define SSW_IS_READ (1<<6) +#define SSW_DF (1<<8) + +// throw the long-format (format 0xb) buss error. Mac II ROM expects to see this format for nubus bus errors. +// FIXME: nearly all the fields here are bogus +void throw_long_bus_error(uint32_t addr, uint8_t is_write) +{ + if (shoe.suppress_exceptions) { + shoe.abort = 1; + return ; + } + // Save this value now, because lset() calls will reset it + const uint8_t fc = shoe.logical_fc; + + //printf("throw_long_bus_error(): I'm throwing a LONG bus error (at pc = 0x%08x)!\n", shoe.orig_pc); + + // set supervisor bit + set_sr_s(1); + + // inhibit tracing + set_sr_t0(0); + set_sr_t1(0); + + // compute vector offset + const uint32_t vector_num = 2; + const uint32_t vector_offset = vector_num * 4; + + // fetch vector handler address + const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4); + //printf("throw_long_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x\n", shoe.vbr, vector_addr, addr, shoe.op); + assert(!shoe.abort); // FIXME: I can't handle another exception here + + const uint16_t ssw = SSW_DF | (is_write ? 0 : SSW_IS_READ) | fc; + + // Note: We're pushing frame format 0xA + + push_a7(0, 4); // internal registers, 18 words + push_a7(0, 4); + push_a7(0, 4); + push_a7(0, 4); + push_a7(0, 4); + push_a7(0, 4); + push_a7(0, 4); + push_a7(0, 4); + push_a7(0, 4); + + push_a7(0x0000, 2); // version + internal information + + push_a7(0, 2); // internal registers, 3 words + push_a7(0, 4); + + push_a7(0, 4); // data input buffer + + push_a7(0, 4); // Internal register, 2 words + + push_a7(0, 4); // Stage B addr + + push_a7(0, 4); // Internal register, 4 words + push_a7(0, 4); // + + push_a7(0, 4); // data output buffer + push_a7(0, 4); // internal registers 3 and 2 + push_a7(addr, 4); // data cycle fault address + push_a7(0, 4); // instruction pipe stage B and C + push_a7(ssw, 2); // special status word + push_a7(0, 2); // internal register 1 + push_a7(0xB000 | vector_offset, 2); // format word + push_a7(shoe.orig_pc, 4); // PC for the current instruction + push_a7(shoe.orig_sr, 2); // original status register + + shoe.pc = vector_addr; + + assert(!shoe.abort); // FIXME: again, can't handle an exception here + + shoe.abort = 1; +} + +void throw_bus_error(uint32_t addr, uint8_t is_write) +{ + if (shoe.suppress_exceptions) { + shoe.abort = 1; + return ; + } + + // Save this value now, because lset() calls will reset it + const uint8_t fc = shoe.logical_fc; + + //dbg_state.running = 0; + + //printf("throw_bus_error(): I'm throwing a bus error (at pc = 0x%08x)!\n", shoe.orig_pc); + + // set supervisor bit + set_sr_s(1); + + // inhibit tracing + set_sr_t0(0); + set_sr_t1(0); + + // compute vector offset + const uint32_t vector_num = 2; + const uint32_t vector_offset = vector_num * 4; + + // fetch vector handler address + const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4); + //printf("throw_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x, a7=0x%08x", shoe.vbr, vector_addr, addr, shoe.op, shoe.a[7]); + assert(!shoe.abort); // FIXME: I can't handle another exception here + + const uint16_t ssw = + SSW_DF | // the cpu will rerun the memory access + (is_write ? 0 : SSW_IS_READ) | // read or write + fc; // a/ux 3.0.1 cares about this - the address space + + //printf(" fc=%u\n", shoe.logical_fc); + + // Note: We're pushing frame format 0xA + push_a7(0, 4); // internal registers 5 and 4 + push_a7(0, 4); // data output buffer + push_a7(0, 4); // internal registers 3 and 2 + push_a7(addr, 4); // data cycle fault address + push_a7(0, 4); // instruction pipe stage B and C + push_a7(ssw, 2); // special status word + push_a7(0, 2); // internal register 1 + push_a7(0xA000 | vector_offset, 2); // format word + push_a7(shoe.orig_pc, 4); // PC for the current instruction + push_a7(shoe.orig_sr, 2); // original status register + + shoe.pc = vector_addr; + + assert(!shoe.abort); // FIXME: again, can't handle an exception here + + shoe.abort = 1; +} + + +void throw_address_error() +{ + printf("throw_address_error(): I'm throwing an address error!\n"); + assert(!"address error"); + shoe.abort = 1; +} + +static void throw_frame_zero(uint16_t sr, uint32_t pc, uint16_t vector_num) +{ + // set supervisor bit + set_sr_s(1); + + // inhibit tracing + set_sr_t0(0); + set_sr_t1(0); + + const uint32_t vector_addr = lget(shoe.vbr + vector_num*4, 4); + assert(!shoe.abort); // FIXME: I can't handle another exception here + + push_a7(vector_num*4, 2); + push_a7(pc, 4); + push_a7(sr, 2); + + shoe.pc = vector_addr; + + shoe.abort = 1; +} + +void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32_t orig_pc) +{ + set_sr_s(1); + + // inhibit tracing + set_sr_t0(0); + set_sr_t1(0); + + const uint32_t vector_addr = lget(shoe.vbr + vector_num*4, 4); + assert(!shoe.abort); // FIXME: can't handle exception here + + const uint16_t frame_word = 0x2000 | (vector_num*4); + + push_a7(orig_pc, 4); + push_a7(frame_word, 2); + push_a7(next_pc, 4); + push_a7(sr, 2); + + shoe.pc = vector_addr; + shoe.abort = 1; +} + +void throw_illegal_instruction() +{ + //printf("throw_illegal_instruction(): I'm throwing an illegal instruction exception! (shoe.pc = 0x%08x, op=0x%04x, a7=0x%08x)\n", shoe.orig_pc, shoe.op, shoe.a[7]); + + if ((shoe.op != 0xf010) && ((shoe.op >> 12) != 0xa)) + //assert(!"illegal"); + dbg_state.running = 0; + + // fetch vector number + const uint32_t vector_num = + ((shoe.op>>12) == 0xa) ? 10 : + (((shoe.op>>12) == 0xf) ? 11 : 4); + + throw_frame_zero(shoe.orig_sr, shoe.orig_pc, vector_num); + + /*if ((shoe.op >> 12) == 0xa) { + printf("Atrap: %s\n", atrap_names[shoe.op & 0xfff]?atrap_names[shoe.op & 0xfff]:"???"); + } + else + dbg_state.running = 0;*/ + shoe.abort = 1; +} + +void throw_privilege_violation() +{ + //printf("throw_privilege_violation(): I'm throwing a privilege violation exception! (shoe.orig_pc = 0x%08x op=0x%04x\n", shoe.orig_pc, shoe.op); + + throw_frame_zero(shoe.orig_sr, shoe.orig_pc, 8); + shoe.abort = 1; + +} + +void throw_divide_by_zero() +{ + printf("throw_divide_by_zero(): I'm throwing a divide-by-zero exception!\n"); + assert(0); + shoe.abort = 1; +} \ No newline at end of file diff --git a/core/floppy.c b/core/floppy.c new file mode 100644 index 0000000..d79fde0 --- /dev/null +++ b/core/floppy.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2013, 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 "shoebill.h" + +const char *latch_names[8] = { + "phase0", "phase1", "phase2", "phase3", + "motor", "drive", "L6", "L7" +}; + +const char *reg_names[8] = { + "ones", "read-data", "status", "status", + "handshake", "handshake", "mode", "write-data" +}; + +uint8_t iwm_dma_read() +{ + const uint8_t latch_addr = (shoe.physical_addr >> 10) & 0x7; + const uint8_t latch_val = (shoe.physical_addr >> 9) & 1; + uint8_t result; + + if (latch_val) + shoe.iwm.latch |= (1 << latch_addr); + else + shoe.iwm.latch &= (~(1 << latch_addr)); + + // reg = {q7, q6, motor} + const uint8_t reg = ((shoe.iwm.latch >> 5) & 6) | + ((shoe.iwm.latch >> 4) & 1); + + printf("iwm_dma_read: %s %s (reg = %u%u%u '%s' ", + latch_val ? "setting" : "clearing", + latch_names[latch_addr], + (reg>>2), (reg>>1)&1, reg&1, reg_names[reg]); + + + // Allegedly, register reads can only occur when latch_val==0 + if (latch_val) { + result = 0; + goto done; + } + + switch (reg) { + case 0: // read all ones + result = 0xff; + break; + case 1: // read data register + result = shoe.iwm.data; + break; + case 2: + case 3: // Read status register + // High 3 bits are mode register, low 5 are status + result = (shoe.iwm.status & 0b10100000); + result |= (shoe.iwm.mode & 0b11111); + break; + case 4: + case 5: // Read "write-handshake" register + result = (shoe.iwm.handshake | 0b00111111); // low 6 bits all 1's + break; + default: + result = 0; + break; + } +done: + + printf("result=0x%02x)\n", result); + + return result; +} +void iwm_dma_write() +{ + const uint8_t latch_addr = (shoe.physical_addr >> 10) & 0x7; + const uint8_t latch_val = (shoe.physical_addr >> 9) & 1; + + uint8_t data = shoe.physical_dat; + + if (latch_val) + shoe.iwm.latch |= (1 << latch_addr); + else + shoe.iwm.latch &= (~(1 << latch_addr)); + + // reg = {q7, q6, motor} + const uint8_t reg = ((shoe.iwm.latch >> 5) & 6) | + ((shoe.iwm.latch >> 4) & 1); + + printf("iwm_dma_write: %s %s (reg = %u%u%u '%s' val 0x%02x)\n", + latch_val ? "setting" : "clearing", + latch_names[latch_addr], + (reg>>2), (reg>>1)&1, reg&1, reg_names[reg], + data); + + // Allegedly, register writes can only occur when latch_val==1 + if (!latch_val) { + return ; + } + + switch (reg) { + case 6: // Write mode + shoe.iwm.mode = data & 0b01111111; + break; + case 7: // Write data + shoe.iwm.data = data; + break; + } +} \ No newline at end of file diff --git a/core/fpu.c b/core/fpu.c new file mode 100644 index 0000000..05cb7fc --- /dev/null +++ b/core/fpu.c @@ -0,0 +1,1484 @@ +/* + * Copyright (c) 2013, 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 +#include +#include "../core/shoebill.h" + +extern struct dis_t dis; +extern uint16_t dis_op; + +#define FPU_JUMP_EMU 0 +#define FPU_JUMP_DIS 1 +typedef void (fpu_func_t)(uint16_t, uint16_t); + +typedef struct { + fpu_func_t *emu, *dis; + const char *name; +} fpu_inst_t; + +~newmacro(create_fpu_jump_table, 0, { + my $names = [ + 'unknown', 'fabs', 'facos', 'fadd', 'fasin', 'fatan', 'fatanh', 'fbcc', 'fcmp', 'fcos', 'fcosh', + 'fdbcc', 'fdiv', 'fetox', 'fetoxm1', 'fgetexp', 'fgetman', 'fint', 'fintrz', 'flog10', 'flog2', + 'flogn', 'flognp1', 'fmod', 'fmove', 'fmovecr', 'fmovem', 'fmovem_control', 'fmul', 'fneg', 'fnop', + 'frem', 'frestore', 'fsave', 'fscale', 'fscc', 'fsgldiv', 'fsglmul', 'fsin', 'fsincos', 'fsinh', + 'fsqrt', 'fsub', 'ftan', 'ftanh', 'ftentox', 'ftrapcc', 'ftst', 'ftwotox' + ]; + my $fpu_enum = "typedef enum {\n"; + foreach my $n (@$names) { + $fpu_enum .= "\tfpu_inst_$n,\n"; + } + $fpu_enum .= "\nfpu_inst_max} fpu_inst_name_t;"; + + my $fpu_table = "fpu_inst_t fpu_inst_table[fpu_inst_max] = {\n"; + foreach my $n (@$names) { + $fpu_table .= "\t{NULL, NULL, \"" . $n . "\"},\n"; + } + $fpu_table = substr($fpu_table, 0, -2); + $fpu_table .= "\n};"; + + my $out = "$fpu_enum \n $fpu_table \n"; + return $out; +}) + +~create_fpu_jump_table() + +static fpu_inst_name_t fpu_decode_op(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 ttt MMMMMM); + + if (t) { + switch (t) { + case 1: + if ((M>>3) == 1) + return fpu_inst_fdbcc; + else if ((M>>3) == 7) + return fpu_inst_ftrapcc; + return fpu_inst_fscc; + case 2: + if (M==0 && ext == 0) + return fpu_inst_fnop; // same as fbf.w + // fall through + case 3: + return fpu_inst_fbcc; + case 4: + return fpu_inst_fsave; + case 5: + return fpu_inst_frestore; + } + return fpu_inst_unknown; + } + + ~decompose(ext, ccc xxx yyy eeeeeee) + + switch (c) { + case 0: // Reg to reg + break; + case 1: // unused + return fpu_inst_unknown; + case 2: // Memory->reg & movec + break; + + case 3: // reg->mem + return fpu_inst_fmove; + + case 4: // mem -> sys ctl registers + case 5: // sys ctl registers -> mem + return fpu_inst_fmovem_control; + + case 6: // movem to fp registers + case 7: // movem to memory + return fpu_inst_fmovem; + } + + // Here c == 0b000 or 010 + + if (M == 0 && ~bmatch(ext, 010 111 xxx xxxxxxx)) + return fpu_inst_fmovecr; + + if ((e>>3) == ~b(0110)) + return fpu_inst_fsincos; + + switch (e) { + + case ~b(0000000): + case ~b(1000000): + case ~b(1000100): + return fpu_inst_fmove; + + case ~b(0000001): return fpu_inst_fint; + case ~b(0000010): return fpu_inst_fsinh; + case ~b(0000011): return fpu_inst_fintrz; + case ~b(0000110): return fpu_inst_flognp1; + case ~b(0001000): return fpu_inst_fetoxm1; + case ~b(0001001): return fpu_inst_ftanh; + case ~b(0001010): return fpu_inst_fatan; + case ~b(0001100): return fpu_inst_fasin; + case ~b(0001101): return fpu_inst_fatanh; + case ~b(0001110): return fpu_inst_fsin; + case ~b(0001111): return fpu_inst_ftan; + case ~b(0010000): return fpu_inst_fetox; + case ~b(0010001): return fpu_inst_ftwotox; + case ~b(0010010): return fpu_inst_ftentox; + case ~b(0010100): return fpu_inst_flogn; + case ~b(0010101): return fpu_inst_flog10; + case ~b(0010110): return fpu_inst_flog2; + case ~b(0011001): return fpu_inst_fcosh; + case ~b(0011100): return fpu_inst_facos; + case ~b(0011101): return fpu_inst_fcos; + case ~b(0011110): return fpu_inst_fgetexp; + case ~b(0011111): return fpu_inst_fgetman; + case ~b(0100001): return fpu_inst_fmod; + case ~b(0100100): return fpu_inst_fsgldiv; + case ~b(0100101): return fpu_inst_frem; + case ~b(0100110): return fpu_inst_fscale; + case ~b(0111000): return fpu_inst_fcmp; + case ~b(0111010): return fpu_inst_ftst; + + case ~b(0011000): + case ~b(1011000): + case ~b(1011100): + return fpu_inst_fabs; + + case ~b(0100010): + case ~b(1100010): + case ~b(1100110): + return fpu_inst_fadd; + + case ~b(0100000): + case ~b(1100000): + case ~b(1100100): + return fpu_inst_fdiv; + + + case ~b(0100011): + case ~b(1100011): + case ~b(1100111): + return fpu_inst_fmul; + + case ~b(0011010): + case ~b(1011010): + case ~b(1011110): + return fpu_inst_fneg; + + case ~b(0000100): + case ~b(1000001): + case ~b(1000101): + return fpu_inst_fsqrt; + + case ~b(0101000): + case ~b(1101000): + case ~b(1101100): + return fpu_inst_fsub; + } + + return fpu_inst_unknown; + +} + +#define nextword() ({const uint16_t w=lget(shoe.pc,2); if (shoe.abort) {return;}; shoe.pc+=2; w;}) +#define verify_supervisor() {if (!sr_s()) {throw_privilege_violation(); return;}} + +void dis_fpu_decode () +{ + ~decompose(dis_op, 1111 001 xxx 000000); + + fpu_inst_name_t name; + uint16_t ext = 0; + + if (x == 4) + name = fpu_inst_fsave; + else if (x == 5) + name = fpu_inst_frestore; + else { + ext = dis_next_word(); + name = fpu_decode_op(dis_op, ext); + } + + if (fpu_inst_table[name].dis) { + (*fpu_inst_table[name].dis)(dis_op, ext); + return ; + } + + sprintf(dis.str, "%s ???", fpu_inst_table[name].name); +} + +void inst_fpu_decode () +{ + ~decompose(shoe.op, 1111 001 xxx 000000); + + fpu_inst_name_t name; + uint16_t ext = 0; + + if (x == 4) + name = fpu_inst_fsave; + else if (x == 5) + name = fpu_inst_frestore; + else { + ext = nextword(); + name = fpu_decode_op(shoe.op, ext); + // "For FPCP instructions that generate FPU exceptions, + // FPIAR is loaded with the address of an instruction before it's executed, + // unless all arithmetic exceptions are disabled." + // My take: set fpiar for all instructions except fsave, frestore, and fmovem_control + if (name != fpu_inst_fmovem_control) + shoe.fpiar = shoe.orig_pc; + } + + if (fpu_inst_table[name].emu) { + (*fpu_inst_table[name].emu)(shoe.op, ext); + return ; + } + + printf("inst_fpu_decode: unhandled instruction: %s op=0x%04x ext = 0x%04x pc=0x%08x\n", fpu_inst_table[name].name, shoe.op, ext, shoe.orig_pc); + dbg_state.running = 0; + +} + + +void dis_fsave(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 100 MMMMMM); + ~decompose(op, 1111 001 100 mmmrrr); + + if (m == 4) + sprintf(dis.str, "fsave -(a%u)", r); + else + sprintf(dis.str, "fsave %s", decode_ea_addr(M)); +} + +void inst_fsave(uint16_t op, uint16_t ext) +{ + verify_supervisor(); + + ~decompose(op, 1111 001 100 MMMMMM); + ~decompose(op, 1111 001 100 mmmrrr); + + const uint32_t size = 0x1c; // IDLE frame + const uint16_t frame_header = 0xfd18; + uint32_t addr; + + if (m == 4) + addr = shoe.a[r] - size; + else { + call_ea_addr(M); + addr = shoe.dat; + } + + lset(addr, 2, frame_header); + if (shoe.abort) + return ; + + if (m == 4) + shoe.a[r] = addr; +} + +void dis_frestore(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 101 MMMMMM); + ~decompose(op, 1111 001 101 mmmrrr); + + if (m == 3) + sprintf(dis.str, "frestore (a%u)+", r); + else + sprintf(dis.str, "frestore %s", decode_ea_addr(M)); +} + +void inst_frestore(uint16_t op, uint16_t ext) +{ + verify_supervisor(); + + ~decompose(op, 1111 001 101 MMMMMM); + ~decompose(op, 1111 001 101 mmmrrr); + + uint32_t addr, size; + + if (m == 3) + addr = shoe.a[r]; + else { + call_ea_addr(M); + addr = shoe.dat; + } + + const uint16_t word = lget(addr, 2); + if (shoe.abort) return ; + + // XXX: These frame sizes are different on 68881/68882/68040 + if ((word & 0xff00) == 0x0000) + size = 4; // NULL state frame + else if ((word & 0xff) == 0x0018) + size = 0x1c; // IDLE state frame + else if ((word & 0xff) == 0x00b4) + size = 0xb8; // BUSY state frame + else { + printf("Frestore encountered an unknown state frame 0x%04x\n", word); + assert("inst_frestore: bad state frame"); + return ; + } + + if (m==3) { + shoe.a[r] += size; + printf("frestore: changing shoe.a[%u] += %u\n", r, size); + } +} + +typedef struct { + uint8_t inexact; + uint8_t dat[4][12]; +} fmovecr_t; + +fmovecr_t fmovecr_pi = {1, 0x40, 0x00, 0x00, 0x00, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x35, 0x40, 0x00, 0x00, 0x00, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0x40, 0x00, 0x00, 0x00, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0x40, 0x00, 0x00, 0x00, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x35, }; +fmovecr_t fmovecr_log10_2 = {1, 0x3f, 0xfd, 0x00, 0x00, 0x9a, 0x20, 0x9a, 0x84, 0xfb, 0xcf, 0xf7, 0x98, 0x3f, 0xfd, 0x00, 0x00, 0x9a, 0x20, 0x9a, 0x84, 0xfb, 0xcf, 0xf7, 0x98, 0x3f, 0xfd, 0x00, 0x00, 0x9a, 0x20, 0x9a, 0x84, 0xfb, 0xcf, 0xf7, 0x98, 0x3f, 0xfd, 0x00, 0x00, 0x9a, 0x20, 0x9a, 0x84, 0xfb, 0xcf, 0xf7, 0x99, }; +fmovecr_t fmovecr_e = {1, 0x40, 0x00, 0x00, 0x00, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a, 0x40, 0x00, 0x00, 0x00, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a, 0x40, 0x00, 0x00, 0x00, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a, 0x40, 0x00, 0x00, 0x00, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9b, }; +fmovecr_t fmovecr_log2_e = {1, 0x3f, 0xff, 0x00, 0x00, 0xb8, 0xaa, 0x3b, 0x29, 0x5c, 0x17, 0xf0, 0xbc, 0x3f, 0xff, 0x00, 0x00, 0xb8, 0xaa, 0x3b, 0x29, 0x5c, 0x17, 0xf0, 0xbb, 0x3f, 0xff, 0x00, 0x00, 0xb8, 0xaa, 0x3b, 0x29, 0x5c, 0x17, 0xf0, 0xbb, 0x3f, 0xff, 0x00, 0x00, 0xb8, 0xaa, 0x3b, 0x29, 0x5c, 0x17, 0xf0, 0xbc, }; +fmovecr_t fmovecr_log10_e = {0, 0x3f, 0xfd, 0x00, 0x00, 0xde, 0x5b, 0xd8, 0xa9, 0x37, 0x28, 0x71, 0x95, 0x3f, 0xfd, 0x00, 0x00, 0xde, 0x5b, 0xd8, 0xa9, 0x37, 0x28, 0x71, 0x95, 0x3f, 0xfd, 0x00, 0x00, 0xde, 0x5b, 0xd8, 0xa9, 0x37, 0x28, 0x71, 0x95, 0x3f, 0xfd, 0x00, 0x00, 0xde, 0x5b, 0xd8, 0xa9, 0x37, 0x28, 0x71, 0x95, }; +fmovecr_t fmovecr_zero = {0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_ln_2 = {1, 0x3f, 0xfe, 0x00, 0x00, 0xb1, 0x72, 0x17, 0xf7, 0xd1, 0xcf, 0x79, 0xac, 0x3f, 0xfe, 0x00, 0x00, 0xb1, 0x72, 0x17, 0xf7, 0xd1, 0xcf, 0x79, 0xab, 0x3f, 0xfe, 0x00, 0x00, 0xb1, 0x72, 0x17, 0xf7, 0xd1, 0xcf, 0x79, 0xab, 0x3f, 0xfe, 0x00, 0x00, 0xb1, 0x72, 0x17, 0xf7, 0xd1, 0xcf, 0x79, 0xac, }; +fmovecr_t fmovecr_ln_10 = {1, 0x40, 0x00, 0x00, 0x00, 0x93, 0x5d, 0x8d, 0xdd, 0xaa, 0xa8, 0xac, 0x17, 0x40, 0x00, 0x00, 0x00, 0x93, 0x5d, 0x8d, 0xdd, 0xaa, 0xa8, 0xac, 0x16, 0x40, 0x00, 0x00, 0x00, 0x93, 0x5d, 0x8d, 0xdd, 0xaa, 0xa8, 0xac, 0x16, 0x40, 0x00, 0x00, 0x00, 0x93, 0x5d, 0x8d, 0xdd, 0xaa, 0xa8, 0xac, 0x17, }; +fmovecr_t fmovecr_10_0 = {0, 0x3f, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_10_1 = {0, 0x40, 0x02, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_10_2 = {0, 0x40, 0x05, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_10_4 = {0, 0x40, 0x0c, 0x00, 0x00, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0c, 0x00, 0x00, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0c, 0x00, 0x00, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0c, 0x00, 0x00, 0x9c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_10_8 = {0, 0x40, 0x19, 0x00, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_10_16 = {0, 0x40, 0x34, 0x00, 0x00, 0x8e, 0x1b, 0xc9, 0xbf, 0x04, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x8e, 0x1b, 0xc9, 0xbf, 0x04, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x8e, 0x1b, 0xc9, 0xbf, 0x04, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x8e, 0x1b, 0xc9, 0xbf, 0x04, 0x00, 0x00, 0x00, }; +fmovecr_t fmovecr_10_32 = {1, 0x40, 0x69, 0x00, 0x00, 0x9d, 0xc5, 0xad, 0xa8, 0x2b, 0x70, 0xb5, 0x9e, 0x40, 0x69, 0x00, 0x00, 0x9d, 0xc5, 0xad, 0xa8, 0x2b, 0x70, 0xb5, 0x9d, 0x40, 0x69, 0x00, 0x00, 0x9d, 0xc5, 0xad, 0xa8, 0x2b, 0x70, 0xb5, 0x9d, 0x40, 0x69, 0x00, 0x00, 0x9d, 0xc5, 0xad, 0xa8, 0x2b, 0x70, 0xb5, 0x9e, }; +fmovecr_t fmovecr_10_64 = {1, 0x40, 0xd3, 0x00, 0x00, 0xc2, 0x78, 0x1f, 0x49, 0xff, 0xcf, 0xa6, 0xd5, 0x40, 0xd3, 0x00, 0x00, 0xc2, 0x78, 0x1f, 0x49, 0xff, 0xcf, 0xa6, 0xd5, 0x40, 0xd3, 0x00, 0x00, 0xc2, 0x78, 0x1f, 0x49, 0xff, 0xcf, 0xa6, 0xd5, 0x40, 0xd3, 0x00, 0x00, 0xc2, 0x78, 0x1f, 0x49, 0xff, 0xcf, 0xa6, 0xd6, }; +fmovecr_t fmovecr_10_128 = {1, 0x41, 0xa8, 0x00, 0x00, 0x93, 0xba, 0x47, 0xc9, 0x80, 0xe9, 0x8c, 0xe0, 0x41, 0xa8, 0x00, 0x00, 0x93, 0xba, 0x47, 0xc9, 0x80, 0xe9, 0x8c, 0xdf, 0x41, 0xa8, 0x00, 0x00, 0x93, 0xba, 0x47, 0xc9, 0x80, 0xe9, 0x8c, 0xdf, 0x41, 0xa8, 0x00, 0x00, 0x93, 0xba, 0x47, 0xc9, 0x80, 0xe9, 0x8c, 0xe0, }; +fmovecr_t fmovecr_10_256 = {1, 0x43, 0x51, 0x00, 0x00, 0xaa, 0x7e, 0xeb, 0xfb, 0x9d, 0xf9, 0xde, 0x8e, 0x43, 0x51, 0x00, 0x00, 0xaa, 0x7e, 0xeb, 0xfb, 0x9d, 0xf9, 0xde, 0x8d, 0x43, 0x51, 0x00, 0x00, 0xaa, 0x7e, 0xeb, 0xfb, 0x9d, 0xf9, 0xde, 0x8d, 0x43, 0x51, 0x00, 0x00, 0xaa, 0x7e, 0xeb, 0xfb, 0x9d, 0xf9, 0xde, 0x8e, }; +fmovecr_t fmovecr_10_512 = {1, 0x46, 0xa3, 0x00, 0x00, 0xe3, 0x19, 0xa0, 0xae, 0xa6, 0x0e, 0x91, 0xc7, 0x46, 0xa3, 0x00, 0x00, 0xe3, 0x19, 0xa0, 0xae, 0xa6, 0x0e, 0x91, 0xc6, 0x46, 0xa3, 0x00, 0x00, 0xe3, 0x19, 0xa0, 0xae, 0xa6, 0x0e, 0x91, 0xc6, 0x46, 0xa3, 0x00, 0x00, 0xe3, 0x19, 0xa0, 0xae, 0xa6, 0x0e, 0x91, 0xc7, }; +fmovecr_t fmovecr_10_1024 = {1, 0x4d, 0x48, 0x00, 0x00, 0xc9, 0x76, 0x75, 0x86, 0x81, 0x75, 0x0c, 0x17, 0x4d, 0x48, 0x00, 0x00, 0xc9, 0x76, 0x75, 0x86, 0x81, 0x75, 0x0c, 0x17, 0x4d, 0x48, 0x00, 0x00, 0xc9, 0x76, 0x75, 0x86, 0x81, 0x75, 0x0c, 0x17, 0x4d, 0x48, 0x00, 0x00, 0xc9, 0x76, 0x75, 0x86, 0x81, 0x75, 0x0c, 0x18, }; +fmovecr_t fmovecr_10_2048 = {1, 0x5a, 0x92, 0x00, 0x00, 0x9e, 0x8b, 0x3b, 0x5d, 0xc5, 0x3d, 0x5d, 0xe5, 0x5a, 0x92, 0x00, 0x00, 0x9e, 0x8b, 0x3b, 0x5d, 0xc5, 0x3d, 0x5d, 0xe5, 0x5a, 0x92, 0x00, 0x00, 0x9e, 0x8b, 0x3b, 0x5d, 0xc5, 0x3d, 0x5d, 0xe5, 0x5a, 0x92, 0x00, 0x00, 0x9e, 0x8b, 0x3b, 0x5d, 0xc5, 0x3d, 0x5d, 0xe6, }; +fmovecr_t fmovecr_10_4096 = {1, 0x75, 0x25, 0x00, 0x00, 0xc4, 0x60, 0x52, 0x02, 0x8a, 0x20, 0x97, 0x9b, 0x75, 0x25, 0x00, 0x00, 0xc4, 0x60, 0x52, 0x02, 0x8a, 0x20, 0x97, 0x9a, 0x75, 0x25, 0x00, 0x00, 0xc4, 0x60, 0x52, 0x02, 0x8a, 0x20, 0x97, 0x9a, 0x75, 0x25, 0x00, 0x00, 0xc4, 0x60, 0x52, 0x02, 0x8a, 0x20, 0x97, 0x9b, }; + +const int _fpu_round_map[4] = {FE_TONEAREST, FE_TOWARDZERO, FE_DOWNWARD, FE_UPWARD}; +#define fpu_set_round() assert(0 == fesetround(_fpu_round_map[shoe.fpcr.b.mc_rnd])) +#define fpu_reset_round() assert(0 == fesetround(FE_TONEAREST)) + +static void fpu_set_cc(long double f) +{ + // Set condition codes + shoe.fpsr.raw &= 0x00ffffff; + shoe.fpsr.b.cc_nan = (0 != isnan(f)); + if (!shoe.fpsr.b.cc_nan) { + shoe.fpsr.b.cc_n = (0 != signbit(f)); + if (isinf(f)) + shoe.fpsr.b.cc_i = 1; + else + shoe.fpsr.b.cc_z = (f == 0.0); + } +} + +static long double fpu_set_reg(long double f, uint8_t r) +{ + // Round the number according to the mode control byte + { + fpu_set_round(); + + if (shoe.fpcr.b.mc_prec == 1) { + const float tmp = (float)f; + f = tmp; + } else if (shoe.fpcr.b.mc_prec == 2) { + const double tmp = (double)f; + f = tmp; + } + + fpu_reset_round(); + } + + // Store it + shoe.fp[r] = f; + return f; +} + +// fpu_set_reg_cc() and fpu_set_ea() set the condition codes. (what else should they set?) +static void fpu_set_reg_cc(long double f, uint8_t r) +{ + fpu_set_cc(fpu_set_reg(f, r)); +} + +static long double fpu_bytes_to_long_double(uint8_t bytes[12]) +{ + volatile long double f; + uint8_t *ptr = (uint8_t*)&f; + + ptr[9] = bytes[0]; + ptr[8] = bytes[1]; + + ptr[7] = bytes[4]; + ptr[6] = bytes[5]; + ptr[5] = bytes[6]; + ptr[4] = bytes[7]; + ptr[3] = bytes[8]; + ptr[2] = bytes[9]; + ptr[1] = bytes[10]; + ptr[0] = bytes[11]; + + return f; +} + +void inst_fmovecr(uint16_t op, uint16_t ext) +{ + ~decompose(ext, 010111 rrr xxxxxxx); + + fmovecr_t *c = &fmovecr_zero; + + switch (x) { + case 0x00: c = &fmovecr_pi; break; + case 0x0b: c = &fmovecr_log10_2; break; + case 0x0c: c = &fmovecr_e; break; + case 0x0d: c = &fmovecr_log2_e; break; + case 0x0e: c = &fmovecr_log10_e; break; + case 0x0f: c = &fmovecr_zero; break; + case 0x30: c = &fmovecr_ln_2; break; + case 0x31: c = &fmovecr_ln_10; break; + case 0x32: c = &fmovecr_10_0; break; + case 0x33: c = &fmovecr_10_1; break; + case 0x34: c = &fmovecr_10_2; break; + case 0x35: c = &fmovecr_10_4; break; + case 0x36: c = &fmovecr_10_8; break; + case 0x37: c = &fmovecr_10_16; break; + case 0x38: c = &fmovecr_10_32; break; + case 0x39: c = &fmovecr_10_64; break; + case 0x3a: c = &fmovecr_10_128; break; + case 0x3b: c = &fmovecr_10_256; break; + case 0x3c: c = &fmovecr_10_512; break; + case 0x3d: c = &fmovecr_10_1024; break; + case 0x3e: c = &fmovecr_10_2048; break; + case 0x3f: c = &fmovecr_10_4096; break; + } + + // The constants in the 68881's ROM must be in the "intermediate" format, because they're rounded differently based on fpcr.rnd + const long double f = fpu_bytes_to_long_double(c->dat[shoe.fpcr.b.mc_rnd]); + + fpu_set_reg_cc(f, r); + + printf("inst_fmovecr: set fp%u=%.30Lg\n", r, shoe.fp[r]); + + // fpu_finalize_exceptions(); +} + +void dis_fmovecr(uint16_t op, uint16_t ext) +{ + ~decompose(ext, 010111 rrr xxxxxxx); + + sprintf(dis.str, "fmovecr.x 0x%02x,fp%u", x, r); +} + +void inst_fmovem_control(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 mmmrrr); + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(ext, 10d CSI 0000000000); + + const uint32_t count = C + S + I; + const uint32_t size = count * 4; + + if (count == 0) // I don't know if this is even a valid instruction + return ; + + if ((m == 0 || m == 1) && (count > 1)) { // data and addr reg modes are valid, but only if count==1 + throw_illegal_instruction(); + return ; + } + + uint32_t addr, buf[3]; + uint32_t i; + + if (d) { // reg to memory + i=0; + if (C) buf[i++] = shoe.fpcr.raw; + if (S) buf[i++] = shoe.fpsr.raw; + if (I) buf[i++] = shoe.fpiar; + + if (m == 0) { + shoe.d[r] = buf[0]; + return ; + } + else if (m == 1) { + shoe.a[r] = buf[0]; + return ; + } + else if (m == 3) + addr = shoe.a[r]; + else if (m == 4) + addr = shoe.a[r] - size; + else { + call_ea_addr(M); + addr = shoe.dat; + } + + for (i=0; i %u\n", round, newround); + } + } + if (S) shoe.fpsr.raw = buf[i++]; + if (I) shoe.fpiar = buf[i++]; + + // Commit immediate-EA-mode PC change + if (M == 0x3c) + shoe.pc += size; + } + + // Commit pre/post-inc/decrement + + if (m == 3) + shoe.a[r] += size; + if (m == 4) + shoe.a[r] -= size; + + + + printf("inst_fmove_control: notice: (EA = %u/%u %08x CSI = %u%u%u)\n", m, r, (uint32_t)shoe.dat, C, S, I); +} + +void dis_fmovem_control(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 mmmrrr); + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(ext, 10d CSI 0000000000); + + if (d) + sprintf(dis.str, "fmovem.l [%u%u%u],%s\n", C, S, I, decode_ea_addr(M)); // <- XXX: decode_ea_addr() is the wrong function to use + else + sprintf(dis.str, "fmovem.l %s,[%u%u%u]\n", decode_ea_addr(M), C, S, I); // <- XXX: decode_ea_addr() is the wrong function to use +} + + +static uint8_t fpu_test_cc(uint8_t cc) +{ + const uint8_t z = shoe.fpsr.b.cc_z; + const uint8_t n = shoe.fpsr.b.cc_n; + const uint8_t nan = shoe.fpsr.b.cc_nan; + + switch (cc & 0x0f) { + case 0: // false + return 0; + case 1: // equal + return z; + case 2: // greater than + return !(nan || z || n); + case 3: // greater than or equal + return z || !(nan || n); + case 4: // less than + return n && !(nan || z); + case 5: // less than or equal + return z || (n && !nan); + case 6: // greater or less than + return !(nan || z); + case 7: // ordered + return !nan; + case 8: // unordered + return nan; + case 9: // not (greater or less than) + return nan || z; + case 10: // not (less than or equal) + return nan || !(n || z); + case 11: // not (less than) + return nan || (z || !n); + case 12: // not (greater than or equal) + return nan || (n && !z); + case 13: // not (greater than) + return nan || z || n; + case 14: // not equal + return !z; + case 15: // true + return 1; + } + + assert(0); + return 0; +} + +void inst_fbcc(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 01 s 0bcccc); // b => raise BSUN if NaN + + uint32_t displacement; + if (s) { + const uint16_t ext2 = nextword(); + displacement = (ext << 16) | ext2; + } + else { + const int16_t tmp = ext; + const int32_t tmp2 = tmp; + displacement = tmp2; + } + + if (b) { + printf("inst_fbcc: fixme: Got a CC that wants to set BSUN, not implemented\n"); + //assert(0); // FIXME: implement BSUN, or uncomment this + } + + if (fpu_test_cc(c)) { + const uint32_t addr = shoe.orig_pc + 2 + displacement; + shoe.pc = addr; + } +} + +const char *fpu_cc_names[32] = { + "f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", + "un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", + "sf", "seq", "gt", "ge", "lt", "le", "gl", "gle", + "ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st" +}; + +void dis_fbcc(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 01 s 0ccccc); // only the low 5 bits of cc are significant + + uint32_t displacement; + if (s) { + const uint16_t ext2 = dis_next_word(); + displacement = (ext << 16) | ext2; + } + else { + const int16_t tmp = ext; + const int32_t tmp2 = tmp; + displacement = tmp2; + } + + const uint32_t addr = dis.orig_pc + 2 + displacement; + + sprintf(dis.str, "fb%s.%c *0x%08x", fpu_cc_names[c], "wl"[s], addr); +} + +static void x87_to_motorola(long double x87, uint8_t motorola[12]) +{ + uint8_t *x87_ptr = (uint8_t*)&x87; + motorola[0] = x87_ptr[9]; + motorola[1] = x87_ptr[8]; + motorola[2] = 0; + motorola[3] = 0; + motorola[4] = x87_ptr[7]; + motorola[5] = x87_ptr[6]; + motorola[6] = x87_ptr[5]; + motorola[7] = x87_ptr[4]; + motorola[8] = x87_ptr[3]; + motorola[9] = x87_ptr[2]; + motorola[10] = x87_ptr[1]; + motorola[11] = x87_ptr[0]; +} + +static long double motorola_to_x87(const uint8_t motorola[12]) +{ + uint8_t x87[12]; + + x87[11] = 0; + x87[10] = 0; + x87[9] = motorola[0]; + x87[8] = motorola[1]; + + x87[7] = motorola[4]; + x87[6] = motorola[5]; + x87[5] = motorola[6]; + x87[4] = motorola[7]; + x87[3] = motorola[8]; + x87[2] = motorola[9]; + x87[1] = motorola[10]; + x87[0] = motorola[11]; + return *(long double*)&x87[0]; +} + +static void reverse_order(uint8_t *buf, const uint32_t size) +{ + uint32_t i; + for (i=0; i < (size/2); i++) { + const uint8_t tmp = buf[i]; + buf[i] = buf[size-(1+i)]; + buf[size-(1+i)] = tmp; + } +} + +void inst_fmovem(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 mmmrrr); + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(ext, 11 d ps 000 LLLLLLLL); // Static register mask + ~decompose(ext, 11 0 00 000 0yyy0000); // Register for dynamic mode + + const uint8_t pre_mask = s ? shoe.d[y] : L; // pre-adjusted mask + + // Count the number of bits in the mask + uint32_t count, maskcpy = pre_mask; + for (count=0; maskcpy; maskcpy >>= 1) + count += (maskcpy & 1); + + const uint32_t size = count * 12; + + // for predecrement mode, the mask is reversed + uint8_t mask = 0; + if (m == 4) { + uint32_t i; + for (i=0; i < 8; i++) { + const uint8_t bit = (pre_mask << i) & 0x80; + mask = (mask >> 1) | bit; + } + } + else + mask = pre_mask; + + uint32_t i, addr; + + // Find the EA + if (m == 3) { + addr = shoe.a[r]; + assert(p); // assert post-increment mask + } + else if (m == 4) { + addr = shoe.a[r] - size; + assert(!p); // assert pre-decrement mask + } + else { + call_ea_addr(M); + addr = shoe.dat; + assert(p); // assert post-increment mask + } + + printf("inst_fmovem: pre=%08x mask=%08x EA=%u/%u addr=0x%08x size=%u %s\n", pre_mask, mask, m, r, addr, size, d?"to mem":"from mem"); + + if (d) { + // Write those registers + for (i=0; i<8; i++) { + if (!(mask & (0x80 >> i))) + continue; + + uint8_t buf[12]; + x87_to_motorola(shoe.fp[i], buf); + + printf("inst_fmovem: writing %Lf from fp%u", shoe.fp[i], i); + uint32_t j; + for (j=0; j<12; j++) { + printf(" %02x", buf[j]); + lset(addr, 1, buf[j]); + addr++; + if (shoe.abort) + return ; + } + printf("\n"); + } + } + else { + // Read those registers + for (i=0; i<8; i++) { + if (!(mask & (0x80 >> i))) + continue; + + uint8_t buf[12]; + uint32_t j; + for (j=0; j<12; j++) { + buf[j] = lget(addr, 1); + addr++; + if (shoe.abort) + return ; + } + shoe.fp[i] = motorola_to_x87(buf); + + printf("inst_fmovem: read %Lf to fp%u\n", shoe.fp[i], i); + } + } + + // Commit the write for pre/post-inc/decrement + if (m == 3) + shoe.a[r] += size; + else if (m == 4) + shoe.a[r] -= size; + + //printf("inst_fmovem: notice: not implemented (EA = %u/%u, mask=0x%02x)\n", m, r, mask); + +} + +void dis_fmovem(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 mmmrrr); + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(ext, 11 d ps 000 LLLLLLLL); // Static register mask + ~decompose(ext, 11 0 00 000 0yyy0000); // Register for dynamic mode + + sprintf(dis.str, "fmovem ???"); +} + +enum { + format_L = 0, + format_S = 1, + format_X = 2, + format_Ps = 3, + format_W = 4, + format_D = 5, + format_B = 6, + format_Pd = 7 +} fpu_formats; +/* + * 0 L long word integer + * 1 S single precision real + * 2 X extended precision real + * 3 P{#k} packed decimal real with static k factor + * 4 W word integer + * 5 D double precision real + * 6 B byte integer + * 7 P{Dn} packed decimal real with dynamic k factor + */ + +static void fpu_read_ea_commit(uint8_t mr, uint8_t format) +{ + const uint8_t m = mr >> 3; + const uint8_t r = mr & 7; + const uint8_t sizes[8] = {4, 4, 12, 12, 2, 8, 1, 12}; + + if (m == 3) + shoe.a[r] += sizes[format]; + else if (m == 4) + shoe.a[r] -= sizes[format]; +} + +// Note: fpu_read_ea modifies shoe.pc, fpu_read_ea_commit modies shoe.a[r] for pre/post-inc/decrement +static long double fpu_read_ea(uint8_t mr, uint8_t format) +{ + const uint8_t m = mr >> 3; + const uint8_t r = mr & 7; + const uint8_t sizes[8] = {4, 4, 12, 12, 2, 8, 1, 12}; + + long double data, result; + uint32_t addr; + + // If mode==a-reg, or mode==data reg and the size is > 4 bytes, no dice + if ((m == 1) || + ((m == 0) && (sizes[format] > 4))) { + throw_illegal_instruction(); + return 0.0; + } + + switch (m) { + case 0: { + if (format == format_S) { + float tmp = shoe.d[r]; + data = tmp; + } + else if (format == format_B) { + int8_t tmp = shoe.d[r]; + data = tmp; + } + else if (format == format_W) { + int16_t tmp = shoe.d[r]; + data = tmp; + } + else if (format == format_L) { + int32_t tmp = shoe.d[r]; + data = tmp; + } + + goto got_data; + } + + case 3: + addr = shoe.a[r]; + assert(!( r==7 && sizes[format]==1)); + goto got_address; + + case 4: + addr = shoe.a[r] - sizes[format]; + assert(!( r==7 && sizes[format]==1)); + goto got_address; + + case 7: + if (r == 4) { + addr = shoe.pc; + shoe.pc += sizes[format]; + goto got_address; + } + + // fall through to default: + + default: { + + shoe.mr=mr; + ea_addr(); + if (shoe.abort) + return 0.0; + + addr = (uint32_t)shoe.dat; + goto got_address; + } + } + +got_address: + + { + uint8_t buf[12]; + uint8_t *ptr = &buf[sizes[format]]; + uint32_t i; + + printf("inst_f fpu_read_ea: format=%u, data =", format); + for (i=0; i> 3; + const uint8_t r = mr & 7; + const uint8_t sizes[8] = {4, 4, 12, 12, 2, 8, 1, 12}; + uint8_t buf[12], *ptr = &buf[0]; + uint32_t addr, i; + + // If mode==a-reg, or mode==data reg and the size is > 4 bytes, no dice + if ((m == 1) || + ((m == 0) && (sizes[format] > 4))) { + throw_illegal_instruction(); + return ; + } + + printf("inst_f fpu_write_ea EA=%u/%u data=%Lf format=%u\n", m, r, data, format); + + // Convert to the appropriate format + + switch (format) { + case format_B: { + int8_t tmp = data; + *((int8_t*)ptr) = tmp; + goto write_to_mem; + } + case format_W: { + int16_t tmp = data; + *((int16_t*)ptr) = tmp; + printf("inst_f fpu_write_ea formatted=%u (0x%04x)\n", *((int16_t*)ptr), *((uint16_t*)ptr)); + break; + } + case format_L: { + int32_t tmp = data; + *((int32_t*)ptr) = tmp; + break; + } + case format_S: { + float tmp = data; + *((float*)ptr) = tmp; + break; + } + case format_D: { + double tmp = data; + *((double*)ptr) = tmp; + break; + } + case format_X: { + x87_to_motorola(data, ptr); + goto write_to_mem; // ptr is already big endian + } + default: { + assert(!"unsupported format (packed something)"); + } + } + +swap_order: + reverse_order(buf, sizes[format]); + + +write_to_mem: + // Lookup the EA + + switch (m) { + case 0: { + if (format == format_B) { + int8_t tmp = data; + set_d(r, tmp, 1); + } + else if (format == format_W) { + int16_t tmp = data; + set_d(r, tmp, 2); + } + else if (format == format_L) { + int32_t tmp = data; + shoe.d[r] = tmp; + } + else if (format == format_S) { + float tmp = data; + *((float*)&shoe.d[r]) = tmp; + } + + goto done; + } + case 3: // post-increment + addr = shoe.a[r]; + assert(!( r==7 && sizes[format]==1)); + break; + case 4: // pre-decrement + addr = shoe.a[r] - sizes[format]; + assert(!( r==7 && sizes[format]==1)); + break; + default: + call_ea_addr(mr); + addr = (uint32_t)shoe.dat; + break; + } + + // Copy the formatted data into the EA + printf("inst_f fpu_write_ea: addr=0x%08x\n", addr); + for (i=0; i < sizes[format]; i++) { + lset(addr + i, 1, buf[i]); + if (shoe.abort) + return ; + } + +done: // set condition codes and update pre/post-inc/decrement registers + + // Set condition codes + shoe.fpsr.raw &= 0x00ffffff; + shoe.fpsr.b.cc_nan = (0 != isnan(data)); + if (!shoe.fpsr.b.cc_nan) { + shoe.fpsr.b.cc_n = (0 != signbit(data)); + if (isinf(data)) + shoe.fpsr.b.cc_i = 1; + else + shoe.fpsr.b.cc_z = (data == 0.0); + } + + if (m == 3) + shoe.a[r] += sizes[format]; + else if (m == 4) + shoe.a[r] -= sizes[format]; +} + +void inst_fmove(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(op, 1111 001 000 mmmrrr); + ~decompose(ext, 0 E V aaa zzz KKKKKKK); + + const uint8_t format = a; + + if (K == ~b(1000100) || K == ~b(1000000)) { + assert(!"inst_fmove: This is either a K-value, or somebody called fmove and specified the secret precision bits"); + } + + // E==0 => Don't use EA (reg->reg) + // E==1 => Use EA + // V==0 => reg->reg or mem->reg + // V==1 => reg->mem + + // Load the source value into 'data' + + long double data; + + if (E && !V) { // mem -> reg + data = fpu_read_ea(M, format); + if (shoe.abort) + return ; + } + else if (!E) { // reg -> mem + data = shoe.fp[a]; + } + else { // reg -> reg + data = shoe.fp[z]; + } + + + // XXX: Check for exceptions? + + // Write the result + + if (E && V) { // reg -> mem + fpu_write_ea(M, format, data); + if (shoe.abort) + return ; + } + else if (!V) { // mem -> reg + fpu_set_reg_cc(data, z); + fpu_read_ea_commit(M, format); + } + else { // reg -> reg + fpu_set_reg_cc(data, z); + } + + const uint8_t sizes[8] = {4, 4, 12, 12, 2, 8, 1, 12}; + printf("inst_fmove src=%Lf size=%u a=%u z=%u to-mem=%u useEA=%u EA = %u/%u\n", data, sizes[format], a, z, V, E, m, r); +} + +void dis_fnop(uint16_t op, uint16_t ext) +{ + sprintf(dis.str, "fnop"); +} + +void inst_fnop(uint16_t op, uint16_t ext) +{ +} + +void dis_fmove(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(op, 1111 001 000 mmmrrr); + ~decompose(ext, 0 E V aaa bbb KKKKKKK); + + // E==0 => reg to reg + // E==1 => mem to reg / reg to mem + // V==0 => reg->reg or mem->reg + // V==1 => reg->mem + + + sprintf(dis.str, "fmove ???"); + +} + +void dis_dyadic(uint16_t op, uint16_t ext) +{ + sprintf(dis.str, "dyadic fpu???"); +} + +void dis_monadic(uint16_t op, uint16_t ext) +{ + sprintf(dis.str, "monadic fpu??"); +} + +static void fpu_set_fpsr_quotient(long double a, long double b, long double result) +{ + // Thanks for being super vague on the meaning of this register, 68881 documentation + + const long double quo = truncl((a - result) / b); + const uint8_t sign = signbit(quo); + const uint64_t quo_int = fabsl(quo); + + shoe.fpsr.b.qu_quotient = quo_int & 0x7f; + shoe.fpsr.b.qu_s = sign; +} + +void inst_fmath(uint16_t op, uint16_t ext) +{ + ~decompose(op, 1111 001 000 MMMMMM); + ~decompose(ext, 0 a 0 sss ddd eeeeeee); + + const uint8_t src_in_ea = a; + const uint8_t source_specifier = s; + const uint8_t dest_register = d; + const uint8_t extension = e; + + uint8_t do_write_back_result = 1; + + long double source, dest, result; + + if (src_in_ea) { + source = fpu_read_ea(M, source_specifier); + printf("inst_fmath: source = %u/%u = %Lf", M>>3, M&7, source); + if ((M>>3) == 3) + printf(" a[%u]=0x%08x", M&7, shoe.a[M&7]); + + if (shoe.abort) + return ; + } + else { + source = shoe.fp[source_specifier]; + printf("inst_fmath: source = fp%u = %Lf", source_specifier, source); + } + + dest = shoe.fp[dest_register]; + printf(" dest = fp%u = %Lf\n", dest_register, dest); + + switch (e) { + case ~b(0000001): assert(!"fpu_inst_fint;"); + case ~b(0000010): assert(!"fpu_inst_fsinh;"); + case ~b(0000011): // fpu_inst_fintrz + printf("inst_fintrz dest = %Lf source = %Lf\n", dest, source); + result = truncl(source); + break; + + case ~b(0000110): // flognp1 + printf("inst_flognp1 dest = %Lf source = %Lf\n", dest, source); + assert(source > -1.0); + result = log1pl(source); + break; + case ~b(0001000): assert(!"fpu_inst_fetoxm1;"); + case ~b(0001001): assert(!"fpu_inst_ftanh;"); + case ~b(0001010): assert(!"fpu_inst_fatan;"); + case ~b(0001100): assert(!"fpu_inst_fasin;"); + case ~b(0001101): assert(!"fpu_inst_fatanh;"); + case ~b(0001110): assert(!"fpu_inst_fsin;"); + case ~b(0001111): assert(!"fpu_inst_ftan;"); + case ~b(0010000): // fetox + printf("inst_fetox dest = %Lf source = %Lf\n", dest, source); + result = expl(source); + break; + case ~b(0010001): assert(!"fpu_inst_ftwotox;"); + case ~b(0010010): assert(!"fpu_inst_ftentox;"); + case ~b(0010100): assert(!"fpu_inst_flogn;"); + case ~b(0010101): assert(!"fpu_inst_flog10;"); + case ~b(0010110): assert(!"fpu_inst_flog2;"); + case ~b(0011001): assert(!"fpu_inst_fcosh;"); + case ~b(0011100): assert(!"fpu_inst_facos;"); + case ~b(0011101): assert(!"fpu_inst_fcos;"); + case ~b(0011110): assert(!"fpu_inst_fgetexp;"); + case ~b(0011111): assert(!"fpu_inst_fgetman;"); + case ~b(0100001): + // don't forget to set fpu_set_fpsr_quotient(); + assert(!"fpu_inst_fmod;"); + case ~b(0100100): assert(!"fpu_inst_fsgldiv;"); + case ~b(0100101): { // fpu_inst_frem + assert(source != 0.0); + result = remainderl(dest, source); + fpu_set_fpsr_quotient(dest, source, result); + printf("inst_frem: dest = %Lf source = %Lf quot = %u result = %Lf\n", dest, source, shoe.fpsr.b.qu_quotient, result); + break; + } + case ~b(0100110): assert(!"fpu_inst_fscale;"); + + case ~b(0111000): { // fpu_inst_fcmp + const long double diff = dest - source; + printf("inst_fcmp: dest = %Lf source = %Lf\n", dest, source); + fpu_set_cc(diff); + do_write_back_result = 0; // don't write result back to register + break; + } + case ~b(0111010): assert(!"fpu_inst_ftst;"); + + case ~b(0011000): + case ~b(1011000): + case ~b(1011100): + assert(!"fpu_inst_fabs;"); + + case ~b(1100010): + case ~b(1100110): + assert(!"can't handle"); + case ~b(0100010): { // fpu_inst_fadd + printf("inst_fadd dest = %Lf source = %Lf\n", dest, source); + result = dest + source; + break; + } + + case ~b(1100000): + case ~b(1100100): + assert(!"can't handle"); + case ~b(0100000): { // fpu_inst_fdiv + assert(source != 0.0); + printf("inst_fdiv dest = %Lf source = %Lf\n", dest, source); + + result = dest / source; + break; + } + + + case ~b(1100011): + case ~b(1100111): + assert(!"can't handle"); + case ~b(0100011): { // fpu_inst_fmul + printf("inst_fmul dest = %Lf source = %Lf\n", dest, source); + result = source * dest; + break; + } + + case ~b(0011010): + case ~b(1011010): + case ~b(1011110): + assert(!"fpu_inst_fneg;"); + + case ~b(1000001): + case ~b(1000101): + assert(!"can't handle"); + case ~b(0000100): { // fpu_inst_fsqrt + printf("inst_fsqrt dest = %Lf source = %Lf\n", dest, source); + result = sqrtl(source); + break; + } + + case ~b(1101000): + case ~b(1101100): + assert(!"can't handle"); + case ~b(0101000): { // fpu_inst_fsub + printf("inst_fsub dest = %Lf source = %Lf\n", dest, source); + result = dest - source; + break; + } + + case ~b(0110000) ... ~b(0110111): + assert(!"fpu_inst_fsincos;"); + } + + // Finalize the read, if source was in memory + if (src_in_ea) { + fpu_read_ea_commit(M, source_specifier); + } + + // Only write back the result if necessary (fcmp doesn't do this) + if (do_write_back_result) { + printf("inst_fmath: result = %Lf\n", result); + fpu_set_reg_cc(result, dest_register); + } +} + + + + +// Setup the jump table for fpu instructions +// XXX: come up with a better, unified system for decoding instructions +void fpu_setup_jump_table() +{ + uint32_t i; + + + fpu_inst_table[fpu_inst_fnop].emu = inst_fnop; + fpu_inst_table[fpu_inst_fnop].dis = dis_fnop; + + fpu_inst_table[fpu_inst_fbcc].emu = inst_fbcc; + fpu_inst_table[fpu_inst_fbcc].dis = dis_fbcc; + + fpu_inst_table[fpu_inst_fmovecr].emu = inst_fmovecr; + fpu_inst_table[fpu_inst_fmovecr].dis = dis_fmovecr; + + fpu_inst_table[fpu_inst_fmove].emu = inst_fmove; + fpu_inst_table[fpu_inst_fmove].dis = dis_fmove; + + fpu_inst_table[fpu_inst_fmovem].emu = inst_fmovem; + fpu_inst_table[fpu_inst_fmovem].dis = dis_fmovem; + + fpu_inst_table[fpu_inst_fmovem_control].emu = inst_fmovem_control; + fpu_inst_table[fpu_inst_fmovem_control].dis = dis_fmovem_control; + + fpu_inst_table[fpu_inst_frestore].emu = inst_frestore; + fpu_inst_table[fpu_inst_frestore].dis = dis_frestore; + + fpu_inst_table[fpu_inst_fsave].emu = inst_fsave; + fpu_inst_table[fpu_inst_fsave].dis = dis_fsave; + + const fpu_inst_name_t monadic[] = { + fpu_inst_fintrz, + fpu_inst_fsqrt, + fpu_inst_flognp1, + fpu_inst_fetox, + }; + + const fpu_inst_name_t dyadic[] = { + fpu_inst_fcmp, + fpu_inst_fadd, + fpu_inst_fdiv, + fpu_inst_fmul, + fpu_inst_fsub, + fpu_inst_frem, + }; + + for (i=0; i < sizeof(monadic) / sizeof(monadic[0]); i++) { + fpu_inst_table[monadic[i]].emu = inst_fmath; + fpu_inst_table[monadic[i]].dis = dis_monadic; + } + + for (i=0; i < sizeof(dyadic) / sizeof(dyadic[0]); i++) { + fpu_inst_table[dyadic[i]].emu = inst_fmath; + fpu_inst_table[dyadic[i]].dis = dis_dyadic; + } + +} + + + diff --git a/core/macii_symbols.c b/core/macii_symbols.c new file mode 100644 index 0000000..ccab6af --- /dev/null +++ b/core/macii_symbols.c @@ -0,0 +1,1520 @@ +#include "shoebill.h" + +/* Ganked from MacIIROM.map symbols file in MPW. */ + +const struct macii_rom_symbols_t macii_rom_symbols[] = { + {0x0, "MYFIRSTPROC"}, + {0x0, "BASEOFROM"}, + {0x0, "MYROM"}, + {0x22, "DISPOFF"}, + {0x26, "CRITICAL"}, + {0x50, "NUMAP"}, + {0x9A, "STARTINIT1"}, + {0x142, "BOOTRETRY"}, + {0x210, "JMPTBLINIT"}, + {0x212, "JMPTBL2"}, + {0x220, "FILLWITHONES"}, + {0x230, "COMPBOOTSTACK"}, + {0x23E, "SETUPSYSAPPZONE"}, + {0x27C, "DRAWBEEPSCREEN"}, + {0x2CA, "INITADBVARS"}, + {0x2DE, "INITHIMEMGLOBALS"}, + {0x300, "INITGLOBALVARS"}, + {0x3F4, "SWITCHGOODIES"}, + {0x460, "WDCBSWOS"}, + {0x462, "PMSPSWOS"}, + {0x464, "INITSWITCHERTABLE"}, + {0x478, "GETPRAM"}, + {0x4B6, "INITXVECTTABLES"}, + {0x532, "WHICHCPU"}, + {0x560, "SETUPTIMEK"}, + {0x634, "INITSCSIGLOBALS"}, + {0x66C, "INITSCSI"}, + {0x692, "INITIWMGLOBALS"}, + {0x6AA, "INITIWM"}, + {0x6E8, "INITVIAGLOBALS"}, + {0x6F2, "INITVIA"}, + {0x73E, "REV8CHK"}, + {0x74C, "VIATIMERENABLES"}, + {0x780, "INITSCCGLOBALS"}, + {0x796, "#0001"}, + {0x7B4, "INITSCC"}, + {0x7D6, "WRITESCC"}, + {0x7E6, "INITVIDGLOBALS"}, + {0x7E8, "RDVIDPARAM"}, + {0x8D0, "OPENSDRVR"}, + {0x928, "OPNVIDDEFLT"}, + {0x974, "INITVIDDEFLT"}, + {0x9B0, "ADDVIDDEVICE"}, + {0x9F6, "GETDEFVIDMODE"}, + {0xA4E, "INITDEFGAMMA"}, + {0xAA0, "INITDUMMYSCREEN"}, + {0xB58, "FROVIDEO"}, + {0xBA8, "INITCRSRVARS"}, + {0xBB8, "INITCRSRMGR"}, + {0xC3E, "GNEFILTER"}, + {0xD0A, "INITDISPATCHER"}, + {0xD98, "BADTRAP"}, + {0xD9E, "INITIOMGR"}, + {0xE04, "INITMEMMGR"}, + {0xE22, "INITRSRCMGR"}, + {0xE32, "INITSLOTS"}, + {0xE80, "INITTIMERMGR"}, + {0xE92, "GOOFYDOEJECT"}, + {0xE96, "MYBOOT"}, + {0xE96, "BOOTME"}, + {0x1298, "CENTERRECT"}, + {0x12CA, "MOUSEINIT"}, + {0x1310, "OPENBDRVRS"}, + {0x1370, "OPENSLOTS"}, + {0x1408, "INITFS"}, + {0x14F2, "INITEVENTS"}, + {0x151C, "FINDSTARTUPDEVICE"}, + {0x155A, "GETDEFAULTSTARTUP"}, + {0x1564, "SETDEFAULTSTARTUP"}, + {0x156E, "GETOSDEFAULT"}, + {0x1578, "SETOSDEFAULT"}, + {0x1582, "GETVIDEODEFAULT"}, + {0x158C, "SETVIDEODEFAULT"}, + {0x1596, "INTERNALWAIT"}, + {0x15BE, "EMBARKONSEARCH"}, + {0x15EA, "WAITFORINTERNAL"}, + {0x166C, "LOADSLOTDRVRS"}, + {0x16D6, "LOADDRIVERS"}, + {0x16F4, "PLANSTRATEGY"}, + {0x1700, "FINDNEXTCANDIDATE"}, + {0x1714, "NEXTDQENTRY"}, + {0x1724, "SELECTDEVICE"}, + {0x1742, "CHECKMOUSEEJECT"}, + {0x174E, "GETSTARTUPINFO"}, + {0x176E, "REACTTOFAILURE"}, + {0x178A, "#0001"}, + {0x178A, "VISUALUPDATE"}, + {0x17C6, "ENABLEXFLASH"}, + {0x17CC, "SHOWSUCCESS"}, + {0x17E0, "EJECTME"}, + {0x17EE, "ISREJECT"}, + {0x1800, "ISITFLOPORDEF"}, + {0x1816, "ISITFLOPPY"}, + {0x181E, "ISITHD20"}, + {0x1826, "ISITSCSI"}, + {0x183A, "ISITANYTHING"}, + {0x183E, "NEVERAGAIN"}, + {0x1854, "INBOOTMASK"}, + {0x1872, "SHOWDEVICEFAIL"}, + {0x187E, "#0002"}, + {0x187E, "HAPPYMAC"}, + {0x188C, "SHOWPLAINDISK"}, + {0x1894, "SHOWDISKQ"}, + {0x189C, "SHOWDISKX"}, + {0x18A4, "ERASEMYICON"}, + {0x18BE, "PLOTMYICON"}, + {0x18D4, "PLOTICNN"}, + {0x1924, "PSHICNRECT"}, + {0x1948, "#0003"}, + {0x1948, "HAPPYICON"}, + {0x1A48, "DISKICON"}, + {0x1B48, "QDISKICON"}, + {0x1C48, "XDISKICON"}, + {0x1D48, "GETTIMEOUT"}, + {0x1D52, "SETTIMEOUT"}, + {0x1D6E, "GETWAITFLAGS"}, + {0x1D78, "SETWAITFLAGS"}, + {0x1D8E, "DISABLEDYNWAIT"}, + {0x1DA0, "ENABLEDYNWAIT"}, + {0x1DB2, "DISABLEPERMWAIT"}, + {0x1DC4, "ENABLEPERMWAIT"}, + {0x1DD6, "GETRAWTIMEOUT"}, + {0x1DE8, "SETRAWTIMEOUT"}, + {0x1DF8, "#0001"}, + {0x1DF8, "CRITERR"}, + {0x1F42, "PUTSYMBOL"}, + {0x1F52, "PUTICON"}, + {0x201C, "SYSERRINIT"}, + {0x2066, "DEBUGGER"}, + {0x20A6, "DEBUGPROLOG"}, + {0x20B8, "TODEEPSHIT"}, + {0x20FA, "GENEXCPS"}, + {0x2112, "IRQEXCEPTION"}, + {0x2114, "NMIEXCP"}, + {0x2120, "SYSTEMERROR"}, + {0x2136, "SYSERR2"}, + {0x2186, "#0001"}, + {0x2186, "ALLOCFAKERGNS"}, + {0x21D4, "DSERRORHANDLER"}, + {0x2806, "MEMTEST"}, + {0x2A14, "STARTTEST1"}, + {0x2BBC, "RAMTEST"}, + {0x2CFE, "TESTMANAGER"}, + {0x2E96, "TMRESTART"}, + {0x2E96, "TMENTRY1"}, + {0x370C, "CKSUMBR"}, + {0x3A8A, "#0001"}, + {0x3A8A, "SWAPMMUMODE"}, + {0x3AA2, "MMU_INIT"}, + {0x3ADE, "COMPMMUTYPE"}, + {0x3BAA, "SREADBYTE"}, + {0x3BC6, "SREADWORD"}, + {0x3BE2, "SREADLONG"}, + {0x3C00, "SGETCSTRING"}, + {0x3CA4, "SGETBLOCK"}, + {0x3CE8, "SFINDSTRUCT"}, + {0x3CFA, "SREADSTRUCT"}, + {0x3D92, "SREADINFO"}, + {0x3DB6, "SREADPRAMREC"}, + {0x3DF8, "SPUTPRAMREC"}, + {0x3E3E, "SREADFHEADER"}, + {0x3E9A, "SNEXTSRSRC"}, + {0x3F10, "SNEXTTYPESRSRC"}, + {0x3F82, "SRSRCINFO"}, + {0x3FE4, "SDISPOSEPTR"}, + {0x3FFC, "SCKCARDSTAT"}, + {0x4020, "SREADDRVRNAME"}, + {0x408E, "SMACBOOT"}, + {0x40FC, "SFINDDEVBASE"}, + {0x4152, "STARTSDECLMGR"}, + {0x41DC, "INITSDECLMGR"}, + {0x44B4, "SPRIMARYINIT"}, + {0x4564, "SCARDCHANGED"}, + {0x4580, "SEXEC"}, + {0x45E6, "SOFFSETDATA"}, + {0x4708, "SREADPBSIZE"}, + {0x47AA, "SNEWPTR"}, + {0x4808, "SCALCSTEP"}, + {0x48D6, "INITSRSRCTABLE"}, + {0x4A78, "INITPRAMRECS"}, + {0x4B86, "SSEARCHSRT"}, + {0x4C00, "SUPDATESRT"}, + {0x4CF4, "SCALCSPOINTER"}, + {0x4D84, "SGETDRIVER"}, + {0x4E4C, "SPTRTOSLOT"}, + {0x4E9C, "SFINDSINFORECPTR"}, + {0x4EC4, "SFINDSRSRCPTR"}, + {0x4EDA, "SDELETESRTREC"}, + {0x4F28, "SBUSERRPROC"}, + {0x4F44, "SLOTMANAGER"}, + {0x4F5C, "SDMJUMPTABLE"}, + {0x4FCE, "CallPascal"}, + {0x4FCE, "CALLCALLBACKROUTINE"}, + {0x4FCE, "CALLMODIFIERROUTINE"}, + {0x4FD6, "#0001"}, + {0x4FD6, "TimerCode"}, + {0x5048, "InitTimer"}, + {0x505E, "WriteMinTimer"}, + {0x507A, "WriteTimer"}, + {0x50A6, "ReadTimer"}, + {0x50C0, "NewPtr"}, + {0x50CA, "NewSysPtr"}, + {0x50D4, "DisposPtr"}, + {0x50DC, "HLock"}, + {0x50E4, "HGetState"}, + {0x50EC, "HSetState"}, + {0x50F8, "MemError"}, + {0x5100, "StripAddress"}, + {0x5108, "RecoverHandle"}, + {0x5112, "WaitBit"}, + {0x5122, "inAppHeap"}, + {0x514C, "SndAllOff"}, + {0x5156, "initGlobals"}, + {0x5182, "insertInQueue"}, + {0x51DA, "nextFromQueue"}, + {0x5232, "ChannelModifier"}, + {0x538C, "processCommandFrom"}, + {0x53F4, "processCommand"}, + {0x541A, "processNextCommand"}, + {0x5452, "sendEmptyCommand"}, + {0x5484, "tickleModifier"}, + {0x54AA, "findModifier"}, + {0x54F6, "disposChannel"}, + {0x55AC, "checkChannel"}, + {0x55C8, "pumpResource"}, + {0x565C, "OnTimeInterrupt"}, + {0x5746, "SNDAPPDEAD"}, + {0x5782, "SNDDOCOMMAND"}, + {0x5808, "SNDDOIMMEDIATE"}, + {0x5850, "SNDADDMODIFIER"}, + {0x5984, "SNDNEWCHANNEL"}, + {0x5A5E, "SNDDISPOSECHANNEL"}, + {0x5AEE, "SNDPLAY"}, + {0x5C00, "SNDCONTROL"}, + {0x5CAC, "SINTCORE"}, + {0x5CAC, "INITSDTBL"}, + {0x5CCA, "INITSPTBL"}, + {0x5CE0, "SINTINSTALL"}, + {0x5D90, "SINTREMOVE"}, + {0x5DB2, "DTCORE"}, + {0x5DB2, "DTINSTALL"}, + {0x5DCA, "#0001"}, + {0x5DCA, "SYSTEMBEEP"}, + {0x5E4A, "BOOTBEEP"}, + {0x5E5A, "ERRORBEEP1"}, + {0x5E60, "ERRORBEEP2"}, + {0x5E66, "ERRORBEEP3"}, + {0x5E6C, "ERRORBEEP4"}, + {0x6004, "QSTUFF"}, + {0x6004, "ENQUEUE"}, + {0x602A, "DEQUEUE"}, + {0x6072, "INITQUEUE"}, + {0x607C, "INTHND"}, + {0x607C, "LVL1INT"}, + {0x60D0, "LVL2INT"}, + {0x612C, "SPURIOUS"}, + {0x612E, "EXTBINT"}, + {0x613A, "EXTAINT"}, + {0x6158, "ONESECINT"}, + {0x6180, "LVL2RTS"}, + {0x6180, "LVL1RTS"}, + {0x6182, "VBLINT"}, + {0x61E4, "SLOTVBLINT"}, + {0x622E, "VIA2INT"}, + {0x6284, "SLOTINT"}, + {0x62E6, "POWEROFF"}, + {0x6306, "VDISPTCH"}, + {0x6344, "VBLCORE"}, + {0x6344, "VINSTALL"}, + {0x6394, "VREMOVE"}, + {0x63A8, "CORESTUB"}, + {0x63AA, "INITVBLQS"}, + {0x63DE, "SLOTVINSTALL"}, + {0x6446, "SLOTVREMOVE"}, + {0x6468, "ATTACHVBL"}, + {0x6486, "DOVBLTASK"}, + {0x649E, "CHKSLOT"}, + {0x64BA, "DSPATCH"}, + {0x64BA, "ATRAP68020"}, + {0x64F2, "ATRAP68010"}, + {0x64FA, "EMT1010"}, + {0x6568, "SETTRAPADDRESS"}, + {0x65C2, "GETTRAPADDRESS"}, + {0x65F2, "VCACHEFLUSH"}, + {0x6600, "IOCORE"}, + {0x6600, "FSIODNETBL"}, + {0x6606, "FETCH"}, + {0x664A, "STASH"}, + {0x6652, "IODONE"}, + {0x673A, "VGODRIVER"}, + {0x684C, "OPEN"}, + {0x6B52, "CLOSE"}, + {0x6B74, "VWAITUNTIL"}, + {0x6BC4, "READ"}, + {0x6C36, "VSYNCWAIT"}, + {0x6C44, "WRITE"}, + {0x6C58, "CONTROL"}, + {0x6C68, "STATUS"}, + {0x6C8E, "KILLIO"}, + {0x6CE2, "DRVRINSTALL"}, + {0x6D40, "DRVRREMOVE"}, + {0x6D70, "ADDDRIVE"}, + {0x6D80, "KBDMNGR"}, + {0x6D80, "INITADB"}, + {0x7002, "FDBSHIFTINT"}, + {0x72FA, "ADBOP"}, + {0x7704, "ADBREINIT"}, + {0x7724, "INITADBDRVR"}, + {0x7778, "COUNTADBS"}, + {0x7792, "GETINDADB"}, + {0x77BE, "GETADBINFO"}, + {0x77C4, "SETADBINFO"}, + {0x789E, "KEYTRANS"}, + {0x796C, "EVENTS"}, + {0x796C, "POSTEVENT"}, + {0x79E4, "OSEVENTAVAIL"}, + {0x7A6E, "GETOSEVENT"}, + {0x7A8C, "FLUSHEVENTS"}, + {0x7AD4, "SCSIBOOTS"}, + {0x7AD4, "SCSILOAD"}, + {0x7D3C, "TURBOFS"}, + {0x7D3C, "TFSDISPATCH"}, + {0x7F56, "FINITQUEUE"}, + {0x7F70, "DSHOOK"}, + {0x810C, "DOEJECT"}, + {0x810C, "VDOEJECT"}, + {0x8140, "DIVUP"}, + {0x8154, "ROUNDALLOC"}, + {0x8196, "GETVCBRFN"}, + {0x820E, "MARKVCB"}, + {0x8210, "MARKVCBTIME"}, + {0x821E, "FLUSHMDB"}, + {0x8224, "VFLUSHMDB"}, + {0x82E6, "MAKESTKPB"}, + {0x82F8, "MOUNTVOL"}, + {0x850E, "VCHECKREMOUNT"}, + {0x8698, "VMTCHECK"}, + {0x8874, "VBMCHK"}, + {0x8956, "FINDDRIVE"}, + {0x895C, "VFINDDRIVE"}, + {0x8982, "OFFLINE"}, + {0x8A28, "EJECT"}, + {0x8AFC, "UNMOUNTVOL"}, + {0x8B44, "FLUSHVOL"}, + {0x8B86, "VCKEXTFS"}, + {0x8B96, "VDTRMV3"}, + {0x8BAA, "VDTRMV1"}, + {0x8CE2, "VDTRMV2"}, + {0x8D7A, "GETVOLINFO"}, + {0x8F22, "SETVOLINFO"}, + {0x8FDE, "GETVOL"}, + {0x9026, "SETVOL"}, + {0x9066, "SETDIR"}, + {0x909A, "GETDIR"}, + {0x90BE, "OPENWD"}, + {0x916A, "CLOSEWD"}, + {0x91A4, "GETWDINFO"}, + {0x9574, "OPENRF"}, + {0x957E, "FILEOPEN"}, + {0x9584, "VFILEOPEN"}, + {0x96CE, "VPERMSSNCHK"}, + {0x9732, "CREATEDIR"}, + {0x973E, "FILECREATE"}, + {0x9968, "FILEDELETE"}, + {0x99E8, "RENAME"}, + {0x9BA4, "TFMOVE"}, + {0x9DC4, "SETFILTYPE"}, + {0x9DFC, "SETFILLOCK"}, + {0x9E06, "RSTFILLOCK"}, + {0x9E48, "SETFILEINFO"}, + {0x9E7A, "SETCATINFO"}, + {0x9F08, "VFNDFILNAME"}, + {0xA042, "GETCATINFO"}, + {0xA054, "GETFILEINFO"}, + {0xA43E, "TFSVCBTST"}, + {0xA488, "GETFPOS"}, + {0xA48C, "SETFPOS"}, + {0xA490, "FILEREAD"}, + {0xA5A6, "FILEWRITE"}, + {0xA6C0, "FLUSHFILE"}, + {0xA6CA, "FILECLOSE"}, + {0xA6EA, "VFCLOSE"}, + {0xA8B6, "GETEOF"}, + {0xA8CE, "VRFNCALL"}, + {0xA918, "VTSTMOD"}, + {0xA92E, "GETFCBINFO"}, + {0xAA0C, "FILEALLOC"}, + {0xAA3C, "SETEOF"}, + {0xAAAC, "VADJEOF"}, + {0xAB50, "LG2PHYS"}, + {0xAB56, "VLG2PHYS"}, + {0xAD46, "VSM"}, + {0xAD46, "BLKALLOC"}, + {0xAD4C, "VBLKALLOC"}, + {0xAEA0, "BLKDEALLOC"}, + {0xAEA6, "VBLKDEALLOC"}, + {0xAEE6, "BLKCHK"}, + {0xAF40, "UPDATEFREE"}, + {0xAF74, "VREADBM"}, + {0xB014, "FXM"}, + {0xB014, "DEALLOCFILE"}, + {0xB01A, "VDEALLOCFILE"}, + {0xB0E8, "EXTENDFILE"}, + {0xB0EE, "VEXTENDFILE"}, + {0xB264, "FXMKEYCMP"}, + {0xB2A2, "MAPFBLOCK"}, + {0xB2A8, "VMAPFBLOCK"}, + {0xB324, "TRUNCATEFILE"}, + {0xB32A, "VTRUNCATEFILE"}, + {0xB498, "VXFSEARCH"}, + {0xB5D6, "CMSVCS"}, + {0xB5D6, "CMCREATECN"}, + {0xB71C, "CMDELETECN"}, + {0xB7C8, "CMGETCN"}, + {0xB7E8, "CMGETOFF"}, + {0xB84C, "CMMOVECN"}, + {0xB9F2, "CMRENAMECN"}, + {0xBAFA, "CMUPDATECN"}, + {0xBB32, "VCMSETUP"}, + {0xBB64, "CMMAINT"}, + {0xBB64, "BUILDKEY"}, + {0xBB92, "CMFLUSH"}, + {0xBBC6, "CMKEYCMP"}, + {0xBC02, "LOCCNODE"}, + {0xBC22, "LOCCREC"}, + {0xBC28, "VLOCCREC"}, + {0xBC50, "UPDCNAME"}, + {0xBC6A, "BTSVCS"}, + {0xBC6A, "BTCLOSE"}, + {0xBC70, "VBTCLOSE"}, + {0xBCAA, "BTDELETE"}, + {0xBCB0, "VBTDELETE"}, + {0xBE5C, "BTFLUSH"}, + {0xBE62, "VBTFLUSH"}, + {0xBEC0, "BTGETRECORD"}, + {0xBEC6, "VBTGETRECORD"}, + {0xBF78, "BTINSERT"}, + {0xBF7E, "VBTINSERT"}, + {0xC218, "BTOPEN"}, + {0xC21E, "VBTOPEN"}, + {0xC2D0, "BTSEARCH"}, + {0xC2D6, "VBTSEARCH"}, + {0xC35A, "BTUPDATE"}, + {0xC360, "VBTUPDATE"}, + {0xC3BC, "BTALLOC"}, + {0xC3BC, "ALLOCNODE"}, + {0xC3C2, "VALLOCNODE"}, + {0xC452, "EXTBTFILE"}, + {0xC458, "VEXTBTFILE"}, + {0xC540, "FREENODE"}, + {0xC546, "VFREENODE"}, + {0xC68C, "BTMAINT1"}, + {0xC68C, "ROTATELT"}, + {0xC77C, "SPLITLT"}, + {0xC806, "TREESEARCH"}, + {0xC80C, "VTREESEARCH"}, + {0xC8C4, "BTMAINT2"}, + {0xC8C4, "BUILDIREC"}, + {0xC8E6, "CHKNODE"}, + {0xC96A, "CLRNODE"}, + {0xC986, "DELETEREC"}, + {0xC9D6, "GETLTSIB"}, + {0xC9E0, "GETRTSIB"}, + {0xCA10, "GETMAXKEY"}, + {0xCA1C, "GETNODE"}, + {0xCA22, "VGETNODE"}, + {0xCA56, "GETNODESIZ"}, + {0xCA6E, "GETOFFSET"}, + {0xCA86, "GETRECA"}, + {0xCAA2, "INITNODE"}, + {0xCAD4, "INSERTREC"}, + {0xCB46, "LOCBTCB"}, + {0xCB50, "LOCREC"}, + {0xCB82, "LOCTPR"}, + {0xCB92, "MOVOFFLT"}, + {0xCBA2, "MOVOFFRT"}, + {0xCBB8, "MOVRECLT"}, + {0xCBCE, "MOVRECRT"}, + {0xCBE8, "RELNODE"}, + {0xCBEE, "VRELNODE"}, + {0xCC02, "SEARCHNODE"}, + {0xCC5E, "UPDDREC"}, + {0xCC80, "UPDIKEY"}, + {0xCCB2, "CACHE"}, + {0xCCDC, "FLUSHCACHE"}, + {0xCCE2, "VFLUSHCACHE"}, + {0xCDC6, "GETBLOCK"}, + {0xCDCC, "VGETBLOCK"}, + {0xCFAE, "INITCACHE"}, + {0xD008, "MARKBLOCK"}, + {0xD00E, "VMARKBLOCK"}, + {0xD016, "MARKA5BLOCK"}, + {0xD01E, "RELBLOCK"}, + {0xD024, "VRELBLOCK"}, + {0xD070, "TRASHVBLKS"}, + {0xD076, "VTRASHVBLKS"}, + {0xD09E, "TRASHFBLOCKS"}, + {0xD0A8, "TRASHBLOCKS"}, + {0xD0FC, "VTRASHBLOCKS"}, + {0xD13E, "CACHERDIP"}, + {0xD144, "VCACHERDIP"}, + {0xD16A, "CACHEWRIP"}, + {0xD170, "VCACHEWRIP"}, + {0xD1C2, "CACHEIO"}, + {0xD1C2, "READOWNBUF"}, + {0xD1C2, "READBLOCK"}, + {0xD1CC, "WRITEOWNBUF"}, + {0xD1D4, "WRITEBLOCK"}, + {0xD22E, "VBASICIO"}, + {0xD2A2, "RDBLOCKS"}, + {0xD2A8, "VRDBLOCKS"}, + {0xD2F0, "WRBLOCKS"}, + {0xD2F6, "VWRBLOCKS"}, + {0xD308, "VSETUPTAGS"}, + {0xD356, "LOADER"}, + {0xD356, "LOADSEG"}, + {0xD3EA, "UNLOADSEG"}, + {0xD434, "APPZONEADDR"}, + {0xD456, "FLUSHAPPLVBLS"}, + {0xD47E, "CHAIN"}, + {0xD484, "LAUNCH"}, + {0xD580, "VSEGSTACK"}, + {0xD5CE, "EXITTOSHELL"}, + {0xD604, "VLAUNCHINIT"}, + {0xD636, "GETAPPPARMS"}, + {0xD652, "INSTALLRDRIVERS"}, + {0xD6B4, "SGLDREND"}, + {0xD6B4, "SYSUTIL"}, + {0xD6B4, "ASYNCPATCH"}, + {0xD6B6, "READPARAM"}, + {0xD6D0, "WRITEPARAM"}, + {0xD6F0, "READDATETIME"}, + {0xD6FA, "SETDATETIME"}, + {0xD702, "DELAY"}, + {0xD714, "CMPSTRING"}, + {0xD72A, "RELSTRING"}, + {0xD79E, "UPRSTRING"}, + {0xDBB0, "READPRAM"}, + {0xDBE8, "INITUTIL"}, + {0xDD12, "WPON"}, + {0xDD1A, "WPOFF"}, + {0xDD52, "CLOCK"}, + {0xDD52, "CLKRW"}, + {0xDD78, "READXPRAM"}, + {0xDD82, "WRITEXPRAM"}, + {0xDDD6, "CLKNOMEM"}, + {0xDE68, "HEAP"}, + {0xDE68, "SETAPPLBASE"}, + {0xDE8E, "INITAPPLZONE"}, + {0xDEF8, "VIAZINIT"}, + {0xDFAE, "VIAZPOSTINIT"}, + {0xDFB8, "INITZONE"}, + {0xE052, "GETZONE"}, + {0xE058, "SETZONE"}, + {0xE05E, "MAXBLOCK"}, + {0xE06C, "COMPACTMEM"}, + {0xE09C, "PURGEMEM"}, + {0xE0B8, "PURGESPACE"}, + {0xE0C2, "FREEMEM"}, + {0xE0CC, "RESRVMEM"}, + {0xE0EA, "MAXMEM"}, + {0xE11E, "SETGROWZONE"}, + {0xE128, "SETAPPLLIMIT"}, + {0xE15C, "STACKSPACE"}, + {0xE16E, "MAXAPPLZONE"}, + {0xE1A4, "NEWPTR"}, + {0xE1C0, "DISPOSEPTR"}, + {0xE1D6, "GETPTRSIZE"}, + {0xE1E0, "SETPTRSIZE"}, + {0xE1EA, "PTRZONE"}, + {0xE208, "NEWEMPTYHANDLE"}, + {0xE21C, "NWHANDLE"}, + {0xE23E, "DSPOSEHANDLE"}, + {0xE25E, "GETHANDLESIZE"}, + {0xE26A, "SETHANDLESIZE"}, + {0xE27C, "HANDLEZONE"}, + {0xE284, "RECOVERHANDLE"}, + {0xE2C8, "EMPTYHANDLE"}, + {0xE2D8, "REALLOCHANDLE"}, + {0xE320, "HLOCK"}, + {0xE32A, "HUNLOCK"}, + {0xE334, "HPURGE"}, + {0xE33E, "HNOPURGE"}, + {0xE352, "HRSRC"}, + {0xE35C, "HNORSRC"}, + {0xE378, "HGETFLAGS"}, + {0xE386, "HSETFLAGS"}, + {0xE390, "MOREMASTERS"}, + {0xE3A8, "STRIPADDRESS"}, + {0xE3AE, "MOVEHHI"}, + {0xE590, "HEAPGUTS"}, + {0xE61A, "MMPPROLOGUE"}, + {0xE62E, "MMHPROLOGUE"}, + {0xE676, "MMPROLOGUE"}, + {0xE698, "MMRHPROLOGUE"}, + {0xE6D6, "MMEPILOGUE"}, + {0xE6E2, "MMNOERREPILOGUE"}, + {0xE6E8, "MAKEBKF"}, + {0xE6EE, "EH"}, + {0xE73C, "PURGEHEAP"}, + {0xE7CE, "TOTEPURGEABLES"}, + {0xE82E, "BKCOMPACTS"}, + {0xE8CA, "ALLOCBK"}, + {0xE97E, "COMPACTHP"}, + {0xEA14, "TOMAXLIMIT"}, + {0xEA1C, "MAXLIMIT"}, + {0xEA36, "ZONEADJUSTEND"}, + {0xEAA0, "ACTUALS"}, + {0xEAB4, "GETSIZE"}, + {0xEACC, "CLEARGZSTUFF"}, + {0xEAD6, "SETSIZE"}, + {0xEC50, "ADJUSTFREE"}, + {0xEC5C, "NEXTMASTER"}, + {0xEC78, "HMAKEMOREMASTERS"}, + {0xECA8, "RELEASEMP"}, + {0xECB2, "MAKEPTRSPC"}, + {0xEE22, "FREEBK"}, + {0xEE4E, "STDGZ"}, + {0xEEA2, "MEMMGREND"}, + {0xEEA2, "BLOCK2"}, + {0xEEA2, "BLOCKMOVE"}, + {0xF0BE, "MISCMGR"}, + {0xF0BE, "GETKEYS"}, + {0xF0DA, "BUTTON"}, + {0xF0EC, "TICKCOUNT"}, + {0xF12E, "GETMOUSE"}, + {0xF144, "STILLDOWN"}, + {0xF16C, "WAITMOUSEUP"}, + {0xF18A, "EVENTAVAIL"}, + {0xF18E, "GETNEXTEVENT"}, + {0xF3B0, "WMGR"}, + {0xF400, "NEWSTRING"}, + {0xF418, "SETSTRING"}, + {0xF474, "DELETEWINDOW"}, + {0xF48C, "CALCVIS"}, + {0xF4EA, "CALCVISBEHIND"}, + {0xF52E, "CLIPABOVE"}, + {0xF552, "PAINTONE"}, + {0xF650, "PAINTBEHIND"}, + {0xF6A8, "GETNEWRGN"}, + {0xF6B4, "SAVEOLD"}, + {0xF6E2, "DRAWNEW"}, + {0xF742, "SHOWHIDE"}, + {0xF774, "SETWPORT"}, + {0xF77E, "RESTOREPORT"}, + {0xF784, "GETWMGRPORT"}, + {0xF78E, "GETCWMGRPORT"}, + {0xF798, "CHECKUPDATE"}, + {0xF836, "INITWINDOWS"}, + {0xF9F6, "NEWCWINDOW"}, + {0xFA08, "NEWWINDOW"}, + {0xFB6E, "CLOSEWINDOW"}, + {0xFC20, "DISPOSEWINDOW"}, + {0xFC2E, "SHOWWINDOW"}, + {0xFC56, "HIDEWINDOW"}, + {0xFC80, "GETWREFCON"}, + {0xFC8E, "SETWREFCON"}, + {0xFC9E, "SETWINDOWPIC"}, + {0xFCA4, "GETWINDOWPIC"}, + {0xFCAA, "GETWTITLE"}, + {0xFCC2, "SETWTITLE"}, + {0xFD40, "DELTAPOINT"}, + {0xFD9C, "MOVEWINDOW"}, + {0xFF12, "GETWVARIANT"}, + {0xFFCE, "HILITEWINDOW"}, + {0x1000E, "SIZEWINDOW"}, + {0x10062, "ZOOMWINDOW"}, + {0x100C8, "TRACKGOAWAY"}, + {0x100D0, "TRACKBOX"}, + {0x1013E, "SELECTWINDOW"}, + {0x1016E, "BRINGTOFRONT"}, + {0x10210, "SENDBEHIND"}, + {0x10266, "BEGINUPDATE"}, + {0x102A6, "ENDUPDATE"}, + {0x102CE, "FRONTWINDOW"}, + {0x102F8, "DRAGWINDOW"}, + {0x103B2, "WMGRGRAY"}, + {0x103BA, "DRAGGRAYRGN"}, + {0x103C6, "DRAGTHERGN"}, + {0x105D4, "INVALRGN"}, + {0x1061A, "INVALRECT"}, + {0x10638, "VALIDRGN"}, + {0x1063C, "VALIDRECT"}, + {0x10640, "GROWWINDOW"}, + {0x1076A, "FINDWINDOW"}, + {0x107EE, "DRAWGROWICON"}, + {0x1080C, "SETDESKCPAT"}, + {0x10846, "SETWINCOLOR"}, + {0x1089E, "SETCTLCOLOR"}, + {0x10984, "GETAUXWIN"}, + {0x1098A, "GETAUXCTL"}, + {0x109BE, "WMGREND"}, + {0x109BE, "MMGR"}, + {0x109BE, "INITPROCMENU"}, + {0x109EE, "INITMENUS"}, + {0x10A4E, "CALCMBHEIGHT"}, + {0x10B0A, "CLEARMENUBAR"}, + {0x10B30, "INSERTMENU"}, + {0x10C2C, "DELETEMENU"}, + {0x10C8E, "DELMCENTRIES"}, + {0x10D0C, "DRAWMBAR"}, + {0x10D16, "DRAWMENUBAR"}, + {0x10D26, "HILITEMENU"}, + {0x10D6E, "ENABLEITEM"}, + {0x10D90, "DISABLEITEM"}, + {0x10DDE, "MENUSELECT"}, + {0x112C0, "FULLCLIP"}, + {0x112EE, "MENUCHOICE"}, + {0x112F6, "GETMENUBAR"}, + {0x11302, "GETMCINFO"}, + {0x11312, "SETMENUBAR"}, + {0x11326, "SETMCINFO"}, + {0x11342, "DISPOSEMENU"}, + {0x1135A, "DISPMCINFO"}, + {0x11364, "FLASHMENUBAR"}, + {0x113A6, "CALLMBARPROC"}, + {0x11474, "GETITEMICON"}, + {0x11478, "SETITEMICON"}, + {0x1147C, "GETITEMSTYLE"}, + {0x11480, "SETITEMSTYLE"}, + {0x11484, "GETITEMMARK"}, + {0x11488, "SETITEMMARK"}, + {0x1148C, "CHECKITEM"}, + {0x114AC, "SETMCENTRIES"}, + {0x11626, "GETMCENTRY"}, + {0x11654, "MENUKEY"}, + {0x11784, "GETITEM"}, + {0x117B8, "CALCMENUSIZE"}, + {0x117EE, "NEWMENU"}, + {0x11840, "APPENDMENU"}, + {0x11848, "INSMENUITEM"}, + {0x119C0, "GETMHANDLE"}, + {0x119E8, "DELMENUITEM"}, + {0x11A28, "SETITEM"}, + {0x11A6E, "SETMENUFLASH"}, + {0x11A78, "ADDRESMENU"}, + {0x11A80, "INSRTRESMENU"}, + {0x11BDE, "COUNTMITEMS"}, + {0x11BFA, "PLOTICON"}, + {0x11C36, "MMGREND"}, + {0x11C36, "CMGR"}, + {0x11C36, "NEWCONTROL"}, + {0x11D5A, "GETCVARIANT"}, + {0x11DBE, "DISPOSECONTROL"}, + {0x11DFC, "KILLCONTROLS"}, + {0x11E0E, "DRAWONECONTROL"}, + {0x11E1E, "SHOWCONTROL"}, + {0x11E3C, "HIDECONTROL"}, + {0x11E50, "MOVECONTROL"}, + {0x11E8E, "GETCREFCON"}, + {0x11E9C, "SETCREFCON"}, + {0x11EAC, "GETCTLACTION"}, + {0x11EB0, "SETCTLACTION"}, + {0x11EB4, "SIZECONTROL"}, + {0x11EDC, "HILITECONTROL"}, + {0x11F08, "GETCTITLE"}, + {0x11F20, "SETCTITLE"}, + {0x11F62, "GETCTLVALUE"}, + {0x11F70, "GETCTLMIN"}, + {0x11F74, "GETCTLMAX"}, + {0x11F78, "SETCTLVALUE"}, + {0x11FBA, "SETCTLMIN"}, + {0x11FBE, "SETCTLMAX"}, + {0x11FC2, "TESTCONTROL"}, + {0x11FF0, "DRAGCONTROL"}, + {0x120A2, "TRACKCONTROL"}, + {0x12190, "UPDTCONTROLS"}, + {0x121A0, "DRAWCONTROLS"}, + {0x12228, "FINDCONTROL"}, + {0x12296, "CMGREND"}, + {0x12296, "RMGR"}, + {0x122B8, "INITRESOURCES"}, + {0x12414, "VSUPERLOAD"}, + {0x1254C, "VNEWMAP"}, + {0x12638, "RSRCZONEINIT"}, + {0x126DE, "CREATERESFILE"}, + {0x12728, "OPENRESFILE"}, + {0x12758, "OPENRFPERM"}, + {0x1276C, "USERESFILE"}, + {0x12776, "GETRESFILEATTRS"}, + {0x12782, "SETRESFILEATTRS"}, + {0x12838, "UPDATERESFILE"}, + {0x12920, "VCMPFRM"}, + {0x12B18, "CLOSERESFILE"}, + {0x12BB8, "COUNT1RESOURCES"}, + {0x12BBC, "COUNTRESOURCES"}, + {0x12BE2, "GET1INDRESOURCE"}, + {0x12BE6, "GETINDRESOURCE"}, + {0x12C7E, "COUNT1TYPES"}, + {0x12C82, "COUNTTYPES"}, + {0x12CC8, "GET1INDTYPE"}, + {0x12CCC, "GETINDTYPE"}, + {0x12CEE, "UNIQUE1ID"}, + {0x12CF2, "UNIQUEID"}, + {0x12D2C, "GET1RESOURCE"}, + {0x12D30, "GETRESOURCE"}, + {0x12D70, "GET1NAMEDRESOURCE"}, + {0x12D74, "GETNAMEDRESOURCE"}, + {0x1307E, "VCHECKLOAD"}, + {0x13322, "LOADRESOURCE"}, + {0x13360, "RELEASERESOURCE"}, + {0x1338A, "DETACHRESOURCE"}, + {0x133A2, "CHANGEDRESOURCE"}, + {0x133DE, "WRITERESOURCE"}, + {0x13418, "HOMERESFILE"}, + {0x13442, "SETRESPURGE"}, + {0x13462, "SETRESLOAD"}, + {0x1346C, "CURRESFILE"}, + {0x13474, "RESERROR"}, + {0x1347C, "ADDREFERENCE"}, + {0x1348C, "RMVEREFERENCE"}, + {0x13496, "GETRESATTRS"}, + {0x134AA, "SETRESATTRS"}, + {0x134DC, "GETRESINFO"}, + {0x13522, "SETRESINFO"}, + {0x1356C, "ADDRESOURCE"}, + {0x13644, "RMVERESOURCE"}, + {0x137C0, "SIZERESOURCE"}, + {0x137E2, "MAXSIZERSRC"}, + {0x137F6, "RSRCMAPENTRY"}, + {0x13802, "RGETRESOURCE"}, + {0x1382E, "IAPPEND"}, + {0x1382E, "DMGR"}, + {0x13838, "INITDIALOGS"}, + {0x138EE, "STOPALERT"}, + {0x138F2, "NOTEALERT"}, + {0x138F6, "CAUTIONALERT"}, + {0x138FA, "ALERT"}, + {0x13A58, "GETNEWDIALOG"}, + {0x13ADA, "NEWCDIALOG"}, + {0x13ADE, "NEWDIALOG"}, + {0x13BB0, "ISDIALOGEVENT"}, + {0x13BEC, "DIALOGSELECT"}, + {0x13C2E, "MODALDIALOG"}, + {0x13CD8, "DRAWDIALOG"}, + {0x13CF2, "UPDTDIALOG"}, + {0x13D10, "CLOSEDIALOG"}, + {0x13DAC, "DISPOSDIALOG"}, + {0x13E0C, "COULDDIALOG"}, + {0x13E1A, "COULDALERT"}, + {0x13EB0, "FREEDIALOG"}, + {0x13EBE, "FREEALERT"}, + {0x13F12, "PARAMTEXT"}, + {0x13F36, "ERRORSOUND"}, + {0x13F3E, "GETDITEM"}, + {0x13F84, "SETDITEM"}, + {0x13FBC, "GETITEXT"}, + {0x13FDC, "SETITEXT"}, + {0x14046, "SELITEXT"}, + {0x140A2, "HIDEDITEM"}, + {0x14100, "SHOWDITEM"}, + {0x14174, "FINDDITEM"}, + {0x14902, "DMGREND"}, + {0x14902, "BYTES"}, + {0x14902, "MUNGER"}, + {0x14930, "XMUNGER"}, + {0x14A66, "HANDTOHAND"}, + {0x14A8E, "PTRTOXHAND"}, + {0x14A96, "PTRTOHAND"}, + {0x14AB0, "HANDANDHAND"}, + {0x14AD4, "PTRANDHAND"}, + {0x14AE4, "METHODDISPATCH"}, + {0x14B40, "LONGMUL"}, + {0x14B5E, "FRACMUL"}, + {0x14B64, "FIXMUL"}, + {0x14C52, "FRACDIV"}, + {0x14C58, "FIXDIV"}, + {0x14CA8, "FRACSQRT"}, + {0x14CE2, "FIXRATIO"}, + {0x14D34, "LOWORD"}, + {0x14D3C, "HIWORD"}, + {0x14D46, "FIXROUND"}, + {0x14D60, "FRACCOS"}, + {0x14D68, "FRACSIN"}, + {0x14E0E, "FIXATAN2"}, + {0x14ECC, "FIX2X"}, + {0x14ED2, "FRAC2X"}, + {0x14EFE, "X2FIX"}, + {0x14F04, "X2FRAC"}, + {0x14F60, "FIX2LONG"}, + {0x14F64, "FRAC2FIX"}, + {0x14F80, "LONG2FIX"}, + {0x14F84, "FIX2FRAC"}, + {0x14F94, "DESKMGR"}, + {0x14F94, "SYSTEMEVENT"}, + {0x1506A, "SYSTEMCLICK"}, + {0x1513E, "SYSTEMTASK"}, + {0x151BA, "SYSTEMMENU"}, + {0x15202, "SYSTEMEDIT"}, + {0x15230, "OPENDESKACC"}, + {0x1527E, "CLOSEDESKACC"}, + {0x15298, "GMGR"}, + {0x15298, "GETPATTERN"}, + {0x152B2, "GETCURSOR"}, + {0x152BA, "GETSTRING"}, + {0x152C2, "GETICON"}, + {0x152CA, "GETPICTURE"}, + {0x152D2, "GETNEWCWINDOW"}, + {0x152DE, "GETNEWWINDOW"}, + {0x15386, "GETNEWCONTROL"}, + {0x15408, "GETMENU"}, + {0x154BA, "GETNEWMBAR"}, + {0x15518, "GETMGREND"}, + {0x15518, "TEXTEDIT"}, + {0x1552C, "TEGETTEXT"}, + {0x15538, "TEINIT"}, + {0x1555E, "TEDISPOSE"}, + {0x1559A, "TEXTBOX"}, + {0x15664, "TESETTEXT"}, + {0x15774, "TECALTEXT"}, + {0x157D8, "TESETSELECT"}, + {0x15804, "TENEW"}, + {0x15878, "TESTYLNEW"}, + {0x1594A, "TEUPDATE"}, + {0x15978, "TECLICK"}, + {0x15A8E, "VPIXEL2CHAR"}, + {0x15FC8, "XTRIMMEASURE"}, + {0x1607C, "VCHAR2PIXEL"}, + {0x162E4, "TEDISPATCH"}, + {0x162FC, "TECOPY"}, + {0x163D2, "TECUT"}, + {0x163E2, "TEDELETE"}, + {0x16508, "XFINDWORD"}, + {0x16600, "XFINDLINE"}, + {0x169E8, "TEACTIVATE"}, + {0x16A0A, "TEDEACTIVATE"}, + {0x16A20, "TEIDLE"}, + {0x16A48, "TEPASTE"}, + {0x16D3C, "TEINSERT"}, + {0x16D6A, "TEKEY"}, + {0x16E54, "TESETJUST"}, + {0x16E7A, "TESCROLL"}, + {0x16ED4, "TEPINSCROLL"}, + {0x16F5E, "TESELVIEW"}, + {0x16FCC, "TEAUTOVIEW"}, + {0x1744C, "TEGETOFFSET"}, + {0x175A8, "TE68KEND"}, + {0x175A8, "SCRAPMGR"}, + {0x175A8, "INFOSCRAP"}, + {0x17622, "UNLOADSCRAP"}, + {0x17658, "LOADSCRAP"}, + {0x1768C, "ZEROSCRAP"}, + {0x176D8, "GETSCRAP"}, + {0x17748, "PUTSCRAP"}, + {0x1778E, "PRGLUE"}, + {0x17A0C, "FONTMANAGER"}, + {0x17A0C, "INITFONTS"}, + {0x17B58, "FMSWAPFONT"}, + {0x189FA, "FPOINTONE"}, + {0x18A68, "GETFONTNAME"}, + {0x18AD6, "REALFONT"}, + {0x18B40, "GETFNUM"}, + {0x18B84, "SETFONTLOCK"}, + {0x18BAC, "SETFSCALEDISABLE"}, + {0x18BBA, "SETFRACTENABLE"}, + {0x18BC2, "FONTMETRICS"}, + {0x18DA2, "FMGREND"}, + {0x18DA2, "BLOCKHEAD"}, + {0x18DA2, "NEWGDEVICE"}, + {0x18E3C, "DISPOSGDEVICE"}, + {0x18E48, "DISPOSGDHANDLES"}, + {0x18E84, "INITGDEVICE"}, + {0x18FC0, "GETDEVPIXMAP"}, + {0x19142, "CHECKDEVICES"}, + {0x1943E, "GETGDEVICE"}, + {0x19446, "SETGDEVICE"}, + {0x1944E, "GETDEVICELIST"}, + {0x19456, "GETMAINDEVICE"}, + {0x1945E, "GETNEXTDEVICE"}, + {0x1946A, "TESTDEVICEATTRIBUTE"}, + {0x19480, "SETDEVICEATTRIBUTE"}, + {0x1949E, "GETMAXDEVICE"}, + {0x194FA, "GETDEVPIX"}, + {0x19508, "STDTEXT"}, + {0x19794, "CALLTEXT"}, + {0x197B4, "TEXTFACE"}, + {0x197C0, "DRAWCHAR"}, + {0x197CE, "CHARWIDTH"}, + {0x197E8, "TEXTFONT"}, + {0x197EC, "TEXTMODE"}, + {0x197F0, "TEXTSIZE"}, + {0x19804, "SPACEEXTRA"}, + {0x19810, "DRAWSTRING"}, + {0x19822, "DRAWTEXT"}, + {0x1983A, "STRINGWIDTH"}, + {0x1984A, "TEXTWIDTH"}, + {0x198B0, "STDTXMEAS"}, + {0x19978, "MEASURETEXT"}, + {0x19A74, "GETFONTINFO"}, + {0x19B16, "CALCCHAREXTRA"}, + {0x19B6C, "CHAREXTRA"}, + {0x19B98, "STDLINE"}, + {0x19C6E, "LINETO"}, + {0x19C84, "LINE"}, + {0x19C9C, "MOVETO"}, + {0x19CA6, "COMMONMOVEEND"}, + {0x19CB4, "MOVE"}, + {0x19CB4, "MOOV"}, + {0x19CC8, "DOLINE"}, + {0x19D50, "HIDEPEN"}, + {0x19D54, "SHOWPEN"}, + {0x19D60, "GETPENSTATE"}, + {0x19D9C, "SETPENSTATE"}, + {0x19DD4, "GETPEN"}, + {0x19DE4, "PENSIZE"}, + {0x19DF2, "PENMODE"}, + {0x19DF8, "PENPAT"}, + {0x19E20, "PENNORMAL"}, + {0x19E3A, "PUTLINE"}, + {0x19F28, "DRTEXT"}, + {0x1AB94, "CRSRCORE"}, + {0x1AB94, "INITCRTABLE"}, + {0x1AFC0, "GETMAINCRSR"}, + {0x1B040, "SCRNADDRESS"}, + {0x1B048, "SCRNSIZE"}, + {0x1B06C, "SCRNBITMAP"}, + {0x1B08E, "CRSRVBLTASK"}, + {0x1B2E4, "PINRECT"}, + {0x1B2F6, "SETCRSRDATA"}, + {0x1B352, "ALLOCCRSR"}, + {0x1B4BA, "BITBLT"}, + {0x1B8A8, "BLEFT0"}, + {0x1B8D4, "BSETUP0"}, + {0x1B8F6, "BEND0"}, + {0x1B8F8, "BMAIN0"}, + {0x1B94C, "BEND1"}, + {0x1B94E, "BMAIN1"}, + {0x1B968, "BEND2"}, + {0x1B96A, "BMAIN2"}, + {0x1B984, "BEND3"}, + {0x1B986, "BMAIN3"}, + {0x1B9A2, "BCEND0"}, + {0x1B9A4, "BCMAIN0"}, + {0x1B9CE, "BCEND1"}, + {0x1B9D0, "BCMAIN1"}, + {0x1B9F2, "BCEND3"}, + {0x1B9F4, "BCMAIN3"}, + {0x1BA16, "BLONG8"}, + {0x1BA42, "BSETUP8"}, + {0x1BAB0, "BEND9"}, + {0x1BAB2, "BMAIN9"}, + {0x1BACC, "BSETUP10"}, + {0x1BAE8, "BEND10"}, + {0x1BB26, "BEND11"}, + {0x1BB28, "BMAIN11"}, + {0x1BB42, "BXLONG8"}, + {0x1BB7A, "BXMAIN8"}, + {0x1BB98, "BXEND9"}, + {0x1BB9A, "BXMAIN9"}, + {0x1BBBA, "BXEND10"}, + {0x1BBBC, "BXMAIN10"}, + {0x1BBD2, "BXEND11"}, + {0x1BBD4, "BXMAIN11"}, + {0x1BBF4, "BADDOVER"}, + {0x1BC6A, "BADDPIN"}, + {0x1BD06, "BSUBOVER"}, + {0x1BD7C, "BSUBPIN"}, + {0x1BE18, "BMAX"}, + {0x1BE9E, "BMIN"}, + {0x1BF24, "BAVG"}, + {0x1BFBE, "BHILITE"}, + {0x1C04E, "BSLOHILITE"}, + {0x1C0B0, "BTRANSPARENT"}, + {0x1C13E, "DRAWLINE"}, + {0x1C76C, "RGNBLT"}, + {0x1CBF8, "RMASK0"}, + {0x1CC18, "RMASK1"}, + {0x1CC30, "RMASK2"}, + {0x1CC48, "RMASK3"}, + {0x1CC62, "RCMASK0"}, + {0x1CC8C, "RCMASK1"}, + {0x1CCAC, "RCMASK3"}, + {0x1CCCC, "RMASK8"}, + {0x1CCE2, "RMASK9"}, + {0x1CCFA, "RMASK10"}, + {0x1CD08, "RMASK11"}, + {0x1CD20, "RXMASK8"}, + {0x1CD40, "RXMASK9"}, + {0x1CD62, "RXMASK10"}, + {0x1CD7A, "RXMASK11"}, + {0x1CD9C, "RADDOVER"}, + {0x1CDE8, "RADDPIN"}, + {0x1CE3C, "RSUBOVER"}, + {0x1CE88, "RSUBPIN"}, + {0x1CEDC, "RMAX"}, + {0x1CF38, "RMIN"}, + {0x1CF94, "RAVG"}, + {0x1D000, "RHILITE"}, + {0x1D056, "RSLOWHILITE"}, + {0x1D094, "RTRANSPARENT"}, + {0x1D0DA, "STDRECT"}, + {0x1D15C, "STDDEVLOOP"}, + {0x1D312, "PINIT"}, + {0x1D328, "PUSHVERB"}, + {0x1D37C, "FILLRECT"}, + {0x1D380, "FILLCRECT"}, + {0x1D394, "FRAMERECT"}, + {0x1D398, "PAINTRECT"}, + {0x1D39C, "ERASERECT"}, + {0x1D3A0, "INVERTRECT"}, + {0x1D3A2, "CALLRECT"}, + {0x1D3C2, "DRAWRECT"}, + {0x1D406, "FRMRECT"}, + {0x1D500, "SETRECT"}, + {0x1D50E, "EQUALRECT"}, + {0x1D528, "EMPTYRECT"}, + {0x1D542, "OFFSETRECT"}, + {0x1D554, "INSETRECT"}, + {0x1D566, "SECTRECT"}, + {0x1D58A, "RSECT"}, + {0x1D5FE, "UNIONRECT"}, + {0x1D63C, "PT2RECT"}, + {0x1D672, "PTINRECT"}, + {0x1D6A0, "PUTRECT"}, + {0x1D6F8, "ALLOCCURSOR"}, + {0x1D706, "INITCURSOR"}, + {0x1D718, "SETCURSOR"}, + {0x1D734, "SETCCURSOR"}, + {0x1D742, "HIDECURSOR"}, + {0x1D748, "SHOWCURSOR"}, + {0x1D74E, "SHIELDCURSOR"}, + {0x1D77E, "OBSCURECURSOR"}, + {0x1D784, "BITNOT"}, + {0x1D78C, "BITAND"}, + {0x1D794, "BITXOR"}, + {0x1D79E, "BITOR"}, + {0x1D7A6, "BITSHIFT"}, + {0x1D7BC, "BITTST"}, + {0x1D7CA, "BITSET"}, + {0x1D7D4, "BITCLR"}, + {0x1D7EC, "RANDOM"}, + {0x1D83E, "FORECOLOR"}, + {0x1D88A, "BACKCOLOR"}, + {0x1D88E, "PORTLONG"}, + {0x1D89A, "COLORBIT"}, + {0x1D89C, "PORTWORD"}, + {0x1D8A8, "GETMASKTAB"}, + {0x1D8AE, "LEFTMASK"}, + {0x1D8BA, "RIGHTMASK"}, + {0x1D8C6, "BITMASK"}, + {0x1D8D2, "MASKTAB"}, + {0x1D932, "ARITHMODE"}, + {0x1D93A, "COLORMAP"}, + {0x1DBD2, "GETCPIXEL"}, + {0x1DBDE, "GETPIXEL"}, + {0x1DCA6, "STUFFHEX"}, + {0x1DCE0, "XORSLAB"}, + {0x1DD26, "DRAWSLAB"}, + {0x1DD7E, "SLMASK8"}, + {0x1DD9A, "SLMASK9"}, + {0x1DDAC, "SLMASK10"}, + {0x1DDC8, "SLMASK11"}, + {0x1DDCE, "SLXMASK8"}, + {0x1DE0A, "SLXMASK9"}, + {0x1DE48, "SLXMASK10"}, + {0x1DE7C, "SLXMASK11"}, + {0x1DEBA, "SLADDOVER"}, + {0x1DF50, "SLADDPIN"}, + {0x1DFDA, "SLSUBOVER"}, + {0x1E042, "SLSUBPIN"}, + {0x1E0CE, "SLMAX"}, + {0x1E146, "SLMIN"}, + {0x1E1BE, "SLAVG"}, + {0x1E26A, "SLHILITE"}, + {0x1E2CE, "SLTRANSPARENT"}, + {0x1E318, "SLABMODE"}, + {0x1E3DC, "FASTSLABMODE"}, + {0x1E3F0, "COPYHANDLE"}, + {0x1E41A, "NEWHANDLE"}, + {0x1E436, "RNEWHANDLE"}, + {0x1E43C, "SETHSIZE"}, + {0x1E44A, "RSETHSIZE"}, + {0x1E450, "INITGRAF"}, + {0x1E5BC, "NEWPORT"}, + {0x1E5DC, "OPENPORT"}, + {0x1E5EA, "INITPORT"}, + {0x1E634, "INITSHARED"}, + {0x1E692, "SETSTDPROCS"}, + {0x1E6CC, "SETSTDCPROCS"}, + {0x1E6EC, "LOCALTOGLOBAL"}, + {0x1E6F4, "GLOBALTOLOCAL"}, + {0x1E726, "ADDPT"}, + {0x1E72E, "SUBPT"}, + {0x1E74C, "SETPORT"}, + {0x1E754, "GETPORT"}, + {0x1E75E, "GRAFDEVICE"}, + {0x1E764, "SETPORTBITS"}, + {0x1E782, "BACKPAT"}, + {0x1E7A6, "PORTSIZE"}, + {0x1E7C6, "MOVEPORTTO"}, + {0x1E7F6, "SETORIGIN"}, + {0x1E836, "CLIPRECT"}, + {0x1E84A, "SETCLIP"}, + {0x1E856, "GETCLIP"}, + {0x1E86A, "SETPT"}, + {0x1E874, "EQUALPT"}, + {0x1E880, "INSPORTLIST"}, + {0x1E8AA, "DELPORTLIST"}, + {0x1E8DA, "ONEBITCTABLE"}, + {0x1E8E6, "FILLONEBIT"}, + {0x1E8FC, "PORTTOMAP"}, + {0x1E8FE, "BITSTOMAP"}, + {0x1E912, "OPENCPORT"}, + {0x1E948, "INITCPORT"}, + {0x1E982, "INITCOLORSTUFF"}, + {0x1EA00, "CLOSECPORT"}, + {0x1EA00, "CLOSEPORT"}, + {0x1EA64, "SETCPORTPIX"}, + {0x1EA78, "GETCTABLE"}, + {0x1EAC0, "NEWCTAB"}, + {0x1EAD0, "DISPOSCTABLE"}, + {0x1EAD8, "GETCTSEED"}, + {0x1EAFE, "OPENPIXMAP"}, + {0x1EB1E, "NEWPIXMAP"}, + {0x1EB2E, "DISPOSPIXMAP"}, + {0x1EB48, "INITPIXMAP"}, + {0x1EB78, "COPYPIXMAP"}, + {0x1EBA2, "BITSTOPIX"}, + {0x1EC44, "COPYPMAP"}, + {0x1EC60, "ONEBITDATA"}, + {0x1EC92, "SHFTTBL"}, + {0x1ECB4, "SETCPIXEL"}, + {0x1ED08, "HILITECOLOR"}, + {0x1ED0C, "OPCOLOR"}, + {0x1ED0E, "SETGRAFVARSCOMMON"}, + {0x1ED2C, "GETCCURSOR"}, + {0x1ED3A, "GETPIXPAT"}, + {0x1ED46, "PATSHARE"}, + {0x1EE44, "NEWPIXPAT"}, + {0x1EEAC, "DISPOSCCURSOR"}, + {0x1EEAC, "DISPOSPIXPAT"}, + {0x1EF16, "SETFILLPAT"}, + {0x1EF4A, "PENPIXPAT"}, + {0x1EF50, "PHILPIXPAT"}, + {0x1EF56, "BACKPIXPAT"}, + {0x1EFC0, "COPYPIXPAT"}, + {0x1F004, "OLDPATTONEW"}, + {0x1F08A, "PATEXPAND"}, + {0x1F36A, "PATCONVERT"}, + {0x1F49E, "MAKESCALETBL"}, + {0x1F5BA, "PATDITHER"}, + {0x1F710, "MAKERGBPAT"}, + {0x1F7C4, "GETCICON"}, + {0x1F886, "PLOTCICON"}, + {0x1F914, "DISPOSCICON"}, + {0x1F92E, "STDCOMMENT"}, + {0x1F98C, "STDGETPIC"}, + {0x1F9AC, "STDPUTPIC"}, + {0x1FA2A, "STDOPCODEPROC"}, + {0x1FA74, "PICCOMMENT"}, + {0x1FA8A, "OPENCPICTURE"}, + {0x1FA98, "OPENPICTURE"}, + {0x1FAA2, "OPSHARE"}, + {0x1FBF8, "CLOSEPICTURE"}, + {0x1FC60, "KILLPICTURE"}, + {0x1FC68, "DRAWPICTURE"}, + {0x1FDFE, "PICITEM1"}, + {0x20790, "GETUBYTE"}, + {0x207A2, "GETWORD"}, + {0x207B2, "GETLONG"}, + {0x207C2, "GETPICDATA"}, + {0x207F0, "PUTPICDATA"}, + {0x20806, "DPUTPICBYTE"}, + {0x2080C, "PUTPICBYTE"}, + {0x2081E, "PUTPICWORD"}, + {0x20830, "PUTPICLONG"}, + {0x20840, "PUTPICRECT"}, + {0x20884, "DPUTPICOP"}, + {0x2088A, "PUTPICOP"}, + {0x2088E, "PUTPICOP2"}, + {0x208B8, "PUTPICRGN"}, + {0x208D2, "PUTPICPAD"}, + {0x208F8, "PUTPICPAT"}, + {0x20904, "PUTPICVERB"}, + {0x209F4, "UPDATEPAT"}, + {0x20A9C, "EQUALPAT"}, + {0x20B38, "GETPICTABLE"}, + {0x20B74, "PUTPICTABLE"}, + {0x20B9A, "GETPICPIXMAP"}, + {0x20BCE, "PUTPICPIXMAP"}, + {0x20BFE, "GETPICPIXPAT"}, + {0x20C38, "PUTGRAY"}, + {0x20D2A, "PUTPICPIXPAT"}, + {0x20DB0, "GETPMDATA"}, + {0x20E48, "PUTPMDATA"}, + {0x20EF2, "CHECKPIC"}, + {0x2110C, "SCALEPT"}, + {0x21160, "MAPPT"}, + {0x211BE, "MAPFIXPT"}, + {0x21214, "MAPRECT"}, + {0x2122C, "MAPRATIO"}, + {0x21274, "STDRRECT"}, + {0x21328, "FRAMEROUNDRECT"}, + {0x2132C, "PAINTROUNDRECT"}, + {0x21330, "ERASEROUNDRECT"}, + {0x21334, "INVERTROUNDRECT"}, + {0x21338, "FILLROUNDRECT"}, + {0x2133C, "FILLCROUNDRECT"}, + {0x2134E, "CALLRRECT"}, + {0x21372, "STDPOLY"}, + {0x21428, "FRAMEPOLY"}, + {0x2142C, "PAINTPOLY"}, + {0x21430, "ERASEPOLY"}, + {0x21434, "INVERTPOLY"}, + {0x21438, "FILLPOLY"}, + {0x2143C, "FILLCPOLY"}, + {0x2144E, "CALLPOLY"}, + {0x2146E, "OPENPOLY"}, + {0x214A4, "CLOSEPOLY"}, + {0x21514, "KILLPOLY"}, + {0x2151C, "OFFSETPOLY"}, + {0x21538, "MAPPOLY"}, + {0x21594, "FRPOLY"}, + {0x215D6, "DRAWPOLY"}, + {0x2162E, "DRAWARC"}, + {0x21D7C, "INITOVAL"}, + {0x21E26, "BUMPOVAL"}, + {0x21E68, "STRETCHBITS"}, + {0x227EC, "STMASK0"}, + {0x22812, "STMASK1"}, + {0x22832, "STMASK2"}, + {0x22846, "STMASK3"}, + {0x22866, "STADDOVER"}, + {0x228A8, "STADDPIN"}, + {0x2290E, "STSUBOVER"}, + {0x22950, "STSUBPIN"}, + {0x229B6, "STMAX"}, + {0x22A08, "STMIN"}, + {0x22A5A, "STAVG"}, + {0x22ABA, "STTRANSPARENT"}, + {0x22AF2, "STHILITE"}, + {0x22B2A, "SETUPSTRETCH"}, + {0x22C16, "EXTBL"}, + {0x22C22, "EXTBL1"}, + {0x22D62, "TABLE2"}, + {0x22E28, "TABLE4"}, + {0x23304, "TABLE8"}, + {0x23516, "SCALERTN"}, + {0x23548, "INITRGN"}, + {0x23582, "SEEKRGN"}, + {0x235BC, "SEEKDOWN"}, + {0x235F6, "SEEKUP"}, + {0x236AC, "STDRGN"}, + {0x2373A, "FRAMERGN"}, + {0x2373E, "PAINTRGN"}, + {0x23742, "ERASERGN"}, + {0x23746, "INVERTRGN"}, + {0x2374A, "FILLRGN"}, + {0x2374E, "FILLCRGN"}, + {0x23760, "CALLRGN"}, + {0x23780, "DRAWRGN"}, + {0x237DA, "FRRGN"}, + {0x2384E, "NEWRGN"}, + {0x23872, "DISPOSERGN"}, + {0x2387A, "OPENRGN"}, + {0x238AA, "CLOSERGN"}, + {0x23908, "COPYRGN"}, + {0x23954, "SETEMPTYRGN"}, + {0x23960, "SETRECTRGN"}, + {0x239B8, "RECTRGN"}, + {0x239C6, "OFFSETRGN"}, + {0x239F8, "INSETRGN"}, + {0x23A9A, "EMPTYRGN"}, + {0x23AAA, "EQUALRGN"}, + {0x23AE8, "SECTRGN"}, + {0x23AEC, "UNIONRGN"}, + {0x23AF0, "DIFFRGN"}, + {0x23AF4, "XORRGN"}, + {0x23AF6, "DORGNOP"}, + {0x23BE6, "PTINRGN"}, + {0x23C44, "RECTINRGN"}, + {0x23CCE, "TRIMRECT"}, + {0x23D2E, "MAPRGN"}, + {0x23DE4, "GETSEEK"}, + {0x24320, "STDBITS"}, + {0x245BA, "DEVLOOP"}, + {0x24A1E, "COPYBITS"}, + {0x24B08, "GODEVLOOP"}, + {0x24B36, "COPYMASK"}, + {0x24BA8, "CMDEVLOOP"}, + {0x24BCA, "SEEDFILL"}, + {0x24BD2, "CALCMASK"}, + {0x24D22, "SCROLLRECT"}, + {0x24E5C, "PACKBITS"}, + {0x24F10, "UNPACKBITS"}, + {0x24F56, "STDOVAL"}, + {0x25002, "FRAMEOVAL"}, + {0x25006, "PAINTOVAL"}, + {0x2500A, "ERASEOVAL"}, + {0x2500E, "INVERTOVAL"}, + {0x25012, "FILLOVAL"}, + {0x25016, "FILLCOVAL"}, + {0x25028, "CALLOVAL"}, + {0x25048, "STDARC"}, + {0x250E6, "FRAMEARC"}, + {0x250EA, "PAINTARC"}, + {0x250EE, "ERASEARC"}, + {0x250F2, "INVERTARC"}, + {0x250F6, "FILLARC"}, + {0x250FA, "FILLCARC"}, + {0x2510C, "CALLARC"}, + {0x25130, "SORTPOINTS"}, + {0x251C0, "CULLPOINTS"}, + {0x2520E, "PUTRGN"}, + {0x2528C, "UPDATEPIXMAP"}, + {0x2528E, "MAKEITABLE"}, + {0x255BE, "ITABMATCH"}, + {0x256C6, "COLOR2INDEX"}, + {0x2573E, "INDEX2COLOR"}, + {0x2577A, "INVERTCOLOR"}, + {0x257BC, "RGBFORECOLOR"}, + {0x25800, "RGB2OLD"}, + {0x2582C, "RGBBACKCOLOR"}, + {0x25832, "GETFORECOLOR"}, + {0x25874, "GETBACKCOLOR"}, + {0x2587A, "REALCOLOR"}, + {0x258EE, "SETENTRIES"}, + {0x25A14, "RESTOREENTRIES"}, + {0x25B04, "SAVEENTRIES"}, + {0x25B92, "PROTECTENTRY"}, + {0x25BE4, "RESERVEENTRY"}, + {0x25C0A, "SETCLIENTID"}, + {0x25C1A, "ADDSEARCH"}, + {0x25C4C, "ADDCOMP"}, + {0x25C76, "DELSEARCH"}, + {0x25CA2, "DELCOMP"}, + {0x25CCE, "GETSUBTABLE"}, + {0x25D82, "QDERROR"}, + {0x25D8E, "ANGLEFROMSLOPE"}, + {0x25DCC, "SLOPEFROMANGLE"}, + {0x25EF0, "PTTOANGLE"}, + {0x25F8A, "PUTOVAL"}, + {0x260B4, "PACKRGN"}, + {0x26178, "RGNOP"}, + {0x263AA, "SECTSCAN"}, + {0x263B0, "DIFFSCAN"}, + {0x263B4, "UNIONSCAN"}, + {0x263F6, "INSETSCAN"}, + {0x26440, "XORSCAN"}, + {0x26456, "PACKDISPATCHER"}, + {0x26456, "INITPACK"}, + {0x26478, "INITALLPACKS"}, + {0x2649C, "PACK4"}, + {0x264BE, "PACK5"}, + {0x2653C, "PACK0"}, + {0x2653E, "PACK1"}, + {0x26540, "PACK2"}, + {0x26542, "PACK3"}, + {0x26548, "PACK6"}, + {0x2654A, "PACK7"}, + {0x2654C, "PACK8"}, + {0x2654E, "PACK9"}, + {0x26550, "PACK10"}, + {0x26552, "PACK11"}, + {0x26554, "PACK12"}, + {0x26556, "PACK13"}, + {0x26558, "PACK14"}, + {0x2655A, "PACK15"}, + {0x2655C, "PACKMGREND"}, + {0x2655C, "SEXYDATE"}, + {0x2655C, "SECS2DATE"}, + {0x265D4, "DATE2SECS"}, + {0x26636, "SCSISTUFF"}, + {0x26636, "INITSCSIMGR"}, + {0x266A4, "SCSIMGR"}, + {0x26D98, "TIMEMGR"}, + {0x26D98, "INSTIME"}, + {0x26DA6, "RMVTIME"}, + {0x26DC0, "PRIMETIME"}, + {0x26EE2, "RESTOP"}, + {0x26EE2, "DSPTABLE"}, + {0x26EE2, "DISPTABLE"}, + {0x27970, "_clut_1_1BitStd"}, + {0x27990, "_clut_2_2BitStd"}, + {0x279C0, "_clut_4_4BitStd"}, + {0x27A50, "_clut_8_8BitStd"}, + {0x28260, "_clut_127_DefQDColors"}, + {0x282B0, "_gama_0_StdGamma"}, + {0x283C4, "_mitq_0_"}, + {0x283D8, "_wctb_0_"}, + {0x28410, "_cctb_0_"}, + {0x28440, "_PACK_5_"}, + {0x29510, "_PACK_4_"}, + {0x2A608, "_PACK_7_"}, + {0x2AB58, "_SERD_0_"}, + {0x2B480, "_DRVR_10_.ATP"}, + {0x2C19C, "_DRVR_9_.MPP"}, + {0x2D72C, "_DRVR_4_.Sony"}, + {0x2F010, "_DRVR_3_.Sound"}, + {0x2F478, "_DRVR_40_.XPP"}, + {0x2FE94, "_CDEF_0_"}, + {0x3035C, "_CDEF_1_"}, + {0x30908, "_KCHR_0_"}, + {0x30E7C, "_KMAP_0_"}, + {0x30F0C, "_MBDF_0_"}, + {0x31B20, "_MDEF_0_"}, + {0x3255C, "_WDEF_1_"}, + {0x32A5C, "_WDEF_0_"}, + {0x332C4, "_CURS_4_"}, + {0x33310, "_CURS_1_"}, + {0x3335C, "_CURS_3_"}, + {0x333A8, "_CURS_2_"}, + {0x333F4, "_FONT_0_Chicago"}, + {0x333FC, "_FONT_393_"}, + {0x33E28, "_FONT_396_"}, + {0x34A98, "_FONT_521_"}, + {0x35444, "_FONT_384_Geneva"}, + {0x3544C, "_FONT_512_Monaco"}, + {0x35454, "_FONT_12_"}, + {0x3627C, "_NFNT_34_"}, + {0x37B48, "_NFNT_3_"}, + {0x3C3AC, "_NFNT_2_"}, + {0x3EAC8, "_snd_1_Brass_Horn"}, + {0, NULL} +}; diff --git a/core/macro.pl b/core/macro.pl new file mode 100755 index 0000000..4af7a67 --- /dev/null +++ b/core/macro.pl @@ -0,0 +1,562 @@ +#!/usr/bin/perl +# +# Copyright (c) 2013, 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. +# + +use strict; +use Carp; +use Storable qw(dclone); + +my $glob_printLineNumbers = 1; # Whether to prepend generated lines with their corresponding input file's line numbers +my $tab = " "; # one tab => four spaces + +main(); + +sub main { + + my $input = ""; + + if (($#ARGV) != 1) { + my $args = $#ARGV + 1; + croak "I need two arguments (got $args)"; + } + + open(INPUT, $ARGV[0]) or die croak "I can't open $ARGV[0]!"; + while (my $line = ) { + $input .= $line; + } + close(INPUT); + + $input = tabs_to_spaces($input); # it's simpler to deal with if all indentation can be represented as a # of spaces + my $ctx = { + text => line_logic($input), # the input text + out => "", # the output text + depth => 0, # the recursive depth of the parser + filename => $ARGV[0], # the name of the input file + adhoc => {} # hash of adhoc function refs + }; + parse($ctx); + + open(OUTPUT, '>'.$ARGV[1]); + print OUTPUT "/* Generated from $ARGV[0] */\n\n"; + print OUTPUT $ctx->{out}; + close(OUTPUT); +} + +sub tabs_to_spaces { + my @chars = split //,shift; + my $output = ""; + foreach my $c (@chars) { + if ($c eq "\t") { + $output .= $tab; # a tab is 4 spaces (imho) + } else { + $output .= $c; + } + } + return $output; +} + +sub line_logic { + # For simplicity, line numbers start at 0 + my $raw = shift; + my @lines = split /\n/,$raw; + + my @indents; # $indents[n] => the indent prefix for nth line + my @chars; # all the characters in the input text + my @line_map; # $line_map[n] => the line number to which the nth character belongs + + my $line_no = 0; + foreach my $line (@lines) { + my $past_indent = 0; + my $indent_count = 0; + my @l_chars = split //, $line; + foreach my $c (@l_chars) { + unless ($c eq " ") { + $past_indent = 1; + } + if ($past_indent) { + push @chars, $c; + push @line_map, $line_no; + } + else { + $indent_count++; + } + } + push @indents, $indent_count; + push @chars, "\n"; + push @line_map, $line_no; + $line_no++; + } + + return { + indents => \@indents, + chars => \@chars, + line_map => \@line_map, + line_no => $line_no + }; +} + +sub spaces { + my $count = shift; + my $out = ""; + for (my $i=0; $i < $count; $i++) { + $out .= " "; + } + return $out; +} + +sub parse { + my $ctx = shift; + my $out = ""; + my $text = $ctx->{text}; + + my $newline = 1; + for (my $i=0; $i < scalar(@{$text->{chars}}); $i++) { # iterate over every character in the input + my $c = $text->{chars}->[$i]; + my $line_no = $text->{line_map}->[$i]; + $ctx->{current_line} = $line_no+1; # this is so macros can know what line they were called from + + if ($newline) { # a newline just began + $newline = 0; + $ctx->{indent} = $text->{indents}->[$line_no]; # keep track of how many indents are on this line + if ($glob_printLineNumbers and ($ctx->{depth}==0)) { + # $out .= sprintf('/*%04u*/ ', $line_no+1); + } + $out .= spaces($ctx->{indent}); # and begin the line with the appropriate indentation + } + + if ($c ne "~") { + $out .= $c; + } else { + my $line_str = ""; + $ctx->{cur_pos} = $i; + + my $macro = resolve_macro($ctx); + + $i = $ctx->{cur_pos}; + if ($glob_printLineNumbers and ($ctx->{depth}==0)) { + # $line_str = sprintf('/*%04u*/ ', $line_no+1); + } + $out .= join("\n$line_str".spaces($ctx->{indent}), split(/\n/, $macro->{str})); + } + + if ($c eq "\n") { # a newline begins on the next character + $newline = 1; + } + } + + $ctx->{out} = $out; +} + +sub trim { + my $str = shift; + $str =~ s/^\s+//; + $str =~ s/\s+$//; + return $str; +} + +sub resolve_macro { + my $ctx = shift; + my $text = $ctx->{text}; + my $chars = $text->{chars}; + my $i = $ctx->{cur_pos}; + + # "~~" => "~" + if (($chars->[$i] eq "~") and ($chars->[$i+1] eq "~")) { + $ctx->{cur_pos} = $i+1; + return {str => "~"}; + } + + # ~macro_name(arg1, arg2, { + # printf("code goes here"); + # }) + + # parse out the macro name + my $macro_name = ""; + for ($i++; ($i < scalar(@$chars)) and ($chars->[$i] ne "("); $i++) { + $macro_name .= $chars->[$i]; + } + if ((length($macro_name) > 80) or ($i == scalar(@$chars)) or ($chars->[$i] ne "(")) { + croak sprintf("line=%u: I call bullshit on this macro call: starts \"%s...\"", + 1+$text->{line_map}->[$ctx->{cur_pos}], substr($macro_name, 0, 10)); + } + $macro_name = trim($macro_name); + + # parse out the macro arguments + my @macro_args; + for ($i++; ($i < scalar(@$chars)) and ($chars->[$i] ne ")"); ) { + + if (($chars->[$i] =~ /\s/) or ($chars->[$i] eq ',')) { + $i++; + } + elsif ($chars->[$i] eq "{") { + # process code block + $ctx->{cur_pos} = $i; + my $block = do_parse_recurse($ctx); + $i = $ctx->{cur_pos}; + push @macro_args, $block; + } + else { + # plain text argument + my $arg = ""; + my $paren_count = 1; + for (; ($i < scalar(@$chars)) and (!(($paren_count==1)and($chars->[$i]eq')'))) and ($chars->[$i] ne ","); $i++) { + if ($chars->[$i] eq ')') {$paren_count--;} + elsif ($chars->[$i] eq '(') {$paren_count++;} + $arg .= $chars->[$i]; + # printf("character = %s, paren_count = %u\n", $chars->[$i], $paren_count); + } + + if ($i == scalar(@$chars)) { + croak(sprintf('line=%u: argument #%u seems bogus', $text->{line_map}->[$ctx->{cur_pos}], scalar(@macro_args))); + } + $arg = trim($arg); + + # if the argument is encased in quotes, eval it + if ( (length($arg)>0) and ( (substr($arg, 0, 1) eq "'") or (substr($arg, 0, 1) eq "\"") ) ) { + my $newarg = ""; + eval '$newarg'." = $arg;"; + croak(sprintf("line=%u: eval() doesn't like argument at all: \"%s\" (%s)", + 1+$text->{line_map}->[$ctx->{cur_pos}], $arg, $@)) if $@; + $arg = $newarg; + } + + push @macro_args, $arg; + } + } + + # evaluate macro + my $macro_call; + my $macro_return; + if (exists $ctx->{adhoc}->{$macro_name}) { + $macro_call = sprintf('$macro_return = $ctx->{adhoc}->{%s}->(\@macro_args,$ctx);', $macro_name); + } else { + $macro_call = sprintf('$macro_return = macro_%s(\@macro_args,$ctx);', $macro_name); + } + eval $macro_call; + if ($@) { + croak(sprintf("line=%u: Macro failed (exploded):\n%s", 1+$text->{line_map}->[$ctx->{cur_pos}], $@)); + } + + $ctx->{cur_pos} = $i; + return {str => $macro_return}; +} + +sub do_parse_recurse { + my $oldctx = shift; + my $oldtext = $oldctx->{text}; + my $oldchars = $oldtext->{chars}; + my $oldline_map = $oldtext->{line_map}; + my $old_indents = $oldtext->{indents}; + + # dclone can't handle CODE references, apparently + my $adhoc_backup = $oldctx->{adhoc}; + delete $oldctx->{adhoc}; + my $newctx = dclone($oldctx); + $oldctx->{adhoc} = $adhoc_backup; + $newctx->{adhoc} = {}; + foreach my $key (keys %$adhoc_backup) { + $newctx->{adhoc}->{$key} = $adhoc_backup->{$key}; + } + + my $blockstart = $oldctx->{cur_pos}; # points to '{' + my $i = $blockstart+1; # the first character we're given is '{', skip past it + for (my $curly_level=1; ($i < scalar(@$oldchars)) and ($curly_level != 0); $i++) { + if ($oldchars->[$i] eq '{') {$curly_level++;} + elsif ($oldchars->[$i] eq '}') {$curly_level--;} + } + my $blockend = $i - 1; # points to '}' + my $blocklen = $blockend - ($blockstart + 1); # the length of the text inside the block + + my @newchars = @{$oldchars}[($blockstart+1)..($blockend-1)]; + my @newline_map = @{$oldline_map}[($blockstart+1)..($blockend-1)]; + + my $orig_indent = $old_indents->[$oldline_map->[$blockstart]]; + for (my $i=0; $i < $blocklen; $i++) { + my $oldi = $blockstart+1+$i; + my $line = $newline_map[$i]; + + if ($old_indents->[$line] >= $orig_indent) { + $newctx->{text}->{indents}->[$line] = $old_indents->[$line] - $orig_indent; + } else { + $newctx->{text}->{indents}->[$line] = 0; + } + } + + $newctx->{text}->{chars} = \@newchars; + $newctx->{text}->{line_map} = \@newline_map; + $newctx->{depth}++; + $newctx->{out} = ""; + + parse($newctx); + + $oldctx->{cur_pos} = $blockend+1; + return $newctx->{out}; +} + +sub count_args { + my ($name, $args, $ctx, $num) = @_; + if ($num == -1) {return ;} + if ((scalar(@$args)) != $num) { + croak(sprintf("line %u: ~$name: I expect $num arguments, but I got %u instead.", $ctx->{current_line}, scalar(@$args))); + } +} + + +# ------------------------------------------------------------------ +# Macros go here: +# ------------------------------------------------------------------ + +sub macro_repeat { + my $args = shift; + my $num = $args->[0]; + my $text = $args->[1]; + + my $str = ""; + for (my $i=0; $i < $num; $i++) { + $str .= $text; + } + + return "{$str}"; +} + +# ~decompose(op, "0101 ab0cd mmmrrr") +sub macro_decompose { + my ($args, $ctx) = @_; + count_args("decompose", $args, $ctx, 2); + + my ($op, $input_pattern) = @$args; + my @raw = split //, $input_pattern; + my @spaceless; + foreach my $c (reverse(@raw)) { + if ($c ne " ") {push @spaceless, $c;} + } + + if (scalar(@spaceless) != 16) { + carp sprintf("line %u: ~decompose: the pattern doesn't have 16 bits (or something else is wrong with it)", $ctx->{current_line}); + } + + my $lastc = ""; + my %symbols; + for (my $i = 0; $i < scalar(@spaceless); $i++) { + my $c = $spaceless[$i]; + if (index("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", $c) != -1) { + if (exists $symbols{$c}) { + if ($lastc ne $c) { + croak sprintf("line %u: ~decompose: the pattern uses '%s' more than once", $ctx->{current_line}, $c); + } + $symbols{$c}->{len}++; + } + else { + $symbols{$c} = { + start => $i, + len => 1 + }; + } + } + + $lastc = $c; + } + + my $output = ""; + foreach my $key (keys %symbols) { + my $dat = $symbols{$key}; + my $mask = sprintf("0x%x", (2 ** $dat->{len})-1); + $output .= sprintf("const uint16_t %s = ((%s)>>%u)&%s;\n", $key, $op, $dat->{start}, $mask); + } + + return $output; +} + +# ~b(1010) == 5 +sub macro_b { + my $args = shift; + my $ctx = shift; + if (scalar(@$args) != 1) { + croak(sprintf("line %u: ~bin: ~bin() expects 1 argument, got %u", $ctx->{current_line}, scalar(@$args))); + } + my @digits; + foreach my $c (split //, $args->[0]) { + unless ($c eq ' ') { + push @digits, $c; + } + } + my $count = 0; + my $val = 0; + foreach my $c (@digits) { + if ($c eq "0") { + $val = ($val * 2); + } elsif ($c eq "1") { + $val = ($val * 2) + 1; + } else { + croak(sprintf("line %u: ~bin: non-digit in [%s]", $ctx->{current_line}, $args->[0])); + } + } + return sprintf("0x%x", $val); +} + +# ~perl({my $str="hello"; print $str; return $str;}) // causes macrophile.pl to print hello and insert "hello" into the generated file +sub macro_perl { + my ($args, $ctx) = @_; + if (scalar(@$args) != 1) { + croak(sprintf("line %u: ~perl: ~perl() expects 1 argument (preferably a block), got %u", $ctx->{current_line}, scalar(@$args))); + } + my $code = $args->[0]; + + my $_perl_return_val; + eval 'sub ___macro_perl_sub {'.$code.'} $_perl_return_val=___macro_perl_sub($args,$ctx);'; + if ($@) { + croak(sprintf("line %u: ~perl: code fragment croaked, err={%s}", $ctx->{current_line}, $@)); + } + + return $_perl_return_val; +} + +# if (~bmatch(op, 1000 xxxx 01 xxx xxx)) {...} +sub macro_bmatch { + my ($args, $ctx) = @_; + count_args("bmatch", $args, $ctx, 2); + + my $op = $args->[0]; + my $pattern_raw = $args->[1]; + + my @pattern; + foreach my $c (split '', $pattern_raw) { + if (($c eq 'x') or ($c eq '1') or ($c eq '0')) { + push @pattern, $c; + } elsif ($c ne ' ') { + croak(sprintf("line %u: ~bmatch: I hate to be picky! But there's a bogus character in this bit pattern '%s'.", $ctx->{current_line}, $c)); + } + } + if ((scalar(@pattern) != 8) and (scalar(@pattern) != 16) and (scalar(@pattern) != 32)) { + croak(sprintf("line %u: ~bmatch: The number of bits in this pattern isn't in {8,16,32} (it's %u).", $ctx->{current_line}, scalar(@pattern))); + } + + (my $count=0, my $mask_val=0, my $eq_val=0, my $mask="0x", my $eq="0x"); + foreach my $c (@pattern) { + if ($c eq '1') { + $mask_val = ($mask_val * 2) + 1; + $eq_val = ($eq_val * 2) + 1; + } elsif ($c eq '0') { + $mask_val = ($mask_val * 2) + 1; + $eq_val = ($eq_val * 2) + 0; + } else { # $c eq 'x' + $mask_val = ($mask_val * 2) + 0; + $eq_val = ($eq_val * 2) + 0; + } + $count++; + if ($count == 8) { + $mask .= sprintf("%02x", $mask_val); + $eq .= sprintf("%02x", $eq_val); + $mask_val = 0; + $eq_val = 0; + $count = 0; + } + } + return sprintf("(((%s)&%s)==%s)", $op, $mask, $eq); +} + +# ~newmacro(memcpy, 3, {return "memcpy($args->[0], $args->[1], $args->[2])";} +sub macro_newmacro { + my ($args, $ctx) = @_; + count_args("newmacro", $args, $ctx, 3); + + my ($name, $numargs, $code) = @$args; + my $sub_ref; + eval sprintf('$sub_ref = sub {my ($args, $ctx) = @_;count_args("%s", $args, $ctx, %d);%s};', $name, $numargs, $code); + if ($@) { + croak(sprintf("line %u: ~newmacro: failed to create adhoc macro: {%s}", $ctx->{current_line}, $@)); + } + + if (exists $ctx->{adhoc}->{$name}) { + carp(sprintf("line %u: ~newmacro: warning! redefining already-existing adhoc function (%s)", $ctx->{current_line}, $name)); + } + $ctx->{adhoc}->{$name} = $sub_ref; + + return ""; +} + +# ~ignore( This is a comment, the only character you can't use is the closing paren. ) +sub macro_ignore { + # ignore arguments, return empty string + return ""; +} + +# qw(word, foobar) -> {"word", "foobar"} +sub macro_qw { + my ($args, $ctx) = @_; + my $str = "{"; + + if (scalar(@$args)==0) { + return "{}"; + } + foreach my $word (@$args) { + $str .= '"'.$word.'", '; + } + + $str = substr($str, 0, -2); + $str .= "}"; + return $str; +} + +sub macro_bytes { + my ($args, $ctx) = @_; + count_args("bytes", $args, $ctx, 1); + my $input_str = $args->[0]; + + my %tab; + foreach my $c (qw(0 1 2 3 4 5 6 7 8 9 a b c d e f)) { + $tab{$c} = hex($c); + } + + # parse out each hex character (nibble) + my @nibbles; + foreach my $c (split //,$input_str) { + if (exists $tab{lc($c)}) { + push @nibbles, $tab{lc($c)}; + } + } + # if it's an empty string, just return {} + if (scalar(@nibbles) == 0) { + return "{}"; + } + # make sure we have an even number of nibbles (for bytes) + if ((scalar(@nibbles)%2)==1) { + croak("~bytes: I need an even number of hex nibbles"); + } + # concatenate them into bytes + my @bytes; + for (my $i=0; $i < scalar(@nibbles); $i+=2) { + push @bytes, (($nibbles[$i]<<4) + $nibbles[$i+1]); + } + # generate a set of hex constants, e.g. {0xde, 0xad, 0xbe, 0xef} + my $out = "{"; + foreach my $c (@bytes) { + $out .= sprintf("0x%02x, ", $c); + } + # kill the final ', ', and replace it with a '}' + $out = substr($out, 0, -2) . "}"; + return $out +} + diff --git a/core/mc68851.c b/core/mc68851.c new file mode 100644 index 0000000..338e8d2 --- /dev/null +++ b/core/mc68851.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2013, 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 +#include "../core/shoebill.h" +#include "../core/mc68851.h" + +#define verify_supervisor() {if (!sr_s()) {throw_privilege_violation(); return;}} + +extern struct dis_t dis; +extern uint16_t dis_op; + +void inst_mc68851_prestore() { + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + +void inst_mc68851_psave(){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + +void inst_mc68851_pbcc(){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + + +void inst_mc68851_pdbcc(uint16_t cond){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + +void inst_mc68851_ptrapcc(uint16_t cond){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + +void inst_mc68851_pscc(uint16_t cond){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + + +void inst_mc68851_pload(uint16_t ext){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + +void inst_mc68851_pvalid(uint16_t ext){ + printf("%s: Error, not implemented!\n", __func__); + assert(!"blowup"); +} + +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); +} + +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); + // printf("%s: Error, not implemented!\n", __func__); +} + +void inst_mc68851_pmove(uint16_t ext){ + + verify_supervisor(); + + ~decompose(shoe.op, 1111 000 000 MMMMMM); + ~decompose(ext, fff ppp w 0000 nnn 00); + + + + // instruction format #1 + if (f == ~b(010)) { + const uint8_t sizes[8] = {4, 8, 8, 8, 1, 1, 1, 2}; + + // if accessing d or a reg, and sz==8 bytes, that's bogus + if (((M>>3) < 2) && (sizes[p]==8)) { + throw_illegal_instruction(); + return ; + } + + if (!w) { // if we're reading from EA + call_ea_read(M, sizes[p]); + call_ea_read_commit(M, sizes[p]); + } + + switch (p) { + case 0: // tc + if (!w) shoe.tc = shoe.dat & 0x83FFFFFF; + else { + shoe.dat = shoe.tc; + //if (!tc_fcl()) assert(!"pmove->tc: function codes not supported\n"); + + } + break; + case 1: // drp + if (!w) shoe.drp = shoe.dat & 0xffff0203ffffffff; + else shoe.dat = shoe.drp; + break; + case 2: // srp + if (!w) shoe.srp = shoe.dat & 0xffff0203ffffffff; + else shoe.dat = shoe.srp; + break; + case 3: // crp + if (!w) shoe.crp = shoe.dat & 0xffff0203ffffffff; + else shoe.dat = shoe.crp; + break; + case 4: // cal + if (!w) shoe.cal = shoe.dat & ~b(11100000); + else shoe.dat = shoe.cal; + break; + case 5: // val + if (!w) shoe.val = shoe.dat & ~b(11100000); + else shoe.dat = shoe.val; + break; + case 6: // scc + if (!w) shoe.scc = shoe.dat; + else shoe.dat = shoe.scc; + break; + case 7: // ac + if (!w) shoe.ac = shoe.dat & ~b(0000000010110011); + else shoe.dat = shoe.ac; + break; + } + + if (w) + call_ea_write(M, sizes[p]); + return ; + } + else if (f == ~b(011)) { + if (p == 0) { // psr + if (!w) shoe.psr.word = shoe.dat & ~b(11111111 10000111); + else shoe.dat = shoe.psr.word; + } + else if (p==1) { // pcsr + if (!w) shoe.pcsr = shoe.dat; + else shoe.dat = shoe.pcsr; + } + else { + assert(!"Unknown register number for pmove format 3!\n"); + throw_illegal_instruction(); + } + + if (w) + call_ea_write(M, 2); + return ; + } + + // TODO: implement instruction formats 2 and 3 (for BAD/BAC, etc.) + assert(!"Unsupported pmove instruction format"); + throw_illegal_instruction(); +} + +static int64_t ptest_search(const uint32_t _logical_addr, const uint64_t rootp) +{ + // const uint64_t rootp = (tc_sre() && sr_s()) ? shoe.srp : shoe.crp; + uint8_t desc_level = 0; + int64_t desc_addr = -1; // address of the descriptor (-1 -> register) + uint8_t wp = 0; // Whether any descriptor in the search has wp (write protected) set + uint8_t i; + 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) + + shoe.psr.word = 0; + + desc_addr = -1; // address of the descriptor (-1 -> register) + + /* We'll keep shifting logical_addr such that its most significant bits are the next ti-index */ + uint32_t logical_addr = _logical_addr << used_bits; + + // TODO: Check limit here + + // If root descriptor is invalid, throw a bus error + if (rp_dt(rootp) == 0) { + shoe.psr.bits.b = 1; // bus error + shoe.psr.bits.n = 0; + return desc_addr; + } + + // desc is a page descriptor, skip right ahead to search_done: + if (rp_dt(rootp) == 1) + goto search_done; + + for (i=0; i < 4; i++) { // (the condition is unnecessary - just leaving it in for clarity) + // desc must be a table descriptor here + + const uint8_t ti = tc_ti(i); + used_bits += ti; + + // TODO: do the limit check here + + // Find the index into our current i-level table + const uint32_t index = logical_addr >> (32-ti); + logical_addr <<= ti; + + // load the child descriptor + if (_logical_addr == 0) + printf("Loading descriptor s=%llu from addr=0x%08x\n", desc_dt(desc, desc_size) & 1, (uint32_t)desc_table_addr(desc)); + const uint32_t table_base_addr = desc_table_addr(desc); + const uint8_t s = desc_dt(desc, desc_size) & 1; + + // desc = pget(table_base_addr + (4 << s)*index, (4 << s)); + get_desc(table_base_addr + (4 << s)*index, (4 << s)); + desc_size = s; + + // Desc may be a table descriptor, page descriptor, or indirect descriptor + + const uint8_t dt = desc_dt(desc, desc_size); + if (_logical_addr == 0) + printf("i=%u desc = 0x%llx dt=%u\n", i, desc, dt); + + // If this descriptor is invalid, throw a bus error + if (dt == 0) { + shoe.psr.bits.i = 1; // invalid + assert(desc_level <= 7); + shoe.psr.bits.n = desc_level; + return desc_addr; + } + + if (dt == 1) { + // TODO: do a limit check here + goto search_done; // it's a page descriptor + } + else if ((i==3) || (tc_ti(i+1)==0)) { + desc_size = desc_dt(desc, s) & 1; + + /* Otherwise, if this is a leaf in the tree, it's an indirect descriptor. + The size of the page descriptor is indicated by DT in the indirect descriptor. (or is it???) */ + //desc = pget(desc & 0xfffffff0, (4 << desc_size)); + get_desc(desc & 0xfffffff0, (4 << desc_size)); + + // I think it's possible for an indirect descriptor to point to an invalid descriptor... + if (desc_dt(desc, desc_size) == 0) { + shoe.psr.bits.i = 1; // invalid + assert(desc_level <= 7); + shoe.psr.bits.n = desc_level; + return desc_addr; + } + + goto search_done; + } + + // Now it must be a table descriptor + + // TODO: set the U (used) bit in this table descriptor + + wp |= desc_wp(desc, desc_size); // or in the wp flag for this table descriptor + + } + + // never get here + assert(!"translate_logical_addr: never get here"); + + +search_done: + // Desc must be a page descriptor + + // NOTE: The limit checks have been done already + + // TODO: check U (used) bit + + wp |= desc_wp(desc, desc_size); // or in the wp flag for this page descriptor + + shoe.psr.bits.w = wp; + + if (desc & (desc_size ? desc_m_long : desc_m_short)) + shoe.psr.bits.m = 1; + + assert(desc_level <= 7); + shoe.psr.bits.n = desc_level; + + return desc_addr; +} + +void inst_mc68851_ptest(uint16_t ext){ + verify_supervisor(); + + ~decompose(shoe.op, 1111 0000 00 MMMMMM); + ~decompose(ext, 100 LLL R AAAA FFFFF); // Erata in 68kPRM - F is 6 bits, and A is 3 + + assert(tc_enable()); // XXX: Throws some exception if tc_enable isn't set + assert(tc_fcl() == 0); // XXX: I can't handle function code lookups, and I don't want to + assert(L == 7); // XXX: Not currently handling searching to a particular level + + // Find the function code + uint8_t fc; + if (F>>4) // Function code is the low 4 bits of F + fc = F & 0xf; + else if ((F >> 3) == 1) // Function code is in shoe.d[F & 7] + fc = shoe.d[F & 7] & 0xf; + else if (F == 1) // Function code is SFC + fc = shoe.sfc; + else if (F == 0) // Function code is DFC + fc = shoe.dfc; + else + assert(!"ptest: unknown FC bits in instruction"); + + // Pick a root pointer based on the function code + uint64_t rootp; + if (fc == 1) + rootp = shoe.crp; + else if (fc == 5) + rootp = shoe.srp; + else { + printf("ptest: I can't handle this FC: %u pc=0x%08x\n", fc, shoe.orig_pc); + assert(!"ptest: I can't handle this FC"); + } + + call_ea_addr(M); + + const int64_t desc_addr = ptest_search(shoe.dat, rootp); + + if ((desc_addr >= 0) && (A >> 3)) { + shoe.a[A & 7] = (uint32_t)desc_addr; + } + + + + // printf("%s: Error, not implemented!\n", __func__); +} + +void dis_mc68851_prestore() { + sprintf(dis.str, "prestore"); +} + +void dis_mc68851_psave() { + sprintf(dis.str, "psave"); +} + +void dis_mc68851_pbcc() { + sprintf(dis.str, "pbcc"); +} + + +void dis_mc68851_pdbcc(uint16_t cond) { + sprintf(dis.str, "pdbcc"); +} + +void dis_mc68851_ptrapcc(uint16_t cond) { + sprintf(dis.str, "ptrapcc"); +} + +void dis_mc68851_pscc(uint16_t cond) { + sprintf(dis.str, "pscc"); +} + + +void dis_mc68851_pload(uint16_t ext) { + sprintf(dis.str, "pload"); +} + +void dis_mc68851_pvalid(uint16_t ext) { + sprintf(dis.str, "pvalid"); +} + +void dis_mc68851_pflush(uint16_t ext) { + sprintf(dis.str, "pflush"); +} + +void dis_mc68851_pmove(uint16_t ext) { + ~decompose(dis_op, 1111 000 000 MMMMMM); + ~decompose(ext, fff ppp w 0000 nnn 00); + + // instruction format #1 + if (f == ~b(010)) { + const uint8_t sizes[8] = {4, 8, 8, 8, 1, 1, 1, 2}; + char *names[8] = { + "tc", "drp", "srp", "crp", "cal", "val", "scc", "ac" + }; + + if (w) + sprintf(dis.str, "pmove %s,%s", names[p], decode_ea_rw(M, sizes[p])); + else + sprintf(dis.str, "pmove %s,%s", decode_ea_rw(M, sizes[p]), names[p]); + + return ; + } + else if (f == ~b(011)) { + char *names[8] = {"psr" , "pcsr", "?", "?", "?", "?", "?", "?"}; + if (w) + sprintf(dis.str, "pmove %s,%s", names[p], decode_ea_rw(M, 2)); + else + sprintf(dis.str, "pmove %s,%s", decode_ea_rw(M, 2), names[p]); + + return ; + } + + // TODO: implement instruction formats 2 and 3 (for BAD/BAC, etc.) + sprintf(dis.str, "pmove ???"); + +} + +void dis_mc68851_ptest(uint16_t ext) { + ~decompose(dis_op, 1111 0000 00 MMMMMM); + ~decompose(ext, 100 LLL R AAAA FFFFF); // Erata in 68kPRM - F is 6 bits, and A is 3 + + if (A >> 3) + sprintf(dis.str, "ptest%c 0x%x,%s,%u,a%u", "wr"[R], F, decode_ea_addr(M), L, A & 7); + else + sprintf(dis.str, "ptest%c 0x%x,%s,%u", "wr"[R], F, decode_ea_addr(M), L); +} + +void dis_mc68851_pflushr(uint16_t ext) { + sprintf(dis.str, "pflushr"); +} + + + + diff --git a/core/mc68851.h b/core/mc68851.h new file mode 100644 index 0000000..18229cc --- /dev/null +++ b/core/mc68851.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, 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. + */ + +// FIXME: unify all these weird instruction decoders (cpu/68881/68851) + +#ifndef _MC68851_H +#define _MC68851_H + +#include + +void inst_mc68851_prestore(); +void inst_mc68851_psave(); +void inst_mc68851_pbcc(); + +void inst_mc68851_pdbcc(uint16_t cond); +void inst_mc68851_ptrapcc(uint16_t cond); +void inst_mc68851_pscc(uint16_t cond); + +void inst_mc68851_pload(uint16_t ext); +void inst_mc68851_pvalid(uint16_t ext); +void inst_mc68851_pflush(uint16_t ext); +void inst_mc68851_pmove(uint16_t ext); +void inst_mc68851_ptest(uint16_t ext); +void inst_mc68851_pflushr(uint16_t ext); + + +void dis_mc68851_prestore(); +void dis_mc68851_psave(); +void dis_mc68851_pbcc(); + +void dis_mc68851_pdbcc(uint16_t cond); +void dis_mc68851_ptrapcc(uint16_t cond); +void dis_mc68851_pscc(uint16_t cond); + +void dis_mc68851_pload(uint16_t ext); +void dis_mc68851_pvalid(uint16_t ext); +void dis_mc68851_pflush(uint16_t ext); +void dis_mc68851_pmove(uint16_t ext); +void dis_mc68851_ptest(uint16_t ext); +void dis_mc68851_pflushr(uint16_t ext); + +#endif // _MC68851_H \ No newline at end of file diff --git a/core/mem.c b/core/mem.c new file mode 100644 index 0000000..616ac7e --- /dev/null +++ b/core/mem.c @@ -0,0 +1,1172 @@ +/* + * Copyright (c) 2013, 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 +#include +#include "../core/shoebill.h" + +static void translate_logical_addr(); + +void _logical_get (void); +void logical_get (void) { + const uint32_t addr = shoe.logical_addr; + // uint8_t super = sr_s(); + + _logical_get(); + +// if ((addr >= 0x100) && (addr < 0x2000)) { +// printf("LOMEM READ: 0x%08x = 0x%llx\n", addr, shoe.logical_dat); +// } +} + +void physical_get (void) { + + switch (shoe.physical_addr) { + case 0 ... 0x3FFFFFFF: { + void *addr = &shoe.physical_mem_base[shoe.physical_addr & (shoe.physical_mem_size-1)]; + 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> 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? + return ; + } + case 0xf0000000 ... 0xffffffff: { + 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 + return ; + } + + default: { + printf("physical_get: I got an access to 0x%x (sz=%u), but I don't know how to handle it...\n", + shoe.physical_addr, shoe.physical_size); + shoe.physical_dat = 0; + return ; + } + } +} + +void physical_set (void) +{ + switch (shoe.physical_addr) { + case 0 ... 0x3FFFFFFF: { // The first RAM bank (64MB) + const uint32_t dat = htonl(shoe.physical_dat) >> ((4-shoe.physical_size)*8); + void *addr = &shoe.physical_mem_base[shoe.physical_addr & (shoe.physical_mem_size-1)]; + 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 0x40000000 ... 0x4FFFFFFF: { // ROM + // Nothing happens when you try to modify ROM + return ; + } + case 0x50000000 ... 0x50ffffff: { // 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 0x60000000 ... 0xefffffff: { // 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); + return ; + } + case 0xf0000000 ... 0xffffffff: { // 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); + return ; + // Writing to a disconnected slot won't cause a bus error on macii + } + + default: { + printf("physical_set: I got a write (addr=0x%x) (val=0x%llx) (sz=%u), but I don't know how to handle it...\n", + shoe.physical_addr, shoe.physical_dat, shoe.physical_size); + return ; + } + } +} + +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; + + // If the the data access will wrap across multiple pages, then fuck + 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) + 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); + 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) + 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 ; + } + + 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) +{ +// if ((shoe.logical_addr >= 0x12fffff6) && (shoe.logical_addr <= 0x12ffffff)) +// printf("aux3: setting 0x%08x = 0x%x\n", shoe.logical_addr, (uint32_t)shoe.logical_dat); +// +// if ((shoe.logical_addr >= 0x100) && (shoe.logical_addr < 0x2000)) { +// printf("LOMEM WRITE: 0x%08x = 0x%x\n", shoe.logical_addr, (uint32_t) shoe.logical_dat); +// } + + // 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; + + // If the the data access will wrap across multiple pages, then fuck + 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); + */ +} + +#define PMMU_CACHE_CRP 0 +#define PMMU_CACHE_SRP 1 + +/*typedef struct { + uint32_t logical_value : 24; // At most the high 24 bits of the logical address + uint32_t used_bits : 5; + uint32_t wp : 1; // whether the page is write protected + uint32_t modified : 1; // whether the page has been modified + uint32_t unused1 : 1; + uint32_t unused2 : 8; + uint32_t physical_addr : 24; +} pmmu_cache_entry; + +struct { + pmmu_cache_entry entry[512]; + uint8_t valid_map[512 / 8]; +} pmmu_cache[2];*/ + +#define write_back_desc() { \ + if (desc_addr < 0) { \ + *rootp_ptr = desc; \ + } else { \ + pset((uint32_t)desc_addr, 4<= 4)); + + uint32_t debug_predicted = 0; + // First check for an entry in pmmu_cache + + // 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 + + // 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); + // debug_predicted = ((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 + } + + + uint64_t *rootp_ptr = (use_srp ? (&shoe.srp) : (&shoe.crp)); + const uint64_t rootp = *rootp_ptr; + uint8_t desc_did_change = 0; + uint8_t desc_level = 0; + int64_t desc_addr = -1; // address of the descriptor (-1 -> register) + uint8_t wp = 0; // Whether any descriptor in the search has wp (write protected) set + uint8_t i; + 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) + + desc_addr = -1; // address of the descriptor (-1 -> register) + + /* We'll keep shifting logical_addr such that its most significant bits are the next ti-index */ + uint32_t logical_addr = shoe.logical_addr << used_bits; + + // TODO: Check limit here + + // If root descriptor is invalid, throw a bus error + if (rp_dt(rootp) == 0) { + throw_bus_error(shoe.logical_addr, shoe.logical_is_write); + return ; + } + + // desc is a page descriptor, skip right ahead to search_done: + if (rp_dt(rootp) == 1) + goto search_done; + + for (i=0; i < 4; i++) { // (the condition is unnecessary - just leaving it in for clarity) + // desc must be a table descriptor here + + const uint8_t ti = tc_ti(i); + used_bits += ti; + + // TODO: do the limit check here + + // Find the index into our current i-level table + const uint32_t index = logical_addr >> (32-ti); + logical_addr <<= ti; + + // load the child descriptor + if (shoe.logical_addr == 0) + printf("Loading descriptor s=%llu from addr=0x%08x\n", desc_dt(desc, desc_size) & 1, (uint32_t)desc_table_addr(desc)); + const uint32_t table_base_addr = desc_table_addr(desc); + const uint8_t s = desc_dt(desc, desc_size) & 1; + + // desc = pget(table_base_addr + (4 << s)*index, (4 << s)); + get_desc(table_base_addr + (4 << s)*index, (4 << s)); + desc_size = s; + + // Desc may be a table descriptor, page descriptor, or indirect descriptor + + const uint8_t dt = desc_dt(desc, desc_size); + if (shoe.logical_addr == 0) + printf("i=%u desc = 0x%llx dt=%u\n", i, desc, dt); + + // If this descriptor is invalid, throw a bus error + if (dt == 0) { + throw_bus_error(shoe.logical_addr, shoe.logical_is_write); + return ; + } + + if (dt == 1) { + // TODO: do a limit check here + goto search_done; // it's a page descriptor + } + else if ((i==3) || (tc_ti(i+1)==0)) { + desc_size = desc_dt(desc, s) & 1; + + /* Otherwise, if this is a leaf in the tree, it's an indirect descriptor. + The size of the page descriptor is indicated by DT in the indirect descriptor. (or is it???) */ + //desc = pget(desc & 0xfffffff0, (4 << desc_size)); + get_desc(desc & 0xfffffff0, (4 << desc_size)); + + // I think it's possible for an indirect descriptor to point to an invalid descriptor... + if (desc_dt(desc, desc_size) == 0) { + throw_bus_error(shoe.logical_addr, shoe.logical_is_write); + return ; + } + + goto search_done; + } + + // Now it must be a table descriptor + + // TODO: set the U (used) bit in this table descriptor + + wp |= desc_wp(desc, desc_size); // or in the wp flag for this table descriptor + + } + + // never get here + assert(!"translate_logical_addr: never get here"); + + +search_done: + // Desc must be a page descriptor + + // NOTE: The limit checks have been done already + + // TODO: update U (used) bit + + wp |= desc_wp(desc, desc_size); // or in the wp flag for this page descriptor + + // And finally throw a bus error + if (wp && shoe.logical_is_write) { + throw_bus_error(shoe.logical_addr, shoe.logical_is_write); + return ; + } + + // If we're writing, set the modified flag + if (shoe.logical_is_write && !(desc & ( desc_size ? desc_m_long : desc_m_short ))) { + desc |= ( desc_size ? desc_m_long : desc_m_short ); + write_back_desc(); + } + + 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); + shoe.physical_addr = paddr; + + if (shoe.logical_addr == 0) { + printf("Success! desc = 0x%llx sz=%u bytes\n", desc, 4<> 8; + entry.wp = wp; + entry.modified = desc_m(desc, desc_size); + entry.used_bits = used_bits; + shoe.pmmu_cache[use_srp].entry[key] = entry; + + // if (debug_predicted) + // assert(debug_predicted == shoe.physical_addr); +} + + + +// +// EA routines begin here: +// + +#define nextword(pc) ({const uint16_t w=lget((pc),2);if (shoe.abort){return;}(pc)+=2; w;}) + +// ea_decode_extended() - find the EA for those hiddeous 68020 addr modes +static void ea_decode_extended() +{ + const uint32_t start_pc = shoe.pc; // the original PC + uint32_t mypc = start_pc; // our local PC (don't modify up the real PC) + const uint32_t ext_a = nextword(mypc); // the extension word + ~decompose(ext_a, d rrr w ss F b i zz 0 III) + + // d == index register type + // r == index register + // w == word/long-word index size + // s == scale factor + // F == extension word format (0==brief, 1==full) + // b == base register suppress + // i == index suppress + // z == base displacement size + // I == index/indirect selection + + + if (F == 0) { // If this is the brief extension word + // use the sign-extended least significant byte in the extension word + uint32_t base_disp = (int8_t)(ext_a & 0xff); + + // load the base_address + uint32_t base_addr; + if (~bmatch(shoe.mr, 00xx1xxx)) { // consult the MR, use the PC? + base_addr = start_pc; // start at the beginning of the extension word + } + else { // otherwise, it's shoe.a[shoe.mr&7] + base_addr = shoe.a[shoe.mr&7]; + } + + // load the index value + uint32_t index_val; + if (w==0) { // use signed-extended lower word of the register + if (d==0) // shoe.d[] + index_val = (int16_t)(get_d(r, 2)); + else // shoe.a[] + index_val = (int16_t)(get_a(r, 2)); + } else { // use entire register + if (d==0) index_val = shoe.d[r]; + else index_val = shoe.a[r]; + } + // Scale the index value + index_val <<= s; + + // the brief extension word is implicitly preindexed + shoe.extended_addr = base_addr + base_disp + index_val; + shoe.extended_len = mypc - start_pc; + //printf("I found address 0x%x\n", shoe.extended_addr); + return ; + } + else { // If this is a full extension word, + + // first find the base address, which may be shoe.a[?] or shoe.pc + uint32_t base_addr = 0; + if (b == 0) { // only if it isn't suppressed + if (~bmatch(shoe.mr, 00xx1xxx)) { // consult the MR, + base_addr = start_pc; // start at the beginning of the extension word + } + else { // otherwise, it's shoe.a[shoe.mr&7] + base_addr = shoe.a[shoe.mr&7]; + } + } + + // Find the index value + uint32_t index_val = 0; + if (i == 0) { // only if it isn't suppressed + if (w==0) { // use signed-extended lower word of the register + if (d==0) // shoe.d[] + index_val = (int16_t)(get_d(r, 2)); + else // shoe.a[] + index_val = (int16_t)(get_a(r, 2)); + } else { // use entire register + if (d==0) index_val = shoe.d[r]; + else index_val = shoe.a[r]; + } + // Scale the index value + index_val <<= s; + } + + // Find the base displacement + uint32_t base_disp = 0; + // ... but only if the size is > null + if (z > 1) { + 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); + } + } + + // Find the outer displacement + uint32_t outer_disp = 0; + // based on the I/IS behavior + switch ((i<<3)|I) { + case 0b0010: case 0b0110: case 0b1010: + // sign-extended word-length outer displacement + outer_disp = (int16_t)nextword(mypc); + break; + case 0b0011: case 0b0111: case 0b1011: { + // long word outer displacement + outer_disp = nextword(mypc); + outer_disp = (outer_disp<<16) | nextword(mypc); + break ; + } + } + + //printf("D/A=%u, reg=%u, W/L=%u, Scale=%u, F=%u, BS=%u, IS=%u, BDSize=%u, I/IS=%u\n", + //d, r, w, s, F, b, i, z, I); + //printf("base_addr=%x, index_val=%x, base_disp=%x, outer_disp=%x\n", + //base_addr, index_val, base_disp, outer_disp); + + // Now mash all these numbers together to get an EA + switch ((i<<3)|I) { + case 0b0001: case 0b0010: case 0b0011: + case 0b1001: case 0b1010: case 0b1011: { + // Indirect preindexed + const uint32_t intermediate = lget(base_addr + base_disp + index_val, 4); + if (shoe.abort) return ; + shoe.extended_addr = intermediate + outer_disp; + shoe.extended_len = mypc - start_pc; + // printf("addr=0x%x len=%u\n", shoe.extended_addr, shoe.extended_len); + return ; + } + + case 0b0101: case 0b0110: case 0b0111: { + // Indirect postindexed + const uint32_t intermediate = lget(base_addr + base_disp, 4); + if (shoe.abort) return ; + shoe.extended_addr = intermediate + index_val + outer_disp; + shoe.extended_len = mypc - start_pc; + return ; + } + + case 0b1000: case 0b0000: { + // No memory indirect action + // EA = base_addr + base_disp + index + shoe.extended_addr = base_addr + base_disp + index_val; + shoe.extended_len = mypc - start_pc; + return ; + } + default: + printf("ea_decode_extended: oh noes! invalid I/IS!\n"); + // I think that 68040 *doesn't* throw an exception here... + // FIXME: figure out what actually happens here + break; + } + } +} + + +void ea_read() +{ + 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 uint16_t u_disp = nextword(shoe.uncommitted_ea_read_pc); + const int16_t disp = (int16_t)u_disp; // sign-extend word to long + 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: { + 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 + //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); + 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 + 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 + const uint16_t ext = nextword(shoe.uncommitted_ea_read_pc); + if (shoe.sz==1) { + shoe.dat = ext & 0xff; + } else if (shoe.sz == 2) { + shoe.dat = ext; + } else if (shoe.sz == 4) { + const uint16_t ext2 = nextword(shoe.uncommitted_ea_read_pc); + shoe.dat = ((uint32_t)ext)<<16; + shoe.dat |= ext2; + } 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; + } + return ; + } + case 5 ... 7: { + throw_illegal_instruction(); + return ; + } + } + } + } +} + +void ea_read_commit() +{ + const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7); + switch (mode) { + case 0: { // Data register direct mode + return ; // nothing to do + } + case 1: { // address register direct mode + return ; // nothing to do + } + 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; + //printf("ea_read_commit(): %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.a[reg] -= delta; + return ; + } + case 5: { // address register indirect with displacement mode + shoe.pc += 2; // this mode fetches one word + return ; + } + case 6: { + //printf("ea_read_commit(): %u %u not implemented\n", mode, reg); + ea_decode_extended(); + if (shoe.abort) return ; + 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 ...) + ea_decode_extended(); + if (shoe.abort) return ; + shoe.pc += shoe.extended_len; + return ; + } + case 4: { // immediate data + if (shoe.sz==1) shoe.pc += 2; + else shoe.pc += shoe.sz; + return ; + } + case 5 ... 7: { + throw_illegal_instruction(); + return ; + } + } + } + } +} + +void ea_write() +{ + 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); + //set_a(reg, shoe.dat, shoe.sz); + 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: { + //printf("ea_write(): %u %u not implemented\n", mode, reg); + ea_decode_extended(); + if (shoe.abort) return ; + lset(shoe.extended_addr, shoe.sz, shoe.dat); + if (shoe.abort) return ; + shoe.pc += shoe.extended_len; + //printf("write(0x%x) = 0x%x\n", shoe.extended_addr, shoe.dat); + 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 + uint32_t addr = nextword(shoe.pc); + addr = (addr << 16) | nextword(shoe.pc); + lset(addr, shoe.sz, shoe.dat); + // printf("ea_write(): %u %u not implemented\n", mode, reg); + return ; + } + case 2: { // program counter indirect with displacement mode + printf("ea_write(): %u %u not implemented\n", mode, reg); + throw_illegal_instruction(); + return ; + } + case 3: { // (program counter ...) + printf("ea_write(): %u %u not implemented\n", mode, reg); + throw_illegal_instruction(); + return ; + } + case 4: { // immediate data + printf("ea_write(): %u %u not implemented\n", mode, reg); + throw_illegal_instruction(); + return ; + } + case 5 ... 7: { + throw_illegal_instruction(); + return ; + } + } + } + } +} + +void ea_addr() +{ + const uint8_t mode = (shoe.mr>>3)&7, reg = (shoe.mr&7); + switch (mode) { + case 0: { // Data register direct mode + // this must be invalid. Figure out which exception this throws. + printf("ea_addr(): %u %u not implemented, pc = 0x%08x\n", mode, reg, shoe.orig_pc); + return ; + } + case 1: { // address register direct mode + printf("ea_addr(): %u %u not implemented\n", mode, reg); + // this must be invalid. Figure out which exception this throws. + return ; + } + case 2: { // address register indirect mode + shoe.dat = shoe.a[reg]; + return ; + } + case 3: { // address register indirect with postincrement mode + printf("ea_addr(): %u %u not implemented\n", mode, reg); + return ; + } + case 4: { // address register indirect with predecrement mode + printf("ea_addr(): %u %u not implemented\n", mode, 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: { + // printf("ea_addr(): %u %u not implemented\n", mode, reg); + ea_decode_extended(); + if (shoe.abort) return ; + shoe.dat = shoe.extended_addr; + 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 + uint32_t addr = (nextword(shoe.pc)) << 16; + addr |= (nextword(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 ; + } + case 4: { // immediate data + printf("ea_addr(): %u %u not implemented, pc = 0x%08x\n", mode, reg, shoe.orig_pc); + return ; + } + case 5 ... 7: { + throw_illegal_instruction(); + return ; + } + } + } + } +} + + + + + + + + + + + + + + + diff --git a/core/redblack.c b/core/redblack.c new file mode 100644 index 0000000..059da52 --- /dev/null +++ b/core/redblack.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2013, 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 "shoebill.h" +#include "redblack.h" + +// Create a new red-black tree +// (just return an empty black leaf pointer) +rb_tree* rb_new() +{ + return calloc(sizeof(rb_tree), 1); +} + +// Insert a new key/value into the tree +// (and return the old value if *old_value is non-null.) +// Returns true if the key already existed. +uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old_value) +{ + // Special edge case: insert the root node if tree's empty + if (*root == NULL) { + *root = calloc(sizeof(rb_node), 1); + (*root)->key = key; + (*root)->value = value; + return 0; + } + + // traverse + rb_node **cur = root, *parent = NULL; + while (*cur) { + parent = *cur; + if (key < (*cur)->key) // left + cur = &((*cur)->left); + else if (key > (*cur)->key) // right + cur = &((*cur)->right); + else { // the key already exists + if (old_value) + *old_value = (*cur)->value; + (*cur)->value = value; + return 1; // 1 => the key already existed + } + } + + // insert + *cur = calloc(sizeof(rb_node), 1); + (*cur)->parent = parent; + (*cur)->key = key; + (*cur)->value = value; + (*cur)->is_red = 1; + + // resolve + + rb_node *red = *cur; + while (red) { + rb_node *parent = red->parent; + if (red->is_red == 0) // if this node isn't actually red, return + break; + else if (!parent) // if this is the root node, return + break; + else if (!parent->is_red) // if the parent is black, then we're done. + break; + + // otherwise, the parent is red - the grandparent must exist, and must be black + assert((red->parent->parent) && (!red->parent->parent->is_red)); + + rb_node *gparent = parent->parent; + rb_node *uncle = (gparent->left==parent)?gparent->right:gparent->left; + + // 8 cases: + // LLr LRr RLr RRr (uncle is red) + if (uncle && (uncle->is_red)) { + uncle->is_red = 0; + parent->is_red = 0; + gparent->is_red = 1; + red = gparent; + continue ; + } + + // uncle is black + + rb_node **gparent_ptr; + if (gparent->parent) { // great-grandparent exists + rb_node *ggparent = gparent->parent; + gparent_ptr = (ggparent->left==gparent)? (&ggparent->left) : (&ggparent->right); + } else { // grandparent is root + gparent_ptr = root; + } + + uint8_t mycase = ((gparent->left==parent)?0:1); + mycase = (mycase << 1) | ((parent->left==red)?0:1); + switch (mycase) { + + case 0: {// LLb + rb_node *Br = parent->right; + *gparent_ptr = parent; + parent->right = gparent; + gparent->left = Br; + parent->is_red = 0; + gparent->is_red = 1; + + parent->parent = gparent->parent; + gparent->parent = parent; + if (Br) Br->parent = gparent; + + red = gparent->right; // gparent became red, gparent->left is black, check gparent->right + break ; + } + case 1: {// LRb + rb_node *Cl = red->left; + rb_node *Cr = red->right; + *gparent_ptr = red; + red->left = parent; + red->right = gparent; + parent->right = Cl; + gparent->left = Cr; + red->is_red = 0; + gparent->is_red = 1; + + red->parent = gparent->parent; + parent->parent = red; + gparent->parent = red; + if (Cl) Cl->parent = parent; + if (Cr) Cr->parent = gparent; + + red = gparent->right; + break ; + } + case 2: { // RLb + rb_node *Cr = red->right, *Cl = red->left; + *gparent_ptr = red; + red->left = gparent; + red->right = parent; + gparent->right = Cl; + parent->left = Cr; + red->is_red = 0; + gparent->is_red = 1; + + + red->parent = gparent->parent; + gparent->parent = red; + parent->parent = red; + if (Cr) Cr->parent = parent; + if (Cl) Cl->parent = gparent; + + red = gparent->left; + break; + } + case 3: { // RRb + rb_node *Bl = parent->left; + *gparent_ptr = parent; + parent->left = gparent; + gparent->right = Bl; + parent->is_red = 0; + gparent->is_red = 1; + + parent->parent = gparent->parent; + gparent->parent = parent; + if (Bl) Bl->parent = gparent; + + red = gparent->left; + break; + } + } + } + + (*root)->is_red = 0; // make double-sure root is red + return 0; +} + +// Find a value given a key +uint8_t rb_find (rb_tree *tree, rb_key_t key, rb_value_t *value) +{ + rb_node *cur = *tree; + + while (cur) { + if (key < cur->key) + cur = cur->left; + else if (key > cur->key) + cur = cur->right; + else { + if (value) + *value = cur->value; + return 1; + } + } + return 0; +} + +uint8_t _rb_index (rb_node *cur, uint32_t *index, rb_node **result) +{ + if (!cur) + return 0; + + else if (_rb_index(cur->left, index, result) == 1) + return 1; + + else if (0 == *index) { + *result = cur; + return 1; + } + --*index; + + return _rb_index(cur->right, index, result); +} + +// Do an in-order traversal, and retrieve the (index)th sorted key/value +uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, rb_value_t *value) +{ + rb_node *cur = *tree, *result; + if (_rb_index(cur, &index, &result)) { + if (key) *key = result->key; + if (value) *value = result->value; + return 1; + } + return 0; +} + +// Count the number of nodes in the tree +uint32_t rb_count (rb_tree *tree) +{ + rb_node *node = *tree; + if (!node) + return 0; + return 1 + rb_count(&node->left) + rb_count(&node->right); +} + +void _rb_free (rb_node *node) +{ + if (!node) return ; + _rb_free(node->right); + if (node->right) free(node->right); + _rb_free(node->left); + if (node->left) free(node->left); +} + +// Free all the nodes (and the rb_tree ptr itself) +void rb_free (rb_tree *tree) +{ + _rb_free(*tree); + free(*tree); + free(tree); +} + diff --git a/core/redblack.h b/core/redblack.h new file mode 100644 index 0000000..d91e520 --- /dev/null +++ b/core/redblack.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef _REDBLACK_H +#define _REDBLACK_H + +typedef uint32_t rb_key_t; +typedef void* rb_value_t; + +typedef struct _rb_node { + struct _rb_node *left, *right, *parent; + rb_key_t key; + rb_value_t value; + uint8_t is_red : 1; +} rb_node; + +typedef rb_node* rb_tree; + + +rb_tree* rb_new(); +void rb_free (rb_tree *tree); + +uint8_t rb_insert (rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old_value); +uint8_t rb_find (rb_tree *tree, rb_key_t key, rb_value_t *value); +uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, rb_value_t *value); +uint32_t rb_count (rb_tree *tree); + +#endif // _REDBLACK_H \ No newline at end of file diff --git a/core/scsi.c b/core/scsi.c new file mode 100644 index 0000000..1b40b03 --- /dev/null +++ b/core/scsi.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2013, 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 +#include "shoebill.h" + +// Target command register bits +#define TARGET_COMM_LAST_BYTE_SENT (1<<7) +#define TARGET_COMM_ASSERT_REQ (1<<3) +#define TARGET_COMM_ASSERT_MSG (1<<2) +#define TARGET_COMM_ASSERT_CD (1<<1) +#define TARGET_COMM_ASSERT_IO (1<<0) + +// Initiator command register bits +#define INIT_COMM_ASSERT_RST (1<<7) +#define INIT_COMM_TEST_MODE (1<<6) // write-only +#define INIT_COMM_ARBITRATION_IN_PROGRESS (1<<6) // read-only +#define INIT_COMM_LOST_ARBITRATION (1<<5) // read-only +#define INIT_COMM_ASSERT_ACK (1<<4) +#define INIT_COMM_ASSERT_BSY (1<<3) +#define INIT_COMM_ASSERT_SEL (1<<2) +#define INIT_COMM_ASSERT_ATN (1<<1) +#define INIT_COMM_ASSERT_DATA_BUS (1<<0) + +// Current scsi control register bits +#define CURR_SCSI_CONTROL_RST (1<<7) +#define CURR_SCSI_CONTROL_BSY (1<<6) +#define CURR_SCSI_CONTROL_REQ (1<<5) +#define CURR_SCSI_CONTROL_MSG (1<<4) +#define CURR_SCSI_CONTROL_CD (1<<3) +#define CURR_SCSI_CONTROL_IO (1<<2) +#define CURR_SCSI_CONTROL_SEL (1<<1) +#define CURR_SCSI_CONTROL_PARITY (1<<0) + +// Bus and status register bits +#define BUS_STATUS_ACK (1<<0) +#define BUS_STATUS_ATN (1<<1) +#define BUS_STATUS_BUSY_ERROR (1<<2) +#define BUS_STATUS_PHASE_MATCH (1<<3) +#define BUS_STATUS_INTERRUPT_REQUEST_ACTIVE (1<<4) +#define BUS_STATUS_PARITY_ERROR (1<<5) +#define BUS_STATUS_DMA_REQUEST (1<<6) +#define BUS_STATUS_END_OF_DMA (1<<7) + +// Mode register bits +#define MODE_BLOCK_MODE_DMA (1<<7) +#define MODE_TARGET_MODE (1<<6) +#define MODE_ENABLE_PARITY_CHECKING (1<<5) +#define MODE_ENABLE_PARITY_INTERRUPT (1<<4) +#define MODE_ENABLE_EOP_INTERRUPT (1<<3) +#define MODE_MONITOR_BUSY (1<<2) +#define MODE_DMA_MODE (1<<1) +#define MODE_ARBITRATE (1<<0) + +// Invalid scsi device ID +#define INVALID_ID 8 + +const char *scsi_read_reg_str[8] = { + "current_scsi_data_bus", + "initiator_command", + "mode", + "target_command", + "current_scsi_control", + "bus_and_status", + "input_data", + "reset_interrupt" +}; + +const char *scsi_write_reg_str[8] = { + "output_data", + "initiator_command", + "mode", + "target_command", + "id_select", + "start_dma_send", + "start_dma_target_receive", + "start_dma_initiator_receive" +}; + +enum scsi_bus_phase { + BUS_FREE = 0, + ARBITRATION, + SELECTION, + RESELECTION, + COMMAND, + DATA_OUT, + DATA_IN, + STATUS, + MESSAGE_IN, + MESSAGE_OUT +}; + +typedef struct { + // Phase + enum scsi_bus_phase phase; + + // Scsi bus signals + + uint8_t init_bsy:1; // BSY, driven by initiator + uint8_t target_bsy:1; // BSY, driven by target + + uint8_t sel:1; // SEL, driven by both target and initiator + + uint8_t rst:1; // RST, driven by both target and initiator + + uint8_t cd:1; // C/D (control or data), driven by target + uint8_t io:1; // I/O, driven by target + uint8_t ack:1; // ACK, driven by initiator + uint8_t msg:1; // MSG, driven by target + uint8_t atn:1; // ATN, driven by initiator + uint8_t req:1; // REQ, driven by target + + uint8_t data; // DB0-7, data lines, driven by both target and initiator + + // NCR 5380 registers + uint8_t initiator_command; + uint8_t mode; + uint8_t target_command; + uint8_t select_enable; // probably not implementing this... + + // Arbitration state + uint8_t init_id; // initiator ID (as a bit mask) (usually 0x80) + + // Selection state + uint8_t target_id; // target ID (as an int [0, 7]) + + // transfer buffers + uint8_t buf[512 * 64]; + uint32_t bufi; + uint32_t in_len, in_i; + uint32_t out_len, out_i; + uint32_t write_offset; + uint8_t status_byte; + uint8_t message_byte; // only one-byte messages supported for now + + // hack + uint8_t dma_send_written; // Gets set whenever register 5 (start_dma_send) is written to, and cleared randomly. + // This is because aux 1.1.1 sends an extra byte after sending the write command, and that's not + // part of the write data. start_dma_send will be written when the data is actually starting. + uint8_t sent_status_byte_via_reg0; // Gets set when the status byte is red via register 0. + // This lets us know it's safe to switch to the MESSAGE_IN phase + +} scsi_bus_state_t; + +scsi_bus_state_t scsi; + +static void switch_status_phase (uint8_t status_byte) +{ + + printf("scsi_reg_something: switching to STATUS phase\n"); + + scsi.phase = STATUS; + scsi.status_byte = status_byte; + scsi.msg = 0; + scsi.cd = 1; + scsi.io = 1; + + scsi.bufi = 0; + + // Phase mismatch (I think) + via_raise_interrupt(2, 0); +} + +static void switch_command_phase (void) +{ + printf("scsi_reg_something: switching to COMMAND phase\n"); + scsi.phase = COMMAND; + + scsi.msg = 0; + scsi.cd = 1; + scsi.io = 0; + + scsi.bufi = 0; + + // Phase mismatch, probably + via_raise_interrupt(2, 0); +} + +static void switch_message_in_phase (uint8_t message_byte) +{ + printf("scsi_reg_something: switching to MESSAGE_IN phase\n"); + + scsi.phase = MESSAGE_IN; + scsi.msg = 1; + scsi.cd = 1; + scsi.io = 1; + + scsi.message_byte = message_byte; // only one-byte messages supported for now + + // Phase mismatch, probably + via_raise_interrupt(2, 0); +} + +static void switch_bus_free_phase (void) +{ + printf("scsi_reg_something: switching to BUS_FREE phase\n"); + + scsi.phase = BUS_FREE; + + scsi.msg = 0; + scsi.cd = 0; + scsi.io = 0; + + scsi.target_bsy = 0; + scsi.req = 0; + + scsi.bufi = 0; + // Phase mismatch not possible here. +} + +static void switch_data_in_phase (void) +{ + printf("scsi_reg_something: switching to DATA_IN phase\n"); + + scsi.phase = DATA_IN; + + scsi.msg = 0; + scsi.cd = 0; + scsi.io = 1; + + // Phase mismatch, probably + via_raise_interrupt(2, 0); +} + +static void switch_data_out_phase (void) +{ + printf("scsi_reg_something: switching to DATA_OUT phase\n"); + + scsi.phase = DATA_OUT; + + scsi.msg = 0; + scsi.cd = 0; + scsi.io = 0; + + via_raise_interrupt(2, 0); +} + +struct inquiry_response_t { + uint8_t periph_device_type:5; + uint8_t periph_qualifier:3; + + uint8_t device_type_modifier:7; + uint8_t rmb:1; + + uint8_t ansi_vers:3; + uint8_t ecma_vers:3; + uint8_t iso_vers:2; + + uint8_t resp_format:4; + uint8_t unused_1:2; + uint8_t trmiop:1; + uint8_t anec:1; + + uint8_t additional_length; + + uint8_t unused_2; + uint8_t unused_3; + + uint8_t sftre:1; + uint8_t cmdque:1; + uint8_t unused_4:1; + uint8_t linked:1; + uint8_t sync:1; + uint8_t wbus16:1; + uint8_t wbus32:1; + uint8_t reladr:1; + + uint8_t vendor_id[8]; + uint8_t product_id[16]; + uint8_t product_rev[4]; +}; + +static void scsi_handle_inquiry_command(const uint8_t alloc_len) +{ + struct inquiry_response_t resp; + + assert(alloc_len >= 6); + + memset(&resp, 0, sizeof(struct inquiry_response_t)); + + resp.periph_qualifier = 0; // I'm connected to the specified LUN (sure, whatever) + resp.periph_device_type = 0; // 0 -> direct access device (hard disk) + + resp.rmb = 0; // not removable + resp.device_type_modifier = 0; // Vendor-specific + + resp.ansi_vers = 1; // complies with ANSI X3.131-1986 (SCSI-1) + resp.ecma_vers = 1; // whatever + resp.iso_vers = 1; // whatever + + resp.anec = 0; // only applies to "processor" devices + resp.trmiop = 0; // we don't support TERMINATE I/O PROCESS, whatever that is + resp.resp_format = 0; // SCSI-1 INQUIRY response format + + resp.additional_length = 0; // no additional parameters + + resp.reladr = 0; // don't support relative addressing + resp.wbus16 = 0; // these must be SCSI-2 things. (I'm looking at the ANSI SCSI-2 docs) + resp.wbus32 = 0; + resp.sync = 0; // don't support synchronous transfer + resp.cmdque = 0; // don't support tagged command queuing + resp.linked = 0; // don't support linked commands + resp.sftre = 0; // don't support soft reset + + memcpy(resp.vendor_id, "Shoebill", 8); + strcpy((char*)resp.product_id, "Phony SCSI disk"); + memcpy(resp.product_rev, "fded", 4); + + // XXX: added this because A/UX 3.0.1 requsts 6 bytes of the the inquiry response (sometimes?) I think it's polling for all attached scsi devices. + // Fixme: figure out how to respond "not attached" + if (alloc_len > sizeof(resp)) + scsi.in_len = sizeof(resp); + else + scsi.in_len = alloc_len; + memcpy(scsi.buf, &resp, scsi.in_len); + scsi.in_i = 0; + + switch_data_in_phase(); +} + +static void scsi_buf_set (uint8_t byte) +{ + assert(scsi.bufi <= sizeof(scsi.buf)); + scsi.buf[scsi.bufi++] = byte; + + if (scsi.phase == COMMAND) { + const uint32_t cmd_len = (scsi.buf[0] >= 0x20) ? 10 : 6; // 10 or 6 byte command? + + assert(scsi.target_id < 8); + scsi_device_t *dev = &shoe.scsi_devices[scsi.target_id]; + + // If we need more data for this command, keep driving REQ + if (scsi.bufi < cmd_len) { + // scsi.req = 1; + // FIXME: keep driving DMA_REQUEST too + return ; + } + + switch (scsi.buf[0]) { + case 0: // test unit ready (6) + printf("scsi_buf_set: responding to test-unit-ready\n"); + switch_status_phase(0); // switch to the status phase, with a status byte of 0 + break; + + case 0x15: // mode select (6) + printf("scsi_buf_set: responding to mode-select\n"); + switch_status_phase(0); + break; + + case 0x25: // read capacity (10) + printf("scsi_buf_set: responding to read-capacity\n"); + // bytes [0,3] -> BE number of blocks + scsi.buf[0] = (dev->num_blocks >> 24) & 0xff; + scsi.buf[1] = (dev->num_blocks >> 16) & 0xff; + scsi.buf[2] = (dev->num_blocks >> 8) & 0xff; + scsi.buf[3] = (dev->num_blocks) & 0xff; + + // bytes [4,7] -> BE block size (needs to be 512) + + scsi.buf[4] = (dev->block_size >> 24) & 0xff; + scsi.buf[5] = (dev->block_size >> 16) & 0xff; + scsi.buf[6] = (dev->block_size >> 8) & 0xff; + scsi.buf[7] = (dev->block_size) & 0xff; + + scsi.in_i = 0; + scsi.in_len = 8; + + switch_data_in_phase(); + break; + + case 0x12: { // inquiry command (6) + printf("scsi_buf_set: responding to inquiry\n"); + const uint8_t alloc_len = scsi.buf[4]; + + scsi_handle_inquiry_command(alloc_len); + break; + } + + case 0x8: { // read (6) + const uint32_t offset = + (scsi.buf[1] << 16) | + (scsi.buf[2] << 8 ) | + (scsi.buf[3]); + const uint8_t len = scsi.buf[4]; + + assert(dev->f); + + printf("scsi_buf_set: Responding to read at off=%u len=%u\n", offset, len); + + assert(len <= 64); + + assert(dev->num_blocks > offset); + + 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; + + switch_data_in_phase(); + break; + } + + case 0xa: { // write (6) + const uint32_t offset = + (scsi.buf[1] << 16) | + (scsi.buf[2] << 8 ) | + (scsi.buf[3]); + const uint8_t len = scsi.buf[4]; + + printf("scsi_buf_set: Responding to write at off=%u len=%u\n", offset, len); + + assert(len <= 64); + + scsi.write_offset = offset; + scsi.out_len = len * 512; + scsi.out_i = 0; + + scsi.dma_send_written = 0; // reset here. The real data will come in after start_dma_send is written to. + switch_data_out_phase(); + break; + } + + default: + assert(!"unknown commmand!"); + break; + } + + scsi.bufi = 0; + } +} + +void init_scsi_bus_state () +{ + memset(&scsi, 0, sizeof(scsi_bus_state_t)); + + scsi.phase = BUS_FREE; +} + +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); + + switch (reg) { + case 0: // Current scsi data bus register + if (scsi.phase == ARBITRATION) + shoe.physical_dat = 0; // I don't know why A/UX expects 0 here. It should be the initiator's ID, I think + else if (scsi.phase == MESSAGE_IN) { + shoe.physical_dat = scsi.message_byte; // one-byte messages supported for now + } + else if (scsi.phase == STATUS) { + shoe.physical_dat = scsi.status_byte; + scsi.sent_status_byte_via_reg0 = 1; + } + else + assert(!"scsi_reg_read: reading data reg (0) from unknown phase\n"); + + break; + + case 1: // Initiator command register + + if (scsi.phase == ARBITRATION && + (scsi.initiator_command & INIT_COMM_ARBITRATION_IN_PROGRESS)) { + + shoe.physical_dat = scsi.initiator_command; + + // the INIT_COMM_ARBITRATION_IN_PROGRESS bit is transient. Just clear + // it after the first access (it needs to go hi, then later low) + scsi.initiator_command &= ~INIT_COMM_ARBITRATION_IN_PROGRESS; + + } + else + shoe.physical_dat = scsi.initiator_command; + + break; + + case 2: // Mode register + shoe.physical_dat = scsi.mode; + break; + + case 3: // Target command register + shoe.physical_dat = scsi.target_command & 0xf; // only the low 4 bits are significant + break; + + case 4: { // Current SCSI control register + uint8_t tmp = 0; + tmp |= (scsi.sel * CURR_SCSI_CONTROL_SEL); + tmp |= (scsi.io * CURR_SCSI_CONTROL_IO); + tmp |= (scsi.cd * CURR_SCSI_CONTROL_CD); + tmp |= (scsi.msg * CURR_SCSI_CONTROL_MSG); + tmp |= (scsi.req * CURR_SCSI_CONTROL_REQ); + tmp |= ((scsi.target_bsy || scsi.init_bsy) ? CURR_SCSI_CONTROL_BSY : 0); + tmp |= (scsi.rst * CURR_SCSI_CONTROL_RST); + shoe.physical_dat = tmp; + break; + } + + case 5: { // Bus and status register + uint8_t tmp = 0; + + // Compute phase match (IO, CD, MSG match the assertions in target_command register) + uint8_t phase_tmp = 0; + { + phase_tmp = (phase_tmp << 1) | scsi.msg; + phase_tmp = (phase_tmp << 1) | scsi.cd; + phase_tmp = (phase_tmp << 1) | scsi.io; + phase_tmp = (phase_tmp == (scsi.target_command & 7)); + } + + tmp |= (scsi.ack * BUS_STATUS_ACK); + tmp |= (scsi.atn * BUS_STATUS_ATN); + tmp |= (phase_tmp * BUS_STATUS_PHASE_MATCH); + + // let's just say BUS_ERROR is always false (fixme: wrong) + // let's just say INTERRUPT_REQUEST_ACTIVE is always false (fixme: wrong) + // let's just say PARITY_ERROR is always false + tmp |= BUS_STATUS_DMA_REQUEST; // let's just say DMA_REQUEST is always true (fixme: wrong) + shoe.physical_dat = tmp; + break; + } + + case 6: // Input data register + shoe.physical_dat = 0; + break; + + case 7: // Reset error / Interrupt register + shoe.physical_dat = 0; + break; + } + + printf("(set to 0x%02x)\n\n", (uint32_t)shoe.physical_dat); +} + +void scsi_reg_write () +{ + const uint32_t reg = ((shoe.physical_addr & 0xffff) >> 4) & 0xf; + const uint8_t dat = shoe.physical_dat & 0xff; + + switch (reg) { + case 0: // Output data register + scsi.data = dat; + break; + + case 1: { // Initiator command register + scsi.initiator_command = dat; + + scsi.ack = ((scsi.initiator_command & INIT_COMM_ASSERT_ACK) != 0); + scsi.rst = ((scsi.initiator_command & INIT_COMM_ASSERT_RST) != 0); + scsi.init_bsy = ((scsi.initiator_command & INIT_COMM_ASSERT_BSY) != 0); + scsi.sel = ((scsi.initiator_command & INIT_COMM_ASSERT_SEL) != 0); + scsi.atn = ((scsi.initiator_command & INIT_COMM_ASSERT_ATN) != 0); + +/* +// --- Arbitration --- + // Check whether to switch from ARBITRATION to SELECTION + if (scsi.sel && scsi.phase == ARBITRATION) { + // Asserting SEL in arbitration phase means we switch to selection phase :) + scsi.phase = SELECTION; + scsi.target_id = INVALID_ID; // invalid ID + printf("scsi_reg_write: selection phase\n"); + break; + } +*/ +// --- Selection --- + // If we're in SELECTION, receive the target_id from scsi.data + if (scsi.sel && (scsi.initiator_command & INIT_COMM_ASSERT_DATA_BUS) && + ((scsi.phase == ARBITRATION) || (scsi.phase == BUS_FREE))) + { + uint8_t id; + for (id=0; (id < 8) && !(scsi.data & (1 << id)); id++) ; + assert(id != 8); + scsi.target_id = id; + printf("scsi_reg_write: selected target id %u\n", id); + scsi.target_bsy = 1; // target asserts BSY to acknowledge being selected + scsi.phase = SELECTION; + break; + } + + // SELECTION ends when SEL gets unset + if (!scsi.sel && scsi.phase == SELECTION) { + printf("scsi_reg_write: switch to COMMAND phase\n"); // what's next? + + scsi.req = 1; // target asserts REQ after initiator deasserts SEL + + // Switch to COMMAND phase + scsi.cd = 1; + scsi.io = 0; + scsi.msg = 0; + scsi.phase = COMMAND; + break; + } + +// --- Information transfer --- + // If initiator asserts ACK, then target needs to deassert REQ + // (I think this only makes sense for non-arbitration/selection/busfree situations + if ((scsi.phase != BUS_FREE) && (scsi.phase != ARBITRATION) && (scsi.phase != SELECTION)) { + + // If this is the message_in phase, use the unsetting-ACK portion of the REQ/ACK handshake + // to go to BUS_FREE. + // Don't bother asserting REQ here. Also, switch_bus_free_phase() will deassert target_BSY. + if (scsi.phase == MESSAGE_IN && !scsi.ack && !scsi.req) { + switch_bus_free_phase(); + break ; + } + // If the status byte was read through register 0, then we need to manually switch to + // message_in phase when the initiator sets ACK + // Do this when the OS deasserts ACK. We know that ACK was previously asserted if !REQ. + // (This is kinda hacky - maybe I can detect if ACK is deasserted by looking at the + // previous value of reg1) + else if (scsi.phase == STATUS && !scsi.ack && !scsi.req && scsi.sent_status_byte_via_reg0) { + scsi.req = 1; + switch_message_in_phase(0); + } + else { + scsi.req = !scsi.ack; + } + } + + break; + } + + case 2: { // Mode register + scsi.mode = dat; + + if (scsi.mode & MODE_ARBITRATE) { + printf("scsi_reg_write: arbitration phase\n"); + scsi.phase = ARBITRATION; + scsi.initiator_command |= INIT_COMM_ARBITRATION_IN_PROGRESS; + } + else { + + } + + break; + } + case 3: // Target command register + scsi.target_command = dat & 0xf; // only the bottom 4 bits are writable + break; + + case 4: // ID select register + scsi.select_enable = dat; + break; + + case 5: // Start DMA send + scsi.dma_send_written = 1; + via_raise_interrupt(2, 0); + break; + + case 6: // Start DMA target receive + break; + + case 7: // Start DMA initiator receive + via_raise_interrupt(2, 0); + break; + } + + printf("\nscsi_reg_write: writing to register %s(%u) (0x%x)\n\n", scsi_write_reg_str[reg], reg, dat); +} + +void scsi_dma_write_long(const uint32_t dat) +{ + scsi_dma_write((dat >> 24) & 0xff); + scsi_dma_write((dat >> 16) & 0xff); + scsi_dma_write((dat >> 8 ) & 0xff); + scsi_dma_write(dat & 0xff); +} + +void scsi_dma_write (const uint8_t byte) +{ + if (scsi.phase == COMMAND) { + printf("scsi_reg_dma_write: writing COMMAND byte 0x%02x\n", byte); + scsi_buf_set(byte); + } + else if (scsi.phase == DATA_OUT && scsi.dma_send_written) { + scsi.buf[scsi.out_i++] = byte; + + //printf("scsi_reg_dma_write: writing DATA_OUT byte 0x%02x (%c)\n", byte, isprint(byte)?byte:'.'); + + if (scsi.out_i >= scsi.out_len) { + assert(scsi.target_id < 8); + scsi_device_t *dev = &shoe.scsi_devices[scsi.target_id]; + assert(dev->f); + + assert(0 == fseeko(dev->f, 512 * scsi.write_offset, SEEK_SET)); + assert(fwrite(scsi.buf, scsi.out_len, 1, dev->f) == 1); + fflush(dev->f); + + scsi.out_i = 0; + scsi.out_len = 0; + switch_status_phase(0); + } + } + else if (scsi.phase == DATA_OUT) { + printf("scsi_reg_dma_write: writing DATA_OUT byte (without scsi.dma_send_written) 0x%02x\n", byte); + } + else { + printf("scsi_reg_dma_write: writing 0x%02x in UNKNOWN PHASE!\n", byte); + } + +} + +uint32_t scsi_dma_read_long() +{ + uint32_t i, result = 0; + + for (i=0; i<4; i++) { + result = (result << 8) + scsi_dma_read(); + } + + return result; +} + +uint8_t scsi_dma_read () +{ + uint8_t result = 0; + + if (scsi.phase == STATUS) { + // If in the STATUS phase, return the status byte and switch back to COMMAND phase + result = scsi.status_byte; + switch_message_in_phase(0); + } + else if (scsi.phase == DATA_IN) { + assert(scsi.in_len > 0); + result = scsi.buf[scsi.in_i++]; + if (scsi.in_i >= scsi.in_len) { + scsi.in_i = 0; + scsi.in_len = 0; + + switch_status_phase(0); + } + } + + //printf("scsi_reg_dma_read: called, returning 0x%02x\n", (uint8_t)result); + + return result; +} diff --git a/core/shoebill.h b/core/shoebill.h new file mode 100644 index 0000000..9f2a800 --- /dev/null +++ b/core/shoebill.h @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2013, 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. + */ + +#ifndef _SHOEBILL_H +#define _SHOEBILL_H + +#include +#include +#include +#include + +#include "coff.h" + +// -- Global constants -- + + // bit manipulation + #define bitchop(v, s) ({const uint32_t _v = (v), _s = 32 - (s); (_v << _s) >> _s;}) + // #define bitchop(v, s) ((v) & (0xffffffff>>(32-(s)))) + #define bitchop_64(v, s) ({const uint64_t _v = (v); const uint32_t _s = 64 - (s); (_v << _s) >> _s;}) + // #define bitchop_64(v, s) ((v) & (0xffffffffffffffff>>(64-(s)))) + #define chop(v, s) bitchop_64((v), (s)*8) + #define mib(v, s) (((v)>>((s)*8-1))&1) + + #define lrot32(v, r) (uint32_t)(((((uint64_t)(v))<<(r)) | (((uint64_t)(v))>>(32-(r))))) + #define rrot32(v, r) lrot32((v), 32-(r)) + + + // set register + #define set_reg__(reg, val, s) do { \ + const uint32_t mask_v=(0xffffffff)>>(8*(4-(s))), mask_r=~mask_v; \ + (reg) = ((reg)&mask_r) | ((val)&mask_v);\ + } while (0) + #define get_reg__(reg, s) chop(reg, s) + + #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) + #define sr_v() ((shoe.sr>>1)&1) + #define sr_z() ((shoe.sr>>2)&1) + #define sr_n() ((shoe.sr>>3)&1) + #define sr_x() ((shoe.sr>>4)&1) + #define sr_mask() ((shoe.sr>>8)&7) + #define sr_m() ((shoe.sr>>12)&1) + #define sr_s() ((shoe.sr>>13)&1) + #define sr_t0() ((shoe.sr>>14)&1) + #define sr_t1() ((shoe.sr>>15)&1) + + // a7 can actually point to isp, msp, or usp, depending on bits in the status register. + // So every time we modify those bits, save a7 to the correct internal register. + #define make_stack_pointers_valid() { \ + if (sr_s() && sr_m()) \ + shoe.msp = shoe.a[7]; \ + else if (sr_s()) \ + shoe.isp = shoe.a[7]; \ + else \ + shoe.usp = shoe.a[7]; \ + } + + // Load the correct stack pointer into a7 based on bits in sr + #define load_stack_pointer() { \ + if (sr_s() && sr_m()) \ + shoe.a[7] = shoe.msp; \ + else if (sr_s()) \ + shoe.a[7] = shoe.isp; \ + else \ + shoe.a[7] = shoe.usp; \ + } + + // set the status register, swapping a7 if necessary + #define set_sr(newsr) { \ + make_stack_pointers_valid(); \ + 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);} + // 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();} + #define set_sr_t0(b) {shoe.sr &= (~(1<<14)); shoe.sr |= (((b)!=0)<<14);} + #define set_sr_t1(b) {shoe.sr &= (~(1<<15)); shoe.sr |= (((b)!=0)<<15);} + + // MMU + #define tc_enable() (shoe.tc >> 31) + #define tc_sre() ((shoe.tc >> 25) & 1) + #define tc_fcl() ((shoe.tc >> 24) & 1) + #define tc_ps() ((shoe.tc >> 20) & 0xf) + #define tc_is() ((shoe.tc >> 16) & 0xf) + #define tc_tia() ((shoe.tc >> 12) & 0xf) + #define tc_tib() ((shoe.tc >> 8) & 0xf) + #define tc_tic() ((shoe.tc >> 4) & 0xf) + #define tc_tid() (shoe.tc & 0xf) + #define tc_ti(n) ((shoe.tc >> ((3-(n))*4)) & 0xf) + + #define rp_lu(x) ((uint32_t)(((x) >> 63) & 1)) + #define rp_limit(x) ((uint32_t)(((x) >> 48) & 0x7fff)) + #define rp_sg(x) ((uint32_t)(((x) >> 41) & 1)) + #define rp_dt(x) ((uint32_t)(((x) >> 32) & 3)) + #define rp_addr(x) ((uint32_t)(((x) >> 0) & 0xfffffff0)) + + // misc + #define ea_n(s) ((shoe.dat>>((s)*8-1))&1) + #define ea_z(s) ((shoe.dat&((0xffffffff)>>(8*(4-(s)))))==0) + +typedef struct dbg_breakpoint_t { + struct dbg_breakpoint_t *next; + uint32_t addr; + uint64_t num; +} dbg_breakpoint_t; + +struct dbg_state_t { + EditLine *el; + uint8_t running; + uint64_t breakpoint_counter; + dbg_breakpoint_t *breakpoints; +}; +extern struct dbg_state_t dbg_state; + +typedef enum { + adb_talk, + adb_listen, + adb_reset, + adb_flush +} adb_command_type_t; + +typedef struct { + adb_command_type_t command_type; + + uint8_t command_byte; // The command byte passed in during state 0 + uint8_t command_device_id; // the device id in the command byte + uint8_t command_reg; // the register in the command byte + + uint8_t service_request, timeout; + uint16_t pending_service_requests; + uint8_t pending_poll; + uint8_t poll; // a poll is in progress + + + uint8_t state; // State machine state (0 => host send command, 1 => even byte, 2 => odd byte, 3 => idle + uint8_t data_i, data_len; + uint8_t data[8]; + + pthread_mutex_t lock; + +} adb_state_t; + +typedef struct { + uint8_t ifr, ier, rega, regb, ddrb, ddra, sr; +} via_state_t; + +typedef struct { + uint8_t scsi_id; + uint32_t num_blocks, block_size; + FILE *f; + const char *image_path; +} scsi_device_t; + +#define KEYBOARD_STATE_MAX_KEYS 128 +typedef struct { + struct { + uint8_t code_a, code_b; + } keys[KEYBOARD_STATE_MAX_KEYS]; + + int down_modifiers; // Modifiers that we've already told the OS are down (shift, ctrl, + uint32_t key_i; + uint8_t last_modifier_mask; +} keyboard_state_t; + +typedef struct { + int32_t old_x, old_y; + int32_t delta_x, delta_y; + uint8_t button_down; + uint8_t changed; +} mouse_state_t; + +typedef struct { + uint8_t *buf_base; + uint32_t buf_size; + + uint32_t h_offset; // offset in bytes for each horizontal line + + uint8_t vsync; + + // unit8_t via_interrupt_flag; + + uint8_t depth; + uint8_t clut[256 * 3]; + uint32_t clut_idx; + +} video_state_t; + +typedef struct { + // lsb==phase0, msb==L7 + uint8_t latch; + + // Registers + uint8_t data, status, mode, handshake; +} 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); + void *ctx; + uint8_t slotnum, connected, interrupts_enabled; + int32_t glut_window_id; + long double interrupt_rate, last_fired; +} nubus_card_t; + +typedef struct { + uint32_t logical_value : 24; // At most the high 24 bits of the logical address + uint32_t used_bits : 5; + uint32_t wp : 1; // whether the page is write protected + uint32_t modified : 1; // whether the page has been modified + uint32_t unused1 : 1; + uint32_t unused2 : 8; + uint32_t physical_addr : 24; +} pmmu_cache_entry_t; + +typedef struct { + uint64_t emu_start_time; + struct timeval last_60hz_tick; // for via1 ca1 + +} via_clock_t; + +typedef struct { + +#define SHOEBILL_STATE_STOPPED (1<<9) +#define SHOEBILL_STATE_SWITCH_MODE (1<<10) + + // bits 0-6 are CPU interrupt priorities + // bit 8 indicates that STOP was called + volatile uint32_t cpu_thread_notifications; + + pthread_mutex_t cpu_thread_lock; + pthread_mutex_t via_clock_thread_lock; + pthread_mutex_t cpu_freeze_lock; + +#define CPU_MODE_FAST 0 +#define CPU_MODE_DEBUG 1 +#define CPU_MODE_STEPI 2 +#define CPU_MODE_STEPI_COMPLETE 3 +#define CPU_MODE_FREEZE 4 + uint32_t cpu_mode; + + // -- PMMU caching structures --- + struct { + pmmu_cache_entry_t entry[512]; + uint8_t valid_map[512 / 8]; + } pmmu_cache[2]; + + // -- Assorted CPU state variables -- + uint16_t op; // the first word of the instruction we're currently running + uint16_t orig_sr; // the sr before we began executing the instruction + uint32_t orig_pc; // the address of the instruction we're currently running + uint16_t exception; + uint16_t abort; + uint32_t suppress_exceptions; + + // -- Physical memory -- + uint8_t *physical_mem_base; + uint32_t physical_mem_size; + uint8_t *physical_rom_base; + uint32_t physical_rom_size; + + uint32_t physical_size; // <- Size of transfer + uint32_t logical_size; // <- Size of transfer + uint32_t physical_addr; // <- Address for physical reads/writes + uint32_t logical_addr; // <- Address for logical reads/writes + uint64_t physical_dat; // <- Data for physical fetches is put/stored here + uint64_t logical_dat; // <- Data for logical fetches is put/stored here + + uint8_t logical_is_write; // <- boolean: true iff the operation is logical_set() + uint8_t logical_fc; // logical function code + + // -- Interrupts/VIA chips -- + + // uint8_t stopped; // whether STOP was called + // uint8_t pending_interrupt; // (0 -> no pending interrupt, >0 -> interrupt priority (autovector)) + via_state_t via[2]; + adb_state_t adb; + keyboard_state_t key; + mouse_state_t mouse; + iwm_state_t iwm; + + nubus_card_t slots[16]; + // video_state_t video; + + // -- Registers -- + uint32_t d[8]; + uint32_t a[8]; + uint32_t pc; + + uint32_t vbr; // vector base register + uint32_t sfc; // source function code + uint32_t dfc; // destination function code + uint32_t cacr; // cache control register + + uint32_t usp; // user stack pointer + uint32_t isp; // interrupt stack pointer + uint32_t msp; // master stack pointer + + uint16_t sr; // status register (use a macro to modify sr!) + + // 68851 registers + uint64_t crp, srp, drp; // user/supervisor/DMA root pointers + uint32_t tc; // translation control + uint16_t pcsr; // PMMU cache status + uint16_t ac; // access control + uint16_t bad[8]; // breakpoint acknowledge data registers + uint16_t bac[8]; // breakpoint acknowledge control registers + uint8_t cal; // current access level + uint8_t val; // validate access level + uint8_t scc; // stack change control + union { + uint16_t word; + struct { + uint16_t n : 3; // number-of-levels + uint16_t unused : 4; // (zeroed out) + uint16_t c : 1; // globally shared + uint16_t g : 1; // gate + uint16_t m : 1; // modified + uint16_t i : 1; // invalid + uint16_t w : 1; // write-protected + uint16_t a : 1; // access level violation + uint16_t s : 1; // supervisor-only + uint16_t l : 1; // limit violation + uint16_t b : 1; // bus error + } bits; + } psr; + + // FPU registers + uint32_t fpiar; // FPU iaddr + + union { // fpcr, fpu control register + struct { + // Mode control byte + uint16_t mc_zero : 4; // zero/dummy + uint16_t mc_rnd : 2; // rounding mode + uint16_t mc_prec : 2; // rounding precision + // Exception enable byte + uint16_t ee_inex1 : 1; // inexact decimal input + uint16_t ee_inex2 : 1; // inxact operation + uint16_t ee_dz : 1; // divide by zero + uint16_t ee_unfl : 1; // underflow + uint16_t ee_ovfl : 1; // overflow + uint16_t ee_operr : 1; // operand error + uint16_t ee_snan : 1; // signalling not a number + uint16_t ee_bsun : 1; // branch/set on unordered + } b; + + uint16_t raw; + } fpcr; + + union { // fpsr, fpu status register + struct { + // Accrued exception byte + uint32_t dummy1 : 3; // dummy/zero + uint32_t ae_inex : 1; // inexact + uint32_t ae_dz : 1; // divide by zero + uint32_t ae_unfl : 1; // underflow + uint32_t ae_ovfl : 1; // overflow + uint32_t ae_iop : 1; // invalid operation + // Exception status byte + uint32_t es_inex1 : 1; // inexact decimal input + uint32_t es_inex2 : 1; // inxact operation + uint32_t es_dz : 1; // divide by zero + uint32_t es_unfl : 1; // underflow + uint32_t es_ovfl : 1; // overflow + uint32_t es_operr : 1; // operand error + uint32_t es_snan : 1; // signalling not a number + uint32_t es_bsun : 1; // branch/set on unordered + // Quotient byte + uint32_t qu_quotient : 7; + uint32_t qu_s : 1; + // Condition code byte + uint32_t cc_nan : 1; // not a number + uint32_t cc_i : 1; // infinity + uint32_t cc_z : 1; // zero + uint32_t cc_n : 1; // negative + uint32_t dummy2 : 4; // dummy/zero + } b; + uint32_t raw; + } fpsr; + + long double fp[8]; // 80 bit floating point general registers + + + // -- EA state -- + uint32_t uncommitted_ea_read_pc; // set by ea_read(). It's the PC that ea_read_commit will set. + uint64_t dat; // the raw input/output for the transaction + uint32_t extended_addr; // EA returned by ea_decode_extended() + uint32_t extended_len; // number of instruction bytes used by ea_decode_extended() + uint8_t sz; // the size of the EA transaction + uint8_t mr; // a 6-bit mode/reg pair + + via_clock_t via_clocks; + + uint32_t dbg; + + struct timeval start_time; // when the emulator started (for computing timer interrupts) + uint64_t total_ticks; // how many 60hz ticks have been generated + + coff_file *coff; // Data/symbols from the unix kernel + + coff_file *launch; // FIXME: delete me: coff symbols from aux 1.1.1 launch binary + + scsi_device_t scsi_devices[8]; // SCSI devices +} global_shoebill_context_t; + +extern global_shoebill_context_t shoe; // declared in cpu.c + +// fpu.c functions +void inst_fpu_decode(void); +void dis_fpu_decode(void); +void fpu_setup_jump_table(); + +// cpu.c fuctions +void cpu_step (void); +inline void inst_decode (void); + +// exception.c functions + +void throw_bus_error(uint32_t addr, uint8_t is_write); +void throw_long_bus_error(uint32_t addr, uint8_t is_write); +void throw_address_error(); +void throw_illegal_instruction(); +void throw_privilege_violation(); +void throw_divide_by_zero(); +void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32_t orig_pc); + + +// mem.c functions + +void inline physical_get (void); +#define pget(addr, s) ({shoe.physical_addr=(addr); shoe.physical_size=(s); physical_get(); shoe.physical_dat;}) + +void inline logical_get (void); +#define lget_fc(addr, s, fc) ({ \ + shoe.logical_addr=(addr); \ + shoe.logical_size=(s); \ + shoe.logical_fc = (fc); \ + logical_get(); \ + shoe.logical_dat; \ +}) + +#define lget(addr, s) ({ \ + shoe.logical_addr=(addr); \ + shoe.logical_size=(s); \ + shoe.logical_fc = (sr_s() ? 5 : 1); \ + logical_get(); \ + shoe.logical_dat; \ +}) + +void inline physical_set (void); +#define pset(addr, s, val) {shoe.physical_addr=(addr); shoe.physical_size=(s); shoe.physical_dat=(val); physical_set();} + +void inline logical_set (void); +#define lset_fc(addr, s, val, fc) {\ + shoe.logical_addr=(addr); \ + shoe.logical_size=(s); \ + shoe.logical_dat=(val); \ + shoe.logical_fc = (fc); \ + logical_set();\ +} +#define lset(addr, s, val) { \ + lset_fc((addr), (s), (val), sr_s() ? 5 : 1) \ +} + + +void ea_read(); +void ea_read_commit(); +void ea_write(); +void ea_addr(); + +#define call_ea_read(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read();if (shoe.abort) return;} +#define call_ea_write(M, s) {shoe.mr=(M);shoe.sz=(s);ea_write();if (shoe.abort) return;} +#define call_ea_read_commit(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read_commit();if (shoe.abort) return;} +#define call_ea_addr(M) {shoe.mr=(M);ea_addr();if (shoe.abort) return;} + +#define push_a7(_dat, _sz) {shoe.a[7]-=(_sz);lset(shoe.a[7], (_sz), (_dat));} + +// 68851 MMU stuff + +#define desc_dt(d,s) (((d) >> (32 * (s))) & 3) +#define desc_table_addr(d) ((uint32_t)((d) & 0xFFFFFFF0)) +#define desc_page_addr(d) ((uint32_t)((d) & 0xffffff00)) +#define desc_wp(d,s) ((((d) >> (32 * (s))) >> 2) & 1) +#define desc_m(d,s) ((((d) >> (32 * (s))) >> 4) & 1) + +#define desc_m_long (((uint64_t)1) << 36) +#define desc_m_short (((uint64_t)1) << 4) + +#define get_desc(_addr, _size) { \ + desc = pget((_addr), (_size)); \ + desc_addr = (_addr); \ + desc_level++; \ +} +// if (shoe.dbg) \ +// printf("desc_addr *0x%08x = 0x%llx\n", (uint32_t)(_addr), desc); \ +// } + + +// dis.c functions +void disassemble_inst(uint8_t binary[24], uint32_t orig_pc, char *str, uint32_t *instlen); +char* decode_ea_rw (uint8_t mr, uint8_t sz); +char* decode_ea_addr (uint8_t mr); +inline void dis_decode(void); +uint16_t dis_next_word (void); +char* decode_ea_addr (uint8_t mr); +char* decode_ea_rw (uint8_t mr, uint8_t sz); +struct dis_t { + // static + uint8_t binary[24]; // raw instruction (up to 24 bytes) + uint32_t orig_pc; // the PC when disassemble_inst() was called + + // volatile + char ea_str_internal[1024]; // data for storing decoded ea strings (ring buffer) + uint32_t ea_last_pos_internal; + uint32_t pos; // the current computed length of the instruction + + // return + char *str; // the final returned string +}; + +// IWM / floppy +uint8_t iwm_dma_read(); +void iwm_dma_write(); + +// ncr5380 (scsi) +void scsi_reg_read(); +void scsi_reg_write(); +uint8_t scsi_dma_read(); +uint32_t scsi_dma_read_long(); +void scsi_dma_write(uint8_t byte); +void scsi_dma_write_long(uint32_t dat); + +// via1 & via2 (+ CPU interrupts) +void check_time(); +void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit); +void process_pending_interrupt(); +void via_reg_read(); +void via_reg_write(); +void *via_clock_thread(void *arg); + +// VIA registers +#define VIA_ORB 0 +#define VIA_ORA 1 +#define VIA_DDRB 2 +#define VIA_DDRA 3 +#define VIA_T1C_LO 4 +#define VIA_T1C_HI 5 +#define VIA_T1L_LO 6 +#define VIA_T1L_HI 7 +#define VIA_T2C_LO 8 +#define VIA_T2C_HI 9 +#define VIA_SR 10 +#define VIA_ACR 11 +#define VIA_PCR 12 +#define VIA_IFR 13 +#define VIA_IER 14 +#define VIA_ORA_AUX 15 + +// IFR interrupt bits +#define IFR_CA2 0 +#define IFR_CA1 1 +#define IFR_SHIFT_REG 2 +#define IFR_CB2 3 +#define IFR_CB1 4 +#define IFR_TIMER1 5 +#define IFR_TIMER2 6 +#define IFR_IRQ 7 + +// adb / keyboard / mouse stuff + +void adb_handle_state_change(uint8_t old_state, uint8_t new_state); +void adb_request_service_request(uint8_t id); + +extern const char *atrap_names[4096]; + +struct macii_rom_symbols_t { + uint32_t addr; + const char *name; +}; +extern const struct macii_rom_symbols_t macii_rom_symbols[]; + +// Emulated Toby Frame Buffer nubus card +void nubus_tfb_init(uint8_t slotnum); +uint32_t nubus_tfb_read_func(uint32_t, uint32_t, uint8_t); +void nubus_tfb_write_func(uint32_t, uint32_t, uint32_t, uint8_t); + +// Shoebill Virtual Video Card +void nubus_video_init(void *_ctx, uint8_t slotnum, + uint16_t width, uint16_t height, uint16_t scanline_width, + double refresh_rate); + +uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size, + const uint8_t slotnum); +void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size, + const uint32_t data, const uint8_t slotnum); + + +#endif // _SHOEBILL_H diff --git a/core/toby_frame_buffer.c b/core/toby_frame_buffer.c new file mode 100644 index 0000000..5ed25e7 --- /dev/null +++ b/core/toby_frame_buffer.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2013, 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 +#include "shoebill.h" + +#define ROM_SIZE 4096 + +uint8_t macii_video_rom[ROM_SIZE] = { + /* + * Redacted! + * But if you own a toby frame buffer card, you + * can dump its 4kb ROM and stick it here. + * A/UX 1, 2 and 3 seem happy with this hacky + * implementation. + */ +}; + +typedef struct { + uint8_t *buf_base; + uint32_t buf_size; + uint32_t clut_idx; + uint32_t h_offset; // offset in bytes for each horizontal line + uint8_t clut[256 * 3]; + uint8_t depth; + uint8_t vsync; + + uint8_t *gldat; +} tfb_ctx_t; + + +void nubus_tfb_display_func (void) +{ + uint32_t myw = glutGet(GLUT_WINDOW_WIDTH); + uint32_t myh = glutGet(GLUT_WINDOW_HEIGHT); + uint32_t slotnum, i; + int32_t my_window_id = glutGetWindow(); + + for (slotnum = 0; slotnum < 16; slotnum++) + if (shoe.slots[slotnum].glut_window_id == my_window_id) + break; + + tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx; + + const uint8_t depth = ctx->depth; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, myw, 0, myh, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.1, 0.1, 0.8); + + uint32_t gli = 0; + for (i=0; i < (1024 * 480);) { + uint8_t code; + + if (i % 1024 == 640) { + i += (1024 - 640); + continue; + } + + assert(gli < (640 * 480)); + + if (depth <= 1) { + code = (ctx->buf_base[ctx->h_offset + i/8] & (0x80 >> (i % 8))) != 0; + code = (code << 7) | 0x7f; + } + else if (depth == 2) { + const uint8_t byte = ctx->buf_base[ctx->h_offset + i/4]; + const uint8_t mod = i % 4; + code = (byte << (mod * 2)) & 0xc0; + code |= 0x3f; + } + else if (depth == 4) { + const uint8_t byte = ctx->buf_base[ctx->h_offset + i/2]; + const uint8_t mod = i % 2; + code = (byte << (mod * 4)) & 0xf0; + code |= 0x0f; + } + else if (depth == 8) { + code = ctx->buf_base[ctx->h_offset + i]; + } + + ctx->gldat[gli * 3 + 0] = ctx->clut[code * 3 + 2]; + ctx->gldat[gli * 3 + 1] = ctx->clut[code * 3 + 1]; + ctx->gldat[gli * 3 + 2] = ctx->clut[code * 3 + 0]; + + gli++; + i++; + } + + glViewport(0, 0, myw, myh); + glRasterPos2i(0, myh); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glPixelZoom(1.0, -1.0); + + glDrawPixels(myw, myh, GL_RGB, GL_UNSIGNED_BYTE, ctx->gldat); + + glFlush(); +} + +void global_mouse_func (int button, int state, int x, int y); +void global_motion_func (int x, int y); +void global_passive_motion_func (int x, int y); +void global_keyboard_up_func (unsigned char c, int x, int y); +void global_keyboard_down_func (unsigned char c, int x, int y); +void global_special_up_func (int special, int x, int y); +void global_special_down_func (int special, int x, int y); + +void nubus_tfb_init(uint8_t slotnum) +{ + tfb_ctx_t *ctx = (tfb_ctx_t*)calloc(sizeof(tfb_ctx_t), 1); + + ctx->buf_size = 512 * 1024; + ctx->buf_base = (uint8_t*)calloc(ctx->buf_size, 1); + ctx->depth = 1; + ctx->clut_idx = 786; + ctx->gldat = valloc(480 * 640 * 3); + + memset(ctx->clut, 0x0, 384); + memset(ctx->clut+384, 0xff, 384); + memset(ctx->buf_base, 0xff, ctx->buf_size); + + shoe.slots[slotnum].ctx = ctx; + + glutInitWindowSize(640, 480); + shoe.slots[slotnum].glut_window_id = glutCreateWindow(""); + glutDisplayFunc(nubus_tfb_display_func); + + glutIgnoreKeyRepeat(1); + glutKeyboardFunc(global_keyboard_down_func); + glutKeyboardUpFunc(global_keyboard_up_func); + + glutSpecialFunc(global_special_down_func); + glutSpecialUpFunc(global_special_up_func); + + glutMouseFunc(global_mouse_func); + glutMotionFunc(global_motion_func); + glutPassiveMotionFunc(global_passive_motion_func); + + glShadeModel(GL_FLAT); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glClearColor(0.1, 1.0, 0.1, 1.0); +} + +uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const uint8_t slotnum) +{ + // 1111 nnnn xxxx rrrr SSSSSSSS SSSSSSxx + // n -> slot number + // S -> significant bits + // x -> ignored + // region -> + // 0000-0111(?) - framebuffer + // 1000 + // 1001 + // 1010 + // 1011 + // 1100 + // 1101 + // 1110 + // 1111 = ROM (repeating 4kb images in S bits) + tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx; + + const uint32_t addr = rawaddr & 0x000fffff; + uint32_t result = 0; + + switch (addr >> 16) { + case 0x0 ... 0x7: { // frame buffer + uint32_t i; + for (i=0; ibuf_base[addr + i]; + break; + } + + case 0xf: { // rom + if ((addr & 3) == 0) { + const uint32_t rom_addr = (addr >> 2) % 4096; + result = macii_video_rom[rom_addr]; + printf("nubus_tfb_read_func: returning %x for addr %x (rom_addr=%x)\n", (uint32_t)result, shoe.physical_addr, rom_addr); + } + else + result = 0; + break; + } + + case 0xd: { // vsync registers + // 0xd0000 = ReadVSync + // 0xd0004, d0008 = ?? + if (addr == 0xd0000) { + ctx->vsync++; + result = (ctx->vsync >> 7)&1; + printf("nubus_tfb_read_func: reading vsync bit shoe.pc=0x%08x\n", shoe.orig_pc); + // We just need to oscillate the vsync bit, to pretend we're going in and out of the blanking interval. + // The card driver waits until the bit goes low, then waits until it goes high + // FIXME: clean this up + break; + } + else { + printf("nubus_tfb_read_func: unknown read of *0x%08x\n", shoe.physical_addr); + result = 0; + break; + } + } + + default: { + printf("nubus_tfb_read_func: unknown read of *0x%08x\n", shoe.physical_addr); + result = 0; + break; + } + } + + return result; +} + +void nubus_tfb_write_func(const uint32_t rawaddr, const uint32_t size, + const uint32_t data, const uint8_t slotnum) +{ + tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx; + const uint32_t addr = rawaddr & 0x000fffff; + + switch (addr >> 16) { + + case 0x0 ... 0x7: { // frame buffer + uint32_t i; + for (i=0; ibuf_base[addr + size - (i+1)] = (data >> (8*i)) & 0xFF; + } + return ; + } + + case 0x8: { // other registers + + if (addr == 0x80000) { // some register that seems to indicate the color depth + const uint8_t val = data & 0xff; + if (val == 0xdf) + ctx->depth = 1; + else if (val == 0xbf) + ctx->depth = 2; + else if (val == 0x7f) + ctx->depth = 4; + else if (val == 0xff) + ctx->depth = 8; + else + assert(!"Can't figure out the color depth!"); + return ; + } + + if (addr == 0x8000c) { // horizontal offset + ctx->h_offset = 4 * ((~data) & 0xff); + return ; + } + else { + printf("video_nubus_set: unknown write to *0x%08x (0x%x)\n", shoe.physical_addr, data); + return ; + } + } + + case 0x9: { // CLUT registers? + if (addr == 0x90018) { // CLUT + printf("clut[0x%03x (0x%02x+%u)] = 0x%02x\n", ctx->clut_idx, ctx->clut_idx/3, ctx->clut_idx%3, (uint8_t)(data & 0xff)); + ctx->clut[ctx->clut_idx] = 255 - (data & 0xff); + + ctx->clut_idx = (ctx->clut_idx == 0) ? 767 : ctx->clut_idx-1; + + return ; + } + + if (addr == 0x9001c) { // CLUT register? + const uint32_t clut_dat = data & 0xff; + + ctx->clut_idx = clut_dat * 3 + 2; + + } + printf("video_nubus_set: unknown write to *0x%08x (0x%x)\n", shoe.physical_addr, data); + return ; + } + + case 0xa: { // clear interrupt for slot 0xa(?) in via2.rega (by setting the appropriate bit) + assert((data & 0xff) == 0); + // shoe.via[1].rega |= 0b00000010; + shoe.via[1].rega |= (1 << (slotnum - 9)); + return ; + } + + default: { + printf("video_nubus_set: unknown write to *0x%08x (0x%x)\n", shoe.physical_addr, data); + return ; + } + } +} diff --git a/core/via.c b/core/via.c new file mode 100644 index 0000000..582e7b9 --- /dev/null +++ b/core/via.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2013, 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 +#include +#include +#include "../core/shoebill.h" + +char *via_reg_str[16] = { + "orb", + "ora", + "ddrb", + "ddra", + "t1c-l", + "t1c-h", + "t1l-l", + "t1l-h", + "t2c-l", + "t2c-h", + "sr", + "acr", + "pcr", + "ifr", + "ier", + "ora15" +}; + +#define set_pending_interrupt(pri) ({ \ + shoe.cpu_thread_notifications |= (1<<(pri)); \ +}) + +// Have a VIA chip raise an interrupt +void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit) +{ + assert((vianum == 1) || (vianum == 2)); + + via_state_t *via = &shoe.via[vianum - 1]; + // Always set the bit in ifr (I think) + via->ifr |= (1 << ifr_bit); + + // Only if the bit is enabled in IER do we raise a cpu interrupt + if (via->ier & (1 << ifr_bit)) + set_pending_interrupt(vianum); + else + printf("didn't set pending interrupt\n"); +} + + +void process_pending_interrupt () +{ + // FIXME: address errors on lget() here aren't handled + + uint32_t i; + const uint8_t pending_interrupt = shoe.cpu_thread_notifications & 0xff; + uint8_t priority; + + // Find the highest-priority pending interrupt, if any + + if (pending_interrupt == 0) + return ; + else if (pending_interrupt & (1<<7)) + priority = 7; + else { + for (priority=6; priority > 0; priority--) { + if (pending_interrupt & (1< adb FSM state +// e -> adb timeout occurred / service request (?) +// f/g/h nvram stuff + +#define VIA_REGB_DONE 8 + +// VIA registers +#define VIA_ORB 0 +#define VIA_ORA 1 +#define VIA_DDRB 2 +#define VIA_DDRA 3 +#define VIA_T1C_LO 4 +#define VIA_T1C_HI 5 +#define VIA_T1L_LO 6 +#define VIA_T1L_HI 7 +#define VIA_T2C_LO 8 +#define VIA_T2C_HI 9 +#define VIA_SR 10 +#define VIA_ACR 11 +#define VIA_PCR 12 +#define VIA_IFR 13 +#define VIA_IER 14 +#define VIA_ORA_AUX 15 + +uint16_t counter; + +void via_reg_read () +{ + const uint8_t vianum = (shoe.physical_addr >= 0x50002000) ? 2 : 1; + const uint8_t reg = (shoe.physical_addr >> 9) & 15; + via_state_t *via = &shoe.via[vianum - 1]; + + printf("via_reg_read: reading from via%u reg %s (%u)\n", vianum, via_reg_str[reg], reg); + + switch (reg) { + case VIA_IER: + // According to the eratta, bit 7 is always set during a read + shoe.physical_dat = via->ier | 0x80; + break ; + case VIA_IFR: { + // Figure out whether any enabled interrupts are set, and set IRQ accordingly + const uint8_t irq = (via->ifr & via->ier & 0x7f) ? 0x80 : 0x0; + shoe.physical_dat = (via->ifr & 0x7f) | irq; + break ; + } + + case VIA_SR: + shoe.physical_dat = via->sr; + break; + + case VIA_ORB: + shoe.physical_dat = via->regb; + break; + + case VIA_ORA_AUX: + case VIA_ORA: + //if ((vianum==2) && !(via->ifr & (1<rega = 0x3f; + shoe.physical_dat = via->rega; + break; + + case VIA_DDRB: + shoe.physical_dat = via->ddrb; + break; + + case VIA_DDRA: + shoe.physical_dat = via->ddra; + break; + + case VIA_T2C_LO: + // XXX: A/UX 3.0.1 tries to precisely time a huge dbra loop + // using via timer2. It won't accept any result shorter than + // 0x492, and hypothetically, this emulator could execute the + // loop faster than that (although not currently). So this is + // a super dumb hack that always returns a delta-t of 0x492 + // between sequential reads from t2c. + // (oh, also, a/ux 3.0.1 cleverly reads from both t2c_lo and _hi + // simultaneously by doing a word-size read at VIA+0x11ff) + counter -= 0x492; + shoe.physical_dat = 0xffff & ((counter >> 8) | (counter << 8)); + break; + + default: + printf("via_reg_read: (unhandled!)\n"); + break; + } +} + +void via_reg_write() +{ + const uint8_t vianum = (shoe.physical_addr >= 0x50002000) ? 2 : 1; + const uint8_t reg = (shoe.physical_addr >> 9) & 15; + const uint8_t data = (uint8_t)shoe.physical_dat; + via_state_t *via = &shoe.via[vianum - 1]; + + printf("via_reg_write: writing 0x%02x to via%u reg %s (%u)\n", (uint8_t)shoe.physical_dat, vianum, via_reg_str[reg], reg); + + switch (reg) { + case VIA_IER: { + const uint8_t bits = data & 0x7f; + if (data >> 7) // if we're setting these bits + via->ier |= bits; + else // else, unsetting them + via->ier &= ~~bits; + + // Raise a cpu-interrupt if any via interrupts are newly enabled + if (via->ier & via->ifr & 0x7f) + set_pending_interrupt(vianum); + + break ; + } + case VIA_IFR: + // clear the specified bits + via->ifr &= ~~data; + + break ; + + case VIA_SR: + via->sr = data; + break; + + case VIA_ORB: { + via->regb = data; + + if (vianum == 1) { + const uint8_t adb_state = (data >> 4) & 3; + if (shoe.adb.state != adb_state) { + const uint8_t old_state = shoe.adb.state; + shoe.adb.state = adb_state; + + adb_handle_state_change(old_state, adb_state); + } + } + + break; + } + + case VIA_ORA_AUX: + case VIA_ORA: + via->rega = data; + break; + + case VIA_DDRB: + via->ddrb = data; + break; + + case VIA_DDRA: + via->ddra = data; + break; + + default: + printf("via_reg_read: (unhandled!)\n"); + break; + } +} + +// FIXME: check_time() is bad and needs rewritten +void check_time() +{ + struct timeval now, delta_tv; + const uint32_t hz = 10; + + // return ; + + gettimeofday(&now, NULL); + + delta_tv.tv_sec = now.tv_sec - shoe.start_time.tv_sec; + if (now.tv_usec < shoe.start_time.tv_usec) { + delta_tv.tv_sec--; + delta_tv.tv_usec = (now.tv_usec + 1000000) - shoe.start_time.tv_usec; + } + else + delta_tv.tv_usec = now.tv_usec - shoe.start_time.tv_usec; + + uint64_t delta = delta_tv.tv_sec * 1000; + delta += delta_tv.tv_usec / 1000; + + uint64_t ticks = delta / hz; + if (ticks <= shoe.total_ticks) + return ; + + shoe.total_ticks = ticks; + //printf("ticks = %llu\n", ticks); + + via_raise_interrupt(1, IFR_CA1); + // + shoe.via[1].rega = 0b00111101; + via_raise_interrupt(2, IFR_CA1); +} + +static long double _now (void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + + long double secs = tv.tv_sec; + long double usecs = tv.tv_usec; + + return secs + (usecs / 1000000.0); +} + +#define fire(s) ({assert((s) >= 0); if (earliest_next_timer > (s)) earliest_next_timer = (s);}) +void *via_clock_thread(void *arg) +{ + pthread_mutex_lock(&shoe.via_clock_thread_lock); + + const long double start_time = _now(); + uint64_t ca1_ticks = 0, ca2_ticks = 0; + uint32_t i; + + while (1) { + const long double now = _now(); + + long double earliest_next_timer = 1.0; + + // Check whether the 60.15hz timer should fire (via1 CA1) + const uint64_t expected_ca1_ticks = ((now - start_time) * 60.15L); + if (expected_ca1_ticks > ca1_ticks) { + // Figure out when the timer should fire next + const long double next_firing = (1.0L/60.15L) - fmodl(now - start_time, 1.0L/60.15L); + fire(next_firing); + + ca1_ticks = expected_ca1_ticks; + + // Raise VIA1 CA1 + via_raise_interrupt(1, IFR_CA1); + } + + // Check whether the 1hz timer should fire (via1 CA2) + const uint64_t expected_ca2_ticks = now - start_time; + if (expected_ca2_ticks > ca2_ticks) { + const long double next_firing = 1.0L - fmodl(now - start_time, 1.0L); + fire(next_firing); + + ca2_ticks = expected_ca2_ticks; + + via_raise_interrupt(1, IFR_CA2); + + /*via_raise_interrupt(1, IFR_TIMER1); + via_raise_interrupt(1, IFR_TIMER2); + via_raise_interrupt(2, IFR_TIMER1); + via_raise_interrupt(2, IFR_TIMER2);*/ + } + + // Check if any nubus cards have interrupt timers + for (i=9; i<15; i++) { + if (!shoe.slots[i].connected) + continue; + + if (now >= (shoe.slots[i].last_fired + (1.0L/shoe.slots[i].interrupt_rate))) { + shoe.slots[i].last_fired = now; + + fire(1.0L/shoe.slots[i].interrupt_rate); + + if (shoe.slots[i].interrupts_enabled) { + shoe.via[1].rega = 0b00111111 & ~~(1<<(i-9)); + via_raise_interrupt(2, IFR_CA1); + printf("Fired nubus interrupt %u\n", i); + } + } + } + + + + + usleep((useconds_t)(earliest_next_timer * 1000000.0L)); + } +} + + diff --git a/core/video.c b/core/video.c new file mode 100644 index 0000000..15b3739 --- /dev/null +++ b/core/video.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2013, 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 +#include "shoebill.h" +#include "core_api.h" + +#include "video_rom/rom.c" + +typedef struct __attribute__ ((__packed__)) { + uint32_t structure_size; + uint32_t offset_to_ram; + + uint16_t line_width; // the number of byten is a scan line + uint16_t top; + uint16_t left; + uint16_t bottom; + uint16_t right; + uint16_t version; + uint16_t pack_type; + + uint32_t pack_size; + uint32_t hres; + uint32_t vres; + + uint16_t pixel_type; + uint16_t pixel_size; + uint16_t num_comp; + uint16_t comp_size; + + uint32_t plane_bytes; +} video_params_t; + +/*void nubus_video_display_func (void) +{ + uint32_t myw = glutGet(GLUT_WINDOW_WIDTH); + uint32_t myh = glutGet(GLUT_WINDOW_HEIGHT); + uint32_t slotnum, i; + int32_t my_window_id = glutGetWindow(); + + for (slotnum = 0; slotnum < 16; slotnum++) + if (shoe.slots[slotnum].glut_window_id == my_window_id) + break; + + video_ctx_t *ctx = (video_ctx_t*)shoe.slots[slotnum].ctx; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, myw, 0, myh, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.1, 0.1, 0.8); + + uint32_t gli = 0; + + switch (ctx->depth) { + case 1: { + for (i=0; i < ctx->pixels/8; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1]; + ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1]; + ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1]; + ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1]; + ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1]; + ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1]; + ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1]; + ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1]; + } + break; + } + case 2: { + for (i=0; i < ctx->pixels/4; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3]; + ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3]; + ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3]; + ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3]; + } + break; + } + case 4: { + for (i=0; i < ctx->pixels/2; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf]; + ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf]; + } + break; + } + case 8: + for (i=0; i < ctx->pixels; i++) + ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]]; + break; + + default: + assert(!"unknown depth"); + } + + glViewport(0, 0, myw, myh); + glRasterPos2i(0, myh); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glPixelZoom(1.0, -1.0); + + glDrawPixels(myw, myh, GL_RGBA, GL_UNSIGNED_BYTE, ctx->direct_buf); + + glFlush(); +}*/ + +uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len) +{ + uint32_t i, sum = 0; + + for (i=0; i> 31) + byte; + } + + rom[len-9] = sum & 0xff; + rom[len-10] = (sum >> 8) & 0xff; + rom[len-11] = (sum >> 16) & 0xff; + rom[len-12] = (sum >> 24) & 0xff; + + return sum; +} + +void nubus_video_init(void *_ctx, uint8_t slotnum, + uint16_t width, uint16_t height, uint16_t scanline_width, + double refresh_rate) +{ + shoebill_card_video_t *ctx = (shoebill_card_video_t*)_ctx; + ctx->width = width; + ctx->height = height; + ctx->scanline_width = scanline_width; + ctx->pixels = scanline_width * height; + + ctx->direct_buf = valloc(ctx->pixels * sizeof(video_ctx_color_t)); + ctx->indexed_buf = valloc(ctx->pixels); + ctx->clut = malloc(256 * sizeof(video_ctx_color_t)); + ctx->rom = malloc(4096); + + // Set the depth and clut for B&W + ctx->depth = 1; + bzero(ctx->clut, 256 * 4); + ctx->clut[0].r = 0xff; + ctx->clut[0].g = 0xff; + ctx->clut[0].b = 0xff; + + memcpy(ctx->rom, _video_rom, 4096); + + video_params_t *params = (video_params_t*)ctx->rom; + + // Load our chosen width/height into all the paramater blocks in the video rom + params[0].line_width = htons(scanline_width / 8); + params[0].right = htons(width); + params[0].bottom = htons(height); + + params[1].line_width = htons(scanline_width / 4); + params[1].right = htons(width); + params[1].bottom = htons(height); + + params[2].line_width = htons(scanline_width / 2); + params[2].right = htons(width); + params[2].bottom = htons(height); + + params[3].line_width = htons(scanline_width); + params[3].right = htons(width); + params[3].bottom = htons(height); + + // Recompute the rom crc + compute_nubus_crc(ctx->rom, 4096); + + shoe.slots[slotnum].ctx = ctx; +} + +uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size, + const uint8_t slotnum) +{ + shoebill_card_video_t *ctx = (shoebill_card_video_t*)shoe.slots[slotnum].ctx; + const uint32_t addr = rawaddr & 0x00ffffff; + + // ROM and control registers + if ((addr >> 20) == 0xf) { + + printf("nubus_video_read_func: got a read to 0x%08x sz=%u\n", rawaddr, size); + + // ROM (0xFsFFxxxx) + if ((addr >> 16) == 0xff) { + if (addr & 3) // Respond to lane 1 only + return 0; + return ctx->rom[(addr >> 2) % 4096]; + } + + // CLUT table (0xFsFE0xxx) + + // Control registers (0xFsF0xxxx) + if ((addr >> 16) == 0xf0) { + switch ((addr & 0x0000ffff) >> 2) { + // case 0: // clear interrupt flag (write-only) + + } + } + + return 0; + } + + // Else, this is video ram + + uint32_t i, myaddr = addr % ctx->pixels, result = 0; + for (i=0; iindexed_buf[(myaddr + i) % ctx->pixels]; + } + + return result; +} + + + +void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size, + const uint32_t data, const uint8_t slotnum) +{ + shoebill_card_video_t *ctx = (shoebill_card_video_t*)shoe.slots[slotnum].ctx; + const uint32_t addr = rawaddr & 0x00ffffff; + + // ROM and control registers + if ((addr >> 20) == 0xf) { + + printf("nubus_video_write_func: got a write to 0x%08x sz=%u data=0x%x\n", rawaddr, size, data); + + // ROM (0xFsFFxxxx) + if ((addr >> 16) == 0xff) + return ; // can't write to rom + + // CLUT table (0xFsFE0xxx) + + // Control registers (0xFsF0xxxx) + if ((addr >> 16) == 0xf0) { + switch ((addr & 0x0000ffff) >> 2) { + case 0: {// Clear interrupt flag + shoe.via[1].rega |= (1 << (slotnum - 9)); + break; + } + case 1: { // Set depth + const uint32_t depth = 1 << (data - 128); // FIXME: this won't work for direct mode + ctx->depth = depth; + printf("nubus_magic: set depth = %u\n", ctx->depth); + break; + } + case 2: { // Gray out screen + // FIXME: implement me + printf("nubus_magic: grey screen\n"); + break; + } + case 3: { // Set clut index + ctx->clut_idx = data & 0xff; + // assert(ctx->clut_idx < 256); + printf("nubus_magic: set clut_idx = %u\n", ctx->clut_idx); + break; + } + case 4: { // Set red component of clut + ctx->clut[ctx->clut_idx].r = (data >> 8) & 0xff; + printf("nubus_magic: set %u.red = 0x%04x\n", ctx->clut_idx, data); + break; + } + case 5: { // Set green component of clut + ctx->clut[ctx->clut_idx].g = (data >> 8) & 0xff; + printf("nubus_magic: set %u.green = 0x%04x\n", ctx->clut_idx, data); + break; + } + case 6: { // Set blue component of clut + ctx->clut[ctx->clut_idx].b = (data >> 8) & 0xff; + printf("nubus_magic: set %u.blue = 0x%04x\n", ctx->clut_idx, data); + break; + } + } + } + + return ; + } + + // Else, this is video ram + // uint32_t i, myaddr = addr % ctx->indexed_buf_len, mydata = data; + uint32_t myaddr, mydata; + for (myaddr = addr + size, mydata = data; addr < myaddr; ) { + // assert(myaddr < ctx->pixels) + ctx->indexed_buf[(--myaddr) % ctx->pixels] = mydata & 0xff; + mydata >>= 8; + } +} + + + + + + + + + diff --git a/core/video_rom/rom.bin b/core/video_rom/rom.bin new file mode 100644 index 0000000000000000000000000000000000000000..fe2b8f98113f46fadb8abfa98084ce2d86157b4a GIT binary patch literal 4096 zcmeH_F=!J}7{~wba)~KiF-R#vs$3-rA*q2D6$dG_WJpRpLLwqA(U61$gL$YaDFhqa zjvWLSkq(*E#Z5${bP{xM&_TgP?bIJcbRO>3vVXNJ3wH%@LQtef7 z0T?adey_jw^S~(+NS^^_0>Hf5S0XjC?gBatl&ci@C$S!o~K)6&L&S+D)XtF1Hnb+Rr%-nIO~|;?14YCmfp;4yo#58 z$PUlD#(KJao}wj^dq|f^o*~6Z$A)B*yhA!c8XJ->JE`xhU8^2y9$=>v+Wz)pr(?;# z$sF5#thE3fH!B1@-I8QyI1V@tI1V@tI1V@tI1V@tI1V@tI1c +#include +#include +#include + +int main (int argc, char **argv) +{ + FILE *in, *out; + uint8_t *rom = malloc(4096); + uint32_t i; + + if (argc != 3) { + printf("usage ./rom_to_c video_rom.bin video_rom.c\n"); + return 0; + } + + assert(in = fopen(argv[1], "r")); + assert(out = fopen(argv[2], "w")); + + assert(fread(rom, 4096, 1, in) == 1); + + fprintf(out, "uint8_t _video_rom[4096] = {\n\t"); + for (i=0; i<4095; i++) { + fprintf(out, "0x%02x, ", rom[i]); + if ((i % 8) == 7) + fprintf(out, "\n\t"); + } + fprintf(out, "0x%02x\n};\n", rom[i]); + fclose(out); + + return 0; +} + diff --git a/core/video_rom/shoebill_video.make b/core/video_rom/shoebill_video.make new file mode 100644 index 0000000..003e455 --- /dev/null +++ b/core/video_rom/shoebill_video.make @@ -0,0 +1 @@ +# File: shoebill_video.make # Target: shoebill_video # Sources: shoebill_video_rom.a OBJECTS = shoebill_video_rom.a.o shoebill_video shoebill_video.make {OBJECTS} Link {OBJECTS} -o shoebill_video shoebill_video_rom.a.o shoebill_video.make shoebill_video_rom.a Asm shoebill_video_rom.a \ No newline at end of file diff --git a/core/video_rom/shoebill_video_driver.a b/core/video_rom/shoebill_video_driver.a new file mode 100644 index 0000000..fa6ee9d --- /dev/null +++ b/core/video_rom/shoebill_video_driver.a @@ -0,0 +1 @@ + BLANKS ON STRING ASIS IMPORT test_func shoeClearInterrupt EQU 4*0 ; Write 1 to clear the via2 interrupt shoeSetMode EQU 4*1 ; write depth in bits shoeGrayScreen EQU 4*2 ; Gray out the screen buffer shoeSetClutIndex EQU 4*3 ; Set the index of the clut entry I'm about to modify shoeSetClutRed EQU 4*4 ; Set the red uint16_t for this clut entry shoeSetClutGreen EQU 4*5 ; green shoeSetClutBlue EQU 4*6 ; blue DriverStart DC.W $4C00 ; "ctl, status, needsLock" (what?) DC.W 0, 0, 0 ; "not an ornament" (??) DC.W VideoOpen-DriverStart DC.W 0 ; What does "prime" do? DC.W VideoCtl-DriverStart DC.W VideoStatus-DriverStart DC.W VideoClose-DriverStart STRING Pascal ; This needs to match the name in shoebill_video_rom.a DC.B '.Display_Video_Apple_Shoebill' STRING ASIS ALIGN 2 DC.W $0 ; Version number (overrides INIT if very high) VideoOpen move.l a0, a2 ; param block pointer move.l a1, a3 ; DCE pointer ; Allocate a slot queue element moveq.l #sqHDSize, d0 _NewPtr ,SYS,CLEAR bne Reset ; Install the interrupt handler lea InterruptHandler, a4 move.w #SIQType, SQType(a0) move.l a4, SQAddr(a0) move.l dctlDevBase(a3), SQParm(a0) moveq.l #0, d0 move.b dctlSlot(a3), d0 _SIntInstall bne Reset ; Return success moveq.l #0, d0 rts VideoCtl movem.l a0-a6/d1-d7, -(sp) moveq.l #0, d1 move.w csCode(a0), d1 move.l dCtlDevBase(a1), a2 add.l #$00F00000, a2 move.l csParam(a0), a3 ; a0 -> "IO parameter block" ; a1 -> DCE pointer ; a2 -> register base address ; a3 -> parameters ; d1 -> ctl code VideoCtl_reset cmp.w #0, d1 bne VideoCtl_killio move.l OneBitMode, shoeSetMode(a2) ; set to B&W move.l #1, shoeGrayScreen(a2) ; gray out the screen move.l #noErr, d0 ; success bra VideoCtl_rtn VideoCtl_killio cmp.w #1, d1 bne VideoCtl_setvidmode moveq.l #noErr, d0 ; no async IO on shoebill, so succeed bra VideoCtl_rtn VideoCtl_setvidmode cmp.w #2, d1 bne VideoCtl_setentries ; (it's okay to write bytes/words to these long register addresses) move.w csMode(a3), shoeSetMode(a2) moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_setentries cmp.w #3, d1 bne VideoCtl_setgamma move.l (a3), a4 ; csTable moveq.l #0, d2 move.w 4(a3), d2 ; csStart moveq.l #0, d3 move.w 6(a3), d3 ; csCount cmp.w #$ffff, d2 bne cont reset cont: move.l d2, d4 lsl.l #3, d4 ; multiply csStart by 8, sizeof(ColorSpec)==8 add.l d4, a4 ; add (csStart*8) to csTable addq.l #1, d3 ; csCount is 0-based (why??) Make it 1-based moveq.l #0, d4 setentries_loop: move.l d2, shoeSetClutIndex(a2) ; communicate the clut entry index move.w 2(a4), shoeSetClutRed(a2) ; communicate the red component move.w 4(a4), shoeSetClutGreen(a2) move.w 6(a4), shoeSetClutBlue(a2) addq.l #1, d2 ; increment csStart addq.l #8, a4 ; increment csTable pointer addq.l #1, d4 ; increment loop counter cmp d4, d3 bne setentries_loop ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_setgamma cmp.w #4, d1 bne VideoCtl_graypage ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_graypage cmp.w #5, d1 bne VideoCtl_setgray ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_setgray cmp.w #6, d1 bne VideoCtl_setinterrupt ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_setinterrupt cmp.w #7, d1 bne VideoCtl_directsetentries ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_directsetentries cmp.w #8, d1 bne VideoCtl_setdefault ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_setdefault cmp.w #9, d1 bne VideoCtl_bogus ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_bogus move.l #controlErr, d0; ; fall through VideoCtl_rtn movem.l (sp)+, a0-a6/d1-d7 rts ; ---- Video status ---- VideoStatus move.l #$fa00beef, a3 move.l #$deadbeef, (a3) reset VideoClose move.l #$fa00beef, a3 move.l #$deadbeef, (a3) reset InterruptHandler ; Compute the slot number given the base address in a1 move.l a1, d0 rol.l #8, d0 and.l #$0f, d0 ; Tell Shoebill to clear the interrupt flag move.l a1, a0 add.l #$00F00000, a0 ; the "clear interrupt" register move.l #1, (a0) ; Call JVBLTask (with d0 = slot number) move.l JVBLTask, a0 jsr (a0) ; Return success moveq.l #1, d0 rts Reset reset \ No newline at end of file diff --git a/core/video_rom/shoebill_video_primary_init.a b/core/video_rom/shoebill_video_primary_init.a new file mode 100644 index 0000000..9913b08 --- /dev/null +++ b/core/video_rom/shoebill_video_primary_init.a @@ -0,0 +1 @@ + BLANKS ON STRING ASIS MACHINE MC68020 WITH seBlock DC.B 2 ; Code revision DC.B 2 ; 68020 DC.W 0 ; reserved DC.L PrimaryInitStart-* PrimaryInitStart move.w #1, seStatus(a0) ; seStatus > 0 -> success move.l a0, a5 rts PrimaryInitEnd \ No newline at end of file diff --git a/core/video_rom/shoebill_video_rom.a b/core/video_rom/shoebill_video_rom.a new file mode 100644 index 0000000..942ef86 --- /dev/null +++ b/core/video_rom/shoebill_video_rom.a @@ -0,0 +1 @@ + MACHINE MC68020 STRING C PRINT OFF ; What does this do? INCLUDE 'SysErr.a' INCLUDE 'SysEqu.a' INCLUDE 'ROMEqu.a' INCLUDE 'SlotEqu.a' INCLUDE 'TimeEqu.a' INCLUDE 'Traps.a' INCLUDE 'VideoEqu.a' PRINT ON VideoDeclROM MAIN WITH VDPageInfo,SlotIntQElement FormatBlockSize EQU 20 ROMSize EQU 4096 MyBoardID EQU $0050 ; FIXME: CHANGE THIS ; ---- 1 bit video params ---- myVidParams_one DC.L myVidParams_one_end-myVidParams_one DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440/8 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 1 ; Pixel size (1 bit/px) DC.W 1 ; Number of components DC.W 1 ; Size of components (size of a single component, or of all?) DC.L 0 ; hmPlaneBytes (??) myVidParams_one_end ; ---- 2 bit video params ---- myVidParams_two DC.L myVidParams_two_end-myVidParams_two DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440/4 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 2 ; Pixel size (1 bit/px) DC.W 1 ; Number of components DC.W 2 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_two_end ; ---- 4 bit video params ---- myVidParams_four DC.L myVidParams_four_end-myVidParams_four DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440/2 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 4 ; Pixel size (1 bit/px) DC.W 1 ; Number of components DC.W 4 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_four_end ; ---- 8 bit video params ---- myVidParams_eight DC.L myVidParams_eight_end-myVidParams_eight DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 8 ; Pixel size (1 bit/px) DC.W 1 ; Number of components DC.W 8 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_eight_end ; ---- sResource directory ---- CategoryBoard EQU 1 CategoryVideo EQU 128 sResourceDir OSLstEntry CategoryBoard, sResourceBoard OSLstEntry CategoryVideo, sResourceVideo DatLstEntry endOfList,0 ; ---- Board sResource ---- sResourceBoard OSLstEntry sRsrcType, boardType OSLstEntry sRsrcName, boardName DatLstEntry boardID, MyBoardID OSLstEntry primaryInit, myPrimaryInit OSLstEntry vendorInfo, myVendorInfo DatLstEntry endOfList, 0 boardType DC.W CatBoard ; category DC.W TypBoard ; type DC.W 0 ; driver sw ? DC.W 0 ; driver hw ? boardName DC.L 'Shoebill Phony Video' myPrimaryInit DC.L myPrimaryInit_end-myPrimaryInit INCLUDE 'shoebill_video_primary_init.a' myPrimaryInit_end EQU * STRING C myVendorInfo OSLstEntry VendorId, myVendorID OSLstEntry RevLevel, myRevLevel OSLstEntry PartNum, myPartNum myVendorID DC.L 'Shoebill' myRevLevel DC.L 'Rev-1' myPartNum DC.L 'Moof' ; ---- Video sResource ---- sResourceVideo OSLstEntry sRsrcType, myVideoType OSLstEntry sRsrcName, myVideoName OSLstEntry sRsrcDrvrDir, videoDriverDirectory DatLstEntry sRsrcHWDevId, 1 ; DatLstEntry sRsrcFlags, 4 ; f32BitMode (A/UX refuses to load the driver when field is included) ;OSLstEntry MinorBaseOS, myMinorBaseOS ;OSLstEntry MinorLength, myMinorLength OSLstEntry MajorBaseOS, myMajorBaseOS OSLstEntry MajorLength, myMajorLength OSLstEntry OneBitMode, myOneBitMode OSLstEntry TwoBitMode, myTwoBitMode OSLstEntry FourBitMode, myFourBitMode OSLstEntry EightBitMode, myEightBitMode DatLstEntry endOfList, 0 myOneBitMode OSLstEntry mVidParams, myVidParams_one DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myTwoBitMode OSLstEntry mVidParams, myVidParams_two DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myFourBitMode OSLstEntry mVidParams, myVidParams_four DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myEightBitMode OSLstEntry mVidParams, myVidParams_eight DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myMinorBaseOS DC.L 0 myMinorLength DC.L $00040000 myMajorBaseOS DC.L 0 ; // the offset into the superslot space for video ram myMajorLength DC.L $00F00000 ; // the maxsize of video ram myVideoName DC.L 'Display_Video_Apple_Shoebill' myVideoType DC.W CatDisplay DC.W TypVideo DC.W DrSwApple ; implements the standard apple video driver api DC.W $5403 ; FIXME: is this right? videoDriverDirectory OSLstEntry sMacOS68020, driver_020_start DatLstEntry endOfList, 0 driver_020_start DC.L driver_020_end-driver_020_start INCLUDE 'shoebill_video_driver.a' driver_020_end EQU * ; Cleanup any macros the driver code modified STRING C ; ---- Format block ---- ; Pad to align this structure with the end of the rom ORG ROMSize-FormatBlockSize ; Offset to sResource directory ;OSLstEntry 0,sResourceDir DC.L (sResourceDir-*)**$00FFFFFF DC.L ROMSize DC.L 0 ; CRC goes here DC.B 1 ; Rom revision level DC.B AppleFormat DC.L TestPattern DC.B 0 ; Reserved DC.B $E1 ; Byte lanes 1110 0001 (LSB from CPU's perspective) ENDP END \ No newline at end of file diff --git a/gui/Shoebill.xcodeproj/project.pbxproj b/gui/Shoebill.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1cd5e59 --- /dev/null +++ b/gui/Shoebill.xcodeproj/project.pbxproj @@ -0,0 +1,381 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 87495445189980E200E80F5B /* shoeScreenView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 87495444189980E200E80F5B /* shoeScreenView.xib */; }; + 8749544718999F5300E80F5B /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8749544618999F5300E80F5B /* OpenGL.framework */; }; + 874954491899A22D00E80F5B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 874954481899A22D00E80F5B /* QuartzCore.framework */; }; + 8781D24C18A19C340016F604 /* shoePreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */; }; + 8781D24D18A19C340016F604 /* shoePreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */; }; + 8782FCE4189AFEFB0081E19E /* shoeApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 8782FCE3189AFEFB0081E19E /* shoeApplication.m */; }; + 87F9772C18987700000D589E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87F9772B18987700000D589E /* Cocoa.framework */; }; + 87F9773618987700000D589E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 87F9773418987700000D589E /* InfoPlist.strings */; }; + 87F9773818987700000D589E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 87F9773718987700000D589E /* main.m */; }; + 87F9773C18987700000D589E /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 87F9773A18987700000D589E /* Credits.rtf */; }; + 87F9773F18987700000D589E /* shoeAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 87F9773E18987700000D589E /* shoeAppDelegate.m */; }; + 87F9774218987700000D589E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 87F9774018987700000D589E /* MainMenu.xib */; }; + 87F9774418987700000D589E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87F9774318987700000D589E /* Images.xcassets */; }; + 87F9776118987767000D589E /* shoeScreenView.m in Sources */ = {isa = PBXBuildFile; fileRef = 87F9776018987767000D589E /* shoeScreenView.m */; }; + 87F977651898790B000D589E /* libshoebill_core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 87F977641898790B000D589E /* libshoebill_core.a */; }; + AE75B30918A8210D00E66DB6 /* shoeScreenWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = AE75B30818A8210D00E66DB6 /* shoeScreenWindow.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 87495444189980E200E80F5B /* shoeScreenView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = shoeScreenView.xib; sourceTree = ""; }; + 8749544618999F5300E80F5B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; + 874954481899A22D00E80F5B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = ""; }; + 8781D24918A19C340016F604 /* shoePreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoePreferencesWindowController.h; sourceTree = ""; }; + 8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoePreferencesWindowController.m; sourceTree = ""; }; + 8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = shoePreferencesWindowController.xib; sourceTree = ""; }; + 8782FCE2189AFEFB0081E19E /* shoeApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeApplication.h; sourceTree = ""; }; + 8782FCE3189AFEFB0081E19E /* shoeApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeApplication.m; sourceTree = ""; }; + 87F9772818987700000D589E /* Shoebill.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Shoebill.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 87F9772B18987700000D589E /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 87F9772E18987700000D589E /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 87F9772F18987700000D589E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 87F9773018987700000D589E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 87F9773318987700000D589E /* Shoebill-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Shoebill-Info.plist"; sourceTree = ""; }; + 87F9773518987700000D589E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 87F9773718987700000D589E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 87F9773918987700000D589E /* Shoebill-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Shoebill-Prefix.pch"; sourceTree = ""; }; + 87F9773B18987700000D589E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; + 87F9773D18987700000D589E /* shoeAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = shoeAppDelegate.h; sourceTree = ""; }; + 87F9773E18987700000D589E /* shoeAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = shoeAppDelegate.m; sourceTree = ""; }; + 87F9774118987700000D589E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 87F9774318987700000D589E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 87F9775F18987767000D589E /* shoeScreenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeScreenView.h; sourceTree = ""; }; + 87F9776018987767000D589E /* shoeScreenView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeScreenView.m; sourceTree = ""; }; + 87F977641898790B000D589E /* libshoebill_core.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libshoebill_core.a; path = ../../intermediates/libshoebill_core.a; sourceTree = ""; }; + AE75B30718A8210D00E66DB6 /* shoeScreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeScreenWindow.h; sourceTree = ""; }; + AE75B30818A8210D00E66DB6 /* shoeScreenWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeScreenWindow.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 87F9772518987700000D589E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 874954491899A22D00E80F5B /* QuartzCore.framework in Frameworks */, + 87F977651898790B000D589E /* libshoebill_core.a in Frameworks */, + 87F9772C18987700000D589E /* Cocoa.framework in Frameworks */, + 8749544718999F5300E80F5B /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 87F9771F18987700000D589E = { + isa = PBXGroup; + children = ( + 87F9773118987700000D589E /* Shoebill */, + 87F9772A18987700000D589E /* Frameworks */, + 87F9772918987700000D589E /* Products */, + ); + sourceTree = ""; + }; + 87F9772918987700000D589E /* Products */ = { + isa = PBXGroup; + children = ( + 87F9772818987700000D589E /* Shoebill.app */, + ); + name = Products; + sourceTree = ""; + }; + 87F9772A18987700000D589E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 874954481899A22D00E80F5B /* QuartzCore.framework */, + 8749544618999F5300E80F5B /* OpenGL.framework */, + 87F9772B18987700000D589E /* Cocoa.framework */, + 87F9772D18987700000D589E /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + 87F9772D18987700000D589E /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 87F9772E18987700000D589E /* AppKit.framework */, + 87F9772F18987700000D589E /* CoreData.framework */, + 87F9773018987700000D589E /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 87F9773118987700000D589E /* Shoebill */ = { + isa = PBXGroup; + children = ( + 87F977641898790B000D589E /* libshoebill_core.a */, + 87F9774018987700000D589E /* MainMenu.xib */, + 8782FCE2189AFEFB0081E19E /* shoeApplication.h */, + 8782FCE3189AFEFB0081E19E /* shoeApplication.m */, + 87F9773D18987700000D589E /* shoeAppDelegate.h */, + 87F9773E18987700000D589E /* shoeAppDelegate.m */, + 87495444189980E200E80F5B /* shoeScreenView.xib */, + AE75B30718A8210D00E66DB6 /* shoeScreenWindow.h */, + AE75B30818A8210D00E66DB6 /* shoeScreenWindow.m */, + 87F9775F18987767000D589E /* shoeScreenView.h */, + 87F9776018987767000D589E /* shoeScreenView.m */, + 8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */, + 8781D24918A19C340016F604 /* shoePreferencesWindowController.h */, + 8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */, + 87F9773218987700000D589E /* Supporting Files */, + ); + path = Shoebill; + sourceTree = ""; + }; + 87F9773218987700000D589E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 87F9774318987700000D589E /* Images.xcassets */, + 87F9773318987700000D589E /* Shoebill-Info.plist */, + 87F9773418987700000D589E /* InfoPlist.strings */, + 87F9773718987700000D589E /* main.m */, + 87F9773918987700000D589E /* Shoebill-Prefix.pch */, + 87F9773A18987700000D589E /* Credits.rtf */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 87F9772718987700000D589E /* Shoebill */ = { + isa = PBXNativeTarget; + buildConfigurationList = 87F9775918987700000D589E /* Build configuration list for PBXNativeTarget "Shoebill" */; + buildPhases = ( + 87F9772418987700000D589E /* Sources */, + 87F9772518987700000D589E /* Frameworks */, + 87F9772618987700000D589E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Shoebill; + productName = Shoebill; + productReference = 87F9772818987700000D589E /* Shoebill.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 87F9772018987700000D589E /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = shoe; + LastUpgradeCheck = 0500; + ORGANIZATIONNAME = "Peter Rutenbar"; + }; + buildConfigurationList = 87F9772318987700000D589E /* Build configuration list for PBXProject "Shoebill" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + English, + ); + mainGroup = 87F9771F18987700000D589E; + productRefGroup = 87F9772918987700000D589E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 87F9772718987700000D589E /* Shoebill */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 87F9772618987700000D589E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8781D24D18A19C340016F604 /* shoePreferencesWindowController.xib in Resources */, + 87F9773618987700000D589E /* InfoPlist.strings in Resources */, + 87F9774418987700000D589E /* Images.xcassets in Resources */, + 87F9773C18987700000D589E /* Credits.rtf in Resources */, + 87495445189980E200E80F5B /* shoeScreenView.xib in Resources */, + 87F9774218987700000D589E /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 87F9772418987700000D589E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 87F9773818987700000D589E /* main.m in Sources */, + 87F9773F18987700000D589E /* shoeAppDelegate.m in Sources */, + 87F9776118987767000D589E /* shoeScreenView.m in Sources */, + 8781D24C18A19C340016F604 /* shoePreferencesWindowController.m in Sources */, + AE75B30918A8210D00E66DB6 /* shoeScreenWindow.m in Sources */, + 8782FCE4189AFEFB0081E19E /* shoeApplication.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 87F9773418987700000D589E /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 87F9773518987700000D589E /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 87F9773A18987700000D589E /* Credits.rtf */ = { + isa = PBXVariantGroup; + children = ( + 87F9773B18987700000D589E /* en */, + ); + name = Credits.rtf; + sourceTree = ""; + }; + 87F9774018987700000D589E /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 87F9774118987700000D589E /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 87F9775718987700000D589E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 87F9775818987700000D589E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + SDKROOT = macosx; + }; + name = Release; + }; + 87F9775A18987700000D589E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Shoebill/Shoebill-Prefix.pch"; + INFOPLIST_FILE = "Shoebill/Shoebill-Info.plist"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + ../intermediates, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 87F9775B18987700000D589E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Shoebill/Shoebill-Prefix.pch"; + INFOPLIST_FILE = "Shoebill/Shoebill-Info.plist"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + ../intermediates, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 87F9772318987700000D589E /* Build configuration list for PBXProject "Shoebill" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 87F9775718987700000D589E /* Debug */, + 87F9775818987700000D589E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 87F9775918987700000D589E /* Build configuration list for PBXNativeTarget "Shoebill" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 87F9775A18987700000D589E /* Debug */, + 87F9775B18987700000D589E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 87F9772018987700000D589E /* Project object */; +} diff --git a/gui/Shoebill/Base.lproj/MainMenu.xib b/gui/Shoebill/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..ea724df --- /dev/null +++ b/gui/Shoebill/Base.lproj/MainMenu.xib @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/Shoebill/Images.xcassets/AppIcon.appiconset/Contents.json b/gui/Shoebill/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2db2b1c --- /dev/null +++ b/gui/Shoebill/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/gui/Shoebill/Shoebill-Info.plist b/gui/Shoebill/Shoebill-Info.plist new file mode 100644 index 0000000..7c9f7fb --- /dev/null +++ b/gui/Shoebill/Shoebill-Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + org.shoebill.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSHumanReadableCopyright + Copyright © 2014 Peter Rutenbar. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + shoeApplication + + diff --git a/gui/Shoebill/Shoebill-Prefix.pch b/gui/Shoebill/Shoebill-Prefix.pch new file mode 100644 index 0000000..35d7640 --- /dev/null +++ b/gui/Shoebill/Shoebill-Prefix.pch @@ -0,0 +1,9 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#ifdef __OBJC__ + #import +#endif diff --git a/gui/Shoebill/en.lproj/Credits.rtf b/gui/Shoebill/en.lproj/Credits.rtf new file mode 100644 index 0000000..46576ef --- /dev/null +++ b/gui/Shoebill/en.lproj/Credits.rtf @@ -0,0 +1,29 @@ +{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw9840\paperh8400 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Some people\ +\ + +\b Human Interface Design: +\b0 \ + Some other people\ +\ + +\b Testing: +\b0 \ + Hopefully not nobody\ +\ + +\b Documentation: +\b0 \ + Whoever\ +\ + +\b With special thanks to: +\b0 \ + Mom\ +} diff --git a/gui/Shoebill/en.lproj/InfoPlist.strings b/gui/Shoebill/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/gui/Shoebill/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/gui/Shoebill/main.m b/gui/Shoebill/main.m new file mode 100644 index 0000000..3eb7a37 --- /dev/null +++ b/gui/Shoebill/main.m @@ -0,0 +1,6 @@ +#import + +int main(int argc, const char * argv[]) +{ + return NSApplicationMain(argc, argv); +} diff --git a/gui/Shoebill/shoeAppDelegate.h b/gui/Shoebill/shoeAppDelegate.h new file mode 100644 index 0000000..959547f --- /dev/null +++ b/gui/Shoebill/shoeAppDelegate.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#import + +@interface shoeAppDelegate : NSObject { + +@public + NSWindowController *windowController; +} + +@property (assign) IBOutlet NSWindow *window; + +@end diff --git a/gui/Shoebill/shoeAppDelegate.m b/gui/Shoebill/shoeAppDelegate.m new file mode 100644 index 0000000..8550a87 --- /dev/null +++ b/gui/Shoebill/shoeAppDelegate.m @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#import "shoeAppDelegate.h" + + +@implementation shoeAppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + /*windowController = [[NSWindowController alloc] initWithWindowNibName:@"shoeScreenView"]; + [windowController showWindow:nil]; + [windowController.window makeKeyAndOrderFront:nil];*/ +} + + + +@end diff --git a/gui/Shoebill/shoeApplication.h b/gui/Shoebill/shoeApplication.h new file mode 100644 index 0000000..9571196 --- /dev/null +++ b/gui/Shoebill/shoeApplication.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#import +#include "../../core/core_api.h" +#include "../../core/redblack.h" + +@interface shoeApplication : NSApplication { + rb_tree *keymap; + NSWindowController *windowController[16]; + + @public + BOOL doCaptureMouse, doCaptureKeys; + BOOL isRunning; + shoebill_control_t control; +} + +- (void) startEmulator; + +@end diff --git a/gui/Shoebill/shoeApplication.m b/gui/Shoebill/shoeApplication.m new file mode 100644 index 0000000..169ab0b --- /dev/null +++ b/gui/Shoebill/shoeApplication.m @@ -0,0 +1,317 @@ +/* + * 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. + */ + +#import "shoeApplication.h" +#import "shoeScreenWindow.h" + +@implementation shoeApplication + +#define mapkeymod(u, a, m) do { \ + assert((a >> 7) == 0); \ + void *value = (void*)(((m) << 8)| (a)); \ + rb_insert(keymap, u, value, NULL); \ +} while (0) \ + +#define mapkey(_u, a) mapkeymod(_u, a, 0) + +- (void)initKeyboardMap +{ + keymap = rb_new(); + + // Letters + mapkey('a', 0x00); + mapkey('b', 0x0b); + mapkey('c', 0x08); + mapkey('d', 0x02); + mapkey('e', 0x0e); + mapkey('f', 0x03); + mapkey('g', 0x05); + mapkey('h', 0x04); + mapkey('i', 0x22); + mapkey('j', 0x26); + mapkey('k', 0x28); + mapkey('l', 0x25); + mapkey('m', 0x2e); + mapkey('n', 0x2d); + mapkey('o', 0x1f); + mapkey('p', 0x23); + mapkey('q', 0x0c); + mapkey('r', 0x0f); + mapkey('s', 0x01); + mapkey('t', 0x11); + mapkey('u', 0x20); + mapkey('v', 0x09); + mapkey('w', 0x0d); + mapkey('x', 0x07); + mapkey('y', 0x10); + mapkey('z', 0x06); + + // Numbers + mapkey('0', 0x1d); + mapkey('1', 0x12); + mapkey('2', 0x13); + mapkey('3', 0x14); + mapkey('4', 0x15); + mapkey('5', 0x17); + mapkey('6', 0x16); + mapkey('7', 0x1a); + mapkey('8', 0x1c); + mapkey('9', 0x19); + + // Top row symbols + mapkeymod(')', 0x1d, modShift); + mapkeymod('!', 0x12, modShift); + mapkeymod('@', 0x13, modShift); + mapkeymod('#', 0x14, modShift); + mapkeymod('$', 0x15, modShift); + mapkeymod('%', 0x17, modShift); + mapkeymod('^', 0x16, modShift); + mapkeymod('&', 0x1a, modShift); + mapkeymod('*', 0x1c, modShift); + mapkeymod('(', 0x19, modShift); + + // Other symbols (no shift) + mapkeymod('`', 0x32, 0); + mapkeymod('-', 0x1b, 0); + mapkeymod('=', 0x18, 0); + mapkeymod('[', 0x21, 0); + mapkeymod(']', 0x1e, 0); + mapkeymod('\\', 0x2a, 0); + mapkeymod(';', 0x29, 0); + mapkeymod('\'', 0x27, 0); + mapkeymod(',', 0x2b, 0); + mapkeymod('.', 0x2f, 0); + mapkeymod('/', 0x2c, 0); + + // Other symbols (with shift) + mapkeymod('~', 0x32, modShift); + mapkeymod('_', 0x1b, modShift); + mapkeymod('+', 0x18, modShift); + mapkeymod('{', 0x21, modShift); + mapkeymod('}', 0x1e, modShift); + mapkeymod('|', 0x2a, modShift); + mapkeymod(':', 0x29, modShift); + mapkeymod('"', 0x27, modShift); + mapkeymod('<', 0x2b, modShift); + mapkeymod('>', 0x2f, modShift); + mapkeymod('?', 0x2c, modShift); + + // Function keys + mapkey(NSF1FunctionKey, 0x7a); + mapkey(NSF2FunctionKey, 0x78); + mapkey(NSF3FunctionKey, 0x63); + mapkey(NSF4FunctionKey, 0x76); + mapkey(NSF5FunctionKey, 0x60); + mapkey(NSF6FunctionKey, 0x61); + mapkey(NSF7FunctionKey, 0x62); + mapkey(NSF8FunctionKey, 0x64); + mapkey(NSF9FunctionKey, 0x65); + mapkey(NSF10FunctionKey, 0x6d); + mapkey(NSF11FunctionKey, 0x67); + mapkey(NSF12FunctionKey, 0x6f); + mapkey(NSF13FunctionKey, 0x69); + mapkey(NSF14FunctionKey, 0x6b); + mapkey(NSF15FunctionKey, 0x71); + + // Arrows + mapkey(NSUpArrowFunctionKey, 0x3e); + mapkey(NSDownArrowFunctionKey, 0x3d); + mapkey(NSRightArrowFunctionKey, 0x3c); + mapkey(NSLeftArrowFunctionKey, 0x3b); + + // Delete + mapkey(NSDeleteFunctionKey, 0x75); + mapkey(NSBackspaceCharacter, 0x33); + mapkey(NSDeleteCharacter, 0x33); + + // Enter, NL, CR + mapkey(NSCarriageReturnCharacter, 0x24); + mapkey(NSNewlineCharacter, 0x24); + mapkey(NSEnterCharacter, 0x24); + + // Other keys + mapkey(0x1b, 0x35); // escape + mapkey(' ', 0x31); // space + mapkey(NSTabCharacter, 0x30); // tab +} + +- (void)sendEvent:(NSEvent *)event +{ + if (doCaptureKeys) { + assert(isRunning); + NSEventType type = [event type]; + if (type == NSFlagsChanged) { + NSUInteger modifierFlags = [event modifierFlags]; + shoebill_key_modifier(modifierFlags >> 16); + return ; + } + else if (type == NSKeyDown || type == NSKeyUp) { + NSString *chars = [[event charactersIgnoringModifiers] lowercaseString]; + NSUInteger modifierFlags = [event modifierFlags]; + unichar c = [chars characterAtIndex:0]; + void *_value; + + if (keymap == NULL) + [self initKeyboardMap]; + + if (rb_find(keymap, c, &_value)) { + uint16_t value = (uint16_t)_value; + shoebill_key_modifier((value >> 8) | (modifierFlags >> 16)); + shoebill_key((type == NSKeyDown), value & 0xff); + + } + + return ; + } + } + + [super sendEvent:event]; +} + + +- (void) complain:(NSString*)str +{ + NSAlert *theAlert = [NSAlert + alertWithMessageText:nil + defaultButton:nil + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", str + ]; + [theAlert runModal]; +} + + +- (BOOL) fetchUserDefaults:(uint16_t*)height width:(uint16_t*)width +{ + uint32_t i; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + NSString *kernelPathStr = [defaults objectForKey:@"kernelPath"]; + NSString *romPathStr = [defaults objectForKey:@"romPath"]; + NSInteger verboseState = [defaults integerForKey:@"verboseState"]; + NSInteger memsize = [defaults integerForKey:@"memorySize"]; + + if (kernelPathStr == Nil || [kernelPathStr length]==0) { + [self complain:@"Kernel path invalid!"]; + return NO; + } + + else if (romPathStr == Nil || [romPathStr length] == 0) { + [self complain:@"ROM path invalid!"]; + return NO; + } + + if ((memsize < 1) || (memsize > 1024)) + memsize = 8; + + NSInteger screenHeightValue = [defaults integerForKey:@"screenHeight"]; + NSInteger screenWidthValue = [defaults integerForKey:@"screenWidth"]; + + if ((screenHeightValue < 342) || (screenHeightValue > 0xffff)) + screenHeightValue = 480; + + if ((screenWidthValue < 512) || (screenWidthValue > 0xffff)) + screenWidthValue = 640; + + + for (i=0; i<7; i++) { + NSString *str = [defaults objectForKey:[NSString stringWithFormat:@"scsiPath%u", i]]; + if (str == nil || [str length] == 0) + control.scsi_devices[i].path = NULL; + else + control.scsi_devices[i].path = strdup([str UTF8String]); + + } + + char *kernelPathCString = strdup([kernelPathStr UTF8String]); + char *romPathCString = strdup([romPathStr UTF8String]); + + // FIXME: I'm leaking these strings. Stop leaking stuff when the UI is more finalized + + control.aux_verbose = (verboseState == NSOnState); + control.ram_size = (uint32_t)memsize * 1024 * 1024; + control.aux_kernel_path = kernelPathCString; + control.rom_path = romPathCString; + + *width = screenWidthValue; + *height = screenHeightValue; + + return YES; +} + +- (void) createScreenWindow:(uint8_t)slotnum + height:(uint16_t)height + width:(uint16_t)width + refresh_freq:(double)refresh_freq +{ + shoebill_install_video_card(&control, + slotnum, + width, + height, + refresh_freq); + + windowController[slotnum] = [[NSWindowController alloc] initWithWindowNibName:@"shoeScreenView"]; + shoeScreenWindow *win = (shoeScreenWindow*)windowController[slotnum].window; + [win configure:slotnum]; +} + +- (void) startEmulator +{ + uint16_t width, height; + uint32_t i; + + bzero(&control, sizeof(shoebill_control_t)); + + [self fetchUserDefaults:&height width:&width]; + + uint32_t result = shoebill_initialize(&control); + + if (!result) { + [self complain:[NSString stringWithFormat:@"%s", control.error_msg]]; + return ; + } + + [self createScreenWindow:10 height:height width:width refresh_freq:200.0/3.0]; + + shoebill_start(); + isRunning = true; + + for (i=0; i<16; i++) + if (windowController[i]) { + shoeScreenWindow *win = (shoeScreenWindow*)[windowController[i] window]; + [win reevaluateKeyWindowness]; + } + +} + +- (IBAction)runMenuItem:(id)sender +{ + [self startEmulator]; + +} + + +@end diff --git a/gui/Shoebill/shoePreferencesWindowController.h b/gui/Shoebill/shoePreferencesWindowController.h new file mode 100644 index 0000000..639b56a --- /dev/null +++ b/gui/Shoebill/shoePreferencesWindowController.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#import + +@interface shoePreferencesWindowController : NSWindowController { + + IBOutlet __weak NSButton *apply, *cancel, *applyAndRun, *verbose; + IBOutlet __weak NSTextField *kernelPath, *romPath, *memorySize; + IBOutlet __weak NSTextField *scsiPath0, *scsiPath1, *scsiPath2, *scsiPath3, *scsiPath4, *scsiPath5, *scsiPath6; + IBOutlet __weak NSTextField *screenHeight, *screenWidth; +} + + +- (IBAction)applyPressed:(id)sender; +- (IBAction)cancelPressed:(id)sender; +- (IBAction)applyAndRunPressed:(id)sender; +- (IBAction)browsePressed:(id)sender; + +@end diff --git a/gui/Shoebill/shoePreferencesWindowController.m b/gui/Shoebill/shoePreferencesWindowController.m new file mode 100644 index 0000000..e1abacb --- /dev/null +++ b/gui/Shoebill/shoePreferencesWindowController.m @@ -0,0 +1,190 @@ +/* + * 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. + */ + +#import "shoePreferencesWindowController.h" +#import "shoeApplication.h" + +@implementation shoePreferencesWindowController + +- (id) init +{ + return [super initWithWindowNibName:@"shoePreferencesWindowController"]; +} + +- (void)windowDidLoad +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + NSString *kernelPathStr = [defaults objectForKey:@"kernelPath"]; + NSString *romPathStr = [defaults objectForKey:@"romPath"]; + NSInteger verboseState = [defaults integerForKey:@"verboseState"]; + NSInteger memsize = [defaults integerForKey:@"memorySize"]; + + if ((memsize < 1) || (memsize > 1024)) { + memsize = 8; + [defaults setInteger:memsize forKey:@"memorySize"]; + } + + verboseState = (verboseState == NSOnState) ? NSOnState : NSOffState; + [defaults setInteger:verboseState forKey:@"verboseState"]; + + NSString *scsiPath0Str = [defaults objectForKey:@"scsiPath0"]; + NSString *scsiPath1Str = [defaults objectForKey:@"scsiPath1"]; + NSString *scsiPath2Str = [defaults objectForKey:@"scsiPath2"]; + NSString *scsiPath3Str = [defaults objectForKey:@"scsiPath3"]; + NSString *scsiPath4Str = [defaults objectForKey:@"scsiPath4"]; + NSString *scsiPath5Str = [defaults objectForKey:@"scsiPath5"]; + NSString *scsiPath6Str = [defaults objectForKey:@"scsiPath6"]; + + if (romPath) [romPath setStringValue:romPathStr]; + if (kernelPath) [kernelPath setStringValue:kernelPathStr]; + [verbose setState:verboseState]; + [memorySize setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)memsize]]; + + if (scsiPath0Str) [scsiPath0 setStringValue:scsiPath0Str]; + if (scsiPath1Str) [scsiPath1 setStringValue:scsiPath1Str]; + if (scsiPath2Str) [scsiPath2 setStringValue:scsiPath2Str]; + if (scsiPath3Str) [scsiPath3 setStringValue:scsiPath3Str]; + if (scsiPath4Str) [scsiPath4 setStringValue:scsiPath4Str]; + if (scsiPath5Str) [scsiPath5 setStringValue:scsiPath5Str]; + if (scsiPath6Str) [scsiPath6 setStringValue:scsiPath6Str]; + + NSInteger screenHeightValue = [defaults integerForKey:@"screenHeight"]; + NSInteger screenWidthValue = [defaults integerForKey:@"screenWidth"]; + + if ((screenHeightValue < 342) || (screenHeightValue > 0xffff)) { + screenHeightValue = 480; + [defaults setInteger:screenHeightValue forKey:@"screenHeight"]; + } + + if ((screenWidthValue < 512) || (screenWidthValue > 0xffff)) { + screenWidthValue = 640; + [defaults setInteger:screenWidthValue forKey:@"screenWidth"]; + } + + [screenWidth setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)screenWidthValue]]; + [screenHeight setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)screenHeightValue]]; + + [defaults synchronize]; +} + + +- (IBAction)browsePressed:(id)sender +{ + NSOpenPanel* openPanel = [NSOpenPanel openPanel]; + + [openPanel setCanChooseFiles:YES]; + [openPanel setAllowsMultipleSelection:NO]; + + if ([openPanel runModal] != NSOKButton) + return ; + + NSArray *urls = [openPanel URLs]; + if ([urls count] != 1) + return ; + + NSURL *url = [urls firstObject]; + if (![url isFileURL]) + return ; + + NSString *buttonID = [sender identifier]; + NSTextField *field; + + if ([buttonID isEqualToString:@"kernelPathBrowse"]) + field = kernelPath; + else if ([buttonID isEqualToString:@"romPathBrowse"]) + field = romPath; + else if ([buttonID isEqualToString:@"scsiPath0Browse"]) + field = scsiPath0; + else if ([buttonID isEqualToString:@"scsiPath1Browse"]) + field = scsiPath1; + else if ([buttonID isEqualToString:@"scsiPath2Browse"]) + field = scsiPath2; + else if ([buttonID isEqualToString:@"scsiPath3Browse"]) + field = scsiPath3; + else if ([buttonID isEqualToString:@"scsiPath4Browse"]) + field = scsiPath4; + else if ([buttonID isEqualToString:@"scsiPath5Browse"]) + field = scsiPath5; + else if ([buttonID isEqualToString:@"scsiPath6Browse"]) + field = scsiPath6; + else + return ; + + [field setStringValue: [url path]]; +} + +- (IBAction)applyPressed:(id)sender +{ + + NSString *kernelPathStr = [kernelPath stringValue]; + NSString *romPathStr = [romPath stringValue]; + NSInteger verboseState = [verbose state]; + NSInteger memsize = [memorySize integerValue]; + + NSString *scsiPath0Str = [scsiPath0 stringValue]; + NSString *scsiPath1Str = [scsiPath1 stringValue]; + NSString *scsiPath2Str = [scsiPath2 stringValue]; + NSString *scsiPath3Str = [scsiPath3 stringValue]; + NSString *scsiPath4Str = [scsiPath4 stringValue]; + NSString *scsiPath5Str = [scsiPath5 stringValue]; + NSString *scsiPath6Str = [scsiPath6 stringValue]; + + NSInteger screenHeightValue = [screenHeight integerValue]; + NSInteger screenWidthValue = [screenWidth integerValue]; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + [defaults setObject:kernelPathStr forKey:@"kernelPath"]; + [defaults setObject:romPathStr forKey:@"romPath"]; + [defaults setInteger:verboseState forKey:@"verboseState"]; + [defaults setInteger:memsize forKey:@"memorySize"]; + + [defaults setObject:scsiPath0Str forKey:@"scsiPath0"]; + [defaults setObject:scsiPath1Str forKey:@"scsiPath1"]; + [defaults setObject:scsiPath2Str forKey:@"scsiPath2"]; + [defaults setObject:scsiPath3Str forKey:@"scsiPath3"]; + [defaults setObject:scsiPath4Str forKey:@"scsiPath4"]; + [defaults setObject:scsiPath5Str forKey:@"scsiPath5"]; + [defaults setObject:scsiPath6Str forKey:@"scsiPath6"]; + + [defaults setInteger:screenHeightValue forKey:@"screenHeight"]; + [defaults setInteger:screenWidthValue forKey:@"screenWidth"]; + + [defaults synchronize]; +} + +- (IBAction)cancelPressed:(id)sender +{ + [[self window] close]; +} +- (IBAction)applyAndRunPressed:(id)sender +{ + shoeApplication *shoeApp = (shoeApplication*) NSApp; + [self applyPressed:sender]; + [shoeApp startEmulator]; +} + +@end diff --git a/gui/Shoebill/shoePreferencesWindowController.xib b/gui/Shoebill/shoePreferencesWindowController.xib new file mode 100644 index 0000000..492c628 --- /dev/null +++ b/gui/Shoebill/shoePreferencesWindowController.xib @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/Shoebill/shoeScreenView.h b/gui/Shoebill/shoeScreenView.h new file mode 100644 index 0000000..469fdd9 --- /dev/null +++ b/gui/Shoebill/shoeScreenView.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#import +#import +#import +#import "shoeApplication.h" + + +@interface shoeScreenView : NSOpenGLView { + CGColorSpaceRef colorspace; + shoebill_control_t *control; + NSTimer *timer; + NSRecursiveLock *lock; + CIContext *ciContext; + shoeApplication *shoeApp; +} + +@end diff --git a/gui/Shoebill/shoeScreenView.m b/gui/Shoebill/shoeScreenView.m new file mode 100644 index 0000000..21d6a22 --- /dev/null +++ b/gui/Shoebill/shoeScreenView.m @@ -0,0 +1,291 @@ +/* + * 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. + */ + +#import "shoeScreenView.h" +#import "shoeAppDelegate.h" +#import "shoeApplication.h" +#import + +@implementation shoeScreenView + + +- (void)initCommon +{ + shoeApp = (shoeApplication*) NSApp; + control = &shoeApp->control; +} + + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + [self initCommon]; + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self) + [self initCommon]; + return self; +} + +- (void) awakeFromNib +{ + NSOpenGLPixelFormatAttribute attrs[] = + { + NSOpenGLPFADoubleBuffer, + 0 + }; + + NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + assert(pf); + + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; + [self setPixelFormat:pf]; + [self setOpenGLContext:context]; + + colorspace = CGColorSpaceCreateDeviceRGB(); + + timer = [NSTimer + scheduledTimerWithTimeInterval:(0.015/2.0) + target:self + selector:@selector(timerFireMethod:) + userInfo:nil + repeats:YES]; + + shoebill_card_video_t *video = &control->slots[10].card.video; + NSSize size = { + .height=video->height, + .width=video->width + }; + + [[self window] setContentSize:size]; + [[self window] setTitle:[NSString stringWithFormat:@"Shoebill - Screen 1"]]; + [[self window] makeKeyAndOrderFront:nil]; +} + +- (void)timerFireMethod:(NSTimer *)timer +{ + [self setNeedsDisplay:YES]; +} + +- (void)prepareOpenGL +{ + NSRect frame = [self frame]; + NSRect bounds = [self bounds]; + GLfloat minX, minY, maxX, maxY; + + minX = NSMinX(bounds); + minY = NSMinY(bounds); + maxX = NSMaxX(bounds); + maxY = NSMaxY(bounds); + + //[self update]; + + if(NSIsEmptyRect([self visibleRect])) + { + glViewport(0, 0, 1, 1); + } else { + glViewport(0, 0, frame.size.width ,frame.size.height); + } + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(minX, maxX, minY, maxY, -1.0, 1.0); +} + +static void _do_clut_translation(shoebill_card_video_t *ctx) +{ + uint32_t i; + + switch (ctx->depth) { + case 1: { + for (i=0; i < ctx->pixels/8; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1]; + ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1]; + ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1]; + ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1]; + ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1]; + ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1]; + ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1]; + ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1]; + } + break; + } + case 2: { + for (i=0; i < ctx->pixels/4; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3]; + ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3]; + ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3]; + ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3]; + } + break; + } + case 4: { + for (i=0; i < ctx->pixels/2; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf]; + ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf]; + } + break; + } + case 8: + for (i=0; i < ctx->pixels; i++) + ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]]; + break; + + default: + assert(!"unknown depth"); + } +} + + +- (void)drawRect:(NSRect)rect +{ + [[self openGLContext] makeCurrentContext]; + + + glDrawBuffer(GL_BACK); + glClear(GL_COLOR_BUFFER_BIT); + + glClearColor(0.0, 0.0, 0.0, 0.0); + + if (shoeApp->isRunning) { + shoebill_card_video_t *video = &control->slots[10].card.video; + _do_clut_translation(video); + glViewport(0, 0, video->width, video->height); + glRasterPos2i(0, video->height); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glPixelZoom(1.0, -1.0); + + glDrawPixels(video->width, + video->height, + GL_RGBA, + GL_UNSIGNED_BYTE, + video->direct_buf); + } + + [[self openGLContext] flushBuffer]; +} + +- (void) warpToCenter +{ + // Convert the cocoa window frame to quartz global coordinates + NSRect winrect = [[self window] frame]; + NSScreen *mainScreen = (NSScreen*)[[NSScreen screens] objectAtIndex:0]; + winrect.origin.y = NSMaxY([mainScreen frame]) - NSMaxY(winrect); + CGRect cgwinrect = NSRectToCGRect(winrect); + + // Find the center of the window + cgwinrect.origin.x += cgwinrect.size.width / 2.0; + cgwinrect.origin.y += cgwinrect.size.height / 2.0; + + CGWarpMouseCursorPosition(cgwinrect.origin); +} + +- (void)viewDidMoveToWindow +{ + [[self window] setAcceptsMouseMovedEvents:YES]; + [[self window] makeFirstResponder:self]; +} + +- (void)mouseEntered:(NSEvent *)theEvent +{ + [[self window] setAcceptsMouseMovedEvents:YES]; + [[self window] makeFirstResponder:self]; +} + + +- (void)mouseMoved:(NSEvent *)theEvent +{ + if (shoeApp->doCaptureMouse) { + assert(shoeApp->isRunning); + //NSPoint point = [theEvent locationInWindow]; + //NSPoint point = [self convertPoint:windowPoint fromView:self]; + + /*NSRect winFrame = [[self window] frame]; + NSPoint winCenter; + winCenter.x = winFrame.size.width / 2.0; + winCenter.y = winFrame.size.height / 2.0;*/ + + /*int32_t delta_x = (int32_t)(point.x - winCenter.x); + int32_t delta_y = -(int32_t)(point.y - winCenter.y);*/ + + int32_t delta_x, delta_y; + CGGetLastMouseDelta(&delta_x, &delta_y); + shoebill_mouse_move_delta(delta_x, delta_y); + [self warpToCenter]; + } +} + +-(void)mouseDragged:(NSEvent *)theEvent +{ + [self mouseMoved:theEvent]; +} + +- (void) say:(NSString*)str +{ + NSAlert *theAlert = [NSAlert + alertWithMessageText:nil + defaultButton:nil + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", str + ]; + [theAlert runModal]; +} + +- (void)mouseDown:(NSEvent *)theEvent +{ + if (shoeApp->doCaptureMouse) { + assert(shoeApp->isRunning); + shoebill_mouse_click(1); + + // Warp experiment + + + + //[self say:[NSString stringWithFormat:@"view origin x=%f, y=%f, window origin x=%f, y=%f", rect.origin.x, rect.origin.y, winrect.origin.x, winrect.origin.y]]; + + } +} + +- (void)mouseUp:(NSEvent *)theEvent +{ + if (shoeApp->doCaptureMouse) { + assert(shoeApp->isRunning); + shoebill_mouse_click(0); + } +} + +@end diff --git a/gui/Shoebill/shoeScreenView.xib b/gui/Shoebill/shoeScreenView.xib new file mode 100644 index 0000000..6d86a58 --- /dev/null +++ b/gui/Shoebill/shoeScreenView.xib @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/Shoebill/shoeScreenWindow.h b/gui/Shoebill/shoeScreenWindow.h new file mode 100644 index 0000000..7bae283 --- /dev/null +++ b/gui/Shoebill/shoeScreenWindow.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + + +#import + +@interface shoeScreenWindow : NSWindow { + @public + uint8_t slotnum; +} + +- (void)configure:(uint8_t) _slotnum; +- (void)reevaluateKeyWindowness; +@end diff --git a/gui/Shoebill/shoeScreenWindow.m b/gui/Shoebill/shoeScreenWindow.m new file mode 100644 index 0000000..98977e2 --- /dev/null +++ b/gui/Shoebill/shoeScreenWindow.m @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#import "shoeScreenWindow.h" +#import "shoeApplication.h" +#import "shoeAppDelegate.h" + +@implementation shoeScreenWindow + +- (void)configure:(uint8_t) _slotnum +{ + slotnum = _slotnum; +} + +// Called after all the shoeScreenWindows are created and configured, +// because one of them was already made key while isRunning==NO, +// so -becomeKeyWindow didn't set doCapture=YES +- (void)reevaluateKeyWindowness +{ + shoeApplication *shoeApp = (shoeApplication*)NSApp; + + assert(shoeApp->isRunning); + + if ([self isKeyWindow]) { + shoeApp->doCaptureKeys = YES; + shoeApp->doCaptureMouse = YES; + CGDisplayHideCursor(0); + } + else { + shoeApp->doCaptureKeys = NO; + shoeApp->doCaptureMouse = NO; + CGDisplayShowCursor(0); + } +} + +- (void)becomeKeyWindow +{ + shoeApplication *shoeApp = (shoeApplication*)NSApp; + + if (shoeApp->isRunning) { + shoeApp->doCaptureKeys = YES; + shoeApp->doCaptureMouse = YES; + CGDisplayHideCursor(0); + } + [super becomeKeyWindow]; +} + +- (void)resignKeyWindow +{ + shoeApplication *shoeApp = (shoeApplication*)NSApp; + + if (shoeApp->isRunning) { + shoeApp->doCaptureKeys = NO; + shoeApp->doCaptureMouse = NO; + CGDisplayShowCursor(0); + } + [super resignKeyWindow]; +} + + +@end diff --git a/test.c b/test.c new file mode 100644 index 0000000..0842caa --- /dev/null +++ b/test.c @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "core/shoebill.h" +#include "core/core_api.h" + +shoebill_control_t control; +shoebill_card_video_t *video_card = NULL; + +void glut_display_func (void) +{ + uint32_t myw = glutGet(GLUT_WINDOW_WIDTH); + uint32_t myh = glutGet(GLUT_WINDOW_HEIGHT); + uint32_t slotnum, i; + shoebill_card_video_t *ctx = video_card; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, myw, 0, myh, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.1, 0.1, 0.8); + + uint32_t gli = 0; + + switch (ctx->depth) { + case 1: { + for (i=0; i < ctx->pixels/8; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1]; + ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1]; + ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1]; + ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1]; + ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1]; + ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1]; + ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1]; + ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1]; + } + break; + } + case 2: { + for (i=0; i < ctx->pixels/4; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3]; + ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3]; + ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3]; + ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3]; + } + break; + } + case 4: { + for (i=0; i < ctx->pixels/2; i++) { + const uint8_t byte = ctx->indexed_buf[i]; + ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf]; + ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf]; + } + break; + } + case 8: + for (i=0; i < ctx->pixels; i++) + ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]]; + break; + + default: + assert(!"unknown depth"); + } + + glViewport(0, 0, myw, myh); + glRasterPos2i(0, myh); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glPixelZoom(1.0, -1.0); + + glDrawPixels(myw, myh, GL_RGBA, GL_UNSIGNED_BYTE, ctx->direct_buf); + + glFlush(); +} + +/*void vbl_callback (shoebill_control_t *ctrl, uint8_t slotnum) +{ + + +} + +void video_depth_calback (sheobill_control_t *ctrl, uint8_t slotnum) +{ + + +}*/ + +#define KEY_SHIFT 1 + +const struct { + uint8_t code; + char c; + uint8_t modifiers; +} key_codes[] = { + {0x0, 'A', 0}, + {0x1, 'S', 0}, + {2, 'D', 0}, + {3, 'F', 0}, + {4, 'H', 0}, + {5, 'G', 0}, + {6, 'Z', 0}, + {7, 'X', 0}, + {8, 'C', 0}, + {9, 'V', 0}, + // {0xa ?? + {0xb, 'B', 0}, + {0xc, 'Q', 0}, + {0xd, 'W', 0}, + {0xe, 'E', 0}, + {0xf, 'R', 0}, + {0x10, 'Y', 0}, + {0x11, 'T', 0}, + + {0x12, '1', 0}, + {0x12, '!', KEY_SHIFT}, + + + {0x13, '2', 0}, + {0x13, '@', KEY_SHIFT}, + + {0x14, '3', 0}, + {0x14, '#', KEY_SHIFT}, + + {0x15, '4', 0}, + {0x15, '$', KEY_SHIFT}, + + {0x16, '6', 0}, + {0x16, '^', KEY_SHIFT}, + + {0x17, '5', 0}, + {0x17, '%', KEY_SHIFT}, + + {0x18, '=', 0}, + {0x18, '+', KEY_SHIFT}, + + {0x19, '9', 0}, + {0x19, '(', KEY_SHIFT}, + + {0x1a, '7', 0}, + {0x1a, '&', KEY_SHIFT}, + + {0x1b, '-', 0}, + {0x1b, '_', KEY_SHIFT}, + + {0x1c, '8', 0}, + {0x1c, '*', KEY_SHIFT}, + + {0x1d, '0', 0}, + {0x1d, ')', KEY_SHIFT}, + + {0x1e, ']', 0}, + {0x1e, '}', KEY_SHIFT}, + + {0x1f, 'O', 0}, + {0x20, 'U', 0}, + + {0x21, '[', 0}, + {0x21, '{', KEY_SHIFT}, + + {0x22, 'I', 0}, + {0x23, 'P', 0}, + + {0x24, '\n', 0}, + {0x24, '\r', 0}, + + {0x25, 'L', 0}, + {0x26, 'J', 0}, + + {0x27, '"', KEY_SHIFT}, + {0x27, '\'', 0}, + + {0x28, 'K', 0}, + + {0x29, ';', 0}, + {0x29, ':', KEY_SHIFT}, + + {0x2a, '\\', 0}, + {0x2a, '|', KEY_SHIFT}, + + {0x2b, ',', 0}, + {0x2b, '<', KEY_SHIFT}, + + {0x2c, '/', 0}, + {0x2c, '?', 0}, + + {0x2d, 'N', 0}, + {0x2e, 'M', 0}, + + {0x2f, '.', 0}, + {0x2f, '>', KEY_SHIFT}, + + {0x30, '\t', 0}, + {0x31, ' ', 0}, + + {0x32, '`', 0}, + {0x32, '~', KEY_SHIFT}, + + {0x33, '\b', 0}, + {0x33, 0x7f, 0}, + // {0x34, ?? + // {0x35 // escape char + // 0x36 // ctrl + // 0x37 // command + // 0x38 // shift + // 0x39 // caps lock + // 0x3a // option + // 0x3b // left arrow + // 0x3c // right arrow + // 0x3d // down arrow + // 0x3e // up arrow + + {0, 0, 0}, +}; + +static uint8_t lookup_key(char c) +{ + uint32_t i; + uint8_t upper=toupper(c); + + for (i=0; key_codes[i].c; i++) { + if (key_codes[i].c == upper) + return key_codes[i].code; + + } + + return 0xff; +} + +static uint8_t lookup_special(int special) +{ + switch (special) { + case GLUT_KEY_UP: return 0x3e; + case GLUT_KEY_DOWN: return 0x3d; + case GLUT_KEY_LEFT: return 0x3b; + case GLUT_KEY_RIGHT: return 0x3c; + default: return 0xff; + } +} + +static void keyboard_add_entry(uint8_t code, uint8_t up) +{ + uint8_t up_mask = up ? 0x80 : 0; + uint32_t i; + int modifiers = glutGetModifiers(); + + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + if ((shoe.key.key_i+1) < KEYBOARD_STATE_MAX_KEYS) { + if (modifiers & GLUT_ACTIVE_SHIFT) { + shoe.key.keys[shoe.key.key_i].code_a = 0x38; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } + else if (shoe.key.down_modifiers & GLUT_ACTIVE_SHIFT) { + shoe.key.keys[shoe.key.key_i].code_a = 0x80 | 0x38; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } + shoe.key.keys[shoe.key.key_i].code_a = code | up_mask; + shoe.key.keys[shoe.key.key_i].code_b = 0xff; + shoe.key.key_i++; + } + + shoe.key.down_modifiers = modifiers; + + adb_request_service_request(2); + + pthread_mutex_unlock(&shoe.adb.lock); +} + +void global_mouse_func (int button, int state, int x, int y) +{ + //if (button != GLUT_LEFT_BUTTON) + // return ; + + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + shoe.mouse.button_down = (state == GLUT_DOWN); + shoe.mouse.changed = 1; + + adb_request_service_request(3); + + pthread_mutex_unlock(&shoe.adb.lock); + + // printf("mouse_func: setting service request\n"); +} + +static void move_mouse (int x, int y, uint8_t button_down) +{ + printf("%s: lock\n", __func__); fflush(stdout); + assert(pthread_mutex_lock(&shoe.adb.lock) == 0); + + int32_t delta_x = x - shoe.mouse.old_x; + int32_t delta_y = y - shoe.mouse.old_y; + + shoe.mouse.old_x = x; + shoe.mouse.old_y = y; + + shoe.mouse.delta_x += delta_x; + shoe.mouse.delta_y += delta_y; + shoe.mouse.button_down = button_down; + shoe.mouse.changed = 1; + + adb_request_service_request(3); + printf("%s: unlock\n", __func__); fflush(stdout); + pthread_mutex_unlock(&shoe.adb.lock); + + // printf("move_mouse: setting service request\n"); +} + +void global_motion_func (int x, int y) +{ + move_mouse(x, y, 1); +} + +void global_passive_motion_func (int x, int y) +{ + move_mouse(x, y, 0); +} + +void global_keyboard_up_func (unsigned char c, int x, int y) +{ + uint8_t code = lookup_key(c); + if (code != 0xff) + keyboard_add_entry(code, 1); +} + +void global_keyboard_down_func (unsigned char c, int x, int y) +{ + uint8_t code = lookup_key(c); + if (code != 0xff) + keyboard_add_entry(code, 0); +} + +void global_special_up_func (int special, int x, int y) +{ + const uint8_t code = lookup_special(special); + if (code != 0xff) + keyboard_add_entry(code, 1); +} + +void global_special_down_func (int special, int x, int y) +{ + const uint8_t code = lookup_special(special); + if (code != 0xff) + keyboard_add_entry(code, 0); +} + +void timer_func (int arg) +{ + glutTimerFunc(15, timer_func, 0); // 66.67hz is the usual refresh interval (right?) + glutPostRedisplay(); +} + +int main (int argc, char **argv) +{ + bzero(&control, sizeof(shoebill_control_t)); + + control.aux_verbose = 1; + control.ram_size = 1024*1024*1024; + control.aux_kernel_path = "priv/unix2"; + control.rom_path = "priv/macii.rom"; + + control.scsi_devices[0].path = "priv/aux2.img"; + + uint32_t result = shoebill_initialize(&control); + if (!result) { + printf("fail: %s\n", control.error_msg); + return 0; + } + else + printf("success!\n"); + + shoebill_install_video_card(&control, 10, 800, 600, + (2.0/3.0) * 100.0); // 66.67hz + video_card = &control.slots[10].card.video; + + + int dummyargc = 1; + glutInit(&dummyargc, argv); + glutInitWindowSize(video_card->scanline_width, video_card->height); + glutCreateWindow(""); + glutDisplayFunc(glut_display_func); + glShadeModel(GL_FLAT); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glClearColor(0.1, 1.0, 0.1, 1.0); + + shoebill_start(); + + glutTimerFunc(15, timer_func, 0); + glutMainLoop(); + + return 0; +}