Improved handling of IO port operations

This commit is contained in:
copy 2014-10-21 21:51:42 +02:00
parent 117f7820fe
commit 5fd2a1bd35
14 changed files with 608 additions and 468 deletions

View file

@ -28,45 +28,45 @@ function ACPI(cpu)
var elcr = 0;
// ACPI, ELCR register
io.register_write(0x4d0, function(data)
io.register_write(0x4d0, this, function(data)
{
elcr = elcr & 0xFF00 | data;
});
io.register_write(0x4d1, function(data)
io.register_write(0x4d1, this, function(data)
{
elcr = elcr & 0xFF | data << 8;
});
io.register_read(0xb3, function()
io.register_read(0xb3, this, function()
{
return 0;
});
// ACPI, pmtimer
io.register_read(0xb008, function()
io.register_read(0xb008, this, function()
{
return 0;
});
io.register_read(0xb009, function()
io.register_read(0xb009, this, function()
{
return 0;
});
io.register_read(0xb00a, function()
io.register_read(0xb00a, this, function()
{
return 0;
});
io.register_read(0xb00b, function()
io.register_read(0xb00b, this, function()
{
return 0;
});
// ACPI status
io.register_read(0xb004, function(data)
io.register_read(0xb004, this, function(data)
{
dbg_log("b004 read");
return 1;
});
io.register_read(0xb005, function(data)
io.register_read(0xb005, this, function(data)
{
dbg_log("b005 read");
return 0;

View file

@ -662,12 +662,12 @@ v86.prototype.init = function(settings)
var a20_byte = 0;
io.register_read(0x92, function()
io.register_read(0x92, this, function()
{
return a20_byte;
});
io.register_write(0x92, function(out_byte)
io.register_write(0x92, this, function(out_byte)
{
a20_byte = out_byte;
});
@ -676,7 +676,7 @@ v86.prototype.init = function(settings)
{
// Use by linux for port-IO delay
// Avoid generating tons of debug messages
io.register_write(0x80, function(out_byte)
io.register_write(0x80, this, function(out_byte)
{
});
}

View file

@ -17,12 +17,12 @@ function DMA(dev)
this.lsb_msb_flipflop = 0;
this.io.register_write(0x04, this.port_write.bind(this, 0x04));
this.io.register_write(0x05, this.port_write.bind(this, 0x05));
this.io.register_write(0x0A, this.portA_write.bind(this));
this.io.register_write(0x0B, this.portB_write.bind(this));
this.io.register_write(0x0C, this.portC_write.bind(this));
this.io.register_write(0x81, this.port81_write.bind(this));
this.io.register_write(0x04, this, this.port_write.bind(this, 0x04));
this.io.register_write(0x05, this, this.port_write.bind(this, 0x05));
this.io.register_write(0x0A, this, this.portA_write);
this.io.register_write(0x0B, this, this.portB_write);
this.io.register_write(0x0C, this, this.portC_write);
this.io.register_write(0x81, this, this.port81_write);
/** @const */
this._state_skip = ["io", "memory"];

View file

@ -77,14 +77,14 @@ function FloppyController(cpu, fda_image, fdb_image)
this.number_of_heads = number_of_heads;
this.number_of_cylinders = number_of_cylinders;
this.io.register_read(0x3F0, this.port3F0_read, this);
this.io.register_read(0x3F2, this.port3F2_read, this);
this.io.register_read(0x3F4, this.port3F4_read, this);
this.io.register_read(0x3F5, this.port3F5_read, this);
this.io.register_read(0x3F7, this.port3F7_read, this);
this.io.register_read(0x3F0, this, this.port3F0_read);
this.io.register_read(0x3F2, this, this.port3F2_read);
this.io.register_read(0x3F4, this, this.port3F4_read);
this.io.register_read(0x3F5, this, this.port3F5_read);
this.io.register_read(0x3F7, this, this.port3F7_read);
this.io.register_write(0x3F2, this.port3F2_write, this);
this.io.register_write(0x3F5, this.port3F5_write, this);
this.io.register_write(0x3F2, this, this.port3F2_write);
this.io.register_write(0x3F5, this, this.port3F5_write);
}
FloppyController.prototype.port3F0_read = function()

View file

@ -137,11 +137,11 @@ function IDEDevice(cpu, buffer, is_cd, nr)
cpu.devices.pci.register_device(this);
// status
cpu.io.register_read(this.ata_port | 7, this.read_status, this);
cpu.io.register_read(this.ata_port_high | 2, this.read_status, this);
cpu.io.register_read(this.ata_port | 7, this, this.read_status);
cpu.io.register_read(this.ata_port_high | 2, this, this.read_status);
cpu.io.register_write(this.ata_port | 7, this.write_control, this);
cpu.io.register_write(this.ata_port_high | 2, this.write_control, this);
cpu.io.register_write(this.ata_port | 7, this, this.write_control);
cpu.io.register_write(this.ata_port_high | 2, this, this.write_control);
/** @type {number} */
this.device_control = 2;
@ -191,44 +191,44 @@ function IDEDevice(cpu, buffer, is_cd, nr)
/** @type {number} */
this.dma_status = 0;
cpu.io.register_read(this.ata_port | 0, this.read_data_port, this);
cpu.io.register_read(this.ata_port | 1, this.read_data_port, this);
cpu.io.register_read(this.ata_port | 2, this.read_data_port, this);
cpu.io.register_read(this.ata_port | 3, this.read_data_port, this);
cpu.io.register_read(this.ata_port | 0, this, this.read_data_port8, this.read_data_port16, this.read_data_port32);
cpu.io.register_read(this.ata_port | 1, this, this.read_lba_port);
cpu.io.register_read(this.ata_port | 2, this, this.read_bytecount_port);
cpu.io.register_read(this.ata_port | 3, this, this.read_sector_port);
cpu.io.register_read(this.ata_port | 4, function()
cpu.io.register_read(this.ata_port | 4, this, function()
{
dbg_log("Read 1F4: " + h(this.cylinder_low & 0xFF), LOG_DISK);
return this.cylinder_low & 0xFF;
}, this);
cpu.io.register_read(this.ata_port | 5, function(port)
});
cpu.io.register_read(this.ata_port | 5, this, function(port)
{
dbg_log("Read 1F5: " + h(this.cylinder_high & 0xFF), LOG_DISK);
return this.cylinder_high & 0xFF;
}, this);
cpu.io.register_read(this.ata_port | 6, function()
});
cpu.io.register_read(this.ata_port | 6, this, function()
{
dbg_log("Read 1F6", LOG_DISK);
return this.drive_head;
}, this);
});
cpu.io.register_write(this.ata_port | 0, this.write_data_port, this);
cpu.io.register_write(this.ata_port | 1, this.write_data_port, this);
cpu.io.register_write(this.ata_port | 2, this.write_data_port, this);
cpu.io.register_write(this.ata_port | 3, this.write_data_port, this);
cpu.io.register_write(this.ata_port | 0, this, this.write_data_port8, this.write_data_port16, this.write_data_port32);
cpu.io.register_write(this.ata_port | 1, this, this.write_lba_port);
cpu.io.register_write(this.ata_port | 2, this, this.write_bytecount_port);
cpu.io.register_write(this.ata_port | 3, this, this.write_sector_port);
cpu.io.register_write(this.ata_port | 4, function(data)
cpu.io.register_write(this.ata_port | 4, this, function(data)
{
dbg_log("1F4/sector low: " + h(data), LOG_DISK);
this.cylinder_low = (this.cylinder_low << 8 | data) & 0xFFFF;
}, this);
cpu.io.register_write(this.ata_port | 5, function(data)
});
cpu.io.register_write(this.ata_port | 5, this, function(data)
{
dbg_log("1F5/sector high: " + h(data), LOG_DISK);
this.cylinder_high = (this.cylinder_high << 8 | data) & 0xFFFF;
}, this);
cpu.io.register_write(this.ata_port | 6, function(data)
});
cpu.io.register_write(this.ata_port | 6, this, function(data)
{
var slave = data & 0x10,
mode = data & 0xE0,
@ -253,24 +253,18 @@ function IDEDevice(cpu, buffer, is_cd, nr)
this.is_lba = data >> 6 & 1;
this.head = data & 0xF;
this.last_drive = data;
}, this);
});
cpu.io.register_write(this.ata_port | 7, this.ata_command, this);
cpu.io.register_write(this.ata_port | 7, this, this.ata_command);
cpu.io.register_read(this.master_port | 4, this.dma_read_addr0, this);
cpu.io.register_read(this.master_port | 5, this.dma_read_addr1, this);
cpu.io.register_read(this.master_port | 6, this.dma_read_addr2, this);
cpu.io.register_read(this.master_port | 7, this.dma_read_addr3, this);
cpu.io.register_read(this.master_port | 4, this, undefined, undefined, this.dma_read_addr);
cpu.io.register_write(this.master_port | 4, this, undefined, undefined, this.dma_set_addr);
cpu.io.register_write(this.master_port | 4, this.dma_set_addr0, this);
cpu.io.register_write(this.master_port | 5, this.dma_set_addr1, this);
cpu.io.register_write(this.master_port | 6, this.dma_set_addr2, this);
cpu.io.register_write(this.master_port | 7, this.dma_set_addr3, this);
cpu.io.register_read(this.master_port, this, this.dma_read_command8, undefined, this.dma_read_command);
cpu.io.register_write(this.master_port, this, undefined, undefined, this.dma_write_command);
cpu.io.register_read(this.master_port | 2, this.dma_read_status, this);
cpu.io.register_write(this.master_port | 2, this.dma_write_status, this);
cpu.io.register_read(this.master_port, this.dma_read_command, this);
cpu.io.register_write(this.master_port, this.dma_write_command, this);
cpu.io.register_read(this.master_port | 2, this, this.dma_read_status, undefined, undefined);
cpu.io.register_write(this.master_port | 2, this, this.dma_write_status, undefined);
/** @const */
this._state_skip = [
@ -821,27 +815,38 @@ IDEDevice.prototype.atapi_read_dma = function(cmd)
}
};
IDEDevice.prototype.read_data_port = function(port_addr)
IDEDevice.prototype.read_data_port8 = function()
{
if(port_addr === this.ata_port)
{
return this.read_data();
}
else if(port_addr === (this.ata_port | 1))
{
dbg_log("Read lba_count: " + h(this.lba_count & 0xFF), LOG_DISK);
return this.lba_count & 0xFF;
}
else if(port_addr === (this.ata_port | 2))
{
dbg_log("Read bytecount: " + h(this.bytecount & 0xFF), LOG_DISK);
return this.bytecount & 0xFF;
}
else if(port_addr === (this.ata_port | 3))
{
dbg_log("Read sector: " + h(this.sector & 0xFF), LOG_DISK);
return this.sector & 0xFF;
}
return this.read_data();
};
IDEDevice.prototype.read_data_port16 = function()
{
return this.read_data() | this.read_data() << 8;
};
IDEDevice.prototype.read_data_port32 = function()
{
return this.read_data() | this.read_data() << 8 |
this.read_data() << 16 | this.read_data() << 24;
};
IDEDevice.prototype.read_lba_port = function()
{
dbg_log("Read lba_count: " + h(this.lba_count & 0xFF), LOG_DISK);
return this.lba_count & 0xFF;
};
IDEDevice.prototype.read_bytecount_port = function()
{
dbg_log("Read bytecount: " + h(this.bytecount & 0xFF), LOG_DISK);
return this.bytecount & 0xFF;
};
IDEDevice.prototype.read_sector_port = function()
{
dbg_log("Read sector: " + h(this.sector & 0xFF), LOG_DISK);
return this.sector & 0xFF;
};
IDEDevice.prototype.read_data = function()
@ -910,54 +915,67 @@ IDEDevice.prototype.read_data = function()
}
};
IDEDevice.prototype.write_data_port = function(data, port_addr)
IDEDevice.prototype.write_data_port8 = function(data)
{
if(port_addr === this.ata_port)
if(this.data_port_current >= this.data_port_count)
{
if(this.data_port_current >= this.data_port_count)
dbg_log("Redundant write to data port: " + h(data) + " count=" + h(this.data_port_count) +
" cur=" + h(this.data_port_current), LOG_DISK);
}
else
{
if((this.data_port_current + 1 & 255) === 0 || this.data_port_count < 20)
{
dbg_log("Redundant write to data port: " + h(data) + " count=" + h(this.data_port_count) +
dbg_log("Data port: " + h(data) + " count=" + h(this.data_port_count) +
" cur=" + h(this.data_port_current), LOG_DISK);
}
else
this.data_port_buffer[this.data_port_current++] = data;
if((this.data_port_current % (this.sectors_per_drq * 512)) === 0)
{
if((this.data_port_current + 1 & 255) === 0 || this.data_port_count < 20)
{
dbg_log("Data port: " + h(data) + " count=" + h(this.data_port_count) +
" cur=" + h(this.data_port_current), LOG_DISK);
}
this.data_port_buffer[this.data_port_current++] = data;
if((this.data_port_current % (this.sectors_per_drq * 512)) === 0)
{
dbg_log("ATA IRQ", LOG_DISK);
this.push_irq();
}
if(this.data_port_current === this.data_port_count)
{
dbg_assert(typeof this[this.data_port_callback] === "function");
this[this.data_port_callback]();
}
dbg_log("ATA IRQ", LOG_DISK);
this.push_irq();
}
if(this.data_port_current === this.data_port_count)
{
dbg_assert(typeof this[this.data_port_callback] === "function");
this[this.data_port_callback]();
}
}
else if(port_addr === (this.ata_port | 1))
{
dbg_log("1F1/lba_count: " + h(data), LOG_DISK);
this.lba_count = (this.lba_count << 8 | data) & 0xFFFF;
}
else if(port_addr === (this.ata_port | 2))
{
dbg_log("1F2/bytecount: " + h(data), LOG_DISK);
this.bytecount = (this.bytecount << 8 | data) & 0xFFFF;
}
else if(port_addr === (this.ata_port | 3))
{
};
IDEDevice.prototype.write_data_port16 = function(data)
{
this.write_data_port8(data & 0xFF);
this.write_data_port8(data >> 8 & 0xFF);
};
IDEDevice.prototype.write_data_port32 = function(data)
{
this.write_data_port8(data & 0xFF);
this.write_data_port8(data >> 8 & 0xFF);
this.write_data_port8(data >> 16 & 0xFF);
this.write_data_port8(data >> 24 & 0xFF);
};
IDEDevice.prototype.write_lba_port = function(data)
{
dbg_log("1F1/lba_count: " + h(data), LOG_DISK);
this.lba_count = (this.lba_count << 8 | data) & 0xFFFF;
};
IDEDevice.prototype.write_bytecount_port = function(data)
{
dbg_log("1F2/bytecount: " + h(data), LOG_DISK);
this.bytecount = (this.bytecount << 8 | data) & 0xFFFF;
};
IDEDevice.prototype.write_sector_port = function(data)
{
dbg_log("1F3/sector: " + h(data), LOG_DISK);
this.sector = (this.sector << 8 | data) & 0xFFFF;
}
};
IDEDevice.prototype.ata_read_sectors = function(cmd)
@ -1343,39 +1361,14 @@ IDEDevice.prototype.create_identify_packet = function()
}
};
IDEDevice.prototype.dma_read_addr0 = function()
IDEDevice.prototype.dma_read_addr = function()
{
return this.prdt_addr & 0xFF;
};
IDEDevice.prototype.dma_read_addr1 = function()
{
return this.prdt_addr >> 8 & 0xFF;
};
IDEDevice.prototype.dma_read_addr2 = function()
{
return this.prdt_addr >> 16 & 0xFF;
};
IDEDevice.prototype.dma_read_addr3 = function()
{
return this.prdt_addr >> 24 & 0xFF;
return this.prdt_addr;
};
IDEDevice.prototype.dma_set_addr0 = function(data)
IDEDevice.prototype.dma_set_addr = function(data)
{
this.prdt_addr = this.prdt_addr & ~0xFF | data;
};
IDEDevice.prototype.dma_set_addr1 = function(data)
{
this.prdt_addr = this.prdt_addr & ~0xFF00 | data << 8;
};
IDEDevice.prototype.dma_set_addr2 = function(data)
{
this.prdt_addr = this.prdt_addr & ~0xFF0000 | data << 16;
};
IDEDevice.prototype.dma_set_addr3 = function(data)
{
this.prdt_addr = this.prdt_addr & 0xFFFFFF | data << 24;
dbg_log("Set PRDT addr: " + h(this.prdt_addr), LOG_DISK);
this.prdt_addr = data;
};
IDEDevice.prototype.dma_read_status = function()
@ -1394,9 +1387,16 @@ IDEDevice.prototype.dma_write_status = function(value)
IDEDevice.prototype.dma_read_command = function()
{
dbg_log("DMA read command", LOG_DISK);
return 1 | this.dma_read_status() << 16;
};
IDEDevice.prototype.dma_read_command8 = function()
{
dbg_log("DMA read command8", LOG_DISK);
return 1;
};
IDEDevice.prototype.dma_write_command = function(value)
{
dbg_log("DMA write command: " + h(value), LOG_DISK);
@ -1405,5 +1405,7 @@ IDEDevice.prototype.dma_write_command = function(value)
{
this.push_irq();
}
this.dma_write_status(value >> 16 & 0xFF);
};

301
src/io.js
View file

@ -10,6 +10,8 @@ function IO(memory)
{
var memory_size = memory.size;
this._state_skip = ["devices", "ports",];
function get_port_description(addr)
{
// via seabios ioport.h
@ -79,90 +81,188 @@ function IO(memory)
}
}
function empty_port_read_debug(port_addr)
function empty_port_read8()
{
dbg_log(
"read port #" + h(port_addr, 3) + get_port_description(port_addr),
LOG_IO
);
return 0xFF;
}
function empty_port_write_debug(out_byte, port_addr)
function empty_port_read16()
{
dbg_log(
"write port #" + h(port_addr, 3) + " <- " + h(out_byte, 2) + get_port_description(port_addr),
LOG_IO
);
return 0xFFFF;
}
function empty_port_read()
function empty_port_read32()
{
return 0xFF;
return -1;
}
function empty_port_write(x)
{
}
// Why 0x10003 if there are only 0x10000 ports:
// Reading/Writing from port 0xFFFF could make the number
// go outside of the valid range and cause an exception otherwise
/** @const */
var NUM_PORTS = 0x10003;
this.ports = [];
this.devices = Array(0x10000);
var read_callbacks = Array(NUM_PORTS),
write_callbacks = Array(NUM_PORTS);
for(var i = 0; i < NUM_PORTS; i++)
for(var i = 0; i < 0x10000; i++)
{
// avoid sparse arrays
this.ports[i] = {
read8: empty_port_read8,
read16: empty_port_read16,
read32: empty_port_read32,
if(DEBUG)
{
read_callbacks[i] = empty_port_read_debug;
write_callbacks[i] = empty_port_write_debug;
}
else
{
read_callbacks[i] = empty_port_read;
write_callbacks[i] = empty_port_write;
}
write8: empty_port_write,
write16: empty_port_write,
write32: empty_port_write,
device: undefined,
};
}
/**
* @param {number} port_addr
* @param {function():number} callback
* @param {Object=} device
* @param {Object} device
* @param {function():number} r8
* @param {function():number=} r16
* @param {function():number=} r32
*/
this.register_read = function(port_addr, callback, device)
this.register_read = function(port_addr, device, r8, r16, r32)
{
dbg_assert(typeof port_addr === "number");
dbg_assert(typeof device === "object");
dbg_assert(!r8 || typeof r8 === "function");
dbg_assert(!r16 || typeof r16 === "function");
dbg_assert(!r32 || typeof r32 === "function");
dbg_assert(r8 || r16 || r32);
if(device !== undefined)
if(DEBUG)
{
callback = callback.bind(device);
var fail = function(n) {
dbg_assert(false, "Overlapped read" + n + " " + h(port_addr, 4));
return -1;
};
if(!r8) r8 = fail.bind(this, 8);
if(!r16) r16 = fail.bind(this, 16);
if(!r32) r32 = fail.bind(this, 32);
}
read_callbacks[port_addr] = callback;
this.ports[port_addr].read8 = r8;
this.ports[port_addr].read16 = r16;
this.ports[port_addr].read32 = r32;
this.ports[port_addr].device = device;
};
/**
* @param {number} port_addr
* @param {function(number)} callback
* @param {Object=} device
* @param {Object} device
* @param {function(number)} w8
* @param {function(number)=} w16
* @param {function(number)=} w32
*/
this.register_write = function(port_addr, callback, device)
this.register_write = function(port_addr, device, w8, w16, w32)
{
dbg_assert(typeof port_addr === "number");
dbg_assert(typeof device === "object");
dbg_assert(!w8 || typeof w8 === "function");
dbg_assert(!w16 || typeof w16 === "function");
dbg_assert(!w32 || typeof w32 === "function");
dbg_assert(w8 || w16 || w32);
if(device !== undefined)
if(DEBUG)
{
callback = callback.bind(device);
var fail = function(n) {
dbg_assert(false, "Overlapped write" + n + " " + h(port_addr));
};
if(!w8) w8 = fail.bind(this, 8);
if(!w16) w16 = fail.bind(this, 16);
if(!w32) w32 = fail.bind(this, 32);
}
write_callbacks[port_addr] = callback;
this.ports[port_addr].write8 = w8;
this.ports[port_addr].write16 = w16;
this.ports[port_addr].write32 = w32;
this.ports[port_addr].device = device;
};
/*
* > Any two consecutive 8-bit ports can be treated as a 16-bit port;
* > and four consecutive 8-bit ports can be treated as a 32-bit port
* > http://css.csail.mit.edu/6.858/2012/readings/i386/s08_01.htm
*
* This info is not correct for all ports, but handled by the following functions
*
* Register the write of 2 or 4 consecutive 8-bit ports, 1 or 2 16-bit
* ports and 0 or 1 32-bit ports
*/
this.register_read_consecutive = function(port_addr, device, r8_1, r8_2, r8_3, r8_4)
{
dbg_assert(arguments.length === 4 || arguments.length === 6);
function r16_1()
{
return r8_1.call(this) |
r8_2.call(this) << 8;
}
function r16_2()
{
return r8_3.call(this) |
r8_4.call(this) << 8;
}
function r32()
{
return r8_1.call(this) |
r8_2.call(this) << 8 |
r8_3.call(this) << 16 |
r8_4.call(this) << 24;
}
if(r8_3 && r8_4)
{
this.register_read(port_addr, device, r8_1, r16_1, r32);
this.register_read(port_addr + 1, device, r8_2);
this.register_read(port_addr + 2, device, r8_3, r16_2);
this.register_read(port_addr + 3, device, r8_4);
}
else
{
this.register_read(port_addr, device, r8_1, r16_1);
this.register_read(port_addr + 1, device, r8_2);
}
};
this.register_write_consecutive = function(port_addr, device, w8_1, w8_2, w8_3, w8_4)
{
dbg_assert(arguments.length === 4 || arguments.length === 6);
function w16_1(data)
{
w8_1.call(this, data & 0xFF);
w8_2.call(this, data >> 8 & 0xFF);
}
function w16_2(data)
{
w8_3.call(this, data & 0xFF);
w8_4.call(this, data >> 8 & 0xFF);
}
function w32(data)
{
w8_1.call(this, data & 0xFF);
w8_2.call(this, data >> 8 & 0xFF);
w8_3.call(this, data >> 16 & 0xFF);
w8_4.call(this, data >>> 24);
}
if(w8_3 && w8_4)
{
this.register_write(port_addr, device, w8_1, w16_1, w32);
this.register_write(port_addr + 1, device, w8_2);
this.register_write(port_addr + 2, device, w8_3, w16_2);
this.register_write(port_addr + 3, device, w8_4);
}
else
{
this.register_write(port_addr, device, w8_1, w16_1);
this.register_write(port_addr + 1, device, w8_2);
}
};
this.mmap_read32_shim = function(addr)
@ -201,10 +301,10 @@ function IO(memory)
dbg_assert(size && (size & MMAP_BLOCK_SIZE - 1) === 0);
if(!read_func32)
read_func32 = this.mmap_read32_shim.bind(this);
read_func32 = this.mmap_read32_shim;
if(!write_func32)
write_func32 = this.mmap_write32_shim.bind(this);
write_func32 = this.mmap_write32_shim;
var aligned_addr = addr >>> MMAP_BLOCK_BITS;
@ -237,8 +337,15 @@ function IO(memory)
function(addr, value) {
// write outside of the memory size
dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value, 2), LOG_IO);
});
},
function(addr) {
dbg_log("Read from unmapped memory space, addr=" + h(addr >>> 0, 8), LOG_IO);
return -1;
},
function(addr, value) {
dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value >>> 0, 8), LOG_IO);
}
);
this.in_mmap_range = function(start, count)
{
@ -268,58 +375,88 @@ function IO(memory)
return false;
};
// any two consecutive 8-bit ports can be treated as a 16-bit port;
// and four consecutive 8-bit ports can be treated as a 32-bit port
//
// http://css.csail.mit.edu/6.858/2012/readings/i386/s08_01.htm
//
// This info seems to be incorrect, at least some multibyte ports are next
// to each other, such as 1CE and 1CF (VBE dispi) or the 170 (ATA data port).
//
// As a workaround, we pass the original port to the callback as the last argument.
this.port_write8 = function(port_addr, out_byte)
this.port_write8 = function(port_addr, data)
{
write_callbacks[port_addr](out_byte, port_addr);
var entry = this.ports[port_addr];
if(entry.write8 === empty_port_write)
{
dbg_log(
"write8 port #" + h(port_addr, 4) + " <- " + h(data, 2) + get_port_description(port_addr),
LOG_IO
);
}
return entry.write8.call(entry.device, data);
};
this.port_write16 = function(port_addr, out_byte)
this.port_write16 = function(port_addr, data)
{
//dbg_log("16 bit write port=" + h(port_addr) + " " + get_port_description(port_addr));
write_callbacks[port_addr](out_byte & 0xFF, port_addr);
write_callbacks[port_addr + 1](out_byte >> 8, port_addr);
var entry = this.ports[port_addr];
if(entry.write16 === empty_port_write)
{
dbg_log(
"write16 port #" + h(port_addr, 4) + " <- " + h(data, 4) + get_port_description(port_addr),
LOG_IO
);
}
return entry.write16.call(entry.device, data);
};
this.port_write32 = function(port_addr, out_byte)
this.port_write32 = function(port_addr, data)
{
//dbg_log("32 bit write port=" + h(port_addr) + " " + get_port_description(port_addr));
write_callbacks[port_addr](out_byte & 0xFF, port_addr);
write_callbacks[port_addr + 1](out_byte >> 8 & 0xFF, port_addr);
write_callbacks[port_addr + 2](out_byte >> 16 & 0xFF, port_addr);
write_callbacks[port_addr + 3](out_byte >>> 24, port_addr);
var entry = this.ports[port_addr];
if(entry.write32 === empty_port_write)
{
dbg_log(
"write32 port #" + h(port_addr, 4) + " <- " + h(data, 8) + get_port_description(port_addr),
LOG_IO
);
}
return entry.write32.call(entry.device, data);
};
// read byte from port
this.port_read8 = function(port_addr)
{
return read_callbacks[port_addr](port_addr);
var entry = this.ports[port_addr];
if(entry.read8 === empty_port_read8)
{
dbg_log(
"read8 port #" + h(port_addr, 4) + get_port_description(port_addr),
LOG_IO
);
}
return entry.read8.call(entry.device);
};
this.port_read16 = function(port_addr)
{
//dbg_log("16 bit read port=" + h(port_addr) + " " + get_port_description(port_addr));
return read_callbacks[port_addr](port_addr) |
read_callbacks[port_addr + 1](port_addr) << 8;
var entry = this.ports[port_addr];
if(entry.read16 === empty_port_read16)
{
dbg_log(
"read16 port #" + h(port_addr, 4) + get_port_description(port_addr),
LOG_IO
);
}
return entry.read16.call(entry.device);
};
this.port_read32 = function(port_addr)
{
//dbg_log("32 bit read port=" + h(port_addr) + " " + get_port_description(port_addr));
return read_callbacks[port_addr](port_addr) |
read_callbacks[port_addr + 1](port_addr) << 8 |
read_callbacks[port_addr + 2](port_addr) << 16 |
read_callbacks[port_addr + 3](port_addr) << 24;
var entry = this.ports[port_addr];
if(entry.read32 === empty_port_read32)
{
dbg_log(
"read32 port #" + h(port_addr, 4) + get_port_description(port_addr),
LOG_IO
);
}
return entry.read32.call(entry.device);
};
}

