EventQueue im Logiksimulator

Dramago

Mitglied
Guten Abend,

ich soll einen Logiksimulator implementieren.

Dazu habe ich die Klasse TimingSimulator vorgegeben bekommen. Dazu sollte ich im 1. Schritt eine Klasse Nand und Signal schreiben. Das hat auch alles funktioniert.
Jetzt sollen aber die Signaländerungen eventgesteuert erfolgen, das heißt wenn sich der Ausgangswert eines Logikelements ändert, dann wird ein neues Event erstellt. Dazu soll ich die Klassen Event und EventQueue implementieren, deren Methoden schon teilweise durch TimingSimulator vorgegeben sind.

Ich habe 2 Probleme:

1. Es wird in TimingSimulator der Ausgangszustand berechnet. Dazu werden keine Events erzeugt, sondern die Signalwerte direkt gesetzt. Um das zu implementieren ist mir bis jetzt nur eine, meiner Meinung nach sehr unschöne, Art eingefallen: Ich überlade die Methoden setValue in Signal und update in Nand. Der einzige unterschied besteht nur daraus, dass einmal ein zusätzlicher Parameter übergeben wird. Vielleicht habt ihr eine bessere Möglichkeit dafür?

2. Es fehlt ca. die 2. Hälfte der Ausgabe. Anscheinend werden irgendwann keine neuen Events erzeugt.

Hier mein Code mit Konsolenausgabe. Ich pack ihn in den Spoiler, zwecks Länge und so ;)
Die Klasse TimingSimulator enthält in den Kommentaren keine Umlaute, da die Datei in der Aufgabenstellung mit der falschen Kodierung gespeichert wurde. Sollte aber trotzdem verständlich sein.

Java:
/**
 * Klasse TimingSimulator ist ein Logiksimulator, der nur 
 * Nand-Gatter simulieren kann und Zeitverzgerungen bercksichtigt.
 * Die zu simulierende Schaltung wird in der Methode
 * <CODE>buildCircuit()</CODE> der
 * Klasse erzeugt.
 * Es handelt sich hierbei um ein einfaches RS-FlipFlop.
 * Nach der Konstruktion der Schaltung muss zunchst der Ruhezustand
 * der Schaltung berechnet werden. Dies bernimmt die Methode
 * <CODE>findSteadyState()</CODE>. Die Eingabe-Events zur Stimulation der Schaltung werden durch die Methode
 * <CODE>setInputEvents()</CODE> erzeugt.
 * Zum Testen Ihrer Klassen <CODE>Nand</CODE>, <CODE>Signal</CODE>,
 * <CODE>Event</CODE>,und <CODE>EventQueue</CODE> mssen Sie
 * einfach nur eine Instanz dieser Klasse erzeugen und dann die Methode
 * <CODE>simulate()</CODE> aufrufen.
 * @author Christian Hochberger, TU Dresden
 * @version 1.0 Erste Fassung
 */
public class TimingSimulator {
    // EventQueue fr diesen Simulator, wird im Konstruktor initialisiert
    private EventQueue queue;
    // Die beiden Eingangssignale
    private Signal	inS,inR;
    // Die beiden Ausgangssignale (werden nur bentigt, wenn mann die Ausgnge
    // zwischendurch auch mal ausgeben mhte)
    private Signal oQ,onQ;

    /**
     * Konstruktor, der die zu simulierende Schaltung aufbaut, den Ruhezustand
     * ermittelt und die Eingabe-Events erzeugt.
     * Simuliert wird ein einfaches RS-FlipFlop.
     */
    public TimingSimulator() {
	// Erzeugt die EventQueue fr diesen Simulator
	queue=new EventQueue();

	// Trgt diese EventQueue in ein statisches Feld der Klasse Event ein
	// Dazu muss Event die statische Methode setEventQueue(EventQueue e)
	// besitzen.
	Event.setEventQueue(queue);

	// Schaltung aufbauen
	buildCircuit();

	// Ruhezustand berechnen
	findSteadyState();
	
	// Zum Testen einfach mal den Zustand der Ausgabesignale ausgeben
	System.out.println("Q = "+oQ.getValue());
	System.out.println("nQ = "+onQ.getValue());

	// EventQueue mit Eingabe-Events fllen
	setInputEvents();
    }

