📄 idechannel.java
字号:
/* JPC: A x86 PC Hardware Emulator for a pure Java Virtual Machine Release Version 2.0 A project from the Physics Dept, The University of Oxford Copyright (C) 2007 Isis Innovation Limited This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: www.physics.ox.ac.uk/jpc*/package org.jpc.emulator.pci.peripheral;import org.jpc.emulator.motherboard.*;import org.jpc.support.*;import org.jpc.emulator.*;import java.io.*;public class IDEChannel implements IOPortCapable{ private IDEState[] devices; private IDEState currentDevice; private int ioBase, ioBaseTwo, irq; private InterruptController irqDevice; private int nextDriveSerial; public void dumpState(DataOutput output) throws IOException { output.writeInt(ioBase); output.writeInt(ioBaseTwo); output.writeInt(irq); output.writeInt(nextDriveSerial); for (int i = 0; i < devices.length; i++) devices[i].dumpState(output); int currentDeviceIndex = -1; for (int i=0; i< devices.length; i++) if (currentDevice == devices[i]) currentDeviceIndex = i; output.writeInt(currentDeviceIndex); } public void loadState(DataInput input) throws IOException { ioBase = input.readInt(); ioBaseTwo = input.readInt(); irq = input.readInt(); nextDriveSerial = input.readInt(); for (int i = 0; i < devices.length; i++) { devices[i].loadState(input); } int currentDeviceIndex = input.readInt(); currentDevice = devices[currentDeviceIndex]; } public void reset() {} public boolean initialised() {return true;} public boolean updated() {return true;} public void updateComponent(org.jpc.emulator.HardwareComponent component) {} public void acceptComponent(org.jpc.emulator.HardwareComponent component) {} private static void shortToBigEndianBytes(byte[] buffer, int offset, short val) { buffer[offset + 0] = (byte)(val >> 8); buffer[offset + 1] = (byte)(val); } private static void intToBigEndianBytes(byte[] buffer, int offset, int val) { buffer[offset + 0] = (byte)(val >> 24); buffer[offset + 1] = (byte)(val >> 16); buffer[offset + 2] = (byte)(val >> 8); buffer[offset + 3] = (byte)(val); } private static int bigEndianBytesToInt(byte[] buffer, int offset) { int val = 0; val |= ((buffer[offset + 0] << 24) & 0xff000000); val |= ((buffer[offset + 1] << 16) & 0x00ff0000); val |= ((buffer[offset + 2] << 8) & 0x0000ff00); val |= ((buffer[offset + 3] << 0) & 0x000000ff); return val; } private static short bigEndianBytesToShort(byte[] buffer, int offset) { short val = 0; val |= ((buffer[offset + 0] << 8) & 0xff00); val |= ((buffer[offset + 1] << 0) & 0x00ff); return val; } private static void lbaToMSF(byte[] buffer, int offset, int lba) { lba += 150; buffer[offset + 0] = (byte)((lba / 75) / 60); buffer[offset + 1] = (byte)((lba / 75) % 60); buffer[offset + 2] = (byte)(lba % 75); } private static void putLE16InByte(byte[] dest, int offset, int data) { dest[offset + 0] = (byte)data; dest[offset + 1] = (byte)(data >>> 8); } private static void stringToBytes(String text, byte[] dest, int start, int length) { byte[] temp = text.getBytes(); int i = 0; for (; i < Math.min(temp.length, length); i++) dest[(start + i) ^ 1] = temp[i]; for (; i < length; i++) dest[(start + i) ^ 1] = 0x20; } public IDEChannel() {} public IDEChannel(int irq, InterruptController irqDevice, int ioBase, int ioBaseTwo, BlockDevice[] drives, BMDMAIORegion bmdma) { this.irq = irq; this.irqDevice = irqDevice; this.ioBase = ioBase; this.ioBaseTwo = ioBaseTwo; this.nextDriveSerial = 1; devices = new IDEState[2]; devices[0] = new IDEState(drives[0]); // master devices[1] = new IDEState(drives[1]); // slave devices[0].bmdma = bmdma; devices[1].bmdma = bmdma; this.currentDevice = devices[0]; } public void setDrives(BlockDevice[] drives) { devices[0].setDrive(drives[0]); devices[1].setDrive(drives[1]); } public void ioPortWriteByte(int address, int data) { if (address == ioBaseTwo) { this.writeCommand(data); return; } else { this.writeIDE(address, data); return; } } public void ioPortWriteWord(int address, int data) { switch(address - ioBase) { case 0: case 1: this.writeDataWord(address, data); break; default: this.ioPortWriteByte(address, data); this.ioPortWriteByte(address + 1, data >>> 8); break; } } public void ioPortWriteLong(int address, int data) { switch(address - ioBase) { case 0: case 1: case 2: case 3: this.writeDataLong(address, data); break; default: this.ioPortWriteWord(address, data); this.ioPortWriteWord(address + 2, data >>> 16); break; } } public int ioPortReadByte(int address) { if (address == ioBaseTwo) { return this.readStatus(); } else { return this.readIDE(address); } } public int ioPortReadWord(int address) { switch(address - ioBase) { case 0: case 1: return this.readDataWord(address); default: return (0xff & ioPortReadByte(address)) | (0xff00 & (ioPortReadByte(address + 1) << 8)); } } public int ioPortReadLong(int address) { switch (address - ioBase) { case 0: case 1: case 2: case 3: return this.readDataLong(address); default: return (0xffff & ioPortReadWord(address)) | (0xffff0000 & (ioPortReadWord(address + 2) << 16)); } } public int[] ioPortsRequested() { if (ioBaseTwo == 0) return new int[]{ioBase, ioBase + 1, ioBase + 2, ioBase + 3, ioBase + 4, ioBase + 5, ioBase + 6, ioBase + 7}; else return new int[]{ioBase, ioBase + 1, ioBase + 2, ioBase + 3, ioBase + 4, ioBase + 5, ioBase + 6, ioBase + 7, ioBaseTwo}; } private void writeCommand(int data) { /* common for both drives */ if (((devices[0].command & IDEState.IDE_CMD_RESET) == 0) && ((data & IDEState.IDE_CMD_RESET) != 0)) { /* reset low to high */ devices[0].status = (byte)(IDEState.BUSY_STAT | IDEState.SEEK_STAT); devices[0].error = 0x01; devices[1].status = (byte)(IDEState.BUSY_STAT | IDEState.SEEK_STAT); devices[1].error = 0x01; } else if (((devices[0].command & IDEState.IDE_CMD_RESET) != 0) && ((data & IDEState.IDE_CMD_RESET) == 0)) { /* reset high to low */ for (int i = 0; i < 2; i++) { if (devices[i].isCDROM) devices[i].status = 0x00; /* NOTE: READY is not set */ else devices[i].status = (byte)(IDEState.READY_STAT | IDEState.SEEK_STAT); devices[i].setSignature(); } } devices[0].command = (byte)data; devices[1].command = (byte)data; } private int readStatus() { if (((devices[0].drive == null) && (devices[1].drive == null)) || ((currentDevice != devices[0]) && (currentDevice.drive == null))) { return 0; } else { return currentDevice.status; } } private void writeIDE(int address, int data) { boolean lba48 = false; address &= 7; switch (address) { case 0: break; case 1: clearHob(); /* NOTE: data is written to the two drives */ devices[0].hobFeature = devices[0].feature; devices[1].hobFeature = devices[1].feature; devices[0].feature = (byte)data; devices[1].feature = (byte)data; break; case 2: clearHob(); devices[0].hobNSector = (byte)devices[0].nSector; devices[1].hobNSector = (byte)devices[1].nSector; devices[0].nSector = 0xff & data; devices[1].nSector = 0xff & data; break; case 3: clearHob(); devices[0].hobSector = devices[0].sector; devices[1].hobSector = devices[1].sector; devices[0].sector = (byte)data; devices[1].sector = (byte)data; break; case 4: clearHob(); devices[0].hobLCyl = devices[0].lcyl; devices[1].hobLCyl = devices[1].lcyl; devices[0].lcyl = (byte)data; devices[1].lcyl = (byte)data; break; case 5: clearHob(); devices[0].hobHCyl = devices[0].hcyl; devices[1].hobHCyl = devices[1].hcyl; devices[0].hcyl = (byte)data; devices[1].hcyl = (byte)data; break; case 6: // FIXME: HOB readback uses bit 7 devices[0].select = (byte)((data & ~0x10) | 0xa0); devices[1].select = (byte)(data | 0x10 | 0xa0); /* select drive */ currentDevice = devices[(data >> 4) & 1]; break; default: case 7: /* ignore commands to non existant slave */ if (currentDevice != devices[0] && currentDevice.drive == null) break; switch(data) { case IDEState.WIN_IDENTIFY: if ((currentDevice.drive != null) && !currentDevice.isCDROM) { currentDevice.identify(); currentDevice.status = (byte)(IDEState.READY_STAT | IDEState.SEEK_STAT); currentDevice.transferStart(currentDevice.ioBuffer, 0, 512, IDEState.ETF_TRANSFER_STOP); } else { if (currentDevice.isCDROM) { currentDevice.setSignature(); } currentDevice.abortCommand(); } currentDevice.setIRQ(); break; case IDEState.WIN_SPECIFY: case IDEState.WIN_RECAL: currentDevice.error = 0; currentDevice.status = (byte)(IDEState.READY_STAT | IDEState.SEEK_STAT); currentDevice.setIRQ(); break; case IDEState.WIN_SETMULT: if (currentDevice.nSector > IDEState.MAX_MULT_SECTORS || currentDevice.nSector == 0 || (currentDevice.nSector & (currentDevice.nSector - 1)) != 0) { currentDevice.abortCommand(); } else { currentDevice.multSectors = currentDevice.nSector; currentDevice.status = IDEState.READY_STAT; } currentDevice.setIRQ(); break; case IDEState.WIN_VERIFY_EXT: lba48 = true; case IDEState.WIN_VERIFY: case IDEState.WIN_VERIFY_ONCE: currentDevice.commandLBA48Transform(lba48); /* do sector number check ? */ currentDevice.status = IDEState.READY_STAT; currentDevice.setIRQ(); break; case IDEState.WIN_READ_EXT: lba48 = true; case IDEState.WIN_READ: case IDEState.WIN_READ_ONCE: if (currentDevice.drive == null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -