ScriptedAmigaEmulator/sae/cia.js
Rupert Hausberger fbf36a4fa5 update 0.9.0
2016-07-15 19:44:16 +02:00

1725 lines
44 KiB
JavaScript

/*-------------------------------------------------------------------------
| SAE - Scripted Amiga Emulator
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of the GNU General Public License
| as published by the Free Software Foundation; either version 2
| of the License, or (at your option) any later version.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| Note: ported from WinUAE 3.2.x
-------------------------------------------------------------------------*/
/* global variables */
var SAEV_CIA_bank = null;
/*---------------------------------*/
function SAEO_CIA() {
const TOD_HACK = true;
/* 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) * SAEC_Events_CYCLE_UNIT >> 1; /* Yes, a bad identifier. */
const CIASTARTCYCLESHI = 3;
const CIASTARTCYCLESCRA = 2;
var ciaaicr = 0, ciaaimask = 0, ciabicr = 0, ciabimask = 0; //uint
var ciaacra = 0, ciaacrb = 0, ciabcra = 0, ciabcrb = 0; //uint
var ciaastarta = 0, ciaastartb = 0, ciabstarta = 0, ciabstartb = 0; //uint
/* Values of the CIA timers. */
var ciaata = 0, ciaatb = 0, ciabta = 0, ciabtb = 0; //ulong
/* Computed by compute_passed_time. */
var ciaata_passed = 0, ciaatb_passed = 0, ciabta_passed = 0, ciabtb_passed = 0; //ulong
var ciaatod = 0, ciabtod = 0, ciaatol = 0, ciabtol = 0, ciaaalarm = 0, ciabalarm = 0; //ulong
var ciaatlatch = 0, ciabtlatch = 0; //int
var oldovl = false, oldcd32mute = false; //bool
var led = false; //bool
var led_old_brightness = 0; //int
var led_cycles_on = 0, led_cycles_off = 0, led_cycle = 0; //ulong
var ciabpra = 0; //uint
var ciaala = 0, ciaalb = 0, ciabla = 0, ciablb = 0; //ulong
var ciaatodon = 0, ciabtodon = 0; //int
var ciaapra = 0, ciaaprb = 0, ciaadra = 0, ciaadrb = 0, ciaasdr = 0, ciaasdr_cnt = 0; //ulong
var ciabprb = 0, ciabdra = 0, ciabdrb = 0, ciabsdr = 0, ciabsdr_cnt = 0; //ulong
var div10 = 0; //int
var kbstate = 0, kblostsynccnt = 0; //int
var kbcode = 0; //u8
var serbits = 0; //u8
var warned = 10; //int
/*static void setclr (unsigned int *p, unsigned int val) {
if (val & 0x80) {
*p |= val & 0x7F;
} else {
*p &= ~val;
}
}*/
/* delay interrupt after current CIA register access if interrupt would have triggered mid access */
var cia_interrupt_disabled = 0; //int
var cia_interrupt_delay = 0; //int
/*-----------------------------------------------------------------------*/
function ICR(data) {
SAER.custom.INTREQ_0(SAEC_Custom_INTF_SETCLR | data);
}
function ICRA(data) {
ciaaicr |= 0x40;
ciaaicr |= 0x20;
ICR(0x0008);
}
function ICRB(data) {
ciabicr |= 0x40;
ciabicr |= 0x20;
if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V)
ICR(0x0008); /* Both CIAs in Velvet are connected to level 2 */
else
ICR(0x2000);
}
function RethinkICRA() {
if (ciaaicr & ciaaimask) {
if (!(ciaaicr & 0x80)) {
ciaaicr |= 0x80;
ICRA(0x0008);
}
}
}
function RethinkICRB() {
if (ciabicr & ciabimask) {
if (!(ciabicr & 0x80)) {
ciabicr |= 0x80;
ICRB(0);
}
}
}
this.rethink = function() { //rethink_cias()
if (ciaaicr & 0x40) ICRA(0);
if (ciabicr & 0x40) ICRB(0);
}
/* 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 = SAEV_Events_currcycle - SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles + div10;
var ciaclocks = ccount / DIV10 >>> 0;
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;
SAEF_assert((ciaata + 1) >= cc);
ciaata_passed = cc;
}
if ((ciaacrb & 0x61) == 0x01) {
var cc = ciaclocks;
if (cc > ciaastartb)
cc -= ciaastartb;
else
cc = 0;
SAEF_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;
SAEF_assert((ciabta + 1) >= cc);
ciabta_passed = cc;
}
if ((ciabcrb & 0x61) == 0x01) {
var cc = ciaclocks;
if (cc > ciabstartb)
cc -= ciabstartb;
else
cc = 0;
SAEF_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 = SAEV_Events_currcycle - SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles + div10;
var ciaclocks = ccount / DIV10 >>> 0;
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) {
SAEF_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) {
SAEF_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) {
SAEF_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) {
SAEF_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;
SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles = SAEV_Events_currcycle;
if ((ciaacra & 0x21) == 0x01) {
ciaatimea = div10diff + DIV10 * (ciaata + ciaastarta);
}
/*#if 0
if ((ciaacrb & 0x61) == 0x41) {
// Timer B will not get any pulses if Timer A is off.
if (ciaatimea >= 0) {
// If Timer A is in one-shot mode, and Timer B needs more than one pulse, it will not underflow.
if (ciaatb == 0 || (ciaacra & 0x8) == 0) {
// Otherwise, we can determine the time of the underflow.
// This may overflow, however. So just ignore this timer and use the fact that we"ll call CIA_handler for the A timer.
// ciaatimeb = ciaatimea + ciaala * DIV10 * ciaatb;
}
}
}
#endif*/
if ((ciaacrb & 0x61) == 0x01) {
ciaatimeb = div10diff + DIV10 * (ciaatb + ciaastartb);
}
if ((ciabcra & 0x21) == 0x01) {
ciabtimea = div10diff + DIV10 * (ciabta + ciabstarta);
}
/*#if 0
if ((ciabcrb & 0x61) == 0x41) {
// Timer B will not get any pulses if Timer A is off.
if (ciabtimea >= 0) {
// If Timer A is in one-shot mode, and Timer B needs more than one pulse, it will not underflow.
if (ciabtb == 0 || (ciabcra & 0x8) == 0) {
// Otherwise, we can determine the time of the underflow.
// ciabtimeb = ciabtimea + ciabla * DIV10 * ciabtb;
}
}
}
#endif*/
if ((ciabcrb & 0x61) == 0x01) {
ciabtimeb = div10diff + DIV10 * (ciabtb + ciabstartb);
}
SAER_Events_eventtab[SAEC_Events_EV_CIA].active = (ciaatimea != -1 || ciaatimeb != -1 || ciabtimea != -1 || ciabtimeb != -1);
if (SAER_Events_eventtab[SAEC_Events_EV_CIA].active) {
var ciatime = SAEC_Events_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;
SAER_Events_eventtab[SAEC_Events_EV_CIA].evtime = SAEV_Events_currcycle + ciatime;
}
SAER.events.schedule();
}
this.handler = function() { //CIA_handler()
CIA_update();
CIA_calctimers();
}
this.diskindex = function() { //cia_diskindex()
ciabicr |= 0x10;
RethinkICRB();
}
/*function cia_parallelack() {
ciaaicr |= 0x10;
RethinkICRA();
}*/
function checkalarm(tod, alarm, inc, ab) {
if (tod == alarm)
return true;
/*#if 0
if (!ab)
return false;
#endif*/
if (!SAEV_config.chipset.cia.todBug)
return false;
if (!inc)
return false;
/* 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 false;
return (((tod - 1) >>> 0) & 0xfff000) == alarm;
}
//function munge24(x) { return x & (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 ? 0x00ffffff : 0xffffffff); }
function ciab_checkalarm(inc, irq) {
// hack: do not trigger alarm interrupt if KS code and both
// tod and alarm == 0. This incorrectly triggers on non-cycle exact
// modes. Real hardware value written to ciabtod by KS is always
// at least 1 or larger due to bus cycle delays when reading old value.
//#if 1
//if ((munge24(SAER.cpu.m68k_getpc2()) & 0xFFF80000) != 0xF80000) {
if (!SAER.cpu.pc_in_rom()) {
if (ciabtod == 0 && ciabalarm == 0)
return false;
}
//#endif
if (checkalarm(ciabtod, ciabalarm, inc, 1)) {
if (irq) {
ciabicr |= 4;
RethinkICRB();
}
return true;
}
return false;
}
function ciaa_checkalarm(inc) {
if (checkalarm (ciaatod, ciaaalarm, inc, 0)) {
ciaaicr |= 4;
RethinkICRA();
}
}
//#ifdef TOD_HACK
var tod_hack_tv = 0, tod_hack_tod = 0, tod_hack_tod_last = 0; //u64
var tod_hack_enabled = 0; //all int
var tod_hack_delay = 0;
var tod_diff_cnt = 0;
const TOD_HACK_DELAY = 50;
const TOD_HACK_TIME = 312 * 50 * 10;
function tod_hack_reset() {
var tv = {};
SAEF_gettimeofday(tv, null);
tod_hack_tv = tv.tv_sec * 1000000 + tv.tv_usec;
tod_hack_tod = ciaatod;
tod_hack_tod_last = tod_hack_tod;
tod_diff_cnt = 0;
}
//#endif
var heartbeat_cnt = 0; //int
/*this.cia_heartbeat = function() {
heartbeat_cnt = 10;
}*/
var oldrate = 0;
function do_tod_hack(dotod) {
//struct timeval tv;
//static int oldrate;
var rate;
var docount = false;
if (tod_hack_enabled == 0)
return;
/*OWN
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) {
SAEF_log("cia.do_tod_hack() enabled");
tod_hack_reset();
}
return;
}
if (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync) {
rate = Math.floor(SAER.playfield.get_vblank_hz() + 0.5);
if (rate >= 59 && rate <= 61)
rate = 60;
if (rate >= 49 && rate <= 51)
rate = 50;
} else if (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_50Hz)
rate = 50;
else
rate = 60;
if (rate <= 0)
return;
if (rate != oldrate || (ciaatod & 0xfff) != (tod_hack_tod_last & 0xfff)) {
SAEF_log("cia.do_tod_hack() reset");
tod_hack_reset();
oldrate = rate;
docount = true;
}
if (!dotod && SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync)
return;
if (tod_hack_delay > 0) {
tod_hack_delay--;
if (tod_hack_delay > 0)
return;
tod_hack_delay = TOD_HACK_DELAY;
}
var tv = {};
SAEF_gettimeofday(tv, null);
var t = tv.tv_sec * 1000000 + tv.tv_usec;
var base = 1000000 / rate >>> 0;
if (t - tod_hack_tv >= base) {
tod_hack_tv += base;
tod_diff_cnt += 1000000 - base * rate;
tod_hack_tv += (tod_diff_cnt / rate >>> 0);
tod_diff_cnt %= rate;
docount = true;
}
if (docount) {
ciaatod++;
ciaatod &= 0x00ffffff;
tod_hack_tod_last = ciaatod;
ciaa_checkalarm(false);
}
}
/*var resetwarning_phase = 0, resetwarning_timer = 0; //int
function sendrw() {
setcode(AK_RESETWARNING);
ciaasdr = kbcode;
kblostsynccnt = 8 * maxvpos * 8; // 8 frames * 8 bits.
ciaaicr |= 8;
RethinkICRA ();
SAEF_log("cia.sendrw() sent reset warning code (phase=%d)", resetwarning_phase);
}
int resetwarning_do (int canreset) {
if (resetwarning_phase || SAR.m68k.halted > 0) {
if (canreset) {
resetwarning_phase = 0;
resetwarning_timer = 0;
}
return 0;
}
resetwarning_phase = 1;
resetwarning_timer = maxvpos_nom * 5;
SAEF_log("cia.resetwarning_do() triggered");
sendrw();
return 1;
}
static void resetwarning_check (void) {
if (resetwarning_timer > 0) {
resetwarning_timer--;
if (resetwarning_timer <= 0) {
SAEF_log("cia.resetwarning_check() forced reset. phase=%d", resetwarning_phase);
resetwarning_phase = -1;
kblostsynccnt = 0;
send_internalevent(INTERNALEVENT_KBRESET);
uae_reset(0, 1);
}
}
if (resetwarning_phase == 1) {
if (!kblostsynccnt) { // first AK_RESETWARNING handshake received
SAEF_log("cia.resetwarning_check() second phase...");
resetwarning_phase = 2;
resetwarning_timer = maxvpos_nom * 5;
sendrw();
}
} else if (resetwarning_phase == 2) {
if (ciaacra & 0x40) { // second AK_RESETWARNING handshake active
resetwarning_phase = 3;
SAEF_log("cia.resetwarning_check() reset warning SP = output");
/* System won"t reset until handshake signal becomes inactive or 10s has passed
resetwarning_timer = 10 * maxvpos_nom * SAER.playfield.get_vblank_hz();
}
} else if (resetwarning_phase == 3) {
if (!(ciaacra & 0x40)) { // second AK_RESETWARNING handshake disabled
SAEF_log("cia.resetwarning_check() reset warning end by software. reset.");
resetwarning_phase = -1;
kblostsynccnt = 0;
send_internalevent(INTERNALEVENT_KBRESET);
uae_reset (0, 1);
}
}
}*/
//this.hsync = function() {} //CIA_hsync_prehandler()
function setcode(keycode) {
kbcode = ~((keycode << 1) | (keycode >> 7)) & 0xff;
}
function keyreq() {
ciaasdr = kbcode;
kblostsynccnt = 8 * SAER.playfield.get_maxvpos() * 8; // 8 frames * 8 bits.
ciaaicr |= 8;
RethinkICRA();
}
/* All this complexity to lazy evaluate TOD increase.
* Only increase it cycle-exactly if it is visible to running program:
* causes interrupt or program is reading or writing TOD registers
*/
var ciab_tod_hoffset = 0; //int
var ciab_tod_event_state = 0; //int
// TOD increase has extra 14-16 E-clock delay
// Possibly TICK input pin has built-in debounce circuit
const TOD_INC_DELAY = 14 * (ECLOCK_DATA_CYCLE + ECLOCK_WAIT_CYCLE) >> 1;
function CIAB_tod_inc(irq) {
ciab_tod_event_state = 3; // done
if (!ciabtodon)
return;
ciabtod++;
ciabtod &= 0xFFFFFF;
ciab_checkalarm(true, irq);
}
function CIAB_tod_inc_event(v) {
if (ciab_tod_event_state != 2)
return;
CIAB_tod_inc(true);
}
// Someone reads or writes TOD registers, sync TOD increase
function CIAB_tod_check() {
if (ciab_tod_event_state != 1 || !ciabtodon)
return;
var hpos = SAER.events.current_hpos();
hpos -= ciab_tod_hoffset;
if (hpos >= 0 || SAEV_config.cpu.speed < 0) {
// Program should see the changed TOD
CIAB_tod_inc(true);
return;
}
// Not yet, add event to guarantee exact TOD inc position
ciab_tod_event_state = 2; // event active
SAER.events.event2_newevent_xx(-1, -hpos, 0, CIAB_tod_inc_event);
}
this.b_tod_handler = function(hoffset) { //CIAB_tod_handler()
if (!ciabtodon)
return;
ciab_tod_hoffset = hoffset + TOD_INC_DELAY;
ciab_tod_event_state = 1; // TOD inc needed
if (checkalarm((ciabtod + 1) & 0xffffff, ciabalarm, true, 1)) {
// causes interrupt on this line, add event
ciab_tod_event_state = 2; // event active
SAER.events.event2_newevent_xx (-1, ciab_tod_hoffset, 0, CIAB_tod_inc_event);
}
}
//const RAWKEY_RESETWARNING = 0x78;
const RAWKEY_INIT_POWER_UP = 0xFD;
const RAWKEY_TERM_POWER_UP = 0xFE;
function check_keyboard() {
if ((SAER.input.keyboard.keysAvail() || kbstate < 3) && !kblostsynccnt ) {
switch (kbstate) {
case 0:
kbcode = 0; //powerup resync
kbstate++;
break;
case 1:
setcode(RAWKEY_INIT_POWER_UP);
kbstate++;
break;
case 2:
setcode(RAWKEY_TERM_POWER_UP);
kbstate++;
break;
case 3:
kbcode = ~SAER.input.keyboard.nextKey() & 0xff;
break;
}
keyreq();
}
}
this.hsync_post = function(dotod) { //CIA_hsync_posthandler()
// Previous line was supposed to increase TOD but no one cared. Do it now.
if (ciab_tod_event_state == 1)
CIAB_tod_inc(false);
ciab_tod_event_state = 0;
if (SAEV_config.chipset.cia.todHack && ciaatodon)
do_tod_hack(dotod);
/*if (resetwarning_phase) {
resetwarning_check();
while (keys_available())
get_next_key();
} else*/ {
if ((SAEV_Events_hsync_counter & 15) == 0)
check_keyboard();
}
}
function calc_led(old_led) {
var c = SAEV_Events_currcycle;
var t = ((c - led_cycle) * SAEC_Events_CYCLE_UNIT_INV) >>> 0;
if (old_led)
led_cycles_on += t;
else
led_cycles_off += t;
led_cycle = c;
}
function led_vsync() {
calc_led(led);
if (led_cycles_on && !led_cycles_off)
var v = 255;
else if (led_cycles_off && !led_cycles_on)
var v = 0;
else if (led_cycles_off)
var v = ~~(led_cycles_on * 255 / (led_cycles_on + led_cycles_off));
else
var v = 255;
if (v < 0)
v = 0;
else if (v > 255)
v = 255;
led_cycles_on = 0;
led_cycles_off = 0;
SAER.gui.data.powerled_brightness = v;
if (led_old_brightness != SAER.gui.data.powerled_brightness) {
SAER.gui.data.powerled = SAER.gui.data.powerled_brightness > 127;
SAER.gui.led(SAEC_GUI_LED_POWER, SAER.gui.data.powerled, SAER.gui.data.powerled_brightness);
SAER.audio.led_filter_audio();
}
led_old_brightness = v;
led_cycle = SAEV_Events_currcycle;
}
this.vsync = function() { //CIA_vsync_prehandler()
if (heartbeat_cnt > 0)
heartbeat_cnt--;
if (SAEV_RTC_delayed_write < 0)
SAEV_RTC_delayed_write = 50;
else if (SAEV_RTC_delayed_write > 0) {
SAEV_RTC_delayed_write--;
if (SAEV_RTC_delayed_write == 0)
SAER.rtc.write();
}
led_vsync();
this.handler();
if (kblostsynccnt > 0) {
kblostsynccnt -= SAER.playfield.get_maxvpos();
if (kblostsynccnt <= 0) {
kblostsynccnt = 0;
keyreq();
}
}
}
function CIAA_tod_handler(v) {
ciaatod++;
ciaatod &= 0xFFFFFF;
ciaa_checkalarm(true);
}
this.a_tod_inc = function(cycles) { //CIAA_tod_inc()
//#ifdef TOD_HACK
if (SAEV_config.chipset.cia.todHack && tod_hack_enabled == 1)
return;
//#endif
if (!ciaatodon)
return;
SAER.events.event2_newevent_xx(-1, cycles + TOD_INC_DELAY, 0, CIAA_tod_handler);
}
function check_led() {
var v = ciaapra;
v |= ~ciaadra; /* output is high when pin"s direction is input */
var led2 = (v & 2) ? 0 : 1;
if (led2 != led) {
calc_led(led);
led = led2;
led_old_brightness = -1;
}
}
function bfe001_change() {
var v = ciaapra;
check_led();
if (SAEV_config.chipset.cia.overlay && (v & 1) != oldovl) {
oldovl = v & 1;
if (!oldovl)
SAER.memory.mapOverlay(true);
else
SAER.memory.mapOverlay(false);
}
/*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 (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Mouse) {
if (!SAER.input.mouse.button[0]) tmp |= 0x40;
if (dra & 0x40) tmp = (tmp & ~0x40) | (pra & 0x40);
} else if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Joy0) {
if (!SAER.input.joystick[0].button[0]) tmp |= 0x40;
if (dra & 0x40) tmp = (tmp & ~0x40) | (pra & 0x40);
} else tmp |= 0x40;
if (SAEV_config.ports[1].type == SAEC_Config_Ports_Type_Joy1) {
if (!SAER.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 getciatod(tod) {
if (SAEV_config.chipset.cia.type6526) {
var bcdtod = 0; //u32
for (var i = 0; i < 4; i++) {
var val = tod % 10;
bcdtod *= 16; if (bcdtod > 0xffffffff) bcdtod -= 0x100000000;
bcdtod += val; if (bcdtod > 0xffffffff) bcdtod -= 0x100000000;
tod = tod / 10 >>> 0;
}
return bcdtod;
}
return tod;
}
function calc_bintod(v) { //OWN
var bintod = 0;
for (var i = 0; i < 4; i++) {
var val = v / 16 >>> 0;
bintod *= 10; if (bintod > 0xffffffff) bintod -= 0x100000000;
bintod += val; if (bintod > 0xffffffff) bintod -= 0x100000000;
v = v / 16 >>> 0;
}
return bintod;
}
//function setciatod(*tod, v) {
function setciatod_ciaatod(v) {
ciaatod = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v;
}
function setciatod_ciaaalarm(v) {
ciaaalarm = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v;
}
function setciatod_ciabtod(v) {
ciabtod = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v;
}
function setciatod_ciabalarm(v) {
ciabalarm = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v;
}
function ReadCIAA(addr) {
var tmp;
var reg = addr & 15;
compute_passed_time();
switch (reg) {
case 0:
/*#ifdef ACTION_REPLAY
action_replay_cia_access(false);
#endif*/
tmp = SAER.disk.status_ciaa() & 0x3c;
tmp |= handle_joystick_buttons(ciaapra, ciaadra);
tmp |= (ciaapra | (ciaadra ^ 3)) & 0x03;
//tmp = dongle_cia_read(0, reg, tmp);
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;
#ifdef ARCADIA
} else if (arcadia_bios) {
tmp = arcadia_parport (0, ciaaprb, ciaadrb);
#endif
} else if (currprefs.win32_samplersoundcard >= 0) {
tmp = sampler_getsample ((ciabpra & 4) ? 1 : 0);
#endif
}*/ {
tmp = handle_parport_joystick(0, ciaaprb, ciaadrb);
//tmp = dongle_cia_read(1, reg, tmp);
}
if (ciaacrb & 2) {
var pb7 = 0;
if (ciaacrb & 4)
pb7 = ciaacrb & 1;
tmp &= ~0x80;
tmp |= pb7 ? 0x80 : 00;
}
if (ciaacra & 2) {
var pb6 = 0;
if (ciaacra & 4)
pb6 = ciaacra & 1;
tmp &= ~0x40;
tmp |= pb6 ? 0x40 : 00;
}
return tmp;
case 2:
return ciaadra;
case 3:
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 getciatod(ciaatol) & 0xff;
} else
return getciatod(ciaatod) & 0xff;
case 9:
if (ciaatlatch)
return (getciatod(ciaatol) >>> 8) & 0xff;
else
return (getciatod(ciaatod) >>> 8) & 0xff;
case 10:
/* only if not already latched. A1200 confirmed. (TW) */
if (!SAEV_config.chipset.cia.type6526) {
if (!ciaatlatch) {
/* no latching if ALARM is set */
if (!(ciaacrb & 0x80))
ciaatlatch = 1;
ciaatol = ciaatod;
}
return (getciatod(ciaatol) >>> 16) & 0xff;
} else {
if (ciaatlatch)
return (getciatod(ciaatol) >>> 16) & 0xff;
else
return (getciatod(ciaatod) >>> 16) & 0xff;
}
break;
case 11:
if (SAEV_config.chipset.cia.type6526) {
if (!ciaatlatch) {
if (!(ciaacrb & 0x80))
ciaatlatch = 1;
ciaatol = ciaatod;
}
if (ciaatlatch)
return getciatod(ciaatol) >>> 24;
else
return getciatod(ciaatod) >>> 24;
}
break;
case 12:
return ciaasdr;
case 13:
tmp = ciaaicr & ~(0x40 | 0x20);
ciaaicr = 0;
return tmp;
case 14:
return ciaacra;
case 15:
return ciaacrb;
}
return 0;
}
function ReadCIAB(addr) {
var tmp;
var reg = addr & 15;
compute_passed_time();
switch (reg) {
case 0:
tmp = 0;
/*#ifdef ARCADIA
// CD inactive, Arcadia bios 4.00 does not detect printer
if (arcadia_bios && !SAEV_config.serial.enabled)
tmp = 0x20;
#endif*/
if (SAEV_config.serial.enabled)
tmp = SAER.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;
}*/ {
tmp |= handle_parport_joystick(1, ciabpra, ciabdra);
}
//#endif
//tmp = dongle_cia_read(1, reg, tmp);
return tmp;
case 1:
tmp = ciabprb;
tmp = SAER.disk.status_ciab(tmp);
//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:
CIAB_tod_check();
if (ciabtlatch) {
ciabtlatch = 0;
return getciatod(ciabtol) & 0xff;
} else
return getciatod(ciabtod) & 0xff;
case 9:
CIAB_tod_check();
if (ciabtlatch)
return (getciatod(ciabtol) >>> 8) & 0xff;
else
return (getciatod(ciabtod) >>> 8) & 0xff;
case 10:
CIAB_tod_check();
if (!SAEV_config.chipset.cia.type6526) {
if (!ciabtlatch) {
/* no latching if ALARM is set */
if (!(ciabcrb & 0x80))
ciabtlatch = 1;
ciabtol = ciabtod;
}
return (getciatod(ciabtol) >>> 16) & 0xff;
} else {
if (ciabtlatch)
return (getciatod(ciabtol) >>> 16) & 0xff;
else
return (getciatod(ciabtod) >>> 16) & 0xff;
}
case 11:
if (SAEV_config.chipset.cia.type6526) {
if (!ciabtlatch) {
if (!(ciabcrb & 0x80))
ciabtlatch = 1;
ciabtol = ciabtod;
}
if (ciabtlatch)
return getciatod(ciabtol) >>> 24;
else
return getciatod(ciabtod) >>> 24;
}
break;
case 12:
return ciabsdr;
case 13:
tmp = ciabicr & ~(0x40 | 0x20);
ciabicr = 0;
return tmp;
case 14:
return ciabcra;
case 15:
return ciabcrb;
}
return 0;
}
function WriteCIAA(addr, val) {
var reg = addr & 15;
/*#ifdef ACTION_REPLAY
ar_ciaa[reg] = val;
#endif*/
if (!SAEV_config.chipset.cia.overlay && oldovl) {
SAER.memory.mapOverlay(true);
oldovl = 0;
}
switch (reg) {
case 0:
ciaapra = (ciaapra & ~0xc3) | (val & 0xc3);
bfe001_change();
//handle_cd32_joystick_cia (ciaapra, ciaadra);
//dongle_cia_write (0, reg, val);
//if (is_device_rom(SAEV_config, SAEC_RomType_AMAX, 0) > 0)
if (SAEV_config.memory.amaxRom.size > 0)
SAER.disk.amax_bfe001_write(val, ciaadra);
break;
case 1:
ciaaprb = val;
//dongle_cia_write (0, reg, val);
/*#ifdef PARALLEL_PORT
if (isprinter() > 0) {
doprinter (val);
cia_parallelack ();
} else if (isprinter() < 0) {
parallel_direct_write_data (val, ciaadrb);
cia_parallelack ();
#ifdef ARCADIA
} else if (arcadia_bios) {
arcadia_parport (1, ciaaprb, ciaadrb);
#endif
}
#endif*/
break;
case 2:
ciaadra = val;
//dongle_cia_write(0, reg, val);
bfe001_change();
break;
case 3:
ciaadrb = val;
//dongle_cia_write(0, reg, val);
/*#ifdef ARCADIA
if (arcadia_bios)
arcadia_parport (1, ciaaprb, ciaadrb);
#endif*/
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) {
//setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff) | val);
setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0xffffff00) | val) >>> 0);
} else {
//setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff) | val);
setciatod_ciaatod(((getciatod(ciaatod) & 0xffffff00) | val) >>> 0);
ciaatodon = 1;
ciaa_checkalarm(false);
}
break;
case 9:
if (ciaacrb & 0x80) {
//setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff00) | (val << 8));
setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0xffff00ff) | (val << 8)) >>> 0);
} else {
//setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff00) | (val << 8));
setciatod_ciaatod(((getciatod(ciaatod) & 0xffff00ff) | (val << 8)) >>> 0);
}
break;
case 10:
if (ciaacrb & 0x80) {
//setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff0000) | (val << 16));
setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0xff00ffff) | (val << 16)) >>> 0);
} else {
//setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff0000) | (val << 16));
setciatod_ciaatod(((getciatod(ciaatod) & 0xff00ffff) | (val << 16)) >>> 0);
if (!SAEV_config.chipset.cia.type6526)
ciaatodon = 0;
}
break;
case 11:
if (SAEV_config.chipset.cia.type6526) {
if (ciaacrb & 0x80) {
//setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff000000) | (val << 24));
setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0x00ffffff) | (val << 24)) >>> 0);
} else {
//setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff000000) | (val << 24));
setciatod_ciaatod(((getciatod(ciaatod) & 0x00ffffff) | (val << 24)) >>> 0);
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:
//setclr(&ciaaimask, val);
if (val & 0x80) ciaaimask |= val & 0x7F; else ciaaimask &= ~val;
RethinkICRA();
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) {
/* todo: check if low to high or high to low only */
kblostsynccnt = 0;
}
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;
/*#ifdef ACTION_REPLAY
ar_ciab[reg] = val;
#endif*/
switch (reg) {
case 0:
//dongle_cia_write(1, reg, val);
ciabpra = val;
if (SAEV_config.serial.enabled)
SAER.serial.writestatus(ciabpra, ciabdra);
/*#ifdef PARALLEL_PORT
if (isprinter () < 0) {
parallel_direct_write_status (val, ciabdra);
}
#endif*/
break;
case 1:
/*#ifdef ACTION_REPLAY
action_replay_cia_access(true);
#endif*/
//dongle_cia_write(1, reg, val);
ciabprb = val;
SAER.disk.select(val);
break;
case 2:
//dongle_cia_write(1, reg, val);
ciabdra = val;
if (SAEV_config.serial.enabled)
SAER.serial.writestatus(ciabpra, ciabdra);
break;
case 3:
//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:
CIAB_tod_check();
if (ciabcrb & 0x80) {
//setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff) | val);
setciatod_ciabalarm(((getciatod(ciabalarm) & 0xffffff00) | val) >>> 0);
} else {
//setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff) | val);
setciatod_ciabtod(((getciatod(ciabtod) & 0xffffff00) | val) >>> 0);
ciabtodon = 1;
ciab_checkalarm(false, true);
}
break;
case 9:
CIAB_tod_check ();
if (ciabcrb & 0x80) {
//setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff00) | (val << 8));
setciatod_ciabalarm(((getciatod(ciabalarm) & 0xffff00ff) | (val << 8)) >>> 0);
} else {
//setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff00) | (val << 8));
setciatod_ciabtod(((getciatod(ciabtod) & 0xffff00ff) | (val << 8)) >>> 0);
}
break;
case 10:
CIAB_tod_check();
if (ciabcrb & 0x80) {
//setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff0000) | (val << 16));
setciatod_ciabalarm(((getciatod(ciabalarm) & 0xff00ffff) | (val << 16)) >>> 0);
} else {
//setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff0000) | (val << 16));
setciatod_ciabtod(((getciatod(ciabtod) & 0xff00ffff) | (val << 16)) >>> 0);
if (!SAEV_config.chipset.cia.type6526)
ciabtodon = 0;
}
break;
case 11:
if (SAEV_config.chipset.cia.type6526) {
CIAB_tod_check();
if (ciabcrb & 0x80) {
//setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff000000) | (val << 24));
setciatod_ciabalarm(((getciatod(ciabalarm) & 0x00ffffff) | (val << 24)) >>> 0);
} else {
//setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff000000) | (val << 24));
setciatod_ciabtod(((getciatod(ciabtod) & 0x00ffffff) | (val << 24)) >>> 0);
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:
//setclr(&ciabimask, val);
if (val & 0x80) ciabimask |= val & 0x7F; else ciabimask &= ~val;
RethinkICRB();
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.cia_set_overlay = function(overlay) {
oldovl = overlay;
}*/
/*-----------------------------------------------------------------------*/
//this.setup = function () {}
this.reset = function() { //CIA_reset()
//#ifdef TOD_HACK
tod_hack_tv = 0;
tod_hack_tod = 0;
tod_hack_enabled = 0;
if (SAEV_config.chipset.cia.todHack)
tod_hack_enabled = TOD_HACK_TIME;
//#endif
kblostsynccnt = 0;
serbits = 0;
oldcd32mute = 1;
//resetwarning_phase = resetwarning_timer = 0;
heartbeat_cnt = 0;
ciab_tod_event_state = 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();
SAER.disk.select_set(ciabprb);
}
SAER.memory.mapOverlay(false);
check_led();
if (SAEV_config.serial.enabled)
SAER.serial.dtr_off(); // Drop DTR at reset
/*#ifdef CD32
akiko_reset ();
if (!akiko_init ())
currprefs.cs_cd32cd = changed_prefs.cs_cd32cd = 0;
#endif*/
}
this.dump = function() { //dumpcia()
SAEF_log("cia.dump() A: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)", ciaacra, ciaacrb, ciaaicr, ciaaimask, ciaata, ciaala, ciaatb, ciaalb);
SAEF_log("cia.dump() TOD %06x (%06x) ALARM %06x %c%c CYC=%08X", ciaatod, ciaatol, ciaaalarm, ciaatlatch ? "L" : " ", ciaatodon ? " " : "S", SAEV_Events_currcycle);
SAEF_log("cia.dump() B: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)", ciabcra, ciabcrb, ciabicr, ciabimask, ciabta, ciabla, ciabtb, ciablb);
SAEF_log("cia.dump() TOD %06x (%06x) ALARM %06x %c%c CLK=%d", ciabtod, ciabtol, ciabalarm, ciabtlatch ? "L" : " ", ciabtodon ? " " : "S", div10 / SAEC_Events_CYCLE_UNIT);
}
/*-----------------------------------------------------------------------*/
// 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 SAEV_config.chipset.ide || SAEV_config.chipset.pcmcia || SAEV_config.chipset.mbdmac;
}
function isgayle() {
return SAEV_config.chipset.ide || SAEV_config.chipset.pcmcia;
}
function iscia(addr) {
var mask = addr & 0xf000;
return mask == 0xe000 || mask == 0xd000;
}
function isgaylenocia(addr) {
if (!isgayle())
return true;
// gayle CIA region is only 4096 bytes at 0xbfd000 and 0xbfe000
return iscia(addr);
}
function isgarynocia(addr) {
return !iscia(addr) && SAEV_config.chipset.fatGaryRev >= 0;
}
/*---------------------------------*/
function cia_wait_pre(cianummask) {
var div = (SAEV_Events_currcycle - SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles) % DIV10;
var help = DIV10 * ECLOCK_DATA_CYCLE / 10 >>> 0;
var cycles;
if (div >= help) {
cycles = DIV10 - div;
cycles += help;
} else if (div)
cycles = DIV10 + help - div;
else
cycles = help - div;
if (cycles)
SAER.events.do_cycles(cycles);
}
function cia_wait_post(cianummask, value) {
SAER.events.do_cycles(6 * SAEC_Events_CYCLE_UNIT >> 1);
if (cia_interrupt_delay) {
var v = cia_interrupt_delay;
cia_interrupt_delay = 0;
if (v & 1) ICR(0x0008);
if (v & 2) ICR(0x2000);
}
}
/*---------------------------------*/
function get8(addr) {
var r = (addr & 0xf00) >> 8;
var v = 0xff;
if (isgarynocia(addr))
return SAER.memory.dummyGet(addr, 1, false, 0);
if (!isgaylenocia(addr))
return v;
switch ((addr >> 12) & 3) {
case 0:
if (!issinglecia()) {
cia_wait_pre(1 | 2);
v = (addr & 1) ? ReadCIAA(r) : ReadCIAB(r);
cia_wait_post(1 | 2, v);
}
break;
case 1:
cia_wait_pre(2);
if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) {
v = (addr & 1) ? SAER_CPU_regs.irc & 0xff : ReadCIAB(r);
} else {
v = (addr & 1) ? 0xff : ReadCIAB(r);
}
cia_wait_post(2, v);
break;
case 2:
cia_wait_pre(1);
if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible)
v = (addr & 1) ? ReadCIAA(r) : SAER_CPU_regs.irc >> 8;
else
v = (addr & 1) ? ReadCIAA(r) : 0xff;
cia_wait_post(1, v);
break;
case 3:
if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) {
cia_wait_pre(0);
v = (addr & 1) ? SAER_CPU_regs.irc & 0xff : SAER_CPU_regs.irc >> 8;
cia_wait_post(0, v);
}
break;
}
return v;
}
function get16(addr) {
var r = (addr & 0xf00) >> 8;
var v = 0xffff;
if (isgarynocia(addr))
return SAER.memory.dummyGet(addr, 2, false, 0);
if (!isgaylenocia (addr))
return v;
switch ((addr >> 12) & 3) {
case 0:
if (!issinglecia()) {
cia_wait_pre(1 | 2);
v = (ReadCIAB(r) << 8) | ReadCIAA(r);
cia_wait_post(1 | 2, v);
}
break;
case 1:
cia_wait_pre(2);
v = (ReadCIAB(r) << 8) | 0xff;
cia_wait_post(2, v);
break;
case 2:
cia_wait_pre(1);
v = (0xff << 8) | ReadCIAA (r);
cia_wait_post(1, v);
break;
case 3:
if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) {
cia_wait_pre(0);
v = SAER_CPU_regs.irc;
cia_wait_post(0, v);
}
break;
}
return v;
}
function get32(addr) {
return ((get16(addr) << 16) | get16(addr + 2)) >>> 0;
}
function put8(addr, value) {
var r = (addr & 0xf00) >> 8;
if (isgarynocia(addr)) {
SAER.memory.dummyPut(addr, 1, 0);
return;
}
if (!isgaylenocia (addr))
return;
if (!issinglecia() || (addr & 0x3000) != 0) {
cia_wait_pre(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0));
if ((addr & 0x2000) == 0)
WriteCIAB(r, value);
if ((addr & 0x1000) == 0)
WriteCIAA(r, value);
cia_wait_post(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0), value);
}
}
function put16(addr, value) {
var r = (addr & 0xf00) >> 8;
if (isgarynocia(addr)) {
SAER.memory.dummyPut(addr, 2, 0);
return;
}
if (!isgaylenocia (addr))
return;
if (!issinglecia() || (addr & 0x3000) != 0) {
cia_wait_pre(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0));
if ((addr & 0x2000) == 0)
WriteCIAB(r, value >> 8);
if ((addr & 0x1000) == 0)
WriteCIAA(r, value & 0xff);
cia_wait_post(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0), value);
}
}
function put32(addr, value) {
put16(addr, value >>> 16);
put16(addr + 2, value & 0xffff);
}
function getInst32(addr) {
if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) return SAEF_Memory_dummyGetInst32(addr);
return get32(addr);
}
function getInst16(addr) {
if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) return SAEF_Memory_dummyGetInst16(addr);
return get16(addr);
}
SAEV_CIA_bank = new SAEO_Memory_addrbank(
get32, get16, get8,
put32, put16, put8,
SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "CIA",
getInst32, getInst16,
//SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_CIA, S_READ, S_WRITE, null, 0x3f01, 0xbfc000
SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_CIA, null, 0x3f01, 0xbfc000
);
}