SandboXP

Форк
0
/
hpet.js 
295 строк · 7.9 Кб
1
"use strict";
2

3

4
var HPET_ADDR = 0xFED00000,
5
    HPET_PERIOD = 0x05F5E100, // in nano seconds
6
    HPET_FREQ_MS = 1e12 / HPET_PERIOD, // in kHZ
7
    HPET_SUPPORT_64 = 0,
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;
11

12
/**
13
 * HPET - High Precision Event Timer
14
 * http://wiki.osdev.org/HPET
15
 *
16
 * @constructor
17
 * @param {CPU} cpu
18
 */
19
function HPET(cpu)
20
{
21
    var me = this,
22

23
        hpet_enabled = false,
24
        hpet_start = Date.now(),
25

26
        hpet_offset_low = 0,
27
        hpet_offset_high = 0,
28

29
        counter_read_acc_next = false,
30
        interrupt_status = 0,
31

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);
35

36
    //var counter_last_irq = new Int32Array(HPET_NUM_COUNTERS << 1);
37

38

39
    var last_check = 0;
40

41

42
    this.legacy_mode = false;
43

44
    this.timer = function(now)
45
    {
46
        if(!hpet_enabled)
47
        {
48
            return 100;
49
        }
50

51
        var
52
            counter_value = get_counter() >>> 0,
53
            config,
54
            //last_irq,
55
            comparator,
56
            do_irq;
57

58
        for(var i = 0; i < HPET_NUM_COUNTERS; i++)
59
        {
60
            config = counter_config[i << 1];
61
            //last_irq = counter_last_irq[i << 1] >>> 0;
62
            comparator = counter_comparator[i << 1] >>> 0;
63

64
            if(last_check <= counter_value ?
65
                    comparator > last_check && comparator <= counter_value :
66
                    comparator > last_check || comparator <= counter_value
67
            ) {
68
                do_irq = config & 4;
69
                //counter_last_irq[i << 1] = comparator;
70

71
                if(config & 2)
72
                {
73
                    // level triggered
74
                    do_irq = do_irq && !(interrupt_status & 1 << i);
75
                    interrupt_status |= 1 << i;
76
                }
77
                else
78
                {
79
                    // edge-triggered
80
                    interrupt_status &= ~(1 << i);
81
                }
82

83
                if(config & 1 << 3)
84
                {
85
                    // periodic mode
86
                    counter_comparator[i << 1] += counter_accumulator[i << 1];
87
                }
88

89
                //dbg_log("do_irq=" + do_irq, LOG_HPET);
90
                if(do_irq)
91
                {
92
                    if(me.legacy_mode && i === 0)
93
                    {
94
                        cpu.device_raise_irq(0);
95
                    }
96
                    else if(me.legacy_mode && i === 1)
97
                    {
98
                        cpu.device_raise_irq(0);
99
                    }
100
                    else
101
                    {
102
                        // TODO
103
                        cpu.device_raise_irq(0);
104
                    }
105
                }
106
            }
107
        }
108

109
        last_check = counter_value;
110

111
        return 100; // TODO
112
    };
113

114
    function get_counter()
115
    {
116
        if(hpet_enabled)
117
        {
118
            return (Date.now() - hpet_start) * HPET_FREQ_MS + hpet_offset_low | 0;
119
        }
120
        else
121
        {
122
            return hpet_offset_low;
123
        }
124
    }
125

126
    function get_counter_high()
127
    {
128
        if(HPET_SUPPORT_64)
129
        {
130
            if(hpet_enabled)
131
            {
132
                return (Date.now() - hpet_start) * (HPET_FREQ_MS / 0x100000000) + hpet_offset_high | 0;
133
            }
134
            else
135
            {
136
                return hpet_offset_high;
137
            }
138
        }
139
        else
140
        {
141
            return 0;
142
        }
143
    }
144

145
    cpu.io.mmap_register(HPET_ADDR, 0x4000, mmio_read, mmio_write);
146

147

148

149
    function mmio_read(addr)