    /**
     * Diese Methode konstruiert die Schaltung. Die erzeugten Gatter und die
     * inneren Signale sind nur in dieser Methode bekannt, da sie im Verlauf
     * der Simulation implizit durch die Events, bzw. die Signale angesprochen
     * werden. 
     */
    private void buildCircuit() {
	Signal s1,s2,s3,s4;
	Nand n1,n2,n3,n4,n5,n6;

	// Alle Signale anlegen
	// Der Konstruktor bekommt einen Signalnamen als Parameter
	inS=new Signal("S");
	inR=new Signal("R");
	// Die Signale oQ und onQ sind mit keinen weiteren Gattern verbunden.
	// Sorgen Sie dafr, dass in diesem Fall eine Wertnderung dieser
	// Signale ausgegeben wird.
	oQ=new Signal("Q");
	onQ=new Signal("nQ");
	s1=new Signal("s1");
	s2=new Signal("s2");
	s3=new Signal("s3");
	s4=new Signal("s4");

	// Alle Gatter anlegen
	// Parameter des Konstruktors sind die Anzahl von Eingngen und
	// die Verzgerungszeit
	// Die Inverter sind sozusagen entartete Nand-Gatter (1 Eingang)
	n1=new Nand(1,5);
	n2=new Nand(1,5);
	n3=new Nand(2,10);
	n4=new Nand(2,10);
	n5=new Nand(1,5);
	n6=new Nand(1,5);

	// Inverter mit Ein- und Ausgngen verbinden.
	// Die Methode setInput() des Gatters bekommt die Nummer des Eingangs
	// und das Signal, mit dem dieser Eingang verbunden werden soll.
	n1.setInput(0,inR);
	// Die Methode setOutput() bekommt nur ein Signal, welches durch diesen
	// Ausgang bestimmt wird
	n1.setOutput(s1);
	n2.setInput(0,inS);
	n2.setOutput(s2);

	// Die Nand-Gatter des FlipFlops richtig verbinden
	n3.setOutput(s3);
	n3.setInput(0,s1);
	n3.setInput(1,s4);
	n4.setOutput(s4);
	n4.setInput(0,s2);
	n4.setInput(1,s3);

	// Die Ausgangs-Inverter verbinden.
	n5.setOutput(oQ);
	n5.setInput(0,s3);
	n6.setOutput(onQ);
	n6.setInput(0,s4);
    }

    /**
     * Diese Methode ermittelt den Ruhezustand der Schaltung. Dazu werden
     * vernnftige Initialwerte an die Eingnge angelegt. Diese Initialwerte
     * mssen mindestens einmal durch die Schaltung propagiert werden,
     * bis sich ein stabiler Zustand einstellt. Um das festzustellen gibt
     * es verschiedene Methoden (im Gatter mitzhlen, wie oft sich der Wert
     * ndert. Im Signal mitzhlen, wie oft es gendert wurde).
     * Bei diesem Propagieren darf natrlich nicht mit den Zeitverzgerungen
     * gearbeitet werden.  Sie knnen also im Grunde die Wert-Propagierung
     * aus der ersten Teilaufgabe benutzen.
     */
    private void findSteadyState() {
	inS.setValue(false);
	inR.setValue(false);
    }

    /**
     * Diese Methode erzeugt eine Reihe von Eingabe-Events, die dann zur
     * Stimulation der Schaltung dienen.  Die Events werden durch ihren
     * eigenen Konstruktor in die EventQueue eingetragen, so dass hier nur
     * das Erzeugen der Events zu sehen ist.
     * Jedes Event bekommt beim Erzeugen das betroffene Signal, den Zeitpunkt
     * und den <bold>neuen Wert</bold> mit.
     */
    private void setInputEvents() {
	new Event(inS, 10, true);
	new Event(inS, 30, false);
	new Event(inR, 50, true);
	new Event(inR, 100, false);
	new Event(inS, 120, true);
	new Event(inR, 150, true);
	new Event(inS, 170, false);
	new Event(inR, 180, false);
    }

    /**
     * Diese Methode fhrt die eigentliche Simulation durch. Dazu wird
     * geprft, ob in der EventQueue noch weitere Events vorhanden sind. Ist
     * dies der Fall, dann wird das nchste anstehende Event behandelt. Dazu
     * muss das Event die Methode propagate() zur Verfgung stellen, die
     * dann das betroffene Signal informiert.
     */
    public void simulate() {
	while (queue.hasMore()) {
	    Event e=queue.getFirst();

	    //System.out.println(e);
	    e.propagate();
	}
    }
    
