333 lines
11 KiB
JavaScript
333 lines
11 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_RTC_bank = null;
|
|
|
|
var SAEV_RTC_delayed_write = 0;
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEO_RTC() {
|
|
const RTC_DEBUG = false;
|
|
|
|
var clock_control_d = 0;
|
|
var clock_control_e = 0;
|
|
var clock_control_f = 0;
|
|
|
|
const RF5C01A_RAM_SIZE = 16;
|
|
var rtc_memory = null;
|
|
var rtc_alarm = null;
|
|
|
|
/*---------------------------------*/
|
|
|
|
function localtime(t) {
|
|
this.tm_sec = t.getSeconds(); //seconds [0,61]
|
|
this.tm_min = t.getMinutes(); //minutes [0,59]
|
|
this.tm_hour = t.getHours(); //hour [0,23]
|
|
this.tm_mday = t.getDate(); //day of month [1,31]
|
|
this.tm_mon = t.getMonth(); //month of year [0,11]
|
|
this.tm_year = t.getFullYear() - 1900; //years since 1900
|
|
this.tm_wday = t.getDay(); //day of week [0,6] (Sunday = 0)
|
|
this.tm_yday = 0; //day of year [0,365]
|
|
this.tm_isdst = false; //daylight savings flag
|
|
}
|
|
|
|
function getct() {
|
|
var d = new Date();
|
|
if (SAEV_config.chipset.rtc.adjust) {
|
|
var n = d.valueOf();
|
|
d.setTime(n + SAEV_config.chipset.rtc.adjust * 1000);
|
|
}
|
|
return new localtime(d);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function getclockreg(addr, ct) {
|
|
var v = 0;
|
|
|
|
if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */
|
|
switch (addr) {
|
|
case 0x0: v = ct.tm_sec % 10; break;
|
|
case 0x1: v = ct.tm_sec / 10 >>> 0; break;
|
|
case 0x2: v = ct.tm_min % 10; break;
|
|
case 0x3: v = ct.tm_min / 10 >>> 0; break;
|
|
case 0x4: v = ct.tm_hour % 10; break;
|
|
case 0x5: {
|
|
if (clock_control_f & 4)
|
|
v = ct.tm_hour / 10 >>> 0; /* 24h */
|
|
else {
|
|
v = (ct.tm_hour % 12) / 10 >>> 0; /* 12h */
|
|
v |= ct.tm_hour >= 12 ? 4 : 0; /* AM/PM bit */
|
|
}
|
|
break;
|
|
}
|
|
case 0x6: v = ct.tm_mday % 10; break;
|
|
case 0x7: v = ct.tm_mday / 10 >>> 0; break;
|
|
case 0x8: v = (ct.tm_mon + 1) % 10; break;
|
|
case 0x9: v = (ct.tm_mon + 1) / 10 >>> 0; break;
|
|
case 0xA: v = ct.tm_year % 10; break;
|
|
case 0xB: v = ((ct.tm_year / 10) >>> 0) & 0x0f; break;
|
|
case 0xC: v = ct.tm_wday; break;
|
|
case 0xD: v = clock_control_d; break;
|
|
case 0xE: v = clock_control_e; break;
|
|
case 0xF: v = clock_control_f; break;
|
|
}
|
|
} else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */
|
|
var bank = clock_control_d & 3;
|
|
/* memory access */
|
|
if (bank >= 2 && addr < 0x0d)
|
|
return (rtc_memory[addr] >> ((bank == 2) ? 0 : 4)) & 0x0f;
|
|
/* alarm */
|
|
if (bank == 1 && addr < 0x0d) {
|
|
v = rtc_alarm[addr];
|
|
if (RTC_DEBUG) SAEF_log("rtc.get8(0x%X, ct) ALARM (0x%x)", addr, v);
|
|
return v;
|
|
}
|
|
switch (addr) {
|
|
case 0x0: v = ct.tm_sec % 10; break;
|
|
case 0x1: v = ct.tm_sec / 10 >>> 0; break;
|
|
case 0x2: v = ct.tm_min % 10; break;
|
|
case 0x3: v = ct.tm_min / 10 >>> 0; break;
|
|
case 0x4: v = ct.tm_hour % 10; break;
|
|
case 0x5: {
|
|
if (rtc_alarm[10] & 1)
|
|
v = ct.tm_hour / 10 >>> 0; /* 24h */
|
|
else {
|
|
v = (ct.tm_hour % 12) / 10 >>> 0; /* 12h */
|
|
v |= ct.tm_hour >= 12 ? 2 : 0; /* AM/PM bit */
|
|
}
|
|
break;
|
|
}
|
|
case 0x6: v = ct.tm_wday; break;
|
|
case 0x7: v = ct.tm_mday % 10; break;
|
|
case 0x8: v = ct.tm_mday / 10 >>> 0; break;
|
|
case 0x9: v = (ct.tm_mon + 1) % 10; break;
|
|
case 0xA: v = (ct.tm_mon + 1) / 10 >>> 0; break;
|
|
case 0xB: v = (ct.tm_year % 100) % 10; break;
|
|
case 0xC: v = (ct.tm_year % 100) / 10 >>> 0; break;
|
|
case 0xD: v = clock_control_d; break;
|
|
case 0xE: v = 0; break; //E and F = write-only, reads as zero
|
|
case 0xF: v = 0; break;
|
|
}
|
|
}
|
|
if (RTC_DEBUG) SAEF_log("rtc.get8(0x%X, ct) (0x%x)", addr, v);
|
|
return v;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function read() { //read_battclock()
|
|
//if (SAEV_config.chipset.rtc.file.length)
|
|
{
|
|
var f = null; //SAEF_ZFile_fopen(SAEV_config.chipset.rtc.file, "rb");
|
|
if (f) {
|
|
var data = new Uint8Array(16);
|
|
SAEF_ZFile_fread(data,0, 16, 1, f);
|
|
clock_control_d = data[13];
|
|
clock_control_e = data[14];
|
|
clock_control_f = data[15];
|
|
if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) {
|
|
SAEF_ZFile_fread(rtc_alarm,0, RF5C01A_RAM_SIZE, 1, f);
|
|
SAEF_ZFile_fread(rtc_memory,0, RF5C01A_RAM_SIZE, 1, f);
|
|
}
|
|
SAEF_ZFile_fclose(f);
|
|
}
|
|
}
|
|
}
|
|
this.write = function() { //write_battclock() called from cia.vsync()
|
|
if (SAEV_config.chipset.rtc.type != SAEC_Config_RTC_Type_None) {
|
|
//if (SAEV_config.chipset.rtc.file.length)
|
|
{
|
|
var f = null; //SAEF_ZFile_fopen(SAEV_config.chipset.rtc.file, "wb");
|
|
if (f) {
|
|
var ct = getct();
|
|
var data = new Uint8Array(16);
|
|
var od = clock_control_d;
|
|
if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A)
|
|
clock_control_d &= ~3;
|
|
for (var i = 0; i < 13; i++)
|
|
data[i] = getclockreg(i, ct);
|
|
clock_control_d = od;
|
|
data[i] = clock_control_d;
|
|
data[i] = clock_control_e;
|
|
data[i] = clock_control_f;
|
|
SAEF_ZFile_fwrite(data,0, 16, 1, f);
|
|
if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) {
|
|
SAEF_ZFile_fwrite(rtc_alarm,0, RF5C01A_RAM_SIZE, 1, f);
|
|
SAEF_ZFile_fwrite(rtc_memory,0, RF5C01A_RAM_SIZE, 1, f);
|
|
}
|
|
SAEF_ZFile_fclose(f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
this.hardreset = function() { //rtc_hardreset()
|
|
switch (SAEV_config.chipset.rtc.type) {
|
|
case SAEC_Config_RTC_Type_None: type = "none"; break;
|
|
case SAEC_Config_RTC_Type_MSM6242B: type = "MSM6242B"; break;
|
|
case SAEC_Config_RTC_Type_RF5C01A: type = "RF5C01A"; break;
|
|
case SAEC_Config_RTC_Type_MSM6242B_A2000: type = "MSM6242B A2000"; break;
|
|
}
|
|
SAEF_log("rtc.hardreset() type '%s'", type);
|
|
|
|
SAEV_RTC_delayed_write = 0;
|
|
if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */
|
|
clock_control_d = 0x1;
|
|
clock_control_e = 0;
|
|
clock_control_f = 0x4; /* 24/12 */
|
|
rtc_memory = null;
|
|
rtc_alarm = null;
|
|
} else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */
|
|
clock_control_d = 0x8; /* Timer EN */
|
|
clock_control_e = 0;
|
|
clock_control_f = 0;
|
|
rtc_memory = new Uint8Array(RF5C01A_RAM_SIZE);
|
|
rtc_alarm = new Uint8Array(RF5C01A_RAM_SIZE);
|
|
for (var i = 0; i < RF5C01A_RAM_SIZE; i++)
|
|
rtc_memory[i] = rtc_alarm[i] = 0;
|
|
|
|
rtc_alarm[10] = 1; /* 24H mode */
|
|
}
|
|
SAEV_RTC_bank.name = "Battery backed up clock ("+type+")";
|
|
read();
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function get32(addr) {
|
|
if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0)
|
|
return SAER.memory.dummyGet(addr, 4, false, 0);
|
|
|
|
return ((get16(addr) << 16) | get16(addr + 2)) >>> 0;
|
|
}
|
|
|
|
function get16(addr) {
|
|
if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0)
|
|
return SAER.memory.dummyGet(addr, 2, false, 0);
|
|
|
|
return (get8(addr) << 8) | get8(addr + 1);
|
|
}
|
|
|
|
function get8(addr) {
|
|
if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0)
|
|
return SAER.memory.dummyGet(addr, 1, false, 0);
|
|
/*#ifdef CDTV
|
|
if (currprefs.cs_cdtvram && (addr & 0xffff) >= 0x8000)
|
|
return cdtv_battram_read(addr);
|
|
#endif*/
|
|
|
|
addr &= 0x3f;
|
|
if ((addr & 3) == 2 || (addr & 3) == 0 || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_None)
|
|
return SAER.memory.dummyGet(addr, 1, false, 0);
|
|
|
|
var ct = getct();
|
|
return getclockreg(addr >> 2, ct);
|
|
}
|
|
|
|
function put32(addr, value) {
|
|
if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) {
|
|
SAER.memory.dummyPut(addr, 4, value);
|
|
return;
|
|
}
|
|
put16(addr, value >>> 16);
|
|
put16(addr + 2, value & 0xffff);
|
|
}
|
|
|
|
function put16(addr, value) {
|
|
if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) {
|
|
SAER.memory.dummyPut(addr, 2, value);
|
|
return;
|
|
}
|
|
put8(addr, value >> 8);
|
|
put8(addr + 1, value & 0xff);
|
|
}
|
|
|
|
function put8(addr, value) {
|
|
if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) {
|
|
SAER.memory.dummyPut(addr, 1, value);
|
|
return;
|
|
}
|
|
/*#ifdef CDTV
|
|
if (currprefs.cs_cdtvram && (addr & 0xffff) >= 0x8000) {
|
|
cdtv_battram_write(addr, value);
|
|
return;
|
|
}
|
|
#endif*/
|
|
|
|
addr &= 0x3f;
|
|
if ((addr & 1) != 1 || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_None)
|
|
return;
|
|
addr >>= 2;
|
|
value &= 0x0f;
|
|
if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */
|
|
if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x)", addr, value);
|
|
switch (addr) {
|
|
case 0xD: clock_control_d = value & (1|8); break;
|
|
case 0xE: clock_control_e = value; break;
|
|
case 0xF: clock_control_f = value; break;
|
|
}
|
|
} else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */
|
|
var bank = clock_control_d & 3;
|
|
/* memory access */
|
|
if (bank >= 2 && addr < 0x0d) {
|
|
var ov = rtc_memory[addr];
|
|
rtc_memory[addr] &= ((bank == 2) ? 0xf0 : 0x0f);
|
|
rtc_memory[addr] |= value << ((bank == 2) ? 0 : 4);
|
|
if (rtc_memory[addr] != ov) SAEV_RTC_delayed_write = -1;
|
|
return;
|
|
}
|
|
/* alarm */
|
|
if (bank == 1 && addr < 0x0d) {
|
|
if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x) ALARM", addr, value);
|
|
var ov = rtc_alarm[addr];
|
|
rtc_alarm[addr] = value;
|
|
rtc_alarm[0] = rtc_alarm[1] = rtc_alarm[9] = rtc_alarm[12] = 0;
|
|
rtc_alarm[3] &= ~0x8;
|
|
rtc_alarm[5] &= ~0xc;
|
|
rtc_alarm[6] &= ~0x8;
|
|
rtc_alarm[8] &= ~0xc;
|
|
rtc_alarm[10] &= ~0xe;
|
|
rtc_alarm[11] &= ~0xc;
|
|
if (rtc_alarm[addr] != ov) SAEV_RTC_delayed_write = -1;
|
|
return;
|
|
}
|
|
if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x)", addr, value);
|
|
switch (addr) {
|
|
case 0xD: clock_control_d = value; break;
|
|
case 0xE: clock_control_e = value; break;
|
|
case 0xF: clock_control_f = value; break;
|
|
}
|
|
}
|
|
SAEV_RTC_delayed_write = -1;
|
|
}
|
|
|
|
SAEV_RTC_bank = new SAEO_Memory_addrbank(
|
|
get32, get16, get8,
|
|
put32, put16, put8,
|
|
SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Battery backed up clock (none)",
|
|
SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16,
|
|
//SAEC_Memory_addrbank_flag_IO, S_READ, S_WRITE, null, 0x3f, 0xd80000
|
|
SAEC_Memory_addrbank_flag_IO, null, 0x3f, 0xd80000
|
|
);
|
|
}
|