<commit_before>package fi.hu.cs.titokone;

import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.io.*;
import java.util.*;
import fi.hu.cs.ttk91.TTK91Cpu;


/** This class takes care of the animation window. It digs the 
    needed information from a RunInfo instance. */
public class Animator extends JPanel implements Runnable {
    
    private final static Font textFont = new Font ("Arial", Font.BOLD, 16);

    private final static int R0 = 0;
    private final static int R1 = 1;
    private final static int R2 = 2;
    private final static int R3 = 3;
    private final static int R4 = 4;
    private final static int R5 = 5;
    private final static int R6 = 6;
    private final static int R7 = 7;
    private final static int TR = 8;
    private final static int PC = 9;
    private final static int IR = 10;
    private final static int SR = 11;
    private final static int BASE = 12;
    private final static int LIMIT = 13;
    private final static int MAR = 14;
    private final static int MBR = 15;
    private final static int ALU_IN1 = 16;
    private final static int ALU_IN2 = 17;
    private final static int ALU_OUT = 18;
    private final static int EXTERNAL_DEVICE = 19;
    private final static int MEMORY = 20;
    
    private final static int[][] routeToBus = {
        {182,97,  220,97},              // R0
        {182,119, 220,119},             // R1
        {182,141, 220,141},             // R2
        {182,163, 220,163},             // R3
        {182,185, 220,185},             // R4
        {182,207, 220,207},             // R5
        {182,229, 220,229},             // R6
        {182,251, 220,251},             // R7
        {257,110, 220,110},             // TR
        {257,132, 220,132},             // PC
        {257,154, 220,154},             // IR
        {257,176, 220,176},             // SR
        {257,295, 220,295},             // BASE
        {257,317, 220,317},             // LIMIT
        {257,339, 220,339},             // MAR
        {257,361, 220,361},             // MBR
        {182,327, 220,327},             // ALU_IN1
        {182,349, 220,349},             // ALU_IN2
        {182,393, 220,393},             // ALU_OUT
        {520,423, 520,491, 220,491},    // EXTERNAL_DEVICE
        {661,423, 661,491, 220,491},    // MEMORY
    };
    
    private final static int[][] whereWriteValueTo = {
        {73,105},                       // R0
        {73,127},                       // R1
        {73,149},                       // R2
        {73,171},                       // R3
        {73,193},                       // R4
        {73,215},                       // R5
        {73,237},                       // R6
        {73,259},                       // R7
        {264,117},                      // TR
        {264,139},                      // PC
        {264,161},                      // IR
        {264,183},                      // SR
        {264,303},                      // BASE
        {264,325},                      // LIMIT
        {264,347},                      // MAR
        {264,369},                      // MBR
        {74,334},                       // ALU_IN1
        {74,356},                       // ALU_IN2
        {74,401},                       // ALU_OUT
    };
    
    private final static int[][] whereWriteLabelTo = {
        {35,103},                       // R0
        {35,125},                       // R1
        {35,147},                       // R2
        {35,169},                       // R3
        {35,191},                       // R4
        {35,213},                       // R5
        {35,235},                       // R6
        {35,257},                       // R7
        {376,116},                      // TR
        {376,138},                      // PC
        {376,160},                      // IR
        {376,182},                      // SR
        {376,302},                      // BASE
        {376,324},                      // LIMIT
        {376,346},                      // MAR
        {376,368},                      // MBR
        {35,333},                       // ALU_IN1
        {35,355},                       // ALU_IN2
        {35,400},                       // ALU_OUT
        {35,80},                        // Registers
        {261,80},                       // Control unit
        {261,270},                      // MMU
        {35,305},                       // ALU
        {525,385},                      // External device
        {525,70},                       // Memory
    };

    private final static String[] labels = {
        "R0",
        "R1",
        "R2",
        "R3",
        "R4",
        "R5",
        "R6",
        "R7",
        "TR",
        "PC",
        "IR",
        "SR",
        "BASE",
        "LIMIT",
        "MAR",
        "MBR",
        "IN1",
        "IN2",
        "OUT",
        "Registers",
        "Control unit",
        "MMU",
        "ALU",
        "External device",
        "Memory"
    };        
    
    /** Contains values of registers, alu, memory and external device. */
    private int[] value = new int[routeToBus.length];
   
    /** Current command label */
    private String currentCommand = "";
    
    /** Comment label */
    private String comment1 = "";
    private String comment2 = "";
    
    /** String presentation of status register. */
    private String SR_String = "";
    
