1725 lines
44 KiB
JavaScript
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
|
|
);
|
|
}
|