4
var PIC_LOG_VERBOSE = false;
14
function PIC(cpu, master)
49
this.requested_irq = -1;
52
this.is_master = this.master === undefined;
53
this.slave = undefined;
55
this.name = this.is_master ? "master" : "slave ";
57
this.expect_icw4 = false;
61
this.special_mask_mode = 0;
77
this.slave = new PIC(this.cpu, this);
79
this.check_irqs = function()
81
if(this.requested_irq >= 0)
83
PIC_LOG_VERBOSE && dbg_log("master> Already requested irq: " + this.requested_irq, LOG_PIC);
84
this.cpu.handle_irqs();
88
var enabled_irr = this.irr & this.irq_mask;
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);
100
var irq_mask = enabled_irr & -enabled_irr;
101
var special_mask = this.special_mask_mode ? this.irq_mask : -1;
103
if(this.isr && (this.isr & -this.isr & special_mask) <= irq_mask)
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);
111
dbg_assert(irq_mask !== 0);
112
var irq_number = v86util.int_log2_byte(irq_mask);
113
dbg_assert(irq_mask === (1 << irq_number));
115
PIC_LOG_VERBOSE && dbg_log("master> request irq " + irq_number, LOG_PIC);
117
this.requested_irq = irq_number;
118
this.cpu.handle_irqs();
121
this.acknowledge_irq = function()
123
if(this.requested_irq === -1)
130
PIC_LOG_VERBOSE && dbg_log("master> spurious requested=" + this.requested_irq, LOG_PIC);
131
this.requested_irq = -1;
135
dbg_assert(this.irr);
136
dbg_assert(this.requested_irq >= 0);
138
var irq_mask = 1 << this.requested_irq;
140
if((this.elcr & irq_mask) === 0)
142
this.irr &= ~irq_mask;
147
this.isr |= irq_mask;
150
PIC_LOG_VERBOSE && dbg_log("master> acknowledge " + this.requested_irq, LOG_PIC);
151
if(this.requested_irq === 2)
153
this.slave.acknowledge_irq();
157
this.cpu.pic_call_irq(this.irq_map | this.requested_irq);
160
this.requested_irq = -1;
167
this.check_irqs = function()
169
if(this.requested_irq >= 0)
171
PIC_LOG_VERBOSE && dbg_log("slave > Already requested irq: " + this.requested_irq, LOG_PIC);
172
this.cpu.handle_irqs();
176
var enabled_irr = this.irr & this.irq_mask;
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);
188
var irq_mask = enabled_irr & -enabled_irr;
189
var special_mask = this.special_mask_mode ? this.irq_mask : -1;
191
if(this.isr && (this.isr & -this.isr & special_mask) <= irq_mask)
194
PIC_LOG_VERBOSE && dbg_log("slave > higher prio: isr=" + h(this.isr, 2) + " irq=" + h(irq_mask, 2), LOG_PIC);
198
dbg_assert(irq_mask !== 0);
199
var irq_number = v86util.int_log2_byte(irq_mask);
200
dbg_assert(irq_mask === (1 << irq_number));
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);
207
this.acknowledge_irq = function()
209
if(this.requested_irq === -1)
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);
223
dbg_assert(this.irr);
224
dbg_assert(this.requested_irq >= 0);
226
var irq_mask = 1 << this.requested_irq;
228
if((this.elcr & irq_mask) === 0)
230
this.irr &= ~irq_mask;
235
this.isr |= irq_mask;
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);
242
this.requested_irq = -1;
247
this.dump = function()
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);
273
this.cpu.io.register_write(io_base, this, this.port20_write);
274
this.cpu.io.register_read(io_base, this, this.port20_read);
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);
279
this.cpu.io.register_write(iobase_high, this, this.port4D0_write);
280
this.cpu.io.register_read(iobase_high, this, this.port4D0_read);
285
this.set_irq = function(irq_number)
287
dbg_assert(irq_number >= 0 && irq_number < 16);
291
this.slave.set_irq(irq_number - 8);
295
var irq_mask = 1 << irq_number;
296
if((this.irq_value & irq_mask) === 0)
300
dbg_log("master> set irq " + irq_number, LOG_PIC);
303
this.irr |= irq_mask;
304
this.irq_value |= irq_mask;
311
dbg_log("master> set irq " + irq_number + ": already set!", LOG_PIC);
316
this.clear_irq = function(irq_number)
318
dbg_assert(irq_number >= 0 && irq_number < 16);
321
dbg_log("master> clear irq " + irq_number, LOG_PIC);
326
this.slave.clear_irq(irq_number - 8);
330
var irq_mask = 1 << irq_number;
331
if(this.irq_value & irq_mask)
333
this.irq_value &= ~irq_mask;
334
this.irr &= ~irq_mask;
341
this.set_irq = function(irq_number)
343
dbg_assert(irq_number >= 0 && irq_number < 8);
345
var irq_mask = 1 << irq_number;
346
if((this.irq_value & irq_mask) === 0)
350
dbg_log("slave > set irq " + irq_number, LOG_PIC);
353
this.irr |= irq_mask;
354
this.irq_value |= irq_mask;
361
dbg_log("slave > set irq " + irq_number + ": already set!", LOG_PIC);
366
this.clear_irq = function(irq_number)
368
dbg_assert(irq_number >= 0 && irq_number < 8);
371
dbg_log("slave > clear irq " + irq_number, LOG_PIC);
374
var irq_mask = 1 << irq_number;
375
if(this.irq_value & irq_mask)
377
this.irq_value &= ~irq_mask;
378
this.irr &= ~irq_mask;
384
this.get_isr = function()
390
PIC.prototype.get_state = function()
394
state[0] = this.irq_mask;
395
state[1] = this.irq_map;
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;
409
PIC.prototype.set_state = function(state)
411
this.irq_mask = state[0];
412
this.irq_map = state[1];
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];
424
PIC.prototype.port20_write = function(data_byte)
430
dbg_log("icw1 = " + h(data_byte), LOG_PIC);
436
this.requested_irq = -1;
438
this.expect_icw4 = data_byte & 1;
441
else if(data_byte & 8)
444
dbg_log("ocw3: " + h(data_byte), LOG_PIC);
447
this.read_isr = data_byte & 1;
451
dbg_assert(false, "unimplemented: polling", LOG_PIC);
455
this.special_mask_mode = (data_byte & 0x20) === 0x20;
456
dbg_log("special mask mode: " + this.special_mask_mode, LOG_PIC);
463
dbg_log("eoi: " + h(data_byte) + " (" + this.name + ")", LOG_PIC);
465
var eoi_type = data_byte >> 5;
470
this.isr &= this.isr - 1;
471
dbg_log("new isr: " + h(this.isr, 2), LOG_PIC);
473
else if(eoi_type === 3)
476
this.isr &= ~(1 << (data_byte & 7));
478
else if((data_byte & 0xC8) === 0xC0)
481
let priority = data_byte & 7;
482
dbg_log("lowest priority: " + h(priority), LOG_PIC);
486
dbg_log("Unknown eoi: " + h(data_byte), LOG_PIC);
488
this.isr &= this.isr - 1;
495
PIC.prototype.port20_read = function()
499
dbg_log("read port 20h (isr): " + h(this.isr), LOG_PIC);
504
dbg_log("read port 20h (irr): " + h(this.irr), LOG_PIC);
509
PIC.prototype.port21_write = function(data_byte)
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);
521
if((data_byte & 1) === 0)
523
dbg_assert(false, "unimplemented: not 8086 mode", LOG_PIC);
529
this.irq_mask = ~data_byte;
533
dbg_log("interrupt mask: " + (this.irq_mask & 0xFF).toString(2) +
534
" (" + this.name + ")", LOG_PIC);
540
else if(this.state === 1)
543
this.irq_map = data_byte;
544
dbg_log("interrupts are mapped to " + h(this.irq_map) +
545
" (" + this.name + ")", LOG_PIC);
548
else if(this.state === 2)
552
dbg_log("icw3: " + h(data_byte), LOG_PIC);
556
PIC.prototype.port21_read = function()
558
dbg_log("21h read " + h(~this.irq_mask & 0xff), LOG_PIC);
559
return ~this.irq_mask & 0xFF;
562
PIC.prototype.port4D0_read = function()
564
dbg_log("elcr read: " + h(this.elcr, 2), LOG_PIC);
568
PIC.prototype.port4D0_write = function(value)
570
dbg_log("elcr write: " + h(value, 2), LOG_PIC);