150
    {
151
        dbg_log("Read " + h(addr, 4) + " (ctr=" + h(get_counter() >>> 0) + ")", LOG_HPET);
152

153
        switch(addr)
154
        {
155
            case 0:
156
                return 1 << 16 | HPET_NUM_COUNTERS - 1 << 8 | 0x8000 | 0x01 | HPET_SUPPORT_64 << 13;
157
            case 4:
158
                return HPET_PERIOD;
159

160
            case 0x10:
161
                return me.legacy_mode << 1 | hpet_enabled;
162

163
            case 0xF0:
164
                return get_counter();
165

166
            case 0xF4:
167
                return get_counter_high();
168
        }
169

170
        // read from counter register
171
        var register = addr >> 2 & 7,
172
            counter = addr - 0x100 >> 5;
173

174
        if(addr < 0x100 || counter >= HPET_NUM_COUNTERS || register > 5)
175
        {
176
            dbg_log("Read reserved address: " + h(addr), LOG_HPET);
177
            return 0;
178
        }
179

180
        dbg_log("Read counter: addr=" + h(addr) + " counter=" + h(counter, 2) +
181
                " reg=" + h(register), LOG_HPET);
182

183
        switch(register)
184
        {
185
            case 0:
186
                return counter_config[counter << 1] & ~HPET_COUNTER_CONFIG_MASK | HPET_COUNTER_CONFIG;
187
            case 1:
188
                return counter_config[counter << 1 | 1];
189

190
            case 2:
191
                return counter_comparator[counter << 1];
192
            case 3:
193
                return counter_comparator[counter << 1 | 1];
194

195
            case 4:
196
            case 5:
197
                // TODO interrupt route register
198
                return 0;
199
        }
200
    }
201

202
    function mmio_write(addr, data)
203
    {
204
        dbg_log("Write " + h(addr, 4) + ": " + h(data, 2), LOG_HPET);
205

206
        switch(addr)
207
        {
208
            case 0x10:
209
                dbg_log("conf: enabled=" + (data & 1) + " legacy=" + (data >> 1 & 1), LOG_HPET);
210

211
                if((hpet_enabled ^ data) & 1)
212
                {
213
                    if(data & 1)
214
                    {
215
                        // counter is enabled now, start counting now
216
                        hpet_start = Date.now();
217
                    }
218
                    else
219
                    {
220
                        // counter is disabled now, save current count
221
                        hpet_offset_low = get_counter();
222
                        hpet_offset_high = get_counter_high();
223
                    }
224
                }
225

226
                hpet_enabled = (data & 1) === 1;
227
                me.legacy_mode = (data & 2) === 2;
228

229
                return;
230

231
            case 0x20:
232
                // writing a 1 clears bits
233
                interrupt_status &= ~data;
234
                return;
235

236
            case 0xF0:
237
                hpet_offset_low = data;
238
                return;
239

240
            case 0xF4:
241
                hpet_offset_high = data;
242
                return;
243
        }
244

245
        // read from counter register
246
        var register = addr >> 2 & 7,
247
            counter = addr - 0x100 >> 5;
248

249
        if(addr < 0x100 || counter >= HPET_NUM_COUNTERS || register > 2)
250
        {
251
            dbg_log("Write reserved address: " + h(addr) + " data=" + h(data), LOG_HPET);
252
            return;
253
        }
254

255
        dbg_log("Write counter: addr=" + h(addr) + " counter=" + h(counter, 2) +
256
                " reg=" + h(register) + " data=" + h(data, 2), LOG_HPET);
257

258
        switch(register)
259
        {
260
            case 0:
261
                counter_config[counter << 1] = data;
262
                break;
263
            case 1:
264
                //counter_config[counter << 1 | 1] = data;
265
                break;
266

267
            case 2:
268
                if(counter_read_acc_next)
269
                {
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);
273
                }
274
                else
275
                {
276
                    counter_comparator[counter << 1] = data;
277

278
                    if(counter_config[counter << 1] & 1 << 6)
279
                    {
280
                        counter_read_acc_next = true;
281
                        counter_config[counter << 1] &= ~(1 << 6);
282
                    }
283
                }
284
                break;
285
            case 3:
286
                counter_comparator[counter << 1 | 1] = data;
287
                break;
288

289
            case 4:
290
            case 5:
291
                // TODO interrupt route register
292

293
        }
294
    }
295
}
296

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.