ScriptedAmigaEmulator/sae/playfield.js
Rupert Hausberger 0c5b018866 update 0.7.0
2012-12-22 19:39:33 +01:00

1376 lines
42 KiB
JavaScript

/**************************************************************************
* SAE - Scripted Amiga Emulator
*
* https://github.com/naTmeg/ScriptedAmigaEmulator
*
* ©2012 Rupert Hausberger
* Commercial use is prohibited.
*
**************************************************************************/
function Sprite(num) {
this.num = num;
this.pt = 0;
this.pos = 0;
this.ctl = 0;
this.data = 0;
this.datb = 0;
this.xpos = 0;
this.vstart = 0;
this.vstop = 0;
this.armed = false;
this.dmastate = 0;
this.dmacycle = 0;
}
function Sprites() {
const MAX_SPRITES = 8;
this.sprite = new Array(MAX_SPRITES);
for (var i = 0; i < MAX_SPRITES; i++)
this.sprite[i] = new Sprite(i);
var spr_data = [];
var spr_state = [];
var spr_attach = [];
var dblpf_ms = null;
var dblpf_ms1 = null;
var dblpf_ms2 = null;
var sprite_offs = null;
var sprtabb = null;
var sprtaba = null;
var sprite_ab_merge = null;
var sprclx = null;
var clxmask = null;
this.nr_armed = 0;
var sprite_vblank_endline = 0;
var sprite_mask = 0;
//var sprite_minx, sprite_maxx;
this.clxdat = 0;
this.clxcon = 0;
var clxcon_bpl_enable = 0;
var clxcon_bpl_match = 0;
this.init_sprite_tables = function() {
//spr_data = new Array(800);
//spr_state = new Array(800);
//spr_attach = new Array(800);
dblpf_ms = new Array(256);
dblpf_ms1 = new Array(256);
dblpf_ms2 = new Array(256);
sprite_offs = new Array(256);
sprtaba = new Array(256);
sprtabb = new Array(256);
sprite_ab_merge = new Array(256);
for (var i = 0; i < 256; i++) {
var plane1 = ((i >> 0) & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8);
var plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8);
dblpf_ms[i] = i == 0 ? 16 : 8;
dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0;
dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8;
sprite_offs[i] = (i & 15) ? 0 : 2;
sprtaba[i] = ((((i >> 7) & 1) << 0) | (((i >> 6) & 1) << 2) | (((i >> 5) & 1) << 4) | (((i >> 4) & 1) << 6) | (((i >> 3) & 1) << 8) | (((i >> 2) & 1) << 10) | (((i >> 1) & 1) << 12) | (((i >> 0) & 1) << 14));
sprtabb[i] = sprtaba[i] << 1;
sprite_ab_merge[i] = (((i & 15) ? 1 : 0) | ((i & 240) ? 2 : 0));
}
sprclx = new Array(16);
clxmask = new Array(16);
for (var i = 0; i < 16; i++) {
clxmask[i] = (((i & 1) ? 0xF : 0x3) | ((i & 2) ? 0xF0 : 0x30) | ((i & 4) ? 0xF00 : 0x300) | ((i & 8) ? 0xF000 : 0x3000));
sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0) | ((i & 0x5) == 0x5 ? 2 : 0) | ((i & 0x9) == 0x9 ? 4 : 0) | ((i & 0x6) == 0x6 ? 8 : 0) | ((i & 0xA) == 0xA ? 16 : 0) | ((i & 0xC) == 0xC ? 32 : 0)) << 9;
}
}
this.setup = function() {
sprite_vblank_endline = AMIGA.config.video.ntsc ? 20 : 25;
if (dblpf_ms == null) this.init_sprite_tables();
}
this.cleanup = function() {}
this.reset = function() {}
this.clear = function() {
spr_data = [];
spr_state = [];
spr_attach = [];
}
this.setMask = function (pf1p, pf2p) {
sprite_mask = 0xFFFF0000 << (4 * pf2p);
sprite_mask &= 0xFFFFFFFF;
sprite_mask |= (0x0000FFFF << (4 * pf1p)) & 0xFFFF;
sprite_mask &= 0xFFFFFFFF;
}
this.render = function (pos, apixel) {
if (!spr_data[pos]) return 0;
var maskshift = AMIGA.playfield.state.dpf ? (AMIGA.playfield.state.pf2pri ? dblpf_ms2[apixel] : dblpf_ms1[apixel]) : dblpf_ms[apixel];
var plfmask = (sprite_mask >>> maskshift) >>> maskshift;
var v = spr_data[pos] & ~plfmask;
if (v != 0) {
var v1 = v & 255;
var offs;
var col;
if (v1 == 0) offs = sprite_offs[v >> 8] + 4;
else offs = sprite_offs[v1];
v = (v >> (offs << 1)) & 15;
//v ^= 8; /* debug */
if (spr_attach[pos] && (spr_state[pos] & (3 << offs))) {
col = 16 + v;
} else {
var vlo = v & 3;
var vhi = (v & (vlo - 1)) >> 2;
col = 16 + (vlo | vhi) + offs * 2;
}
return col;
}
return 0;
}
this.spr_plf_collision = function() {
if (clxcon_bpl_enable == 0) {
this.clxdat |= 0x1fe;
return;
}
var collision_mask = clxmask[this.clxcon >> 12];
for (var i = 0; i < MAX_SPRITES; i++) {
var sprxp = (this.sprite[i].xpos - AMIGA.playfield.state.hstart + 1) * (AMIGA.playfield.state.hires ? 2 : 1);
if (!this.sprite[i].armed || sprxp < 0) continue;
var minpos = sprxp;
var maxpos = sprxp + 16;
for (var j = minpos; j < maxpos; j++) {
var sprpix = spr_data[j] & collision_mask;
var match = 1;
if (sprpix == 0) continue;
sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2);
sprpix <<= 1;
for (var k = 1; k >= 0; k--) {
if (AMIGA.playfield.bplcon0 & 0x400) match = 1;
for (var l = k; match && l < 6; l += 2) {
if (clxcon_bpl_enable & (1 << l)) {
var t = 0;
if (l < AMIGA.playfield.state.planes) {
t = (AMIGA.playfield.linedata[j] >> l) & 1;
}
if (t != ((clxcon_bpl_match >> l) & 1)) match = 0;
}
}
if (match) {
this.clxdat |= sprpix << (k * 4);
}
}
}
}
}
this.draw_1 = function (sprxp, bufpos, datab, num, dbl, mask, do_collisions, collision_mask) {
var j = 0;
while (datab) {
var col = 0;
var coltmp = 0;
//if ((sprxp >= this.sprite_minx && sprxp < this.sprite_maxx) || (AMIGA.playfield.bplcon3 & 2))
col = (datab & 3) << (2 * num);
/*if (0) {
if (sprxp == this.sprite_minx || sprxp == this.sprite_maxx - 1)
col ^= (rand () << 16) | rand ();
}*/
//if ((j & mask) == 0)
{
var tmp = spr_data[bufpos] | col;
spr_data[bufpos++] = tmp;
if (do_collisions) coltmp |= tmp;
//sprxp++;
}
if (dbl > 0) {
var tmp = spr_data[bufpos] | col;
spr_data[bufpos++] = tmp;
if (do_collisions) coltmp |= tmp;
//sprxp++;
}
j++;
datab >>>= 2;
if (do_collisions) {
coltmp &= collision_mask;
if (coltmp) {
var shrunk_tmp = sprite_ab_merge[coltmp & 255] | (sprite_ab_merge[coltmp >> 8] << 2);
this.clxdat |= sprclx[shrunk_tmp];
}
}
}
}
this.draw = function() {
//if (this.nr_armed == 0) return;
var nrs = [], posns = [];
var count = 0;
var xoffs = (180 - (AMIGA.playfield.state.hlen >> 1)) << (AMIGA.playfield.state.hires ? 1 : 0);
for (var i = 0; i < MAX_SPRITES; i++) {
var sprxp = xoffs + ((this.sprite[i].xpos - AMIGA.playfield.state.hstart) << (AMIGA.playfield.state.hires ? 1 : 0));
if (!this.sprite[i].armed || sprxp < 0) continue;
var j, bestp;
for (bestp = 0; bestp < count; bestp++) {
if (posns[bestp] > sprxp) break;
if (posns[bestp] == sprxp && nrs[bestp] < i) break;
}
for (j = count; j > bestp; j--) {
posns[j] = posns[j - 1];
nrs[j] = nrs[j - 1];
}
posns[j] = sprxp;
nrs[j] = i;
count++;
}
//if (count) { for (i = 0; i < count; i++) BUG.info('SPR n %d, x %d', nrs[i], posns[i]); BUG.info('------------'); }
var collision_mask = clxmask[this.clxcon >> 12];
for (i = 0; i < count; i++) {
var sprxp = posns[i];
var nr = nrs[i];
var attachment = this.sprite[nr | 1].ctl & 0x80;
var da = this.sprite[nr].data;
var db = this.sprite[nr].datb;
var datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8] | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]);
var dbl = AMIGA.playfield.state.hires ? 1 : 0;
var mask = 0;
if (AMIGA.config.chipset.colLevel != SAEV_Config_Chipset_ColLevel_None && collision_mask) this.draw_1(sprxp, sprxp, datab, nr, dbl, mask, 1, collision_mask);
else this.draw_1(sprxp, sprxp, datab, nr, dbl, mask, 0, collision_mask);
if (attachment) {
var state = (1 << (nr & ~1)) & 0xff;
for (j = 0; j < 16; j++) {
spr_state[sprxp + j] |= state;
spr_attach[sprxp + j] = true;
}
}
}
}
this.sprite_fetch = function(n, dma, hpos, cycle, mode) {
var data = AMIGA.custom.last_value;
if (dma)
data = AMIGA.mem.load16_chip(this.sprite[n].pt);
this.sprite[n].pt += 2;
return data;
}
this.cycle_1 = function (vp, n, cycle, hpos) {
var isdma = AMIGA.dmaen(DMAF_SPREN) || ((n & 1) && this.sprite[n & ~1].dmacycle);
if (isdma && vp == sprite_vblank_endline) this.sprArm(n, 0);
if (vp == this.sprite[n].vstart) {
this.sprite[n].dmastate = 1;
//if (n == 0 && cycle == 0) cursorsprite();
}
if (vp == this.sprite[n].vstop || vp == sprite_vblank_endline) {
this.sprite[n].dmastate = 0;
if (1) {
// roots 2.0 flower zoomer bottom part missing if this enabled
if (vp == this.sprite[n].vstop) {
this.sprArm(n, 0);
//return;
}
}
}
if (!isdma) return;
if (cycle && !this.sprite[n].dmacycle) return; /* Superfrog intro flashing bee fix */
var dma = hpos < AMIGA.playfield.state.dstart;
var posctl = 0;
if (vp == this.sprite[n].vstop || vp == sprite_vblank_endline) {
this.sprite[n].dmastate = 0;
posctl = 1;
if (dma) {
var data = this.sprite_fetch(n, dma, hpos, cycle, 0);
if (cycle == 0) {
this.SPRxPOS(data, n);
this.sprite[n].dmacycle = 1;
} else {
this.SPRxCTL(data, n);
this.sprite[n].dmastate = 0;
this.sprStartStop(n);
}
}
}
if (this.sprite[n].dmastate && !posctl && dma) {
var data = this.sprite_fetch(n, dma, hpos, cycle, 1);
if (cycle == 0) {
this.SPRxDATA(data, n);
this.sprite[n].dmacycle = 1;
} else {
this.SPRxDATB(data, n);
this.sprArm(n, 1);
}
}
}
this.cycle = function (hpos) {
var vp = AMIGA.events.vpos;
if (vp < sprite_vblank_endline) return;
for (var i = 0; i < MAX_SPRITES * 2; i++) {
this.sprite[i >> 1].dmacycle = 1;
this.cycle_1(vp, i >> 1, i & 1, 0);
}
}
this.sprArm = function (n, state) {
switch (state) {
case 0:
this.nr_armed -= this.sprite[n].armed;
this.sprite[n].armed = 0;
break;
default:
this.nr_armed += 1 - this.sprite[n].armed;
this.sprite[n].armed = 1;
}
}
this.sprStartStop = function (n) {
if (AMIGA.events.vpos + 1 == this.sprite[n].vstart) this.sprite[n].dmastate = 1;
if (AMIGA.events.vpos + 1 == this.sprite[n].vstop) this.sprite[n].dmastate = 0;
}
this.SPRxCTLPOS = function (n) {
this.sprStartStop(n);
this.sprite[n].xpos = (this.sprite[n].pos & 0xff) * 2 + (this.sprite[n].ctl & 1);
this.sprite[n].vstart = (this.sprite[n].pos >> 8) | ((this.sprite[n].ctl << 6) & 0x100);
this.sprite[n].vstop = (this.sprite[n].ctl >> 8) | ((this.sprite[n].ctl << 7) & 0x100);
/*if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS) {
this.sprite[n].vstart |= (this.sprite[n].ctl << 3) & 0x200;
this.sprite[n].vstop |= (this.sprite[n].ctl << 4) & 0x200;
}*/
this.sprStartStop(n);
}
this.SPRxCTL = function (v, n) {
this.sprite[n].ctl = v;
this.sprArm(n, 0);
this.SPRxCTLPOS(n);
}
this.SPRxPOS = function (v, n) {
this.sprite[n].pos = v;
this.SPRxCTLPOS(n);
}
this.SPRxDATA = function (v, n) {
this.sprite[n].data = v;
this.sprArm(n, 1);
}
this.SPRxDATB = function (v, n) {
this.sprite[n].datb = v;
}
this.SPRxPTH = function (v, n) {
this.sprite[n].pt = ((v << 16) | (this.sprite[n].pt & 0xffff)) >>> 0;
}
this.SPRxPTL = function (v, n) {
this.sprite[n].pt = ((this.sprite[n].pt & 0xffff0000) | v) >>> 0;
}
this.CLXCON = function (v) {
this.clxcon = v;
clxcon_bpl_enable = (v >> 6) & 63;
clxcon_bpl_match = v & 63;
}
this.CLXDAT = function() {
var v = this.clxdat | 0x8000;
this.clxdat = 0;
return v;
}
}
function Plane(num) {
this.num = num;
this.pt = 0;
this.dat = -1;
this.line = new Uint16Array(45);
}
function Playfield() {
/* BPLCON0 flags */
const BPLF_ERSY = 1 << 1;
const BPLF_LACE = 1 << 2;
const BPLF_LPEN = 1 << 3;
const BPLF_GAUD = 1 << 8;
const BPLF_COLOR = 1 << 9;
const BPLF_DBLPF = 1 << 10;
const BPLF_HOMOD = 1 << 11;
const BPLF_HIRES = 1 << 15;
/* BPLCON2 flags */
const BPLF_PF2PRI = 1 << 6;
this.sprites = new Sprites();
this.plane = new Array(6);
for (var i = 0; i < 6; i++)
this.plane[i] = new Plane(i);
this.color_std = new Uint16Array(32);
this.color_ehb = new Uint16Array(32);
for (var i = 0; i < 32; i++) this.color_std[i] = this.color_ehb[i] = 0;
this.linedata = [];
this.bplcon0 = 0;
this.bplcon1 = 0;
this.bplcon2 = 0;
this.bplcon3 = 0;
this.bpl1mod = 0;
this.bpl2mod = 0;
this.diwstrt = 0;
this.diwstop = 0;
this.diwhigh = -1; //ECS
this.ddfstrt = 0;
this.ddfstop = 0;
this.state = {
vstart: 0,
vstop: 0,
vlen: 0,
vlenreal: 0,
vlenrealset: 0,
vlenrealtmp: 0,
hstart: 0,
hstop: 0,
hlen: 0,
hnum: 0,
hpixel: 0,
hleft: 0,
dstart: 0,
dstop: 0,
dlen: 0,
dnum: 0,
dwords: 0,
ddiff: 0,
altget: false,
hires: false,
ilace: false,
std: false,
ehb: false,
dpf: false,
ham: false,
planes: 0,
delay1: 0,
delay2: 0,
pf2pri: false,
pf1p: 0,
pf2p: 0,
colorOnly: true,
hScale: true,
vScale: true,
};
this.frame = {
skip: false,
skipcount: 0,
count: 0
};
/* for playfield development */
/*this.lamps = function() {
var e = document.getElementById('lamp_hir');
if (e) e.style.color = this.state.hires ? '#8c8' : '#888';
e = document.getElementById('lamp_ila');
if (e) e.style.color = this.state.ilace ? '#8c8' : '#888';
e = document.getElementById('lamp_dpf');
if (e) e.style.color = this.state.dpf ? '#8c8' : '#888';
e = document.getElementById('lamp_ham');
if (e) e.style.color = this.state.ham ? '#8c8' : '#888';
e = document.getElementById('lamp_ehb');
if (e) e.style.color = this.state.ehb ? '#8c8' : '#888';
e = document.getElementById('lamp_scr');
if (e) e.style.color = this.state.altget ? '#8c8' : '#888';
e = document.getElementById('lamp_p2p');
if (e) e.style.color = this.state.pf2pri ? '#8c8' : '#888';
e = document.getElementById('lamp_nPl');
if (e) e.innerHTML = this.state.planes;
e = document.getElementById('lamp_dl1');
if (e) e.innerHTML = sprintf('%02d', this.state.delay1);
e = document.getElementById('lamp_dl2');
if (e) e.innerHTML = sprintf('%02d', this.state.delay2);
//if (this.state.hlen > 0 && this.state.hlen <= 720 && this.state.vlen > 0 && this.state.vlen <= 288)
{
e = document.getElementById('lamp_diw');
if (e) e.innerHTML = sprintf('%dx%d', this.state.hlen, this.state.vlenreal);
}
e = document.getElementById('lamp_dff');
if (e) e.innerHTML = sprintf('%d (%d)', this.state.dlen, this.state.ddiff);
}*/
this.setup = function() {
this.create_cycle_diagram_table();
this.sprites.setup();
}
this.cleanup = function() {
this.sprites.cleanup();
}
this.reset = function() {
this.state.colorOnly = true;
this.state.hScale = true;
this.state.vScale = true;
for (var i = 0; i < 32; i++)
this.color_std[i] = this.color_ehb[i] = 0;
this.frame.skip = false;
this.frame.skipcount = 0;
}
this.recalc = function() {
this.state.vlen = this.state.vstop - this.state.vstart;
this.state.hlen = this.state.hstop - this.state.hstart;
this.state.hnum = this.state.hlen >> 3;
this.state.dlen = (this.state.dstop - this.state.dstart + 15) & ~7;
this.state.dnum = this.state.dlen >> 3;
this.state.ddiff = (this.state.dnum << 1) - this.state.hnum;
if (this.state.ddiff < 0) this.state.ddiff = 0;
//this.state.hlen = this.state.dlen << 1;
this.state.hpixel = this.state.hlen << (this.state.hires ? 1 : 0);
this.state.hleft = (180 - Math.min(this.state.hlen >> 1, this.state.dlen)) << (this.state.hires ? 1 : 0);
this.state.dwords = this.state.dnum << (this.state.hires ? 1 : 0);
this.state.altget = this.state.ddiff != 0 && ((this.state.dstart >> 3) & 1) != 0;
//this.lamps();
}
this.calcdiw = function() {
this.state.vstart = this.diwstrt >> 8;
this.state.vstop = this.diwstop >> 8;
this.state.hstart = this.diwstrt & 0xff;
this.state.hstop = this.diwstop & 0xff;
this.state.hstart &= ~7;
this.state.hstop &= ~7;
if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS && this.diwhigh != -1) {
this.state.vstart |= (this.diwhigh & 7) << 8;
this.state.vstop |= ((this.diwhigh >> 8) & 7) << 8;
this.state.hstart |= ((this.diwhigh >> 5) & 1) << 8;
this.state.hstop |= ((this.diwhigh >> 13) & 1) << 8;
} else {
if ((this.state.vstop & 0x80) == 0) this.state.vstop |= 0x100;
this.state.hstop += 0x100;
}
this.recalc();
//BUG.info('Playfield.calcdiw() diwstrt $%04x diwstop $%04x | v %d-%d, h %d-%d | %d x %d', this.diwstrt, this.diwstop, this.state.vstart, this.state.vstop, this.state.hstart, this.state.hstop, this.state.hlen, this.state.vlen);
}
this.calcddf = function(stop) {
this.state.dstart = this.ddfstrt & 0xff;
this.state.dstop = this.ddfstop & 0xff;
this.state.dstart &= ~3;
this.state.dstop &= ~3;
if (this.state.dstart < 0x18) this.state.dstart = 0x18;
if (this.state.dstop > 0xd8) this.state.dstop = 0xd8;
/*if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS) {
if (this.state.dstop > AMIGA.events.maxhpos) this.state.dstart = 0;
if (this.state.dstart < 0x18) this.state.dstart = 0x18;
} else {
if (this.state.dstart >= this.state.dstop && this.state.dstart >= 0x18) this.state.dstop = 0xff;
}*/
this.recalc();
//BUG.info('Playfield.calcddf() ddfstrt $%04x ddfstop $%04x | plflinelen %d', this.ddfstrt, this.ddfstop, this.state.dlen);
}
this.drawpixel = function (xpos, ypos, rgb) {
/*if (this.state.ilace) {
if (this.state.hires)
AMIGA.video.drawpixel(xpos, ypos, rgb);
else {
AMIGA.video.drawpixel(xpos*2, ypos, rgb);
AMIGA.video.drawpixel(xpos*2+1, ypos, rgb);
}
} else {
if (this.state.hires) {
AMIGA.video.drawpixel(xpos, ypos*2, rgb);
AMIGA.video.drawpixel(xpos, ypos*2+1, rgb);
} else {
AMIGA.video.drawpixel(xpos*2, ypos*2, rgb);
AMIGA.video.drawpixel(xpos*2+1, ypos*2, rgb);
AMIGA.video.drawpixel(xpos*2, ypos*2+1, rgb);
AMIGA.video.drawpixel(xpos*2+1, ypos*2+1, rgb);
}
}*/
if (this.state.hires)
AMIGA.video.drawpixel(xpos, ypos, rgb);
else
AMIGA.video.draw2pixel(xpos << 1, ypos, rgb);
}
this.drawpixel_std = function (xpos, ypos, col) {
var spritecol = this.sprites.render(xpos, col);
var rgb = this.color_std[spritecol ? spritecol : col];
this.linedata[xpos] = col;
//AMIGA.video.drawpixel(xpos, ypos, rgb);
this.drawpixel(xpos, ypos, rgb);
}
this.drawpixel_ehb = function (xpos, ypos, col, ehb) {
var rgb;
var spritecol = this.sprites.render(xpos, col);
if (spritecol) rgb = this.color_std[spritecol];
else rgb = ehb ? this.color_ehb[col] : this.color_std[col];
this.linedata[xpos] = col;
//AMIGA.video.drawpixel(xpos, ypos, rgb);
this.drawpixel(xpos, ypos, rgb);
}
this.drawpixel_dpf = function (xpos, ypos, col1, col2) {
var rgb, col = this.state.pf2pri ? col2 : col1;
var spritecol = this.sprites.render(xpos, col);
if (spritecol)
rgb = this.color_std[spritecol];
else {
col = this.state.pf2pri ? (col2 > 0 ? (8 + col2) : col1) : (col1 > 0 ? col1 : (8 + col2));
rgb = this.color_std[col];
}
this.linedata[xpos] = col;
//AMIGA.video.drawpixel(xpos, ypos, rgb);
this.drawpixel(xpos, ypos, rgb);
}
this.drawpixel_ham_col = function (xpos, ypos, col) {
var spritecol = this.sprites.render(xpos, col);
var rgb = this.color_std[spritecol ? spritecol : col]
this.linedata[xpos] = col;
//AMIGA.video.drawpixel(xpos, ypos, rgb);
this.drawpixel(xpos, ypos, rgb);
}
this.drawpixel_ham_rgb = function (xpos, ypos, rgb) {
var spritecol = this.sprites.render(xpos, 0);
if (spritecol) rgb = this.color_std[spritecol];
this.linedata[xpos] = 0;
//AMIGA.video.drawpixel(xpos, ypos, rgb);
this.drawpixel(xpos, ypos, rgb);
}
this.drawline_std = function(x, y, o) {
var i, j, l;
if (this.state.altget && this.state.ddiff < 4) {
for (j = 0; j < 4; j++) AMIGA.video.drawpixel(x + j, y, this.color_std[0]);
for (j = 4, l = 11; j < 16; j++, l--) {
var col = 0;
switch (this.state.planes) {
case 5: col = ((this.plane[4].line[o] >> l) & 1);
case 4: col = (col << 1) | ((this.plane[3].line[o] >> l) & 1);
case 3: col = (col << 1) | ((this.plane[2].line[o] >> l) & 1);
case 2: col = (col << 1) | ((this.plane[1].line[o] >> l) & 1);
case 1: col = (col << 1) | ((this.plane[0].line[o] >> l) & 1);
}
this.drawpixel_std(x + j, y, col);
}
i = 16; o++;
} else
i = 0;
for (; i < this.state.hpixel; i += 16, o++) {
for (j = 0, l = 15; j < 16; j++, l--) {
var col = 0;
switch (this.state.planes) {
case 5: col = ((this.plane[4].line[o] >> l) & 1);
case 4: col = (col << 1) | ((this.plane[3].line[o] >> l) & 1);
case 3: col = (col << 1) | ((this.plane[2].line[o] >> l) & 1);
case 2: col = (col << 1) | ((this.plane[1].line[o] >> l) & 1);
case 1: col = (col << 1) | ((this.plane[0].line[o] >> l) & 1);
}
this.drawpixel_std(x + i + j, y, col);
}
}
}
this.drawline_ehb = function(x, y, o) {
for (var i = 0; i < this.state.hpixel; i += 16, o++) {
for (var j = 0, l = 15; j < 16; j++, l--) {
var ehb = ((this.plane[5].line[o] >> l) & 1);
var col = ((this.plane[4].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[3].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[2].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[1].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[0].line[o] >> l) & 1);
this.drawpixel_ehb(x + i + j, y, col, ehb);
}
}
}
this.drawline_dpf = function(x, y, o) {
for (var i = 0; i < this.state.hpixel; i += 16, o++) {
for (var j = 0, l = 15; j < 16; j++, l--) {
var col1 = 0, col2 = 0;
switch (this.state.planes) {
case 6: col2 = ((this.plane[5].line[o] >> l) & 1);
case 5: col1 = ((this.plane[4].line[o] >> l) & 1);
case 4: col2 = (col2 << 1) | ((this.plane[3].line[o] >> l) & 1);
case 3: col1 = (col1 << 1) | ((this.plane[2].line[o] >> l) & 1);
case 2: col2 = (col2 << 1) | ((this.plane[1].line[o] >> l) & 1);
case 1: col1 = (col1 << 1) | ((this.plane[0].line[o] >> l) & 1);
}
this.drawpixel_dpf(x + i + j, y, col1, col2);
}
}
}
this.drawline_ham = function(x, y, o) {
var opm, col, r = 0, g = 0, b = 0;
for (var i = 0; i < this.state.hpixel; i += 16, o++) {
for (var j = 0, l = 15; j < 16; j++, l--) {
opm = (((this.plane[5].line[o] >> l) & 1) << 1) | ((this.plane[4].line[o] >> l) & 1);
col = ((this.plane[3].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[2].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[1].line[o] >> l) & 1);
col = (col << 1) | ((this.plane[0].line[o] >> l) & 1);
switch (opm) {
case 2: { r = col; this.drawpixel_ham_rgb(x + i + j, y, ((r << 1) << 11) | ((g << 2) << 5) | (b << 1)); break; }
case 3: { g = col; this.drawpixel_ham_rgb(x + i + j, y, ((r << 1) << 11) | ((g << 2) << 5) | (b << 1)); break; }
case 1: { b = col; this.drawpixel_ham_rgb(x + i + j, y, ((r << 1) << 11) | ((g << 2) << 5) | (b << 1)); break; }
default: {
r = ((this.color_std[col] >> 11) & 31) >> 1;
g = ((this.color_std[col] >> 5) & 63) >> 2;
b = (this.color_std[col] & 31) >> 1;
this.drawpixel_ham_col(x + i + j, y, col);
}
}
}
}
}
this.drawline_border = function(y) {
var l = this.state.hleft;
var w = this.state.hpixel;
var r = this.state.hires ? VIDEO_WIDTH : VIDEO_WIDTH >> 1;
var x, rgb = this.color_std[0];
if (!this.state.hires) {
l <<= 1;
w <<= 1;
r <<= 1;
}
AMIGA.video.drawline_from_to(0, l, y, rgb);
AMIGA.video.drawline_from_to(l + w, r, y, rgb);
}
this.drawline_empty = function(y) {
var l = this.state.hleft;
var w = this.state.hpixel;
var x, rgb = this.color_std[0];
if (!this.state.hires) {
l <<= 1;
w <<= 1;
}
AMIGA.video.drawline_from_to(l, l + w, y, rgb);
}
this.fetchline = function() {
var pt5 = this.plane[5].pt >>> 1;
var pt4 = this.plane[4].pt >>> 1;
var pt3 = this.plane[3].pt >>> 1;
var pt2 = this.plane[2].pt >>> 1;
var pt1 = this.plane[1].pt >>> 1;
var pt0 = this.plane[0].pt >>> 1;
if (this.state.altget) {
switch (this.state.planes) {
case 6: { this.plane[5].line[0] = AMIGA.mem.chip.data[pt5] >> 8; }
case 5: { this.plane[4].line[0] = AMIGA.mem.chip.data[pt4] >> 8; }
case 4: { this.plane[3].line[0] = AMIGA.mem.chip.data[pt3] >> 8; }
case 3: { this.plane[2].line[0] = AMIGA.mem.chip.data[pt2] >> 8; }
case 2: { this.plane[1].line[0] = AMIGA.mem.chip.data[pt1] >> 8; }
case 1: { this.plane[0].line[0] = AMIGA.mem.chip.data[pt0] >> 8; }
}
for (var i = 1; i < this.state.dwords + 1; i++) {
switch (this.state.planes) {
case 6: { this.plane[5].line[i] = ((AMIGA.mem.chip.data[pt5] & 0xff) << 8) | (AMIGA.mem.chip.data[++pt5] >> 8); }
case 5: { this.plane[4].line[i] = ((AMIGA.mem.chip.data[pt4] & 0xff) << 8) | (AMIGA.mem.chip.data[++pt4] >> 8); }
case 4: { this.plane[3].line[i] = ((AMIGA.mem.chip.data[pt3] & 0xff) << 8) | (AMIGA.mem.chip.data[++pt3] >> 8); }
case 3: { this.plane[2].line[i] = ((AMIGA.mem.chip.data[pt2] & 0xff) << 8) | (AMIGA.mem.chip.data[++pt2] >> 8); }
case 2: { this.plane[1].line[i] = ((AMIGA.mem.chip.data[pt1] & 0xff) << 8) | (AMIGA.mem.chip.data[++pt1] >> 8); }
case 1: { this.plane[0].line[i] = ((AMIGA.mem.chip.data[pt0] & 0xff) << 8) | (AMIGA.mem.chip.data[++pt0] >> 8); }
}
}
switch (this.state.planes) {
case 6: { this.plane[5].line[i] = 0; }
case 5: { this.plane[4].line[i] = 0; }
case 4: { this.plane[3].line[i] = 0; }
case 3: { this.plane[2].line[i] = 0; }
case 2: { this.plane[1].line[i] = 0; }
case 1: { this.plane[0].line[i] = 0; }
}
} else {
for (var i = 0; i < this.state.dwords; i++) {
switch (this.state.planes) {
case 6: { this.plane[5].line[i] = AMIGA.mem.chip.data[pt5++]; }
case 5: { this.plane[4].line[i] = AMIGA.mem.chip.data[pt4++]; }
case 4: { this.plane[3].line[i] = AMIGA.mem.chip.data[pt3++]; }
case 3: { this.plane[2].line[i] = AMIGA.mem.chip.data[pt2++]; }
case 2: { this.plane[1].line[i] = AMIGA.mem.chip.data[pt1++]; }
case 1: { this.plane[0].line[i] = AMIGA.mem.chip.data[pt0++]; }
}
}
}
switch (this.state.planes) {
case 6: this.plane[5].pt = pt5 << 1;
case 5: this.plane[4].pt = pt4 << 1;
case 4: this.plane[3].pt = pt3 << 1;
case 3: this.plane[2].pt = pt2 << 1;
case 2: this.plane[1].pt = pt1 << 1;
case 1: this.plane[0].pt = pt0 << 1;
}
}
this.scrollline = function(d1, d2) {
var d1n = 16 - d1;
var d2n = 16 - d2;
for (var i = this.state.dwords - 1; i > 0; i--) {
switch (this.state.planes) {
case 6: { if (d2) this.plane[5].line[i] = (this.plane[5].line[i] >> d2) | (this.plane[5].line[i - 1] << d2n); }
case 5: { if (d1) this.plane[4].line[i] = (this.plane[4].line[i] >> d1) | (this.plane[4].line[i - 1] << d1n); }
case 4: { if (d2) this.plane[3].line[i] = (this.plane[3].line[i] >> d2) | (this.plane[3].line[i - 1] << d2n); }
case 3: { if (d1) this.plane[2].line[i] = (this.plane[2].line[i] >> d1) | (this.plane[2].line[i - 1] << d1n); }
case 2: { if (d2) this.plane[1].line[i] = (this.plane[1].line[i] >> d2) | (this.plane[1].line[i - 1] << d2n); }
case 1: { if (d1) this.plane[0].line[i] = (this.plane[0].line[i] >> d1) | (this.plane[0].line[i - 1] << d1n); }
}
}
switch (this.state.planes) {
case 6: { if (d2) this.plane[5].line[i] = this.plane[5].line[i] >> d2; }
case 5: { if (d1) this.plane[4].line[i] = this.plane[4].line[i] >> d1; }
case 4: { if (d2) this.plane[3].line[i] = this.plane[3].line[i] >> d2; }
case 3: { if (d1) this.plane[2].line[i] = this.plane[2].line[i] >> d1; }
case 2: { if (d2) this.plane[1].line[i] = this.plane[1].line[i] >> d2; }
case 1: { if (d1) this.plane[0].line[i] = this.plane[0].line[i] >> d1; }
}
}
this.mod = function() {
switch (this.state.planes) {
case 6: this.plane[5].pt += this.bpl2mod;
case 5: this.plane[4].pt += this.bpl1mod;
case 4: this.plane[3].pt += this.bpl2mod;
case 3: this.plane[2].pt += this.bpl1mod;
case 2: this.plane[1].pt += this.bpl2mod;
case 1: this.plane[0].pt += this.bpl1mod;
}
}
this.hSync = function() {
if (!this.frame.skip) {
var x = this.state.hleft;
var y = AMIGA.events.vpos - ((this.state.vlenreal > 256) ? this.state.vstart : 0x2c);
if (this.state.ilace) y = y * 2 + 1 - AMIGA.events.lof;
if (x < 0) x = 0;
if (y < 0) y = 0; else if (y >= VIDEO_HEIGHT) y = VIDEO_HEIGHT - 1;
if (AMIGA.events.vpos >= this.state.vstart && AMIGA.events.vpos < this.state.vstop) {
if (this.state.planes > 0 && AMIGA.dmaen(DMAF_BPLEN)) {
var offs = this.state.ddiff ? (this.state.ddiff - 1) >> 1 : 0;
if (this.state.ddiff == 2) { this.state.altget = false; offs++ };
this.state.colorOnly = false;
if (this.sprites.nr_armed > 0) this.sprites.draw();
this.fetchline();
this.mod();
if (this.state.delay1 || this.state.delay2) {
var d1 = this.state.hires ? ((this.state.delay1 & 7) << 1) : this.state.delay1;
var d2 = this.state.hires ? ((this.state.delay2 & 7) << 1) : this.state.delay2;
this.scrollline(d1, d2);
}
if (this.state.std) this.drawline_std(x, y, offs);
else if (this.state.ehb) this.drawline_ehb(x, y, offs);
else if (this.state.dpf) this.drawline_dpf(x, y, offs);
else if (this.state.ham) this.drawline_ham(x, y, offs);
else AMIGA.video.drawline(y, this.color_std[0]);
this.drawline_border(y);
if (this.state.vlenrealset == 0) {
this.state.vlenrealset++;
this.state.vlenrealtmp = AMIGA.events.vpos;
}
} else {
AMIGA.video.drawline(y, this.color_std[0]);
}
} else {
if (this.state.vlenrealset == 1) {
this.state.vlenrealset++;
this.state.vlenreal = AMIGA.events.vpos - this.state.vlenrealtmp;
//this.lamps();
}
AMIGA.video.drawline(y, this.color_std[0]);
}
}
//AMIGA.events.eventtab[EV_RENDER].oldcycles = AMIGA.events.currcycle;
//AMIGA.events.eventtab[EV_RENDER].evtime = AMIGA.events.currcycle + AMIGA.events.maxhpos * CYCLE_UNIT;
}
this.vSync = function() {
if (!this.frame.skip && (!this.state.ilace || (this.state.ilace && AMIGA.events.lof == 0))) {
AMIGA.video.draw(this.color_std[0], this.state.hScale, this.state.vScale, this.state.colorOnly);
//if (!this.state.colorOnly) AMIGA.video.clear_pixels();
}
if (this.state.ilace) { if (AMIGA.events.lof == 0) this.frame.count++; } else this.frame.count++; if (this.frame.count == AMIGA.events.hz) this.frame.count = 0;
/*this.state.hires = false;
this.state.ilace = false;
this.state.ham = false;
this.state.dpf = false;
this.state.ehb = false;
this.state.std = false;
this.state.altget = false;
this.state.hScale = true;
this.state.vScale = true;*/
this.state.colorOnly = true;
this.state.vlenrealset = 0;
}
this.COLORxx = function (v, num) {
//BUG.info('Playfield.COLOR%02d() $%04x', num, v);
var r = (v >> 8) & 15;
var g = (v >> 4) & 15;
var b = v & 15;
this.color_std[num] = ((r << 1) << 11) | ((g << 2) << 5) | (b << 1);
this.color_ehb[num] = (r << 11) | ((g << 1) << 5) | b;
}
this.BPLxPTx = function (v, num, hi) {
if (hi) {
this.plane[num].pt = ((v << 16) | (this.plane[num].pt & 0xffff)) >>> 0;
} else {
/*if (AMIGA.copper.access && this.is_bitplane_dma(AMIGA.events.hpos() + 1) == num + 1) {
console.log('BPLxPTx() SKIP! ', num, AMIGA.events.hpos());
return;
}*/
this.plane[num].pt = ((this.plane[num].pt & 0xffff0000) | v) >>> 0;
}
}
this.BPLxDAT = function (v, num) {
//if (v) BUG.info('Custom.BPL%dDAT() $%04x', num, v);
this.plane[num].dat = v;
}
/*this.BPLCON0_getRes = function (v) {
if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_OCS)
v &= ~0x40;
return (v & 0x8000) ? 2 : ((v & 0x40) ? 3 : 1);
}*/
this.BPLCON0_getPlanes = function (v) {
if ((v & 0x0010) && (v & 0x7000))
return 0;
if (v & 0x0010)
return 8;
return (v >> 12) & 7;
}
this.BPLCON0 = function (v) {
//BUG.info('Custom.BPLCON0() $%04x', v);
//var hires_old = this.state.hires;
var ilace_old = this.state.ilace;
if (!(this.bplcon0 & 2)) {
AMIGA.events.vpos_previous = AMIGA.events.vpos;
AMIGA.events.hpos_previous = AMIGA.events.hpos();
}
this.bplcon0 = v;
this.state.planes = this.BPLCON0_getPlanes(v);
this.state.hires = (v & BPLF_HIRES) != 0;
this.state.ilace = (v & BPLF_LACE) != 0;
this.state.dpf = (v & BPLF_DBLPF) != 0;
this.state.ham = (v & BPLF_HOMOD) != 0;
this.state.ehb = (this.state.planes == 6 && !this.state.dpf && !this.state.ham);
this.state.std = (!this.state.ehb && !this.state.dpf && !this.state.ham);
this.state.hpixel = this.state.hlen << (this.state.hires ? 1 : 0);
this.state.hleft = (180 - Math.min(this.state.hlen >> 1, this.state.dlen)) << (this.state.hires ? 1 : 0);
this.state.dwords = this.state.dnum << (this.state.hires ? 1 : 0);
if (this.state.planes) {
this.state.hScale = !this.state.hires;
this.state.vScale = !this.state.ilace;
}
//if (this.state.hires != hires_old) BUG.info('Custom.BPLCON0() hires change %d, vpos %d, hpos %d', this.state.hires?1:0, AMIGA.events.vpos, AMIGA.events.hpos());
if (this.state.ilace != ilace_old) {
//BUG.info('Custom.BPLCON0() ilace change %d, vpos %d, hpos %d', this.state.ilace?1:0, AMIGA.events.vpos, AMIGA.events.hpos());
if (!this.state.ilace) AMIGA.video.clear_pixels();
AMIGA.audio.recalc_sample_evtime();
}
this.setup_fmodes(AMIGA.events.hpos());
//this.lamps();
}
this.BPLCON1 = function (v) {
this.bplcon1 = v;
this.state.delay1 = v & 0xf;
this.state.delay2 = (v >> 4) & 0xf;
//this.lamps();
}
this.BPLCON2 = function (v) {
this.bplcon2 = v;
this.state.pf2pri = (v & BPLF_PF2PRI) != 0;
this.state.pf1p = v & 7;
this.state.pf2p = (v >> 3) & 7;
this.sprites.setMask(this.state.pf1p, this.state.pf2p);
//this.lamps();
}
this.BPLCON3 = function (v) {
this.bplcon3 = v;
}
this.BPL1MOD = function (v) {
//if (v) BUG.info('Custom.BPL1MOD() $%04x', v);
this.bpl1mod = (v & 0x8000) ? (v - 0x10000) : v;
}
this.BPL2MOD = function (v) {
//if (v) BUG.info('Custom.BPL2MOD() $%04x', v);
this.bpl2mod = (v & 0x8000) ? (v - 0x10000) : v;
}
this.DIWSTRT = function (v) {
//BUG.info('Custom.DIWSTRT() $%04x', v);
this.diwstrt = v;
this.calcdiw();
}
this.DIWSTOP = function (v) {
//BUG.info('Custom.DIWSTOP() $%04x', v);
this.diwstop = v;
this.calcdiw();
}
this.DDFSTRT = function (v) {
//BUG.info('Custom.DDFSTRT() $%04x', v);
this.ddfstrt = v;
this.calcddf(0);
}
this.DDFSTOP = function (v) {
//BUG.info('Custom.DDFSTOP() $%04x', v);
this.ddfstop = v;
this.calcddf(1);
}
/* ECS
* 7-4 Lisa/Denise/ECS Denise Revision level (decrement to bump revision level, hex F represents 0th rev. level)
* 3 Maintain as a 1 for future generation
* 2 When low indicates AA feature set (LISA)
* 1 When low indicates ECS feature set (LISA or ECS DENISE)
* 0 Maintain as a 1 for future generation
*
* Denise ID: OCS = 0xFF, ECS = 0xFC, AGA = 0xF8
*/
this.DENISEID___ = function() {
var smb = 0xff;
var v = ((0xf - AMIGA.config.chipset.agnus_rev) << 4);
v |= 8;
v |= 4; /* low = AGA */
/* v |= 2; low = ECS */
//v |= 1;
BUG.info('Custom.DENISEID() $%04x', (smb << 8) | v);
return (smb << 8) | v;
}
this.DENISEID = function() {
//if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_AGA) return [0, 0x00F8];
if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS) return [0, 0xFFFC];
if (AMIGA.config.cpu.model == 68000 && (AMIGA.config.cpu.compatible || AMIGA.config.cpu.exact))
return [1, 0xFFFF];
return [0, 0xFFFF];
}
this.DIWHIGH = function (v) {
//if (!(AMIGA.config.chipset.type == CHIPSET_AGA))
v &= ~ (0x0008 | 0x0010 | 0x1000 | 0x0800);
v &= ~ (0x8000 | 0x4000 | 0x0080 | 0x0040);
//BUG.info('Custom.DIWHIGH() $%04x', v);
this.diwhigh = v;
this.calcdiw();
}
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
var bplcon0_res = 0;
var bplcon0_planes = 0;
var bplcon0_planes_limit = 0;
var real_bitplane_number = []; //[3][3][9];
var fmode = 0;
var fetchmode = 0;
var fetchunits = [ 8,8,8,0, 16,8,8,0, 32,16,8,0 ];
var fetchstarts = [ 3,2,1,0, 4,3,2,0, 5,4,3,0 ];
var fm_maxplanes = [ 3,2,1,0, 3,3,2,0, 3,3,3,0 ];
var fetchunit = 0;
var fetchunit_mask = 0;
var fetchstart_shift = 0;
var fetchstart = 0;
var fetchstart_mask = 0;
var cycle_diagram_table = []; //[3][3][9][32];
var cycle_diagram_free_cycles = []; //[3][3][9];
var cycle_diagram_total_cycles = []; //[3][3][9];
var cycle_sequences = [ [2,1,2,1,2,1,2,1], [4,2,3,1,4,2,3,1], [8,4,6,2,7,3,5,1] ];
var curr_diagram = [];
this.create_cycle_diagram_table = function () {
var fm, res, cycle, planes, rplanes, v;
var fetch_start, max_planes, freecycles;
var cycle_sequence;
var i, j, k, l;
for (i = 0; i < 3; i++) {
real_bitplane_number[i] = [];
cycle_diagram_free_cycles[i] = [];
cycle_diagram_total_cycles[i] = [];
for (j = 0; j < 3; j++) {
real_bitplane_number[i][j] = [];
cycle_diagram_free_cycles[i][j] = [];
cycle_diagram_total_cycles[i][j] = [];
for (k = 0; k < 9; k++) {
real_bitplane_number[i][j][k] = 0;
cycle_diagram_free_cycles[i][j][k] = 0;
cycle_diagram_total_cycles[i][j][k] = 0;
}
}
}
for (i = 0; i < 3; i++) {
cycle_diagram_table[i] = [];
for (j = 0; j < 3; j++) {
cycle_diagram_table[i][j] = [];
for (k = 0; k < 9; k++) {
cycle_diagram_table[i][j][k] = [];
for (l = 0; l < 32; l++)
cycle_diagram_table[i][j][k][l] = 0;
}
}
}
for (fm = 0; fm <= 2; fm++) {
for (res = 0; res <= 2; res++) {
max_planes = fm_maxplanes[fm * 4 + res];
fetch_start = 1 << fetchstarts[fm * 4 + res];
cycle_sequence = cycle_sequences[max_planes - 1];
max_planes = 1 << max_planes;
for (planes = 0; planes <= 8; planes++) {
freecycles = 0;
for (cycle = 0; cycle < 32; cycle++)
cycle_diagram_table[fm][res][planes][cycle] = -1;
if (planes <= max_planes) {
for (cycle = 0; cycle < fetch_start; cycle++) {
if (cycle < max_planes && planes >= cycle_sequence[cycle & 7]) {
v = cycle_sequence[cycle & 7];
} else {
v = 0;
freecycles++;
}
cycle_diagram_table[fm][res][planes][cycle] = v;
}
}
cycle_diagram_free_cycles[fm][res][planes] = freecycles;
cycle_diagram_total_cycles[fm][res][planes] = fetch_start;
rplanes = planes;
if (rplanes > max_planes)
rplanes = 0;
if (rplanes == 7 && fm == 0 && res == 0) //&& !(currprefs.chipset_mask & CSMASK_AGA))
rplanes = 4;
real_bitplane_number[fm][res][planes] = rplanes;
}
}
}
}
//var estimated_last_fetch_cycle = 0;
//var cycle_diagram_shift = 0;
/*this.estimate_last_fetch_cycle = function (hpos) {
var fetchunit = fetchunits[fetchmode * 4 + bplcon0_res];
if (plf_state < plf_passed_stop) {
var stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop;
var fetch_cycle_at_stop = fetch_cycle + (stop - hpos);
var starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1);
estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
} else {
var starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1);
if (plf_state == plf_passed_stop2)
starting_last_block_at -= fetchunit;
estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
}
}*/
const RES_LORES = 0;
const RES_HIRES = 1;
const RES_SUPERHIRES = 2;
this.GET_RES_DENISE = function (con0) {
//if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE))
con0 &= ~0x40; // SUPERHIRES
return (con0 & 0x8000) ? RES_HIRES : (con0 & 0x40) ? RES_SUPERHIRES : RES_LORES;
}
this.GET_RES_AGNUS = function (con0) {
//if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
con0 &= ~0x40; // SUPERHIRES
return (con0 & 0x8000) ? RES_HIRES : (con0 & 0x40) ? RES_SUPERHIRES : RES_LORES;
}
this.GET_PLANES = function (con0) {
if ((con0 & 0x0010) && (con0 & 0x7000))
return 0; // >8 planes = 0 planes
if (con0 & 0x0010)
return 8; // AGA 8-planes bit
return (con0 >> 12) & 7; // normal planes bits
}
this.GET_PLANES_LIMIT = function (con0) {
var res = this.GET_RES_AGNUS (con0);
var planes = this.GET_PLANES (con0);
return real_bitplane_number[fetchmode][res][planes];
}
this.setup_fmodes = function (hpos) {
switch (fmode & 3) {
case 0:
fetchmode = 0;
break;
case 1:
case 2:
fetchmode = 1;
break;
case 3:
fetchmode = 2;
break;
}
//badmode = GET_RES_AGNUS (bplcon0) != GET_RES_DENISE (this.bplcon0);
bplcon0_res = this.GET_RES_AGNUS (this.bplcon0);
bplcon0_planes = this.GET_PLANES (this.bplcon0);
bplcon0_planes_limit = this.GET_PLANES_LIMIT (this.bplcon0);
//console.log(bplcon0_res, bplcon0_planes, bplcon0_planes_limit);
fetchunit = fetchunits[fetchmode * 4 + bplcon0_res];
fetchunit_mask = fetchunit - 1;
fetchstart_shift = fetchstarts[fetchmode * 4 + bplcon0_res];
fetchstart = 1 << fetchstart_shift;
fetchstart_mask = fetchstart - 1;
/*fm_maxplane_shift = fm_maxplanes[fetchmode * 4 + bplcon0_res];
fm_maxplane = 1 << fm_maxplane_shift;
fetch_modulo_cycle = fetchunit - fetchstart;
if (is_bitplane_dma (hpos - 1)) cycle_line[hpos - 1] = 1;*/
curr_diagram = cycle_diagram_table[fetchmode][bplcon0_res][bplcon0_planes_limit];
//console.log(curr_diagram);
//console.log(fetchstart_mask);
//estimate_last_fetch_cycle (hpos);
//if (bpldmasetuphpos >= 0 && debug_dma) record_dma_event (DMA_EVENT_BPLFETCHUPDATE, hpos, vpos);
/*bpldmasetuphpos = -1;
bpldmasetupphase = 0;
ddf_change = vpos;*/
//console.log('setup_fmodes()', fetchstart, fetchstart_shift, fetchstart_mask, curr_diagram);
}
this.is_bitplane_dma = function (hpos) {
if (hpos < this.state.dstart*2) //plfstrt)
return 0;
//if ((plf_state == plf_end && hpos >= thisline_decision.plfright) || hpos >= estimated_last_fetch_cycle)
if (hpos >= this.state.dstop*2) //|| hpos >= estimated_last_fetch_cycle)
return 0;
//console.log(hpos - this.state.hstart);
//return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask];
return curr_diagram[hpos & fetchstart_mask];
}
this.get_data = function() {
return [
this.state.hstart,
this.state.hstop - (16 << fetchmode),
cycle_diagram_total_cycles[fetchmode][this.GET_RES_AGNUS(this.bplcon0)][this.GET_PLANES_LIMIT(this.bplcon0)],
cycle_diagram_free_cycles[fetchmode][this.GET_RES_AGNUS(this.bplcon0)][this.GET_PLANES_LIMIT(this.bplcon0)]
]
}
}