VIA Timers + 16/32-bit video support

- VIA timers should probably work now, although it turns out A/UX rarely uses them
  (only during startup to time a dbra loop and other stuff)

- Updated video.c and the fake nubus video card driver to support "thousands"
  and "millions" of colors when 32-bit QuickDraw is available
This commit is contained in:
Peter Rutenbar 2014-06-02 00:59:08 -04:00
parent a16a6700e4
commit 5c1fdf6b73
13 changed files with 299 additions and 294 deletions

View File

@ -60,6 +60,8 @@ void shoebill_stop()
pthread_join(shoe.cpu_thread_pid, NULL);
pthread_mutex_destroy(&shoe.cpu_thread_lock);
pthread_mutex_destroy(&shoe.via_cpu_lock);
shoe.running = 0;
// Close all the SCSI disk images
@ -542,43 +544,72 @@ static void _do_clut_translation(shoebill_card_video_t *ctx)
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];
const uint8_t byte = ctx->direct_buf[i];
ctx->temp_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1];
ctx->temp_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1];
ctx->temp_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1];
ctx->temp_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1];
ctx->temp_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1];
ctx->temp_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1];
ctx->temp_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1];
ctx->temp_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];
const uint8_t byte = ctx->direct_buf[i];
ctx->temp_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3];
ctx->temp_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3];
ctx->temp_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3];
ctx->temp_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];
const uint8_t byte = ctx->direct_buf[i];
ctx->temp_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf];
ctx->temp_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf];
}
break;
}
case 8:
case 8: {
for (i=0; i < ctx->pixels; i++)
ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]];
ctx->temp_buf[i] = ctx->clut[ctx->direct_buf[i]];
break;
}
case 16: {
uint16_t *direct = (uint16_t*)ctx->direct_buf;
for (i=0; i < ctx->pixels; i++) {
const uint16_t p = ntohs(direct[i]);
video_ctx_color_t tmp;
tmp.r = ((p >> 10) & 31);
tmp.g = (p >> 5) & 31;
tmp.b = (p >> 0) & 31;
ctx->temp_buf[i].r = (tmp.r << 3) | (tmp.r >> 2);
ctx->temp_buf[i].g = (tmp.g << 3) | (tmp.g >> 2);
ctx->temp_buf[i].b = (tmp.b << 3) | (tmp.b >> 2);
}
break;
}
case 32: {
uint32_t *direct = (uint32_t*)ctx->direct_buf, *tmp = (uint32_t*)ctx->temp_buf;
for (i=0; i < ctx->pixels; i++)
tmp[i] = direct[i] >> 8;
// OpenGL wants RGBA
// Apple must be ARGB (which is BGRA, when dereferenced)
break;
}
default:
assert(!"unknown depth");
assert(!"unsupported depth");
}
}
@ -604,14 +635,12 @@ shoebill_video_frame_info_t shoebill_get_video_frame(uint8_t slotnum,
if (just_params)
return result;
if (ctx->depth <= 8) {
_do_clut_translation(ctx);
result.buf = (uint8_t*)ctx->direct_buf;
return result;
}
_do_clut_translation(ctx);
result.buf = (uint8_t*)ctx->temp_buf;
return result;
assert(!"depth not supported");
}
/*
@ -729,6 +758,8 @@ uint32_t shoebill_initialize(shoebill_config_t *config)
shoe.pc = pc;
memcpy(shoe.scsi_devices, disks, 8 * sizeof(scsi_device_t));
pthread_mutex_init(&shoe.via_cpu_lock, NULL);
pthread_mutex_init(&shoe.via_clock_thread_lock, NULL);
pthread_mutex_lock(&shoe.via_clock_thread_lock);
pthread_create(&shoe.via_thread_pid, NULL, via_clock_thread, NULL);

View File

@ -102,6 +102,17 @@ const char *scsi_write_reg_str[8] = {
"start_dma_initiator_receive"
};
static void scsi_raise_irq() {via_raise_interrupt(2, IFR_CB2);}
static void scsi_raise_drq() {via_raise_interrupt(2, IFR_CA2);}
static _Bool phase_match (void)
{
uint8_t phase_tmp = shoe.scsi.msg;
phase_tmp = (phase_tmp << 1) | shoe.scsi.cd;
phase_tmp = (phase_tmp << 1) | shoe.scsi.io;
return (phase_tmp == (shoe.scsi.target_command & 7));
}
static void switch_status_phase (uint8_t status_byte)
{
printf("scsi_reg_something: switching to STATUS phase\n");
@ -115,7 +126,7 @@ static void switch_status_phase (uint8_t status_byte)
shoe.scsi.bufi = 0;
// Phase mismatch (I think)
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_command_phase (void)
@ -130,7 +141,7 @@ static void switch_command_phase (void)
shoe.scsi.bufi = 0;
// Phase mismatch, probably
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_message_in_phase (uint8_t message_byte)
@ -145,7 +156,7 @@ static void switch_message_in_phase (uint8_t message_byte)
shoe.scsi.message_byte = message_byte; // only one-byte messages supported for now
// Phase mismatch, probably
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_bus_free_phase (void)
@ -176,7 +187,7 @@ static void switch_data_in_phase (void)
shoe.scsi.io = 1;
// Phase mismatch, probably
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_data_out_phase (void)
@ -189,7 +200,7 @@ static void switch_data_out_phase (void)
shoe.scsi.cd = 0;
shoe.scsi.io = 0;
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
struct inquiry_response_t {
@ -471,13 +482,7 @@ void scsi_reg_read ()
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) | shoe.scsi.msg;
phase_tmp = (phase_tmp << 1) | shoe.scsi.cd;
phase_tmp = (phase_tmp << 1) | shoe.scsi.io;
phase_tmp = (phase_tmp == (shoe.scsi.target_command & 7));
}
uint8_t phase_tmp = phase_match();
tmp |= (shoe.scsi.ack * BUS_STATUS_ACK);
tmp |= (shoe.scsi.atn * BUS_STATUS_ATN);
@ -615,14 +620,14 @@ void scsi_reg_write ()
case 5: // Start DMA send
shoe.scsi.dma_send_written = 1;
via_raise_interrupt(2, 0);
scsi_raise_drq();
break;
case 6: // Start DMA target receive
break;
case 7: // Start DMA initiator receive
via_raise_interrupt(2, 0);
scsi_raise_drq();
break;
}

View File

@ -390,11 +390,13 @@ typedef struct {
typedef struct {
uint8_t ifr, ier, ddrb, ddra, sr, acr, pcr;
// uint8_t rega, regb;
uint16_t t1c, t2c, t1l;
uint8_t rega_input, regb_input;
uint8_t rega_output, regb_output;
uint16_t t1c, t2c, t1l;
long double t1_last_set, t2_last_set;
_Bool /*t1_interrupt_enabled,*/ t2_interrupt_enabled; // whether the "one-shot" interrupt can fire
} via_state_t;
#define PRAM_READ 1
@ -540,9 +542,8 @@ typedef struct {
} video_ctx_color_t;
typedef struct {
video_ctx_color_t *direct_buf, *clut;
uint8_t *indexed_buf, *rom;
uint8_t *cur_buf;
video_ctx_color_t *temp_buf, *clut;
uint8_t *rom, *direct_buf;
uint32_t pixels;
@ -611,8 +612,9 @@ typedef struct {
volatile uint32_t via_thread_notifications;
pthread_mutex_t cpu_thread_lock;
pthread_mutex_t via_clock_thread_lock;
pthread_mutex_t via_clock_thread_lock; // synchronizes shoebill_start() and the starting of via_clock_thread()
pthread_mutex_t cpu_freeze_lock;
pthread_mutex_t via_cpu_lock; // synchronizes reads/writes of VIA registers and via_clock_thread()
// -- Assorted CPU state variables --
uint16_t op; // the first word of the instruction we're currently running
@ -946,8 +948,8 @@ void *via_clock_thread(void *arg);
#define IFR_SHIFT_REG 2
#define IFR_CB2 3
#define IFR_CB1 4
#define IFR_TIMER1 5
#define IFR_TIMER2 6
#define IFR_TIMER2 5
#define IFR_TIMER1 6
#define IFR_IRQ 7
// adb / keyboard / mouse stuff

View File

@ -195,10 +195,10 @@ 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);
const long double secs = tv.tv_sec;
const long double usecs = tv.tv_usec;
const long double result = secs + (usecs / 1000000.0);
return result;
}
static void handle_pram_write_byte (void)
@ -489,17 +489,22 @@ void init_via_state (uint8_t pram_data[256], shoebill_pram_callback_t callback,
memcpy(pram->data, pram_data, 256);
pram->callback = callback;
pram->callback_param = callback_param;
/* -- Init clock stuff -- */
const long double now = _now();
shoe.via[0].t1_last_set = now;
shoe.via[0].t2_last_set = now;
shoe.via[1].t1_last_set = now;
shoe.via[1].t2_last_set = now;
}
#define E_CLOCK 783360
#define HALF_E_CLOCK (E_CLOCK / 2)
#define _via_get_delta_counter(last_set) ({ \
const long double delta_t = now - (last_set); \
const long double delta_ticks = fmodl((delta_t * (long double)E_CLOCK), 0x10000); \
const long double delta_ticks = fmodl((delta_t * (long double)E_CLOCK), 0x80000000); \
/* The VIA timers decrement by 2 for every E_CLOCK tick */ \
const uint16_t delta_counter = ((uint16_t)delta_ticks) << 1; \
printf("_via_get_delta_counter: now = %Lf delta_t = %Lf delta_ticks = %Lf delta_counter = %u\n", now, delta_t, delta_ticks, delta_counter); \
const uint32_t delta_counter = ((uint32_t)delta_ticks) << 1; \
delta_counter; \
})
@ -514,7 +519,7 @@ static uint8_t via_read_reg(const uint8_t vianum, const uint8_t reg, const long
{
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);
printf("via_reg_read: reading from via%u reg %s (%u) (shoe.pc = 0x%08x)\n", vianum, via_reg_str[reg], reg, shoe.pc);
switch (reg) {
case VIA_ACR:
@ -566,11 +571,11 @@ static uint8_t via_read_reg(const uint8_t vianum, const uint8_t reg, const long
return via->ddra;
case VIA_T2C_HI: {
const uint16_t counter = via->t2c - _via_get_delta_counter(via->t2_last_set);
const uint16_t counter = via->t2c - (uint16_t)_via_get_delta_counter(via->t2_last_set);
return counter >> 8;
}
case VIA_T2C_LO: {
const uint16_t counter = via->t2c - _via_get_delta_counter(via->t2_last_set);
const uint16_t counter = via->t2c - (uint16_t)_via_get_delta_counter(via->t2_last_set);
via->ifr &= ~~VIA_IFR_T2; // Read from T2C_LOW clears TIMER 2 interrupt
return (uint8_t)counter;
}
@ -595,7 +600,7 @@ static void via_write_reg(const uint8_t vianum, const uint8_t reg, const uint8_t
{
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);
printf("via_reg_write: writing 0x%02x to via%u reg %s (%u) (pc=0x%08x)\n", data, vianum, via_reg_str[reg], reg, shoe.pc);
switch (reg) {
case VIA_IER: {
@ -670,6 +675,7 @@ static void via_write_reg(const uint8_t vianum, const uint8_t reg, const uint8_t
case VIA_T2C_HI:
via->ifr &= ~~VIA_IFR_T2; // Write to T2C_HI clears TIMER 2 interrupt
via->t2_last_set = now;
via->t2_interrupt_enabled = 1;
break;
case VIA_T1C_LO:
@ -692,6 +698,8 @@ void via_write_raw (void)
const uint8_t vianum = ((shoe.physical_addr >> 13) & 1) + 1;
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
pthread_mutex_lock(&shoe.via_cpu_lock);
if (shoe.physical_size == 1) {
const long double now = ((reg >= VIA_T1C_LO) && (reg <= VIA_T2C_HI)) ? _now() : 0.0;
// Common case: writing to only one register
@ -702,7 +710,7 @@ void via_write_raw (void)
const long double now = ((reg >= VIA_T1C_LO) && ((reg+1) <= VIA_T2C_HI)) ? _now() : 0.0;
// Uncommon case: writing to two registers simultaneously
printf("via_write_raw: writing to two registers simultaneously %u and %u\n", reg, reg+1);
printf("via_write_raw: writing to two registers simultaneously %u and %u (0x%x)\n", reg, reg+1 , (uint32_t)shoe.physical_dat);
assert(reg != 15); // If A/UX is trying to write to two VIA chips simultanously, that's not cool
@ -712,6 +720,7 @@ void via_write_raw (void)
else
assert("Writing multiple bytes to the same VIA register!");
pthread_mutex_unlock(&shoe.via_cpu_lock);
}
void via_read_raw (void)
@ -719,6 +728,8 @@ void via_read_raw (void)
const uint8_t vianum = ((shoe.physical_addr >> 13) & 1) + 1;
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
pthread_mutex_lock(&shoe.via_cpu_lock);
if (shoe.physical_size == 1) {
const long double now = ((reg >= VIA_T1C_LO) && (reg <= VIA_T2C_HI)) ? _now() : 0.0;
@ -741,21 +752,28 @@ void via_read_raw (void)
}
else
assert(!"Reading multiple bytes from the same VIA register!");
pthread_mutex_unlock(&shoe.via_cpu_lock);
}
#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();
// const long double multiplier = 1.0 / 60.0;
const long double multiplier = 1.0;
const long double start_time = multiplier * _now();
uint64_t ca1_ticks = 0, ca2_ticks = 0;
uint32_t i;
while (1) {
const long double now = _now();
pthread_mutex_lock(&shoe.via_cpu_lock);
const long double now = multiplier * _now();
long double earliest_next_timer = 1.0;
const uint32_t via1_t2_delta = _via_get_delta_counter(shoe.via[0].t2_last_set);
/*
* Check whether the 60hz timer should fire (via1 CA1)
@ -792,29 +810,18 @@ void *via_clock_thread(void *arg)
via_raise_interrupt(2, IFR_TIMER2);*/
}
/*
// Check if any nubus cards have interrupt timers
shoe.via[1].rega_input = 0b00111111;
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));
shoe.via[1].rega_input &= 0b00111111 & ~~(1<<(i-9));
via_raise_interrupt(2, IFR_CA1);
// printf("Fired nubus interrupt %u\n", i);
}
// I'm only checking VIA1 T2, since the time manager only seems to use/care about that timer
if (shoe.via[0].t2_interrupt_enabled) {
if (via1_t2_delta >= shoe.via[0].t2c) {
shoe.via[0].t2_interrupt_enabled = 0;
via_raise_interrupt(1, IFR_TIMER2);
}
else {
fire((long double)(shoe.via[0].t2c - via1_t2_delta) / (E_CLOCK / 2.0));
}
}
*/
pthread_mutex_unlock(&shoe.via_cpu_lock);
usleep((useconds_t)(earliest_next_timer * 1000000.0L));

View File

@ -78,10 +78,6 @@ uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len)
static void _switch_depth(shoebill_card_video_t *ctx, uint32_t depth)
{
ctx->depth = depth;
if (depth > 8)
ctx->cur_buf = (uint8_t*)ctx->direct_buf;
else
ctx->cur_buf = ctx->indexed_buf;
}
void nubus_video_init(void *_ctx, uint8_t slotnum,
@ -94,8 +90,8 @@ void nubus_video_init(void *_ctx, uint8_t slotnum,
ctx->scanline_width = scanline_width;
ctx->pixels = scanline_width * height;
ctx->direct_buf = p_alloc(shoe.pool, ctx->pixels * sizeof(video_ctx_color_t));
ctx->indexed_buf = p_alloc(shoe.pool, ctx->pixels);
ctx->direct_buf = p_alloc(shoe.pool, (ctx->pixels+4) * sizeof(video_ctx_color_t));
ctx->temp_buf = p_alloc(shoe.pool, (ctx->pixels+4) * sizeof(video_ctx_color_t));
ctx->clut = p_alloc(shoe.pool, 256 * sizeof(video_ctx_color_t));
ctx->rom = p_alloc(shoe.pool, 4096);
@ -128,13 +124,13 @@ void nubus_video_init(void *_ctx, uint8_t slotnum,
params[3].right = htons(width);
params[3].bottom = htons(height);
/*params[4].line_width = htons(scanline_width * 2);
params[4].line_width = htons(scanline_width * 2);
params[4].right = htons(width);
params[4].bottom = htons(height);
params[5].line_width = htons(scanline_width * 4);
params[5].right = htons(width);
params[5].bottom = htons(height);*/
params[5].bottom = htons(height);
// Recompute the rom crc
compute_nubus_crc(ctx->rom, 4096);
@ -175,10 +171,10 @@ uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size,
// 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];
uint32_t i, result = 0;
if (addr < (ctx->pixels * 4)) {
for (i=0; i<size; i++)
result = (result << 8) | ((uint8_t*)ctx->direct_buf)[addr + i];
}
return result;
@ -272,13 +268,13 @@ void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
// Else, this is video ram
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;
if (addr < (ctx->pixels * 4)) {
uint32_t mydata, myaddr;
for (myaddr = addr + size, mydata = data; addr < myaddr; ) {
((uint8_t*)ctx->direct_buf)[--myaddr] = mydata & 0xff;
mydata >>= 8;
}
}
}

Binary file not shown.

View File

@ -22,97 +22,141 @@ uint8_t _video_rom[4096] = {
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,
0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x40, 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, 0x10, 0x00, 0x10, 0x00, 0x03,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80,
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, 0x10, 0x00, 0x20, 0x00, 0x03, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
0x80, 0x00, 0x01, 0x66, 0x81, 0x00, 0x01, 0x2e,
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1c,
0x02, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x50,
0x22, 0x00, 0x00, 0x30, 0x24, 0x00, 0x00, 0xee,
0x26, 0x00, 0x00, 0x3c, 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, 0x14, 0x02, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x31, 0x7c, 0x00, 0x01,
0x00, 0x02, 0x4e, 0x75, 0x00, 0x00, 0x00, 0xae,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x31, 0x7c, 0x00, 0x01, 0x00, 0x02, 0x2a, 0x48,
0x31, 0x7c, 0x00, 0x01, 0x00, 0x02, 0x10, 0x10,
0x12, 0x00, 0x00, 0x01, 0x00, 0xf0, 0xe0, 0x99,
0x22, 0x41, 0x9e, 0xfc, 0x00, 0x38, 0x20, 0x4f,
0x11, 0x40, 0x00, 0x31, 0x42, 0x28, 0x00, 0x33,
0x42, 0xa8, 0x00, 0x04, 0x20, 0x3c, 0x00, 0x00,
0xa8, 0x9f, 0xa7, 0x46, 0x22, 0x08, 0x20, 0x3c,
0x00, 0x00, 0xab, 0x03, 0xa7, 0x46, 0xb1, 0xc1,
0x67, 0x62, 0x20, 0x4f, 0x42, 0x28, 0x00, 0x32,
0x42, 0x28, 0x00, 0x30, 0x31, 0x7c, 0x00, 0x03,
0x00, 0x28, 0x31, 0x7c, 0x00, 0x01, 0x00, 0x2a,
0x31, 0x7c, 0x00, 0x01, 0x00, 0x2c, 0x31, 0x7c,
0x54, 0x03, 0x00, 0x2e, 0x70, 0x15, 0xa0, 0x6e,
0x3a, 0x28, 0x00, 0x26, 0x0c, 0x28, 0x00, 0x81,
0x00, 0x32, 0x67, 0x00, 0x00, 0x30, 0x70, 0x31,
0xa0, 0x6e, 0x11, 0x78, 0x00, 0x81, 0x00, 0x32,
0x42, 0x68, 0x00, 0x26, 0x42, 0xa8, 0x00, 0x18,
0x42, 0xa8, 0x00, 0x04, 0x70, 0x0a, 0xa0, 0x6e,
0x59, 0x4f, 0xaa, 0x29, 0x20, 0x5f, 0x20, 0x50,
0xba, 0x50, 0x66, 0x08, 0x20, 0x68, 0x00, 0x16,
0x20, 0x50, 0x20, 0x89, 0x4f, 0xef, 0x00, 0x38,
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,
0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x02, 0x00,
0x00, 0xcc, 0x04, 0x00, 0x00, 0xf0, 0x08, 0x00,
0x00, 0x01, 0x0c, 0x00, 0x00, 0xb8, 0x0d, 0x00,
0x00, 0xb8, 0x80, 0x00, 0x00, 0x48, 0x81, 0x00,
0x00, 0x54, 0x82, 0x00, 0x00, 0x60, 0x83, 0x00,
0x00, 0x6c, 0x84, 0x00, 0x00, 0x78, 0x85, 0x00,
0x00, 0x84, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0xbc, 0x02, 0x00, 0x00, 0x98, 0x04, 0x00,
0x00, 0xbc, 0x08, 0x00, 0x00, 0x01, 0x0c, 0x00,
0x00, 0x84, 0x0d, 0x00, 0x00, 0x84, 0x80, 0x00,
0x00, 0x14, 0x81, 0x00, 0x00, 0x20, 0x82, 0x00,
0x00, 0x2c, 0x83, 0x00, 0x00, 0x38, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0x56, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0x74, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0x92, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0xb0, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0xce, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0xec, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x02, 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, 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, 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,
@ -464,50 +508,7 @@ uint8_t _video_rom[4096] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0xff, 0xf1, 0x28,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x5a, 0x93, 0x2b, 0xc7, 0x00, 0xe1};
0x01, 0x01, 0x5a, 0x93, 0x2b, 0xc7, 0x00, 0xe1
};

0
core/video_rom/shoebill_video.make Normal file → Executable file
View File

0
core/video_rom/shoebill_video_driver.a Normal file → Executable file
View File

2
core/video_rom/shoebill_video_primary_init.a Normal file → Executable file
View File

@ -1 +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
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 ; Return "success" move.w #1, seStatus(a0) ; seStatus > 0 -> success ; FIXME: Designing Cards and Drivers for the Macintosh Family says I should disable VBLs here... ; FIXME: Also gray out the screen ; Usually, we would check if 32bit QD exists ; If it doesn't, then we'd try to invalidate sResourceVideo_qd32 ; unless the Mac II slot manager is loaded, in which case, we can't actually ; invalidate anything. ; Since Shoebill very likely won't support non-Mac II ROMs for a while, ; we have nothing to do rts PrimaryInitEnd

2
core/video_rom/shoebill_video_rom.a Normal file → Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
BLANKS ON STRING ASIS MACHINE MC68020 WITH seBlock,spBlock DC.B 2 ; Code revision DC.B 2 ; 68020 DC.W 0 ; reserved DC.L SecondaryInitStart-* SecondaryInitStart ; Return "success" move.w #1, seStatus(a0) ; seStatus > 0 -> success ; Figure out the slot base address (non-superslot) move.b seSlot(a0), d0 ; -> d0.b = slotnum move.b d0, d1 or.b #$F0, d1 ror.l #8, d1 move.l d1, a1 ; -> a1 = slot base addr ; Set up a slot parameter block suba #spBlockSize, sp move.l sp, a0 move.b d0, spSlot(a0) clr.b spExtDev(a0) clr.l spsPointer(a0) ; Verify that 32bit QD is loaded move.l #$a89f, d0 _GetTrapAddress ,NewTool move.l a0, d1 move.l #$ab03, d0 _GetTrapAddress ,NewTool cmpa.l d1, a0 beq.s sec_done ; Find the current video sResource move.l sp, a0 clr.b spID(a0) ; start at id=0 clr.b spTBMask(a0) ; match exactly move.w #CatDisplay, spCategory(a0) move.w #TypVideo, spCType(a0) move.w #DrSwApple, spDrvrSW(a0) move.w #DrHwShoe, spDrvrHW(a0) _sNextTypesRsrc move.w spRefNum(a0), d5 ; If, somehow, the 32 bit video sResource is the only active one, then just return cmp.b #CategoryVideo_qd32, spID(a0) beq.w sec_done ; Otherwise, it's the non-32bit sResource - so nuke it _sDeleteSRTRec ; And activate the 32bit sResource move.b CategoryVideo_qd32, spID(a0) clr.w spRefNum(a0) ; ? clr.l spParamData(a0) ; clear for activation clr.l spsPointer(a0) ; add back a sRsrc in directory _InsertSRTRec ; If this is the boot screen, then update its gDevice subq #4, sp ; make room for function return _GetDeviceList ; get the boot gDevice move.l (sp)+, a0 ; get the gdHandle move.l (a0), a0 ; get pointer to gDevice cmp.w gdRefNum(a0), d5 ; was this the boot device? bne.s sec_done ; No? then return move.l gdPMap(a0), a0 ; get pixMap handle move.l (a0), a0 ; getpixMap ptr move.l a1, pmBaseAddr(a0) ; save new base address ; FIXME: Wait, that wasn't necessary. All video modes have the same pmBaseAddr, I think sec_done adda #spBlockSize, sp rts SecondaryInitEnd

View File

@ -42,6 +42,9 @@ struct dbg_state_t {
uint64_t breakpoint_counter;
dbg_breakpoint_t *breakpoints;
_Bool trace;
char *ring;
uint32_t ring_i, ring_len;
};
@ -369,6 +372,8 @@ void stepper()
cpu_step();
if (dbg_state.trace) {
print_pc();
printregs();
@ -622,58 +627,10 @@ void timer_func (int arg)
glutPostRedisplay();
}
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 _display_func (void)
{
shoebill_card_video_t *video = (shoebill_card_video_t*)shoe.slots[9].ctx;
_do_clut_translation(video);
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 0);
shoebill_send_vbl_interrupt(9);
@ -682,18 +639,18 @@ void _display_func (void)
glClearColor(0.0, 0.0, 0.0, 0.0);
glViewport(0, 0, video->width, video->height);
glRasterPos2i(0, video->height);
glViewport(0, 0, frame.width, frame.height);
glRasterPos2i(0, frame.height);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(video->width,
video->height,
glDrawPixels(frame.width,
frame.height,
GL_RGBA,
GL_UNSIGNED_BYTE,
video->direct_buf);
frame.buf);
glutSwapBuffers();
}
@ -883,11 +840,16 @@ int main (int argc, char **argv)
config.debug_mode = 1;
config.aux_verbose = 1;
config.ram_size = 16 * 1024 * 1024;
config.ram_size = 8 * 1024 * 1024;
config.aux_kernel_path = "/unix";
config.rom_path = "../priv/macii.rom";
config.scsi_devices[0].path = "../priv/Apple_UNIX_3.iso";
config.scsi_devices[0].path = "../priv/aux_3.0.1.img";
config.scsi_devices[1].path = "../priv/marathon.img";
/*dbg_state.ring_len = 256 * 1024 * 1024;
dbg_state.ring = malloc(dbg_state.ring_len);
dbg_state.ring_i = 0;*/
if (!shoebill_initialize(&config)) {
printf("%s\n", config.error_msg);
@ -898,8 +860,8 @@ int main (int argc, char **argv)
shoebill_install_video_card(&config,
9, // slotnum
1024,
768,
640, // 1024,
480, // 768,
60.0);
// Start the VIA timer thread