package ckelling.baukasten;

import java.applet.*;
import java.awt.*;
import java.lang.*;
import java.util.*;
/* import java.io.*; */
import java.net.*;


// Versionsgeschichte
// 0.1.9,  05.03.97
// 0.1.9a, 19.04.97
// 0.2.0,  21.05.97
// 0.2.1,  29.06.97

/**
 *  Pipeline_1.java
 *
 *  Erster Aufbau zur Verdeutlichung von Pipelining
 *  nach Hennessy/Patterson
 *
 *  @author   Carsten Kelling
 *  @version  0.2.1, 29.06.97
 */
public class Pipeline_1 extends Rechner
{
    public final static String VERSIONSTRING = "Pipeline-1 0.2.1";

	// Moegliche Werte fuer c_state stehen nun
	// in der Klasse "Rechner"

	///// Konstanten Ende /////


	//private String			INSTRUCTIONS = "mips_instructions";
	public	String			INSTRUCTIONS = "mips_single";
	private String			DATA = "3address";
	private String			REGISTERS = "mips_random";

	private Color			READ_COLOR;
	private Color			WRITE_COLOR;

	private Vector			elements;


//// Komponenten Anfang ////
	private SimpleBus		instructionMem_abus;
	private SimpleBus		instructionMem_dbus;
	private SimpleBus		pcInc_lowerInput;
	private SimpleBus		pcInc_output;
	private SimpleBus		pc_input;
	private SimpleBus		registers_abus;
	private SimpleBus		registers_output1;
	private SimpleBus		registers_output2;
	private SimpleBus		id_signExtended;
	private SimpleBus		id_pc;
	private SimpleBus		alu_upperInput;
	private SimpleBus		alu_lowerInput;
	private SimpleBus		addressAlu_lowerInput;
	private SimpleBus		addressAlu_output;
	private SimpleBus		ex_data2;
	private SimpleBus		ex_signExtended;
	private SimpleBus		ex_aluResult;
	private SimpleBus		ex_zeroFlag;
	private SimpleBus		ex_pc;
	private SimpleBus		ex_writeRegister;
	private SimpleBus		dataMem_abus;
	private SimpleBus		dataMem_output;
	private SimpleBus		dataMem_input;
	private SimpleBus		mem_zeroFlag;
	private SimpleBus		mem_addResult;
	private SimpleBus		mem_writeRegister;
	private SimpleBus		wbMux_upperInput;
	private SimpleBus		wbMux_lowerInput;
	private SimpleBus		wbMux_output;
	private SimpleBus		wb_writeRegister;

	private EditableMemory	instructionMem;
	private EditableMemory	registers;
	private EditableMemory	dataMem;

	private PipelineStageLabel	if_label;
	private PipelineStageLabel	id_label;
	private PipelineStageLabel	ex_label;
	private PipelineStageLabel	mem_label;
	private PipelineStageLabel	wb_label;

	private PipelineRegister	pre_if;
	private PipelineRegister	if_id;
	private PipelineRegister	id_ex;
	private PipelineRegister	ex_mem;
	private PipelineRegister	mem_wb;

	private Register16		pc;

	private Mux				pcMux;
	private Mux				aluMux;
	private Mux				wbMux;

	private Misc			signExtender;
	private Misc			shifter;

	private ALU				pcInc;
	private ALU				addressAlu;
	private ALU				alu;
//// Komponenten Ende ////

    private Pipeline_1_Control  pipeline_1_Control;
	//NHT private DescriptionLibrary	descriptionLibrary;
	//NHT private RTFTextArea		helpText;


	public String getAppletInfo()
	{
		return "Pipelining-Aufbau Nr. 1";
	}

	public String getVersionString()
	{
		return VERSIONSTRING;
	}


	public void init()
	{
		System.out.println(VERSIONSTRING);
		System.out.println("Initialisierung - Anfang");

		initialize(new Dimension(1012, 514), new Dimension(1012, 514)); // defined in class Rechner

		Point coord;
		Point coord2;
		int stringWidth;
		int stringHeight = getHeight(DIALOGFONT);

	//// Breite der Busse ////
		LINEWIDTH = 3;
		STRIPEWIDTH = 6;

	//// Farben ////
		REG_COLOR_ACTIVATED = MIPS_COLOR;
		ALU_COLOR_ACTIVATED = MIPS_COLOR;
		MEM_COLOR_ACTIVATED = Color.blue;
		READ_COLOR = MEM_COLOR_ACTIVATED;
		WRITE_COLOR = Color.red;


		elements = new Vector(55, 5);
        pipeline_1_Control = new Pipeline_1_Control(this);
        pipeline_1_Control.setTitle("Pipeline steuern");
        add (pipeline_1_Control);
		//double faktor = SMALLFONTSIZE / (double) NORMALFONTSIZE;
        //pipeline_1_Control.resize((int) (295*faktor), (int) (150*faktor));

		//NHT coord = clockBus.getCoordinates("end");
		//NHT coord.translate(0, CONTROLHEIGHT + LINEWIDTH);
		//NHT helpText = new RTFTextArea(SMALLFONT, 4, 70);

		//NHT helpText.setText("Hier werden Hilfetexte erscheinen.");
		//NHT helpText.move(0, coord.y + 20);
		//NHT helpText.resize(WIDTH, HEIGHT - coord.y - 20);
		//NHT descriptionLibrary = new DescriptionLibrary();


	//// Testaufbau ////
		int aluWidth = 50;
		int pipRegWidth = 20;
		int pipRegHeight = 300;
		int pipStageLabelHeight = 30;
		int pipStageLabelGap = 0;
		int muxWidth = 30;
		int muxHeight = 40;
		int gap = 15;
		int busFlags = SimpleBus.WITH_SOLDER_DOTS;


	//// IF ////
		pc = new Register16("PC", gap + LINEWIDTH, 240 + pipStageLabelHeight + pipStageLabelGap, 20, 40, "left", (Rechner) this);
		elements.addElement(new Editor_Source(pc));
		//add(pc); pc.show();

		coord = pc.getCoordinates("right");
		instructionMem_abus = new SimpleBus("", coord.x, coord.y, gap*2, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(instructionMem_abus));

		coord = instructionMem_abus.getCoordinates("end");
		instructionMem = new EditableMemory("", coord.x, coord.y - gap, 1, 8, MIPS_INSTRUCTION_MEM_SIZE, 32, (Rechner) this);
		// Format:                         (    x,       y,             Zellen x,                        Speicherbreite,   )
		//                                  Titel,                         Zellen y,                         Verweis auf dieses Objekt
		//                                                                    Speichergroesse,
		add(instructionMem.getRessource()); (instructionMem.getRessource()).show();
		instructionMem.setOpcodesSupported(false);
		elements.addElement(new Editor_Source(instructionMem));

		coord = instructionMem.getCoordinates("right");
		instructionMem_dbus = new SimpleBus("", coord.x, coord.y, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(instructionMem_dbus));

		coord = instructionMem_dbus.getCoordinates("end");
		int pipRegTop = coord.y;
		if_id = new PipelineRegister("IF/ID", coord.x, pipRegTop, pipRegWidth, pipRegHeight, "left", (Rechner) this);
		elements.addElement(new Editor_Source(if_id));
		pre_if = new PipelineRegister("before IF", 0, 0, 0, 0, "left", (Rechner) this);
		elements.addElement(new Editor_Source(pre_if));
		//coord = if_id.getCoordinates("bottom");
		//if_label = new PipelineStageLabel("", "Instruction fetch", 0, coord.y + pipStageLabelGap, coord.x, pipStageLabelHeight, "left", (Rechner) this);
		coord = if_id.getCoordinates("top");
		if_label = new PipelineStageLabel("", "Instruction fetch", 0, 0, coord.x, pipStageLabelHeight, "leftTop", (Rechner) this);
		elements.addElement(new Editor_Source(if_label));

		coord = if_id.getCoordinates("top");
		coord2 = if_id.getCoordinates("left");
		coord = new Point(coord2.x, coord.y);  // "leftTop"
		pcInc_output = new SimpleBus("", coord.x - 3*gap, coord.y + gap, 3*gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(pcInc_output));

		coord = pcInc_output.getCoordinates("start");
		stringWidth = stringWidth(DIALOGFONT, "Add") + 10;
		int pcIncHeight = 60;
		pcInc = new ALU("Add", coord.x, coord.y, stringWidth, pcIncHeight, "output", ">", (Rechner) this);
		elements.addElement(new Editor_Source(pcInc));

		coord = pcInc.getCoordinates("lowerInput");
		pcInc_lowerInput = new SimpleBus("4", coord.x - 2*gap, coord.y, 2*gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(pcInc_lowerInput));

		coord = pcInc.getCoordinates("upperInput");
		coord2 = instructionMem_abus.getCoordinates("start");
		coord.translate(-coord2.x, -coord2.y);
		instructionMem_abus.addEdge("pcInc", gap, 0, 0, coord.y, coord.x - gap, 0);

		coord = pcInc.getCoordinates("upperInput");
		pcMux = new Mux("Mux", coord.x, coord.y - pcIncHeight/6 - 3*gap - Mux.CORNER_RADIUS, muxWidth, muxHeight, "lowerInput", (Rechner) this);
		elements.addElement(new Editor_Source(pcMux));

		coord = pcMux.getCoordinates("upperInput");
		coord2 = pcInc_output.getCoordinates("start");
		coord.translate(-coord2.x, -coord2.y);
		pcInc_output.addEdge("pcMux", gap, 0, 0, - pcIncHeight/2 - 2*gap, coord.x - 3*gap, 0, 0, coord.y + pcIncHeight/2 + 2*gap, 2*gap, 0);

		coord = pcMux.getCoordinates("output");
		pc_input = new SimpleBus("", coord.x, coord.y, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(pc_input));

		coord = pc.getCoordinates("left");
		coord2 = pc_input.getCoordinates("end");
		coord.translate(-coord2.x, -coord2.y);
		pc_input.addEdge("pc", gap - LINEWIDTH, 0,
		                     0, - muxHeight/2 - 2*gap,
		                     coord.x - gap, 0,
		                     0, coord.y + muxHeight/2 + 2*gap,
		                     gap + LINEWIDTH, 0);
		pc_input.setFlag("pc", SimpleBus.NONE);


	//// ID ////
		coord = if_id.getCoordinates("right");
		registers_abus = new SimpleBus("", coord.x + gap, coord.y - pipRegHeight/4, 0, (5*pipRegHeight)/8, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(registers_abus));
		coord2 = registers_abus.getCoordinates("start");
		registers_abus.addEdge("if_id", 0, coord.y - coord2.y,	-gap,	0);
		registers_abus.addEdge("read1", 0, 0,					3*gap,	0);
		registers_abus.addEdge("read2", 0, 20,					3*gap,	0);
		coord = registers_abus.getCoordinates("end");
		registers_abus.addEdge("signExtender", 0, coord.y - coord2.y - 10 - LINEWIDTH - 1, 6*gap, 0);

		coord = registers_abus.getCoordinates("read1");
		registers = new EditableMemory("", coord.x, coord.y - gap, 1, 8, MIPS_NUMBER_OF_REGISTERS, 32, (Rechner) this);
		elements.addElement(new Editor_Source(registers));
		// Format:                    (    x,       y,             Zellen x,                       Speicherbreite,   )
		//                             Titel,                         Zellen y,                        Verweis auf dieses Objekt
		//                                                               Speichergroesse,
		registers.setOpcodesSupported(false);
		add(registers.getRessource()); (registers.getRessource()).show();

		coord = registers.getCoordinates("rightTop");
		coord2 = registers.getCoordinates("rightBottom");
		coord2.translate(-coord.x, -coord.y);
		String[] reTitle1 = {"Read", "data 1"};
		stringWidth = stringWidth(DIALOGFONT, reTitle1[1]) + 20;
		registers_output1 = new SimpleBus(reTitle1, coord.x, coord.y + coord2.y/4, stringWidth, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(registers_output1));
		registers_output1.setLabelPosition("start", "top");
		String[] reTitle2 = {"Read", "data 2"};
		registers_output2 = new SimpleBus(reTitle2, coord.x, coord.y + (3*coord2.y)/4, stringWidth, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(registers_output2));
		registers_output2.setLabelPosition("start", "bottom");

		coord = registers_abus.getCoordinates("signExtender");
		String[] seTitle = {"Sign", "Extend"};
		signExtender = new Misc(seTitle, coord.x, coord.y, 55, 60, "left", (Rechner) this);
		elements.addElement(new Editor_Source(signExtender));
		coord = signExtender.getCoordinates("right");
		coord2 = registers_output1.getCoordinates("end");
		coord2.translate(-coord.x, -coord.y);
		id_signExtended = new SimpleBus("32", coord.x, coord.y, coord2.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(id_signExtended));

		coord = registers_output1.getCoordinates("end");
		id_ex = new PipelineRegister("ID/EX", coord.x, pipRegTop, pipRegWidth, pipRegHeight, "left", (Rechner) this);
		elements.addElement(new Editor_Source(id_ex));
		coord = id_ex.getCoordinates("top");
		coord2 = if_id.getCoordinates("top");
		//id_label = new PipelineStageLabel("", "Instruction decode", coord2.x, coord2.y + pipStageLabelGap, coord.x - coord2.x, pipStageLabelHeight, "left", (Rechner) this);
		id_label = new PipelineStageLabel("", "Instruction decode", coord2.x, 0, coord.x - coord2.x, pipStageLabelHeight, "leftTop", (Rechner) this);
		elements.addElement(new Editor_Source(id_label));

		coord = registers_abus.getCoordinates("start");
		coord2 = registers_abus.getCoordinates("end");
		int y1 = coord2.y - coord.y;
		coord = new Point(id_ex.getCoordinates("left").x, id_ex.getCoordinates("bottom").y);  // "leftBottom"
		coord.translate(-coord2.x, -coord2.y);
		registers_abus.addEdge("id_ex", 0, y1 - LINEWIDTH - 1, 0, coord.y - gap + LINEWIDTH + 1, coord.x, 0);
		registers_abus.setFlag("id_ex", SimpleBus.NONE);

		coord = pcInc_output.getCoordinates("end");
		coord = new Point(if_id.getCoordinates("right").x, coord.y);
		coord2 = id_ex.getCoordinates("left");
		id_pc = new SimpleBus("", coord.x, coord.y, coord2.x - coord.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(id_pc));


	//// EX ////
		coord = registers_output1.getCoordinates("end");
		coord2 = id_ex.getCoordinates("right");
		alu_upperInput = new SimpleBus("", coord2.x, coord.y, 4*gap + muxWidth, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(alu_upperInput));

		coord = registers_output2.getCoordinates("end");
		ex_data2 = new SimpleBus("", coord2.x, coord.y, 3*gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(ex_data2));

		coord = id_signExtended.getCoordinates("end");
		int length1 = 165;
		ex_signExtended = new SimpleBus("", coord2.x + 2*gap, coord.y - length1 + LINEWIDTH, 0, length1, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(ex_signExtended));
		ex_signExtended.addEdge("signExtender", 0, length1 - LINEWIDTH, -2*gap, 0);
		ex_signExtended.setFlag("signExtender", SimpleBus.NONE);

		coord = ex_signExtended.getCoordinates("start");
		String[] sTitle = {"Shift", "left 2"};
		shifter = new Misc(sTitle, coord.x, coord.y, 45, 55, "bottom", (Rechner) this);
		elements.addElement(new Editor_Source(shifter));

		coord = shifter.getCoordinates("right");
		addressAlu_lowerInput = new SimpleBus("", coord.x, coord.y, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(addressAlu_lowerInput));

		coord = id_pc.getCoordinates("end");
		coord = new Point(id_ex.getCoordinates("right").x, coord.y);
		coord2 = addressAlu_lowerInput.getCoordinates("end");
		ex_pc = new SimpleBus("", coord.x, coord.y, coord2.x - coord.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(ex_pc));

		coord = ex_pc.getCoordinates("end");
		coord2 = addressAlu_lowerInput.getCoordinates("end");
		addressAlu = new ALU("Add", coord.x, coord.y, aluWidth, (3*(coord2.y - coord.y))/2, "upper", ">", (Rechner) this);
		// ALU habe Breite 'aluWidth' und Hoehe entsprechend dem vertikalen Abstand ihrer beiden Eingaenge
		elements.addElement(new Editor_Source(addressAlu));

		coord = ex_data2.getCoordinates("end");
		aluMux = new Mux("Mux", coord.x, coord.y, muxWidth, muxHeight, "upperInput", (Rechner) this);
		elements.addElement(new Editor_Source(aluMux));

		coord = aluMux.getCoordinates("lowerInput");
		coord2 = ex_signExtended.getCoordinates("start");
		coord.translate(-coord2.x, -coord2.y);
		ex_signExtended.addEdge("aluMux", 0, coord.y, coord.x, 0);

		coord = aluMux.getCoordinates("output");
		alu_lowerInput = new SimpleBus("", coord.x, coord.y, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(alu_lowerInput));

		coord = alu_upperInput.getCoordinates("end");
		coord2 = alu_lowerInput.getCoordinates("end");
		alu = new ALU("ALU", coord.x, coord.y, aluWidth, (3*(coord2.y - coord.y))/2, "upper", ">", (Rechner) this);
		// ALU habe Breite 'aluWidth' und Hoehe entsprechend dem vertikalen Abstand ihrer beiden Eingaenge
		elements.addElement(new Editor_Source(alu));

		coord = alu.getCoordinates("output");
		String[] arTitle = {"ALU", "result"};
		stringWidth = stringWidth(DIALOGFONT, arTitle[1]) + 20;
		ex_aluResult = new SimpleBus(arTitle, coord.x, coord.y + stringHeight, stringWidth, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(ex_aluResult));
		ex_aluResult.setLabelPosition("start", "bottom");
		ex_zeroFlag = new SimpleBus("Zero", coord.x, coord.y - stringHeight, stringWidth, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(ex_zeroFlag));
		ex_zeroFlag.setLabelPosition("start", "top");

		coord = ex_aluResult.getCoordinates("end");
		ex_mem = new PipelineRegister("EX/MEM", coord.x, pipRegTop, pipRegWidth, pipRegHeight, "left", (Rechner) this);
		elements.addElement(new Editor_Source(ex_mem));
		coord = ex_mem.getCoordinates("top");
		coord2 = id_ex.getCoordinates("top");
		//ex_label = new PipelineStageLabel("", "Execution", coord2.x, coord2.y + pipStageLabelGap, coord.x - coord2.x, pipStageLabelHeight, "left", (Rechner) this);
		ex_label = new PipelineStageLabel("", "Execution", coord2.x, 0, coord.x - coord2.x, pipStageLabelHeight, "leftTop", (Rechner) this);
		elements.addElement(new Editor_Source(ex_label));

		coord = new Point(id_ex.getCoordinates("right").x, id_ex.getCoordinates("bottom").y);  // rightBottom
		coord2 = ex_mem.getCoordinates("left");
		ex_writeRegister = new SimpleBus("", coord.x, coord.y - gap, coord2.x - coord.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(ex_writeRegister));

		coord = ex_mem.getCoordinates("left");
		coord2 = ex_data2.getCoordinates("start");
		coord.translate(-coord2.x, -coord2.y);
		ex_data2.addEdge("ex_mem", gap, 0, 0, muxHeight + 2*gap, coord.x - gap, 0);

		coord = addressAlu.getCoordinates("output");
		coord2 = ex_mem.getCoordinates("left");
		String aaoTitle[] = {"Add", "result"};
		addressAlu_output = new SimpleBus(aaoTitle, coord.x, coord.y, coord2.x - coord.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(addressAlu_output));
		addressAlu_output.setLabelPosition("end", "top");


	//// MEM ////
		coord = new Point(ex_mem.getCoordinates("right").x, addressAlu_output.getCoordinates("end").y);
		mem_addResult = new SimpleBus("", coord.x, coord.y, 2*gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(mem_addResult));
		coord = mem_addResult.getCoordinates("end");
		coord2 = pcMux.getCoordinates("lowerInput");
		coord2.translate(-coord.x, -coord.y);
		int bottomY = pcMux.getCoordinates("bottom").y - coord.y;
		mem_addResult.addEdge("pcMux", 2*gap - LINEWIDTH, 0, 0, bottomY + gap/2, coord2.x - gap, 0, 0, coord2.y - bottomY - gap/2, gap + LINEWIDTH, 0);
		mem_addResult.setFlag("pcMux", SimpleBus.NONE);

		coord = ex_zeroFlag.getCoordinates("end");
		coord2 = ex_mem.getCoordinates("right");
		mem_zeroFlag = new SimpleBus("", coord2.x, coord.y, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(mem_zeroFlag));
		coord = ex_aluResult.getCoordinates("end");
		dataMem_abus = new SimpleBus("", coord2.x, coord.y, 2*gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(dataMem_abus));
		dataMem_abus.addEdge("readAddress", 2*gap - LINEWIDTH, 0, 0, -2*gap, gap, 0);
		dataMem_abus.addEdge("writeAddress", 2*gap - LINEWIDTH, 0, 0, 2*gap, gap, 0);

		coord = dataMem_abus.getCoordinates("readAddress");
		dataMem = new EditableMemory("", coord.x, coord.y - gap, 1, 8, MIPS_DATA_MEM_SIZE, 32, (Rechner) this);
		// Format:                  (    x,       y,             Zellen x,                 Speicherbreite,   )
		//                           Titel,                         Zellen y,                  Verweis auf dieses Objekt
		//                                                             Speichergroesse,
		add(dataMem.getRessource()); (dataMem.getRessource()).show();
		dataMem.setOpcodesSupported(false);
		elements.addElement(new Editor_Source(dataMem));

		coord = dataMem.getCoordinates("right");
		String dmoTitle[] = {"Read", "data"};
		stringWidth = stringWidth(DIALOGFONT, dmoTitle[0]) + 20;
		dataMem_output = new SimpleBus(dmoTitle, coord.x, coord.y, stringWidth, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(dataMem_output));

		coord = dataMem.getCoordinates("left");
		coord2 = ex_mem.getCoordinates("right");
		coord.translate(-coord2.x, -coord2.y);
		coord2 = new Point(coord2.x, ex_data2.getCoordinates("ex_mem").y);
		dataMem_input = new SimpleBus("", coord2.x, coord2.y, coord.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(dataMem_input));

		coord = dataMem_output.getCoordinates("end");
		mem_wb = new PipelineRegister("MEM/WB", coord.x, pipRegTop, pipRegWidth, pipRegHeight, "left", (Rechner) this);
		elements.addElement(new Editor_Source(mem_wb));
		coord2 = dataMem_abus.getCoordinates("start");
		int bigBow = dataMem.getCoordinates("bottom").y - coord2.y + gap;
		coord.translate(-coord2.x, -coord2.y);
		dataMem_abus.addEdge("mem_wb", gap, 0, 0, bigBow, coord.x - gap, 0);

		coord = mem_wb.getCoordinates("top");
		coord2 = ex_mem.getCoordinates("top");
		//mem_label = new PipelineStageLabel("", "Memory", coord2.x, coord2.y + pipStageLabelGap, coord.x - coord2.x, pipStageLabelHeight, "left", (Rechner) this);
		mem_label = new PipelineStageLabel("", "Memory", coord2.x, 0, coord.x - coord2.x, pipStageLabelHeight, "leftTop", (Rechner) this);
		elements.addElement(new Editor_Source(mem_label));

		coord = new Point(ex_mem.getCoordinates("right").x, ex_mem.getCoordinates("bottom").y);  // rightBottom
		coord2 = mem_wb.getCoordinates("left");
		mem_writeRegister = new SimpleBus("", coord.x, coord.y - gap, coord2.x - coord.x, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(mem_writeRegister));


	//// WB ////
		coord = dataMem_output.getCoordinates("end");
		coord2 = mem_wb.getCoordinates("right");
		wbMux_upperInput = new SimpleBus("", coord2.x, coord.y, 2*gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(wbMux_upperInput));

		coord = wbMux_upperInput.getCoordinates("end");
		wbMux = new Mux("Mux", coord.x, coord.y, muxWidth, muxHeight, "upperInput", (Rechner) this);
		elements.addElement(new Editor_Source(wbMux));
		coord = wbMux.getCoordinates("lowerInput");
		coord2 = dataMem_abus.getCoordinates("mem_wb");
		wbMux_lowerInput = new SimpleBus("", coord.x - gap, coord.y, 0, coord2.y - coord.y + LINEWIDTH, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(wbMux_lowerInput));
		wbMux_lowerInput.addEdge("mem_wb", 0, coord2.y - coord.y, -gap, 0);
		wbMux_lowerInput.setFlag("mem_wb", SimpleBus.NONE);
		wbMux_lowerInput.addEdge("wbMux", 0, 0, gap, 0);
		wbMux_lowerInput.setFlag("wbMux", SimpleBus.NONE);

		coord = wbMux.getCoordinates("output");
		//bigBow = pipRegTop + pipRegHeight - coord.y + gap;
		bigBow = mem_wb.getCoordinates("bottom").y - coord.y + 2*gap;
		coord2 = registers.getCoordinates("leftBottom");
		coord2.translate(-coord.x, -coord.y);
		wbMux_output = new SimpleBus("", coord.x, coord.y, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(wbMux_output));
		wbMux_output.addEdge("registers", gap - LINEWIDTH, 0, 0, bigBow, coord2.x - 2*gap, 0, 0, coord2.y - bigBow - gap, gap + LINEWIDTH, 0);
		wbMux_output.setFlag("registers", SimpleBus.NONE);

		coord = wbMux_output.getCoordinates("end");
		coord2 = mem_wb.getCoordinates("top");
		//wb_label = new PipelineStageLabel("", "Write Back", coord2.x, coord2.y + pipStageLabelGap, coord.x - coord2.x + 20, pipStageLabelHeight, "left", (Rechner) this);
		wb_label = new PipelineStageLabel("", "Write Back", coord2.x, 0, coord.x - coord2.x + 20, pipStageLabelHeight, "leftTop", (Rechner) this);
		elements.addElement(new Editor_Source(wb_label));

		coord = new Point(mem_wb.getCoordinates("right").x, mem_wb.getCoordinates("bottom").y);  // rightBottom
		coord2 = registers.getCoordinates("left");
		coord2.translate(-(coord.x + gap), -coord.y);
		wb_writeRegister = new SimpleBus("", coord.x, coord.y - gap, gap, 0, busFlags, (Rechner) this);
		elements.addElement(new Editor_Source(wb_writeRegister));
		wb_writeRegister.addEdge("registers", gap - LINEWIDTH, 0, 0, 2*gap, coord2.x - 2*gap, 0, 0, coord2.y - 2*gap, 2*gap + LINEWIDTH, 0);
		wb_writeRegister.setFlag("registers", SimpleBus.NONE);



		stopSimulation();  // diverse Initialisierungen


		setLayout (new BorderLayout() );
		//NHT add("South", helpText);

		System.out.println("Initialisierung - Ende");

		//show();

		System.out.println("Nach Initialisierung (1)");

        pipeline_1_Control.show();
		//NHT helpText.show();

		versionStringX = WIDTH - stringWidth(DIALOGFONT, VERSIONSTRING) - 5;

		System.out.println("Nach Initialisierung (2)");

		paint(onScreenGC);

		System.out.println("Nach Initialisierung (3)");
			//{{INIT_CONTROLS
		//}}
} /* end init */


	public void stop()
	{
		super.stop();  // Alle Threads anhalten und beseitigen

        pipeline_1_Control.hide();
	}

	public void start()
	{
		super.start();  // Alle Threads erzeugen und starten

		Rectangle bounds = bounds();
        Rectangle bbounds = pipeline_1_Control.bounds();
		int x = Math.min(bounds.x + bounds.width, screenSize.width - bbounds.width);
        pipeline_1_Control.move(x, bounds.y);
        pipeline_1_Control.show();
	}

	public void showInfoTip(Point p)
	{
		if (infoTipLabel == null)
			return;

		String itt = "";

		for (int i = 0; i < elements.size(); i++)
		{
			Editor_Source es = (Editor_Source) elements.elementAt(i);
			if (es.intersectsWith(p))
			{
				itt = es.getInfoTipText(p);
				break;
			}
		}

		if (! itt.equals(""))
		{
			if (itt.equals("(nicht getrieben)"))
				itt = "(nicht benötigt)";

			int stringWidth = stringWidth(SMALLFONT, itt);
			int gap = 16;
			if (p.x + gap + stringWidth > bounds().width)
				p = new Point(p.x - stringWidth - 2*gap, p.y);
			if (p.y + SMALLFONTHEIGHT > bounds().height)
				p = new Point(p.x, p.y - SMALLFONTHEIGHT);

			symantec.itools.awt.InfoTipManager.draw(p.x + gap, p.y, itt, SMALLFONTMETRICS, Color.yellow, Color.black);
			Rectangle b = infoTipPanel.bounds();
			infoTipLabel.setText(itt);
			infoTipLabel.reshape(0, 0, b.width, b.height);
			infoTipLabel.setBackground(Color.yellow);
		}
	} /* end showInfoTip */


	/**
		this method is called when repaint of the panel is requested
	*/

	public synchronized void paint (Graphics onScreenGC)
	{
		// Flaeche des Applets loeschen
		offScreenGC.setColor(BACKGROUND);
		offScreenGC.fillRect(0, 0, WIDTH, HEIGHT);

		// Komponenten neu zeichnen
		paintComponents(offScreenGC);

		offScreenGC.drawString(VERSIONSTRING, versionStringX, 70);

		onScreenGC.drawImage(offScreenImage, 0, 0, this);
	} /* end paint */

	public synchronized void paintComponents (Graphics g)
	{
		instructionMem_abus		.paint(g);
		instructionMem_dbus		.paint(g);
		pcInc_lowerInput		.paint(g);
		pcInc_output			.paint(g);
		pc_input				.paint(g);
		registers_abus			.paint(g);
		registers_output1		.paint(g);
		registers_output2		.paint(g);
		id_signExtended			.paint(g);
		id_pc					.paint(g);
		alu_upperInput			.paint(g);
		alu_lowerInput			.paint(g);
		addressAlu_lowerInput	.paint(g);
		addressAlu_output		.paint(g);
		ex_data2				.paint(g);
		ex_signExtended			.paint(g);
		ex_aluResult			.paint(g);
		ex_zeroFlag				.paint(g);
		ex_pc					.paint(g);
		ex_writeRegister		.paint(g);
		dataMem_abus			.paint(g);
		dataMem_output			.paint(g);
		dataMem_input			.paint(g);
		mem_zeroFlag			.paint(g);
		mem_addResult			.paint(g);
		mem_writeRegister		.paint(g);
		wbMux_upperInput		.paint(g);
		wbMux_lowerInput		.paint(g);
		wbMux_output			.paint(g);
		wb_writeRegister		.paint(g);

		instructionMem			.paint(g);
		registers				.paint(g);
		dataMem					.paint(g);

		if_label				.paint(g);
		id_label				.paint(g);
		ex_label				.paint(g);
		wb_label				.paint(g);
		mem_label				.paint(g);

		if_id					.paint(g);
		id_ex					.paint(g);
		ex_mem					.paint(g);
		mem_wb					.paint(g);

		pc						.paint(g);

		pcMux					.paint(g);
		aluMux					.paint(g);
		wbMux					.paint(g);

		signExtender			.paint(g);
		shifter					.paint(g);

		pcInc					.paint(g);
		addressAlu				.paint(g);
		alu						.paint(g);

		//NHT helpText.	repaint();
	} /* end paintComponents */

	public synchronized void paintActivated (Graphics onScreenGC)
	{
		instructionMem_abus		.paintActivated(offScreenGC);
		instructionMem_dbus		.paintActivated(offScreenGC);
		pcInc_lowerInput		.paintActivated(offScreenGC);
		pcInc_output			.paintActivated(offScreenGC);
		pc_input				.paintActivated(offScreenGC);
		registers_abus			.paintActivated(offScreenGC);
		registers_output1		.paintActivated(offScreenGC);
		registers_output2		.paintActivated(offScreenGC);
		id_signExtended			.paintActivated(offScreenGC);
		id_pc					.paintActivated(offScreenGC);
		alu_upperInput			.paintActivated(offScreenGC);
		alu_lowerInput			.paintActivated(offScreenGC);
		addressAlu_lowerInput	.paintActivated(offScreenGC);
		addressAlu_output		.paintActivated(offScreenGC);
		ex_data2				.paintActivated(offScreenGC);
		ex_signExtended			.paintActivated(offScreenGC);
		ex_aluResult			.paintActivated(offScreenGC);
		ex_zeroFlag				.paintActivated(offScreenGC);
		ex_pc					.paintActivated(offScreenGC);
		ex_writeRegister		.paintActivated(offScreenGC);
		dataMem_abus			.paintActivated(offScreenGC);
		dataMem_output			.paintActivated(offScreenGC);
		dataMem_input			.paintActivated(offScreenGC);
		mem_zeroFlag			.paintActivated(offScreenGC);
		mem_addResult			.paintActivated(offScreenGC);
		mem_writeRegister		.paintActivated(offScreenGC);
		wbMux_upperInput		.paintActivated(offScreenGC);
		wbMux_lowerInput		.paintActivated(offScreenGC);
		wbMux_output			.paintActivated(offScreenGC);
		wb_writeRegister		.paintActivated(offScreenGC);

		instructionMem			.paintActivated(offScreenGC);
		registers				.paintActivated(offScreenGC);
		dataMem					.paintActivated(offScreenGC);

		if_label				.paintActivated(offScreenGC);
		id_label				.paintActivated(offScreenGC);
		ex_label				.paintActivated(offScreenGC);
		wb_label				.paintActivated(offScreenGC);
		mem_label				.paintActivated(offScreenGC);

		if_id					.paintActivated(offScreenGC);
		id_ex					.paintActivated(offScreenGC);
		ex_mem					.paintActivated(offScreenGC);
		mem_wb					.paintActivated(offScreenGC);

		pc						.paintActivated(offScreenGC);

		pcMux					.paintActivated(offScreenGC);
		aluMux					.paintActivated(offScreenGC);
		wbMux					.paintActivated(offScreenGC);

		signExtender			.paintActivated(offScreenGC);
		shifter					.paintActivated(offScreenGC);

		pcInc					.paintActivated(offScreenGC);
		addressAlu				.paintActivated(offScreenGC);
		alu						.paintActivated(offScreenGC);

		onScreenGC.drawImage(offScreenImage, 0, 0, this);
	} /* end paintActivated */

	public void deactivateAll()
	{
		if (! activationLocked)
		{
			instructionMem_abus		.deactivate();
			instructionMem_dbus		.deactivate();
			pcInc_lowerInput		.deactivate();
			pcInc_output			.deactivate();
			pc_input				.deactivate();
			registers_abus			.deactivate();
			registers_output1		.deactivate();
			registers_output2		.deactivate();
			id_signExtended			.deactivate();
			id_pc					.deactivate();
			alu_upperInput			.deactivate();
			alu_lowerInput			.deactivate();
			addressAlu_lowerInput	.deactivate();
			addressAlu_output		.deactivate();
			ex_data2				.deactivate();
			ex_signExtended			.deactivate();
			ex_aluResult			.deactivate();
			ex_zeroFlag				.deactivate();
			ex_pc					.deactivate();
			ex_writeRegister		.deactivate();
			dataMem_abus			.deactivate();
			dataMem_output			.deactivate();
			dataMem_input			.deactivate();
			mem_zeroFlag			.deactivate();
			mem_addResult			.deactivate();
			mem_writeRegister		.deactivate();
			wbMux_upperInput		.deactivate();
			wbMux_lowerInput		.deactivate();
			wbMux_output			.deactivate();
			wb_writeRegister		.deactivate();

			instructionMem			.deactivate();
			registers				.deactivate();
			dataMem					.deactivate();

			if_label				.deactivate();
			id_label				.deactivate();
			ex_label				.deactivate();
			wb_label				.deactivate();
			mem_label				.deactivate();

			if_id					.deactivate();
			id_ex					.deactivate();
			ex_mem					.deactivate();
			mem_wb					.deactivate();

			pc						.deactivate();

			pcMux					.deactivate();
			aluMux					.deactivate();
			wbMux					.deactivate();

			signExtender			.deactivate();
			shifter					.deactivate();

			pcInc					.deactivate();
			addressAlu				.deactivate();
			alu						.deactivate();
		}
	} /* end deactivateAll */


	public synchronized void scrollAll()
	{
		if (! activationLocked)
		{
			instructionMem_abus		.scroll();
			instructionMem_dbus		.scroll();
			pcInc_lowerInput		.scroll();
			pcInc_output			.scroll();
			pc_input				.scroll();
			registers_abus			.scroll();
			registers_output1		.scroll();
			registers_output2		.scroll();
			id_signExtended			.scroll();
			id_pc					.scroll();
			alu_upperInput			.scroll();
			alu_lowerInput			.scroll();
			addressAlu_lowerInput	.scroll();
			addressAlu_output		.scroll();
			ex_data2				.scroll();
			ex_signExtended			.scroll();
			ex_aluResult			.scroll();
			ex_zeroFlag				.scroll();
			ex_pc					.scroll();
			ex_writeRegister		.scroll();
			dataMem_abus			.scroll();
			dataMem_output			.scroll();
			dataMem_input			.scroll();
			mem_zeroFlag			.scroll();
			mem_addResult			.scroll();
			mem_writeRegister		.scroll();
			wbMux_upperInput		.scroll();
			wbMux_lowerInput		.scroll();
			wbMux_output			.scroll();
			wb_writeRegister		.scroll();

			instructionMem_abus		.paintActivated(offScreenGC);
			instructionMem_dbus		.paintActivated(offScreenGC);
			pcInc_lowerInput		.paintActivated(offScreenGC);
			pcInc_output			.paintActivated(offScreenGC);
			pc_input				.paintActivated(offScreenGC);
			registers_abus			.paintActivated(offScreenGC);
			registers_output1		.paintActivated(offScreenGC);
			registers_output2		.paintActivated(offScreenGC);
			id_signExtended			.paintActivated(offScreenGC);
			id_pc					.paintActivated(offScreenGC);
			alu_upperInput			.paintActivated(offScreenGC);
			alu_lowerInput			.paintActivated(offScreenGC);
			addressAlu_lowerInput	.paintActivated(offScreenGC);
			addressAlu_output		.paintActivated(offScreenGC);
			ex_data2				.paintActivated(offScreenGC);
			ex_signExtended			.paintActivated(offScreenGC);
			ex_aluResult			.paintActivated(offScreenGC);
			ex_zeroFlag				.paintActivated(offScreenGC);
			ex_pc					.paintActivated(offScreenGC);
			ex_writeRegister		.paintActivated(offScreenGC);
			dataMem_abus			.paintActivated(offScreenGC);
			dataMem_output			.paintActivated(offScreenGC);
			dataMem_input			.paintActivated(offScreenGC);
			mem_zeroFlag			.paintActivated(offScreenGC);
			mem_addResult			.paintActivated(offScreenGC);
			mem_writeRegister		.paintActivated(offScreenGC);
			wbMux_upperInput		.paintActivated(offScreenGC);
			wbMux_lowerInput		.paintActivated(offScreenGC);
			wbMux_output			.paintActivated(offScreenGC);
			wb_writeRegister		.paintActivated(offScreenGC);
		}

		onScreenGC.drawImage(offScreenImage, 0, 0, this);
	} /* end scrollAll */


	public void blinkAll()
	{
		blinker = !blinker;

		instructionMem			.updateAll();
		registers				.updateAll();
		dataMem					.updateAll();

		if_id					.blink(blinker);
		id_ex					.blink(blinker);
		ex_mem					.blink(blinker);
		mem_wb					.blink(blinker);

		pc						.blink(blinker);

		pcInc					.blink(blinker);
		addressAlu				.blink(blinker);
		alu						.blink(blinker);
    } /* end blinkAll */


	/**
	 *  Alle Komponenten, die zwischen ihrem eigentlichem Wert (value)
	 *  und dem gerade sichtbaren Wert (displayValue) unterscheiden,
	 *  führen ein "displayValue = value" durch.
	 */
	public void updateAll()
	{
		instructionMem			.updateAll();
		registers				.updateAll();
		dataMem					.updateAll();

		if_id					.update();
		id_ex					.update();
		ex_mem					.update();
		mem_wb					.update();

		pc						.update();

		pcInc					.update();
		addressAlu				.update();
		alu						.update();
	} /* end updateAll */


	public void lockAll()
	// Keine Komponente reagiert mehr auf activate(),
	// activateCompared() oder deactivate().
	{
		activationLocked = true;

		instructionMem_abus		.lock();
		instructionMem_dbus		.lock();
		pcInc_lowerInput		.lock();
		pcInc_output			.lock();
		pc_input				.lock();
		registers_abus			.lock();
		registers_output1		.lock();
		registers_output2		.lock();
		id_signExtended			.lock();
		id_pc					.lock();
		alu_upperInput			.lock();
		alu_lowerInput			.lock();
		addressAlu_lowerInput	.lock();
		addressAlu_output		.lock();
		ex_data2				.lock();
		ex_signExtended			.lock();
		ex_aluResult			.lock();
		ex_zeroFlag				.lock();
		ex_pc					.lock();
		ex_writeRegister		.lock();
		dataMem_abus			.lock();
		dataMem_output			.lock();
		dataMem_input			.lock();
		mem_zeroFlag			.lock();
		mem_addResult			.lock();
		mem_writeRegister		.lock();
		wbMux_upperInput		.lock();
		wbMux_lowerInput		.lock();
		wbMux_output			.lock();
		wb_writeRegister		.lock();

		instructionMem			.lock();
		registers				.lock();
		dataMem					.lock();

		if_label				.lock();
		id_label				.lock();
		ex_label				.lock();
		wb_label				.lock();
		mem_label				.lock();

		if_id					.lock();
		id_ex					.lock();
		ex_mem					.lock();
		mem_wb					.lock();

		pc						.lock();

		pcMux					.lock();
		aluMux					.lock();
		wbMux					.lock();

		signExtender			.lock();
		shifter					.lock();

		pcInc					.lock();
		addressAlu				.lock();
		alu						.lock();
	} /* end lockAll */


	public void unlockAll()
	// Alle Komponenten reagieren wieder auf activate(),
	// activateCompared() und deactivate().
	{
		activationLocked = false;

		instructionMem_abus		.unlock();
		instructionMem_dbus		.unlock();
		pcInc_lowerInput		.unlock();
		pcInc_output			.unlock();
		pc_input				.unlock();
		registers_abus			.unlock();
		registers_output1		.unlock();
		registers_output2		.unlock();
		id_signExtended			.unlock();
		id_pc					.unlock();
		alu_upperInput			.unlock();
		alu_lowerInput			.unlock();
		addressAlu_lowerInput	.unlock();
		addressAlu_output		.unlock();
		ex_data2				.unlock();
		ex_signExtended			.unlock();
		ex_aluResult			.unlock();
		ex_zeroFlag				.unlock();
		ex_pc					.unlock();
		ex_writeRegister		.unlock();
		dataMem_abus			.unlock();
		dataMem_output			.unlock();
		dataMem_input			.unlock();
		mem_zeroFlag			.unlock();
		mem_addResult			.unlock();
		mem_writeRegister		.unlock();
		wbMux_upperInput		.unlock();
		wbMux_lowerInput		.unlock();
		wbMux_output			.unlock();
		wb_writeRegister		.unlock();

		instructionMem			.unlock();
		registers				.unlock();
		dataMem					.unlock();

		if_label				.unlock();
		id_label				.unlock();
		ex_label				.unlock();
		wb_label				.unlock();
		mem_label				.unlock();

		if_id					.unlock();
		id_ex					.unlock();
		ex_mem					.unlock();
		mem_wb					.unlock();

		pc						.unlock();

		pcMux					.unlock();
		aluMux					.unlock();
		wbMux					.unlock();

		signExtender			.unlock();
		shifter					.unlock();

		pcInc					.unlock();
		addressAlu				.unlock();
		alu						.unlock();
	} /* end unlockAll */


	public synchronized void invalidateAllImageCaches()
	{
		instructionMem_abus		.invalidateImageCache();
		instructionMem_dbus		.invalidateImageCache();
		pcInc_lowerInput		.invalidateImageCache();
		pcInc_output			.invalidateImageCache();
		pc_input				.invalidateImageCache();
		registers_abus			.invalidateImageCache();
		registers_output1		.invalidateImageCache();
		registers_output2		.invalidateImageCache();
		id_signExtended			.invalidateImageCache();
		id_pc					.invalidateImageCache();
		alu_upperInput			.invalidateImageCache();
		alu_lowerInput			.invalidateImageCache();
		addressAlu_lowerInput	.invalidateImageCache();
		addressAlu_output		.invalidateImageCache();
		ex_data2				.invalidateImageCache();
		ex_signExtended			.invalidateImageCache();
		ex_aluResult			.invalidateImageCache();
		ex_zeroFlag				.invalidateImageCache();
		ex_pc					.invalidateImageCache();
		ex_writeRegister		.invalidateImageCache();
		dataMem_abus			.invalidateImageCache();
		dataMem_output			.invalidateImageCache();
		dataMem_input			.invalidateImageCache();
		mem_zeroFlag			.invalidateImageCache();
		mem_addResult			.invalidateImageCache();
		mem_writeRegister		.invalidateImageCache();
		wbMux_upperInput		.invalidateImageCache();
		wbMux_lowerInput		.invalidateImageCache();
		wbMux_output			.invalidateImageCache();
		wb_writeRegister		.invalidateImageCache();

		instructionMem			.invalidateImageCache();
		registers				.invalidateImageCache();
		dataMem					.invalidateImageCache();

	} /* end invalidateAllImageCaches() */


	public synchronized void timerWokeUp(String title)
	{
		if (title.equalsIgnoreCase("scrolltimer"))
		{
			scrollAll();
		}
		else if (title.equalsIgnoreCase("blinktimer"))
		{
			blinkAll();
		    onScreenGC.drawImage(offScreenImage, 0, 0, this);
		}
	} /* end timerWokeUp */


	public void stopSimulation()
	{
		//NDR demonstrationReady = true;

		instructionMem			.initRam(INSTRUCTIONS);
		registers				.initRam(REGISTERS);
		dataMem					.initRam(DATA);

		if_id					.reset();
		id_ex					.reset();
		ex_mem					.reset();
		mem_wb					.reset();

		pc						.setValue(0);

		pcInc					.calculate(ADD_MEM, 0, 0, true);
		addressAlu				.calculate(ADD_MEM, 0, 0, true);
		alu						.calculate(ADD_MEM, 0, 0, true);

		//NHT helpText.setText(descriptionLibrary.helpText_Von_Neumann_Rechner(c_state, 1) );
	} /* end stopSimulation */


	public void goUntilBreakpoint()
	// ">> BP"
	{
	}


	public void singleInstruction(boolean doRepaint)
	// ">>"
	{
		deactivateAll();

		// Die folgenden Zeilen zwischen den Lock-Anweisungen simulieren
		// das Verhalten des Benutzers, bis zum Ende des Befehls
		// ">" zu druecken. Durch das "Lock" wird dabei jede Ausgabe
		// vermieden, sehr wohl aber wird die Statistik fortgefuehrt.
		lockAll();

		demonstrate(false);  // Erster Ansatz:
		demonstrate(false);  // soviele Schritte machen,
		demonstrate(false);  // wie die Pipeline Stufen hat.
		demonstrate(false);
		demonstrate(doRepaint);
		/**
		demonstrate(false);  // Mindestens einen Unterschritt machen

		boolean dodoRepaint;
		while ( ! ((c_state == FETCH) && (demonstrationStep == 1)))
		// Der erste Unterschritt eines Befehls steht noch bevor.
		{
			dodoRepaint = doRepaint && demonstrationReady && (n_state == FETCH);
			demonstrate(dodoRepaint);
			// Nur der Hilfetext "Der Befehl Xxx ist beeendet." sollte erscheinen.
		}
		*/

		unlockAll();

		if (doRepaint)
		{
			updateAll();

			paint(onScreenGC);
		}
		//speedup System.out.println("SingleInstruction beendet");
	} /* end singleInstruction */

	public void singleInstructionBack(boolean doRepaint)
	// "<<"
	{
		if (simBufferTop == simBufferBottom)
			System.out.println("'<<': Keine weiteren Arbeitsschritte mehr gespeichert!");
		else
		{
			setComputer();  // Erster Ansatz:
			setComputer();  // soviele Schritte rueckwaerts machen,
			setComputer();  // wie die Pipeline Stufen hat.
			setComputer();
			setComputer();
			setComputer();
			demonstrate(doRepaint);

			if (doRepaint)
			{
				updateAll();

				paint(onScreenGC);
			}
		}
	} /* end singleInstructionBack */


	public synchronized void bufferComputer()
	{
		Vector v = new Vector(11);

		v.addElement(instructionMem.getAllValues());
		v.addElement(registers.getAllValues());
		v.addElement(dataMem.getAllValues());

		v.addElement(if_id.getAllValues());
		v.addElement(id_ex.getAllValues());
		v.addElement(ex_mem.getAllValues());
		v.addElement(mem_wb.getAllValues());

		v.addElement(new Integer(pc.getValue()));

		v.addElement(pcInc.getFlags());
		v.addElement(addressAlu.getFlags());
		v.addElement(alu.getFlags());

		simBuffer[simBufferTop] = v;

		simBufferTop = (simBufferTop+1) % SIM_BUFFER_SIZE;
		if (simBufferTop == simBufferBottom)
			simBufferBottom = (simBufferBottom+1) % SIM_BUFFER_SIZE;

	} /* end bufferComputer */

	public synchronized void setComputer()
	{
			if (simBufferTop == simBufferBottom)
				System.out.println("'<': Keine weiteren Arbeitsschritte mehr gespeichert!");
			else
			{
				simBufferTop--;
				if (simBufferTop == -1)
					simBufferTop = SIM_BUFFER_SIZE - 1;
				//debug System.out.println("'<<' - simBufferTop = " + simBufferTop);
			}

			Vector v = simBuffer[simBufferTop];

			instructionMem.	setValue((int[]) v.elementAt(0));
			registers.		setValue((int[]) v.elementAt(1));
			dataMem.		setValue((int[]) v.elementAt(2));

			if_id.			setValue((Vector) v.elementAt(3));
			id_ex.			setValue((Vector) v.elementAt(4));
			ex_mem.			setValue((Vector) v.elementAt(5));
			mem_wb.			setValue((Vector) v.elementAt(6));

			pc.				setValue( ((Integer) v.elementAt(7)).intValue() );

			pcInc.			setFlags((boolean[]) v.elementAt(8));
			addressAlu.		setFlags((boolean[]) v.elementAt(9));
			alu.			setFlags((boolean[]) v.elementAt(10));

			deactivateAll();
			//NDR demonstrationReady = false;
	} /* end setComputer */


	public void demonstrate()
	{
		demonstrate(true);
	}

	public synchronized void demonstrate(boolean doRepaint)
	{
		int LEFT = 2;
		int RIGHT = 1;
		long iword;
		int aluResult;
		int op, funct;
		boolean storeWord = false;

		bufferComputer();

		if (doRepaint)
			deactivateAll();


	//// IF ////
			instructionMem.setAddress(pc.getValue() / 4);
			iword = (long) instructionMem.getValue();
			if_id.setInput("instructionWord", (int) iword);
			if ( (iword < 0) && (iword != MIPS_UNIMPORTANT) )
				iword += instructionMem.zwei_hoch_bitWidth;
			if_id.setInput("funct", (int) (iword & 63));
			if_id.setInput("immediate", (int) (iword & 65535));
			if_id.setInput( "target address", (int) (iword & (long) Math.pow(2, 24)-1) );
			iword >>= 6;
			if_id.setInput("shamt", (int) (iword & 31));
			iword >>= 5;
			if_id.setInput("rd", (int) (iword & 31));
			iword >>= 5;
			if_id.setInput("rt", (int) (iword & 31));
			iword >>= 5;
			if_id.setInput("rs", (int) (iword & 31));
			iword >>= 5;
			if_id.setInput("address", pc.getValue() + 4);
			if (iword != MIPS_UNIMPORTANT)
				if_id.setInput("op", (int) (iword & 63));
			else
				if_id.setInput("op", MIPS_UNIMPORTANT);

		pre_if.setValue(if_id.getAllInputs());
		if_label.activate(describeStage(pre_if));

		if (pre_if.getValue("op") != MIPS_UNIMPORTANT)
		{
		pc.activate();
			instructionMem_abus.setValue(pc.getValue());
		instructionMem_abus.activate("start", "end", "pcInc");
		instructionMem.activate();
			pcInc_lowerInput.setValue(4);
		pcInc_lowerInput.activate("start", "end");
		pcInc.calculate(ADD_MEM, pc.getValue(), pcInc_lowerInput.getValue(), true);
		pcInc.activate();
			pcInc_output.setValue(pcInc.getValue());
		pcInc_output.activate("start", "end", "pcMux");
		pcMux.activate();
			//pc_input.setValue() steht ganz unten
		pc_input.activate("start", "pc");
			instructionMem_dbus.setValue(instructionMem.getValue());
		instructionMem_dbus.activate("start", "end");
		if_id.activate(LEFT);
		}

	//// ID/Reg. prefetch ////
			op = if_id.getValue("op");
			id_ex.setInput("funct", if_id.getValue("funct"));
			id_ex.setInput("immediate", if_id.getValue("immediate"));
			id_signExtended.setValue(if_id.getValue("immediate"));
			id_ex.setInput("target address", if_id.getValue("target address"));
			id_ex.setInput("shamt", if_id.getValue("shamt"));
			id_ex.setInput("rd", if_id.getValue("rd"));
			id_ex.setInput("rt", if_id.getValue("rt"));
			registers.setAddress(if_id.getValue("rt"));
			id_ex.setInput("read data 2", registers.getValue());
			registers_output2.setValue(registers.getValue());
		if (op != MIPS_UNIMPORTANT) registers.activate(READ_COLOR, READ_COLOR);
			id_ex.setInput("rs", if_id.getValue("rs"));
			registers.setAddress((int) if_id.getValue("rs"));
			id_ex.setInput("read data 1", registers.getValue());
			registers_output1.setValue(registers.getValue());
		if (op != MIPS_UNIMPORTANT) registers.activate(READ_COLOR, READ_COLOR);
			id_ex.setInput("address", if_id.getValue("address"));
			id_ex.setInput("op", if_id.getValue("op"));

		id_label.activate(describeStage(if_id));

		if (op != MIPS_UNIMPORTANT)
		{
		if_id.activate(RIGHT);

			registers_abus.setValue(if_id.getValue("instructionWord"));
		registers_abus.activate("if_id", "read1", "id_ex");
		registers_abus.activateTo("read2");
		registers_abus.activateTo("signExtender");

		registers_output1.activate("start", "end");
		registers_output2.activate("start", "end");

		signExtender.activate();
		id_signExtended.activate("start", "end");

			id_pc.setValue(if_id.getValue("address"));
		id_pc.activate("start", "end");

		id_ex.activate(LEFT);
		}


	//// EX ////
		ex_mem.setInput("op", id_ex.getValue("op"));
		ex_mem.setInput("rs", id_ex.getValue("rs"));
		ex_mem.setInput("rt", id_ex.getValue("rt"));
		ex_mem.setInput("rd", id_ex.getValue("rd"));
		ex_mem.setInput("funct", id_ex.getValue("funct"));
		ex_mem.setInput("immediate", id_ex.getValue("immediate"));

		ex_label.activate(describeStage(id_ex));

		switch(id_ex.getValue("op"))
		{
			case MIPS_SW:
					ex_mem.setInput("write data", id_ex.getValue("read data 2"));
				storeWord = true;
					ex_data2.setValue(id_ex.getValue("read data 2"));
				ex_data2.activate("start", "ex_mem");
			case MIPS_LW:
					aluResult = alu.calculate(ADD_MEM, id_ex.getValue("read data 1"), id_ex.getValue("immediate"));
					ex_mem.setInput("alu result", aluResult);
					ex_mem.setInput("zero", alu.getFlag("zero") ? 1 : 0);
				//debug if (storeWord == false)
				//debug 	System.out.println("--EX: lw");
				//debug else
				//debug		System.out.println("--EX: sw");
				id_ex.activate(RIGHT);
					alu_upperInput.setValue(id_ex.getValue("read data 1"));
				alu_upperInput.activate("start", "end");
					ex_signExtended.setValue(id_ex.getValue("immediate"));
				ex_signExtended.activate("signExtender", "aluMux");
				aluMux.activate();
					alu_lowerInput.setValue(id_ex.getValue("immediate"));
				alu_lowerInput.activate("start", "end");
				alu.activate();
					ex_aluResult.setValue(aluResult);
				ex_aluResult.activate("start", "end");
				ex_mem.activate(LEFT);
					ex_writeRegister.setValue(id_ex.getValue("rt"));
				ex_writeRegister.activate("start", "end");
				break;
			case MIPS_R:  // R-Format: Befehle ADD, SUB, SLT und JR
					funct = id_ex.getValue("funct");
					if (funct == 32)
						aluResult = alu.calculate(ADD_MEM, id_ex.getValue("read data 1"), id_ex.getValue("read data 2"));
					else if (funct == 34)
						aluResult = alu.calculate(SUB_MEM, id_ex.getValue("read data 1"), id_ex.getValue("read data 2"));
					else
						aluResult = 0;
					ex_mem.setInput("alu result", aluResult);
					ex_mem.setInput("zero", alu.getFlag("zero") ? 1 : 0);
				//debug System.out.println("--EX: " + opcode);
				id_ex.activate(RIGHT);
					alu_upperInput.setValue(id_ex.getValue("read data 1"));
				alu_upperInput.activate("start", "end");
					ex_data2.setValue(id_ex.getValue("read data 2"));
				ex_data2.activate("start", "end");
				aluMux.activate();
					alu_lowerInput.setValue(id_ex.getValue("read data 2"));
				alu_lowerInput.activate("start", "end");
				alu.activate();
					ex_aluResult.setValue(aluResult);
				ex_aluResult.activate("start", "end");
					ex_zeroFlag.setValue(alu.getFlag("zero") ? 1 : 0);
				ex_zeroFlag.activate("start", "end");
				ex_mem.activate(LEFT);
					ex_writeRegister.setValue(id_ex.getValue("rd"));
				ex_writeRegister.activate("start", "end");
				break;
			case MIPS_UNIMPORTANT:
				break;
			default:
				//debug System.out.println("     --- Unbekannter Opcode in Phase EX! ---");
		}


	//// MEM ////
		mem_wb.setInput("op", ex_mem.getValue("op"));
		mem_wb.setInput("rs", ex_mem.getValue("rs"));
		mem_wb.setInput("rt", ex_mem.getValue("rt"));
		mem_wb.setInput("rd", ex_mem.getValue("rd"));
		mem_wb.setInput("funct", ex_mem.getValue("funct"));
		mem_wb.setInput("immediate", ex_mem.getValue("immediate"));

		mem_label.activate(describeStage(ex_mem));

		switch(ex_mem.getValue("op"))
		{
			case MIPS_LW:
					dataMem.setAddress(ex_mem.getValue("alu result"));
					mem_wb.setInput("read data", dataMem.getValue());
				//debug System.out.println("--MEM: lw");
				ex_mem.activate(RIGHT);
					dataMem_abus.setValue(ex_mem.getValue("alu result"));
				dataMem_abus.activate("start", "readAddress");
				dataMem.activate();
					dataMem_output.setValue(dataMem.getValue());
				dataMem_output.activate("start", "end");
					mem_writeRegister.setValue(ex_mem.getValue("rt"));
				mem_writeRegister.activate("start", "end");
				mem_wb.activate(LEFT);
				break;
			case MIPS_SW:
					dataMem.setAddress(ex_mem.getValue("alu result"));
					dataMem.setValue(ex_mem.getValue("write data"));
				//debug System.out.println("--MEM: sw");
				ex_mem.activate(RIGHT);
					dataMem_abus.setValue(ex_mem.getValue("alu result"));
				dataMem_abus.activate("start", "writeAddress");
					dataMem_input.setValue(ex_mem.getValue("write data"));
				dataMem_input.activate("start", "end");
				dataMem.activate();
					mem_writeRegister.setValue(ex_mem.getValue("rt"));
				mem_writeRegister.activate("start", "end");
				break;
			case MIPS_R:  // R-Format: Befehle ADD, SUB, SLT und JR
					mem_wb.setInput("alu result", ex_mem.getValue("alu result"));
				//debug System.out.println("--MEM: " + opcode);
				ex_mem.activate(RIGHT);
					dataMem_abus.setValue(ex_mem.getValue("alu result"));
				dataMem_abus.activate("start", "mem_wb");
					mem_writeRegister.setValue(ex_mem.getValue("rd"));
				mem_writeRegister.activate("start", "end");
					mem_zeroFlag.setValue(ex_mem.getValue("zero"));
				mem_zeroFlag.activate("start", "end");
				mem_wb.activate(LEFT);
				break;
			case MIPS_UNIMPORTANT:
				break;
			default:
				//debug System.out.println("     --- Unbekannter Opcode in Phase MEM! ---");
		}


	//// WB ////
		wb_label.activate(describeStage(mem_wb));

		switch(mem_wb.getValue("op"))
		{
			case MIPS_LW:
					registers.setAddress(mem_wb.getValue("rt"));
					registers.setValue(mem_wb.getValue("read data"));
				//debug System.out.println("--WB: lw");
				mem_wb.activate(RIGHT);
					wbMux_upperInput.setValue(mem_wb.getValue("read data"));
				wbMux_upperInput.activate("start", "end");
				wbMux.activate();
					wbMux_output.setValue(mem_wb.getValue("read data"));
				wbMux_output.activate("start", "registers");
					wb_writeRegister.setValue(mem_wb.getValue("rt"));
				wb_writeRegister.activate("start", "registers");
				registers.activate(WRITE_COLOR, WRITE_COLOR);
				break;
			case MIPS_SW:
				//debug System.out.println("--WB: sw");
				break;
			case MIPS_R:  // R-Format: Befehle ADD, SUB, SLT und JR
					registers.setAddress(mem_wb.getValue("rd"));
					registers.setValue(mem_wb.getValue("alu result"));
				//debug System.out.println("--WB: " + opcode);
				mem_wb.activate(RIGHT);
					wbMux_lowerInput.setValue(mem_wb.getValue("alu result"));
				wbMux_lowerInput.activate("mem_wb", "wbMux");
				wbMux.activate();
					wbMux_output.setValue(mem_wb.getValue("alu result"));
				wbMux_output.activate("start", "registers");
					wb_writeRegister.setValue(mem_wb.getValue("rd"));
				wb_writeRegister.activate("start", "registers");
				registers.activate(WRITE_COLOR, WRITE_COLOR);
				break;
			case MIPS_UNIMPORTANT:
				break;
			default:
				//debug System.out.println("     --- Unbekannter Opcode in Phase WB! ---");
		}

		//debug System.out.println("");
		mem_wb.acceptInputs();
		ex_mem.acceptInputs();
		id_ex.acceptInputs();
		if_id.acceptInputs();
		pc.setValue(pc.getValue() + 4); // Aendern: +4 oder +x bei Sprung
		pc_input.setValue(pc.getValue());  // verkehrte Reihenfolge, aber tut

		if (doRepaint)
		{
			//NHT helpText.setText(descriptionLibrary.helpText_Pip(data));
		}

	} /* end demonstrate */

	public void demonstrateBack()
	// "<"
	{
		setComputer();
		setComputer();
		updateAll();
		demonstrate(true);

	} /* end demonstrateBack */


	public void initCacheComponents(int cSize, int tSize, int assoc) {}
	public void removeCacheRessources() {}

	public void showAllOpcodes(boolean b) {}

	public void showWindow(String name) {}
	public void hideWindow(String name) {}

	private String describeStage(PipelineRegister pipReg)
	{
		String opcode;
		boolean rFormat = false;

		switch (pipReg.getValue("op"))
		{
			case MIPS_LW:
				opcode = "lw";
				break;
			case MIPS_SW:
				opcode = "sw";
				break;
			case MIPS_R:
				rFormat = true;
				if (pipReg.getValue("funct") == 32)
					opcode = "add";
				else if (pipReg.getValue("funct") == 34)
					opcode = "sub";
				else
					opcode = "?+-";
				break;
			case MIPS_UNIMPORTANT:
				opcode = "";
				break;
			default:
				opcode = "???";

		}

		if (opcode.equals("") || opcode.equals("???"))
			return opcode;
		else if (rFormat)
			return new String(opcode + " $" + Integer.toString(pipReg.getValue("rt"), 16) + ", $" + Integer.toString(pipReg.getValue("immediate"), 16) + ", $" + Integer.toString(pipReg.getValue("rs"), 16));
		else
			return new String(opcode + " $" + Integer.toString(pipReg.getValue("rd"), 16) + ", " + Integer.toString(pipReg.getValue("rs"), 16) + "($" + Integer.toString(pipReg.getValue("rt"), 16) + ")");
	}


	//{{DECLARE_CONTROLS
	//}}
} /* end Pipeline_1 */
