SandboXP

Форк
0
/
pic.js 
573 строки · 15.0 Кб
1
"use strict";
2

3
/** @const */
4
var PIC_LOG_VERBOSE = false;
5

6
/**
7
 * Programmable Interrupt Controller
8
 * http://stanislavs.org/helppc/8259.html
9
 *
10
 * @constructor
11
 * @param {CPU} cpu
12
 * @param {PIC=} master
13
 */
14
function PIC(cpu, master)
15
{
16
    /**
17
     * all irqs off
18
     * @type {number}
19
     */
20
    this.irq_mask = 0;
21

22
    /**
23
     * @type {number}
24
     *
25
     * Bogus default value (both master and slave mapped to 0).
26
     * Will be initialized by the BIOS
27
     */
28
    this.irq_map = 0;
29

30
    /**
31
     * in-service register
32
     * Holds interrupts that are currently being serviced
33
     * @type {number}
34
     */
35
    this.isr = 0;
36

37
    /**
38
     * interrupt request register
39
     * Holds interrupts that have been requested
40
     * @type {number}
41
     */
42
    this.irr = 0;
43

44
    this.irq_value = 0;
45

46
    /**
47
     * @type {number}
48
     */
49
    this.requested_irq = -1;
50

51
    this.master = master;
52
    this.is_master = this.master === undefined;
53
    this.slave = undefined;
54

55
    this.name = this.is_master ? "master" : "slave ";
56

57
    this.expect_icw4 = false;
58
    this.state = 0;
59
    this.read_isr = 0;
60
    this.auto_eoi = 1;
61
    this.special_mask_mode = 0;
62

63
    this.elcr = 0;
64

65
    this.cpu = cpu;
66

67
    // Checking for callable interrupts:
68
    // (cpu changes interrupt flag) -> cpu.handle_irqs -> pic.check_irqs -> cpu.pic_call_irq
69
    // (pic changes isr/irr) -> cpu.handle_irqs -> ...
70

71
    // triggering irqs:
72
    // (io device has irq) -> cpu.device_raise_irq -> pic.set_irq -> cpu.handle_irqs -> (see above)
73

74

75
    if(this.is_master)
76
    {
77
        this.slave = new PIC(this.cpu, this);
78

79
        this.check_irqs = function()
80
        {
81
            if(this.requested_irq >= 0)
82
            {
83
                PIC_LOG_VERBOSE && dbg_log("master> Already requested irq: " + this.requested_irq, LOG_PIC);
84
                this.cpu.handle_irqs();
85
                return;
86
            }
87

88
            var enabled_irr = this.irr & this.irq_mask;
89

90
            if(!enabled_irr)
91
            {
92
                if(PIC_LOG_VERBOSE)
93
                {
94
                    dbg_log("master> no unmasked irrs. irr=" + h(this.irr, 2) +
95
                            " mask=" + h(this.irq_mask & 0xff, 2) + " isr=" + h(this.isr, 2), LOG_PIC);
96
                }
97
                return;
98
            }
99

100
            var irq_mask = enabled_irr & -enabled_irr;
101
            var special_mask = this.special_mask_mode ? this.irq_mask : -1;
102

103
            if(this.isr && (this.isr & -this.isr & special_mask) <= irq_mask)
104
            {
105
                // wait for eoi of higher or same priority interrupt
106
                dbg_log("master> higher prio: isr=" + h(this.isr, 2) +
107
                        " mask=" + h(this.irq_mask & 0xff, 2) + " irq=" + h(irq_mask, 2), LOG_PIC);
108
                return;
109
            }
110

111
            dbg_assert(irq_mask !== 0);
112
            var irq_number = v86util.int_log2_byte(irq_mask);
113
            dbg_assert(irq_mask === (1 << irq_number));
114

115
            PIC_LOG_VERBOSE && dbg_log("master> request irq " + irq_number, LOG_PIC);
116

117
            this.requested_irq = irq_number;
118
            this.cpu.handle_irqs();
119
        };
120

121
        this.acknowledge_irq = function()
122
        {
123
            if(this.requested_irq === -1)
124
            {
125
                return;
126
            }
127

128
            if(this.irr === 0)
129
            {
130
                PIC_LOG_VERBOSE && dbg_log("master> spurious requested=" + this.requested_irq, LOG_PIC);
131
                this.requested_irq = -1;
132
                //this.cpu.pic_call_irq(this.irq_map | 7);
133
                return;
134
            }
135
            dbg_assert(this.irr); // spurious
136
            dbg_assert(this.requested_irq >= 0);
137

138
            var irq_mask = 1 << this.requested_irq;
139

140
            if((this.elcr & irq_mask) === 0) // not in level mode
141
            {
142
                this.irr &= ~irq_mask;
143
            }
144

145
            if(!this.auto_eoi)
146
            {
147
                this.isr |= irq_mask;
148
            }
149

150
            PIC_LOG_VERBOSE && dbg_log("master> acknowledge " + this.requested_irq, LOG_PIC);
151
            if(this.requested_irq === 2)
152
            {
153
                this.slave.acknowledge_irq();
154
            }
155
            else
156
            {
157
                this.cpu.pic_call_irq(this.irq_map | this.requested_irq);
158
            }
159

160
            this.requested_irq = -1;
161
            this.check_irqs();
162
        };
163
    }
164
    else
165
    {
166
        // is slave
167
        this.check_irqs = function()
168
        {
169
            if(this.requested_irq >= 0)
170
            {
171
                PIC_LOG_VERBOSE && dbg_log("slave > Already requested irq: " + this.requested_irq, LOG_PIC);
172
                this.cpu.handle_irqs();
173
                return;
174
            }
175

176
            var enabled_irr = this.irr & this.irq_mask;
177

178
            if(!enabled_irr)
179
            {
180
                if(PIC_LOG_VERBOSE)
181
                {
182
                    dbg_log("slave > no unmasked irrs. irr=" + h(this.irr, 2) +
183
                            " mask=" + h(this.irq_mask & 0xff, 2) + " isr=" + h(this.isr, 2), LOG_PIC);
184
                }
185
                return;
186
            }
187

188
            var irq_mask = enabled_irr & -enabled_irr;
189
            var special_mask = this.special_mask_mode ? this.irq_mask : -1;
190

191
            if(this.isr && (this.isr & -this.isr & special_mask) <= irq_mask)
192
            {
193
                // wait for eoi of higher or same priority interrupt
194
                PIC_LOG_VERBOSE && dbg_log("slave > higher prio: isr=" + h(this.isr, 2) + " irq=" + h(irq_mask, 2), LOG_PIC);
195
                return;
196
            }
197

198
            dbg_assert(irq_mask !== 0);
199
            var irq_number = v86util.int_log2_byte(irq_mask);
200
            dbg_assert(irq_mask === (1 << irq_number));
201

202
            PIC_LOG_VERBOSE && dbg_log("slave > request irq " + irq_number, LOG_PIC);
203
            this.requested_irq = irq_number;
204
            this.master.set_irq(2);
205
        };
206

207
        this.acknowledge_irq = function()
208
        {
209
            if(this.requested_irq === -1)
210
            {
211
                return;
212
            }
213

214
            if(this.irr === 0)
215
            {
216
                PIC_LOG_VERBOSE && dbg_log("slave > spurious requested=" + this.requested_irq, LOG_PIC);
217
                this.requested_irq = -1;
218
                this.master.irq_value &= ~(1 << 2);
219
                this.cpu.pic_call_irq(this.irq_map | 7);
220
                return;
221
            }
222

223
            dbg_assert(this.irr); // spurious
224
            dbg_assert(this.requested_irq >= 0);
225

226
            var irq_mask = 1 << this.requested_irq;
227

228
            if((this.elcr & irq_mask) === 0) // not in level mode
229
            {
230
                this.irr &= ~irq_mask;
231
            }
232

233
            if(!this.auto_eoi)
234
            {
235
                this.isr |= irq_mask;
236
            }
237

238
            this.master.irq_value &= ~(1 << 2);
239
            PIC_LOG_VERBOSE && dbg_log("slave > acknowledge " + this.requested_irq, LOG_PIC);
240
            this.cpu.pic_call_irq(this.irq_map | this.requested_irq);
241

242
            this.requested_irq = -1;
243
            this.check_irqs();
244
        };
245
    }
246

247
    this.dump = function()
248
    {
249
        dbg_log("mask: " + h(this.irq_mask & 0xFF), LOG_PIC);
250
        dbg_log("base: " + h(this.irq_map), LOG_PIC);
251
        dbg_log("requested: " + h(this.irr), LOG_PIC);
252
        dbg_log("serviced: " + h(this.isr), LOG_PIC);
253

254
        if(this.is_master)
255
        {
256
            this.slave.dump();
257
        }
258
    };
259

260
    var io_base;
261
    var iobase_high;
262
    if(this.is_master)
263
    {
264
        io_base = 0x20;
265
        iobase_high = 0x4D0;
266
    }
267
    else
268
    {
269
        io_base = 0xA0;
270
        iobase_high = 0x4D1;
271
    }
272

273
    this.cpu.io.register_write(io_base, this, this.port20_write);
274
    this.cpu.io.register_read(io_base, this, this.port20_read);
275

276
    this.cpu.io.register_write(io_base | 1, this, this.port21_write);
277
    this.cpu.io.register_read(io_base | 1, this, this.port21_read);
278

279
    this.cpu.io.register_write(iobase_high, this, this.port4D0_write);
280
    this.cpu.io.register_read(iobase_high, this, this.port4D0_read);
281

282

283
    if(this.is_master)
284
    {
285
        this.set_irq = function(irq_number)
286
        {
287
            dbg_assert(irq_number >= 0 && irq_number < 16);
288

289
            if(irq_number >= 8)
290
            {
291
                this.slave.set_irq(irq_number - 8);
292
                return;
293
            }
294

295
            var irq_mask = 1 << irq_number;
296
            if((this.irq_value & irq_mask) === 0)
297
            {
298
                if(PIC_LOG_VERBOSE)
299
                {
300
                    dbg_log("master> set irq " + irq_number, LOG_PIC);
301
                }
302

303
                this.irr |= irq_mask;
304
                this.irq_value |= irq_mask;
305
                this.check_irqs();
306
            }
307
            else
308
            {
309
                if(PIC_LOG_VERBOSE)
310
                {
311
                    dbg_log("master> set irq " + irq_number + ": already set!", LOG_PIC);
312
                }
313
            }
314
        };
315

316
        this.clear_irq = function(irq_number)
317
        {
318
            dbg_assert(irq_number >= 0 && irq_number < 16);
319
            if(PIC_LOG_VERBOSE)
320
            {
321
                dbg_log("master> clear irq " + irq_number, LOG_PIC);
322
            }
323

324
            if(irq_number >= 8)
325
            {
326
                this.slave.clear_irq(irq_number - 8);
327
                return;
328
            }
329

330
            var irq_mask = 1 << irq_number;
331
            if(this.irq_value & irq_mask)
332
            {
333
                this.irq_value &= ~irq_mask;
334
                this.irr &= ~irq_mask;
335
                this.check_irqs();
336
            }
337
        };
338
    }
339
    else
340
    {
341
        this.set_irq = function(irq_number)
342
        {
343
            dbg_assert(irq_number >= 0 && irq_number < 8);
344

345
            var irq_mask = 1 << irq_number;
346
            if((this.irq_value & irq_mask) === 0)
347
            {
348
                if(PIC_LOG_VERBOSE)
349
                {
350
                    dbg_log("slave > set irq " + irq_number, LOG_PIC);
351
                }
352

353
                this.irr |= irq_mask;
354
                this.irq_value |= irq_mask;
355
                this.check_irqs();
356
            }
357
            else
358
            {
359
                if(PIC_LOG_VERBOSE)
360
                {
361
                    dbg_log("slave > set irq " + irq_number + ": already set!", LOG_PIC);
362
                }
363
            }
364
        };
365

366
        this.clear_irq = function(irq_number)
367
        {
368
            dbg_assert(irq_number >= 0 && irq_number < 8);
369
            if(PIC_LOG_VERBOSE)
370
            {
371
                dbg_log("slave > clear irq " + irq_number, LOG_PIC);
372
            }
373

374
            var irq_mask = 1 << irq_number;
375
            if(this.irq_value & irq_mask)
376
            {
377
                this.irq_value &= ~irq_mask;
378
                this.irr &= ~irq_mask;
379
                this.check_irqs();
380
            }
381
        };
382
    }
383

384
    this.get_isr = function()
385
    {
386
        return this.isr;
387
    };
388
}
389

