FloppyController implements Device { public FloppyController(Computer computer) { this.clockTicksPerTrack = computer.nanosToCpuTime(NANOSECS_PER_TRACK); this.clockTicksPerWord = computer.nanosToCpuTime(NANOSECS_PER_TRACK / WORDS_PER_TRACK); this.clockTicksPerIndexHole = computer.nanosToCpuTime(NANOSECS_PER_INDEX_HOLE); for (FloppyDriveIdentifier driveIdentifier : FloppyDriveIdentifier.values()) { floppyDrives[driveIdentifier.ordinal()] = new FloppyDrive(driveIdentifier); } } FloppyController(Computer computer); void setDebugEnabled(boolean state); @Override int[] getAddresses(); @Override synchronized void init(long cpuTime); @Override synchronized void saveState(Bundle outState); @Override synchronized void restoreState(Bundle inState); @Override synchronized int read(long cpuTime, int address); @Override synchronized boolean write(long cpuTime, boolean isByteMode, int address, int value); synchronized long getLastAccessCpuTime(); synchronized void setLastAccessCpuTime(long lastAccessCpuTime); synchronized void mountDiskImage(File diskImageFile, FloppyDriveIdentifier drive,
            boolean isReadOnly); synchronized void unmountDiskImage(FloppyDriveIdentifier drive); synchronized void unmountDiskImages(); synchronized boolean isMotorStarted(); synchronized boolean isFloppyDriveMounted(FloppyDriveIdentifier driveIdentifier); synchronized File getFloppyDriveImageFile(FloppyDriveIdentifier driveIdentifier); final static int CONTROL_REGISTER_ADDRESS; final static int TR0; final static int RDY; final static int WRP; final static int TR; final static int CRC; final static int IND; final static int DS0; final static int DS1; final static int DS2; final static int DS3; final static int MSW; final static int HS; final static int DIR; final static int ST; final static int GOR; final static int WM; final static int DATA_REGISTER_ADDRESS; final static int DISK_ROTATIONS_PER_SECOND; final static int WORDS_PER_TRACK; final static long NANOSECS_PER_TRACK; final static long NANOSECS_PER_INDEX_HOLE; final static int TRACKS_PER_DISK; final static int SECTORS_PER_TRACK; final static int BYTES_PER_SECTOR; final static int BYTES_PER_DISK; }
