First big barely-functional code drop

This commit is contained in:
Peter Rutenbar 2014-02-24 17:14:52 -05:00
parent 6b3a5839d2
commit 93cefd9451
58 changed files with 24982 additions and 13 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/intermediates
/shoebill
.DS_Store
*.xcworkspace
xcuserdata

26
LICENSE
View File

@ -1,23 +1,23 @@
Copyright (c) 2014, pruten
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:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

16
Makefile Normal file
View 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
View 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 cant 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 cant 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
View 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
View 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

File diff suppressed because it is too large Load Diff

329
core/coff.c Normal file
View 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(&timestamp, 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

1240
core/debugger.c Normal file

File diff suppressed because it is too large Load Diff

1484
core/decoder_gen.c Normal file

File diff suppressed because it is too large Load Diff

1478
core/dis.c Normal file

File diff suppressed because it is too large Load Diff

251
core/exception.c Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

1520
core/macii_symbols.c Normal file

File diff suppressed because it is too large Load Diff

562
core/macro.pl Executable file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

267
core/redblack.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

513
core/video_rom/rom.c Normal file
View 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
View 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;
}

View 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

View 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

View 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

File diff suppressed because one or more lines are too long

View 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 */;
}

View 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>

View File

@ -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"
}
}

View 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>

View 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

View 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\
}

View File

@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */

6
gui/Shoebill/main.m Normal file
View File

@ -0,0 +1,6 @@
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[])
{
return NSApplicationMain(argc, argv);
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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>

View 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

View 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

View 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>

View 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

View 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
View 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;
}