📄 rtc.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.peripheral.*;import org.jpc.support.*;import java.util.Calendar;import org.jpc.emulator.*;import java.io.*;/** * MC146818 RealTime Clock emulation */public class RTC extends AbstractHardwareComponent implements IOPortCapable{ private static final int RTC_SECONDS = 0; private static final int RTC_SECONDS_ALARM = 1; private static final int RTC_MINUTES = 2; private static final int RTC_MINUTES_ALARM = 3; private static final int RTC_HOURS = 4; private static final int RTC_HOURS_ALARM = 5; private static final int RTC_ALARM_DONT_CARE = 0xc0; private static final int RTC_DAY_OF_WEEK = 6; private static final int RTC_DAY_OF_MONTH = 7; private static final int RTC_MONTH = 8; private static final int RTC_YEAR = 9; private static final int RTC_REG_EQUIPMENT_BYTE = 0x14; private static final int RTC_REG_IBM_CENTURY_BYTE = 0x32; private static final int RTC_REG_IBM_PS2_CENTURY_BYTE = 0x37; private static final int RTC_REG_A = 10; private static final int RTC_REG_B = 11; private static final int RTC_REG_C = 12; private static final int RTC_REG_D = 13; private static final int REG_A_UIP = 0x80; private static final int REG_B_SET = 0x80; private static final int REG_B_PIE = 0x40; private static final int REG_B_AIE = 0x20; private static final int REG_B_UIE = 0x10; private byte[] cmosData; //rowa private byte cmosIndex; //rw private int irq; //r private Calendar currentTime; //rw /* periodic timer */ private Timer periodicTimer; private long nextPeriodicTime; //rw /* second update */ private Timer secondTimer; private Timer delayedSecondTimer; private long nextSecondTime; //ri private PeriodicCallback periodicCallback; private SecondCallback secondCallback; private DelayedSecondCallback delayedSecondCallback; private InterruptController irqDevice; private Clock timeSource; private int ioPortBase, bootType; private boolean ioportRegistered; private boolean drivesInited; private boolean floppiesInited; public RTC(int ioPort, int irq) { bootType = -1; ioportRegistered = false; drivesInited = false; floppiesInited = false; ioPortBase = ioPort; this.irq = irq; cmosData = new byte[128]; cmosData[RTC_REG_A] = 0x26; cmosData[RTC_REG_B] = 0x02; cmosData[RTC_REG_C] = 0x00; cmosData[RTC_REG_D] = (byte)0x80; periodicCallback = new PeriodicCallback(); secondCallback = new SecondCallback(); delayedSecondCallback = new DelayedSecondCallback(); } public void dumpState(DataOutput output) throws IOException { output.writeInt(cmosData.length); output.write(cmosData); output.writeByte(cmosIndex); output.writeInt(irq); //calendar output.writeLong(nextSecondTime); output.writeInt(ioPortBase); output.writeInt(bootType); output.writeBoolean(ioportRegistered); output.writeBoolean(drivesInited); output.writeBoolean(floppiesInited); //timers periodicTimer.dumpState(output); secondTimer.dumpState(output); delayedSecondTimer.dumpState(output); } public void loadState(DataInput input) throws IOException { ioportRegistered = false; int len = input.readInt(); input.readFully(cmosData,0,len); cmosIndex = input.readByte(); irq = input.readInt(); //calendar nextSecondTime = input.readLong(); ioPortBase = input.readInt(); bootType = input.readInt(); ioportRegistered = input.readBoolean(); drivesInited = input.readBoolean(); floppiesInited = input.readBoolean(); //timers periodicTimer = timeSource.newTimer(periodicCallback); secondTimer = timeSource.newTimer(secondCallback); delayedSecondTimer = timeSource.newTimer(delayedSecondCallback); periodicTimer.loadState(input); secondTimer.loadState(input); delayedSecondTimer.loadState(input); } static final long scale64(long input, int multiply, int divide) { //return (BigInteger.valueOf(input).multiply(BigInteger.valueOf(multiply)).divide(BigInteger.valueOf(divide))).longValue(); long rl = (0xffffffffl & input) * multiply; long rh = (input >>> 32) * multiply; rh += (rl >> 32); long resultHigh = 0xffffffffl & (rh / divide); long resultLow = 0xffffffffl & ((((rh % divide) << 32) + (rl & 0xffffffffl)) / divide); return (resultHigh << 32) | resultLow; } public void init() { Calendar now = Calendar.getInstance(); this.setTime(now); int val = this.toBCD(now.get(Calendar.YEAR) / 100); cmosData[RTC_REG_IBM_CENTURY_BYTE] = (byte)val; cmosData[RTC_REG_IBM_PS2_CENTURY_BYTE] = (byte)val; /* memory size */ val = 640; /* base memory in K */ cmosData[0x15] = (byte)val; cmosData[0x16] = (byte)(val >>> 8); int ramSize = PC.SYS_RAM_SIZE; val = (ramSize / 1024) - 1024; if (val > 65535) val = 65535; cmosData[0x17] = (byte)val; cmosData[0x18] = (byte)(val >>> 8); cmosData[0x30] = (byte)val; cmosData[0x31] = (byte)(val >>> 8); if (ramSize > (16 * 1024 * 1024)) { val = (ramSize / 65536) - ((16 * 1024 * 1024) / 65536); } else { val = 0; } if (val > 65535) val = 65535; cmosData[0x34] = (byte)val; cmosData[0x35] = (byte)(val >>> 8); switch(bootType) { case DriveSet.FLOPPY_BOOT: cmosData[0x3d] = (byte)0x01; /* floppy boot */ break; default: case DriveSet.HARD_DRIVE_BOOT: cmosData[0x3d] = (byte)0x02; /* hard drive boot */ break; case DriveSet.CD_BOOT: cmosData[0x3d] = (byte)0x03; /* CD-ROM boot */ break; } } public void cmosInitHD(DriveSet drives) { BlockDevice drive0 = drives.getHardDrive(0); BlockDevice drive1 = drives.getHardDrive(1); cmosData[0x12] = (byte)(((drive0 != null) ? 0xf0 : 0) | ((drive1 != null) ? 0x0f : 0)); if (drive0 != null) { cmosData[0x19] = (byte)47; cmosData[0x1b] = (byte)drive0.cylinders(); cmosData[0x1b + 1] = (byte)(drive0.cylinders() >>> 8); cmosData[0x1b + 2] = (byte)drive0.heads(); cmosData[0x1b + 3] = (byte)0xff; cmosData[0x1b + 4] = (byte)0xff; cmosData[0x1b + 5] = (byte)(0xc0 | ((drive0.heads() > 8) ? 0x8 : 0)); cmosData[0x1b + 6] = (byte)drive0.cylinders(); cmosData[0x1b + 7] = (byte)(drive0.cylinders() >>> 8); cmosData[0x1b + 8] = (byte)drive0.sectors(); } if (drive1 != null) { cmosData[0x1a] = (byte)47; cmosData[0x24] = (byte)drive1.cylinders(); cmosData[0x24 + 1] = (byte)(drive1.cylinders() >>> 8); cmosData[0x24 + 2] = (byte)drive1.heads(); cmosData[0x24 + 3] = (byte)0xff; cmosData[0x24 + 4] = (byte)0xff; cmosData[0x24 + 5] = (byte)(0xc0 | ((drive1.heads() > 8) ? 0x8 : 0)); cmosData[0x24 + 6] = (byte)drive1.cylinders(); cmosData[0x24 + 7] = (byte)(drive1.cylinders() >>> 8); cmosData[0x24 + 8] = (byte)drive1.sectors(); } int value = 0; for (int i = 0; i < 4; i++) { if (drives.getHardDrive(i) != null) { int translation; if ((drives.getHardDrive(i).cylinders() <= 1024) && (drives.getHardDrive(i).heads() <= 16) && (drives.getHardDrive(i).sectors() <= 63)) { /* No Translation. */ translation = 0; } else { /* LBA Translation */ translation = 1; } value |= translation << (i * 2); } } cmosData[0x39] = (byte)value; } public void cmosInitFloppy(FloppyController fdc) { int val = (cmosGetFDType(fdc, 0) << 4) | cmosGetFDType(fdc, 1); cmosData[0x10] = (byte)val; int num = 0; val = 0; if (fdc.getDriveType(0) < 3) num++; if (fdc.getDriveType(1) < 3) num++; switch (num) { case 0: break; case 1: val |= 0x01; break; case 2: val |= 0x41; break; } val |= 0x02; // Have FPU val |= 0x04; // Have PS2 Mouse cmosData[RTC_REG_EQUIPMENT_BYTE] = (byte)val; } private int cmosGetFDType(FloppyController fdc, int drive) { switch (fdc.getDriveType(drive)) { case 0: return 4; case 1: return 5; case 2: return 2; default: return 0; } } public int[] ioPortsRequested() { int base = ioPortBase; return new int[]{base, base+1}; } public int ioPortReadByte(int address) { return 0xff & cmosIOPortRead(address); } public int ioPortReadWord(int address) { return (0xff & ioPortReadByte(address)) | (0xff00 & (ioPortReadByte(address + 1) << 8)); } public int ioPortReadLong(int address) { return (0xffff & ioPortReadWord(address)) | (0xffff0000 & (ioPortReadWord(address + 2) << 16)); } public void ioPortWriteByte(int address, int data) { cmosIOPortWrite(address, 0xff & data); } public void ioPortWriteWord(int address, int data) { this.ioPortWriteByte(address, data); this.ioPortWriteByte(address + 1, data >> 8); } public void ioPortWriteLong(int address, int data) { this.ioPortWriteWord(address, data); this.ioPortWriteWord(address + 2, data >> 16); } private class PeriodicCallback extends AbstractHardwareComponent { public void timerCallback()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -