Preparations for configurable PCI, base address registers
This commit is contained in:
parent
125b7748a1
commit
e73c75b8ee
105
src/cpu.macro.js
105
src/cpu.macro.js
|
@ -313,6 +313,7 @@ var
|
|||
reg8s,
|
||||
|
||||
sreg,
|
||||
dreg,
|
||||
|
||||
|
||||
// sp or esp, depending on stack size attribute
|
||||
|
@ -473,6 +474,7 @@ function cpu_init(settings)
|
|||
reg8 = new Uint8Array(reg32.buffer);
|
||||
reg8s = new Int8Array(reg32.buffer);
|
||||
sreg = new Uint16Array(8);
|
||||
dreg = new Int32Array(8);
|
||||
protected_mode = false;
|
||||
|
||||
idtr_size = 0;
|
||||
|
@ -531,6 +533,15 @@ function cpu_init(settings)
|
|||
last_op_size = 0;
|
||||
|
||||
|
||||
var devapi = {
|
||||
memory: memory,
|
||||
reboot: cpu_reboot_internal,
|
||||
time: function() { return performance.now(); },
|
||||
};
|
||||
|
||||
cpu.dev = {};
|
||||
|
||||
devapi.io = cpu.dev.io = io = new IO(memory);
|
||||
|
||||
if(settings.bios)
|
||||
{
|
||||
|
@ -548,7 +559,7 @@ function cpu_init(settings)
|
|||
}
|
||||
|
||||
// seabios expects the bios to be mapped to 0xFFF00000 also
|
||||
memory.mmap_register(0xFFF00000, 0x100000, 1,
|
||||
io.mmap_register(0xFFF00000, 0x100000, 1,
|
||||
function(addr)
|
||||
{
|
||||
return memory.mem8[addr];
|
||||
|
@ -615,17 +626,31 @@ function cpu_init(settings)
|
|||
}
|
||||
|
||||
|
||||
cpu.dev = {};
|
||||
var a20_byte = 0;
|
||||
|
||||
io.register_read(0x92, function()
|
||||
{
|
||||
return a20_byte;
|
||||
});
|
||||
|
||||
io.register_write(0x92, function(out_byte)
|
||||
{
|
||||
a20_byte = out_byte;
|
||||
});
|
||||
|
||||
if(DEBUG)
|
||||
{
|
||||
// Use by linux for port-IO delay
|
||||
// Avoid generating tons of debug messages
|
||||
io.register_write(0x80, function(out_byte)
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// TODO: Make this more configurable
|
||||
if(settings.load_devices)
|
||||
{
|
||||
var devapi = {
|
||||
memory: memory,
|
||||
reboot: cpu_reboot_internal,
|
||||
time: function() { return performance.now(); },
|
||||
};
|
||||
|
||||
devapi.io = cpu.dev.io = io = new IO();
|
||||
devapi.pic = pic = new PIC(devapi, call_interrupt_vector, handle_irqs);
|
||||
devapi.pci = pci = new PCI(devapi);
|
||||
devapi.dma = dma = new DMA(devapi);
|
||||
|
@ -665,54 +690,58 @@ function cpu_init(settings)
|
|||
hpet = new HPET(devapi);
|
||||
}
|
||||
|
||||
var acpi = {
|
||||
pci_id: 0x07 << 3,
|
||||
pci_space: [
|
||||
0x86, 0x80, 0x13, 0x71, 0x07, 0x00, 0x80, 0x02, 0x08, 0x00, 0x80, 0x06, 0x00, 0x00, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00,
|
||||
],
|
||||
pci_bars: [],
|
||||
};
|
||||
|
||||
// 00:07.0 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
|
||||
this.register_device([
|
||||
0x86, 0x80, 0x13, 0x71, 0x07, 0x00, 0x80, 0x02, 0x08, 0x00, 0x80, 0x06, 0x00, 0x00, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00,
|
||||
], 0x07 << 3);
|
||||
|
||||
|
||||
io.register_device(acpi);
|
||||
|
||||
var elcr = 0;
|
||||
|
||||
// ACPI, ELCR register
|
||||
dev.io.register_write(0x4d0, function(data)
|
||||
io.register_write(0x4d0, function(data)
|
||||
{
|
||||
elcr = elcr & 0xFF00 | data;
|
||||
});
|
||||
dev.io.register_write(0x4d1, function(data)
|
||||
io.register_write(0x4d1, function(data)
|
||||
{
|
||||
elcr = elcr & 0xFF | data << 8;
|
||||
});
|
||||
|
||||
|
||||
// ACPI, pmtimer
|
||||
dev.io.register_read(0xb008, function(data)
|
||||
io.register_read(0xb008, function(data)
|
||||
{
|
||||
return 0;
|
||||
});
|
||||
dev.io.register_read(0xb009, function(data)
|
||||
io.register_read(0xb009, function(data)
|
||||
{
|
||||
return 0;
|
||||
});
|
||||
dev.io.register_read(0xb00a, function(data)
|
||||
io.register_read(0xb00a, function(data)
|
||||
{
|
||||
return 0;
|
||||
});
|
||||
dev.io.register_read(0xb00b, function(data)
|
||||
io.register_read(0xb00b, function(data)
|
||||
{
|
||||
return 0;
|
||||
});
|
||||
|
||||
// ACPI status
|
||||
dev.io.register_read(0xb004, function(data)
|
||||
io.register_read(0xb004, function(data)
|
||||
{
|
||||
dbg_log("b004 read");
|
||||
return 1;
|
||||
});
|
||||
dev.io.register_read(0xb005, function(data)
|
||||
io.register_read(0xb005, function(data)
|
||||
{
|
||||
dbg_log("b005 read");
|
||||
return 0;
|
||||
|
@ -922,12 +951,12 @@ var npe_functions = {
|
|||
|
||||
read_imm8: function()
|
||||
{
|
||||
return memory.mem8[instruction_pointer++];
|
||||
return memory.read8(instruction_pointer++);
|
||||
},
|
||||
|
||||
read_imm8s: function()
|
||||
{
|
||||
return memory.mem8s[instruction_pointer++];
|
||||
return memory.read8(instruction_pointer++) << 24 >> 24;
|
||||
},
|
||||
|
||||
read_imm16 : function()
|
||||
|
@ -1262,10 +1291,10 @@ function call_interrupt_vector(interrupt_nr, is_software_int, error_code)
|
|||
//}
|
||||
|
||||
|
||||
//if(interrupt_nr === 14)
|
||||
//{
|
||||
// dbg_log("int14 error_code=" + error_code + " cr2=" + h(cr2 >>> 0) + " prev=" + h(previous_ip >>> 0) + " cpl=" + cpl, LOG_CPU);
|
||||
//}
|
||||
if(interrupt_nr === 14)
|
||||
{
|
||||
dbg_log("int14 error_code=" + error_code + " cr2=" + h(cr2 >>> 0) + " prev=" + h(previous_ip >>> 0) + " cpl=" + cpl, LOG_CPU);
|
||||
}
|
||||
|
||||
|
||||
if(in_hlt)
|
||||
|
@ -1426,6 +1455,7 @@ function call_interrupt_vector(interrupt_nr, is_software_int, error_code)
|
|||
|
||||
if(flags & flag_vm)
|
||||
{
|
||||
dbg_log("return from vm86 mode", LOG_CPU);
|
||||
flags &= ~flag_vm & ~flag_rf;
|
||||
|
||||
push32(sreg[reg_gs]);
|
||||
|
@ -1680,14 +1710,15 @@ function test_privileges_for_io(port, size)
|
|||
{
|
||||
if(tsr_size >= 0x67)
|
||||
{
|
||||
var iomap_base = safe_read16(tsr_offset + 0x64 + 2),
|
||||
var iomap_base = memory.read16(translate_address_system_read(tsr_offset + 0x64 + 2)),
|
||||
high_port = port + size - 1;
|
||||
|
||||
if(tsr_size >= iomap_base + (high_port >> 3))
|
||||
{
|
||||
var mask = ((1 << size) - 1) << (port & 7),
|
||||
addr = translate_address_system_read(tsr_offset + iomap_base + (port >> 3)),
|
||||
port_info = (mask & 0xFF00) ?
|
||||
safe_read16(port >> 3) : safe_read8(port >> 3);
|
||||
memory.read16(addr) : memory.read8(addr);
|
||||
|
||||
if(!(port_info & mask))
|
||||
{
|
||||
|
@ -1750,7 +1781,7 @@ function cpuid()
|
|||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) throw "cpuid: unimplemented eax: " + h(id);
|
||||
//if(DEBUG) throw "cpuid: unimplemented eax: " + h(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2019,7 +2050,7 @@ function switch_seg(reg, selector)
|
|||
|
||||
if(!info.dc_bit && info.dpl < cpl)
|
||||
{
|
||||
throw unimpl("inter privilege interrupt");
|
||||
throw unimpl("inter privilege call");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2426,7 +2457,9 @@ function trigger_pagefault(write, user, present)
|
|||
{
|
||||
if(LOG_LEVEL & LOG_CPU)
|
||||
{
|
||||
//dbg_trace();
|
||||
//dbg_log("page fault", LOG_CPU);
|
||||
dbg_trace();
|
||||
//throw "stop";
|
||||
}
|
||||
|
||||
if(page_fault)
|
||||
|
|
|
@ -140,7 +140,7 @@ function HPET(dev)
|
|||
}
|
||||
}
|
||||
|
||||
dev.memory.mmap_register(HPET_ADDR, 0x4000, 4, mmio_read, mmio_write);
|
||||
dev.io.mmap_register(HPET_ADDR, 0x4000, 4, mmio_read, mmio_write);
|
||||
|
||||
|
||||
|
||||
|
|
54
src/ide.js
54
src/ide.js
|
@ -21,7 +21,7 @@ function IDEDevice(dev, buffer, is_cd, nr)
|
|||
}
|
||||
else
|
||||
{
|
||||
this.ata_port = 0x170;
|
||||
this.ata_port = 0x1F0;
|
||||
this.irq = 15;
|
||||
}
|
||||
|
||||
|
@ -63,12 +63,8 @@ function IDEDevice(dev, buffer, is_cd, nr)
|
|||
}
|
||||
}
|
||||
|
||||
// 00:1f.2 IDE interface: Intel Corporation 82801JI (ICH10 Family) 4 port SATA IDE Controller #1
|
||||
//0x86, 0x80, 0x20, 0x3a, 0x05, 0x00, 0xb0, 0x02, 0x00, 0x8f, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
//0x01, 0x90, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x81, 0x88, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00,
|
||||
//0x81, 0x84, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x10, 0xd4, 0x82,
|
||||
//0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00,
|
||||
dev.pci.register_device([
|
||||
this.pci_id = 0x1F << 3;
|
||||
this.pci_space = [
|
||||
0x86, 0x80, 0x20, 0x3a, 0x05, 0x00, 0xa0, 0x02, 0x00, 0x8f, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
this.ata_port & 0xFF | 1, this.ata_port >> 8, 0x00, 0x00,
|
||||
this.ata_port_high & 0xFF | 1, this.ata_port_high >> 8, 0x00, 0x00,
|
||||
|
@ -78,8 +74,23 @@ function IDEDevice(dev, buffer, is_cd, nr)
|
|||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x43, 0x10, 0xd4, 0x82,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this.irq, 0x02, 0x00, 0x00,
|
||||
], 0x1f << 3);
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, this.irq, 0x00, 0x00, 0x00,
|
||||
];
|
||||
this.pci_bars = [
|
||||
{
|
||||
size: 8,
|
||||
},
|
||||
{
|
||||
size: 4,
|
||||
},
|
||||
];
|
||||
|
||||
// 00:1f.2 IDE interface: Intel Corporation 82801JI (ICH10 Family) 4 port SATA IDE Controller #1
|
||||
//0x86, 0x80, 0x20, 0x3a, 0x05, 0x00, 0xb0, 0x02, 0x00, 0x8f, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
//0x01, 0x90, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x81, 0x88, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00,
|
||||
//0x81, 0x84, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x10, 0xd4, 0x82,
|
||||
//0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00,
|
||||
dev.pci.register_device(this);
|
||||
|
||||
// status
|
||||
this.io.register_read(this.ata_port | 7, read_status);
|
||||
|
@ -159,15 +170,16 @@ function IDEDevice(dev, buffer, is_cd, nr)
|
|||
cylinder_low = transfered_ata_blocks >> 8;
|
||||
cylinder_high = transfered_ata_blocks;
|
||||
|
||||
if(start + byte_count > buffer.byteLength)
|
||||
if(start >= buffer.byteLength)
|
||||
{
|
||||
dbg_log("CD read: Outside of disk", LOG_DISK);
|
||||
dbg_log("CD read: Outside of disk end=" + h(start + byte_count) + " size=" + h(buffer.byteLength), LOG_DISK);
|
||||
|
||||
status = 0xFF;
|
||||
push_irq();
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_count = Math.min(byte_count, buffer.byteLength - start);
|
||||
status = 0xFF;
|
||||
|
||||
me.buffer.get(start, byte_count, function(data)
|
||||
|
@ -189,14 +201,14 @@ function IDEDevice(dev, buffer, is_cd, nr)
|
|||
if((data_pointer + 1) % (sectors_per_drq * 512) === 0 ||
|
||||
data_pointer + 1 === pio_data.length)
|
||||
{
|
||||
if(data_pointer + 1 === pio_data.length)
|
||||
{
|
||||
status = 0x50;
|
||||
bytecount = 3;
|
||||
}
|
||||
|
||||
dbg_log("ATA IRQ", LOG_DISK);
|
||||
push_irq();
|
||||
//push_irq();
|
||||
}
|
||||
|
||||
if(data_pointer + 1 >= pio_data.length)
|
||||
{
|
||||
status = 0x50;
|
||||
bytecount = 3;
|
||||
}
|
||||
|
||||
if((data_pointer + 1 & 255) === 0)
|
||||
|
@ -310,7 +322,11 @@ function IDEDevice(dev, buffer, is_cd, nr)
|
|||
break;
|
||||
case 0x43:
|
||||
// read header
|
||||
pio_data = new Uint8Array(Math.min(atapi_command[8], 4));
|
||||
pio_data = new Uint8Array(2048);
|
||||
pio_data[0] = 0;
|
||||
pio_data[1] = 10;
|
||||
pio_data[2] = 1;
|
||||
pio_data[3] = 1;
|
||||
status = 0x58;
|
||||
data_pointer = 0;
|
||||
bytecount = 2;
|
||||
|
|
67
src/io.js
67
src/io.js
|
@ -6,10 +6,9 @@
|
|||
*
|
||||
* @constructor
|
||||
*/
|
||||
function IO()
|
||||
function IO(memory)
|
||||
{
|
||||
var a20_byte = 0,
|
||||
me = this;
|
||||
var me = this;
|
||||
|
||||
function get_port_description(addr)
|
||||
{
|
||||
|
@ -150,25 +149,61 @@ function IO()
|
|||
write_callbacks[port_addr] = callback;
|
||||
};
|
||||
|
||||
// should maybe be somewhere else?
|
||||
this.register_read(0x92, function()
|
||||
/**
|
||||
* @param addr {number}
|
||||
* @param size {number}
|
||||
*
|
||||
*/
|
||||
this.mmap_register = function(addr, size, fn_size, read_func, write_func)
|
||||
{
|
||||
return a20_byte;
|
||||
});
|
||||
dbg_log("mmap_register addr=" + h(addr >>> 0, 8) + " size=" + h(size, 8) + " fn_size=" + fn_size, LOG_IO);
|
||||
|
||||
this.register_write(0x92, function(out_byte)
|
||||
{
|
||||
a20_byte = out_byte;
|
||||
});
|
||||
dbg_assert((addr & MMAP_BLOCK_SIZE - 1) === 0);
|
||||
dbg_assert(size && (size & MMAP_BLOCK_SIZE - 1) === 0);
|
||||
dbg_assert(fn_size === 1 || fn_size === 4);
|
||||
|
||||
if(DEBUG)
|
||||
{
|
||||
// use by linux for timing
|
||||
this.register_write(0x80, function(out_byte)
|
||||
var aligned_addr = addr >>> MMAP_BLOCK_BITS;
|
||||
|
||||
for(; size > 0; aligned_addr++)
|
||||
{
|
||||
});
|
||||
memory.memory_map_registered[aligned_addr] = fn_size;
|
||||
|
||||
memory.memory_map_read[aligned_addr] = do_read;
|
||||
memory.memory_map_write[aligned_addr] = do_write;
|
||||
|
||||
size -= MMAP_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
function do_read(read_addr)
|
||||
{
|
||||
return read_func(read_addr - addr | 0);
|
||||
}
|
||||
|
||||
function do_write(write_addr, value)
|
||||
{
|
||||
write_func(write_addr - addr | 0, value);
|
||||
}
|
||||
};
|
||||
|
||||
for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++)
|
||||
{
|
||||
// avoid sparse arrays
|
||||
memory.memory_map_read[i] = memory.memory_map_write[i] = undefined;
|
||||
}
|
||||
|
||||
this.mmap_register(memory_size, 0x100000000 - memory_size, 1,
|
||||
function(addr) {
|
||||
// read outside of the memory size
|
||||
addr += memory_size;
|
||||
dbg_log("Read from unmapped memory space, addr=" + h(addr >>> 0, 8), LOG_IO);
|
||||
return 0xFF;
|
||||
},
|
||||
function(addr, value) {
|
||||
// write outside of the memory size
|
||||
addr += memory_size;
|
||||
dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value, 2), LOG_IO);
|
||||
});
|
||||
|
||||
|
||||
// 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
|
||||
|
|
|
@ -111,82 +111,19 @@ function Memory(buffer, memory_size)
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
var
|
||||
/**
|
||||
* Arbritary value, the minimum number of bytes that can be mapped
|
||||
* by one device. This might be spec'd somewhere ...
|
||||
*
|
||||
* @const
|
||||
*/
|
||||
MMAP_BLOCK_BITS = 14,
|
||||
/** @const */
|
||||
MMAP_BLOCK_SIZE = 1 << MMAP_BLOCK_BITS,
|
||||
|
||||
// this only supports a 32 bit address space
|
||||
memory_map_registered = new Int8Array(1 << (32 - MMAP_BLOCK_BITS)),
|
||||
|
||||
// this only supports a 32 bit address space
|
||||
var memory_map_registered = new Uint8Array(1 << (32 - MMAP_BLOCK_BITS)),
|
||||
memory_map_read = [],
|
||||
memory_map_write = [];
|
||||
|
||||
// managed by IO() in io.js
|
||||
this.memory_map_registered = memory_map_registered;
|
||||
this.memory_map_read = memory_map_read;
|
||||
this.memory_map_write = memory_map_write;
|
||||
|
||||
dbg_assert((memory_size & MMAP_BLOCK_SIZE - 1) === 0);
|
||||
|
||||
/**
|
||||
* @param addr {number}
|
||||
* @param size {number}
|
||||
*
|
||||
*/
|
||||
this.mmap_register = function(addr, size, fn_size, read_func, write_func)
|
||||
{
|
||||
dbg_log("mmap_register addr=" + h(addr >>> 0, 8) + " size=" + h(size, 8) + " fn_size=" + fn_size, LOG_IO);
|
||||
|
||||
dbg_assert((addr & MMAP_BLOCK_SIZE - 1) === 0);
|
||||
dbg_assert(size && (size & MMAP_BLOCK_SIZE - 1) === 0);
|
||||
dbg_assert(fn_size === 1 || fn_size === 4);
|
||||
|
||||
var aligned_addr = addr >>> MMAP_BLOCK_BITS;
|
||||
|
||||
for(; size > 0; aligned_addr++)
|
||||
{
|
||||
memory_map_registered[aligned_addr] = fn_size;
|
||||
|
||||
memory_map_read[aligned_addr] = do_read;
|
||||
memory_map_write[aligned_addr] = do_write;
|
||||
|
||||
size -= MMAP_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
function do_read(read_addr)
|
||||
{
|
||||
return read_func(read_addr - addr | 0);
|
||||
}
|
||||
|
||||
function do_write(write_addr, value)
|
||||
{
|
||||
write_func(write_addr - addr | 0, value);
|
||||
}
|
||||
};
|
||||
|
||||
for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++)
|
||||
{
|
||||
// avoid sparse arrays
|
||||
memory_map_read[i] = memory_map_write[i] = undefined;
|
||||
}
|
||||
|
||||
this.mmap_register(memory_size, 0x100000000 - memory_size, 1,
|
||||
function(addr) {
|
||||
// read outside of the memory size
|
||||
addr += memory_size;
|
||||
dbg_log("Read from unmapped memory space, addr=" + h(addr >>> 0, 8), LOG_IO);
|
||||
return 0xFF;
|
||||
},
|
||||
function(addr, value) {
|
||||
// write outside of the memory size
|
||||
addr += memory_size;
|
||||
dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value, 2), LOG_IO);
|
||||
});
|
||||
|
||||
function mmap_read8(addr)
|
||||
{
|
||||
return memory_map_read[addr >>> MMAP_BLOCK_BITS](addr);
|
||||
|
@ -200,24 +137,27 @@ function Memory(buffer, memory_size)
|
|||
function mmap_read32(addr)
|
||||
{
|
||||
var aligned_addr = addr >>> MMAP_BLOCK_BITS,
|
||||
size = memory_map_registered[aligned_addr],
|
||||
fn = memory_map_read[aligned_addr];
|
||||
|
||||
if(memory_map_registered[aligned_addr] === 4)
|
||||
if(size & 4)
|
||||
{
|
||||
return fn(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fn(addr) | fn(addr + 1) << 8 | fn(addr + 2) << 16 | fn(addr + 3) << 24;
|
||||
return fn(addr) | fn(addr + 1) << 8 |
|
||||
fn(addr + 2) << 16 | fn(addr + 3) << 24;
|
||||
}
|
||||
}
|
||||
|
||||
function mmap_write32(addr, value)
|
||||
{
|
||||
var aligned_addr = addr >>> MMAP_BLOCK_BITS,
|
||||
size = memory_map_registered[aligned_addr],
|
||||
fn = memory_map_write[aligned_addr];
|
||||
|
||||
if(memory_map_registered[aligned_addr] === 4)
|
||||
if(size & 4)
|
||||
{
|
||||
fn(addr, value);
|
||||
}
|
||||
|
|
145
src/pci.js
145
src/pci.js
|
@ -22,16 +22,17 @@ function PCI(dev)
|
|||
{
|
||||
var
|
||||
io = dev.io,
|
||||
pci_data = new Uint8Array(4),
|
||||
pci_addr = new Uint8Array(4),
|
||||
pci_response = new Uint8Array(4),
|
||||
pci_status = new Uint8Array(4),
|
||||
|
||||
pci_data32 = new Int32Array(pci_data.buffer),
|
||||
pci_addr32 = new Int32Array(pci_addr.buffer),
|
||||
pci_response32 = new Int32Array(pci_response.buffer),
|
||||
pci_status32 = new Int32Array(pci_status.buffer),
|
||||
pci = this;
|
||||
|
||||
this.devices = Array(0x10000);
|
||||
var device_spaces = Array(0x10000),
|
||||
devices = Array(0x10000);
|
||||
|
||||
/*
|
||||
io.register_write(0xCF9, function(value)
|
||||
|
@ -45,35 +46,26 @@ function PCI(dev)
|
|||
}
|
||||
});*/
|
||||
|
||||
function pci_write_byte(byte_pos, byte)
|
||||
{
|
||||
var bdf = pci_data[2] << 8 | pci_data[1],
|
||||
addr = pci_data[0] & 0xFC;
|
||||
|
||||
//if(bdf === (7 << 3))
|
||||
//{
|
||||
// var device = me.devices[bdf];
|
||||
|
||||
// (new Uint8Array(device.buffer))[addr] = byte;
|
||||
//}
|
||||
}
|
||||
|
||||
io.register_write(PCI_CONFIG_DATA, function(out_byte)
|
||||
{
|
||||
dbg_log("PCI data0: " + h(out_byte, 2) + " addr=" + h(pci_data32[0] >>> 0), LOG_PCI);
|
||||
|
||||
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_data32[0] >>> 0), LOG_PCI);
|
||||
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_data32[0] >>> 0), LOG_PCI);
|
||||
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_data32[0] >>> 0), LOG_PCI);
|
||||
dbg_log("PCI data3: " + h(out_byte, 2) + " addr=" + h(pci_addr32[0] >>> 0), LOG_PCI);
|
||||
|
||||
pci_write_byte(3, out_byte);
|
||||
});
|
||||
|
||||
io.register_read(PCI_CONFIG_DATA, function()
|
||||
|
@ -112,19 +104,19 @@ function PCI(dev)
|
|||
|
||||
io.register_write(PCI_CONFIG_ADDRESS, function(out_byte)
|
||||
{
|
||||
pci_data[0] = out_byte;
|
||||
pci_addr[0] = out_byte;
|
||||
});
|
||||
io.register_write(PCI_CONFIG_ADDRESS | 1, function(out_byte)
|
||||
{
|
||||
pci_data[1] = out_byte;
|
||||
pci_addr[1] = out_byte;
|
||||
});
|
||||
io.register_write(PCI_CONFIG_ADDRESS | 2, function(out_byte)
|
||||
{
|
||||
pci_data[2] = out_byte;
|
||||
pci_addr[2] = out_byte;
|
||||
});
|
||||
io.register_write(PCI_CONFIG_ADDRESS | 3, function(out_byte)
|
||||
{
|
||||
pci_data[3] = out_byte;
|
||||
pci_addr[3] = out_byte;
|
||||
|
||||
pci_query();
|
||||
});
|
||||
|
@ -136,25 +128,25 @@ function PCI(dev)
|
|||
// Bit | .31 .0
|
||||
// Fmt | EBBBBBBBBDDDDDFFFRRRRRR00
|
||||
|
||||
var bdf = pci_data[2] << 8 | pci_data[1],
|
||||
addr = pci_data[0] & 0xFC,
|
||||
var bdf = pci_addr[2] << 8 | pci_addr[1],
|
||||
addr = pci_addr[0] & 0xFC,
|
||||
devfn = bdf & 0xFF,
|
||||
bus = bdf >> 8,
|
||||
dev = bdf >> 3 & 0x1F,
|
||||
fn = bdf & 7,
|
||||
enabled = pci_data[3] >> 7;
|
||||
enabled = pci_addr[3] >> 7;
|
||||
|
||||
dbg_line += " enabled=" + (enabled);
|
||||
dbg_line += " bdf=" + h(bdf, 4);
|
||||
dbg_line += " addr=" + h(addr, 2);
|
||||
|
||||
//dbg_log(dbg_line + " " + h(pci_data32[0] >>> 0, 8), LOG_PCI);
|
||||
//dbg_log(dbg_line + " " + h(pci_addr32[0] >>> 0, 8), LOG_PCI);
|
||||
|
||||
var device = pci.devices[bdf];
|
||||
var device = device_spaces[bdf];
|
||||
|
||||
if(device !== undefined)
|
||||
{
|
||||
dbg_log(dbg_line + " " + h(pci_data32[0] >>> 0, 8), LOG_PCI);
|
||||
dbg_log(dbg_line + " " + h(pci_addr32[0] >>> 0, 8), LOG_PCI);
|
||||
|
||||
pci_status32[0] = 0x80000000 | 0;
|
||||
|
||||
|
@ -174,26 +166,97 @@ function PCI(dev)
|
|||
}
|
||||
}
|
||||
|
||||
this.register_device = function(device, device_id)
|
||||
function pci_write_byte(byte_pos, byte)
|
||||
{
|
||||
var bdf = pci_addr[2] << 8 | pci_addr[1],
|
||||
addr = pci_addr[0] & 0xFC;
|
||||
|
||||
var space = device_spaces[bdf],
|
||||
device = devices[bdf];
|
||||
|
||||
if(space)
|
||||
{
|
||||
(new Uint8Array(space.buffer))[addr | byte_pos] = byte;
|
||||
|
||||
if(byte_pos === 3 && addr >= 0x10 && addr < 0x28)
|
||||
{
|
||||
var bar_nr = addr - 0x10 >> 2,
|
||||
bar = device.pci_bars[bar_nr],
|
||||
value = space[addr >> 2];
|
||||
|
||||
dbg_log("BAR" + bar_nr + " changed to " + h(space[addr >> 2] >>> 0) + " dev=" + h(bdf, 2), LOG_PCI);
|
||||
|
||||
if(bar)
|
||||
{
|
||||
dbg_assert(!(bar.size & bar.size - 1));
|
||||
space[addr >> 2] = value & ~(bar.size - 1) | 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
space[addr >> 2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.register_device = function(device)
|
||||
{
|
||||
dbg_assert(device.pci_id !== undefined);
|
||||
dbg_assert(device.pci_space !== undefined);
|
||||
dbg_assert(device.pci_bars !== undefined);
|
||||
|
||||
var device_id = device.pci_id;
|
||||
|
||||
dbg_log("PCI register bdf=" + h(device_id), LOG_PCI);
|
||||
|
||||
dbg_assert(!pci.devices[device_id]);
|
||||
dbg_assert(device.length === 64);
|
||||
dbg_assert(!devices[device_id]);
|
||||
dbg_assert(device.pci_space.length === 64);
|
||||
|
||||
// convert bytewise notation from lspci to double words
|
||||
pci.devices[device_id] = new Int32Array(new Uint8Array(device).buffer);
|
||||
device_spaces[device_id] = new Int32Array(new Uint8Array(device.pci_space).buffer);
|
||||
devices[device_id] = device;
|
||||
};
|
||||
|
||||
// Some experimental PCI devices taken from my PC:
|
||||
|
||||
// 00:00.0 Host bridge: Intel Corporation 4 Series Chipset DRAM Controller (rev 02)
|
||||
this.register_device([
|
||||
0x86, 0x80, 0x20, 0x2e, 0x06, 0x00, 0x90, 0x20, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x10, 0xd3, 0x82,
|
||||
0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
], 0);
|
||||
//var host_bridge = {
|
||||
// pci_id: 0,
|
||||
// pci_space: [
|
||||
// 0x86, 0x80, 0x20, 0x2e, 0x06, 0x00, 0x90, 0x20, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x10, 0xd3, 0x82,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// ],
|
||||
// pci_bars: [],
|
||||
//};
|
||||
|
||||
var host_bridge = {
|
||||
pci_id: 0,
|
||||
pci_space: [
|
||||
// 00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
|
||||
0x86, 0x80, 0x37, 0x12, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
pci_bars: [],
|
||||
};
|
||||
this.register_device(host_bridge);
|
||||
|
||||
var isa_bridge = {
|
||||
pci_id: 1 << 3,
|
||||
pci_space: [
|
||||
// 00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
|
||||
0x86, 0x80, 0x00, 0x70, 0x07, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
pci_bars: [],
|
||||
};
|
||||
this.register_device(isa_bridge);
|
||||
|
||||
// 00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 90)
|
||||
//this.register_device([
|
||||
|
|
17
src/vga.js
17
src/vga.js
|
@ -110,15 +110,22 @@ function VGAScreen(dev, adapter, vga_memory_size)
|
|||
plane3;
|
||||
|
||||
|
||||
|
||||
// Experimental, could probably need some changes
|
||||
// 01:00.0 VGA compatible controller: NVIDIA Corporation GT216 [GeForce GT 220] (rev a2)
|
||||
dev.pci.register_device([
|
||||
this.pci_space = [
|
||||
0xde, 0x10, 0x20, 0x0a, 0x07, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x00,
|
||||
0x08, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00,
|
||||
], 0x12 << 3);
|
||||
];
|
||||
this.pci_id = 0x12 << 3;
|
||||
this.pci_bars = [
|
||||
{
|
||||
size: vga_memory_size,
|
||||
},
|
||||
];
|
||||
|
||||
dev.pci.register_device(this);
|
||||
|
||||
|
||||
function init()
|
||||
|
@ -147,8 +154,8 @@ function VGAScreen(dev, adapter, vga_memory_size)
|
|||
screen.set_size_text(80, 25);
|
||||
screen.update_cursor_scanline();
|
||||
|
||||
memory.mmap_register(0xA0000, 0x20000, 1, vga_memory_read, vga_memory_write);
|
||||
memory.mmap_register(0xE0000000, vga_memory_size, 1, svga_memory_read, svga_memory_write);
|
||||
io.mmap_register(0xA0000, 0x20000, 1, vga_memory_read, vga_memory_write);
|
||||
io.mmap_register(0xE0000000, vga_memory_size, 1, svga_memory_read, svga_memory_write);
|
||||
}
|
||||
|
||||
function vga_memory_read(addr)
|
||||
|
|
Loading…
Reference in a new issue