3
var CMOS_RTC_SECONDS = 0x00;
4
var CMOS_RTC_SECONDS_ALARM = 0x01;
5
var CMOS_RTC_MINUTES = 0x02;
6
var CMOS_RTC_MINUTES_ALARM = 0x03;
7
var CMOS_RTC_HOURS = 0x04;
8
var CMOS_RTC_HOURS_ALARM = 0x05;
9
var CMOS_RTC_DAY_WEEK = 0x06;
10
var CMOS_RTC_DAY_MONTH = 0x07;
11
var CMOS_RTC_MONTH = 0x08;
12
var CMOS_RTC_YEAR = 0x09;
13
var CMOS_STATUS_A = 0x0a;
14
var CMOS_STATUS_B = 0x0b;
15
var CMOS_STATUS_C = 0x0c;
16
var CMOS_STATUS_D = 0x0d;
17
var CMOS_RESET_CODE = 0x0f;
19
var CMOS_FLOPPY_DRIVE_TYPE = 0x10;
20
var CMOS_DISK_DATA = 0x12;
21
var CMOS_EQUIPMENT_INFO = 0x14;
22
var CMOS_MEM_BASE_LOW = 0x15;
23
var CMOS_MEM_BASE_HIGH = 0x16;
24
var CMOS_MEM_OLD_EXT_LOW = 0x17;
25
var CMOS_MEM_OLD_EXT_HIGH = 0x18;
26
var CMOS_DISK_DRIVE1_TYPE = 0x19;
27
var CMOS_DISK_DRIVE2_TYPE = 0x1a;
28
var CMOS_DISK_DRIVE1_CYL = 0x1b;
29
var CMOS_DISK_DRIVE2_CYL = 0x24;
30
var CMOS_MEM_EXTMEM_LOW = 0x30;
31
var CMOS_MEM_EXTMEM_HIGH = 0x31;
32
var CMOS_CENTURY = 0x32;
33
var CMOS_MEM_EXTMEM2_LOW = 0x34;
34
var CMOS_MEM_EXTMEM2_HIGH = 0x35;
35
var CMOS_BIOS_BOOTFLAG1 = 0x38;
36
var CMOS_BIOS_DISKTRANSFLAG = 0x39;
37
var CMOS_BIOS_BOOTFLAG2 = 0x3d;
38
var CMOS_MEM_HIGHMEM_LOW = 0x5b;
39
var CMOS_MEM_HIGHMEM_MID = 0x5c;
40
var CMOS_MEM_HIGHMEM_HIGH = 0x5d;
41
var CMOS_BIOS_SMP_COUNT = 0x5f;
55
this.cmos_data = new Uint8Array(128);
58
this.rtc_time = Date.now();
59
this.last_update = this.rtc_time;
62
this.next_interrupt = 0;
65
this.next_interrupt_alarm = 0;
67
this.periodic_interrupt = false;
70
this.periodic_interrupt_time = 1000 / 1024;
76
this.nmi_disabled = 0;
78
cpu.io.register_write(0x70, this, function(out_byte)
80
this.cmos_index = out_byte & 0x7F;
81
this.nmi_disabled = out_byte >> 7;
84
cpu.io.register_write(0x71, this, this.cmos_port_write);
85
cpu.io.register_read(0x71, this, this.cmos_port_read);
88
RTC.prototype.get_state = function()
92
state[0] = this.cmos_index;
93
state[1] = this.cmos_data;
94
state[2] = this.rtc_time;
95
state[3] = this.last_update;
96
state[4] = this.next_interrupt;
97
state[5] = this.next_interrupt_alarm;
98
state[6] = this.periodic_interrupt;
99
state[7] = this.periodic_interrupt_time;
100
state[8] = this.cmos_a;
101
state[9] = this.cmos_b;
102
state[10] = this.cmos_c;
103
state[11] = this.nmi_disabled;
108
RTC.prototype.set_state = function(state)
110
this.cmos_index = state[0];
111
this.cmos_data = state[1];
112
this.rtc_time = state[2];
113
this.last_update = state[3];
114
this.next_interrupt = state[4];
115
this.next_interrupt_alarm = state[5];
116
this.periodic_interrupt = state[6];
117
this.periodic_interrupt_time = state[7];
118
this.cmos_a = state[8];
119
this.cmos_b = state[9];
120
this.cmos_c = state[10];
121
this.nmi_disabled = state[11];
124
RTC.prototype.timer = function(time, legacy_mode)
127
this.rtc_time += time - this.last_update;
128
this.last_update = time;
130
if(this.periodic_interrupt && this.next_interrupt < time)
132
this.cpu.device_raise_irq(8);
133
this.cmos_c |= 1 << 6 | 1 << 7;
135
this.next_interrupt += this.periodic_interrupt_time *
136
Math.ceil((time - this.next_interrupt) / this.periodic_interrupt_time);
138
else if(this.next_interrupt_alarm && this.next_interrupt_alarm < time)
140
this.cpu.device_raise_irq(8);
141
this.cmos_c |= 1 << 5 | 1 << 7;
143
this.next_interrupt_alarm = 0;
148
if(this.periodic_interrupt && this.next_interrupt)
150
t = Math.min(t, Math.max(0, this.next_interrupt - time));
152
if(this.next_interrupt_alarm)
154
t = Math.min(t, Math.max(0, this.next_interrupt_alarm - time));
160
RTC.prototype.bcd_pack = function(n)
170
result |= digit << (4 * i);
172
n = (n - digit) / 10;
178
RTC.prototype.bcd_unpack = function(n)
181
const high = n >> 4 & 0xF;
183
dbg_assert(n < 0x100);
184
dbg_assert(low < 10);
185
dbg_assert(high < 10);
187
return low + 10 * high;
190
RTC.prototype.encode_time = function(t)
199
return this.bcd_pack(t);
203
RTC.prototype.decode_time = function(t)
212
return this.bcd_unpack(t);
222
RTC.prototype.cmos_port_read = function()
224
var index = this.cmos_index;
230
case CMOS_RTC_SECONDS:
231
return this.encode_time(new Date(this.rtc_time).getUTCSeconds());
232
case CMOS_RTC_MINUTES:
233
return this.encode_time(new Date(this.rtc_time).getUTCMinutes());
236
return this.encode_time(new Date(this.rtc_time).getUTCHours());
237
case CMOS_RTC_DAY_MONTH:
238
return this.encode_time(new Date(this.rtc_time).getUTCDate());
240
return this.encode_time(new Date(this.rtc_time).getUTCMonth() + 1);
242
return this.encode_time(new Date(this.rtc_time).getUTCFullYear() % 100);
255
this.cpu.device_lower_irq(8);
257
dbg_log("cmos reg C read", LOG_RTC);
262
this.cmos_c &= ~0xF0;
270
return this.encode_time(new Date(this.rtc_time).getUTCFullYear() / 100 | 0);
273
dbg_log("cmos read from index " + h(index), LOG_RTC);
274
return this.cmos_data[this.cmos_index];
278
RTC.prototype.cmos_port_write = function(data_byte)
280
switch(this.cmos_index)
283
this.cmos_a = data_byte & 0x7F;
284
this.periodic_interrupt_time = 1000 / (32768 >> (this.cmos_a & 0xF) - 1);
286
dbg_log("Periodic interrupt, a=" + h(this.cmos_a, 2) + " t=" + this.periodic_interrupt_time , LOG_RTC);
289
this.cmos_b = data_byte;
290
if(this.cmos_b & 0x40)
292
this.next_interrupt = Date.now();
295
if(this.cmos_b & 0x20)
297
const now = new Date();
299
const seconds = this.decode_time(this.cmos_data[CMOS_RTC_SECONDS_ALARM]);
300
const minutes = this.decode_time(this.cmos_data[CMOS_RTC_MINUTES_ALARM]);
301
const hours = this.decode_time(this.cmos_data[CMOS_RTC_HOURS_ALARM]);
303
const alarm_date = new Date(Date.UTC(
304
now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),
305
hours, minutes, seconds
308
const ms_from_now = alarm_date - now;
309
dbg_log("RTC alarm scheduled for " + alarm_date +
310
" hh:mm:ss=" + hours + ":" + minutes + ":" + seconds +
311
" ms_from_now=" + ms_from_now, LOG_RTC);
313
this.next_interrupt_alarm = +alarm_date;
316
if(this.cmos_b & 0x10) dbg_log("Unimplemented: updated interrupt", LOG_RTC);
318
dbg_log("cmos b=" + h(this.cmos_b, 2), LOG_RTC);
321
case CMOS_RTC_SECONDS_ALARM:
322
case CMOS_RTC_MINUTES_ALARM:
323
case CMOS_RTC_HOURS_ALARM:
324
this.cmos_write(this.cmos_index, data_byte);
328
dbg_log("cmos write index " + h(this.cmos_index) + ": " + h(data_byte), LOG_RTC);
331
this.periodic_interrupt = (this.cmos_b & 0x40) === 0x40 && (this.cmos_a & 0xF) > 0;
337
RTC.prototype.cmos_read = function(index)
339
dbg_assert(index < 128);
340
return this.cmos_data[index];
347
RTC.prototype.cmos_write = function(index, value)
349
dbg_log("cmos " + h(index) + " <- " + h(value), LOG_RTC);
350
dbg_assert(index < 128);
351
this.cmos_data[index] = value;