2013-11-06 01:12:55 +01:00
|
|
|
/**
|
|
|
|
* RTC (real time clock) and CMOS
|
|
|
|
* @constructor
|
|
|
|
*/
|
2014-01-08 03:16:28 +01:00
|
|
|
function RTC(dev, diskette_type, boot_order)
|
2013-11-06 01:12:55 +01:00
|
|
|
{
|
|
|
|
var
|
|
|
|
io = dev.io,
|
|
|
|
pic = dev.pic,
|
|
|
|
|
2014-01-08 03:16:28 +01:00
|
|
|
memory_size = dev.memory.size,
|
|
|
|
|
2013-11-06 01:12:55 +01:00
|
|
|
cmos_index = 0,
|
|
|
|
me = this,
|
|
|
|
|
|
|
|
// used for cmos entries
|
|
|
|
rtc_time = Date.now(),
|
|
|
|
last_update = rtc_time,
|
|
|
|
|
|
|
|
// used for periodic interrupt
|
|
|
|
next_interrupt,
|
|
|
|
|
|
|
|
periodic_interrupt = false,
|
|
|
|
|
|
|
|
// corresponds to default value for cmos_a
|
|
|
|
periodic_interrupt_time = 1000 / 1024;
|
|
|
|
|
|
|
|
|
|
|
|
var cmos_a = 0x26,
|
|
|
|
cmos_b = 2;
|
|
|
|
|
|
|
|
this.nmi_disabled = 0;
|
|
|
|
|
|
|
|
this.timer = function(time)
|
|
|
|
{
|
|
|
|
if(periodic_interrupt)
|
|
|
|
{
|
|
|
|
while(next_interrupt < time)
|
|
|
|
{
|
|
|
|
next_interrupt += periodic_interrupt_time;
|
|
|
|
|
|
|
|
pic.push_irq(8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rtc_time += time - last_update;
|
|
|
|
last_update = time;
|
|
|
|
};
|
|
|
|
|
|
|
|
io.register_write(0x70, function(out_byte)
|
|
|
|
{
|
|
|
|
cmos_index = out_byte & 0x7F;
|
|
|
|
me.nmi_disabled = out_byte >> 7;
|
|
|
|
});
|
|
|
|
|
|
|
|
io.register_write(0x71, cmos_write);
|
|
|
|
io.register_read(0x71, cmos_read);
|
|
|
|
|
|
|
|
function encode_time(t)
|
|
|
|
{
|
|
|
|
if(cmos_b & 4)
|
|
|
|
{
|
|
|
|
// binary mode
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Math.bcd_pack(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
// - interrupt on update
|
|
|
|
// - countdown
|
|
|
|
// - letting bios/os set values
|
|
|
|
// (none of these are used by seabios or the OSes we're
|
|
|
|
// currently testing)
|
|
|
|
function cmos_read()
|
|
|
|
{
|
|
|
|
var index = cmos_index;
|
|
|
|
|
2014-01-08 03:16:28 +01:00
|
|
|
//cmos_index = 0xD;
|
2013-11-06 01:12:55 +01:00
|
|
|
|
|
|
|
switch(index)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return encode_time(new Date(rtc_time).getUTCSeconds());
|
|
|
|
case 2:
|
|
|
|
return encode_time(new Date(rtc_time).getUTCMinutes());
|
|
|
|
case 4:
|
|
|
|
// TODO: 12 hour mode
|
|
|
|
return encode_time(new Date(rtc_time).getUTCHours());
|
|
|
|
case 7:
|
|
|
|
return encode_time(new Date(rtc_time).getUTCDate());
|
|
|
|
case 8:
|
|
|
|
return encode_time(new Date(rtc_time).getUTCMonth() + 1);
|
|
|
|
case 9:
|
|
|
|
return encode_time(new Date(rtc_time).getUTCFullYear() % 100);
|
|
|
|
|
|
|
|
case 0xA:
|
|
|
|
return cmos_a;
|
|
|
|
case 0xB:
|
|
|
|
//dbg_log("cmos read from index " + h(index));
|
|
|
|
return cmos_b;
|
|
|
|
|
|
|
|
case 0xE:
|
|
|
|
// post info
|
|
|
|
return 0;
|
|
|
|
case 0xC:
|
|
|
|
//dbg_log("cmos read from index " + h(index));
|
|
|
|
// TODO:
|
|
|
|
// It is important to know that upon a IRQ 8, Status Register C
|
|
|
|
// will contain a bitmask telling which interrupt happened.
|
|
|
|
// What is important is that if register C is not read after an
|
|
|
|
// IRQ 8, then the interrupt will not happen again.
|
|
|
|
|
|
|
|
//dbg_log("cmos Ch read");
|
|
|
|
return 0;
|
|
|
|
// Missing IRQF flag
|
|
|
|
//return cmos_b & 0x70;
|
|
|
|
|
|
|
|
case 0xF:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case 0x10:
|
|
|
|
// floppy type
|
|
|
|
return diskette_type;
|
|
|
|
|
|
|
|
case 0x14:
|
|
|
|
// equipment
|
|
|
|
return 0x2D;
|
|
|
|
|
|
|
|
case 0x32:
|
|
|
|
return encode_time(new Date(rtc_time).getUTCFullYear() / 100 | 0);
|
|
|
|
|
|
|
|
case 0x34:
|
|
|
|
return (memory_size - 16 * 1024 * 1024) >> 16 & 0xff;
|
|
|
|
case 0x35:
|
|
|
|
return (memory_size - 16 * 1024 * 1024) >> 24 & 0xff;
|
|
|
|
|
2014-01-08 03:16:28 +01:00
|
|
|
|
2013-11-06 01:12:55 +01:00
|
|
|
case 0x38:
|
|
|
|
// used by seabios to determine the boot order
|
2014-01-08 03:16:28 +01:00
|
|
|
// Nibble
|
|
|
|
// 1: FloppyPrio
|
|
|
|
// 2: HDPrio
|
|
|
|
// 3: CDPrio
|
|
|
|
// 4: BEVPrio
|
2013-11-06 01:12:55 +01:00
|
|
|
// bootflag 1, high nibble, lowest priority
|
2013-11-07 19:57:43 +01:00
|
|
|
// Low nibble: Disable floppy signature check (1)
|
2014-01-08 03:16:28 +01:00
|
|
|
return 1 | boot_order >> 4 & 0xF0;
|
2013-11-06 01:12:55 +01:00
|
|
|
case 0x3D:
|
|
|
|
// bootflag 2, both nibbles, high and middle priority
|
2014-01-08 03:16:28 +01:00
|
|
|
return boot_order & 0xFF;
|
2013-11-06 01:12:55 +01:00
|
|
|
|
|
|
|
case 0x5B:
|
|
|
|
case 0x5C:
|
|
|
|
case 0x5D:
|
|
|
|
// memory above 4GB
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dbg_log("cmos read from index " + h(index), LOG_RTC);
|
|
|
|
|
|
|
|
return 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
function cmos_write(data_byte)
|
|
|
|
{
|
|
|
|
switch(cmos_index)
|
|
|
|
{
|
|
|
|
case 0xA:
|
|
|
|
cmos_a = data_byte & 0x7F;
|
|
|
|
periodic_interrupt_time = 1000 / (32768 >> (cmos_a & 0xF) - 1);
|
|
|
|
|
|
|
|
dbg_log("Periodic interrupt, a=" + h(cmos_a, 2) + " t=" + periodic_interrupt_time , LOG_RTC);
|
|
|
|
break;
|
|
|
|
case 0xB:
|
|
|
|
cmos_b = data_byte;
|
|
|
|
if(cmos_b & 0x40)
|
|
|
|
{
|
|
|
|
next_interrupt = Date.now();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(cmos_b & 0x20) dbg_log("Unimplemented: alarm interrupt");
|
|
|
|
if(cmos_b & 0x10) dbg_log("Unimplemented: updated interrupt");
|
|
|
|
|
|
|
|
dbg_log("cmos b=" + h(cmos_b, 2), LOG_RTC);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dbg_log("cmos write index " + h(cmos_index) + ": " + h(data_byte), LOG_RTC);
|
|
|
|
}
|
|
|
|
|
|
|
|
periodic_interrupt = (cmos_b & 0x40) === 0x40 && (cmos_a & 0xF) > 0;
|
|
|
|
}
|
|
|
|
}
|