RTC changes :
- Replace linux-time.c and win-time.c with universal rtc.c code - Add RTC binary and 12-hour modes, century register, and alarm support - Cleaned up nvr.c a bit - Fix handling of update ended flag - Add ability to disable host clock synchronisation Changes from Battler and Mahod.
This commit is contained in:
parent
9f4b159121
commit
074de51639
14 changed files with 561 additions and 135 deletions
|
|
@ -21,8 +21,8 @@ codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing
|
||||||
dac.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \
|
dac.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \
|
||||||
headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c joystick_standard.c joystick_sw_pad.c \
|
headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c joystick_standard.c joystick_sw_pad.c \
|
||||||
keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \
|
keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \
|
||||||
linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c \
|
lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c \
|
||||||
olivetti_m24.c opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c scat.c serial.c sis496.c sound.c \
|
opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c rtc.c scat.c serial.c sis496.c sound.c \
|
||||||
sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \
|
sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \
|
||||||
sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \
|
sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \
|
||||||
sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c thread-pthread.c \
|
sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c thread-pthread.c \
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
|
||||||
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o headland.o i430lx.o i430fx.o \
|
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o headland.o i430lx.o i430fx.o \
|
||||||
i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_standard.o joystick_sw_pad.o keyboard.o keyboard_amstrad.o keyboard_at.o \
|
i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_standard.o joystick_sw_pad.o keyboard.o keyboard_amstrad.o keyboard_at.o \
|
||||||
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
|
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
|
||||||
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \
|
||||||
scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
|
scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
|
||||||
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \
|
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \
|
||||||
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
|
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
|
||||||
|
|
@ -20,7 +20,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
|
||||||
vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \
|
vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \
|
||||||
vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
||||||
win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \
|
win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \
|
||||||
win-status.o win-time.o win-video.o x86seg.o x87.o xtide.o pc.res
|
win-status.o win-video.o x86seg.o x87.o xtide.o pc.res
|
||||||
DBOBJ = dbopl.o vid_cga_comp.o
|
DBOBJ = dbopl.o vid_cga_comp.o
|
||||||
SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o
|
SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
|
||||||
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o headland.o i430lx.o i430fx.o \
|
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o headland.o i430lx.o i430fx.o \
|
||||||
i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_standard.o joystick_sw_pad.o keyboard.o keyboard_amstrad.o keyboard_at.o \
|
i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_standard.o joystick_sw_pad.o keyboard.o keyboard_amstrad.o keyboard_at.o \
|
||||||
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
|
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
|
||||||
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \
|
||||||
scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
|
scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
|
||||||
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \
|
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \
|
||||||
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \
|
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \
|
||||||
|
|
@ -20,7 +20,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
|
||||||
vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \
|
vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \
|
||||||
vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
vid_vga.o vid_voodoo.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
||||||
win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \
|
win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \
|
||||||
win-status.o win-time.o win-video.o x86seg.o x87.o xtide.o pc.res
|
win-status.o win-video.o x86seg.o x87.o xtide.o pc.res
|
||||||
DBOBJ = dbopl.o vid_cga_comp.o
|
DBOBJ = dbopl.o vid_cga_comp.o
|
||||||
SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o
|
SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
#include <sys/time.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "ibm.h"
|
|
||||||
#include "nvr.h"
|
|
||||||
|
|
||||||
void time_get(char *nvrram)
|
|
||||||
{
|
|
||||||
int c,d;
|
|
||||||
uint8_t baknvr[10];
|
|
||||||
time_t cur_time;
|
|
||||||
struct tm cur_time_tm;
|
|
||||||
|
|
||||||
memcpy(baknvr,nvrram,10);
|
|
||||||
|
|
||||||
cur_time = time(NULL);
|
|
||||||
localtime_r(&cur_time, &cur_time_tm);
|
|
||||||
|
|
||||||
d = cur_time_tm.tm_sec % 10;
|
|
||||||
c = cur_time_tm.tm_sec / 10;
|
|
||||||
nvrram[0] = d | (c << 4);
|
|
||||||
d = cur_time_tm.tm_min % 10;
|
|
||||||
c = cur_time_tm.tm_min / 10;
|
|
||||||
nvrram[2] = d | (c << 4);
|
|
||||||
d = cur_time_tm.tm_hour % 10;
|
|
||||||
c = cur_time_tm.tm_hour / 10;
|
|
||||||
nvrram[4] = d | (c << 4);
|
|
||||||
d = cur_time_tm.tm_wday % 10;
|
|
||||||
c = cur_time_tm.tm_wday / 10;
|
|
||||||
nvrram[6] = d | (c << 4);
|
|
||||||
d = cur_time_tm.tm_mday % 10;
|
|
||||||
c = cur_time_tm.tm_mday / 10;
|
|
||||||
nvrram[7] = d | (c << 4);
|
|
||||||
d = cur_time_tm.tm_mon % 10;
|
|
||||||
c = cur_time_tm.tm_mon / 10;
|
|
||||||
nvrram[8] = d | (c << 4);
|
|
||||||
d = cur_time_tm.tm_year % 10;
|
|
||||||
c = (cur_time_tm.tm_year / 10) % 10;
|
|
||||||
nvrram[9] = d | (c << 4);
|
|
||||||
if (baknvr[0] != nvrram[0] ||
|
|
||||||
baknvr[2] != nvrram[2] ||
|
|
||||||
baknvr[4] != nvrram[4] ||
|
|
||||||
baknvr[6] != nvrram[6] ||
|
|
||||||
baknvr[7] != nvrram[7] ||
|
|
||||||
baknvr[8] != nvrram[8] ||
|
|
||||||
baknvr[9] != nvrram[9])
|
|
||||||
nvrram[0xA] |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
146
src/nvr.c
146
src/nvr.c
|
|
@ -4,6 +4,7 @@
|
||||||
#include "nvr.h"
|
#include "nvr.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "rtc.h"
|
||||||
|
|
||||||
int oldromset;
|
int oldromset;
|
||||||
int nvrmask=63;
|
int nvrmask=63;
|
||||||
|
|
@ -23,7 +24,7 @@ void nvr_recalc()
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int newrtctime;
|
int newrtctime;
|
||||||
c=1<<((nvrram[0xA]&0xF)-1);
|
c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
|
||||||
newrtctime=(int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
newrtctime=(int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
||||||
if (rtctime>newrtctime) rtctime=newrtctime;
|
if (rtctime>newrtctime) rtctime=newrtctime;
|
||||||
}
|
}
|
||||||
|
|
@ -31,64 +32,136 @@ void nvr_recalc()
|
||||||
void nvr_rtc(void *p)
|
void nvr_rtc(void *p)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
if (!(nvrram[0xA]&0xF))
|
if (!(nvrram[RTC_REGA] & RTC_RS))
|
||||||
{
|
{
|
||||||
rtctime=0x7fffffff;
|
rtctime=0x7fffffff;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
c=1<<((nvrram[0xA]&0xF)-1);
|
c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
|
||||||
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
||||||
// pclog("RTCtime now %f\n",rtctime);
|
// pclog("RTCtime now %f\n",rtctime);
|
||||||
nvrram[0xC] |= 0x40;
|
nvrram[RTC_REGC] |= RTC_PF;
|
||||||
if (nvrram[0xB]&0x40)
|
if (nvrram[RTC_REGB] & RTC_PIE)
|
||||||
{
|
{
|
||||||
nvrram[0xC]|=0x80;
|
nvrram[RTC_REGC] |= RTC_IRQF;
|
||||||
if (AMSTRAD) picint(2);
|
if (AMSTRAD) picint(2);
|
||||||
else picint(0x100);
|
else picint(0x100);
|
||||||
// pclog("RTC int\n");
|
// pclog("RTC int\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nvr_update_status = 0;
|
||||||
|
|
||||||
|
#define ALARM_DONTCARE 0xc0
|
||||||
|
|
||||||
|
int nvr_check_alarm(int nvraddr)
|
||||||
|
{
|
||||||
|
return (nvrram[nvraddr + 1] == nvrram[nvraddr] || (nvrram[nvraddr + 1] & ALARM_DONTCARE) == ALARM_DONTCARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvr_update_end_count = 0;
|
||||||
|
|
||||||
|
void nvr_update_end(void *p)
|
||||||
|
{
|
||||||
|
if (!(nvrram[RTC_REGB] & RTC_SET))
|
||||||
|
{
|
||||||
|
getnvrtime();
|
||||||
|
/* Clear update status. */
|
||||||
|
nvr_update_status = 0;
|
||||||
|
|
||||||
|
if (nvr_check_alarm(RTC_SECONDS) && nvr_check_alarm(RTC_MINUTES) && nvr_check_alarm(RTC_HOURS))
|
||||||
|
{
|
||||||
|
nvrram[RTC_REGC] |= RTC_AF;
|
||||||
|
if (nvrram[RTC_REGB] & RTC_AIE)
|
||||||
|
{
|
||||||
|
nvrram[RTC_REGC] |= RTC_IRQF;
|
||||||
|
if (AMSTRAD) picint(2);
|
||||||
|
else picint(0x100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The flag and interrupt should be issued on update ended, not started. */
|
||||||
|
nvrram[RTC_REGC] |= RTC_UF;
|
||||||
|
if (nvrram[RTC_REGB] & RTC_UIE)
|
||||||
|
{
|
||||||
|
nvrram[RTC_REGC] |= RTC_IRQF;
|
||||||
|
if (AMSTRAD) picint(2);
|
||||||
|
else picint(0x100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pclog("RTC onesec\n");
|
||||||
|
|
||||||
|
nvr_update_end_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void nvr_onesec(void *p)
|
void nvr_onesec(void *p)
|
||||||
{
|
{
|
||||||
nvr_onesec_cnt++;
|
nvr_onesec_cnt++;
|
||||||
if (nvr_onesec_cnt >= 100)
|
if (nvr_onesec_cnt >= 100)
|
||||||
{
|
{
|
||||||
nvr_onesec_cnt = 0;
|
if (!(nvrram[RTC_REGB] & RTC_SET))
|
||||||
nvrram[0xC] |= 0x10;
|
|
||||||
if (nvrram[0xB] & 0x10)
|
|
||||||
{
|
{
|
||||||
nvrram[0xC] |= 0x80;
|
nvr_update_status = RTC_UIP;
|
||||||
if (AMSTRAD) picint(2);
|
/* If sync is disabled, move internal clock ahead by 1 second. */
|
||||||
else picint(0x100);
|
if (!enable_sync)
|
||||||
|
rtc_tick();
|
||||||
|
|
||||||
|
nvr_update_end_count = (int)((244.0 + 1984.0) * TIMER_USEC);
|
||||||
}
|
}
|
||||||
// pclog("RTC onesec\n");
|
|
||||||
}
|
}
|
||||||
nvr_onesec_time += (int)(10000 * TIMER_USEC);
|
nvr_onesec_time += (int)(10000 * TIMER_USEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writenvr(uint16_t addr, uint8_t val, void *priv)
|
void writenvr(uint16_t addr, uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
int c;
|
int c, old;
|
||||||
// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins);
|
// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins);
|
||||||
if (addr&1)
|
if (addr&1)
|
||||||
{
|
{
|
||||||
|
if (nvraddr==RTC_REGC || nvraddr==RTC_REGD)
|
||||||
|
return; /* Registers C and D are read-only. There's no reason to continue. */
|
||||||
// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins);
|
// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins);
|
||||||
if (nvraddr >= 0xe && nvrram[nvraddr] != val)
|
if (nvraddr > RTC_REGD && nvrram[nvraddr] != val)
|
||||||
nvr_dosave = 1;
|
nvr_dosave = 1;
|
||||||
if (nvraddr!=0xC && nvraddr!=0xD) nvrram[nvraddr]=val;
|
|
||||||
|
|
||||||
if (nvraddr==0xA)
|
old = nvrram[nvraddr];
|
||||||
|
nvrram[nvraddr]=val;
|
||||||
|
|
||||||
|
if (nvraddr == RTC_REGA)
|
||||||
{
|
{
|
||||||
// pclog("NVR rate %i\n",val&0xF);
|
// pclog("NVR rate %i\n",val&0xF);
|
||||||
if (val&0xF)
|
if (val & RTC_RS)
|
||||||
{
|
{
|
||||||
c=1<<((val&0xF)-1);
|
c = 1 << ((val & RTC_RS) - 1);
|
||||||
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rtctime = 0x7fffffff;
|
rtctime = 0x7fffffff;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nvraddr == RTC_REGB)
|
||||||
|
{
|
||||||
|
if (((old ^ val) & RTC_SET) && (val & RTC_SET))
|
||||||
|
{
|
||||||
|
nvrram[RTC_REGA] &= ~RTC_UIP; /* This has to be done according to the datasheet. */
|
||||||
|
nvrram[RTC_REGB] &= ~RTC_UIE; /* This also has to happen per the specification. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nvraddr < RTC_REGA) || (nvraddr == RTC_CENTURY))
|
||||||
|
{
|
||||||
|
if ((nvraddr != 1) && (nvraddr != 3) && (nvraddr != 5))
|
||||||
|
{
|
||||||
|
if ((old != val) && !enable_sync)
|
||||||
|
{
|
||||||
|
time_update(nvrram, nvraddr);
|
||||||
|
nvr_dosave = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else nvraddr=val&nvrmask;
|
else nvraddr=val&nvrmask;
|
||||||
}
|
}
|
||||||
|
|
@ -99,20 +172,16 @@ uint8_t readnvr(uint16_t addr, void *priv)
|
||||||
// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc);
|
// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc);
|
||||||
if (addr&1)
|
if (addr&1)
|
||||||
{
|
{
|
||||||
if (nvraddr<=0xA) getnvrtime();
|
if (nvraddr == RTC_REGA)
|
||||||
if (nvraddr==0xD) nvrram[0xD]|=0x80;
|
return ((nvrram[RTC_REGA] & 0x7F) | nvr_update_status);
|
||||||
if (nvraddr==0xA)
|
if (nvraddr == RTC_REGD)
|
||||||
{
|
nvrram[RTC_REGD] |= RTC_VRT;
|
||||||
temp=nvrram[0xA];
|
if (nvraddr == RTC_REGC)
|
||||||
nvrram[0xA]&=~0x80;
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
if (nvraddr==0xC)
|
|
||||||
{
|
{
|
||||||
if (AMSTRAD) picintc(2);
|
if (AMSTRAD) picintc(2);
|
||||||
else picintc(0x100);
|
else picintc(0x100);
|
||||||
temp=nvrram[0xC];
|
temp = nvrram[RTC_REGC];
|
||||||
nvrram[0xC]=0;
|
nvrram[RTC_REGC] = 0;
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
// if (AMIBIOS && nvraddr==0x36) return 0;
|
// if (AMIBIOS && nvraddr==0x36) return 0;
|
||||||
|
|
@ -161,13 +230,22 @@ void loadnvr()
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
memset(nvrram,0xFF,128);
|
memset(nvrram,0xFF,128);
|
||||||
|
if (!enable_sync)
|
||||||
|
{
|
||||||
|
nvrram[RTC_SECONDS] = nvrram[RTC_MINUTES] = nvrram[RTC_HOURS] = 0;
|
||||||
|
nvrram[RTC_DOM] = nvrram[RTC_MONTH] = 1;
|
||||||
|
nvrram[RTC_YEAR] = BCD(80);
|
||||||
|
nvrram[RTC_CENTURY] = BCD(19);
|
||||||
|
nvrram[RTC_REGB] = RTC_2412;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fread(nvrram,128,1,f);
|
fread(nvrram,128,1,f);
|
||||||
|
if (!enable_sync) time_update(nvrram, 0xFF); /* Update the internal clock state based on the NVR registers. */
|
||||||
fclose(f);
|
fclose(f);
|
||||||
nvrram[0xA]=6;
|
nvrram[RTC_REGA] = 6;
|
||||||
nvrram[0xB]=0;
|
nvrram[RTC_REGB] = RTC_2412;
|
||||||
c=1<<((6&0xF)-1);
|
c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1);
|
||||||
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
||||||
}
|
}
|
||||||
void savenvr()
|
void savenvr()
|
||||||
|
|
@ -212,4 +290,6 @@ void nvr_init()
|
||||||
io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL, NULL);
|
io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL, NULL);
|
||||||
timer_add(nvr_rtc, &rtctime, TIMER_ALWAYS_ENABLED, NULL);
|
timer_add(nvr_rtc, &rtctime, TIMER_ALWAYS_ENABLED, NULL);
|
||||||
timer_add(nvr_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL);
|
timer_add(nvr_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL);
|
||||||
|
timer_add(nvr_update_end, &nvr_update_end_count, &nvr_update_end_count, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
void nvr_init();
|
void nvr_init();
|
||||||
|
|
||||||
|
extern int enable_sync;
|
||||||
|
|
||||||
extern int nvr_dosave;
|
extern int nvr_dosave;
|
||||||
|
|
||||||
void time_get(char *nvrram);
|
void time_get(char *nvrram);
|
||||||
|
|
|
||||||
5
src/pc.c
5
src/pc.c
|
|
@ -97,6 +97,7 @@ void fatal(const char *format, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
fputs(buf,pclogf);
|
fputs(buf,pclogf);
|
||||||
fflush(pclogf);
|
fflush(pclogf);
|
||||||
|
savenvr();
|
||||||
dumppic();
|
dumppic();
|
||||||
dumpregs();
|
dumpregs();
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
@ -679,6 +680,8 @@ void loadconfig(char *fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enable_sync = config_get_int(NULL, "enable_sync", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveconfig()
|
void saveconfig()
|
||||||
|
|
@ -764,6 +767,8 @@ void saveconfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config_set_int(NULL, "enable_sync", enable_sync);
|
||||||
|
|
||||||
config_save(config_file_default);
|
config_save(config_file_default);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/pc.rc
11
src/pc.rc
|
|
@ -57,13 +57,13 @@ BEGIN
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
|
|
||||||
ConfigureDlg DIALOGEX 0, 0, 232+40, 292+40+40
|
ConfigureDlg DIALOGEX 0, 0, 232+40, 308+40+40
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
CAPTION "Configure PCem"
|
CAPTION "Configure PCem"
|
||||||
FONT 8, "MS Sans Serif"
|
FONT 8, "MS Sans Serif"
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "OK",IDOK,64,308+40,50,14, WS_TABSTOP
|
DEFPUSHBUTTON "OK",IDOK,64,324+40,50,14, WS_TABSTOP
|
||||||
PUSHBUTTON "Cancel",IDCANCEL,128,308+40,50,14, WS_TABSTOP
|
PUSHBUTTON "Cancel",IDCANCEL,128,324+40,50,14, WS_TABSTOP
|
||||||
COMBOBOX IDC_COMBO1,62,16,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
|
COMBOBOX IDC_COMBO1,62,16,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
|
||||||
COMBOBOX IDC_COMBOVID,62,36,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
|
COMBOBOX IDC_COMBOVID,62,36,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
|
||||||
PUSHBUTTON "Configure", IDC_CONFIGUREVID, 224, 36, 40, 14, WS_TABSTOP
|
PUSHBUTTON "Configure", IDC_CONFIGUREVID, 224, 36, 40, 14, WS_TABSTOP
|
||||||
|
|
@ -81,8 +81,9 @@ BEGIN
|
||||||
CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,288,118,10
|
CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,288,118,10
|
||||||
CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,304,118,10
|
CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,304,118,10
|
||||||
CONTROL "Composite CGA",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,320,118,10
|
CONTROL "Composite CGA",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,320,118,10
|
||||||
CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,336,118,10
|
CONTROL "Synchronise time to host clock",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,336,118,10
|
||||||
PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 336, 40, 14, WS_TABSTOP
|
CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,352,118,10
|
||||||
|
PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 352, 40, 14, WS_TABSTOP
|
||||||
LTEXT "Machine :",IDC_STATIC,15,16,40,10
|
LTEXT "Machine :",IDC_STATIC,15,16,40,10
|
||||||
LTEXT "Video :",IDC_STATIC,15,36,34,10
|
LTEXT "Video :",IDC_STATIC,15,36,34,10
|
||||||
LTEXT "CPU type :",IDC_STATIC,15,56,34,10
|
LTEXT "CPU type :",IDC_STATIC,15,56,34,10
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
#define IDC_CHECKSSI 1015
|
#define IDC_CHECKSSI 1015
|
||||||
#define IDC_CHECKVOODOO 1016
|
#define IDC_CHECKVOODOO 1016
|
||||||
#define IDC_CHECKDYNAREC 1017
|
#define IDC_CHECKDYNAREC 1017
|
||||||
|
#define IDC_CHECKSYNC 1018
|
||||||
#define IDC_STATIC 1020
|
#define IDC_STATIC 1020
|
||||||
#define IDC_EDIT1 1030
|
#define IDC_EDIT1 1030
|
||||||
#define IDC_EDIT2 1031
|
#define IDC_EDIT2 1031
|
||||||
|
|
|
||||||
244
src/rtc.c
Normal file
244
src/rtc.c
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
/* Emulation of:
|
||||||
|
Dallas Semiconductor DS12C887 Real Time Clock
|
||||||
|
|
||||||
|
http://datasheets.maximintegrated.com/en/ds/DS12885-DS12C887A.pdf
|
||||||
|
|
||||||
|
http://dev-docs.atariforge.org/files/MC146818A_RTC_1984.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "nvr.h"
|
||||||
|
#include "rtc.h"
|
||||||
|
|
||||||
|
int enable_sync;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int sec;
|
||||||
|
int min;
|
||||||
|
int hour;
|
||||||
|
int mday;
|
||||||
|
int mon;
|
||||||
|
int year;
|
||||||
|
} internal_clock;
|
||||||
|
|
||||||
|
/* When the RTC was last updated */
|
||||||
|
static time_t rtc_set_time = 0;
|
||||||
|
|
||||||
|
/* Table for days in each month */
|
||||||
|
static int rtc_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
/* Called to determine whether the year is leap or not */
|
||||||
|
static int rtc_is_leap(int org_year)
|
||||||
|
{
|
||||||
|
if (org_year % 400 == 0) return 1;
|
||||||
|
if (org_year % 100 == 0) return 0;
|
||||||
|
if (org_year % 4 == 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called to determine the days in the current month */
|
||||||
|
static int rtc_get_days(int org_month, int org_year)
|
||||||
|
{
|
||||||
|
if (org_month != 2)
|
||||||
|
return rtc_days_in_month[org_month];
|
||||||
|
else
|
||||||
|
return rtc_is_leap(org_year) ? 29 : 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the internal clock gets updated */
|
||||||
|
static void rtc_recalc()
|
||||||
|
{
|
||||||
|
if (internal_clock.sec == 60)
|
||||||
|
{
|
||||||
|
internal_clock.sec = 0;
|
||||||
|
internal_clock.min++;
|
||||||
|
}
|
||||||
|
if (internal_clock.min == 60)
|
||||||
|
{
|
||||||
|
internal_clock.min = 0;
|
||||||
|
internal_clock.hour++;
|
||||||
|
}
|
||||||
|
if (internal_clock.hour == 24)
|
||||||
|
{
|
||||||
|
internal_clock.hour = 0;
|
||||||
|
internal_clock.mday++;
|
||||||
|
}
|
||||||
|
if (internal_clock.mday == (rtc_get_days(internal_clock.mon, internal_clock.year) + 1))
|
||||||
|
{
|
||||||
|
internal_clock.mday = 1;
|
||||||
|
internal_clock.mon++;
|
||||||
|
}
|
||||||
|
if (internal_clock.mon == 13)
|
||||||
|
{
|
||||||
|
internal_clock.mon = 1;
|
||||||
|
internal_clock.year++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when ticking the second */
|
||||||
|
void rtc_tick()
|
||||||
|
{
|
||||||
|
internal_clock.sec++;
|
||||||
|
rtc_recalc();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when modifying the NVR registers */
|
||||||
|
void time_update(char *nvrram, int reg)
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
switch(reg)
|
||||||
|
{
|
||||||
|
case RTC_SECONDS:
|
||||||
|
internal_clock.sec = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_SECONDS] : DCB(nvrram[RTC_SECONDS]);
|
||||||
|
break;
|
||||||
|
case RTC_MINUTES:
|
||||||
|
internal_clock.min = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MINUTES] : DCB(nvrram[RTC_MINUTES]);
|
||||||
|
break;
|
||||||
|
case RTC_HOURS:
|
||||||
|
temp = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_HOURS] : DCB(nvrram[RTC_HOURS]);
|
||||||
|
|
||||||
|
if (nvrram[RTC_REGB] & RTC_2412)
|
||||||
|
internal_clock.hour = temp;
|
||||||
|
else
|
||||||
|
internal_clock.hour = ((temp & ~RTC_AMPM) % 12) + ((temp & RTC_AMPM) ? 12 : 0);
|
||||||
|
break;
|
||||||
|
case RTC_DOM:
|
||||||
|
internal_clock.mday = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_DOM] : DCB(nvrram[RTC_DOM]);
|
||||||
|
break;
|
||||||
|
case RTC_MONTH:
|
||||||
|
internal_clock.mon = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MONTH] : DCB(nvrram[RTC_MONTH]);
|
||||||
|
break;
|
||||||
|
case RTC_YEAR:
|
||||||
|
internal_clock.year = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_YEAR] : DCB(nvrram[RTC_YEAR]);
|
||||||
|
internal_clock.year += (nvrram[RTC_REGB] & RTC_DM) ? 1900 : (DCB(nvrram[RTC_CENTURY]) * 100);
|
||||||
|
break;
|
||||||
|
case RTC_CENTURY:
|
||||||
|
if (nvrram[RTC_REGB] & RTC_DM)
|
||||||
|
return;
|
||||||
|
internal_clock.year %= 100;
|
||||||
|
internal_clock.year += (DCB(nvrram[RTC_CENTURY]) * 100);
|
||||||
|
break;
|
||||||
|
case 0xFF: /* Load the entire internal clock state from the NVR. */
|
||||||
|
internal_clock.sec = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_SECONDS] : DCB(nvrram[RTC_SECONDS]);
|
||||||
|
internal_clock.min = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MINUTES] : DCB(nvrram[RTC_MINUTES]);
|
||||||
|
|
||||||
|
temp = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_HOURS] : DCB(nvrram[RTC_HOURS]);
|
||||||
|
|
||||||
|
if (nvrram[RTC_REGB] & RTC_2412)
|
||||||
|
internal_clock.hour = temp;
|
||||||
|
else
|
||||||
|
internal_clock.hour = ((temp & ~RTC_AMPM) % 12) + ((temp & RTC_AMPM) ? 12 : 0);
|
||||||
|
|
||||||
|
internal_clock.mday = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_DOM] : DCB(nvrram[RTC_DOM]);
|
||||||
|
internal_clock.mon = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MONTH] : DCB(nvrram[RTC_MONTH]);
|
||||||
|
internal_clock.year = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_YEAR] : DCB(nvrram[RTC_YEAR]);
|
||||||
|
internal_clock.year += (nvrram[RTC_REGB] & RTC_DM) ? 1900 : (DCB(nvrram[RTC_CENTURY]) * 100);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called to obtain the current day of the week based on the internal clock */
|
||||||
|
static int time_week_day()
|
||||||
|
{
|
||||||
|
int day_of_month = internal_clock.mday;
|
||||||
|
int month2 = internal_clock.mon;
|
||||||
|
int year2 = internal_clock.year % 100;
|
||||||
|
int century = ((internal_clock.year - year2) / 100) % 4;
|
||||||
|
int sum = day_of_month + month2 + year2 + century;
|
||||||
|
/* (Sum mod 7) gives 0 for Saturday, we need it for Sunday, so +6 for Saturday to get 6 and Sunday 0 */
|
||||||
|
int raw_wd = ((sum + 6) % 7);
|
||||||
|
return raw_wd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called to get time into the internal clock */
|
||||||
|
static void time_internal(struct tm **time_var)
|
||||||
|
{
|
||||||
|
if (*time_var == NULL)
|
||||||
|
*time_var = (struct tm *)malloc(sizeof(struct tm));
|
||||||
|
|
||||||
|
(*time_var)->tm_sec = internal_clock.sec;
|
||||||
|
(*time_var)->tm_min = internal_clock.min;
|
||||||
|
(*time_var)->tm_hour = internal_clock.hour;
|
||||||
|
(*time_var)->tm_wday = time_week_day();
|
||||||
|
(*time_var)->tm_mday = internal_clock.mday;
|
||||||
|
(*time_var)->tm_mon = internal_clock.mon - 1;
|
||||||
|
(*time_var)->tm_year = internal_clock.year - 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_t cur_time;
|
||||||
|
static struct tm *cur_time_tm;
|
||||||
|
|
||||||
|
/* Periodic RTC update function
|
||||||
|
See also: nvr_onesec() in nvr.c
|
||||||
|
*/
|
||||||
|
void time_get(char *nvrram)
|
||||||
|
{
|
||||||
|
int dow, mon, year;
|
||||||
|
|
||||||
|
if (enable_sync)
|
||||||
|
{
|
||||||
|
time(&cur_time);
|
||||||
|
|
||||||
|
/* Mingw doesn't support localtime_r */
|
||||||
|
#if __MINGW32__
|
||||||
|
cur_time_tm = localtime(&cur_time);
|
||||||
|
#else
|
||||||
|
#if __MINGW64__
|
||||||
|
cur_time_tm = localtime(&cur_time);
|
||||||
|
#else
|
||||||
|
localtime_r(&cur_time, &cur_time_tm);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_internal(&cur_time_tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nvrram[RTC_REGB] & RTC_DM)
|
||||||
|
{
|
||||||
|
nvrram[RTC_SECONDS] = cur_time_tm->tm_sec;
|
||||||
|
nvrram[RTC_MINUTES] = cur_time_tm->tm_min;
|
||||||
|
nvrram[RTC_DOW] = cur_time_tm->tm_wday + 1;
|
||||||
|
nvrram[RTC_DOM] = cur_time_tm->tm_mday;
|
||||||
|
nvrram[RTC_MONTH] = cur_time_tm->tm_mon + 1;
|
||||||
|
nvrram[RTC_YEAR] = cur_time_tm->tm_year % 100;
|
||||||
|
|
||||||
|
if (nvrram[RTC_REGB] & RTC_2412)
|
||||||
|
{
|
||||||
|
nvrram[RTC_HOURS] = cur_time_tm->tm_hour;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[RTC_HOURS] = (cur_time_tm->tm_hour % 12) ? (cur_time_tm->tm_hour % 12) : 12;
|
||||||
|
if (cur_time_tm->tm_hour > 11)
|
||||||
|
nvrram[RTC_HOURS] |= RTC_AMPM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[RTC_SECONDS] = BCD(cur_time_tm->tm_sec);
|
||||||
|
nvrram[RTC_MINUTES] = BCD(cur_time_tm->tm_min);
|
||||||
|
nvrram[RTC_DOW] = BCD(cur_time_tm->tm_wday + 1);
|
||||||
|
nvrram[RTC_DOM] = BCD(cur_time_tm->tm_mday);
|
||||||
|
nvrram[RTC_MONTH] = BCD(cur_time_tm->tm_mon + 1);
|
||||||
|
nvrram[RTC_YEAR] = BCD(cur_time_tm->tm_year % 100);
|
||||||
|
|
||||||
|
if (nvrram[RTC_REGB] & RTC_2412)
|
||||||
|
{
|
||||||
|
nvrram[RTC_HOURS] = BCD(cur_time_tm->tm_hour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[RTC_HOURS] = (cur_time_tm->tm_hour % 12) ? BCD(cur_time_tm->tm_hour % 12) : BCD(12);
|
||||||
|
if (cur_time_tm->tm_hour > 11)
|
||||||
|
nvrram[RTC_HOURS] |= RTC_AMPM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
172
src/rtc.h
Normal file
172
src/rtc.h
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
#define BCD(X) (((X) % 10) | (((X) / 10) << 4))
|
||||||
|
#define DCB(X) ((((X) & 0xF0) >> 4) * 10 + ((X) & 0x0F))
|
||||||
|
|
||||||
|
enum RTC_ADDR
|
||||||
|
{
|
||||||
|
RTC_SECONDS,
|
||||||
|
RTC_ALARMSECONDS,
|
||||||
|
RTC_MINUTES,
|
||||||
|
RTC_ALARMMINUTES,
|
||||||
|
RTC_HOURS,
|
||||||
|
RTC_ALARMHOURS,
|
||||||
|
RTC_DOW,
|
||||||
|
RTC_DOM,
|
||||||
|
RTC_MONTH,
|
||||||
|
RTC_YEAR,
|
||||||
|
RTC_REGA,
|
||||||
|
RTC_REGB,
|
||||||
|
RTC_REGC,
|
||||||
|
RTC_REGD
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The century register at location 32h is a BCD register designed to automatically load the BCD value 20 as the year register changes from 99 to 00.
|
||||||
|
The MSB of this register is not affected when the load of 20 occurs, and remains at the value written by the user. */
|
||||||
|
#define RTC_CENTURY 0x32
|
||||||
|
|
||||||
|
/* When the 12-hour format is selected, the higher-order bit of the hours byte represents PM when it is logic 1. */
|
||||||
|
#define RTC_AMPM 0b10000000
|
||||||
|
|
||||||
|
/* Register A bitflags */
|
||||||
|
enum RTC_RA_BITS
|
||||||
|
{
|
||||||
|
/* Rate Selector (RS0)
|
||||||
|
|
||||||
|
These four rate-selection bits select one of the 13 taps on the 15-stage divider or disable the divider output.
|
||||||
|
The tap selected can be used to generate an output square wave (SQW pin) and/or a periodic interrupt.
|
||||||
|
The user can do one of the following:
|
||||||
|
- Enable the interrupt with the PIE bit;
|
||||||
|
- Enable the SQW output pin with the SQWE bit;
|
||||||
|
- Enable both at the same time and the same rate; or
|
||||||
|
- Enable neither.
|
||||||
|
|
||||||
|
Table 3 lists the periodic interrupt rates and the square wave frequencies that can be chosen with the RS bits.
|
||||||
|
These four read/write bits are not affected by !RESET. */
|
||||||
|
RTC_RS = 0b1111,
|
||||||
|
/* DV0
|
||||||
|
|
||||||
|
These three bits are used to turn the oscillator on or off and to reset the countdown chain.
|
||||||
|
A pattern of 010 is the only combination of bits that turn the oscillator on and allow the RTC to keep time.
|
||||||
|
A pattern of 11x enables the oscillator but holds the countdown chain in reset.
|
||||||
|
The next update occurs at 500ms after a pattern of 010 is written to DV0, DV1, and DV2. */
|
||||||
|
RTC_DV0 = 0b1110000,
|
||||||
|
/* Update-In-Progress (UIP)
|
||||||
|
|
||||||
|
This bit is a status flag that can be monitored. When the UIP bit is a 1, the update transfer occurs soon.
|
||||||
|
When UIP is a 0, the update transfer does not occur for at least 244us.
|
||||||
|
The time, calendar, and alarm information in RAM is fully available for access when the UIP bit is 0.
|
||||||
|
The UIP bit is read-only and is not affected by !RESET.
|
||||||
|
Writing the SET bit in Register B to a 1 inhibits any update transfer and clears the UIP status bit. */
|
||||||
|
RTC_UIP = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register B bitflags */
|
||||||
|
enum RTC_RB_BITS
|
||||||
|
{
|
||||||
|
/* Daylight Saving Enable (DSE)
|
||||||
|
|
||||||
|
This bit is a read/write bit that enables two daylight saving adjustments when DSE is set to 1.
|
||||||
|
On the first Sunday in April (or the last Sunday in April in the MC146818A), the time increments from 1:59:59 AM to 3:00:00 AM.
|
||||||
|
On the last Sunday in October when the time first reaches 1:59:59 AM, it changes to 1:00:00 AM.
|
||||||
|
When DSE is enabled, the internal logic test for the first/last Sunday condition at midnight.
|
||||||
|
If the DSE bit is not set when the test occurs, the daylight saving function does not operate correctly.
|
||||||
|
These adjustments do not occur when the DSE bit is 0. This bit is not affected by internal functions or !RESET. */
|
||||||
|
RTC_DSE = 0b1,
|
||||||
|
/* 24/12
|
||||||
|
|
||||||
|
The 24/12 control bit establishes the format of the hours byte. A 1 indicates the 24-hour mode and a 0 indicates the 12-hour mode.
|
||||||
|
This bit is read/write and is not affected by internal functions or !RESET. */
|
||||||
|
RTC_2412 = 0b10,
|
||||||
|
/* Data Mode (DM)
|
||||||
|
|
||||||
|
This bit indicates whether time and calendar information is in binary or BCD format.
|
||||||
|
The DM bit is set by the program to the appropriate format and can be read as required.
|
||||||
|
This bit is not modified by internal functions or !RESET. A 1 in DM signifies binary data, while a 0 in DM specifies BCD data. */
|
||||||
|
RTC_DM = 0b100,
|
||||||
|
/* Square-Wave Enable (SQWE)
|
||||||
|
|
||||||
|
When this bit is set to 1, a square-wave signal at the frequency set by the rate-selection bits RS3-RS0 is driven out on the SQW pin.
|
||||||
|
When the SQWE bit is set to 0, the SQW pin is held low. SQWE is a read/write bit and is cleared by !RESET.
|
||||||
|
SQWE is low if disabled, and is high impedance when VCC is below VPF. SQWE is cleared to 0 on !RESET. */
|
||||||
|
RTC_SQWE = 0b1000,
|
||||||
|
/* Update-Ended Interrupt Enable (UIE)
|
||||||
|
|
||||||
|
This bit is a read/write bit that enables the update-end flag (UF) bit in Register C to assert !IRQ.
|
||||||
|
The !RESET pin going low or the SET bit going high clears the UIE bit.
|
||||||
|
The internal functions of the device do not affect the UIE bit, but is cleared to 0 on !RESET. */
|
||||||
|
RTC_UIE = 0b10000,
|
||||||
|
/* Alarm Interrupt Enable (AIE)
|
||||||
|
|
||||||
|
This bit is a read/write bit that, when set to 1, permits the alarm flag (AF) bit in Register C to assert !IRQ.
|
||||||
|
An alarm interrupt occurs for each second that the three time bytes equal the three alarm bytes, including a don't-care alarm code of binary 11XXXXXX.
|
||||||
|
The AF bit does not initiate the !IRQ signal when the AIE bit is set to 0.
|
||||||
|
The internal functions of the device do not affect the AIE bit, but is cleared to 0 on !RESET. */
|
||||||
|
RTC_AIE = 0b100000,
|
||||||
|
/* Periodic Interrupt Enable (PIE)
|
||||||
|
|
||||||
|
The PIE bit is a read/write bit that allows the periodic interrupt flag (PF) bit in Register C to drive the !IRQ pin low.
|
||||||
|
When the PIE bit is set to 1, periodic interrupts are generated by driving the !IRQ pin low at a rate specified by the RS3-RS0 bits of Register A.
|
||||||
|
A 0 in the PIE bit blocks the !IRQ output from being driven by a periodic interrupt, but the PF bit is still set at the periodic rate.
|
||||||
|
PIE is not modified by any internal device functions, but is cleared to 0 on !RESET. */
|
||||||
|
RTC_PIE = 0b1000000,
|
||||||
|
/* SET
|
||||||
|
|
||||||
|
When the SET bit is 0, the update transfer functions normally by advancing the counts once per second.
|
||||||
|
When the SET bit is written to 1, any update transfer is inhibited, and the program can initialize the time and calendar bytes without an update
|
||||||
|
occurring in the midst of initializing. Read cycles can be executed in a similar manner. SET is a read/write bit and is not affected by !RESET or
|
||||||
|
internal functions of the device. */
|
||||||
|
RTC_SET = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register C bitflags */
|
||||||
|
enum RTC_RC_BITS
|
||||||
|
{
|
||||||
|
/* Unused
|
||||||
|
|
||||||
|
These bits are unused in Register C. These bits always read 0 and cannot be written. */
|
||||||
|
RTC_RC = 0b1111,
|
||||||
|
/* Update-Ended Interrupt Flag (UF)
|
||||||
|
|
||||||
|
This bit is set after each update cycle. When the UIE bit is set to 1, the 1 in UF causes the IRQF bit to be a 1, which asserts the !IRQ pin.
|
||||||
|
This bit can be cleared by reading Register C or with a !RESET. */
|
||||||
|
RTC_UF = 0b10000,
|
||||||
|
/* Alarm Interrupt Flag (AF)
|
||||||
|
|
||||||
|
A 1 in the AF bit indicates that the current time has matched the alarm time.
|
||||||
|
If the AIE bit is also 1, the !IRQ pin goes low and a 1 appears in the IRQF bit. This bit can be cleared by reading Register C or with a !RESET. */
|
||||||
|
RTC_AF = 0b100000,
|
||||||
|
/* Periodic Interrupt Flag (PF)
|
||||||
|
|
||||||
|
This bit is read-only and is set to 1 when an edge is detected on the selected tap of the divider chain.
|
||||||
|
The RS3 through RS0 bits establish the periodic rate. PF is set to 1 independent of the state of the PIE bit.
|
||||||
|
When both PF and PIE are 1s, the !IRQ signal is active and sets the IRQF bit. This bit can be cleared by reading Register C or with a !RESET. */
|
||||||
|
RTC_PF = 0b1000000,
|
||||||
|
/* Interrupt Request Flag (IRQF)
|
||||||
|
|
||||||
|
The interrupt request flag (IRQF) is set to a 1 when one or more of the following are true:
|
||||||
|
- PF == PIE == 1
|
||||||
|
- AF == AIE == 1
|
||||||
|
- UF == UIE == 1
|
||||||
|
|
||||||
|
Any time the IRQF bit is a 1, the !IRQ pin is driven low.
|
||||||
|
All flag bits are cleared after Register C is read by the program or when the !RESET pin is low. */
|
||||||
|
RTC_IRQF = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register D bitflags */
|
||||||
|
enum RTC_RD_BITS
|
||||||
|
{
|
||||||
|
/* Unused
|
||||||
|
|
||||||
|
The remaining bits of Register D are not usable. They cannot be written and they always read 0. */
|
||||||
|
RTC_RD = 0b1111111,
|
||||||
|
/* Valid RAM and Time (VRT)
|
||||||
|
|
||||||
|
This bit indicates the condition of the battery connected to the VBAT pin. This bit is not writeable and should always be 1 when read.
|
||||||
|
If a 0 is ever present, an exhausted internal lithium energy source is indicated and both the contents of the RTC data and RAM data are questionable.
|
||||||
|
This bit is unaffected by !RESET. */
|
||||||
|
RTC_VRT = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
void rtc_tick();
|
||||||
|
void time_update(char *nvrram, int reg);
|
||||||
|
void time_get(char *nvrram);
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "fdd.h"
|
#include "fdd.h"
|
||||||
#include "gameport.h"
|
#include "gameport.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
#include "nvr.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
|
|
@ -142,6 +143,9 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
|
||||||
h=GetDlgItem(hdlg, IDC_CHECK4);
|
h=GetDlgItem(hdlg, IDC_CHECK4);
|
||||||
SendMessage(h, BM_SETCHECK, cga_comp, 0);
|
SendMessage(h, BM_SETCHECK, cga_comp, 0);
|
||||||
|
|
||||||
|
h=GetDlgItem(hdlg, IDC_CHECKSYNC);
|
||||||
|
SendMessage(h, BM_SETCHECK, enable_sync, 0);
|
||||||
|
|
||||||
h=GetDlgItem(hdlg, IDC_CHECKVOODOO);
|
h=GetDlgItem(hdlg, IDC_CHECKVOODOO);
|
||||||
SendMessage(h, BM_SETCHECK, voodoo_enabled, 0);
|
SendMessage(h, BM_SETCHECK, voodoo_enabled, 0);
|
||||||
|
|
||||||
|
|
@ -277,6 +281,9 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
|
||||||
h = GetDlgItem(hdlg, IDC_CHECKSSI);
|
h = GetDlgItem(hdlg, IDC_CHECKSSI);
|
||||||
temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0);
|
temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0);
|
||||||
|
|
||||||
|
h = GetDlgItem(hdlg, IDC_CHECKSYNC);
|
||||||
|
enable_sync = SendMessage(h, BM_GETCHECK, 0, 0);
|
||||||
|
|
||||||
h = GetDlgItem(hdlg, IDC_CHECKVOODOO);
|
h = GetDlgItem(hdlg, IDC_CHECKVOODOO);
|
||||||
temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0);
|
temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0);
|
||||||
|
|
||||||
|
|
@ -302,6 +309,7 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
|
||||||
{
|
{
|
||||||
if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK)
|
if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK)
|
||||||
{
|
{
|
||||||
|
savenvr();
|
||||||
model = temp_model;
|
model = temp_model;
|
||||||
romset = model_getromset();
|
romset = model_getromset();
|
||||||
gfxcard = gfx;
|
gfxcard = gfx;
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
#include <windows.h>
|
|
||||||
#include "ibm.h"
|
|
||||||
#include "nvr.h"
|
|
||||||
|
|
||||||
void time_get(char *nvrram)
|
|
||||||
{
|
|
||||||
SYSTEMTIME systemtime;
|
|
||||||
int c, d;
|
|
||||||
uint8_t baknvr[10];
|
|
||||||
|
|
||||||
memcpy(baknvr,nvrram,10);
|
|
||||||
GetLocalTime(&systemtime);
|
|
||||||
|
|
||||||
d = systemtime.wSecond % 10;
|
|
||||||
c = systemtime.wSecond / 10;
|
|
||||||
nvrram[0] = d | (c << 4);
|
|
||||||
d = systemtime.wMinute % 10;
|
|
||||||
c = systemtime.wMinute / 10;
|
|
||||||
nvrram[2] = d | (c << 4);
|
|
||||||
d = systemtime.wHour % 10;
|
|
||||||
c = systemtime.wHour / 10;
|
|
||||||
nvrram[4] = d | (c << 4);
|
|
||||||
d = systemtime.wDayOfWeek % 10;
|
|
||||||
c = systemtime.wDayOfWeek / 10;
|
|
||||||
nvrram[6] = d | (c << 4);
|
|
||||||
d = systemtime.wDay % 10;
|
|
||||||
c = systemtime.wDay / 10;
|
|
||||||
nvrram[7] = d | (c << 4);
|
|
||||||
d = systemtime.wMonth % 10;
|
|
||||||
c = systemtime.wMonth / 10;
|
|
||||||
nvrram[8] = d | (c << 4);
|
|
||||||
d = systemtime.wYear % 10;
|
|
||||||
c = (systemtime.wYear / 10) % 10;
|
|
||||||
nvrram[9] = d | (c << 4);
|
|
||||||
if (baknvr[0] != nvrram[0] ||
|
|
||||||
baknvr[2] != nvrram[2] ||
|
|
||||||
baknvr[4] != nvrram[4] ||
|
|
||||||
baknvr[6] != nvrram[6] ||
|
|
||||||
baknvr[7] != nvrram[7] ||
|
|
||||||
baknvr[8] != nvrram[8] ||
|
|
||||||
baknvr[9] != nvrram[9])
|
|
||||||
nvrram[0xA]|=0x80;
|
|
||||||
}
|
|
||||||
|
|
@ -717,6 +717,7 @@ int WINAPI WinMain (HINSTANCE hThisInstance,
|
||||||
TerminateThread(mainthreadh,0);
|
TerminateThread(mainthreadh,0);
|
||||||
// pclog("Quited? %i\n",quited);
|
// pclog("Quited? %i\n",quited);
|
||||||
// pclog("Closepc\n");
|
// pclog("Closepc\n");
|
||||||
|
savenvr();
|
||||||
if (save_window_pos && window_remember)
|
if (save_window_pos && window_remember)
|
||||||
saveconfig();
|
saveconfig();
|
||||||
closepc();
|
closepc();
|
||||||
|
|
@ -877,18 +878,21 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
|
||||||
case IDM_FILE_RESET:
|
case IDM_FILE_RESET:
|
||||||
pause=1;
|
pause=1;
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
|
savenvr();
|
||||||
resetpc();
|
resetpc();
|
||||||
pause=0;
|
pause=0;
|
||||||
break;
|
break;
|
||||||
case IDM_FILE_HRESET:
|
case IDM_FILE_HRESET:
|
||||||
pause=1;
|
pause=1;
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
|
savenvr();
|
||||||
resetpchard();
|
resetpchard();
|
||||||
pause=0;
|
pause=0;
|
||||||
break;
|
break;
|
||||||
case IDM_FILE_RESET_CAD:
|
case IDM_FILE_RESET_CAD:
|
||||||
pause=1;
|
pause=1;
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
|
savenvr();
|
||||||
resetpc_cad();
|
resetpc_cad();
|
||||||
pause=0;
|
pause=0;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue