/* * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ package jace.hardware; import jace.apple2e.MOS65C02; import jace.core.Computer; import jace.core.RAM; import jace.hardware.massStorage.CardMassStorage; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; /** * Generic abstraction of a smartport device. * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ public abstract class SmartportDriver { Computer computer; public SmartportDriver(Computer computer) { this.computer = computer; } public static enum ERROR_CODE { NO_ERROR(0), INVALID_COMMAND(0x01), BAD_PARAM_COUNT(0x04), INVALID_UNIT(0x011), INVALID_CODE(0x021), BAD_BLOCK_NUMBER(0x02d); int intValue; ERROR_CODE(int c) { intValue = c; } } public void handleSmartport() { int returnCode = callSmartport().intValue; MOS65C02 cpu = (MOS65C02) computer.getCpu(); cpu.A = returnCode; // Clear carry flag if no error, otherwise set carry flag cpu.C = (returnCode == 0x00) ? 00 : 01; } private ERROR_CODE callSmartport() { MOS65C02 cpu = (MOS65C02) computer.getCpu(); RAM ram = computer.getMemory(); int callAddress = cpu.popWord() + 1; int command = ram.readRaw(callAddress); boolean extendedCall = command >= 0x040; // command &= 0x0f; // Modify stack so that RTS goes to the right place after the smartport device call //cpu.pushWord(callAddress + (extendedCall ? 5 : 3)); // Kludge due to the CPU not getting the faked RTS opcode cpu.setProgramCounter(callAddress + (extendedCall ? 5 : 3)); // Calculate parameter address block int parmAddr; if (!extendedCall) { parmAddr = ram.readWordRaw(callAddress + 1); } else { // Extended calls -- not gonna happen on this platform anyway int parmAddrLo = ram.readWordRaw(callAddress + 1); int parmAddrHi = ram.readWordRaw(callAddress + 3); parmAddr = parmAddrHi << 16 | parmAddrLo; } // Now process command System.out.println("Received command " + command + " with address block " + Integer.toHexString(parmAddr)); byte numParms = ram.readRaw(parmAddr); int[] params = new int[16]; for (int i = 0; i < 16; i++) { int value = 0x0ff & ram.readRaw(parmAddr + i); params[i] = value; System.out.print(Integer.toHexString(value) + " "); } System.out.println(); int unitNumber = params[1]; if (!changeUnit(unitNumber)) { System.out.println("Invalid unit: "+unitNumber); return ERROR_CODE.INVALID_UNIT; } int dataBuffer = params[2] | (params[3] << 8); try { switch (command) { case 0: //Status return returnStatus(dataBuffer, params); case 1: //Read Block int blockNum = params[4] | (params[5] << 8) | (params[6] << 16); read(blockNum, dataBuffer); return ERROR_CODE.NO_ERROR; // System.out.println("reading "+blockNum+" to $"+Integer.toHexString(dataBuffer)); case 2: //Write Block blockNum = params[4] | (params[5] << 8) | (params[6] << 16); write(blockNum, dataBuffer); return ERROR_CODE.NO_ERROR; case 3: //Format case 4: //Control case 5: //Init case 6: //Open case 7: //Close case 8: //Read case 9: //Write default: System.out.println("Unimplemented command "+command); return ERROR_CODE.INVALID_COMMAND; } } catch (IOException ex) { Logger.getLogger(CardMassStorage.class.getName()).log(Level.SEVERE, null, ex); return ERROR_CODE.INVALID_CODE; } } abstract public boolean changeUnit(int unitNumber); abstract public void read(int blockNum, int buffer) throws IOException; abstract public void write(int blockNum, int buffer) throws IOException; abstract public ERROR_CODE returnStatus(int dataBuffer, int[] params); }