ScriptedAmigaEmulator/sae/cia.js
Rupert Hausberger eda41a625b update 0.8.0
2013-01-16 19:00:33 +01:00

1320 lines
31 KiB
JavaScript

/**************************************************************************
* SAE - Scripted Amiga Emulator
*
* https://github.com/naTmeg/ScriptedAmigaEmulator
*
* ©2012 Rupert Hausberger
* Commercial use is prohibited.
*
***************************************************************************
* Notes: Ported from WinUAE 2.5.0
*
**************************************************************************/
const CIAA_DEBUG_R = 0;
const CIAA_DEBUG_W = 0;
const CIAB_DEBUG_R = 0;
const CIAB_DEBUG_W = 0;
const DONGLE_DEBUG = 0;
const KB_DEBUG = 0;
const CLOCK_DEBUG = 0;
const TOD_HACK = 1;
/* e-clock is 10 CPU cycles, 4 cycles high, 6 low data transfer happens during 4 high cycles */
const ECLOCK_DATA_CYCLE = 4;
const ECLOCK_WAIT_CYCLE = 6;
const DIV10 = ((ECLOCK_DATA_CYCLE + ECLOCK_WAIT_CYCLE) * CYCLE_UNIT / 2); /* Yes, a bad identifier. */
const CIASTARTCYCLESHI = 3;
const CIASTARTCYCLESCRA = 2;
//console.log('DIV10', CYCLE_UNIT, DIV10);
function CIA() {
var ciaaicr = 0, ciaaimask = 0, ciabicr = 0, ciabimask = 0;
var ciaacra = 0, ciaacrb = 0, ciabcra = 0, ciabcrb = 0;
var ciaastarta = 0, ciaastartb = 0, ciabstarta = 0, ciabstartb = 0;
var ciaaicr_reg = 0, ciabicr_reg = 0;
var ciaata = 0, ciaatb = 0, ciabta = 0, ciabtb = 0;
var ciaata_passed = 0, ciaatb_passed = 0, ciabta_passed = 0, ciabtb_passed = 0;
var ciaatod = 0, ciabtod = 0, ciaatol = 0, ciabtol = 0, ciaaalarm = 0, ciabalarm = 0;
var ciaatlatch = 0, ciabtlatch = 0;
var oldled = false;//, oldovl = false, oldcd32mute = false;
var led = false;
var led_old_brightness = 0;
var led_cycles_on = 0, led_cycles_off = 0, led_cycle = 0;
var ciaala = 0, ciaalb = 0, ciabla = 0, ciablb = 0;
var ciaatodon = 0, ciabtodon = 0;
var ciaapra = 0, ciaaprb = 0, ciaadra = 0, ciaadrb = 0, ciaasdr = 0, ciaasdr_cnt = 0;
var ciabpra = 0, ciabprb = 0, ciabdra = 0, ciabdrb = 0, ciabsdr = 0, ciabsdr_cnt = 0;
var div10 = 0;
//var kbstate = 0, kblostsynccnt = 0, kbcode = 0;
var serbits = 0;
var warned = 10;
//var rtc_delayed_write = 0;
/*function setclr (unsigned int *p, unsigned int val) {
if (val & 0x80) {
*p |= val & 0x7F;
} else {
*p &= ~val;
}
}*/
function setclra(val) {
if (val & 0x80) {
ciaaimask |= val & 0x7F;
} else {
ciaaimask &= ~val;
}
}
function setclrb(val) {
if (val & 0x80) {
ciabimask |= val & 0x7F;
} else {
ciabimask &= ~val;
}
}
function RethinkICRA() {
if (ciaaicr) {
if (ciaaimask & ciaaicr) {
ciaaicr |= 0x80;
AMIGA.INTREQ_0(0x8000 | 0x0008);
}
ciaaicr_reg |= ciaaicr;
}
}
function RethinkICRB() {
if (ciabicr) {
if (ciabimask & ciabicr) {
ciabicr |= 0x80;
AMIGA.INTREQ_0(0x8000 | 0x2000);
}
ciabicr_reg |= ciabicr;
}
}
this.SetICRA = function(icr, sdr) {
ciaaicr |= icr;
ciaasdr = sdr;
RethinkICRA();
}
this.SetICRB = function(icr, sdr) {
ciabicr |= icr;
if (sdr !== null)
ciabsdr = sdr;
RethinkICRB();
}
this.rethink = function() {
RethinkICRA();
RethinkICRB();
}
/* Figure out how many CIA timer cycles have passed for each timer since the last call of CIA_calctimers. */
function compute_passed_time() {
var ccount = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles + div10);
var ciaclocks = Math.floor(ccount / DIV10);
ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0;
/* CIA A timers */
if ((ciaacra & 0x21) == 0x01) {
var cc = ciaclocks;
if (cc > ciaastarta)
cc -= ciaastarta;
else
cc = 0;
//assert((ciaata + 1) >= cc);
ciaata_passed = cc;
}
if ((ciaacrb & 0x61) == 0x01) {
var cc = ciaclocks;
if (cc > ciaastartb)
cc -= ciaastartb;
else
cc = 0;
//assert((ciaatb + 1) >= cc);
ciaatb_passed = cc;
}
/* CIA B timers */
if ((ciabcra & 0x21) == 0x01) {
var cc = ciaclocks;
if (cc > ciabstarta)
cc -= ciabstarta;
else
cc = 0;
//assert((ciabta + 1) >= cc);
ciabta_passed = cc;
}
if ((ciabcrb & 0x61) == 0x01) {
var cc = ciaclocks;
if (cc > ciabstartb)
cc -= ciabstartb;
else
cc = 0;
//assert((ciabtb + 1) >= cc);
ciabtb_passed = cc;
}
}
/* Called to advance all CIA timers to the current time. This expects that
one of the timer values will be modified, and CIA_calctimers will be called
in the same cycle. */
function CIA_update_check() {
var ccount = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles + div10);
var ciaclocks = Math.floor(ccount / DIV10);
var aovfla = 0, aovflb = 0, asp = 0, bovfla = 0, bovflb = 0, bsp = 0;
var icr = 0;
div10 = ccount % DIV10;
/* CIA A timers */
if ((ciaacra & 0x21) == 0x01) {
var check = true;
var cc = ciaclocks;
if (ciaastarta > 0) {
if (cc > ciaastarta) {
cc -= ciaastarta;
ciaastarta = 0;
} else {
ciaastarta -= cc;
check = false;
}
}
if (check) {
//assert((ciaata + 1) >= cc);
if ((ciaata + 1) == cc) {
if ((ciaacra & 0x48) == 0x40 && ciaasdr_cnt > 0 && --ciaasdr_cnt == 0)
asp = 1;
aovfla = 1;
if ((ciaacrb & 0x61) == 0x41 || (ciaacrb & 0x61) == 0x61) {
if (ciaatb-- == 0)
aovflb = 1;
}
}
ciaata -= cc;
}
}
if ((ciaacrb & 0x61) == 0x01) {
var check = true;
var cc = ciaclocks;
if (ciaastartb > 0) {
if (cc > ciaastartb) {
cc -= ciaastartb;
ciaastartb = 0;
} else {
ciaastartb -= cc;
check = false;
}
}
if (check) {
//assert((ciaatb + 1) >= cc);
if ((ciaatb + 1) == cc)
aovflb = 1;
ciaatb -= cc;
}
}
/* CIA B timers */
if ((ciabcra & 0x21) == 0x01) {
var check = true;
var cc = ciaclocks;
if (ciabstarta > 0) {
if (cc > ciabstarta) {
cc -= ciabstarta;
ciabstarta = 0;
} else {
ciabstarta -= cc;
check = false;
}
}
if (check) {
//assert((ciabta + 1) >= cc);
if ((ciabta + 1) == cc) {
if ((ciabcra & 0x48) == 0x40 && ciabsdr_cnt > 0 && --ciabsdr_cnt == 0)
bsp = 1;
bovfla = 1;
if ((ciabcrb & 0x61) == 0x41 || (ciabcrb & 0x61) == 0x61) {
if (ciabtb-- == 0)
bovflb = 1;
}
}
ciabta -= cc;
}
}
if ((ciabcrb & 0x61) == 0x01) {
var check = true;
var cc = ciaclocks;
if (ciabstartb > 0) {
if (cc > ciabstartb) {
cc -= ciabstartb;
ciabstartb = 0;
} else {
ciabstartb -= cc;
check = false;
}
}
if (check) {
//assert((ciabtb + 1) >= cc);
if ((ciabtb + 1) == cc)
bovflb = 1;
ciabtb -= cc;
}
}
if (aovfla) {
ciaaicr |= 1; icr = 1;
ciaata = ciaala;
if (ciaacra & 0x8) {
ciaacra &= ~1;
}
}
if (aovflb) {
ciaaicr |= 2; icr = 1;
ciaatb = ciaalb;
if (ciaacrb & 0x8) {
ciaacrb &= ~1;
}
}
if (asp) {
ciaaicr |= 8; icr = 1;
}
if (bovfla) {
ciabicr |= 1; icr |= 2;
ciabta = ciabla;
if (ciabcra & 0x8) {
ciabcra &= ~1;
}
}
if (bovflb) {
ciabicr |= 2; icr |= 2;
ciabtb = ciablb;
if (ciabcrb & 0x8) {
ciabcrb &= ~1;
}
}
if (bsp) {
ciabicr |= 8; icr |= 2;
}
return icr;
}
function CIA_update() {
var icr = CIA_update_check ();
if (icr & 1)
RethinkICRA();
if (icr & 2)
RethinkICRB();
}
/* Call this only after CIA_update has been called in the same cycle. */
function CIA_calctimers() {
var ciaatimea = -1, ciaatimeb = -1, ciabtimea = -1, ciabtimeb = -1;
var div10diff = DIV10 - div10;
if ((ciaacra & 0x21) == 0x01) ciaatimea = div10diff + DIV10 * (ciaata + ciaastarta);
if ((ciaacrb & 0x61) == 0x01) ciaatimeb = div10diff + DIV10 * (ciaatb + ciaastartb);
if ((ciabcra & 0x21) == 0x01) ciabtimea = div10diff + DIV10 * (ciabta + ciabstarta);
if ((ciabcrb & 0x61) == 0x01) ciabtimeb = div10diff + DIV10 * (ciabtb + ciabstartb);
AMIGA.events.eventtab[EV_CIA].oldcycles = AMIGA.events.currcycle;
AMIGA.events.eventtab[EV_CIA].active = (ciaatimea != -1 || ciaatimeb != -1 || ciabtimea != -1 || ciabtimeb != -1);
if (AMIGA.events.eventtab[EV_CIA].active) {
var ciatime = CYCLE_MAX;
if (ciaatimea != -1) ciatime = ciaatimea;
if (ciaatimeb != -1 && ciaatimeb < ciatime) ciatime = ciaatimeb;
if (ciabtimea != -1 && ciabtimea < ciatime) ciatime = ciabtimea;
if (ciabtimeb != -1 && ciabtimeb < ciatime) ciatime = ciabtimeb;
AMIGA.events.eventtab[EV_CIA].evtime = ciatime + AMIGA.events.currcycle;
}
AMIGA.events.schedule();
}
this.handler = function() {
CIA_update();
CIA_calctimers();
}
/*this.diskindex = function() {
ciabicr |= 0x10;
RethinkICRB();
}
this.parallelack = function() {
ciaaicr |= 0x10;
RethinkICRA();
}*/
function checkalarm (tod, alarm, inc) {
if (tod == alarm)
return 1;
if (!inc)
return 0;
/* emulate buggy TODMED counter.
* it counts: .. 29 2A 2B 2C 2D 2E 2F 20 30 31 32 ..
* (2F->20->30 only takes couple of cycles but it will trigger alarm..
*/
if (tod & 0x000fff)
return 0;
if (((tod - 1) & 0xfff000) == alarm)
return 1;
return 0;
}
function ciab_checkalarm(inc) {
if (checkalarm(ciabtod, ciabalarm, inc)) {
ciabicr |= 4;
RethinkICRB();
}
}
function ciaa_checkalarm(inc) {
if (checkalarm(ciaatod, ciaaalarm, inc)) {
ciaaicr |= 4;
RethinkICRA();
}
}
function gettimeofday() {
return Math.floor(new Date().getTime());
}
//#ifdef TOD_HACK
var tod_hack_tv = 0, tod_hack_tod = 0, tod_hack_tod_last = 0;
var tod_hack_enabled = -1;
const TOD_HACK_TIME = 312 * 50 * 10;
function tod_hack_reset() {
//var tv;
//gettimeofday (&tv, NULL);
//tod_hack_tv = (uae_u64)tv.tv_sec * 1000000 + tv.tv_usec;
tod_hack_tv = gettimeofday();
tod_hack_tod = ciaatod;
tod_hack_tod_last = tod_hack_tod;
}
//#endif
/*var heartbeat_cnt = 0;
function cia_heartbeat() {
heartbeat_cnt = 10;
}*/
var oldrate = 0;
function do_tod_hack(dotod) {
//console.log('tod',tod_hack_enabled);
//var tv;
var t;
var rate;
var docount = 0;
if (tod_hack_enabled == 0)
return;
/*if (!heartbeat_cnt) {
if (tod_hack_enabled > 0)
tod_hack_enabled = -1;
return;
}*/
if (tod_hack_enabled < 0) {
tod_hack_enabled = TOD_HACK_TIME;
return;
}
if (tod_hack_enabled > 1) {
tod_hack_enabled--;
if (tod_hack_enabled == 1) {
BUG.info('TOD HACK enabled');
tod_hack_reset();
}
return;
}
if (AMIGA.config.cia.tod == 0)
rate = Math.floor(AMIGA.playfield.vblank_hz + 0.5);
else if (AMIGA.config.cia.tod == 1)
rate = 50;
else
rate = 60;
if (rate <= 0)
return;
if (rate != oldrate || ciaatod != tod_hack_tod_last) {
if (ciaatod != 0) BUG.info('TOD HACK reset %d,%d %d,%d', rate, oldrate, ciaatod, tod_hack_tod_last);
tod_hack_reset();
oldrate = rate;
docount = 1;
}
if (!dotod && AMIGA.config.cia.tod == 0)
return;
/*gettimeofday (&tv, NULL);
t = (uae_u64)tv.tv_sec * 1000000 + tv.tv_usec;
if (t - tod_hack_tv >= 1000000 / rate) {
tod_hack_tv += 1000000 / rate;
docount = 1;
}*/
t = gettimeofday();
if (t - tod_hack_tv >= Math.floor(1000 / rate)) {
tod_hack_tv += Math.floor(1000 / rate);
docount = 1;
}
if (docount) {
ciaatod++;
ciaatod &= 0x00ffffff;
tod_hack_tod_last = ciaatod;
ciaa_checkalarm(0);
}
}
//this.hsync_prehandler = function() {}
this.hsync_posthandler = function(dotod) {
if (ciabtodon && dotod) {
ciabtod++;
ciabtod &= 0xFFFFFF;
ciab_checkalarm(1);
}
if (AMIGA.config.cia.tod_hack && ciaatodon)
do_tod_hack(dotod);
/*if (resetwarning_phase) {
resetwarning_check ();
while (keys_available ())
get_next_key ();
} else if ((keys_available () || kbstate < 3) && !kblostsynccnt && (hsync_counter & 15) == 0) {
switch (kbstate) {
case 0:
kbcode = 0;
kbstate++;
break;
case 1:
setcode(AK_INIT_POWERUP);
kbstate++;
break;
case 2:
setcode(AK_TERM_POWERUP);
kbstate++;
break;
case 3:
kbcode = ~get_next_key();
break;
}
keyreq();
}*/
AMIGA.input.keyboard.hsync();
}
function calc_led(old_led) {
var c = AMIGA.events.currcycle;
var t = Math.floor((c - led_cycle) * CYCLE_UNIT_INV);
if (old_led)
led_cycles_on += t;
else
led_cycles_off += t;
led_cycle = c;
}
var powerled_brightness = 255;
var powerled = true;
function led_vsync() {
var v;
calc_led(led);
if (led_cycles_on && !led_cycles_off)
v = 255;
else if (led_cycles_off && !led_cycles_on)
v = 0;
else if (led_cycles_off)
v = Math.floor(led_cycles_on * 255 / (led_cycles_on + led_cycles_off));
else
v = 255;
if (v < 0) v = 0;
if (v > 255) v = 255;
/*gui_data.powerled_brightness = v;
if (led_old_brightness != gui_data.powerled_brightness) {
gui_data.powerled = gui_data.powerled_brightness > 127;
gui_led (LED_POWER, gui_data.powerled);
led_filter_audio ();
}
led_old_brightness = gui_data.powerled_brightness;*/
powerled_brightness = v;
if (led_old_brightness != powerled_brightness) {
powerled = powerled_brightness > 127;
AMIGA.config.hooks.power_led(powerled);
AMIGA.audio.filter.led_filter_on = powerled;
}
led_old_brightness = powerled_brightness;
led_cycle = AMIGA.events.currcycle;
led_cycles_on = 0;
led_cycles_off = 0;
}
this.vsync_prehandler = function() {
/*if (rtc_delayed_write < 0) {
rtc_delayed_write = 50;
} else if (rtc_delayed_write > 0) {
rtc_delayed_write--;
if (rtc_delayed_write == 0)
write_battclock ();
}*/
led_vsync();
this.handler();
/*if (kblostsynccnt > 0) {
kblostsynccnt -= maxvpos;
if (kblostsynccnt <= 0) {
kblostsynccnt = 0;
keyreq ();
write_log (_T('lostsync\n'));
}
}*/
AMIGA.input.keyboard.vsync();
}
this.vsync_posthandler = function(dotod) {
//if (heartbeat_cnt > 0) heartbeat_cnt--;
if (TOD_HACK) {
if (AMIGA.config.cia.tod_hack && tod_hack_enabled == 1)
return;
}
if (ciaatodon && dotod) {
ciaatod++;
ciaatod &= 0xFFFFFF;
ciaa_checkalarm (1);
}
/*if (vpos == 0) {
write_log ('%d', vsync_counter);
this.dump();
}*/
}
function bfe001_change() {
var v = ciaapra;
var led2;
v |= ~ciaadra; /* output is high when pin's direction is input */
led2 = (v & 2) ? 0 : 1;
if (led2 != led) {
calc_led(led);
led = led2;
led_old_brightness = -1;
}
/*if (currprefs.cs_ciaoverlay && (v & 1) != oldovl) {
oldovl = v & 1;
if (!oldovl) {
map_overlay (1);
} else {
//activate_debugger ();
map_overlay (0);
}
}
if (currprefs.cs_cd32cd && (v & 1) != oldcd32mute) {
oldcd32mute = v & 1;
akiko_mute (oldcd32mute ? 0 : 1);
}*/
}
function handle_joystick_buttons(pra, dra) {
var tmp = 0;
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
if (!AMIGA.input.mouse.button[0]) tmp |= 0x40;
if (dra & 0x40) tmp = (tmp & ~0x40) | (pra & 0x40);
} else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) {
if (!AMIGA.input.joystick[0].button[0]) tmp |= 0x40;
if (dra & 0x40) tmp = (tmp & ~0x40) | (pra & 0x40);
} else tmp |= 0x40;
if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) {
if (!AMIGA.input.joystick[1].button[0]) tmp |= 0x80;
if (dra & 0x80) tmp = (tmp & ~0x80) | (pra & 0x80);
} else tmp |= 0x80;
return tmp;
}
function handle_parport_joystick (port, pra, dra) {
var v;
switch (port) {
case 0:
v = (pra & dra) | (dra ^ 0xff);
return v;
case 1:
v = ((pra & dra) | (dra ^ 0xff)) & 0x7;
return v;
default:
return 0;
}
}
function ReadCIAA(addr) {
var tmp;
var reg = addr & 15;
compute_passed_time();
//if (CIAA_DEBUG_R) write_log (_T('R_CIAA: bfe%x01 %08X\n'), reg, M68K_GETPC);
switch (reg) {
case 0:
tmp = AMIGA.disk.status() & 0x3c;
tmp |= handle_joystick_buttons(ciaapra, ciaadra);
tmp |= (ciaapra | (ciaadra ^ 3)) & 0x03;
//tmp = dongle_cia_read (0, reg, tmp);
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE001 R %02X %s\n'), tmp, debuginfo(0));
return tmp;
case 1:
/*#ifdef PARALLEL_PORT
if (isprinter () > 0) {
tmp = ciaaprb;
} else if (isprinter () < 0) {
uae_u8 v;
parallel_direct_read_data (&v);
tmp = v;
} else if (currprefs.win32_samplersoundcard >= 0) {
tmp = sampler_getsample ((ciabpra & 4) ? 1 : 0);
} else
#endif*/
{
tmp = handle_parport_joystick(0, ciaaprb, ciaadrb);
//tmp = dongle_cia_read (1, reg, tmp);
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE101 R %02X %s\n'), tmp, debuginfo(0));
}
if (ciaacrb & 2) {
var pb7 = 0;
if (ciaacrb & 4)
pb7 = ciaacrb & 1;
tmp &= ~0x80;
tmp |= pb7 ? 0x80 : 0;
}
if (ciaacra & 2) {
var pb6 = 0;
if (ciaacra & 4)
pb6 = ciaacra & 1;
tmp &= ~0x40;
tmp |= pb6 ? 0x40 : 0;
}
return tmp;
case 2:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE201 R %02X %s\n'), ciaadra, debuginfo(0));
return ciaadra;
case 3:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE301 R %02X %s\n'), ciaadrb, debuginfo(0));
return ciaadrb;
case 4:
return (ciaata - ciaata_passed) & 0xff;
case 5:
return ((ciaata - ciaata_passed) >> 8) & 0xff;
case 6:
return (ciaatb - ciaatb_passed) & 0xff;
case 7:
return ((ciaatb - ciaatb_passed) >> 8) & 0xff;
case 8:
if (ciaatlatch) {
ciaatlatch = 0;
return ciaatol & 0xff;
} else
return ciaatod & 0xff;
case 9:
if (ciaatlatch)
return (ciaatol >> 8) & 0xff;
else
return (ciaatod >> 8) & 0xff;
case 10:
if (!ciaatlatch) {
if (!(ciaacrb & 0x80))
ciaatlatch = 1;
ciaatol = ciaatod;
}
return (ciaatol >> 16) & 0xff;
case 12:
return ciaasdr;
case 13:
tmp = ciaaicr_reg;
ciaaicr &= ~ciaaicr_reg;
ciaaicr_reg = 0;
RethinkICRA();
return tmp;
case 14:
return ciaacra;
case 15:
return ciaacrb;
}
return 0;
}
function ReadCIAB(addr) {
var tmp;
var reg = addr & 15;
//if ((addr >= 8 && addr <= 10) || CIAB_DEBUG_R > 1) write_log (_T('R_CIAB: bfd%x00 %08X\n'), reg, M68K_GETPC);
compute_passed_time ();
switch (reg) {
case 0:
//if (currprefs.use_serial)
tmp = AMIGA.serial.readStatus(ciabdra);
/*#ifdef PARALLEL_PORT
if (isprinter () > 0) {
//tmp |= ciabpra & (0x04 | 0x02 | 0x01);
tmp &= ~3; // clear BUSY and PAPEROUT
tmp |= 4; // set SELECT
} else if (isprinter () < 0) {
uae_u8 v;
parallel_direct_read_status (&v);
tmp |= v & 7;
} else
#endif*/
{
tmp |= handle_parport_joystick(1, ciabpra, ciabdra);
//tmp = dongle_cia_read (1, reg, tmp);
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD000 R %02X %s\n'), tmp, debuginfo(0));
}
return tmp;
case 1:
if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD100 R %02X %s\n'), ciabprb, debuginfo(0));
tmp = ciabprb;
//tmp = dongle_cia_read(1, reg, tmp);
if (ciabcrb & 2) {
var pb7 = 0;
if (ciabcrb & 4)
pb7 = ciabcrb & 1;
tmp &= ~0x80;
tmp |= pb7 ? 0x80 : 00;
}
if (ciabcra & 2) {
var pb6 = 0;
if (ciabcra & 4)
pb6 = ciabcra & 1;
tmp &= ~0x40;
tmp |= pb6 ? 0x40 : 00;
}
return tmp;
case 2:
return ciabdra;
case 3:
return ciabdrb;
case 4:
return (ciabta - ciabta_passed) & 0xff;
case 5:
return ((ciabta - ciabta_passed) >> 8) & 0xff;
case 6:
return (ciabtb - ciabtb_passed) & 0xff;
case 7:
return ((ciabtb - ciabtb_passed) >> 8) & 0xff;
case 8:
if (ciabtlatch) {
ciabtlatch = 0;
return ciabtol & 0xff;
} else
return ciabtod & 0xff;
case 9:
if (ciabtlatch)
return (ciabtol >> 8) & 0xff;
else
return (ciabtod >> 8) & 0xff;
case 10:
if (!ciabtlatch) {
if (!(ciabcrb & 0x80))
ciabtlatch = 1;
ciabtol = ciabtod;
}
return (ciabtol >> 16) & 0xff;
case 12:
return ciabsdr;
case 13:
tmp = ciabicr_reg;
ciabicr &= ~ciabicr_reg;
ciabicr_reg = 0;
RethinkICRB();
return tmp;
case 14:
//write_log (_T('CIABCRA READ %d %x\n'), ciabcra, M68K_GETPC);
return ciabcra;
case 15:
return ciabcrb;
}
return 0;
}
function WriteCIAA(addr, val) {
var reg = addr & 15;
//if (CIAA_DEBUG_W) write_log (_T('W_CIAA: bfe%x01 %02X %08X\n'), reg, val, M68K_GETPC);
/*if (!currprefs.cs_ciaoverlay && oldovl) {
map_overlay (1);
oldovl = 0;
}*/
switch (reg) {
case 0:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE001 W %02X %s\n'), val, debuginfo(0));
ciaapra = (ciaapra & ~0xc3) | (val & 0xc3);
bfe001_change();
//handle_cd32_joystick_cia(ciaapra, ciaadra);
//dongle_cia_write (0, reg, val);
break;
case 1:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE101 W %02X %s\n'), val, debuginfo(0));
ciaaprb = val;
//dongle_cia_write (0, reg, val);
/*#ifdef PARALLEL_PORT
if (isprinter() > 0) {
doprinter (val);
this.parallelack();
} else if (isprinter() < 0) {
parallel_direct_write_data (val, ciaadrb);
this.parallelack();
}
#endif*/
break;
case 2:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE201 W %02X %s\n'), val, debuginfo(0));
ciaadra = val;
//dongle_cia_write (0, reg, val);
bfe001_change();
break;
case 3:
ciaadrb = val;
//dongle_cia_write (0, reg, val);
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE301 W %02X %s\n'), val, debuginfo(0));
break;
case 4:
CIA_update();
ciaala = (ciaala & 0xff00) | val;
CIA_calctimers();
break;
case 5:
CIA_update();
ciaala = (ciaala & 0xff) | (val << 8);
if ((ciaacra & 1) == 0)
ciaata = ciaala;
if (ciaacra & 8) {
ciaata = ciaala;
ciaacra |= 1;
ciaastarta = CIASTARTCYCLESHI;
}
CIA_calctimers();
break;
case 6:
CIA_update();
ciaalb = (ciaalb & 0xff00) | val;
CIA_calctimers();
break;
case 7:
CIA_update();
ciaalb = (ciaalb & 0xff) | (val << 8);
if ((ciaacrb & 1) == 0)
ciaatb = ciaalb;
if (ciaacrb & 8) {
ciaatb = ciaalb;
ciaacrb |= 1;
ciaastartb = CIASTARTCYCLESHI;
}
CIA_calctimers();
break;
case 8:
if (ciaacrb & 0x80) {
ciaaalarm = (ciaaalarm & ~0xff) | val;
} else {
ciaatod = (ciaatod & ~0xff) | val;
ciaatodon = 1;
ciaa_checkalarm(0);
}
break;
case 9:
if (ciaacrb & 0x80) {
ciaaalarm = (ciaaalarm & ~0xff00) | (val << 8);
} else {
ciaatod = (ciaatod & ~0xff00) | (val << 8);
}
break;
case 10:
if (ciaacrb & 0x80) {
ciaaalarm = (ciaaalarm & ~0xff0000) | (val << 16);
} else {
ciaatod = (ciaatod & ~0xff0000) | (val << 16);
ciaatodon = 0;
}
break;
case 12:
CIA_update();
ciaasdr = val;
if ((ciaacra & 0x41) == 0x41 && ciaasdr_cnt == 0)
ciaasdr_cnt = 8 * 2;
CIA_calctimers();
break;
case 13:
setclra(val);
break;
case 14:
CIA_update();
val &= 0x7f; /* bit 7 is unused */
if ((val & 1) && !(ciaacra & 1))
ciaastarta = CIASTARTCYCLESCRA;
if ((val & 0x40) == 0 && (ciaacra & 0x40) != 0) {
AMIGA.input.keyboard.lostsynccnt = 0;
//if (KB_DEBUG) BUG.info('KB_ACK %02x->%02x', ciaacra, val);
}
ciaacra = val;
if (ciaacra & 0x10) {
ciaacra &= ~0x10;
ciaata = ciaala;
}
CIA_calctimers();
break;
case 15:
CIA_update();
if ((val & 1) && !(ciaacrb & 1))
ciaastartb = CIASTARTCYCLESCRA;
ciaacrb = val;
if (ciaacrb & 0x10) {
ciaacrb &= ~0x10;
ciaatb = ciaalb;
}
CIA_calctimers();
break;
}
}
function WriteCIAB(addr, val) {
var reg = addr & 15;
//if ((addr >= 8 && addr <= 10) || CIAB_DEBUG_W > 1) write_log (_T('W_CIAB: bfd%x00 %02X %08X\n'), reg, val, M68K_GETPC);
switch (reg) {
case 0:
if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD000 W %02X %s\n'), val, debuginfo(0));
//dongle_cia_write (1, reg, val);
ciabpra = val;
//if (currprefs.use_serial)
AMIGA.serial.writeStatus(ciabpra, ciabdra);
/*#ifdef PARALLEL_PORT
if (isprinter () < 0)
parallel_direct_write_status (val, ciabdra);
#endif*/
break;
case 1:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD100 W %02X %s\n'), val, debuginfo(0));
//dongle_cia_write (1, reg, val);
ciabprb = val;
AMIGA.disk.select(val);
break;
case 2:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD200 W %02X %s\n'), val, debuginfo(0));
//dongle_cia_write (1, reg, val);
ciabdra = val;
//if (currprefs.use_serial)
AMIGA.serial.writeStatus(ciabpra, ciabdra);
break;
case 3:
//if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD300 W %02X %s\n'), val, debuginfo(0));
//dongle_cia_write (1, reg, val);
ciabdrb = val;
break;
case 4:
CIA_update();
ciabla = (ciabla & 0xff00) | val;
CIA_calctimers();
break;
case 5:
CIA_update();
ciabla = (ciabla & 0xff) | (val << 8);
if ((ciabcra & 1) == 0)
ciabta = ciabla;
if (ciabcra & 8) {
ciabta = ciabla;
ciabcra |= 1;
ciabstarta = CIASTARTCYCLESHI;
}
CIA_calctimers();
break;
case 6:
CIA_update();
ciablb = (ciablb & 0xff00) | val;
CIA_calctimers();
break;
case 7:
CIA_update();
ciablb = (ciablb & 0xff) | (val << 8);
if ((ciabcrb & 1) == 0)
ciabtb = ciablb;
if (ciabcrb & 8) {
ciabtb = ciablb;
ciabcrb |= 1;
ciabstartb = CIASTARTCYCLESHI;
}
CIA_calctimers();
break;
case 8:
if (ciabcrb & 0x80) {
ciabalarm = (ciabalarm & ~0xff) | val;
} else {
ciabtod = (ciabtod & ~0xff) | val;
ciabtodon = 1;
ciab_checkalarm (0);
}
break;
case 9:
if (ciabcrb & 0x80) {
ciabalarm = (ciabalarm & ~0xff00) | (val << 8);
} else {
ciabtod = (ciabtod & ~0xff00) | (val << 8);
}
break;
case 10:
if (ciabcrb & 0x80) {
ciabalarm = (ciabalarm & ~0xff0000) | (val << 16);
} else {
ciabtod = (ciabtod & ~0xff0000) | (val << 16);
ciabtodon = 0;
}
break;
case 12:
CIA_update();
ciabsdr = val;
if ((ciabcra & 0x40) == 0)
ciabsdr_cnt = 0;
if ((ciabcra & 0x41) == 0x41 && ciabsdr_cnt == 0)
ciabsdr_cnt = 8 * 2;
CIA_calctimers();
break;
case 13:
setclrb(val);
break;
case 14:
CIA_update();
val &= 0x7f; /* bit 7 is unused */
if ((val & 1) && !(ciabcra & 1))
ciabstarta = CIASTARTCYCLESCRA;
ciabcra = val;
if (ciabcra & 0x10) {
ciabcra &= ~0x10;
ciabta = ciabla;
}
CIA_calctimers();
break;
case 15:
CIA_update();
if ((val & 1) && !(ciabcrb & 1))
ciabstartb = CIASTARTCYCLESCRA;
ciabcrb = val;
if (ciabcrb & 0x10) {
ciabcrb &= ~0x10;
ciabtb = ciablb;
}
CIA_calctimers();
break;
}
}
this.setup = function() {}
this.reset = function() {
if (TOD_HACK) {
tod_hack_tv = 0;
tod_hack_tod = 0;
tod_hack_enabled = 0;
if (AMIGA.config.cia.tod_hack)
tod_hack_enabled = TOD_HACK_TIME;
}
//kblostsynccnt = 0;
//serbits = 0;
//oldcd32mute = 1;
oldled = true;
//resetwarning_phase = resetwarning_timer = 0;
//heartbeat_cnt = 0;
//oldovl = true;
//kbstate = 0;
ciaatlatch = ciabtlatch = 0;
ciaapra = 0; ciaadra = 0;
ciaatod = ciabtod = 0; ciaatodon = ciabtodon = 0;
ciaaicr = ciabicr = ciaaimask = ciabimask = 0;
ciaacra = ciaacrb = ciabcra = ciabcrb = 0x4; /* outmode = toggle; */
ciaala = ciaalb = ciabla = ciablb = ciaata = ciaatb = ciabta = ciabtb = 0xFFFF;
ciaaalarm = ciabalarm = 0;
ciabpra = 0x8C; ciabdra = 0;
div10 = 0;
ciaasdr_cnt = 0; ciaasdr = 0;
ciabsdr_cnt = 0; ciabsdr = 0;
ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0;
CIA_calctimers();
AMIGA.disk.select_set(ciabprb);
//map_overlay (0);
//if (currprefs.use_serial) serial_dtr_off (); NI /* Drop DTR at reset */
}
this.dump = function() {
BUG.info('A: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)', ciaacra, ciaacrb, ciaaicr, ciaaimask, ciaata, ciaala, ciaatb, ciaalb);
BUG.info('TOD %06x (%06x) ALARM %06x %s%s CYC=%.1f', ciaatod, ciaatol, ciaaalarm, ciaatlatch ? 'L' : ' ', ciaatodon ? ' ' : 'S', AMIGA.events.currcycle * CYCLE_UNIT_INV);
BUG.info('B: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)', ciabcra, ciabcrb, ciabicr, ciabimask, ciabta, ciabla, ciabtb, ciablb);
BUG.info('TOD %06x (%06x) ALARM %06x %s%s CLK=%.1f', ciabtod, ciabtol, ciabalarm, ciabtlatch ? 'L' : ' ', ciabtodon ? ' ' : 'S', div10 * CYCLE_UNIT_INV);
}
// Gayle or Fat Gary does not enable CIA /CS lines if both CIAs are selected
// Old Gary based Amigas enable both CIAs in this situation
function issinglecia() {
return false; //currprefs.cs_ide || currprefs.cs_pcmcia || currprefs.cs_mbdmac;
}
function isgayle() {
return false; //currprefs.cs_ide || currprefs.cs_pcmcia;
}
function cia_wait_pre() {
if (!CUSTOM_SIMPLE) {
var div = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles) % DIV10;
var tmp = Math.floor(DIV10 * ECLOCK_DATA_CYCLE / 10);
var cycles;
if (div >= tmp)
cycles = DIV10 - div + tmp;
else if (div)
cycles = DIV10 + tmp - div;
else
cycles = tmp - div;
if (cycles)
AMIGA.events.cycle(cycles);
}
}
function cia_wait_post(value) {
AMIGA.events.cycle(6 * CYCLE_UNIT / 2);
}
function isgaylenocia(addr) {
// gayle CIA region is only 4096 bytes at 0xbfd000 and 0xbfe000
if (!isgayle())
return true;
var mask = addr & 0xf000;
return mask == 0xe000 || mask == 0xd000;
}
this.load8 = function(addr) {
var r = (addr & 0xf00) >> 8;
var v = 0xff;
if (!isgaylenocia(addr))
return v;
cia_wait_pre();
switch ((addr >> 12) & 3) {
case 0:
if (!issinglecia())
v = (addr & 1) ? ReadCIAA(r) : ReadCIAB(r);
break;
case 1:
v = (addr & 1) ? 0xff : ReadCIAB(r);
break;
case 2:
v = (addr & 1) ? ReadCIAA(r) : 0xff;
break;
case 3: {
//if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) v = (addr & 1) ? regs.irc : regs.irc >> 8;
if (warned > 0) {
BUG.info('cia_bget: unknown CIA address %x', addr);
warned--;
}
break;
}
}
cia_wait_post(v);
return v;
}
this.load16 = function(addr) {
var r = (addr & 0xf00) >> 8;
var v = 0xffff;
if (!isgaylenocia(addr))
return v;
cia_wait_pre();
switch ((addr >> 12) & 3) {
case 0:
if (!issinglecia())
v = (ReadCIAB(r) << 8) | ReadCIAA(r);
break;
case 1:
v = (ReadCIAB(r) << 8) | 0xff;
break;
case 2:
v = (0xff << 8) | ReadCIAA(r);
break;
case 3: {
//if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) v = regs.irc;
if (warned > 0) {
BUG.info('cia_wget: unknown CIA address %x', addr);
warned--;
}
break;
}
}
cia_wait_post(v);
return v;
}
this.load32 = function(addr) {
var v = this.load16(addr) << 16;
v |= this.load16(addr + 2);
return v >>> 0;
}
this.store8 = function (addr, value) {
var r = (addr & 0xf00) >> 8;
if (!isgaylenocia(addr))
return;
cia_wait_pre();
if (!issinglecia() || (addr & 0x3000) != 0) {
if ((addr & 0x2000) == 0)
WriteCIAB(r, value);
if ((addr & 0x1000) == 0)
WriteCIAA(r, value);
if (((addr & 0x3000) == 0x3000) && warned > 0) {
BUG.info('cia_bput: unknown CIA address %x %x', addr, value);
warned--;
}
}
cia_wait_post(value);
}
this.store16 = function (addr, value) {
var r = (addr & 0xf00) >> 8;
if (!isgaylenocia(addr))
return;
cia_wait_pre();
if (!issinglecia() || (addr & 0x3000) != 0) {
if ((addr & 0x2000) == 0)
WriteCIAB(r, value >> 8);
if ((addr & 0x1000) == 0)
WriteCIAA(r, value & 0xff);
if (((addr & 0x3000) == 0x3000) && warned > 0) {
BUG.info('cia_wput: unknown CIA address %x %x', addr, value);
warned--;
}
}
cia_wait_post(value);
}
this.store32 = function (addr, value) {
this.store16(addr, value >> 16);
this.store16(addr + 2, value & 0xffff);
}
}