This repository has been archived by the owner on Oct 12, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
rtc.c
127 lines (103 loc) · 3.04 KB
/
rtc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* Xep128: Minimalistic Enterprise-128 emulator with focus on "exotic" hardware
Copyright (C)2015,2016 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
http://xep128.lgb.hu/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "xep128.h"
#include "rtc.h"
#include "main.h"
#include <time.h>
//#define RESET_RTC_INDEX
static int _rtc_register;
static Uint8 cmos_ram[0x100];
int rtc_update_trigger;
void rtc_set_reg(Uint8 val)
{
_rtc_register = val;
DEBUG("RTC: register number %02X has been selected" NL, val);
}
void rtc_write_reg(Uint8 val)
{
DEBUG("RTC: write reg %02X with data %02X" NL, _rtc_register, val);
if (_rtc_register == 0xC || _rtc_register == 0xD) return;
if (_rtc_register == 0xA) val &= 127;
cmos_ram[_rtc_register] = val;
#ifdef RESET_RTC_INDEX
_rtc_register = 0xD;
#endif
}
static int _rtc_conv(int bin, int is_hour)
{
int b7 = 0;
if (is_hour && (!(cmos_ram[0xB] & 2))) { // AM/PM
if (bin == 0) {
bin = 12;
} else if (bin == 12) {
b7 = 128;
} else if (bin > 12) {
bin -= 12;
b7 = 128;
}
}
if (!(cmos_ram[0xB] & 4)) { // do bin->bcd
bin = ((bin / 10) << 4) | (bin % 10);
}
return bin | b7;
}
static void _rtc_update(void)
{
struct tm *t = localtime(&unix_time);
cmos_ram[ 0] = _rtc_conv(t->tm_sec, 0);
cmos_ram[ 2] = _rtc_conv(t->tm_min, 0);
cmos_ram[ 4] = _rtc_conv(t->tm_hour, 1);
cmos_ram[ 6] = _rtc_conv(t->tm_wday + 1, 0); // day, 1-7 (week)
cmos_ram[ 7] = _rtc_conv(t->tm_mday, 0); // date, 1-31
cmos_ram[ 8] = _rtc_conv(t->tm_mon + 1, 0); // month, 1 -12
cmos_ram[ 9] = _rtc_conv((t->tm_year % 100) + 20, 0); // year, 0 - 99
cmos_ram[0x32] = _rtc_conv(21, 0); // century???
DEBUG("RTC: time/date has been updated for \"%d-%02d-%02d %02d:%02d:%02d\" at UNIX epoch %ld" NL,
t->tm_year + 1900,
t->tm_mon + 1,
t->tm_mday,
t->tm_hour,
t->tm_min,
t->tm_sec,
(long int)unix_time
);
}
void rtc_reset(void)
{
memset(cmos_ram, 0, 0x100);
_rtc_register = 0xD;
rtc_update_trigger = 0;
cmos_ram[0xA] = 32;
cmos_ram[0xB] = 2; // 2 | 4;
cmos_ram[0xC] = 0;
cmos_ram[0xD] = 128;
DEBUG("RTC: reset" NL);
_rtc_update();
}
Uint8 rtc_read_reg(void)
{
int i = _rtc_register;
#ifdef RESET_RTC_INDEX
_rtc_register = 0xD;
#endif
if (i > 63)
return 0xFF;
if (rtc_update_trigger && (cmos_ram[0xB] & 128) == 0 && i < 10) {
_rtc_update();
rtc_update_trigger = 0;
}
DEBUG("RTC: reading register %02X, result will be: %02X" NL, i, cmos_ram[i]);
return cmos_ram[i];
}