afbbf0cc7c
Continuing from PR #184, fixes #182. Two main changes: 1. Pulse the interrupt lines to ensure rising edge. Some say that the controller clears the interrupt lines themselves after a small delay to create a pulse: - http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/ - https://wiki.osdev.org/8259_PIC#What_does_the_8259_PIC_do.3F (paragraph 1) although that contradicts with: - Section "Reading Keyboard Input" paragraph 3 http://www.computer-engineering.org/ps2keyboard/#General%20Description%20FN where they say the interrupts are cleared only after reading port 0x60. Could possibly be because they are referring to the older AT keyboard controller. 2. Wait until current byte has been read via port 0x60 before changing between kbd and mouse queues. In hardware terms: inhibit kbd and mouse communication, and don't overwrite the DBBOUT output buffer until OBF is cleared. Interesting reading: - Section "Reading Keyboard Input" paragraph 1 http://www.computer-engineering.org/ps2keyboard/#General%20Description%20FN - Disassembly "Main Entry" $0102 http://www.halicery.com/8042/8042_1503033.TXT Unlike PR #184, this gives kbd data priority over mouse data (as it used to), and this seems to avoid requiring timers to expire abandoned bytes.
716 lines
18 KiB
JavaScript
716 lines
18 KiB
JavaScript
"use strict";
|
|
|
|
/** @const */
|
|
let PS2_LOG_VERBOSE = false;
|
|
|
|
/**
|
|
* @constructor
|
|
* @param {CPU} cpu
|
|
* @param {BusConnector} bus
|
|
*/
|
|
function PS2(cpu, bus)
|
|
{
|
|
/** @const @type {CPU} */
|
|
this.cpu = cpu;
|
|
|
|
/** @const @type {BusConnector} */
|
|
this.bus = bus;
|
|
|
|
/** @type {boolean} */
|
|
this.enable_mouse_stream = false;
|
|
|
|
/** @type {boolean} */
|
|
this.use_mouse = false;
|
|
|
|
/** @type {boolean} */
|
|
this.have_mouse = true;
|
|
|
|
/** @type {number} */
|
|
this.mouse_delta_x = 0;
|
|
/** @type {number} */
|
|
this.mouse_delta_y = 0;
|
|
/** @type {number} */
|
|
this.mouse_clicks = 0;
|
|
|
|
/** @type {boolean} */
|
|
this.have_keyboard = true;
|
|
|
|
/** @type {boolean} */
|
|
this.enable_keyboard_stream = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_is_mouse_command = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_read_sample = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_read_led = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_handle_scan_code_set = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_read_rate = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_read_resolution = false;
|
|
|
|
/**
|
|
* @type {ByteQueue}
|
|
*/
|
|
this.kbd_buffer = new ByteQueue(1024);
|
|
|
|
this.last_port60_byte = 0;
|
|
|
|
/** @type {number} */
|
|
this.sample_rate = 100;
|
|
|
|
/** @type {number} */
|
|
this.resolution = 4;
|
|
|
|
/** @type {boolean} */
|
|
this.scaling2 = false;
|
|
|
|
/** @type {number} */
|
|
this.last_mouse_packet = -1;
|
|
|
|
/**
|
|
* @type {ByteQueue}
|
|
*/
|
|
this.mouse_buffer = new ByteQueue(1024);
|
|
|
|
/**
|
|
* @type {boolean}
|
|
* Also known as DBBOUT OBF - Output Buffer Full flag
|
|
*/
|
|
this.next_byte_is_ready = false;
|
|
|
|
/** @type {boolean} */
|
|
this.next_byte_is_aux = false;
|
|
|
|
this.bus.register("keyboard-code", function(code)
|
|
{
|
|
this.kbd_send_code(code);
|
|
}, this);
|
|
|
|
this.bus.register("mouse-click", function(data)
|
|
{
|
|
this.mouse_send_click(data[0], data[1], data[2]);
|
|
}, this);
|
|
|
|
this.bus.register("mouse-delta", function(data)
|
|
{
|
|
this.mouse_send_delta(data[0], data[1]);
|
|
}, this);
|
|
|
|
this.bus.register("mouse-wheel", function(data)
|
|
{
|
|
// TODO: Mouse Wheel
|
|
// http://www.computer-engineering.org/ps2mouse/
|
|
}, this);
|
|
|
|
this.command_register = 1 | 4;
|
|
this.read_output_register = false;
|
|
this.read_command_register = false;
|
|
|
|
cpu.io.register_read(0x60, this, this.port60_read);
|
|
cpu.io.register_read(0x64, this, this.port64_read);
|
|
|
|
cpu.io.register_write(0x60, this, this.port60_write);
|
|
cpu.io.register_write(0x64, this, this.port64_write);
|
|
}
|
|
|
|
PS2.prototype.get_state = function()
|
|
{
|
|
var state = [];
|
|
|
|
state[0] = this.enable_mouse_stream;
|
|
state[1] = this.use_mouse;
|
|
state[2] = this.have_mouse;
|
|
state[3] = this.mouse_delta_x;
|
|
state[4] = this.mouse_delta_y;
|
|
state[5] = this.mouse_clicks;
|
|
state[6] = this.have_keyboard;
|
|
state[7] = this.enable_keyboard_stream;
|
|
state[8] = this.next_is_mouse_command;
|
|
state[9] = this.next_read_sample;
|
|
state[10] = this.next_read_led;
|
|
state[11] = this.next_handle_scan_code_set;
|
|
state[12] = this.next_read_rate;
|
|
state[13] = this.next_read_resolution;
|
|
//state[14] = this.kbd_buffer;
|
|
state[15] = this.last_port60_byte;
|
|
state[16] = this.sample_rate;
|
|
state[17] = this.resolution;
|
|
state[18] = this.scaling2;
|
|
//state[19] = this.mouse_buffer;
|
|
state[20] = this.command_register;
|
|
state[21] = this.read_output_register;
|
|
state[22] = this.read_command_register;
|
|
|
|
return state;
|
|
};
|
|
|
|
PS2.prototype.set_state = function(state)
|
|
{
|
|
this.enable_mouse_stream = state[0];
|
|
this.use_mouse = state[1];
|
|
this.have_mouse = state[2];
|
|
this.mouse_delta_x = state[3];
|
|
this.mouse_delta_y = state[4];
|
|
this.mouse_clicks = state[5];
|
|
this.have_keyboard = state[6];
|
|
this.enable_keyboard_stream = state[7];
|
|
this.next_is_mouse_command = state[8];
|
|
this.next_read_sample = state[9];
|
|
this.next_read_led = state[10];
|
|
this.next_handle_scan_code_set = state[11];
|
|
this.next_read_rate = state[12];
|
|
this.next_read_resolution = state[13];
|
|
//this.kbd_buffer = state[14];
|
|
this.last_port60_byte = state[15];
|
|
this.sample_rate = state[16];
|
|
this.resolution = state[17];
|
|
this.scaling2 = state[18];
|
|
//this.mouse_buffer = state[19];
|
|
this.command_register = state[20];
|
|
this.read_output_register = state[21];
|
|
this.read_command_register = state[22];
|
|
|
|
this.next_byte_is_ready = false;
|
|
this.next_byte_is_aux = false;
|
|
this.kbd_buffer.clear();
|
|
this.mouse_buffer.clear();
|
|
|
|
this.bus.send("mouse-enable", this.use_mouse);
|
|
};
|
|
|
|
PS2.prototype.raise_irq = function()
|
|
{
|
|
if(this.next_byte_is_ready)
|
|
{
|
|
// Wait until previous byte is read
|
|
// http://halicery.com/Hardware/8042/8042_1503033_TXT.htm
|
|
return;
|
|
}
|
|
|
|
// Kbd has priority over aux
|
|
if(this.kbd_buffer.length)
|
|
{
|
|
this.kbd_irq();
|
|
}
|
|
else if(this.mouse_buffer.length)
|
|
{
|
|
this.mouse_irq();
|
|
}
|
|
};
|
|
|
|
PS2.prototype.mouse_irq = function()
|
|
{
|
|
this.next_byte_is_ready = true;
|
|
this.next_byte_is_aux = true;
|
|
|
|
if(this.command_register & 2)
|
|
{
|
|
dbg_log("Mouse irq", LOG_PS2);
|
|
|
|
// Pulse the irq line
|
|
// Note: can't lower immediately after rising, so lower before rising
|
|
// http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/
|
|
this.cpu.device_lower_irq(12);
|
|
this.cpu.device_raise_irq(12);
|
|
}
|
|
};
|
|
|
|
PS2.prototype.kbd_irq = function()
|
|
{
|
|
this.next_byte_is_ready = true;
|
|
this.next_byte_is_aux = false;
|
|
|
|
if(this.command_register & 1)
|
|
{
|
|
dbg_log("Keyboard irq", LOG_PS2);
|
|
|
|
// Pulse the irq line
|
|
// Note: can't lower immediately after rising, so lower before rising
|
|
// http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/
|
|
this.cpu.device_lower_irq(1);
|
|
this.cpu.device_raise_irq(1);
|
|
}
|
|
};
|
|
|
|
PS2.prototype.kbd_send_code = function(code)
|
|
{
|
|
if(this.enable_keyboard_stream)
|
|
{
|
|
dbg_log("adding kbd code: " + h(code), LOG_PS2);
|
|
this.kbd_buffer.push(code);
|
|
this.raise_irq();
|
|
}
|
|
};
|
|
|
|
PS2.prototype.mouse_send_delta = function(delta_x, delta_y)
|
|
{
|
|
if(!this.have_mouse || !this.use_mouse)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// note: delta_x or delta_y can be floating point numbers
|
|
|
|
var factor = this.resolution * this.sample_rate / 80;
|
|
|
|
this.mouse_delta_x += delta_x * factor;
|
|
this.mouse_delta_y += delta_y * factor;
|
|
|
|
if(this.enable_mouse_stream)
|
|
{
|
|
var change_x = this.mouse_delta_x | 0,
|
|
change_y = this.mouse_delta_y | 0;
|
|
|
|
if(change_x || change_y)
|
|
{
|
|
var now = Date.now();
|
|
|
|
//if(now - this.last_mouse_packet < 1000 / this.sample_rate)
|
|
//{
|
|
// // TODO: set timeout
|
|
// return;
|
|
//}
|
|
|
|
this.mouse_delta_x -= change_x;
|
|
this.mouse_delta_y -= change_y;
|
|
|
|
this.send_mouse_packet(change_x, change_y);
|
|
}
|
|
}
|
|
};
|
|
|
|
PS2.prototype.mouse_send_click = function(left, middle, right)
|
|
{
|
|
if(!this.have_mouse || !this.use_mouse)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.mouse_clicks = left | right << 1 | middle << 2;
|
|
|
|
if(this.enable_mouse_stream)
|
|
{
|
|
this.send_mouse_packet(0, 0);
|
|
}
|
|
};
|
|
|
|
PS2.prototype.send_mouse_packet = function(dx, dy)
|
|
{
|
|
var info_byte =
|
|
(dy < 0) << 5 |
|
|
(dx < 0) << 4 |
|
|
1 << 3 |
|
|
this.mouse_clicks,
|
|
delta_x = dx,
|
|
delta_y = dy;
|
|
|
|
this.last_mouse_packet = Date.now();
|
|
|
|
//if(this.scaling2)
|
|
//{
|
|
// // only in automatic packets, not 0xEB requests
|
|
// delta_x = this.apply_scaling2(delta_x);
|
|
// delta_y = this.apply_scaling2(delta_y);
|
|
//}
|
|
|
|
this.mouse_buffer.push(info_byte);
|
|
this.mouse_buffer.push(delta_x);
|
|
this.mouse_buffer.push(delta_y);
|
|
|
|
if(PS2_LOG_VERBOSE)
|
|
{
|
|
dbg_log("adding mouse packets: " + [info_byte, dx, dy], LOG_PS2);
|
|
}
|
|
|
|
this.raise_irq();
|
|
};
|
|
|
|
PS2.prototype.apply_scaling2 = function(n)
|
|
{
|
|
// http://www.computer-engineering.org/ps2mouse/#Inputs.2C_Resolution.2C_and_Scaling
|
|
var abs = Math.abs(n),
|
|
sign = n >> 31;
|
|
|
|
switch(abs)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 3:
|
|
return n;
|
|
case 2:
|
|
return sign;
|
|
case 4:
|
|
return 6 * sign;
|
|
case 5:
|
|
return 9 * sign;
|
|
default:
|
|
return n << 1;
|
|
}
|
|
};
|
|
|
|
PS2.prototype.port60_read = function()
|
|
{
|
|
//dbg_log("port 60 read: " + (buffer[0] || "(none)"));
|
|
|
|
this.next_byte_is_ready = false;
|
|
|
|
if(!this.kbd_buffer.length && !this.mouse_buffer.length)
|
|
{
|
|
// should not happen
|
|
dbg_log("Port 60 read: Empty", LOG_PS2);
|
|
return this.last_port60_byte;
|
|
}
|
|
|
|
if(this.next_byte_is_aux)
|
|
{
|
|
this.cpu.device_lower_irq(12);
|
|
this.last_port60_byte = this.mouse_buffer.shift();
|
|
dbg_log("Port 60 read (mouse): " + h(this.last_port60_byte), LOG_PS2);
|
|
}
|
|
else
|
|
{
|
|
this.cpu.device_lower_irq(1);
|
|
this.last_port60_byte = this.kbd_buffer.shift();
|
|
dbg_log("Port 60 read (kbd) : " + h(this.last_port60_byte), LOG_PS2);
|
|
}
|
|
|
|
if(this.kbd_buffer.length || this.mouse_buffer.length)
|
|
{
|
|
this.raise_irq();
|
|
}
|
|
|
|
return this.last_port60_byte;
|
|
};
|
|
|
|
PS2.prototype.port64_read = function()
|
|
{
|
|
// status port
|
|
|
|
var status_byte = 0x10;
|
|
|
|
if(this.next_byte_is_ready)
|
|
{
|
|
status_byte |= 0x1;
|
|
}
|
|
if(this.next_byte_is_aux)
|
|
{
|
|
status_byte |= 0x20;
|
|
}
|
|
|
|
dbg_log("port 64 read: " + h(status_byte), LOG_PS2);
|
|
|
|
return status_byte;
|
|
};
|
|
|
|
PS2.prototype.port60_write = function(write_byte)
|
|
{
|
|
dbg_log("port 60 write: " + h(write_byte), LOG_PS2);
|
|
|
|
if(this.read_command_register)
|
|
{
|
|
this.command_register = write_byte;
|
|
this.read_command_register = false;
|
|
|
|
// not sure, causes "spurious ack" in Linux
|
|
//this.kbd_buffer.push(0xFA);
|
|
//this.kbd_irq();
|
|
|
|
dbg_log("Keyboard command register = " + h(this.command_register), LOG_PS2);
|
|
}
|
|
else if(this.read_output_register)
|
|
{
|
|
this.read_output_register = false;
|
|
|
|
this.mouse_buffer.clear();
|
|
this.mouse_buffer.push(write_byte);
|
|
this.mouse_irq();
|
|
}
|
|
else if(this.next_read_sample)
|
|
{
|
|
this.next_read_sample = false;
|
|
this.mouse_buffer.clear();
|
|
this.mouse_buffer.push(0xFA);
|
|
|
|
this.sample_rate = write_byte;
|
|
dbg_log("mouse sample rate: " + h(write_byte), LOG_PS2);
|
|
if(!this.sample_rate)
|
|
{
|
|
dbg_log("invalid sample rate, reset to 100", LOG_PS2);
|
|
this.sample_rate = 100;
|
|
}
|
|
this.mouse_irq();
|
|
}
|
|
else if(this.next_read_resolution)
|
|
{
|
|
this.next_read_resolution = false;
|
|
this.mouse_buffer.clear();
|
|
this.mouse_buffer.push(0xFA);
|
|
|
|
if(write_byte > 3)
|
|
{
|
|
this.resolution = 4;
|
|
dbg_log("invalid resolution, resetting to 4", LOG_PS2);
|
|
}
|
|
else
|
|
{
|
|
this.resolution = 1 << write_byte;
|
|
dbg_log("resolution: " + this.resolution, LOG_PS2);
|
|
}
|
|
this.mouse_irq();
|
|
}
|
|
else if(this.next_read_led)
|
|
{
|
|
// nope
|
|
this.next_read_led = false;
|
|
this.kbd_buffer.push(0xFA);
|
|
this.kbd_irq();
|
|
}
|
|
else if(this.next_handle_scan_code_set)
|
|
{
|
|
this.next_handle_scan_code_set = false;
|
|
|
|
this.kbd_buffer.push(0xFA);
|
|
this.kbd_irq();
|
|
|
|
if(write_byte)
|
|
{
|
|
// set scan code set
|
|
}
|
|
else
|
|
{
|
|
this.kbd_buffer.push(2);
|
|
}
|
|
}
|
|
else if(this.next_read_rate)
|
|
{
|
|
// nope
|
|
this.next_read_rate = false;
|
|
this.kbd_buffer.push(0xFA);
|
|
this.kbd_irq();
|
|
}
|
|
else if(this.next_is_mouse_command)
|
|
{
|
|
this.next_is_mouse_command = false;
|
|
dbg_log("Port 60 data register write: " + h(write_byte), LOG_PS2);
|
|
|
|
if(!this.have_mouse)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// send ack
|
|
this.kbd_buffer.clear();
|
|
this.mouse_buffer.clear();
|
|
this.mouse_buffer.push(0xFA);
|
|
|
|
switch(write_byte)
|
|
{
|
|
case 0xE6:
|
|
// set scaling to 1:1
|
|
dbg_log("Scaling 1:1", LOG_PS2);
|
|
this.scaling2 = false;
|
|
break;
|
|
case 0xE7:
|
|
// set scaling to 2:1
|
|
dbg_log("Scaling 2:1", LOG_PS2);
|
|
this.scaling2 = true;
|
|
break;
|
|
case 0xE8:
|
|
// set mouse resolution
|
|
this.next_read_resolution = true;
|
|
break;
|
|
case 0xE9:
|
|
// status request - send one packet
|
|
this.send_mouse_packet(0, 0);
|
|
break;
|
|
case 0xEB:
|
|
// request single packet
|
|
dbg_log("unimplemented request single packet", LOG_PS2);
|
|
this.send_mouse_packet(0, 0);
|
|
break;
|
|
case 0xF2:
|
|
// MouseID Byte
|
|
this.mouse_buffer.push(0);
|
|
this.mouse_buffer.push(0);
|
|
|
|
this.mouse_clicks = this.mouse_delta_x = this.mouse_delta_y = 0;
|
|
break;
|
|
case 0xF3:
|
|
// sample rate
|
|
this.next_read_sample = true;
|
|
break;
|
|
case 0xF4:
|
|
// enable streaming
|
|
this.enable_mouse_stream = true;
|
|
this.use_mouse = true;
|
|
this.bus.send("mouse-enable", true);
|
|
|
|
this.mouse_clicks = this.mouse_delta_x = this.mouse_delta_y = 0;
|
|
break;
|
|
case 0xF5:
|
|
// disable streaming
|
|
this.enable_mouse_stream = false;
|
|
break;
|
|
case 0xF6:
|
|
// set defaults
|
|
this.enable_mouse_stream = false;
|
|
this.sample_rate = 100;
|
|
this.scaling2 = false;
|
|
this.resolution = 4;
|
|
break;
|
|
case 0xFF:
|
|
// reset, send completion code
|
|
dbg_log("Mouse reset", LOG_PS2);
|
|
this.mouse_buffer.push(0xAA);
|
|
this.mouse_buffer.push(0);
|
|
|
|
this.use_mouse = true;
|
|
this.bus.send("mouse-enable", true);
|
|
|
|
this.enable_mouse_stream = false;
|
|
this.sample_rate = 100;
|
|
this.scaling2 = false;
|
|
this.resolution = 4;
|
|
|
|
this.mouse_clicks = this.mouse_delta_x = this.mouse_delta_y = 0;
|
|
break;
|
|
|
|
default:
|
|
dbg_log("Unimplemented mouse command: " + h(write_byte), LOG_PS2);
|
|
}
|
|
|
|
this.mouse_irq();
|
|
}
|
|
else
|
|
{
|
|
dbg_log("Port 60 data register write: " + h(write_byte), LOG_PS2);
|
|
|
|
// send ack
|
|
this.mouse_buffer.clear();
|
|
this.kbd_buffer.clear();
|
|
this.kbd_buffer.push(0xFA);
|
|
|
|
switch(write_byte)
|
|
{
|
|
case 0xED:
|
|
this.next_read_led = true;
|
|
break;
|
|
case 0xF0:
|
|
// get/set scan code set
|
|
this.next_handle_scan_code_set = true;
|
|
break;
|
|
case 0xF2:
|
|
// identify
|
|
this.kbd_buffer.push(0xAB);
|
|
this.kbd_buffer.push(83);
|
|
break;
|
|
case 0xF3:
|
|
// Set typematic rate and delay
|
|
this.next_read_rate = true;
|
|
break;
|
|
case 0xF4:
|
|
// enable scanning
|
|
dbg_log("kbd enable scanning", LOG_PS2);
|
|
this.enable_keyboard_stream = true;
|
|
break;
|
|
case 0xF5:
|
|
// disable scanning
|
|
dbg_log("kbd disable scanning", LOG_PS2);
|
|
this.enable_keyboard_stream = false;
|
|
break;
|
|
case 0xF6:
|
|
// reset defaults
|
|
//this.enable_keyboard_stream = false;
|
|
break;
|
|
case 0xFF:
|
|
this.kbd_buffer.clear();
|
|
this.kbd_buffer.push(0xFA);
|
|
this.kbd_buffer.push(0xAA);
|
|
this.kbd_buffer.push(0);
|
|
break;
|
|
default:
|
|
dbg_log("Unimplemented keyboard command: " + h(write_byte), LOG_PS2);
|
|
}
|
|
|
|
this.kbd_irq();
|
|
}
|
|
};
|
|
|
|
PS2.prototype.port64_write = function(write_byte)
|
|
{
|
|
dbg_log("port 64 write: " + h(write_byte), LOG_PS2);
|
|
|
|
switch(write_byte)
|
|
{
|
|
case 0x20:
|
|
this.kbd_buffer.clear();
|
|
this.mouse_buffer.clear();
|
|
this.kbd_buffer.push(this.command_register);
|
|
this.kbd_irq();
|
|
break;
|
|
case 0x60:
|
|
this.read_command_register = true;
|
|
break;
|
|
case 0xD3:
|
|
this.read_output_register = true;
|
|
break;
|
|
case 0xD4:
|
|
this.next_is_mouse_command = true;
|
|
break;
|
|
case 0xA7:
|
|
// Disable second port
|
|
dbg_log("Disable second port", LOG_PS2);
|
|
this.command_register |= 0x20;
|
|
break;
|
|
case 0xA8:
|
|
// Enable second port
|
|
dbg_log("Enable second port", LOG_PS2);
|
|
this.command_register &= ~0x20;
|
|
break;
|
|
case 0xA9:
|
|
// test second ps/2 port
|
|
this.kbd_buffer.clear();
|
|
this.mouse_buffer.clear();
|
|
this.kbd_buffer.push(0);
|
|
this.kbd_irq();
|
|
break;
|
|
case 0xAA:
|
|
this.kbd_buffer.clear();
|
|
this.mouse_buffer.clear();
|
|
this.kbd_buffer.push(0x55);
|
|
this.kbd_irq();
|
|
break;
|
|
case 0xAB:
|
|
// Test first PS/2 port
|
|
this.kbd_buffer.clear();
|
|
this.mouse_buffer.clear();
|
|
this.kbd_buffer.push(0);
|
|
this.kbd_irq();
|
|
break;
|
|
case 0xAD:
|
|
// Disable Keyboard
|
|
dbg_log("Disable Keyboard", LOG_PS2);
|
|
this.command_register |= 0x10;
|
|
break;
|
|
case 0xAE:
|
|
// Enable Keyboard
|
|
dbg_log("Enable Keyboard", LOG_PS2);
|
|
this.command_register &= ~0x10;
|
|
break;
|
|
case 0xFE:
|
|
dbg_log("CPU reboot via PS2");
|
|
this.cpu.reboot_internal();
|
|
break;
|
|
default:
|
|
dbg_log("port 64: Unimplemented command byte: " + h(write_byte), LOG_PS2);
|
|
}
|
|
};
|