4
var HPET_ADDR = 0xFED00000,
5
HPET_PERIOD = 0x05F5E100,
6
HPET_FREQ_MS = 1e12 / HPET_PERIOD,
8
HPET_COUNTER_CONFIG = 1 << 4 | HPET_SUPPORT_64 << 5,
9
HPET_COUNTER_CONFIG_MASK = 1 << 4 | 1 << 5 | 1 << 15,
10
HPET_NUM_COUNTERS = 4;
24
hpet_start = Date.now(),
29
counter_read_acc_next = false,
32
counter_config = new Int32Array(HPET_NUM_COUNTERS << 1),
33
counter_comparator = new Int32Array(HPET_NUM_COUNTERS << 1),
34
counter_accumulator = new Int32Array(HPET_NUM_COUNTERS << 1);
42
this.legacy_mode = false;
44
this.timer = function(now)
52
counter_value = get_counter() >>> 0,
58
for(var i = 0; i < HPET_NUM_COUNTERS; i++)
60
config = counter_config[i << 1];
62
comparator = counter_comparator[i << 1] >>> 0;
64
if(last_check <= counter_value ?
65
comparator > last_check && comparator <= counter_value :
66
comparator > last_check || comparator <= counter_value
74
do_irq = do_irq && !(interrupt_status & 1 << i);
75
interrupt_status |= 1 << i;
80
interrupt_status &= ~(1 << i);
86
counter_comparator[i << 1] += counter_accumulator[i << 1];
92
if(me.legacy_mode && i === 0)
94
cpu.device_raise_irq(0);
96
else if(me.legacy_mode && i === 1)
98
cpu.device_raise_irq(0);
103
cpu.device_raise_irq(0);
109
last_check = counter_value;
114
function get_counter()
118
return (Date.now() - hpet_start) * HPET_FREQ_MS + hpet_offset_low | 0;
122
return hpet_offset_low;
126
function get_counter_high()
132
return (Date.now() - hpet_start) * (HPET_FREQ_MS / 0x100000000) + hpet_offset_high | 0;
136
return hpet_offset_high;
145
cpu.io.mmap_register(HPET_ADDR, 0x4000, mmio_read, mmio_write);
149
function mmio_read(addr)
151
dbg_log("Read " + h(addr, 4) + " (ctr=" + h(get_counter() >>> 0) + ")", LOG_HPET);
156
return 1 << 16 | HPET_NUM_COUNTERS - 1 << 8 | 0x8000 | 0x01 | HPET_SUPPORT_64 << 13;
161
return me.legacy_mode << 1 | hpet_enabled;
164
return get_counter();
167
return get_counter_high();
171
var register = addr >> 2 & 7,
172
counter = addr - 0x100 >> 5;
174
if(addr < 0x100 || counter >= HPET_NUM_COUNTERS || register > 5)
176
dbg_log("Read reserved address: " + h(addr), LOG_HPET);
180
dbg_log("Read counter: addr=" + h(addr) + " counter=" + h(counter, 2) +
181
" reg=" + h(register), LOG_HPET);
186
return counter_config[counter << 1] & ~HPET_COUNTER_CONFIG_MASK | HPET_COUNTER_CONFIG;
188
return counter_config[counter << 1 | 1];
191
return counter_comparator[counter << 1];
193
return counter_comparator[counter << 1 | 1];
202
function mmio_write(addr, data)
204
dbg_log("Write " + h(addr, 4) + ": " + h(data, 2), LOG_HPET);
209
dbg_log("conf: enabled=" + (data & 1) + " legacy=" + (data >> 1 & 1), LOG_HPET);
211
if((hpet_enabled ^ data) & 1)
216
hpet_start = Date.now();
221
hpet_offset_low = get_counter();
222
hpet_offset_high = get_counter_high();
226
hpet_enabled = (data & 1) === 1;
227
me.legacy_mode = (data & 2) === 2;
233
interrupt_status &= ~data;
237
hpet_offset_low = data;
241
hpet_offset_high = data;
246
var register = addr >> 2 & 7,
247
counter = addr - 0x100 >> 5;
249
if(addr < 0x100 || counter >= HPET_NUM_COUNTERS || register > 2)
251
dbg_log("Write reserved address: " + h(addr) + " data=" + h(data), LOG_HPET);
255
dbg_log("Write counter: addr=" + h(addr) + " counter=" + h(counter, 2) +
256
" reg=" + h(register) + " data=" + h(data, 2), LOG_HPET);
261
counter_config[counter << 1] = data;
268
if(counter_read_acc_next)
270
counter_accumulator[counter << 1] = data;
271
counter_read_acc_next = false;
272
dbg_log("Accumulator acc=" + h(data >>> 0, 8) + " ctr=" + h(counter, 2), LOG_HPET);
276
counter_comparator[counter << 1] = data;
278
if(counter_config[counter << 1] & 1 << 6)
280
counter_read_acc_next = true;
281
counter_config[counter << 1] &= ~(1 << 6);
286
counter_comparator[counter << 1 | 1] = data;