/* CycleElement.java
*
* This class represents the single element that is then drawn in the cycles
* component.
* (c) 2006 Filippo Mondello
*
* This file is part of the EduMIPS64 project, and is released under the GNU
* General Public License.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.edumips64.utils;
import java.util.*;
import java.util.logging.Logger;
import org.edumips64.core.is.Instruction;
/**
* This class represents the single element that is then drawn in the cycles
* component.
* @author Filippo Mondello
*/
public class CycleElement {
private int startTime;
private LinkedList<String> states;
private Instruction instruction;
// Boolean storing whether this CycleElement contains one or more invalid transactions.
// Used for testing and debugging purposes.
private boolean hasInvalidTransaction = false;
private static final Logger logger = Logger.getLogger(CycleElement.class.getName());
/**
* A new element of this class is created.
* @param instruction the instruction object
* @param startTime the time in which the element entered in the pipeline
*/
CycleElement(Instruction instruction, int startTime) {
this.startTime = startTime;
this.instruction = instruction;
states = new LinkedList<>();
states.add("IF");
}
/**
* @return the name of the instruction
*/
public String getName() {
return instruction.getFullName();
}
public int getSerialNumber() {
return instruction.getSerialNumber();
}
/**
* This method is called for every clock cycle.
* @param newState the current stage in pipeline of the instruction.
*/
void addState(String newState) {
String lastState = states.getLast();
if (!validateStateTransition(lastState, newState)) {
hasInvalidTransaction = true;
logger.severe("Instruction: " + instruction + ", startTime: " + startTime);
logger.severe("State " + newState + " is not allowed after state " + lastState);
}
states.add(newState);
}
// Should only be called when the Cycle refers to a completed instruction. Used only in unit tests.
boolean isFinalStateValid() {
String lastState = states.getLast();
// Valid termination states. IF is valid due to branches.
if (lastState.equals("WB") || lastState.equals("IF")) {
return true;
}
// " " is the only other valid end state, but it is acceptable only if it's added to IF.
if (lastState.equals(" ")) {
Set<String> allStates = new HashSet<>(states);
if (allStates.size() == 2 && states.getFirst() == "IF") {
return true;
} else {
logger.severe("The empty state is not valid as a final state if there are not only IF states. All states: " + states.toString());
return false;
}
}
logger.severe(lastState + " is not a valid final state.");
return false;
}
// Should only be called when the Cycle refers to a completed instruction. Used only in unit tests.
public boolean isValid() {
return !hasInvalidTransaction && isFinalStateValid();
}
/**
* @return the whole list of stages in pipeline
*/
public LinkedList<String> getStates() {
return states;
}
String getLastState() {
return states.getLast();
}
/**
* @return the initial time in which the instruction occupied the IF stage in pipeline.
*/
public int getTime() {
return startTime;
}
public boolean shouldRender() {
return !instruction.isBubble();
}
// Map that associates to a given state the set of allowed successor states.
// The states that are not added in the list are not checked.
// TODO: complete the map (it does not contain all possible transitions).
private static Map<String, Set<String>> allowedTransitions;
static {
allowedTransitions = new HashMap<>();
allowedTransitions.put("IF", new HashSet<>(Arrays.asList("ID", " ")));
allowedTransitions.put("ID", new HashSet<>(Arrays.asList("ID", "EX", "RAW", "WAW", "DIV", "StDiv", "StEx", "StFun", "A1", "M1")));
allowedTransitions.put("RAW", new HashSet<>(Arrays.asList("RAW", "WAW", "EX", "M1", "A1")));
allowedTransitions.put("WAW", new HashSet<>(Arrays.asList("WAW", "EX", "M1", "A1")));
allowedTransitions.put("EX", new HashSet<>(Arrays.asList("MEM", "Str")));
allowedTransitions.put("MEM", new HashSet<>(Arrays.asList("WB")));
allowedTransitions.put("WB", new HashSet<>(Arrays.asList(" ")));
}
private static boolean validateStateTransition(String curState, String nextState) {
// Don't check states that are not in the map.
return !allowedTransitions.containsKey(curState) || allowedTransitions.get(curState).contains(nextState);
}
}