git @ Cat's Eye Technologies JaC64 / master com / dreamfabric / jac64 / ExtChip.java
master

Tree @master (Download .tar.gz)

ExtChip.java @masterraw · history · blame

/**
 * This file is a part of JaC64 - a Java C64 Emulator
 * Main Developer: Joakim Eriksson (Dreamfabric.com)
 * Contact: joakime@sics.se
 * Web: http://www.dreamfabric.com/c64
 * ---------------------------------------------------
 */

package com.dreamfabric.jac64;

import java.util.Hashtable;

/**
 * ExtChip - used for implementing HW Chips connected to the
 * CPU.
 * handles IRQs/NMIs for all the implemented CPU/IO chips
 * and defines some APIs that is called by CPU
 *
 *
 * Created: Tue Aug 02 08:58:12 2005
 *
 * @author Joakim Eriksson
 * @version 1.0
 */
public abstract class ExtChip {

  public static final boolean DEBUG_INTERRUPS = false;

  // C64 specific names - but... basically just numbers
  public static final int VIC_IRQ = 1;
  public static final int CIA_TIMER_IRQ = 2;
  public static final int KEYBOARD_NMI = 1;
  public static final int CIA_TIMER_NMI = 2;

  // One InterruptManager per named CPU.
  private static Hashtable<String, InterruptManager> managers = 
    new Hashtable<String, InterruptManager>();
  MOS6510Core cpu;
  private Observer observer;
  private InterruptManager im;
  
  public void init(MOS6510Core cpu) {
    this.cpu = cpu;
    if (managers.get(cpu.getName()) == null) {
        System.out.println("creating new IM...");
        managers.put(cpu.getName(), new InterruptManager(cpu));
    }
    im = (InterruptManager) managers.get(cpu.getName());
  }

  public void deleteInterruptManagers() {
    managers = new Hashtable<String, InterruptManager>();
  }

  public int getNMIFlags() {
    return im.nmiFlags;
  }

  public int getIRQFlags() {
    return im.irqFlags;
  }

  public boolean setIRQ(int irq) {
    return im.setIRQ(irq);
  }
  
  public void clearIRQ(int irq) {
    im.clearIRQ(irq);
  }
  
  public boolean setNMI(int nmi) {
    return im.setNMI(nmi);
  }
  
  public void clearNMI(int nmi) {
    im.clearNMI(nmi);
  }
  
  public void resetInterrupts() {
    im.reset();
  }

  
  public abstract void reset();
  public abstract void stop();

  public abstract int performRead(int address, long cycles);
  public abstract void performWrite(int address, int data, long cycles);
  public abstract void clock(long cycles);

  public void setObserver(Observer o) {
    observer = o;
  }

  public void update(Object source, Object data) {
    if (observer != null) {
      observer.update(source, data);
    }
  }
  
  private static class InterruptManager {
    int nmiFlags;
    int irqFlags;
    int oldIrqFlags;
    int oldNmiFlags;
    MOS6510Core cpu;
    
    InterruptManager(MOS6510Core cpu) {
      this.cpu = cpu;
    }

    private void reset() {
      nmiFlags = 0;
      irqFlags = 0;
      oldIrqFlags = 0;
      oldNmiFlags = 0;
      cpu.setIRQLow(false);
      cpu.setNMILow(false);
      cpu.log("ExtChip: Resetting IRQ flags!");
    }
    
    public boolean setIRQ(int irq) {
    	boolean val = (irqFlags & irq) == 0;
    	irqFlags |= irq;
    	if (irqFlags != oldIrqFlags) {
    		if (DEBUG_INTERRUPS && irqFlags != 0 && cpu.debug) {
    			cpu.log("ExtChips: Setting IRQ! " + irq + " => " + irqFlags +  " at " + cpu.cycles);
    		}
    		cpu.setIRQLow(irqFlags != 0);
    		oldIrqFlags = irqFlags;
    	}
    	return val;
    }

    public void clearIRQ(int irq) {
    	irqFlags &= ~irq;
    	if (irqFlags != oldIrqFlags) {
    		if (DEBUG_INTERRUPS && oldIrqFlags != 0 && cpu.debug) {
    			System.out.println("Clearing IRQ! " + irq + " => " + irqFlags +  " at " + cpu.cycles);
    		}
    		cpu.setIRQLow(irqFlags != 0);
    		oldIrqFlags = irqFlags;
    	}
    }

    public boolean setNMI(int nmi) {
      boolean val = (nmiFlags & nmi) == 0;
      nmiFlags |= nmi;
      if (nmiFlags != oldNmiFlags) {
        if (DEBUG_INTERRUPS && cpu.debug)
          System.out.println("Setting NMI! " + nmi + " => " + nmiFlags +  " at " + cpu.cycles);
        cpu.setNMILow(nmiFlags != 0);
        oldNmiFlags = nmiFlags;
      }
      return val;
    }


    public void clearNMI(int nmi) {
      nmiFlags &= ~nmi;
      if (nmiFlags != oldNmiFlags) {
        if (DEBUG_INTERRUPS && oldNmiFlags != 0 && cpu.debug) {
          System.out.println("Clearing NMI! " + nmi + " => " + nmiFlags +  " at " + cpu.cycles);
        }
        cpu.setNMILow(nmiFlags != 0);
        oldNmiFlags = nmiFlags;
      }
    }
  }
}