mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-27 17:50:37 +00:00
apple2: AppleSingle header for CC65 by default, try to parse 4-byte DOS headers
This commit is contained in:
parent
16fcf33881
commit
c189875be3
55
presets/apple2/lz4test.c
Normal file
55
presets/apple2/lz4test.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
Test of the LZ4 decompression library
|
||||||
|
with a hires graphics image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// CC65 config, reserves space for the HGR1 screen buffer
|
||||||
|
#define CFGFILE apple2-hgr.cfg
|
||||||
|
|
||||||
|
#pragma data-name(push,"HGR")
|
||||||
|
// this segment is required, but we leave it empty
|
||||||
|
// since we're going to decompress the image here
|
||||||
|
#pragma data-name(pop)
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <apple2.h>
|
||||||
|
#include <peekpoke.h>
|
||||||
|
#include <lz4.h>
|
||||||
|
|
||||||
|
// STROBE = write any value to an I/O address
|
||||||
|
#define STROBE(addr) __asm__ ("sta %w", addr)
|
||||||
|
|
||||||
|
// start address of the two hi-res graphics regions
|
||||||
|
#define HGR1 0x2000
|
||||||
|
#define HGR2 0x4000
|
||||||
|
|
||||||
|
// the LZ4 compressed data
|
||||||
|
const unsigned char BITMAP_DATA_LZ4[] = {
|
||||||
|
#embed "parrot-apple2.hires.lz4"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// clear screen and set graphics mode
|
||||||
|
void clear_hgr1() {
|
||||||
|
memset((char*)HGR1, 0, 0x2000); // clear page 1
|
||||||
|
STROBE(0xc052); // turn off mixed-mode
|
||||||
|
STROBE(0xc054); // page 1
|
||||||
|
STROBE(0xc057); // hi-res
|
||||||
|
STROBE(0xc050); // set graphics mode
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
// set hgr1 mode and clear
|
||||||
|
clear_hgr1();
|
||||||
|
// skip the header (usually 11 bytes)
|
||||||
|
decompress_lz4(BITMAP_DATA_LZ4+11, (char*)HGR1, 0x2000);
|
||||||
|
// wait for a key
|
||||||
|
cgetc();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
BIN
presets/apple2/parrot-apple2.hires.lz4
Normal file
BIN
presets/apple2/parrot-apple2.hires.lz4
Normal file
Binary file not shown.
@ -243,6 +243,8 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P
|
|||||||
}
|
}
|
||||||
loadROM(data: Uint8Array, title?: string): void {
|
loadROM(data: Uint8Array, title?: string): void {
|
||||||
if (!this.rom) this.rom = new Uint8Array(this.defaultROMSize);
|
if (!this.rom) this.rom = new Uint8Array(this.defaultROMSize);
|
||||||
|
if (data.length > this.rom.length)
|
||||||
|
throw new Error(`ROM too big: ${data.length} > ${this.rom.length}}`);
|
||||||
this.rom.set(data);
|
this.rom.set(data);
|
||||||
}
|
}
|
||||||
loadState(state) {
|
loadState(state) {
|
||||||
|
@ -2,13 +2,7 @@
|
|||||||
import { MOS6502, MOS6502State } from "../common/cpu/MOS6502";
|
import { MOS6502, MOS6502State } from "../common/cpu/MOS6502";
|
||||||
import { Bus, BasicScanlineMachine, SavesState, AcceptsBIOS } from "../common/devices";
|
import { Bus, BasicScanlineMachine, SavesState, AcceptsBIOS } from "../common/devices";
|
||||||
import { KeyFlags } from "../common/emu"; // TODO
|
import { KeyFlags } from "../common/emu"; // TODO
|
||||||
import { hex, lzgmini, stringToByteArray, RGBA, printFlags } from "../common/util";
|
import { hex, lzgmini, stringToByteArray, RGBA, printFlags, arrayCompare } from "../common/util";
|
||||||
|
|
||||||
// TODO: read prodos/ca65 header?
|
|
||||||
const VM_BASE = 0x803; // where to JMP after pr#6
|
|
||||||
const LOAD_BASE = VM_BASE;
|
|
||||||
const PGM_BASE = VM_BASE;
|
|
||||||
const HDR_SIZE = PGM_BASE - LOAD_BASE;
|
|
||||||
|
|
||||||
interface AppleIIStateBase {
|
interface AppleIIStateBase {
|
||||||
ram : Uint8Array;
|
ram : Uint8Array;
|
||||||
@ -43,7 +37,11 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS {
|
|||||||
canvasWidth = 280;
|
canvasWidth = 280;
|
||||||
numVisibleScanlines = 192;
|
numVisibleScanlines = 192;
|
||||||
numTotalScanlines = 262;
|
numTotalScanlines = 262;
|
||||||
defaultROMSize = 0xbf00-0x803; // TODO
|
defaultROMSize = 0x13000; // we'll never need one that big, but...
|
||||||
|
|
||||||
|
// these are set later
|
||||||
|
LOAD_BASE = 0;
|
||||||
|
HDR_SIZE = 0;
|
||||||
|
|
||||||
ram = new Uint8Array(0x13000); // 64K + 16K LC RAM - 4K hardware + 12K ROM
|
ram = new Uint8Array(0x13000); // 64K + 16K LC RAM - 4K hardware + 12K ROM
|
||||||
bios : Uint8Array;
|
bios : Uint8Array;
|
||||||
@ -78,8 +76,8 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS {
|
|||||||
// SHOULD load program into RAM here, but have to do it
|
// SHOULD load program into RAM here, but have to do it
|
||||||
// below instead.
|
// below instead.
|
||||||
return 0;
|
return 0;
|
||||||
case 1: return VM_BASE&0xff;
|
case 1: return this.LOAD_BASE&0xff;
|
||||||
case 2: return (VM_BASE>>8)&0xff;
|
case 2: return (this.LOAD_BASE>>8)&0xff;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,8 +95,7 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS {
|
|||||||
// into RAM and returning the JMP here, instead of above
|
// into RAM and returning the JMP here, instead of above
|
||||||
// where it would otherwise belong.
|
// where it would otherwise belong.
|
||||||
if (this.rom) {
|
if (this.rom) {
|
||||||
console.log(`Loading program into Apple ][ RAM at \$${PGM_BASE.toString(16)}`);
|
this.loadRAMWithProgram();
|
||||||
this.ram.set(this.rom.slice(HDR_SIZE), PGM_BASE);
|
|
||||||
}
|
}
|
||||||
return 0x4c; // JMP
|
return 0x4c; // JMP
|
||||||
case 1: return 0x20;
|
case 1: return 0x20;
|
||||||
@ -168,26 +165,57 @@ export class AppleII extends BasicScanlineMachine implements AcceptsBIOS {
|
|||||||
console.log("will load BIOS to end of memory anyway...");
|
console.log("will load BIOS to end of memory anyway...");
|
||||||
}
|
}
|
||||||
this.bios = Uint8Array.from(data);
|
this.bios = Uint8Array.from(data);
|
||||||
this.ram.set(this.bios, 0x10000 - this.bios.length);
|
|
||||||
this.ram[0xbf00] = 0x4c; // fake DOS detect for C
|
|
||||||
this.ram[0xbf6f] = 0x01; // fake DOS detect for C
|
|
||||||
}
|
}
|
||||||
loadROM(data) {
|
loadROM(data) {
|
||||||
if (data.length == 35*16*256) { // is it a disk image?
|
// is it a 16-sector 35-track disk image?
|
||||||
var diskii = new DiskII(this, data);
|
if (data.length == 16 * 35 * 256) {
|
||||||
this.slots[6] = diskii;
|
var diskii = new DiskII(this, data);
|
||||||
} else { // it's a binary, use a fake drive
|
this.slots[6] = diskii;
|
||||||
super.loadROM(data);
|
this.reset();
|
||||||
this.slots[6] = this.fakeDrive;
|
} else { // it's a binary, use a fake drive
|
||||||
|
// set this.rom variable
|
||||||
|
super.loadROM(data);
|
||||||
|
// AppleSingle header? https://github.com/cc65/cc65/blob/master/libsrc/apple2/exehdr.s
|
||||||
|
if (arrayCompare(this.rom.slice(0, 4), [0x00, 0x05, 0x16, 0x00])) {
|
||||||
|
this.LOAD_BASE = this.rom[0x39] | (this.rom[0x38] << 8); // big endian
|
||||||
|
this.HDR_SIZE = 58;
|
||||||
|
} else {
|
||||||
|
// 4-byte DOS header? (TODO: hacky detection)
|
||||||
|
const origin = this.rom[0] | (this.rom[1] << 8);
|
||||||
|
const size = this.rom[2] | (this.rom[3] << 8);
|
||||||
|
let isPlausible = origin < 0xc000
|
||||||
|
&& origin + size < 0x13000
|
||||||
|
&& (origin == 0x803 || (origin & 0xff) == 0);
|
||||||
|
if (size == data.length - 4 && isPlausible) {
|
||||||
|
this.LOAD_BASE = origin;
|
||||||
|
this.HDR_SIZE = 4;
|
||||||
|
} else {
|
||||||
|
// default = raw binary @ $803
|
||||||
|
this.LOAD_BASE = 0x803;
|
||||||
|
this.HDR_SIZE = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.slots[6] = this.fakeDrive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadRAMWithProgram() {
|
||||||
|
console.log(`Loading program into Apple ][ RAM at \$${this.LOAD_BASE.toString(16)}`);
|
||||||
|
// truncate if needed to fit into RAM
|
||||||
|
const exedata = this.rom.slice(this.HDR_SIZE, this.HDR_SIZE + this.ram.length - this.LOAD_BASE);
|
||||||
|
this.ram.set(exedata, this.LOAD_BASE);
|
||||||
|
// fake DOS detect for CC65 (TODO?)
|
||||||
|
if (this.HDR_SIZE == 58) {
|
||||||
|
this.ram[0xbf00] = 0x4c;
|
||||||
|
this.ram[0xbf6f] = 0x01;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
reset() {
|
reset() {
|
||||||
super.reset();
|
|
||||||
this.auxRAMselected = false;
|
this.auxRAMselected = false;
|
||||||
this.auxRAMbank = 1;
|
this.auxRAMbank = 1;
|
||||||
this.writeinhibit = true;
|
this.writeinhibit = true;
|
||||||
this.ram.fill(0, 0x300, 0x400); // Clear soft-reset vector
|
this.ram.fill(0, 0x300, 0x400); // Clear soft-reset vector
|
||||||
// (force hard reset)
|
// (force hard reset)
|
||||||
|
super.reset();
|
||||||
this.skipboot();
|
this.skipboot();
|
||||||
}
|
}
|
||||||
skipboot() {
|
skipboot() {
|
||||||
@ -479,7 +507,7 @@ var Apple2Display = function(pixels : Uint32Array, apple : AppleGRParams) {
|
|||||||
var oldgrmode = -1;
|
var oldgrmode = -1;
|
||||||
var textbuf = new Array(40*24);
|
var textbuf = new Array(40*24);
|
||||||
|
|
||||||
const flashInterval = 500;
|
const flashInterval = 250;
|
||||||
|
|
||||||
// https://mrob.com/pub/xapple2/colors.html
|
// https://mrob.com/pub/xapple2/colors.html
|
||||||
const loresColor = [
|
const loresColor = [
|
||||||
|
@ -16,7 +16,7 @@ const APPLE2_PRESETS : Preset[] = [
|
|||||||
{id:'cosmic.c', name:'Cosmic Impalas'},
|
{id:'cosmic.c', name:'Cosmic Impalas'},
|
||||||
{id:'farmhouse.c', name:"Farmhouse Adventure"},
|
{id:'farmhouse.c', name:"Farmhouse Adventure"},
|
||||||
{id:'yum.c', name:"Yum Dice Game"},
|
{id:'yum.c', name:"Yum Dice Game"},
|
||||||
{id:'lzgtest.c', name:"LZG Decompressor"},
|
{id:'lz4test.c', name:"LZ4 Decompressor"},
|
||||||
{id:'hgrtest.a', name:"HGR Test", category:"Assembly Language"},
|
{id:'hgrtest.a', name:"HGR Test", category:"Assembly Language"},
|
||||||
{id:'conway.a', name:"Conway's Game of Life"},
|
{id:'conway.a', name:"Conway's Game of Life"},
|
||||||
{id:'lz4fh.a', name:"LZ4FH Decompressor"},
|
{id:'lz4fh.a', name:"LZ4FH Decompressor"},
|
||||||
|
@ -249,7 +249,7 @@ var PLATFORM_PARAMS = {
|
|||||||
arch: '6502',
|
arch: '6502',
|
||||||
define: ['__APPLE2__'],
|
define: ['__APPLE2__'],
|
||||||
cfgfile: 'apple2.cfg',
|
cfgfile: 'apple2.cfg',
|
||||||
libargs: [ '--lib-path', '/share/target/apple2/drv', '-D', '__EXEHDR__=0', 'apple2.lib'],
|
libargs: [ '--lib-path', '/share/target/apple2/drv', 'apple2.lib'],
|
||||||
__CODE_RUN__: 16384,
|
__CODE_RUN__: 16384,
|
||||||
code_start: 0x803,
|
code_start: 0x803,
|
||||||
acmeargs: ['-f', 'apple'],
|
acmeargs: ['-f', 'apple'],
|
||||||
|
Loading…
Reference in New Issue
Block a user