View file

@ -106,13 +106,13 @@ function Ne2k(cpu, adapter)
var io = cpu.io;
io.register_read(this.port | E8390_CMD, function()
io.register_read(this.port | E8390_CMD, this, function()
{
dbg_log("Read cmd", LOG_NET);
return this.cr;
}, this);
});
io.register_write(this.port | E8390_CMD, function(data_byte)
io.register_write(this.port | E8390_CMD, this, function(data_byte)
{
this.cr = data_byte | (this.cr & 4);
dbg_log("Write command: " + h(data_byte, 2), LOG_NET);
@ -123,27 +123,27 @@ function Ne2k(cpu, adapter)
{
this.remote_buffer = new Uint8Array(this.rcnt);
}
}, this);
});
io.register_read(this.port | EN0_COUNTER0, function()
io.register_read(this.port | EN0_COUNTER0, this, function()
{
dbg_log("Read counter0", LOG_NET);
return 0;
}, this);
});
io.register_read(this.port | EN0_COUNTER1, function()
io.register_read(this.port | EN0_COUNTER1, this, function()
{
dbg_log("Read counter1", LOG_NET);
return 0;
}, this);
});
io.register_read(this.port | EN0_COUNTER2, function()
io.register_read(this.port | EN0_COUNTER2, this, function()
{
dbg_log("Read counter2", LOG_NET);
return 0;
}, this);
});
io.register_read(this.port | NE_RESET, function()
io.register_read(this.port | NE_RESET, this, function()
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -156,9 +156,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Read pg1/1f", LOG_NET);
}
}, this);
});
io.register_write(this.port | NE_RESET, function(data_byte)
io.register_write(this.port | NE_RESET, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -170,9 +170,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/1f: " + h(data_byte), LOG_NET);
}
}, this);
});
io.register_read(this.port | EN0_ISR, function()
io.register_read(this.port | EN0_ISR, this, function()
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -185,9 +185,9 @@ function Ne2k(cpu, adapter)
dbg_log("Read curpg: " + h(this.curpg, 2), LOG_NET);
return this.curpg;
}
}, this);
});
io.register_write(this.port | EN0_ISR, function(data_byte)
io.register_write(this.port | EN0_ISR, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -201,9 +201,9 @@ function Ne2k(cpu, adapter)
dbg_log("Write curpg: " + h(data_byte, 2), LOG_NET);
this.curpg = data_byte
}
}, this);
});
io.register_write(this.port | EN0_TXCR, function(data_byte)
io.register_write(this.port | EN0_TXCR, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -214,9 +214,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x0d " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_write(this.port | EN0_DCFG, function(data_byte)
io.register_write(this.port | EN0_DCFG, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -227,9 +227,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x0e " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_write(this.port | EN0_RCNTLO, function(data_byte)
io.register_write(this.port | EN0_RCNTLO, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -241,9 +241,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x0a " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_write(this.port | EN0_RCNTHI, function(data_byte)
io.register_write(this.port | EN0_RCNTHI, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -255,9 +255,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x0b " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_write(this.port | EN0_RSARLO, function(data_byte)
io.register_write(this.port | EN0_RSARLO, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -269,9 +269,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x08 " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_write(this.port | EN0_RSARHI, function(data_byte)
io.register_write(this.port | EN0_RSARHI, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -283,9 +283,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x09 " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_write(this.port | EN0_IMR, function(data_byte)
io.register_write(this.port | EN0_IMR, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -297,9 +297,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x0f " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_read(this.port | EN0_BOUNDARY, function()
io.register_read(this.port | EN0_BOUNDARY, this, function()
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -312,9 +312,9 @@ function Ne2k(cpu, adapter)
dbg_log("Read pg1/0x03", LOG_NET);
return 0;
}
}, this);
});
io.register_write(this.port | EN0_BOUNDARY, function(data_byte)
io.register_write(this.port | EN0_BOUNDARY, this, function(data_byte)
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -326,9 +326,9 @@ function Ne2k(cpu, adapter)
{
dbg_log("Write pg1/0x03 " + h(data_byte, 2), LOG_NET);
}
}, this);
});
io.register_read(this.port | EN0_TSR, function()
io.register_read(this.port | EN0_TSR, this, function()
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -340,9 +340,9 @@ function Ne2k(cpu, adapter)
dbg_log("Read pg1/0x04", LOG_NET);
return 0;
}
}, this);
});
io.register_read(this.port | EN0_RSR, function()
io.register_read(this.port | EN0_RSR, this, function()
{
var pg = this.cr & 0xC0;
if(pg === 0)
@ -354,17 +354,10 @@ function Ne2k(cpu, adapter)
dbg_log("Read pg1/0x0c", LOG_NET);
return 0;
}
}, this);
});
io.register_read(this.port | NE_DATAPORT | 0, this.data_port_read, this);
io.register_read(this.port | NE_DATAPORT | 1, this.data_port_read, this);
io.register_read(this.port | NE_DATAPORT | 2, this.data_port_read, this);
io.register_read(this.port | NE_DATAPORT | 3, this.data_port_read, this);
io.register_write(this.port | NE_DATAPORT | 0, this.data_port_write, this);
io.register_write(this.port | NE_DATAPORT | 1, this.data_port_write, this);
io.register_write(this.port | NE_DATAPORT | 2, this.data_port_write, this);
io.register_write(this.port | NE_DATAPORT | 3, this.data_port_write, this);
io.register_read(this.port | NE_DATAPORT | 0, this, this.data_port_read, this.data_port_read16, this.data_port_read32);
io.register_write(this.port | NE_DATAPORT | 0, this, this.data_port_write, this.data_port_write16, this.data_port_write32);
this._state_skip = [
"adapter",
@ -403,6 +396,20 @@ Ne2k.prototype.data_port_write = function(data_byte)
}
};
Ne2k.prototype.data_port_write16 = function(data)
{
this.data_port_write(data);
this.data_port_write(data >> 8);
};
Ne2k.prototype.data_port_write32 = function(data)
{
this.data_port_write(data);
this.data_port_write(data >> 8);
this.data_port_write(data >> 16);
this.data_port_write(data >> 24);
};
Ne2k.prototype.data_port_read = function()
{
var data = this.receive_buffer[this.rsar++];
@ -412,6 +419,17 @@ Ne2k.prototype.data_port_read = function()
return data;
};
Ne2k.prototype.data_port_read16 = function()
{
return this.data_port_read() | this.data_port_read() << 8;
};
Ne2k.prototype.data_port_read32 = function()
{
return this.data_port_read() | this.data_port_read() << 8 |
this.data_port_read() << 16 | this.data_port_read() << 24;
};
Ne2k.prototype.receive = function(data)
{
// called from the adapter when data is received over the network

View file

@ -46,80 +46,86 @@ function PCI(cpu)
}
});*/
io.register_write(PCI_CONFIG_DATA, function(out_byte)
{
dbg_log("PCI data0: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(0, out_byte);
});
io.register_write(PCI_CONFIG_DATA | 1, function(out_byte)
{
dbg_log("PCI data1: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(1, out_byte);
});
io.register_write(PCI_CONFIG_DATA | 2, function(out_byte)
{
dbg_log("PCI data2: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(2, out_byte);
});
io.register_write(PCI_CONFIG_DATA | 3, function(out_byte)
{
dbg_log("PCI data3: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
io.register_write_consecutive(PCI_CONFIG_DATA, this,
function(out_byte)
{
dbg_log("PCI data0: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(0, out_byte);
},
function(out_byte)
{
dbg_log("PCI data1: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(1, out_byte);
},
function(out_byte)
{
dbg_log("PCI data2: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(2, out_byte);
},
function(out_byte)
{
dbg_log("PCI data3: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
pci_write_byte(3, out_byte);
}
);
pci_write_byte(3, out_byte);
});
io.register_read_consecutive(PCI_CONFIG_DATA, this,
function()
{
return pci_response[0];
},
function()
{
return pci_response[1];
},
function()
{
return pci_response[2];
},
function()
{
return pci_response[3];
}
);
io.register_read(PCI_CONFIG_DATA, function()
{
return pci_response[0];
});
io.register_read(PCI_CONFIG_DATA | 1, function()
{
return pci_response[1];
});
io.register_read(PCI_CONFIG_DATA | 2, function()
{
return pci_response[2];
});
io.register_read(PCI_CONFIG_DATA | 3, function()
{
return pci_response[3];
});
io.register_read_consecutive(PCI_CONFIG_ADDRESS, this,
function()
{
return pci_status[0];
},
function()
{
return pci_status[1];
},
function()
{
return pci_status[2];
},
function()
{
return pci_status[3];
}
);
io.register_read(PCI_CONFIG_ADDRESS, function()
{
return pci_status[0];
});
io.register_read(PCI_CONFIG_ADDRESS | 1, function()
{
return pci_status[1];
});
io.register_read(PCI_CONFIG_ADDRESS | 2, function()
{
return pci_status[2];
});
io.register_read(PCI_CONFIG_ADDRESS | 3, function()
{
return pci_status[3];
});
io.register_write(PCI_CONFIG_ADDRESS, function(out_byte)
{
pci_addr[0] = out_byte;
});
io.register_write(PCI_CONFIG_ADDRESS | 1, function(out_byte)
{
pci_addr[1] = out_byte;
});
io.register_write(PCI_CONFIG_ADDRESS | 2, function(out_byte)
{
pci_addr[2] = out_byte;
});
io.register_write(PCI_CONFIG_ADDRESS | 3, function(out_byte)
{
pci_addr[3] = out_byte;
pci_query();
});
io.register_write_consecutive(PCI_CONFIG_ADDRESS, this,
function(out_byte)
{
pci_addr[0] = out_byte;
},
function(out_byte)
{
pci_addr[1] = out_byte;
},
function(out_byte)
{
pci_addr[2] = out_byte;
},
function(out_byte)
{
pci_addr[3] = out_byte;
pci_query();
}
);
function pci_query()
{

View file

@ -91,7 +91,7 @@ function PIC(cpu, master)
cpu.call_interrupt_vector(this.irq_map | irq_number, false, false);
return true;
}.bind(this);
};
}
else
{
@ -135,7 +135,7 @@ function PIC(cpu, master)
}
return true;
}.bind(this);
};
}
this.dump = function()
@ -161,11 +161,11 @@ function PIC(cpu, master)
io_base = 0xA0;
}
cpu.io.register_write(io_base, port20_write, this);
cpu.io.register_read(io_base, port20_read, this);
cpu.io.register_write(io_base, this, port20_write);
cpu.io.register_read(io_base, this, port20_read);
cpu.io.register_write(io_base | 1, port21_write, this);
cpu.io.register_read(io_base | 1, port21_read, this);
cpu.io.register_write(io_base | 1, this, port21_write);
cpu.io.register_read(io_base | 1, this, port21_read);
function port20_write(data_byte)
{

View file

@ -39,7 +39,7 @@ function PIT(cpu)
var parity = 0;
cpu.io.register_read(0x61, function()
cpu.io.register_read(0x61, this, function()
{
// > xxx1 xxxx 0=RAM parity error enable
// > PS/2: Read: This bit tiggles for each refresh request.
@ -48,17 +48,17 @@ function PIT(cpu)
parity ^= 0x10;
return parity | this.counter2_out << 5;
}.bind(this));
});
cpu.io.register_read(0x40, this.counter_read.bind(this, 0));
cpu.io.register_read(0x41, this.counter_read.bind(this, 1));
cpu.io.register_read(0x42, this.counter_read.bind(this, 2));
cpu.io.register_read(0x40, this, function() { return this.counter_read(0); });
cpu.io.register_read(0x41, this, function() { return this.counter_read(1); });
cpu.io.register_read(0x42, this, function() { return this.counter_read(2); });
cpu.io.register_write(0x40, this.counter_write.bind(this, 0));
cpu.io.register_write(0x41, this.counter_write.bind(this, 1));
cpu.io.register_write(0x42, this.counter_write.bind(this, 2));
cpu.io.register_write(0x40, this, function(data) { this.counter_write(0, data); });
cpu.io.register_write(0x41, this, function(data) { this.counter_write(1, data); });
cpu.io.register_write(0x42, this, function(data) { this.counter_write(2, data); });
cpu.io.register_write(0x43, this.port43_write.bind(this));
cpu.io.register_write(0x43, this, this.port43_write);
/** @const */
this._state_skip = ["pic"];

View file

@ -93,11 +93,11 @@ function PS2(cpu, keyboard, mouse)
this.read_output_register = false;
this.read_command_register = false;
cpu.io.register_read(0x60, this.port60_read, this);
cpu.io.register_read(0x64, this.port64_read, this);
cpu.io.register_read(0x60, this, this.port60_read);
cpu.io.register_read(0x64, this, this.port64_read);
cpu.io.register_write(0x60, this.port60_write, this);
cpu.io.register_write(0x64, this.port64_write, this);
cpu.io.register_write(0x60, this, this.port60_write);
cpu.io.register_write(0x64, this, this.port64_write);
/** @const */
this._state_skip = ["pic", "cpu"];

View file

@ -31,14 +31,14 @@ function RTC(cpu, diskette_type, boot_order)
this.nmi_disabled = 0;
cpu.io.register_write(0x70, function(out_byte)
cpu.io.register_write(0x70, this, function(out_byte)
{
this.cmos_index = out_byte & 0x7F;
this.nmi_disabled = out_byte >> 7;
}.bind(this));
});
cpu.io.register_write(0x71, this.cmos_write.bind(this));
cpu.io.register_read(0x71, this.cmos_read.bind(this));
cpu.io.register_write(0x71, this, this.cmos_write);
cpu.io.register_read(0x71, this, this.cmos_read);
this._state_skip = ["cpu", "pic"];
}

