/**
* 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;
}
}
}
}