    /** If this is true, animation will be executed without repaitings and delays. */
    private boolean executeAnimationImmediately = false;
    
    /** Is animation currently running. */
    private boolean isAnimating = false;
    
    /** Thread, that runs animation. */
    private Thread animationThread;
    
    /** RunInfo object of currently running animation. */
    private RunInfo info;

    private BufferedImage backgroundImage, doubleBuffer;
    private int pointX=-1, pointY=-1;
    private int delay = 40;
    
    /** Creats new animator. 
        @throws IOException If there are problems reading background image throw IOException. */
    public Animator () throws IOException {
        // read the background image
        ClassLoader foo = getClass ().getClassLoader();
        BufferedImage bi = ImageIO.read (foo.getResourceAsStream ("fi/hu/cs/titokone/resources/animator.gif"));
		backgroundImage = new BufferedImage (bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB);
        doubleBuffer = new BufferedImage (bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB);
		backgroundImage.createGraphics().drawImage (bi, 0,0, null);
    }
    
    public void paint (Graphics g) {
        // copy backround image to dublebuffer
        backgroundImage.copyData (doubleBuffer.getRaster());
        
        Graphics g2 = doubleBuffer.createGraphics();
        g2.setColor (Color.BLACK);
    	g2.setFont (textFont);
        
        // write labels
        for (int i=0; i < labels.length; i++)
            g2.drawString (new Message(labels[i]).toString(), whereWriteLabelTo[i][0], whereWriteLabelTo[i][1]);
        
        // write values (registers, alu, control unit, mmu)
        for (int i=0; i < whereWriteValueTo.length; i++)
            if (i != SR)
                g2.drawString ("" + value[i], whereWriteValueTo[i][0], whereWriteValueTo[i][1]);
            else
                g2.drawString (SR_String, whereWriteValueTo[i][0], whereWriteValueTo[i][1]);
            
        // write current command and comments
        g2.drawString (new Message ("Current command: ").toString() + currentCommand, 217, 23);
        g2.drawString (comment1, 29, 548);
        g2.drawString (comment2, 29, 581);
        
        // draw red animation spot
        if (pointX != -1) {
            g2.setColor (Color.RED);
            g2.fillOval (pointX -5, pointY -5, 10, 10);
        }
        
        // draw double buffer to frame
        g.drawImage (doubleBuffer, 0,0, getWidth(), getHeight(), null);
    }
    
