/* $Id: I8254Generic.java,v 1.2 2012-07-08 10:40:43 user Exp $ */ package mce.arch; import mce.Cat; import mce.Emulation; import mce.cpu.CPU; import mce.cpu.CPUPlugin; import mce.cpu.ResPlugin; import mce.memory.Memory; import mce.memory.RAM16; import mce.tools.ConfigException; import mce.tools.JDOMUtils; import java.util.Map; /** * MCE Generic I8254 handler. * This module holds a basic handler for I8254 port access. */ public class I8254Generic extends RAM16 implements ResPlugin, CPUPlugin, I8254Listener { // local references private I8254 timer; // local variables private int freqDivisor; private int timerTicksRemaining; /** * MemoryAccess interface: Get memory access type * * @return int containing the implemented memory access type (one of Memory.MEMTYPE_* constants) */ public int getMemoryType() { return Memory.MEMTYPE_OTHER; } /** * Get subname from memory handler for read operation on the given address * * @param addr Address for which to get the name * @return String containing the name (or null if no name was defined) */ public String getReadMemorySubName(int addr) { switch (addr & 3) { case 0: return "cntr0"; case 1: return "cntr1"; case 2: return "cntr2"; case 3: return "cntr?"; } return null; } /** * Get subname from memory handler for write operation on the given address * * @param addr Address for which to get the name * @return String containing the name (or null if no name was defined) */ public String getWriteMemorySubName(int addr) { switch (addr & 3) { case 0: return "cntr0"; case 1: return "cntr1"; case 2: return "cntr1"; case 3: return "cntrc"; } return null; } /** * Get byte from port memory * * @param addr int containing the flat port address * @return int containing the unsigned byte of the requested port */ public int getByte(int addr) { return timer.getPort(addr); // System.out.println("I8254 get pc = " + FormatUtils.toHex( cpu.getRegPC(), 4 ) + ", addr = " + FormatUtils.toHex( addr, 4 ) + ", value " + FormatUtils.toHex( value, 2 ) ); // if( ( addr & 3 ) == 2 ) // System.out.println("timer = " + timer); // return value; } /** * MemoryAccess interface: Set byte to port memory * * @param addr int containing the flat port address * @param value int containing the unsigned byte * @return int containing the spent cpu t-states (in the low byte of the high word) */ public int setByte(int addr, int value) { // System.out.println("I8254 set pc = " + FormatUtils.toHex( cpu.getRegPC(), 4 ) + ", addr = " + FormatUtils.toHex( addr, 4 ) + ", value " + FormatUtils.toHex( value, 2 ) ); timer.setPort(addr, value); return 0; } /** * Processes interrupt generation signal from given counter * * @param counter counter number */ public void processCounterInterrupt(int counter) { } /** * Returns I8254 timer * * @return working timer object */ public I8254 getTimer() { return timer; } /** * Processes specific timer counter * * @param counter counter number * @param ticks number of ticks */ public void processTimer(int counter, int ticks) { timer.processTimer(counter, ticks); } /** * CPUPlugin interface: process routine externally from CPU unit * * @param ticks number of ticks since last method call * @return number of ticks to add to the ticks count */ public int processCPUExternal(int ticks) { int timerTicks = ticks * freqDivisor + timerTicksRemaining; int timerTicksProcessed = timerTicks >> 10; timerTicksRemaining = timerTicks - (timerTicksProcessed << 10); if (timerTicksProcessed > 0) timer.processTimer(0, timerTicksProcessed); return 0; } /** * ResPlugin interface: do reset routine external to CPU unit (called when CPU does a reset) * * @param ticks number of ticks since last method call * @return number of ticks to add to the ticks count */ public int doCPUReset(CPU cpu, int ticks) { timer.doCPUReset(cpu, ticks); timer.setSignalGate(0, false); timer.setSignalGate(1, true); timer.setSignalGate(2, true); timerTicksRemaining = 0; return 0; } /** * Configurable interface: configure according to the given configuration parameters * * @param emu Emulation object used as the object resource * @param config a Map containing the configuration */ public void configure(Emulation emu, Map config) throws ConfigException { // call the ancestor super.configure(emu, config); // get the frequency divisor for CPU Plugin / counter 0 String freqVal = JDOMUtils.getStringParam(config, "freq-divisor"); try { if (freqVal == null) freqVal = "3.2"; freqDivisor = (int) ((1F / Float.parseFloat(freqVal)) * 1024); } catch (NumberFormatException nfe) { throw new ConfigException(this, "freq-divisor", Cat.get("must contain proper timer frequency divisor")); } // create the counter instance and set gate to true for counters 1,2 timer = new I8254(); timer.setSignalGate(0, false); timer.setSignalGate(1, true); timer.setSignalGate(2, true); timer.addListener(this); } }