123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- "use strict";
- var HPET_ADDR = 0xFED00000,
- HPET_PERIOD = 0x05F5E100, // in nano seconds
- HPET_FREQ_MS = 1e12 / HPET_PERIOD, // in kHZ
- HPET_SUPPORT_64 = 0,
- HPET_COUNTER_CONFIG = 1 << 4 | HPET_SUPPORT_64 << 5,
- HPET_COUNTER_CONFIG_MASK = 1 << 4 | 1 << 5 | 1 << 15,
- HPET_NUM_COUNTERS = 4;
- /**
- * HPET - High Precision Event Timer
- * http://wiki.osdev.org/HPET
- *
- * @constructor
- * @param {CPU} cpu
- */
- function HPET(cpu)
- {
- var me = this,
- hpet_enabled = false,
- hpet_start = Date.now(),
- hpet_offset_low = 0,
- hpet_offset_high = 0,
- counter_read_acc_next = false,
- interrupt_status = 0,
- counter_config = new Int32Array(HPET_NUM_COUNTERS << 1),
- counter_comparator = new Int32Array(HPET_NUM_COUNTERS << 1),
- counter_accumulator = new Int32Array(HPET_NUM_COUNTERS << 1);
- //var counter_last_irq = new Int32Array(HPET_NUM_COUNTERS << 1);
- var last_check = 0;
- this.legacy_mode = false;
- this.timer = function(now)
- {
- if(!hpet_enabled)
- {
- return 100;
- }
- var
- counter_value = get_counter() >>> 0,
- config,
- //last_irq,
- comparator,
- do_irq;
- for(var i = 0; i < HPET_NUM_COUNTERS; i++)
- {
- config = counter_config[i << 1];
- //last_irq = counter_last_irq[i << 1] >>> 0;
- comparator = counter_comparator[i << 1] >>> 0;
- if(last_check <= counter_value ?
- comparator > last_check && comparator <= counter_value :
- comparator > last_check || comparator <= counter_value
- ) {
- do_irq = config & 4;
- //counter_last_irq[i << 1] = comparator;
- if(config & 2)
- {
- // level triggered
- do_irq = do_irq && !(interrupt_status & 1 << i);
- interrupt_status |= 1 << i;
- }
- else
- {
- // edge-triggered
- interrupt_status &= ~(1 << i);
- }
- if(config & 1 << 3)
- {
- // periodic mode
- counter_comparator[i << 1] += counter_accumulator[i << 1];
- }
- //dbg_log("do_irq=" + do_irq, LOG_HPET);
- if(do_irq)
- {
- if(me.legacy_mode && i === 0)
- {
- cpu.device_raise_irq(0);
- }
- else if(me.legacy_mode && i === 1)
- {
- cpu.device_raise_irq(0);
- }
- else
- {
- // TODO
- cpu.device_raise_irq(0);
- }
- }
- }
- }
- last_check = counter_value;
- return 100; // TODO
- };
- function get_counter()
- {
- if(hpet_enabled)
- {
- return (Date.now() - hpet_start) * HPET_FREQ_MS + hpet_offset_low | 0;
- }
- else
- {
- return hpet_offset_low;
- }
- }
- function get_counter_high()
- {
- if(HPET_SUPPORT_64)
- {
- if(hpet_enabled)
- {
- return (Date.now() - hpet_start) * (HPET_FREQ_MS / 0x100000000) + hpet_offset_high | 0;
- }
- else
- {
- return hpet_offset_high;
- }
- }
- else
- {
- return 0;
- }
- }
- cpu.io.mmap_register(HPET_ADDR, 0x4000, mmio_read, mmio_write);
- function mmio_read(addr)
- {
- dbg_log("Read " + h(addr, 4) + " (ctr=" + h(get_counter() >>> 0) + ")", LOG_HPET);
- switch(addr)
- {
- case 0:
- return 1 << 16 | HPET_NUM_COUNTERS - 1 << 8 | 0x8000 | 0x01 | HPET_SUPPORT_64 << 13;
- case 4:
- return HPET_PERIOD;
- case 0x10:
- return me.legacy_mode << 1 | hpet_enabled;
- case 0xF0:
- return get_counter();
- case 0xF4:
- return get_counter_high();
- }
- // read from counter register
- var register = addr >> 2 & 7,
- counter = addr - 0x100 >> 5;
- if(addr < 0x100 || counter >= HPET_NUM_COUNTERS || register > 5)
- {
- dbg_log("Read reserved address: " + h(addr), LOG_HPET);
- return 0;
- }
- dbg_log("Read counter: addr=" + h(addr) + " counter=" + h(counter, 2) +
- " reg=" + h(register), LOG_HPET);
- switch(register)
- {
- case 0:
- return counter_config[counter << 1] & ~HPET_COUNTER_CONFIG_MASK | HPET_COUNTER_CONFIG;
- case 1:
- return counter_config[counter << 1 | 1];
- case 2:
- return counter_comparator[counter << 1];
- case 3:
- return counter_comparator[counter << 1 | 1];
- case 4:
- case 5:
- // TODO interrupt route register
- return 0;
- }
- }
- function mmio_write(addr, data)
- {
- dbg_log("Write " + h(addr, 4) + ": " + h(data, 2), LOG_HPET);
- switch(addr)
- {
- case 0x10:
- dbg_log("conf: enabled=" + (data & 1) + " legacy=" + (data >> 1 & 1), LOG_HPET);
- if((hpet_enabled ^ data) & 1)
- {
- if(data & 1)
- {
- // counter is enabled now, start counting now
- hpet_start = Date.now();
- }
- else
- {
- // counter is disabled now, save current count
- hpet_offset_low = get_counter();
- hpet_offset_high = get_counter_high();
- }
- }
- hpet_enabled = (data & 1) === 1;
- me.legacy_mode = (data & 2) === 2;
- return;
- case 0x20:
- // writing a 1 clears bits
- interrupt_status &= ~data;
- return;
- case 0xF0:
- hpet_offset_low = data;
- return;
- case 0xF4:
- hpet_offset_high = data;
- return;
- }
- // read from counter register
- var register = addr >> 2 & 7,
- counter = addr - 0x100 >> 5;
- if(addr < 0x100 || counter >= HPET_NUM_COUNTERS || register > 2)
- {
- dbg_log("Write reserved address: " + h(addr) + " data=" + h(data), LOG_HPET);
- return;
- }
- dbg_log("Write counter: addr=" + h(addr) + " counter=" + h(counter, 2) +
- " reg=" + h(register) + " data=" + h(data, 2), LOG_HPET);
- switch(register)
- {
- case 0:
- counter_config[counter << 1] = data;
- break;
- case 1:
- //counter_config[counter << 1 | 1] = data;
- break;
- case 2:
- if(counter_read_acc_next)
- {
- counter_accumulator[counter << 1] = data;
- counter_read_acc_next = false;
- dbg_log("Accumulator acc=" + h(data >>> 0, 8) + " ctr=" + h(counter, 2), LOG_HPET);
- }
- else
- {
- counter_comparator[counter << 1] = data;
- if(counter_config[counter << 1] & 1 << 6)
- {
- counter_read_acc_next = true;
- counter_config[counter << 1] &= ~(1 << 6);
- }
- }
- break;
- case 3:
- counter_comparator[counter << 1 | 1] = data;
- break;
- case 4:
- case 5:
- // TODO interrupt route register
- }
- }
- }
|