From 4131aa709fa5d564b78b0bca888b4cfc6e99a4c8 Mon Sep 17 00:00:00 2001 From: Christian Schnell Date: Mon, 12 May 2025 20:17:08 +0200 Subject: [PATCH] renamed register members to better align with the standard Renamed members that carry register values to better align with the actual wording in the ATA/ATAPI-6 standard. Other changes in this commit include: - added a bunch of named constants for ATA registers and their bits - improved PCI configuration space setup - renamed class IDEPCIAdapter to IDEController --- src/cpu.js | 4 +- src/ide.js | 776 +++++++++++++++++++++++++++-------------------------- 2 files changed, 395 insertions(+), 385 deletions(-) diff --git a/src/cpu.js b/src/cpu.js index 0375f03b..00a2992a 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -29,7 +29,7 @@ import { PS2 } from "./ps2.js"; import { read_elf } from "./elf.js"; import { FloppyController } from "./floppy.js"; -import { IDEPCIAdapter } from "./ide.js"; +import { IDEController } from "./ide.js"; import { VirtioNet } from "./virtio_net.js"; import { VGAScreen } from "./vga.js"; import { VirtioBalloon } from "./virtio_balloon.js"; @@ -1120,7 +1120,7 @@ CPU.prototype.init = function(settings, device_bus) }; } - this.devices.ide = new IDEPCIAdapter(this, device_bus, ide_config); + this.devices.ide = new IDEController(this, device_bus, ide_config); if(settings.hda) { this.devices.hda = this.devices.ide.channels[0]; diff --git a/src/ide.js b/src/ide.js index 33426548..9b61d9ef 100644 --- a/src/ide.js +++ b/src/ide.js @@ -7,20 +7,67 @@ import { CMOS_BIOS_DISKTRANSFLAG, CMOS_DISK_DATA, CMOS_DISK_DRIVE1_CYL, CMOS_DIS import { CPU } from "./cpu.js"; import { BusConnector } from "./bus.js"; +// References +// [ATA-6] +// AT Attachment with Packet Interface - 6 (ATA/ATAPI-6) (Rev. 3a, 14 Dec. 2001) +// https://technion-csl.github.io/ose/readings/hardware/ATA-d1410r3a.pdf + const CDROM_SECTOR_SIZE = 2048; const HD_SECTOR_SIZE = 512; +// Per-channel PIO register offsets, legend: +// (*1*) Control block register (BAR1/3), else: Command block register (BAR0/2) +// +// Read-only registers: +const ATA_REG_ERROR = 0x01; // Error register, see [ATA-6] 7.9 +const ATA_REG_STATUS = 0x07; // Status register, see [ATA-6] 7.15 +const ATA_REG_ALT_STATUS = 0x02; // (*1*) Alternate Status register, see [ATA-6] 7.3 +// Read-/writable registers: +const ATA_REG_DATA = 0x00; // Data register, see [ATA-6] 7.6 +const ATA_REG_SECTOR = 0x02; // Sector Count register, see [ATA-6] 7.14 +const ATA_REG_LBA_LOW = 0x03; // LBA Low register, see [ATA-6] 7.12 +const ATA_REG_LBA_MID = 0x04; // LBA Mid register, see [ATA-6] 7.13 +const ATA_REG_LBA_HIGH = 0x05; // LBA High register, see [ATA-6] 7.11 +const ATA_REG_DEVICE = 0x06; // Device register, see [ATA-6] 7.7 +// Write-only registers: +const ATA_REG_FEATURES = 0x01; // Features register, see [ATA-6] 7.10 +const ATA_REG_COMMAND = 0x07; // Command register, see [ATA-6] 7.4 +const ATA_REG_CONTROL = 0x02; // (*1*) Device Control register, see [ATA-6] 7.8 + +// Error register bits: +// - All remaining bits (except bit 3) are command dependent. +const ATA_ER_ABRT = 0x04; // Command aborted + +// Status register bits: +// - Bits 1 and 2 are obsolete, 4 and 5 are command dependent. +// - Bit 1 used to be called "Index" (IDX), bit 2 "Corrected data" (CORR), +// bit 4 "Drive seek complete" (DSC), and bit 5 "Drive write fault" (DF). +const ATA_SR_ERR = 0x01; // Error +const ATA_SR_DRQ = 0x08; // Data request ready +const ATA_SR_DRDY = 0x40; // Drive ready +const ATA_SR_BSY = 0x80; // Busy + +// Device register bits: +// - Bits 5 and 7 are obsolete, 0-3 and 6 are command dependent. +const ATA_DR_DEV = 0x10; // Device select, slave device if set, else master device + +// Device Control register bits: +// - Bits 0 and 3-6 are reserved. +const ATA_CR_NIEN = 0x02; // Interrupt disable (Not Interrupt Enable) +const ATA_CR_SRST = 0x04; // Software reset +const ATA_CR_HOB = 0x80; // 48-bit Address feature set + /** * @constructor * @param {CPU} cpu * @param {BusConnector} bus * - * adapter_config: [ [, ], [, ] ] + * ide_config: [ [, ], [, ] ] * * Each of the four arguments (, , ...) is - * either undefined or an interface_config object of the form: + * either undefined or an ide_config object of the form: * - * interface_config := { buffer: Uint8Array, is_cdrom: bool } + * ide_config := { buffer: Uint8Array, is_cdrom: bool } * * If is_cdrom is defined and true: * - If buffer is defined: create an ATAPI CD-ROM device using buffer as inserted disk @@ -31,112 +78,111 @@ const HD_SECTOR_SIZE = 512; * * A slave drive can only exist if a master drive also exists. * */ -export function IDEPCIAdapter(cpu, bus, adapter_config) +export function IDEController(cpu, bus, ide_config) { - // Except for bus_master_port, all ports and IRQs are predefined and - // cannot be changed in Compatibility mode. - // The 16 registers of the Bus Master port are split in two, registers - // 0..7 are used for the primary channel, and 8..15 for the secondary. - const bus_master_port = 0xB400; - const pri = { ata_port: 0x1f0, ata_port_high: 0x3f4, irq: 14, bus_master_port: bus_master_port }; - const sec = { ata_port: 0x170, ata_port_high: 0x374, irq: 15, bus_master_port: bus_master_port | 0x8 }; - this.cpu = cpu; this.bus = bus; this.primary = undefined; this.secondary = undefined; this.channels = [undefined, undefined]; - const has_primary = adapter_config && adapter_config[0][0]; - const has_secondary = adapter_config && adapter_config[1][0]; - if(!has_primary && !has_secondary) { - Object.seal(this); - return; - } - if(has_primary) { - this.primary = new IDEChannel(this, adapter_config, 0, pri); - } - if(has_secondary) { - this.secondary = new IDEChannel(this, adapter_config, 1, sec); - } - this.channels = [this.primary, this.secondary]; - - const vendor_id = 0x8086; // Intel Corporation - const device_id = 0x7010; // 82371SB PIIX3 IDE [Natoma/Triton II] - const class_code = 0x01; // Mass Storage Controller - const subclass = 0x01; // IDE Controller - const prog_if = 0x80; // ISA Compatibility mode-only controller, supports bus mastering - const interrupt_line = 0x00; // IRQs 14 and 15 are predefined in Compatibility mode and this field is ignored - - this.pci_id = 0x1F << 3; - this.pci_space = [ - vendor_id & 0xFF, vendor_id >> 8, device_id & 0xFF, device_id >> 8, 0x05, 0x00, 0xA0, 0x02, - 0x00, prog_if, subclass, class_code, 0x00, 0x00, 0x00, 0x00, - pri.ata_port & 0xFF | 1, pri.ata_port >> 8, 0x00, 0x00, - pri.ata_port_high & 0xFF | 1, pri.ata_port_high >> 8, 0x00, 0x00, - sec.ata_port & 0xFF | 1, sec.ata_port >> 8, 0x00, 0x00, - sec.ata_port_high & 0xFF | 1, sec.ata_port_high >> 8, 0x00, 0x00, - bus_master_port & 0xFF | 1, bus_master_port >> 8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x43, 0x10, 0xD4, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, interrupt_line, 0x01, 0x00, 0x00, - // 0x40 - 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, - ]; - this.pci_bars = [ - { - size: 8, // BAR0: Command block registers of primary ATA Channel - }, - { - size: 4, // BAR1: Control registers of primary ATA Channel - }, - { - size: 8, // BAR2: Command block registers of secondary ATA Channel - }, - { - size: 4, // BAR3: Control registers of secondary ATA Channel - }, - { - size: 16, // BAR4: ATA Bus Master I/O registers (primary ATA Channel: 0..7, secondary: 8..15) + const has_primary = ide_config && ide_config[0][0]; + const has_secondary = ide_config && ide_config[1][0]; + if(has_primary || has_secondary) { + const bus_master_base = 0xB400; + if(has_primary) { + this.primary = new IDEChannel(this, ide_config, 0, { + command_base: 0x1f0, control_base: 0x3f4, bus_master_base: bus_master_base, irq: 14 + }); + this.channels[0] = this.primary; + } + if(has_secondary) { + this.secondary = new IDEChannel(this, ide_config, 1, { + command_base: 0x170, control_base: 0x374, bus_master_base: bus_master_base | 0x8, irq: 15 + }); + this.channels[1] = this.secondary; } - ]; - cpu.devices.pci.register_device(this); + const vendor_id = 0x8086; // Intel Corporation + const device_id = 0x7010; // 82371SB PIIX3 IDE [Natoma/Triton II] + const class_code = 0x01; // Mass Storage Controller + const subclass = 0x01; // IDE Controller + const prog_if = 0x80; // ISA Compatibility mode-only controller, supports bus mastering + const interrupt_line = 0x00; // IRQs 14 and 15 are predefined in Compatibility mode and this field is ignored + const command_base0 = has_primary ? this.primary.command_base : 0; + const control_base0 = has_primary ? this.primary.control_base : 0; + const command_base1 = has_secondary ? this.secondary.command_base : 0; + const control_base1 = has_secondary ? this.secondary.control_base : 0; + + this.pci_id = 0x1F << 3; + this.pci_space = [ + vendor_id & 0xFF, vendor_id >> 8, device_id & 0xFF, device_id >> 8, 0x05, 0x00, 0xA0, 0x02, + 0x00, prog_if, subclass, class_code, 0x00, 0x00, 0x00, 0x00, + command_base0 & 0xFF | 1, command_base0 >> 8, 0x00, 0x00, + control_base0 & 0xFF | 1, control_base0 >> 8, 0x00, 0x00, + command_base1 & 0xFF | 1, command_base1 >> 8, 0x00, 0x00, + control_base1 & 0xFF | 1, control_base1 >> 8, 0x00, 0x00, + bus_master_base & 0xFF | 1, bus_master_base >> 8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x43, 0x10, 0xD4, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, interrupt_line, 0x01, 0x00, 0x00, + // 0x40 + 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, + ]; + this.pci_bars = [ + { + size: 8, // BAR0: Command block registers of primary ATA Channel + }, + { + size: 4, // BAR1: Control registers of primary ATA Channel + }, + { + size: 8, // BAR2: Command block registers of secondary ATA Channel + }, + { + size: 4, // BAR3: Control registers of secondary ATA Channel + }, + { + size: 16, // BAR4: ATA Bus Master I/O registers (primary ATA Channel: 0..7, secondary: 8..15) + } + ]; + cpu.devices.pci.register_device(this); + } Object.seal(this); } /** * @constructor - * @param {IDEPCIAdapter} adapter + * @param {IDEController} controller * @param {number} channel_nr * */ -function IDEChannel(adapter, adapter_config, channel_nr, channel_config) +function IDEChannel(controller, controller_config, channel_nr, channel_config) { - this.adapter = adapter; - this.cpu = adapter.cpu; - this.bus = adapter.bus; - this.ata_port = channel_config.ata_port; - this.ata_port_high = channel_config.ata_port_high; + this.controller = controller; + this.cpu = controller.cpu; + this.bus = controller.bus; + this.command_base = channel_config.command_base; + this.control_base = channel_config.control_base; this.irq = channel_config.irq; this.name = "ide" + channel_nr; const create_interface = interface_nr => { - const config = adapter_config && adapter_config[channel_nr] ? - adapter_config[channel_nr][interface_nr] : undefined; + const config = controller_config && controller_config[channel_nr] ? + controller_config[channel_nr][interface_nr] : undefined; const buffer = config ? config.buffer : undefined; const is_cdrom = config ? !!config.is_cdrom : false; return new IDEInterface(this, this.cpu, buffer, is_cdrom, channel_nr, interface_nr, this.bus); @@ -151,7 +197,7 @@ function IDEChannel(adapter, adapter_config, channel_nr, channel_config) this.slave.init_interface(); /** @type {number} */ - this.device_control = 2; + this.device_control_reg = 2; /** @type {number} */ this.prdt_addr = 0; @@ -162,14 +208,14 @@ function IDEChannel(adapter, adapter_config, channel_nr, channel_config) /** @type {number} */ this.dma_command = 0; - const cpu = adapter.cpu; + const cpu = controller.cpu; // - // Command Block Registers: ata_port + 0...7 (BAR0: 1F0h, BAR2: 170h) + // Command Block Registers: command_base + 0...7 (BAR0: 1F0h, BAR2: 170h) // // read Data register - cpu.io.register_read(this.ata_port | 0, this, function() + cpu.io.register_read(this.command_base | ATA_REG_DATA, this, function() { return this.current_interface.read_data(1); }, function() @@ -180,56 +226,56 @@ function IDEChannel(adapter, adapter_config, channel_nr, channel_config) return this.current_interface.read_data(4); }); - cpu.io.register_read(this.ata_port | 1, this, function() + cpu.io.register_read(this.command_base | ATA_REG_ERROR, this, function() { dbg_log(this.current_interface.name + ": read Error register: " + - h(this.current_interface.error & 0xFF) + " slave=" + + h(this.current_interface.error_reg & 0xFF) + " slave=" + (this.current_interface === this.slave), LOG_DISK); - return this.current_interface.error & 0xFF; + return this.current_interface.error_reg & 0xFF; }); - cpu.io.register_read(this.ata_port | 2, this, function() + cpu.io.register_read(this.command_base | ATA_REG_SECTOR, this, function() { dbg_log(this.current_interface.name + ": read Sector Count register: " + - h(this.current_interface.bytecount & 0xFF), LOG_DISK); - return this.current_interface.bytecount & 0xFF; + h(this.current_interface.sector_count_reg & 0xFF), LOG_DISK); + return this.current_interface.sector_count_reg & 0xFF; }); - cpu.io.register_read(this.ata_port | 3, this, function() + cpu.io.register_read(this.command_base | ATA_REG_LBA_LOW, this, function() { dbg_log(this.current_interface.name + ": read LBA Low register: " + - h(this.current_interface.sector & 0xFF), LOG_DISK); - return this.current_interface.sector & 0xFF; + h(this.current_interface.lba_low_reg & 0xFF), LOG_DISK); + return this.current_interface.lba_low_reg & 0xFF; }); - cpu.io.register_read(this.ata_port | 4, this, function() + cpu.io.register_read(this.command_base | ATA_REG_LBA_MID, this, function() { dbg_log(this.current_interface.name + ": read LBA Mid register: " + - h(this.current_interface.cylinder_low & 0xFF), LOG_DISK); - return this.current_interface.cylinder_low & 0xFF; + h(this.current_interface.lba_mid_reg & 0xFF), LOG_DISK); + return this.current_interface.lba_mid_reg & 0xFF; }); - cpu.io.register_read(this.ata_port | 5, this, function() + cpu.io.register_read(this.command_base | ATA_REG_LBA_HIGH, this, function() { dbg_log(this.current_interface.name + ": read LBA High register: " + - h(this.current_interface.cylinder_high & 0xFF), LOG_DISK); - return this.current_interface.cylinder_high & 0xFF; + h(this.current_interface.lba_high_reg & 0xFF), LOG_DISK); + return this.current_interface.lba_high_reg & 0xFF; }); - cpu.io.register_read(this.ata_port | 6, this, function() + cpu.io.register_read(this.command_base | ATA_REG_DEVICE, this, function() { dbg_log(this.current_interface.name + ": read Device register", LOG_DISK); - return this.current_interface.drive_head & 0xFF; + return this.current_interface.device_reg & 0xFF; }); - cpu.io.register_read(this.ata_port | 7, this, function() { + cpu.io.register_read(this.command_base | ATA_REG_STATUS, this, function() { dbg_log(this.current_interface.name + ": read Status register", LOG_DISK); dbg_log(this.current_interface.name + ": lower IRQ " + this.irq, LOG_DISK); this.cpu.device_lower_irq(this.irq); return this.read_status(); }); - cpu.io.register_write(this.ata_port | 0, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_DATA, this, function(data) { this.current_interface.write_data_port8(data); }, function(data) @@ -240,69 +286,37 @@ function IDEChannel(adapter, adapter_config, channel_nr, channel_config) this.current_interface.write_data_port32(data); }); - cpu.io.register_write(this.ata_port | 1, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_FEATURES, this, function(data) { dbg_log(this.current_interface.name + ": write Features register: " + h(data), LOG_DISK); -/*** - * this.master.lba_count = (this.master.lba_count << 8 | data) & 0xFFFF; - * this.slave.lba_count = (this.slave.lba_count << 8 | data) & 0xFFFF; - ***/ - this.current_interface.lba_count = (this.current_interface.lba_count << 8 | data) & 0xFFFF; + this.current_interface.features_reg = (this.current_interface.features_reg << 8 | data) & 0xFFFF; }); - cpu.io.register_write(this.ata_port | 2, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_SECTOR, this, function(data) { dbg_log(this.current_interface.name + ": write Sector Count register: " + h(data), LOG_DISK); -/*** - * this.master.bytecount = (this.master.bytecount << 8 | data) & 0xFFFF; - * if(slave_buffer) - * { - * this.slave.bytecount = (this.slave.bytecount << 8 | data) & 0xFFFF; - * } - ***/ - this.current_interface.bytecount = (this.current_interface.bytecount << 8 | data) & 0xFFFF; + this.current_interface.sector_count_reg = (this.current_interface.sector_count_reg << 8 | data) & 0xFFFF; }); - cpu.io.register_write(this.ata_port | 3, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_LBA_LOW, this, function(data) { dbg_log(this.current_interface.name + ": write LBA Low register: " + h(data), LOG_DISK); -/*** - * this.master.sector = (this.master.sector << 8 | data) & 0xFFFF; - * if(slave_buffer) - * { - * this.slave.sector = (this.slave.sector << 8 | data) & 0xFFFF; - * } - ***/ - this.current_interface.sector = (this.current_interface.sector << 8 | data) & 0xFFFF; + this.current_interface.lba_low_reg = (this.current_interface.lba_low_reg << 8 | data) & 0xFFFF; }); - cpu.io.register_write(this.ata_port | 4, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_LBA_MID, this, function(data) { dbg_log(this.current_interface.name + ": write LBA Mid register: " + h(data), LOG_DISK); -/*** - * this.master.cylinder_low = (this.master.cylinder_low << 8 | data) & 0xFFFF; - * if(slave_buffer) - * { - * this.slave.cylinder_low = (this.slave.cylinder_low << 8 | data) & 0xFFFF; - * } - ***/ - this.current_interface.cylinder_low = (this.current_interface.cylinder_low << 8 | data) & 0xFFFF; + this.current_interface.lba_mid_reg = (this.current_interface.lba_mid_reg << 8 | data) & 0xFFFF; }); - cpu.io.register_write(this.ata_port | 5, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_LBA_HIGH, this, function(data) { dbg_log(this.current_interface.name + ": write LBA High register: " + h(data), LOG_DISK); -/*** - * this.master.cylinder_high = (this.master.cylinder_high << 8 | data) & 0xFFFF; - * if(slave_buffer) - * { - * this.slave.cylinder_high = (this.slave.cylinder_high << 8 | data) & 0xFFFF; - * } - ***/ - this.current_interface.cylinder_high = (this.current_interface.cylinder_high << 8 | data) & 0xFFFF; + this.current_interface.lba_high_reg = (this.current_interface.lba_high_reg << 8 | data) & 0xFFFF; }); - cpu.io.register_write(this.ata_port | 6, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_DEVICE, this, function(data) { var slave = data & 0x10; // var mode = data & 0xE0; // unused @@ -321,67 +335,62 @@ function IDEChannel(adapter, adapter_config, channel_nr, channel_config) this.current_interface = this.master; } } -/*** - * this.master.drive_head = data; - * this.slave.drive_head = data; - * this.master.is_lba = this.slave.is_lba = data >> 6 & 1; - * this.master.head = this.slave.head = data & 0xF; - ***/ - this.current_interface.drive_head = data; + + this.current_interface.device_reg = data; this.current_interface.is_lba = data >> 6 & 1; this.current_interface.head = data & 0xF; }); - cpu.io.register_write(this.ata_port | 7, this, function(data) + cpu.io.register_write(this.command_base | ATA_REG_COMMAND, this, function(data) { dbg_log(this.current_interface.name + ": write Command register", LOG_DISK); dbg_log(this.current_interface.name + ": lower IRQ " + this.irq, LOG_DISK); this.cpu.device_lower_irq(this.irq); // clear error and DF bits - this.current_interface.status &= ~(1 | (1 << 5)); + this.current_interface.status_reg &= ~(1 | (1 << 5)); this.current_interface.ata_command(data); }); // - // Control Block Register: ata_port_high + 0...3 (BAR1: 3F4h, BAR3: 374h) + // Control Block Register: control_base + 0...3 (BAR1: 3F4h, BAR3: 374h) // // read Alternate Status register - cpu.io.register_read(this.ata_port_high | 2, this, this.read_status); + cpu.io.register_read(this.control_base | ATA_REG_ALT_STATUS, this, this.read_status); // write Device Control register - cpu.io.register_write(this.ata_port_high | 2, this, this.write_control); + cpu.io.register_write(this.control_base | ATA_REG_CONTROL, this, this.write_control); // - // Bus Master Registers: bus_master_port + 0...16 (BAR4, lower 8 for primary and upper 8 for secondary channel) + // Bus Master Registers: bus_master_base + 0...15 (BAR4: B400h, lower 8 for primary and upper 8 for secondary channel) // - const bus_master_port = channel_config.bus_master_port; + const bus_master_base = channel_config.bus_master_base; - cpu.io.register_read(bus_master_port, this, + cpu.io.register_read(bus_master_base, this, this.dma_read_command8, undefined, this.dma_read_command); - cpu.io.register_write(bus_master_port, this, + cpu.io.register_write(bus_master_base, this, this.dma_write_command8, undefined, this.dma_write_command); - cpu.io.register_read(bus_master_port | 2, this, this.dma_read_status); - cpu.io.register_write(bus_master_port | 2, this, this.dma_write_status); + cpu.io.register_read(bus_master_base | 2, this, this.dma_read_status); + cpu.io.register_write(bus_master_base | 2, this, this.dma_write_status); - cpu.io.register_read(bus_master_port | 4, this, undefined, undefined, this.dma_read_addr); - cpu.io.register_write(bus_master_port | 4, this, undefined, undefined, this.dma_set_addr); + cpu.io.register_read(bus_master_base | 4, this, undefined, undefined, this.dma_read_addr); + cpu.io.register_write(bus_master_base | 4, this, undefined, undefined, this.dma_set_addr); DEBUG && Object.seal(this); } IDEChannel.prototype.read_status = function() { - const ret = this.current_interface.drive_connected ? this.current_interface.status : 0; + const ret = this.current_interface.drive_connected ? this.current_interface.status_reg : 0; dbg_log(this.current_interface.name + ": ATA read status: " + h(ret, 2), LOG_DISK); return ret; }; IDEChannel.prototype.write_control = function(data) { - dbg_log(this.current_interface.name + ": write Device control register: " + + dbg_log(this.current_interface.name + ": write Device Control register: " + h(data, 2) + " interrupts " + ((data & 2) ? "disabled" : "enabled"), LOG_DISK); if(data & 0x04) @@ -394,7 +403,7 @@ IDEChannel.prototype.write_control = function(data) this.slave.device_reset(); } - this.device_control = data; + this.device_control_reg = data; }; IDEChannel.prototype.dma_read_addr = function() @@ -489,7 +498,7 @@ IDEChannel.prototype.dma_write_command8 = function(value) IDEChannel.prototype.push_irq = function() { - if((this.device_control & 2) === 0) + if((this.device_control_reg & 2) === 0) { dbg_log(this.current_interface.name + ": push IRQ " + this.irq, LOG_DISK); this.dma_status |= 4; @@ -502,13 +511,13 @@ IDEChannel.prototype.get_state = function() var state = []; state[0] = this.master; state[1] = this.slave; - state[2] = this.ata_port; + state[2] = this.command_base; state[3] = this.irq; // state[4] = this.pci_id; - state[5] = this.ata_port_high; - // state[6] = this.bus_master_port; + state[5] = this.control_base; + // state[6] = this.bus_master_base; state[7] = this.name; - state[8] = this.device_control; + state[8] = this.device_control_reg; state[9] = this.prdt_addr; state[10] = this.dma_status; state[11] = this.current_interface === this.master; @@ -520,13 +529,13 @@ IDEChannel.prototype.set_state = function(state) { this.master.set_state(state[0]); this.slave.set_state(state[1]); - this.ata_port = state[2]; + this.command_base = state[2]; this.irq = state[3]; // this.pci_id = state[4]; - this.ata_port_high = state[5]; - // this.bus_master_port = state[6]; + this.control_base = state[5]; + // this.bus_master_base = state[6]; this.name = state[7]; - this.device_control = state[8]; + this.device_control_reg = state[8]; this.prdt_addr = state[9]; this.dma_status = state[10]; this.current_interface = state[11] ? this.master : this.slave; @@ -535,6 +544,12 @@ IDEChannel.prototype.set_state = function(state) /** * @constructor + * @param {IDEChannel} channel + * @param {CPU} cpu + * @param {boolean} is_cd + * @param {number} channel_nr + * @param {number} interface_nr + * @param {BusConnector} bus */ function IDEInterface(channel, cpu, buffer, is_cd, channel_nr, interface_nr, bus) { @@ -589,34 +604,34 @@ function IDEInterface(channel, cpu, buffer, is_cd, channel_nr, interface_nr, bus this.is_lba = 0; /** @type {number} */ - this.bytecount = 0; + this.sector_count_reg = 0; /** @type {number} */ - this.sector = 0; + this.lba_low_reg = 0; /** @type {number} */ - this.lba_count = 0; + this.features_reg = 0; /** @type {number} */ - this.cylinder_low = 0; + this.lba_mid_reg = 0; /** @type {number} */ - this.cylinder_high = 0; + this.lba_high_reg = 0; /** @type {number} */ this.head = 0; /** @type {number} */ - this.drive_head = 0; + this.device_reg = 0; /** @type {number} */ - this.status = 0x50; + this.status_reg = 0x50; /** @type {number} */ this.sectors_per_drq = 0x80; /** @type {number} */ - this.error = 0; + this.error_reg = 0; /** @type {number} */ this.data_pointer = 0; @@ -662,8 +677,8 @@ IDEInterface.prototype.eject = function() { this.media_changed = true; this.buffer = null; - this.status = 0x59; - this.error = 0x60; + this.status_reg = 0x59; + this.error_reg = 0x60; this.push_irq(); } }; @@ -687,8 +702,8 @@ IDEInterface.prototype.set_disk_buffer = function(buffer) this.buffer = buffer; if(this.is_atapi) { - this.status = 0x59; - this.error = 0x60; + this.status_reg = 0x59; + this.error_reg = 0x60; } this.sector_count = this.buffer.byteLength / this.sector_size; @@ -744,26 +759,25 @@ IDEInterface.prototype.set_disk_buffer = function(buffer) IDEInterface.prototype.device_reset = function() { + // for details, see [ATA-6] 9.11 "DEVICE RESET command protocol" if(this.is_atapi) { - this.status = 0; - this.bytecount = 1; - this.error = 1; - this.sector = 1; // lba_low - this.cylinder_low = 0x14; // lba_mid - this.cylinder_high = 0xEB; // lba_high + this.sector_count_reg = 1; + this.lba_low_reg = 1; + this.lba_mid_reg = 0x14; + this.lba_high_reg = 0xEB; + this.device_reg &= ATA_DR_DEV; } else { - this.status = 0x50 | 1; - this.bytecount = 1; - this.error = 1; - this.sector = 1; // lba_low - - // 0, 0 needed by bochs bios - this.cylinder_low = 0; // lba_mid - this.cylinder_high = 0; // lba_high + this.sector_count_reg = 1; + this.lba_low_reg = 1; + this.lba_mid_reg = 0; + this.lba_high_reg = 0; + this.device_reg = 0; } + this.error_reg &= ~0x80; // clear bit 7 only (explicitly, why?) + this.status_reg &= ~(ATA_SR_ERR|ATA_SR_BSY); this.cancel_io_operations(); }; @@ -775,7 +789,7 @@ IDEInterface.prototype.push_irq = function() IDEInterface.prototype.ata_command = function(cmd) { - dbg_log(this.name + ": ATA Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); + dbg_log(this.name + ": ATA Command: " + h(cmd) + " slave=" + (this.device_reg >> 4 & 1), LOG_DISK); if(!this.drive_connected && cmd !== 0x90) { @@ -784,11 +798,11 @@ IDEInterface.prototype.ata_command = function(cmd) } this.current_command = cmd; - this.error = 0; + this.error_reg = 0; switch(cmd) { - case 0x08: + case 0x08: // DEVICE RESET, see [ATA-6] 8.10 and 9.11 dbg_log(this.name + ": ATA device reset", LOG_DISK); this.data_pointer = 0; this.data_end = 0; @@ -797,32 +811,32 @@ IDEInterface.prototype.ata_command = function(cmd) this.push_irq(); break; - case 0x10: - dbg_log(this.name + ": ATA calibrate drive", LOG_DISK); // ATA/ATAPI-6: obsolete - this.status = 0x50; - this.cylinder_low = 0; + case 0x10: // see [ATA-6] Table E.2: obsolete! + dbg_log(this.name + ": ATA calibrate drive", LOG_DISK); + this.status_reg = 0x50; + this.lba_mid_reg = 0; this.push_irq(); break; case 0xF8: dbg_log(this.name + ": ATA read native max address", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; var last_sector = this.sector_count - 1; - this.sector = last_sector & 0xFF; - this.cylinder_low = last_sector >> 8 & 0xFF; - this.cylinder_high = last_sector >> 16 & 0xFF; - this.drive_head = this.drive_head & 0xF0 | last_sector >> 24 & 0x0F; + this.lba_low_reg = last_sector & 0xFF; + this.lba_mid_reg = last_sector >> 8 & 0xFF; + this.lba_high_reg = last_sector >> 16 & 0xFF; + this.device_reg = this.device_reg & 0xF0 | last_sector >> 24 & 0x0F; this.push_irq(); break; case 0x27: dbg_log(this.name + ": ATA read native max address ext", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; var last_sector = this.sector_count - 1; - this.sector = last_sector & 0xFF; - this.cylinder_low = last_sector >> 8 & 0xFF; - this.cylinder_high = last_sector >> 16 & 0xFF; - this.sector |= last_sector >> 24 << 8 & 0xFF00; + this.lba_low_reg = last_sector & 0xFF; + this.lba_mid_reg = last_sector >> 8 & 0xFF; + this.lba_high_reg = last_sector >> 16 & 0xFF; + this.lba_low_reg |= last_sector >> 24 << 8 & 0xFF00; this.push_irq(); break; @@ -848,33 +862,33 @@ IDEInterface.prototype.ata_command = function(cmd) this.ata_write_sectors(cmd); break; - case 0x90: + case 0x90: // EXECUTE DEVICE DIAGNOSTIC, see [ATA-6] 8.11 dbg_log(this.name + ": ATA execute device diagnostic", LOG_DISK); - // assign diagnostics code (used to be 0x101?) to error register + // assign diagnostic code (used to be 0x101?) to error register if(this.interface_nr === 0) { // master drive is currently selected if(this.channel.slave.drive_connected) { - this.error = 0x01; // Master drive passed, slave passed or not present + this.error_reg = 0x01; // Master drive passed, slave passed or not present } else { - this.error = 0x81; // Master drive passed, slave failed + this.error_reg = 0x81; // Master drive passed, slave failed } } else { if(this.channel.slave.drive_connected) { - this.error = 0x01; // Slave drive passed + this.error_reg = 0x01; // Slave drive passed } else { - this.error = 0x00; // Slave drive failed + this.error_reg = 0x00; // Slave drive failed } } - this.status = 0x50; + this.status_reg = ATA_SR_DRDY; this.push_irq(); break; case 0x91: - // initialize device parameters (not mentioned in ATA/ATAPI-6) - this.status = 0x50; + // initialize device parameters (not mentioned in ATA-6) + this.status_reg = 0x50; this.push_irq(); break; @@ -882,10 +896,10 @@ IDEInterface.prototype.ata_command = function(cmd) // ATA packet if(this.is_atapi) { - this.status = 0x58; + this.status_reg = 0x58; this.data_allocate(12); this.data_end = 12; - this.bytecount = 1; + this.sector_count_reg = 1; this.push_irq(); } break; @@ -895,16 +909,16 @@ IDEInterface.prototype.ata_command = function(cmd) if(this.is_atapi) { this.create_identify_packet(); - this.status = 0x58; + this.status_reg = 0x58; - this.cylinder_low = 0x14; - this.cylinder_high = 0xEB; + this.lba_mid_reg = 0x14; + this.lba_high_reg = 0xEB; this.push_irq(); } else { - this.status = 0x41; + this.status_reg = 0x41; this.push_irq(); } break; @@ -912,9 +926,9 @@ IDEInterface.prototype.ata_command = function(cmd) case 0xC6: dbg_log(this.name + ": ATA set multiple mode", LOG_DISK); // Logical sectors per DRQ Block in word 1 - dbg_log(this.name + ": logical sectors per DRQ Block: " + h(this.bytecount & 0xFF), LOG_DISK); - this.sectors_per_drq = this.bytecount & 0xFF; - this.status = 0x50; + dbg_log(this.name + ": logical sectors per DRQ Block: " + h(this.sector_count_reg & 0xFF), LOG_DISK); + this.sectors_per_drq = this.sector_count_reg & 0xFF; + this.status_reg = 0x50; this.push_irq(); break; @@ -930,42 +944,42 @@ IDEInterface.prototype.ata_command = function(cmd) case 0x40: dbg_log(this.name + ": ATA read verify sector(s)", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; case 0xDA: dbg_log(this.name + ": ATA get media status", LOG_DISK); - this.status = 0x50; - this.error = 0; + this.status_reg = 0x50; + this.error_reg = 0; if(this.is_atapi) { if(!this.buffer) { - this.error |= 0x02; // NM: No Media + this.error_reg |= 0x02; // NM: No Media } if(this.media_changed) { - this.error |= 0x20; // MC: Media Change + this.error_reg |= 0x20; // MC: Media Change this.media_changed = false; } - this.error |= 0x40; // WP: Write Protect + this.error_reg |= 0x40; // WP: Write Protect } this.push_irq(); break; case 0xE0: dbg_log(this.name + ": ATA standby immediate", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; case 0xE1: dbg_log(this.name + ": ATA idle immediate", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; case 0xE7: dbg_log(this.name + ": ATA flush cache", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; @@ -974,61 +988,61 @@ IDEInterface.prototype.ata_command = function(cmd) if(this.is_atapi) { - this.status = 0x41; - this.error = 4; + this.status_reg = 0x41; + this.error_reg = 4; this.push_irq(); return; } this.create_identify_packet(); - this.status = 0x58; + this.status_reg = 0x58; this.push_irq(); break; case 0xEA: dbg_log(this.name + ": ATA flush cache ext", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; case 0xEF: - dbg_log(this.name + ": ATA set features: " + h(this.bytecount & 0xFF), LOG_DISK); - this.status = 0x50; + dbg_log(this.name + ": ATA set features: " + h(this.sector_count_reg & 0xFF), LOG_DISK); + this.status_reg = 0x50; this.push_irq(); break; case 0xDE: dbg_log(this.name + ": ATA media lock", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; case 0xF5: dbg_log(this.name + ": ATA security freeze lock", LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); break; case 0xF9: dbg_log(this.name + ": ATA set max address (unimplemented)", LOG_DISK); - this.status = 0x41; - this.error = 4; + this.status_reg = 0x41; + this.error_reg = 4; break; default: dbg_assert(false, this.name + ": unhandled ATA command: " + h(cmd), LOG_DISK); - this.status = 0x41; + this.status_reg = 0x41; // abort bit set - this.error = 4; + this.error_reg = 4; } }; IDEInterface.prototype.atapi_handle = function() { dbg_log(this.name + ": ATAPI Command: " + h(this.data[0]) + - " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); + " slave=" + (this.device_reg >> 4 & 1), LOG_DISK); this.data_pointer = 0; this.current_atapi_command = this.data[0]; @@ -1039,11 +1053,11 @@ IDEInterface.prototype.atapi_handle = function() this.current_atapi_command === 0x51)) { dbg_log(this.name + ": CD read-related action: no buffer", LOG_DISK); - this.status = 0x51; - this.error = 0x21; + this.status_reg = 0x51; + this.error_reg = 0x21; this.data_allocate(0); this.data_end = this.data_length; - this.bytecount = this.bytecount & ~7 | 2 | 1; + this.sector_count_reg = this.sector_count_reg & ~7 | 2 | 1; this.push_irq(); return; } @@ -1055,24 +1069,24 @@ IDEInterface.prototype.atapi_handle = function() // test unit ready this.data_allocate(0); this.data_end = this.data_length; - this.status = 0x50; + this.status_reg = 0x50; break; case 0x03: // request sense this.data_allocate(this.data[4]); this.data_end = this.data_length; - this.status = 0x58; + this.status_reg = 0x58; this.data[0] = 0x80 | 0x70; - this.data[2] = this.error >> 4; + this.data[2] = this.error_reg >> 4; this.data[7] = 8; break; case 0x12: // inquiry var length = this.data[4]; - this.status = 0x58; + this.status_reg = 0x58; dbg_log(this.name + ": inquiry: " + h(this.data[1], 2) + " length=" + length, LOG_DISK); @@ -1104,14 +1118,14 @@ IDEInterface.prototype.atapi_handle = function() // mode sense (6) this.data_allocate(this.data[4]); this.data_end = this.data_length; - this.status = 0x58; + this.status_reg = 0x58; break; case 0x1E: // prevent/allow medium removal this.data_allocate(0); this.data_end = this.data_length; - this.status = 0x50; + this.status_reg = 0x50; break; case 0x25: @@ -1128,12 +1142,12 @@ IDEInterface.prototype.atapi_handle = function() this.sector_size & 0xFF, ])); this.data_end = this.data_length; - this.status = 0x58; + this.status_reg = 0x58; break; case 0x28: // read - if(this.lba_count & 1) + if(this.features_reg & 1) { this.atapi_read_dma(this.data); } @@ -1148,7 +1162,7 @@ IDEInterface.prototype.atapi_handle = function() this.data_allocate(Math.min(8, length)); this.data_end = this.data_length; dbg_log(this.name + ": read q subcode: length=" + length, LOG_DISK); - this.status = 0x58; + this.status_reg = 0x58; break; case 0x43: @@ -1202,7 +1216,7 @@ IDEInterface.prototype.atapi_handle = function() dbg_assert(false, this.name + ": Unimplemented format: " + format); } - this.status = 0x58; + this.status_reg = 0x58; break; case 0x46: @@ -1217,21 +1231,21 @@ IDEInterface.prototype.atapi_handle = function() this.data[3] = length - 4 & 0xFF; this.data[6] = 0x08; this.data[10] = 3; - this.status = 0x58; + this.status_reg = 0x58; break; case 0x51: // read disk information this.data_allocate(0); this.data_end = this.data_length; - this.status = 0x50; + this.status_reg = 0x50; break; case 0x52: dbg_log(this.name + ": unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); - this.status = 0x51; + this.status_reg = 0x51; this.data_length = 0; - this.error = 5 << 4; + this.error_reg = 5 << 4; break; case 0x5A: @@ -1244,7 +1258,7 @@ IDEInterface.prototype.atapi_handle = function() this.data_allocate(Math.min(30, length)); } this.data_end = this.data_length; - this.status = 0x58; + this.status_reg = 0x58; break; case 0xBD: @@ -1252,13 +1266,13 @@ IDEInterface.prototype.atapi_handle = function() this.data_allocate(this.data[9] | this.data[8] << 8); this.data_end = this.data_length; this.data[5] = 1; - this.status = 0x58; + this.status_reg = 0x58; break; case 0x4A: - this.status = 0x51; + this.status_reg = 0x51; this.data_length = 0; - this.error = 5 << 4; + this.error_reg = 5 << 4; dbg_log(this.name + ": unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); break; @@ -1267,34 +1281,34 @@ IDEInterface.prototype.atapi_handle = function() dbg_log(this.name + ": unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); this.data_allocate(0); this.data_end = this.data_length; - this.status = 0x50; + this.status_reg = 0x50; break; default: - this.status = 0x51; + this.status_reg = 0x51; this.data_length = 0; - this.error = 5 << 4; + this.error_reg = 5 << 4; dbg_log(this.name + ": unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); dbg_assert(false); } - this.bytecount = this.bytecount & ~7 | 2; + this.sector_count_reg = this.sector_count_reg & ~7 | 2; - if((this.status & 0x80) === 0) + if((this.status_reg & 0x80) === 0) { this.push_irq(); } - if((this.status & 0x80) === 0 && this.data_length === 0) + if((this.status_reg & 0x80) === 0 && this.data_length === 0) { - this.bytecount |= 1; - this.status &= ~8; + this.sector_count_reg |= 1; + this.status_reg &= ~8; } }; IDEInterface.prototype.do_write = function() { - this.status = 0x50; + this.status_reg = 0x50; dbg_assert(this.data_length <= this.data.length); var data = this.data.subarray(0, this.data_length); @@ -1326,9 +1340,9 @@ IDEInterface.prototype.atapi_read = function(cmd) " flags=" + h(flags), LOG_DISK); this.data_length = 0; - var req_length = this.cylinder_high << 8 & 0xFF00 | this.cylinder_low & 0xFF; - dbg_log(this.name + ": " + h(this.cylinder_high, 2) + " " + h(this.cylinder_low, 2), LOG_DISK); - this.cylinder_low = this.cylinder_high = 0; // oak technology driver (windows 3.0) + var req_length = this.lba_high_reg << 8 & 0xFF00 | this.lba_mid_reg & 0xFF; + dbg_log(this.name + ": " + h(this.lba_high_reg, 2) + " " + h(this.lba_mid_reg, 2), LOG_DISK); + this.lba_mid_reg = this.lba_high_reg = 0; // oak technology driver (windows 3.0) if(req_length === 0xFFFF) req_length--; @@ -1341,8 +1355,8 @@ IDEInterface.prototype.atapi_read = function(cmd) if(!this.buffer) { dbg_assert(false, this.name + ": CD read: no buffer", LOG_DISK); - this.status = 0xFF; - this.error = 0x41; + this.status_reg = 0xFF; + this.error_reg = 0x41; this.push_irq(); } else if(start >= this.buffer.byteLength) @@ -1350,12 +1364,12 @@ IDEInterface.prototype.atapi_read = function(cmd) dbg_assert(false, this.name + ": CD read: Outside of disk end=" + h(start + byte_count) + " size=" + h(this.buffer.byteLength), LOG_DISK); - this.status = 0xFF; + this.status_reg = 0xFF; this.push_irq(); } else if(byte_count === 0) { - this.status = 0x50; + this.status_reg = 0x50; this.data_pointer = 0; //this.push_irq(); @@ -1363,7 +1377,7 @@ IDEInterface.prototype.atapi_read = function(cmd) else { byte_count = Math.min(byte_count, this.buffer.byteLength - start); - this.status = 0x50 | 0x80; + this.status_reg = 0x50 | 0x80; this.report_read_start(); this.read_buffer(start, byte_count, (data) => @@ -1371,8 +1385,8 @@ IDEInterface.prototype.atapi_read = function(cmd) //setTimeout(() => { dbg_log(this.name + ": CD read: data arrived", LOG_DISK); this.data_set(data); - this.status = 0x58; - this.bytecount = this.bytecount & ~7 | 2; + this.status_reg = 0x58; + this.sector_count_reg = this.sector_count_reg & ~7 | 2; this.push_irq(); @@ -1383,8 +1397,8 @@ IDEInterface.prototype.atapi_read = function(cmd) { this.data_end = this.data_length; } - this.cylinder_low = this.data_end & 0xFF; - this.cylinder_high = this.data_end >> 8 & 0xFF; + this.lba_mid_reg = this.data_end & 0xFF; + this.lba_high_reg = this.data_end >> 8 & 0xFF; this.report_read_end(byte_count); //}, 10); @@ -1411,20 +1425,20 @@ IDEInterface.prototype.atapi_read_dma = function(cmd) dbg_assert(false, this.name + ": CD read: Outside of disk end=" + h(start + byte_count) + " size=" + h(this.buffer.byteLength), LOG_DISK); - this.status = 0xFF; + this.status_reg = 0xFF; this.push_irq(); } else { - this.status = 0x50 | 0x80; + this.status_reg = 0x50 | 0x80; this.report_read_start(); this.read_buffer(start, byte_count, (data) => { dbg_log(this.name + ": atapi_read_dma: Data arrived"); this.report_read_end(byte_count); - this.status = 0x58; - this.bytecount = this.bytecount & ~7 | 2; + this.status_reg = 0x58; + this.sector_count_reg = this.sector_count_reg & ~7 | 2; this.data_set(data); this.do_atapi_dma(); @@ -1440,7 +1454,7 @@ IDEInterface.prototype.do_atapi_dma = function() return; } - if((this.status & 0x8) === 0) + if((this.status_reg & 0x8) === 0) { dbg_log(this.name + ": do_atapi_dma: DRQ not set", LOG_DISK); return; @@ -1482,9 +1496,9 @@ IDEInterface.prototype.do_atapi_dma = function() dbg_log(this.name + ": end offset=" + offset, LOG_DISK); - this.status = 0x50; + this.status_reg = 0x50; this.channel.dma_status &= ~1; - this.bytecount = this.bytecount & ~7 | 3; + this.sector_count_reg = this.sector_count_reg & ~7 | 3; this.push_irq(); }; @@ -1544,21 +1558,21 @@ IDEInterface.prototype.read_end = function() { if(this.data_end === this.data_length) { - this.status = 0x50; - this.bytecount = this.bytecount & ~7 | 3; + this.status_reg = 0x50; + this.sector_count_reg = this.sector_count_reg & ~7 | 3; this.push_irq(); } else { - this.status = 0x58; - this.bytecount = this.bytecount & ~7 | 2; + this.status_reg = 0x58; + this.sector_count_reg = this.sector_count_reg & ~7 | 2; this.push_irq(); - var byte_count = this.cylinder_high << 8 & 0xFF00 | this.cylinder_low & 0xFF; + var byte_count = this.lba_high_reg << 8 & 0xFF00 | this.lba_mid_reg & 0xFF; if(this.data_end + byte_count > this.data_length) { - this.cylinder_low = (this.data_length - this.data_end) & 0xFF; - this.cylinder_high = (this.data_length - this.data_end) >> 8 & 0xFF; + this.lba_mid_reg = (this.data_length - this.data_end) & 0xFF; + this.lba_high_reg = (this.data_length - this.data_end) >> 8 & 0xFF; this.data_end = this.data_length; } else @@ -1570,10 +1584,10 @@ IDEInterface.prototype.read_end = function() } else { - this.error = 0; + this.error_reg = 0; if(this.data_pointer >= this.data_length) { - this.status = 0x50; + this.status_reg = 0x50; } else { @@ -1590,7 +1604,7 @@ IDEInterface.prototype.read_end = function() } this.ata_advance(this.current_command, sector_count); this.data_end += 512 * sector_count; - this.status = 0x58; + this.status_reg = 0x58; this.push_irq(); } } @@ -1676,7 +1690,7 @@ IDEInterface.prototype.write_end = function() // XXX: Should advance here, but do_write does all the advancing //this.ata_advance(this.current_command, 1); - this.status = 0x58; + this.status_reg = 0x58; this.data_end += 512; this.push_irq(); } @@ -1685,23 +1699,23 @@ IDEInterface.prototype.write_end = function() IDEInterface.prototype.ata_advance = function(cmd, sectors) { - dbg_log(this.name + ": advance sectors=" + sectors + " old_bytecount=" + this.bytecount, LOG_DISK); - this.bytecount -= sectors; + dbg_log(this.name + ": advance sectors=" + sectors + " old_sector_count_reg=" + this.sector_count_reg, LOG_DISK); + this.sector_count_reg -= sectors; if(cmd === 0x24 || cmd === 0x29 || cmd === 0x34 || cmd === 0x39 || cmd === 0x25 || cmd === 0x35) { var new_sector = sectors + this.get_lba48(); - this.sector = new_sector & 0xFF | new_sector >> 16 & 0xFF00; - this.cylinder_low = new_sector >> 8 & 0xFF; - this.cylinder_high = new_sector >> 16 & 0xFF; + this.lba_low_reg = new_sector & 0xFF | new_sector >> 16 & 0xFF00; + this.lba_mid_reg = new_sector >> 8 & 0xFF; + this.lba_high_reg = new_sector >> 16 & 0xFF; } else if(this.is_lba) { var new_sector = sectors + this.get_lba28(); - this.sector = new_sector & 0xFF; - this.cylinder_low = new_sector >> 8 & 0xFF; - this.cylinder_high = new_sector >> 16 & 0xFF; + this.lba_low_reg = new_sector & 0xFF; + this.lba_mid_reg = new_sector >> 8 & 0xFF; + this.lba_high_reg = new_sector >> 16 & 0xFF; this.head = this.head & ~0xF | new_sector & 0xF; } else // chs @@ -1709,10 +1723,10 @@ IDEInterface.prototype.ata_advance = function(cmd, sectors) var new_sector = sectors + this.get_chs(); var c = new_sector / (this.head_count * this.sectors_per_track) | 0; - this.cylinder_low = c & 0xFF; - this.cylinder_high = c >> 8 & 0xFF; + this.lba_mid_reg = c & 0xFF; + this.lba_high_reg = c >> 8 & 0xFF; this.head = (new_sector / this.sectors_per_track | 0) % this.head_count & 0xF; - this.sector = (new_sector % this.sectors_per_track + 1) & 0xFF; + this.lba_low_reg = (new_sector % this.sectors_per_track + 1) & 0xFF; dbg_assert(new_sector === this.get_chs()); } @@ -1739,12 +1753,12 @@ IDEInterface.prototype.ata_read_sectors = function(cmd) { dbg_assert(false, this.name + ": ATA read: Outside of disk", LOG_DISK); - this.status = 0xFF; + this.status_reg = 0xFF; this.push_irq(); } else { - this.status = 0x80 | 0x40; + this.status_reg = 0x80 | 0x40; this.report_read_start(); this.read_buffer(start, byte_count, (data) => @@ -1753,7 +1767,7 @@ IDEInterface.prototype.ata_read_sectors = function(cmd) dbg_log(this.name + ": ata_read: Data arrived", LOG_DISK); this.data_set(data); - this.status = 0x58; + this.status_reg = 0x58; this.data_end = is_single ? 512 : Math.min(byte_count, this.sectors_per_drq * 512); this.ata_advance(cmd, is_single ? 1 : Math.min(count, this.sectors_per_track)); @@ -1781,12 +1795,12 @@ IDEInterface.prototype.ata_read_sectors_dma = function(cmd) { dbg_assert(false, this.name + ": ATA read: Outside of disk", LOG_DISK); - this.status = 0xFF; + this.status_reg = 0xFF; this.push_irq(); return; } - this.status = 0x58; + this.status_reg = 0x58; this.channel.dma_status |= 1; }; @@ -1839,7 +1853,7 @@ IDEInterface.prototype.do_ata_read_sectors_dma = function() dbg_assert(offset === byte_count); this.ata_advance(this.current_command, count); - this.status = 0x50; + this.status_reg = 0x50; this.channel.dma_status &= ~1; this.current_command = -1; @@ -1869,12 +1883,12 @@ IDEInterface.prototype.ata_write_sectors = function(cmd) { dbg_assert(false, this.name + ": ATA write: Outside of disk", LOG_DISK); - this.status = 0xFF; + this.status_reg = 0xFF; this.push_irq(); } else { - this.status = 0x58; + this.status_reg = 0x58; this.data_allocate_noclear(byte_count); this.data_end = is_single ? 512 : Math.min(byte_count, this.sectors_per_drq * 512); this.write_dest = start; @@ -1898,12 +1912,12 @@ IDEInterface.prototype.ata_write_sectors_dma = function(cmd) { dbg_assert(false, this.name + ": ATA DMA write: Outside of disk", LOG_DISK); - this.status = 0xFF; + this.status_reg = 0xFF; this.push_irq(); return; } - this.status = 0x58; + this.status_reg = 0x58; this.channel.dma_status |= 1; }; @@ -1959,7 +1973,7 @@ IDEInterface.prototype.do_ata_write_sectors_dma = function() { dbg_log(this.name + ": DMA write completed", LOG_DISK); this.ata_advance(this.current_command, count); - this.status = 0x50; + this.status_reg = 0x50; this.push_irq(); this.channel.dma_status &= ~1; this.current_command = -1; @@ -1970,9 +1984,9 @@ IDEInterface.prototype.do_ata_write_sectors_dma = function() IDEInterface.prototype.get_chs = function() { - var c = this.cylinder_low & 0xFF | this.cylinder_high << 8 & 0xFF00; + var c = this.lba_mid_reg & 0xFF | this.lba_high_reg << 8 & 0xFF00; var h = this.head; - var s = this.sector & 0xFF; + var s = this.lba_low_reg & 0xFF; dbg_log(this.name + ": get_chs: c=" + c + " h=" + h + " s=" + s, LOG_DISK); @@ -1981,19 +1995,19 @@ IDEInterface.prototype.get_chs = function() IDEInterface.prototype.get_lba28 = function() { - return this.sector & 0xFF | - this.cylinder_low << 8 & 0xFF00 | - this.cylinder_high << 16 & 0xFF0000 | + return this.lba_low_reg & 0xFF | + this.lba_mid_reg << 8 & 0xFF00 | + this.lba_high_reg << 16 & 0xFF0000 | (this.head & 0xF) << 24; }; IDEInterface.prototype.get_lba48 = function() { // Note: Bits over 32 missing - return (this.sector & 0xFF | - this.cylinder_low << 8 & 0xFF00 | - this.cylinder_high << 16 & 0xFF0000 | - (this.sector >> 8) << 24 & 0xFF000000) >>> 0; + return (this.lba_low_reg & 0xFF | + this.lba_mid_reg << 8 & 0xFF00 | + this.lba_high_reg << 16 & 0xFF0000 | + (this.lba_low_reg >> 8) << 24 & 0xFF000000) >>> 0; }; IDEInterface.prototype.get_lba = function(is_lba48) @@ -2016,13 +2030,13 @@ IDEInterface.prototype.get_count = function(is_lba48) { if(is_lba48) { - var count = this.bytecount; + var count = this.sector_count_reg; if(count === 0) count = 0x10000; return count; } else { - var count = this.bytecount & 0xFF; + var count = this.sector_count_reg & 0xFF; if(count === 0) count = 0x100; return count; } @@ -2126,11 +2140,7 @@ IDEInterface.prototype.create_identify_packet = function() IDEInterface.prototype.data_allocate = function(len) { this.data_allocate_noclear(len); - - for(var i = 0; i < (len + 3 >> 2); i++) - { - this.data32[i] = 0; - } + this.data32.fill(0, 0, len + 3 >> 2); }; IDEInterface.prototype.data_allocate_noclear = function(len) @@ -2201,30 +2211,30 @@ IDEInterface.prototype.cancel_io_operations = function() IDEInterface.prototype.get_state = function() { var state = []; - state[0] = this.bytecount; + state[0] = this.sector_count_reg; state[1] = this.cylinder_count; - state[2] = this.cylinder_high; - state[3] = this.cylinder_low; + state[2] = this.lba_high_reg; + state[3] = this.lba_mid_reg; state[4] = this.data_pointer; state[5] = 0; state[6] = 0; state[7] = 0; state[8] = 0; - state[9] = this.drive_head; - state[10] = this.error; + state[9] = this.device_reg; + state[10] = this.error_reg; state[11] = this.head; state[12] = this.head_count; state[13] = this.is_atapi; state[14] = this.is_lba; - state[15] = this.lba_count; + state[15] = this.features_reg; state[16] = this.data; state[17] = this.data_length; - state[18] = this.sector; + state[18] = this.lba_low_reg; state[19] = this.sector_count; state[20] = this.sector_size; state[21] = this.sectors_per_drq; state[22] = this.sectors_per_track; - state[23] = this.status; + state[23] = this.status_reg; state[24] = this.write_dest; state[25] = this.current_command; state[26] = this.data_end; @@ -2235,27 +2245,27 @@ IDEInterface.prototype.get_state = function() IDEInterface.prototype.set_state = function(state) { - this.bytecount = state[0]; + this.sector_count_reg = state[0]; this.cylinder_count = state[1]; - this.cylinder_high = state[2]; - this.cylinder_low = state[3]; + this.lba_high_reg = state[2]; + this.lba_mid_reg = state[3]; this.data_pointer = state[4]; - this.drive_head = state[9]; - this.error = state[10]; + this.device_reg = state[9]; + this.error_reg = state[10]; this.head = state[11]; this.head_count = state[12]; this.is_atapi = state[13]; this.is_lba = state[14]; - this.lba_count = state[15]; + this.features_reg = state[15]; this.data = state[16]; this.data_length = state[17]; - this.sector = state[18]; + this.lba_low_reg = state[18]; this.sector_count = state[19]; this.sector_size = state[20]; this.sectors_per_drq = state[21]; this.sectors_per_track = state[22]; - this.status = state[23]; + this.status_reg = state[23]; this.write_dest = state[24]; this.current_command = state[25];