📄 floppycontroller.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.peripheral;import org.jpc.emulator.motherboard.*;import org.jpc.support.*;import org.jpc.emulator.*;import java.io.*;public class FloppyController implements IOPortCapable, DMATransferCapable, HardwareComponent { /* Will always be a fixed parameter for us */ private static final int SECTOR_LENGTH = 512; private static final int SECTOR_SIZE_CODE = 2; // Sector size code /* Floppy disk drive emulation */ private static final int CONTROL_ACTIVE = 0x01; /* XXX: suppress that */ private static final int CONTROL_RESET = 0x02; private static final int CONTROL_SLEEP = 0x04; /* XXX: suppress that */ private static final int CONTROL_BUSY = 0x08; /* dma transfer in progress */ private static final int CONTROL_INTERRUPT = 0x10; private static final int DIRECTION_WRITE = 0; private static final int DIRECTION_READ = 1; private static final int DIRECTION_SCANE = 2; private static final int DIRECTION_SCANL = 3; private static final int DIRECTION_SCANH = 4; private static final int STATE_COMMAND = 0x00; private static final int STATE_STATUS = 0x01; private static final int STATE_DATA = 0x02; private static final int STATE_STATE = 0x03; private static final int STATE_MULTI = 0x10; private static final int STATE_SEEK = 0x20; private static final int STATE_FORMAT = 0x40; private static final byte CONTROLLER_VERSION = (byte)0x90; /* Intel 82078 Controller */ private static final int INTERRUPT_LEVEL = 6; private static final int DMA_CHANNEL = 2; private static final int IOPORT_BASE = 0x3f0; private boolean drivesUpdated; private Timer resultTimer; private Clock clock; private int state; private boolean dmaEnabled; private int currentDrive; private int bootSelect; /* Command FIFO */ private byte[] fifo; private int dataOffset; private int dataLength; private int dataState; private int dataDirection; private int interruptStatus; private byte eot; // last wanted sector /* State kept only to be returned back */ /* Timers state */ private byte timer0; private byte timer1; /* precompensation */ private byte preCompensationTrack; private byte config; private byte lock; /* Power down config */ private byte pwrd; /* Drives */ private FloppyDrive[] drives; private InterruptController irqDevice; private DMAController dma; public FloppyController() { ioportRegistered = false; drives = new FloppyDrive[2]; config = (byte)0x60; /* Implicit Seek, polling & fifo enabled */ state = CONTROL_ACTIVE; fifo = new byte[SECTOR_LENGTH]; } public void dumpState(DataOutput output) throws IOException { output.writeInt(state); output.writeBoolean(dmaEnabled); output.writeInt(currentDrive); output.writeInt(bootSelect); output.writeInt(fifo.length); output.write(fifo,0,fifo.length); output.writeInt(dataOffset); output.writeInt(dataLength); output.writeInt(dataState); output.writeInt(dataDirection); output.writeInt(interruptStatus); output.writeByte(eot); output.writeByte(timer0); output.writeByte(timer1); output.writeByte(preCompensationTrack); output.writeByte(config); output.writeByte(lock); output.writeByte(pwrd); drives[0].dumpState(output); drives[1].dumpState(output); resultTimer.dumpState(output); } public void loadState(DataInput input) throws IOException { drivesUpdated = false; ioportRegistered = false; state = input.readInt(); dmaEnabled = input.readBoolean(); currentDrive = input.readInt(); bootSelect = input.readInt(); int len = input.readInt();//be careful fifo = new byte[len]; input.readFully(fifo,0,len); dataOffset = input.readInt(); dataLength = input.readInt(); dataState = input.readInt(); dataDirection = input.readInt(); interruptStatus = input.readInt(); eot = input.readByte(); timer0 = input.readByte(); timer1 = input.readByte(); preCompensationTrack = input.readByte(); config = input.readByte(); lock = input.readByte(); pwrd = input.readByte(); drives[0].loadState(input); drives[1].loadState(input); resultTimer.loadState(input); ioportRegistered = false; //make sure the drives aren't reset when driveset is passed in. } public void timerCallback() { stopTransfer((byte)0x00, (byte)0x00, (byte)0x00); } public int getDriveType(int number) { return drives[number].drive; } public int[] ioPortsRequested() { return new int[]{IOPORT_BASE + 1, IOPORT_BASE + 2, IOPORT_BASE + 3, IOPORT_BASE + 4, IOPORT_BASE + 5, IOPORT_BASE + 7}; } public int ioPortReadByte(int address) { switch(address & 0x07) { case 0x01: return readStatusB(); case 0x02: return readDOR(); case 0x03: return readTape(); case 0x04: return readMainStatus(); case 0x05: return readData(); case 0x07: return readDirection(); default: return 0xff; } } public int ioPortReadWord(int address) { return (ioPortReadByte(address) & 0xff) | ((ioPortReadByte(address + 1) << 8) & 0xff00); } public int ioPortReadLong(int address) { return (ioPortReadWord(address) & 0xffff) | ((ioPortReadWord(address + 2) << 16) & 0xffff0000); } public void ioPortWriteByte(int address, int data) { switch(address & 0x07) { case 0x02: writeDOR(data); break; case 0x03: writeTape(data); break; case 0x04: writeRate(data); break; case 0x05: writeData(data); break; default: break; } } public void ioPortWriteWord(int address, int data) { ioPortWriteByte(address, data & 0xff); ioPortWriteByte(address + 1, (data >>> 8) & 0xff); } public void ioPortWriteLong(int address, int data) { ioPortWriteWord(address, data & 0xffff); ioPortWriteWord(address + 2, (data >>> 16) & 0xffff); } private void reset(boolean doIRQ) { resetIRQ(); currentDrive = 0; dataOffset = 0; dataLength = 0; dataState = STATE_COMMAND; dataDirection = DIRECTION_WRITE; drives[0].reset(); drives[1].reset(); resetFIFO(); if (doIRQ) raiseIRQ(0xc0); } private void raiseIRQ(int status) { if (~(state & CONTROL_INTERRUPT) != 0) { irqDevice.setIRQ(INTERRUPT_LEVEL, 1); state |= CONTROL_INTERRUPT; } interruptStatus = status; } private void resetFIFO() { dataDirection = DIRECTION_WRITE; dataOffset = 0; dataState = (dataState & ~STATE_STATE) | STATE_COMMAND; } private void resetIRQ() { irqDevice.setIRQ(INTERRUPT_LEVEL, 0); state &= ~CONTROL_INTERRUPT; } private int readStatusB() { return 0; } private int readDOR() { int retval = 0; /* Drive motors state indicators */ if ((getDrive(0).driveFlags & FloppyDrive.MOTOR_ON) != 0) retval |= 1 << 5; if ((getDrive(1).driveFlags & FloppyDrive.MOTOR_ON) != 0) retval |= 1 << 4; /* DMA enable */ retval |= dmaEnabled ? 1 << 3 : 0; /* Reset indicator */ retval |= (state & CONTROL_RESET) == 0 ? 1 << 2 : 0; /* Selected drive */ retval |= currentDrive; return retval; } private int readTape() { /* Disk boot selection indicator */ return bootSelect << 2; /* Tape indicators: never allowed */ } private int readMainStatus() { int retval = 0; state &= ~(CONTROL_SLEEP | CONTROL_RESET); if ((state & CONTROL_BUSY) == 0) { /* Data transfer allowed */ retval |= 0x80; /* Data transfer direction indicator */ if (dataDirection == DIRECTION_READ) retval |= 0x40; } /* Should handle 0x20 for SPECIFY command */ /* Command busy indicator */ if ((dataState & STATE_STATE) == STATE_DATA || (dataState & STATE_STATE) == STATE_STATUS) retval |= 0x10; return retval; } private int readData() { FloppyDrive drive; drive = getCurrentDrive(); state &= ~CONTROL_SLEEP; if ((dataState & STATE_STATE) == STATE_COMMAND) { System.err.println("fdc >> can't read data in COMMAND state"); return 0; } int offset = dataOffset; if ((dataState & STATE_STATE) == STATE_DATA) { offset %= SECTOR_LENGTH; if (offset == 0) { int length = Math.min(dataLength - dataOffset, SECTOR_LENGTH); drive.read(drive.currentSector(), fifo, length); } } int retval = fifo[offset]; if (++dataOffset == dataLength) { dataOffset = 0; /* Switch from transfer mode to status mode * then from status mode to command mode */ if ((dataState & STATE_STATE) == STATE_DATA) { stopTransfer((byte)0x20, (byte)0x00, (byte)0x00); } else { resetFIFO(); resetIRQ(); } } return retval; } private int readDirection() { int retval = 0; if (((getDrive(0).driveFlags & FloppyDrive.REVALIDATE) != 0) || ((getDrive(1).driveFlags & FloppyDrive.REVALIDATE) != 0)) retval |= 0x80; getDrive(0).driveFlags &= ~FloppyDrive.REVALIDATE; getDrive(1).driveFlags &= ~FloppyDrive.REVALIDATE; return retval; } private void writeDOR(int data) { /* Reset mode */ if (((state & CONTROL_RESET) != 0) && ((data & 0x04) == 0)) return; /* Drive motors state indicators */ if ((data & 0x20) != 0) getDrive(1).start(); else getDrive(1).stop(); if ((data & 0x10) != 0) getDrive(0).start(); else getDrive(0).stop(); /* DMA enable */ /* Reset */ if ((data & 0x04) == 0) { if ((state & CONTROL_RESET) == 0) { state |= CONTROL_RESET; } } else { if ((state & CONTROL_RESET) != 0) { reset(true); state &= ~(CONTROL_RESET | CONTROL_SLEEP); } } /* Selected drive */ currentDrive = data & 1; } private void writeTape(int data) { /* Reset mode */ if ((state & CONTROL_RESET) != 0) return; /* Disk boot selection indicator */ bootSelect = (data >>> 2) & 1; /* Tape indicators: never allow */ } private void writeRate(int data) { /* Reset mode */ if ((state & CONTROL_RESET) != 0) return; /* Reset: autoclear */ if ((data & 0x80) != 0) { state |= CONTROL_RESET; reset(true); state &= ~CONTROL_RESET; } if ((data & 0x40) != 0) { state |= CONTROL_SLEEP; reset(true); } //precomp = (data >>> 2) & 0x07; } private void writeData(int data) { FloppyDrive drive = getCurrentDrive(); /* Reset Mode */ if ((state & CONTROL_RESET) != 0) { System.err.println("fdc >> floppy controller in RESET state!"); return; } state &= ~CONTROL_SLEEP; if ((dataState & STATE_STATE) == STATE_STATUS) { System.err.println("fdc >> can't write data in status mode"); return; } /* Is it write command time? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -