/*******************************************************************************
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package hr.fer.zemris.vhdllab.applets.simulations;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Klasa sluzi za parsiranje stringa koji sadrzi rezultate simulacije prikazane
* u jednom stringu, internog formata. Parsirane rezultate direktno koristi
* applet za iscrtavanje rezultata simulacije
*
* @author Boris Ozegovic
*/
public class GhdlResults
{
/** Glavni limiter, razdvaja imena signala, vrijednosti i maxSignalName */
private static final String HEAD_LIMITER = "%%%";
/** Razdvaja svako ime signala posebno, vrijednosti signala itd. */
private static final String LIMITER = "###";
/* Razdvaja vrijednosti po signalima */
private static final String VALUE_LIMITER = "&&&";
/** Rezultat simulacije predstavljen kao string */
private String resultInString;
/** Sadrzi razdvojene signale */
private String[] splitResults;
/**
* Lista koji sadrzi imena signala nakon parsiranja, ovisno o ekspandiranim
* vektorima moze biti veca od defaultne liste koja sadrzi imena vektora
* prikazane kao vektor
*/
private List<String> signalNames = new LinkedList<String>();
/** Sadrzi default imena signala */
private String[] defaultSignalNames;
/** Svaki redak predstavlja sve vrijednosti pojedinog signala */
private List<String[]> signalValues = new LinkedList<String[]>();
/** Defaultne vrijednosti */
private String[][] defaultSignalValues;
/** Sadrzi tocke u kojima se dogada promjena vrijednosti signala */
private String[] transitionPointsInStrings;
/** Tocke u kojima se dogada promjena */
private long[] transitionPoints;
/**
* Kod za crtanje modificira {@link #transitionPoints}. Zadaca ovog polja jest
* sacuvati original.
*/
private long[] unscaledTransitionPoints;
/** Broj znakova najduljeg imena signala */
private int maximumSignalNameLength;
/** Makimalna duljina vektora, ukoliko postoje vektori */
private int maximumVectorSize = 1;
/** Sadrzi informaciju jesu li bit-vectori prosireni */
private List<Boolean> expandedSignalNames = new ArrayList<Boolean>();
/**
* Lista trenutnih indeksa vektora u listi sa signalima
*/
private List<Integer> currentVectorIndex = new ArrayList<Integer>();
/**
* Pomocni objekt koji predstavlja cache za objekte tipa SignalChangeEvent.
*/
private SignalChangeEventCache sceCache;
/**
* Objekt koji za svaki signal (ukljucivo i vektore i komponente vektora) cuva
* trenutke kada su se dogodile promjene.
*/
private SignalChangeTracker signalChangeTracker;
/**
* Metoda koja vrsi samo parsiranje stringa zapisanog u internom formatu
*/
public void parseString (String resultString)
{
/*
* razdvaja u cetiri stringa, imena signala, vrijednosti, tocke
* promjene vrijednosti signala i konacno broj znakova najduljeg imena
* signala
*/
this.resultInString = resultString;
splitResults = resultInString.split(HEAD_LIMITER);
/* [0] su imena signala, [1] values, [2] tocke promjene, [3] max ime */
defaultSignalNames = splitResults[0].split(LIMITER);
/* prvo razdvaja sve signale (0&&&Z&&&1 itd za svaki) */
String[] temp = splitResults[1].split(LIMITER);
String[][] matrica = new String[temp.length][];
/* a onda pojedinacno sve vrijednosti tih signala */
for (int i = 0; i < temp.length; i++)
{
matrica[i] = temp[i].split(VALUE_LIMITER);
expandedSignalNames.add(false);
if (matrica[i][0].length() != 1)
{
currentVectorIndex.add(i);
if (matrica[i][0].length() > maximumVectorSize)
{
maximumVectorSize = matrica[i][0].length();
}
}
else
{
currentVectorIndex.add(-1);
}
}
defaultSignalValues = matrica;
/* dobivanje tocaka u kojima se dogada promjena vrijednosti signala */
transitionPointsInStrings = splitResults[2].split(LIMITER);
transitionPoints = new long[transitionPointsInStrings.length];
unscaledTransitionPoints = new long[transitionPoints.length];
for (int i = 0; i < transitionPointsInStrings.length; i++)
{
transitionPoints[i] = Long.valueOf(transitionPointsInStrings[i]).longValue();
unscaledTransitionPoints[i] = transitionPoints[i];
}
/* broj znakova najduljeg imena signala */
maximumSignalNameLength = Integer.valueOf(splitResults[3]).intValue();
/* postavi vrijednosti liste na pocetno stanje */
for (String string : defaultSignalNames)
{
signalNames.add(string);
}
for (String[] array : defaultSignalValues)
{
signalValues.add(array);
}
// Sada za svaki signal napravi popis samo njegovih promjena
Map<String, SignalChangeEvent[]> signalChangeMap = rebuildSignalChangeMap();
signalChangeTracker = new SignalChangeTracker(signalChangeMap);
}
private Map<String, SignalChangeEvent[]> rebuildSignalChangeMap() {
// Sada za svaki signal napravi popis samo njegovih promjena
Map<String, SignalChangeEvent[]> signalChangeMap = new HashMap<String, SignalChangeEvent[]>(signalNames.size()*2);
if(sceCache==null) {
sceCache = new SignalChangeEventCache();
}
for(int signalIndex = 0; signalIndex < signalNames.size(); signalIndex++) {
List<SignalChangeEvent> scEvents = new ArrayList<SignalChangeEvent>();
String[] sValues = signalValues.get(signalIndex);
for(int transIndex = 0; transIndex < transitionPoints.length-1; transIndex++) {
String signalValue = sValues[transIndex];
// Ako je ovo prvi trenutak, dodaj ga i vozi dalje
if(transIndex==0) {
scEvents.add(sceCache.get(signalValue, transitionPoints[transIndex]));
continue;
}
// Inace usporedi vrijednost sa onom od prethodnog trenutka; ako su iste, ovo nije promjena!
if(signalValue.equals(sValues[transIndex-1])) continue;
scEvents.add(sceCache.get(signalValue, transitionPoints[transIndex]));
}
SignalChangeEvent[] array = new SignalChangeEvent[scEvents.size()];
scEvents.toArray(array);
signalChangeMap.put(signalNames.get(signalIndex), array);
signalChangeMap.put("!sig:"+signalIndex, array);
if(transitionPoints.length<1) continue;
// Ako je ovo vektor:
if(sValues[0].length()>1) {
int vectorLength = sValues[0].length();
for(int scalarIndex = 0; scalarIndex < vectorLength; scalarIndex++) {
scEvents = new ArrayList<SignalChangeEvent>();
for(int transIndex = 0; transIndex < transitionPoints.length-1; transIndex++) {
char signalValue = sValues[transIndex].charAt(scalarIndex);
// Ako je ovo prvi trenutak, dodaj ga i vozi dalje
if(transIndex==0) {
scEvents.add(sceCache.get(Character.toString(signalValue), transitionPoints[transIndex]));
continue;
}
// Inace usporedi vrijednost sa onom od prethodnog trenutka; ako su iste, ovo nije promjena!
if(signalValue==sValues[transIndex-1].charAt(scalarIndex)) continue;
scEvents.add(sceCache.get(Character.toString(signalValue), transitionPoints[transIndex]));
}
array = new SignalChangeEvent[scEvents.size()];
scEvents.toArray(array);
signalChangeMap.put(signalNames.get(signalIndex)+"\t"+scalarIndex, array);
signalChangeMap.put("!sig:"+signalIndex+"_"+scalarIndex, array);
}
}
}
return signalChangeMap;
}
/**
* Dohvat objekta koji cuva promjene signala.
*
* @return signalChangeTracker za trenutni rezultat simulacije
*/
public SignalChangeTracker getSignalChangeTracker() {
return signalChangeTracker;
}
/**
* Metoda koja mijenja poredak signala prema gore. Mijenja se poredak imena
* i poredak vrijednosti..
*
* MČ: promjene signala su u ovoj verziji vhdllab-a ONEMOGUCENE tako dugo dok se pamcenje
* stanja ne prebaci na jedno mjesto. Trenutno je postalo nemoguce sinkronizirati sve
* komponente koje pamte svaka za sebe je li nesto ekspandirano ili nije i gdje bi se
* to na ekranu trebalo nalaziti (2010-09-25).
*
* @param index Indeks signala koji se pomice prema gore
* @return Vraca indeks tako da se ponovno pozicionira na signal koji se pomicao
*/
public int changeSignalOrderUp (int index)
{
/* ako je signal vec na vrhu */
if (index == 0)
{
return index;
}
return index;
// /* prethodni index defaultnog polja s imenima signala */
// Integer previousDefaultIndex;
// int vectorSize;
//
// /* ako gore ide obican signal ili neekspandirani vektor*/
// if (currentVectorIndex.get(index) == -1 ||
// (currentVectorIndex.get(index) != -1 &&
// !expandedSignalNames.get(currentVectorIndex.get(index))))
// {
// previousDefaultIndex = currentVectorIndex.get(index - 1);
// /* ako je iznad obicnog signala bio obican signal ili neekspandirani vektor*/
// if (previousDefaultIndex == -1 ||
// (previousDefaultIndex != -1 &&
// !expandedSignalNames.get(previousDefaultIndex)))
// {
// /* promjena poretka imena signala */
// signalNames.add(index - 1, signalNames.get(index));
// signalNames.remove(index + 1);
//
// /* promjena poretka vrijednosti signala */
// signalValues.add(index - 1, signalValues.get(index));
// signalValues.remove(index + 1);
//
// /* promjena poretka u listi indeksa */
// currentVectorIndex.add(index - 1, currentVectorIndex.get(index));
// currentVectorIndex.remove(index + 1);
//
// index--;
// }
// /* inace ako je iznad obicnog signala bio ekspandirani vektor */
// else if (previousDefaultIndex != -1 &&
// expandedSignalNames.get(previousDefaultIndex) == true)
// {
// vectorSize = defaultSignalValues[previousDefaultIndex][0].length();
//
// /* promjena poretka imena signala */
// signalNames.add(index - vectorSize, signalNames.get(index));
// signalNames.remove(index + 1);
//
// /* promjena poretka vrijednosti */
// signalValues.add(index - vectorSize, signalValues.get(index));
// signalValues.remove(index + 1);
//
// /* promjena u listi indeksa */
// currentVectorIndex.add(index - vectorSize,
// currentVectorIndex.get(index));
// currentVectorIndex.remove(index + 1);
//
// index -= vectorSize;
// }
// }
// /* Inace ako gore ide ekspandirani vektor */
// else
// {
// vectorSize = defaultSignalValues[currentVectorIndex.get(index)][0].length();
// int vectorStartIndex = currentVectorIndex.indexOf(currentVectorIndex.get(index));
// if (vectorStartIndex == 0)
// {
// return index;
// }
// previousDefaultIndex = currentVectorIndex.get(vectorStartIndex - 1);
//
// /* ako je iznad bio obican signal ili neekspandirani vektor */
// if (previousDefaultIndex == -1 ||
// (previousDefaultIndex != -1 &&
// !expandedSignalNames.get(previousDefaultIndex)))
// {
// /* promjena poretka imena signala */
// signalNames.add(vectorStartIndex + vectorSize,
// signalNames.get(vectorStartIndex - 1));
// signalNames.remove(vectorStartIndex - 1);
//
// /* promjena poretka vrijednosti */
// signalValues.add(vectorStartIndex + vectorSize,
// signalValues.get(vectorStartIndex - 1));
// signalValues.remove(vectorStartIndex - 1);
//
// /* promjena poretka indeksa u listi */
// currentVectorIndex.add(vectorStartIndex + vectorSize,
// currentVectorIndex.get(vectorStartIndex - 1));
// currentVectorIndex.remove(vectorStartIndex - 1);
//
// index--;
// }
// /* ako je iznad bio ekspandirani vektor */
// else
// {
// vectorStartIndex = currentVectorIndex.indexOf(currentVectorIndex.get(index));
// int vectorSizeUp = defaultSignalValues[currentVectorIndex.get(index)][0].length();
// int vectorSizeDown =
// defaultSignalValues[currentVectorIndex.get(vectorStartIndex - 1)][0].length();
//
// /* promjena poretka imena signala */
// for (int i = 0; i < vectorSizeDown; i++)
// {
// signalNames.add(vectorStartIndex + vectorSizeUp - i,
// signalNames.get(vectorStartIndex - 1 - i));
// signalNames.remove(vectorStartIndex - i - 1);
// }
//
// /* promjena poretka vrijednosti */
// for (int i = 0; i < vectorSizeDown; i++)
// {
// signalValues.add(vectorStartIndex + vectorSizeUp - i,
// signalValues.get(vectorStartIndex - 1 - i));
// signalValues.remove(vectorStartIndex - i - 1);
// }
//
// /* promjena poretka indeksa */
// for (int i = 0; i < vectorSizeDown; i++)
// {
// currentVectorIndex.add(vectorStartIndex + vectorSizeUp - i,
// currentVectorIndex.get(vectorStartIndex - 1 - i));
// currentVectorIndex.remove(vectorStartIndex - i - 1);
// }
//
// index -= vectorSizeDown;
// }
// }
// signalChangeTracker.update(rebuildSignalChangeMap());
// /* Vraca indeks tako da se pozicionira na signal koji se pomicao u pocetku */
// return index;
}
/**
* Metoda koja mijenja poredak signala prema dolje.
*
* MČ: promjene signala su u ovoj verziji vhdllab-a ONEMOGUCENE tako dugo dok se pamcenje
* stanja ne prebaci na jedno mjesto. Trenutno je postalo nemoguce sinkronizirati sve
* komponente koje pamte svaka za sebe je li nesto ekspandirano ili nije i gdje bi se
* to na ekranu trebalo nalaziti (2010-09-25).
*
* @param index indeks signala koji se pomice prema dolje
* @return Vraca indeks tako da se ponovno pozicionira na signal koji se pomicao
*/
public int changeSignalOrderDown (int index)
{
/* ako je signal vec na dnu */
if (index == (signalNames.size() - 1))
{
return index;
}
return index;
// /* Sljedeci index defaultnog polja s imenima signala */
// Integer nextDefaultIndex;
// int vectorSize;
//
// /* ako dolje ide obican signal ili neekspandirani vektor*/
// if (currentVectorIndex.get(index) == -1 ||
// (currentVectorIndex.get(index) != -1 &&
// !expandedSignalNames.get(currentVectorIndex.get(index))))
// {
// nextDefaultIndex = currentVectorIndex.get(index + 1);
// /* ako je ispod obicnog signala bio obican signal ili neekspandirani vektor */
// if (nextDefaultIndex == -1 ||
// (nextDefaultIndex != -1 &&
// !expandedSignalNames.get(nextDefaultIndex)))
// {
// /* promjena poretka imena signala */
// signalNames.add(index, signalNames.get(index + 1));
// signalNames.remove(index + 2);
//
// /* promjena poretka vrijednosti signala */
// signalValues.add(index, signalValues.get(index + 1));
// signalValues.remove(index + 2);
//
// /* promjena poretka u listi indeksa */
// currentVectorIndex.add(index, currentVectorIndex.get(index + 1));
// currentVectorIndex.remove(index + 2);
//
// index++;
// }
// /* inace ako je ispod obicnog signala bio ekspandirani vektor */
// else if (nextDefaultIndex != -1 &&
// expandedSignalNames.get(nextDefaultIndex) == true)
// {
// vectorSize = defaultSignalValues[nextDefaultIndex][0].length();
//
// /* promjena poretka imena signala */
// signalNames.add(index + vectorSize + 1, signalNames.get(index));
// signalNames.remove(index);
//
// /* promjena poretka vrijednosti */
// signalValues.add(index + vectorSize + 1, signalValues.get(index));
// signalValues.remove(index);
//
// /* promjena u listi indeksa */
// currentVectorIndex.add(index + vectorSize + 1,
// currentVectorIndex.get(index));
// currentVectorIndex.remove(index);
//
// index += vectorSize;
// }
// }
// /* Inace ako dolje ide ekspandirani vektor */
// else
// {
// vectorSize =
// defaultSignalValues[currentVectorIndex.get(index)][0].length();
// int vectorStartIndex =
// currentVectorIndex.indexOf(currentVectorIndex.get(index));
// if (vectorStartIndex + vectorSize - 1 == (signalNames.size() - 1))
// {
// return index;
// }
// nextDefaultIndex = currentVectorIndex.get(vectorStartIndex + vectorSize);
//
// /* ako je ispod bio obican signal ili neekspandirani vektor */
// if (nextDefaultIndex == -1 ||
// (nextDefaultIndex != -1 &&
// !expandedSignalNames.get(nextDefaultIndex)))
// {
// /* promjena poretka imena signala */
// signalNames.add(vectorStartIndex,
// signalNames.get(vectorStartIndex + vectorSize));
// signalNames.remove(vectorStartIndex + vectorSize + 1);
//
// /* promjena poretka vrijednosti */
// signalValues.add(vectorStartIndex,
// signalValues.get(vectorStartIndex + vectorSize));
// signalValues.remove(vectorStartIndex + vectorSize + 1);
//
// /* promjena poretka indeksa u listi */
// currentVectorIndex.add(vectorStartIndex,
// currentVectorIndex.get(vectorStartIndex + vectorSize));
// currentVectorIndex.remove(vectorStartIndex + vectorSize + 1);
//
// index++;
// }
// /* ako je ispod bio ekspandirani vektor */
// else
// {
// vectorStartIndex =
// currentVectorIndex.indexOf(currentVectorIndex.get(index));
// int vectorSizeDown =
// defaultSignalValues[currentVectorIndex.get(index)][0].length();
// int vectorSizeUp =
// defaultSignalValues[currentVectorIndex.get(vectorStartIndex +
// vectorSizeDown)][0].length();
//
// /* promjena poretka imena signala */
// for (int i = 0; i < vectorSizeDown; i++)
// {
// signalNames.add(vectorStartIndex + vectorSizeUp + vectorSizeDown - i,
// signalNames.get(vectorStartIndex + vectorSizeDown - 1 - i));
// signalNames.remove(vectorStartIndex + vectorSizeDown - i - 1);
// }
//
// /* promjena poretka vrijednosti */
// for (int i = 0; i < vectorSizeDown; i++)
// {
// signalValues.add(vectorStartIndex + vectorSizeUp + vectorSizeDown - i,
// signalValues.get(vectorStartIndex + vectorSizeDown - 1 - i));
// signalValues.remove(vectorStartIndex + vectorSizeDown - i - 1);
// }
//
// /* promjena poretka indeksa */
// for (int i = 0; i < vectorSizeDown; i++)
// {
// currentVectorIndex.add(vectorStartIndex + vectorSizeUp + vectorSizeDown - i,
// currentVectorIndex.get(vectorStartIndex + vectorSizeDown - 1 - i));
// currentVectorIndex.remove(vectorStartIndex + vectorSizeDown - i - 1);
// }
//
// index += vectorSizeUp;
// }
// }
// signalChangeTracker.update(rebuildSignalChangeMap());
// /* Vraca indeks tako da se ponovno pozicionira na signal koji se pomicao */
// return index;
}
/**
* Metoda koja vraca defaultni poredak
*/
public void setDefaultOrder ()
{
signalNames.clear();
signalValues.clear();
for (String string : defaultSignalNames)
{
signalNames.add(string);
}
for (String[] array : defaultSignalValues)
{
signalValues.add(array);
}
}
/**
* Getter vrijednosti po signalima
*/
public List<String[]> getSignalValues ()
{
return signalValues;
}
/**
* Getter imena signala
*/
public List<String> getSignalNames ()
{
return signalNames;
}
/**
* Getter vrijednosti defaultnih signala
*/
public String[][] getDefaultSignalValues ()
{
return defaultSignalValues;
}
/**
* Getter default imena signala
*/
public String[] getDefaultSignalNames ()
{
return defaultSignalNames;
}
/**
* Vraca polje tocaka u kojima se dogada promjena signala
*/
public long[] getTransitionPoints()
{
return transitionPoints;
}
/**
* Vraca polje tocaka u kojima se dogada promjena signala; pri tome su vrijednosti
* u mjernim jedinicama u kojima radi sam simulator.
* @return polje vremena promjena
*/
public long[] getUnscaledTransitionPoints() {
return unscaledTransitionPoints;
}
/**
* Vraca najveci trenutak u kojem se je dogodila bilo kakva promjena.
* @return najveci trenutak bilo kakve promjene
*/
public long getMaxUnscaledSimulationTime() {
if(unscaledTransitionPoints.length==0) return 0;
return unscaledTransitionPoints[unscaledTransitionPoints.length-1];
}
/**
* Vraca broj znakova najduljeg imena signala
*/
public int getMaximumSignalNameLength()
{
return maximumSignalNameLength;
}
/**
* Vraca duljinu najveceg vektora
*/
public int getMaximumVectorSize()
{
return maximumVectorSize;
}
/**
* Vraca informaciju o ekspandiranim bit-vektorima u panelu s imenima
* signala
*/
public List<Boolean> getExpandedSignalNames()
{
return expandedSignalNames;
}
/**
* Zatvara sve expandirane bit-vektore
*/
public void setDefaultExpandedSignalNames()
{
expandedSignalNames.clear();
currentVectorIndex.clear();
for (int i = 0; i < defaultSignalValues.length; i++)
{
expandedSignalNames.add(false);
if (defaultSignalValues[i].length >= 2 && defaultSignalValues[i][1].length() != 1)
{
currentVectorIndex.add(i);
}
else
{
currentVectorIndex.add(-1);
}
}
}
/**
* Trenutni ideksi vektora u listi sa signalima
*/
public List<Integer> getCurrentVectorIndex()
{
return currentVectorIndex;
}
/**
* Test metoda
*/
public static void main (String[] args)
{
// VcdParser parser = new VcdParser("adder2.vcd");
// parser.parse();
// GhdlResults sParser = new GhdlResults();
// sParser.parseString(parser.getResultInString());
//System.out.println(sParser.getSignalNames());
//System.out.println(sParser.getSignalValues());
// System.out.println(sParser.getExpandedSignalNames());
// System.out.println(sParser.getCurrentVectorIndex());
}
}