View file

@ -62,7 +62,7 @@ function UART(cpu, port, adapter)
var io = cpu.io;
io.register_write(port, function(out_byte)
io.register_write(port, this, function(out_byte)
{
if(this.line_control & DLAB)
{
@ -98,9 +98,9 @@ function UART(cpu, port, adapter)
{
adapter.put_str(String.fromCharCode(out_byte));
}
}, this);
});
io.register_write(port | 1, function(out_byte)
io.register_write(port | 1, this, function(out_byte)
{
if(this.line_control & DLAB)
{
@ -112,9 +112,9 @@ function UART(cpu, port, adapter)
this.interrupt_enable = out_byte;
dbg_log("interrupt enable: " + h(out_byte), LOG_SERIAL);
}
}, this);
});
io.register_read(port, function()
io.register_read(port, this, function()
{
if(this.line_control & DLAB)
{
@ -135,9 +135,9 @@ function UART(cpu, port, adapter)
return data;
}
}, this);
});
io.register_read(port | 1, function()
io.register_read(port | 1, this, function()
{
if(this.line_control & DLAB)
{
@ -147,45 +147,45 @@ function UART(cpu, port, adapter)
{
return this.interrupt_enable;
}
}, this);
});
io.register_read(port | 2, function()
io.register_read(port | 2, this, function()
{
var ret = this.iir;
dbg_log("read interrupt identification: " + h(this.iir), LOG_SERIAL);
this.iir ^= 1;
return ret;
}, this);
io.register_write(port | 2, function(out_byte)
});
io.register_write(port | 2, this, function(out_byte)
{
dbg_log("fifo control: " + h(out_byte), LOG_SERIAL);
this.fifo_control = out_byte;
}, this);
});
io.register_read(port | 3, function()
io.register_read(port | 3, this, function()
{
dbg_log("read line control: " + h(this.line_control), LOG_SERIAL);
return this.line_control;
}, this);
io.register_write(port | 3, function(out_byte)
});
io.register_write(port | 3, this, function(out_byte)
{
dbg_log("line control: " + h(out_byte), LOG_SERIAL);
this.line_control = out_byte;
}, this);
});
io.register_read(port | 4, function()
io.register_read(port | 4, this, function()
{
return this.modem_control;
}, this);
io.register_write(port | 4, function(out_byte)
});
io.register_write(port | 4, this, function(out_byte)
{
dbg_log("modem control: " + h(out_byte), LOG_SERIAL);
this.modem_control = out_byte;
}, this);
});
io.register_read(port | 5, function()
io.register_read(port | 5, this, function()
{
var line_status = 0;
@ -198,30 +198,30 @@ function UART(cpu, port, adapter)
dbg_log("read line status: " + h(line_status), LOG_SERIAL);
return line_status;
}, this);
io.register_write(port | 5, function(out_byte)
});
io.register_write(port | 5, this, function(out_byte)
{
dbg_log("Factory test write", LOG_SERIAL);
}, this);
});
io.register_read(port | 6, function()
io.register_read(port | 6, this, function()
{
dbg_log("read modem status: " + h(this.modem_status), LOG_SERIAL);
return this.modem_status;
}, this);
io.register_write(port | 6, function(out_byte)
});
io.register_write(port | 6, this, function(out_byte)
{
dbg_log("Unkown register write (base+6)", LOG_SERIAL);
}, this);
});
io.register_read(port | 7, function()
io.register_read(port | 7, this, function()
{
return this.scratch_register;
}, this);
io.register_write(port | 7, function(out_byte)
});
io.register_write(port | 7, this, function(out_byte)
{
this.scratch_register = out_byte;
}, this);
});
}
UART.prototype.push_irq = function()