    /** Animation is done in this run method. animate method awakes new thread
        with this run method.
    */
    public void run() {
        // Information about command cycle:
        // http://www.cs.helsinki.fi/u/kerola/tito/html/lu05_files/frame.html
        currentCommand = "";        
        
        // animate instruction fetch
        comment1 = new Message ("Fetch the next instruction from memory slot {0} to IR and increase PC by one.", ""+value[PC]).toString();
        animateAnEvent (PC, MAR);
        animateAnEvent (PC, PC, value[PC]+1);
        animateAnEvent (MAR, MEMORY);
        animateAnEvent (MEMORY, MBR, info.getBinary());
        animateAnEvent (MBR, IR);
        currentCommand = info.getLineContents(); //+ "   (" + info.getColonString() + ")";
        pause();
        
        int opcode = info.getBinary() >>> 24;
        int Rj = info.getFirstOperand();
        int Ri = info.getIndexRegister();
        int ADDR = info.getADDR();
        int memoryFetches = info.getMemoryfetches();
        int[] regs = info.getRegisters();
        int Rj_value = value[Rj];
        int Ri_value = value[Ri];
        
        // if NOP interrupt immediately
        if (opcode == 0) {
            comment1 = new Message ("No-operation command completed.").toString();
            pause();
            isAnimating = executeAnimationImmediately = false;
            return;
        }
        
        if (Ri != 0) ADDR += Ri_value;
        int param = ADDR;
        int whereIsSecondOperand = IR;
        if (memoryFetches == 1) {
            param = info.getValueAtADDR();
            whereIsSecondOperand = MBR;
            comment1 = new Message ("Fetch second operand from memory slot {0}.", ""+ADDR).toString();
            animateAnEvent (IR, MAR, ADDR);
            animateAnEvent (MAR, MEMORY);
            animateAnEvent (MEMORY, MBR, param);
        }
        else if (memoryFetches == 2) {
            param = info.getSecondFetchValue();
            whereIsSecondOperand = MBR;
            comment1 = new Message ("Indirect memory accessing mode.").toString();
            comment2 = new Message ("1: Fetch indexing value from memory slot {0}.", ""+ADDR).toString();
            animateAnEvent (IR, MAR, ADDR);
            animateAnEvent (MAR, MEMORY);
            animateAnEvent (MEMORY, MBR, info.getValueAtADDR());
            comment1 = new Message ("Indirect memory accessing mode.").toString();
            comment2 = new Message ("2: Fetch second operand from memory slot {0}.", ""+value[MBR]).toString();
            pause();
            animateAnEvent (MBR, MAR);
            animateAnEvent (MAR, MEMORY);
            animateAnEvent (MEMORY, MBR, param);
            comment2 = "";
        }
  
        
        switch (info.getOperationtype()) {
            case RunDebugger.DATA_TRANSFER_OPERATION :
            switch (opcode) {
                case 1 : // STORE
                comment1 = new Message ("Write value {0} from register R{1} to memory slot {2}.", new String[] {""+Rj_value, ""+Rj, ""+param}).toString();
                animateAnEvent (whereIsSecondOperand, MAR, param);
                animateAnEvent (Rj, MBR);
                animateAnEvent (MBR, MEMORY);
                break;
                
                case 2 : // LOAD
                comment1 = new Message ("Load value {0} to register R{1}.", new String[] {""+param, ""+Rj}).toString();
                animateAnEvent (whereIsSecondOperand, Rj, param);
                break;
                
                case 3 : // IN
                int inValue = info.whatIN()[1];
                comment1 = new Message ("Read value {0} from {1} to register R{2}.", new String[] {""+inValue, info.whatDevice(), ""+Rj}).toString();
        	animateAnEvent (whereIsSecondOperand, MAR);
		animateAnEvent (MAR, EXTERNAL_DEVICE);
                animateAnEvent (EXTERNAL_DEVICE, MBR, inValue);
                animateAnEvent (MBR, Rj);
                break;
                
                case 4 : // OUT
                int outValue = info.whatOUT()[1];
                comment1 = new Message ("Write value {0} from register R{1} to {2}.", new String[] {""+value[Rj], ""+Rj, info.whatDevice()}).toString();
                animateAnEvent (Rj, MBR);
		animateAnEvent (MBR, EXTERNAL_DEVICE);
		
                break;
            }
            pause();
            break;

            case RunDebugger.ALU_OPERATION :
            comment1 = new Message ("Copy register R{0} to ALU IN1.", ""+Rj).toString();
            animateAnEvent (Rj, ALU_IN1);
            comment1 = new Message ("Copy second operand to ALU IN2.").toString();
            animateAnEvent (whereIsSecondOperand, ALU_IN2, param);
            comment1 = new Message ("ALU computes the result.").toString();
            pause();
            comment1 = new Message ("Copy ALU result to register R{0}", ""+Rj).toString();
            value[ALU_OUT] = info.getALUResult();
            animateAnEvent (ALU_OUT, Rj);
            pause();
            break;

            case RunDebugger.COMP_OPERATION :
            comment1 = new Message ("Copy register R{0} to ALU IN1.", ""+Rj).toString();
            animateAnEvent (Rj, ALU_IN1);
            comment1 = new Message ("Copy second operand to ALU IN2.").toString();
            animateAnEvent (whereIsSecondOperand, ALU_IN2, param);
            comment1 = new Message ("ALU computes the comparision result.").toString();
            comment2 = new Message ("0=greater, 1=equals, 2=less").toString();
            pause();
            value[ALU_OUT] = info.getCompareStatus();
            comment1 = new Message ("Set comparision result to SR").toString();
            animateAnEvent (ALU_OUT, SR);
            switch (info.getCompareStatus()) {
                case  0 : SR_String = "1   0   0...";break;
                case  1 : SR_String = "0   1   0...";break;
                case  2 : SR_String = "0   0   1...";break;
                default : SR_String = "0   0   0...";break;
            }
            pause();
            comment2 = "";
            break;

            case RunDebugger.BRANCH_OPERATION :
            if (value[PC] == info.getNewPC()) {
                comment1 = new Message ("Branching command - branching condition is false, so do nothing.").toString();
            }
            else {
                comment1 = new Message ("Branching command - branching condition is true, so update PC.").toString();
                animateAnEvent (whereIsSecondOperand, PC, param);
            }
            pause();
            break;

            case RunDebugger.SUB_OPERATION :<commit_msg>Comparision -> comparison kahdessa viestissä; käännökset jo oikein.<commit_after>package fi.hu.cs.titokone;

import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.io.*;
import java.util.*;
import fi.hu.cs.ttk91.TTK91Cpu;


/** This class takes care of the animation window. It digs the 
    needed information from a RunInfo instance. */
public class Animator extends JPanel implements Runnable {
    
    private final static Font textFont = new Font ("Arial", Font.BOLD, 16);

    private final static int R0 = 0;
    private final static int R1 = 1;
    private final static int R2 = 2;
    private final static int R3 = 3;
    private final static int R4 = 4;
    private final static int R5 = 5;
    private final static int R6 = 6;
    private final static int R7 = 7;
    private final static int TR = 8;
    private final static int PC = 9;
    private final static int IR = 10;
    private final static int SR = 11;
    private final static int BASE = 12;
    private final static int LIMIT = 13;
    private final static int MAR = 14;
    private final static int MBR = 15;
    private final static int ALU_IN1 = 16;
    private final static int ALU_IN2 = 17;
    private final static int ALU_OUT = 18;
    private final static int EXTERNAL_DEVICE = 19;
    private final static int MEMORY = 20;
    
    private final static int[][] routeToBus = {
        {182,97,  220,97},              // R0
        {182,119, 220,119},             // R1
        {182,141, 220,141},             // R2
        {182,163, 220,163},             // R3
        {182,185, 220,185},             // R4
        {182,207, 220,207},             // R5
        {182,229, 220,229},             // R6
        {182,251, 220,251},             // R7
        {257,110, 220,110},             // TR
        {257,132, 220,132},             // PC
        {257,154, 220,154},             // IR
        {257,176, 220,176},             // SR
        {257,295, 220,295},             // BASE
        {257,317, 220,317},             // LIMIT
        {257,339, 220,339},             // MAR
        {257,361, 220,361},             // MBR
        {182,327, 220,327},             // ALU_IN1
        {182,349, 220,349},             // ALU_IN2
        {182,393, 220,393},             // ALU_OUT
        {520,423, 520,491, 220,491},    // EXTERNAL_DEVICE
        {661,423, 661,491, 220,491},    // MEMORY
    };
    
    private final static int[][] whereWriteValueTo = {
        {73,105},                       // R0
        {73,127},                       // R1
        {73,149},                       // R2
        {73,171},                       // R3
        {73,193},                       // R4
        {73,215},                       // R5
        {73,237},                       // R6
        {73,259},                       // R7
        {264,117},                      // TR
        {264,139},                      // PC
        {264,161},                      // IR
        {264,183},                      // SR
        {264,303},                      // BASE
        {264,325},                      // LIMIT
        {264,347},                      // MAR
        {264,369},                      // MBR
        {74,334},                       // ALU_IN1
        {74,356},                       // ALU_IN2
        {74,401},                       // ALU_OUT
    };
    
    private final static int[][] whereWriteLabelTo = {
        {35,103},                       // R0
        {35,125},                       // R1
        {35,147},                       // R2
        {35,169},                       // R3
        {35,191},                       // R4
        {35,213},                       // R5
        {35,235},                       // R6
        {35,257},                       // R7
        {376,116},                      // TR
        {376,138},                      // PC
        {376,160},                      // IR
        {376,182},                      // SR
        {376,302},                      // BASE
        {376,324},                      // LIMIT
        {376,346},                      // MAR
        {376,368},                      // MBR
        {35,333},                       // ALU_IN1
        {35,355},                       // ALU_IN2
        {35,400},                       // ALU_OUT
        {35,80},                        // Registers
        {261,80},                       // Control unit
        {261,270},                      // MMU
        {35,305},                       // ALU
        {525,385},                      // External device
        {525,70},                       // Memory
    };

    private final static String[] labels = {
        "R0",
        "R1",
        "R2",
        "R3",
        "R4",
        "R5",
        "R6",
        "R7",
        "TR",
        "PC",
        "IR",
        "SR",
        "BASE",
        "LIMIT",
        "MAR",
        "MBR",
        "IN1",
        "IN2",
        "OUT",
        "Registers",
        "Control unit",
        "MMU",
        "ALU",
        "External device",
        "Memory"
    };        
    
    /** Contains values of registers, alu, memory and external device. */
    private int[] value = new int[routeToBus.length];
   
    /** Current command label */
    private String currentCommand = "";
    
    /** Comment label */
    private String comment1 = "";
    private String comment2 = "";
    
    /** String presentation of status register. */
    private String SR_String = "";
    
    /** If this is true, animation will be executed without repaitings and delays. */
    private boolean executeAnimationImmediately = false;
    
    /** Is animation currently running. */
    private boolean isAnimating = false;
    
    /** Thread, that runs animation. */
    private Thread animationThread;
    
    /** RunInfo object of currently running animation. */
    private RunInfo info;

    private BufferedImage backgroundImage, doubleBuffer;
    private int pointX=-1, pointY=-1;
    private int delay = 40;
    
    /** Creats new animator. 
        @throws IOException If there are problems reading background image throw IOException. */
    public Animator () throws IOException {
        // read the background image
        ClassLoader foo = getClass ().getClassLoader();
        BufferedImage bi = ImageIO.read (foo.getResourceAsStream ("fi/hu/cs/titokone/resources/animator.gif"));
		backgroundImage = new BufferedImage (bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB);
        doubleBuffer = new BufferedImage (bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB);
		backgroundImage.createGraphics().drawImage (bi, 0,0, null);
    }
    
    public void paint (Graphics g) {
        // copy backround image to dublebuffer
        backgroundImage.copyData (doubleBuffer.getRaster());
        
        Graphics g2 = doubleBuffer.createGraphics();
        g2.setColor (Color.BLACK);
    	g2.setFont (textFont);
        
        // write labels
        for (int i=0; i < labels.length; i++)
            g2.drawString (new Message(labels[i]).toString(), whereWriteLabelTo[i][0], whereWriteLabelTo[i][1]);
        
        // write values (registers, alu, control unit, mmu)
        for (int i=0; i < whereWriteValueTo.length; i++)
            if (i != SR)
                g2.drawString ("" + value[i], whereWriteValueTo[i][0], whereWriteValueTo[i][1]);
            else
                g2.drawString (SR_String, whereWriteValueTo[i][0], whereWriteValueTo[i][1]);
            
        // write current command and comments
        g2.drawString (new Message ("Current command: ").toString() + currentCommand, 217, 23);
        g2.drawString (comment1, 29, 548);
        g2.drawString (comment2, 29, 581);
        
        // draw red animation spot
        if (pointX != -1) {
            g2.setColor (Color.RED);
            g2.fillOval (pointX -5, pointY -5, 10, 10);
        }
        
        // draw double buffer to frame
        g.drawImage (doubleBuffer, 0,0, getWidth(), getHeight(), null);
    }
    
    /** Animation is done in this run method. animate method awakes new thread
        with this run method.
    */
    public void run() {
        // Information about command cycle:
        // http://www.cs.helsinki.fi/u/kerola/tito/html/lu05_files/frame.html
        currentCommand = "";        
        
        // animate instruction fetch
        comment1 = new Message ("Fetch the next instruction from memory slot {0} to IR and increase PC by one.", ""+value[PC]).toString();
        animateAnEvent (PC, MAR);
        animateAnEvent (PC, PC, value[PC]+1);
        animateAnEvent (MAR, MEMORY);
        animateAnEvent (MEMORY, MBR, info.getBinary());
        animateAnEvent (MBR, IR);
        currentCommand = info.getLineContents(); //+ "   (" + info.getColonString() + ")";
        pause();
        
        int opcode = info.getBinary() >>> 24;
        int Rj = info.getFirstOperand();
        int Ri = info.getIndexRegister();
        int ADDR = info.getADDR();
        int memoryFetches = info.getMemoryfetches();
        int[] regs = info.getRegisters();
        int Rj_value = value[Rj];
        int Ri_value = value[Ri];
        
        // if NOP interrupt immediately
        if (opcode == 0) {
            comment1 = new Message ("No-operation command completed.").toString();
            pause();
            isAnimating = executeAnimationImmediately = false;
            return;
        }
        
        if (Ri != 0) ADDR += Ri_value;
        int param = ADDR;
        int whereIsSecondOperand = IR;
        if (memoryFetches == 1) {
            param = info.getValueAtADDR();
            whereIsSecondOperand = MBR;
            comment1 = new Message ("Fetch second operand from memory slot {0}.", ""+ADDR).toString();
            animateAnEvent (IR, MAR, ADDR);
            animateAnEvent (MAR, MEMORY);
            animateAnEvent (MEMORY, MBR, param);
        }
        else if (memoryFetches == 2) {
            param = info.getSecondFetchValue();
            whereIsSecondOperand = MBR;
            comment1 = new Message ("Indirect memory accessing mode.").toString();
            comment2 = new Message ("1: Fetch indexing value from memory slot {0}.", ""+ADDR).toString();
            animateAnEvent (IR, MAR, ADDR);
            animateAnEvent (MAR, MEMORY);
            animateAnEvent (MEMORY, MBR, info.getValueAtADDR());
            comment1 = new Message ("Indirect memory accessing mode.").toString();
            comment2 = new Message ("2: Fetch second operand from memory slot {0}.", ""+value[MBR]).toString();
            pause();
            animateAnEvent (MBR, MAR);
            animateAnEvent (MAR, MEMORY);
            animateAnEvent (MEMORY, MBR, param);
            comment2 = "";
        }
  
        
        switch (info.getOperationtype()) {
            case RunDebugger.DATA_TRANSFER_OPERATION :
            switch (opcode) {
                case 1 : // STORE
                comment1 = new Message ("Write value {0} from register R{1} to memory slot {2}.", new String[] {""+Rj_value, ""+Rj, ""+param}).toString();
                animateAnEvent (whereIsSecondOperand, MAR, param);
                animateAnEvent (Rj, MBR);
                animateAnEvent (MBR, MEMORY);
                break;
                
                case 2 : // LOAD
                comment1 = new Message ("Load value {0} to register R{1}.", new String[] {""+param, ""+Rj}).toString();
                animateAnEvent (whereIsSecondOperand, Rj, param);
                break;
                
                case 3 : // IN
                int inValue = info.whatIN()[1];
                comment1 = new Message ("Read value {0} from {1} to register R{2}.", new String[] {""+inValue, info.whatDevice(), ""+Rj}).toString();
        	animateAnEvent (whereIsSecondOperand, MAR);
		animateAnEvent (MAR, EXTERNAL_DEVICE);
                animateAnEvent (EXTERNAL_DEVICE, MBR, inValue);
                animateAnEvent (MBR, Rj);
                break;
                
                case 4 : // OUT
                int outValue = info.whatOUT()[1];
                comment1 = new Message ("Write value {0} from register R{1} to {2}.", new String[] {""+value[Rj], ""+Rj, info.whatDevice()}).toString();
                animateAnEvent (Rj, MBR);
		animateAnEvent (MBR, EXTERNAL_DEVICE);
		
                break;
            }
            pause();
            break;

            case RunDebugger.ALU_OPERATION :
            comment1 = new Message ("Copy register R{0} to ALU IN1.", ""+Rj).toString();
            animateAnEvent (Rj, ALU_IN1);
            comment1 = new Message ("Copy second operand to ALU IN2.").toString();
            animateAnEvent (whereIsSecondOperand, ALU_IN2, param);
            comment1 = new Message ("ALU computes the result.").toString();
            pause();
            comment1 = new Message ("Copy ALU result to register R{0}", ""+Rj).toString();
            value[ALU_OUT] = info.getALUResult();
            animateAnEvent (ALU_OUT, Rj);
            pause();
            break;

            case RunDebugger.COMP_OPERATION :
            comment1 = new Message ("Copy register R{0} to ALU IN1.", ""+Rj).toString();
            animateAnEvent (Rj, ALU_IN1);
            comment1 = new Message ("Copy second operand to ALU IN2.").toString();
            animateAnEvent (whereIsSecondOperand, ALU_IN2, param);
            comment1 = new Message ("ALU computes the comparison result.").toString();
            comment2 = new Message ("0=greater, 1=equals, 2=less").toString();
            pause();
            value[ALU_OUT] = info.getCompareStatus();
            comment1 = new Message ("Set comparison result to SR").toString();
            animateAnEvent (ALU_OUT, SR);
            switch (info.getCompareStatus()) {
                case  0 : SR_String = "1   0   0...";break;
                case  1 : SR_String = "0   1   0...";break;
                case  2 : SR_String = "0   0   1...";break;
                default : SR_String = "0   0   0...";break;
            }
            pause();
            comment2 = "";
            break;

            case RunDebugger.BRANCH_OPERATION :
            if (value[PC] == info.getNewPC()) {
                comment1 = new Message ("Branching command - branching condition is false, so do nothing.").toString();
            }
            else {
                comment1 = new Message ("Branching command - branching condition is true, so update PC.").toString();
                animateAnEvent (whereIsSecondOperand, PC, param);
            }
            pause();
            break;

            case RunDebugger.SUB_OPERATION :
{'fraction_non_alphanumeric': 0.12172259203912512, 'fraction_numerical': 0.0492460263551148, 'mean_word_length': 1.466906836461126, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5193179', 'n_tokens_mistral': 9171, 'n_tokens_neox': 8050, 'n_words': 2290}