4
let PS2_LOG_VERBOSE = false;
20
this.enable_mouse_stream = false;
23
this.use_mouse = false;
26
this.have_mouse = true;
29
this.mouse_delta_x = 0;
31
this.mouse_delta_y = 0;
33
this.mouse_clicks = 0;
36
this.have_keyboard = true;
39
this.enable_keyboard_stream = false;
42
this.next_is_mouse_command = false;
45
this.next_read_sample = false;
48
this.next_read_led = false;
51
this.next_handle_scan_code_set = false;
54
this.next_read_rate = false;
57
this.next_read_resolution = false;
62
this.kbd_buffer = new ByteQueue(1024);
64
this.last_port60_byte = 0;
67
this.sample_rate = 100;
73
this.scaling2 = false;
76
this.last_mouse_packet = -1;
81
this.mouse_buffer = new ByteQueue(1024);
87
this.next_byte_is_ready = false;
90
this.next_byte_is_aux = false;
92
this.bus.register("keyboard-code", function(code)
94
this.kbd_send_code(code);
97
this.bus.register("mouse-click", function(data)
99
this.mouse_send_click(data[0], data[1], data[2]);
102
this.bus.register("mouse-delta", function(data)
104
this.mouse_send_delta(data[0], data[1]);
107
this.bus.register("mouse-wheel", function(data)
113
this.command_register = 1 | 4;
115
this.controller_output_port = 0;
116
this.read_output_register = false;
117
this.read_command_register = false;
118
this.read_controller_output_port = false;
120
cpu.io.register_read(0x60, this, this.port60_read);
121
cpu.io.register_read(0x64, this, this.port64_read);
123
cpu.io.register_write(0x60, this, this.port60_write);
124
cpu.io.register_write(0x64, this, this.port64_write);
127
PS2.prototype.get_state = function()
131
state[0] = this.enable_mouse_stream;
132
state[1] = this.use_mouse;
133
state[2] = this.have_mouse;
134
state[3] = this.mouse_delta_x;
135
state[4] = this.mouse_delta_y;
136
state[5] = this.mouse_clicks;
137
state[6] = this.have_keyboard;
138
state[7] = this.enable_keyboard_stream;
139
state[8] = this.next_is_mouse_command;
140
state[9] = this.next_read_sample;
141
state[10] = this.next_read_led;
142
state[11] = this.next_handle_scan_code_set;
143
state[12] = this.next_read_rate;
144
state[13] = this.next_read_resolution;
146
state[15] = this.last_port60_byte;
147
state[16] = this.sample_rate;
148
state[17] = this.resolution;
149
state[18] = this.scaling2;
151
state[20] = this.command_register;
152
state[21] = this.read_output_register;
153
state[22] = this.read_command_register;
154
state[23] = this.controller_output_port;
155
state[24] = this.read_controller_output_port;
160
PS2.prototype.set_state = function(state)
162
this.enable_mouse_stream = state[0];
163
this.use_mouse = state[1];
164
this.have_mouse = state[2];
165
this.mouse_delta_x = state[3];
166
this.mouse_delta_y = state[4];
167
this.mouse_clicks = state[5];
168
this.have_keyboard = state[6];
169
this.enable_keyboard_stream = state[7];
170
this.next_is_mouse_command = state[8];
171
this.next_read_sample = state[9];
172
this.next_read_led = state[10];
173
this.next_handle_scan_code_set = state[11];
174
this.next_read_rate = state[12];
175
this.next_read_resolution = state[13];
177
this.last_port60_byte = state[15];
178
this.sample_rate = state[16];
179
this.resolution = state[17];
180
this.scaling2 = state[18];
182
this.command_register = state[20];
183
this.read_output_register = state[21];
184
this.read_command_register = state[22];
185
this.controller_output_port = state[23];
186
this.read_controller_output_port = state[24];
188
this.next_byte_is_ready = false;
189
this.next_byte_is_aux = false;
190
this.kbd_buffer.clear();
191
this.mouse_buffer.clear();
193
this.bus.send("mouse-enable", this.use_mouse);
196
PS2.prototype.raise_irq = function()
198
if(this.next_byte_is_ready)
206
if(this.kbd_buffer.length)
210
else if(this.mouse_buffer.length)
216
PS2.prototype.mouse_irq = function()
218
this.next_byte_is_ready = true;
219
this.next_byte_is_aux = true;
221
if(this.command_register & 2)
223
dbg_log("Mouse irq", LOG_PS2);
228
this.cpu.device_lower_irq(12);
229
this.cpu.device_raise_irq(12);
233
PS2.prototype.kbd_irq = function()
235
this.next_byte_is_ready = true;
236
this.next_byte_is_aux = false;
238
if(this.command_register & 1)
240
dbg_log("Keyboard irq", LOG_PS2);
245
this.cpu.device_lower_irq(1);
246
this.cpu.device_raise_irq(1);
250
PS2.prototype.kbd_send_code = function(code)
252
if(this.enable_keyboard_stream)
254
dbg_log("adding kbd code: " + h(code), LOG_PS2);
255
this.kbd_buffer.push(code);
260
PS2.prototype.mouse_send_delta = function(delta_x, delta_y)
262
if(!this.have_mouse || !this.use_mouse)
269
var factor = this.resolution * this.sample_rate / 80;
271
this.mouse_delta_x += delta_x * factor;
272
this.mouse_delta_y += delta_y * factor;
274
if(this.enable_mouse_stream)
276
var change_x = this.mouse_delta_x | 0,
277
change_y = this.mouse_delta_y | 0;
279
if(change_x || change_y)
281
var now = Date.now();
289
this.mouse_delta_x -= change_x;
290
this.mouse_delta_y -= change_y;
292
this.send_mouse_packet(change_x, change_y);
297
PS2.prototype.mouse_send_click = function(left, middle, right)
299
if(!this.have_mouse || !this.use_mouse)
304
this.mouse_clicks = left | right << 1 | middle << 2;
306
if(this.enable_mouse_stream)
308
this.send_mouse_packet(0, 0);
312
PS2.prototype.send_mouse_packet = function(dx, dy)
322
this.last_mouse_packet = Date.now();
331
this.mouse_buffer.push(info_byte);
332
this.mouse_buffer.push(delta_x);
333
this.mouse_buffer.push(delta_y);
337
dbg_log("adding mouse packets: " + [info_byte, dx, dy], LOG_PS2);
343
PS2.prototype.apply_scaling2 = function(n)
346
var abs = Math.abs(n),
366
PS2.prototype.port60_read = function()
370
this.next_byte_is_ready = false;
372
if(!this.kbd_buffer.length && !this.mouse_buffer.length)
375
dbg_log("Port 60 read: Empty", LOG_PS2);
376
return this.last_port60_byte;
379
if(this.next_byte_is_aux)
381
this.cpu.device_lower_irq(12);
382
this.last_port60_byte = this.mouse_buffer.shift();
383
dbg_log("Port 60 read (mouse): " + h(this.last_port60_byte), LOG_PS2);
387
this.cpu.device_lower_irq(1);
388
this.last_port60_byte = this.kbd_buffer.shift();
389
dbg_log("Port 60 read (kbd) : " + h(this.last_port60_byte), LOG_PS2);
392
if(this.kbd_buffer.length || this.mouse_buffer.length)
397
return this.last_port60_byte;
400
PS2.prototype.port64_read = function()
404
var status_byte = 0x10;
406
if(this.next_byte_is_ready)
410
if(this.next_byte_is_aux)
415
dbg_log("port 64 read: " + h(status_byte), LOG_PS2);
420
PS2.prototype.port60_write = function(write_byte)
422
dbg_log("port 60 write: " + h(write_byte), LOG_PS2);
424
if(this.read_command_register)
426
this.command_register = write_byte;
427
this.read_command_register = false;
433
dbg_log("Keyboard command register = " + h(this.command_register), LOG_PS2);
435
else if(this.read_output_register)
437
this.read_output_register = false;
439
this.mouse_buffer.clear();
440
this.mouse_buffer.push(write_byte);
443
else if(this.next_read_sample)
445
this.next_read_sample = false;
446
this.mouse_buffer.clear();
447
this.mouse_buffer.push(0xFA);
449
this.sample_rate = write_byte;
450
dbg_log("mouse sample rate: " + h(write_byte), LOG_PS2);
451
if(!this.sample_rate)
453
dbg_log("invalid sample rate, reset to 100", LOG_PS2);
454
this.sample_rate = 100;
458
else if(this.next_read_resolution)
460
this.next_read_resolution = false;
461
this.mouse_buffer.clear();
462
this.mouse_buffer.push(0xFA);
467
dbg_log("invalid resolution, resetting to 4", LOG_PS2);
471
this.resolution = 1 << write_byte;
472
dbg_log("resolution: " + this.resolution, LOG_PS2);
476
else if(this.next_read_led)
479
this.next_read_led = false;
480
this.kbd_buffer.push(0xFA);
483
else if(this.next_handle_scan_code_set)
485
this.next_handle_scan_code_set = false;
487
this.kbd_buffer.push(0xFA);
496
this.kbd_buffer.push(2);
499
else if(this.next_read_rate)
502
this.next_read_rate = false;
503
this.kbd_buffer.push(0xFA);
506
else if(this.next_is_mouse_command)
508
this.next_is_mouse_command = false;
509
dbg_log("Port 60 data register write: " + h(write_byte), LOG_PS2);
517
this.kbd_buffer.clear();
518
this.mouse_buffer.clear();
519
this.mouse_buffer.push(0xFA);
525
dbg_log("Scaling 1:1", LOG_PS2);
526
this.scaling2 = false;
530
dbg_log("Scaling 2:1", LOG_PS2);
531
this.scaling2 = true;
535
this.next_read_resolution = true;
539
this.send_mouse_packet(0, 0);
543
dbg_log("unimplemented request single packet", LOG_PS2);
544
this.send_mouse_packet(0, 0);
548
this.mouse_buffer.push(0);
549
this.mouse_buffer.push(0);
551
this.mouse_clicks = this.mouse_delta_x = this.mouse_delta_y = 0;
555
this.next_read_sample = true;
559
this.enable_mouse_stream = true;
560
this.use_mouse = true;
561
this.bus.send("mouse-enable", true);
563
this.mouse_clicks = this.mouse_delta_x = this.mouse_delta_y = 0;
567
this.enable_mouse_stream = false;
571
this.enable_mouse_stream = false;
572
this.sample_rate = 100;
573
this.scaling2 = false;
578
dbg_log("Mouse reset", LOG_PS2);
579
this.mouse_buffer.push(0xAA);
580
this.mouse_buffer.push(0);
582
this.use_mouse = true;
583
this.bus.send("mouse-enable", true);
585
this.enable_mouse_stream = false;
586
this.sample_rate = 100;
587
this.scaling2 = false;
590
this.mouse_clicks = this.mouse_delta_x = this.mouse_delta_y = 0;
594
dbg_log("Unimplemented mouse command: " + h(write_byte), LOG_PS2);
599
else if (this.read_controller_output_port)
601
this.read_controller_output_port = false;
602
this.controller_output_port = write_byte;
608
dbg_log("Port 60 data register write: " + h(write_byte), LOG_PS2);
611
this.mouse_buffer.clear();
612
this.kbd_buffer.clear();
613
this.kbd_buffer.push(0xFA);
618
this.next_read_led = true;
622
this.next_handle_scan_code_set = true;
626
this.kbd_buffer.push(0xAB);
627
this.kbd_buffer.push(83);
631
this.next_read_rate = true;
635
dbg_log("kbd enable scanning", LOG_PS2);
636
this.enable_keyboard_stream = true;
640
dbg_log("kbd disable scanning", LOG_PS2);
641
this.enable_keyboard_stream = false;
648
this.kbd_buffer.clear();
649
this.kbd_buffer.push(0xFA);
650
this.kbd_buffer.push(0xAA);
651
this.kbd_buffer.push(0);
654
dbg_log("Unimplemented keyboard command: " + h(write_byte), LOG_PS2);
661
PS2.prototype.port64_write = function(write_byte)
663
dbg_log("port 64 write: " + h(write_byte), LOG_PS2);
668
this.kbd_buffer.clear();
669
this.mouse_buffer.clear();
670
this.kbd_buffer.push(this.command_register);
674
this.read_command_register = true;
677
this.read_controller_output_port = true;
680
this.read_output_register = true;
683
this.next_is_mouse_command = true;
687
dbg_log("Disable second port", LOG_PS2);
688
this.command_register |= 0x20;
692
dbg_log("Enable second port", LOG_PS2);
693
this.command_register &= ~0x20;
697
this.kbd_buffer.clear();
698
this.mouse_buffer.clear();
699
this.kbd_buffer.push(0);
703
this.kbd_buffer.clear();
704
this.mouse_buffer.clear();
705
this.kbd_buffer.push(0x55);
710
this.kbd_buffer.clear();
711
this.mouse_buffer.clear();
712
this.kbd_buffer.push(0);
717
dbg_log("Disable Keyboard", LOG_PS2);
718
this.command_register |= 0x10;
722
dbg_log("Enable Keyboard", LOG_PS2);
723
this.command_register &= ~0x10;
726
dbg_log("CPU reboot via PS2");
727
this.cpu.reboot_internal();
730
dbg_log("port 64: Unimplemented command byte: " + h(write_byte), LOG_PS2);