390
PIC.prototype.get_state = function()
391
{
392
    var state = [];
393

394
    state[0] = this.irq_mask;
395
    state[1] = this.irq_map;
396
    state[2] = this.isr;
397
    state[3] = this.irr;
398
    state[4] = this.is_master;
399
    state[5] = this.slave;
400
    state[6] = this.expect_icw4;
401
    state[7] = this.state;
402
    state[8] = this.read_isr;
403
    state[9] = this.auto_eoi;
404
    state[10] = this.elcr;
405

406
    return state;
407
};
408

409
PIC.prototype.set_state = function(state)
410
{
411
    this.irq_mask = state[0];
412
    this.irq_map = state[1];
413
    this.isr = state[2];
414
    this.irr = state[3];
415
    this.is_master = state[4];
416
    this.slave && this.slave.set_state(state[5]);
417
    this.expect_icw4 = state[6];
418
    this.state = state[7];
419
    this.read_isr = state[8];
420
    this.auto_eoi = state[9];
421
    this.elcr = state[10];
422
};
423

424
PIC.prototype.port20_write = function(data_byte)
425
{
426
    //dbg_log("20 write: " + h(data_byte), LOG_PIC);
427
    if(data_byte & 0x10) // xxxx1xxx
428
    {
429
        // icw1
430
        dbg_log("icw1 = " + h(data_byte), LOG_PIC);
431
        this.isr = 0;
432
        this.irr = 0;
433
        this.irq_mask = 0;
434
        this.irq_value = 0;
435
        this.auto_eoi = 1;
436
        this.requested_irq = -1;
437

438
        this.expect_icw4 = data_byte & 1;
439
        this.state = 1;
440
    }
441
    else if(data_byte & 8) // xxx01xxx
442
    {
443
        // ocw3
444
        dbg_log("ocw3: " + h(data_byte), LOG_PIC);
445
        if(data_byte & 2)
446
        {
447
            this.read_isr = data_byte & 1;
448
        }
449
        if(data_byte & 4)
450
        {
451
            dbg_assert(false, "unimplemented: polling", LOG_PIC);
452
        }
453
        if(data_byte & 0x40)
454
        {
455
            this.special_mask_mode = (data_byte & 0x20) === 0x20;
456
            dbg_log("special mask mode: " + this.special_mask_mode, LOG_PIC);
457
        }
458
    }
459
    else // xxx00xxx
460
    {
461
        // ocw2
462
        // end of interrupt
463
        dbg_log("eoi: " + h(data_byte) + " (" + this.name + ")", LOG_PIC);
464

465
        var eoi_type = data_byte >> 5;
466

467
        if(eoi_type === 1)
468
        {
469
            // non-specific eoi
470
            this.isr &= this.isr - 1;
471
            dbg_log("new isr: " + h(this.isr, 2), LOG_PIC);
472
        }
473
        else if(eoi_type === 3)
474
        {
475
            // specific eoi
476
            this.isr &= ~(1 << (data_byte & 7));
477
        }
478
        else if((data_byte & 0xC8) === 0xC0)
479
        {
480
            // os2 v4
481
            let priority = data_byte & 7;
482
            dbg_log("lowest priority: " + h(priority), LOG_PIC);
483
        }
484
        else
485
        {
486
            dbg_log("Unknown eoi: " + h(data_byte), LOG_PIC);
487
            dbg_assert(false);
488
            this.isr &= this.isr - 1;
489
        }
490

491
        this.check_irqs();
492
    }
493
};
494

