Proper RTC emulation based on work by Mahod.
Updated README.md. Updated AMD makefile.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# PCem Experimental [](http://citadel.rol.im:8080/job/PCem-Experimental)
|
# PCem Unofficial [](http://polar.rol.im:8080/job/PCem-Unofficial)
|
||||||
PCem Experimental is an unofficial branch of the PCem emulator, which aims to emulate IBM compatible machines from 1981-2000 period. This branch adds several emulated motherboards.
|
PCem Unofficial is an unofficial branch of the PCem emulator, which aims to emulate IBM compatible machines from 1981-2000 period. This branch adds several emulated motherboards.
|
||||||
|
|
||||||
---
|
---
|
||||||
Keep in touch with the PCem Experimental community:
|
Keep in touch with the PCem Unoffical community:
|
||||||
|
|
||||||
[](https://kiwiirc.com/client/irc.rol.im/?nick=pcem|?#pcem-x)
|
[](https://kiwiirc.com/client/irc.rol.im/?nick=pcem|?#pcem-x)
|
||||||
|
@@ -8,7 +8,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429
|
|||||||
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \
|
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \
|
||||||
i430nx.o i430vx.o i440fx.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 \
|
i430nx.o i430vx.o i440fx.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 memregs.o model.o mouse.o mouse_ps2.o \
|
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \
|
||||||
mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \
|
||||||
scat.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \
|
scat.o serial.o sis496.o sis85c471.o sio.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_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_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 acerm3a.o ali1429
|
|||||||
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 w83877f.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 w83877f.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
||||||
win-ddraw-fs.o win-ddraw-screenshot.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-ddraw-screenshot.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
|
||||||
SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o
|
SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o
|
||||||
|
@@ -8,7 +8,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429
|
|||||||
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \
|
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \
|
||||||
i430nx.o i430vx.o i440fx.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 \
|
i430nx.o i430vx.o i440fx.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 memregs.o model.o mouse.o mouse_ps2.o \
|
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \
|
||||||
mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \
|
||||||
scat.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \
|
scat.o serial.o sis496.o sis85c471.o sio.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_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_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 acerm3a.o ali1429
|
|||||||
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 w83877f.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 w83877f.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
||||||
win-ddraw-fs.o win-ddraw-screenshot.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-ddraw-screenshot.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
|
||||||
SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o
|
SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o
|
||||||
|
@@ -8,28 +8,28 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429
|
|||||||
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \
|
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \
|
||||||
i430nx.o i430vx.o i440fx.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 \
|
i430nx.o i430vx.o i440fx.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 memregs.o model.o mouse.o mouse_ps2.o \
|
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \
|
||||||
mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
|
mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \
|
||||||
scat.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \
|
scat.o serial.o sis496.o sis85c471.o sio.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_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_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 \
|
||||||
soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \
|
soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \
|
||||||
vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cga_comp.o vid_cl5429.o vid_ega.o vid_et4000.o \
|
vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \
|
||||||
vid_et4000w32.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \
|
vid_et4000w32.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \
|
||||||
vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
|
vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
|
||||||
vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \
|
vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.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_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 w83877f.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 w83877f.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \
|
||||||
win-ddraw-fs.o win-ddraw-screenshot.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-ddraw-screenshot.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
|
||||||
FMOBJ = dbopl.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
|
||||||
SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o
|
SLIRPOBJ = bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o ip_input.o queue.o tcp_input.o tftp.o debug.o ip_output.o sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o
|
||||||
|
|
||||||
|
|
||||||
LIBS = -mwindows -lwinmm -lopenal.dll -lopenal -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 -lwsock32 -liphlpapi -lstdc++ -static-libstdc++ -static-libgcc -static
|
LIBS = -mwindows -lwinmm -lopenal.dll -lopenal -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 -lwsock32 -liphlpapi -lstdc++ -static-libstdc++ -static-libgcc -static
|
||||||
|
|
||||||
PCem.exe: $(OBJ) $(FMOBJ) $(SIDOBJ) $(SLIRPOBJ)
|
PCem.exe: $(OBJ) $(DBOBJ) $(SIDOBJ) $(SLIRPOBJ)
|
||||||
$(CC) $(OBJ) $(FMOBJ) $(SIDOBJ) $(SLIRPOBJ) -o "PCem.exe" $(LIBS)
|
$(CC) $(OBJ) $(DBOBJ) $(SIDOBJ) $(SLIRPOBJ) -o "PCem.exe" $(LIBS)
|
||||||
strip "PCem.exe"
|
strip "PCem.exe"
|
||||||
|
|
||||||
all : PCem.exe
|
all : PCem.exe
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
392
src/nvr.c
392
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;
|
||||||
@@ -14,230 +15,16 @@ int nvr_dosave = 0;
|
|||||||
|
|
||||||
static int nvr_onesec_time = 0, nvr_onesec_cnt = 0;
|
static int nvr_onesec_time = 0, nvr_onesec_cnt = 0;
|
||||||
|
|
||||||
int enable_sync = 0;
|
|
||||||
|
|
||||||
#define second internal_time[0]
|
|
||||||
#define minute internal_time[1]
|
|
||||||
#define hour internal_time[2]
|
|
||||||
#define day internal_time[3]
|
|
||||||
#define month internal_time[4]
|
|
||||||
#define year internal_time[5]
|
|
||||||
int internal_time[6];
|
|
||||||
int days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
||||||
|
|
||||||
static int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_days(int org_month, int org_year)
|
|
||||||
{
|
|
||||||
if (org_month != 2)
|
|
||||||
{
|
|
||||||
return days_in_month[org_month];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return is_leap(org_year) ? 29 : 28;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int convert_to_bcd(int number)
|
|
||||||
{
|
|
||||||
int n1, n2;
|
|
||||||
n1 = number % 10;
|
|
||||||
n2 = number - n1;
|
|
||||||
n2 /= 10;
|
|
||||||
n2 <<= 4;
|
|
||||||
return (n2 | n1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int convert_from_bcd(int number)
|
|
||||||
{
|
|
||||||
int n1, n2;
|
|
||||||
n1 = number & 0xF;
|
|
||||||
n2 = number >> 4;
|
|
||||||
n2 *= 10;
|
|
||||||
return (n2 + n1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int final_form(int isbcd, int number)
|
|
||||||
{
|
|
||||||
return isbcd ? convert_to_bcd(number) : number;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int original_form(int isbcd, int number)
|
|
||||||
{
|
|
||||||
return isbcd ? convert_from_bcd(number) : number;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nvr_recalc_clock()
|
|
||||||
{
|
|
||||||
if (second == 60)
|
|
||||||
{
|
|
||||||
second = 0;
|
|
||||||
minute++;
|
|
||||||
}
|
|
||||||
if (minute == 60)
|
|
||||||
{
|
|
||||||
minute = 0;
|
|
||||||
hour++;
|
|
||||||
}
|
|
||||||
if (hour == 24)
|
|
||||||
{
|
|
||||||
hour = 0;
|
|
||||||
day++;
|
|
||||||
}
|
|
||||||
if (day == (get_days(month, year) + 1))
|
|
||||||
{
|
|
||||||
day = 1;
|
|
||||||
month++;
|
|
||||||
}
|
|
||||||
if (month == 13)
|
|
||||||
{
|
|
||||||
month = 1;
|
|
||||||
year++;
|
|
||||||
}
|
|
||||||
nvr_dosave = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nvr_update_internal_clock()
|
|
||||||
{
|
|
||||||
second++;
|
|
||||||
nvr_recalc_clock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nvr_add_10sec()
|
|
||||||
{
|
|
||||||
time_sleep(10000);
|
|
||||||
if (!enable_sync)
|
|
||||||
{
|
|
||||||
second+=10;
|
|
||||||
nvr_recalc_clock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int to_12_hour(int org_hour)
|
|
||||||
{
|
|
||||||
int hour2 = org_hour;
|
|
||||||
hour2 %= 12;
|
|
||||||
if (!hour2) hour2 = 12;
|
|
||||||
return hour2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int from_12_hour(int org_hour)
|
|
||||||
{
|
|
||||||
int hour2 = org_hour & 0x7F;
|
|
||||||
if (hour2 == 12) hour2 = 0;
|
|
||||||
if (hour & 0x80) hour2 += 12;
|
|
||||||
return hour2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int week_day()
|
|
||||||
{
|
|
||||||
int day_of_month = day;
|
|
||||||
int month2 = month;
|
|
||||||
int year2 = year % 100;
|
|
||||||
int century = ((year - year2) / 100) % 4;
|
|
||||||
int sum = day_of_month + month2 + year2 + century;
|
|
||||||
/* (sum mod 7) gives 0 for Saturday, we need it for Monday, so +5 */
|
|
||||||
int raw_wd = ((sum + 5) % 7);
|
|
||||||
/* +1 so 1 = Monday, 7 = Sunday */
|
|
||||||
return raw_wd + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called on every get time. */
|
|
||||||
static void set_registers()
|
|
||||||
{
|
|
||||||
int is24hour = (nvrram[0xB] & 2) ? 1 : 0;
|
|
||||||
int isbcd = (nvrram[0xB] & 4) ? 0 : 1;
|
|
||||||
|
|
||||||
uint8_t baknvr[10];
|
|
||||||
|
|
||||||
memcpy(baknvr,nvrram,10);
|
|
||||||
|
|
||||||
if (AMSTRAD)
|
|
||||||
{
|
|
||||||
is24hour = 1;
|
|
||||||
isbcd = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvrram[0] = final_form(isbcd, second);
|
|
||||||
nvrram[2] = final_form(isbcd, minute);
|
|
||||||
nvrram[4] = is24hour ? final_form(isbcd, hour) : final_form(isbcd, to_12_hour(hour));
|
|
||||||
nvrram[6] = week_day();
|
|
||||||
nvrram[7] = final_form(isbcd, day);
|
|
||||||
nvrram[8] = final_form(isbcd, month);
|
|
||||||
nvrram[9] = final_form(isbcd, (year % 100));
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called on NVR load and write. */
|
|
||||||
static void get_registers()
|
|
||||||
{
|
|
||||||
int is24hour = (nvrram[0xB] & 2) ? 1 : 0;
|
|
||||||
int isbcd = (nvrram[0xB] & 4) ? 0 : 1;
|
|
||||||
|
|
||||||
int temp_hour = 0;
|
|
||||||
|
|
||||||
if (AMSTRAD)
|
|
||||||
{
|
|
||||||
is24hour = 1;
|
|
||||||
isbcd = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
second = original_form(isbcd, nvrram[0]);
|
|
||||||
minute = original_form(isbcd, nvrram[2]);
|
|
||||||
hour = is24hour ? original_form(isbcd, nvrram[4]) : from_12_hour(original_form(isbcd, nvrram[4]));
|
|
||||||
day = original_form(isbcd, nvrram[7]);
|
|
||||||
month = original_form(isbcd, nvrram[8]);
|
|
||||||
year = original_form(isbcd, nvrram[9]) + 1900;
|
|
||||||
}
|
|
||||||
|
|
||||||
void getnvrtime()
|
void getnvrtime()
|
||||||
{
|
{
|
||||||
if (enable_sync)
|
time_get(nvrram);
|
||||||
{
|
|
||||||
/* Get time from host. */
|
|
||||||
time_get(nvrram);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Get time from internal clock. */
|
|
||||||
set_registers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_sync()
|
|
||||||
{
|
|
||||||
if (enable_sync)
|
|
||||||
{
|
|
||||||
/* Get time from host. */
|
|
||||||
time_get(nvrram);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Save time to registers but keep it as is. */
|
|
||||||
get_registers();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvr_recalc()
|
void nvr_recalc()
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int newrtctime;
|
int newrtctime;
|
||||||
c=1<<((nvrram[0xA]&0xF)-1);
|
c=1<<((nvrram[RTCREGA]&(RTCRS0|RTCRS1|RTCRS2|RTCRS3))-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;
|
||||||
}
|
}
|
||||||
@@ -245,42 +32,80 @@ void nvr_recalc()
|
|||||||
void nvr_rtc(void *p)
|
void nvr_rtc(void *p)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
if (!(nvrram[0xA]&0xF))
|
if (!(nvrram[RTCREGA]&(RTCRS0|RTCRS1|RTCRS2|RTCRS3)))
|
||||||
{
|
{
|
||||||
rtctime=0x7fffffff;
|
rtctime=0x7fffffff;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
c=1<<((nvrram[0xA]&0xF)-1);
|
c=1<<((nvrram[RTCREGA]&(RTCRS0|RTCRS1|RTCRS2|RTCRS3))-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[RTCREGC] |= RTCPF;
|
||||||
if (nvrram[0xB]&0x40)
|
if (nvrram[RTCREGB]&RTCPIE)
|
||||||
{
|
{
|
||||||
nvrram[0xC]|=0x80;
|
nvrram[RTCREGC]|=RTCIRQF;
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
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 >= 32768)
|
||||||
{
|
{
|
||||||
nvr_onesec_cnt = 0;
|
nvr_onesec_cnt = 0;
|
||||||
/* If sync is disabled, move internal clock ahead by 1 second. */
|
|
||||||
if (!enable_sync) nvr_update_internal_clock();
|
/* If sync is disabled, move internal clock ahead by 1 second. */
|
||||||
nvrram[0xC] |= 0x10;
|
if (!(nvrram[RTCREGB] & RTCSET))
|
||||||
if (nvrram[0xB] & 0x10)
|
|
||||||
{
|
{
|
||||||
nvrram[0xC] |= 0x80;
|
nvr_update_status = RTCUIP;
|
||||||
if (AMSTRAD) picint(2);
|
if (!enable_sync) rtc_tick();
|
||||||
else picint(0x100);
|
getnvrtime();
|
||||||
|
nvr_dosave = 1;
|
||||||
}
|
}
|
||||||
// pclog("RTC onesec\n");
|
|
||||||
}
|
}
|
||||||
nvr_onesec_time += (int)(10000 * TIMER_USEC);
|
else if (nvr_onesec_cnt == 73) /* 73 of our cycles means 244+1984 us = update in progress time per the specification. */
|
||||||
|
{
|
||||||
|
if (!(nvrram[RTCREGB] & RTCSET))
|
||||||
|
{
|
||||||
|
/* Clear update status. */
|
||||||
|
nvr_update_status = 0;
|
||||||
|
|
||||||
|
if (nvr_check_alarm(RTCSECONDS) && nvr_check_alarm(RTCMINUTES) && nvr_check_alarm(RTCHOURS))
|
||||||
|
{
|
||||||
|
nvrram[RTCREGC] |= RTCAF;
|
||||||
|
if (nvrram[RTCREGB] & RTCAIE)
|
||||||
|
{
|
||||||
|
nvrram[RTCREGC] |= RTCIRQF;
|
||||||
|
if (AMSTRAD) picint(2);
|
||||||
|
else picint(0x100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The flag and interrupt should be issued on update ended, not started. */
|
||||||
|
nvrram[RTCREGC] |= RTCUF;
|
||||||
|
if (nvrram[RTCREGB] & RTCUIE)
|
||||||
|
{
|
||||||
|
nvrram[RTCREGC] |= RTCIRQF;
|
||||||
|
if (AMSTRAD) picint(2);
|
||||||
|
else picint(0x100);
|
||||||
|
}
|
||||||
|
// pclog("RTC onesec\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* This is correct! The real RTC's one second timer operates at 32768 Hz, not 100 Hz! */
|
||||||
|
nvr_onesec_time += (int)((1000000.0 / 32768.0) * TIMER_USEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writenvr(uint16_t addr, uint8_t val, void *priv)
|
void writenvr(uint16_t addr, uint8_t val, void *priv)
|
||||||
@@ -289,45 +114,50 @@ void writenvr(uint16_t addr, uint8_t val, void *priv)
|
|||||||
// 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==RTCREGC || nvraddr==RTCREGD) 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);
|
||||||
old = nvrram[nvraddr];
|
if (nvraddr > RTCREGD && nvrram[nvraddr] != val)
|
||||||
if (nvraddr >= 0xe && nvrram[nvraddr] != val)
|
|
||||||
nvr_dosave = 1;
|
nvr_dosave = 1;
|
||||||
// if (nvraddr==0xB) update_reg_0B(val);
|
|
||||||
if (nvraddr!=0xC && nvraddr!=0xD) nvrram[nvraddr]=val;
|
old = nvrram[nvraddr];
|
||||||
|
nvrram[nvraddr]=val;
|
||||||
|
|
||||||
/* If not syncing the time with the host, we need to update our internal clock on write. */
|
if (nvraddr==RTCREGA)
|
||||||
if (!enable_sync)
|
|
||||||
{
|
|
||||||
switch(nvraddr)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 2:
|
|
||||||
case 4:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
case 8:
|
|
||||||
case 9:
|
|
||||||
if (old != val)
|
|
||||||
{
|
|
||||||
get_registers();
|
|
||||||
nvr_dosave = 1;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvraddr==0xA)
|
|
||||||
{
|
{
|
||||||
// pclog("NVR rate %i\n",val&0xF);
|
// pclog("NVR rate %i\n",val&0xF);
|
||||||
if (val&0xF)
|
if (val&(RTCRS0|RTCRS1|RTCRS2|RTCRS3))
|
||||||
{
|
{
|
||||||
c=1<<((val&0xF)-1);
|
c=1<<((val&(RTCRS0|RTCRS1|RTCRS2|RTCRS3))-1);
|
||||||
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rtctime = 0x7fffffff;
|
rtctime = 0x7fffffff;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
old = nvrram[nvraddr];
|
||||||
|
nvrram[nvraddr]=val;
|
||||||
|
if (nvraddr==RTCREGB)
|
||||||
|
{
|
||||||
|
if (((old ^ val) & RTCSET) && (val & RTCSET))
|
||||||
|
{
|
||||||
|
nvrram[RTCREGA] &= ~RTCUIP; /* This has to be done according to the datasheet. */
|
||||||
|
nvrram[RTCREGB] &= ~RTCUIE; /* This also has to happen per the specification. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nvraddr < RTCREGA) || (nvraddr == RTCCENTURY))
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@@ -338,20 +168,14 @@ 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==RTCREGA) return ((nvrram[RTCREGA] & 0x7F) | nvr_update_status);
|
||||||
if (nvraddr==0xD) nvrram[0xD]|=0x80;
|
if (nvraddr==RTCREGD) nvrram[RTCREGD]|=RTCVRT;
|
||||||
if (nvraddr==0xA)
|
if (nvraddr==RTCREGC)
|
||||||
{
|
|
||||||
temp=nvrram[0xA];
|
|
||||||
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[RTCREGC];
|
||||||
nvrram[0xC]=0;
|
nvrram[RTCREGC]=0; /* All flags in register C are unused (always 0) or cleared on read */
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
// if (AMIBIOS && nvraddr==0x36) return 0;
|
// if (AMIBIOS && nvraddr==0x36) return 0;
|
||||||
@@ -379,7 +203,7 @@ void loadnvr()
|
|||||||
case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "rb"); nvrmask = 127; break;
|
case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "rb"); nvrmask = 127; break;
|
||||||
case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "rb"); nvrmask = 127; break;
|
case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "rb"); nvrmask = 127; break;
|
||||||
case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "rb"); nvrmask = 127; break;
|
case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "rb"); nvrmask = 127; break;
|
||||||
case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "rb"); nvrmask = 127; break;
|
case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "rb"); nvrmask = 127; break;
|
||||||
case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "rb"); nvrmask = 127; break;
|
case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "rb"); nvrmask = 127; break;
|
||||||
case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "rb"); nvrmask = 127; break;
|
case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "rb"); nvrmask = 127; break;
|
||||||
case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "rb"); break;
|
case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "rb"); break;
|
||||||
@@ -413,19 +237,22 @@ void loadnvr()
|
|||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
memset(nvrram,0xFF,128);
|
memset(nvrram,0xFF,128);
|
||||||
|
if (!enable_sync)
|
||||||
|
{
|
||||||
|
nvrram[RTCSECONDS] = nvrram[RTCMINUTES] = nvrram[RTCHOURS] = 0;
|
||||||
|
nvrram[RTCDOM] = nvrram[RTCMONTH] = 1;
|
||||||
|
nvrram[RTCYEAR] = BCD(80);
|
||||||
|
nvrram[RTCCENTURY] = BCD(19);
|
||||||
|
nvrram[RTCREGB]=RTC2412;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fread(nvrram,128,1,f);
|
fread(nvrram,128,1,f);
|
||||||
if (!(feof(f)))
|
if (!enable_sync) time_update(nvrram, 0xFF); /* Update the internal clock state based on the NVR registers. */
|
||||||
fread(internal_time,6,4,f);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!enable_sync) get_registers();
|
|
||||||
}
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
nvrram[0xA]=6;
|
nvrram[RTCREGA]=(RTCRS1|RTCRS2);
|
||||||
nvrram[0xB]=0;
|
nvrram[RTCREGB]=RTC2412;
|
||||||
c=1<<((6&0xF)-1);
|
c=1<<((nvrram[RTCREGA]&(RTCRS0|RTCRS1|RTCRS2|RTCRS3))-1);
|
||||||
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT));
|
||||||
}
|
}
|
||||||
void savenvr()
|
void savenvr()
|
||||||
@@ -443,7 +270,7 @@ void savenvr()
|
|||||||
case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "wb"); break;
|
case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "wb"); break;
|
||||||
case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "wb"); break;
|
case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "wb"); break;
|
||||||
case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "wb"); break;
|
case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "wb"); break;
|
||||||
case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "wb"); break;
|
case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "wb"); break;
|
||||||
case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "wb"); break;
|
case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "wb"); break;
|
||||||
case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "wb"); break;
|
case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "wb"); break;
|
||||||
case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "wb"); break;
|
case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "wb"); break;
|
||||||
@@ -474,10 +301,7 @@ void savenvr()
|
|||||||
case ROM_KN97: f = romfopen("nvr/kn97.nvr", "wb"); break;
|
case ROM_KN97: f = romfopen("nvr/kn97.nvr", "wb"); break;
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
/* If sync is disabled, save internal clock to registers. */
|
|
||||||
if (!enable_sync) set_registers();
|
|
||||||
fwrite(nvrram,128,1,f);
|
fwrite(nvrram,128,1,f);
|
||||||
fwrite(internal_time,6,4,f);
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
void nvr_init();
|
void nvr_init();
|
||||||
|
|
||||||
extern int nvr_dosave;
|
|
||||||
extern int enable_sync;
|
extern int enable_sync;
|
||||||
|
|
||||||
void time_sleep(int count);
|
extern int nvr_dosave;
|
||||||
|
|
||||||
void time_get(char *nvrram);
|
void time_get(char *nvrram);
|
||||||
void nvr_add_10sec();
|
|
||||||
|
|
||||||
void update_sync();
|
|
||||||
|
2
src/pc.c
2
src/pc.c
@@ -675,7 +675,7 @@ void loadconfig(char *fn)
|
|||||||
enable_overscan = config_get_int(NULL, "enable_overscan", 0);
|
enable_overscan = config_get_int(NULL, "enable_overscan", 0);
|
||||||
enable_flash = config_get_int(NULL, "enable_flash", 1);
|
enable_flash = config_get_int(NULL, "enable_flash", 1);
|
||||||
|
|
||||||
enable_sync = config_get_int(NULL, "enable_sync", 0);
|
enable_sync = config_get_int(NULL, "enable_sync", 1);
|
||||||
mouse_always_serial = config_get_int(NULL, "mouse_always_serial", 0);
|
mouse_always_serial = config_get_int(NULL, "mouse_always_serial", 0);
|
||||||
|
|
||||||
window_w = config_get_int(NULL, "window_w", 0);
|
window_w = config_get_int(NULL, "window_w", 0);
|
||||||
|
261
src/rtc.c
Normal file
261
src/rtc.c
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
/* 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;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int sec;
|
||||||
|
int min;
|
||||||
|
int hour;
|
||||||
|
int mday;
|
||||||
|
int mon;
|
||||||
|
int year;
|
||||||
|
}
|
||||||
|
internal_clock_t;
|
||||||
|
|
||||||
|
internal_clock_t internal_clock;
|
||||||
|
|
||||||
|
/* When the RTC was last updated */
|
||||||
|
time_t rtc_set_time = 0;
|
||||||
|
|
||||||
|
/* Table for days in each month */
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
nvr_dosave = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 RTCSECONDS:
|
||||||
|
internal_clock.sec = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCSECONDS] : DCB(nvrram[RTCSECONDS]);
|
||||||
|
break;
|
||||||
|
case RTCMINUTES:
|
||||||
|
internal_clock.min = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCMINUTES] : DCB(nvrram[RTCMINUTES]);
|
||||||
|
break;
|
||||||
|
case RTCHOURS:
|
||||||
|
temp = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCHOURS] : DCB(nvrram[RTCHOURS]);
|
||||||
|
|
||||||
|
if (nvrram[RTCREGB] & RTC2412)
|
||||||
|
{
|
||||||
|
internal_clock.hour = temp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
internal_clock.hour = ((temp & ~RTCAMPM) % 12) + ((temp & RTCAMPM) ? 12 : 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RTCDOM:
|
||||||
|
internal_clock.mday = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCDOM] : DCB(nvrram[RTCDOM]);
|
||||||
|
break;
|
||||||
|
case RTCMONTH:
|
||||||
|
internal_clock.mon = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCMONTH] : DCB(nvrram[RTCMONTH]);
|
||||||
|
break;
|
||||||
|
case RTCYEAR:
|
||||||
|
internal_clock.year = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCYEAR] : DCB(nvrram[RTCYEAR]);
|
||||||
|
internal_clock.year += (nvrram[RTCREGB] & RTCDM) ? 1900 : (DCB(nvrram[RTCCENTURY]) * 100);
|
||||||
|
break;
|
||||||
|
case RTCCENTURY:
|
||||||
|
if (nvrram[RTCREGB] & RTCDM) return;
|
||||||
|
internal_clock.year %= 100;
|
||||||
|
internal_clock.year += (DCB(nvrram[RTCCENTURY]) * 100);
|
||||||
|
break;
|
||||||
|
case 0xFF: /* Load the entire internal clock state from the NVR. */
|
||||||
|
internal_clock.sec = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCSECONDS] : DCB(nvrram[RTCSECONDS]);
|
||||||
|
internal_clock.min = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCMINUTES] : DCB(nvrram[RTCMINUTES]);
|
||||||
|
|
||||||
|
temp = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCHOURS] : DCB(nvrram[RTCHOURS]);
|
||||||
|
|
||||||
|
if (nvrram[RTCREGB] & RTC2412)
|
||||||
|
{
|
||||||
|
internal_clock.hour = temp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
internal_clock.hour = ((temp & ~RTCAMPM) % 12) + ((temp & RTCAMPM) ? 12 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_clock.mday = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCDOM] : DCB(nvrram[RTCDOM]);
|
||||||
|
internal_clock.mon = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCMONTH] : DCB(nvrram[RTCMONTH]);
|
||||||
|
internal_clock.year = (nvrram[RTCREGB] & RTCDM) ? nvrram[RTCYEAR] : DCB(nvrram[RTCYEAR]);
|
||||||
|
internal_clock.year += (nvrram[RTCREGB] & RTCDM) ? 1900 : (DCB(nvrram[RTCCENTURY]) * 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Periodic RTC update function
|
||||||
|
See also: nvr_onesec() in nvr.c
|
||||||
|
*/
|
||||||
|
void time_get(char *nvrram)
|
||||||
|
{
|
||||||
|
time_t cur_time;
|
||||||
|
struct tm* cur_time_tm;
|
||||||
|
int dow, mon, year;
|
||||||
|
|
||||||
|
if (enable_sync)
|
||||||
|
{
|
||||||
|
cur_time = time(NULL);
|
||||||
|
|
||||||
|
/* 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[RTCREGB] & RTCDM)
|
||||||
|
{
|
||||||
|
nvrram[RTCSECONDS] = cur_time_tm->tm_sec;
|
||||||
|
nvrram[RTCMINUTES] = cur_time_tm->tm_min;
|
||||||
|
nvrram[RTCDOW] = cur_time_tm->tm_wday + 1;
|
||||||
|
nvrram[RTCDOM] = cur_time_tm->tm_mday;
|
||||||
|
nvrram[RTCMONTH] = cur_time_tm->tm_mon + 1;
|
||||||
|
nvrram[RTCYEAR] = cur_time_tm->tm_year % 100;
|
||||||
|
|
||||||
|
if (nvrram[RTCREGB] & RTC2412)
|
||||||
|
{
|
||||||
|
nvrram[RTCHOURS] = cur_time_tm->tm_hour;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[RTCHOURS] = (cur_time_tm->tm_hour % 12) ? (cur_time_tm->tm_hour % 12) : 12;
|
||||||
|
if (cur_time_tm->tm_hour > 11)
|
||||||
|
{
|
||||||
|
nvrram[RTCHOURS] |= RTCAMPM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[RTCSECONDS] = BCD(cur_time_tm->tm_sec);
|
||||||
|
nvrram[RTCMINUTES] = BCD(cur_time_tm->tm_min);
|
||||||
|
nvrram[RTCDOW] = BCD(cur_time_tm->tm_wday + 1);
|
||||||
|
nvrram[RTCDOM] = BCD(cur_time_tm->tm_mday);
|
||||||
|
nvrram[RTCMONTH] = BCD(cur_time_tm->tm_mon + 1);
|
||||||
|
nvrram[RTCYEAR] = BCD(cur_time_tm->tm_year % 100);
|
||||||
|
|
||||||
|
if (nvrram[RTCREGB] & RTC2412)
|
||||||
|
{
|
||||||
|
nvrram[RTCHOURS] = BCD(cur_time_tm->tm_hour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nvrram[RTCHOURS] = (cur_time_tm->tm_hour % 12) ? BCD(cur_time_tm->tm_hour % 12) : BCD(12);
|
||||||
|
if (cur_time_tm->tm_hour > 11)
|
||||||
|
{
|
||||||
|
nvrram[RTCHOURS] |= RTCAMPM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
src/rtc.h
Normal file
186
src/rtc.h
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#define BCD(X) (((X) % 10) | (((X) / 10) << 4))
|
||||||
|
#define DCB(X) ((((X) & 0xF0) >> 4) * 10 + ((X) & 0x0F))
|
||||||
|
|
||||||
|
enum RTCADDR
|
||||||
|
{
|
||||||
|
RTCSECONDS,
|
||||||
|
RTCALARMSECONDS,
|
||||||
|
RTCMINUTES,
|
||||||
|
RTCALARMMINUTES,
|
||||||
|
RTCHOURS,
|
||||||
|
RTCALARMHOURS,
|
||||||
|
RTCDOW,
|
||||||
|
RTCDOM,
|
||||||
|
RTCMONTH,
|
||||||
|
RTCYEAR,
|
||||||
|
RTCREGA,
|
||||||
|
RTCREGB,
|
||||||
|
RTCREGC,
|
||||||
|
RTCREGD
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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 RTCCENTURY 0x32
|
||||||
|
|
||||||
|
/* When the 12-hour format is selected, the higher-order bit of the hours byte represents PM when it is logic 1. */
|
||||||
|
#define RTCAMPM 0b10000000
|
||||||
|
|
||||||
|
/* Register A bitflags */
|
||||||
|
enum RTCRABITS
|
||||||
|
{
|
||||||
|
/* 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. */
|
||||||
|
RTCRS0 = 0b1,
|
||||||
|
RTCRS1 = 0b10, /*!<RS1*/
|
||||||
|
RTCRS2 = 0b100, /*!<RS2*/
|
||||||
|
RTCRS3 = 0b1000, /*!<RS3*/
|
||||||
|
/* 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. */
|
||||||
|
RTCDV0 = 0b10000,
|
||||||
|
RTCDV1 = 0b100000, /*!<DV1*/
|
||||||
|
RTCDV2 = 0b1000000, /*!<DV2*/
|
||||||
|
/* 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. */
|
||||||
|
RTCUIP = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register B bitflags */
|
||||||
|
enum RTCRBBITS
|
||||||
|
{
|
||||||
|
/* 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. */
|
||||||
|
RTCDSE = 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. */
|
||||||
|
RTC2412 = 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. */
|
||||||
|
RTCDM = 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. */
|
||||||
|
RTCSQWE = 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. */
|
||||||
|
RTCUIE = 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. */
|
||||||
|
RTCAIE = 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. */
|
||||||
|
RTCPIE = 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. */
|
||||||
|
RTCSET = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register C bitflags */
|
||||||
|
enum RTCRCBITS
|
||||||
|
{
|
||||||
|
/* Unused
|
||||||
|
|
||||||
|
These bits are unused in Register C. These bits always read 0 and cannot be written. */
|
||||||
|
RTCRC0 = 0b1,
|
||||||
|
RTCRC1 = 0b10, /*!<Unused*/
|
||||||
|
RTCRC2 = 0b100, /*!<Unused*/
|
||||||
|
RTCRC3 = 0b1000, /*!<Unused*/
|
||||||
|
/* 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. */
|
||||||
|
RTCUF = 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. */
|
||||||
|
RTCAF = 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. */
|
||||||
|
RTCPF = 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. */
|
||||||
|
RTCIRQF = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register D bitflags */
|
||||||
|
enum RTCRDBITS
|
||||||
|
{
|
||||||
|
/* Unused
|
||||||
|
|
||||||
|
The remaining bits of Register D are not usable. They cannot be written and they always read 0. */
|
||||||
|
RTCRD0 = 0b1,
|
||||||
|
RTCRD1 = 0b10, /*!<Unused*/
|
||||||
|
RTCRD2 = 0b100, /*!<Unused*/
|
||||||
|
RTCRD3 = 0b1000, /*!<Unused*/
|
||||||
|
RTCRD4 = 0b10000, /*!<Unused*/
|
||||||
|
RTCRD5 = 0b100000, /*!<Unused*/
|
||||||
|
RTCRD6 = 0b1000000, /*!<Unused*/
|
||||||
|
/* 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. */
|
||||||
|
RTCVRT = 0b10000000
|
||||||
|
};
|
||||||
|
|
||||||
|
void rtc_tick();
|
||||||
|
void time_update(char *nvrram, int reg);
|
||||||
|
void time_get(char *nvrram);
|
@@ -339,7 +339,6 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
|
|||||||
|
|
||||||
h = GetDlgItem(hdlg, IDC_CHECKSYNC);
|
h = GetDlgItem(hdlg, IDC_CHECKSYNC);
|
||||||
enable_sync = SendMessage(h, BM_GETCHECK, 0, 0);
|
enable_sync = SendMessage(h, BM_GETCHECK, 0, 0);
|
||||||
update_sync();
|
|
||||||
|
|
||||||
h = GetDlgItem(hdlg, IDC_CHECKSERIAL);
|
h = GetDlgItem(hdlg, IDC_CHECKSERIAL);
|
||||||
temp_always_serial = SendMessage(h, BM_GETCHECK, 0, 0);
|
temp_always_serial = SendMessage(h, BM_GETCHECK, 0, 0);
|
||||||
|
@@ -1,48 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
#include "ibm.h"
|
|
||||||
#include "nvr.h"
|
|
||||||
|
|
||||||
void time_sleep(int count)
|
|
||||||
{
|
|
||||||
Sleep(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
Reference in New Issue
Block a user