mirror of
https://github.com/pruten/shoebill.git
synced 2024-05-28 09:41:31 +00:00
First big barely-functional code drop
This commit is contained in:
parent
6b3a5839d2
commit
93cefd9451
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/intermediates
|
||||||
|
/shoebill
|
||||||
|
.DS_Store
|
||||||
|
*.xcworkspace
|
||||||
|
xcuserdata
|
26
LICENSE
26
LICENSE
|
@ -1,23 +1,23 @@
|
||||||
Copyright (c) 2014, pruten
|
Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without
|
||||||
are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
list of conditions and the following disclaimer.
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
this list of conditions and the following disclaimer in the documentation
|
||||||
list of conditions and the following disclaimer in the documentation and/or
|
and/or other materials provided with the distribution.
|
||||||
other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
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
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
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
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
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
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
16
Makefile
Normal file
16
Makefile
Normal file
|
@ -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
|
42
README
Normal file
42
README
Normal file
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
58
core/Makefile
Normal file
58
core/Makefile
Normal file
|
@ -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)
|
||||||
|
|
393
core/adb.c
Normal file
393
core/adb.c
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "../core/shoebill.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
4102
core/atrap_tab.c
Normal file
4102
core/atrap_tab.c
Normal file
File diff suppressed because it is too large
Load Diff
329
core/coff.c
Normal file
329
core/coff.c
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#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; i<cf->num_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; i<cf->num_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; i<cf->num_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; i<coff->num_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;
|
||||||
|
}
|
||||||
|
|
84
core/coff.h
Normal file
84
core/coff.h
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COFF_H
|
||||||
|
#define _COFF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#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
|
908
core/core_api.c
Normal file
908
core/core_api.c
Normal file
|
@ -0,0 +1,908 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#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<len; i+=2) {
|
||||||
|
printf("%02x%02x ", binary[i], binary[i+1]);
|
||||||
|
}
|
||||||
|
printf("] %s\n", str);
|
||||||
|
|
||||||
|
shoe.abort = old_abort;
|
||||||
|
shoe.suppress_exceptions = 0;
|
||||||
|
|
||||||
|
if (name && strcmp(name, "ui_ioctl")==0)
|
||||||
|
printregs();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void shoebill_start()
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&shoe.cpu_thread_lock);
|
||||||
|
pthread_mutex_unlock(&shoe.via_clock_thread_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _cpu_loop_fast()
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
if (shoe.cpu_thread_notifications) {
|
||||||
|
|
||||||
|
// If there's an interrupt pending
|
||||||
|
if (shoe.cpu_thread_notifications & 0xff) {
|
||||||
|
// process_pending_interrupt() may clear SHOEBILL_STATE_STOPPED
|
||||||
|
process_pending_interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
|
||||||
|
continue; // FIXME: yield or block on a condition variable here
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_SWITCH_MODE)
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _cpu_loop_debug()
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
if (shoe.cpu_thread_notifications) {
|
||||||
|
// I think we can safely ignore "stop" instructions for A/UX in debug mode
|
||||||
|
shoe.cpu_thread_notifications &= ~SHOEBILL_STATE_STOPPED;
|
||||||
|
|
||||||
|
if (shoe.cpu_thread_notifications & 0xff) {
|
||||||
|
process_pending_interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *_cpu_thread (void *arg) {
|
||||||
|
|
||||||
|
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
shoe.cpu_thread_notifications &= ~SHOEBILL_STATE_SWITCH_MODE;
|
||||||
|
|
||||||
|
if (shoe.cpu_mode == CPU_MODE_FAST)
|
||||||
|
_cpu_loop_fast();
|
||||||
|
else if (shoe.cpu_mode == CPU_MODE_DEBUG)
|
||||||
|
_cpu_loop_debug();
|
||||||
|
else if (shoe.cpu_mode == CPU_MODE_STEPI) {
|
||||||
|
cpu_step();
|
||||||
|
shoe.cpu_mode = CPU_MODE_STEPI_COMPLETE;
|
||||||
|
while (shoe.cpu_mode == CPU_MODE_STEPI_COMPLETE)
|
||||||
|
pthread_yield_np();
|
||||||
|
}
|
||||||
|
else if (shoe.cpu_mode == CPU_MODE_FREEZE) {
|
||||||
|
pthread_mutex_lock(&shoe.cpu_freeze_lock);
|
||||||
|
pthread_mutex_unlock(&shoe.cpu_freeze_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shoebill_cpu_stepi (void)
|
||||||
|
{
|
||||||
|
if (shoe.cpu_mode != CPU_MODE_FREEZE)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
shoe.cpu_mode = CPU_MODE_STEPI;
|
||||||
|
pthread_mutex_unlock(&shoe.cpu_freeze_lock);
|
||||||
|
|
||||||
|
// Just spin until the instruction completes - it should be quick
|
||||||
|
while (shoe.cpu_mode != CPU_MODE_STEPI_COMPLETE)
|
||||||
|
pthread_yield_np();
|
||||||
|
|
||||||
|
pthread_mutex_lock(&shoe.cpu_freeze_lock);
|
||||||
|
shoe.cpu_mode = CPU_MODE_FREEZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shoebill_cpu_freeze (void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&shoe.cpu_freeze_lock);
|
||||||
|
shoe.cpu_mode = CPU_MODE_FREEZE;
|
||||||
|
shoe.cpu_thread_notifications &= SHOEBILL_STATE_SWITCH_MODE;
|
||||||
|
|
||||||
|
while (shoe.cpu_thread_notifications & SHOEBILL_STATE_SWITCH_MODE);
|
||||||
|
pthread_yield_np();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The A/UX bootloader blasts this structure into memory
|
||||||
|
* somewhere before jumping into the kernel to commmunicate
|
||||||
|
* stuff like: which scsi device/partition is root?
|
||||||
|
*/
|
||||||
|
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; // Not the same as gestalt IDs!
|
||||||
|
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;
|
||||||
|
|
||||||
|
// A series of DrvQEl (drive queue elements) follow this structure
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Inside Macintosh: Files 2-85 throughtfully provides this information
|
||||||
|
* on the secret internal flags:
|
||||||
|
*
|
||||||
|
* The File Manager also maintains four flag bytes preceding each drive queue element.
|
||||||
|
* These bytes contain the following information:
|
||||||
|
* Byte (from low address to high address)
|
||||||
|
* 0 Bit 7=1 if the volume on the drive is locked
|
||||||
|
* 1 0 if no disk in drive; 1 or 2 if disk in drive; 8 if nonejectable disk in drive; $FC–$FF if
|
||||||
|
* disk was ejected within last 1.5 seconds; $48 if disk in drive is nonejectable but driver
|
||||||
|
* wants a call
|
||||||
|
* 2 Used internally during system startup
|
||||||
|
* 3 Bit 7=0 if disk is single-sided
|
||||||
|
* You can read these flags by subtracting 4 bytes from the beginning of a drive queue element,
|
||||||
|
* as illustrated in Listing 2-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct __attribute__ ((__packed__)) drive_queue_element {
|
||||||
|
/* Secret internal flags */
|
||||||
|
uint8_t unknown_1 : 7;
|
||||||
|
uint8_t is_locked : 1; // 1 if locked, 0 -> 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);
|
||||||
|
}
|
||||||
|
|
129
core/core_api.h
Normal file
129
core/core_api.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CORE_API_H
|
||||||
|
#define _CORE_API_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
3019
core/cpu.c
Normal file
3019
core/cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
1240
core/debugger.c
Normal file
1240
core/debugger.c
Normal file
File diff suppressed because it is too large
Load Diff
1484
core/decoder_gen.c
Normal file
1484
core/decoder_gen.c
Normal file
File diff suppressed because it is too large
Load Diff
1478
core/dis.c
Normal file
1478
core/dis.c
Normal file
File diff suppressed because it is too large
Load Diff
251
core/exception.c
Normal file
251
core/exception.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#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;
|
||||||
|
}
|
130
core/floppy.c
Normal file
130
core/floppy.c
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
1484
core/fpu.c
Normal file
1484
core/fpu.c
Normal file
File diff suppressed because it is too large
Load Diff
1520
core/macii_symbols.c
Normal file
1520
core/macii_symbols.c
Normal file
File diff suppressed because it is too large
Load Diff
562
core/macro.pl
Executable file
562
core/macro.pl
Executable file
|
@ -0,0 +1,562 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
# list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
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>) {
|
||||||
|
$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
|
||||||
|
}
|
||||||
|
|
446
core/mc68851.c
Normal file
446
core/mc68851.c
Normal file
|
@ -0,0 +1,446 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
64
core/mc68851.h
Normal file
64
core/mc68851.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// FIXME: unify all these weird instruction decoders (cpu/68881/68851)
|
||||||
|
|
||||||
|
#ifndef _MC68851_H
|
||||||
|
#define _MC68851_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
1172
core/mem.c
Normal file
1172
core/mem.c
Normal file
File diff suppressed because it is too large
Load Diff
267
core/redblack.c
Normal file
267
core/redblack.c
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
50
core/redblack.h
Normal file
50
core/redblack.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
763
core/scsi.c
Normal file
763
core/scsi.c
Normal file
|
@ -0,0 +1,763 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#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;
|
||||||
|
}
|
634
core/shoebill.h
Normal file
634
core/shoebill.h
Normal file
|
@ -0,0 +1,634 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SHOEBILL_H
|
||||||
|
#define _SHOEBILL_H
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <histedit.h>
|
||||||
|
|
||||||
|
#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
|
321
core/toby_frame_buffer.c
Normal file
321
core/toby_frame_buffer.c
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <GLUT/glut.h>
|
||||||
|
#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; i<size; i++)
|
||||||
|
result = (result << 8) | ctx->buf_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; i<size; i++) {
|
||||||
|
ctx->buf_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 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
441
core/via.c
Normal file
441
core/via.c
Normal file
|
@ -0,0 +1,441 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#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<<priority))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore interrupt levels less than sr_mask (pri 7 is NMI)
|
||||||
|
if (priority <= sr_mask())
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the CPU was stopped, unstop it
|
||||||
|
shoe.cpu_thread_notifications &= ~~SHOEBILL_STATE_STOPPED;
|
||||||
|
|
||||||
|
printf("Interrupt pri %u! mask=%u\n", priority, sr_mask());
|
||||||
|
|
||||||
|
const uint16_t vector_offset = (priority + 24) * 4;
|
||||||
|
|
||||||
|
// Save the old SR, and switch to supervisor mode
|
||||||
|
const uint16_t old_sr = shoe.sr;
|
||||||
|
set_sr_s(1);
|
||||||
|
|
||||||
|
// Write a "format 0" exception frame to ISP or MSP
|
||||||
|
push_a7(0x0000 | vector_offset, 2);
|
||||||
|
printf("interrupt: pushed format 0x%04x to 0x%08x\n", 0x0000 | vector_offset, shoe.a[7]);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
|
||||||
|
push_a7(shoe.pc, 4);
|
||||||
|
printf("interrupt: pushed pc 0x%08x to 0x%08x\n", shoe.pc, shoe.a[7]);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
|
||||||
|
push_a7(old_sr, 2);
|
||||||
|
printf("interrupt: pushed sr 0x%04x to 0x%08x\n", old_sr, shoe.a[7]);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
|
||||||
|
|
||||||
|
if (sr_m()) {
|
||||||
|
// clear sr_m, and write a format 1 exception to the ISP
|
||||||
|
const uint16_t old_sr2 = shoe.sr;
|
||||||
|
|
||||||
|
set_sr_m(0);
|
||||||
|
|
||||||
|
push_a7(0x1000 | vector_offset, 2);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
|
||||||
|
push_a7(shoe.pc, 4);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
|
||||||
|
push_a7(old_sr2, 2);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the autovector handler address
|
||||||
|
const uint32_t newpc = lget(shoe.vbr + vector_offset, 4);
|
||||||
|
assert(!shoe.abort);
|
||||||
|
|
||||||
|
shoe.pc = newpc;
|
||||||
|
|
||||||
|
// Clear this pending interrupt bit
|
||||||
|
shoe.cpu_thread_notifications &= ~~(1 << priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reset:
|
||||||
|
Host sends command, switch to state 0
|
||||||
|
Device sends byte 1
|
||||||
|
Host switches to state 2
|
||||||
|
Device sends byte 2
|
||||||
|
Host switches to state 3
|
||||||
|
|
||||||
|
Talk:
|
||||||
|
Host sends command, switch to state 0
|
||||||
|
Device sends byte 0 (even)
|
||||||
|
Hosts switches to state 1 (even = "just got even byte")
|
||||||
|
Device sends byte 1 (odd)
|
||||||
|
Host switches to state 2 (odd = "just got odd byte")
|
||||||
|
Device sends byte 2 (even)
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// via1 ORB bits abcd efgh
|
||||||
|
// cd -> 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<<IFR_CA1)))
|
||||||
|
//via->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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
331
core/video.c
Normal file
331
core/video.c
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <GLUT/glut.h>
|
||||||
|
#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<len; i++) {
|
||||||
|
uint8_t byte = rom[i];
|
||||||
|
|
||||||
|
if (i==(len-9) || i==(len-10) || i==(len-11) || i==(len-12))
|
||||||
|
byte = 0;
|
||||||
|
|
||||||
|
sum = (sum << 1) + (sum >> 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; i<size; i++) {
|
||||||
|
result <<= 8;
|
||||||
|
result |= ctx->indexed_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
core/video_rom/rom.bin
Normal file
BIN
core/video_rom/rom.bin
Normal file
Binary file not shown.
513
core/video_rom/rom.c
Normal file
513
core/video_rom/rom.c
Normal file
|
@ -0,0 +1,513 @@
|
||||||
|
uint8_t _video_rom[4096] = {
|
||||||
|
0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x03, 0x84,
|
||||||
|
0x05, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04,
|
||||||
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x84, 0x05, 0xa0,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x03, 0x84, 0x05, 0xa0, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||||
|
0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x05, 0xa0, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x03, 0x84, 0x05, 0xa0, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00,
|
||||||
|
0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08,
|
||||||
|
0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x00, 0x7e,
|
||||||
|
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x18,
|
||||||
|
0x02, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x50,
|
||||||
|
0x22, 0x00, 0x00, 0x2c, 0x24, 0x00, 0x00, 0x3e,
|
||||||
|
0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x53, 0x68, 0x6f, 0x65,
|
||||||
|
0x62, 0x69, 0x6c, 0x6c, 0x20, 0x50, 0x68, 0x6f,
|
||||||
|
0x6e, 0x79, 0x20, 0x56, 0x69, 0x64, 0x65, 0x6f,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
|
||||||
|
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||||
|
0x31, 0x7c, 0x00, 0x01, 0x00, 0x02, 0x2a, 0x48,
|
||||||
|
0x4e, 0x75, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00,
|
||||||
|
0x00, 0x14, 0x04, 0x00, 0x00, 0x18, 0x53, 0x68,
|
||||||
|
0x6f, 0x65, 0x62, 0x69, 0x6c, 0x6c, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x52, 0x65, 0x76, 0x2d, 0x31, 0x00,
|
||||||
|
0x00, 0x00, 0x4d, 0x6f, 0x6f, 0x66, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x9c, 0x02, 0x00,
|
||||||
|
0x00, 0x78, 0x04, 0x00, 0x00, 0x9c, 0x08, 0x00,
|
||||||
|
0x00, 0x01, 0x0c, 0x00, 0x00, 0x64, 0x0d, 0x00,
|
||||||
|
0x00, 0x64, 0x80, 0x00, 0x00, 0x14, 0x81, 0x00,
|
||||||
|
0x00, 0x20, 0x82, 0x00, 0x00, 0x2c, 0x83, 0x00,
|
||||||
|
0x00, 0x38, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
|
||||||
|
0xfe, 0x9a, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
|
||||||
|
0xfe, 0xb8, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
|
||||||
|
0xfe, 0xd6, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
|
||||||
|
0xfe, 0xf4, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x44, 0x69,
|
||||||
|
0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x56, 0x69,
|
||||||
|
0x64, 0x65, 0x6f, 0x5f, 0x41, 0x70, 0x70, 0x6c,
|
||||||
|
0x65, 0x5f, 0x53, 0x68, 0x6f, 0x65, 0x62, 0x69,
|
||||||
|
0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||||
|
0x00, 0x01, 0x00, 0x01, 0x54, 0x03, 0x02, 0x00,
|
||||||
|
0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0xa6, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x62,
|
||||||
|
0x01, 0x62, 0x01, 0x70, 0x1d, 0x2e, 0x44, 0x69,
|
||||||
|
0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x56, 0x69,
|
||||||
|
0x64, 0x65, 0x6f, 0x5f, 0x41, 0x70, 0x70, 0x6c,
|
||||||
|
0x65, 0x5f, 0x53, 0x68, 0x6f, 0x65, 0x62, 0x69,
|
||||||
|
0x6c, 0x6c, 0x00, 0x00, 0x24, 0x48, 0x26, 0x49,
|
||||||
|
0x70, 0x10, 0xa7, 0x1e, 0x66, 0x00, 0x01, 0x64,
|
||||||
|
0x49, 0xfa, 0x01, 0x3e, 0x31, 0x7c, 0x00, 0x06,
|
||||||
|
0x00, 0x04, 0x21, 0x4c, 0x00, 0x08, 0x21, 0x6b,
|
||||||
|
0x00, 0x2a, 0x00, 0x0c, 0x70, 0x00, 0x10, 0x2b,
|
||||||
|
0x00, 0x28, 0xa0, 0x75, 0x66, 0x00, 0x01, 0x44,
|
||||||
|
0x70, 0x00, 0x4e, 0x75, 0x48, 0xe7, 0x7f, 0xfe,
|
||||||
|
0x72, 0x00, 0x32, 0x28, 0x00, 0x1a, 0x24, 0x69,
|
||||||
|
0x00, 0x2a, 0xd5, 0xfc, 0x00, 0xf0, 0x00, 0x00,
|
||||||
|
0x26, 0x68, 0x00, 0x1c, 0x0c, 0x41, 0x00, 0x00,
|
||||||
|
0x66, 0x00, 0x00, 0x16, 0x25, 0x78, 0x00, 0x80,
|
||||||
|
0x00, 0x04, 0x25, 0x7c, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x00, 0x08, 0x70, 0x00, 0x60, 0x00, 0x00, 0xc8,
|
||||||
|
0x0c, 0x41, 0x00, 0x01, 0x66, 0x00, 0x00, 0x08,
|
||||||
|
0x70, 0x00, 0x60, 0x00, 0x00, 0xba, 0x0c, 0x41,
|
||||||
|
0x00, 0x02, 0x66, 0x00, 0x00, 0x0c, 0x35, 0x53,
|
||||||
|
0x00, 0x04, 0x70, 0x00, 0x60, 0x00, 0x00, 0xa8,
|
||||||
|
0x0c, 0x41, 0x00, 0x03, 0x66, 0x00, 0x00, 0x4a,
|
||||||
|
0x28, 0x53, 0x74, 0x00, 0x34, 0x2b, 0x00, 0x04,
|
||||||
|
0x76, 0x00, 0x36, 0x2b, 0x00, 0x06, 0x0c, 0x42,
|
||||||
|
0xff, 0xff, 0x66, 0x00, 0x00, 0x04, 0x4e, 0x70,
|
||||||
|
0x28, 0x02, 0xe7, 0x8c, 0xd9, 0xc4, 0x52, 0x83,
|
||||||
|
0x78, 0x00, 0x25, 0x42, 0x00, 0x0c, 0x35, 0x6c,
|
||||||
|
0x00, 0x02, 0x00, 0x10, 0x35, 0x6c, 0x00, 0x04,
|
||||||
|
0x00, 0x14, 0x35, 0x6c, 0x00, 0x06, 0x00, 0x18,
|
||||||
|
0x52, 0x82, 0x50, 0x8c, 0x52, 0x84, 0xb6, 0x44,
|
||||||
|
0x66, 0xe0, 0x70, 0xef, 0x60, 0x00, 0x00, 0x58,
|
||||||
|
0x0c, 0x41, 0x00, 0x04, 0x66, 0x00, 0x00, 0x08,
|
||||||
|
0x70, 0xef, 0x60, 0x00, 0x00, 0x4a, 0x0c, 0x41,
|
||||||
|
0x00, 0x05, 0x66, 0x00, 0x00, 0x08, 0x70, 0xef,
|
||||||
|
0x60, 0x00, 0x00, 0x3c, 0x0c, 0x41, 0x00, 0x06,
|
||||||
|
0x66, 0x00, 0x00, 0x08, 0x70, 0xef, 0x60, 0x00,
|
||||||
|
0x00, 0x2e, 0x0c, 0x41, 0x00, 0x07, 0x66, 0x00,
|
||||||
|
0x00, 0x08, 0x70, 0xef, 0x60, 0x00, 0x00, 0x20,
|
||||||
|
0x0c, 0x41, 0x00, 0x08, 0x66, 0x00, 0x00, 0x08,
|
||||||
|
0x70, 0xef, 0x60, 0x00, 0x00, 0x12, 0x0c, 0x41,
|
||||||
|
0x00, 0x09, 0x66, 0x00, 0x00, 0x08, 0x70, 0xef,
|
||||||
|
0x60, 0x00, 0x00, 0x04, 0x70, 0xef, 0x4c, 0xdf,
|
||||||
|
0x7f, 0xfe, 0x4e, 0x75, 0x26, 0x7c, 0xfa, 0x00,
|
||||||
|
0xbe, 0xef, 0x26, 0xbc, 0xde, 0xad, 0xbe, 0xef,
|
||||||
|
0x4e, 0x70, 0x26, 0x7c, 0xfa, 0x00, 0xbe, 0xef,
|
||||||
|
0x26, 0xbc, 0xde, 0xad, 0xbe, 0xef, 0x4e, 0x70,
|
||||||
|
0x20, 0x09, 0xe1, 0x98, 0x02, 0x80, 0x00, 0x00,
|
||||||
|
0x00, 0x0f, 0x20, 0x49, 0xd1, 0xfc, 0x00, 0xf0,
|
||||||
|
0x00, 0x00, 0x20, 0xbc, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
0x20, 0x78, 0x0d, 0x28, 0x4e, 0x90, 0x70, 0x01,
|
||||||
|
0x4e, 0x75, 0x4e, 0x70, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x00, 0xff, 0xf0, 0xcc,
|
||||||
|
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x01, 0x5a, 0x93, 0x2b, 0xc7, 0x00, 0xe1};
|
33
core/video_rom/rom_to_c.c
Normal file
33
core/video_rom/rom_to_c.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
1
core/video_rom/shoebill_video.make
Normal file
1
core/video_rom/shoebill_video.make
Normal file
|
@ -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
|
1
core/video_rom/shoebill_video_driver.a
Normal file
1
core/video_rom/shoebill_video_driver.a
Normal file
|
@ -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
|
1
core/video_rom/shoebill_video_primary_init.a
Normal file
1
core/video_rom/shoebill_video_primary_init.a
Normal file
|
@ -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
|
1
core/video_rom/shoebill_video_rom.a
Normal file
1
core/video_rom/shoebill_video_rom.a
Normal file
File diff suppressed because one or more lines are too long
381
gui/Shoebill.xcodeproj/project.pbxproj
Normal file
381
gui/Shoebill.xcodeproj/project.pbxproj
Normal file
|
@ -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 = "<group>"; };
|
||||||
|
8749544618999F5300E80F5B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
|
||||||
|
874954481899A22D00E80F5B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
|
||||||
|
8781D24918A19C340016F604 /* shoePreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoePreferencesWindowController.h; sourceTree = "<group>"; };
|
||||||
|
8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoePreferencesWindowController.m; sourceTree = "<group>"; };
|
||||||
|
8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = shoePreferencesWindowController.xib; sourceTree = "<group>"; };
|
||||||
|
8782FCE2189AFEFB0081E19E /* shoeApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeApplication.h; sourceTree = "<group>"; };
|
||||||
|
8782FCE3189AFEFB0081E19E /* shoeApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeApplication.m; sourceTree = "<group>"; };
|
||||||
|
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 = "<group>"; };
|
||||||
|
87F9773518987700000D589E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
87F9773718987700000D589E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
87F9773918987700000D589E /* Shoebill-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Shoebill-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
|
87F9773B18987700000D589E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
|
||||||
|
87F9773D18987700000D589E /* shoeAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = shoeAppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
87F9773E18987700000D589E /* shoeAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = shoeAppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
87F9774118987700000D589E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
|
87F9774318987700000D589E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||||
|
87F9775F18987767000D589E /* shoeScreenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeScreenView.h; sourceTree = "<group>"; };
|
||||||
|
87F9776018987767000D589E /* shoeScreenView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeScreenView.m; sourceTree = "<group>"; };
|
||||||
|
87F977641898790B000D589E /* libshoebill_core.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libshoebill_core.a; path = ../../intermediates/libshoebill_core.a; sourceTree = "<group>"; };
|
||||||
|
AE75B30718A8210D00E66DB6 /* shoeScreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeScreenWindow.h; sourceTree = "<group>"; };
|
||||||
|
AE75B30818A8210D00E66DB6 /* shoeScreenWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeScreenWindow.m; sourceTree = "<group>"; };
|
||||||
|
/* 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 = "<group>";
|
||||||
|
};
|
||||||
|
87F9772918987700000D589E /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
87F9772818987700000D589E /* Shoebill.app */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
87F9772A18987700000D589E /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
874954481899A22D00E80F5B /* QuartzCore.framework */,
|
||||||
|
8749544618999F5300E80F5B /* OpenGL.framework */,
|
||||||
|
87F9772B18987700000D589E /* Cocoa.framework */,
|
||||||
|
87F9772D18987700000D589E /* Other Frameworks */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
87F9772D18987700000D589E /* Other Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
87F9772E18987700000D589E /* AppKit.framework */,
|
||||||
|
87F9772F18987700000D589E /* CoreData.framework */,
|
||||||
|
87F9773018987700000D589E /* Foundation.framework */,
|
||||||
|
);
|
||||||
|
name = "Other Frameworks";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
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 = "<group>";
|
||||||
|
};
|
||||||
|
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 = "<group>";
|
||||||
|
};
|
||||||
|
/* 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 = "<group>";
|
||||||
|
};
|
||||||
|
87F9773A18987700000D589E /* Credits.rtf */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
87F9773B18987700000D589E /* en */,
|
||||||
|
);
|
||||||
|
name = Credits.rtf;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
87F9774018987700000D589E /* MainMenu.xib */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
87F9774118987700000D589E /* Base */,
|
||||||
|
);
|
||||||
|
name = MainMenu.xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* 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 */;
|
||||||
|
}
|
188
gui/Shoebill/Base.lproj/MainMenu.xib
Normal file
188
gui/Shoebill/Base.lproj/MainMenu.xib
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
|
<dependencies>
|
||||||
|
<deployment defaultVersion="1080" identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="shoeApplication">
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="494" id="495"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="shoeApplication"/>
|
||||||
|
<menu title="AMainMenu" systemMenu="main" id="29">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Shoebill" id="56">
|
||||||
|
<menu key="submenu" title="Shoebill" systemMenu="apple" id="57">
|
||||||
|
<items>
|
||||||
|
<menuItem title="About Shoebill" id="58">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="236">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Preferences…" keyEquivalent="," id="129">
|
||||||
|
<connections>
|
||||||
|
<action selector="showWindow:" target="VMD-IW-vcf" id="AoF-Ai-TV4"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="143">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Services" id="131">
|
||||||
|
<menu key="submenu" title="Services" systemMenu="services" id="130"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="144">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Hide Shoebill" keyEquivalent="h" id="134">
|
||||||
|
<connections>
|
||||||
|
<action selector="hide:" target="-1" id="367"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Hide Others" keyEquivalent="h" id="145">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="hideOtherApplications:" target="-1" id="368"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Show All" id="150">
|
||||||
|
<connections>
|
||||||
|
<action selector="unhideAllApplications:" target="-1" id="370"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="149">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Quit Shoebill" keyEquivalent="q" id="136">
|
||||||
|
<connections>
|
||||||
|
<action selector="terminate:" target="-3" id="449"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="File" id="83">
|
||||||
|
<menu key="submenu" title="File" id="81">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Run" keyEquivalent="r" id="82">
|
||||||
|
<connections>
|
||||||
|
<action selector="runMenuItem:" target="-2" id="eMo-K7-j0j"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="79">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Close" keyEquivalent="w" id="73">
|
||||||
|
<connections>
|
||||||
|
<action selector="performClose:" target="-1" id="193"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="74">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Page Setup..." keyEquivalent="P" id="77">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="runPageLayout:" target="-1" id="87"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Print…" keyEquivalent="p" id="78">
|
||||||
|
<connections>
|
||||||
|
<action selector="print:" target="-1" id="86"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Edit" id="217">
|
||||||
|
<menu key="submenu" title="Edit" id="205">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Undo" keyEquivalent="z" id="207">
|
||||||
|
<connections>
|
||||||
|
<action selector="undo:" target="-1" id="223"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Redo" keyEquivalent="Z" id="215">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="redo:" target="-1" id="231"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="206">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Cut" keyEquivalent="x" id="199">
|
||||||
|
<connections>
|
||||||
|
<action selector="cut:" target="-1" id="228"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy" keyEquivalent="c" id="197">
|
||||||
|
<connections>
|
||||||
|
<action selector="copy:" target="-1" id="224"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste" keyEquivalent="v" id="203">
|
||||||
|
<connections>
|
||||||
|
<action selector="paste:" target="-1" id="226"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="214">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Select All" keyEquivalent="a" id="198">
|
||||||
|
<connections>
|
||||||
|
<action selector="selectAll:" target="-1" id="232"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Window" id="19">
|
||||||
|
<menu key="submenu" title="Window" systemMenu="window" id="24">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Minimize" keyEquivalent="m" id="23">
|
||||||
|
<connections>
|
||||||
|
<action selector="performMiniaturize:" target="-1" id="37"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Zoom" id="239">
|
||||||
|
<connections>
|
||||||
|
<action selector="performZoom:" target="-1" id="240"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="92">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Bring All to Front" id="5">
|
||||||
|
<connections>
|
||||||
|
<action selector="arrangeInFront:" target="-1" id="39"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Help" id="490">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Help" systemMenu="help" id="491">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Shoebill Help" keyEquivalent="?" id="492">
|
||||||
|
<connections>
|
||||||
|
<action selector="showHelp:" target="-1" id="493"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
<customObject id="494" customClass="shoeAppDelegate"/>
|
||||||
|
<customObject id="420" customClass="NSFontManager"/>
|
||||||
|
<customObject id="VMD-IW-vcf" userLabel="Preferences" customClass="shoePreferencesWindowController"/>
|
||||||
|
</objects>
|
||||||
|
</document>
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
34
gui/Shoebill/Shoebill-Info.plist
Normal file
34
gui/Shoebill/Shoebill-Info.plist
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>org.shoebill.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2014 Peter Rutenbar. All rights reserved.</string>
|
||||||
|
<key>NSMainNibFile</key>
|
||||||
|
<string>MainMenu</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>shoeApplication</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
9
gui/Shoebill/Shoebill-Prefix.pch
Normal file
9
gui/Shoebill/Shoebill-Prefix.pch
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
//
|
||||||
|
// Prefix header
|
||||||
|
//
|
||||||
|
// The contents of this file are implicitly included at the beginning of every source file.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
29
gui/Shoebill/en.lproj/Credits.rtf
Normal file
29
gui/Shoebill/en.lproj/Credits.rtf
Normal file
|
@ -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\
|
||||||
|
}
|
2
gui/Shoebill/en.lproj/InfoPlist.strings
Normal file
2
gui/Shoebill/en.lproj/InfoPlist.strings
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/* Localized versions of Info.plist keys */
|
||||||
|
|
6
gui/Shoebill/main.m
Normal file
6
gui/Shoebill/main.m
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[])
|
||||||
|
{
|
||||||
|
return NSApplicationMain(argc, argv);
|
||||||
|
}
|
36
gui/Shoebill/shoeAppDelegate.h
Normal file
36
gui/Shoebill/shoeAppDelegate.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface shoeAppDelegate : NSObject <NSApplicationDelegate> {
|
||||||
|
|
||||||
|
@public
|
||||||
|
NSWindowController *windowController;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (assign) IBOutlet NSWindow *window;
|
||||||
|
|
||||||
|
@end
|
40
gui/Shoebill/shoeAppDelegate.m
Normal file
40
gui/Shoebill/shoeAppDelegate.m
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "shoeAppDelegate.h"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation shoeAppDelegate
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||||
|
{
|
||||||
|
/*windowController = [[NSWindowController alloc] initWithWindowNibName:@"shoeScreenView"];
|
||||||
|
[windowController showWindow:nil];
|
||||||
|
[windowController.window makeKeyAndOrderFront:nil];*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
42
gui/Shoebill/shoeApplication.h
Normal file
42
gui/Shoebill/shoeApplication.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#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
|
317
gui/Shoebill/shoeApplication.m
Normal file
317
gui/Shoebill/shoeApplication.m
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
42
gui/Shoebill/shoePreferencesWindowController.h
Normal file
42
gui/Shoebill/shoePreferencesWindowController.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@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
|
190
gui/Shoebill/shoePreferencesWindowController.m
Normal file
190
gui/Shoebill/shoePreferencesWindowController.m
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
438
gui/Shoebill/shoePreferencesWindowController.xib
Normal file
438
gui/Shoebill/shoePreferencesWindowController.xib
Normal file
|
@ -0,0 +1,438 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
|
<dependencies>
|
||||||
|
<deployment defaultVersion="1080" identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="shoePreferencesWindowController">
|
||||||
|
<connections>
|
||||||
|
<outlet property="kernelPath" destination="ZXf-9X-ulR" id="fFe-5B-6dc"/>
|
||||||
|
<outlet property="memorySize" destination="uvm-gd-pCd" id="zzI-jI-ZUW"/>
|
||||||
|
<outlet property="romPath" destination="LoN-Nd-9cy" id="R3k-vY-TPo"/>
|
||||||
|
<outlet property="screenHeight" destination="Wyt-jg-xmk" id="Sq6-IJ-xbQ"/>
|
||||||
|
<outlet property="screenWidth" destination="EMf-gC-m9T" id="xxW-Ji-t7R"/>
|
||||||
|
<outlet property="scsiPath0" destination="nhQ-gw-2di" id="Ayi-Wk-Nhf"/>
|
||||||
|
<outlet property="scsiPath1" destination="8th-va-hXP" id="xTk-Kd-9v2"/>
|
||||||
|
<outlet property="scsiPath2" destination="RTT-NZ-Tte" id="w7D-05-cvN"/>
|
||||||
|
<outlet property="scsiPath3" destination="pKG-3S-zID" id="2nc-18-YUX"/>
|
||||||
|
<outlet property="scsiPath4" destination="Biz-iI-IiP" id="gbh-Jl-dxV"/>
|
||||||
|
<outlet property="scsiPath5" destination="GE2-3P-G1I" id="ohD-Fj-EX9"/>
|
||||||
|
<outlet property="scsiPath6" destination="cy8-jg-woV" id="QoH-Z0-e8d"/>
|
||||||
|
<outlet property="verbose" destination="RnS-Yp-G7M" id="VjB-1f-ejM"/>
|
||||||
|
<outlet property="window" destination="rKy-wc-8AE" id="sYz-fH-ohd"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application"/>
|
||||||
|
<window title="Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" wantsToBeColor="NO" visibleAtLaunch="NO" animationBehavior="default" id="rKy-wc-8AE">
|
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
||||||
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
|
<rect key="contentRect" x="196" y="240" width="498" height="433"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
|
||||||
|
<view key="contentView" id="4Fm-p8-6h9">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="498" height="433"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<tabView fixedFrame="YES" drawsBackground="NO" initialItem="Ffn-1Z-2rp" translatesAutoresizingMaskIntoConstraints="NO" id="i29-bb-k7Y">
|
||||||
|
<rect key="frame" x="13" y="33" width="472" height="394"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<tabViewItems>
|
||||||
|
<tabViewItem label="General" identifier="1" id="Ffn-1Z-2rp">
|
||||||
|
<view key="view" ambiguous="YES" id="BF8-Dm-rF5">
|
||||||
|
<rect key="frame" x="10" y="33" width="452" height="348"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Nqd-aN-fI5">
|
||||||
|
<rect key="frame" x="12" y="311" width="81" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Kernel Path:" usesSingleLineMode="YES" id="i7G-KP-OrH">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oVj-nA-5GP">
|
||||||
|
<rect key="frame" x="12" y="264" width="81" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Rom Path:" usesSingleLineMode="YES" id="7qD-i1-FXI">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="kernelPathBrowse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Dep-2G-fPK">
|
||||||
|
<rect key="frame" x="359" y="300" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Dnb-hA-OHJ">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="hW9-m5-Ovo"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="kernelPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZXf-9X-ulR">
|
||||||
|
<rect key="frame" x="99" y="289" width="258" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="unix" drawsBackground="YES" id="gUb-0H-eoA">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="romPathBrowse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="fjl-Jg-nIF">
|
||||||
|
<rect key="frame" x="359" y="253" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ITb-nX-hmP">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="NQd-R9-Nge"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="romPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LoN-Nd-9cy">
|
||||||
|
<rect key="frame" x="99" y="242" width="258" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="macii.rom" drawsBackground="YES" id="IvC-yQ-qdn">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RDI-wU-bdg">
|
||||||
|
<rect key="frame" x="3" y="217" width="90" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Memory (MB):" usesSingleLineMode="YES" id="8mu-le-9YC">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uvm-gd-pCd">
|
||||||
|
<rect key="frame" x="99" y="212" width="42" height="22"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="8" placeholderString="8" drawsBackground="YES" id="I5v-kb-eCo">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tgt-1x-QT0">
|
||||||
|
<rect key="frame" x="3" y="160" width="90" height="42"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" allowsUndo="NO" alignment="right" title="Screen Resolution:" id="9bl-WA-bhb">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JNe-0k-g4e">
|
||||||
|
<rect key="frame" x="147" y="174" width="14" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" allowsUndo="NO" alignment="center" title="x" id="9cf-Xq-tuu">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aSg-xG-o1t">
|
||||||
|
<rect key="frame" x="224" y="173" width="59" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" allowsUndo="NO" alignment="left" title="pixels" id="D5V-Zm-Grd">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EMf-gC-m9T">
|
||||||
|
<rect key="frame" x="99" y="170" width="43" height="22"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="width" placeholderString="width" drawsBackground="YES" id="sbq-WW-C05">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wyt-jg-xmk">
|
||||||
|
<rect key="frame" x="169" y="170" width="49" height="22"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="height" placeholderString="height" drawsBackground="YES" id="qvE-Bk-NDl">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RnS-Yp-G7M">
|
||||||
|
<rect key="frame" x="295" y="210" width="142" height="18"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="check" title="A/UX Verbose Boot" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Ww6-qg-dn1">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
</tabViewItem>
|
||||||
|
<tabViewItem label="Disks" identifier="2" id="doq-vE-JoC">
|
||||||
|
<view key="view" id="zUz-5u-7yG">
|
||||||
|
<rect key="frame" x="10" y="33" width="452" height="348"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dA0-AE-SsA">
|
||||||
|
<rect key="frame" x="1" y="321" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 0" usesSingleLineMode="YES" id="YYd-8o-kqe">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath0Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="BUV-3F-sRD">
|
||||||
|
<rect key="frame" x="353" y="310" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Ekq-OL-WH9">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="Ui7-aN-BsV"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath0" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="nhQ-gw-2di">
|
||||||
|
<rect key="frame" x="79" y="299" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="4NZ-tu-sNu">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gjz-Nn-CkC">
|
||||||
|
<rect key="frame" x="1" y="274" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 1" usesSingleLineMode="YES" id="oPB-iw-Fuy">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath1Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="0OE-Ny-sRU">
|
||||||
|
<rect key="frame" x="353" y="263" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="iRT-nY-bQx">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="X8s-cd-MI2"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath1" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8th-va-hXP">
|
||||||
|
<rect key="frame" x="79" y="252" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="wM4-Hu-6dD">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="17i-H8-woP">
|
||||||
|
<rect key="frame" x="1" y="227" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 2" usesSingleLineMode="YES" id="rWu-qs-tIH">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath2Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="OS6-vm-18P">
|
||||||
|
<rect key="frame" x="353" y="216" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ojq-kT-7Hz">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="kS3-Pk-jYF"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath2" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RTT-NZ-Tte">
|
||||||
|
<rect key="frame" x="79" y="205" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="bx9-L2-52p">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zeV-Os-yjZ">
|
||||||
|
<rect key="frame" x="1" y="180" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 3" usesSingleLineMode="YES" id="4Ir-Qy-6TG">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath3Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="hyG-x9-NBA">
|
||||||
|
<rect key="frame" x="353" y="169" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Toc-PB-8FO">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="azt-xR-Nhi"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath3" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pKG-3S-zID">
|
||||||
|
<rect key="frame" x="79" y="158" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="Ksz-dn-t4g">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rpv-lh-1BC">
|
||||||
|
<rect key="frame" x="1" y="133" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 4" usesSingleLineMode="YES" id="RSB-J8-WHv">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath4Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="FUw-LT-FRg">
|
||||||
|
<rect key="frame" x="353" y="122" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="CDZ-hc-2Kz">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="Jmt-T5-ePc"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath4" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Biz-iI-IiP">
|
||||||
|
<rect key="frame" x="79" y="111" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="j2E-vU-3LZ">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eGO-wX-v7I">
|
||||||
|
<rect key="frame" x="1" y="86" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 5" usesSingleLineMode="YES" id="lVw-XZ-DkQ">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath5Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Ur1-2a-9nV">
|
||||||
|
<rect key="frame" x="353" y="75" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QW3-hO-eDz">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="v9q-PV-Eva"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath5" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GE2-3P-G1I">
|
||||||
|
<rect key="frame" x="79" y="64" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="BrK-XM-gcx">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c4H-Kt-ANK">
|
||||||
|
<rect key="frame" x="1" y="39" width="72" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 6" usesSingleLineMode="YES" id="NS8-2m-U2B">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button identifier="scsiPath6Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Twn-Yd-cyf">
|
||||||
|
<rect key="frame" x="353" y="28" width="97" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JNl-qq-v8p">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browsePressed:" target="-2" id="WZ9-XG-oJD"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField identifier="scsiPath6" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cy8-jg-woV">
|
||||||
|
<rect key="frame" x="79" y="17" width="272" height="39"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="gZa-0y-cOt">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
</tabViewItem>
|
||||||
|
</tabViewItems>
|
||||||
|
</tabView>
|
||||||
|
<button identifier="applyAndRun" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r8k-B7-iXM">
|
||||||
|
<rect key="frame" x="352" y="5" width="132" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Apply and Run" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="oR1-x8-VgY">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="applyAndRunPressed:" target="-2" id="zan-RK-Z0V"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button identifier="cancel" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T6y-kh-jgH">
|
||||||
|
<rect key="frame" x="188" y="5" width="82" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Sk4-hr-Ot6">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<string key="keyEquivalent" base64-UTF8="YES">
|
||||||
|
Gw
|
||||||
|
</string>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="cancelPressed:" target="-2" id="WEd-0w-LNd"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button identifier="apply" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZDd-0H-a3B">
|
||||||
|
<rect key="frame" x="270" y="5" width="82" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bC6-3u-5Op">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<string key="keyEquivalent" base64-UTF8="YES">
|
||||||
|
Gw
|
||||||
|
</string>
|
||||||
|
<connections>
|
||||||
|
<action selector="applyPressed:" target="-2" id="d4O-vk-Urw"/>
|
||||||
|
</connections>
|
||||||
|
</buttonCell>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="-2" id="Rjx-7O-z3m"/>
|
||||||
|
</connections>
|
||||||
|
</window>
|
||||||
|
</objects>
|
||||||
|
</document>
|
41
gui/Shoebill/shoeScreenView.h
Normal file
41
gui/Shoebill/shoeScreenView.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <OpenGL/gl.h>
|
||||||
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
#import "shoeApplication.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface shoeScreenView : NSOpenGLView {
|
||||||
|
CGColorSpaceRef colorspace;
|
||||||
|
shoebill_control_t *control;
|
||||||
|
NSTimer *timer;
|
||||||
|
NSRecursiveLock *lock;
|
||||||
|
CIContext *ciContext;
|
||||||
|
shoeApplication *shoeApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
291
gui/Shoebill/shoeScreenView.m
Normal file
291
gui/Shoebill/shoeScreenView.m
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "shoeScreenView.h"
|
||||||
|
#import "shoeAppDelegate.h"
|
||||||
|
#import "shoeApplication.h"
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@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
|
26
gui/Shoebill/shoeScreenView.xib
Normal file
26
gui/Shoebill/shoeScreenView.xib
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
|
<dependencies>
|
||||||
|
<deployment defaultVersion="1080" identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="NSWindowController">
|
||||||
|
<connections>
|
||||||
|
<outlet property="window" destination="1" id="aqm-Nb-PaF"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="shoeApplication"/>
|
||||||
|
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" wantsToBeColor="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" customClass="shoeScreenWindow">
|
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
||||||
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
|
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
|
||||||
|
<view key="contentView" id="2" customClass="shoeScreenView">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</view>
|
||||||
|
</window>
|
||||||
|
</objects>
|
||||||
|
</document>
|
36
gui/Shoebill/shoeScreenWindow.h
Normal file
36
gui/Shoebill/shoeScreenWindow.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface shoeScreenWindow : NSWindow {
|
||||||
|
@public
|
||||||
|
uint8_t slotnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)configure:(uint8_t) _slotnum;
|
||||||
|
- (void)reevaluateKeyWindowness;
|
||||||
|
@end
|
83
gui/Shoebill/shoeScreenWindow.m
Normal file
83
gui/Shoebill/shoeScreenWindow.m
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
407
test.c
Normal file
407
test.c
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <GLUT/glut.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user