📄 dmacontroller.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.motherboard;import org.jpc.emulator.memory.*;import org.jpc.emulator.HardwareComponent;import java.io.*;public class DMAController implements IOPortCapable, HardwareComponent{ private static final int pagePortList0 = 0x1; private static final int pagePortList1 = 0x2; private static final int pagePortList2 = 0x3; private static final int pagePortList3 = 0x7; private static final int[] pagePortList = new int[]{pagePortList0, pagePortList1, pagePortList2, pagePortList3}; private static final int CMD_MEMORY_TO_MEMORY = 0x01; private static final int CMD_FIXED_ADDRESS = 0x02; private static final int CMD_BLOCK_CONTROLLER = 0x04; private static final int CMD_COMPRESSED_TIME = 0x08; private static final int CMD_CYCLIC_PRIORITY = 0x10; private static final int CMD_EXTENDED_WRITE = 0x20; private static final int CMD_LOW_DREQ = 0x40; private static final int CMD_LOW_DACK = 0x80; private static final int CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE | CMD_LOW_DREQ | CMD_LOW_DACK; private int status; private int command; private int mask; private boolean flipFlop; private int dShift; private int iobase, pageBase, pageHBase; private int controllerNumber; private PhysicalAddressSpace memory;// private DMABackgroundTask dmaTask;// private static final int DMA_TRANSFER_TASK_PERIOD_MAX = 200;// private static final int DMA_TRANSFER_TASK_PERIOD_MIN = 1; static class DMARegister { public static final int ADDRESS = 0; public static final int COUNT = 1; public int nowAddress; public int nowCount; public short baseAddress; public short baseCount; public int mode; public byte page, pageh, dack, eop; public DMATransferCapable transferDevice; public DMARegister() { } public void dumpState(DataOutput output) throws IOException { output.writeInt(nowAddress); output.writeInt(nowCount); output.writeShort(baseAddress); output.writeShort(baseCount); output.writeInt(mode); output.writeByte(page); output.writeByte(pageh); output.writeByte(dack); output.writeByte(eop); //tactfully ignore transferDevice } public void loadState(DataInput input) throws IOException { nowAddress = input.readInt(); nowCount = input.readInt(); baseAddress = input.readShort(); baseCount = input.readShort(); mode = input.readInt(); page = input.readByte(); pageh = input.readByte(); dack = input.readByte(); eop = input.readByte(); //tactfully ignore transferDevice } public void reset() { transferDevice = null; nowAddress = nowCount = mode = 0; baseAddress = baseCount = 0; page = pageh = dack = eop = 0; } } private DMARegister[] dmaRegs; public DMAController(boolean highPageEnable, boolean zeroth) { ioportRegistered = false; this.dShift = zeroth ? 0 : 1; this.iobase = zeroth ? 0x00 : 0xc0; this.pageBase = zeroth ? 0x80 : 0x88; this.pageHBase = highPageEnable ? (zeroth ? 0x480 : 0x488) : -1; this.controllerNumber = zeroth ? 0 : 1; dmaRegs = new DMARegister[4]; for (int i = 0; i < 4; i++) dmaRegs[i] = new DMARegister(); this.reset();// dmaTask = new DMABackgroundTask();// dmaTask.start(); } public void dumpState(DataOutput output) throws IOException { output.writeInt(status); output.writeInt(command); output.writeInt(mask); output.writeBoolean(flipFlop); output.writeInt(dShift); output.writeInt(iobase); output.writeInt(pageBase); output.writeInt(pageHBase); output.writeInt(controllerNumber); output.writeInt(dmaRegs.length); for (int i=0; i < dmaRegs.length; i++) dmaRegs[i].dumpState(output); } public void loadState(DataInput input) throws IOException { ioportRegistered = false; status = input.readInt(); command = input.readInt(); mask = input.readInt(); flipFlop = input.readBoolean(); dShift = input.readInt(); iobase = input.readInt(); pageBase = input.readInt(); pageHBase = input.readInt(); controllerNumber = input.readInt(); int len = input.readInt(); dmaRegs = new DMARegister[len]; for (int i=0; i < dmaRegs.length; i++) { dmaRegs[i] = new DMARegister(); dmaRegs[i].loadState(input); } } public boolean isFirst() { return (this.dShift == 0); } public void reset() { for (int i = 0; i < dmaRegs.length; i++) dmaRegs[i].reset(); this.writeController(0x0d << this.dShift, 0); memory = null; ioportRegistered = false; } private void writeChannel(int portNumber, int data) { int port = (portNumber >>> dShift) & 0x0f; int channelNumber = port >>> 1; DMARegister r = dmaRegs[channelNumber]; if (getFlipFlop()) { if ((port & 1) == DMARegister.ADDRESS) r.baseAddress = (short)((r.baseAddress & 0xff) | ((data << 8) & 0xff00)); else r.baseCount = (short)((r.baseCount & 0xff) | ((data << 8) & 0xff00)); initChannel(channelNumber); } else { if ((port & 1) == DMARegister.ADDRESS) r.baseAddress = (short)((r.baseAddress & 0xff00) | (data & 0xff)); else r.baseCount = (short)((r.baseCount & 0xff00) | (data & 0xff)); } } private void writeController(int portNumber, int data) { int port = (portNumber >>> this.dShift) & 0x0f; switch (port) { case 0x08: /* command */ if ((data != 0) && ((data & CMD_NOT_SUPPORTED) != 0)) break; command = data; break; case 0x09: int channelNumber = data & 3; if ((data & 4) != 0) { status |= 1 << (channelNumber + 4); } else { status &= ~(1 << (channelNumber + 4)); } status &= ~(1 << channelNumber); runTransfers(); break; case 0x0a: /* single mask */ if ((data & 0x4) != 0) { mask |= 1 << (data & 3); } else { mask &= ~(1 << (data & 3)); runTransfers(); } break; case 0x0b: /* mode */ channelNumber = data & 3; dmaRegs[channelNumber].mode = data; break; case 0x0c: /* clear flipFlop */ flipFlop = false; break; case 0x0d: /* reset */ flipFlop = false; mask = ~0; status = 0; command = 0; break; case 0x0e: /* clear mask for all channels */ mask = 0; runTransfers(); break; case 0x0f: /* write mask for all channels */ mask = data; runTransfers(); break; default: break; } } private static final int[] channels = new int[]{-1, 2, 3, 1, -1, -1, -1, 0}; private void writePage(int portNumber, int data) { int channelNumber = channels[portNumber & 7]; if (-1 == channelNumber) { return; } dmaRegs[channelNumber].page = (byte)data; } private void writePageH(int portNumber, int data) { int channelNumber = channels[portNumber & 7]; if (-1 == channelNumber) { return; } dmaRegs[channelNumber].pageh = (byte)data; } private int readChannel(int portNumber) { int port = (portNumber >>> dShift) & 0x0f; int channelNumber = port >>> 1; int registerNumber = port & 1; DMARegister r = dmaRegs[channelNumber]; int direction = ((r.mode & 0x20) == 0) ? 1 : -1; boolean flipflop = getFlipFlop(); int val; if (registerNumber != 0) { val = ((0xffff & r.baseCount) << dShift) - r.nowCount; } else { val = r.nowAddress + r.nowCount * direction; } return (val >>> (dShift + (flipflop ? 0x8 : 0x0))) & 0xff; } private int readController(int portNumber) { int val; int port = (portNumber >>> dShift) & 0x0f; switch (port) { case 0x08: val = status; status &= 0xf0; break; case 0x0f:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -