/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution 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 3 of the License, or * (at your option) any later version. * * logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.hepia.logisim.chronodata; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; import java.util.ArrayList; import java.util.TreeMap; import com.hepia.logisim.chronogui.ChronoFrame; /** * Contains all data to be plotted */ public class ChronoData extends TreeMap<String, SignalData> { private static final long serialVersionUID = 1L; private ArrayList<String> mSignalOrder = new ArrayList<String>(); public ChronoData() { } /** * Loads and format all the data from logisimLogFile * * @throws IOException */ public ChronoData(String logisimLogFile, ChronoFrame chronoFr) throws IOException, NoSysclkException { LineNumberReader lineReader = null; lineReader = new LineNumberReader(new FileReader(logisimLogFile)); ArrayList<ArrayList<String>> rawData = new ArrayList<ArrayList<String>>(); boolean sysclkFound = false; // read the first line with the signal name // The delimiter is the tabulation String line = lineReader.readLine(); String[] splittedLine = line.split("\\t"); for (int i = 0; i < splittedLine.length; ++i) { ArrayList<String> v = new ArrayList<String>(); v.add(splittedLine[i]); if (splittedLine[i].equals("sysclk")) sysclkFound = true; rawData.add(v); } if (!sysclkFound) { lineReader.close(); throw new NoSysclkException("No sysclk signal found"); } // read the tick frequency line = lineReader.readLine(); try { chronoFr.setTimelineParam(new TimelineParam(line)); } catch (Exception e) { chronoFr.setTimelineParam(null); } // read the rest of the file while ((line = lineReader.readLine()) != null) { splittedLine = line.split("\\t"); for (int i = 0; i < splittedLine.length; ++i) { // if the signal added is a bus wider than 4bit, we have to // remove spaces // (there is a space every 4 bits in a bus in the log file) rawData.get(i).add(splittedLine[i].replaceAll("\\s", "")); } } lineReader.close(); // creates the SignalData et SignalDataBus // and store the signal name order mSignalOrder = new ArrayList<String>(); for (ArrayList<String> vs : rawData) { String name = vs.get(0); mSignalOrder.add(name); if (vs.get(1).length() > 1) { this.put(name, new SignalDataBus(name, vs)); } else { this.put(name, new SignalData(name, vs)); } vs.remove(0); } normalize(); } public void appendValueToSignal(String signalName, String signalValue) { this.get(signalName).getSignalValues() .add(signalValue.replaceAll("\\s", "")); } /** * Hide all signals that compose busName */ public void contractBus(SignalDataBus sd) { if (sd.getSignalValues().size() > 0) { int signalNbr = sd.getSignalValues().get(0).length(); int busNamePos = (mSignalOrder.indexOf(sd.getName())); for (int signalI = 0; signalI < signalNbr; ++signalI) { String name = sd.getName() + "__s__" + signalI; this.remove(name); mSignalOrder.remove(busNamePos + 1); } sd.setExpanded(false); } } /** * Display all signals that compose busName */ public void expandBus(SignalDataBus sd) { if (sd.getSignalValues().size() > 0) { int signalNbr = sd.getSignalValues().get(0).length(); int busNamePos = (mSignalOrder.indexOf(sd.getName())); // for each signal that defines the bus for (int signalI = 0; signalI < signalNbr; ++signalI) { int bitPos = signalNbr - signalI - 1; ArrayList<String> sig = new ArrayList<String>(); String name = sd.getName() + "__s__" + signalI; for (String s : sd.getSignalValues()) { sig.add(s.substring(bitPos, bitPos + 1)); } // add signalData this.put(name, new SignalData(name, sig)); // insert new signal in name signal order mSignalOrder.add(busNamePos + signalI + 1, name); } sd.setExpanded(true); } } public ArrayList<String> getSignalOrder() { return mSignalOrder; } /** * Remove if the sysclk has 2 or more identical states */ private void normalize() { try { ArrayList<String> vClk = this.get("sysclk").getSignalValues(); int i = 0; while (i < vClk.size() - 1) { if (vClk.get(i).equals(vClk.get(i + 1))) { for (SignalData sd : this.values()) { sd.getSignalValues().remove(i); } } else { i++; } } } catch (Exception e) { e.printStackTrace(); } } public void setSignalOrder(ArrayList<String> order) { mSignalOrder = new ArrayList<String>(order); } /** * In real time mode, if a bus is expanded we need to add the new data to * every signal */ public void updateRealTimeExpandedBus() { for (java.util.Map.Entry<String, SignalData> entry : this.entrySet()) { if (entry.getValue() instanceof SignalDataBus) { SignalDataBus sdb = (SignalDataBus) entry.getValue(); if (sdb.isExpanded()) { int signalNbr = sdb.getSignalValues().get(0).length(); for (int signalI = 0; signalI < signalNbr; ++signalI) { int bitPos = signalNbr - signalI - 1; String name = sdb.getName() + "__s__" + signalI; this.get(name) .getSignalValues() .add(sdb.getSignalValues() .get(sdb.getSignalValues().size() - 1) .substring(bitPos, bitPos + 1)); } } } } } }