View file

@ -182,49 +182,43 @@ function VGAScreen(cpu, adapter, vga_memory_size)
var io = cpu.io;
io.register_write(0x3C0, this.port3C0_write, this);
io.register_read(0x3C0, this.port3C0_read, this);
io.register_write(0x3C0, this, this.port3C0_write);
io.register_read(0x3C0, this, this.port3C0_read);
io.register_read(0x3C1, this.port3C1_read, this);
io.register_write(0x3C2, this.port3C2_write, this);
io.register_read(0x3C1, this, this.port3C1_read);
io.register_write(0x3C2, this, this.port3C2_write);
io.register_write(0x3C4, this.port3C4_write, this);
io.register_read(0x3C4, this.port3C4_read, this);
io.register_write_consecutive(0x3C4, this, this.port3C4_write, this.port3C5_write);
io.register_write(0x3C5, this.port3C5_write, this);
io.register_read(0x3C5, this.port3C5_read, this);
io.register_read(0x3C4, this, this.port3C4_read);
io.register_read(0x3C5, this, this.port3C5_read);
io.register_write(0x3CE, this.port3CE_write, this);
io.register_read(0x3CE, this.port3CE_read, this);
io.register_write_consecutive(0x3CE, this, this.port3CE_write, this.port3CF_write);
io.register_write(0x3CF, this.port3CF_write, this);
io.register_read(0x3CF, this.port3CF_read, this);
io.register_read(0x3CE, this, this.port3CE_read);
io.register_read(0x3CF, this, this.port3CF_read);
io.register_write(0x3C7, this.port3C7_write, this);
io.register_write(0x3C8, this.port3C8_write, this);
io.register_write(0x3C9, this.port3C9_write, this);
io.register_write(0x3C7, this, this.port3C7_write);
io.register_write(0x3C8, this, this.port3C8_write);
io.register_write(0x3C9, this, this.port3C9_write);
io.register_read(0x3CC, this.port3CC_read, this);
io.register_read(0x3CC, this, this.port3CC_read);
io.register_write(0x3D4, this.port3D4_write, this);
io.register_write(0x3D5, this.port3D5_write, this);
io.register_read(0x3D5, this.port3D5_read, this);
io.register_write_consecutive(0x3D4, this, this.port3D4_write, this.port3D5_write);
io.register_read(0x3D5, this, this.port3D5_read);
io.register_read(0x3DA, this.port3DA_read, this);
io.register_read(0x3DA, this, this.port3DA_read);
// Bochs VBE Extensions
// http://wiki.osdev.org/Bochs_VBE_Extensions
this.dispi_index = -1;
this.dispi_value = -1;
this.dispi_enable_value = 0;
io.register_write(0x1CE, this.port1CE_write, this);
io.register_write(0x1CF, this.port1CF_write, this);
io.register_write(0x1D0, this.port1D0_write, this);
io.register_write(0x1CE, this, undefined, this.port1CE_write);
io.register_read(0x1CF, this.port1CF_read, this);
io.register_read(0x1D0, this.port1D0_read, this);
io.register_write(0x1CF, this, undefined, this.port1CF_write);
io.register_read(0x1CF, this, undefined, this.port1CF_read);
if(this.vga_memory_size === undefined || this.vga_memory_size < 4 * VGA_BANK_SIZE)
{
@ -252,13 +246,16 @@ function VGAScreen(cpu, adapter, vga_memory_size)
this.set_size_text(80, 25);
this.update_cursor_scanline();
var me = this;
io.mmap_register(0xA0000, 0x20000,
this.vga_memory_read.bind(this),
this.vga_memory_write.bind(this)
function(addr) { return me.vga_memory_read(addr); },
function(addr, value) { me.vga_memory_write(addr, value); }
);
io.mmap_register(0xE0000000, this.vga_memory_size,
this.svga_memory_read8.bind(this), this.svga_memory_write8.bind(this),
this.svga_memory_read32.bind(this), this.svga_memory_write32.bind(this)
function(addr) { return me.svga_memory_read8(addr); },
function(addr, value) { me.svga_memory_write8(addr, value); },
function(addr) { return me.svga_memory_read32(addr); },
function(addr, value) { me.svga_memory_write32(addr, value); }
);
/** @const */
@ -1211,29 +1208,14 @@ VGAScreen.prototype.port1CE_write = function(value)
this.dispi_index = value;
};
VGAScreen.prototype.port1CF_write = function(value, low_port)
VGAScreen.prototype.port1CF_write = function(value)
{
if(low_port === 0x1CE)
{
this.dispi_index = this.dispi_index & 0xFF | value << 8;
}
else
{
this.dispi_value = value;
dbg_log("1CF / dispi write low " + h(this.dispi_index) + ": " + h(value), LOG_VGA);
}
};
VGAScreen.prototype.port1D0_write = function(value)
{
dbg_log("1D0 / dispi write high " + h(this.dispi_index) + ": " + h(value), LOG_VGA);
this.dispi_value = this.dispi_value & 0xFF | value << 8;
dbg_log("1CF / dispi write " + h(this.dispi_index) + ": " + h(value), LOG_VGA);
switch(this.dispi_index)
{
case 1:
this.svga_width = this.dispi_value;
this.svga_width = value;
if(this.svga_width > MAX_XRES)
{
dbg_log("svga_width reduced from " + this.svga_width + " to " + MAX_XRES, LOG_VGA);
@ -1241,7 +1223,7 @@ VGAScreen.prototype.port1D0_write = function(value)
}
break;
case 2:
this.svga_height = this.dispi_value;
this.svga_height = value;
if(this.svga_height > MAX_YRES)
{
dbg_log("svga_height reduced from " + this.svga_height + " to " + MAX_YRES, LOG_VGA);
@ -1249,17 +1231,17 @@ VGAScreen.prototype.port1D0_write = function(value)
}
break;
case 3:
this.svga_bpp = this.dispi_value;
this.svga_bpp = value;
break;
case 4:
// enable, options
this.svga_enabled = (this.dispi_value & 1) === 1;
this.dispi_enable_value = this.dispi_value;
this.svga_enabled = (value & 1) === 1;
this.dispi_enable_value = value;
break;
case 9:
// y offset
this.svga_offset = this.dispi_value * this.svga_bytes_per_line();
dbg_log("SVGA offset: " + h(this.svga_offset) + " y=" + h(this.dispi_value), LOG_VGA);
this.svga_offset = value * this.svga_bytes_per_line();
dbg_log("SVGA offset: " + h(this.svga_offset) + " y=" + h(value), LOG_VGA);
this.do_complete_redraw = true;
break;
default:
@ -1287,14 +1269,9 @@ VGAScreen.prototype.port1D0_write = function(value)
VGAScreen.prototype.port1CF_read = function()
{
dbg_log("1CF / dispi read low " + h(this.dispi_index), LOG_VGA);
dbg_log("1CF / dispi read " + h(this.dispi_index), LOG_VGA);
return this.svga_register_read(this.dispi_index);
};
VGAScreen.prototype.port1D0_read = function()
{
dbg_log("1D0 / dispi read high " + h(this.dispi_index), LOG_VGA);
return this.svga_register_read(this.dispi_index) >> 8;
};
VGAScreen.prototype.svga_register_read = function(n)
{
@ -1304,11 +1281,11 @@ VGAScreen.prototype.svga_register_read = function(n)
// id
return 0xB0C0;
case 1:
return this.dispi_value & 2 ? MAX_XRES : this.svga_width;
return this.dispi_enable_value & 2 ? MAX_XRES : this.svga_width;
case 2:
return this.dispi_value & 2 ? MAX_YRES : this.svga_height;
return this.dispi_enable_value & 2 ? MAX_YRES : this.svga_height;
case 3:
return this.dispi_value & 2 ? MAX_BPP : this.svga_bpp;
return this.dispi_enable_value & 2 ? MAX_BPP : this.svga_bpp;
case 4:
return this.dispi_enable_value;
case 6: