/** * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.codesourcery.jasm16.emulator.devices.impl; import java.io.IOException; import org.apache.commons.lang.StringUtils; import de.codesourcery.jasm16.Address; import de.codesourcery.jasm16.Size; import de.codesourcery.jasm16.disassembler.ByteArrayMemoryAdapter; import de.codesourcery.jasm16.emulator.memory.IMemory; /** * Abstract super-class for floppy disk media implementations. * * <p>Subclasses need to implement {@link #read(byte[], long)} and * {@link #write(byte[], long)}.</p> * * @author tobias.gierke@code-sourcery.de */ public abstract class FloppyDisk { public static final int CAPACITY_IN_WORDS = 737280; public static final int TRACKS = 80; public static final int SECTORS_PER_TRACK = 18; private static final int SECTOR_COUNT = TRACKS * SECTORS_PER_TRACK; public static final int WORDS_PER_SECTOR = 512; private final String identifier; private volatile boolean writeProtected; public FloppyDisk(String identifier,boolean writeProtected) { if (StringUtils.isBlank(identifier)) { throw new IllegalArgumentException("identifier must not be blank/null"); } this.identifier = identifier; this.writeProtected = writeProtected; } public FloppyDisk(String identifier) { this(identifier,false); } @SuppressWarnings("deprecation") public final void readSector(int sector,IMemory target,Address targetAddress) throws IOException { final long byteOffset = sector * 512 * 2; final byte[] buffer = new byte[ WORDS_PER_SECTOR * 2 ]; read( buffer , byteOffset ); final ByteArrayMemoryAdapter mem = new ByteArrayMemoryAdapter( buffer ); // TODO: Requires atomic memory write in IMemoryRegion int len = WORDS_PER_SECTOR; for ( int src = 0 , dst = targetAddress.getWordAddressValue() ; len > 0 ; len-- ) { target.write( dst++ , mem.read( src++ ) ); } } public abstract void read(byte[] buffer,long byteOffset) throws IOException; @SuppressWarnings("deprecation") public final void writeSector(int sector,IMemory source,Address sourceAddress) throws IOException { final long byteOffset = sector * 512 * 2; final byte[] buffer = new byte[ WORDS_PER_SECTOR * 2 ]; final ByteArrayMemoryAdapter mem = new ByteArrayMemoryAdapter( buffer ); // TODO: Requires atomic memory write in IMemoryRegion int len = WORDS_PER_SECTOR; for ( int src = sourceAddress.getWordAddressValue() , dst = 0 ; len > 0 ; len-- ) { mem.write( dst++ , source.read( src++ ) ); } write( buffer , byteOffset ); } public abstract void write(byte[] buffer, long byteOffset ) throws IOException; public boolean isWriteProtected() { return writeProtected; } public void setWriteProtected(boolean writeProtected) { this.writeProtected = writeProtected; } public int getSectorCount() { return SECTOR_COUNT; } public Size getSectorSize() { return Size.words( WORDS_PER_SECTOR ); } @Override public String toString() { return "disk '"+identifier+"'"; } }