495
PIC.prototype.port20_read = function()
496
{
497
    if(this.read_isr)
498
    {
499
        dbg_log("read port 20h (isr): " + h(this.isr), LOG_PIC);
500
        return this.isr;
501
    }
502
    else
503
    {
504
        dbg_log("read port 20h (irr): " + h(this.irr), LOG_PIC);
505
        return this.irr;
506
    }
507
};
508

509
PIC.prototype.port21_write = function(data_byte)
510
{
511
    //dbg_log("21 write: " + h(data_byte), LOG_PIC);
512
    if(this.state === 0)
513
    {
514
        if(this.expect_icw4)
515
        {
516
            // icw4
517
            this.expect_icw4 = false;
518
            this.auto_eoi = data_byte & 2;
519
            dbg_log("icw4: " + h(data_byte) + " autoeoi=" + this.auto_eoi, LOG_PIC);
520

521
            if((data_byte & 1) === 0)
522
            {
523
                dbg_assert(false, "unimplemented: not 8086 mode", LOG_PIC);
524
            }
525
        }
526
        else
527
        {
528
            // ocw1
529
            this.irq_mask = ~data_byte;
530

531
            if(PIC_LOG_VERBOSE)
532
            {
533
                dbg_log("interrupt mask: " + (this.irq_mask & 0xFF).toString(2) +
534
                        " (" + this.name + ")", LOG_PIC);
535
            }
536

537
            this.check_irqs();
538
        }
539
    }
540
    else if(this.state === 1)
541
    {
542
        // icw2
543
        this.irq_map = data_byte;
544
        dbg_log("interrupts are mapped to " + h(this.irq_map) +
545
                " (" + this.name + ")", LOG_PIC);
546
        this.state++;
547
    }
548
    else if(this.state === 2)
549
    {
550
        // icw3
551
        this.state = 0;
552
        dbg_log("icw3: " + h(data_byte), LOG_PIC);
553
    }
554
};
555

556
PIC.prototype.port21_read = function()
557
{
558
    dbg_log("21h read " + h(~this.irq_mask & 0xff), LOG_PIC);
559
    return ~this.irq_mask & 0xFF;
560
};
561

562
PIC.prototype.port4D0_read = function()
563
{
564
    dbg_log("elcr read: " + h(this.elcr, 2), LOG_PIC);
565
    return this.elcr;
566
};
567

568
PIC.prototype.port4D0_write = function(value)
569
{
570
    dbg_log("elcr write: " + h(value, 2), LOG_PIC);
571
    // set by seabios to 00 0C (only set for pci interrupts)
572
    this.elcr = value;
573
};
574

575

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

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

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

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