@Test public void testFloppyController() throws Exception { for (FloppyDriveIdentifier driveIdentifier : FloppyDriveIdentifier.values()) { FloppyDrive drive = floppyController.getFloppyDrive(driveIdentifier); assertNotNull(drive); assertEquals(0, drive.getCurrentTrackNumber()); assertEquals(FloppyDriveSide.DOWN, drive.getCurrentTrackSide()); } FloppyDrive drive = floppyController.getFloppyDrive(FloppyDriveIdentifier.A); assertEquals(0, drive.getNextTrackNumber(false)); assertEquals(1, drive.getNextTrackNumber(true)); drive.setCurrentTrack(FloppyController.TRACKS_PER_DISK - 1, FloppyDriveSide.DOWN); assertEquals(FloppyController.TRACKS_PER_DISK - 2, drive.getNextTrackNumber(false)); assertEquals(FloppyController.TRACKS_PER_DISK - 1, drive.getNextTrackNumber(true)); drive.setCurrentTrack(0, FloppyDriveSide.DOWN); for (int position = 0; position < FloppyController.WORDS_PER_TRACK; position++) { assertEquals(0, drive.readCurrentTrackData(position)); } byte[] testDiskImageData = mountTestDiskImage(); int testDiskImageDataIndex = 0; for (int trackNumber = 0; trackNumber < TEST_DISK_NUM_TRACKS; trackNumber++) { System.out.println("Track: " + trackNumber); for (FloppyDriveSide trackSide : FloppyDriveSide.values()) { drive.setCurrentTrack(trackNumber, trackSide); int trackPosition = 0; int wordsToCheck = FloppyDriveTrackSequence.SEQ_GAP1_LENGTH; while (wordsToCheck-- > 0) { assertEquals("GAP1 position: " + trackPosition, FloppyDriveTrackSequence.SEQ_GAP, drive.readCurrentTrackData(trackPosition++)); } for (int sectorNumber = 1; sectorNumber <= FloppyController.SECTORS_PER_TRACK; sectorNumber++) { wordsToCheck = FloppyDriveTrackSequence.SEQ_SYNC_LENGTH; while (wordsToCheck-- > 0) { assertEquals("header sync position: " + trackPosition, FloppyDriveTrackSequence.SEQ_SYNC, drive.readCurrentTrackData(trackPosition++)); } assertTrue("IDAM position: " + trackPosition, drive.isCurrentTrackDataMarkerPosition(trackPosition)); assertEquals("IDAM word 1 position: " + trackPosition, 0xa1a1, drive.readCurrentTrackData(trackPosition++)); assertEquals("IDAM word 2 position: " + trackPosition, 0xa1fe, drive.readCurrentTrackData(trackPosition++)); assertEquals("head/track numbers position: " + trackPosition, (drive.getCurrentTrackNumber() << 8) | drive.getCurrentTrackSide().ordinal(), drive.readCurrentTrackData(trackPosition++)); assertEquals("sector number / size position: " + trackPosition, (sectorNumber << 8) | 2, drive.readCurrentTrackData(trackPosition++)); assertTrue("sector header CRC position: " + trackPosition, drive.isCurrentTrackDataCrcPosition(trackPosition)); assertEquals("sector header CRC position: " + trackPosition, Crc16.calculate(new byte[] { (byte) 0xa1, (byte) 0xa1, (byte) 0xa1, (byte) 0xfe, (byte) drive.getCurrentTrackNumber(), (byte) drive.getCurrentTrackSide().ordinal(), (byte) sectorNumber, 2 }) & 0177777, drive.readCurrentTrackData(trackPosition++) & 0177777); wordsToCheck = FloppyDriveTrackSequence.SEQ_GAP2_LENGTH; while (wordsToCheck-- > 0) { assertEquals("GAP2 position: " + trackPosition, FloppyDriveTrackSequence.SEQ_GAP, drive.readCurrentTrackData(trackPosition++)); } wordsToCheck = FloppyDriveTrackSequence.SEQ_SYNC_LENGTH; while (wordsToCheck-- > 0) { assertEquals("data sync position: " + trackPosition, FloppyDriveTrackSequence.SEQ_SYNC, drive.readCurrentTrackData(trackPosition++)); } assertTrue("DATA AM position: " + trackPosition, drive.isCurrentTrackDataMarkerPosition(trackPosition)); assertEquals("DATA AM word 1 position: " + trackPosition, 0xa1a1, drive.readCurrentTrackData(trackPosition++)); assertEquals("DATA AM word 2 position: " + trackPosition, 0xa1fb, drive.readCurrentTrackData(trackPosition++)); short crcValue = Crc16.calculate(new byte[] { (byte) 0xa1, (byte) 0xa1, (byte) 0xa1, (byte) 0xfb }); wordsToCheck = FloppyController.BYTES_PER_SECTOR >> 1; while (wordsToCheck-- > 0) { byte dataByte1 = testDiskImageData[testDiskImageDataIndex++]; byte dataByte2 = testDiskImageData[testDiskImageDataIndex++]; assertEquals("Sector data position: " + trackPosition + ", image index: " + (testDiskImageDataIndex - 2), ((dataByte1 << 8) & 0177400) | (dataByte2 & 0377), drive.readCurrentTrackData(trackPosition++)); crcValue = Crc16.calculate(crcValue, dataByte1); crcValue = Crc16.calculate(crcValue, dataByte2); } assertTrue("sector data CRC position: " + trackPosition, drive.isCurrentTrackDataCrcPosition(trackPosition)); assertEquals("sector data CRC", crcValue & 0177777, drive.readCurrentTrackData(trackPosition++) & 0177777); wordsToCheck = (sectorNumber < FloppyController.SECTORS_PER_TRACK) ? FloppyDriveTrackSequence.SEQ_GAP3_LENGTH : (FloppyController.WORDS_PER_TRACK - trackPosition ); while (wordsToCheck-- > 0) { assertEquals("GAP3/GAP4B position: " + trackPosition, FloppyDriveTrackSequence.SEQ_GAP, drive.readCurrentTrackData(trackPosition++)); } } } } }