mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-21 21:29:17 +00:00
astrocade: worked on arcade emulation
This commit is contained in:
parent
0ede0e514b
commit
d08d73f422
@ -71,6 +71,7 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
const swidth = arcade ? 320 : 160;
|
||||
const sheight = arcade ? 204 : 102;
|
||||
const swbytes = swidth >> 2;
|
||||
const samask = arcade ? 0x3fff : 0xfff;
|
||||
const INITIAL_WATCHDOG = 256;
|
||||
const PIXEL_ON = 0xffeeeeee;
|
||||
const PIXEL_OFF = 0xff000000;
|
||||
@ -90,19 +91,19 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
var palinds = new Uint8Array(8);
|
||||
var refreshlines = 0;
|
||||
var dirtylines = new Uint8Array(arcade ? 262 : 131);
|
||||
var vidactive = false;
|
||||
var rotdata = new Uint8Array(4);
|
||||
var rotcount = 0;
|
||||
var intst = 0;
|
||||
var waitstates = 0;
|
||||
|
||||
var patboard = new Uint8Array(0x08);
|
||||
var patdest = 0;
|
||||
|
||||
function ramwrite(a: number, v: number) {
|
||||
// set RAM
|
||||
ram[a] = v;
|
||||
waitstates++;
|
||||
// mark scanline as dirty
|
||||
dirtylines[((a & 0xfff) / swbytes) | 0] = 1;
|
||||
dirtylines[((a & samask) / swbytes) | 0] = 1;
|
||||
// this was old behavior where we updated instantly
|
||||
// but it had problems if we had mid-screen palette changes
|
||||
//ramupdate(a, v);
|
||||
@ -201,7 +202,105 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
function refreshall() {
|
||||
refreshlines = sheight;
|
||||
}
|
||||
|
||||
|
||||
// bally astrocade pattern board
|
||||
// https://github.com/mamedev/mame/blob/7ff10685c56a6e123336c684e5e96fdb9e8b3674/src/mame/midway/astrocde_v.cpp#L726
|
||||
function xfer_patboard() {
|
||||
let m_pattern_source = patboard[0] | (patboard[1] << 8);
|
||||
let m_pattern_mode = patboard[2] & 0x3f;
|
||||
let m_pattern_skip = patboard[3];
|
||||
let m_pattern_dest = (patdest & 0xff) | (patboard[4] << 8);
|
||||
let m_pattern_width = patboard[5];
|
||||
let m_pattern_height = patboard[6] + 1;
|
||||
|
||||
let curwidth: number;
|
||||
let u13ff: number = 0;
|
||||
let cycles: number = 0;
|
||||
|
||||
u13ff = 0;
|
||||
|
||||
if ((m_pattern_mode & 0x02) === 0) {
|
||||
u13ff = 1;
|
||||
}
|
||||
|
||||
function incrementSource(): void {
|
||||
if (u13ff && (m_pattern_mode & 0x04) !== 0 && (curwidth !== 0 || (m_pattern_mode & 0x08) === 0)) {
|
||||
m_pattern_source++;
|
||||
}
|
||||
|
||||
if ((m_pattern_mode & 0x02) !== 0) {
|
||||
u13ff ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
function incrementDest(): void {
|
||||
if (curwidth !== 0) {
|
||||
if ((m_pattern_mode & 0x20) !== 0) {
|
||||
m_pattern_dest++;
|
||||
} else {
|
||||
m_pattern_dest--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over height
|
||||
while (m_pattern_height >= 0) {
|
||||
let carry: number;
|
||||
|
||||
curwidth = m_pattern_width;
|
||||
|
||||
// Loop over width
|
||||
while (curwidth >= 0) {
|
||||
let busaddr: number;
|
||||
let busdata: number;
|
||||
|
||||
// Read Phase
|
||||
busaddr = (m_pattern_mode & 0x01) === 0 ? m_pattern_source : m_pattern_dest;
|
||||
|
||||
if (curwidth === 0 && (m_pattern_mode & 0x08) !== 0) {
|
||||
busdata = 0;
|
||||
} else {
|
||||
busdata = membus.read(m_pattern_source);
|
||||
}
|
||||
|
||||
if ((m_pattern_mode & 0x01) === 0) {
|
||||
incrementSource();
|
||||
} else {
|
||||
incrementDest();
|
||||
}
|
||||
|
||||
// Write Phase
|
||||
busaddr = (m_pattern_mode & 0x01) !== 0 ? m_pattern_source : m_pattern_dest;
|
||||
ramwrite(busaddr, busdata);
|
||||
|
||||
if ((m_pattern_mode & 0x01) === 0) {
|
||||
incrementDest();
|
||||
} else {
|
||||
incrementSource();
|
||||
}
|
||||
|
||||
cycles += 4;
|
||||
curwidth--;
|
||||
}
|
||||
|
||||
// At the end of each row, adjust m_pattern_dest
|
||||
carry = ((m_pattern_dest & 0xff) + m_pattern_skip) & 0x100;
|
||||
m_pattern_dest = (m_pattern_dest & 0xff00) | ((m_pattern_dest + m_pattern_skip) & 0xff);
|
||||
|
||||
if ((m_pattern_mode & 0x10) === 0) {
|
||||
m_pattern_dest += carry;
|
||||
} else {
|
||||
m_pattern_dest -= carry ^ 0x100;
|
||||
}
|
||||
|
||||
m_pattern_height--;
|
||||
}
|
||||
|
||||
// Adjust m_maincpu.icount
|
||||
// m_maincpu.adjust_icount(-cycles);
|
||||
// Replace the above line with the actual adjustment of icount.
|
||||
}
|
||||
|
||||
this.drawScanline = (sl:number) => {
|
||||
// interrupt
|
||||
if (sl == inlin && (inmod & 0x8)) {
|
||||
@ -226,9 +325,9 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
ram = r;
|
||||
inputs = inp;
|
||||
psg = psgg;
|
||||
//bios = padBytes(ASTROCADE_MINIMAL_BIOS, 0x2000);
|
||||
bios = padBytes(new lzgmini().decode(stringToByteArray(atob(ASTROLIBRE_BIOS_LZG))), 0x2000);
|
||||
if (!arcade) {
|
||||
//bios = padBytes(ASTROCADE_MINIMAL_BIOS, 0x2000);
|
||||
bios = padBytes(new lzgmini().decode(stringToByteArray(atob(ASTROLIBRE_BIOS_LZG))), 0x2000);
|
||||
// game console
|
||||
membus = {
|
||||
read: newAddressDecoder([
|
||||
@ -246,13 +345,14 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
membus = {
|
||||
read: newAddressDecoder([
|
||||
[0x4000, 0x7fff, 0x3fff, function(a) { return ram[a]; }], // screen RAM
|
||||
[0xd000, 0xdfff, 0xfff, function(a) { return ram[a + 0x4000]; }], // static RAM
|
||||
[0x0000, 0xafff, 0xffff, function(a) { return rom ? rom[a] : 0; }], // ROM (0-3fff,8000-afff)
|
||||
[0xd000, 0xdfff, 0x0fff, function(a) { return ram[a + 0x4000]; }], // static RAM
|
||||
[0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : 0; }], // ROM
|
||||
[0x8000, 0xbfff, 0x3fff, function(a) { return rom ? rom[a + 0x4000] : 0; }], // ROM
|
||||
]),
|
||||
write: newAddressDecoder([
|
||||
[0x4000, 0x7fff, 0x3fff, ramwrite],
|
||||
[0xd000, 0xdfff, 0xfff, function(a, v) { ramwrite(a + 0x4000, v); }], // static RAM
|
||||
[0x0000, 0x3fff, 0x3fff, magicwrite],
|
||||
[0xd000, 0xdfff, 0x0fff, function(a, v) { ramwrite(a + 0x4000, v); }], // static RAM
|
||||
]),
|
||||
}
|
||||
}
|
||||
@ -273,6 +373,19 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
return rtn;
|
||||
},
|
||||
write: function(addr, val) {
|
||||
if (addr == 0xa55b) {
|
||||
// TODO: protected_ram_enable_w
|
||||
return;
|
||||
}
|
||||
addr &= 0xff;
|
||||
// pattern board
|
||||
if (addr > 0x78 && addr < 0x80) {
|
||||
patboard[addr & 7] = val;
|
||||
if (addr == 0x72) { patdest = 0; }
|
||||
if (addr == 0x74) { patdest = (patdest + patboard[3]) & 0xff; }
|
||||
if (addr == 0x7e) { xfer_patboard(); }
|
||||
return;
|
||||
}
|
||||
addr &= 0x1f;
|
||||
val &= 0xff;
|
||||
switch (addr) {
|
||||
@ -332,8 +445,15 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
case 0x19: // XPAND
|
||||
xpand = val;
|
||||
break;
|
||||
case 0x1a:
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
//psg2.setACRegister(addr - 0x1a, val);
|
||||
break;
|
||||
default:
|
||||
console.log('IO write', hex(addr, 4), hex(val, 2));
|
||||
//console.log('IO write', hex(addr, 4), hex(val, 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -372,6 +492,8 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
rotdata.set(state.rotdata);
|
||||
intst = state.intst;
|
||||
inputs.set(state.inputs);
|
||||
patboard.set(state.patboard);
|
||||
patdest = state.patdest;
|
||||
refreshall();
|
||||
}
|
||||
|
||||
@ -393,7 +515,9 @@ const _BallyAstrocade = function(arcade:boolean) {
|
||||
verbl: verbl,
|
||||
rotcount: rotcount,
|
||||
rotdata: rotdata.slice(0),
|
||||
intst: intst
|
||||
intst: intst,
|
||||
patboard: patboard.slice(0),
|
||||
patdest: patdest,
|
||||
};
|
||||
}
|
||||
this.reset = () => {
|
||||
@ -450,6 +574,7 @@ export class BallyAstrocade extends BasicScanlineMachine implements AcceptsPaddl
|
||||
ram : Uint8Array;
|
||||
cpu : Z80;
|
||||
m; // _BallyAstrocade
|
||||
arcade : boolean;
|
||||
|
||||
psg: AstrocadeAudio;
|
||||
audioadapter;
|
||||
@ -458,6 +583,7 @@ export class BallyAstrocade extends BasicScanlineMachine implements AcceptsPaddl
|
||||
|
||||
constructor(arcade:boolean) {
|
||||
super();
|
||||
this.arcade = arcade;
|
||||
this.cpu = new Z80();
|
||||
this.psg = new AstrocadeAudio(new MasterAudio());
|
||||
this.audioadapter = new TssChannelAdapter(this.psg.psg, audioOversample, this.sampleRate);
|
||||
@ -471,6 +597,12 @@ export class BallyAstrocade extends BasicScanlineMachine implements AcceptsPaddl
|
||||
//this.cpuCyclesPerVisible = this.cpuCyclesPerLine - this.cpuCyclesPerHBlank;
|
||||
this.m = new _BallyAstrocade(arcade);
|
||||
this.m.init(this, this.cpu, this.ram, this.inputs, this.psg);
|
||||
if (arcade) {
|
||||
this.inputs[0x10] = 0xff; // switches (active low)
|
||||
this.inputs[0x11] = 0xff; // switches (active low)
|
||||
this.inputs[0x12] = 0x00;
|
||||
this.inputs[0x13] = 0x08; // dip switches
|
||||
}
|
||||
}
|
||||
|
||||
read(a:number) : number {
|
||||
@ -556,8 +688,16 @@ export class BallyAstrocade extends BasicScanlineMachine implements AcceptsPaddl
|
||||
case 'Astro': return this.m.toLongString(state);
|
||||
}
|
||||
}
|
||||
getRasterCanvasPosition() { return { x: this.getRasterX(), y: this.getRasterY() }; }
|
||||
|
||||
getRasterCanvasPosition() {
|
||||
return { x: this.getRasterX(), y: this.getRasterY() };
|
||||
}
|
||||
getVideoParams() {
|
||||
if (this.arcade) {
|
||||
return { width: 320, height: 204, rotate: 180 };
|
||||
} else {
|
||||
return { width: 160, height: 102 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////
|
||||
@ -591,16 +731,6 @@ class AstrocadeAudio extends AY38910_Audio {
|
||||
}
|
||||
}
|
||||
|
||||
export const _BallyArcade = function() {
|
||||
this.__proto__ = new (_BallyAstrocade as any)(true);
|
||||
// TODO: inputs[0x13] = 0xfe; // dip switch on arcade
|
||||
// TODO: arcade controls, bit blit
|
||||
var _in = this.saveControlsState();
|
||||
_in.in[0x10] = 0xff; // switches
|
||||
_in.in[0x13] = 0xfe; // dip switches
|
||||
this.loadControlsState(_in);
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
//http://glankonian.com/~lance/astrocade_palette.html
|
||||
|
@ -26,6 +26,10 @@ const ASTROCADE_BIOS_PRESETS = [
|
||||
{ id: 'bios.c', name: 'BIOS' },
|
||||
];
|
||||
|
||||
const ASTROCADE_ARCADE_PRESETS = [
|
||||
{ id: 'hello.c', name: 'Hello Graphics' },
|
||||
];
|
||||
|
||||
class BallyAstrocadePlatform extends BaseZ80MachinePlatform<BallyAstrocade> implements Platform {
|
||||
|
||||
newMachine() { return new BallyAstrocade(false); }
|
||||
@ -52,10 +56,13 @@ class BallyAstrocadeBIOSPlatform extends BallyAstrocadePlatform implements Platf
|
||||
class BallyArcadePlatform extends BallyAstrocadePlatform implements Platform {
|
||||
|
||||
newMachine() { return new BallyAstrocade(true); }
|
||||
getPresets() { return ASTROCADE_ARCADE_PRESETS; }
|
||||
|
||||
getMemoryMap = function() { return { main:[
|
||||
{name:'ROM',start:0x0,size:0x4000,type:'rom'},
|
||||
{name:'Magic RAM',start:0x0,size:0x4000,type:'ram'},
|
||||
{name:'Screen RAM',start:0x4000,size:0x4000,type:'ram'},
|
||||
{name:'ROM',start:0x8000,size:0x4000,type:'rom'},
|
||||
] } };
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user