From 27b472164c643f39c0a2a7a9a0acf5c198f7095e Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 7 May 2017 15:02:42 +0300 Subject: [PATCH] More generic RTC emulation. Comspec RTC emulation. --- a2091.cpp | 20 ++++- cia.cpp | 206 +++++++++++++++--------------------------------- include/a2091.h | 1 + include/rtc.h | 25 ++++++ rtc.cpp | 156 ++++++++++++++++++++++++++++++++++++ 5 files changed, 265 insertions(+), 143 deletions(-) create mode 100644 include/rtc.h create mode 100644 rtc.cpp diff --git a/a2091.cpp b/a2091.cpp index a6809d8b..67720f35 100644 --- a/a2091.cpp +++ b/a2091.cpp @@ -43,6 +43,7 @@ #include "cdtv.h" #include "savestate.h" #include "cpuboard.h" +#include "rtc.h" #define DMAC_8727_ROM_VECTOR 0x8000 #define CDMAC_ROM_VECTOR 0x2000 @@ -291,6 +292,7 @@ static void freencrunit(struct wd_state *wd) free_expansion_bank(&wd->bank); else xfree (wd->rom); + xfree(wd->userdata); wd->rom = NULL; if (wd->self_ptr) *wd->self_ptr = NULL; @@ -2568,6 +2570,11 @@ static uae_u8 comspec_read_byte(struct wd_state *wd, uaecptr addr) v = comspec_status(wd); } else if ((addr & 0xf1) == 0x81) { v = wdscsi_get_data(&wd->wc, wd); + } else if ((addr & 0xa0) == 0xa0) { + if (wd->comspec.status & 1) { + int rtc = (addr >> 1) & 15; + v = get_clock_msm((struct rtc_msm_data*)wd->userdata, rtc, NULL); + } } else { if (comspec_wd_aux(addr)) { v = wdscsi_getauxstatus(&wd->wc); @@ -2597,6 +2604,11 @@ static void comspec_write_byte(struct wd_state *wd, uaecptr addr, uae_u8 v) #endif } else if ((addr & 0xf1) == 0xe1) { wdscsi_put_data(&wd->wc, wd, v); + } else if ((addr & 0xa0) == 0xa0) { + if (wd->comspec.status & 1) { + int rtc = (addr >> 1) & 15; + put_clock_msm((struct rtc_msm_data*)wd->userdata, rtc, v); + } } else { if (comspec_wd_aux(addr)) { wdscsi_sasr(&wd->wc, v); @@ -4122,7 +4134,7 @@ bool comspec_init (struct autoconfig_info *aci) ew(aci->autoconfig_raw, 0x18, 0x00); ew(aci->autoconfig_raw, 0x1c, 0x00); ew(aci->autoconfig_raw, 0x20, 0x00); - ew(aci->autoconfig_raw, 0x24, 0x00); + ew(aci->autoconfig_raw, 0x24, (aci->rc->device_settings & 1) ? 0x00 : 0x01); aci->label = _T("COMSPEC"); if (!aci->doinit) @@ -4165,6 +4177,12 @@ bool comspec_init (struct autoconfig_info *aci) wd->baseaddress2 = 0xf00000; } + wd->userdata = xcalloc(struct rtc_msm_data, 1); + struct rtc_msm_data *rtc = (struct rtc_msm_data*)wd->userdata; + rtc->clock_control_d = 1; + rtc->clock_control_f = 0x4; /* 24/12 */ + rtc->yearmode = true; + return true; } diff --git a/cia.cpp b/cia.cpp index c3428f37..738b582e 100644 --- a/cia.cpp +++ b/cia.cpp @@ -43,6 +43,7 @@ #include "uae/ppc.h" #include "rommgr.h" #include "scsi.h" +#include "rtc.h" #define CIAA_DEBUG_R 0 #define CIAA_DEBUG_W 0 @@ -102,8 +103,9 @@ static uae_u8 kbcode; static uae_u8 serbits; static int warned = 10; -static int rtc_delayed_write; +static struct rtc_msm_data rtc_msm; +static struct rtc_ricoh_data rtc_ricoh; static void setclr (unsigned int *p, unsigned int val) { @@ -914,13 +916,22 @@ void CIA_vsync_prehandler (void) { if (heartbeat_cnt > 0) heartbeat_cnt--; - if (rtc_delayed_write < 0) { - rtc_delayed_write = 50; - } else if (rtc_delayed_write > 0) { - rtc_delayed_write--; - if (rtc_delayed_write == 0) + + if (rtc_msm.delayed_write < 0) { + rtc_msm.delayed_write = 50; + } else if (rtc_msm.delayed_write > 0) { + rtc_msm.delayed_write--; + if (rtc_msm.delayed_write == 0) + write_battclock (); + } + if (rtc_ricoh.delayed_write < 0) { + rtc_ricoh.delayed_write = 50; + } else if (rtc_ricoh.delayed_write > 0) { + rtc_ricoh.delayed_write--; + if (rtc_ricoh.delayed_write == 0) write_battclock (); } + led_vsync (); CIA_handler (); if (kblostsynccnt > 0) { @@ -2092,80 +2103,14 @@ addrbank clock_bank = { ABFLAG_IO, S_READ, S_WRITE, NULL, 0x3f, 0xd80000 }; -static unsigned int clock_control_d; -static unsigned int clock_control_e; -static unsigned int clock_control_f; - -#define RF5C01A_RAM_SIZE 16 -static uae_u8 rtc_memory[RF5C01A_RAM_SIZE], rtc_alarm[RF5C01A_RAM_SIZE]; - static uae_u8 getclockreg (int addr, struct tm *ct) { uae_u8 v = 0; if (currprefs.cs_rtc == 1 || currprefs.cs_rtc == 3) { /* MSM6242B */ - switch (addr) { - case 0x0: v = ct->tm_sec % 10; break; - case 0x1: v = ct->tm_sec / 10; break; - case 0x2: v = ct->tm_min % 10; break; - case 0x3: v = ct->tm_min / 10; break; - case 0x4: v = ct->tm_hour % 10; break; - case 0x5: - if (clock_control_f & 4) { - v = ct->tm_hour / 10; // 24h - } else { - v = (ct->tm_hour % 12) / 10; // 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; break; - case 0x8: v = (ct->tm_mon + 1) % 10; break; - case 0x9: v = (ct->tm_mon + 1) / 10; break; - case 0xA: v = ct->tm_year % 10; break; - case 0xB: v = (ct->tm_year / 10) & 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; - } + return get_clock_msm(&rtc_msm, addr, ct); } else if (currprefs.cs_rtc == 2) { /* RF5C01A */ - int 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 CLOCK_DEBUG - write_log (_T("CLOCK ALARM R %X: %X\n"), addr, v); -#endif - return v; - } - switch (addr) { - case 0x0: v = ct->tm_sec % 10; break; - case 0x1: v = ct->tm_sec / 10; break; - case 0x2: v = ct->tm_min % 10; break; - case 0x3: v = ct->tm_min / 10; break; - case 0x4: v = ct->tm_hour % 10; break; - case 0x5: - if (rtc_alarm[10] & 1) - v = ct->tm_hour / 10; // 24h - else - v = ((ct->tm_hour % 12) / 10) | (ct->tm_hour >= 12 ? 2 : 0); // 12h - break; - case 0x6: v = ct->tm_wday; break; - case 0x7: v = ct->tm_mday % 10; break; - case 0x8: v = ct->tm_mday / 10; break; - case 0x9: v = (ct->tm_mon + 1) % 10; break; - case 0xA: v = (ct->tm_mon + 1) / 10; break; - case 0xB: v = (ct->tm_year % 100) % 10; break; - case 0xC: v = (ct->tm_year % 100) / 10; break; - case 0xD: v = clock_control_d; break; - /* E and F = write-only, reads as zero */ - case 0xE: v = 0; break; - case 0xF: v = 0; break; - } + return get_clock_ricoh(&rtc_ricoh, addr, ct); } #if CLOCK_DEBUG write_log(_T("CLOCK R: %X = %X, PC=%08x\n"), addr, v, M68K_GETPC); @@ -2183,20 +2128,31 @@ static void write_battclock (void) time_t t = time (0); t += currprefs.cs_rtc_adjust; ct = localtime (&t); - uae_u8 od = clock_control_d; - if (currprefs.cs_rtc == 2) - clock_control_d &= ~3; + uae_u8 od; + if (currprefs.cs_rtc == 2) { + od = rtc_ricoh.clock_control_d; + rtc_ricoh.clock_control_d &= ~3; + } else { + od = rtc_msm.clock_control_d; + } for (int i = 0; i < 13; i++) { uae_u8 v = getclockreg (i, ct); zfile_fwrite (&v, 1, 1, f); } - clock_control_d = od; - zfile_fwrite (&clock_control_d, 1, 1, f); - zfile_fwrite (&clock_control_e, 1, 1, f); - zfile_fwrite (&clock_control_f, 1, 1, f); if (currprefs.cs_rtc == 2) { - zfile_fwrite (rtc_alarm, RF5C01A_RAM_SIZE, 1, f); - zfile_fwrite (rtc_memory, RF5C01A_RAM_SIZE, 1, f); + rtc_ricoh.clock_control_d = od; + zfile_fwrite (&rtc_ricoh.clock_control_d, 1, 1, f); + zfile_fwrite (&rtc_ricoh.clock_control_e, 1, 1, f); + zfile_fwrite (&rtc_ricoh.clock_control_f, 1, 1, f); + } else { + rtc_msm.clock_control_d = od; + zfile_fwrite (&rtc_msm.clock_control_d, 1, 1, f); + zfile_fwrite (&rtc_msm.clock_control_e, 1, 1, f); + zfile_fwrite (&rtc_msm.clock_control_f, 1, 1, f); + } + if (currprefs.cs_rtc == 2) { + zfile_fwrite (rtc_ricoh.rtc_alarm, RF5C01A_RAM_SIZE, 1, f); + zfile_fwrite (rtc_ricoh.rtc_memory, RF5C01A_RAM_SIZE, 1, f); } zfile_fclose (f); } @@ -2204,31 +2160,39 @@ static void write_battclock (void) void rtc_hardreset (void) { - rtc_delayed_write = 0; if (currprefs.cs_rtc == 1 || currprefs.cs_rtc == 3) { /* MSM6242B */ clock_bank.name = currprefs.cs_rtc == 1 ? _T("Battery backed up clock (MSM6242B)") : _T("Battery backed up clock A2000 (MSM6242B)"); - clock_control_d = 0x1; - clock_control_e = 0; - clock_control_f = 0x4; /* 24/12 */ + rtc_msm.clock_control_d = 0x1; + rtc_msm.clock_control_e = 0; + rtc_msm.clock_control_f = 0x4; /* 24/12 */ + rtc_msm.delayed_write = 0; } else if (currprefs.cs_rtc == 2) { /* RF5C01A */ clock_bank.name = _T("Battery backed up clock (RF5C01A)"); - clock_control_d = 0x8; /* Timer EN */ - clock_control_e = 0; - clock_control_f = 0; - memset (rtc_memory, 0, RF5C01A_RAM_SIZE); - memset (rtc_alarm, 0, RF5C01A_RAM_SIZE); - rtc_alarm[10] = 1; /* 24H mode */ + rtc_ricoh.clock_control_d = 0x8; /* Timer EN */ + rtc_ricoh.clock_control_e = 0; + rtc_ricoh.clock_control_f = 0; + memset (rtc_ricoh.rtc_memory, 0, RF5C01A_RAM_SIZE); + memset (rtc_ricoh.rtc_alarm, 0, RF5C01A_RAM_SIZE); + rtc_ricoh.rtc_alarm[10] = 1; /* 24H mode */ + rtc_ricoh.delayed_write = 0; } if (currprefs.rtcfile[0]) { struct zfile *f = zfile_fopen (currprefs.rtcfile, _T("rb")); if (f) { uae_u8 empty[13]; zfile_fread (empty, 13, 1, f); - zfile_fread (&clock_control_d, 1, 1, f); - zfile_fread (&clock_control_e, 1, 1, f); - zfile_fread (&clock_control_f, 1, 1, f); - zfile_fread (rtc_alarm, RF5C01A_RAM_SIZE, 1, f); - zfile_fread (rtc_memory, RF5C01A_RAM_SIZE, 1, f); + uae_u8 v; + zfile_fread (&v, 1, 1, f); + rtc_ricoh.clock_control_d = v; + rtc_msm.clock_control_d = v; + zfile_fread (&v, 1, 1, f); + rtc_ricoh.clock_control_e = v; + rtc_msm.clock_control_d = v; + zfile_fread (&v, 1, 1, f); + rtc_ricoh.clock_control_f = v; + rtc_msm.clock_control_d = v; + zfile_fread (rtc_ricoh.rtc_alarm, RF5C01A_RAM_SIZE, 1, f); + zfile_fread (rtc_ricoh.rtc_memory, RF5C01A_RAM_SIZE, 1, f); zfile_fclose (f); } } @@ -2321,52 +2285,10 @@ static void REGPARAM2 clock_bput (uaecptr addr, uae_u32 value) #if CLOCK_DEBUG write_log (_T("CLOCK W %X: %X\n"), addr, value); #endif - 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; - } + put_clock_msm(&rtc_msm, addr, value); } else if (currprefs.cs_rtc == 2) { /* RF5C01A */ - int bank = clock_control_d & 3; - /* memory access */ - if (bank >= 2 && addr < 0x0d) { - uae_u8 ov = rtc_memory[addr]; - rtc_memory[addr] &= ((bank == 2) ? 0xf0 : 0x0f); - rtc_memory[addr] |= value << ((bank == 2) ? 0 : 4); - if (rtc_memory[addr] != ov) - rtc_delayed_write = -1; - return; - } - /* alarm */ - if (bank == 1 && addr < 0x0d) { -#if CLOCK_DEBUG - write_log (_T("CLOCK ALARM W %X: %X\n"), addr, value); -#endif - uae_u8 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) - rtc_delayed_write = -1; - return; - } -#if CLOCK_DEBUG - write_log (_T("CLOCK W %X: %X\n"), addr, value); -#endif - switch (addr) - { - case 0xD: clock_control_d = value; break; - case 0xE: clock_control_e = value; break; - case 0xF: clock_control_f = value; break; - } + put_clock_ricoh(&rtc_ricoh, addr, value); } - rtc_delayed_write = -1; } #ifdef SAVESTATE diff --git a/include/a2091.h b/include/a2091.h index 033ab837..3576a9aa 100644 --- a/include/a2091.h +++ b/include/a2091.h @@ -104,6 +104,7 @@ struct wd_state { struct gvp_dmac gdmac; struct comspec_chip comspec; addrbank bank; + void *userdata; }; extern wd_state *wd_cdtv; diff --git a/include/rtc.h b/include/rtc.h new file mode 100644 index 00000000..e394e9b6 --- /dev/null +++ b/include/rtc.h @@ -0,0 +1,25 @@ + +struct rtc_msm_data +{ + uae_u8 clock_control_d; + uae_u8 clock_control_e; + uae_u8 clock_control_f; + int delayed_write; + bool yearmode; +}; + +#define RF5C01A_RAM_SIZE 16 +struct rtc_ricoh_data +{ + uae_u8 clock_control_d; + uae_u8 clock_control_e; + uae_u8 clock_control_f; + uae_u8 rtc_memory[RF5C01A_RAM_SIZE], rtc_alarm[RF5C01A_RAM_SIZE]; + int delayed_write; +}; + +uae_u8 get_clock_msm(struct rtc_msm_data *data, int addr, struct tm *ct); +bool put_clock_msm(struct rtc_msm_data *data, int addr, uae_u8 v); + +uae_u8 get_clock_ricoh(struct rtc_ricoh_data *data, int addr, struct tm *ct); +void put_clock_ricoh(struct rtc_ricoh_data *data, int addr, uae_u8 v); diff --git a/rtc.cpp b/rtc.cpp new file mode 100644 index 00000000..bc4578a3 --- /dev/null +++ b/rtc.cpp @@ -0,0 +1,156 @@ +/* +* UAE - The Un*x Amiga Emulator +* +* RTC chips +*/ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "options.h" + +#include "rtc.h" + +uae_u8 get_clock_msm(struct rtc_msm_data *data, int addr, struct tm *ct) +{ + uae_u8 v; + int year; + + if (!ct) { + time_t t = time (0); + t += currprefs.cs_rtc_adjust; + ct = localtime (&t); + } + year = ct->tm_year; + if (data->yearmode && year >= 100) + year -= 100; + + switch (addr) + { + case 0x0: v = ct->tm_sec % 10; break; + case 0x1: v = ct->tm_sec / 10; break; + case 0x2: v = ct->tm_min % 10; break; + case 0x3: v = ct->tm_min / 10; break; + case 0x4: v = ct->tm_hour % 10; break; + case 0x5: + if (data->clock_control_f & 4) { + v = ct->tm_hour / 10; // 24h + } else { + v = (ct->tm_hour % 12) / 10; // 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; break; + case 0x8: v = (ct->tm_mon + 1) % 10; break; + case 0x9: v = (ct->tm_mon + 1) / 10; break; + case 0xA: v = year % 10; break; + case 0xB: v = (year / 10) & 0x0f; break; + case 0xC: v = ct->tm_wday; break; + case 0xD: v = data->clock_control_d; break; + case 0xE: v = data->clock_control_e; break; + case 0xF: v = data->clock_control_f; break; + } + return v; +} + +bool put_clock_msm(struct rtc_msm_data *data, int addr, uae_u8 v) +{ + switch (addr) + { + case 0xD: data->clock_control_d = v & (1|8); break; + case 0xE: data->clock_control_e = v; break; + case 0xF: data->clock_control_f = v; break; + } + return false; +} + +uae_u8 get_clock_ricoh(struct rtc_ricoh_data *data, int addr, struct tm *ct) +{ + uae_u8 v = 0; + int bank = data->clock_control_d & 3; + + /* memory access */ + if (bank >= 2 && addr < 0x0d) + return (data->rtc_memory[addr] >> ((bank == 2) ? 0 : 4)) & 0x0f; + /* alarm */ + if (bank == 1 && addr < 0x0d) { + v = data->rtc_alarm[addr]; +#if CLOCK_DEBUG + write_log (_T("CLOCK ALARM R %X: %X\n"), addr, v); +#endif + return v; + } + if (!ct) { + time_t t = time (0); + t += currprefs.cs_rtc_adjust; + ct = localtime (&t); + } + switch (addr) + { + case 0x0: v = ct->tm_sec % 10; break; + case 0x1: v = ct->tm_sec / 10; break; + case 0x2: v = ct->tm_min % 10; break; + case 0x3: v = ct->tm_min / 10; break; + case 0x4: v = ct->tm_hour % 10; break; + case 0x5: + if (data->rtc_alarm[10] & 1) + v = ct->tm_hour / 10; // 24h + else + v = ((ct->tm_hour % 12) / 10) | (ct->tm_hour >= 12 ? 2 : 0); // 12h + break; + case 0x6: v = ct->tm_wday; break; + case 0x7: v = ct->tm_mday % 10; break; + case 0x8: v = ct->tm_mday / 10; break; + case 0x9: v = (ct->tm_mon + 1) % 10; break; + case 0xA: v = (ct->tm_mon + 1) / 10; break; + case 0xB: v = (ct->tm_year % 100) % 10; break; + case 0xC: v = (ct->tm_year % 100) / 10; break; + case 0xD: v = data->clock_control_d; break; + /* E and F = write-only, reads as zero */ + case 0xE: v = 0; break; + case 0xF: v = 0; break; + } + return v; +} + +void put_clock_ricoh(struct rtc_ricoh_data *data, int addr, uae_u8 v) +{ + int bank = data->clock_control_d & 3; + /* memory access */ + if (bank >= 2 && addr < 0x0d) { + uae_u8 ov = data->rtc_memory[addr]; + data->rtc_memory[addr] &= ((bank == 2) ? 0xf0 : 0x0f); + data->rtc_memory[addr] |= v << ((bank == 2) ? 0 : 4); + if (data->rtc_memory[addr] != ov) + data->delayed_write = -1; + return; + } + /* alarm */ + if (bank == 1 && addr < 0x0d) { +#if CLOCK_DEBUG + write_log (_T("CLOCK ALARM W %X: %X\n"), addr, value); +#endif + uae_u8 ov = data->rtc_alarm[addr]; + data->rtc_alarm[addr] = v; + data->rtc_alarm[0] = data->rtc_alarm[1] = data->rtc_alarm[9] = data->rtc_alarm[12] = 0; + data->rtc_alarm[3] &= ~0x8; + data->rtc_alarm[5] &= ~0xc; + data->rtc_alarm[6] &= ~0x8; + data->rtc_alarm[8] &= ~0xc; + data->rtc_alarm[10] &= ~0xe; + data->rtc_alarm[11] &= ~0xc; + if (data->rtc_alarm[addr] != ov) + data->delayed_write = -1; + return; + } +#if CLOCK_DEBUG + write_log (_T("CLOCK W %X: %X\n"), addr, value); +#endif + switch (addr) + { + case 0xD: data->clock_control_d = v; break; + case 0xE: data->clock_control_e = v; break; + case 0xF: data->clock_control_f = v; break; + } +} -- 2.47.3