    /**
     * Main Methode dieser Klasse. Sie mssen das im Moment noch nicht
     * verstehen. Diese Methode wird bentigt, wenn Sie den Simulator ohne
     * BlueJ laufen lassen wollen. Wenn Sie diese Klasse in BlueJ nutzen,
     * dann ignorieren Sie diese Methode einfach.
     */
    static public void main(String[] args) {
	TimingSimulator	t=new TimingSimulator();
	t.simulate();
    }
}
Java:
import java.util.ArrayList;
/**
 * Write a description of class Signal here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Signal
{
    // instance variables - replace the example below with your own
    private String name;
    
    private boolean value;
    
    private ArrayList<Nand> signalEnds;
    
    /**
     * Constructor for objects of class Signal
     */
    public Signal(String name)
    {
        
        this.name = name;
        value = false;
        signalEnds = new ArrayList<Nand>();
        
    }

    public void setValue(boolean value)
    {
        this.value = value;
        if(signalEnds.isEmpty())
        {
            System.out.println(name + " -> " + value);
        }
        else
        {
            for(Nand signalEnd : signalEnds)
            {
                signalEnd.update();
            }
        }
    }
    
    public void setValue(boolean value, int time)
    {
        this.value = value;
        if(signalEnds.isEmpty())
        {
            System.out.println(name + " -> " + value);
        }
        else
        {
            for(Nand signalEnd : signalEnds)
            {
                signalEnd.update(time);
            }
        }
    }
    
    public boolean getValue()
    {
        return value;
    }   
    
    
    public void addSignalEnd(Nand nand)
    {
        signalEnds.add(nand);
    }
}
Java:
/**
 * Write a description of class Nand here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Nand
{
    // instance variables - replace the example below with your own
    private int maxInputs;
    
    private Signal[] inputSignals;
    
    private Signal outputSignal;
    
    private int delay;
    
    /**
     * Constructor for objects of class Nand
     */
    public Nand(int maxInputs, int delay)
    {
        
        this.maxInputs = maxInputs;
        inputSignals = new Signal[maxInputs];
        this.delay = delay;
       
    }

    public void setInput(int numInput, Signal input)
    {
        inputSignals[numInput] = input;
        inputSignals[numInput].addSignalEnd(this);
    }   
    
    public void setOutput(Signal output)
    {
        outputSignal = output;
    }
    
    public void update()
    {   
                       
        for(int numInput = 0; numInput < maxInputs; numInput++) 
        {
            if(inputSignals[numInput].getValue() == false) 
            {
                if(outputSignal.getValue() != true)
                {
                    outputSignal.setValue(true);
                }  
                return;
            }
        }
        
        if(outputSignal.getValue() != false)
                {
                    outputSignal.setValue(false);
                }  
    }
    
    public void update(int time)
    {   
                       
        for(int numInput = 0; numInput < maxInputs; numInput++) 
        {
            if(inputSignals[numInput].getValue() == false) 
            {
                if(outputSignal.getValue() != true)
                {
                    new Event(outputSignal, time + delay, true);
                }  
                return;
            }
        }
        
        if(outputSignal.getValue() != false)
                {
                    new Event(outputSignal, time + delay, false);
                }  
    }
}
Java:
/**
 * Write a description of class Event here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Event
{
    // instance variables - replace the example below with your own
    private static EventQueue queue;
    
    private Signal signal;
    
    private int time;
    
    private boolean newValue;

    /**
     * Constructor for objects of class Event
     */
    public Event(Signal signal, int time, boolean newValue)
    {
       this.signal = signal;
       this.time = time;
       this.newValue = newValue;
        
       queue.addEvent(this);
    }
    
    public static void setEventQueue(EventQueue q)
    {
        queue = q;
    }
    
    public void propagate()
    {
        signal.setValue(newValue, time);
    }
    
    public int getTime()
    {
        return time;
    }
}
Java:
import java.util.*;
/**
 * Write a description of class EventQueue here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class EventQueue
{
    // instance variables - replace the example below with your own
    
    private LinkedList<Event> queue;
    
    private ListIterator<Event> iterator;
    
    private LinkedList<Event> bufferQueue;
    
    /**
     * Constructor for objects of class EventQueue
     */
    public EventQueue()
    {
        queue = new LinkedList<Event>();
        bufferQueue = new LinkedList<Event>(queue);
        iterator = bufferQueue.listIterator();
    }

    public void addEvent(Event event)
    {
        while(iterator.hasNext() && (event.getTime() > iterator.next().getTime()));
        //> bei gleichheit der Zeiten dahinter
        
        if(!iterator.hasNext()) 
        {
                queue.add(iterator.nextIndex(), event);
        }
        else
        {
            iterator.previous();
            queue.add(iterator.nextIndex(), event);
        }
    }
    
    public boolean hasMore()
    {
        return !queue.isEmpty();
    }
    
    public Event getFirst()
    {
        return queue.removeFirst();
    }
}
Code:
nQ -> true
Q = false
nQ = true
nQ -> false
Q -> true
Q -> false
nQ -> true
nQ -> false

Vielen Dank schonmal,
Dramago
 

Neue Themen


Oben